Plan 9 from Bell Labs’s /usr/web/sources/contrib/mospak/tls-1.2/tls-aead-cipher-preference.diff

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


--- sys/src/libsec/port/tlshand.c
+++ sys/src/libsec/port/tlshand.c
@@ -88,6 +88,7 @@ typedef struct TlsConnection{
 	// for finished messages
 	HandHash	hs;	// handshake hash
 	Finished	finished;
+	int	serverSignFlags;	/* AlgRsaSign|AlgEcSign; gates okCipher */
 	int	serverCurve;	/* negotiated ECDHE group, 0 = none */
 } TlsConnection;
 
@@ -597,6 +598,32 @@ tlsServer2(int ctl, int hand, uchar *cert, int ncert, 
 
 	memmove(c->crandom, m.u.clientHello.random, RandomSize);
 	/*
+	 * Derive c->serverSignFlags from the server's cert SPKI key type
+	 * (RFC 4492 Section 2.2): RSA cert -> AlgRsaSign, ECDSA cert ->
+	 * AlgEcSign.  okCipher() consults this to skip cipher suites
+	 * whose authentication algorithm doesn't match the loaded cert;
+	 * without the gate, an RSA-cert server can pick TLS_ECDHE_ECDSA_*
+	 * and emit a (cipher, sigalg) pair that strict TLS 1.2 clients
+	 * will reject.
+	 */
+	{
+		RSApub *rpk;
+		ECpub *epk;
+		ECdomain dom;
+
+		rpk = X509toRSApub(cert, ncert, nil, 0);
+		if(rpk != nil){
+			c->serverSignFlags |= AlgRsaSign;
+			rsapubfree(rpk);
+		}
+		epk = X509toECpub(cert, ncert, nil, 0, &dom);
+		if(epk != nil){
+			c->serverSignFlags |= AlgEcSign;
+			ecpubfree(epk);
+			ecdomfree(&dom);
+		}
+	}
+	/*
 	 * Walk client's supported_groups in preference order and pick the first
 	 * curve we also implement (RFC 8422 Section 5.1.1, RFC 7919 Section 4).
 	 * Inline parse rather than going through the extension framework so this
@@ -1965,6 +1992,7 @@ okCipher(TlsConnection *c, Ints *cv)
 {
 	int weak, i, j, id;
 
+	/* track if client offered only weak ciphers */
 	weak = 1;
 	for(i = 0; i < cv->len; i++) {
 		id = cv->data[i];
@@ -1972,9 +2000,29 @@ okCipher(TlsConnection *c, Ints *cv)
 			weak = 0;
 		else
 			weak &= weakCipher[id];
-		for(j = 0; j < nelem(cipherAlgs); j++)
-			if(cipherAlgs[j].ok && cipherAlgs[j].tlsid == id)
-				return id;
+	}
+	/* server preference: iterate cipherAlgs[] in our preferred
+	 * order, pick first that the client also offered.  AEAD
+	 * entries are listed first in cipherAlgs[] so AEAD wins
+	 * over CBC when both are offered. */
+	for(j = 0; j < nelem(cipherAlgs); j++) {
+		if(!cipherAlgs[j].ok)
+			continue;
+		/* RFC 8422 Section 5.1.1 + RFC 7919 Section 4: skip ECDHE
+		 * suites when the client and we share no named curve. */
+		if(c != nil && isECDHE(cipherAlgs[j].tlsid) && c->serverCurve == 0)
+			continue;
+		/* RFC 4492 Section 2.2: cipher's authentication algorithm
+		 * must match the server cert's key type.  Skip
+		 * TLS_ECDHE_ECDSA_* against an RSA cert and TLS_ECDHE_RSA_*
+		 * / TLS_RSA_* against an ECDSA-only cert.
+		 */
+		if(c != nil && cipherAlgs[j].flags != 0
+		&& (cipherAlgs[j].flags & c->serverSignFlags) == 0)
+			continue;
+		for(i = 0; i < cv->len; i++)
+			if(cv->data[i] == cipherAlgs[j].tlsid)
+				return cipherAlgs[j].tlsid;
 	}
 	if(weak)
 		return -2;

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.