9front - general discussion about 9front
 help / color / mirror / Atom feed
From: kemal <kemalinanc8@gmail.com>
To: 9front@9front.org
Subject: Re: [9front] libsec: various tls changes
Date: Mon, 14 Jun 2021 20:27:44 +0000	[thread overview]
Message-ID: <CABO6shdhjPR-MsXxBSaXcz8ZzUOtyZ6Y3_jG5wx32-4_36606A@mail.gmail.com> (raw)
In-Reply-To: <144E4812C04A086AA104EB478BFC153F@felloff.net>

[-- Attachment #1: Type: text/plain, Size: 985 bytes --]

> ok, that looks good. before, we would always just pick secp256r1,
> no negotiation whatsoever. i just wonder what the rfc sais, now
> that we have negotiation for it... it might be better to just
> error and close the connection instead?

according to rfc 8422 section 5.1 we should not
negotiate ecdh* ciphers if we can't find a suitable
curve, if i understood correctly.

   If a server does not understand the Supported Elliptic Curves
   Extension, does not understand the Supported Point Formats Extension,
   or is unable to complete the ECC handshake while restricting itself
   to the enumerated curves and point formats, it MUST NOT negotiate the
   use of an ECC cipher suite.  Depending on what other cipher suites
   are proposed by the client and supported by the server, this may
   result in a fatal handshake failure alert due to the lack of common
   cipher suites.

tlsServer2 now tells okCipher to not pass over
ECDHE ciphers if we couldn't find a suitable curve.

[-- Attachment #2: patchset.txt --]
[-- Type: text/plain, Size: 25530 bytes --]

From 93c6b636680a2069c4a60ac98ca983418fd54922
From: kemal <kemalinanc8@gmail.com>
Date: Mon, 14 Jun 2021 20:21:53 +0000
Subject: [PATCH] libsec: various changes to tls


1. add the curve x25519 to tls, both client and server.
it's more faster, immune to timing attacks by design,
does not require verifying if the public key is valid,
etc etc. server-side has to check if the client supports
the curve, so a new function has been introduced to parse
the client's extensions.

2. reject weak dhe primes that can be easily cracked with
the number field sieve algorithm. this avoids attacks like
logjam.

3. stop putting unix time to the first 4 bytes of client/
server random. it can allow fingerprinting, tls 1.3 doesn't
recommend it any more and there was a draft to deprecate
this behaviour earlier.[1]

4. simply prf code, remove useless cipher enums.

[1] https://datatracker.ietf.org/doc/html/draft-mathewson-no-gmtunixtime-00
---
diff a73a964e51247ed169d322c725a3a18859f109a3 93c6b636680a2069c4a60ac98ca983418fd54922
--- a/sys/src/libsec/port/tlshand.c	Mon Jun 14 03:00:37 2021
+++ b/sys/src/libsec/port/tlshand.c	Mon Jun 14 23:21:53 2021
@@ -66,18 +66,20 @@
 	int psklen;
 	int clientVers;			// version in ClientHello
 	uchar sec[MasterSecretSize];	// master secret
-	uchar crandom[RandomSize];	// client random
 	uchar srandom[RandomSize];	// server random
+	uchar crandom[RandomSize];	// client random
 
+	Namedcurve *nc; // selected curve for ECDHE
 	// diffie hellman state
 	DHstate dh;
 	struct {
 		ECdomain dom;
 		ECpriv Q;
 	} ec;
+	uchar X[32];
 
 	// byte generation and handshake checksum
-	void (*prf)(uchar*, int, uchar*, int, char*, uchar*, int, uchar*, int);
+	void (*prf)(uchar*, int, uchar*, int, char*, uchar*, int);
 	void (*setFinished)(TlsSec*, HandshakeHash, uchar*, int);
 	int nfin;
 };
@@ -107,7 +109,7 @@
 	int tag;
 	union {
 		struct {
-			int version;
+			int	version;
 			uchar 	random[RandomSize];
 			Bytes*	sid;
 			Ints*	ciphers;
@@ -115,7 +117,7 @@
 			Bytes*	extensions;
 		} clientHello;
 		struct {
-			int version;
+			int	version;
 			uchar	random[RandomSize];
 			Bytes*	sid;
 			int	cipher;
@@ -214,79 +216,36 @@
 
 // cipher suites
 enum {
-	TLS_NULL_WITH_NULL_NULL			= 0x0000,
-	TLS_RSA_WITH_NULL_MD5			= 0x0001,
-	TLS_RSA_WITH_NULL_SHA			= 0x0002,
-	TLS_RSA_EXPORT_WITH_RC4_40_MD5		= 0x0003,
-	TLS_RSA_WITH_RC4_128_MD5		= 0x0004,
-	TLS_RSA_WITH_RC4_128_SHA		= 0x0005,
-	TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5	= 0X0006,
-	TLS_RSA_WITH_IDEA_CBC_SHA		= 0X0007,
-	TLS_RSA_EXPORT_WITH_DES40_CBC_SHA	= 0X0008,
-	TLS_RSA_WITH_DES_CBC_SHA		= 0X0009,
 	TLS_RSA_WITH_3DES_EDE_CBC_SHA		= 0X000A,
-	TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA	= 0X000B,
-	TLS_DH_DSS_WITH_DES_CBC_SHA		= 0X000C,
-	TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA	= 0X000D,
-	TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA	= 0X000E,
-	TLS_DH_RSA_WITH_DES_CBC_SHA		= 0X000F,
-	TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA	= 0X0010,
-	TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA	= 0X0011,
-	TLS_DHE_DSS_WITH_DES_CBC_SHA		= 0X0012,
-	TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA	= 0X0013,	// ZZZ must be implemented for tls1.0 compliance
-	TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA	= 0X0014,
-	TLS_DHE_RSA_WITH_DES_CBC_SHA		= 0X0015,
 	TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA	= 0X0016,
-	TLS_DH_anon_EXPORT_WITH_RC4_40_MD5	= 0x0017,
-	TLS_DH_anon_WITH_RC4_128_MD5		= 0x0018,
-	TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA	= 0X0019,
-	TLS_DH_anon_WITH_DES_CBC_SHA		= 0X001A,
-	TLS_DH_anon_WITH_3DES_EDE_CBC_SHA	= 0X001B,
-	TLS_RSA_WITH_AES_128_CBC_SHA		= 0X002F,	// aes, aka rijndael with 128 bit blocks
-	TLS_DH_DSS_WITH_AES_128_CBC_SHA		= 0X0030,
-	TLS_DH_RSA_WITH_AES_128_CBC_SHA		= 0X0031,
-	TLS_DHE_DSS_WITH_AES_128_CBC_SHA	= 0X0032,
+
+	TLS_RSA_WITH_AES_128_CBC_SHA		= 0X002F,
 	TLS_DHE_RSA_WITH_AES_128_CBC_SHA	= 0X0033,
-	TLS_DH_anon_WITH_AES_128_CBC_SHA	= 0X0034,
 	TLS_RSA_WITH_AES_256_CBC_SHA		= 0X0035,
-	TLS_DH_DSS_WITH_AES_256_CBC_SHA		= 0X0036,
-	TLS_DH_RSA_WITH_AES_256_CBC_SHA		= 0X0037,
-	TLS_DHE_DSS_WITH_AES_256_CBC_SHA	= 0X0038,
 	TLS_DHE_RSA_WITH_AES_256_CBC_SHA	= 0X0039,
-	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_DHE_RSA_WITH_AES_128_CBC_SHA256	= 0X0067,
 
 	TLS_RSA_WITH_AES_128_GCM_SHA256		= 0x009C,
-	TLS_RSA_WITH_AES_256_GCM_SHA384		= 0x009D,
 	TLS_DHE_RSA_WITH_AES_128_GCM_SHA256	= 0x009E,
-	TLS_DHE_RSA_WITH_AES_256_GCM_SHA384	= 0x009F,
-	TLS_DH_RSA_WITH_AES_128_GCM_SHA256	= 0x00A0,
-	TLS_DH_RSA_WITH_AES_256_GCM_SHA384	= 0x00A1,
-	TLS_DHE_DSS_WITH_AES_128_GCM_SHA256	= 0x00A2,
-	TLS_DHE_DSS_WITH_AES_256_GCM_SHA384	= 0x00A3,
-	TLS_DH_DSS_WITH_AES_128_GCM_SHA256	= 0x00A4,
-	TLS_DH_DSS_WITH_AES_256_GCM_SHA384	= 0x00A5,
-	TLS_DH_anon_WITH_AES_128_GCM_SHA256	= 0x00A6,
-	TLS_DH_anon_WITH_AES_256_GCM_SHA384	= 0x00A7,
-
-	TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02B,
-	TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256	= 0xC02F,
 
 	TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA	= 0xC013,
 	TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA	= 0xC014,
-	TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256	= 0xC027,
 	TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256	= 0xC023,
+	TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256	= 0xC027,
 
-	TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305	= 0xCCA8,
-	TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305	= 0xCCA9,
-	TLS_DHE_RSA_WITH_CHACHA20_POLY1305	= 0xCCAA,
+	TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02B,
+	TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256	= 0xC02F,
 
 	GOOGLE_ECDHE_RSA_WITH_CHACHA20_POLY1305		= 0xCC13,
 	GOOGLE_ECDHE_ECDSA_WITH_CHACHA20_POLY1305	= 0xCC14,
 	GOOGLE_DHE_RSA_WITH_CHACHA20_POLY1305		= 0xCC15,
 
+	TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305	= 0xCCA8,
+	TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305	= 0xCCA9,
+	TLS_DHE_RSA_WITH_CHACHA20_POLY1305	= 0xCCAA,
+
 	TLS_PSK_WITH_CHACHA20_POLY1305		= 0xCCAB,
 	TLS_PSK_WITH_AES_128_CBC_SHA256		= 0x00AE,
 	TLS_PSK_WITH_AES_128_CBC_SHA		= 0x008C,
@@ -300,6 +259,20 @@
 	CompressionMax
 };
 
+
+// curves
+enum {
+	X25519 = 0x001d,
+};
+
+// extensions
+enum {
+	Extsni = 0x0000,
+	Extec = 0x000a,
+	Extecp = 0x000b,
+	Extsigalgs = 0x000d,
+};
+
 static Algs cipherAlgs[] = {
 	// ECDHE-ECDSA
 	{"ccpoly96_aead", "clear", 2*(32+12), TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305},
@@ -343,6 +316,7 @@
 };
 
 static Namedcurve namedcurves[] = {
+	X25519, nil,
 	0x0017, secp256r1,
 	0x0018, secp384r1,
 };
@@ -402,7 +376,7 @@
 static int isECDSA(int tlsid);
 
 static int setAlgs(TlsConnection *c, int a);
-static int okCipher(Ints *cv, int ispsk);
+static int okCipher(Ints *cv, int ispsk, int canec);
 static int okCompression(Bytes *cv);
 static int initCiphers(void);
 static Ints* makeciphers(int ispsk);
@@ -413,7 +387,7 @@
 
 static void	tlsSecInits(TlsSec *sec, int cvers, uchar *crandom);
 static int	tlsSecRSAs(TlsSec *sec, Bytes *epm);
-static Bytes*	tlsSecECDHEs1(TlsSec *sec, Namedcurve *nc);
+static Bytes*	tlsSecECDHEs1(TlsSec *sec);
 static int	tlsSecECDHEs2(TlsSec *sec, Bytes *Yc);
 static void	tlsSecInitc(TlsSec *sec, int cvers);
 static Bytes*	tlsSecRSAc(TlsSec *sec, uchar *cert, int ncert);
@@ -454,6 +428,7 @@
 {
 	char buf[8];
 	char dname[64];
+	uchar seed[2*RandomSize];
 	int n, data, ctl, hand;
 	TlsConnection *tls;
 
@@ -498,13 +473,15 @@
 	conn->sessionID = nil;
 	if(conn->sessionKey != nil
 	&& conn->sessionType != nil
-	&& strcmp(conn->sessionType, "ttls") == 0)
+	&& strcmp(conn->sessionType, "ttls") == 0){
+		memmove(seed, tls->sec->crandom, RandomSize);
+		memmove(seed+RandomSize, tls->sec->srandom, RandomSize);
 		tls->sec->prf(
 			conn->sessionKey, conn->sessionKeylen,
 			tls->sec->sec, MasterSecretSize,
 			conn->sessionConst, 
-			tls->sec->crandom, RandomSize,
-			tls->sec->srandom, RandomSize);
+			seed, sizeof(seed));
+	}
 	tlsConnectionFree(tls);
 	close(fd);
 	return data;
@@ -526,7 +503,7 @@
 		b = erealloc(b, m + 2+2+2+1+2+n);
 		p = b + m;
 
-		put16(p, 0), p += 2;		/* Type: server_name */
+		put16(p, Extsni), p += 2;	/* Type: server_name */
 		put16(p, 2+1+2+n), p += 2;	/* Length */
 		put16(p, 1+2+n), p += 2;	/* Server Name list length */
 		*p++ = 0;			/* Server Name Type: host_name */
@@ -535,26 +512,26 @@
 		p += n;
 	}
 
-	// ECDHE
+	// Elliptic Curves (also called Supported Groups)
 	if(ProtocolVersion >= TLS10Version){
 		m = p - b;
 		b = erealloc(b, m + 2+2+2+nelem(namedcurves)*2 + 2+2+1+nelem(pointformats));
 		p = b + m;
 
 		n = nelem(namedcurves);
-		put16(p, 0x000a), p += 2;	/* Type: elliptic_curves */
+		put16(p, Extec), p += 2;	/* Type: elliptic_curves / supported_groups */
 		put16(p, (n+1)*2), p += 2;	/* Length */
 		put16(p, n*2), p += 2;		/* Elliptic Curves Length */
-		for(i=0; i < n; i++){		/* Elliptic curves */
+		for(i=0; i < n; i++){		/* Elliptic Curves */
 			put16(p, namedcurves[i].tlsid);
 			p += 2;
 		}
 
 		n = nelem(pointformats);
-		put16(p, 0x000b), p += 2;	/* Type: ec_point_formats */
+		put16(p, Extecp), p += 2;	/* Type: ec_point_formats */
 		put16(p, n+1), p += 2;		/* Length */
 		*p++ = n;			/* EC point formats Length */
-		for(i=0; i < n; i++)		/* Elliptic curves point formats */
+		for(i=0; i < n; i++)		/* EC point formats */
 			*p++ = pointformats[i];
 	}
 
@@ -566,7 +543,7 @@
 		b = erealloc(b, m + 2+2+2+n*2);
 		p = b + m;
 
-		put16(p, 0x000d), p += 2;
+		put16(p, Extsigalgs), p += 2;
 		put16(p, n*2 + 2), p += 2;
 		put16(p, n*2), p += 2;
 		for(i=0; i < n; i++){
@@ -586,6 +563,7 @@
 {
 	char buf[8];
 	char dname[64];
+	uchar seed[2*RandomSize];
 	int n, data, ctl, hand;
 	TlsConnection *tls;
 	uchar *ext;
@@ -641,13 +619,15 @@
 	conn->sessionID = nil;
 	if(conn->sessionKey != nil
 	&& conn->sessionType != nil
-	&& strcmp(conn->sessionType, "ttls") == 0)
+	&& strcmp(conn->sessionType, "ttls") == 0){
+		memmove(seed, tls->sec->crandom, RandomSize);
+		memmove(seed+RandomSize, tls->sec->srandom, RandomSize);
 		tls->sec->prf(
 			conn->sessionKey, conn->sessionKeylen,
 			tls->sec->sec, MasterSecretSize,
 			conn->sessionConst, 
-			tls->sec->crandom, RandomSize,
-			tls->sec->srandom, RandomSize);
+			seed, sizeof(seed));
+	}
 	tlsConnectionFree(tls);
 	close(fd);
 	return data;
@@ -665,6 +645,53 @@
 	return i;
 }
 
+static Bytes *
+tlsServerExtensions(TlsConnection *c, Bytes *ext)
+{
+	uchar *p, *e;
+	int i, j, n;
+
+	p = ext->data;
+	e = p+ext->len;
+	while(p < e){
+		if(e-p < 2)
+			goto Short;
+		switch(get16(p)){
+		case Extec:	
+			p += 2;
+			n = get16(p);
+			if(e-p < n || n < 2)
+				goto Short;
+			p += 2;
+			n = get16(p);
+			p += 2;
+			if(e-p < n || n & 1 || n == 0)
+				goto Short;
+			for(i = 0; i < nelem(namedcurves) && c->sec->nc == nil; i++)
+				for(j = 0; j < n; j += 2)
+					if(namedcurves[i].tlsid == get16(p+j)){
+						c->sec->nc = &namedcurves[i];
+						break;
+					}
+			p += n;
+			break;
+		default:
+			p += 2;
+			n = get16(p);
+			p += 2;
+			if(e-p < n)
+				goto Short;
+			p += n;
+			break;
+		}
+	}
+	// we do not send any extensions yet
+	return nil;
+Short:
+	tlsError(c, EDecodeError, "clienthello extensions has invalid length");
+	return nil; 
+} 
+
 static TlsConnection *
 tlsServer2(int ctl, int hand,
 	uchar *cert, int certlen,
@@ -674,6 +701,7 @@
 	int cipher, compressor, numcerts, i;
 	TlsConnection *c;
 	Msg m;
+	Bytes *ext;
 
 	if(trace)
 		trace("tlsServer2\n");
@@ -708,19 +736,6 @@
 		tlsError(c, EInappropriateFallback, "inappropriate fallback");
 		goto Err;
 	}
-	cipher = okCipher(m.u.clientHello.ciphers, psklen > 0);
-	if(cipher < 0 || !setAlgs(c, cipher)) {
-		tlsError(c, EHandshakeFailure, "no matching cipher suite");
-		goto Err;
-	}
-	compressor = okCompression(m.u.clientHello.compressors);
-	if(compressor < 0) {
-		tlsError(c, EHandshakeFailure, "no matching compressor");
-		goto Err;
-	}
-	if(trace)
-		trace("  cipher %x, compressor %x\n", cipher, compressor);
-
 	tlsSecInits(c->sec, m.u.clientHello.version, m.u.clientHello.random);
 	tlsSecVers(c->sec, c->version);
 	if(psklen > 0){
@@ -740,6 +755,21 @@
 			goto Err;
 		}
 	}
