shithub: riscv

Download patch

ref: c3e1c158f62458f16e5b538f188bad14844d277d
parent: 8baa8593196a1848773eb8dff26b18cc519f0175
author: cinap_lenrek <[email protected]>
date: Tue Sep 22 14:10:52 EDT 2015

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.

--- a/sys/include/libsec.h
+++ b/sys/include/libsec.h
@@ -274,6 +274,8 @@
 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);
 
--- a/sys/src/libsec/port/tlshand.c
+++ b/sys/src/libsec/port/tlshand.c
@@ -140,6 +140,7 @@
 			Bytes *dh_p;
 			Bytes *dh_g;
 			Bytes *dh_Ys;
+			Bytes *dh_parameters;
 			Bytes *dh_signature;
 			int sigalg;
 			int curve;
@@ -267,11 +268,9 @@
 	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 @@
 };
 
 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 @@
 	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 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 @@
 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 @@
 	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 @@
 	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 @@
 	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 @@
 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 @@
 	case HServerKeyExchange:
 		if(n < 2)
 			goto Short;
+		s = p;
 		if(isECDHE(c->cipher)){
 			nn = *p;
 			p++, n--;
@@ -1734,6 +1769,7 @@
 			/* 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 @@
 		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 @@
 		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:
--- a/sys/src/libsec/port/x509.c
+++ b/sys/src/libsec/port/x509.c
@@ -2167,60 +2167,108 @@
 	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 @@
 	CertX509 *c;
 	int digestlen;
 	uchar digest[MAXdlen];
-	Elem *sigalg;
 
 	b = makebytes(cert, ncert);
 	c = decode_cert(b);
@@ -2267,7 +2314,7 @@
 		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 @@
 	RSApub *pk;
 	int digestlen;
 	uchar digest[MAXdlen];
-	Elem *sigalg;
 
 	print("begin X509dump\n");
 	b = makebytes(cert, ncert);
@@ -2700,14 +2746,10 @@
 	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);