diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2015-09-23 16:57:25 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2015-09-23 16:57:25 +0200 |
commit | 9f50ee06f3a78af3767ec061f4647b5446c8619e (patch) | |
tree | 1532d6fc3cd4cf5977a84a78dcbb3835ad7a1dd6 | |
parent | ada54defbcb037f8858b475f90ef215b7d1b44a6 (diff) | |
download | plan9front-9f50ee06f3a78af3767ec061f4647b5446c8619e.tar.xz |
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.
-rw-r--r-- | sys/src/libsec/port/tlshand.c | 50 | ||||
-rw-r--r-- | sys/src/libsec/port/x509.c | 25 |
2 files changed, 60 insertions, 15 deletions
diff --git a/sys/src/libsec/port/tlshand.c b/sys/src/libsec/port/tlshand.c index 4a2e4f481..bc6506704 100644 --- a/sys/src/libsec/port/tlshand.c +++ b/sys/src/libsec/port/tlshand.c @@ -130,6 +130,7 @@ typedef struct Msg{ } certificate; struct { Bytes *types; + Ints *sigalgs; int nca; Bytes **cas; } certificateRequest; @@ -146,6 +147,7 @@ typedef struct Msg{ int curve; } serverKeyExchange; struct { + int sigalg; Bytes *signature; } certificateVerify; Finished finished; @@ -387,6 +389,7 @@ static void freeints(Ints* b); /* 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 @@ tlsClient2(int ctl, int hand, uchar *csid, int ncsid, uchar *cert, int certlen, uchar kd[MaxKeyData]; char *secrets; int creq, dhx, rv, cipher; - mpint *signedMP, *paddedHashes; Bytes *epm; if(!initCiphers()) @@ -1033,10 +1035,6 @@ tlsClient2(int ctl, int hand, uchar *csid, int ncsid, uchar *cert, int certlen, 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,14 +1199,10 @@ tlsClient2(int ctl, int hand, uchar *csid, int ncsid, uchar *cert, int certlen, /* certificate verify */ if(creq && cert != nil && certlen > 0) { - uchar hshashes[MD5dlen+SHA1dlen]; /* content of signature */ + mpint *signedMP, *paddedHashes; HandshakeHash hsave; - - /* 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; + uchar buf[512]; + int buflen; c->sec->rpc = factotum_rsa_open(cert, certlen); if(c->sec->rpc == nil){ @@ -1221,7 +1215,22 @@ tlsClient2(int ctl, int hand, uchar *csid, int ncsid, uchar *cert, int certlen, 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 @@ msgSend(TlsConnection *c, Msg *m, int act) } 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 @@ msgRecv(TlsConnection *c, Msg *m) 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 @@ msgClear(Msg *m) 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,12 +1985,16 @@ msgPrint(char *buf, int n, Msg *m) 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"); 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: diff --git a/sys/src/libsec/port/x509.c b/sys/src/libsec/port/x509.c index b70ed2689..f6a396474 100644 --- a/sys/src/libsec/port/x509.c +++ b/sys/src/libsec/port/x509.c @@ -2496,6 +2496,31 @@ mkDN(char *dn) 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) |