+	ext = tlsServerExtensions(c, m.u.clientHello.extensions);
+	if(c->erred)
+		goto Err;
+	cipher = okCipher(m.u.clientHello.ciphers, psklen > 0, c->sec->nc != nil);
+	if(cipher < 0 || !setAlgs(c, cipher)) {
+		tlsError(c, EHandshakeFailure, "no matching cipher suite");
+		goto Err;
+	}
+	compressor = okCompression(m.u.clientHello.compressors);
+	if(compressor < 0) {
+		tlsError(c, EHandshakeFailure, "no matching compressor");
+		goto Err;
+	}
+	if(trace)
+		trace("  cipher %x, compressor %x\n", cipher, compressor);
 	msgClear(&m);
 
 	m.tag = HServerHello;
@@ -748,6 +778,7 @@
 	m.u.serverHello.cipher = cipher;
 	m.u.serverHello.compressor = compressor;
 	m.u.serverHello.sid = makebytes(nil, 0);
+	m.u.serverHello.extensions = ext;
 	if(!msgSend(c, &m, AQueue))
 		goto Err;
 
@@ -764,11 +795,9 @@
 	}
 
 	if(isECDHE(cipher)){
-		Namedcurve *nc = &namedcurves[0];	/* secp256r1 */
-
 		m.tag = HServerKeyExchange;
-		m.u.serverKeyExchange.curve = nc->tlsid;
-		m.u.serverKeyExchange.dh_parameters = tlsSecECDHEs1(c->sec, nc);
+		m.u.serverKeyExchange.curve = c->sec->nc->tlsid;
+		m.u.serverKeyExchange.dh_parameters = tlsSecECDHEs1(c->sec);
 		if(m.u.serverKeyExchange.dh_parameters == nil){
 			tlsError(c, EInternalError, "can't set DH parameters");
 			goto Err;
@@ -889,7 +918,9 @@
 
 	if(p == nil || g == nil || Ys == nil)
 		return nil;
-
+	// reject dh primes that is susceptible to logjam
+	if(p->len <= 1024/8)
+		return nil;
 	Yc = nil;
 	P = bytestomp(p);
 	G = bytestomp(g);
@@ -922,47 +953,55 @@
 {
 	ECdomain *dom = &sec->ec.dom;
 	ECpriv *Q = &sec->ec.Q;
-	Namedcurve *nc;
 	ECpub *pub;
 	ECpoint K;
+	Namedcurve *nc;
 	Bytes *Yc;
+	Bytes *Z;
 	int n;
 
 	if(Ys == nil)
 		return nil;
-	for(nc = namedcurves; nc != &namedcurves[nelem(namedcurves)]; nc++)
-		if(nc->tlsid == curve)
-			goto Found;
-	return nil;
-
-Found:
-	ecdominit(dom, nc->init);
-	pub = ecdecodepub(dom, Ys->data, Ys->len);
-	if(pub == nil)
-		return nil;
 
-	memset(Q, 0, sizeof(*Q));
-	Q->x = mpnew(0);
-	Q->y = mpnew(0);
-	Q->d = mpnew(0);
-
-	memset(&K, 0, sizeof(K));
-	K.x = mpnew(0);
-	K.y = mpnew(0);
-
-	ecgen(dom, Q);
-	ecmul(dom, pub, Q->d, &K);
-
-	n = (mpsignif(dom->p)+7)/8;
-	setMasterSecret(sec, mptobytes(K.x, n));
-	Yc = newbytes(1 + 2*n);
-	Yc->len = ecencodepub(dom, Q, Yc->data, Yc->len);
+	if(curve == X25519){
+		if(Ys->len != 32)
+			return nil;
+		Yc = newbytes(32);
+		curve25519_dh_new(sec->X, Yc->data);
+		Z = newbytes(32);
+		curve25519_dh_finish(sec->X, Ys->data, Z->data);
+		setMasterSecret(sec, Z);
+	}else{
+		for(nc = namedcurves; nc->tlsid != curve; nc++)
+			if(nc == &namedcurves[nelem(namedcurves)])
+				return nil;
+		ecdominit(dom, nc->init);
+		pub = ecdecodepub(dom, Ys->data, Ys->len);
+		if(pub == nil)
+			return nil;
 
-	mpfree(K.x);
-	mpfree(K.y);
+		memset(Q, 0, sizeof(*Q));
+		Q->x = mpnew(0);
+		Q->y = mpnew(0);
+		Q->d = mpnew(0);
+
+		memset(&K, 0, sizeof(K));
+		K.x = mpnew(0);
+		K.y = mpnew(0);
+
+		ecgen(dom, Q);
+		ecmul(dom, pub, Q->d, &K);
+
+		n = (mpsignif(dom->p)+7)/8;
+		setMasterSecret(sec, mptobytes(K.x, n));
+		Yc = newbytes(1 + 2*n);
+		Yc->len = ecencodepub(dom, Q, Yc->data, Yc->len);
 
-	ecpubfree(pub);
+		mpfree(K.x);
+		mpfree(K.y);
 
+		ecpubfree(pub);
+	}
 	return Yc;
 }
 
@@ -1045,7 +1084,6 @@
 		tlsError(c, EIllegalParameter, "invalid compression");
 		goto Err;
 	}
-
 	dhx = isDHE(cipher) || isECDHE(cipher);
 	if(!msgRecv(c, &m))
 		goto Err;
@@ -2136,13 +2174,17 @@
 }
 
 static int
