diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2015-09-22 18:10:52 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2015-09-22 18:10:52 +0200 |
commit | c3e1c158f62458f16e5b538f188bad14844d277d (patch) | |
tree | c8b976af1e687ad02cabedd520b92f08e8f1d18f | |
parent | 8baa8593196a1848773eb8dff26b18cc519f0175 (diff) | |
download | plan9front-c3e1c158f62458f16e5b538f188bad14844d277d.tar.xz |
libsec: implement dh parameter signature verification, stop lying about non-rsa ciphers, fix memory leaks in X509 code
actually verify the diffie hellman parameter signature, this
comes in two flavours. TLS1.2 uses X509 signature with a
single hash specified by the signature algorithm field in
the signature itself and pre TLS1.2 where md5+sha1 hashes
of the signed blob are pkcs1 padded and encrypted with the
rsa private key.
stop advertizing non-rsa cipher suits (DSS and ECDSA), as
we have not implmenented them.
fix some memory leaks in X509 code while we'r at it.
-rw-r--r-- | sys/include/libsec.h | 2 | ||||
-rw-r--r-- | sys/src/libsec/port/tlshand.c | 90 | ||||
-rw-r--r-- | sys/src/libsec/port/x509.c | 122 |
3 files changed, 148 insertions, 66 deletions
diff --git a/sys/include/libsec.h b/sys/include/libsec.h index d5c3b85fb..16f249f2e 100644 --- a/sys/include/libsec.h +++ b/sys/include/libsec.h @@ -274,6 +274,8 @@ uchar* decodePEM(char *s, char *type, int *len, char **new_s); PEMChain* decodepemchain(char *s, char *type); uchar* X509gen(RSApriv *priv, char *subj, ulong valid[2], int *certlen); uchar* X509req(RSApriv *priv, char *subj, int *certlen); +char* X509verifydigest(uchar *sig, int siglen, uchar *edigest, int edigestlen, RSApub *pk); +char* X509verifydata(uchar *sig, int siglen, uchar *data, int datalen, RSApub *pk); char* X509verify(uchar *cert, int ncert, RSApub *pk); void X509dump(uchar *cert, int ncert); diff --git a/sys/src/libsec/port/tlshand.c b/sys/src/libsec/port/tlshand.c index dd795cd8b..8f5c570d3 100644 --- a/sys/src/libsec/port/tlshand.c +++ b/sys/src/libsec/port/tlshand.c @@ -140,6 +140,7 @@ typedef struct Msg{ Bytes *dh_p; Bytes *dh_g; Bytes *dh_Ys; + Bytes *dh_parameters; Bytes *dh_signature; int sigalg; int curve; @@ -267,11 +268,9 @@ enum { TLS_DH_anon_WITH_AES_256_CBC_SHA = 0X003A, TLS_RSA_WITH_AES_128_CBC_SHA256 = 0X003C, TLS_RSA_WITH_AES_256_CBC_SHA256 = 0X003D, - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0XC009, - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0XC00A, + TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0X0067, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0XC013, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0XC014, - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0XC023, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027, }; @@ -282,12 +281,10 @@ enum { }; static Algs cipherAlgs[] = { - {"aes_128_cbc", "sha256", 2*(16+16+SHA2_256dlen), TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256}, - {"aes_128_cbc", "sha1", 2*(16+16+SHA1dlen), TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA}, - {"aes_256_cbc", "sha1", 2*(32+16+SHA1dlen), TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}, {"aes_128_cbc", "sha256", 2*(16+16+SHA2_256dlen), TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256}, {"aes_128_cbc", "sha1", 2*(16+16+SHA1dlen), TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}, {"aes_256_cbc", "sha1", 2*(32+16+SHA1dlen), TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}, + {"aes_128_cbc", "sha256", 2*(16+16+SHA2_256dlen), TLS_DHE_RSA_WITH_AES_128_CBC_SHA256}, {"aes_128_cbc", "sha1", 2*(16+16+SHA1dlen), TLS_DHE_RSA_WITH_AES_128_CBC_SHA}, {"aes_256_cbc", "sha1", 2*(32+16+SHA1dlen), TLS_DHE_RSA_WITH_AES_256_CBC_SHA}, {"aes_128_cbc", "sha256", 2*(16+16+SHA2_256dlen), TLS_RSA_WITH_AES_128_CBC_SHA256}, @@ -318,16 +315,12 @@ static uchar pointformats[] = { CompressionNull /* support of uncompressed point format is mandatory */ }; -// signature algorithms +// signature algorithms (only RSA at the moment) static int sigalgs[] = { 0x0601, /* SHA512 RSA */ 0x0501, /* SHA384 RSA */ 0x0401, /* SHA256 RSA */ 0x0201, /* SHA1 RSA */ - 0x0603, /* SHA512 ECDSA */ - 0x0503, /* SHA384 ECDSA */ - 0x0403, /* SHA256 ECDSA */ - 0x0203, /* SHA1 ECDSA */ }; static TlsConnection *tlsServer2(int ctl, int hand, uchar *cert, int certlen, int (*trace)(char*fmt, ...), PEMChain *chain); @@ -392,7 +385,8 @@ static Ints* newints(int len); static void freeints(Ints* b); /* x509.c */ -extern mpint* pkcs1padbuf(uchar *buf, int len, mpint *modulus); +extern mpint* pkcs1padbuf(uchar *buf, int len, mpint *modulus); +extern int pkcs1decryptsignature(uchar *sig, int siglen, RSApub *pk, uchar **pbuf); //================= client/server ======================== @@ -783,16 +777,10 @@ static int isDHE(int tlsid) { switch(tlsid){ - case TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA: - case TLS_DHE_DSS_WITH_DES_CBC_SHA: - case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: - case TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA: - case TLS_DHE_RSA_WITH_DES_CBC_SHA: - case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: - case TLS_DHE_DSS_WITH_AES_128_CBC_SHA: - case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: - case TLS_DHE_DSS_WITH_AES_256_CBC_SHA: - case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: + case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: return 1; } return 0; @@ -805,9 +793,6 @@ isECDHE(int tlsid) case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: - case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: - case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: - case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: return 1; } return 0; @@ -988,6 +973,45 @@ Out: return epm; } +static char* +verifyDHparams(TlsConnection *c, Bytes *par, Bytes *sig, int sigalg) +{ + uchar hashes[MD5dlen+SHA1dlen], *buf; + Bytes *blob; + RSApub *pk; + char *err; + + pk = X509toRSApub(c->cert->data, c->cert->len, nil, 0); + if(pk == nil) + return "bad certificate"; + + blob = newbytes(2*RandomSize + par->len); + memmove(blob->data+0*RandomSize, c->crandom, RandomSize); + memmove(blob->data+1*RandomSize, c->srandom, RandomSize); + memmove(blob->data+2*RandomSize, par->data, par->len); + if(c->version >= TLS12Version) { + if((sigalg & 0xFF) == 1) + err = X509verifydata(sig->data, sig->len, blob->data, blob->len, pk); + else + err = "signaure algorithm not RSA"; + } else { + err = nil; + if(pkcs1decryptsignature(sig->data, sig->len, pk, &buf) != sizeof(hashes)) + err = "bad signature"; + else { + md5(blob->data, blob->len, hashes, nil); + sha1(blob->data, blob->len, hashes+MD5dlen, nil); + if(memcmp(buf, hashes, sizeof(hashes)) != 0) + err = "digests did not match"; + } + free(buf); + } + freebytes(blob); + rsapubfree(pk); + + return err; +} + static TlsConnection * tlsClient2(int ctl, int hand, uchar *csid, int ncsid, uchar *cert, int certlen, uchar *ext, int extlen, int (*trace)(char*fmt, ...)) @@ -1077,10 +1101,20 @@ tlsClient2(int ctl, int hand, uchar *csid, int ncsid, uchar *cert, int certlen, if(!msgRecv(c, &m)) goto Err; if(m.tag == HServerKeyExchange) { + char *err; + if(!dhx){ tlsError(c, EUnexpectedMessage, "got an server key exchange"); goto Err; } + err = verifyDHparams(c, + m.u.serverKeyExchange.dh_parameters, + m.u.serverKeyExchange.dh_signature, + m.u.serverKeyExchange.sigalg); + if(err != nil){ + tlsError(c, EBadCertificate, "can't verify dh parameters: %s", err); + goto Err; + } if(isECDHE(cipher)) epm = tlsSecECDHEc(c->sec, c->srandom, c->version, m.u.serverKeyExchange.curve, @@ -1447,7 +1481,7 @@ tlsReadN(TlsConnection *c, int n) static int msgRecv(TlsConnection *c, Msg *m) { - uchar *p; + uchar *p, *s; int type, n, nn, i, nsid, nrandom, nciph; for(;;) { @@ -1691,6 +1725,7 @@ msgRecv(TlsConnection *c, Msg *m) case HServerKeyExchange: if(n < 2) goto Short; + s = p; if(isECDHE(c->cipher)){ nn = *p; p++, n--; @@ -1734,6 +1769,7 @@ msgRecv(TlsConnection *c, Msg *m) /* should not happen */ break; } + m->u.serverKeyExchange.dh_parameters = makebytes(s, p - s); if(n >= 2){ m->u.serverKeyExchange.sigalg = 0; if(c->version >= TLS12Version){ @@ -1835,6 +1871,7 @@ msgClear(Msg *m) freebytes(m->u.serverKeyExchange.dh_p); freebytes(m->u.serverKeyExchange.dh_g); freebytes(m->u.serverKeyExchange.dh_Ys); + freebytes(m->u.serverKeyExchange.dh_parameters); freebytes(m->u.serverKeyExchange.dh_signature); break; case HClientKeyExchange: @@ -1951,6 +1988,7 @@ msgPrint(char *buf, int n, Msg *m) bs = bytesPrint(bs, be, "\tdh_Ys: ", m->u.serverKeyExchange.dh_Ys, "\n"); if(m->u.serverKeyExchange.sigalg != 0) bs = seprint(bs, be, "\tsigalg: %.4x\n", m->u.serverKeyExchange.sigalg); + bs = bytesPrint(bs, be, "\tdh_parameters: ", m->u.serverKeyExchange.dh_parameters, "\n"); bs = bytesPrint(bs, be, "\tdh_signature: ", m->u.serverKeyExchange.dh_signature, "\n"); break; case HClientKeyExchange: diff --git a/sys/src/libsec/port/x509.c b/sys/src/libsec/port/x509.c index 4751524c5..dbad83bf7 100644 --- a/sys/src/libsec/port/x509.c +++ b/sys/src/libsec/port/x509.c @@ -2167,60 +2167,108 @@ digest_certinfo(Bytes *cert, DigestAlg *da, uchar *digest) return da->len; } -static char* -verify_signature(Bytes* signature, RSApub *pk, uchar *edigest, int edigestlen, Elem **psigalg) +int +pkcs1decryptsignature(uchar *sig, int siglen, RSApub *pk, uchar **pbuf) { - Elem e; - Elist *el; - Bytes *digest; - uchar *pkcs1buf, *buf; - int buflen; + int nlen, buflen; mpint *pkcs1; - int nlen; - char *err; + uchar *buf; - err = nil; - pkcs1buf = nil; + *pbuf = nil; /* one less than the byte length of the modulus */ nlen = (mpsignif(pk->n)-1)/8; /* see 9.2.1 of rfc2437 */ - pkcs1 = betomp(signature->data, signature->len, nil); + pkcs1 = betomp(sig, siglen, nil); mpexp(pkcs1, pk->ek, pk->n, pkcs1); - buflen = mptobe(pkcs1, nil, 0, &pkcs1buf); - buf = pkcs1buf; - if(buflen != nlen || buf[0] != 1) { - err = "expected 1"; - goto end; - } + buflen = mptobe(pkcs1, nil, 0, pbuf); + mpfree(pkcs1); + + buf = *pbuf; + if(buflen != nlen || buf[0] != 1) + goto bad; buf++, buflen--; while(buflen > 0 && buf[0] == 0xff) buf++, buflen--; - if(buflen < 1 || buf[0] != 0) { - err = "expected 0"; - goto end; - } + if(buflen < 1 || buf[0] != 0) + goto bad; buf++, buflen--; - if(decode(buf, buflen, &e) != ASN_OK || !is_seq(&e, &el) || elistlen(el) != 2 || + memmove(*pbuf, buf, buflen); + return buflen; +bad: + free(*pbuf); + *pbuf = nil; + return -1; +} + +static char* +verify_digestinfo(uchar *sig, int siglen, RSApub *pk, uchar *pdigest, int *psigalg) +{ + Elem e; + Elist *el; + Bytes *digest; + uchar *buf; + int buflen; + char *err; + + el = nil; + buflen = pkcs1decryptsignature(sig, siglen, pk, &buf); + if(buflen < 0 || decode(buf, buflen, &e) != ASN_OK || !is_seq(&e, &el) || elistlen(el) != 2 || !is_octetstring(&el->tl->hd, &digest)) { err = "signature parse error"; goto end; } - *psigalg = &el->hd; - if(digest->len != edigestlen) { + *psigalg = parse_alg(&el->hd); + if(*psigalg < 0){ + err = "unknown signature algorithm"; + goto end; + } + if(digest->len != digestalg[*psigalg]->len){ err = "bad digest length"; goto end; } - if(memcmp(digest->data, edigest, edigestlen) != 0) - err = "digests did not match"; - + memmove(pdigest, digest->data, digest->len); + err = nil; end: - mpfree(pkcs1); - free(pkcs1buf); + freevalfields(&e.val); + free(buf); return err; } +char* +X509verifydigest(uchar *sig, int siglen, uchar *edigest, int edigestlen, RSApub *pk) +{ + uchar digest[MAXdlen]; + int sigalg; + char *e; + + e = verify_digestinfo(sig, siglen, pk, digest, &sigalg); + if(e != nil) + return e; + if(digestalg[sigalg]->len != edigestlen) + return "bad digest length"; + if(memcmp(digest, edigest, edigestlen) != 0) + return "digests did not match"; + return nil; +} + +char* +X509verifydata(uchar *sig, int siglen, uchar *data, int datalen, RSApub *pk) +{ + uchar digest[MAXdlen], edigest[MAXdlen]; + int sigalg; + char *e; + + e = verify_digestinfo(sig, siglen, pk, digest, &sigalg); + if(e != nil) + return e; + (*digestalg[sigalg]->fun)(data, datalen, edigest, nil); + if(memcmp(digest, edigest, digestalg[sigalg]->len) != 0) + return "digests did not match"; + return nil; +} + RSApub* X509toRSApub(uchar *cert, int ncert, char *name, int nname) { @@ -2253,7 +2301,6 @@ X509verify(uchar *cert, int ncert, RSApub *pk) CertX509 *c; int digestlen; uchar digest[MAXdlen]; - Elem *sigalg; b = makebytes(cert, ncert); c = decode_cert(b); @@ -2267,7 +2314,7 @@ X509verify(uchar *cert, int ncert, RSApub *pk) freecert(c); return "cannot decode certinfo"; } - e = verify_signature(c->signature, pk, digest, digestlen, &sigalg); + e = X509verifydigest(c->signature->data, c->signature->len, digest, digestlen, pk); freecert(c); return e; } @@ -2674,7 +2721,6 @@ X509dump(uchar *cert, int ncert) RSApub *pk; int digestlen; uchar digest[MAXdlen]; - Elem *sigalg; print("begin X509dump\n"); b = makebytes(cert, ncert); @@ -2700,14 +2746,10 @@ X509dump(uchar *cert, int ncert) print("pubkey e=%B n(%d)=%B\n", pk->ek, mpsignif(pk->n), pk->n); print("sigalg=%d digest=%.*H\n", c->signature_alg, digestlen, digest); - e = verify_signature(c->signature, pk, digest, digestlen, &sigalg); - if(e==nil){ + e = X509verifydigest(c->signature->data, c->signature->len, digest, digestlen, pk); + if(e==nil) e = "nil (meaning ok)"; - print("sigalg=\n"); - if(sigalg) - edump(*sigalg); - } - print("self-signed verify_signature returns: %s\n", e); + print("self-signed X509verifydigest returns: %s\n", e); rsapubfree(pk); freecert(c); |