diff options
author | wolfbeast <mcwerewolf@gmail.com> | 2018-12-15 01:42:53 +0100 |
---|---|---|
committer | wolfbeast <mcwerewolf@gmail.com> | 2018-12-15 01:42:53 +0100 |
commit | 74cabf7948b2597f5b6a67d6910c844fd1a88ff6 (patch) | |
tree | db1f30ada487c3831ea8e4e98b2d39edc9e88eea /security/nss/lib/ssl | |
parent | 09ef48bd005a7f9e97a3fe797a079fcf2b5e58d3 (diff) | |
download | UXP-74cabf7948b2597f5b6a67d6910c844fd1a88ff6.tar UXP-74cabf7948b2597f5b6a67d6910c844fd1a88ff6.tar.gz UXP-74cabf7948b2597f5b6a67d6910c844fd1a88ff6.tar.lz UXP-74cabf7948b2597f5b6a67d6910c844fd1a88ff6.tar.xz UXP-74cabf7948b2597f5b6a67d6910c844fd1a88ff6.zip |
Update NSS to 3.41
Diffstat (limited to 'security/nss/lib/ssl')
34 files changed, 2497 insertions, 696 deletions
diff --git a/security/nss/lib/ssl/SSLerrs.h b/security/nss/lib/ssl/SSLerrs.h index f01d16583..9be219494 100644 --- a/security/nss/lib/ssl/SSLerrs.h +++ b/security/nss/lib/ssl/SSLerrs.h @@ -552,3 +552,15 @@ ER3(SSL_ERROR_RX_MALFORMED_DTLS_ACK, (SSL_ERROR_BASE + 174), ER3(SSL_ERROR_DH_KEY_TOO_LONG, (SSL_ERROR_BASE + 175), "SSL received a DH key share that's too long (>8192 bit).") + +ER3(SSL_ERROR_RX_MALFORMED_ESNI_KEYS, (SSL_ERROR_BASE + 176), + "SSL received a malformed ESNI keys structure") + +ER3(SSL_ERROR_RX_MALFORMED_ESNI_EXTENSION, (SSL_ERROR_BASE + 177), + "SSL received a malformed ESNI extension") + +ER3(SSL_ERROR_MISSING_ESNI_EXTENSION, (SSL_ERROR_BASE + 178), + "SSL did not receive an ESNI extension") + +ER3(SSL_ERROR_RX_UNEXPECTED_RECORD_TYPE, (SSL_ERROR_BASE + 179), + "SSL received an unexpected record type.") diff --git a/security/nss/lib/ssl/authcert.c b/security/nss/lib/ssl/authcert.c index 2765c8342..d05b30a72 100644 --- a/security/nss/lib/ssl/authcert.c +++ b/security/nss/lib/ssl/authcert.c @@ -13,7 +13,7 @@ #include "cert.h" #include "nspr.h" #include "secder.h" -#include "key.h" +#include "keyhi.h" #include "nss.h" #include "ssl.h" #include "pk11func.h" /* for PK11_ function calls */ diff --git a/security/nss/lib/ssl/cmpcert.c b/security/nss/lib/ssl/cmpcert.c index e6edbee83..8ab4a7f8d 100644 --- a/security/nss/lib/ssl/cmpcert.c +++ b/security/nss/lib/ssl/cmpcert.c @@ -13,7 +13,7 @@ #include "cert.h" #include "nspr.h" #include "secder.h" -#include "key.h" +#include "keyhi.h" #include "nss.h" /* @@ -27,13 +27,9 @@ NSS_CmpCertChainWCANames(CERTCertificate *cert, CERTDistNames *caNames) SECItem *caname; CERTCertificate *curcert; CERTCertificate *oldcert; - PRInt32 contentlen; int j; - int headerlen; int depth; - SECStatus rv; SECItem issuerName; - SECItem compatIssuerName; if (!cert || !caNames || !caNames->nnames || !caNames->names || !caNames->names->data) @@ -44,29 +40,11 @@ NSS_CmpCertChainWCANames(CERTCertificate *cert, CERTDistNames *caNames) while (curcert) { issuerName = curcert->derIssuer; - /* compute an alternate issuer name for compatibility with 2.0 - * enterprise server, which send the CA names without - * the outer layer of DER header - */ - rv = DER_Lengths(&issuerName, &headerlen, (PRUint32 *)&contentlen); - if (rv == SECSuccess) { - compatIssuerName.data = &issuerName.data[headerlen]; - compatIssuerName.len = issuerName.len - headerlen; - } else { - compatIssuerName.data = NULL; - compatIssuerName.len = 0; - } - for (j = 0; j < caNames->nnames; j++) { caname = &caNames->names[j]; if (SECITEM_CompareItem(&issuerName, caname) == SECEqual) { - rv = SECSuccess; CERT_DestroyCertificate(curcert); - goto done; - } else if (SECITEM_CompareItem(&compatIssuerName, caname) == SECEqual) { - rv = SECSuccess; - CERT_DestroyCertificate(curcert); - goto done; + return SECSuccess; } } if ((depth <= 20) && @@ -82,8 +60,5 @@ NSS_CmpCertChainWCANames(CERTCertificate *cert, CERTDistNames *caNames) curcert = NULL; } } - rv = SECFailure; - -done: - return rv; + return SECFailure; } diff --git a/security/nss/lib/ssl/config.mk b/security/nss/lib/ssl/config.mk index d13613f78..b901a8830 100644 --- a/security/nss/lib/ssl/config.mk +++ b/security/nss/lib/ssl/config.mk @@ -60,3 +60,7 @@ endif ifdef NSS_DISABLE_TLS_1_3 DEFINES += -DNSS_DISABLE_TLS_1_3 endif + +ifeq (,$(filter-out DragonFly FreeBSD Linux NetBSD OpenBSD, $(OS_TARGET))) +CFLAGS += -std=gnu99 +endif diff --git a/security/nss/lib/ssl/dtls13con.c b/security/nss/lib/ssl/dtls13con.c index de6cb47ca..81d196dee 100644 --- a/security/nss/lib/ssl/dtls13con.c +++ b/security/nss/lib/ssl/dtls13con.c @@ -32,7 +32,7 @@ dtls13_InsertCipherTextHeader(const sslSocket *ss, ssl3CipherSpec *cwSpec, return sslBuffer_AppendNumber(wrBuf, seq, 2); } - rv = sslBuffer_AppendNumber(wrBuf, content_application_data, 1); + rv = sslBuffer_AppendNumber(wrBuf, ssl_ct_application_data, 1); if (rv != SECSuccess) { return SECFailure; } @@ -147,7 +147,7 @@ dtls13_SendAck(sslSocket *ss) } ssl_GetXmitBufLock(ss); - sent = ssl3_SendRecord(ss, NULL, content_ack, + sent = ssl3_SendRecord(ss, NULL, ssl_ct_ack, buf.buf, buf.len, 0); ssl_ReleaseXmitBufLock(ss); if (sent != buf.len) { @@ -343,7 +343,7 @@ dtls13_SetupAcks(sslSocket *ss) */ SECStatus dtls13_HandleOutOfEpochRecord(sslSocket *ss, const ssl3CipherSpec *spec, - SSL3ContentType rType, + SSLContentType rType, sslBuffer *databuf) { SECStatus rv; @@ -360,7 +360,7 @@ dtls13_HandleOutOfEpochRecord(sslSocket *ss, const ssl3CipherSpec *spec, SSL_TRC(10, ("%d: DTLS13[%d]: handle out of epoch record: type=%d", SSL_GETPID(), ss->fd, rType)); - if (rType == content_ack) { + if (rType == ssl_ct_ack) { ssl_GetSSL3HandshakeLock(ss); rv = dtls13_HandleAck(ss, &buf); ssl_ReleaseSSL3HandshakeLock(ss); @@ -380,7 +380,7 @@ dtls13_HandleOutOfEpochRecord(sslSocket *ss, const ssl3CipherSpec *spec, * retransmitted Finished (e.g., because our ACK got lost.) * We just retransmit the previous Finished to let the client * complete. */ - if (rType == content_handshake) { + if (rType == ssl_ct_handshake) { if ((ss->sec.isServer) && (ss->ssl3.hs.ws == idle_handshake)) { PORT_Assert(dtls_TimerActive(ss, ss->ssl3.hs.hdTimer)); diff --git a/security/nss/lib/ssl/dtls13con.h b/security/nss/lib/ssl/dtls13con.h index ca48ef363..ce92a8a55 100644 --- a/security/nss/lib/ssl/dtls13con.h +++ b/security/nss/lib/ssl/dtls13con.h @@ -21,7 +21,7 @@ PRBool dtls_NextUnackedRange(sslSocket *ss, PRUint16 msgSeq, PRUint32 offset, PRUint32 len, PRUint32 *startOut, PRUint32 *endOut); SECStatus dtls13_SetupAcks(sslSocket *ss); SECStatus dtls13_HandleOutOfEpochRecord(sslSocket *ss, const ssl3CipherSpec *spec, - SSL3ContentType rType, + SSLContentType rType, sslBuffer *databuf); SECStatus dtls13_HandleAck(sslSocket *ss, sslBuffer *databuf); diff --git a/security/nss/lib/ssl/dtlscon.c b/security/nss/lib/ssl/dtlscon.c index a82295c66..a5c604bca 100644 --- a/security/nss/lib/ssl/dtlscon.c +++ b/security/nss/lib/ssl/dtlscon.c @@ -120,7 +120,7 @@ ssl3_DisableNonDTLSSuites(sslSocket *ss) * Called from dtls_QueueMessage() */ static DTLSQueuedMessage * -dtls_AllocQueuedMessage(ssl3CipherSpec *cwSpec, SSL3ContentType type, +dtls_AllocQueuedMessage(ssl3CipherSpec *cwSpec, SSLContentType ct, const unsigned char *data, PRUint32 len) { DTLSQueuedMessage *msg; @@ -138,7 +138,7 @@ dtls_AllocQueuedMessage(ssl3CipherSpec *cwSpec, SSL3ContentType type, msg->len = len; msg->cwSpec = cwSpec; - msg->type = type; + msg->type = ct; /* Safe if we are < 1.3, since the refct is * already very high. */ ssl_CipherSpecAddRef(cwSpec); @@ -517,7 +517,7 @@ loser: * ssl3_SendChangeCipherSpecs() */ SECStatus -dtls_QueueMessage(sslSocket *ss, SSL3ContentType type, +dtls_QueueMessage(sslSocket *ss, SSLContentType ct, const PRUint8 *pIn, PRInt32 nIn) { SECStatus rv = SECSuccess; @@ -528,7 +528,7 @@ dtls_QueueMessage(sslSocket *ss, SSL3ContentType type, PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); spec = ss->ssl3.cwSpec; - msg = dtls_AllocQueuedMessage(spec, type, pIn, nIn); + msg = dtls_AllocQueuedMessage(spec, ct, pIn, nIn); if (!msg) { PORT_SetError(SEC_ERROR_NO_MEMORY); @@ -562,7 +562,7 @@ dtls_StageHandshakeMessage(sslSocket *ss) if (!ss->sec.ci.sendBuf.buf || !ss->sec.ci.sendBuf.len) return rv; - rv = dtls_QueueMessage(ss, content_handshake, + rv = dtls_QueueMessage(ss, ssl_ct_handshake, ss->sec.ci.sendBuf.buf, ss->sec.ci.sendBuf.len); /* Whether we succeeded or failed, toss the old handshake data. */ @@ -696,7 +696,7 @@ dtls_FragmentHandshake(sslSocket *ss, DTLSQueuedMessage *msg) PORT_Assert(msg->len >= DTLS_HS_HDR_LEN); /* DTLS only supports fragmenting handshaking messages. */ - PORT_Assert(msg->type == content_handshake); + PORT_Assert(msg->type == ssl_ct_handshake); msgSeq = (msg->data[4] << 8) | msg->data[5]; @@ -848,7 +848,7 @@ dtls_TransmitMessageFlight(sslSocket *ss) * be quite fragmented. Adding an extra flush here would push new * messages into new records and reduce fragmentation. */ - if (msg->type == content_handshake) { + if (msg->type == ssl_ct_handshake) { rv = dtls_FragmentHandshake(ss, msg); } else { PORT_Assert(!tls13_MaybeTls13(ss)); @@ -1327,9 +1327,9 @@ dtls_IsLongHeader(SSL3ProtocolVersion version, PRUint8 firstOctet) { #ifndef UNSAFE_FUZZER_MODE return version < SSL_LIBRARY_VERSION_TLS_1_3 || - firstOctet == content_handshake || - firstOctet == content_ack || - firstOctet == content_alert; + firstOctet == ssl_ct_handshake || + firstOctet == ssl_ct_ack || + firstOctet == ssl_ct_alert; #else return PR_TRUE; #endif @@ -1359,7 +1359,7 @@ dtls_ReadEpoch(const ssl3CipherSpec *crSpec, const PRUint8 *hdr) } /* dtls_GatherData should ensure that this works. */ - PORT_Assert(hdr[0] == content_application_data); + PORT_Assert(hdr[0] == ssl_ct_application_data); /* This uses the same method as is used to recover the sequence number in * dtls_ReadSequenceNumber, except that the maximum value is set to the diff --git a/security/nss/lib/ssl/dtlscon.h b/security/nss/lib/ssl/dtlscon.h index 45fc069b9..4ede3c2ca 100644 --- a/security/nss/lib/ssl/dtlscon.h +++ b/security/nss/lib/ssl/dtlscon.h @@ -23,7 +23,7 @@ extern SECStatus dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, extern SECStatus dtls_HandleHelloVerifyRequest(sslSocket *ss, PRUint8 *b, PRUint32 length); extern SECStatus dtls_StageHandshakeMessage(sslSocket *ss); -extern SECStatus dtls_QueueMessage(sslSocket *ss, SSL3ContentType type, +extern SECStatus dtls_QueueMessage(sslSocket *ss, SSLContentType type, const PRUint8 *pIn, PRInt32 nIn); extern SECStatus dtls_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags); SECStatus ssl3_DisableNonDTLSSuites(sslSocket *ss); diff --git a/security/nss/lib/ssl/manifest.mn b/security/nss/lib/ssl/manifest.mn index ca9b9ee7b..fe9470bd0 100644 --- a/security/nss/lib/ssl/manifest.mn +++ b/security/nss/lib/ssl/manifest.mn @@ -1,4 +1,3 @@ -# # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -56,6 +55,7 @@ CSRCS = \ tls13replay.c \ sslcert.c \ sslgrp.c \ + tls13esni.c \ $(NULL) LIBRARY_NAME = ssl diff --git a/security/nss/lib/ssl/ssl.gyp b/security/nss/lib/ssl/ssl.gyp index 3694ab91a..2e28f6775 100644 --- a/security/nss/lib/ssl/ssl.gyp +++ b/security/nss/lib/ssl/ssl.gyp @@ -43,6 +43,7 @@ 'ssltrace.c', 'sslver.c', 'tls13con.c', + 'tls13esni.c', 'tls13exthandle.c', 'tls13hashstate.c', 'tls13hkdf.c', @@ -67,6 +68,11 @@ 'UNSAFE_FUZZER_MODE', ], }], + [ 'OS=="dragonfly" or OS=="freebsd" or OS=="netbsd" or OS=="openbsd" or OS=="linux"', { + 'cflags': [ + '-std=gnu99', + ], + }], ], 'dependencies': [ '<(DEPTH)/exports.gyp:nss_exports', diff --git a/security/nss/lib/ssl/ssl.h b/security/nss/lib/ssl/ssl.h index ecc4f9506..fc4a4a70c 100644 --- a/security/nss/lib/ssl/ssl.h +++ b/security/nss/lib/ssl/ssl.h @@ -13,7 +13,7 @@ #include "prio.h" #include "seccomon.h" #include "cert.h" -#include "keyt.h" +#include "keythi.h" #include "sslt.h" /* public ssl data types */ @@ -282,6 +282,23 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd); */ #define SSL_ENABLE_DTLS_SHORT_HEADER 36 +/* + * Enables the processing of the downgrade sentinel that can be added to the + * ServerHello.random by a server that supports Section 4.1.3 of TLS 1.3 + * [RFC8446]. This sentinel will always be generated by a server that + * negotiates a version lower than its maximum, this only controls whether a + * client will treat receipt of a value that indicates a downgrade as an error. + */ +#define SSL_ENABLE_HELLO_DOWNGRADE_CHECK 37 + +/* Enables the SSLv2-compatible ClientHello for servers. NSS does not support + * SSLv2 and will never send an SSLv2-compatible ClientHello as a client. An + * NSS server with this option enabled will accept a ClientHello that is + * v2-compatible as defined in Appendix E.1 of RFC 6101. + * + * This is disabled by default and will be removed in a future version. */ +#define SSL_ENABLE_V2_COMPATIBLE_HELLO 38 + #ifdef SSL_DEPRECATED_FUNCTION /* Old deprecated function names */ SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRIntn on); diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c index 466fc296f..3b5c69b11 100644 --- a/security/nss/lib/ssl/ssl3con.c +++ b/security/nss/lib/ssl/ssl3con.c @@ -93,8 +93,8 @@ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = { { TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE}, { TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE}, { TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_FALSE, PR_FALSE}, + { TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_TRUE, PR_FALSE}, + { TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_TRUE, PR_FALSE}, /* TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA is out of order to work around * bug 946147. */ @@ -114,7 +114,7 @@ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = { { TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE}, { TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,SSL_ALLOWED,PR_TRUE, PR_FALSE}, { TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_FALSE, PR_FALSE}, - { TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_FALSE, PR_FALSE}, + { TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_TRUE, PR_FALSE}, { TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_FALSE, PR_FALSE}, { TLS_DHE_RSA_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE}, { TLS_DHE_DSS_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE}, @@ -143,7 +143,7 @@ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = { /* RSA */ { TLS_RSA_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_RSA_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_FALSE, PR_FALSE}, + { TLS_RSA_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_TRUE, PR_FALSE}, { TLS_RSA_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE}, { TLS_RSA_WITH_AES_128_CBC_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE}, { TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE}, @@ -501,19 +501,19 @@ ssl3_DecodeContentType(int msgType) static char line[40]; switch (msgType) { - case content_change_cipher_spec: + case ssl_ct_change_cipher_spec: rv = "change_cipher_spec (20)"; break; - case content_alert: + case ssl_ct_alert: rv = "alert (21)"; break; - case content_handshake: + case ssl_ct_handshake: rv = "handshake (22)"; break; - case content_application_data: + case ssl_ct_application_data: rv = "application_data (23)"; break; - case content_ack: + case ssl_ct_ack: rv = "ack (25)"; break; default: @@ -656,7 +656,7 @@ ssl_LookupCipherSuiteCfgMutable(ssl3CipherSuite suite, return NULL; } -const static ssl3CipherSuiteCfg * +const ssl3CipherSuiteCfg * ssl_LookupCipherSuiteCfg(ssl3CipherSuite suite, const ssl3CipherSuiteCfg *suites) { return ssl_LookupCipherSuiteCfgMutable(suite, @@ -765,6 +765,9 @@ ssl_HasCert(const sslSocket *ss, SSLAuthType authType) } return PR_TRUE; } + if (authType == ssl_auth_rsa_sign) { + return ssl_HasCert(ss, ssl_auth_rsa_pss); + } return PR_FALSE; } @@ -851,9 +854,9 @@ ssl3_config_match_init(sslSocket *ss) /* Return PR_TRUE if suite is usable. This if the suite is permitted by policy, * enabled, has a certificate (as needed), has a viable key agreement method, is * usable with the negotiated TLS version, and is otherwise usable. */ -static PRBool -config_match(const ssl3CipherSuiteCfg *suite, PRUint8 policy, - const SSLVersionRange *vrange, const sslSocket *ss) +PRBool +ssl3_config_match(const ssl3CipherSuiteCfg *suite, PRUint8 policy, + const SSLVersionRange *vrange, const sslSocket *ss) { const ssl3CipherSuiteDef *cipher_def; const ssl3KEADef *kea_def; @@ -896,7 +899,7 @@ count_cipher_suites(sslSocket *ss, PRUint8 policy) return 0; } for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) { - if (config_match(&ss->cipherSuites[i], policy, &ss->vrange, ss)) + if (ssl3_config_match(&ss->cipherSuites[i], policy, &ss->vrange, ss)) count++; } if (count == 0) { @@ -1120,6 +1123,8 @@ ssl3_SignHashes(sslSocket *ss, SSL3Hashes *hash, SECKEYPrivateKey *key, if (ss->sec.isServer) { ss->sec.signatureScheme = ss->ssl3.hs.signatureScheme; + ss->sec.authType = + ssl_SignatureSchemeToAuthType(ss->ssl3.hs.signatureScheme); } PRINT_BUF(60, (NULL, "signed hashes", (unsigned char *)buf->data, buf->len)); done: @@ -1255,6 +1260,7 @@ ssl3_VerifySignedHashes(sslSocket *ss, SSLSignatureScheme scheme, SSL3Hashes *ha } if (!ss->sec.isServer) { ss->sec.signatureScheme = scheme; + ss->sec.authType = ssl_SignatureSchemeToAuthType(scheme); } loser: @@ -1506,7 +1512,7 @@ loser: static SECStatus ssl3_BuildRecordPseudoHeader(DTLSEpoch epoch, sslSequenceNumber seqNum, - SSL3ContentType type, + SSLContentType ct, PRBool includesVersion, SSL3ProtocolVersion version, PRBool isDTLS, @@ -1526,7 +1532,7 @@ ssl3_BuildRecordPseudoHeader(DTLSEpoch epoch, if (rv != SECSuccess) { return SECFailure; } - rv = sslBuffer_AppendNumber(buf, type, 1); + rv = sslBuffer_AppendNumber(buf, ct, 1); if (rv != SECSuccess) { return SECFailure; } @@ -1994,7 +2000,7 @@ SECStatus ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec, PRBool isServer, PRBool isDTLS, - SSL3ContentType type, + SSLContentType ct, const PRUint8 *pIn, PRUint32 contentLen, sslBuffer *wrBuf) @@ -2041,7 +2047,7 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec, } rv = ssl3_BuildRecordPseudoHeader( - cwSpec->epoch, cwSpec->nextSeqNum, type, + cwSpec->epoch, cwSpec->nextSeqNum, ct, cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_0, cwSpec->recordVersion, isDTLS, contentLen, &pseudoHeader); PORT_Assert(rv == SECSuccess); @@ -2163,7 +2169,7 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec, /* Note: though this can report failure, it shouldn't. */ SECStatus ssl_InsertRecordHeader(const sslSocket *ss, ssl3CipherSpec *cwSpec, - SSL3ContentType contentType, sslBuffer *wrBuf, + SSLContentType contentType, sslBuffer *wrBuf, PRBool *needsLength) { SECStatus rv; @@ -2175,7 +2181,7 @@ ssl_InsertRecordHeader(const sslSocket *ss, ssl3CipherSpec *cwSpec, return dtls13_InsertCipherTextHeader(ss, cwSpec, wrBuf, needsLength); } - contentType = content_application_data; + contentType = ssl_ct_application_data; } #endif rv = sslBuffer_AppendNumber(wrBuf, contentType, 1); @@ -2202,7 +2208,7 @@ ssl_InsertRecordHeader(const sslSocket *ss, ssl3CipherSpec *cwSpec, } SECStatus -ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSL3ContentType type, +ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSLContentType ct, const PRUint8 *pIn, PRUint32 contentLen, sslBuffer *wrBuf) { PRBool needsLength; @@ -2222,7 +2228,7 @@ ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSL3ContentType type, return SECFailure; } - rv = ssl_InsertRecordHeader(ss, cwSpec, type, wrBuf, &needsLength); + rv = ssl_InsertRecordHeader(ss, cwSpec, ct, wrBuf, &needsLength); if (rv != SECSuccess) { return SECFailure; } @@ -2246,9 +2252,9 @@ ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSL3ContentType type, } #else if (cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_3) { - rv = tls13_ProtectRecord(ss, cwSpec, type, pIn, contentLen, wrBuf); + rv = tls13_ProtectRecord(ss, cwSpec, ct, pIn, contentLen, wrBuf); } else { - rv = ssl3_MACEncryptRecord(cwSpec, ss->sec.isServer, IS_DTLS(ss), type, + rv = ssl3_MACEncryptRecord(cwSpec, ss->sec.isServer, IS_DTLS(ss), ct, pIn, contentLen, wrBuf); } #endif @@ -2270,7 +2276,7 @@ ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSL3ContentType type, } SECStatus -ssl_ProtectNextRecord(sslSocket *ss, ssl3CipherSpec *spec, SSL3ContentType type, +ssl_ProtectNextRecord(sslSocket *ss, ssl3CipherSpec *spec, SSLContentType ct, const PRUint8 *pIn, unsigned int nIn, unsigned int *written) { @@ -2294,7 +2300,7 @@ ssl_ProtectNextRecord(sslSocket *ss, ssl3CipherSpec *spec, SSL3ContentType type, } } - rv = ssl_ProtectRecord(ss, spec, type, pIn, contentLen, wrBuf); + rv = ssl_ProtectRecord(ss, spec, ct, pIn, contentLen, wrBuf); if (rv != SECSuccess) { return SECFailure; } @@ -2328,7 +2334,7 @@ ssl_ProtectNextRecord(sslSocket *ss, ssl3CipherSpec *spec, SSL3ContentType type, PRInt32 ssl3_SendRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, /* non-NULL for DTLS retransmits */ - SSL3ContentType type, + SSLContentType ct, const PRUint8 *pIn, /* input buffer */ PRInt32 nIn, /* bytes of input */ PRInt32 flags) @@ -2339,7 +2345,7 @@ ssl3_SendRecord(sslSocket *ss, PRInt32 totalSent = 0; SSL_TRC(3, ("%d: SSL3[%d] SendRecord type: %s nIn=%d", - SSL_GETPID(), ss->fd, ssl3_DecodeContentType(type), + SSL_GETPID(), ss->fd, ssl3_DecodeContentType(ct), nIn)); PRINT_BUF(50, (ss, "Send record (plain text)", pIn, nIn)); @@ -2349,7 +2355,7 @@ ssl3_SendRecord(sslSocket *ss, if (ss->ssl3.fatalAlertSent) { SSL_TRC(3, ("%d: SSL3[%d] Suppress write, fatal alert already sent", SSL_GETPID(), ss->fd)); - if (type != content_alert) { + if (ct != ssl_ct_alert) { /* If we are sending an alert, then we already have an * error, so don't overwrite. */ PORT_SetError(SSL_ERROR_HANDSHAKE_FAILED); @@ -2366,8 +2372,8 @@ ssl3_SendRecord(sslSocket *ss, if (cwSpec) { /* cwSpec can only be set for retransmissions of the DTLS handshake. */ PORT_Assert(IS_DTLS(ss) && - (type == content_handshake || - type == content_change_cipher_spec)); + (ct == ssl_ct_handshake || + ct == ssl_ct_change_cipher_spec)); spec = cwSpec; } else { spec = ss->ssl3.cwSpec; @@ -2378,7 +2384,7 @@ ssl3_SendRecord(sslSocket *ss, PRInt32 sent; ssl_GetSpecReadLock(ss); - rv = ssl_ProtectNextRecord(ss, spec, type, pIn, nIn, &written); + rv = ssl_ProtectNextRecord(ss, spec, ct, pIn, nIn, &written); ssl_ReleaseSpecReadLock(ss); if (rv != SECSuccess) { goto loser; @@ -2386,7 +2392,7 @@ ssl3_SendRecord(sslSocket *ss, PORT_Assert(written > 0); /* DTLS should not fragment non-application data here. */ - if (IS_DTLS(ss) && type != content_application_data) { + if (IS_DTLS(ss) && ct != ssl_ct_application_data) { PORT_Assert(written == nIn); } @@ -2535,7 +2541,7 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in, * Note that the 0 epoch is OK because flags will never require * its use, as guaranteed by the PORT_Assert above. */ - sent = ssl3_SendRecord(ss, NULL, content_application_data, + sent = ssl3_SendRecord(ss, NULL, ssl_ct_application_data, in + totalSent, toSend, flags); if (sent < 0) { if (totalSent > 0 && PR_GetError() == PR_WOULD_BLOCK_ERROR) { @@ -2618,7 +2624,7 @@ ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags) PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } - count = ssl3_SendRecord(ss, NULL, content_handshake, + count = ssl3_SendRecord(ss, NULL, ssl_ct_handshake, ss->sec.ci.sendBuf.buf, ss->sec.ci.sendBuf.len, flags); if (count < 0) { @@ -2744,7 +2750,7 @@ SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc) rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER); if (rv == SECSuccess) { PRInt32 sent; - sent = ssl3_SendRecord(ss, NULL, content_alert, bytes, 2, + sent = ssl3_SendRecord(ss, NULL, ssl_ct_alert, bytes, 2, (desc == no_certificate) ? ssl_SEND_FLAG_FORCE_INTO_BUFFER : 0); rv = (sent >= 0) ? SECSuccess : (SECStatus)sent; } @@ -3041,13 +3047,13 @@ ssl3_SendChangeCipherSpecsInt(sslSocket *ss) if (!IS_DTLS(ss)) { PRInt32 sent; - sent = ssl3_SendRecord(ss, NULL, content_change_cipher_spec, + sent = ssl3_SendRecord(ss, NULL, ssl_ct_change_cipher_spec, &change, 1, ssl_SEND_FLAG_FORCE_INTO_BUFFER); if (sent < 0) { return SECFailure; /* error code set by ssl3_SendRecord */ } } else { - rv = dtls_QueueMessage(ss, content_change_cipher_spec, &change, 1); + rv = dtls_QueueMessage(ss, ssl_ct_change_cipher_spec, &change, 1); if (rv != SECSuccess) { return SECFailure; } @@ -4002,8 +4008,8 @@ ssl_SignatureSchemeToHashType(SSLSignatureScheme scheme) return ssl_hash_none; } -KeyType -ssl_SignatureSchemeToKeyType(SSLSignatureScheme scheme) +static PRBool +ssl_SignatureSchemeMatchesSpkiOid(SSLSignatureScheme scheme, SECOidTag spkiOid) { switch (scheme) { case ssl_sig_rsa_pkcs1_sha256: @@ -4013,133 +4019,243 @@ ssl_SignatureSchemeToKeyType(SSLSignatureScheme scheme) case ssl_sig_rsa_pss_rsae_sha256: case ssl_sig_rsa_pss_rsae_sha384: case ssl_sig_rsa_pss_rsae_sha512: + case ssl_sig_rsa_pkcs1_sha1md5: + return (spkiOid == SEC_OID_X500_RSA_ENCRYPTION) || + (spkiOid == SEC_OID_PKCS1_RSA_ENCRYPTION); case ssl_sig_rsa_pss_pss_sha256: case ssl_sig_rsa_pss_pss_sha384: case ssl_sig_rsa_pss_pss_sha512: - case ssl_sig_rsa_pkcs1_sha1md5: - return rsaKey; + return spkiOid == SEC_OID_PKCS1_RSA_PSS_SIGNATURE; case ssl_sig_ecdsa_secp256r1_sha256: case ssl_sig_ecdsa_secp384r1_sha384: case ssl_sig_ecdsa_secp521r1_sha512: case ssl_sig_ecdsa_sha1: - return ecKey; + return spkiOid == SEC_OID_ANSIX962_EC_PUBLIC_KEY; case ssl_sig_dsa_sha256: case ssl_sig_dsa_sha384: case ssl_sig_dsa_sha512: case ssl_sig_dsa_sha1: - return dsaKey; + return spkiOid == SEC_OID_ANSIX9_DSA_SIGNATURE; case ssl_sig_none: case ssl_sig_ed25519: case ssl_sig_ed448: break; } PORT_Assert(0); - return nullKey; + return PR_FALSE; } -static SSLNamedGroup -ssl_NamedGroupForSignatureScheme(SSLSignatureScheme scheme) +/* Validate that the signature scheme works for the given key type. */ +static PRBool +ssl_SignatureSchemeValid(SSLSignatureScheme scheme, SECOidTag spkiOid, + PRBool isTls13) { - switch (scheme) { - case ssl_sig_ecdsa_secp256r1_sha256: - return ssl_grp_ec_secp256r1; - case ssl_sig_ecdsa_secp384r1_sha384: - return ssl_grp_ec_secp384r1; - case ssl_sig_ecdsa_secp521r1_sha512: - return ssl_grp_ec_secp521r1; - default: + if (!ssl_IsSupportedSignatureScheme(scheme)) { + return PR_FALSE; + } + if (!ssl_SignatureSchemeMatchesSpkiOid(scheme, spkiOid)) { + return PR_FALSE; + } + if (isTls13) { + if (ssl_SignatureSchemeToHashType(scheme) == ssl_hash_sha1) { + return PR_FALSE; + } + /* With TLS 1.3, EC keys should have been selected based on calling + * ssl_SignatureSchemeFromSpki(), reject them otherwise. */ + return spkiOid != SEC_OID_ANSIX962_EC_PUBLIC_KEY; + } + return PR_TRUE; +} + +static SECStatus +ssl_SignatureSchemeFromPssSpki(CERTSubjectPublicKeyInfo *spki, + SSLSignatureScheme *scheme) +{ + SECKEYRSAPSSParams pssParam = { 0 }; + PORTCheapArenaPool arena; + SECStatus rv; + + /* The key doesn't have parameters, boo. */ + if (!spki->algorithm.parameters.len) { + *scheme = ssl_sig_none; + return SECSuccess; + } + + PORT_InitCheapArena(&arena, DER_DEFAULT_CHUNKSIZE); + rv = SEC_QuickDERDecodeItem(&arena.arena, &pssParam, + SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate), + &spki->algorithm.parameters); + if (rv != SECSuccess) { + goto loser; + } + /* Not having hashAlg means SHA-1 and we don't accept that. */ + if (!pssParam.hashAlg) { + goto loser; + } + switch (SECOID_GetAlgorithmTag(pssParam.hashAlg)) { + case SEC_OID_SHA256: + *scheme = ssl_sig_rsa_pss_pss_sha256; break; + case SEC_OID_SHA384: + *scheme = ssl_sig_rsa_pss_pss_sha384; + break; + case SEC_OID_SHA512: + *scheme = ssl_sig_rsa_pss_pss_sha512; + break; + default: + goto loser; } - PORT_Assert(0); - return 0; + + PORT_DestroyCheapArena(&arena); + return SECSuccess; + +loser: + PORT_DestroyCheapArena(&arena); + PORT_SetError(SSL_ERROR_BAD_CERTIFICATE); + return SECFailure; } -/* Validate that the signature scheme works for the given key. - * If |allowSha1| is set, we allow the use of SHA-1. - * If |matchGroup| is set, we also check that the group and hash match. */ -static PRBool -ssl_SignatureSchemeValidForKey(PRBool allowSha1, PRBool matchGroup, - KeyType keyType, - const sslNamedGroupDef *ecGroup, - SSLSignatureScheme scheme) +static SECStatus +ssl_SignatureSchemeFromEcSpki(CERTSubjectPublicKeyInfo *spki, + SSLSignatureScheme *scheme) { - if (!ssl_IsSupportedSignatureScheme(scheme)) { - return PR_FALSE; + const sslNamedGroupDef *group; + SECKEYPublicKey *key; + + key = SECKEY_ExtractPublicKey(spki); + if (!key) { + PORT_SetError(SSL_ERROR_BAD_CERTIFICATE); + return SECFailure; } - if (keyType != ssl_SignatureSchemeToKeyType(scheme)) { - return PR_FALSE; + group = ssl_ECPubKey2NamedGroup(key); + SECKEY_DestroyPublicKey(key); + if (!group) { + PORT_SetError(SSL_ERROR_BAD_CERTIFICATE); + return SECFailure; } - if (!allowSha1 && ssl_SignatureSchemeToHashType(scheme) == ssl_hash_sha1) { - return PR_FALSE; + switch (group->name) { + case ssl_grp_ec_secp256r1: + *scheme = ssl_sig_ecdsa_secp256r1_sha256; + return SECSuccess; + case ssl_grp_ec_secp384r1: + *scheme = ssl_sig_ecdsa_secp384r1_sha384; + return SECSuccess; + case ssl_grp_ec_secp521r1: + *scheme = ssl_sig_ecdsa_secp521r1_sha512; + return SECSuccess; + default: + break; } - if (keyType != ecKey) { - return PR_TRUE; + PORT_SetError(SSL_ERROR_BAD_CERTIFICATE); + return SECFailure; +} + +/* Newer signature schemes are designed so that a single SPKI can be used with + * that scheme. This determines that scheme from the SPKI. If the SPKI doesn't + * have a single scheme, |*scheme| is set to ssl_sig_none. */ +static SECStatus +ssl_SignatureSchemeFromSpki(CERTSubjectPublicKeyInfo *spki, + PRBool isTls13, SSLSignatureScheme *scheme) +{ + SECOidTag spkiOid = SECOID_GetAlgorithmTag(&spki->algorithm); + + if (spkiOid == SEC_OID_PKCS1_RSA_PSS_SIGNATURE) { + return ssl_SignatureSchemeFromPssSpki(spki, scheme); } - if (!ecGroup) { - return PR_FALSE; + + /* Only do this lookup for TLS 1.3, where the scheme can be determined from + * the SPKI alone because the ECDSA key size determines the hash. Earlier + * TLS versions allow the same EC key to be used with different hashes. */ + if (isTls13 && spkiOid == SEC_OID_ANSIX962_EC_PUBLIC_KEY) { + return ssl_SignatureSchemeFromEcSpki(spki, scheme); } - /* If |allowSha1| is present and the scheme is ssl_sig_ecdsa_sha1, it's OK. - * This scheme isn't bound to a specific group. */ - if (allowSha1 && (scheme == ssl_sig_ecdsa_sha1)) { - return PR_TRUE; + + *scheme = ssl_sig_none; + return SECSuccess; +} + +static PRBool +ssl_SignatureSchemeEnabled(sslSocket *ss, SSLSignatureScheme scheme) +{ + unsigned int i; + for (i = 0; i < ss->ssl3.signatureSchemeCount; ++i) { + if (scheme == ss->ssl3.signatureSchemes[i]) { + return PR_TRUE; + } } - if (!matchGroup) { - return PR_TRUE; + return PR_FALSE; +} + +static PRBool +ssl_SignatureKeyMatchesSpkiOid(const ssl3KEADef *keaDef, SECOidTag spkiOid) +{ + switch (spkiOid) { + case SEC_OID_X500_RSA_ENCRYPTION: + case SEC_OID_PKCS1_RSA_ENCRYPTION: + case SEC_OID_PKCS1_RSA_PSS_SIGNATURE: + return keaDef->signKeyType == rsaKey; + case SEC_OID_ANSIX9_DSA_SIGNATURE: + return keaDef->signKeyType == dsaKey; + case SEC_OID_ANSIX962_EC_PUBLIC_KEY: + return keaDef->signKeyType == ecKey; + default: + break; } - return ecGroup->name == ssl_NamedGroupForSignatureScheme(scheme); + return PR_FALSE; } -/* ssl3_CheckSignatureSchemeConsistency checks that the signature - * algorithm identifier in |sigAndHash| is consistent with the public key in - * |cert|. It also checks the hash algorithm against the configured signature - * algorithms. If all the tests pass, SECSuccess is returned. Otherwise, - * PORT_SetError is called and SECFailure is returned. */ +/* ssl3_CheckSignatureSchemeConsistency checks that the signature algorithm + * identifier in |scheme| is consistent with the public key in |cert|. It also + * checks the hash algorithm against the configured signature algorithms. If + * all the tests pass, SECSuccess is returned. Otherwise, PORT_SetError is + * called and SECFailure is returned. */ SECStatus -ssl_CheckSignatureSchemeConsistency( - sslSocket *ss, SSLSignatureScheme scheme, CERTCertificate *cert) +ssl_CheckSignatureSchemeConsistency(sslSocket *ss, SSLSignatureScheme scheme, + CERTCertificate *cert) { - unsigned int i; - const sslNamedGroupDef *group = NULL; - SECKEYPublicKey *key; - KeyType keyType; + SSLSignatureScheme spkiScheme; PRBool isTLS13 = ss->version == SSL_LIBRARY_VERSION_TLS_1_3; + SECOidTag spkiOid; + SECStatus rv; - key = CERT_ExtractPublicKey(cert); - if (key == NULL) { - ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE); + rv = ssl_SignatureSchemeFromSpki(&cert->subjectPublicKeyInfo, isTLS13, + &spkiScheme); + if (rv != SECSuccess) { return SECFailure; } - - keyType = SECKEY_GetPublicKeyType(key); - if (keyType == ecKey) { - group = ssl_ECPubKey2NamedGroup(key); + if (spkiScheme != ssl_sig_none) { + /* The SPKI in the certificate can only be used for a single scheme. */ + if (spkiScheme != scheme || + !ssl_SignatureSchemeEnabled(ss, scheme)) { + PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM); + return SECFailure; + } + return SECSuccess; } - SECKEY_DestroyPublicKey(key); + + spkiOid = SECOID_GetAlgorithmTag(&cert->subjectPublicKeyInfo.algorithm); /* If we're a client, check that the signature algorithm matches the signing * key type of the cipher suite. */ - if (!isTLS13 && - !ss->sec.isServer && - ss->ssl3.hs.kea_def->signKeyType != keyType) { - PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM); - return SECFailure; + if (!isTLS13 && !ss->sec.isServer) { + if (!ssl_SignatureKeyMatchesSpkiOid(ss->ssl3.hs.kea_def, spkiOid)) { + PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM); + return SECFailure; + } } /* Verify that the signature scheme matches the signing key. */ - if (!ssl_SignatureSchemeValidForKey(!isTLS13 /* allowSha1 */, - isTLS13 /* matchGroup */, - keyType, group, scheme)) { + if (!ssl_SignatureSchemeValid(scheme, spkiOid, isTLS13)) { PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM); return SECFailure; } - for (i = 0; i < ss->ssl3.signatureSchemeCount; ++i) { - if (scheme == ss->ssl3.signatureSchemes[i]) { - return SECSuccess; - } + if (!ssl_SignatureSchemeEnabled(ss, scheme)) { + PORT_SetError(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM); + return SECFailure; } - PORT_SetError(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM); - return SECFailure; + + return SECSuccess; } PRBool @@ -4153,6 +4269,9 @@ ssl_IsSupportedSignatureScheme(SSLSignatureScheme scheme) case ssl_sig_rsa_pss_rsae_sha256: case ssl_sig_rsa_pss_rsae_sha384: case ssl_sig_rsa_pss_rsae_sha512: + case ssl_sig_rsa_pss_pss_sha256: + case ssl_sig_rsa_pss_pss_sha384: + case ssl_sig_rsa_pss_pss_sha512: case ssl_sig_ecdsa_secp256r1_sha256: case ssl_sig_ecdsa_secp384r1_sha384: case ssl_sig_ecdsa_secp521r1_sha512: @@ -4164,9 +4283,6 @@ ssl_IsSupportedSignatureScheme(SSLSignatureScheme scheme) return PR_TRUE; case ssl_sig_rsa_pkcs1_sha1md5: - case ssl_sig_rsa_pss_pss_sha256: - case ssl_sig_rsa_pss_pss_sha384: - case ssl_sig_rsa_pss_pss_sha512: case ssl_sig_none: case ssl_sig_ed25519: case ssl_sig_ed448: @@ -4182,6 +4298,9 @@ ssl_IsRsaPssSignatureScheme(SSLSignatureScheme scheme) case ssl_sig_rsa_pss_rsae_sha256: case ssl_sig_rsa_pss_rsae_sha384: case ssl_sig_rsa_pss_rsae_sha512: + case ssl_sig_rsa_pss_pss_sha256: + case ssl_sig_rsa_pss_pss_sha384: + case ssl_sig_rsa_pss_pss_sha512: return PR_TRUE; default: @@ -4190,6 +4309,41 @@ ssl_IsRsaPssSignatureScheme(SSLSignatureScheme scheme) return PR_FALSE; } +SSLAuthType +ssl_SignatureSchemeToAuthType(SSLSignatureScheme scheme) +{ + switch (scheme) { + case ssl_sig_rsa_pkcs1_sha1: + case ssl_sig_rsa_pkcs1_sha1md5: + case ssl_sig_rsa_pkcs1_sha256: + case ssl_sig_rsa_pkcs1_sha384: + case ssl_sig_rsa_pkcs1_sha512: + /* We report based on the key type for PSS signatures. */ + case ssl_sig_rsa_pss_rsae_sha256: + case ssl_sig_rsa_pss_rsae_sha384: + case ssl_sig_rsa_pss_rsae_sha512: + return ssl_auth_rsa_sign; + case ssl_sig_rsa_pss_pss_sha256: + case ssl_sig_rsa_pss_pss_sha384: + case ssl_sig_rsa_pss_pss_sha512: + return ssl_auth_rsa_pss; + case ssl_sig_ecdsa_secp256r1_sha256: + case ssl_sig_ecdsa_secp384r1_sha384: + case ssl_sig_ecdsa_secp521r1_sha512: + case ssl_sig_ecdsa_sha1: + return ssl_auth_ecdsa; + case ssl_sig_dsa_sha1: + case ssl_sig_dsa_sha256: + case ssl_sig_dsa_sha384: + case ssl_sig_dsa_sha512: + return ssl_auth_dsa; + + default: + PORT_Assert(0); + } + return ssl_auth_null; +} + /* ssl_ConsumeSignatureScheme reads a SSLSignatureScheme (formerly * SignatureAndHashAlgorithm) structure from |b| and puts the resulting value * into |out|. |b| and |length| are updated accordingly. @@ -4617,9 +4771,13 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) * If we have an sid and it comes from an external cache, we use it. */ if (ss->sec.ci.sid && ss->sec.ci.sid->cached == in_external_cache) { PORT_Assert(!ss->sec.isServer); - sid = ss->sec.ci.sid; + sid = ssl_ReferenceSID(ss->sec.ci.sid); SSL_TRC(3, ("%d: SSL3[%d]: using external resumption token in ClientHello", SSL_GETPID(), ss->fd)); + } else if (ss->sec.ci.sid && ss->statelessResume && type == client_hello_retry) { + /* If we are sending a second ClientHello, reuse the same SID + * as the original one. */ + sid = ssl_ReferenceSID(ss->sec.ci.sid); } else if (!ss->opt.noCache) { /* We ignore ss->sec.ci.sid here, and use ssl_Lookup because Lookup * handles expired entries and other details. @@ -4644,7 +4802,7 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) suite = ssl_LookupCipherSuiteCfg(sid->u.ssl3.cipherSuite, ss->cipherSuites); PORT_Assert(suite); - if (!suite || !config_match(suite, ss->ssl3.policy, &ss->vrange, ss)) { + if (!suite || !ssl3_config_match(suite, ss->ssl3.policy, &ss->vrange, ss)) { sidOK = PR_FALSE; } @@ -4765,9 +4923,7 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) } ssl_ReleaseSpecWriteLock(ss); - if (ss->sec.ci.sid != NULL) { - ssl_FreeSID(ss->sec.ci.sid); /* decrement ref count, free if zero */ - } + ssl_FreeSID(ss->sec.ci.sid); /* release the old sid */ ss->sec.ci.sid = sid; /* HACK for SCSV in SSL 3.0. On initial handshake, prepend SCSV, @@ -4792,6 +4948,14 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) PR_RWLock_Rlock(sid->u.ssl3.lock); } + /* Generate a new random if this is the first attempt. */ + if (type == client_hello_initial) { + rv = ssl3_GetNewRandom(ss->ssl3.hs.client_random); + if (rv != SECSuccess) { + goto loser; /* err set by GetNewRandom. */ + } + } + if (ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3 && type == client_hello_initial) { rv = tls13_SetupClientHello(ss); @@ -4799,6 +4963,7 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) goto loser; } } + if (isTLS || (ss->firstHsDone && ss->peerRequestedProtection)) { rv = ssl_ConstructExtensions(ss, &extensionBuf, ssl_hs_client_hello); if (rv != SECSuccess) { @@ -4870,13 +5035,6 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) goto loser; /* err set by ssl3_AppendHandshake* */ } - /* Generate a new random if this is the first attempt. */ - if (type == client_hello_initial) { - rv = ssl3_GetNewRandom(ss->ssl3.hs.client_random); - if (rv != SECSuccess) { - goto loser; /* err set by GetNewRandom. */ - } - } rv = ssl3_AppendHandshake(ss, ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH); if (rv != SECSuccess) { @@ -4931,7 +5089,7 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) } for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) { ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i]; - if (config_match(suite, ss->ssl3.policy, &ss->vrange, ss)) { + if (ssl3_config_match(suite, ss->ssl3.policy, &ss->vrange, ss)) { actual_count++; if (actual_count > num_suites) { /* set error card removal/insertion error */ @@ -5394,6 +5552,7 @@ ssl3_GetWrappingKey(sslSocket *ss, switch (authType) { case ssl_auth_rsa_decrypt: case ssl_auth_rsa_sign: /* bad: see Bug 1248320 */ + case ssl_auth_rsa_pss: asymWrapMechanism = CKM_RSA_PKCS; rv = PK11_PubWrapSymKey(asymWrapMechanism, svrPubKey, unwrappedWrappingKey, &wrappedKey); @@ -5843,20 +6002,59 @@ ssl3_SendClientKeyExchange(sslSocket *ss) return rv; /* err code already set. */ } +/* Used by ssl_PickSignatureScheme(). */ +static PRBool +ssl_CanUseSignatureScheme(SSLSignatureScheme scheme, + const SSLSignatureScheme *peerSchemes, + unsigned int peerSchemeCount, + PRBool requireSha1, + PRBool slotDoesPss) +{ + SSLHashType hashType; + SECOidTag hashOID; + PRUint32 policy; + unsigned int i; + + /* Skip RSA-PSS schemes when the certificate's private key slot does + * not support this signature mechanism. */ + if (ssl_IsRsaPssSignatureScheme(scheme) && !slotDoesPss) { + return PR_FALSE; + } + + hashType = ssl_SignatureSchemeToHashType(scheme); + if (requireSha1 && (hashType != ssl_hash_sha1)) { + return PR_FALSE; + } + hashOID = ssl3_HashTypeToOID(hashType); + if ((NSS_GetAlgorithmPolicy(hashOID, &policy) == SECSuccess) && + !(policy & NSS_USE_ALG_IN_SSL_KX)) { + return PR_FALSE; + } + + for (i = 0; i < peerSchemeCount; i++) { + if (peerSchemes[i] == scheme) { + return PR_TRUE; + } + } + return PR_FALSE; +} + SECStatus ssl_PickSignatureScheme(sslSocket *ss, + CERTCertificate *cert, SECKEYPublicKey *pubKey, SECKEYPrivateKey *privKey, const SSLSignatureScheme *peerSchemes, unsigned int peerSchemeCount, PRBool requireSha1) { - unsigned int i, j; - const sslNamedGroupDef *group = NULL; - KeyType keyType; + unsigned int i; PK11SlotInfo *slot; PRBool slotDoesPss; PRBool isTLS13 = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3; + SECStatus rv; + SSLSignatureScheme scheme; + SECOidTag spkiOid; /* We can't require SHA-1 in TLS 1.3. */ PORT_Assert(!(requireSha1 && isTLS13)); @@ -5874,47 +6072,35 @@ ssl_PickSignatureScheme(sslSocket *ss, slotDoesPss = PK11_DoesMechanism(slot, auth_alg_defs[ssl_auth_rsa_pss]); PK11_FreeSlot(slot); - keyType = SECKEY_GetPublicKeyType(pubKey); - if (keyType == ecKey) { - group = ssl_ECPubKey2NamedGroup(pubKey); + /* If the certificate SPKI indicates a single scheme, don't search. */ + rv = ssl_SignatureSchemeFromSpki(&cert->subjectPublicKeyInfo, + isTLS13, &scheme); + if (rv != SECSuccess) { + return SECFailure; } - - /* Here we look for the first local preference that the client has - * indicated support for in their signature_algorithms extension. */ - for (i = 0; i < ss->ssl3.signatureSchemeCount; ++i) { - SSLHashType hashType; - SECOidTag hashOID; - SSLSignatureScheme preferred = ss->ssl3.signatureSchemes[i]; - PRUint32 policy; - - if (!ssl_SignatureSchemeValidForKey(!isTLS13 /* allowSha1 */, - isTLS13 /* matchGroup */, - keyType, group, preferred)) { - continue; + if (scheme != ssl_sig_none) { + if (!ssl_SignatureSchemeEnabled(ss, scheme) || + !ssl_CanUseSignatureScheme(scheme, peerSchemes, peerSchemeCount, + requireSha1, slotDoesPss)) { + PORT_SetError(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM); + return SECFailure; } + ss->ssl3.hs.signatureScheme = scheme; + return SECSuccess; + } - /* Skip RSA-PSS schemes when the certificate's private key slot does - * not support this signature mechanism. */ - if (ssl_IsRsaPssSignatureScheme(preferred) && !slotDoesPss) { - continue; - } + spkiOid = SECOID_GetAlgorithmTag(&cert->subjectPublicKeyInfo.algorithm); - hashType = ssl_SignatureSchemeToHashType(preferred); - if (requireSha1 && (hashType != ssl_hash_sha1)) { - continue; - } - hashOID = ssl3_HashTypeToOID(hashType); - if ((NSS_GetAlgorithmPolicy(hashOID, &policy) == SECSuccess) && - !(policy & NSS_USE_ALG_IN_SSL_KX)) { - /* we ignore hashes we don't support */ - continue; - } + /* Now we have to search based on the key type. Go through our preferred + * schemes in order and find the first that can be used. */ + for (i = 0; i < ss->ssl3.signatureSchemeCount; ++i) { + scheme = ss->ssl3.signatureSchemes[i]; - for (j = 0; j < peerSchemeCount; j++) { - if (peerSchemes[j] == preferred) { - ss->ssl3.hs.signatureScheme = preferred; - return SECSuccess; - } + if (ssl_SignatureSchemeValid(scheme, spkiOid, isTLS13) && + ssl_CanUseSignatureScheme(scheme, peerSchemes, peerSchemeCount, + requireSha1, slotDoesPss)) { + ss->ssl3.hs.signatureScheme = scheme; + return SECSuccess; } } @@ -5956,17 +6142,19 @@ ssl_PickFallbackSignatureScheme(sslSocket *ss, SECKEYPublicKey *pubKey) static SECStatus ssl3_PickServerSignatureScheme(sslSocket *ss) { - sslKeyPair *keyPair = ss->sec.serverCert->serverKeyPair; + const sslServerCert *cert = ss->sec.serverCert; PRBool isTLS12 = ss->version >= SSL_LIBRARY_VERSION_TLS_1_2; if (!isTLS12 || !ssl3_ExtensionNegotiated(ss, ssl_signature_algorithms_xtn)) { /* If the client didn't provide any signature_algorithms extension then * we can assume that they support SHA-1: RFC5246, Section 7.4.1.4.1. */ - return ssl_PickFallbackSignatureScheme(ss, keyPair->pubKey); + return ssl_PickFallbackSignatureScheme(ss, cert->serverKeyPair->pubKey); } /* Sets error code, if needed. */ - return ssl_PickSignatureScheme(ss, keyPair->pubKey, keyPair->privKey, + return ssl_PickSignatureScheme(ss, cert->serverCert, + cert->serverKeyPair->pubKey, + cert->serverKeyPair->privKey, ss->xtnData.sigSchemes, ss->xtnData.numSigSchemes, PR_FALSE /* requireSha1 */); @@ -5977,23 +6165,18 @@ ssl_PickClientSignatureScheme(sslSocket *ss, const SSLSignatureScheme *schemes, unsigned int numSchemes) { SECKEYPrivateKey *privKey = ss->ssl3.clientPrivateKey; - SECKEYPublicKey *pubKey; SECStatus rv; - PRBool isTLS13 = (PRBool)ss->version >= SSL_LIBRARY_VERSION_TLS_1_3; - pubKey = CERT_ExtractPublicKey(ss->ssl3.clientCertificate); + SECKEYPublicKey *pubKey = CERT_ExtractPublicKey(ss->ssl3.clientCertificate); + PORT_Assert(pubKey); - if (!isTLS13 && numSchemes == 0) { - /* If the server didn't provide any signature algorithms - * then let's assume they support SHA-1. */ - rv = ssl_PickFallbackSignatureScheme(ss, pubKey); - SECKEY_DestroyPublicKey(pubKey); - return rv; + if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) { + /* We should have already checked that a signature scheme was + * listed in the request. */ + PORT_Assert(schemes && numSchemes > 0); } - PORT_Assert(schemes && numSchemes > 0); - if (!isTLS13 && (SECKEY_GetPublicKeyType(pubKey) == rsaKey || SECKEY_GetPublicKeyType(pubKey) == dsaKey) && @@ -6004,7 +6187,8 @@ ssl_PickClientSignatureScheme(sslSocket *ss, const SSLSignatureScheme *schemes, * older, DSA key size is at most 1024 bits and the hash function must * be SHA-1. */ - rv = ssl_PickSignatureScheme(ss, pubKey, privKey, schemes, numSchemes, + rv = ssl_PickSignatureScheme(ss, ss->ssl3.clientCertificate, + pubKey, privKey, schemes, numSchemes, PR_TRUE /* requireSha1 */); if (rv == SECSuccess) { SECKEY_DestroyPublicKey(pubKey); @@ -6013,7 +6197,8 @@ ssl_PickClientSignatureScheme(sslSocket *ss, const SSLSignatureScheme *schemes, /* If this fails, that's because the peer doesn't advertise SHA-1, * so fall back to the full negotiation. */ } - rv = ssl_PickSignatureScheme(ss, pubKey, privKey, schemes, numSchemes, + rv = ssl_PickSignatureScheme(ss, ss->ssl3.clientCertificate, + pubKey, privKey, schemes, numSchemes, PR_FALSE /* requireSha1 */); SECKEY_DestroyPublicKey(pubKey); return rv; @@ -6141,7 +6326,7 @@ ssl_ClientSetCipherSuite(sslSocket *ss, SSL3ProtocolVersion version, ssl3CipherSuiteCfg *suiteCfg = &ss->cipherSuites[i]; if (suite == suiteCfg->cipher_suite) { SSLVersionRange vrange = { version, version }; - if (!config_match(suiteCfg, ss->ssl3.policy, &vrange, ss)) { + if (!ssl3_config_match(suiteCfg, ss->ssl3.policy, &vrange, ss)) { /* config_match already checks whether the cipher suite is * acceptable for the version, but the check is repeated here * in order to give a more precise error code. */ @@ -6201,18 +6386,56 @@ ssl_CheckServerSessionIdCorrectness(sslSocket *ss, SECItem *sidBytes) /* TLS 1.2: Session ID shouldn't match if we sent a fake. */ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - return !sentFakeSid || !sidMatch; + if (sentFakeSid) { + return !sidMatch; + } + return PR_TRUE; } /* TLS 1.3: We sent a session ID. The server's should match. */ - if (sentRealSid || sentFakeSid) { + if (!IS_DTLS(ss) && (sentRealSid || sentFakeSid)) { return sidMatch; } - /* TLS 1.3: The server shouldn't send a session ID. */ + /* TLS 1.3 (no SID)/DTLS 1.3: The server shouldn't send a session ID. */ return sidBytes->len == 0; } +static SECStatus +ssl_CheckServerRandom(sslSocket *ss) +{ + /* Check the ServerHello.random per [RFC 8446 Section 4.1.3]. + * + * TLS 1.3 clients receiving a ServerHello indicating TLS 1.2 or below + * MUST check that the last 8 bytes are not equal to either of these + * values. TLS 1.2 clients SHOULD also check that the last 8 bytes are + * not equal to the second value if the ServerHello indicates TLS 1.1 or + * below. If a match is found, the client MUST abort the handshake with + * an "illegal_parameter" alert. + */ + SSL3ProtocolVersion checkVersion = + ss->ssl3.downgradeCheckVersion ? ss->ssl3.downgradeCheckVersion + : ss->vrange.max; + + if (checkVersion >= SSL_LIBRARY_VERSION_TLS_1_2 && + checkVersion > ss->version) { + /* Both sections use the same sentinel region. */ + PRUint8 *downgrade_sentinel = + ss->ssl3.hs.server_random + + SSL3_RANDOM_LENGTH - sizeof(tls13_downgrade_random); + if (!PORT_Memcmp(downgrade_sentinel, + tls13_downgrade_random, + sizeof(tls13_downgrade_random)) || + !PORT_Memcmp(downgrade_sentinel, + tls12_downgrade_random, + sizeof(tls12_downgrade_random))) { + return SECFailure; + } + } + + return SECSuccess; +} + /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete * ssl3 ServerHello message. * Caller must hold Handshake and RecvBuf locks. @@ -6229,9 +6452,6 @@ ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length) SSL3AlertDescription desc = illegal_parameter; const PRUint8 *savedMsg = b; const PRUint32 savedLength = length; -#ifndef TLS_1_3_DRAFT_VERSION - SSL3ProtocolVersion downgradeCheckVersion; -#endif SSL_TRC(3, ("%d: SSL3[%d]: handle server_hello handshake", SSL_GETPID(), ss->fd)); @@ -6341,9 +6561,20 @@ ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length) goto alert_loser; } - /* The server didn't pick 1.3 although we either received a - * HelloRetryRequest, or we prepared to send early app data. */ + /* There are three situations in which the server must pick + * TLS 1.3. + * + * 1. We offered ESNI. + * 2. We received HRR + * 3. We sent early app data. + * + */ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { + if (ss->xtnData.esniPrivateKey) { + desc = protocol_version; + errCode = SSL_ERROR_UNSUPPORTED_VERSION; + goto alert_loser; + } if (isHelloRetry || ss->ssl3.hs.helloRetry) { /* SSL3_SendAlert() will uncache the SID. */ desc = illegal_parameter; @@ -6368,39 +6599,19 @@ ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length) goto alert_loser; } -#ifndef TLS_1_3_DRAFT_VERSION - /* Check the ServerHello.random per - * [draft-ietf-tls-tls13-11 Section 6.3.1.1]. - * - * TLS 1.3 clients receiving a TLS 1.2 or below ServerHello MUST check - * that the top eight octets are not equal to either of these values. - * TLS 1.2 clients SHOULD also perform this check if the ServerHello - * indicates TLS 1.1 or below. If a match is found the client MUST - * abort the handshake with a fatal "illegal_parameter" alert. - * - * Disable this test during the TLS 1.3 draft version period. - */ - downgradeCheckVersion = ss->ssl3.downgradeCheckVersion ? ss->ssl3.downgradeCheckVersion - : ss->vrange.max; - - if (downgradeCheckVersion >= SSL_LIBRARY_VERSION_TLS_1_2 && - downgradeCheckVersion > ss->version) { - /* Both sections use the same sentinel region. */ - PRUint8 *downgrade_sentinel = - ss->ssl3.hs.server_random + - SSL3_RANDOM_LENGTH - sizeof(tls13_downgrade_random); - if (!PORT_Memcmp(downgrade_sentinel, - tls13_downgrade_random, - sizeof(tls13_downgrade_random)) || - !PORT_Memcmp(downgrade_sentinel, - tls12_downgrade_random, - sizeof(tls12_downgrade_random))) { + if (ss->opt.enableHelloDowngradeCheck +#ifdef DTLS_1_3_DRAFT_VERSION + /* Disable this check while we are on draft DTLS 1.3 versions. */ + && !IS_DTLS(ss) +#endif + ) { + rv = ssl_CheckServerRandom(ss); + if (rv != SECSuccess) { desc = illegal_parameter; errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO; goto alert_loser; } } -#endif /* Finally, now all the version-related checks have passed. */ ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version; @@ -6776,12 +6987,12 @@ ssl_HandleDHServerKeyExchange(sslSocket *ss, PRUint8 *b, PRUint32 length) if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) { rv = ssl_ConsumeSignatureScheme(ss, &b, &length, &sigScheme); if (rv != SECSuccess) { - goto loser; /* malformed or unsupported. */ + goto alert_loser; /* malformed or unsupported. */ } rv = ssl_CheckSignatureSchemeConsistency(ss, sigScheme, ss->sec.peerCert); if (rv != SECSuccess) { - goto loser; + goto alert_loser; } hashAlg = ssl_SignatureSchemeToHashType(sigScheme); } else { @@ -7005,7 +7216,8 @@ ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *arena, SECStatus rv; SECItem buf; SSLSignatureScheme *schemes = NULL; - unsigned int numSchemes = 0; + unsigned int numSupported = 0; + unsigned int numRemaining = 0; unsigned int max; rv = ssl3_ExtConsumeHandshakeVariable(ss, &buf, 2, b, len); @@ -7024,7 +7236,8 @@ ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *arena, } /* Limit the number of schemes we read. */ - max = PR_MIN(buf.len / 2, MAX_SIGNATURE_SCHEMES); + numRemaining = buf.len / 2; + max = PR_MIN(numRemaining, MAX_SIGNATURE_SCHEMES); if (arena) { schemes = PORT_ArenaZNewArray(arena, SSLSignatureScheme, max); @@ -7036,7 +7249,7 @@ ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *arena, return SECFailure; } - for (; max; --max) { + for (; numRemaining && numSupported < MAX_SIGNATURE_SCHEMES; --numRemaining) { PRUint32 tmp; rv = ssl3_ExtConsumeHandshakeNumber(ss, &tmp, 2, &buf.data, &buf.len); if (rv != SECSuccess) { @@ -7045,11 +7258,11 @@ ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *arena, return SECFailure; } if (ssl_IsSupportedSignatureScheme((SSLSignatureScheme)tmp)) { - schemes[numSchemes++] = (SSLSignatureScheme)tmp; + schemes[numSupported++] = (SSLSignatureScheme)tmp; } } - if (!numSchemes) { + if (!numSupported) { if (!arena) { PORT_Free(schemes); } @@ -7058,7 +7271,7 @@ ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *arena, done: *schemesOut = schemes; - *numSchemesOut = numSchemes; + *numSchemesOut = numSupported; return SECSuccess; } @@ -7114,6 +7327,11 @@ ssl3_HandleCertificateRequest(sslSocket *ss, PRUint8 *b, PRUint32 length) PORT_SetError(SSL_ERROR_RX_MALFORMED_CERT_REQUEST); goto loser; /* malformed, alert has been sent */ } + if (signatureSchemeCount == 0) { + errCode = SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM; + desc = handshake_failure; + goto alert_loser; + } } rv = ssl3_ParseCertificateRequestCAs(ss, &b, &length, &ca_list); @@ -7239,16 +7457,25 @@ ssl3_CheckFalseStart(sslSocket *ss) SSL_TRC(3, ("%d: SSL[%d]: no false start callback so no false start", SSL_GETPID(), ss->fd)); } else { - PRBool maybeFalseStart; + PRBool maybeFalseStart = PR_TRUE; SECStatus rv; + rv = ssl_CheckServerRandom(ss); + if (rv != SECSuccess) { + SSL_TRC(3, ("%d: SSL[%d]: no false start due to possible downgrade", + SSL_GETPID(), ss->fd)); + maybeFalseStart = PR_FALSE; + } + /* An attacker can control the selected ciphersuite so we only wish to * do False Start in the case that the selected ciphersuite is * sufficiently strong that the attack can gain no advantage. * Therefore we always require an 80-bit cipher. */ - ssl_GetSpecReadLock(ss); - maybeFalseStart = ss->ssl3.cwSpec->cipherDef->secret_key_size >= 10; - ssl_ReleaseSpecReadLock(ss); + if (maybeFalseStart) { + ssl_GetSpecReadLock(ss); + maybeFalseStart = ss->ssl3.cwSpec->cipherDef->secret_key_size >= 10; + ssl_ReleaseSpecReadLock(ss); + } if (!maybeFalseStart) { SSL_TRC(3, ("%d: SSL[%d]: no false start due to weak cipher", @@ -7647,6 +7874,30 @@ ssl3_KEASupportsTickets(const ssl3KEADef *kea_def) return PR_TRUE; } +SECStatus +ssl3_NegotiateCipherSuiteInner(sslSocket *ss, const SECItem *suites, + PRUint16 version, PRUint16 *suitep) +{ + unsigned int j; + unsigned int i; + + for (j = 0; j < ssl_V3_SUITES_IMPLEMENTED; j++) { + ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j]; + SSLVersionRange vrange = { version, version }; + if (!ssl3_config_match(suite, ss->ssl3.policy, &vrange, ss)) { + continue; + } + for (i = 0; i + 1 < suites->len; i += 2) { + PRUint16 suite_i = (suites->data[i] << 8) | suites->data[i + 1]; + if (suite_i == suite->cipher_suite) { + *suitep = suite_i; + return SECSuccess; + } + } + } + return SECFailure; +} + /* Select a cipher suite. ** ** NOTE: This suite selection algorithm should be the same as the one in @@ -7665,24 +7916,16 @@ SECStatus ssl3_NegotiateCipherSuite(sslSocket *ss, const SECItem *suites, PRBool initHashes) { - unsigned int j; - unsigned int i; + PRUint16 selected; + SECStatus rv; - for (j = 0; j < ssl_V3_SUITES_IMPLEMENTED; j++) { - ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j]; - SSLVersionRange vrange = { ss->version, ss->version }; - if (!config_match(suite, ss->ssl3.policy, &vrange, ss)) { - continue; - } - for (i = 0; i + 1 < suites->len; i += 2) { - PRUint16 suite_i = (suites->data[i] << 8) | suites->data[i + 1]; - if (suite_i == suite->cipher_suite) { - ss->ssl3.hs.cipher_suite = suite_i; - return ssl3_SetupCipherSuite(ss, initHashes); - } - } + rv = ssl3_NegotiateCipherSuiteInner(ss, suites, ss->version, &selected); + if (rv != SECSuccess) { + return SECFailure; } - return SECFailure; + + ss->ssl3.hs.cipher_suite = selected; + return ssl3_SetupCipherSuite(ss, initHashes); } /* @@ -7814,9 +8057,12 @@ ssl3_ServerCallSNICallback(sslSocket *ss) } /* Need to tell the client that application has picked * the name from the offered list and reconfigured the socket. + * Don't do this if we negotiated ESNI. */ - ssl3_RegisterExtensionSender(ss, &ss->xtnData, ssl_server_name_xtn, - ssl_SendEmptyExtension); + if (!ssl3_ExtensionNegotiated(ss, ssl_tls13_encrypted_sni_xtn)) { + ssl3_RegisterExtensionSender(ss, &ss->xtnData, ssl_server_name_xtn, + ssl_SendEmptyExtension); + } } else { /* Callback returned index outside of the boundary. */ PORT_Assert((unsigned int)ret < ss->xtnData.sniNameArrSize); @@ -7845,6 +8091,7 @@ ssl3_SelectServerCert(sslSocket *ss) { const ssl3KEADef *kea_def = ss->ssl3.hs.kea_def; PRCList *cursor; + SECStatus rv; /* If the client didn't include the supported groups extension, assume just * P-256 support and disable all the other ECDHE groups. This also affects @@ -7870,30 +8117,102 @@ ssl3_SelectServerCert(sslSocket *ss) cursor != &ss->serverCerts; cursor = PR_NEXT_LINK(cursor)) { sslServerCert *cert = (sslServerCert *)cursor; - if (!SSL_CERT_IS(cert, kea_def->authKeyType)) { - continue; - } - if (SSL_CERT_IS_EC(cert) && - !ssl_NamedGroupEnabled(ss, cert->namedCurve)) { - continue; + if (kea_def->authKeyType == ssl_auth_rsa_sign) { + /* We consider PSS certificates here as well for TLS 1.2. */ + if (!SSL_CERT_IS(cert, ssl_auth_rsa_sign) && + (!SSL_CERT_IS(cert, ssl_auth_rsa_pss) || + ss->version < SSL_LIBRARY_VERSION_TLS_1_2)) { + continue; + } + } else { + if (!SSL_CERT_IS(cert, kea_def->authKeyType)) { + continue; + } + if (SSL_CERT_IS_EC(cert) && + !ssl_NamedGroupEnabled(ss, cert->namedCurve)) { + continue; + } } /* Found one. */ ss->sec.serverCert = cert; - ss->sec.authType = kea_def->authKeyType; ss->sec.authKeyBits = cert->serverKeyBits; /* Don't pick a signature scheme if we aren't going to use it. */ if (kea_def->signKeyType == nullKey) { + ss->sec.authType = kea_def->authKeyType; return SECSuccess; } - return ssl3_PickServerSignatureScheme(ss); + + rv = ssl3_PickServerSignatureScheme(ss); + if (rv != SECSuccess) { + return SECFailure; + } + ss->sec.authType = + ssl_SignatureSchemeToAuthType(ss->ssl3.hs.signatureScheme); + return SECSuccess; } PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); return SECFailure; } +static SECStatus +ssl_GenerateServerRandom(sslSocket *ss) +{ + SECStatus rv = ssl3_GetNewRandom(ss->ssl3.hs.server_random); + if (rv != SECSuccess) { + return SECFailure; + } + + if (ss->version == ss->vrange.max) { + return SECSuccess; + } +#ifdef DTLS_1_3_DRAFT_VERSION + if (IS_DTLS(ss)) { + return SECSuccess; + } +#endif + + /* + * [RFC 8446 Section 4.1.3]. + * + * TLS 1.3 servers which negotiate TLS 1.2 or below in response to a + * ClientHello MUST set the last 8 bytes of their Random value specially in + * their ServerHello. + * + * If negotiating TLS 1.2, TLS 1.3 servers MUST set the last 8 bytes of + * their Random value to the bytes: + * + * 44 4F 57 4E 47 52 44 01 + * + * If negotiating TLS 1.1 or below, TLS 1.3 servers MUST, and TLS 1.2 + * servers SHOULD, set the last 8 bytes of their ServerHello.Random value to + * the bytes: + * + * 44 4F 57 4E 47 52 44 00 + */ + PRUint8 *downgradeSentinel = + ss->ssl3.hs.server_random + + SSL3_RANDOM_LENGTH - sizeof(tls13_downgrade_random); + + switch (ss->vrange.max) { + case SSL_LIBRARY_VERSION_TLS_1_3: + PORT_Memcpy(downgradeSentinel, + tls13_downgrade_random, sizeof(tls13_downgrade_random)); + break; + case SSL_LIBRARY_VERSION_TLS_1_2: + PORT_Memcpy(downgradeSentinel, + tls12_downgrade_random, sizeof(tls12_downgrade_random)); + break; + default: + /* Do not change random. */ + break; + } + + return SECSuccess; +} + /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete * ssl3 Client Hello message. * Caller must hold Handshake and RecvBuf locks. @@ -8088,56 +8407,6 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length) } } - /* Generate the Server Random now so it is available - * when we process the ClientKeyShare in TLS 1.3 */ - rv = ssl3_GetNewRandom(ss->ssl3.hs.server_random); - if (rv != SECSuccess) { - errCode = SSL_ERROR_GENERATE_RANDOM_FAILURE; - goto loser; - } - -#ifndef TLS_1_3_DRAFT_VERSION - /* - * [draft-ietf-tls-tls13-11 Section 6.3.1.1]. - * TLS 1.3 server implementations which respond to a ClientHello with a - * client_version indicating TLS 1.2 or below MUST set the last eight - * bytes of their Random value to the bytes: - * - * 44 4F 57 4E 47 52 44 01 - * - * TLS 1.2 server implementations which respond to a ClientHello with a - * client_version indicating TLS 1.1 or below SHOULD set the last eight - * bytes of their Random value to the bytes: - * - * 44 4F 57 4E 47 52 44 00 - * - * TODO(ekr@rtfm.com): Note this change was not added in the SSLv2 - * compat processing code since that will most likely be removed before - * we ship the final version of TLS 1.3. Bug 1306672. - */ - if (ss->vrange.max > ss->version) { - PRUint8 *downgrade_sentinel = - ss->ssl3.hs.server_random + - SSL3_RANDOM_LENGTH - sizeof(tls13_downgrade_random); - - switch (ss->vrange.max) { - case SSL_LIBRARY_VERSION_TLS_1_3: - PORT_Memcpy(downgrade_sentinel, - tls13_downgrade_random, - sizeof(tls13_downgrade_random)); - break; - case SSL_LIBRARY_VERSION_TLS_1_2: - PORT_Memcpy(downgrade_sentinel, - tls12_downgrade_random, - sizeof(tls12_downgrade_random)); - break; - default: - /* Do not change random. */ - break; - } - } -#endif - /* If there is a cookie, then this is a second ClientHello (TLS 1.3). */ if (ssl3_FindExtension(ss, ssl_tls13_cookie_xtn)) { ss->ssl3.hs.helloRetry = PR_TRUE; @@ -8397,7 +8666,7 @@ ssl3_HandleClientHelloPart2(sslSocket *ss, * The product policy won't change during the process lifetime. * Implemented ("isPresent") shouldn't change for servers. */ - if (!config_match(suite, ss->ssl3.policy, &vrange, ss)) + if (!ssl3_config_match(suite, ss->ssl3.policy, &vrange, ss)) break; #else if (!suite->enabled) @@ -8779,7 +9048,7 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, unsigned int leng for (j = 0; j < ssl_V3_SUITES_IMPLEMENTED; j++) { ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j]; SSLVersionRange vrange = { ss->version, ss->version }; - if (!config_match(suite, ss->ssl3.policy, &vrange, ss)) { + if (!ssl3_config_match(suite, ss->ssl3.policy, &vrange, ss)) { continue; } for (i = 0; i + 2 < suite_length; i += 3) { @@ -8884,6 +9153,7 @@ ssl_ConstructServerHello(sslSocket *ss, PRBool helloRetry, SECStatus rv; SSL3ProtocolVersion version; sslSessionID *sid = ss->sec.ci.sid; + const PRUint8 *random; version = PR_MIN(ss->version, SSL_LIBRARY_VERSION_TLS_1_2); if (IS_DTLS(ss)) { @@ -8893,9 +9163,17 @@ ssl_ConstructServerHello(sslSocket *ss, PRBool helloRetry, if (rv != SECSuccess) { return SECFailure; } - /* Random already generated in ssl3_HandleClientHello */ - rv = sslBuffer_Append(messageBuf, helloRetry ? ssl_hello_retry_random : ss->ssl3.hs.server_random, - SSL3_RANDOM_LENGTH); + + if (helloRetry) { + random = ssl_hello_retry_random; + } else { + rv = ssl_GenerateServerRandom(ss); + if (rv != SECSuccess) { + return SECFailure; + } + random = ss->ssl3.hs.server_random; + } + rv = sslBuffer_Append(messageBuf, random, SSL3_RANDOM_LENGTH); if (rv != SECSuccess) { return SECFailure; } @@ -9368,7 +9646,7 @@ ssl3_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length) ss->sec.peerCert); if (rv != SECSuccess) { errCode = PORT_GetError(); - desc = decrypt_error; + desc = illegal_parameter; goto alert_loser; } @@ -9501,6 +9779,23 @@ ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec, return pms; } +static void +ssl3_CSwapPK11SymKey(PK11SymKey **x, PK11SymKey **y, PRBool c) +{ + uintptr_t mask = (uintptr_t)c; + unsigned int i; + for (i = 1; i < sizeof(uintptr_t) * 8; i <<= 1) { + mask |= mask << i; + } + uintptr_t x_ptr = (uintptr_t)*x; + uintptr_t y_ptr = (uintptr_t)*y; + uintptr_t tmp = (x_ptr ^ y_ptr) & mask; + x_ptr = x_ptr ^ tmp; + y_ptr = y_ptr ^ tmp; + *x = (PK11SymKey *)x_ptr; + *y = (PK11SymKey *)y_ptr; +} + /* Note: The Bleichenbacher attack on PKCS#1 necessitates that we NEVER * return any indication of failure of the Client Key Exchange message, * where that failure is caused by the content of the client's message. @@ -9521,9 +9816,9 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss, { SECStatus rv; SECItem enc_pms; - PK11SymKey *tmpPms[2] = { NULL, NULL }; - PK11SlotInfo *slot; - int useFauxPms = 0; + PK11SymKey *pms = NULL; + PK11SymKey *fauxPms = NULL; + PK11SlotInfo *slot = NULL; PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); @@ -9544,11 +9839,6 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss, } } -#define currentPms tmpPms[!useFauxPms] -#define unusedPms tmpPms[useFauxPms] -#define realPms tmpPms[1] -#define fauxPms tmpPms[0] - /* * Get as close to algorithm 2 from RFC 5246; Section 7.4.7.1 * as we can within the constraints of the PKCS#11 interface. @@ -9603,40 +9893,33 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss, * the unwrap. Rather, it is the mechanism with which the * unwrapped pms will be used. */ - realPms = PK11_PubUnwrapSymKey(serverKeyPair->privKey, &enc_pms, - CKM_SSL3_MASTER_KEY_DERIVE, CKA_DERIVE, 0); + pms = PK11_PubUnwrapSymKey(serverKeyPair->privKey, &enc_pms, + CKM_SSL3_MASTER_KEY_DERIVE, CKA_DERIVE, 0); /* Temporarily use the PMS if unwrapping the real PMS fails. */ - useFauxPms |= (realPms == NULL); + ssl3_CSwapPK11SymKey(&pms, &fauxPms, pms == NULL); /* Attempt to derive the MS from the PMS. This is the only way to * check the version field in the RSA PMS. If this fails, we * then use the faux PMS in place of the PMS. Note that this * operation should never fail if we are using the faux PMS * since it is correctly formatted. */ - rv = ssl3_ComputeMasterSecret(ss, currentPms, NULL); - - /* If we succeeded, then select the true PMS and discard the - * FPMS. Else, select the FPMS and select the true PMS */ - useFauxPms |= (rv != SECSuccess); + rv = ssl3_ComputeMasterSecret(ss, pms, NULL); - if (unusedPms) { - PK11_FreeSymKey(unusedPms); - } + /* If we succeeded, then select the true PMS, else select the FPMS. */ + ssl3_CSwapPK11SymKey(&pms, &fauxPms, (rv != SECSuccess) & (fauxPms != NULL)); /* This step will derive the MS from the PMS, among other things. */ - rv = ssl3_InitPendingCipherSpecs(ss, currentPms, PR_TRUE); - PK11_FreeSymKey(currentPms); + rv = ssl3_InitPendingCipherSpecs(ss, pms, PR_TRUE); + + /* Clear both PMS. */ + PK11_FreeSymKey(pms); + PK11_FreeSymKey(fauxPms); if (rv != SECSuccess) { (void)SSL3_SendAlert(ss, alert_fatal, handshake_failure); return SECFailure; /* error code set by ssl3_InitPendingCipherSpec */ } -#undef currentPms -#undef unusedPms -#undef realPms -#undef fauxPms - return SECSuccess; } @@ -10429,6 +10712,9 @@ ssl3_AuthCertificate(sslSocket *ss) PR_TRUE, isServer); if (rv != SECSuccess) { errCode = PORT_GetError(); + if (errCode == 0) { + errCode = SSL_ERROR_BAD_CERTIFICATE; + } if (rv != SECWouldBlock) { if (ss->handleBadCert) { rv = (*ss->handleBadCert)(ss->badCertArg, ss->fd); @@ -11252,7 +11538,7 @@ ssl3_FinishHandshake(sslSocket *ss) } SECStatus -ssl_HashHandshakeMessageInt(sslSocket *ss, SSLHandshakeType type, +ssl_HashHandshakeMessageInt(sslSocket *ss, SSLHandshakeType ct, PRUint32 dtlsSeq, const PRUint8 *b, PRUint32 length) { @@ -11262,7 +11548,7 @@ ssl_HashHandshakeMessageInt(sslSocket *ss, SSLHandshakeType type, PRINT_BUF(50, (ss, "Hash handshake message:", b, length)); - hdr[0] = (PRUint8)type; + hdr[0] = (PRUint8)ct; hdr[1] = (PRUint8)(length >> 16); hdr[2] = (PRUint8)(length >> 8); hdr[3] = (PRUint8)(length); @@ -11302,10 +11588,10 @@ ssl_HashHandshakeMessageInt(sslSocket *ss, SSLHandshakeType type, } SECStatus -ssl_HashHandshakeMessage(sslSocket *ss, SSLHandshakeType type, +ssl_HashHandshakeMessage(sslSocket *ss, SSLHandshakeType ct, const PRUint8 *b, PRUint32 length) { - return ssl_HashHandshakeMessageInt(ss, type, ss->ssl3.hs.recvMessageSeq, + return ssl_HashHandshakeMessageInt(ss, ct, ss->ssl3.hs.recvMessageSeq, b, length); } @@ -11885,7 +12171,7 @@ ssl3_UnprotectRecord(sslSocket *ss, PRBool isTLS; unsigned int good; unsigned int ivLen = 0; - SSL3ContentType rType; + SSLContentType rType; SSL3ProtocolVersion rVersion; unsigned int minLength; unsigned int originalLen = 0; @@ -11959,7 +12245,7 @@ ssl3_UnprotectRecord(sslSocket *ss, return SECFailure; } - rType = (SSL3ContentType)cText->hdr[0]; + rType = (SSLContentType)cText->hdr[0]; rVersion = ((SSL3ProtocolVersion)cText->hdr[1] << 8) | (SSL3ProtocolVersion)cText->hdr[2]; if (cipher_def->type == type_aead) { @@ -12071,7 +12357,7 @@ ssl3_UnprotectRecord(sslSocket *ss, } SECStatus -ssl3_HandleNonApplicationData(sslSocket *ss, SSL3ContentType rType, +ssl3_HandleNonApplicationData(sslSocket *ss, SSLContentType rType, DTLSEpoch epoch, sslSequenceNumber seqNum, sslBuffer *databuf) { @@ -12089,20 +12375,20 @@ ssl3_HandleNonApplicationData(sslSocket *ss, SSL3ContentType rType, ** they return SECFailure or SECWouldBlock. */ switch (rType) { - case content_change_cipher_spec: + case ssl_ct_change_cipher_spec: rv = ssl3_HandleChangeCipherSpecs(ss, databuf); break; - case content_alert: + case ssl_ct_alert: rv = ssl3_HandleAlert(ss, databuf); break; - case content_handshake: + case ssl_ct_handshake: if (!IS_DTLS(ss)) { rv = ssl3_HandleHandshake(ss, databuf); } else { rv = dtls_HandleHandshake(ss, epoch, seqNum, databuf); } break; - case content_ack: + case ssl_ct_ack: if (IS_DTLS(ss) && tls13_MaybeTls13(ss)) { rv = dtls13_HandleAck(ss, databuf); break; @@ -12190,7 +12476,7 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText) ssl3CipherSpec *spec = NULL; PRUint16 recordSizeLimit; PRBool outOfOrderSpec = PR_FALSE; - SSL3ContentType rType; + SSLContentType rType; sslBuffer *plaintext = &ss->gs.buf; SSL3AlertDescription alert = internal_error; PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); @@ -12208,7 +12494,7 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText) /* We're waiting for another ClientHello, which will appear unencrypted. * Use the content type to tell whether this should be discarded. */ if (ss->ssl3.hs.zeroRttIgnore == ssl_0rtt_ignore_hrr && - cText->hdr[0] == content_application_data) { + cText->hdr[0] == ssl_ct_application_data) { PORT_Assert(ss->ssl3.hs.ws == wait_client_hello); return SECSuccess; } @@ -12269,7 +12555,7 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText) /* Encrypted application data records could arrive before the handshake * completes in DTLS 1.3. These can look like valid TLS 1.2 application_data * records in epoch 0, which is never valid. Pretend they didn't decrypt. */ - if (spec->epoch == 0 && rType == content_application_data) { + if (spec->epoch == 0 && rType == ssl_ct_application_data) { PORT_SetError(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA); alert = unexpected_message; rv = SECFailure; @@ -12304,7 +12590,7 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText) * 0-RTT session that is resumed from a session that did negotiate it. * We don't care about that corner case right now. */ if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 && - cText->hdr[0] == content_change_cipher_spec && + cText->hdr[0] == ssl_ct_change_cipher_spec && ss->ssl3.hs.ws != idle_handshake && cText->buf->len == 1 && cText->buf->buf[0] == change_cipher_spec_choice) { @@ -12364,7 +12650,7 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText) /* Application data records are processed by the caller of this ** function, not by this function. */ - if (rType == content_application_data) { + if (rType == ssl_ct_application_data) { if (ss->firstHsDone) return SECSuccess; if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 && diff --git a/security/nss/lib/ssl/ssl3ecc.c b/security/nss/lib/ssl/ssl3ecc.c index f8b9a9400..52d5bb515 100644 --- a/security/nss/lib/ssl/ssl3ecc.c +++ b/security/nss/lib/ssl/ssl3ecc.c @@ -327,16 +327,13 @@ ssl3_HandleECDHClientKeyExchange(sslSocket *ss, PRUint8 *b, ** Take an encoded key share and make a public key out of it. */ SECStatus -ssl_ImportECDHKeyShare(sslSocket *ss, SECKEYPublicKey *peerKey, +ssl_ImportECDHKeyShare(SECKEYPublicKey *peerKey, PRUint8 *b, PRUint32 length, const sslNamedGroupDef *ecGroup) { SECStatus rv; SECItem ecPoint = { siBuffer, NULL, 0 }; - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - if (!length) { PORT_SetError(SSL_ERROR_RX_MALFORMED_ECDHE_KEY_SHARE); return SECFailure; @@ -616,7 +613,7 @@ ssl3_HandleECDHServerKeyExchange(sslSocket *ss, PRUint8 *b, PRUint32 length) peerKey->arena = arena; /* create public key from point data */ - rv = ssl_ImportECDHKeyShare(ss, peerKey, ec_point.data, ec_point.len, + rv = ssl_ImportECDHKeyShare(peerKey, ec_point.data, ec_point.len, ecGroup); if (rv != SECSuccess) { /* error code is set */ diff --git a/security/nss/lib/ssl/ssl3ext.c b/security/nss/lib/ssl/ssl3ext.c index 9b6c719f8..60b5889e7 100644 --- a/security/nss/lib/ssl/ssl3ext.c +++ b/security/nss/lib/ssl/ssl3ext.c @@ -50,6 +50,7 @@ static const ssl3ExtensionHandler clientHelloHandlers[] = { { ssl_tls13_early_data_xtn, &tls13_ServerHandleEarlyDataXtn }, { ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ServerHandlePskModesXtn }, { ssl_tls13_cookie_xtn, &tls13_ServerHandleCookieXtn }, + { ssl_tls13_encrypted_sni_xtn, &tls13_ServerHandleEsniXtn }, { ssl_record_size_limit_xtn, &ssl_HandleRecordSizeLimitXtn }, { 0, NULL } }; @@ -136,6 +137,7 @@ static const sslExtensionBuilder clientHelloSendersTLS[] = { ssl_signature_algorithms_xtn, &ssl3_SendSigAlgsXtn }, { ssl_tls13_cookie_xtn, &tls13_ClientSendHrrCookieXtn }, { ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ClientSendPskModesXtn }, + { ssl_tls13_encrypted_sni_xtn, &tls13_ClientSendEsniXtn }, { ssl_record_size_limit_xtn, &ssl_SendRecordSizeLimitXtn }, /* The pre_shared_key extension MUST be last. */ { ssl_tls13_pre_shared_key_xtn, &tls13_ClientSendPreSharedKeyXtn }, @@ -338,8 +340,6 @@ ssl3_ParseExtensions(sslSocket *ss, PRUint8 **b, PRUint32 *length) return SECFailure; /* alert already sent */ } - SSL_TRC(10, ("%d: SSL3[%d]: parsing extension %d", - SSL_GETPID(), ss->fd, extension_type)); /* Check whether an extension has been sent multiple times. */ for (cursor = PR_NEXT_LINK(&ss->ssl3.hs.remoteExtensions); cursor != &ss->ssl3.hs.remoteExtensions; @@ -357,6 +357,9 @@ ssl3_ParseExtensions(sslSocket *ss, PRUint8 **b, PRUint32 *length) return rv; /* alert already sent */ } + SSL_TRC(10, ("%d: SSL3[%d]: parsed extension %d len=%u", + SSL_GETPID(), ss->fd, extension_type, extension_data.len)); + extension = PORT_ZNew(TLSExtension); if (!extension) { return SECFailure; @@ -409,7 +412,9 @@ ssl_CallExtensionHandler(sslSocket *ss, SSLHandshakeType handshakeMessage, /* Find extension_type in table of Hello Extension Handlers. */ for (; handler->ex_handler != NULL; ++handler) { if (handler->ex_type == extension->type) { - rv = (*handler->ex_handler)(ss, &ss->xtnData, &extension->data); + SECItem tmp = extension->data; + + rv = (*handler->ex_handler)(ss, &ss->xtnData, &tmp); break; } } @@ -960,6 +965,8 @@ ssl3_DestroyExtensionData(TLSExtensionData *xtnData) xtnData->certReqAuthorities.arena = NULL; } PORT_Free(xtnData->advertised); + ssl_FreeEphemeralKeyPair(xtnData->esniPrivateKey); + SECITEM_FreeItem(&xtnData->keyShareExtension, PR_FALSE); } /* Free everything that has been allocated and then reset back to diff --git a/security/nss/lib/ssl/ssl3ext.h b/security/nss/lib/ssl/ssl3ext.h index 6d77c7459..d96b4cffe 100644 --- a/security/nss/lib/ssl/ssl3ext.h +++ b/security/nss/lib/ssl/ssl3ext.h @@ -11,6 +11,8 @@ #include "sslencode.h" +#define TLS13_ESNI_NONCE_SIZE 16 + typedef enum { sni_nametype_hostname } SNINameType; @@ -101,6 +103,14 @@ struct TLSExtensionDataStr { /* The record size limit set by the peer. Our value is kept in ss->opt. */ PRUint16 recordSizeLimit; + + /* ESNI working state */ + SECItem keyShareExtension; + ssl3CipherSuite esniSuite; + sslEphemeralKeyPair *esniPrivateKey; + /* Pointer into |ss->esniKeys->keyShares| */ + TLS13KeyShareEntry *peerEsniShare; + PRUint8 esniNonce[TLS13_ESNI_NONCE_SIZE]; }; typedef struct TLSExtensionStr { diff --git a/security/nss/lib/ssl/ssl3exthandle.c b/security/nss/lib/ssl/ssl3exthandle.c index d1f286dc3..a2d83fa97 100644 --- a/security/nss/lib/ssl/ssl3exthandle.c +++ b/security/nss/lib/ssl/ssl3exthandle.c @@ -15,30 +15,40 @@ #include "selfencrypt.h" #include "ssl3ext.h" #include "ssl3exthandle.h" +#include "tls13esni.h" #include "tls13exthandle.h" /* For tls13_ServerSendStatusRequestXtn. */ +PRBool +ssl_ShouldSendSNIExtension(const sslSocket *ss, const char *url) +{ + PRNetAddr netAddr; + + /* must have a hostname */ + if (!url || !url[0]) { + return PR_FALSE; + } + /* must not be an IPv4 or IPv6 address */ + if (PR_SUCCESS == PR_StringToNetAddr(url, &netAddr)) { + /* is an IP address (v4 or v6) */ + return PR_FALSE; + } + + return PR_TRUE; +} + /* Format an SNI extension, using the name from the socket's URL, * unless that name is a dotted decimal string. * Used by client and server. */ SECStatus -ssl3_ClientSendServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +ssl3_ClientFormatServerNameXtn(const sslSocket *ss, const char *url, + TLSExtensionData *xtnData, + sslBuffer *buf) { unsigned int len; - PRNetAddr netAddr; SECStatus rv; - /* must have a hostname */ - if (!ss->url || !ss->url[0]) { - return SECSuccess; - } - /* must not be an IPv4 or IPv6 address */ - if (PR_SUCCESS == PR_StringToNetAddr(ss->url, &netAddr)) { - /* is an IP address (v4 or v6) */ - return SECSuccess; - } - len = PORT_Strlen(ss->url); + len = PORT_Strlen(url); /* length of server_name_list */ rv = sslBuffer_AppendNumber(buf, len + 3, 2); if (rv != SECSuccess) { @@ -50,7 +60,33 @@ ssl3_ClientSendServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, return SECFailure; } /* HostName (length and value) */ - rv = sslBuffer_AppendVariable(buf, (const PRUint8 *)ss->url, len, 2); + rv = sslBuffer_AppendVariable(buf, (const PRUint8 *)url, len, 2); + if (rv != SECSuccess) { + return SECFailure; + } + + return SECSuccess; +} + +SECStatus +ssl3_ClientSendServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) +{ + SECStatus rv; + + const char *url = ss->url; + + /* We only make an ESNI private key if we are going to + * send ESNI. */ + if (ss->xtnData.esniPrivateKey != NULL) { + url = ss->esniKeys->dummySni; + } + + if (!ssl_ShouldSendSNIExtension(ss, url)) { + return SECSuccess; + } + + rv = ssl3_ClientFormatServerNameXtn(ss, url, xtnData, buf); if (rv != SECSuccess) { return SECFailure; } @@ -59,7 +95,6 @@ ssl3_ClientSendServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, return SECSuccess; } -/* Handle an incoming SNI extension. */ SECStatus ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data) @@ -72,6 +107,13 @@ ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, return SECSuccess; /* ignore extension */ } + if (ssl3_ExtensionNegotiated(ss, ssl_tls13_encrypted_sni_xtn)) { + /* If we already have ESNI, make sure we don't overwrite + * the value. */ + PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); + return SECSuccess; + } + /* Server side - consume client data and register server sender. */ /* do not parse the data if don't have user extension handling function. */ if (!ss->sniSocketConfig) { @@ -1174,17 +1216,18 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, const SECItem *ticket, &decryptedTicket.len, decryptedTicket.len); if (rv != SECSuccess) { - SECITEM_ZfreeItem(&decryptedTicket, PR_FALSE); - - /* Fail with no ticket if we're not a recipient. Otherwise - * it's a hard failure. */ - if (PORT_GetError() != SEC_ERROR_NOT_A_RECIPIENT) { - SSL3_SendAlert(ss, alert_fatal, illegal_parameter); - return SECFailure; + /* Ignore decryption failure if we are doing TLS 1.3; that + * means the server rejects the client's resumption + * attempt. In TLS 1.2, however, it's a hard failure, unless + * it's just because we're not the recipient of the ticket. */ + if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 || + PORT_GetError() == SEC_ERROR_NOT_A_RECIPIENT) { + SECITEM_ZfreeItem(&decryptedTicket, PR_FALSE); + return SECSuccess; } - /* We didn't have the right key, so pretend we don't have a - * ticket. */ + SSL3_SendAlert(ss, alert_fatal, illegal_parameter); + goto loser; } rv = ssl_ParseSessionTicket(ss, &decryptedTicket, &parsedTicket); diff --git a/security/nss/lib/ssl/ssl3exthandle.h b/security/nss/lib/ssl/ssl3exthandle.h index eaf7f0081..3e9b418cf 100644 --- a/security/nss/lib/ssl/ssl3exthandle.h +++ b/security/nss/lib/ssl/ssl3exthandle.h @@ -91,6 +91,10 @@ SECStatus ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, SECItem *data); SECStatus ssl3_ProcessSessionTicketCommon(sslSocket *ss, const SECItem *ticket, /* out */ SECItem *appToken); +PRBool ssl_ShouldSendSNIExtension(const sslSocket *ss, const char *url); +SECStatus ssl3_ClientFormatServerNameXtn(const sslSocket *ss, const char *url, + TLSExtensionData *xtnData, + sslBuffer *buf); SECStatus ssl3_ClientSendServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, sslBuffer *buf, PRBool *added); diff --git a/security/nss/lib/ssl/ssl3gthr.c b/security/nss/lib/ssl/ssl3gthr.c index 5ea7cc249..64a1878f7 100644 --- a/security/nss/lib/ssl/ssl3gthr.c +++ b/security/nss/lib/ssl/ssl3gthr.c @@ -60,8 +60,8 @@ ssl3_isLikelyV3Hello(const unsigned char *buf) } /* Check for a typical V3 record header. */ - return (PRBool)(buf[0] >= content_change_cipher_spec && - buf[0] <= content_application_data && + return (PRBool)(buf[0] >= ssl_ct_change_cipher_spec && + buf[0] <= ssl_ct_application_data && buf[1] == MSB(SSL_LIBRARY_VERSION_3_0)); } @@ -314,7 +314,7 @@ dtls_GatherData(sslSocket *ss, sslGather *gs, int flags) contentType = gs->dtlsPacket.buf[gs->dtlsPacketOffset]; if (dtls_IsLongHeader(ss->version, contentType)) { headerLen = 13; - } else if (contentType == content_application_data) { + } else if (contentType == ssl_ct_application_data) { headerLen = 7; } else if ((contentType & 0xe0) == 0x20) { headerLen = 2; @@ -463,15 +463,15 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags) SSL_DBG(("%d: SSL3[%d]: resuming handshake", SSL_GETPID(), ss->fd)); PORT_Assert(!IS_DTLS(ss)); - rv = ssl3_HandleNonApplicationData(ss, content_handshake, + rv = ssl3_HandleNonApplicationData(ss, ssl_ct_handshake, 0, 0, &ss->gs.buf); } else { /* State for SSLv2 client hello support. */ ssl2Gather ssl2gs = { PR_FALSE, 0 }; ssl2Gather *ssl2gs_ptr = NULL; - /* If we're a server and waiting for a client hello, accept v2. */ - if (ss->sec.isServer && ss->ssl3.hs.ws == wait_client_hello) { + if (ss->sec.isServer && ss->opt.enableV2CompatibleHello && + ss->ssl3.hs.ws == wait_client_hello) { ssl2gs_ptr = &ssl2gs; } @@ -484,8 +484,8 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags) } if (!IS_DTLS(ss)) { - /* If we're a server waiting for a ClientHello then pass - * ssl2gs to support SSLv2 ClientHello messages. */ + /* Passing a non-NULL ssl2gs here enables detection of + * SSLv2-compatible ClientHello messages. */ rv = ssl3_GatherData(ss, &ss->gs, flags, ssl2gs_ptr); } else { rv = dtls_GatherData(ss, &ss->gs, flags); diff --git a/security/nss/lib/ssl/ssl3prot.h b/security/nss/lib/ssl/ssl3prot.h index 8e6cf2745..bfaa10d3f 100644 --- a/security/nss/lib/ssl/ssl3prot.h +++ b/security/nss/lib/ssl/ssl3prot.h @@ -13,10 +13,8 @@ typedef PRUint16 SSL3ProtocolVersion; /* version numbers are defined in sslproto.h */ -/* The TLS 1.3 draft version. Used to avoid negotiating - * between incompatible pre-standard TLS 1.3 drafts. - * TODO(ekr@rtfm.com): Remove when TLS 1.3 is published. */ -#define TLS_1_3_DRAFT_VERSION 28 +/* DTLS 1.3 is still a draft. */ +#define DTLS_1_3_DRAFT_VERSION 28 typedef PRUint16 ssl3CipherSuite; /* The cipher suites are defined in sslproto.h */ @@ -35,15 +33,6 @@ typedef PRUint16 ssl3CipherSuite; #define MAX_FRAGMENT_LENGTH 16384 -typedef enum { - content_change_cipher_spec = 20, - content_alert = 21, - content_handshake = 22, - content_application_data = 23, - content_alt_handshake = 24, - content_ack = 25 -} SSL3ContentType; - typedef enum { change_cipher_spec_choice = 1 } SSL3ChangeCipherSpecChoice; typedef enum { alert_warning = 1, diff --git a/security/nss/lib/ssl/sslcert.c b/security/nss/lib/ssl/sslcert.c index 1c3ddb0e7..878df761e 100644 --- a/security/nss/lib/ssl/sslcert.c +++ b/security/nss/lib/ssl/sslcert.c @@ -436,8 +436,6 @@ ssl_GetCertificateAuthTypes(CERTCertificate *cert, SSLAuthType targetAuthType) case SEC_OID_PKCS1_RSA_ENCRYPTION: if (cert->keyUsage & KU_DIGITAL_SIGNATURE) { authTypes |= 1 << ssl_auth_rsa_sign; - /* This certificate is RSA, assume that it's also PSS. */ - authTypes |= 1 << ssl_auth_rsa_pss; } if (cert->keyUsage & KU_KEY_ENCIPHERMENT) { diff --git a/security/nss/lib/ssl/sslerr.h b/security/nss/lib/ssl/sslerr.h index 518a2b887..a4aa27657 100644 --- a/security/nss/lib/ssl/sslerr.h +++ b/security/nss/lib/ssl/sslerr.h @@ -264,6 +264,10 @@ typedef enum { SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR = (SSL_ERROR_BASE + 173), SSL_ERROR_RX_MALFORMED_DTLS_ACK = (SSL_ERROR_BASE + 174), SSL_ERROR_DH_KEY_TOO_LONG = (SSL_ERROR_BASE + 175), + SSL_ERROR_RX_MALFORMED_ESNI_KEYS = (SSL_ERROR_BASE + 176), + SSL_ERROR_RX_MALFORMED_ESNI_EXTENSION = (SSL_ERROR_BASE + 177), + SSL_ERROR_MISSING_ESNI_EXTENSION = (SSL_ERROR_BASE + 178), + SSL_ERROR_RX_UNEXPECTED_RECORD_TYPE = (SSL_ERROR_BASE + 179), SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */ } SSLErrorCodes; #endif /* NO_SECURITY_ERROR_ENUM */ diff --git a/security/nss/lib/ssl/sslexp.h b/security/nss/lib/ssl/sslexp.h index 08654f885..f450e528d 100644 --- a/security/nss/lib/ssl/sslexp.h +++ b/security/nss/lib/ssl/sslexp.h @@ -367,6 +367,7 @@ typedef struct SSLResumptionTokenInfoStr { PRUint8 *alpnSelection; PRUint32 alpnSelectionLen; PRUint32 maxEarlyDataSize; + PRTime expirationTime; /* added in NSS 3.41 */ } SSLResumptionTokenInfo; /* @@ -452,8 +453,65 @@ typedef SECStatus(PR_CALLBACK *SSLResumptionTokenCallback)( (PRFileDesc * _fd, PRUint32 _size), \ (fd, size)) -/* Deprecated experimental APIs */ +/* Set the ESNI key pair on a socket (server side) + * + * fd -- the socket + * record/recordLen -- the encoded DNS record (not base64) + * + * Important: the suites that are advertised in the record must + * be configured on, or this call will fail. + */ +#define SSL_SetESNIKeyPair(fd, \ + privKey, record, recordLen) \ + SSL_EXPERIMENTAL_API("SSL_SetESNIKeyPair", \ + (PRFileDesc * _fd, \ + SECKEYPrivateKey * _privKey, \ + const PRUint8 *_record, unsigned int _recordLen), \ + (fd, privKey, \ + record, recordLen)) +/* Set the ESNI keys on a client + * + * fd -- the socket + * ensikeys/esniKeysLen -- the ESNI key structure (not base64) + * dummyESNI -- the dummy ESNI to use (if any) + */ +#define SSL_EnableESNI(fd, esniKeys, esniKeysLen, dummySNI) \ + SSL_EXPERIMENTAL_API("SSL_EnableESNI", \ + (PRFileDesc * _fd, \ + const PRUint8 *_esniKeys, \ + unsigned int _esniKeysLen, \ + const char *_dummySNI), \ + (fd, esniKeys, esniKeysLen, dummySNI)) + +/* + * Generate an encoded ESNIKeys structure (presumably server side). + * + * cipherSuites -- the cipher suites that can be used + * cipherSuitesCount -- the number of suites in cipherSuites + * group -- the named group this key corresponds to + * pubKey -- the public key for the key pair + * pad -- the length to pad to + * notBefore/notAfter -- validity range + * out/outlen/maxlen -- where to output the data + */ +#define SSL_EncodeESNIKeys(cipherSuites, cipherSuiteCount, \ + group, pubKey, pad, notBefore, notAfter, \ + out, outlen, maxlen) \ + SSL_EXPERIMENTAL_API("SSL_EncodeESNIKeys", \ + (PRUint16 * _cipherSuites, \ + unsigned int _cipherSuiteCount, \ + SSLNamedGroup _group, \ + SECKEYPublicKey *_pubKey, \ + PRUint16 _pad, \ + PRUint64 _notBefore, PRUint64 _notAfter, \ + PRUint8 *_out, unsigned int *_outlen, \ + unsigned int _maxlen), \ + (cipherSuites, cipherSuiteCount, \ + group, pubKey, pad, notBefore, notAfter, \ + out, outlen, maxlen)) + +/* Deprecated experimental APIs */ #define SSL_UseAltServerHelloType(fd, enable) SSL_DEPRECATED_EXPERIMENTAL_API SEC_END_PROTOS diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h index a2209e90a..35240d2fb 100644 --- a/security/nss/lib/ssl/sslimpl.h +++ b/security/nss/lib/ssl/sslimpl.h @@ -36,6 +36,10 @@ typedef struct sslSocketStr sslSocket; typedef struct sslNamedGroupDefStr sslNamedGroupDef; +typedef struct sslEsniKeysStr sslEsniKeys; +typedef struct sslEphemeralKeyPairStr sslEphemeralKeyPair; +typedef struct TLS13KeyShareEntryStr TLS13KeyShareEntry; + #include "sslencode.h" #include "sslexp.h" #include "ssl3ext.h" @@ -230,7 +234,7 @@ typedef struct { #define MAX_DTLS_SRTP_CIPHER_SUITES 4 /* MAX_SIGNATURE_SCHEMES allows for all the values we support. */ -#define MAX_SIGNATURE_SCHEMES 15 +#define MAX_SIGNATURE_SCHEMES 18 typedef struct sslOptionsStr { /* If SSL_SetNextProtoNego has been called, then this contains the @@ -266,6 +270,8 @@ typedef struct sslOptionsStr { unsigned int enable0RttData : 1; unsigned int enableTls13CompatMode : 1; unsigned int enableDtlsShortHeader : 1; + unsigned int enableHelloDowngradeCheck : 1; + unsigned int enableV2CompatibleHello : 1; } sslOptions; typedef enum { sslHandshakingUndetermined = 0, @@ -552,16 +558,16 @@ typedef SECStatus (*sslRestartTarget)(sslSocket *); typedef struct DTLSQueuedMessageStr { PRCList link; /* The linked list link */ ssl3CipherSpec *cwSpec; /* The cipher spec to use, null for none */ - SSL3ContentType type; /* The message type */ + SSLContentType type; /* The message type */ unsigned char *data; /* The data */ PRUint16 len; /* The data length */ } DTLSQueuedMessage; -typedef struct TLS13KeyShareEntryStr { +struct TLS13KeyShareEntryStr { PRCList link; /* The linked list link */ const sslNamedGroupDef *group; /* The group for the entry */ SECItem key_exchange; /* The share itself */ -} TLS13KeyShareEntry; +}; typedef struct TLS13EarlyDataStr { PRCList link; /* The linked list link */ @@ -803,11 +809,11 @@ struct sslKeyPairStr { PRInt32 refCount; /* use PR_Atomic calls for this. */ }; -typedef struct { +struct sslEphemeralKeyPairStr { PRCList link; const sslNamedGroupDef *group; sslKeyPair *keys; -} sslEphemeralKeyPair; +}; struct ssl3DHParamsStr { SSLNamedGroup name; @@ -1064,6 +1070,10 @@ struct sslSocketStr { /* Whether we are doing stream or datagram mode */ SSLProtocolVariant protocolVariant; + + /* The information from the ESNI keys record + * (also the private key for the server). */ + sslEsniKeys *esniKeys; }; struct sslSelfEncryptKeysStr { @@ -1168,11 +1178,13 @@ extern int ssl_Do1stHandshake(sslSocket *ss); extern SECStatus ssl3_InitPendingCipherSpecs(sslSocket *ss, PK11SymKey *secret, PRBool derive); +extern void ssl_DestroyKeyMaterial(ssl3KeyMaterial *keyMaterial); extern sslSessionID *ssl3_NewSessionID(sslSocket *ss, PRBool is_server); extern sslSessionID *ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID, const char *urlSvrName); extern void ssl_FreeSID(sslSessionID *sid); extern void ssl_DestroySID(sslSessionID *sid, PRBool freeIt); +extern sslSessionID *ssl_ReferenceSID(sslSessionID *sid); extern int ssl3_SendApplicationData(sslSocket *ss, const PRUint8 *in, int len, int flags); @@ -1215,7 +1227,7 @@ SECStatus ssl_HashHandshakeMessage(sslSocket *ss, SSLHandshakeType type, extern PRBool ssl3_WaitingForServerSecondRound(sslSocket *ss); extern PRInt32 ssl3_SendRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, - SSL3ContentType type, + SSLContentType type, const PRUint8 *pIn, PRInt32 nIn, PRInt32 flags); @@ -1387,7 +1399,7 @@ SECStatus ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type); * input into the SSL3 machinery from the actualy network reading code */ SECStatus ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cipher); -SECStatus ssl3_HandleNonApplicationData(sslSocket *ss, SSL3ContentType rType, +SECStatus ssl3_HandleNonApplicationData(sslSocket *ss, SSLContentType rType, DTLSEpoch epoch, sslSequenceNumber seqNum, sslBuffer *databuf); @@ -1497,7 +1509,7 @@ extern SECStatus ssl3_HandleECDHClientKeyExchange(sslSocket *ss, sslKeyPair *serverKeys); extern SECStatus ssl3_SendECDHServerKeyExchange(sslSocket *ss); extern SECStatus ssl_ImportECDHKeyShare( - sslSocket *ss, SECKEYPublicKey *peerKey, + SECKEYPublicKey *peerKey, PRUint8 *b, PRUint32 length, const sslNamedGroupDef *curve); extern SECStatus ssl3_ComputeCommonKeyHash(SSLHashType hashAlg, @@ -1562,6 +1574,12 @@ extern void ssl_FreePRSocket(PRFileDesc *fd); * various ciphers */ extern unsigned int ssl3_config_match_init(sslSocket *); +/* Return PR_TRUE if suite is usable. This if the suite is permitted by policy, + * enabled, has a certificate (as needed), has a viable key agreement method, is + * usable with the negotiated TLS version, and is otherwise usable. */ +PRBool ssl3_config_match(const ssl3CipherSuiteCfg *suite, PRUint8 policy, + const SSLVersionRange *vrange, const sslSocket *ss); + /* calls for accessing wrapping keys across processes. */ extern SECStatus ssl_GetWrappingKey(unsigned int symWrapMechIndex, unsigned int wrapKeyIndex, @@ -1591,6 +1609,8 @@ extern SECStatus ssl_InitSessionCacheLocks(PRBool lazyInit); extern SECStatus ssl_FreeSessionCacheLocks(void); CK_MECHANISM_TYPE ssl3_Alg2Mech(SSLCipherAlgorithm calg); +SECStatus ssl3_NegotiateCipherSuiteInner(sslSocket *ss, const SECItem *suites, + PRUint16 version, PRUint16 *suitep); SECStatus ssl3_NegotiateCipherSuite(sslSocket *ss, const SECItem *suites, PRBool initHashes); SECStatus ssl3_InitHandshakeHashes(sslSocket *ss); @@ -1638,8 +1658,12 @@ PK11SymKey *ssl3_GetWrappingKey(sslSocket *ss, SECStatus ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid, PK11SymKey *secret); const ssl3CipherSuiteDef *ssl_LookupCipherSuiteDef(ssl3CipherSuite suite); +const ssl3CipherSuiteCfg *ssl_LookupCipherSuiteCfg(ssl3CipherSuite suite, + const ssl3CipherSuiteCfg *suites); + SECStatus ssl3_SelectServerCert(sslSocket *ss); SECStatus ssl_PickSignatureScheme(sslSocket *ss, + CERTCertificate *cert, SECKEYPublicKey *pubKey, SECKEYPrivateKey *privKey, const SSLSignatureScheme *peerSchemes, @@ -1647,11 +1671,11 @@ SECStatus ssl_PickSignatureScheme(sslSocket *ss, PRBool requireSha1); SECOidTag ssl3_HashTypeToOID(SSLHashType hashType); SSLHashType ssl_SignatureSchemeToHashType(SSLSignatureScheme scheme); -KeyType ssl_SignatureSchemeToKeyType(SSLSignatureScheme scheme); +SSLAuthType ssl_SignatureSchemeToAuthType(SSLSignatureScheme scheme); SECStatus ssl3_SetupCipherSuite(sslSocket *ss, PRBool initHashes); SECStatus ssl_InsertRecordHeader(const sslSocket *ss, ssl3CipherSpec *cwSpec, - SSL3ContentType contentType, sslBuffer *wrBuf, + SSLContentType contentType, sslBuffer *wrBuf, PRBool *needsLength); /* Pull in DTLS functions */ @@ -1703,7 +1727,7 @@ void ssl_Trace(const char *format, ...); void ssl_CacheExternalToken(sslSocket *ss); SECStatus ssl_DecodeResumptionToken(sslSessionID *sid, const PRUint8 *encodedTicket, PRUint32 encodedTicketLen); -PRBool ssl_IsResumptionTokenValid(sslSocket *ss); +PRBool ssl_IsResumptionTokenUsable(sslSocket *ss, sslSessionID *sid); /* Remove when stable. */ diff --git a/security/nss/lib/ssl/sslnonce.c b/security/nss/lib/ssl/sslnonce.c index f79c23fc7..f8fb5d50f 100644 --- a/security/nss/lib/ssl/sslnonce.c +++ b/security/nss/lib/ssl/sslnonce.c @@ -234,9 +234,20 @@ ssl_FreeLockedSID(sslSessionID *sid) void ssl_FreeSID(sslSessionID *sid) { + if (sid) { + LOCK_CACHE; + ssl_FreeLockedSID(sid); + UNLOCK_CACHE; + } +} + +sslSessionID * +ssl_ReferenceSID(sslSessionID *sid) +{ LOCK_CACHE; - ssl_FreeLockedSID(sid); + sid->references++; UNLOCK_CACHE; + return sid; } /************************************************************************/ @@ -704,10 +715,9 @@ ssl_DecodeResumptionToken(sslSessionID *sid, const PRUint8 *encodedToken, } PRBool -ssl_IsResumptionTokenValid(sslSocket *ss) +ssl_IsResumptionTokenUsable(sslSocket *ss, sslSessionID *sid) { PORT_Assert(ss); - sslSessionID *sid = ss->sec.ci.sid; PORT_Assert(sid); // Check that the ticket didn't expire. @@ -1093,10 +1103,12 @@ ssl_CacheExternalToken(sslSocket *ss) PRINT_BUF(40, (ss, "SSL: encoded resumption token", SSL_BUFFER_BASE(&encodedToken), SSL_BUFFER_LEN(&encodedToken))); - ss->resumptionTokenCallback(ss->fd, SSL_BUFFER_BASE(&encodedToken), - SSL_BUFFER_LEN(&encodedToken), - ss->resumptionTokenContext); - + SECStatus rv = ss->resumptionTokenCallback( + ss->fd, SSL_BUFFER_BASE(&encodedToken), SSL_BUFFER_LEN(&encodedToken), + ss->resumptionTokenContext); + if (rv == SECSuccess) { + sid->cached = in_external_cache; + } sslBuffer_Clear(&encodedToken); } @@ -1200,17 +1212,23 @@ ssl3_SetSIDSessionTicket(sslSessionID *sid, PORT_Assert(newSessionTicket->ticket.data); PORT_Assert(newSessionTicket->ticket.len != 0); - /* if sid->u.ssl3.lock, we are updating an existing entry that is already - * cached or was once cached, so we need to acquire and release the write - * lock. Otherwise, this is a new session that isn't shared with anything - * yet, so no locking is needed. + /* If this is in the client cache, we are updating an existing entry that is + * already cached or was once cached, so we need to acquire and release the + * write lock. Otherwise, this is a new session that isn't shared with + * anything yet, so no locking is needed. */ if (sid->u.ssl3.lock) { + PORT_Assert(sid->cached == in_client_cache); PR_RWLock_Wlock(sid->u.ssl3.lock); - if (sid->u.ssl3.locked.sessionTicket.ticket.data) { - SECITEM_FreeItem(&sid->u.ssl3.locked.sessionTicket.ticket, - PR_FALSE); - } + } + /* If this was in the client cache, then we might have to free the old + * ticket. In TLS 1.3, we might get a replacement ticket if the server + * sends more than one ticket. */ + if (sid->u.ssl3.locked.sessionTicket.ticket.data) { + PORT_Assert(sid->cached == in_client_cache || + sid->version >= SSL_LIBRARY_VERSION_TLS_1_3); + SECITEM_FreeItem(&sid->u.ssl3.locked.sessionTicket.ticket, + PR_FALSE); } PORT_Assert(!sid->u.ssl3.locked.sessionTicket.ticket.data); diff --git a/security/nss/lib/ssl/sslsecur.c b/security/nss/lib/ssl/sslsecur.c index a1d389214..c011b66a1 100644 --- a/security/nss/lib/ssl/sslsecur.c +++ b/security/nss/lib/ssl/sslsecur.c @@ -685,23 +685,6 @@ ssl_SecureConnect(sslSocket *ss, const PRNetAddr *sa) } /* - * The TLS 1.2 RFC 5246, Section 7.2.1 says: - * - * Unless some other fatal alert has been transmitted, each party is - * required to send a close_notify alert before closing the write side - * of the connection. The other party MUST respond with a close_notify - * alert of its own and close down the connection immediately, - * discarding any pending writes. It is not required for the initiator - * of the close to wait for the responding close_notify alert before - * closing the read side of the connection. - * - * The second sentence requires that we send a close_notify alert when we - * have received a close_notify alert. In practice, all SSL implementations - * close the socket immediately after sending a close_notify alert (which is - * allowed by the third sentence), so responding with a close_notify alert - * would result in a write failure with the ECONNRESET error. This is why - * we don't respond with a close_notify alert. - * * Also, in the unlikely event that the TCP pipe is full and the peer stops * reading, the SSL3_SendAlert call in ssl_SecureClose and ssl_SecureShutdown * may block indefinitely in blocking mode, and may fail (without retrying) @@ -714,8 +697,7 @@ ssl_SecureClose(sslSocket *ss) int rv; if (!(ss->shutdownHow & ssl_SHUTDOWN_SEND) && - ss->firstHsDone && - !ss->recvdCloseNotify) { + ss->firstHsDone) { /* We don't want the final alert to be Nagle delayed. */ if (!ss->delayDisabled) { @@ -744,8 +726,7 @@ ssl_SecureShutdown(sslSocket *ss, int nsprHow) if ((sslHow & ssl_SHUTDOWN_SEND) != 0 && !(ss->shutdownHow & ssl_SHUTDOWN_SEND) && - ss->firstHsDone && - !ss->recvdCloseNotify) { + ss->firstHsDone) { (void)SSL3_SendAlert(ss, alert_warning, close_notify); } @@ -936,6 +917,25 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags) firstClientWrite = ss->ssl3.hs.ws == idle_handshake; ssl_ReleaseSSL3HandshakeLock(ss); } + /* Allow the server to send 0.5 RTT data in TLS 1.3. Requesting a + * certificate implies that the server might condition its sending on + * client authentication, so force servers that do that to wait. + * + * What might not be obvious here is that this allows 0.5 RTT when doing + * PSK-based resumption. As a result, 0.5 RTT is always enabled when + * early data is accepted. + * + * This check might be more conservative than absolutely necessary. + * It's possible that allowing 0.5 RTT data when the server requests, + * but does not require client authentication is safe because we can + * expect the server to check for a client certificate properly. */ + if (ss->sec.isServer && + ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 && + !tls13_ShouldRequestClientAuth(ss)) { + ssl_GetSSL3HandshakeLock(ss); + allowEarlySend = TLS13_IN_HS_STATE(ss, wait_finished); + ssl_ReleaseSSL3HandshakeLock(ss); + } if (!allowEarlySend && ss->handshake) { rv = ssl_Do1stHandshake(ss); } @@ -971,7 +971,7 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags) * 1-RTT later. */ ssl_GetSpecReadLock(ss); - len = tls13_LimitEarlyData(ss, content_application_data, len); + len = tls13_LimitEarlyData(ss, ssl_ct_application_data, len); ssl_ReleaseSpecReadLock(ss); } diff --git a/security/nss/lib/ssl/sslsock.c b/security/nss/lib/ssl/sslsock.c index 33595ffae..ae904e29b 100644 --- a/security/nss/lib/ssl/sslsock.c +++ b/security/nss/lib/ssl/sslsock.c @@ -18,6 +18,8 @@ #include "private/pprio.h" #include "nss.h" #include "pk11pqg.h" +#include "pk11pub.h" +#include "tls13esni.h" static const sslSocketOps ssl_default_ops = { /* No SSL. */ ssl_DefConnect, @@ -82,7 +84,9 @@ static sslOptions ssl_defaults = { .requireDHENamedGroups = PR_FALSE, .enable0RttData = PR_FALSE, .enableTls13CompatMode = PR_FALSE, - .enableDtlsShortHeader = PR_FALSE + .enableDtlsShortHeader = PR_FALSE, + .enableHelloDowngradeCheck = PR_FALSE, + .enableV2CompatibleHello = PR_FALSE }; /* @@ -359,6 +363,13 @@ ssl_DupSocket(sslSocket *os) ss->resumptionTokenCallback = os->resumptionTokenCallback; ss->resumptionTokenContext = os->resumptionTokenContext; + if (os->esniKeys) { + ss->esniKeys = tls13_CopyESNIKeys(os->esniKeys); + if (!ss->esniKeys) { + goto loser; + } + } + /* Create security data */ rv = ssl_CopySecurityInfo(ss, os); if (rv != SECSuccess) { @@ -444,6 +455,8 @@ ssl_DestroySocketContents(sslSocket *ss) ssl_ClearPRCList(&ss->ssl3.hs.dtlsSentHandshake, NULL); ssl_ClearPRCList(&ss->ssl3.hs.dtlsRcvdHandshake, NULL); + + tls13_DestroyESNIKeys(ss->esniKeys); } /* @@ -821,6 +834,14 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRIntn val) ss->opt.enableDtlsShortHeader = val; break; + case SSL_ENABLE_HELLO_DOWNGRADE_CHECK: + ss->opt.enableHelloDowngradeCheck = val; + break; + + case SSL_ENABLE_V2_COMPATIBLE_HELLO: + ss->opt.enableV2CompatibleHello = val; + break; + default: PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; @@ -963,6 +984,12 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRIntn *pVal) case SSL_ENABLE_DTLS_SHORT_HEADER: val = ss->opt.enableDtlsShortHeader; break; + case SSL_ENABLE_HELLO_DOWNGRADE_CHECK: + val = ss->opt.enableHelloDowngradeCheck; + break; + case SSL_ENABLE_V2_COMPATIBLE_HELLO: + val = ss->opt.enableV2CompatibleHello; + break; default: PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; @@ -1089,6 +1116,12 @@ SSL_OptionGetDefault(PRInt32 which, PRIntn *pVal) case SSL_ENABLE_DTLS_SHORT_HEADER: val = ssl_defaults.enableDtlsShortHeader; break; + case SSL_ENABLE_HELLO_DOWNGRADE_CHECK: + val = ssl_defaults.enableHelloDowngradeCheck; + break; + case SSL_ENABLE_V2_COMPATIBLE_HELLO: + val = ssl_defaults.enableV2CompatibleHello; + break; default: PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; @@ -1284,6 +1317,14 @@ SSL_OptionSetDefault(PRInt32 which, PRIntn val) ssl_defaults.enableDtlsShortHeader = val; break; + case SSL_ENABLE_HELLO_DOWNGRADE_CHECK: + ssl_defaults.enableHelloDowngradeCheck = val; + break; + + case SSL_ENABLE_V2_COMPATIBLE_HELLO: + ssl_defaults.enableV2CompatibleHello = val; + break; + default: PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; @@ -3742,6 +3783,10 @@ ssl_GetKeyPairRef(sslKeyPair *keyPair) void ssl_FreeKeyPair(sslKeyPair *keyPair) { + if (!keyPair) { + return; + } + PRInt32 newCount = PR_ATOMIC_DECREMENT(&keyPair->refCount); if (!newCount) { SECKEY_DestroyPrivateKey(keyPair->privKey); @@ -3801,6 +3846,10 @@ ssl_CopyEphemeralKeyPair(sslEphemeralKeyPair *keyPair) void ssl_FreeEphemeralKeyPair(sslEphemeralKeyPair *keyPair) { + if (!keyPair) { + return; + } + ssl_FreeKeyPair(keyPair->keys); PR_REMOVE_LINK(&keyPair->link); PORT_Free(keyPair); @@ -3908,6 +3957,8 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant) PR_INIT_CLIST(&ss->ssl3.hs.dtlsRcvdHandshake); dtls_InitTimers(ss); + ss->esniKeys = NULL; + if (makeLocks) { rv = ssl_MakeLocks(ss); if (rv != SECSuccess) @@ -3984,6 +4035,9 @@ struct { EXP(SetResumptionToken), EXP(GetResumptionTokenInfo), EXP(DestroyResumptionTokenInfo), + EXP(SetESNIKeyPair), + EXP(EncodeESNIKeys), + EXP(EnableESNI), #endif { "", NULL } }; @@ -4049,6 +4103,7 @@ SSLExp_SetResumptionToken(PRFileDesc *fd, const PRUint8 *token, unsigned int len) { sslSocket *ss = ssl_FindSocket(fd); + sslSessionID *sid = NULL; if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetResumptionToken", @@ -4062,7 +4117,7 @@ SSLExp_SetResumptionToken(PRFileDesc *fd, const PRUint8 *token, if (ss->firstHsDone || ss->ssl3.hs.ws != idle_handshake || ss->sec.isServer || len == 0 || !token) { PORT_SetError(SEC_ERROR_INVALID_ARGS); - goto done; + goto loser; } // We override any previously set session. @@ -4073,41 +4128,44 @@ SSLExp_SetResumptionToken(PRFileDesc *fd, const PRUint8 *token, PRINT_BUF(50, (ss, "incoming resumption token", token, len)); - ss->sec.ci.sid = ssl3_NewSessionID(ss, PR_FALSE); - if (!ss->sec.ci.sid) { - goto done; + sid = ssl3_NewSessionID(ss, PR_FALSE); + if (!sid) { + goto loser; } /* Populate NewSessionTicket values */ - SECStatus rv = ssl_DecodeResumptionToken(ss->sec.ci.sid, token, len); + SECStatus rv = ssl_DecodeResumptionToken(sid, token, len); if (rv != SECSuccess) { // If decoding fails, we assume the token is bad. PORT_SetError(SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR); - ssl_FreeSID(ss->sec.ci.sid); - ss->sec.ci.sid = NULL; - goto done; + goto loser; } - // Make sure that the token is valid. - if (!ssl_IsResumptionTokenValid(ss)) { - ssl_FreeSID(ss->sec.ci.sid); - ss->sec.ci.sid = NULL; + // Make sure that the token is currently usable. + if (!ssl_IsResumptionTokenUsable(ss, sid)) { PORT_SetError(SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR); - goto done; + goto loser; } + // Generate a new random session ID for this ticket. + rv = PK11_GenerateRandom(sid->u.ssl3.sessionID, SSL3_SESSIONID_BYTES); + if (rv != SECSuccess) { + goto loser; // Code set by PK11_GenerateRandom. + } + sid->u.ssl3.sessionIDLength = SSL3_SESSIONID_BYTES; /* Use the sid->cached as marker that this is from an external cache and * we don't have to look up anything in the NSS internal cache. */ - ss->sec.ci.sid->cached = in_external_cache; - // This has to be 2 to not free this in sendClientHello. - ss->sec.ci.sid->references = 2; - ss->sec.ci.sid->lastAccessTime = ssl_TimeSec(); + sid->cached = in_external_cache; + sid->lastAccessTime = ssl_TimeSec(); + + ss->sec.ci.sid = sid; ssl_ReleaseSSL3HandshakeLock(ss); ssl_Release1stHandshakeLock(ss); return SECSuccess; -done: +loser: + ssl_FreeSID(sid); ssl_ReleaseSSL3HandshakeLock(ss); ssl_Release1stHandshakeLock(ss); @@ -4164,6 +4222,7 @@ SSLExp_GetResumptionTokenInfo(const PRUint8 *tokenData, unsigned int tokenLen, } else { token.maxEarlyDataSize = 0; } + token.expirationTime = sid.expirationTime; token.length = PR_MIN(sizeof(SSLResumptionTokenInfo), len); PORT_Memcpy(tokenOut, &token, token.length); diff --git a/security/nss/lib/ssl/sslspec.c b/security/nss/lib/ssl/sslspec.c index 7833eeab6..f2e72a4ec 100644 --- a/security/nss/lib/ssl/sslspec.c +++ b/security/nss/lib/ssl/sslspec.c @@ -203,7 +203,7 @@ ssl_CipherSpecAddRef(ssl3CipherSpec *spec) SSL_GETPID(), SPEC_DIR(spec), spec, spec->refCt)); } -static void +void ssl_DestroyKeyMaterial(ssl3KeyMaterial *keyMaterial) { PK11_FreeSymKey(keyMaterial->key); diff --git a/security/nss/lib/ssl/sslt.h b/security/nss/lib/ssl/sslt.h index bb1bec7a3..bd32a6e18 100644 --- a/security/nss/lib/ssl/sslt.h +++ b/security/nss/lib/ssl/sslt.h @@ -35,6 +35,14 @@ typedef enum { ssl_hs_message_hash = 254, /* Not a real message. */ } SSLHandshakeType; +typedef enum { + ssl_ct_change_cipher_spec = 20, + ssl_ct_alert = 21, + ssl_ct_handshake = 22, + ssl_ct_application_data = 23, + ssl_ct_ack = 25 +} SSLContentType; + typedef struct SSL3StatisticsStr { /* statistics from ssl3_SendClientHello (sch) */ long sch_sid_cache_hits; @@ -446,7 +454,8 @@ typedef enum { ssl_tls13_key_share_xtn = 51, ssl_next_proto_nego_xtn = 13172, /* Deprecated. */ ssl_renegotiation_info_xtn = 0xff01, - ssl_tls13_short_header_xtn = 0xff03 /* Deprecated. */ + ssl_tls13_short_header_xtn = 0xff03, /* Deprecated. */ + ssl_tls13_encrypted_sni_xtn = 0xffce, } SSLExtensionType; /* This is the old name for the supported_groups extensions. */ diff --git a/security/nss/lib/ssl/tls13con.c b/security/nss/lib/ssl/tls13con.c index 4d9170fb0..461cd2eb9 100644 --- a/security/nss/lib/ssl/tls13con.c +++ b/security/nss/lib/ssl/tls13con.c @@ -21,6 +21,7 @@ #include "tls13hkdf.h" #include "tls13con.h" #include "tls13err.h" +#include "tls13esni.h" #include "tls13exthandle.h" #include "tls13hashstate.h" @@ -117,6 +118,7 @@ const char kHkdfLabelFinishedSecret[] = "finished"; const char kHkdfLabelResumptionMasterSecret[] = "res master"; const char kHkdfLabelExporterMasterSecret[] = "exp master"; const char kHkdfLabelResumption[] = "resumption"; +const char kHkdfLabelTrafficUpdate[] = "traffic upd"; const char kHkdfPurposeKey[] = "key"; const char kHkdfPurposeIv[] = "iv"; @@ -132,21 +134,6 @@ const char keylogLabelExporterSecret[] = "EXPORTER_SECRET"; PR_STATIC_ASSERT(SSL_LIBRARY_VERSION_MAX_SUPPORTED <= SSL_LIBRARY_VERSION_TLS_1_3); -/* Use this instead of FATAL_ERROR when no alert shall be sent. */ -#define LOG_ERROR(ss, prError) \ - do { \ - SSL_TRC(3, ("%d: TLS13[%d]: fatal error %d in %s (%s:%d)", \ - SSL_GETPID(), ss->fd, prError, __func__, __FILE__, __LINE__)); \ - PORT_SetError(prError); \ - } while (0) - -/* Log an error and generate an alert because something is irreparably wrong. */ -#define FATAL_ERROR(ss, prError, desc) \ - do { \ - LOG_ERROR(ss, prError); \ - tls13_FatalError(ss, prError, desc); \ - } while (0) - void tls13_FatalError(sslSocket *ss, PRErrorCode prError, SSL3AlertDescription desc) { @@ -354,16 +341,16 @@ tls13_ComputeHash(sslSocket *ss, SSL3Hashes *hashes, } SECStatus -tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef) +tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef, + sslEphemeralKeyPair **keyPair) { SECStatus rv; - sslEphemeralKeyPair *keyPair = NULL; const ssl3DHParams *params; PORT_Assert(groupDef); switch (groupDef->keaType) { case ssl_kea_ecdh: - rv = ssl_CreateECDHEphemeralKeyPair(ss, groupDef, &keyPair); + rv = ssl_CreateECDHEphemeralKeyPair(ss, groupDef, keyPair); if (rv != SECSuccess) { return SECFailure; } @@ -371,7 +358,7 @@ tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef) case ssl_kea_dh: params = ssl_GetDHEParams(groupDef); PORT_Assert(params->name != ssl_grp_ffdhe_custom); - rv = ssl_CreateDHEKeyPair(groupDef, params, &keyPair); + rv = ssl_CreateDHEKeyPair(groupDef, params, keyPair); if (rv != SECSuccess) { return SECFailure; } @@ -382,11 +369,24 @@ tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef) return SECFailure; } - PR_APPEND_LINK(&keyPair->link, &ss->ephemeralKeyPairs); return rv; } SECStatus +tls13_AddKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef) +{ + sslEphemeralKeyPair *keyPair = NULL; + SECStatus rv; + + rv = tls13_CreateKeyShare(ss, groupDef, &keyPair); + if (rv != SECSuccess) { + return SECFailure; + } + PR_APPEND_LINK(&keyPair->link, &ss->ephemeralKeyPairs); + return SECSuccess; +} + +SECStatus SSL_SendAdditionalKeyShares(PRFileDesc *fd, unsigned int count) { sslSocket *ss = ssl_FindSocket(fd); @@ -413,20 +413,26 @@ tls13_SetupClientHello(sslSocket *ss) NewSessionTicket *session_ticket = NULL; sslSessionID *sid = ss->sec.ci.sid; unsigned int numShares = 0; + SECStatus rv; PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); PORT_Assert(PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs)); + /* Do encrypted SNI. This may create a key share as a side effect. */ + rv = tls13_ClientSetupESNI(ss); + if (rv != SECSuccess) { + return SECFailure; + } + /* Select the first enabled group. * TODO(ekr@rtfm.com): be smarter about offering the group * that the other side negotiated if we are resuming. */ for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) { - SECStatus rv; if (!ss->namedGroupPreferences[i]) { continue; } - rv = tls13_CreateKeyShare(ss, ss->namedGroupPreferences[i]); + rv = tls13_AddKeyShare(ss, ss->namedGroupPreferences[i]); if (rv != SECSuccess) { return SECFailure; } @@ -455,8 +461,6 @@ tls13_SetupClientHello(sslSocket *ss) } if (ss->statelessResume) { - SECStatus rv; - PORT_Assert(ss->sec.ci.sid); rv = tls13_RecoverWrappedSharedSecret(ss, ss->sec.ci.sid); if (rv != SECSuccess) { @@ -486,7 +490,7 @@ tls13_SetupClientHello(sslSocket *ss) } static SECStatus -tls13_ImportDHEKeyShare(sslSocket *ss, SECKEYPublicKey *peerKey, +tls13_ImportDHEKeyShare(SECKEYPublicKey *peerKey, PRUint8 *b, PRUint32 length, SECKEYPublicKey *pubKey) { @@ -517,16 +521,20 @@ tls13_ImportDHEKeyShare(sslSocket *ss, SECKEYPublicKey *peerKey, return SECSuccess; } -static SECStatus +SECStatus tls13_HandleKeyShare(sslSocket *ss, TLS13KeyShareEntry *entry, - sslKeyPair *keyPair) + sslKeyPair *keyPair, + SSLHashType hash, + PK11SymKey **out) { PORTCheapArenaPool arena; SECKEYPublicKey *peerKey; CK_MECHANISM_TYPE mechanism; PRErrorCode errorCode; + PK11SymKey *key; SECStatus rv; + int keySize = 0; PORT_InitCheapArena(&arena, DER_DEFAULT_CHUNKSIZE); peerKey = PORT_ArenaZNew(&arena.arena, SECKEYPublicKey); @@ -539,18 +547,19 @@ tls13_HandleKeyShare(sslSocket *ss, switch (entry->group->keaType) { case ssl_kea_ecdh: - rv = ssl_ImportECDHKeyShare(ss, peerKey, + rv = ssl_ImportECDHKeyShare(peerKey, entry->key_exchange.data, entry->key_exchange.len, entry->group); mechanism = CKM_ECDH1_DERIVE; break; case ssl_kea_dh: - rv = tls13_ImportDHEKeyShare(ss, peerKey, + rv = tls13_ImportDHEKeyShare(peerKey, entry->key_exchange.data, entry->key_exchange.len, keyPair->pubKey); mechanism = CKM_DH_PKCS_DERIVE; + keySize = peerKey->u.dh.publicValue.len; break; default: PORT_Assert(0); @@ -560,13 +569,14 @@ tls13_HandleKeyShare(sslSocket *ss, goto loser; } - ss->ssl3.hs.dheSecret = PK11_PubDeriveWithKDF( + key = PK11_PubDeriveWithKDF( keyPair->privKey, peerKey, PR_FALSE, NULL, NULL, mechanism, - tls13_GetHkdfMechanism(ss), CKA_DERIVE, 0, CKD_NULL, NULL, NULL); - if (!ss->ssl3.hs.dheSecret) { + tls13_GetHkdfMechanismForHash(hash), CKA_DERIVE, keySize, CKD_NULL, NULL, NULL); + if (!key) { ssl_MapLowLevelError(SSL_ERROR_KEY_EXCHANGE_FAILURE); goto loser; } + *out = key; PORT_DestroyCheapArena(&arena); return SECSuccess; @@ -603,8 +613,8 @@ tls13_UpdateTrafficKeys(sslSocket *ss, CipherSpecDirection direction) secret = tls13_TrafficSecretRef(ss, direction); rv = tls13_HkdfExpandLabel(*secret, tls13_GetHash(ss), NULL, 0, - kHkdfLabelApplicationTrafficSecret, - strlen(kHkdfLabelApplicationTrafficSecret), + kHkdfLabelTrafficUpdate, + strlen(kHkdfLabelTrafficUpdate), tls13_GetHmacMechanism(ss), tls13_GetHashSize(ss), &updatedSecret); @@ -1417,30 +1427,6 @@ tls13_NegotiateKeyExchange(sslSocket *ss, return SECSuccess; } -SSLAuthType -ssl_SignatureSchemeToAuthType(SSLSignatureScheme scheme) -{ - switch (scheme) { - case ssl_sig_rsa_pkcs1_sha1: - case ssl_sig_rsa_pkcs1_sha256: - case ssl_sig_rsa_pkcs1_sha384: - case ssl_sig_rsa_pkcs1_sha512: - /* We report PSS signatures as being just RSA signatures. */ - case ssl_sig_rsa_pss_rsae_sha256: - case ssl_sig_rsa_pss_rsae_sha384: - case ssl_sig_rsa_pss_rsae_sha512: - return ssl_auth_rsa_sign; - case ssl_sig_ecdsa_secp256r1_sha256: - case ssl_sig_ecdsa_secp384r1_sha384: - case ssl_sig_ecdsa_secp521r1_sha512: - case ssl_sig_ecdsa_sha1: - return ssl_auth_ecdsa; - default: - PORT_Assert(0); - } - return ssl_auth_null; -} - SECStatus tls13_SelectServerCert(sslSocket *ss) { @@ -1469,6 +1455,7 @@ tls13_SelectServerCert(sslSocket *ss) } rv = ssl_PickSignatureScheme(ss, + cert->serverCert, cert->serverKeyPair->pubKey, cert->serverKeyPair->privKey, ss->xtnData.sigSchemes, @@ -2047,7 +2034,7 @@ tls13_HandleClientKeyShare(sslSocket *ss, TLS13KeyShareEntry *peerShare) tls13_SetKeyExchangeType(ss, peerShare->group); /* Generate our key */ - rv = tls13_CreateKeyShare(ss, peerShare->group); + rv = tls13_AddKeyShare(ss, peerShare->group); if (rv != SECSuccess) { return rv; } @@ -2067,7 +2054,9 @@ tls13_HandleClientKeyShare(sslSocket *ss, TLS13KeyShareEntry *peerShare) return SECFailure; /* Error code set already. */ } - rv = tls13_HandleKeyShare(ss, peerShare, keyPair->keys); + rv = tls13_HandleKeyShare(ss, peerShare, keyPair->keys, + tls13_GetHash(ss), + &ss->ssl3.hs.dheSecret); return rv; /* Error code set already. */ } @@ -2334,6 +2323,13 @@ tls13_HandleCertificateRequest(sslSocket *ss, PRUint8 *b, PRUint32 length) return SECSuccess; } +PRBool +tls13_ShouldRequestClientAuth(sslSocket *ss) +{ + return ss->opt.requestCertificate && + ss->ssl3.hs.kea_def->authKeyType != ssl_auth_psk; +} + static SECStatus tls13_SendEncryptedServerSequence(sslSocket *ss) { @@ -2365,7 +2361,7 @@ tls13_SendEncryptedServerSequence(sslSocket *ss) return SECFailure; /* error code is set. */ } - if (ss->opt.requestCertificate) { + if (tls13_ShouldRequestClientAuth(ss)) { rv = tls13_SendCertificateRequest(ss); if (rv != SECSuccess) { return SECFailure; /* error code is set. */ @@ -2484,9 +2480,11 @@ tls13_SendServerHelloSequence(sslSocket *ss) LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - TLS13_SET_HS_STATE(ss, - ss->opt.requestCertificate ? wait_client_cert - : wait_finished); + if (tls13_ShouldRequestClientAuth(ss)) { + TLS13_SET_HS_STATE(ss, wait_client_cert); + } else { + TLS13_SET_HS_STATE(ss, wait_finished); + } } ss->ssl3.hs.serverHelloTime = ssl_TimeUsec(); @@ -2512,6 +2510,7 @@ tls13_HandleServerHelloPart2(sslSocket *ss) } if (ss->statelessResume) { + PORT_Assert(sid->version >= SSL_LIBRARY_VERSION_TLS_1_3); if (tls13_GetHash(ss) != tls13_GetHashForCipherSuite(sid->u.ssl3.cipherSuite)) { FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_SERVER_HELLO, @@ -2657,7 +2656,9 @@ tls13_HandleServerKeyShare(sslSocket *ss) PORT_Assert(ssl_NamedGroupEnabled(ss, entry->group)); - rv = tls13_HandleKeyShare(ss, entry, keyPair->keys); + rv = tls13_HandleKeyShare(ss, entry, keyPair->keys, + tls13_GetHash(ss), + &ss->ssl3.hs.dheSecret); if (rv != SECSuccess) return SECFailure; /* Error code set by caller. */ @@ -3213,6 +3214,21 @@ tls13_SetSpecRecordVersion(sslSocket *ss, ssl3CipherSpec *spec) SSL_GETPID(), ss->fd, spec, spec->recordVersion)); } +SSLAEADCipher +tls13_GetAead(const ssl3BulkCipherDef *cipherDef) +{ + switch (cipherDef->calg) { + case ssl_calg_aes_gcm: + return tls13_AESGCM; + case ssl_calg_chacha20: + return tls13_ChaCha20Poly1305; + default: + PORT_Assert(PR_FALSE); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return NULL; + } +} + static SECStatus tls13_SetupPendingCipherSpec(sslSocket *ss, ssl3CipherSpec *spec) { @@ -3236,16 +3252,9 @@ tls13_SetupPendingCipherSpec(sslSocket *ss, ssl3CipherSpec *spec) SSL_GETPID(), ss->fd, suite)); spec->cipherDef = ssl_GetBulkCipherDef(ssl_LookupCipherSuiteDef(suite)); - switch (spec->cipherDef->calg) { - case ssl_calg_aes_gcm: - spec->aead = tls13_AESGCM; - break; - case ssl_calg_chacha20: - spec->aead = tls13_ChaCha20Poly1305; - break; - default: - PORT_Assert(0); - return SECFailure; + spec->aead = tls13_GetAead(spec->cipherDef); + if (!spec->aead) { + return SECFailure; } if (spec->epoch == TrafficKeyEarlyApplicationData) { @@ -3427,9 +3436,31 @@ loser: return SECFailure; } +TLS13KeyShareEntry * +tls13_CopyKeyShareEntry(TLS13KeyShareEntry *o) +{ + TLS13KeyShareEntry *n; + + PORT_Assert(o); + n = PORT_ZNew(TLS13KeyShareEntry); + if (!n) { + return NULL; + } + + if (SECSuccess != SECITEM_CopyItem(NULL, &n->key_exchange, &o->key_exchange)) { + PORT_Free(n); + return NULL; + } + n->group = o->group; + return n; +} + void tls13_DestroyKeyShareEntry(TLS13KeyShareEntry *offer) { + if (!offer) { + return; + } SECITEM_ZfreeItem(&offer->key_exchange, PR_FALSE); PORT_ZFree(offer, sizeof(*offer)); } @@ -3550,7 +3581,7 @@ tls13_AESGCM(ssl3KeyMaterial *keys, CK_GCM_PARAMS gcmParams; unsigned char nonce[12]; - PORT_Assert(additionalDataLen > 8); + PORT_Assert(additionalDataLen >= 8); memset(&gcmParams, 0, sizeof(gcmParams)); gcmParams.pIv = nonce; gcmParams.ulIvLen = sizeof(nonce); @@ -3627,7 +3658,23 @@ tls13_HandleEncryptedExtensions(sslSocket *ss, PRUint8 *b, PRUint32 length) ss->xtnData.nextProto.data = NULL; ss->xtnData.nextProtoState = SSL_NEXT_PROTO_NO_SUPPORT; } - rv = ssl3_HandleExtensions(ss, &b, &length, ssl_hs_encrypted_extensions); + + rv = ssl3_ParseExtensions(ss, &b, &length); + if (rv != SECSuccess) { + return SECFailure; /* Error code set below */ + } + + /* If we sent ESNI, check the nonce. */ + if (ss->xtnData.esniPrivateKey) { + PORT_Assert(ssl3_ExtensionAdvertised(ss, ssl_tls13_encrypted_sni_xtn)); + rv = tls13_ClientCheckEsniXtn(ss); + if (rv != SECSuccess) { + return SECFailure; + } + } + + /* Handle the rest of the extensions. */ + rv = ssl3_HandleParsedExtensions(ss, ssl_hs_encrypted_extensions); if (rv != SECSuccess) { return SECFailure; /* Error code set below */ } @@ -4025,6 +4072,7 @@ tls13_ComputeFinished(sslSocket *ss, PK11SymKey *baseKey, PK11_FreeSymKey(secret); PK11_DestroyContext(hmacCtx, PR_TRUE); + PRINT_BUF(50, (ss, "finished value", output, outputLenUint)); return SECSuccess; abort: @@ -4189,7 +4237,7 @@ tls13_ServerHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length) return SECFailure; } - if (!ss->opt.requestCertificate && + if (!tls13_ShouldRequestClientAuth(ss) && (ss->ssl3.hs.zeroRttState != ssl_0rtt_done)) { dtls_ReceivedFirstMessageInFlight(ss); } @@ -4679,7 +4727,8 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length) /* Replace a previous session ticket when * we receive a second NewSessionTicket message. */ - if (ss->sec.ci.sid->cached == in_client_cache) { + if (ss->sec.ci.sid->cached == in_client_cache || + ss->sec.ci.sid->cached == in_external_cache) { /* Create a new session ID. */ sslSessionID *sid = ssl3_NewSessionID(ss, PR_FALSE); if (!sid) { @@ -4758,7 +4807,8 @@ static const struct { { ssl_tls13_certificate_authorities_xtn, _M1(certificate_request) }, { ssl_tls13_supported_versions_xtn, _M3(client_hello, server_hello, hello_retry_request) }, - { ssl_record_size_limit_xtn, _M2(client_hello, encrypted_extensions) } + { ssl_record_size_limit_xtn, _M2(client_hello, encrypted_extensions) }, + { ssl_tls13_encrypted_sni_xtn, _M2(client_hello, encrypted_extensions) } }; tls13ExtensionStatus @@ -4834,11 +4884,11 @@ tls13_FormatAdditionalData( } PRInt32 -tls13_LimitEarlyData(sslSocket *ss, SSL3ContentType type, PRInt32 toSend) +tls13_LimitEarlyData(sslSocket *ss, SSLContentType type, PRInt32 toSend) { PRInt32 reduced; - PORT_Assert(type == content_application_data); + PORT_Assert(type == ssl_ct_application_data); PORT_Assert(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3); PORT_Assert(!ss->firstHsDone); if (ss->ssl3.cwSpec->epoch != TrafficKeyEarlyApplicationData) { @@ -4858,7 +4908,7 @@ tls13_LimitEarlyData(sslSocket *ss, SSL3ContentType type, PRInt32 toSend) SECStatus tls13_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, - SSL3ContentType type, + SSLContentType type, const PRUint8 *pIn, PRUint32 contentLen, sslBuffer *wrBuf) @@ -4899,7 +4949,7 @@ tls13_ProtectRecord(sslSocket *ss, *(SSL_BUFFER_NEXT(wrBuf) + contentLen) = type; /* Create the header (ugly that we have to do it twice). */ - rv = ssl_InsertRecordHeader(ss, cwSpec, content_application_data, + rv = ssl_InsertRecordHeader(ss, cwSpec, ssl_ct_application_data, &buf, &needsLength); if (rv != SECSuccess) { return SECFailure; @@ -4951,7 +5001,7 @@ tls13_UnprotectRecord(sslSocket *ss, ssl3CipherSpec *spec, SSL3Ciphertext *cText, sslBuffer *plaintext, - SSL3ContentType *innerType, + SSLContentType *innerType, SSL3AlertDescription *alert) { const ssl3BulkCipherDef *cipher_def = spec->cipherDef; @@ -4966,26 +5016,26 @@ tls13_UnprotectRecord(sslSocket *ss, SSL_GETPID(), ss->fd, spec, spec->epoch, spec->phase, cText->seqNum, cText->buf->len)); - /* We can perform this test in variable time because the record's total - * length and the ciphersuite are both public knowledge. */ - if (cText->buf->len < cipher_def->tag_size) { - SSL_TRC(3, - ("%d: TLS13[%d]: record too short to contain valid AEAD data", - SSL_GETPID(), ss->fd)); - PORT_SetError(SSL_ERROR_BAD_MAC_READ); - return SECFailure; - } - /* Verify that the content type is right, even though we overwrite it. * Also allow the DTLS short header in TLS 1.3. */ - if (!(cText->hdr[0] == content_application_data || + if (!(cText->hdr[0] == ssl_ct_application_data || (IS_DTLS(ss) && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 && (cText->hdr[0] & 0xe0) == 0x20))) { SSL_TRC(3, ("%d: TLS13[%d]: record has invalid exterior type=%2.2x", SSL_GETPID(), ss->fd, cText->hdr[0])); - /* Do we need a better error here? */ + PORT_SetError(SSL_ERROR_RX_UNEXPECTED_RECORD_TYPE); + *alert = unexpected_message; + return SECFailure; + } + + /* We can perform this test in variable time because the record's total + * length and the ciphersuite are both public knowledge. */ + if (cText->buf->len < cipher_def->tag_size) { + SSL_TRC(3, + ("%d: TLS13[%d]: record too short to contain valid AEAD data", + SSL_GETPID(), ss->fd)); PORT_SetError(SSL_ERROR_BAD_MAC_READ); return SECFailure; } @@ -5054,12 +5104,12 @@ tls13_UnprotectRecord(sslSocket *ss, } /* Record the type. */ - *innerType = (SSL3ContentType)plaintext->buf[plaintext->len - 1]; + *innerType = (SSLContentType)plaintext->buf[plaintext->len - 1]; --plaintext->len; /* Check that we haven't received too much 0-RTT data. */ if (spec->epoch == TrafficKeyEarlyApplicationData && - *innerType == content_application_data) { + *innerType == ssl_ct_application_data) { if (plaintext->len > spec->earlyDataRemaining) { *alert = unexpected_message; PORT_SetError(SSL_ERROR_TOO_MUCH_EARLY_DATA); @@ -5242,9 +5292,11 @@ tls13_HandleEndOfEarlyData(sslSocket *ss, PRUint8 *b, PRUint32 length) } ss->ssl3.hs.zeroRttState = ssl_0rtt_done; - TLS13_SET_HS_STATE(ss, - ss->opt.requestCertificate ? wait_client_cert - : wait_finished); + if (tls13_ShouldRequestClientAuth(ss)) { + TLS13_SET_HS_STATE(ss, wait_client_cert); + } else { + TLS13_SET_HS_STATE(ss, wait_finished); + } return SECSuccess; } @@ -5283,11 +5335,12 @@ tls13_HandleEarlyApplicationData(sslSocket *ss, sslBuffer *origBuf) } PRUint16 -tls13_EncodeDraftVersion(SSL3ProtocolVersion version) +tls13_EncodeDraftVersion(SSL3ProtocolVersion version, SSLProtocolVariant variant) { -#ifdef TLS_1_3_DRAFT_VERSION - if (version == SSL_LIBRARY_VERSION_TLS_1_3) { - return 0x7f00 | TLS_1_3_DRAFT_VERSION; +#ifdef DTLS_1_3_DRAFT_VERSION + if (version == SSL_LIBRARY_VERSION_TLS_1_3 && + variant == ssl_variant_datagram) { + return 0x7f00 | DTLS_1_3_DRAFT_VERSION; } #endif return (PRUint16)version; @@ -5297,7 +5350,6 @@ SECStatus tls13_ClientReadSupportedVersion(sslSocket *ss) { PRUint32 temp; - SSL3ProtocolVersion v; TLSExtension *versionExtension; SECItem it; SECStatus rv; @@ -5319,29 +5371,15 @@ tls13_ClientReadSupportedVersion(sslSocket *ss) FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_SERVER_HELLO, illegal_parameter); return SECFailure; } - v = (SSL3ProtocolVersion)temp; - /* You cannot negotiate < TLS 1.3 with supported_versions. */ - if (v < SSL_LIBRARY_VERSION_TLS_1_3) { + if (temp != tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3, + ss->protocolVariant)) { + /* You cannot negotiate < TLS 1.3 with supported_versions. */ FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_SERVER_HELLO, illegal_parameter); return SECFailure; } -#ifdef TLS_1_3_DRAFT_VERSION - if (temp == SSL_LIBRARY_VERSION_TLS_1_3) { - FATAL_ERROR(ss, SSL_ERROR_UNSUPPORTED_VERSION, protocol_version); - return SECFailure; - } - if (temp == tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3)) { - v = SSL_LIBRARY_VERSION_TLS_1_3; - } else { - v = (SSL3ProtocolVersion)temp; - } -#else - v = (SSL3ProtocolVersion)temp; -#endif - - ss->version = v; + ss->version = SSL_LIBRARY_VERSION_TLS_1_3; return SECSuccess; } @@ -5365,7 +5403,7 @@ tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supportedVersions) return SECFailure; } for (version = ss->vrange.max; version >= ss->vrange.min; --version) { - PRUint16 wire = tls13_EncodeDraftVersion(version); + PRUint16 wire = tls13_EncodeDraftVersion(version, ss->protocolVariant); unsigned long offset; for (offset = 0; offset < versions.len; offset += 2) { diff --git a/security/nss/lib/ssl/tls13con.h b/security/nss/lib/ssl/tls13con.h index f35b20023..f3b2cb390 100644 --- a/security/nss/lib/ssl/tls13con.h +++ b/security/nss/lib/ssl/tls13con.h @@ -28,7 +28,7 @@ typedef enum { SECStatus tls13_UnprotectRecord( sslSocket *ss, ssl3CipherSpec *spec, SSL3Ciphertext *cText, sslBuffer *plaintext, - SSL3ContentType *innerType, + SSLContentType *innerType, SSL3AlertDescription *alert); #if defined(WIN32) @@ -64,7 +64,7 @@ void tls13_FatalError(sslSocket *ss, PRErrorCode prError, SSL3AlertDescription desc); SECStatus tls13_SetupClientHello(sslSocket *ss); SECStatus tls13_MaybeDo0RTTHandshake(sslSocket *ss); -PRInt32 tls13_LimitEarlyData(sslSocket *ss, SSL3ContentType type, PRInt32 toSend); +PRInt32 tls13_LimitEarlyData(sslSocket *ss, SSLContentType type, PRInt32 toSend); PRBool tls13_AllowPskCipher(const sslSocket *ss, const ssl3CipherSuiteDef *cipher_def); PRBool tls13_PskSuiteEnabled(sslSocket *ss); @@ -85,26 +85,36 @@ SECStatus tls13_ConstructHelloRetryRequest(sslSocket *ss, sslBuffer *buffer); SECStatus tls13_HandleHelloRetryRequest(sslSocket *ss, const PRUint8 *b, PRUint32 length); +SECStatus tls13_HandleKeyShare(sslSocket *ss, + TLS13KeyShareEntry *entry, + sslKeyPair *keyPair, + SSLHashType hash, + PK11SymKey **out); +TLS13KeyShareEntry *tls13_CopyKeyShareEntry(TLS13KeyShareEntry *o); void tls13_DestroyKeyShareEntry(TLS13KeyShareEntry *entry); void tls13_DestroyKeyShares(PRCList *list); -SECStatus tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef); +SECStatus tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef, + sslEphemeralKeyPair **keyPair); +SECStatus tls13_AddKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef); void tls13_DestroyEarlyData(PRCList *list); SECStatus tls13_SetAlertCipherSpec(sslSocket *ss); tls13ExtensionStatus tls13_ExtensionStatus(PRUint16 extension, SSLHandshakeType message); SECStatus tls13_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, - SSL3ContentType type, + SSLContentType type, const PRUint8 *pIn, PRUint32 contentLen, sslBuffer *wrBuf); PRInt32 tls13_Read0RttData(sslSocket *ss, void *buf, PRInt32 len); SECStatus tls13_HandleEarlyApplicationData(sslSocket *ss, sslBuffer *origBuf); PRBool tls13_ClientAllow0Rtt(const sslSocket *ss, const sslSessionID *sid); -PRUint16 tls13_EncodeDraftVersion(SSL3ProtocolVersion version); +PRUint16 tls13_EncodeDraftVersion(SSL3ProtocolVersion version, + SSLProtocolVariant variant); SECStatus tls13_ClientReadSupportedVersion(sslSocket *ss); SECStatus tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supported_versions); +PRBool tls13_ShouldRequestClientAuth(sslSocket *ss); PRBool tls13_IsReplay(const sslSocket *ss, const sslSessionID *sid); void tls13_AntiReplayRollover(PRTime now); @@ -119,6 +129,22 @@ SECStatus tls13_SendKeyUpdate(sslSocket *ss, tls13KeyUpdateRequest request, PRBool buffer); SECStatus SSLExp_KeyUpdate(PRFileDesc *fd, PRBool requestUpdate); PRBool tls13_MaybeTls13(sslSocket *ss); +SSLAEADCipher tls13_GetAead(const ssl3BulkCipherDef *cipherDef); void tls13_SetSpecRecordVersion(sslSocket *ss, ssl3CipherSpec *spec); +/* Use this instead of FATAL_ERROR when no alert shall be sent. */ +#define LOG_ERROR(ss, prError) \ + do { \ + SSL_TRC(3, ("%d: TLS13[%d]: fatal error %d in %s (%s:%d)", \ + SSL_GETPID(), ss->fd, prError, __func__, __FILE__, __LINE__)); \ + PORT_SetError(prError); \ + } while (0) + +/* Log an error and generate an alert because something is irreparably wrong. */ +#define FATAL_ERROR(ss, prError, desc) \ + do { \ + LOG_ERROR(ss, prError); \ + tls13_FatalError(ss, prError, desc); \ + } while (0) + #endif /* __tls13con_h_ */ diff --git a/security/nss/lib/ssl/tls13esni.c b/security/nss/lib/ssl/tls13esni.c new file mode 100644 index 000000000..e2328769b --- /dev/null +++ b/security/nss/lib/ssl/tls13esni.c @@ -0,0 +1,844 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#define TLS13_ESNI_VERSION 0xff01 + +/* + * struct { + * uint16 version; + * uint8 checksum[4]; + * KeyShareEntry keys<4..2^16-1>; + * CipherSuite cipher_suites<2..2^16-2>; + * uint16 padded_length; + * uint64 not_before; + * uint64 not_after; + * Extension extensions<0..2^16-1>; + * } ESNIKeys; + */ +#include "nss.h" +#include "pk11func.h" +#include "ssl.h" +#include "sslproto.h" +#include "sslimpl.h" +#include "ssl3exthandle.h" +#include "tls13esni.h" +#include "tls13exthandle.h" +#include "tls13hkdf.h" + +const char kHkdfPurposeEsniKey[] = "esni key"; +const char kHkdfPurposeEsniIv[] = "esni iv"; + +void +tls13_DestroyESNIKeys(sslEsniKeys *keys) +{ + if (!keys) { + return; + } + SECITEM_FreeItem(&keys->data, PR_FALSE); + PORT_Free((void *)keys->dummySni); + tls13_DestroyKeyShares(&keys->keyShares); + ssl_FreeEphemeralKeyPair(keys->privKey); + SECITEM_FreeItem(&keys->suites, PR_FALSE); + PORT_ZFree(keys, sizeof(sslEsniKeys)); +} + +sslEsniKeys * +tls13_CopyESNIKeys(sslEsniKeys *okeys) +{ + sslEsniKeys *nkeys; + SECStatus rv; + + PORT_Assert(okeys); + + nkeys = PORT_ZNew(sslEsniKeys); + if (!nkeys) { + return NULL; + } + PR_INIT_CLIST(&nkeys->keyShares); + rv = SECITEM_CopyItem(NULL, &nkeys->data, &okeys->data); + if (rv != SECSuccess) { + goto loser; + } + if (okeys->dummySni) { + nkeys->dummySni = PORT_Strdup(okeys->dummySni); + if (!nkeys->dummySni) { + goto loser; + } + } + for (PRCList *cur_p = PR_LIST_HEAD(&okeys->keyShares); + cur_p != &okeys->keyShares; + cur_p = PR_NEXT_LINK(cur_p)) { + TLS13KeyShareEntry *copy = tls13_CopyKeyShareEntry( + (TLS13KeyShareEntry *)cur_p); + if (!copy) { + goto loser; + } + PR_APPEND_LINK(©->link, &nkeys->keyShares); + } + if (okeys->privKey) { + nkeys->privKey = ssl_CopyEphemeralKeyPair(okeys->privKey); + if (!nkeys->privKey) { + goto loser; + } + } + rv = SECITEM_CopyItem(NULL, &nkeys->suites, &okeys->suites); + if (rv != SECSuccess) { + goto loser; + } + nkeys->paddedLength = okeys->paddedLength; + nkeys->notBefore = okeys->notBefore; + nkeys->notAfter = okeys->notAfter; + return nkeys; + +loser: + tls13_DestroyESNIKeys(nkeys); + return NULL; +} + +/* Checksum is a 4-byte array. */ +static SECStatus +tls13_ComputeESNIKeysChecksum(const PRUint8 *buf, unsigned int len, + PRUint8 *checksum) +{ + SECItem copy; + SECStatus rv; + PRUint8 sha256[32]; + + rv = SECITEM_MakeItem(NULL, ©, buf, len); + if (rv != SECSuccess) { + return SECFailure; + } + + /* Stomp the checksum. */ + PORT_Memset(copy.data + 2, 0, 4); + + rv = PK11_HashBuf(ssl3_HashTypeToOID(ssl_hash_sha256), + sha256, + copy.data, copy.len); + SECITEM_FreeItem(©, PR_FALSE); + if (rv != SECSuccess) { + return SECFailure; + } + PORT_Memcpy(checksum, sha256, 4); + return SECSuccess; +} + +static SECStatus +tls13_DecodeESNIKeys(SECItem *data, sslEsniKeys **keysp) +{ + SECStatus rv; + sslReadBuffer tmp; + PRUint64 tmpn; + sslEsniKeys *keys; + PRUint8 checksum[4]; + sslReader rdr = SSL_READER(data->data, data->len); + + rv = sslRead_ReadNumber(&rdr, 2, &tmpn); + if (rv != SECSuccess) { + return SECFailure; + } + if (tmpn != TLS13_ESNI_VERSION) { + PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION); + return SECFailure; + } + keys = PORT_ZNew(sslEsniKeys); + if (!keys) { + return SECFailure; + } + PR_INIT_CLIST(&keys->keyShares); + + /* Make a copy. */ + rv = SECITEM_CopyItem(NULL, &keys->data, data); + if (rv != SECSuccess) { + goto loser; + } + + rv = tls13_ComputeESNIKeysChecksum(data->data, data->len, checksum); + if (rv != SECSuccess) { + goto loser; + } + + /* Read and check checksum. */ + rv = sslRead_Read(&rdr, 4, &tmp); + if (rv != SECSuccess) { + goto loser; + } + + if (0 != NSS_SecureMemcmp(tmp.buf, checksum, 4)) { + goto loser; + } + + /* Parse the key shares. */ + rv = sslRead_ReadVariable(&rdr, 2, &tmp); + if (rv != SECSuccess) { + goto loser; + } + + sslReader rdr2 = SSL_READER(tmp.buf, tmp.len); + while (SSL_READER_REMAINING(&rdr2)) { + TLS13KeyShareEntry *ks = NULL; + + rv = tls13_DecodeKeyShareEntry(&rdr2, &ks); + if (rv != SECSuccess) { + goto loser; + } + + if (ks) { + PR_APPEND_LINK(&ks->link, &keys->keyShares); + } + } + + /* Parse cipher suites. */ + rv = sslRead_ReadVariable(&rdr, 2, &tmp); + if (rv != SECSuccess) { + goto loser; + } + /* This can't be odd. */ + if (tmp.len & 1) { + goto loser; + } + rv = SECITEM_MakeItem(NULL, &keys->suites, (PRUint8 *)tmp.buf, tmp.len); + if (rv != SECSuccess) { + goto loser; + } + + /* Padded Length */ + rv = sslRead_ReadNumber(&rdr, 2, &tmpn); + if (rv != SECSuccess) { + goto loser; + } + keys->paddedLength = (PRUint16)tmpn; + + /* Not Before */ + rv = sslRead_ReadNumber(&rdr, 8, &keys->notBefore); + if (rv != SECSuccess) { + goto loser; + } + + /* Not After */ + rv = sslRead_ReadNumber(&rdr, 8, &keys->notAfter); + if (rv != SECSuccess) { + goto loser; + } + + /* Extensions, which we ignore. */ + rv = sslRead_ReadVariable(&rdr, 2, &tmp); + if (rv != SECSuccess) { + goto loser; + } + + /* Check that this is empty. */ + if (SSL_READER_REMAINING(&rdr) > 0) { + goto loser; + } + + *keysp = keys; + return SECSuccess; + +loser: + tls13_DestroyESNIKeys(keys); + PORT_SetError(SSL_ERROR_RX_MALFORMED_ESNI_KEYS); + + return SECFailure; +} + +/* Encode an ESNI keys structure. We only allow one key + * share. */ +SECStatus +SSLExp_EncodeESNIKeys(PRUint16 *cipherSuites, unsigned int cipherSuiteCount, + SSLNamedGroup group, SECKEYPublicKey *pubKey, + PRUint16 pad, PRUint64 notBefore, PRUint64 notAfter, + PRUint8 *out, unsigned int *outlen, unsigned int maxlen) +{ + unsigned int savedOffset; + SECStatus rv; + sslBuffer b = SSL_BUFFER_EMPTY; + + rv = sslBuffer_AppendNumber(&b, TLS13_ESNI_VERSION, 2); + if (rv != SECSuccess) { + goto loser; + } + + rv = sslBuffer_Skip(&b, 4, &savedOffset); + if (rv != SECSuccess) { + goto loser; + } + + /* Length of vector. */ + rv = sslBuffer_AppendNumber( + &b, tls13_SizeOfKeyShareEntry(pubKey), 2); + if (rv != SECSuccess) { + goto loser; + } + + /* Our one key share. */ + rv = tls13_EncodeKeyShareEntry(&b, group, pubKey); + if (rv != SECSuccess) { + goto loser; + } + + /* Cipher suites. */ + rv = sslBuffer_AppendNumber(&b, cipherSuiteCount * 2, 2); + if (rv != SECSuccess) { + goto loser; + } + for (unsigned int i = 0; i < cipherSuiteCount; i++) { + rv = sslBuffer_AppendNumber(&b, cipherSuites[i], 2); + if (rv != SECSuccess) { + goto loser; + } + } + + /* Padding Length. Fixed for now. */ + rv = sslBuffer_AppendNumber(&b, pad, 2); + if (rv != SECSuccess) { + goto loser; + } + + /* Start time. */ + rv = sslBuffer_AppendNumber(&b, notBefore, 8); + if (rv != SECSuccess) { + goto loser; + } + + /* End time. */ + rv = sslBuffer_AppendNumber(&b, notAfter, 8); + if (rv != SECSuccess) { + goto loser; + } + + /* No extensions. */ + rv = sslBuffer_AppendNumber(&b, 0, 2); + if (rv != SECSuccess) { + goto loser; + } + + rv = tls13_ComputeESNIKeysChecksum(SSL_BUFFER_BASE(&b), + SSL_BUFFER_LEN(&b), + SSL_BUFFER_BASE(&b) + 2); + if (rv != SECSuccess) { + PORT_Assert(PR_FALSE); + goto loser; + } + + if (SSL_BUFFER_LEN(&b) > maxlen) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + goto loser; + } + PORT_Memcpy(out, SSL_BUFFER_BASE(&b), SSL_BUFFER_LEN(&b)); + *outlen = SSL_BUFFER_LEN(&b); + + sslBuffer_Clear(&b); + return SECSuccess; +loser: + sslBuffer_Clear(&b); + return SECFailure; +} + +SECStatus +SSLExp_SetESNIKeyPair(PRFileDesc *fd, + SECKEYPrivateKey *privKey, + const PRUint8 *record, unsigned int recordLen) +{ + sslSocket *ss; + SECStatus rv; + sslEsniKeys *keys = NULL; + SECKEYPublicKey *pubKey = NULL; + SECItem data = { siBuffer, CONST_CAST(PRUint8, record), recordLen }; + PLArenaPool *arena = NULL; + + ss = ssl_FindSocket(fd); + if (!ss) { + SSL_DBG(("%d: SSL[%d]: bad socket in %s", + SSL_GETPID(), fd, __FUNCTION__)); + return SECFailure; + } + + rv = tls13_DecodeESNIKeys(&data, &keys); + if (rv != SECSuccess) { + return SECFailure; + } + + /* Check the cipher suites. */ + (void)ssl3_config_match_init(ss); + /* Make sure the cipher suite is OK. */ + SSLVersionRange vrange = { SSL_LIBRARY_VERSION_TLS_1_3, + SSL_LIBRARY_VERSION_TLS_1_3 }; + + sslReader csrdr = SSL_READER(keys->suites.data, + keys->suites.len); + while (SSL_READER_REMAINING(&csrdr)) { + PRUint64 asuite; + + rv = sslRead_ReadNumber(&csrdr, 2, &asuite); + if (rv != SECSuccess) { + goto loser; + } + const ssl3CipherSuiteCfg *suiteCfg = + ssl_LookupCipherSuiteCfg(asuite, ss->cipherSuites); + if (!ssl3_config_match(suiteCfg, ss->ssl3.policy, &vrange, ss)) { + /* Illegal suite. */ + PORT_SetError(SEC_ERROR_INVALID_ARGS); + goto loser; + } + } + + if (PR_CLIST_IS_EMPTY(&keys->keyShares)) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + goto loser; + } + if (PR_PREV_LINK(&keys->keyShares) != PR_NEXT_LINK(&keys->keyShares)) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + goto loser; + } + TLS13KeyShareEntry *entry = (TLS13KeyShareEntry *)PR_LIST_HEAD( + &keys->keyShares); + if (entry->group->keaType != ssl_kea_ecdh) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + goto loser; + } + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (!arena) { + goto loser; + } + pubKey = PORT_ArenaZNew(arena, SECKEYPublicKey); + if (!pubKey) { + goto loser; + } + pubKey->arena = arena; + arena = NULL; /* From here, this will be destroyed with the pubkey. */ + /* Dummy PKCS11 values because this key isn't on a slot. */ + pubKey->pkcs11Slot = NULL; + pubKey->pkcs11ID = CK_INVALID_HANDLE; + rv = ssl_ImportECDHKeyShare(pubKey, + entry->key_exchange.data, + entry->key_exchange.len, + entry->group); + if (rv != SECSuccess) { + goto loser; + } + + privKey = SECKEY_CopyPrivateKey(privKey); + if (!privKey) { + goto loser; + } + keys->privKey = ssl_NewEphemeralKeyPair(entry->group, privKey, pubKey); + if (!keys->privKey) { + goto loser; + } + pubKey = NULL; + ss->esniKeys = keys; + return SECSuccess; + +loser: + PORT_FreeArena(arena, PR_FALSE); + SECKEY_DestroyPublicKey(pubKey); + tls13_DestroyESNIKeys(keys); + return SECFailure; +} + +SECStatus +SSLExp_EnableESNI(PRFileDesc *fd, + const PRUint8 *esniKeys, + unsigned int esniKeysLen, + const char *dummySNI) +{ + sslSocket *ss; + sslEsniKeys *keys = NULL; + SECItem data = { siBuffer, CONST_CAST(PRUint8, esniKeys), esniKeysLen }; + SECStatus rv; + + ss = ssl_FindSocket(fd); + if (!ss) { + SSL_DBG(("%d: SSL[%d]: bad socket in %s", + SSL_GETPID(), fd, __FUNCTION__)); + return SECFailure; + } + + rv = tls13_DecodeESNIKeys(&data, &keys); + if (rv != SECSuccess) { + return SECFailure; + } + + if (dummySNI) { + keys->dummySni = PORT_Strdup(dummySNI); + if (!keys->dummySni) { + tls13_DestroyESNIKeys(keys); + return SECFailure; + } + } + + /* Delete in case it was set before. */ + tls13_DestroyESNIKeys(ss->esniKeys); + ss->esniKeys = keys; + + return SECSuccess; +} + +/* + * struct { + * opaque record_digest<0..2^16-1>; + * KeyShareEntry esni_key_share; + * Random client_hello_random; + * } ESNIContents; + */ +SECStatus +tls13_ComputeESNIKeys(const sslSocket *ss, + TLS13KeyShareEntry *entry, + sslKeyPair *keyPair, + const ssl3CipherSuiteDef *suite, + const PRUint8 *esniKeysHash, + const PRUint8 *keyShareBuf, + unsigned int keyShareBufLen, + const PRUint8 *clientRandom, + ssl3KeyMaterial *keyMat) +{ + PK11SymKey *Z = NULL; + PK11SymKey *Zx = NULL; + SECStatus ret = SECFailure; + PRUint8 esniContentsBuf[256]; /* Just big enough. */ + sslBuffer esniContents = SSL_BUFFER(esniContentsBuf); + PRUint8 hash[64]; + const ssl3BulkCipherDef *cipherDef = ssl_GetBulkCipherDef(suite); + size_t keySize = cipherDef->key_size; + size_t ivSize = cipherDef->iv_size + + cipherDef->explicit_nonce_size; /* This isn't always going to + * work, but it does for + * AES-GCM */ + unsigned int hashSize = tls13_GetHashSizeForHash(suite->prf_hash); + SECStatus rv; + + rv = tls13_HandleKeyShare(CONST_CAST(sslSocket, ss), entry, keyPair, + suite->prf_hash, &Z); + if (rv != SECSuccess) { + goto loser; + } + rv = tls13_HkdfExtract(NULL, Z, suite->prf_hash, &Zx); + if (rv != SECSuccess) { + goto loser; + } + + /* Encode ESNIContents. */ + rv = sslBuffer_AppendVariable(&esniContents, + esniKeysHash, hashSize, 2); + if (rv != SECSuccess) { + goto loser; + } + rv = sslBuffer_Append(&esniContents, keyShareBuf, keyShareBufLen); + if (rv != SECSuccess) { + goto loser; + } + rv = sslBuffer_Append(&esniContents, clientRandom, SSL3_RANDOM_LENGTH); + if (rv != SECSuccess) { + goto loser; + } + + PORT_Assert(hashSize <= sizeof(hash)); + rv = PK11_HashBuf(ssl3_HashTypeToOID(suite->prf_hash), + hash, + SSL_BUFFER_BASE(&esniContents), + SSL_BUFFER_LEN(&esniContents)); + ; + if (rv != SECSuccess) { + goto loser; + } + + rv = tls13_HkdfExpandLabel(Zx, suite->prf_hash, + hash, hashSize, + kHkdfPurposeEsniKey, strlen(kHkdfPurposeEsniKey), + ssl3_Alg2Mech(cipherDef->calg), + keySize, + &keyMat->key); + if (rv != SECSuccess) { + goto loser; + } + rv = tls13_HkdfExpandLabelRaw(Zx, suite->prf_hash, + hash, hashSize, + kHkdfPurposeEsniIv, strlen(kHkdfPurposeEsniIv), + keyMat->iv, ivSize); + if (rv != SECSuccess) { + goto loser; + } + + ret = SECSuccess; + +loser: + PK11_FreeSymKey(Z); + PK11_FreeSymKey(Zx); + return ret; +} + +/* Set up ESNI. This generates a private key as a side effect. */ +SECStatus +tls13_ClientSetupESNI(sslSocket *ss) +{ + ssl3CipherSuite suite; + sslEphemeralKeyPair *keyPair; + size_t i; + PRCList *cur; + SECStatus rv; + TLS13KeyShareEntry *share; + const sslNamedGroupDef *group = NULL; + PRTime now = PR_Now() / PR_USEC_PER_SEC; + + if (!ss->esniKeys) { + return SECSuccess; + } + + if ((ss->esniKeys->notBefore > now) || (ss->esniKeys->notAfter < now)) { + return SECSuccess; + } + + /* If we're not sending SNI, don't send ESNI. */ + if (!ssl_ShouldSendSNIExtension(ss, ss->url)) { + return SECSuccess; + } + + /* Pick the group. */ + for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) { + for (cur = PR_NEXT_LINK(&ss->esniKeys->keyShares); + cur != &ss->esniKeys->keyShares; + cur = PR_NEXT_LINK(cur)) { + if (!ss->namedGroupPreferences[i]) { + continue; + } + share = (TLS13KeyShareEntry *)cur; + if (share->group->name == ss->namedGroupPreferences[i]->name) { + group = ss->namedGroupPreferences[i]; + break; + } + } + } + + if (!group) { + /* No compatible group. */ + return SECSuccess; + } + + rv = ssl3_NegotiateCipherSuiteInner(ss, &ss->esniKeys->suites, + SSL_LIBRARY_VERSION_TLS_1_3, &suite); + if (rv != SECSuccess) { + return SECSuccess; + } + + rv = tls13_CreateKeyShare(ss, group, &keyPair); + if (rv != SECSuccess) { + return SECFailure; + } + + ss->xtnData.esniPrivateKey = keyPair; + ss->xtnData.esniSuite = suite; + ss->xtnData.peerEsniShare = share; + + return SECSuccess; +} + +/* + * struct { + * CipherSuite suite; + * KeyShareEntry key_share; + * opaque record_digest<0..2^16-1>; + * opaque encrypted_sni<0..2^16-1>; + * } ClientEncryptedSNI; + * + * struct { + * ServerNameList sni; + * opaque zeros[ESNIKeys.padded_length - length(sni)]; + * } PaddedServerNameList; + * + * struct { + * uint8 nonce[16]; + * PaddedServerNameList realSNI; + * } ClientESNIInner; + */ +SECStatus +tls13_FormatEsniAADInput(sslBuffer *aadInput, + PRUint8 *keyShare, unsigned int keyShareLen) +{ + SECStatus rv; + + /* 8 bytes of 0 for the sequence number. */ + rv = sslBuffer_AppendNumber(aadInput, 0, 8); + if (rv != SECSuccess) { + return SECFailure; + } + + /* Key share. */ + PORT_Assert(keyShareLen > 0); + rv = sslBuffer_Append(aadInput, keyShare, keyShareLen); + if (rv != SECSuccess) { + return SECFailure; + } + + return SECSuccess; +} + +static SECStatus +tls13_ServerGetEsniAEAD(const sslSocket *ss, PRUint64 suite, + const ssl3CipherSuiteDef **suiteDefp, + SSLAEADCipher *aeadp) +{ + SECStatus rv; + const ssl3CipherSuiteDef *suiteDef; + SSLAEADCipher aead; + + /* Check against the suite list for ESNI */ + PRBool csMatch = PR_FALSE; + sslReader csrdr = SSL_READER(ss->esniKeys->suites.data, + ss->esniKeys->suites.len); + while (SSL_READER_REMAINING(&csrdr)) { + PRUint64 asuite; + + rv = sslRead_ReadNumber(&csrdr, 2, &asuite); + if (rv != SECSuccess) { + return SECFailure; + } + if (asuite == suite) { + csMatch = PR_TRUE; + break; + } + } + if (!csMatch) { + return SECFailure; + } + + suiteDef = ssl_LookupCipherSuiteDef(suite); + PORT_Assert(suiteDef); + if (!suiteDef) { + return SECFailure; + } + aead = tls13_GetAead(ssl_GetBulkCipherDef(suiteDef)); + if (!aead) { + return SECFailure; + } + + *suiteDefp = suiteDef; + *aeadp = aead; + return SECSuccess; +} + +SECStatus +tls13_ServerDecryptEsniXtn(const sslSocket *ss, PRUint8 *in, unsigned int inLen, + PRUint8 *out, int *outLen, int maxLen) +{ + sslReader rdr = SSL_READER(in, inLen); + PRUint64 suite; + const ssl3CipherSuiteDef *suiteDef; + SSLAEADCipher aead = NULL; + TLSExtension *keyShareExtension; + TLS13KeyShareEntry *entry = NULL; + ssl3KeyMaterial keyMat = { NULL }; + + sslBuffer aadInput = SSL_BUFFER_EMPTY; + const PRUint8 *keyShareBuf; + sslReadBuffer buf; + unsigned int keyShareBufLen; + PRUint8 hash[64]; + SECStatus rv; + + /* Read the cipher suite. */ + rv = sslRead_ReadNumber(&rdr, 2, &suite); + if (rv != SECSuccess) { + goto loser; + } + + /* Find the AEAD */ + rv = tls13_ServerGetEsniAEAD(ss, suite, &suiteDef, &aead); + if (rv != SECSuccess) { + goto loser; + } + + /* Note where the KeyShare starts. */ + keyShareBuf = SSL_READER_CURRENT(&rdr); + rv = tls13_DecodeKeyShareEntry(&rdr, &entry); + if (rv != SECSuccess) { + goto loser; + } + keyShareBufLen = SSL_READER_CURRENT(&rdr) - keyShareBuf; + if (!entry || entry->group->name != ss->esniKeys->privKey->group->name) { + goto loser; + } + + /* The hash of the ESNIKeys structure. */ + rv = sslRead_ReadVariable(&rdr, 2, &buf); + if (rv != SECSuccess) { + goto loser; + } + + /* Check that the hash matches. */ + unsigned int hashLen = tls13_GetHashSizeForHash(suiteDef->prf_hash); + PORT_Assert(hashLen <= sizeof(hash)); + rv = PK11_HashBuf(ssl3_HashTypeToOID(suiteDef->prf_hash), + hash, + ss->esniKeys->data.data, ss->esniKeys->data.len); + if (rv != SECSuccess) { + goto loser; + } + + if (buf.len != hashLen) { + /* This is malformed. */ + goto loser; + } + if (0 != NSS_SecureMemcmp(hash, buf.buf, hashLen)) { + goto loser; + } + + rv = tls13_ComputeESNIKeys(ss, entry, + ss->esniKeys->privKey->keys, + suiteDef, + hash, keyShareBuf, keyShareBufLen, + ((sslSocket *)ss)->ssl3.hs.client_random, + &keyMat); + if (rv != SECSuccess) { + goto loser; + } + + /* Read the ciphertext. */ + rv = sslRead_ReadVariable(&rdr, 2, &buf); + if (rv != SECSuccess) { + goto loser; + } + + /* Check that this is empty. */ + if (SSL_READER_REMAINING(&rdr) > 0) { + goto loser; + } + + /* Find the key share extension. */ + keyShareExtension = ssl3_FindExtension(CONST_CAST(sslSocket, ss), + ssl_tls13_key_share_xtn); + if (!keyShareExtension) { + goto loser; + } + rv = tls13_FormatEsniAADInput(&aadInput, + keyShareExtension->data.data, + keyShareExtension->data.len); + if (rv != SECSuccess) { + goto loser; + } + + rv = aead(&keyMat, PR_TRUE /* Decrypt */, + out, outLen, maxLen, + buf.buf, buf.len, + SSL_BUFFER_BASE(&aadInput), + SSL_BUFFER_LEN(&aadInput)); + sslBuffer_Clear(&aadInput); + if (rv != SECSuccess) { + goto loser; + } + + ssl_DestroyKeyMaterial(&keyMat); + tls13_DestroyKeyShareEntry(entry); + return SECSuccess; + +loser: + FATAL_ERROR(CONST_CAST(sslSocket, ss), SSL_ERROR_RX_MALFORMED_ESNI_EXTENSION, illegal_parameter); + ssl_DestroyKeyMaterial(&keyMat); /* Safe because zeroed. */ + if (entry) { + tls13_DestroyKeyShareEntry(entry); + } + return SECFailure; +} diff --git a/security/nss/lib/ssl/tls13esni.h b/security/nss/lib/ssl/tls13esni.h new file mode 100644 index 000000000..6c52c9952 --- /dev/null +++ b/security/nss/lib/ssl/tls13esni.h @@ -0,0 +1,51 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is PRIVATE to SSL. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __tls13esni_h_ +#define __tls13esni_h_ + +struct sslEsniKeysStr { + SECItem data; /* The encoded record. */ + sslEphemeralKeyPair *privKey; + const char *dummySni; + PRCList keyShares; /* List of TLS13KeyShareEntry */ + SECItem suites; + PRUint16 paddedLength; + PRUint64 notBefore; + PRUint64 notAfter; +}; + +SECStatus SSLExp_SetESNIKeyPair(PRFileDesc *fd, + SECKEYPrivateKey *privKey, + const PRUint8 *record, unsigned int recordLen); + +SECStatus SSLExp_EnableESNI(PRFileDesc *fd, const PRUint8 *esniKeys, + unsigned int esniKeysLen, const char *dummySNI); +SECStatus SSLExp_EncodeESNIKeys(PRUint16 *cipherSuites, unsigned int cipherSuiteCount, + SSLNamedGroup group, SECKEYPublicKey *pubKey, + PRUint16 pad, PRUint64 notBefore, PRUint64 notAfter, + PRUint8 *out, unsigned int *outlen, unsigned int maxlen); +sslEsniKeys *tls13_CopyESNIKeys(sslEsniKeys *okeys); +void tls13_DestroyESNIKeys(sslEsniKeys *keys); +SECStatus tls13_ClientSetupESNI(sslSocket *ss); +SECStatus tls13_ComputeESNIKeys(const sslSocket *ss, + TLS13KeyShareEntry *entry, + sslKeyPair *keyPair, + const ssl3CipherSuiteDef *suite, + const PRUint8 *esniKeysHash, + const PRUint8 *keyShareBuf, + unsigned int keyShareBufLen, + const PRUint8 *clientRandom, + ssl3KeyMaterial *keyMat); +SECStatus tls13_FormatEsniAADInput(sslBuffer *aadInput, + PRUint8 *keyShare, unsigned int keyShareLen); + +SECStatus tls13_ServerDecryptEsniXtn(const sslSocket *ss, PRUint8 *in, unsigned int inLen, + PRUint8 *out, int *outLen, int maxLen); + +#endif diff --git a/security/nss/lib/ssl/tls13exthandle.c b/security/nss/lib/ssl/tls13exthandle.c index 1ab8a8e59..8ed18f69c 100644 --- a/security/nss/lib/ssl/tls13exthandle.c +++ b/security/nss/lib/ssl/tls13exthandle.c @@ -12,6 +12,7 @@ #include "pk11pub.h" #include "ssl3ext.h" #include "ssl3exthandle.h" +#include "tls13esni.h" #include "tls13exthandle.h" SECStatus @@ -71,7 +72,7 @@ tls13_ServerSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, * * opaque point <1..2^8-1>; */ -static PRUint32 +PRUint32 tls13_SizeOfKeyShareEntry(const SECKEYPublicKey *pubKey) { /* Size = NamedGroup(2) + length(2) + opaque<?> share */ @@ -86,14 +87,14 @@ tls13_SizeOfKeyShareEntry(const SECKEYPublicKey *pubKey) return 0; } -static SECStatus -tls13_EncodeKeyShareEntry(sslBuffer *buf, const sslEphemeralKeyPair *keyPair) +SECStatus +tls13_EncodeKeyShareEntry(sslBuffer *buf, SSLNamedGroup group, + SECKEYPublicKey *pubKey) { SECStatus rv; - SECKEYPublicKey *pubKey = keyPair->keys->pubKey; unsigned int size = tls13_SizeOfKeyShareEntry(pubKey); - rv = sslBuffer_AppendNumber(buf, keyPair->group->name, 2); + rv = sslBuffer_AppendNumber(buf, group, 2); if (rv != SECSuccess) return rv; rv = sslBuffer_AppendNumber(buf, size - 4, 2); @@ -123,6 +124,7 @@ tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, { SECStatus rv; PRCList *cursor; + unsigned int extStart; unsigned int lengthOffset; if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) { @@ -134,6 +136,8 @@ tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, SSL_TRC(3, ("%d: TLS13[%d]: send client key share xtn", SSL_GETPID(), ss->fd)); + extStart = SSL_BUFFER_LEN(buf); + /* Save the offset to the length. */ rv = sslBuffer_Skip(buf, 2, &lengthOffset); if (rv != SECSuccess) { @@ -144,7 +148,9 @@ tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, cursor != &ss->ephemeralKeyPairs; cursor = PR_NEXT_LINK(cursor)) { sslEphemeralKeyPair *keyPair = (sslEphemeralKeyPair *)cursor; - rv = tls13_EncodeKeyShareEntry(buf, keyPair); + rv = tls13_EncodeKeyShareEntry(buf, + keyPair->group->name, + keyPair->keys->pubKey); if (rv != SECSuccess) { return SECFailure; } @@ -154,50 +160,62 @@ tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, return SECFailure; } + rv = SECITEM_MakeItem(NULL, &xtnData->keyShareExtension, + SSL_BUFFER_BASE(buf) + extStart, + SSL_BUFFER_LEN(buf) - extStart); + if (rv != SECSuccess) { + return SECFailure; + } + *added = PR_TRUE; return SECSuccess; } -static SECStatus -tls13_HandleKeyShareEntry(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data) +SECStatus +tls13_DecodeKeyShareEntry(sslReader *rdr, TLS13KeyShareEntry **ksp) { SECStatus rv; - PRUint32 group; + PRUint64 group; const sslNamedGroupDef *groupDef; TLS13KeyShareEntry *ks = NULL; - SECItem share = { siBuffer, NULL, 0 }; + sslReadBuffer share; - rv = ssl3_ExtConsumeHandshakeNumber(ss, &group, 2, &data->data, &data->len); + rv = sslRead_ReadNumber(rdr, 2, &group); if (rv != SECSuccess) { - PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE); goto loser; } groupDef = ssl_LookupNamedGroup(group); - rv = ssl3_ExtConsumeHandshakeVariable(ss, &share, 2, &data->data, - &data->len); + rv = sslRead_ReadVariable(rdr, 2, &share); if (rv != SECSuccess) { goto loser; } + + /* This has to happen here because we want to consume + * the entire entry even if the group is unknown + * or disabled. */ /* If the group is disabled, continue. */ if (!groupDef) { return SECSuccess; } ks = PORT_ZNew(TLS13KeyShareEntry); - if (!ks) + if (!ks) { goto loser; + } ks->group = groupDef; - rv = SECITEM_CopyItem(NULL, &ks->key_exchange, &share); - if (rv != SECSuccess) + rv = SECITEM_MakeItem(NULL, &ks->key_exchange, + share.buf, share.len); + if (rv != SECSuccess) { goto loser; + } - PR_APPEND_LINK(&ks->link, &xtnData->remoteKeyShares); + *ksp = ks; return SECSuccess; loser: - if (ks) - tls13_DestroyKeyShareEntry(ks); + tls13_DestroyKeyShareEntry(ks); + return SECFailure; } /* Handle an incoming KeyShare extension at the client and copy to @@ -209,6 +227,7 @@ tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, { SECStatus rv; PORT_Assert(PR_CLIST_IS_EMPTY(&xtnData->remoteKeyShares)); + TLS13KeyShareEntry *ks = NULL; PORT_Assert(!ss->sec.isServer); @@ -221,16 +240,20 @@ tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, SSL_TRC(3, ("%d: SSL3[%d]: handle key_share extension", SSL_GETPID(), ss->fd)); - rv = tls13_HandleKeyShareEntry(ss, xtnData, data); - if (rv != SECSuccess) { + sslReader rdr = SSL_READER(data->data, data->len); + rv = tls13_DecodeKeyShareEntry(&rdr, &ks); + if ((rv != SECSuccess) || !ks) { + ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter); PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE); return SECFailure; } - if (data->len) { + if (SSL_READER_REMAINING(&rdr)) { + tls13_DestroyKeyShareEntry(ks); PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE); return SECFailure; } + PR_APPEND_LINK(&ks->link, &xtnData->remoteKeyShares); return SECSuccess; } @@ -273,7 +296,7 @@ tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, TLSExtensionData *xtnData, ssl_FreeEphemeralKeyPairs(CONST_CAST(sslSocket, ss)); /* And replace with our new share. */ - rv = tls13_CreateKeyShare(CONST_CAST(sslSocket, ss), group); + rv = tls13_AddKeyShare(CONST_CAST(sslSocket, ss), group); if (rv != SECSuccess) { ssl3_ExtSendAlert(ss, alert_fatal, internal_error); PORT_SetError(SEC_ERROR_KEYGEN_FAIL); @@ -315,12 +338,24 @@ tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, goto loser; } - while (data->len) { - rv = tls13_HandleKeyShareEntry(ss, xtnData, data); - if (rv != SECSuccess) + sslReader rdr = SSL_READER(data->data, data->len); + while (SSL_READER_REMAINING(&rdr)) { + TLS13KeyShareEntry *ks = NULL; + rv = tls13_DecodeKeyShareEntry(&rdr, &ks); + if (rv != SECSuccess) { + PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE); goto loser; + } + if (ks) { + /* |ks| == NULL if this is an unknown group. */ + PR_APPEND_LINK(&ks->link, &xtnData->remoteKeyShares); + } } + /* Keep track of negotiated extensions. */ + xtnData->negotiated[xtnData->numNegotiated++] = + ssl_tls13_key_share_xtn; + return SECSuccess; loser: @@ -342,7 +377,8 @@ tls13_ServerSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, keyPair = (sslEphemeralKeyPair *)PR_NEXT_LINK(&ss->ephemeralKeyPairs); - rv = tls13_EncodeKeyShareEntry(buf, keyPair); + rv = tls13_EncodeKeyShareEntry(buf, keyPair->group->name, + keyPair->keys->pubKey); if (rv != SECSuccess) { return SECFailure; } @@ -396,6 +432,7 @@ tls13_ClientSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, xtnData->lastXtnOffset = buf->len - 4; PORT_Assert(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3); + PORT_Assert(ss->sec.ci.sid->version >= SSL_LIBRARY_VERSION_TLS_1_3); /* Send a single ticket identity. */ session_ticket = &ss->sec.ci.sid->u.ssl3.locked.sessionTicket; @@ -751,7 +788,9 @@ tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnD } for (version = ss->vrange.max; version >= ss->vrange.min; --version) { - rv = sslBuffer_AppendNumber(buf, tls13_EncodeDraftVersion(version), 2); + PRUint16 wire = tls13_EncodeDraftVersion(version, + ss->protocolVariant); + rv = sslBuffer_AppendNumber(buf, wire, 2); if (rv != SECSuccess) { return SECFailure; } @@ -779,8 +818,9 @@ tls13_ServerSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnD SSL_TRC(3, ("%d: TLS13[%d]: server send supported_versions extension", SSL_GETPID(), ss->fd)); - rv = sslBuffer_AppendNumber( - buf, tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3), 2); + PRUint16 ver = tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3, + ss->protocolVariant); + rv = sslBuffer_AppendNumber(buf, ver, 2); if (rv != SECSuccess) { return SECFailure; } @@ -1056,3 +1096,276 @@ tls13_ServerSendHrrCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData, *added = PR_TRUE; return SECSuccess; } + +SECStatus +tls13_ClientSendEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) +{ + SECStatus rv; + PRUint8 sniBuf[1024]; + PRUint8 hash[64]; + sslBuffer sni = SSL_BUFFER(sniBuf); + const ssl3CipherSuiteDef *suiteDef; + ssl3KeyMaterial keyMat; + SSLAEADCipher aead; + PRUint8 outBuf[1024]; + int outLen; + unsigned int sniStart; + unsigned int sniLen; + sslBuffer aadInput = SSL_BUFFER_EMPTY; + unsigned int keyShareBufStart; + unsigned int keyShareBufLen; + + PORT_Memset(&keyMat, 0, sizeof(keyMat)); + + if (!ss->xtnData.esniPrivateKey) { + return SECSuccess; + } + + /* nonce */ + rv = PK11_GenerateRandom( + (unsigned char *)xtnData->esniNonce, sizeof(xtnData->esniNonce)); + if (rv != SECSuccess) { + return SECFailure; + } + rv = sslBuffer_Append(&sni, xtnData->esniNonce, sizeof(xtnData->esniNonce)); + if (rv != SECSuccess) { + return SECFailure; + } + + /* sni */ + sniStart = SSL_BUFFER_LEN(&sni); + rv = ssl3_ClientFormatServerNameXtn(ss, ss->url, xtnData, &sni); + if (rv != SECSuccess) { + return SECFailure; + } + + sniLen = SSL_BUFFER_LEN(&sni) - sniStart; + /* Padding. */ + if (ss->esniKeys->paddedLength > sniLen) { + unsigned int paddingRequired = ss->esniKeys->paddedLength - sniLen; + while (paddingRequired--) { + rv = sslBuffer_AppendNumber(&sni, 0, 1); + if (rv != SECSuccess) { + return SECFailure; + } + } + } + + suiteDef = ssl_LookupCipherSuiteDef(xtnData->esniSuite); + PORT_Assert(suiteDef); + if (!suiteDef) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + aead = tls13_GetAead(ssl_GetBulkCipherDef(suiteDef)); + if (!aead) { + return SECFailure; + } + + /* Format the first part of the extension so we have the + * encoded KeyShareEntry. */ + rv = sslBuffer_AppendNumber(buf, xtnData->esniSuite, 2); + if (rv != SECSuccess) { + return SECFailure; + } + keyShareBufStart = SSL_BUFFER_LEN(buf); + rv = tls13_EncodeKeyShareEntry(buf, + xtnData->esniPrivateKey->group->name, + xtnData->esniPrivateKey->keys->pubKey); + if (rv != SECSuccess) { + return SECFailure; + } + keyShareBufLen = SSL_BUFFER_LEN(buf) - keyShareBufStart; + + if (tls13_GetHashSizeForHash(suiteDef->prf_hash) > sizeof(hash)) { + PORT_Assert(PR_FALSE); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + + rv = PK11_HashBuf(ssl3_HashTypeToOID(suiteDef->prf_hash), + hash, + ss->esniKeys->data.data, + ss->esniKeys->data.len); + if (rv != SECSuccess) { + PORT_Assert(PR_FALSE); + return SECFailure; + } + + rv = sslBuffer_AppendVariable(buf, hash, + tls13_GetHashSizeForHash(suiteDef->prf_hash), 2); + if (rv != SECSuccess) { + return SECFailure; + } + + /* Compute the ESNI keys. */ + rv = tls13_ComputeESNIKeys(ss, xtnData->peerEsniShare, + xtnData->esniPrivateKey->keys, + suiteDef, + hash, + SSL_BUFFER_BASE(buf) + keyShareBufStart, + keyShareBufLen, + CONST_CAST(PRUint8, ss->ssl3.hs.client_random), + &keyMat); + if (rv != SECSuccess) { + return SECFailure; + } + + rv = tls13_FormatEsniAADInput(&aadInput, + xtnData->keyShareExtension.data, + xtnData->keyShareExtension.len); + if (rv != SECSuccess) { + ssl_DestroyKeyMaterial(&keyMat); + return SECFailure; + } + /* Now encrypt. */ + rv = aead(&keyMat, PR_FALSE /* Encrypt */, + outBuf, &outLen, sizeof(outBuf), + SSL_BUFFER_BASE(&sni), + SSL_BUFFER_LEN(&sni), + SSL_BUFFER_BASE(&aadInput), + SSL_BUFFER_LEN(&aadInput)); + ssl_DestroyKeyMaterial(&keyMat); + sslBuffer_Clear(&aadInput); + if (rv != SECSuccess) { + return SECFailure; + } + + /* Encode the rest. */ + rv = sslBuffer_AppendVariable(buf, outBuf, outLen, 2); + if (rv != SECSuccess) { + return SECFailure; + } + + *added = PR_TRUE; + return SECSuccess; +} + +static SECStatus +tls13_ServerSendEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) +{ + SECStatus rv; + + rv = sslBuffer_Append(buf, xtnData->esniNonce, sizeof(xtnData->esniNonce)); + if (rv != SECSuccess) { + return SECFailure; + } + + *added = PR_TRUE; + return SECSuccess; +} + +SECStatus +tls13_ServerHandleEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData, + SECItem *data) +{ + sslReadBuffer buf; + PRUint8 *plainText = NULL; + int ptLen; + SECStatus rv; + + /* If we are doing < TLS 1.3, then ignore this. */ + if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { + return SECSuccess; + } + + if (!ss->esniKeys) { + /* Apparently we used to be configured for ESNI, but + * no longer. This violates the spec, or the client is + * broken. */ + return SECFailure; + } + + plainText = PORT_ZAlloc(data->len); + if (!plainText) { + return SECFailure; + } + rv = tls13_ServerDecryptEsniXtn(ss, data->data, data->len, + plainText, &ptLen, data->len); + if (rv) { + goto loser; + } + + /* Read out the interior extension. */ + sslReader sniRdr = SSL_READER(plainText, ptLen); + + rv = sslRead_Read(&sniRdr, sizeof(xtnData->esniNonce), &buf); + if (rv != SECSuccess) { + goto loser; + } + PORT_Memcpy(xtnData->esniNonce, buf.buf, sizeof(xtnData->esniNonce)); + + /* We need to capture the whole block with the length. */ + SECItem sniItem = { siBuffer, (unsigned char *)SSL_READER_CURRENT(&sniRdr), 0 }; + rv = sslRead_ReadVariable(&sniRdr, 2, &buf); + if (rv != SECSuccess) { + goto loser; + } + sniItem.len = buf.len + 2; + + /* Check the padding. Note we don't need to do this in constant time + * because it's inside the AEAD boundary. */ + /* TODO(ekr@rtfm.com): check that the padding is the right length. */ + PRUint64 tmp; + while (SSL_READER_REMAINING(&sniRdr)) { + rv = sslRead_ReadNumber(&sniRdr, 1, &tmp); + if (rv != SECSuccess) { + goto loser; + } + if (tmp != 0) { + goto loser; + } + } + + rv = ssl3_HandleServerNameXtn(ss, xtnData, &sniItem); + if (rv != SECSuccess) { + goto loser; + } + + rv = ssl3_RegisterExtensionSender(ss, xtnData, + ssl_tls13_encrypted_sni_xtn, + tls13_ServerSendEsniXtn); + if (rv != SECSuccess) { + goto loser; + } + + /* Keep track of negotiated extensions. */ + xtnData->negotiated[xtnData->numNegotiated++] = + ssl_tls13_encrypted_sni_xtn; + + PORT_ZFree(plainText, data->len); + return SECSuccess; +loser: + PORT_ZFree(plainText, data->len); + return SECFailure; +} + +/* Function to check the extension. We don't install a handler here + * because we need to check for the presence of the extension as + * well and it's easier to do it in one place. */ +SECStatus +tls13_ClientCheckEsniXtn(sslSocket *ss) +{ + TLSExtension *esniExtension = + ssl3_FindExtension(ss, ssl_tls13_encrypted_sni_xtn); + if (!esniExtension) { + FATAL_ERROR(ss, SSL_ERROR_MISSING_ESNI_EXTENSION, missing_extension); + return SECFailure; + } + + if (esniExtension->data.len != sizeof(ss->xtnData.esniNonce)) { + FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_ESNI_EXTENSION, illegal_parameter); + return SECFailure; + } + + if (0 != NSS_SecureMemcmp(esniExtension->data.data, + ss->xtnData.esniNonce, + sizeof(ss->xtnData.esniNonce))) { + FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_ESNI_EXTENSION, illegal_parameter); + return SECFailure; + } + + return SECSuccess; +} diff --git a/security/nss/lib/ssl/tls13exthandle.h b/security/nss/lib/ssl/tls13exthandle.h index edce94d83..dd64b44ff 100644 --- a/security/nss/lib/ssl/tls13exthandle.h +++ b/security/nss/lib/ssl/tls13exthandle.h @@ -84,5 +84,14 @@ SECStatus tls13_ServerSendHrrKeyShareXtn(const sslSocket *ss, SECStatus tls13_ServerSendHrrCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData, sslBuffer *buf, PRBool *added); +SECStatus tls13_DecodeKeyShareEntry(sslReader *rdr, TLS13KeyShareEntry **ksp); +PRUint32 tls13_SizeOfKeyShareEntry(const SECKEYPublicKey *pubKey); +SECStatus tls13_EncodeKeyShareEntry(sslBuffer *buf, SSLNamedGroup group, + SECKEYPublicKey *pubKey); +SECStatus tls13_ClientSendEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added); +SECStatus tls13_ServerHandleEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData, + SECItem *data); +SECStatus tls13_ClientCheckEsniXtn(sslSocket *ss); #endif |