-okCipher(Ints *cv, int ispsk)
+okCipher(Ints *cv, int ispsk, int canec)
 {
 	int i, c;
 
 	for(i = 0; i < nelem(cipherAlgs); i++) {
 		c = cipherAlgs[i].tlsid;
-		if(!cipherAlgs[i].ok || isECDSA(c) || isDHE(c) || isPSK(c) != ispsk)
+		if(!cipherAlgs[i].ok || isECDSA(c) || isDHE(c))
+			continue;
+		if(isPSK(c) != ispsk)
+			continue;
+		if(isECDHE(c) && !canec)
 			continue;
 		if(lookupid(cv, c) >= 0)
 			return c;
@@ -2313,114 +2355,55 @@
 }
 
 static void
-tlsPmd5(uchar *buf, int nbuf, uchar *key, int nkey, uchar *label, int nlabel, uchar *seed0, int nseed0, uchar *seed1, int nseed1)
-{
-	uchar ai[MD5dlen], tmp[MD5dlen];
-	int i, n;
-	MD5state *s;
-
-	// generate a1
-	s = hmac_md5(label, nlabel, key, nkey, nil, nil);
-	s = hmac_md5(seed0, nseed0, key, nkey, nil, s);
-	hmac_md5(seed1, nseed1, key, nkey, ai, s);
-
-	while(nbuf > 0) {
-		s = hmac_md5(ai, MD5dlen, key, nkey, nil, nil);
-		s = hmac_md5(label, nlabel, key, nkey, nil, s);
-		s = hmac_md5(seed0, nseed0, key, nkey, nil, s);
-		hmac_md5(seed1, nseed1, key, nkey, tmp, s);
-		n = MD5dlen;
-		if(n > nbuf)
-			n = nbuf;
-		for(i = 0; i < n; i++)
-			buf[i] ^= tmp[i];
-		buf += n;
-		nbuf -= n;
-		hmac_md5(ai, MD5dlen, key, nkey, tmp, nil);
-		memmove(ai, tmp, MD5dlen);
-	}
-}
-
-static void
-tlsPsha1(uchar *buf, int nbuf, uchar *key, int nkey, uchar *label, int nlabel, uchar *seed0, int nseed0, uchar *seed1, int nseed1)
-{
-	uchar ai[SHA1dlen], tmp[SHA1dlen];
-	int i, n;
-	SHAstate *s;
-
-	// generate a1
-	s = hmac_sha1(label, nlabel, key, nkey, nil, nil);
-	s = hmac_sha1(seed0, nseed0, key, nkey, nil, s);
-	hmac_sha1(seed1, nseed1, key, nkey, ai, s);
-
-	while(nbuf > 0) {
-		s = hmac_sha1(ai, SHA1dlen, key, nkey, nil, nil);
-		s = hmac_sha1(label, nlabel, key, nkey, nil, s);
-		s = hmac_sha1(seed0, nseed0, key, nkey, nil, s);
-		hmac_sha1(seed1, nseed1, key, nkey, tmp, s);
-		n = SHA1dlen;
-		if(n > nbuf)
-			n = nbuf;
-		for(i = 0; i < n; i++)
-			buf[i] ^= tmp[i];
-		buf += n;
-		nbuf -= n;
-		hmac_sha1(ai, SHA1dlen, key, nkey, tmp, nil);
-		memmove(ai, tmp, SHA1dlen);
-	}
-}
-
-static void
-p_sha256(uchar *buf, int nbuf, uchar *key, int nkey, uchar *label, int nlabel, uchar *seed, int nseed)
+tlsP(uchar *buf, int nbuf, uchar *key, int nkey, uchar *label, int nlabel, uchar *seed, int nseed,
+	DigestState* (*x)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*), int xlen)
 {
 	uchar ai[SHA2_256dlen], tmp[SHA2_256dlen];
-	SHAstate *s;
+	DigestState *s;
 	int n;
 
+	assert(sizeof(ai) <= xlen && sizeof(tmp) <= xlen);
 	// generate a1
-	s = hmac_sha2_256(label, nlabel, key, nkey, nil, nil);
-	hmac_sha2_256(seed, nseed, key, nkey, ai, s);
+	s = x(label, nlabel, key, nkey, nil, nil);
+	x(seed, nseed, key, nkey, ai, s);
 
 	while(nbuf > 0) {
-		s = hmac_sha2_256(ai, SHA2_256dlen, key, nkey, nil, nil);
-		s = hmac_sha2_256(label, nlabel, key, nkey, nil, s);
-		hmac_sha2_256(seed, nseed, key, nkey, tmp, s);
-		n = SHA2_256dlen;
+		s = x(ai, xlen, key, nkey, nil, nil);
+		s = x(label, nlabel, key, nkey, nil, s);
+		x(seed, nseed, key, nkey, tmp, s);
+		n = xlen;
 		if(n > nbuf)
 			n = nbuf;
 		memmove(buf, tmp, n);
 		buf += n;
 		nbuf -= n;
-		hmac_sha2_256(ai, SHA2_256dlen, key, nkey, tmp, nil);
-		memmove(ai, tmp, SHA2_256dlen);
+		x(ai, xlen, key, nkey, tmp, nil);
+		memmove(ai, tmp, xlen);
 	}
 }
 
 // fill buf with md5(args)^sha1(args)
 static void
