From 9f50ee06f3a78af3767ec061f4647b5446c8619e Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Wed, 23 Sep 2015 16:57:25 +0200 Subject: 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. --- sys/src/libsec/port/tlshand.c | 50 ++++++++++++++++++++++++++++++------------- 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; iu.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; iu.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) -- cgit v1.2.3