diff options
Diffstat (limited to 'libs/nss/src/lib/ssl')
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, ¶m); 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; } |