-tls10PRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label, uchar *seed0, int nseed0, uchar *seed1, int nseed1)
+tls10PRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label, uchar *seed, int nseed)
 {
 	int nlabel = strlen(label);
 	int n = (nkey + 1) >> 1;
 
-	memset(buf, 0, nbuf);
-	tlsPmd5(buf, nbuf, key, n, (uchar*)label, nlabel, seed0, nseed0, seed1, nseed1);
-	tlsPsha1(buf, nbuf, key+nkey-n, n, (uchar*)label, nlabel, seed0, nseed0, seed1, nseed1);
+	tlsP(buf, nbuf, key, n, (uchar*)label, nlabel, seed, nseed,
+		hmac_md5, MD5dlen);
+	tlsP(buf, nbuf, key+nkey-n, n, (uchar*)label, nlabel, seed, nseed,
+		hmac_sha1, SHA1dlen);
 }
 
 static void
-tls12PRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label, uchar *seed0, int nseed0, uchar *seed1, int nseed1)
+tls12PRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label, uchar *seed, int nseed)
 {
-	uchar seed[2*RandomSize];
-
-	assert(nseed0+nseed1 <= sizeof(seed));
-	memmove(seed, seed0, nseed0);
-	memmove(seed+nseed0, seed1, nseed1);
-	p_sha256(buf, nbuf, key, nkey, (uchar*)label, strlen(label), seed, nseed0+nseed1);
+	tlsP(buf, nbuf, key, nkey, (uchar*)label, strlen(label), seed, nseed,
+		hmac_sha2_256, SHA2_256dlen);
 }
 
 static void
-sslPRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label, uchar *seed0, int nseed0, uchar *seed1, int nseed1)
+sslPRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label, uchar *seed, int nseed)
 {
 	uchar sha1dig[SHA1dlen], md5dig[MD5dlen], tmp[26];
 	DigestState *s;
@@ -2435,8 +2418,7 @@
 			tmp[i] = 'A' - 1 + len;
 		s = sha1(tmp, len, nil, nil);
 		s = sha1(key, nkey, nil, s);
-		s = sha1(seed0, nseed0, nil, s);
-		sha1(seed1, nseed1, sha1dig, s);
+		sha1(seed, nseed, sha1dig, s);
 		s = md5(key, nkey, nil, nil);
 		md5(sha1dig, SHA1dlen, md5dig, s);
 		n = MD5dlen;
@@ -2486,18 +2468,18 @@
 static void
 tls10SetFinished(TlsSec *sec, HandshakeHash hsh, uchar *finished, int isclient)
 {
-	uchar h0[MD5dlen], h1[SHA1dlen];
+	uchar h[MD5dlen+SHA1dlen];
 	char *label;
 
 	// get current hash value, but allow further messages to be hashed in
-	md5(nil, 0, h0, &hsh.md5);
-	sha1(nil, 0, h1, &hsh.sha1);
+	md5(nil, 0, h, &hsh.md5);
+	sha1(nil, 0, h+MD5dlen, &hsh.sha1);
 
 	if(isclient)
 		label = "client finished";
 	else
 		label = "server finished";
-	tls10PRF(finished, TLSFinishedLen, sec->sec, MasterSecretSize, label, h0, MD5dlen, h1, SHA1dlen);
+	tls10PRF(finished, TLSFinishedLen, sec->sec, MasterSecretSize, label, h, sizeof(h));
 }
 
 static void
@@ -2513,7 +2495,7 @@
 		label = "client finished";
 	else
 		label = "server finished";
-	p_sha256(finished, TLSFinishedLen, sec->sec, MasterSecretSize, (uchar*)label, strlen(label), seed, SHA2_256dlen);
+	tls12PRF(finished, TLSFinishedLen, sec->sec, MasterSecretSize, label, seed, SHA2_256dlen);
 }
 
 static void
