summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/ssl
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/ssl')
-rw-r--r--security/nss/lib/ssl/SSLerrs.h12
-rw-r--r--security/nss/lib/ssl/authcert.c2
-rw-r--r--security/nss/lib/ssl/cmpcert.c31
-rw-r--r--security/nss/lib/ssl/config.mk4
-rw-r--r--security/nss/lib/ssl/dtls13con.c10
-rw-r--r--security/nss/lib/ssl/dtls13con.h2
-rw-r--r--security/nss/lib/ssl/dtlscon.c22
-rw-r--r--security/nss/lib/ssl/dtlscon.h2
-rw-r--r--security/nss/lib/ssl/manifest.mn2
-rw-r--r--security/nss/lib/ssl/ssl.gyp6
-rw-r--r--security/nss/lib/ssl/ssl.h19
-rw-r--r--security/nss/lib/ssl/ssl3con.c1004
-rw-r--r--security/nss/lib/ssl/ssl3ecc.c7
-rw-r--r--security/nss/lib/ssl/ssl3ext.c13
-rw-r--r--security/nss/lib/ssl/ssl3ext.h10
-rw-r--r--security/nss/lib/ssl/ssl3exthandle.c91
-rw-r--r--security/nss/lib/ssl/ssl3exthandle.h4
-rw-r--r--security/nss/lib/ssl/ssl3gthr.c16
-rw-r--r--security/nss/lib/ssl/ssl3prot.h15
-rw-r--r--security/nss/lib/ssl/sslcert.c2
-rw-r--r--security/nss/lib/ssl/sslerr.h4
-rw-r--r--security/nss/lib/ssl/sslexp.h60
-rw-r--r--security/nss/lib/ssl/sslimpl.h48
-rw-r--r--security/nss/lib/ssl/sslnonce.c48
-rw-r--r--security/nss/lib/ssl/sslsecur.c44
-rw-r--r--security/nss/lib/ssl/sslsock.c97
-rw-r--r--security/nss/lib/ssl/sslspec.c2
-rw-r--r--security/nss/lib/ssl/sslt.h11
-rw-r--r--security/nss/lib/ssl/tls13con.c290
-rw-r--r--security/nss/lib/ssl/tls13con.h36
-rw-r--r--security/nss/lib/ssl/tls13esni.c844
-rw-r--r--security/nss/lib/ssl/tls13esni.h51
-rw-r--r--security/nss/lib/ssl/tls13exthandle.c375
-rw-r--r--security/nss/lib/ssl/tls13exthandle.h9
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(&copy->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, &copy, 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(&copy, 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