summaryrefslogtreecommitdiff
path: root/libs/nss/src/lib/ssl
diff options
context:
space:
mode:
Diffstat (limited to 'libs/nss/src/lib/ssl')
-rw-r--r--libs/nss/src/lib/ssl/Makefile2
-rw-r--r--libs/nss/src/lib/ssl/config.mk7
-rw-r--r--libs/nss/src/lib/ssl/dtls13con.c24
-rw-r--r--libs/nss/src/lib/ssl/dtls13con.h1
-rw-r--r--libs/nss/src/lib/ssl/dtlscon.c14
-rw-r--r--libs/nss/src/lib/ssl/manifest.mn3
-rw-r--r--libs/nss/src/lib/ssl/ssl.gyp1
-rw-r--r--libs/nss/src/lib/ssl/ssl.h19
-rw-r--r--libs/nss/src/lib/ssl/ssl3con.c315
-rw-r--r--libs/nss/src/lib/ssl/ssl3ext.c2
-rw-r--r--libs/nss/src/lib/ssl/ssl3ext.h4
-rw-r--r--libs/nss/src/lib/ssl/ssl3exthandle.c4
-rw-r--r--libs/nss/src/lib/ssl/ssl3gthr.c68
-rw-r--r--libs/nss/src/lib/ssl/ssl3prot.h2
-rw-r--r--libs/nss/src/lib/ssl/sslencode.c5
-rw-r--r--libs/nss/src/lib/ssl/sslerr.h1
-rw-r--r--libs/nss/src/lib/ssl/sslexp.h52
-rw-r--r--libs/nss/src/lib/ssl/sslimpl.h26
-rw-r--r--libs/nss/src/lib/ssl/sslinfo.c37
-rw-r--r--libs/nss/src/lib/ssl/sslnonce.c3
-rw-r--r--libs/nss/src/lib/ssl/sslsecur.c2
-rw-r--r--libs/nss/src/lib/ssl/sslsnce.c4
-rw-r--r--libs/nss/src/lib/ssl/sslsock.c59
-rw-r--r--libs/nss/src/lib/ssl/sslspec.h5
-rw-r--r--libs/nss/src/lib/ssl/sslt.h12
-rw-r--r--libs/nss/src/lib/ssl/tls13con.c639
-rw-r--r--libs/nss/src/lib/ssl/tls13con.h6
-rw-r--r--libs/nss/src/lib/ssl/tls13exthandle.c203
-rw-r--r--libs/nss/src/lib/ssl/tls13hkdf.c35
-rw-r--r--libs/nss/src/lib/ssl/tls13psk.c219
-rw-r--r--libs/nss/src/lib/ssl/tls13psk.h58
-rw-r--r--libs/nss/src/lib/ssl/tls13replay.c8
32 files changed, 1389 insertions, 451 deletions
diff --git a/libs/nss/src/lib/ssl/Makefile b/libs/nss/src/lib/ssl/Makefile
index 24fccc590..8a8b06f4b 100644
--- a/libs/nss/src/lib/ssl/Makefile
+++ b/libs/nss/src/lib/ssl/Makefile
@@ -61,5 +61,3 @@ include $(CORE_DEPTH)/coreconf/rules.mk
#######################################################################
# (7) Execute "local" rules. (OPTIONAL). #
#######################################################################
-
-export:: private_export
diff --git a/libs/nss/src/lib/ssl/config.mk b/libs/nss/src/lib/ssl/config.mk
index d13613f78..df4ab35e6 100644
--- a/libs/nss/src/lib/ssl/config.mk
+++ b/libs/nss/src/lib/ssl/config.mk
@@ -9,13 +9,6 @@ endif
ifeq (,$(filter-out WIN%,$(OS_TARGET)))
-# don't want the 32 in the shared library name
-SHARED_LIBRARY = $(OBJDIR)/$(DLL_PREFIX)$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX)
-IMPORT_LIBRARY = $(OBJDIR)/$(IMPORT_LIB_PREFIX)$(LIBRARY_NAME)$(LIBRARY_VERSION)$(IMPORT_LIB_SUFFIX)
-
-RES = $(OBJDIR)/ssl.res
-RESNAME = ssl.rc
-
ifdef NS_USE_GCC
EXTRA_SHARED_LIBS += \
-L$(DIST)/lib \
diff --git a/libs/nss/src/lib/ssl/dtls13con.c b/libs/nss/src/lib/ssl/dtls13con.c
index daa5e2c7c..5307419b6 100644
--- a/libs/nss/src/lib/ssl/dtls13con.c
+++ b/libs/nss/src/lib/ssl/dtls13con.c
@@ -185,6 +185,27 @@ dtls13_SendAckCb(sslSocket *ss)
(void)dtls13_SendAck(ss);
}
+/* Limits from draft-ietf-tls-dtls13-38; section 4.5.3. */
+PRBool
+dtls13_AeadLimitReached(ssl3CipherSpec *spec)
+{
+ if (spec->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ switch (spec->cipherDef->calg) {
+ case ssl_calg_chacha20:
+ case ssl_calg_aes_gcm:
+ return spec->deprotectionFailures >= (1ULL << 36);
+#ifdef UNSAFE_FUZZER_MODE
+ case ssl_calg_null:
+ return PR_FALSE;
+#endif
+ default:
+ PORT_Assert(0);
+ break;
+ }
+ }
+ return PR_FALSE;
+}
+
/* Zero length messages are very simple to check. */
static PRBool
dtls_IsEmptyMessageAcknowledged(sslSocket *ss, PRUint16 msgSeq, PRUint32 offset)
@@ -392,8 +413,7 @@ dtls13_HandleOutOfEpochRecord(sslSocket *ss, const ssl3CipherSpec *spec,
* server, we might have processed the client's Finished and
* moved on to application data keys, but the client has
* retransmitted Finished (e.g., because our ACK got lost.)
- * We just retransmit the previous Finished to let the client
- * complete. */
+ * We just retransmit the ACK to let the client complete. */
if (rType == ssl_ct_handshake) {
if ((ss->sec.isServer) &&
(ss->ssl3.hs.ws == idle_handshake)) {
diff --git a/libs/nss/src/lib/ssl/dtls13con.h b/libs/nss/src/lib/ssl/dtls13con.h
index 057d63efb..bfe8d4020 100644
--- a/libs/nss/src/lib/ssl/dtls13con.h
+++ b/libs/nss/src/lib/ssl/dtls13con.h
@@ -31,6 +31,7 @@ void dtls13_HolddownTimerCb(sslSocket *ss);
void dtls_ReceivedFirstMessageInFlight(sslSocket *ss);
SECStatus dtls13_MaskSequenceNumber(sslSocket *ss, ssl3CipherSpec *spec,
PRUint8 *hdr, PRUint8 *cipherText, PRUint32 cipherTextLen);
+PRBool dtls13_AeadLimitReached(ssl3CipherSpec *spec);
CK_MECHANISM_TYPE tls13_SequenceNumberEncryptionMechanism(SSLCipherAlgorithm bulkAlgorithm);
diff --git a/libs/nss/src/lib/ssl/dtlscon.c b/libs/nss/src/lib/ssl/dtlscon.c
index 51530de82..10e550e0f 100644
--- a/libs/nss/src/lib/ssl/dtlscon.c
+++ b/libs/nss/src/lib/ssl/dtlscon.c
@@ -270,12 +270,6 @@ SECStatus
dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum,
sslBuffer *origBuf)
{
- /* XXX OK for now.
- * This doesn't work properly with asynchronous certificate validation.
- * because that returns a WOULDBLOCK error. The current DTLS
- * applications do not need asynchronous validation, but in the
- * future we will need to add this.
- */
sslBuffer buf = *origBuf;
SECStatus rv = SECSuccess;
PRBool discarded = PR_FALSE;
@@ -310,7 +304,8 @@ dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum,
if (message_length > MAX_HANDSHAKE_MSG_LEN) {
(void)ssl3_DecodeError(ss);
PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
- return SECFailure;
+ rv = SECFailure;
+ goto loser;
}
#undef MAX_HANDSHAKE_MSG_LEN
@@ -485,7 +480,7 @@ dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum,
}
// This should never happen, but belt and suspenders.
- if (rv == SECFailure) {
+ if (rv != SECSuccess) {
PORT_Assert(0);
goto loser;
}
@@ -505,9 +500,6 @@ dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum,
loser:
origBuf->len = 0; /* So ssl3_GatherAppDataRecord will keep looping. */
-
- /* XXX OK for now. In future handle rv == SECWouldBlock safely in order
- * to deal with asynchronous certificate verification */
return rv;
}
diff --git a/libs/nss/src/lib/ssl/manifest.mn b/libs/nss/src/lib/ssl/manifest.mn
index ac37c8648..5b3584ba9 100644
--- a/libs/nss/src/lib/ssl/manifest.mn
+++ b/libs/nss/src/lib/ssl/manifest.mn
@@ -19,7 +19,6 @@ EXPORTS = \
$(NULL)
MODULE = nss
-MAPFILE = $(OBJDIR)/ssl.def
CSRCS = \
dtlscon.c \
@@ -56,6 +55,7 @@ CSRCS = \
tls13exthandle.c \
tls13hashstate.c \
tls13hkdf.c \
+ tls13psk.c \
tls13replay.c \
sslcert.c \
sslgrp.c \
@@ -66,6 +66,7 @@ CSRCS = \
LIBRARY_NAME = ssl
LIBRARY_VERSION = 3
+MAPFILE = $(OBJDIR)/$(LIBRARY_NAME).def
# This part of the code, including all sub-dirs, can be optimized for size
export ALLOW_OPT_CODE_SIZE = 1
diff --git a/libs/nss/src/lib/ssl/ssl.gyp b/libs/nss/src/lib/ssl/ssl.gyp
index 3e1b5531a..5c84a1f03 100644
--- a/libs/nss/src/lib/ssl/ssl.gyp
+++ b/libs/nss/src/lib/ssl/ssl.gyp
@@ -48,6 +48,7 @@
'tls13exthandle.c',
'tls13hashstate.c',
'tls13hkdf.c',
+ 'tls13psk.c',
'tls13replay.c',
'tls13subcerts.c',
],
diff --git a/libs/nss/src/lib/ssl/ssl.h b/libs/nss/src/lib/ssl/ssl.h
index a55ffcddc..43a0f3228 100644
--- a/libs/nss/src/lib/ssl/ssl.h
+++ b/libs/nss/src/lib/ssl/ssl.h
@@ -327,6 +327,25 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd);
*/
#define SSL_ENABLE_DELEGATED_CREDENTIALS 40
+/* Causes TLS (>=1.3) to suppress the EndOfEarlyData message in stream mode.
+ *
+ * This is not advisable in general, but the message only exists to delineate
+ * early data in a streamed connection. DTLS does not use this message as a
+ * result. The integration of TLS with QUIC, which uses a record/packet
+ * protection layer that is unreliable, also does not use this message.
+ *
+ * On the server, this requires that SSL_RecordLayerData be used.
+ * EndOfEarlyData is otherwise needed to drive key changes. Additionally,
+ * servers that use this API must check that handshake messages (Certificate,
+ * CertificateVerify, and Finished in particular) are only received in epoch 2
+ * (Handshake). SSL_RecordLayerData will accept these handshake messages if
+ * they are passed as epoch 1 (Early Data) in a single call.
+ *
+ * Using this option will cause connections to fail if early data is attempted
+ * and the peer expects this message.
+ */
+#define SSL_SUPPRESS_END_OF_EARLY_DATA 41
+
#ifdef SSL_DEPRECATED_FUNCTION
/* Old deprecated function names */
SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRIntn on);
diff --git a/libs/nss/src/lib/ssl/ssl3con.c b/libs/nss/src/lib/ssl/ssl3con.c
index 7f581e792..b652dcea3 100644
--- a/libs/nss/src/lib/ssl/ssl3con.c
+++ b/libs/nss/src/lib/ssl/ssl3con.c
@@ -21,6 +21,7 @@
#include "sslerr.h"
#include "ssl3ext.h"
#include "ssl3exthandle.h"
+#include "tls13psk.h"
#include "tls13subcerts.h"
#include "prtime.h"
#include "prinrval.h"
@@ -518,7 +519,7 @@ ssl3_DecodeContentType(int msgType)
rv = "application_data (23)";
break;
case ssl_ct_ack:
- rv = "ack (25)";
+ rv = "ack (26)";
break;
default:
sprintf(line, "*UNKNOWN* record type! (%d)", msgType);
@@ -783,15 +784,19 @@ ssl_HasCert(const sslSocket *ss, PRUint16 maxVersion, SSLAuthType authType)
* Both by policy and by having a token that supports it. */
static PRBool
ssl_SignatureSchemeAccepted(PRUint16 minVersion,
- SSLSignatureScheme scheme)
+ SSLSignatureScheme scheme,
+ PRBool forCert)
{
/* Disable RSA-PSS schemes if there are no tokens to verify them. */
if (ssl_IsRsaPssSignatureScheme(scheme)) {
if (!PK11_TokenExists(auth_alg_defs[ssl_auth_rsa_pss])) {
return PR_FALSE;
}
- } else if (ssl_IsRsaPkcs1SignatureScheme(scheme)) {
- /* Disable PKCS#1 signatures if we are limited to TLS 1.3. */
+ } else if (!forCert && ssl_IsRsaPkcs1SignatureScheme(scheme)) {
+ /* Disable PKCS#1 signatures if we are limited to TLS 1.3.
+ * We still need to advertise PKCS#1 signatures in CH and CR
+ * for certificate signatures.
+ */
if (minVersion >= SSL_LIBRARY_VERSION_TLS_1_3) {
return PR_FALSE;
}
@@ -850,7 +855,8 @@ ssl_CheckSignatureSchemes(sslSocket *ss)
/* Ensure that there is a signature scheme that can be accepted.*/
for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
if (ssl_SignatureSchemeAccepted(ss->vrange.min,
- ss->ssl3.signatureSchemes[i])) {
+ ss->ssl3.signatureSchemes[i],
+ PR_FALSE /* forCert */)) {
return SECSuccess;
}
}
@@ -879,7 +885,7 @@ ssl_HasSignatureScheme(const sslSocket *ss, SSLAuthType authType)
PRBool acceptable = authType == schemeAuthType ||
(schemeAuthType == ssl_auth_rsa_pss &&
authType == ssl_auth_rsa_sign);
- if (acceptable && ssl_SignatureSchemeAccepted(ss->version, scheme)) {
+ if (acceptable && ssl_SignatureSchemeAccepted(ss->version, scheme, PR_FALSE /* forCert */)) {
return PR_TRUE;
}
}
@@ -912,6 +918,13 @@ ssl3_config_match_init(sslSocket *ss)
if (SSL_ALL_VERSIONS_DISABLED(&ss->vrange)) {
return 0;
}
+ if (ss->sec.isServer && ss->psk &&
+ PR_CLIST_IS_EMPTY(&ss->serverCerts) &&
+ (ss->opt.requestCertificate || ss->opt.requireCertificate)) {
+ /* PSK and certificate auth cannot be combined. */
+ PORT_SetError(SSL_ERROR_NO_CERTIFICATE);
+ return 0;
+ }
if (ssl_CheckSignatureSchemes(ss) != SECSuccess) {
return 0; /* Code already set. */
}
@@ -1009,6 +1022,16 @@ ssl3_config_match(const ssl3CipherSuiteCfg *suite, PRUint8 policy,
return PR_FALSE;
}
+ /* If a PSK is selected, disable suites that use a different hash than
+ * the PSK. We advertise non-PSK-compatible suites in the CH, as we could
+ * fallback to certificate auth. The client handler will check hash
+ * compatibility before committing to use the PSK. */
+ if (ss->xtnData.selectedPsk) {
+ if (ss->xtnData.selectedPsk->hash != cipher_def->prf_hash) {
+ return PR_FALSE;
+ }
+ }
+
return ssl3_CipherSuiteAllowedForVersionRange(suite->cipher_suite, vrange);
}
@@ -5333,10 +5356,11 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
}
if (extensionBuf.len) {
- /* If we are sending a PSK binder, replace the dummy value. Note that
- * we only set statelessResume on the client in TLS 1.3. */
- if (ss->statelessResume &&
- ss->xtnData.sentSessionTicketInClientHello) {
+ /* If we are sending a PSK binder, replace the dummy value. */
+ if (ssl3_ExtensionAdvertised(ss, ssl_tls13_pre_shared_key_xtn)) {
+ PORT_Assert(ss->psk ||
+ (ss->statelessResume && ss->xtnData.sentSessionTicketInClientHello));
+ PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks));
rv = tls13_WriteExtensionsWithBinder(ss, &extensionBuf);
} else {
rv = ssl3_AppendBufferToHandshakeVariable(ss, &extensionBuf, 2);
@@ -6599,7 +6623,7 @@ ssl_CheckServerSessionIdCorrectness(sslSocket *ss, SECItem *sidBytes)
* fake. Check for the real value. */
if (sentRealSid) {
sidMatch = (sidBytes->len == sid->u.ssl3.sessionIDLength) &&
- PORT_Memcmp(sid->u.ssl3.sessionID, sidBytes->data, sidBytes->len) == 0;
+ (!sidBytes->len || PORT_Memcmp(sid->u.ssl3.sessionID, sidBytes->data, sidBytes->len) == 0);
} else {
/* Otherwise, the session ID was a fake if TLS 1.3 compat mode is
* enabled. If so, check for the fake value. */
@@ -7629,16 +7653,6 @@ ssl3_CompleteHandleCertificateRequest(sslSocket *ss,
/* check what the callback function returned */
if ((!ss->ssl3.clientCertificate) || (!ss->ssl3.clientPrivateKey)) {
/* we are missing either the key or cert */
- if (ss->ssl3.clientCertificate) {
- /* got a cert, but no key - free it */
- CERT_DestroyCertificate(ss->ssl3.clientCertificate);
- ss->ssl3.clientCertificate = NULL;
- }
- if (ss->ssl3.clientPrivateKey) {
- /* got a key, but no cert - free it */
- SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
- ss->ssl3.clientPrivateKey = NULL;
- }
goto send_no_certificate;
}
/* Setting ssl3.clientCertChain non-NULL will cause
@@ -7648,22 +7662,33 @@ ssl3_CompleteHandleCertificateRequest(sslSocket *ss,
ss->ssl3.clientCertificate,
certUsageSSLClient, PR_FALSE);
if (ss->ssl3.clientCertChain == NULL) {
- CERT_DestroyCertificate(ss->ssl3.clientCertificate);
- ss->ssl3.clientCertificate = NULL;
- SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
- ss->ssl3.clientPrivateKey = NULL;
goto send_no_certificate;
}
if (ss->ssl3.hs.hashType == handshake_hash_record ||
ss->ssl3.hs.hashType == handshake_hash_single) {
rv = ssl_PickClientSignatureScheme(ss, signatureSchemes,
signatureSchemeCount);
+ if (rv != SECSuccess) {
+ /* This should only happen if our schemes changed or
+ * if an RSA-PSS cert was selected, but the token
+ * does not support PSS schemes. */
+ goto send_no_certificate;
+ }
}
break; /* not an error */
case SECFailure:
default:
send_no_certificate:
+ CERT_DestroyCertificate(ss->ssl3.clientCertificate);
+ SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
+ ss->ssl3.clientCertificate = NULL;
+ ss->ssl3.clientPrivateKey = NULL;
+ if (ss->ssl3.clientCertChain) {
+ CERT_DestroyCertificateList(ss->ssl3.clientCertChain);
+ ss->ssl3.clientCertChain = NULL;
+ }
+
if (ss->version > SSL_LIBRARY_VERSION_3_0) {
ss->ssl3.sendEmptyCert = PR_TRUE;
} else {
@@ -8105,26 +8130,53 @@ ssl3_KEASupportsTickets(const ssl3KEADef *kea_def)
return PR_TRUE;
}
+static PRBool
+ssl3_PeerSupportsCipherSuite(const SECItem *peerSuites, uint16_t suite)
+{
+ for (unsigned int i = 0; i + 1 < peerSuites->len; i += 2) {
+ PRUint16 suite_i = (peerSuites->data[i] << 8) | peerSuites->data[i + 1];
+ if (suite_i == suite) {
+ return PR_TRUE;
+ }
+ }
+ return PR_FALSE;
+}
+
SECStatus
ssl3_NegotiateCipherSuiteInner(sslSocket *ss, const SECItem *suites,
PRUint16 version, PRUint16 *suitep)
{
- unsigned int j;
unsigned int i;
+ SSLVersionRange vrange = { version, version };
- for (j = 0; j < ssl_V3_SUITES_IMPLEMENTED; j++) {
- ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j];
- SSLVersionRange vrange = { version, version };
+ /* If we negotiated an External PSK and that PSK has a ciphersuite
+ * configured, we need to constrain our choice. If the client does
+ * not support it, negotiate a certificate auth suite and fall back.
+ */
+ if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
+ ss->xtnData.selectedPsk &&
+ ss->xtnData.selectedPsk->type == ssl_psk_external &&
+ ss->xtnData.selectedPsk->zeroRttSuite != TLS_NULL_WITH_NULL_NULL) {
+ PRUint16 pskSuite = ss->xtnData.selectedPsk->zeroRttSuite;
+ ssl3CipherSuiteCfg *pskSuiteCfg = ssl_LookupCipherSuiteCfgMutable(pskSuite,
+ ss->cipherSuites);
+ if (ssl3_config_match(pskSuiteCfg, ss->ssl3.policy, &vrange, ss) &&
+ ssl3_PeerSupportsCipherSuite(suites, pskSuite)) {
+ *suitep = pskSuite;
+ return SECSuccess;
+ }
+ }
+
+ for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
+ ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i];
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;
- }
+ if (!ssl3_PeerSupportsCipherSuite(suites, suite->cipher_suite)) {
+ continue;
}
+ *suitep = suite->cipher_suite;
+ return SECSuccess;
}
PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
return SECFailure;
@@ -9757,12 +9809,13 @@ ssl3_SendServerKeyExchange(sslSocket *ss)
}
SECStatus
-ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion, sslBuffer *buf)
+ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRBool forCert,
+ sslBuffer *buf)
{
SSLSignatureScheme filtered[MAX_SIGNATURE_SCHEMES] = { 0 };
unsigned int filteredCount = 0;
- SECStatus rv = ssl3_FilterSigAlgs(ss, minVersion, PR_FALSE,
+ SECStatus rv = ssl3_FilterSigAlgs(ss, minVersion, PR_FALSE, forCert,
PR_ARRAY_SIZE(filtered),
filtered, &filteredCount);
if (rv != SECSuccess) {
@@ -9797,8 +9850,21 @@ ssl3_EncodeFilteredSigAlgs(const sslSocket *ss, const SSLSignatureScheme *scheme
return sslBuffer_InsertLength(buf, lengthOffset, 2);
}
+/*
+ * In TLS 1.3 we are permitted to advertise support for PKCS#1
+ * schemes. This doesn't affect the signatures in TLS itself, just
+ * those on certificates. Not advertising PKCS#1 signatures creates a
+ * serious compatibility risk as it excludes many certificate chains
+ * that include PKCS#1. Hence, forCert is used to enable advertising
+ * PKCS#1 support. Note that we include these in signature_algorithms
+ * because we don't yet support signature_algorithms_cert. TLS 1.3
+ * requires that PKCS#1 schemes are placed last in the list if they
+ * are present. This sorting can be removed once we support
+ * signature_algorithms_cert.
+ */
SECStatus
ssl3_FilterSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRBool disableRsae,
+ PRBool forCert,
unsigned int maxSchemes, SSLSignatureScheme *filteredSchemes,
unsigned int *numFilteredSchemes)
{
@@ -9810,15 +9876,32 @@ ssl3_FilterSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRBool disableRsae,
}
*numFilteredSchemes = 0;
+ PRBool allowUnsortedPkcs1 = forCert && minVersion < SSL_LIBRARY_VERSION_TLS_1_3;
for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
if (disableRsae && ssl_IsRsaeSignatureScheme(ss->ssl3.signatureSchemes[i])) {
continue;
}
if (ssl_SignatureSchemeAccepted(minVersion,
- ss->ssl3.signatureSchemes[i])) {
+ ss->ssl3.signatureSchemes[i],
+ allowUnsortedPkcs1)) {
filteredSchemes[(*numFilteredSchemes)++] = ss->ssl3.signatureSchemes[i];
}
}
+ if (forCert && !allowUnsortedPkcs1) {
+ for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
+ if (disableRsae && ssl_IsRsaeSignatureScheme(ss->ssl3.signatureSchemes[i])) {
+ continue;
+ }
+ if (!ssl_SignatureSchemeAccepted(minVersion,
+ ss->ssl3.signatureSchemes[i],
+ PR_FALSE) &&
+ ssl_SignatureSchemeAccepted(minVersion,
+ ss->ssl3.signatureSchemes[i],
+ PR_TRUE)) {
+ filteredSchemes[(*numFilteredSchemes)++] = ss->ssl3.signatureSchemes[i];
+ }
+ }
+ }
return SECSuccess;
}
@@ -9855,7 +9938,7 @@ ssl3_SendCertificateRequest(sslSocket *ss)
length = 1 + certTypesLength + 2 + calen;
if (isTLS12) {
- rv = ssl3_EncodeSigAlgs(ss, ss->version, &sigAlgsBuf);
+ rv = ssl3_EncodeSigAlgs(ss, ss->version, PR_TRUE /* forCert */, &sigAlgsBuf);
if (rv != SECSuccess) {
return rv;
}
@@ -11216,6 +11299,8 @@ static SECStatus ssl3_FinishHandshake(sslSocket *ss);
static SECStatus
ssl3_AlwaysFail(sslSocket *ss)
{
+ /* The caller should have cleared the callback. */
+ ss->ssl3.hs.restartTarget = ssl3_AlwaysFail;
PORT_SetError(PR_INVALID_STATE_ERROR);
return SECFailure;
}
@@ -11651,7 +11736,6 @@ ssl3_CacheWrappedSecret(sslSocket *ss, sslSessionID *sid,
static SECStatus
ssl3_HandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length)
{
- sslSessionID *sid = ss->sec.ci.sid;
SECStatus rv = SECSuccess;
PRBool isServer = ss->sec.isServer;
PRBool isTLS;
@@ -11795,15 +11879,6 @@ xmit_loser:
return rv;
}
- if (sid->cached == never_cached && !ss->opt.noCache) {
- rv = ssl3_FillInCachedSID(ss, sid, ss->ssl3.crSpec->masterSecret);
-
- /* If the wrap failed, we don't cache the sid.
- * The connection continues normally however.
- */
- ss->ssl3.hs.cacheSID = rv == SECSuccess;
- }
-
if (ss->ssl3.hs.authCertificatePending) {
if (ss->ssl3.hs.restartTarget) {
PR_NOT_REACHED("ssl3_HandleFinished: unexpected restartTarget");
@@ -11868,33 +11943,45 @@ ssl3_FinishHandshake(sslSocket *ss)
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(ss->ssl3.hs.restartTarget == NULL);
+ sslSessionID *sid = ss->sec.ci.sid;
+ SECStatus sidRv = SECFailure;
/* The first handshake is now completed. */
ss->handshake = NULL;
+ if (sid->cached == never_cached && !ss->opt.noCache) {
+ /* If the wrap fails, don't cache the sid. The connection proceeds
+ * normally, so the rv is only used to determine whether we cache. */
+ sidRv = ssl3_FillInCachedSID(ss, sid, ss->ssl3.crSpec->masterSecret);
+ }
+
/* RFC 5077 Section 3.3: "The client MUST NOT treat the ticket as valid
- * until it has verified the server's Finished message." When the server
- * sends a NewSessionTicket in a resumption handshake, we must wait until
- * the handshake is finished (we have verified the server's Finished
- * AND the server's certificate) before we update the ticket in the sid.
- *
- * This must be done before we call ssl_CacheSessionID(ss)
- * because CacheSID requires the session ticket to already be set, and also
- * because of the lazy lock creation scheme used by CacheSID and
- * ssl3_SetSIDSessionTicket.
- */
+ * until it has verified the server's Finished message." When the server
+ * sends a NewSessionTicket in a resumption handshake, we must wait until
+ * the handshake is finished (we have verified the server's Finished
+ * AND the server's certificate) before we update the ticket in the sid.
+ *
+ * This must be done before we call ssl_CacheSessionID(ss)
+ * because CacheSID requires the session ticket to already be set, and also
+ * because of the lazy lock creation scheme used by CacheSID and
+ * ssl3_SetSIDSessionTicket. */
if (ss->ssl3.hs.receivedNewSessionTicket) {
PORT_Assert(!ss->sec.isServer);
- ssl3_SetSIDSessionTicket(ss->sec.ci.sid, &ss->ssl3.hs.newSessionTicket);
- /* The sid took over the ticket data */
+ if (sidRv == SECSuccess) {
+ /* The sid takes over the ticket data */
+ ssl3_SetSIDSessionTicket(ss->sec.ci.sid,
+ &ss->ssl3.hs.newSessionTicket);
+ } else {
+ PORT_Assert(ss->ssl3.hs.newSessionTicket.ticket.data);
+ SECITEM_FreeItem(&ss->ssl3.hs.newSessionTicket.ticket,
+ PR_FALSE);
+ }
PORT_Assert(!ss->ssl3.hs.newSessionTicket.ticket.data);
ss->ssl3.hs.receivedNewSessionTicket = PR_FALSE;
}
-
- if (ss->ssl3.hs.cacheSID) {
+ if (sidRv == SECSuccess) {
PORT_Assert(ss->sec.ci.sid->cached == never_cached);
ssl_CacheSessionID(ss);
- ss->ssl3.hs.cacheSID = PR_FALSE;
}
ss->ssl3.hs.canFalseStart = PR_FALSE; /* False Start phase is complete */
@@ -12974,12 +13061,18 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText)
ss->ssl3.hs.ws != idle_handshake &&
cText->buf->len == 1 &&
cText->buf->buf[0] == change_cipher_spec_choice) {
- /* Ignore the CCS. */
- return SECSuccess;
+ if (!ss->ssl3.hs.rejectCcs) {
+ /* Allow only the first CCS. */
+ ss->ssl3.hs.rejectCcs = PR_TRUE;
+ return SECSuccess;
+ } else {
+ alert = unexpected_message;
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER);
+ }
}
- if (IS_DTLS(ss) ||
- (ss->sec.isServer &&
+ if ((IS_DTLS(ss) && !dtls13_AeadLimitReached(spec)) ||
+ (!IS_DTLS(ss) && ss->sec.isServer &&
ss->ssl3.hs.zeroRttIgnore == ssl_0rtt_ignore_trial)) {
/* Silently drop the packet unless we sent a fatal alert. */
if (ss->ssl3.fatalAlertSent) {
@@ -13102,7 +13195,6 @@ ssl3_InitState(sslSocket *ss)
ss->ssl3.hs.currentSecret = NULL;
ss->ssl3.hs.resumptionMasterSecret = NULL;
ss->ssl3.hs.dheSecret = NULL;
- ss->ssl3.hs.pskBinderKey = NULL;
ss->ssl3.hs.clientEarlyTrafficSecret = NULL;
ss->ssl3.hs.clientHsTrafficSecret = NULL;
ss->ssl3.hs.serverHsTrafficSecret = NULL;
@@ -13476,8 +13568,6 @@ ssl3_DestroySSL3Info(sslSocket *ss)
PK11_FreeSymKey(ss->ssl3.hs.resumptionMasterSecret);
if (ss->ssl3.hs.dheSecret)
PK11_FreeSymKey(ss->ssl3.hs.dheSecret);
- if (ss->ssl3.hs.pskBinderKey)
- PK11_FreeSymKey(ss->ssl3.hs.pskBinderKey);
if (ss->ssl3.hs.clientEarlyTrafficSecret)
PK11_FreeSymKey(ss->ssl3.hs.clientEarlyTrafficSecret);
if (ss->ssl3.hs.clientHsTrafficSecret)
@@ -13496,6 +13586,63 @@ ssl3_DestroySSL3Info(sslSocket *ss)
ss->ssl3.hs.zeroRttState = ssl_0rtt_none;
/* Destroy TLS 1.3 buffered early data. */
tls13_DestroyEarlyData(&ss->ssl3.hs.bufferedEarlyData);
+ /* Destroy TLS 1.3 PSKs */
+ tls13_DestroyPskList(&ss->ssl3.hs.psks);
+}
+
+/*
+ * parse the policy value for a single algorithm in a cipher_suite,
+ * return TRUE if we disallow by the cipher suite by policy
+ * (we don't have to parse any more algorithm policies on this cipher suite),
+ * otherwise return FALSE.
+ * 1. If we don't have the required policy, disable by default, disallow by
+ * policy and return TRUE (no more processing needed).
+ * 2. If we have the required policy, and we are disabled, return FALSE,
+ * (if we are disabled, we only need to parse policy, not default).
+ * 3. If we have the required policy, and we aren't adjusting the defaults
+ * return FALSE. (only parsing the policy, not default).
+ * 4. We have the required policy and we are adjusting the defaults.
+ * If we are setting default = FALSE, set isDisabled to true so that
+ * we don't try to re-enable the cipher suite based on a different
+ * algorithm.
+ */
+PRBool
+ssl_HandlePolicy(int cipher_suite, SECOidTag policyOid,
+ PRUint32 requiredPolicy, PRBool *isDisabled)
+{
+ PRUint32 policy;
+ SECStatus rv;
+
+ /* first fetch the policy for this algorithm */
+ rv = NSS_GetAlgorithmPolicy(policyOid, &policy);
+ if (rv != SECSuccess) {
+ return PR_FALSE; /* no policy value, continue to the next algorithm */
+ }
+ /* first, are we allowed by policy, if not turn off allow and disable */
+ if (!(policy & requiredPolicy)) {
+ ssl_CipherPrefSetDefault(cipher_suite, PR_FALSE);
+ ssl_CipherPolicySet(cipher_suite, SSL_NOT_ALLOWED);
+ return PR_TRUE;
+ }
+ /* If we are already disabled, or the policy isn't setting a default
+ * we are done processing this algorithm */
+ if (*isDisabled || (policy & NSS_USE_DEFAULT_NOT_VALID)) {
+ return PR_FALSE;
+ }
+ /* set the default value for the cipher suite. If we disable the cipher
+ * suite, remember that so we don't process the next default. This has
+ * the effect of disabling the whole cipher suite if any of the
+ * algorithms it uses are disabled by default. We still have to
+ * process the upper level because the cipher suite is still allowed
+ * by policy, and we may still have to disallow it based on other
+ * algorithms in the cipher suite. */
+ if (policy & NSS_USE_DEFAULT_SSL_ENABLE) {
+ ssl_CipherPrefSetDefault(cipher_suite, PR_TRUE);
+ } else {
+ *isDisabled = PR_TRUE;
+ ssl_CipherPrefSetDefault(cipher_suite, PR_FALSE);
+ }
+ return PR_FALSE;
}
#define MAP_NULL(x) (((x) != 0) ? (x) : SEC_OID_NULL_CIPHER)
@@ -13516,30 +13663,30 @@ ssl3_ApplyNSSPolicy(void)
for (i = 1; i < PR_ARRAY_SIZE(cipher_suite_defs); ++i) {
const ssl3CipherSuiteDef *suite = &cipher_suite_defs[i];
SECOidTag policyOid;
+ PRBool isDisabled = PR_FALSE;
+ /* if we haven't explicitly disabled it below enable by policy */
+ ssl_CipherPolicySet(suite->cipher_suite, SSL_ALLOWED);
+
+ /* now check the various key exchange, ciphers and macs and
+ * if we ever disallow by policy, we are done, go to the next cipher
+ */
policyOid = MAP_NULL(kea_defs[suite->key_exchange_alg].oid);
- rv = NSS_GetAlgorithmPolicy(policyOid, &policy);
- if (rv == SECSuccess && !(policy & NSS_USE_ALG_IN_SSL_KX)) {
- ssl_CipherPrefSetDefault(suite->cipher_suite, PR_FALSE);
- ssl_CipherPolicySet(suite->cipher_suite, SSL_NOT_ALLOWED);
+ if (ssl_HandlePolicy(suite->cipher_suite, policyOid,
+ NSS_USE_ALG_IN_SSL_KX, &isDisabled)) {
continue;
}
policyOid = MAP_NULL(ssl_GetBulkCipherDef(suite)->oid);
- rv = NSS_GetAlgorithmPolicy(policyOid, &policy);
- if (rv == SECSuccess && !(policy & NSS_USE_ALG_IN_SSL)) {
- ssl_CipherPrefSetDefault(suite->cipher_suite, PR_FALSE);
- ssl_CipherPolicySet(suite->cipher_suite, SSL_NOT_ALLOWED);
+ if (ssl_HandlePolicy(suite->cipher_suite, policyOid,
+ NSS_USE_ALG_IN_SSL, &isDisabled)) {
continue;
}
if (ssl_GetBulkCipherDef(suite)->type != type_aead) {
policyOid = MAP_NULL(ssl_GetMacDefByAlg(suite->mac_alg)->oid);
- rv = NSS_GetAlgorithmPolicy(policyOid, &policy);
- if (rv == SECSuccess && !(policy & NSS_USE_ALG_IN_SSL)) {
- ssl_CipherPrefSetDefault(suite->cipher_suite, PR_FALSE);
- ssl_CipherPolicySet(suite->cipher_suite,
- SSL_NOT_ALLOWED);
+ if (ssl_HandlePolicy(suite->cipher_suite, policyOid,
+ NSS_USE_ALG_IN_SSL, &isDisabled)) {
continue;
}
}
diff --git a/libs/nss/src/lib/ssl/ssl3ext.c b/libs/nss/src/lib/ssl/ssl3ext.c
index 1cad98a7f..65a69450d 100644
--- a/libs/nss/src/lib/ssl/ssl3ext.c
+++ b/libs/nss/src/lib/ssl/ssl3ext.c
@@ -10,6 +10,7 @@
#include "nssrenam.h"
#include "nss.h"
+#include "pk11pub.h"
#include "ssl.h"
#include "sslimpl.h"
#include "sslproto.h"
@@ -962,6 +963,7 @@ ssl3_InitExtensionData(TLSExtensionData *xtnData, const sslSocket *ss)
xtnData->peerDelegCred = NULL;
xtnData->peerRequestedDelegCred = PR_FALSE;
xtnData->sendingDelegCredToPeer = PR_FALSE;
+ xtnData->selectedPsk = NULL;
}
void
diff --git a/libs/nss/src/lib/ssl/ssl3ext.h b/libs/nss/src/lib/ssl/ssl3ext.h
index 7f09e5fd7..ff2f7c211 100644
--- a/libs/nss/src/lib/ssl/ssl3ext.h
+++ b/libs/nss/src/lib/ssl/ssl3ext.h
@@ -134,6 +134,10 @@ struct TLSExtensionDataStr {
* |tls13_MaybeSetDelegatedCredential|.
*/
PRBool sendingDelegCredToPeer;
+
+ /* A non-owning reference to the selected PSKs. MUST NOT be freed directly,
+ * rather through tls13_DestoryPskList(). */
+ sslPsk *selectedPsk;
};
typedef struct TLSExtensionStr {
diff --git a/libs/nss/src/lib/ssl/ssl3exthandle.c b/libs/nss/src/lib/ssl/ssl3exthandle.c
index 07565ba00..cb4698253 100644
--- a/libs/nss/src/lib/ssl/ssl3exthandle.c
+++ b/libs/nss/src/lib/ssl/ssl3exthandle.c
@@ -796,7 +796,7 @@ ssl3_EncodeSessionTicket(sslSocket *ss, const NewSessionTicket *ticket,
* This is compared to the expected time, which should differ only as a
* result of clock errors or errors in the RTT estimate.
*/
- ticketAgeBaseline = (ssl_Time(ss) - ss->ssl3.hs.serverHelloTime) / PR_USEC_PER_MSEC;
+ ticketAgeBaseline = ss->ssl3.hs.rttEstimate / PR_USEC_PER_MSEC;
ticketAgeBaseline -= ticket->ticket_age_add;
rv = sslBuffer_AppendNumber(&plaintext, ticketAgeBaseline, 4);
if (rv != SECSuccess)
@@ -1652,7 +1652,7 @@ ssl3_SendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
minVersion = ss->vrange.min; /* ClientHello */
}
- SECStatus rv = ssl3_EncodeSigAlgs(ss, minVersion, buf);
+ SECStatus rv = ssl3_EncodeSigAlgs(ss, minVersion, PR_TRUE /* forCert */, buf);
if (rv != SECSuccess) {
return SECFailure;
}
diff --git a/libs/nss/src/lib/ssl/ssl3gthr.c b/libs/nss/src/lib/ssl/ssl3gthr.c
index 3bc6e8edc..45cfb31bc 100644
--- a/libs/nss/src/lib/ssl/ssl3gthr.c
+++ b/libs/nss/src/lib/ssl/ssl3gthr.c
@@ -611,6 +611,46 @@ ssl3_GatherAppDataRecord(sslSocket *ss, int flags)
return rv;
}
+static SECStatus
+ssl_HandleZeroRttRecordData(sslSocket *ss, const PRUint8 *data, unsigned int len)
+{
+ PORT_Assert(ss->sec.isServer);
+ if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) {
+ sslBuffer buf = { CONST_CAST(PRUint8, data), len, len, PR_TRUE };
+ return tls13_HandleEarlyApplicationData(ss, &buf);
+ }
+ if (ss->ssl3.hs.zeroRttState == ssl_0rtt_ignored &&
+ ss->ssl3.hs.zeroRttIgnore != ssl_0rtt_ignore_none) {
+ /* We're ignoring 0-RTT so drop this record quietly. */
+ return SECSuccess;
+ }
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA);
+ return SECFailure;
+}
+
+/* Ensure that application data in the wrong epoch is blocked. */
+static PRBool
+ssl_IsApplicationDataPermitted(sslSocket *ss, PRUint16 epoch)
+{
+ /* Epoch 0 is never OK. */
+ if (epoch == 0) {
+ return PR_FALSE;
+ }
+ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+ return ss->firstHsDone;
+ }
+ /* TLS 1.3 application data. */
+ if (epoch >= TrafficKeyApplicationData) {
+ return ss->firstHsDone;
+ }
+ /* TLS 1.3 early data is server only. Further checks aren't needed
+ * as those are handled in ssl_HandleZeroRttRecordData. */
+ if (epoch == TrafficKeyEarlyApplicationData) {
+ return ss->sec.isServer;
+ }
+ return PR_FALSE;
+}
+
SECStatus
SSLExp_RecordLayerData(PRFileDesc *fd, PRUint16 epoch,
SSLContentType contentType,
@@ -637,8 +677,8 @@ SSLExp_RecordLayerData(PRFileDesc *fd, PRUint16 epoch,
goto early_loser; /* Rely on the existing code. */
}
- /* Don't allow application data before handshake completion. */
- if (contentType == ssl_ct_application_data && !ss->firstHsDone) {
+ if (contentType == ssl_ct_application_data &&
+ !ssl_IsApplicationDataPermitted(ss, epoch)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto early_loser;
}
@@ -649,7 +689,18 @@ SSLExp_RecordLayerData(PRFileDesc *fd, PRUint16 epoch,
if (epoch < ss->ssl3.crSpec->epoch) {
epochError = SEC_ERROR_INVALID_ARGS; /* Too c/old. */
} else if (epoch > ss->ssl3.crSpec->epoch) {
- epochError = PR_WOULD_BLOCK_ERROR; /* Too warm/new. */
+ /* If a TLS 1.3 server is not expecting EndOfEarlyData,
+ * moving from 1 to 2 is a signal to execute the code
+ * as though that message had been received. Let that pass. */
+ if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
+ ss->opt.suppressEndOfEarlyData &&
+ ss->sec.isServer &&
+ ss->ssl3.crSpec->epoch == TrafficKeyEarlyApplicationData &&
+ epoch == TrafficKeyHandshake) {
+ epochError = 0;
+ } else {
+ epochError = PR_WOULD_BLOCK_ERROR; /* Too warm/new. */
+ }
} else {
epochError = 0; /* Just right. */
}
@@ -660,11 +711,18 @@ SSLExp_RecordLayerData(PRFileDesc *fd, PRUint16 epoch,
}
/* If the handshake is still running, we need to run that. */
- ssl_Get1stHandshakeLock(ss);
rv = ssl_Do1stHandshake(ss);
if (rv != SECSuccess && PORT_GetError() != PR_WOULD_BLOCK_ERROR) {
+ goto early_loser;
+ }
+
+ /* 0-RTT needs its own special handling here. */
+ if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
+ epoch == TrafficKeyEarlyApplicationData &&
+ contentType == ssl_ct_application_data) {
+ rv = ssl_HandleZeroRttRecordData(ss, data, len);
ssl_Release1stHandshakeLock(ss);
- return SECFailure;
+ return rv;
}
/* Finally, save the data... */
diff --git a/libs/nss/src/lib/ssl/ssl3prot.h b/libs/nss/src/lib/ssl/ssl3prot.h
index d7375551f..edf459290 100644
--- a/libs/nss/src/lib/ssl/ssl3prot.h
+++ b/libs/nss/src/lib/ssl/ssl3prot.h
@@ -14,7 +14,7 @@ typedef PRUint16 SSL3ProtocolVersion;
/* version numbers are defined in sslproto.h */
/* DTLS 1.3 is still a draft. */
-#define DTLS_1_3_DRAFT_VERSION 34
+#define DTLS_1_3_DRAFT_VERSION 38
typedef PRUint16 ssl3CipherSuite;
/* The cipher suites are defined in sslproto.h */
diff --git a/libs/nss/src/lib/ssl/sslencode.c b/libs/nss/src/lib/ssl/sslencode.c
index e59e758ff..d07b544ab 100644
--- a/libs/nss/src/lib/ssl/sslencode.c
+++ b/libs/nss/src/lib/ssl/sslencode.c
@@ -64,7 +64,10 @@ sslBuffer_Append(sslBuffer *b, const void *data, unsigned int len)
if (rv != SECSuccess) {
return SECFailure; /* Code already set. */
}
- PORT_Memcpy(SSL_BUFFER_NEXT(b), data, len);
+ if (len > 0) {
+ PORT_Assert(data);
+ PORT_Memcpy(SSL_BUFFER_NEXT(b), data, len);
+ }
b->len += len;
return SECSuccess;
}
diff --git a/libs/nss/src/lib/ssl/sslerr.h b/libs/nss/src/lib/ssl/sslerr.h
index bc2785f9a..eb8f7c2da 100644
--- a/libs/nss/src/lib/ssl/sslerr.h
+++ b/libs/nss/src/lib/ssl/sslerr.h
@@ -275,6 +275,7 @@ typedef enum {
SSL_ERROR_DC_INVALID_KEY_USAGE = (SSL_ERROR_BASE + 184),
SSL_ERROR_DC_EXPIRED = (SSL_ERROR_BASE + 185),
SSL_ERROR_DC_INAPPROPRIATE_VALIDITY_PERIOD = (SSL_ERROR_BASE + 186),
+ SSL_ERROR_FEATURE_DISABLED = (SSL_ERROR_BASE + 187),
SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
} SSLErrorCodes;
#endif /* NO_SECURITY_ERROR_ENUM */
diff --git a/libs/nss/src/lib/ssl/sslexp.h b/libs/nss/src/lib/ssl/sslexp.h
index fb3d612c1..8a92a39ad 100644
--- a/libs/nss/src/lib/ssl/sslexp.h
+++ b/libs/nss/src/lib/ssl/sslexp.h
@@ -254,7 +254,8 @@ typedef struct SSLAntiReplayContextStr SSLAntiReplayContext;
*
* This function will fail unless the socket has an active TLS 1.3 session.
* Earlier versions of TLS do not support the spontaneous sending of the
- * NewSessionTicket message.
+ * NewSessionTicket message. It will also fail when external PSK
+ * authentication has been negotiated.
*/
#define SSL_SendSessionTicket(fd, appToken, appTokenLen) \
SSL_EXPERIMENTAL_API("SSL_SendSessionTicket", \
@@ -380,6 +381,10 @@ typedef SSLHelloRetryRequestAction(PR_CALLBACK *SSLHelloRetryRequestCallback)(
* a server. This can be called once at a time, and is not allowed
* until an answer is received.
*
+ * This function is not allowed for use with DTLS or when external
+ * PSK authentication has been negotiated. SECFailure is returned
+ * in both cases.
+ *
* The AuthCertificateCallback is called when the answer is received.
* If the answer is accepted by the server, the value returned by
* SSL_PeerCertificate() is replaced. If you need to remember all the
@@ -947,6 +952,51 @@ typedef struct SSLMaskingContextStr {
SSL_EXPERIMENTAL_API("SSL_SetDtls13VersionWorkaround", \
(PRFileDesc * _fd, PRBool _enabled), (fd, enabled))
+/* SSL_AddExternalPsk() and SSL_AddExternalPsk0Rtt() can be used to
+ * set an external PSK on a socket. If successful, this PSK will
+ * be used in all subsequent connection attempts for this socket.
+ * This has no effect if the maximum TLS version is < 1.3.
+ *
+ * This API currently only accepts a single PSK, so multiple calls to
+ * either function will fail. An EPSK can be replaced by calling
+ * SSL_RemoveExternalPsk followed by SSL_AddExternalPsk.
+ * For both functions, the label is expected to be a unique identifier
+ * for the external PSK. Should en external PSK have the same label
+ * as a configured resumption PSK identity, the external PSK will
+ * take precedence.
+ *
+ * If you want to enable early data, you need to also provide a
+ * cipher suite for 0-RTT and a limit for the early data using
+ * SSL_AddExternalPsk0Rtt(). If you want to explicitly disallow
+ * certificate authentication, use SSL_AuthCertificateHook to set
+ * a callback that rejects all certificate chains.
+ */
+#define SSL_AddExternalPsk(fd, psk, identity, identityLen, hash) \
+ SSL_EXPERIMENTAL_API("SSL_AddExternalPsk", \
+ (PRFileDesc * _fd, PK11SymKey * _psk, \
+ const PRUint8 *_identity, unsigned int _identityLen, \
+ SSLHashType _hash), \
+ (fd, psk, identity, identityLen, hash))
+
+#define SSL_AddExternalPsk0Rtt(fd, psk, identity, identityLen, hash, \
+ zeroRttSuite, maxEarlyData) \
+ SSL_EXPERIMENTAL_API("SSL_AddExternalPsk0Rtt", \
+ (PRFileDesc * _fd, PK11SymKey * _psk, \
+ const PRUint8 *_identity, unsigned int _identityLen, \
+ SSLHashType _hash, PRUint16 _zeroRttSuite, \
+ PRUint32 _maxEarlyData), \
+ (fd, psk, identity, identityLen, hash, \
+ zeroRttSuite, maxEarlyData))
+
+/* SSLExp_RemoveExternalPsk() removes an external PSK from socket
+ * configuration. Returns SECSuccess if the PSK was removed
+ * successfully, and SECFailure otherwise. */
+#define SSL_RemoveExternalPsk(fd, identity, identityLen) \
+ SSL_EXPERIMENTAL_API("SSL_RemoveExternalPsk", \
+ (PRFileDesc * _fd, const PRUint8 *_identity, \
+ unsigned int _identityLen), \
+ (fd, identity, identityLen))
+
/* Deprecated experimental APIs */
#define SSL_UseAltServerHelloType(fd, enable) SSL_DEPRECATED_EXPERIMENTAL_API
#define SSL_SetupAntiReplay(a, b, c) SSL_DEPRECATED_EXPERIMENTAL_API
diff --git a/libs/nss/src/lib/ssl/sslimpl.h b/libs/nss/src/lib/ssl/sslimpl.h
index 62d253224..35d0c2d6b 100644
--- a/libs/nss/src/lib/ssl/sslimpl.h
+++ b/libs/nss/src/lib/ssl/sslimpl.h
@@ -37,6 +37,7 @@
typedef struct sslSocketStr sslSocket;
typedef struct sslNamedGroupDefStr sslNamedGroupDef;
typedef struct sslEsniKeysStr sslEsniKeys;
+typedef struct sslPskStr sslPsk;
typedef struct sslDelegatedCredentialStr sslDelegatedCredential;
typedef struct sslEphemeralKeyPairStr sslEphemeralKeyPair;
typedef struct TLS13KeyShareEntryStr TLS13KeyShareEntry;
@@ -282,6 +283,7 @@ typedef struct sslOptionsStr {
unsigned int enablePostHandshakeAuth : 1;
unsigned int enableDelegatedCredentials : 1;
unsigned int enableDtls13VersionCompat : 1;
+ unsigned int suppressEndOfEarlyData : 1;
} sslOptions;
typedef enum { sslHandshakingUndetermined = 0,
@@ -654,8 +656,6 @@ typedef struct SSL3HandshakeStateStr {
* One of NULL, ssl3_SendClientSecondRound, ssl3_FinishHandshake,
* or ssl3_AlwaysFail */
sslRestartTarget restartTarget;
- /* Shared state between ssl3_HandleFinished and ssl3_FinishHandshake */
- PRBool cacheSID;
PRBool canFalseStart; /* Can/did we False Start */
/* Which preliminaryinfo values have been set. */
@@ -690,9 +690,8 @@ typedef struct SSL3HandshakeStateStr {
/* This group of values is used for TLS 1.3 and above */
PK11SymKey *currentSecret; /* The secret down the "left hand side"
* of the TLS 1.3 key schedule. */
- PK11SymKey *resumptionMasterSecret; /* The resumption PSK. */
+ PK11SymKey *resumptionMasterSecret; /* The resumption_master_secret. */
PK11SymKey *dheSecret; /* The (EC)DHE shared secret. */
- PK11SymKey *pskBinderKey; /* Used to compute the PSK binder. */
PK11SymKey *clientEarlyTrafficSecret; /* The secret we use for 0-RTT. */
PK11SymKey *clientHsTrafficSecret; /* The source keys for handshake */
PK11SymKey *serverHsTrafficSecret; /* traffic keys. */
@@ -711,18 +710,26 @@ typedef struct SSL3HandshakeStateStr {
* or received. */
PRBool receivedCcs; /* A server received ChangeCipherSpec
* before the handshake started. */
+ PRBool rejectCcs; /* Excessive ChangeCipherSpecs are rejected. */
PRBool clientCertRequested; /* True if CertificateRequest received. */
+ PRBool endOfFlight; /* Processed a full flight (DTLS 1.3). */
ssl3KEADef kea_def_mutable; /* Used to hold the writable kea_def
* we use for TLS 1.3 */
- PRTime serverHelloTime; /* Time the ServerHello flight was sent. */
PRUint16 ticketNonce; /* A counter we use for tickets. */
SECItem fakeSid; /* ... (server) the SID the client used. */
- PRBool endOfFlight; /* Processed a full flight (DTLS 1.3). */
+
+ /* rttEstimate is used to guess the round trip time between server and client.
+ * When the server sends ServerHello it sets this to the current time.
+ * Only after it receives a message from the client's second flight does it
+ * set the value to something resembling an RTT estimate. */
+ PRTime rttEstimate;
/* The following lists contain DTLSHandshakeRecordEntry */
PRCList dtlsSentHandshake; /* Used to map records to handshake fragments. */
PRCList dtlsRcvdHandshake; /* Handshake records we have received
* used to generate ACKs. */
+
+ PRCList psks; /* A list of PSKs, resumption and/or external. */
} SSL3HandshakeState;
#define SSL_ASSERT_HASHES_EMPTY(ss) \
@@ -1100,6 +1107,9 @@ struct sslSocketStr {
/* Anti-replay for TLS 1.3 0-RTT. */
SSLAntiReplayContext *antiReplay;
+
+ /* An out-of-band PSK. */
+ sslPsk *psk;
};
struct sslSelfEncryptKeysStr {
@@ -1683,12 +1693,12 @@ SECStatus ssl3_HandleServerSpki(sslSocket *ss);
SECStatus ssl3_AuthCertificate(sslSocket *ss);
SECStatus ssl_ReadCertificateStatus(sslSocket *ss, PRUint8 *b,
PRUint32 length);
-SECStatus ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion,
+SECStatus ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRBool forCert,
sslBuffer *buf);
SECStatus ssl3_EncodeFilteredSigAlgs(const sslSocket *ss,
const SSLSignatureScheme *schemes,
PRUint32 numSchemes, sslBuffer *buf);
-SECStatus ssl3_FilterSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRBool disableRsae,
+SECStatus ssl3_FilterSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRBool disableRsae, PRBool forCert,
unsigned int maxSchemes, SSLSignatureScheme *filteredSchemes,
unsigned int *numFilteredSchemes);
SECStatus ssl_GetCertificateRequestCAs(const sslSocket *ss,
diff --git a/libs/nss/src/lib/ssl/sslinfo.c b/libs/nss/src/lib/ssl/sslinfo.c
index 115c38dc1..a92ed1604 100644
--- a/libs/nss/src/lib/ssl/sslinfo.c
+++ b/libs/nss/src/lib/ssl/sslinfo.c
@@ -7,6 +7,7 @@
#include "sslimpl.h"
#include "sslproto.h"
#include "tls13hkdf.h"
+#include "tls13psk.h"
#include "tls13subcerts.h"
SECStatus
@@ -80,6 +81,13 @@ SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len)
inf.signatureScheme = sid->sigScheme;
}
inf.resumed = ss->statelessResume || ss->ssl3.hs.isResuming;
+ if (inf.resumed) {
+ inf.pskType = ssl_psk_resume;
+ } else if (inf.authType == ssl_auth_psk) {
+ inf.pskType = ssl_psk_external;
+ } else {
+ inf.pskType = ssl_psk_none;
+ }
inf.peerDelegCred = tls13_IsVerifyingWithDelegatedCredential(ss);
if (sid) {
@@ -147,8 +155,14 @@ SSL_GetPreliminaryChannelInfo(PRFileDesc *fd,
if (ss->sec.ci.sid &&
(ss->ssl3.hs.zeroRttState == ssl_0rtt_sent ||
ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted)) {
- inf.maxEarlyDataSize =
- ss->sec.ci.sid->u.ssl3.locked.sessionTicket.max_early_data_size;
+ if (ss->statelessResume) {
+ inf.maxEarlyDataSize =
+ ss->sec.ci.sid->u.ssl3.locked.sessionTicket.max_early_data_size;
+ } else if (ss->psk) {
+ /* We may have cleared the handshake list, so check the socket.
+ * This is permissable since we only support one EPSK at a time. */
+ inf.maxEarlyDataSize = ss->psk->maxEarlyData;
+ }
} else {
inf.maxEarlyDataSize = 0;
}
@@ -415,20 +429,33 @@ tls13_Exporter(sslSocket *ss, PK11SymKey *secret,
return SECFailure;
}
+ SSLHashType hashAlg;
+ /* Early export requires a PSK. As in 0-RTT, default
+ * to the first PSK if no suite is negotiated yet. */
+ if (secret == ss->ssl3.hs.earlyExporterSecret && !ss->ssl3.hs.suite_def) {
+ if (PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ hashAlg = ((sslPsk *)PR_LIST_HEAD(&ss->ssl3.hs.psks))->hash;
+ } else {
+ hashAlg = tls13_GetHash(ss);
+ }
+
/* Pre-hash the context. */
- rv = tls13_ComputeHash(ss, &contextHash, context, contextLen);
+ rv = tls13_ComputeHash(ss, &contextHash, context, contextLen, hashAlg);
if (rv != SECSuccess) {
return rv;
}
rv = tls13_DeriveSecretNullHash(ss, secret, label, labelLen,
- &innerSecret);
+ &innerSecret, hashAlg);
if (rv != SECSuccess) {
return rv;
}
rv = tls13_HkdfExpandLabelRaw(innerSecret,
- tls13_GetHash(ss),
+ hashAlg,
contextHash.u.raw, contextHash.len,
kExporterInnerLabel,
strlen(kExporterInnerLabel),
diff --git a/libs/nss/src/lib/ssl/sslnonce.c b/libs/nss/src/lib/ssl/sslnonce.c
index 3c30d3aa0..3daab4b75 100644
--- a/libs/nss/src/lib/ssl/sslnonce.c
+++ b/libs/nss/src/lib/ssl/sslnonce.c
@@ -1123,12 +1123,13 @@ ssl_CacheSessionID(sslSocket *ss)
{
sslSecurityInfo *sec = &ss->sec;
PORT_Assert(sec);
+ PORT_Assert(sec->ci.sid->cached == never_cached);
if (sec->ci.sid && !sec->ci.sid->u.ssl3.keys.resumable) {
return;
}
- if (!ss->sec.isServer && ss->resumptionTokenCallback) {
+ if (!sec->isServer && ss->resumptionTokenCallback) {
ssl_CacheExternalToken(ss);
return;
}
diff --git a/libs/nss/src/lib/ssl/sslsecur.c b/libs/nss/src/lib/ssl/sslsecur.c
index 14320fa19..ef978c90a 100644
--- a/libs/nss/src/lib/ssl/sslsecur.c
+++ b/libs/nss/src/lib/ssl/sslsecur.c
@@ -15,6 +15,7 @@
#include "pk11func.h" /* for PK11_GenerateRandom */
#include "nss.h" /* for NSS_RegisterShutdown */
#include "prinit.h" /* for PR_CallOnceWithArg */
+#include "tls13psk.h"
/* Step through the handshake functions.
*
@@ -173,6 +174,7 @@ SSL_ResetHandshake(PRFileDesc *s, PRBool asServer)
ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions);
ssl3_ResetExtensionData(&ss->xtnData, ss);
+ tls13_ResetHandshakePsks(ss, &ss->ssl3.hs.psks);
if (!ss->TCPconnected)
ss->TCPconnected = (PR_SUCCESS == ssl_DefGetpeername(ss, &addr));
diff --git a/libs/nss/src/lib/ssl/sslsnce.c b/libs/nss/src/lib/ssl/sslsnce.c
index 2f43c05c0..acb51a145 100644
--- a/libs/nss/src/lib/ssl/sslsnce.c
+++ b/libs/nss/src/lib/ssl/sslsnce.c
@@ -703,7 +703,7 @@ ServerSessionIDLookup(PRTime sslNow, const PRIPv6Addr *addr,
/* what the ??. Didn't get the cert cache lock.
** Don't invalidate the SID cache entry, but don't find it.
*/
- PORT_Assert(!("Didn't get cert Cache Lock!"));
+ PORT_AssertNotReached("Didn't get cert Cache Lock!");
psce = 0;
pcce = 0;
}
@@ -730,7 +730,7 @@ ServerSessionIDLookup(PRTime sslNow, const PRIPv6Addr *addr,
/* what the ??. Didn't get the cert cache lock.
** Don't invalidate the SID cache entry, but don't find it.
*/
- PORT_Assert(!("Didn't get name Cache Lock!"));
+ PORT_AssertNotReached("Didn't get name Cache Lock!");
psce = 0;
psnce = 0;
}
diff --git a/libs/nss/src/lib/ssl/sslsock.c b/libs/nss/src/lib/ssl/sslsock.c
index e93201647..695f39c50 100644
--- a/libs/nss/src/lib/ssl/sslsock.c
+++ b/libs/nss/src/lib/ssl/sslsock.c
@@ -20,6 +20,7 @@
#include "pk11pqg.h"
#include "pk11pub.h"
#include "tls13esni.h"
+#include "tls13psk.h"
#include "tls13subcerts.h"
static const sslSocketOps ssl_default_ops = { /* No SSL. */
@@ -90,7 +91,8 @@ static sslOptions ssl_defaults = {
.enableDtlsShortHeader = PR_FALSE,
.enableHelloDowngradeCheck = PR_FALSE,
.enableV2CompatibleHello = PR_FALSE,
- .enablePostHandshakeAuth = PR_FALSE
+ .enablePostHandshakeAuth = PR_FALSE,
+ .suppressEndOfEarlyData = PR_FALSE
};
/*
@@ -382,6 +384,12 @@ ssl_DupSocket(sslSocket *os)
goto loser;
}
}
+ if (os->psk) {
+ ss->psk = tls13_CopyPsk(os->psk);
+ if (!ss->psk) {
+ goto loser;
+ }
+ }
/* Create security data */
rv = ssl_CopySecurityInfo(ss, os);
@@ -468,9 +476,15 @@ ssl_DestroySocketContents(sslSocket *ss)
ssl_ClearPRCList(&ss->ssl3.hs.dtlsSentHandshake, NULL);
ssl_ClearPRCList(&ss->ssl3.hs.dtlsRcvdHandshake, NULL);
+ tls13_DestroyPskList(&ss->ssl3.hs.psks);
tls13_DestroyESNIKeys(ss->esniKeys);
tls13_ReleaseAntiReplayContext(ss->antiReplay);
+
+ if (ss->psk) {
+ tls13_DestroyPsk(ss->psk);
+ ss->psk = NULL;
+ }
}
/*
@@ -864,6 +878,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRIntn val)
ss->opt.enablePostHandshakeAuth = val;
break;
+ case SSL_SUPPRESS_END_OF_EARLY_DATA:
+ ss->opt.suppressEndOfEarlyData = val;
+ break;
+
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
@@ -1018,6 +1036,9 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRIntn *pVal)
case SSL_ENABLE_POST_HANDSHAKE_AUTH:
val = ss->opt.enablePostHandshakeAuth;
break;
+ case SSL_SUPPRESS_END_OF_EARLY_DATA:
+ val = ss->opt.suppressEndOfEarlyData;
+ break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
@@ -1156,6 +1177,9 @@ SSL_OptionGetDefault(PRInt32 which, PRIntn *pVal)
case SSL_ENABLE_POST_HANDSHAKE_AUTH:
val = ssl_defaults.enablePostHandshakeAuth;
break;
+ case SSL_SUPPRESS_END_OF_EARLY_DATA:
+ val = ssl_defaults.suppressEndOfEarlyData;
+ break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
@@ -1367,6 +1391,10 @@ SSL_OptionSetDefault(PRInt32 which, PRIntn val)
ssl_defaults.enablePostHandshakeAuth = val;
break;
+ case SSL_SUPPRESS_END_OF_EARLY_DATA:
+ ssl_defaults.suppressEndOfEarlyData = val;
+ break;
+
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
@@ -1432,6 +1460,10 @@ SSL_CipherPolicySet(PRInt32 which, PRInt32 policy)
if (rv != SECSuccess) {
return rv;
}
+ if (NSS_IsPolicyLocked()) {
+ PORT_SetError(SEC_ERROR_POLICY_LOCKED);
+ return SECFailure;
+ }
return ssl_CipherPolicySet(which, policy);
}
@@ -1478,10 +1510,15 @@ SECStatus
SSL_CipherPrefSetDefault(PRInt32 which, PRBool enabled)
{
SECStatus rv = ssl_Init();
+ PRInt32 locks;
if (rv != SECSuccess) {
return rv;
}
+ rv = NSS_OptionGet(NSS_DEFAULT_LOCKS, &locks);
+ if ((rv == SECSuccess) && (locks & NSS_DEFAULT_SSL_LOCK)) {
+ return SECSuccess;
+ }
return ssl_CipherPrefSetDefault(which, enabled);
}
@@ -1507,11 +1544,17 @@ SECStatus
SSL_CipherPrefSet(PRFileDesc *fd, PRInt32 which, PRBool enabled)
{
sslSocket *ss = ssl_FindSocket(fd);
+ PRInt32 locks;
+ SECStatus rv;
if (!ss) {
SSL_DBG(("%d: SSL[%d]: bad socket in CipherPrefSet", SSL_GETPID(), fd));
return SECFailure;
}
+ rv = NSS_OptionGet(NSS_DEFAULT_LOCKS, &locks);
+ if ((rv == SECSuccess) && (locks & NSS_DEFAULT_SSL_LOCK)) {
+ return SECSuccess;
+ }
if (ssl_IsRemovedCipherSuite(which))
return SECSuccess;
return ssl3_CipherPrefSet(ss, (ssl3CipherSuite)which, enabled);
@@ -2453,6 +2496,8 @@ SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd)
}
}
+ tls13_ResetHandshakePsks(sm, &ss->ssl3.hs.psks);
+
if (sm->authCertificate)
ss->authCertificate = sm->authCertificate;
if (sm->authCertificateArg)
@@ -4146,10 +4191,12 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant)
ssl3_InitExtensionData(&ss->xtnData, ss);
PR_INIT_CLIST(&ss->ssl3.hs.dtlsSentHandshake);
PR_INIT_CLIST(&ss->ssl3.hs.dtlsRcvdHandshake);
+ PR_INIT_CLIST(&ss->ssl3.hs.psks);
dtls_InitTimers(ss);
ss->esniKeys = NULL;
ss->antiReplay = NULL;
+ ss->psk = NULL;
if (makeLocks) {
rv = ssl_MakeLocks(ss);
@@ -4216,6 +4263,8 @@ struct {
void *function;
} ssl_experimental_functions[] = {
#ifndef SSL_DISABLE_EXPERIMENTAL_API
+ EXP(AddExternalPsk),
+ EXP(AddExternalPsk0Rtt),
EXP(AeadDecrypt),
EXP(AeadEncrypt),
EXP(CipherSuiteOrderGet),
@@ -4246,6 +4295,7 @@ struct {
EXP(RecordLayerData),
EXP(RecordLayerWriteCallback),
EXP(ReleaseAntiReplayContext),
+ EXP(RemoveExternalPsk),
EXP(SecretCallback),
EXP(SendCertificateRequest),
EXP(SendSessionTicket),
@@ -4457,8 +4507,11 @@ SSLExp_GetResumptionTokenInfo(const PRUint8 *tokenData, unsigned int tokenLen,
if (!token.alpnSelection) {
return SECFailure;
}
- PORT_Memcpy(token.alpnSelection, sid.u.ssl3.alpnSelection.data,
- token.alpnSelectionLen);
+ if (token.alpnSelectionLen > 0) {
+ PORT_Assert(sid.u.ssl3.alpnSelection.data);
+ PORT_Memcpy(token.alpnSelection, sid.u.ssl3.alpnSelection.data,
+ token.alpnSelectionLen);
+ }
if (sid.u.ssl3.locked.sessionTicket.flags & ticket_allow_early_data) {
token.maxEarlyDataSize =
diff --git a/libs/nss/src/lib/ssl/sslspec.h b/libs/nss/src/lib/ssl/sslspec.h
index ad4176bb5..061d888ae 100644
--- a/libs/nss/src/lib/ssl/sslspec.h
+++ b/libs/nss/src/lib/ssl/sslspec.h
@@ -169,8 +169,11 @@ struct ssl3CipherSpecStr {
* content type octet. */
PRUint16 recordSizeLimit;
- /* Masking context used for DTLS 1.3 */
+ /* DTLS 1.3: Sequence number masking context. */
SSLMaskingContext *maskContext;
+
+ /* DTLS 1.3: Count of decryption failures for the given key. */
+ PRUint64 deprotectionFailures;
};
typedef void (*sslCipherSpecChangedFunc)(void *arg,
diff --git a/libs/nss/src/lib/ssl/sslt.h b/libs/nss/src/lib/ssl/sslt.h
index 63dc06c8a..eaf4133e3 100644
--- a/libs/nss/src/lib/ssl/sslt.h
+++ b/libs/nss/src/lib/ssl/sslt.h
@@ -41,7 +41,7 @@ typedef enum {
ssl_ct_alert = 21,
ssl_ct_handshake = 22,
ssl_ct_application_data = 23,
- ssl_ct_ack = 25
+ ssl_ct_ack = 26
} SSLContentType;
typedef enum {
@@ -184,6 +184,12 @@ typedef enum {
ssl_auth_size /* number of authentication types */
} SSLAuthType;
+typedef enum {
+ ssl_psk_none = 0,
+ ssl_psk_resume = 1,
+ ssl_psk_external = 2,
+} SSLPskType;
+
/* This is defined for backward compatibility reasons */
#define ssl_auth_rsa ssl_auth_rsa_decrypt
@@ -358,6 +364,10 @@ typedef struct SSLChannelInfoStr {
*/
PRBool peerDelegCred;
+ /* The following fields were added in NSS 3.54. */
+ /* Indicates what type of PSK, if any, was used in a handshake. */
+ SSLPskType pskType;
+
/* When adding new fields to this structure, please document the
* NSS version in which they were added. */
} SSLChannelInfo;
diff --git a/libs/nss/src/lib/ssl/tls13con.c b/libs/nss/src/lib/ssl/tls13con.c
index b8f31c3f0..5d51d3c5c 100644
--- a/libs/nss/src/lib/ssl/tls13con.c
+++ b/libs/nss/src/lib/ssl/tls13con.c
@@ -25,6 +25,7 @@
#include "tls13exthandle.h"
#include "tls13hashstate.h"
#include "tls13subcerts.h"
+#include "tls13psk.h"
static SECStatus tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch,
SSLSecretDirection install,
@@ -65,13 +66,15 @@ tls13_DeriveSecret(sslSocket *ss, PK11SymKey *key,
const char *label,
unsigned int labelLen,
const SSL3Hashes *hashes,
- PK11SymKey **dest);
+ PK11SymKey **dest,
+ SSLHashType hash);
static SECStatus tls13_SendEndOfEarlyData(sslSocket *ss);
-static SECStatus tls13_HandleEndOfEarlyData(sslSocket *ss, PRUint8 *b,
+static SECStatus tls13_HandleEndOfEarlyData(sslSocket *ss, const PRUint8 *b,
PRUint32 length);
+static SECStatus tls13_MaybeHandleSuppressedEndOfEarlyData(sslSocket *ss);
static SECStatus tls13_SendFinished(sslSocket *ss, PK11SymKey *baseKey);
static SECStatus tls13_ComputePskBinderHash(sslSocket *ss, unsigned int prefix,
- SSL3Hashes *hashes);
+ SSL3Hashes *hashes, SSLHashType type);
static SECStatus tls13_VerifyFinished(sslSocket *ss, SSLHandshakeType message,
PK11SymKey *secret,
PRUint8 *b, PRUint32 length,
@@ -85,14 +88,14 @@ static SECStatus tls13_SendNewSessionTicket(sslSocket *ss,
unsigned int appTokenLen);
static SECStatus tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b,
PRUint32 length);
-static SECStatus tls13_ComputeEarlySecrets(sslSocket *ss);
+static SECStatus tls13_ComputeEarlySecretsWithPsk(sslSocket *ss);
static SECStatus tls13_ComputeHandshakeSecrets(sslSocket *ss);
static SECStatus tls13_ComputeApplicationSecrets(sslSocket *ss);
static SECStatus tls13_ComputeFinalSecrets(sslSocket *ss);
static SECStatus tls13_ComputeFinished(
- sslSocket *ss, PK11SymKey *baseKey, const SSL3Hashes *hashes,
- PRBool sending, PRUint8 *output, unsigned int *outputLen,
- unsigned int maxOutputLen);
+ sslSocket *ss, PK11SymKey *baseKey, SSLHashType hashType,
+ const SSL3Hashes *hashes, PRBool sending, PRUint8 *output,
+ unsigned int *outputLen, unsigned int maxOutputLen);
static SECStatus tls13_SendClientSecondRound(sslSocket *ss);
static SECStatus tls13_SendClientSecondFlight(sslSocket *ss,
PRBool sendClientCert,
@@ -102,7 +105,8 @@ static SECStatus tls13_FinishHandshake(sslSocket *ss);
const char kHkdfLabelClient[] = "c";
const char kHkdfLabelServer[] = "s";
const char kHkdfLabelDerivedSecret[] = "derived";
-const char kHkdfLabelPskBinderKey[] = "res binder";
+const char kHkdfLabelResPskBinderKey[] = "res binder";
+const char kHkdfLabelExtPskBinderKey[] = "ext binder";
const char kHkdfLabelEarlyTrafficSecret[] = "e traffic";
const char kHkdfLabelEarlyExporterSecret[] = "e exp master";
const char kHkdfLabelHandshakeTrafficSecret[] = "hs traffic";
@@ -264,6 +268,16 @@ tls13_GetHashForCipherSuite(ssl3CipherSuite suite)
SSLHashType
tls13_GetHash(const sslSocket *ss)
{
+ /* suite_def may not be set yet when doing EPSK 0-Rtt. */
+ if (!ss->ssl3.hs.suite_def) {
+ if (ss->xtnData.selectedPsk) {
+ return ss->xtnData.selectedPsk->hash;
+ }
+ /* This should never happen. */
+ PORT_Assert(0);
+ return ssl_hash_none;
+ }
+
/* All TLS 1.3 cipher suites must have an explict PRF hash. */
PORT_Assert(ss->ssl3.hs.suite_def->prf_hash != ssl_hash_none);
return ss->ssl3.hs.suite_def->prf_hash;
@@ -318,9 +332,9 @@ tls13_GetHashSize(const sslSocket *ss)
}
static CK_MECHANISM_TYPE
-tls13_GetHmacMechanism(sslSocket *ss)
+tls13_GetHmacMechanismFromHash(SSLHashType hashType)
{
- switch (tls13_GetHash(ss)) {
+ switch (hashType) {
case ssl_hash_sha256:
return CKM_SHA256_HMAC;
case ssl_hash_sha384:
@@ -331,19 +345,25 @@ tls13_GetHmacMechanism(sslSocket *ss)
return CKM_SHA256_HMAC;
}
+static CK_MECHANISM_TYPE
+tls13_GetHmacMechanism(const sslSocket *ss)
+{
+ return tls13_GetHmacMechanismFromHash(tls13_GetHash(ss));
+}
+
SECStatus
tls13_ComputeHash(sslSocket *ss, SSL3Hashes *hashes,
- const PRUint8 *buf, unsigned int len)
+ const PRUint8 *buf, unsigned int len,
+ SSLHashType hash)
{
SECStatus rv;
- rv = PK11_HashBuf(ssl3_HashTypeToOID(tls13_GetHash(ss)),
- hashes->u.raw, buf, len);
+ rv = PK11_HashBuf(ssl3_HashTypeToOID(hash), hashes->u.raw, buf, len);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
return SECFailure;
}
- hashes->len = tls13_GetHashSize(ss);
+ hashes->len = tls13_GetHashSizeForHash(hash);
return SECSuccess;
}
@@ -461,40 +481,50 @@ tls13_SetupClientHello(sslSocket *ss, sslClientHelloType chType)
return SECFailure;
}
- /* Below here checks if we can do stateless resumption. */
- if (sid->cached == never_cached ||
- sid->version < SSL_LIBRARY_VERSION_TLS_1_3) {
- return SECSuccess;
- }
+ /* Try to do stateless resumption, if we can. */
+ if (sid->cached != never_cached &&
+ sid->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ /* The caller must be holding sid->u.ssl3.lock for reading. */
+ session_ticket = &sid->u.ssl3.locked.sessionTicket;
+ PORT_Assert(session_ticket && session_ticket->ticket.data);
- /* The caller must be holding sid->u.ssl3.lock for reading. */
- session_ticket = &sid->u.ssl3.locked.sessionTicket;
- PORT_Assert(session_ticket && session_ticket->ticket.data);
+ if (ssl_TicketTimeValid(ss, session_ticket)) {
+ ss->statelessResume = PR_TRUE;
+ }
- if (ssl_TicketTimeValid(ss, session_ticket)) {
- ss->statelessResume = PR_TRUE;
- }
+ if (ss->statelessResume) {
+ PORT_Assert(ss->sec.ci.sid);
+ rv = tls13_RecoverWrappedSharedSecret(ss, ss->sec.ci.sid);
+ if (rv != SECSuccess) {
+ FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+ SSL_AtomicIncrementLong(&ssl3stats->sch_sid_cache_not_ok);
+ ssl_UncacheSessionID(ss);
+ ssl_FreeSID(ss->sec.ci.sid);
+ ss->sec.ci.sid = NULL;
+ return SECFailure;
+ }
- if (ss->statelessResume) {
- PORT_Assert(ss->sec.ci.sid);
- rv = tls13_RecoverWrappedSharedSecret(ss, ss->sec.ci.sid);
- if (rv != SECSuccess) {
- FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
- SSL_AtomicIncrementLong(&ssl3stats->sch_sid_cache_not_ok);
- ssl_UncacheSessionID(ss);
- ssl_FreeSID(ss->sec.ci.sid);
- ss->sec.ci.sid = NULL;
- return SECFailure;
+ ss->ssl3.hs.cipher_suite = ss->sec.ci.sid->u.ssl3.cipherSuite;
+ rv = ssl3_SetupCipherSuite(ss, PR_FALSE);
+ if (rv != SECSuccess) {
+ FATAL_ERROR(ss, PORT_GetError(), internal_error);
+ return SECFailure;
+ }
+ PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks));
}
+ }
- ss->ssl3.hs.cipher_suite = ss->sec.ci.sid->u.ssl3.cipherSuite;
- rv = ssl3_SetupCipherSuite(ss, PR_FALSE);
- if (rv != SECSuccess) {
- FATAL_ERROR(ss, PORT_GetError(), internal_error);
- return SECFailure;
+ /* Derive the binder keys if any PSKs. */
+ if (!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks)) {
+ /* If an External PSK specified a suite, use that. */
+ sslPsk *psk = (sslPsk *)PR_LIST_HEAD(&ss->ssl3.hs.psks);
+ if (!ss->statelessResume &&
+ psk->type == ssl_psk_external &&
+ psk->zeroRttSuite != TLS_NULL_WITH_NULL_NULL) {
+ ss->ssl3.hs.cipher_suite = psk->zeroRttSuite;
}
- rv = tls13_ComputeEarlySecrets(ss);
+ rv = tls13_ComputeEarlySecretsWithPsk(ss);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
return SECFailure;
@@ -876,6 +906,12 @@ SSLExp_SendCertificateRequest(PRFileDesc *fd)
return SECFailure;
}
+ /* Disallow a CertificateRequest if this connection uses an external PSK. */
+ if (ss->sec.authType == ssl_auth_psk) {
+ PORT_SetError(SSL_ERROR_FEATURE_DISABLED);
+ return SECFailure;
+ }
+
rv = TLS13_CHECK_HS_STATE(ss, SEC_ERROR_INVALID_ARGS,
idle_handshake);
if (rv != SECSuccess) {
@@ -989,20 +1025,34 @@ tls13_RecoverWrappedSharedSecret(sslSocket *ss, sslSessionID *sid)
wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret;
wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len;
- /* unwrap the "master secret" which is actually RMS. */
- ss->ssl3.hs.resumptionMasterSecret = ssl_unwrapSymKey(
- wrapKey, sid->u.ssl3.masterWrapMech,
- NULL, &wrappedMS,
- CKM_SSL3_MASTER_KEY_DERIVE,
- CKA_DERIVE,
- tls13_GetHashSizeForHash(hashType),
- CKF_SIGN | CKF_VERIFY, ss->pkcs11PinArg);
+ PK11SymKey *unwrappedPsk = ssl_unwrapSymKey(wrapKey, sid->u.ssl3.masterWrapMech,
+ NULL, &wrappedMS, CKM_SSL3_MASTER_KEY_DERIVE,
+ CKA_DERIVE, tls13_GetHashSizeForHash(hashType),
+ CKF_SIGN | CKF_VERIFY, ss->pkcs11PinArg);
PK11_FreeSymKey(wrapKey);
- if (!ss->ssl3.hs.resumptionMasterSecret) {
+ if (!unwrappedPsk) {
return SECFailure;
}
+ sslPsk *rpsk = tls13_MakePsk(unwrappedPsk, ssl_psk_resume, hashType, NULL);
+ if (!rpsk) {
+ PK11_FreeSymKey(unwrappedPsk);
+ return SECFailure;
+ }
+ if (sid->u.ssl3.locked.sessionTicket.flags & ticket_allow_early_data) {
+ rpsk->maxEarlyData = sid->u.ssl3.locked.sessionTicket.max_early_data_size;
+ rpsk->zeroRttSuite = sid->u.ssl3.cipherSuite;
+ }
+ PRINT_KEY(50, (ss, "Recovered RMS", rpsk->key));
+ PORT_Assert(PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks) ||
+ ((sslPsk *)PR_LIST_HEAD(&ss->ssl3.hs.psks))->type != ssl_psk_resume);
- PRINT_KEY(50, (ss, "Recovered RMS", ss->ssl3.hs.resumptionMasterSecret));
+ if (ss->sec.isServer) {
+ /* In server, we couldn't select the RPSK in the extension handler
+ * since it was not unwrapped yet. We're committed now, so select
+ * it and add it to the list (to ensure it is freed). */
+ ss->xtnData.selectedPsk = rpsk;
+ }
+ PR_APPEND_LINK(&rpsk->link, &ss->ssl3.hs.psks);
return SECSuccess;
}
@@ -1060,38 +1110,45 @@ tls13_RecoverWrappedSharedSecret(sslSocket *ss, sslSessionID *sid)
* = resumption_master_secret
*
*/
-
static SECStatus
-tls13_ComputeEarlySecrets(sslSocket *ss)
+tls13_ComputeEarlySecretsWithPsk(sslSocket *ss)
{
- SECStatus rv = SECSuccess;
+ SECStatus rv;
SSL_TRC(5, ("%d: TLS13[%d]: compute early secrets (%s)",
SSL_GETPID(), ss->fd, SSL_ROLE(ss)));
- /* Extract off the resumptionMasterSecret (if present), else pass the NULL
- * resumptionMasterSecret which will be internally translated to zeroes. */
PORT_Assert(!ss->ssl3.hs.currentSecret);
- rv = tls13_HkdfExtract(NULL, ss->ssl3.hs.resumptionMasterSecret,
- tls13_GetHash(ss), &ss->ssl3.hs.currentSecret);
+ sslPsk *psk = NULL;
+
+ if (ss->sec.isServer) {
+ psk = ss->xtnData.selectedPsk;
+ } else {
+ /* Client to use the first PSK for early secrets. */
+ PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks));
+ psk = (sslPsk *)PR_LIST_HEAD(&ss->ssl3.hs.psks);
+ }
+ PORT_Assert(psk && psk->key);
+ PORT_Assert(psk->hash != ssl_hash_none);
+
+ PK11SymKey *earlySecret = NULL;
+ rv = tls13_HkdfExtract(NULL, psk->key, psk->hash, &earlySecret);
if (rv != SECSuccess) {
return SECFailure;
}
- PORT_Assert(ss->statelessResume == (ss->ssl3.hs.resumptionMasterSecret != NULL));
- if (ss->statelessResume) {
- PK11_FreeSymKey(ss->ssl3.hs.resumptionMasterSecret);
- ss->ssl3.hs.resumptionMasterSecret = NULL;
-
- rv = tls13_DeriveSecretNullHash(ss, ss->ssl3.hs.currentSecret,
- kHkdfLabelPskBinderKey,
- strlen(kHkdfLabelPskBinderKey),
- &ss->ssl3.hs.pskBinderKey);
- if (rv != SECSuccess) {
- return SECFailure;
- }
+ /* No longer need the raw input key */
+ PK11_FreeSymKey(psk->key);
+ psk->key = NULL;
+ const char *label = (psk->type == ssl_psk_resume) ? kHkdfLabelResPskBinderKey : kHkdfLabelExtPskBinderKey;
+ rv = tls13_DeriveSecretNullHash(ss, earlySecret,
+ label, strlen(label),
+ &psk->binderKey, psk->hash);
+ if (rv != SECSuccess) {
+ PK11_FreeSymKey(earlySecret);
+ return SECFailure;
}
- PORT_Assert(!ss->ssl3.hs.resumptionMasterSecret);
+ ss->ssl3.hs.currentSecret = earlySecret;
return SECSuccess;
}
@@ -1101,7 +1158,7 @@ static SECStatus
tls13_DeriveEarlySecrets(sslSocket *ss)
{
SECStatus rv;
-
+ PORT_Assert(ss->ssl3.hs.currentSecret);
rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret,
kHkdfLabelClient,
kHkdfLabelEarlyTrafficSecret,
@@ -1139,7 +1196,15 @@ tls13_ComputeHandshakeSecrets(sslSocket *ss)
SSL_TRC(5, ("%d: TLS13[%d]: compute handshake secrets (%s)",
SSL_GETPID(), ss->fd, SSL_ROLE(ss)));
- /* First update |currentSecret| to add |dheSecret|, if any. */
+ /* If no PSK, generate the default early secret. */
+ if (!ss->ssl3.hs.currentSecret) {
+ PORT_Assert(!ss->xtnData.selectedPsk);
+ rv = tls13_HkdfExtract(NULL, NULL,
+ tls13_GetHash(ss), &ss->ssl3.hs.currentSecret);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ }
PORT_Assert(ss->ssl3.hs.currentSecret);
PORT_Assert(ss->ssl3.hs.dheSecret);
@@ -1147,7 +1212,7 @@ tls13_ComputeHandshakeSecrets(sslSocket *ss)
rv = tls13_DeriveSecretNullHash(ss, ss->ssl3.hs.currentSecret,
kHkdfLabelDerivedSecret,
strlen(kHkdfLabelDerivedSecret),
- &derivedSecret);
+ &derivedSecret, tls13_GetHash(ss));
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return rv;
@@ -1206,7 +1271,7 @@ tls13_ComputeHandshakeSecrets(sslSocket *ss)
rv = tls13_DeriveSecretNullHash(ss, ss->ssl3.hs.currentSecret,
kHkdfLabelDerivedSecret,
strlen(kHkdfLabelDerivedSecret),
- &derivedSecret);
+ &derivedSecret, tls13_GetHash(ss));
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return rv;
@@ -1278,7 +1343,7 @@ tls13_ComputeFinalSecrets(sslSocket *ss)
PORT_Assert(!ss->ssl3.crSpec->masterSecret);
PORT_Assert(!ss->ssl3.cwSpec->masterSecret);
-
+ PORT_Assert(ss->ssl3.hs.currentSecret);
rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret,
NULL, kHkdfLabelResumptionMasterSecret,
NULL,
@@ -1319,7 +1384,14 @@ tls13_CanResume(sslSocket *ss, const sslSessionID *sid)
return PR_FALSE;
}
+#ifdef UNSAFE_FUZZER_MODE
+ /* When fuzzing, sid could contain garbage that will crash tls13_GetHashForCipherSuite.
+ * Do a direct comparison of cipher suites. This makes us refuse to resume when the
+ * protocol allows it, but resumption is discretionary anyway. */
+ if (sid->u.ssl3.cipherSuite != ss->ssl3.hs.cipher_suite) {
+#else
if (tls13_GetHashForCipherSuite(sid->u.ssl3.cipherSuite) != tls13_GetHashForCipherSuite(ss->ssl3.hs.cipher_suite)) {
+#endif
return PR_FALSE;
}
@@ -1339,21 +1411,40 @@ static PRBool
tls13_CanNegotiateZeroRtt(sslSocket *ss, const sslSessionID *sid)
{
PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_sent);
+ sslPsk *psk = ss->xtnData.selectedPsk;
- if (!sid)
+ if (!ss->opt.enable0RttData) {
return PR_FALSE;
- PORT_Assert(ss->statelessResume);
- if (!ss->statelessResume)
+ }
+ if (!psk) {
return PR_FALSE;
- if (ss->ssl3.hs.cipher_suite != sid->u.ssl3.cipherSuite)
+ }
+ if (psk->zeroRttSuite == TLS_NULL_WITH_NULL_NULL) {
return PR_FALSE;
- if (!ss->opt.enable0RttData)
+ }
+ if (!psk->maxEarlyData) {
return PR_FALSE;
- if (!(sid->u.ssl3.locked.sessionTicket.flags & ticket_allow_early_data))
+ }
+ if (ss->ssl3.hs.cipher_suite != psk->zeroRttSuite) {
return PR_FALSE;
- if (SECITEM_CompareItem(&ss->xtnData.nextProto,
- &sid->u.ssl3.alpnSelection) != 0)
+ }
+ if (psk->type == ssl_psk_resume) {
+ if (!sid) {
+ return PR_FALSE;
+ }
+ PORT_Assert(sid->u.ssl3.locked.sessionTicket.flags & ticket_allow_early_data);
+ PORT_Assert(ss->statelessResume);
+ if (!ss->statelessResume) {
+ return PR_FALSE;
+ }
+ if (SECITEM_CompareItem(&ss->xtnData.nextProto,
+ &sid->u.ssl3.alpnSelection) != 0) {
+ return PR_FALSE;
+ }
+ } else if (psk->type != ssl_psk_external) {
+ PORT_Assert(0);
return PR_FALSE;
+ }
if (tls13_IsReplay(ss, sid)) {
return PR_FALSE;
@@ -1406,7 +1497,7 @@ tls13_NegotiateZeroRtt(sslSocket *ss, const sslSessionID *sid)
}
SSL_TRC(3, ("%d: TLS13[%d]: enable 0-RTT", SSL_GETPID(), ss->fd));
- PORT_Assert(ss->statelessResume);
+ PORT_Assert(ss->xtnData.selectedPsk);
ss->ssl3.hs.zeroRttState = ssl_0rtt_accepted;
ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_none;
ss->ssl3.hs.zeroRttSuite = ss->ssl3.hs.cipher_suite;
@@ -1458,7 +1549,7 @@ tls13_NegotiateKeyExchange(sslSocket *ss,
const sslNamedGroupDef *preferredGroup = NULL;
/* We insist on DHE. */
- if (ss->statelessResume) {
+ if (ssl3_ExtensionNegotiated(ss, ssl_tls13_pre_shared_key_xtn)) {
if (!ssl3_ExtensionNegotiated(ss, ssl_tls13_psk_key_exchange_modes_xtn)) {
FATAL_ERROR(ss, SSL_ERROR_MISSING_PSK_KEY_EXCHANGE_MODES,
missing_extension);
@@ -1482,8 +1573,8 @@ tls13_NegotiateKeyExchange(sslSocket *ss,
return SECFailure;
}
- SSL_TRC(3, ("%d: TLS13[%d]: selected KE = %s",
- SSL_GETPID(), ss->fd, ss->statelessResume ? "PSK + (EC)DHE" : "(EC)DHE"));
+ SSL_TRC(3, ("%d: TLS13[%d]: selected KE = %s", SSL_GETPID(),
+ ss->fd, ss->statelessResume || ss->xtnData.selectedPsk ? "PSK + (EC)DHE" : "(EC)DHE"));
/* Find the preferred group and an according client key share available. */
for (index = 0; index < SSL_NAMED_GROUP_COUNT; ++index) {
@@ -1671,26 +1762,42 @@ tls13_MaybeSendHelloRetry(sslSocket *ss, const sslNamedGroupDef *requestedGroup,
static SECStatus
tls13_NegotiateAuthentication(sslSocket *ss)
{
- SECStatus rv;
-
if (ss->statelessResume) {
- SSL_TRC(3, ("%d: TLS13[%d]: selected PSK authentication",
+ SSL_TRC(3, ("%d: TLS13[%d]: selected resumption PSK authentication",
SSL_GETPID(), ss->fd));
ss->ssl3.hs.signatureScheme = ssl_sig_none;
ss->ssl3.hs.kea_def_mutable.authKeyType = ssl_auth_psk;
+ /* Overwritten by tls13_RestoreCipherInfo. */
+ ss->sec.authType = ssl_auth_psk;
return SECSuccess;
+ } else if (ss->xtnData.selectedPsk) {
+ /* If the EPSK doesn't specify a suite, use what was negotiated.
+ * Else, only use the EPSK if we negotiated that suite. */
+ if (ss->xtnData.selectedPsk->zeroRttSuite == TLS_NULL_WITH_NULL_NULL ||
+ ss->ssl3.hs.cipher_suite == ss->xtnData.selectedPsk->zeroRttSuite) {
+ SSL_TRC(3, ("%d: TLS13[%d]: selected external PSK authentication",
+ SSL_GETPID(), ss->fd));
+ ss->ssl3.hs.signatureScheme = ssl_sig_none;
+ ss->ssl3.hs.kea_def_mutable.authKeyType = ssl_auth_psk;
+ ss->sec.authType = ssl_auth_psk;
+ return SECSuccess;
+ }
+ }
+
+ /* If there were PSKs, they are no longer needed. */
+ if (ss->xtnData.selectedPsk) {
+ tls13_DestroyPskList(&ss->ssl3.hs.psks);
+ ss->xtnData.selectedPsk = NULL;
}
SSL_TRC(3, ("%d: TLS13[%d]: selected certificate authentication",
SSL_GETPID(), ss->fd));
- /* We've now established that we need to sign.... */
- rv = tls13_SelectServerCert(ss);
+ SECStatus rv = tls13_SelectServerCert(ss);
if (rv != SECSuccess) {
return SECFailure;
}
return SECSuccess;
}
-
/* Called from ssl3_HandleClientHello after we have parsed the
* ClientHello and are sure that we are going to do TLS 1.3
* or fail. */
@@ -1854,40 +1961,51 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
goto loser;
}
- if (ss->statelessResume) {
- /* We are now committed to trying to resume. */
- PORT_Assert(sid);
-
- /* Check that the negotiated SNI and the cached SNI match. */
- if (SECITEM_CompareItem(&sid->u.ssl3.srvName,
- &ss->ssl3.hs.srvVirtName) != SECEqual) {
- FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO,
- handshake_failure);
- goto loser;
- }
+ if (ss->sec.authType == ssl_auth_psk) {
+ if (ss->statelessResume) {
+ /* We are now committed to trying to resume. */
+ PORT_Assert(sid);
+ /* Check that the negotiated SNI and the cached SNI match. */
+ if (SECITEM_CompareItem(&sid->u.ssl3.srvName,
+ &ss->ssl3.hs.srvVirtName) != SECEqual) {
+ FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO,
+ handshake_failure);
+ goto loser;
+ }
- ss->sec.serverCert = ssl_FindServerCert(ss, sid->authType,
- sid->namedCurve);
- PORT_Assert(ss->sec.serverCert);
+ ss->sec.serverCert = ssl_FindServerCert(ss, sid->authType,
+ sid->namedCurve);
+ PORT_Assert(ss->sec.serverCert);
- rv = tls13_RecoverWrappedSharedSecret(ss, sid);
- if (rv != SECSuccess) {
- SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_not_ok);
- FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
- goto loser;
- }
- tls13_RestoreCipherInfo(ss, sid);
+ rv = tls13_RecoverWrappedSharedSecret(ss, sid);
+ if (rv != SECSuccess) {
+ SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_not_ok);
+ FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+ goto loser;
+ }
+ tls13_RestoreCipherInfo(ss, sid);
- ss->sec.localCert = CERT_DupCertificate(ss->sec.serverCert->serverCert);
- if (sid->peerCert != NULL) {
- ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
+ ss->sec.localCert = CERT_DupCertificate(ss->sec.serverCert->serverCert);
+ if (sid->peerCert != NULL) {
+ ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
+ }
+ } else if (sid) {
+ /* We should never have a SID in the non-resumption case. */
+ PORT_Assert(0);
+ ssl_UncacheSessionID(ss);
+ ssl_FreeSID(sid);
+ sid = NULL;
}
-
ssl3_RegisterExtensionSender(
ss, &ss->xtnData,
ssl_tls13_pre_shared_key_xtn, tls13_ServerSendPreSharedKeyXtn);
-
tls13_NegotiateZeroRtt(ss, sid);
+
+ rv = tls13_ComputeEarlySecretsWithPsk(ss);
+ if (rv != SECSuccess) {
+ FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+ return SECFailure;
+ }
} else {
if (sid) { /* we had a sid, but it's no longer valid, free it */
SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_not_ok);
@@ -1898,35 +2016,34 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
tls13_NegotiateZeroRtt(ss, NULL);
}
- /* Need to compute early secrets. */
- rv = tls13_ComputeEarlySecrets(ss);
- if (rv != SECSuccess) {
- FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
- return SECFailure;
+ if (ss->statelessResume) {
+ PORT_Assert(ss->xtnData.selectedPsk);
+ PORT_Assert(ss->ssl3.hs.kea_def_mutable.authKeyType == ssl_auth_psk);
}
- /* Now that we have the binder key check the binder. */
- if (ss->statelessResume) {
+ /* Now that we have the binder key, check the binder. */
+ if (ss->xtnData.selectedPsk) {
SSL3Hashes hashes;
-
PORT_Assert(ss->ssl3.hs.messages.len > ss->xtnData.pskBindersLen);
rv = tls13_ComputePskBinderHash(
ss,
ss->ssl3.hs.messages.len - ss->xtnData.pskBindersLen,
- &hashes);
+ &hashes, tls13_GetHash(ss));
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
goto loser;
}
+ PORT_Assert(ss->xtnData.selectedPsk->hash == tls13_GetHash(ss));
+ PORT_Assert(ss->ssl3.hs.suite_def);
rv = tls13_VerifyFinished(ss, ssl_hs_client_hello,
- ss->ssl3.hs.pskBinderKey,
+ ss->xtnData.selectedPsk->binderKey,
ss->xtnData.pskBinder.data,
ss->xtnData.pskBinder.len,
&hashes);
- if (rv != SECSuccess) {
- goto loser;
- }
+ }
+ if (rv != SECSuccess) {
+ goto loser;
}
/* This needs to go after we verify the psk binder. */
@@ -1953,7 +2070,7 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_not_ok);
ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
- } else {
+ } else if (!ss->xtnData.selectedPsk) {
SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_misses);
}
@@ -1983,6 +2100,10 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
return SECFailure;
}
+ /* We're done with PSKs */
+ tls13_DestroyPskList(&ss->ssl3.hs.psks);
+ ss->xtnData.selectedPsk = NULL;
+
return SECSuccess;
loser:
@@ -2314,7 +2435,8 @@ tls13_ReinjectHandshakeTranscript(sslSocket *ss)
// First compute the hash.
rv = tls13_ComputeHash(ss, &hashes,
ss->ssl3.hs.messages.buf,
- ss->ssl3.hs.messages.len);
+ ss->ssl3.hs.messages.len,
+ tls13_GetHash(ss));
if (rv != SECSuccess) {
return SECFailure;
}
@@ -2331,7 +2453,6 @@ tls13_ReinjectHandshakeTranscript(sslSocket *ss)
return SECSuccess;
}
-
static unsigned int
ssl_ListCount(PRCList *list)
{
@@ -2454,6 +2575,12 @@ tls13_HandleCertificateRequest(sslSocket *ss, PRUint8 *b, PRUint32 length)
return SECFailure;
}
+ /* MUST NOT combine external PSKs with certificate authentication. */
+ if (ss->sec.authType == ssl_auth_psk) {
+ FATAL_ERROR(ss, SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST, unexpected_message);
+ return SECFailure;
+ }
+
if (tls13_IsPostHandshake(ss)) {
PORT_Assert(ss->ssl3.hs.shaPostHandshake == NULL);
ss->ssl3.hs.shaPostHandshake = PK11_CloneContext(ss->ssl3.hs.sha);
@@ -2569,6 +2696,8 @@ tls13_HandleCertificateRequest(sslSocket *ss, PRUint8 *b, PRUint32 length)
PRBool
tls13_ShouldRequestClientAuth(sslSocket *ss)
{
+ /* Even if we are configured to request a certificate, we can't
+ * if this handshake used a PSK, even when we are resuming. */
return ss->opt.requestCertificate &&
ss->ssl3.hs.kea_def->authKeyType != ssl_auth_psk;
}
@@ -2737,7 +2866,9 @@ tls13_SendServerHelloSequence(sslSocket *ss)
}
}
- ss->ssl3.hs.serverHelloTime = ssl_Time(ss);
+ /* Here we set a baseline value for our RTT estimation.
+ * This value is updated when we get a response from the client. */
+ ss->ssl3.hs.rttEstimate = ssl_Time(ss);
return SECSuccess;
}
@@ -2749,14 +2880,22 @@ tls13_HandleServerHelloPart2(sslSocket *ss)
SSL3Statistics *ssl3stats = SSL_GetStatistics();
if (ssl3_ExtensionNegotiated(ss, ssl_tls13_pre_shared_key_xtn)) {
- PORT_Assert(ss->statelessResume);
+ PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks));
+ PORT_Assert(ss->xtnData.selectedPsk);
+
+ if (ss->xtnData.selectedPsk->type != ssl_psk_resume) {
+ ss->statelessResume = PR_FALSE;
+ }
} else {
+ /* We may have offered a PSK. If the server didn't negotiate
+ * it, clear this state to re-extract the Early Secret. */
if (ss->ssl3.hs.currentSecret) {
- PORT_Assert(ss->statelessResume);
+ PORT_Assert(ssl3_ExtensionAdvertised(ss, ssl_tls13_pre_shared_key_xtn));
PK11_FreeSymKey(ss->ssl3.hs.currentSecret);
ss->ssl3.hs.currentSecret = NULL;
}
ss->statelessResume = PR_FALSE;
+ ss->xtnData.selectedPsk = NULL;
}
if (ss->statelessResume) {
@@ -2773,19 +2912,22 @@ tls13_HandleServerHelloPart2(sslSocket *ss)
ss->ssl3.hs.kea_def_mutable = *ss->ssl3.hs.kea_def;
ss->ssl3.hs.kea_def = &ss->ssl3.hs.kea_def_mutable;
- if (ss->statelessResume) {
- /* PSK */
+ if (ss->xtnData.selectedPsk) {
ss->ssl3.hs.kea_def_mutable.authKeyType = ssl_auth_psk;
- tls13_RestoreCipherInfo(ss, sid);
- if (sid->peerCert) {
- ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
- }
+ if (ss->statelessResume) {
+ tls13_RestoreCipherInfo(ss, sid);
+ if (sid->peerCert) {
+ ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
+ }
- SSL_AtomicIncrementLong(&ssl3stats->hsh_sid_cache_hits);
- SSL_AtomicIncrementLong(&ssl3stats->hsh_sid_stateless_resumes);
+ SSL_AtomicIncrementLong(&ssl3stats->hsh_sid_cache_hits);
+ SSL_AtomicIncrementLong(&ssl3stats->hsh_sid_stateless_resumes);
+ } else {
+ ss->sec.authType = ssl_auth_psk;
+ }
} else {
- /* !PSK */
- if (ssl3_ExtensionAdvertised(ss, ssl_tls13_pre_shared_key_xtn)) {
+ if (ss->statelessResume &&
+ ssl3_ExtensionAdvertised(ss, ssl_tls13_pre_shared_key_xtn)) {
SSL_AtomicIncrementLong(&ssl3stats->hsh_sid_cache_misses);
}
if (sid->cached == in_client_cache) {
@@ -2794,18 +2936,6 @@ tls13_HandleServerHelloPart2(sslSocket *ss)
}
}
- if (!ss->ssl3.hs.currentSecret) {
- PORT_Assert(!ss->statelessResume);
-
- /* If we don't already have the Early Secret we need to make it
- * now. */
- rv = tls13_ComputeEarlySecrets(ss);
- if (rv != SECSuccess) {
- FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
- return SECFailure;
- }
- }
-
/* Discard current SID and make a new one, though it may eventually
* end up looking a lot like the old one.
*/
@@ -3105,6 +3235,13 @@ tls13_HandleCertificate(sslSocket *ss, PRUint8 *b, PRUint32 length)
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
if (ss->sec.isServer) {
+ /* Receiving this message might be the first sign we have that
+ * early data is over, so pretend we received EOED. */
+ rv = tls13_MaybeHandleSuppressedEndOfEarlyData(ss);
+ if (rv != SECSuccess) {
+ return SECFailure; /* Code already set. */
+ }
+
if (ss->ssl3.clientCertRequested) {
rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERTIFICATE,
idle_handshake);
@@ -3116,8 +3253,9 @@ tls13_HandleCertificate(sslSocket *ss, PRUint8 *b, PRUint32 length)
rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERTIFICATE,
wait_cert_request, wait_server_cert);
}
- if (rv != SECSuccess)
+ if (rv != SECSuccess) {
return SECFailure;
+ }
/* We can ignore any other cleartext from the client. */
if (ss->sec.isServer && IS_DTLS(ss)) {
@@ -3131,6 +3269,11 @@ tls13_HandleCertificate(sslSocket *ss, PRUint8 *b, PRUint32 length)
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
+ } else if (ss->sec.isServer) {
+ /* Our first shot an getting an RTT estimate. If the client took extra
+ * time to fetch a certificate, this will be bad, but we can't do much
+ * about that. */
+ ss->ssl3.hs.rttEstimate = ssl_Time(ss) - ss->ssl3.hs.rttEstimate;
}
/* Process the context string */
@@ -3302,15 +3445,14 @@ tls13_DeriveSecret(sslSocket *ss, PK11SymKey *key,
const char *label,
unsigned int labelLen,
const SSL3Hashes *hashes,
- PK11SymKey **dest)
+ PK11SymKey **dest,
+ SSLHashType hash)
{
SECStatus rv;
- rv = tls13_HkdfExpandLabel(key, tls13_GetHash(ss),
- hashes->u.raw, hashes->len,
- label, labelLen,
- CKM_HKDF_DERIVE,
- tls13_GetHashSize(ss),
+ rv = tls13_HkdfExpandLabel(key, hash, hashes->u.raw, hashes->len,
+ label, labelLen, CKM_HKDF_DERIVE,
+ tls13_GetHashSizeForHash(hash),
ss->protocolVariant, dest);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
@@ -3324,18 +3466,19 @@ SECStatus
tls13_DeriveSecretNullHash(sslSocket *ss, PK11SymKey *key,
const char *label,
unsigned int labelLen,
- PK11SymKey **dest)
+ PK11SymKey **dest,
+ SSLHashType hash)
{
SSL3Hashes hashes;
SECStatus rv;
PRUint8 buf[] = { 0 };
- rv = tls13_ComputeHash(ss, &hashes, buf, 0);
+ rv = tls13_ComputeHash(ss, &hashes, buf, 0, hash);
if (rv != SECSuccess) {
return SECFailure;
}
- return tls13_DeriveSecret(ss, key, label, labelLen, &hashes, dest);
+ return tls13_DeriveSecret(ss, key, label, labelLen, &hashes, dest, hash);
}
/* Convenience wrapper that lets us supply a separate prefix and suffix. */
@@ -3374,7 +3517,7 @@ tls13_DeriveSecretWrap(sslSocket *ss, PK11SymKey *key,
}
rv = tls13_DeriveSecret(ss, key, label, strlen(label),
- &hashes, dest);
+ &hashes, dest, tls13_GetHash(ss));
if (rv != SECSuccess) {
return SECFailure;
}
@@ -3538,8 +3681,10 @@ tls13_SetupPendingCipherSpec(sslSocket *ss, ssl3CipherSpec *spec)
spec->cipherDef = ssl_GetBulkCipherDef(ssl_LookupCipherSuiteDef(suite));
if (spec->epoch == TrafficKeyEarlyApplicationData) {
- spec->earlyDataRemaining =
- ss->sec.ci.sid->u.ssl3.locked.sessionTicket.max_early_data_size;
+ if (ss->xtnData.selectedPsk &&
+ ss->xtnData.selectedPsk->zeroRttSuite != TLS_NULL_WITH_NULL_NULL) {
+ spec->earlyDataRemaining = ss->xtnData.selectedPsk->maxEarlyData;
+ }
}
tls13_SetSpecRecordVersion(ss, spec);
@@ -4005,7 +4150,7 @@ tls13_HandleEncryptedExtensions(sslSocket *ss, PRUint8 *b, PRUint32 length)
/* We can only get here if we offered 0-RTT. */
if (ssl3_ExtensionNegotiated(ss, ssl_tls13_early_data_xtn)) {
PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_sent);
- if (!ss->statelessResume) {
+ if (!ss->xtnData.selectedPsk) {
/* Illegal to accept 0-RTT without also accepting PSK. */
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_ENCRYPTED_EXTENSIONS,
illegal_parameter);
@@ -4043,6 +4188,10 @@ tls13_HandleEncryptedExtensions(sslSocket *ss, PRUint8 *b, PRUint32 length)
TLS13_SET_HS_STATE(ss, wait_cert_request);
}
+ /* Client is done with any PSKs */
+ tls13_DestroyPskList(&ss->ssl3.hs.psks);
+ ss->xtnData.selectedPsk = NULL;
+
return SECSuccess;
}
@@ -4322,7 +4471,7 @@ loser:
static SECStatus
tls13_ComputePskBinderHash(sslSocket *ss, unsigned int prefixLength,
- SSL3Hashes *hashes)
+ SSL3Hashes *hashes, SSLHashType hashType)
{
SECStatus rv;
@@ -4332,14 +4481,14 @@ tls13_ComputePskBinderHash(sslSocket *ss, unsigned int prefixLength,
PRINT_BUF(10, (NULL, "Handshake hash computed over ClientHello prefix",
ss->ssl3.hs.messages.buf, prefixLength));
- rv = PK11_HashBuf(ssl3_HashTypeToOID(tls13_GetHash(ss)),
+ rv = PK11_HashBuf(ssl3_HashTypeToOID(hashType),
hashes->u.raw, ss->ssl3.hs.messages.buf, prefixLength);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
return SECFailure;
}
- hashes->len = tls13_GetHashSize(ss);
+ hashes->len = tls13_GetHashSizeForHash(hashType);
PRINT_BUF(10, (NULL, "PSK Binder hash", hashes->u.raw, hashes->len));
return SECSuccess;
@@ -4357,7 +4506,10 @@ tls13_WriteExtensionsWithBinder(sslSocket *ss, sslBuffer *extensions)
{
SSL3Hashes hashes;
SECStatus rv;
- unsigned int size = tls13_GetHashSize(ss);
+
+ PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks));
+ sslPsk *psk = (sslPsk *)PR_LIST_HEAD(&ss->ssl3.hs.psks);
+ unsigned int size = tls13_GetHashSizeForHash(psk->hash);
unsigned int prefixLen = extensions->len - size - 3;
unsigned int finishedLen;
@@ -4378,15 +4530,18 @@ tls13_WriteExtensionsWithBinder(sslSocket *ss, sslBuffer *extensions)
}
/* Calculate the binder based on what has been written out. */
- rv = tls13_ComputePskBinderHash(ss, ss->ssl3.hs.messages.len, &hashes);
+ rv = tls13_ComputePskBinderHash(ss, ss->ssl3.hs.messages.len,
+ &hashes, psk->hash);
if (rv != SECSuccess) {
return SECFailure;
}
/* Write the binder into the extensions buffer, over the zeros we reserved
- * previously. This avoids an allocation and means that we don't need a
+ * previously. This avoids an allocation and means that we don't need a
* separate write for the extra bits that precede the binder. */
- rv = tls13_ComputeFinished(ss, ss->ssl3.hs.pskBinderKey, &hashes, PR_TRUE,
+ PORT_Assert(psk->binderKey);
+ rv = tls13_ComputeFinished(ss, psk->binderKey,
+ psk->hash, &hashes, PR_TRUE,
extensions->buf + extensions->len - size,
&finishedLen, size);
if (rv != SECSuccess) {
@@ -4406,13 +4561,13 @@ tls13_WriteExtensionsWithBinder(sslSocket *ss, sslBuffer *extensions)
static SECStatus
tls13_ComputeFinished(sslSocket *ss, PK11SymKey *baseKey,
- const SSL3Hashes *hashes,
+ SSLHashType hashType, const SSL3Hashes *hashes,
PRBool sending, PRUint8 *output, unsigned int *outputLen,
unsigned int maxOutputLen)
{
SECStatus rv;
PK11Context *hmacCtx = NULL;
- CK_MECHANISM_TYPE macAlg = tls13_GetHmacMechanism(ss);
+ CK_MECHANISM_TYPE macAlg = tls13_GetHmacMechanismFromHash(hashType);
SECItem param = { siBuffer, NULL, 0 };
unsigned int outputLenUint;
const char *label = kHkdfLabelFinishedSecret;
@@ -4424,18 +4579,16 @@ tls13_ComputeFinished(sslSocket *ss, PK11SymKey *baseKey,
PRINT_BUF(50, (ss, "Handshake hash", hashes->u.raw, hashes->len));
/* Now derive the appropriate finished secret from the base secret. */
- rv = tls13_HkdfExpandLabel(baseKey,
- tls13_GetHash(ss),
- NULL, 0,
- label, strlen(label),
- tls13_GetHmacMechanism(ss),
- tls13_GetHashSize(ss),
+ rv = tls13_HkdfExpandLabel(baseKey, hashType,
+ NULL, 0, label, strlen(label),
+ tls13_GetHmacMechanismFromHash(hashType),
+ tls13_GetHashSizeForHash(hashType),
ss->protocolVariant, &secret);
if (rv != SECSuccess) {
goto abort;
}
- PORT_Assert(hashes->len == tls13_GetHashSize(ss));
+ PORT_Assert(hashes->len == tls13_GetHashSizeForHash(hashType));
hmacCtx = PK11_CreateContextBySymKey(macAlg, CKA_SIGN,
secret, &param);
if (!hmacCtx) {
@@ -4450,7 +4603,7 @@ tls13_ComputeFinished(sslSocket *ss, PK11SymKey *baseKey,
if (rv != SECSuccess)
goto abort;
- PORT_Assert(maxOutputLen >= tls13_GetHashSize(ss));
+ PORT_Assert(maxOutputLen >= tls13_GetHashSizeForHash(hashType));
rv = PK11_DigestFinal(hmacCtx, output, &outputLenUint, maxOutputLen);
if (rv != SECSuccess)
goto abort;
@@ -4494,7 +4647,7 @@ tls13_SendFinished(sslSocket *ss, PK11SymKey *baseKey)
}
ssl_GetSpecReadLock(ss);
- rv = tls13_ComputeFinished(ss, baseKey, &hashes, PR_TRUE,
+ rv = tls13_ComputeFinished(ss, baseKey, tls13_GetHash(ss), &hashes, PR_TRUE,
finishedBuf, &finishedLen, sizeof(finishedBuf));
ssl_ReleaseSpecReadLock(ss);
if (rv != SECSuccess) {
@@ -4531,7 +4684,7 @@ tls13_VerifyFinished(sslSocket *ss, SSLHandshakeType message,
return SECFailure;
}
- rv = tls13_ComputeFinished(ss, secret, hashes, PR_FALSE,
+ rv = tls13_ComputeFinished(ss, secret, tls13_GetHash(ss), hashes, PR_FALSE,
finishedBuf, &finishedLen, sizeof(finishedBuf));
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
@@ -4621,6 +4774,20 @@ tls13_ServerHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length)
SSL_TRC(3, ("%d: TLS13[%d]: server handle finished handshake",
SSL_GETPID(), ss->fd));
+ if (!tls13_ShouldRequestClientAuth(ss)) {
+ /* Receiving this message might be the first sign we have that
+ * early data is over, so pretend we received EOED. */
+ rv = tls13_MaybeHandleSuppressedEndOfEarlyData(ss);
+ if (rv != SECSuccess) {
+ return SECFailure; /* Code already set. */
+ }
+
+ if (!tls13_IsPostHandshake(ss)) {
+ /* Finalize the RTT estimate. */
+ ss->ssl3.hs.rttEstimate = ssl_Time(ss) - ss->ssl3.hs.rttEstimate;
+ }
+ }
+
rv = tls13_CommonHandleFinished(ss,
ss->firstHsDone ? ss->ssl3.hs.clientTrafficSecret : ss->ssl3.hs.clientHsTrafficSecret,
b, length);
@@ -4684,7 +4851,8 @@ tls13_ServerHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length)
}
ssl_GetXmitBufLock(ss);
- if (ss->opt.enableSessionTickets) {
+ /* If resumption, authType is the original value and not ssl_auth_psk. */
+ if (ss->opt.enableSessionTickets && ss->sec.authType != ssl_auth_psk) {
rv = tls13_SendNewSessionTicket(ss, NULL, 0);
if (rv != SECSuccess) {
goto loser;
@@ -5067,6 +5235,14 @@ SSLExp_SendSessionTicket(PRFileDesc *fd, const PRUint8 *token,
return SECFailure;
}
+ /* Disable tickets if we can trace this connection back to a PSK.
+ * We aren't able to issue tickets (currently) without a certificate.
+ * As PSK =~ resumption, there is no reason to do this. */
+ if (ss->sec.authType == ssl_auth_psk) {
+ PORT_SetError(SSL_ERROR_FEATURE_DISABLED);
+ return SECFailure;
+ }
+
ssl_GetSSL3HandshakeLock(ss);
ssl_GetXmitBufLock(ss);
rv = tls13_SendNewSessionTicket(ss, token, tokenLen);
@@ -5541,6 +5717,10 @@ tls13_UnprotectRecord(sslSocket *ss,
cText->buf->buf, /* in */
cText->buf->len); /* inlen */
if (rv != SECSuccess) {
+ if (IS_DTLS(ss)) {
+ spec->deprotectionFailures++;
+ }
+
SSL_TRC(3,
("%d: TLS13[%d]: record has bogus MAC",
SSL_GETPID(), ss->fd));
@@ -5601,9 +5781,10 @@ tls13_UnprotectRecord(sslSocket *ss,
* 1. We are doing TLS 1.3
* 2. This isn't a second ClientHello (in response to HelloRetryRequest)
* 3. The 0-RTT option is set.
- * 4. We have a valid ticket.
- * 5. The server is willing to accept 0-RTT.
- * 6. We have not changed our ALPN settings to disallow the ALPN tag
+ * 4. We have a valid ticket or an External PSK.
+ * 5. If resuming:
+ * 5a. The server is willing to accept 0-RTT.
+ * 5b. We have not changed our ALPN settings to disallow the ALPN tag
* in the ticket.
*
* Called from tls13_ClientSendEarlyDataXtn().
@@ -5613,17 +5794,39 @@ tls13_ClientAllow0Rtt(const sslSocket *ss, const sslSessionID *sid)
{
/* We checked that the cipher suite was still allowed back in
* ssl3_SendClientHello. */
- if (sid->version < SSL_LIBRARY_VERSION_TLS_1_3)
+ if (sid->version < SSL_LIBRARY_VERSION_TLS_1_3) {
return PR_FALSE;
- if (ss->ssl3.hs.helloRetry)
+ }
+ if (ss->ssl3.hs.helloRetry) {
return PR_FALSE;
- if (!ss->opt.enable0RttData)
+ }
+ if (!ss->opt.enable0RttData) {
return PR_FALSE;
- if (!ss->statelessResume)
+ }
+ if (PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks)) {
return PR_FALSE;
- if ((sid->u.ssl3.locked.sessionTicket.flags & ticket_allow_early_data) == 0)
+ }
+ sslPsk *psk = (sslPsk *)PR_LIST_HEAD(&ss->ssl3.hs.psks);
+
+ if (psk->zeroRttSuite == TLS_NULL_WITH_NULL_NULL) {
return PR_FALSE;
- return ssl_AlpnTagAllowed(ss, &sid->u.ssl3.alpnSelection);
+ }
+ if (!psk->maxEarlyData) {
+ return PR_FALSE;
+ }
+
+ if (psk->type == ssl_psk_external) {
+ return psk->hash == tls13_GetHashForCipherSuite(psk->zeroRttSuite);
+ }
+ if (psk->type == ssl_psk_resume) {
+ if (!ss->statelessResume)
+ return PR_FALSE;
+ if ((sid->u.ssl3.locked.sessionTicket.flags & ticket_allow_early_data) == 0)
+ return PR_FALSE;
+ return ssl_AlpnTagAllowed(ss, &sid->u.ssl3.alpnSelection);
+ }
+ PORT_Assert(0);
+ return PR_FALSE;
}
SECStatus
@@ -5670,6 +5873,9 @@ tls13_MaybeDo0RTTHandshake(sslSocket *ss)
}
}
+ /* If we're trying 0-RTT, derive from the first PSK */
+ PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks) && !ss->xtnData.selectedPsk);
+ ss->xtnData.selectedPsk = (sslPsk *)PR_LIST_HEAD(&ss->ssl3.hs.psks);
rv = tls13_DeriveEarlySecrets(ss);
if (rv != SECSuccess) {
return SECFailure;
@@ -5681,6 +5887,7 @@ tls13_MaybeDo0RTTHandshake(sslSocket *ss)
rv = tls13_SetCipherSpec(ss, TrafficKeyEarlyApplicationData,
ssl_secret_write, PR_TRUE);
+ ss->xtnData.selectedPsk = NULL;
if (rv != SECSuccess) {
return SECFailure;
}
@@ -5735,12 +5942,14 @@ tls13_SendEndOfEarlyData(sslSocket *ss)
{
SECStatus rv;
- SSL_TRC(3, ("%d: TLS13[%d]: send EndOfEarlyData", SSL_GETPID(), ss->fd));
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
- rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_end_of_early_data, 0);
- if (rv != SECSuccess) {
- return rv; /* err set by AppendHandshake. */
+ if (!ss->opt.suppressEndOfEarlyData) {
+ SSL_TRC(3, ("%d: TLS13[%d]: send EndOfEarlyData", SSL_GETPID(), ss->fd));
+ rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_end_of_early_data, 0);
+ if (rv != SECSuccess) {
+ return rv; /* err set by AppendHandshake. */
+ }
}
ss->ssl3.hs.zeroRttState = ssl_0rtt_done;
@@ -5748,7 +5957,7 @@ tls13_SendEndOfEarlyData(sslSocket *ss)
}
static SECStatus
-tls13_HandleEndOfEarlyData(sslSocket *ss, PRUint8 *b, PRUint32 length)
+tls13_HandleEndOfEarlyData(sslSocket *ss, const PRUint8 *b, PRUint32 length)
{
SECStatus rv;
@@ -5791,6 +6000,18 @@ tls13_HandleEndOfEarlyData(sslSocket *ss, PRUint8 *b, PRUint32 length)
return SECSuccess;
}
+static SECStatus
+tls13_MaybeHandleSuppressedEndOfEarlyData(sslSocket *ss)
+{
+ PORT_Assert(ss->sec.isServer);
+ if (!ss->opt.suppressEndOfEarlyData ||
+ ss->ssl3.hs.zeroRttState != ssl_0rtt_accepted) {
+ return SECSuccess;
+ }
+
+ return tls13_HandleEndOfEarlyData(ss, NULL, 0);
+}
+
SECStatus
tls13_HandleEarlyApplicationData(sslSocket *ss, sslBuffer *origBuf)
{
diff --git a/libs/nss/src/lib/ssl/tls13con.h b/libs/nss/src/lib/ssl/tls13con.h
index dd693b377..9a3cd14c1 100644
--- a/libs/nss/src/lib/ssl/tls13con.h
+++ b/libs/nss/src/lib/ssl/tls13con.h
@@ -51,13 +51,15 @@ SSLHashType tls13_GetHashForCipherSuite(ssl3CipherSuite suite);
unsigned int tls13_GetHashSize(const sslSocket *ss);
unsigned int tls13_GetHashSizeForHash(SSLHashType hash);
SECStatus tls13_ComputeHash(sslSocket *ss, SSL3Hashes *hashes,
- const PRUint8 *buf, unsigned int len);
+ const PRUint8 *buf, unsigned int len,
+ SSLHashType hash);
SECStatus tls13_ComputeHandshakeHashes(sslSocket *ss,
SSL3Hashes *hashes);
SECStatus tls13_DeriveSecretNullHash(sslSocket *ss, PK11SymKey *key,
const char *label,
unsigned int labelLen,
- PK11SymKey **dest);
+ PK11SymKey **dest,
+ SSLHashType hash);
void tls13_FatalError(sslSocket *ss, PRErrorCode prError,
SSL3AlertDescription desc);
SECStatus tls13_SetupClientHello(sslSocket *ss, sslClientHelloType chType);
diff --git a/libs/nss/src/lib/ssl/tls13exthandle.c b/libs/nss/src/lib/ssl/tls13exthandle.c
index 5768fbce5..5c3930ac2 100644
--- a/libs/nss/src/lib/ssl/tls13exthandle.c
+++ b/libs/nss/src/lib/ssl/tls13exthandle.c
@@ -14,6 +14,7 @@
#include "ssl3exthandle.h"
#include "tls13esni.h"
#include "tls13exthandle.h"
+#include "tls13psk.h"
#include "tls13subcerts.h"
SECStatus
@@ -408,69 +409,92 @@ tls13_ServerSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
* };
*
* } PreSharedKeyExtension;
-
- * Presently the only way to get a PSK is by resumption, so this is
- * really a ticket label and there will be at most one.
*/
SECStatus
tls13_ClientSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added)
{
- NewSessionTicket *session_ticket;
- PRTime age;
const static PRUint8 binder[TLS13_MAX_FINISHED_SIZE] = { 0 };
unsigned int binderLen;
+ unsigned int identityLen = 0;
+ const PRUint8 *identity = NULL;
+ PRTime age;
SECStatus rv;
- /* We only set statelessResume on the client in TLS 1.3 code. */
- if (!ss->statelessResume) {
+ /* Exit early if no PSKs or max version < 1.3. */
+ if (PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks) ||
+ ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) {
+ return SECSuccess;
+ }
+
+ /* ...or if PSK type is resumption, but we're not resuming. */
+ sslPsk *psk = (sslPsk *)PR_LIST_HEAD(&ss->ssl3.hs.psks);
+ if (psk->type == ssl_psk_resume && !ss->statelessResume) {
return SECSuccess;
}
/* Save where this extension starts so that if we have to add padding, it
- * can be inserted before this extension. */
+ * can be inserted before this extension. */
PORT_Assert(buf->len >= 4);
xtnData->lastXtnOffset = buf->len - 4;
+ PORT_Assert(psk->type == ssl_psk_resume || psk->type == ssl_psk_external);
+ binderLen = tls13_GetHashSizeForHash(psk->hash);
+ if (psk->type == ssl_psk_resume) {
+ /* Send a single ticket identity. */
+ NewSessionTicket *session_ticket = &ss->sec.ci.sid->u.ssl3.locked.sessionTicket;
+ identityLen = session_ticket->ticket.len;
+ identity = session_ticket->ticket.data;
+
+ /* Obfuscated age. */
+ age = ssl_Time(ss) - session_ticket->received_timestamp;
+ age /= PR_USEC_PER_MSEC;
+ age += session_ticket->ticket_age_add;
+ PRINT_BUF(50, (ss, "Sending Resumption PSK with identity", identity, identityLen));
+ } else if (psk->type == ssl_psk_external) {
+ identityLen = psk->label.len;
+ identity = psk->label.data;
+ age = 0;
+ PRINT_BUF(50, (ss, "Sending External PSK with label", identity, identityLen));
+ } else {
+ PORT_Assert(0);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
- 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;
- rv = sslBuffer_AppendNumber(buf, 2 + /* identity length */
- session_ticket->ticket.len + /* ticket */
- 4 /* obfuscated_ticket_age */,
- 2);
- if (rv != SECSuccess)
+ /* Length is len(identityLen) + identityLen + len(age) */
+ rv = sslBuffer_AppendNumber(buf, 2 + identityLen + 4, 2);
+ if (rv != SECSuccess) {
goto loser;
- rv = sslBuffer_AppendVariable(buf, session_ticket->ticket.data,
- session_ticket->ticket.len, 2);
- if (rv != SECSuccess)
+ }
+
+ rv = sslBuffer_AppendVariable(buf, identity,
+ identityLen, 2);
+ if (rv != SECSuccess) {
goto loser;
+ }
- /* Obfuscated age. */
- age = ssl_Time(ss) - session_ticket->received_timestamp;
- age /= PR_USEC_PER_MSEC;
- age += session_ticket->ticket_age_add;
rv = sslBuffer_AppendNumber(buf, age, 4);
- if (rv != SECSuccess)
+ if (rv != SECSuccess) {
goto loser;
+ }
/* Write out the binder list length. */
- binderLen = tls13_GetHashSize(ss);
rv = sslBuffer_AppendNumber(buf, binderLen + 1, 2);
- if (rv != SECSuccess)
+ if (rv != SECSuccess) {
goto loser;
- /* Write zeroes for the binder for the moment. */
+ }
+
+ /* Write zeroes for the binder for the moment. These
+ * are overwritten in tls13_WriteExtensionsWithBinder. */
rv = sslBuffer_AppendVariable(buf, binder, binderLen, 1);
- if (rv != SECSuccess)
+ if (rv != SECSuccess) {
goto loser;
+ }
- PRINT_BUF(50, (ss, "Sending PreSharedKey value",
- session_ticket->ticket.data,
- session_ticket->ticket.len));
+ if (psk->type == ssl_psk_resume) {
+ xtnData->sentSessionTicketInClientHello = PR_TRUE;
+ }
- xtnData->sentSessionTicketInClientHello = PR_TRUE;
*added = PR_TRUE;
return SECSuccess;
@@ -479,8 +503,7 @@ loser:
return SECFailure;
}
-/* Handle a TLS 1.3 PreSharedKey Extension. We only accept PSKs
- * that contain session tickets. */
+/* Handle a TLS 1.3 PreSharedKey Extension. */
SECStatus
tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
SECItem *data)
@@ -534,28 +557,52 @@ tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData
return rv;
if (!numIdentities) {
- PRINT_BUF(50, (ss, "Handling PreSharedKey value",
- label.data, label.len));
- rv = ssl3_ProcessSessionTicketCommon(
- CONST_CAST(sslSocket, ss), &label, appToken);
- /* This only happens if we have an internal error, not
- * a malformed ticket. Bogus tickets just don't resume
- * and return SECSuccess. */
- if (rv != SECSuccess)
- return SECFailure;
+ /* Check any configured external PSK for a matching label.
+ * If none exists, try to parse it as a ticket. */
+ PORT_Assert(!xtnData->selectedPsk);
+ for (PRCList *cur_p = PR_LIST_HEAD(&ss->ssl3.hs.psks);
+ cur_p != &ss->ssl3.hs.psks;
+ cur_p = PR_NEXT_LINK(cur_p)) {
+ sslPsk *psk = (sslPsk *)cur_p;
+ if (psk->type != ssl_psk_external ||
+ SECITEM_CompareItem(&psk->label, &label) != SECEqual) {
+ continue;
+ }
+ PRINT_BUF(50, (ss, "Using External PSK with label",
+ psk->label.data, psk->label.len));
+ xtnData->selectedPsk = psk;
+ }
- if (ss->sec.ci.sid) {
- /* xtnData->ticketAge contains the baseline we use for
- * calculating the ticket age (i.e., our RTT estimate less the
- * value of ticket_age_add).
- *
- * Add that to the obfuscated ticket age to recover the client's
- * view of the ticket age plus the estimated RTT.
- *
- * See ssl3_EncodeSessionTicket() for details. */
- xtnData->ticketAge += obfuscatedAge;
+ if (!xtnData->selectedPsk) {
+ PRINT_BUF(50, (ss, "Handling PreSharedKey value",
+ label.data, label.len));
+ rv = ssl3_ProcessSessionTicketCommon(
+ CONST_CAST(sslSocket, ss), &label, appToken);
+ /* This only happens if we have an internal error, not
+ * a malformed ticket. Bogus tickets just don't resume
+ * and return SECSuccess. */
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ if (ss->sec.ci.sid) {
+ /* xtnData->ticketAge contains the baseline we use for
+ * calculating the ticket age (i.e., our RTT estimate less the
+ * value of ticket_age_add).
+ *
+ * Add that to the obfuscated ticket age to recover the client's
+ * view of the ticket age plus the estimated RTT.
+ *
+ * See ssl3_EncodeSessionTicket() for details. */
+ xtnData->ticketAge += obfuscatedAge;
+
+ /* We are not committed to resumption until after unwrapping the
+ * RMS in tls13_HandleClientHelloPart2. The RPSK will be stored
+ * in ss->xtnData.selectedPsk at that point, so continue. */
+ }
}
}
+
++numIdentities;
}
@@ -589,10 +636,14 @@ tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData
if (numBinders != numIdentities)
goto alert_loser;
- /* Keep track of negotiated extensions. Note that this does not
- * mean we are resuming. */
- xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_pre_shared_key_xtn;
+ if (ss->statelessResume) {
+ PORT_Assert(!ss->xtnData.selectedPsk);
+ } else if (!xtnData->selectedPsk) {
+ /* No matching EPSK. */
+ return SECSuccess;
+ }
+ xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_pre_shared_key_xtn;
return SECSuccess;
alert_loser:
@@ -618,8 +669,7 @@ tls13_ServerSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
return SECSuccess;
}
-/* Handle a TLS 1.3 PreSharedKey Extension. We only accept PSKs
- * that contain session tickets. */
+/* Handle a TLS 1.3 PreSharedKey Extension. */
SECStatus
tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
SECItem *data)
@@ -648,12 +698,23 @@ tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData
/* We only sent one PSK label so index must be equal to 0 */
if (index) {
+ ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
PORT_SetError(SSL_ERROR_MALFORMED_PRE_SHARED_KEY);
return SECFailure;
}
+ PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks));
+ sslPsk *candidate = (sslPsk *)PR_LIST_HEAD(&ss->ssl3.hs.psks);
+
+ /* Check that the server-selected ciphersuite hash and PSK hash match. */
+ if (candidate->hash != tls13_GetHashForCipherSuite(ss->ssl3.hs.cipher_suite)) {
+ ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
+ return SECFailure;
+ }
+
/* Keep track of negotiated extensions. */
xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_pre_shared_key_xtn;
+ xtnData->selectedPsk = candidate;
return SECSuccess;
}
@@ -936,10 +997,13 @@ tls13_ClientSendPostHandshakeAuthXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added)
{
- SSL_TRC(3, ("%d: TLS13[%d]: send post_handshake_auth extension",
- SSL_GETPID(), ss->fd));
-
- *added = ss->opt.enablePostHandshakeAuth;
+ /* Only one post-handshake message is supported: a single
+ * NST immediately following the client Finished. */
+ if (!IS_DTLS(ss)) {
+ SSL_TRC(3, ("%d: TLS13[%d]: send post_handshake_auth extension",
+ SSL_GETPID(), ss->fd));
+ *added = ss->opt.enablePostHandshakeAuth;
+ }
return SECSuccess;
}
@@ -956,8 +1020,12 @@ tls13_ServerHandlePostHandshakeAuthXtn(const sslSocket *ss,
return SECFailure;
}
- /* Keep track of negotiated extensions. */
- xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_post_handshake_auth_xtn;
+ /* Only one post-handshake message is supported: a single
+ * NST immediately following the client Finished. */
+ if (!IS_DTLS(ss)) {
+ /* Keep track of negotiated extensions. */
+ xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_post_handshake_auth_xtn;
+ }
return SECSuccess;
}
@@ -1451,7 +1519,8 @@ tls13_ClientSendDelegatedCredentialsXtn(const sslSocket *ss,
SSLSignatureScheme filtered[MAX_SIGNATURE_SCHEMES] = { 0 };
unsigned int filteredCount = 0;
SECStatus rv = ssl3_FilterSigAlgs(ss, ss->vrange.max,
- PR_TRUE,
+ PR_TRUE /* disableRsae */,
+ PR_FALSE /* forCert */,
MAX_SIGNATURE_SCHEMES,
filtered,
&filteredCount);
diff --git a/libs/nss/src/lib/ssl/tls13hkdf.c b/libs/nss/src/lib/ssl/tls13hkdf.c
index 9cf4d0fc0..ed6cdd559 100644
--- a/libs/nss/src/lib/ssl/tls13hkdf.c
+++ b/libs/nss/src/lib/ssl/tls13hkdf.c
@@ -38,6 +38,7 @@ tls13_HkdfExtract(PK11SymKey *ikm1, PK11SymKey *ikm2, SSLHashType baseHash,
SECItem paramsi;
PK11SymKey *prk;
static const PRUint8 zeroKeyBuf[HASH_LENGTH_MAX];
+ SECItem zeroKeyItem = { siBuffer, CONST_CAST(PRUint8, zeroKeyBuf), kTlsHkdfInfo[baseHash].hashSize };
PK11SlotInfo *slot = NULL;
PK11SymKey *newIkm2 = NULL;
PK11SymKey *newIkm1 = NULL;
@@ -102,44 +103,14 @@ tls13_HkdfExtract(PK11SymKey *ikm1, PK11SymKey *ikm2, SSLHashType baseHash,
/* A zero ikm2 is a key of hash-length 0s. */
if (!ikm2) {
- CK_OBJECT_CLASS ckoData = CKO_DATA;
- CK_ATTRIBUTE template[2] = {
- { CKA_CLASS, (CK_BYTE_PTR)&ckoData, sizeof(ckoData) },
- { CKA_VALUE, (CK_BYTE_PTR)zeroKeyBuf, kTlsHkdfInfo[baseHash].hashSize }
- };
- CK_OBJECT_HANDLE handle;
- PK11GenericObject *genObject;
-
/* if we have ikm1, put the zero key in the same slot */
slot = ikm1 ? PK11_GetSlotFromKey(ikm1) : PK11_GetBestSlot(CKM_HKDF_DERIVE, NULL);
if (!slot) {
return SECFailure;
}
- genObject = PK11_CreateGenericObject(slot, template,
- PR_ARRAY_SIZE(template), PR_FALSE);
- if (genObject == NULL) {
- return SECFailure;
- }
- handle = PK11_GetObjectHandle(PK11_TypeGeneric, genObject, NULL);
- if (handle == CK_INVALID_HANDLE) {
- return SECFailure;
- }
- /* A note about ownership of the PKCS #11 handle.
- * PK11_CreateGenericObject() will not destroy the object it creates
- * on Free, For that you want PK11_CreateManagedGenericObject().
- * Below we import the handle into the symKey structure. We pass
- * PR_TRUE as the owner so that the symKey will destroy the object
- * once it's freed. This is way it's safe to free now */
- PK11_DestroyGenericObject(genObject);
- /* NOTE: we can't both be in this block, and the block above where
- * we moved the keys (because this block requires ikm2 to be NULL and
- * the other requires ikm2 to be non-NULL. It's therefore safe to
- * use newIkm2 in both cases and have a single free at the end for
- * both */
- PORT_Assert(newIkm2 == NULL); /* verify logic of the above statement */
- newIkm2 = PK11_SymKeyFromHandle(slot, NULL, PK11_OriginUnwrap,
- CKM_HKDF_DERIVE, handle, PR_TRUE, NULL);
+ newIkm2 = PK11_ImportDataKey(slot, CKM_HKDF_DERIVE, PK11_OriginUnwrap,
+ CKA_DERIVE, &zeroKeyItem, NULL);
if (!newIkm2) {
return SECFailure;
}
diff --git a/libs/nss/src/lib/ssl/tls13psk.c b/libs/nss/src/lib/ssl/tls13psk.c
new file mode 100644
index 000000000..7343c5a6f
--- /dev/null
+++ b/libs/nss/src/lib/ssl/tls13psk.c
@@ -0,0 +1,219 @@
+/* -*- 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/. */
+
+#include "nss.h"
+#include "pk11func.h"
+#include "ssl.h"
+#include "sslproto.h"
+#include "sslimpl.h"
+#include "ssl3exthandle.h"
+#include "tls13exthandle.h"
+#include "tls13hkdf.h"
+#include "tls13psk.h"
+
+SECStatus
+SSLExp_AddExternalPsk0Rtt(PRFileDesc *fd, PK11SymKey *key, const PRUint8 *identity,
+ unsigned int identityLen, SSLHashType hash,
+ PRUint16 zeroRttSuite, PRUint32 maxEarlyData)
+{
+
+ sslSocket *ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSLExp_SetExternalPsk",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ if (!key || !identity || !identityLen || identityLen > 0xFFFF ||
+ (hash != ssl_hash_sha256 && hash != ssl_hash_sha384)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ SECItem label = { siBuffer, CONST_CAST(unsigned char, identity), identityLen };
+ sslPsk *psk = tls13_MakePsk(PK11_ReferenceSymKey(key), ssl_psk_external,
+ hash, &label);
+ if (!psk) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return SECFailure;
+ }
+ psk->zeroRttSuite = zeroRttSuite;
+ psk->maxEarlyData = maxEarlyData;
+ SECStatus rv = SECFailure;
+
+ ssl_Get1stHandshakeLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+
+ if (ss->psk) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ tls13_DestroyPsk(psk);
+ } else {
+ ss->psk = psk;
+ rv = SECSuccess;
+ tls13_ResetHandshakePsks(ss, &ss->ssl3.hs.psks);
+ }
+
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+
+ return rv;
+}
+
+SECStatus
+SSLExp_AddExternalPsk(PRFileDesc *fd, PK11SymKey *key, const PRUint8 *identity,
+ unsigned int identityLen, SSLHashType hash)
+{
+ return SSLExp_AddExternalPsk0Rtt(fd, key, identity, identityLen,
+ hash, TLS_NULL_WITH_NULL_NULL, 0);
+}
+
+SECStatus
+SSLExp_RemoveExternalPsk(PRFileDesc *fd, const PRUint8 *identity, unsigned int identityLen)
+{
+ if (!identity || !identityLen) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ sslSocket *ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetPSK",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ SECItem removeIdentity = { siBuffer,
+ (unsigned char *)identity,
+ identityLen };
+
+ SECStatus rv;
+ ssl_Get1stHandshakeLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+
+ if (!ss->psk || SECITEM_CompareItem(&ss->psk->label, &removeIdentity) != SECEqual) {
+ PORT_SetError(SEC_ERROR_NO_KEY);
+ rv = SECFailure;
+ } else {
+ tls13_DestroyPsk(ss->psk);
+ ss->psk = NULL;
+ tls13_ResetHandshakePsks(ss, &ss->ssl3.hs.psks);
+ rv = SECSuccess;
+ }
+
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+
+ return rv;
+}
+
+sslPsk *
+tls13_CopyPsk(sslPsk *opsk)
+{
+ if (!opsk || !opsk->key) {
+ return NULL;
+ }
+
+ sslPsk *psk = PORT_ZNew(sslPsk);
+ if (!psk) {
+ return NULL;
+ }
+
+ SECStatus rv = SECITEM_CopyItem(NULL, &psk->label, &opsk->label);
+ if (rv != SECSuccess) {
+ PORT_Free(psk);
+ return NULL;
+ }
+ /* We should only have the initial key. Binder keys
+ * are derived during the handshake. */
+ PORT_Assert(opsk->type == ssl_psk_external);
+ PORT_Assert(opsk->key);
+ PORT_Assert(!opsk->binderKey);
+ psk->hash = opsk->hash;
+ psk->type = opsk->type;
+ psk->key = opsk->key ? PK11_ReferenceSymKey(opsk->key) : NULL;
+ psk->binderKey = opsk->binderKey ? PK11_ReferenceSymKey(opsk->binderKey) : NULL;
+ return psk;
+}
+
+void
+tls13_DestroyPsk(sslPsk *psk)
+{
+ if (!psk) {
+ return;
+ }
+ if (psk->key) {
+ PK11_FreeSymKey(psk->key);
+ psk->key = NULL;
+ }
+ if (psk->binderKey) {
+ PK11_FreeSymKey(psk->binderKey);
+ psk->binderKey = NULL;
+ }
+ SECITEM_ZfreeItem(&psk->label, PR_FALSE);
+ PORT_ZFree(psk, sizeof(*psk));
+}
+
+void
+tls13_DestroyPskList(PRCList *list)
+{
+ PRCList *cur_p;
+ while (!PR_CLIST_IS_EMPTY(list)) {
+ cur_p = PR_LIST_TAIL(list);
+ PR_REMOVE_LINK(cur_p);
+ tls13_DestroyPsk((sslPsk *)cur_p);
+ }
+}
+
+sslPsk *
+tls13_MakePsk(PK11SymKey *key, SSLPskType pskType, SSLHashType hashType, const SECItem *label)
+{
+ sslPsk *psk = PORT_ZNew(sslPsk);
+ if (!psk) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return NULL;
+ }
+ psk->type = pskType;
+ psk->hash = hashType;
+ psk->key = key;
+
+ /* Label is NULL in the resumption case. */
+ if (label) {
+ PORT_Assert(psk->type != ssl_psk_resume);
+ SECStatus rv = SECITEM_CopyItem(NULL, &psk->label, label);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ tls13_DestroyPsk(psk);
+ return NULL;
+ }
+ }
+
+ return psk;
+}
+
+/* Destroy any existing PSKs in |list| then copy
+ * in the configured |ss->psk|, if any.*/
+SECStatus
+tls13_ResetHandshakePsks(sslSocket *ss, PRCList *list)
+{
+ tls13_DestroyPskList(list);
+ PORT_Assert(!ss->xtnData.selectedPsk);
+ ss->xtnData.selectedPsk = NULL;
+ if (ss->psk) {
+ PORT_Assert(ss->psk->type == ssl_psk_external);
+ PORT_Assert(ss->psk->key);
+ PORT_Assert(!ss->psk->binderKey);
+
+ sslPsk *epsk = tls13_MakePsk(PK11_ReferenceSymKey(ss->psk->key),
+ ss->psk->type, ss->psk->hash, &ss->psk->label);
+ if (!epsk) {
+ return SECFailure;
+ }
+ epsk->zeroRttSuite = ss->psk->zeroRttSuite;
+ epsk->maxEarlyData = ss->psk->maxEarlyData;
+ PR_APPEND_LINK(&epsk->link, list);
+ }
+ return SECSuccess;
+}
diff --git a/libs/nss/src/lib/ssl/tls13psk.h b/libs/nss/src/lib/ssl/tls13psk.h
new file mode 100644
index 000000000..73013fb9b
--- /dev/null
+++ b/libs/nss/src/lib/ssl/tls13psk.h
@@ -0,0 +1,58 @@
+/* -*- 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 __tls13psk_h_
+#define __tls13psk_h_
+
+/*
+ * Internally, we have track sslPsk pointers in three locations:
+ * 1) An external PSK can be configured to the socket, in which case ss->psk will hold an owned reference.
+ * For now, this only holds one external PSK. The value will persist across handshake restarts.
+ * 2) When a handshake begins, the ss->psk value is deep-copied into ss->ssl3.hs.psks, which may also hold
+ * a resumption PSK. This is essentially a priority-sorted list (where a resumption PSK has higher
+ * priority than external), and we currently only send one PskIdentity and binder.
+ * 3) During negotiation, ss->xtnData.selectedPsk will either be NULL or it will hold a non-owning refernce
+ * to the PSK that has been (or is being) negotiated.
+ */
+
+/* Note: When holding a resumption PSK:
+ * 1. |hash| comes from the original connection.
+ * 2. |label| is ignored: The identity sent in the pre_shared_key_xtn
+ * comes from ss->sec.ci.sid->u.ssl3.locked.sessionTicket.
+ */
+struct sslPskStr {
+ PRCList link;
+ PK11SymKey *key; /* A raw PSK. */
+ PK11SymKey *binderKey; /* The binder key derived from |key|. |key| is NULL after derivation. */
+ SSLPskType type; /* none, resumption, or external. */
+ SECItem label; /* Label (identity) for an external PSK. */
+ SSLHashType hash; /* A hash algorithm associated with a PSK. */
+ ssl3CipherSuite zeroRttSuite; /* For EPSKs, an explicitly-configured ciphersuite for 0-Rtt. */
+ PRUint32 maxEarlyData; /* For EPSKs, a limit on early data. Must be > 0 for 0-Rtt. */
+};
+
+SECStatus SSLExp_AddExternalPsk(PRFileDesc *fd, PK11SymKey *psk, const PRUint8 *identity,
+ unsigned int identitylen, SSLHashType hash);
+
+SECStatus SSLExp_AddExternalPsk0Rtt(PRFileDesc *fd, PK11SymKey *psk, const PRUint8 *identity,
+ unsigned int identitylen, SSLHashType hash,
+ PRUint16 zeroRttSuite, PRUint32 maxEarlyData);
+
+SECStatus SSLExp_RemoveExternalPsk(PRFileDesc *fd, const PRUint8 *identity, unsigned int identitylen);
+
+sslPsk *tls13_CopyPsk(sslPsk *opsk);
+
+void tls13_DestroyPsk(sslPsk *psk);
+
+void tls13_DestroyPskList(PRCList *list);
+
+sslPsk *tls13_MakePsk(PK11SymKey *key, SSLPskType pskType, SSLHashType hashType, const SECItem *label);
+
+SECStatus tls13_ResetHandshakePsks(sslSocket *ss, PRCList *list);
+
+#endif
diff --git a/libs/nss/src/lib/ssl/tls13replay.c b/libs/nss/src/lib/ssl/tls13replay.c
index b6d1416f3..7e00785e0 100644
--- a/libs/nss/src/lib/ssl/tls13replay.c
+++ b/libs/nss/src/lib/ssl/tls13replay.c
@@ -16,6 +16,7 @@
#include "sslbloom.h"
#include "sslimpl.h"
#include "tls13hkdf.h"
+#include "tls13psk.h"
struct SSLAntiReplayContextStr {
/* The number of outstanding references to this context. */
@@ -55,8 +56,7 @@ tls13_ReleaseAntiReplayContext(SSLAntiReplayContext *ctx)
PORT_Free(ctx);
}
-/* Clear the current state and free any resources we allocated. The signature
- * here is odd to allow this to be called during shutdown. */
+/* Clear the current state and free any resources we allocated. */
SECStatus
SSLExp_ReleaseAntiReplayContext(SSLAntiReplayContext *ctx)
{
@@ -250,7 +250,9 @@ tls13_IsReplay(const sslSocket *ss, const sslSessionID *sid)
return PR_TRUE;
}
- if (!tls13_InWindow(ss, sid)) {
+ if (!sid) {
+ PORT_Assert(ss->xtnData.selectedPsk->type == ssl_psk_external);
+ } else if (!tls13_InWindow(ss, sid)) {
return PR_TRUE;
}