@@ -2523,8 +2505,9 @@
 	sec->clientVers = cvers;
 	memmove(sec->crandom, crandom, RandomSize);
 
-	put32(sec->srandom, time(nil));
-	genrandom(sec->srandom+4, RandomSize-4);
+	// putting time()'s output to the first 4 bytes is no
+	// longer recommended and is not useful
+	genrandom(sec->srandom, RandomSize);
 }
 
 static int
@@ -2549,27 +2532,36 @@
 }
 
 static Bytes*
-tlsSecECDHEs1(TlsSec *sec, Namedcurve *nc)
+tlsSecECDHEs1(TlsSec *sec)
 {
 	ECdomain *dom = &sec->ec.dom;
 	ECpriv *Q = &sec->ec.Q;
 	Bytes *par;
 	int n;
 
-	ecdominit(dom, nc->init);
-	memset(Q, 0, sizeof(*Q));
-	Q->x = mpnew(0);
-	Q->y = mpnew(0);
-	Q->d = mpnew(0);
-	ecgen(dom, Q);
-	n = 1 + 2*((mpsignif(dom->p)+7)/8);
-	par = newbytes(1+2+1+n);
-	par->data[0] = 3;
-	put16(par->data+1, nc->tlsid);
-	n = ecencodepub(dom, Q, par->data+4, par->len-4);
-	par->data[3] = n;
-	par->len = 1+2+1+n;
-
+	if(sec->nc == nil)
+		return nil;
+	if(sec->nc->tlsid == X25519){
+		par = newbytes(1+2+1+32);
+		par->data[0] = 3;
+		put16(par->data+1, X25519);
+		par->data[3] = 32;
+		curve25519_dh_new(sec->X, par->data+4);
+	}else{
+		ecdominit(dom, sec->nc->init);
+		memset(Q, 0, sizeof(*Q));
+		Q->x = mpnew(0);
+		Q->y = mpnew(0);
+		Q->d = mpnew(0);
+		ecgen(dom, Q);
+		n = 1 + 2*((mpsignif(dom->p)+7)/8);
+		par = newbytes(1+2+1+n);
+		par->data[0] = 3;
+		put16(par->data+1, sec->nc->tlsid);
+		n = ecencodepub(dom, Q, par->data+4, par->len-4);
+		par->data[3] = n;
+		par->len = 1+2+1+n;
+	}
 	return par;
 }
 
