ref: 9f50ee06f3a78af3767ec061f4647b5446c8619e
parent: ada54defbcb037f8858b475f90ef215b7d1b44a6
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Wed Sep 23 12:57:25 EDT 2015
libsec: implement client certificate authentication for tls1.2 we used to negotiate tls1.1 for client cert authentication because the signature generation was not implemented for tls1.2. this is now fixed and tls1.2 can be negotiated with client certs.
--- a/sys/src/libsec/port/tlshand.c
+++ b/sys/src/libsec/port/tlshand.c
@@ -130,6 +130,7 @@
} certificate;
struct {
Bytes *types;
+ Ints *sigalgs;
int nca;
Bytes **cas;
} certificateRequest;
@@ -146,6 +147,7 @@
int curve;
} serverKeyExchange;
struct {
+ int sigalg;
Bytes *signature;
} certificateVerify;
Finished finished;
@@ -387,6 +389,7 @@
/* x509.c */
extern mpint* pkcs1padbuf(uchar *buf, int len, mpint *modulus);
extern int pkcs1decryptsignature(uchar *sig, int siglen, RSApub *pk, uchar **pbuf);
+extern int X509encodesignature_sha256(uchar digest[SHA2_256dlen], uchar *buf, int len);
//================= client/server ========================
@@ -1024,7 +1027,6 @@
uchar kd[MaxKeyData];
char *secrets;
int creq, dhx, rv, cipher;
- mpint *signedMP, *paddedHashes;
Bytes *epm;
if(!initCiphers())
@@ -1033,10 +1035,6 @@
c = emalloc(sizeof(TlsConnection));
c->version = ProtocolVersion;
- // client certificate signature not implemented for TLS1.2
- if(cert != nil && certlen > 0 && c->version >= TLS12Version)
- c->version = TLS11Version;
-
c->ctl = ctl;
c->hand = hand;
c->trace = trace;
@@ -1201,15 +1199,11 @@
/* certificate verify */
if(creq && cert != nil && certlen > 0) {
- uchar hshashes[MD5dlen+SHA1dlen]; /* content of signature */
+ mpint *signedMP, *paddedHashes;
HandshakeHash hsave;
+ uchar buf[512];
+ int buflen;
- /* save the state for the Finish message */
- hsave = c->handhash;
- md5(nil, 0, hshashes, &c->handhash.md5);
- sha1(nil, 0, hshashes+MD5dlen, &c->handhash.sha1);
- c->handhash = hsave;
-
c->sec->rpc = factotum_rsa_open(cert, certlen);
if(c->sec->rpc == nil){
tlsError(c, EHandshakeFailure, "factotum_rsa_open: %r");
@@ -1221,7 +1215,22 @@
goto Err;
}
- paddedHashes = pkcs1padbuf(hshashes, MD5dlen+SHA1dlen, c->sec->rsapub->n);
+ /* save the state for the Finish message */
+ hsave = c->handhash;
+ if(c->version >= TLS12Version){
+ uchar digest[SHA2_256dlen];
+
+ m.u.certificateVerify.sigalg = 0x0401; /* RSA SHA256 */
+ sha2_256(nil, 0, digest, &c->handhash.sha2_256);
+ buflen = X509encodesignature_sha256(digest, buf, sizeof(buf));
+ } else {
+ md5(nil, 0, buf, &c->handhash.md5);
+ sha1(nil, 0, buf+MD5dlen, &c->handhash.sha1);
+ buflen = MD5dlen+SHA1dlen;
+ }
+ c->handhash = hsave;
+
+ paddedHashes = pkcs1padbuf(buf, buflen, c->sec->rsapub->n);
signedMP = factotum_rsa_decrypt(c->sec->rpc, paddedHashes);
if(signedMP == nil){
tlsError(c, EHandshakeFailure, "factotum_rsa_decrypt: %r");
@@ -1410,6 +1419,10 @@
}
break;
case HCertificateVerify:
+ if(m->u.certificateVerify.sigalg != 0){
+ put16(p, m->u.certificateVerify.sigalg);
+ p += 2;
+ }
put16(p, m->u.certificateVerify.signature->len);
p += 2;
memmove(p, m->u.certificateVerify.signature->data, m->u.certificateVerify.signature->len);
@@ -1684,14 +1697,16 @@
p += nn;
n -= nn;
if(c->version >= TLS12Version){
- /* skip supported_signature_algorithms */
if(n < 2)
goto Short;
nn = get16(p);
p += 2;
n -= 2;
- if(nn > n)
+ if(nn & 1)
goto Short;
+ m->u.certificateRequest.sigalgs = newints(nn>>1);
+ for(i = 0; i < nn; i += 2)
+ m->u.certificateRequest.sigalgs->data[i >> 1] = get16(&p[i]);
p += nn;
n -= nn;
@@ -1861,6 +1876,7 @@
break;
case HCertificateRequest:
freebytes(m->u.certificateRequest.types);
+ freeints(m->u.certificateRequest.sigalgs);
for(i=0; i<m->u.certificateRequest.nca; i++)
freebytes(m->u.certificateRequest.cas[i]);
free(m->u.certificateRequest.cas);
@@ -1969,6 +1985,8 @@
case HCertificateRequest:
bs = seprint(bs, be, "CertificateRequest\n");
bs = bytesPrint(bs, be, "\ttypes: ", m->u.certificateRequest.types, "\n");
+ if(m->u.certificateRequest.sigalgs != nil)
+ bs = intsPrint(bs, be, "\tsigalgs: ", m->u.certificateRequest.sigalgs, "\n");
bs = seprint(bs, be, "\tcertificateauthorities\n");
for(i=0; i<m->u.certificateRequest.nca; i++)
bs = bytesPrint(bs, be, "\t\t", m->u.certificateRequest.cas[i], "\n");
@@ -1975,6 +1993,8 @@
break;
case HCertificateVerify:
bs = seprint(bs, be, "HCertificateVerify\n");
+ if(m->u.certificateVerify.sigalg != 0)
+ bs = seprint(bs, be, "\tsigalg: %.4x\n", m->u.certificateVerify.sigalg);
bs = bytesPrint(bs, be, "\tsignature: ", m->u.certificateVerify.signature,"\n");
break;
case HServerHelloDone:
--- a/sys/src/libsec/port/x509.c
+++ b/sys/src/libsec/port/x509.c
@@ -2496,6 +2496,31 @@
return mkseq(el);
}
+int
+X509encodesignature_sha256(uchar digest[SHA2_256dlen], uchar *buf, int len)
+{
+ Bytes *sigbytes;
+ Elem sig;
+ int err;
+
+ sig = mkseq(
+ mkel(mkalg(ALG_sha256),
+ mkel(mkoctet(digest, SHA2_256dlen),
+ nil)));
+ err = encode(sig, &sigbytes);
+ freevalfields(&sig.val);
+ if(err != ASN_OK)
+ return -1;
+ if(len < sigbytes->len){
+ freebytes(sigbytes);
+ return -1;
+ }
+ len = sigbytes->len;
+ memmove(buf, sigbytes->data, len);
+ freebytes(sigbytes);
+
+ return len;
+}
uchar*
X509gen(RSApriv *priv, char *subj, ulong valid[2], int *certlen)