@@ -2580,30 +2572,40 @@
 	ECpriv *Q = &sec->ec.Q;
 	ECpoint K;
 	ECpub *Y;
+	Bytes *Z;
 
 	if(Yc == nil){
 		werrstr("no public key");
 		return -1;
 	}
 
-	if((Y = ecdecodepub(dom, Yc->data, Yc->len)) == nil){
-		werrstr("bad public key");
-		return -1;
-	}
-
-	memset(&K, 0, sizeof(K));
-	K.x = mpnew(0);
-	K.y = mpnew(0);
+	if(sec->nc->tlsid == X25519){
+		if(Yc->len != 32){
+			werrstr("bad public key");
+			return -1;
+		}
+		Z = newbytes(32);
+		curve25519_dh_finish(sec->X, Yc->data, Z->data);
+		setMasterSecret(sec, Z);
+	}else{
+		if((Y = ecdecodepub(dom, Yc->data, Yc->len)) == nil){
+			werrstr("bad public key");
+			return -1;
+		}
 
-	ecmul(dom, Y, Q->d, &K);
+		memset(&K, 0, sizeof(K));
+		K.x = mpnew(0);
+		K.y = mpnew(0);
 
-	setMasterSecret(sec, mptobytes(K.x, (mpsignif(dom->p)+7)/8));
+		ecmul(dom, Y, Q->d, &K);
 
-	mpfree(K.x);
-	mpfree(K.y);
+		setMasterSecret(sec, mptobytes(K.x, (mpsignif(dom->p)+7)/8));
 
-	ecpubfree(Y);
+		mpfree(K.x);
+		mpfree(K.y);
 
+		ecpubfree(Y);
+	}
 	return 0;
 }
 
@@ -2612,8 +2614,8 @@
 {
 	memset(sec, 0, sizeof(*sec));
 	sec->clientVers = cvers;
-	put32(sec->crandom, time(nil));
-	genrandom(sec->crandom+4, RandomSize-4);
+	// see the comment on tlsSecInits
+	genrandom(sec->crandom, RandomSize);
 }
 
 static Bytes*
@@ -2671,13 +2673,15 @@
 static int
 setSecrets(TlsConnection *c, int isclient)
 {
-	uchar kd[MaxKeyData];
+	uchar kd[MaxKeyData], seed[2*RandomSize];
 	char *secrets;
 	int rv;
 
 	assert(c->nsecret <= sizeof(kd));
 	secrets = emalloc(2*c->nsecret);
 
+	memmove(seed, c->sec->srandom, RandomSize);
+	memmove(seed+RandomSize, c->sec->crandom, RandomSize);
 	/*
 	 * generate secret keys from the master secret.
 	 *
@@ -2686,7 +2690,7 @@
 	 * but it's all generated using the same function.
 	 */
 	(*c->sec->prf)(kd, c->nsecret, c->sec->sec, MasterSecretSize, "key expansion",
-			c->sec->srandom, RandomSize, c->sec->crandom, RandomSize);
+			seed, sizeof(seed));
 
 	enc64(secrets, 2*c->nsecret, kd, c->nsecret);
 	memset(kd, 0, c->nsecret);
@@ -2705,6 +2709,8 @@
 static void
 setMasterSecret(TlsSec *sec, Bytes *pm)
 {
+	uchar seed[2*RandomSize];
+
 	if(sec->psklen > 0){
 		Bytes *opm = pm;
 		uchar *p;
@@ -2721,8 +2727,10 @@
 		freebytes(opm);
 	}
 
+	memmove(seed, sec->crandom, RandomSize);
+	memmove(seed+RandomSize, sec->srandom, RandomSize);
 	(*sec->prf)(sec->sec, MasterSecretSize, pm->data, pm->len, "master secret",
-			sec->crandom, RandomSize, sec->srandom, RandomSize);
+			seed, sizeof(seed));
 
 	memset(pm->data, 0, pm->len);	
 	freebytes(pm);

  reply	other threads:[~2021-06-14 20:39 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-06-11 15:06 kemal
2021-06-12 13:15 ` cinap_lenrek
2021-06-12 19:54   ` kemal
2021-06-14 18:26     ` cinap_lenrek
2021-06-14 20:27       ` kemal [this message]
2021-06-16  9:48         ` cinap_lenrek
2021-06-16 11:59           ` kemal
2021-06-16 14:02             ` cinap_lenrek
2021-06-18 18:51               ` kemal
2021-06-18 19:13                 ` kemal
2021-06-19 14:20                   ` cinap_lenrek
2021-06-20 14:56                 ` cinap_lenrek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CABO6shdhjPR-MsXxBSaXcz8ZzUOtyZ6Y3_jG5wx32-4_36606A@mail.gmail.com \
    --to=kemalinanc8@gmail.com \
    --cc=9front@9front.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).