diff options
author | Moonchild <moonchild@palemoon.org> | 2020-12-23 19:02:52 +0000 |
---|---|---|
committer | Moonchild <moonchild@palemoon.org> | 2020-12-23 19:02:52 +0000 |
commit | 029bcfe189eae5eebbaf58ccff4e1200dd78b228 (patch) | |
tree | 1c226a334ea1a88e2d1c6f949c9320eb0c3bff59 /security/nss/lib/ssl | |
parent | 149d2ffa779826cb48a381099858e76e4624d471 (diff) | |
download | UXP-029bcfe189eae5eebbaf58ccff4e1200dd78b228.tar UXP-029bcfe189eae5eebbaf58ccff4e1200dd78b228.tar.gz UXP-029bcfe189eae5eebbaf58ccff4e1200dd78b228.tar.lz UXP-029bcfe189eae5eebbaf58ccff4e1200dd78b228.tar.xz UXP-029bcfe189eae5eebbaf58ccff4e1200dd78b228.zip |
Issue #1693 - Update NSS to 3.59.1.1
This updates to MoonchildProductions/NSS@bd49b2b88 in the repo created for our
consumption of the library.
Diffstat (limited to 'security/nss/lib/ssl')
37 files changed, 2932 insertions, 1155 deletions
diff --git a/security/nss/lib/ssl/SSLerrs.h b/security/nss/lib/ssl/SSLerrs.h index 87b59b1e8..f9c36b7c1 100644 --- a/security/nss/lib/ssl/SSLerrs.h +++ b/security/nss/lib/ssl/SSLerrs.h @@ -582,3 +582,6 @@ ER3(SSL_ERROR_DC_INVALID_KEY_USAGE, (SSL_ERROR_BASE + 184), ER3(SSL_ERROR_DC_EXPIRED, (SSL_ERROR_BASE + 185), "SSL received a delegated credential that expired.") + +ER3(SSL_ERROR_DC_INAPPROPRIATE_VALIDITY_PERIOD, (SSL_ERROR_BASE + 186), + "SSL received a delegated credential with excessive TTL.") diff --git a/security/nss/lib/ssl/dtls13con.c b/security/nss/lib/ssl/dtls13con.c index 0c4fc7fcd..5307419b6 100644 --- a/security/nss/lib/ssl/dtls13con.c +++ b/security/nss/lib/ssl/dtls13con.c @@ -10,38 +10,52 @@ #include "ssl.h" #include "sslimpl.h" #include "sslproto.h" +#include "keyhi.h" +#include "pk11func.h" +/* + * 0 1 2 3 4 5 6 7 + * +-+-+-+-+-+-+-+-+ + * |0|0|1|C|S|L|E E| + * +-+-+-+-+-+-+-+-+ + * | Connection ID | Legend: + * | (if any, | + * / length as / C - CID present + * | negotiated) | S - Sequence number length + * +-+-+-+-+-+-+-+-+ L - Length present + * | 8 or 16 bit | E - Epoch + * |Sequence Number| + * +-+-+-+-+-+-+-+-+ + * | 16 bit Length | + * | (if present) | + * +-+-+-+-+-+-+-+-+ + */ SECStatus -dtls13_InsertCipherTextHeader(const sslSocket *ss, ssl3CipherSpec *cwSpec, +dtls13_InsertCipherTextHeader(const sslSocket *ss, const ssl3CipherSpec *cwSpec, sslBuffer *wrBuf, PRBool *needsLength) { - PRUint32 seq; - SECStatus rv; - /* Avoid using short records for the handshake. We pack multiple records * into the one datagram for the handshake. */ if (ss->opt.enableDtlsShortHeader && - cwSpec->epoch != TrafficKeyHandshake) { + cwSpec->epoch > TrafficKeyHandshake) { *needsLength = PR_FALSE; /* The short header is comprised of two octets in the form - * 0b001essssssssssss where 'e' is the low bit of the epoch and 's' is - * the low 12 bits of the sequence number. */ - seq = 0x2000 | - (((uint64_t)cwSpec->epoch & 1) << 12) | - (cwSpec->nextSeqNum & 0xfff); - return sslBuffer_AppendNumber(wrBuf, seq, 2); + * 0b001000eessssssss where 'e' is the low two bits of the + * epoch and 's' is the low 8 bits of the sequence number. */ + PRUint8 ct = 0x20 | ((uint64_t)cwSpec->epoch & 0x3); + if (sslBuffer_AppendNumber(wrBuf, ct, 1) != SECSuccess) { + return SECFailure; + } + PRUint8 seq = cwSpec->nextSeqNum & 0xff; + return sslBuffer_AppendNumber(wrBuf, seq, 1); } - rv = sslBuffer_AppendNumber(wrBuf, ssl_ct_application_data, 1); - if (rv != SECSuccess) { + PRUint8 ct = 0x2c | ((PRUint8)cwSpec->epoch & 0x3); + if (sslBuffer_AppendNumber(wrBuf, ct, 1) != SECSuccess) { return SECFailure; } - - /* The epoch and sequence number are encoded on 4 octets, with the epoch - * consuming the first two bits. */ - seq = (((uint64_t)cwSpec->epoch & 3) << 30) | (cwSpec->nextSeqNum & 0x3fffffff); - rv = sslBuffer_AppendNumber(wrBuf, seq, 4); - if (rv != SECSuccess) { + if (sslBuffer_AppendNumber(wrBuf, + (cwSpec->nextSeqNum & 0xffff), 2) != SECSuccess) { return SECFailure; } *needsLength = PR_TRUE; @@ -171,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) @@ -378,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)) { @@ -512,3 +546,56 @@ dtls13_HolddownTimerCb(sslSocket *ss) ssl_CipherSpecReleaseByEpoch(ss, ssl_secret_read, TrafficKeyHandshake); ssl_ClearPRCList(&ss->ssl3.hs.dtlsRcvdHandshake, NULL); } + +SECStatus +dtls13_MaskSequenceNumber(sslSocket *ss, ssl3CipherSpec *spec, + PRUint8 *hdr, PRUint8 *cipherText, PRUint32 cipherTextLen) +{ + PORT_Assert(IS_DTLS(ss)); + if (spec->version < SSL_LIBRARY_VERSION_TLS_1_3) { + return SECSuccess; + } + + if (spec->maskContext) { +#ifdef UNSAFE_FUZZER_MODE + /* Use a null mask. */ + PRUint8 mask[2] = { 0 }; +#else + /* "This procedure requires the ciphertext length be at least 16 bytes. + * Receivers MUST reject shorter records as if they had failed + * deprotection, as described in Section 4.5.2." */ + if (cipherTextLen < 16) { + PORT_SetError(SSL_ERROR_BAD_MAC_READ); + return SECFailure; + } + + PRUint8 mask[2]; + SECStatus rv = ssl_CreateMaskInner(spec->maskContext, cipherText, cipherTextLen, mask, sizeof(mask)); + + if (rv != SECSuccess) { + PORT_SetError(SSL_ERROR_BAD_MAC_READ); + return SECFailure; + } +#endif + + hdr[1] ^= mask[0]; + if (hdr[0] & 0x08) { + hdr[2] ^= mask[1]; + } + } + return SECSuccess; +} + +CK_MECHANISM_TYPE +tls13_SequenceNumberEncryptionMechanism(SSLCipherAlgorithm bulkAlgorithm) +{ + switch (bulkAlgorithm) { + case ssl_calg_aes_gcm: + return CKM_AES_ECB; + case ssl_calg_chacha20: + return CKM_NSS_CHACHA20_CTR; + default: + PORT_Assert(PR_FALSE); + } + return CKM_INVALID_MECHANISM; +} diff --git a/security/nss/lib/ssl/dtls13con.h b/security/nss/lib/ssl/dtls13con.h index ce92a8a55..bfe8d4020 100644 --- a/security/nss/lib/ssl/dtls13con.h +++ b/security/nss/lib/ssl/dtls13con.h @@ -10,7 +10,7 @@ #define __dtls13con_h_ SECStatus dtls13_InsertCipherTextHeader(const sslSocket *ss, - ssl3CipherSpec *cwSpec, + const ssl3CipherSpec *cwSpec, sslBuffer *wrBuf, PRBool *needsLength); SECStatus dtls13_RememberFragment(sslSocket *ss, PRCList *list, @@ -29,5 +29,10 @@ SECStatus dtls13_SendAck(sslSocket *ss); void dtls13_SendAckCb(sslSocket *ss); 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); #endif diff --git a/security/nss/lib/ssl/dtlscon.c b/security/nss/lib/ssl/dtlscon.c index bbd2f6d79..10e550e0f 100644 --- a/security/nss/lib/ssl/dtlscon.c +++ b/security/nss/lib/ssl/dtlscon.c @@ -53,7 +53,7 @@ static const ssl3CipherSuite nonDTLSSuites[] = { * TLS DTLS * 1.1 (0302) 1.0 (feff) * 1.2 (0303) 1.2 (fefd) - * 1.3 (0304) 1.3 (fefc) + * 1.3 (0304) 1.3 (0304) */ SSL3ProtocolVersion dtls_TLSVersionToDTLSVersion(SSL3ProtocolVersion tlsv) @@ -68,7 +68,7 @@ dtls_TLSVersionToDTLSVersion(SSL3ProtocolVersion tlsv) return SSL_LIBRARY_VERSION_DTLS_1_3_WIRE; } - /* Anything other than TLS 1.1 or 1.2 is an error, so return + /* Anything else is an error, so return * the invalid version 0xffff. */ return 0xffff; } @@ -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 @@ -343,6 +338,7 @@ dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum, SSL_TRC(5, ("%d: DTLS[%d]: Received apparent 2nd ClientHello", SSL_GETPID(), ss->fd)); ss->ssl3.hs.recvMessageSeq = 1; + ss->ssl3.hs.helloRetry = PR_TRUE; } /* There are three ways we could not be ready for this packet. @@ -484,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; } @@ -504,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; } @@ -1334,6 +1327,14 @@ dtls_IsLongHeader(SSL3ProtocolVersion version, PRUint8 firstOctet) #endif } +PRBool +dtls_IsDtls13Ciphertext(SSL3ProtocolVersion version, PRUint8 firstOctet) +{ + // Allow no version in case we haven't negotiated one yet. + return (version == 0 || version >= SSL_LIBRARY_VERSION_TLS_1_3) && + (firstOctet & 0xe0) == 0x20; +} + DTLSEpoch dtls_ReadEpoch(const ssl3CipherSpec *crSpec, const PRUint8 *hdr) { @@ -1348,13 +1349,12 @@ dtls_ReadEpoch(const ssl3CipherSpec *crSpec, const PRUint8 *hdr) /* A lot of how we recover the epoch here will depend on how we plan to * manage KeyUpdate. In the case that we decide to install a new read spec * as a KeyUpdate is handled, crSpec will always be the highest epoch we can - * possibly receive. That makes this easier to manage. */ - if ((hdr[0] & 0xe0) == 0x20) { + * possibly receive. That makes this easier to manage. + */ + if (dtls_IsDtls13Ciphertext(crSpec->version, hdr[0])) { + /* TODO(ekr@rtfm.com: do something with the two-bit epoch. */ /* Use crSpec->epoch, or crSpec->epoch - 1 if the last bit differs. */ - if (((hdr[0] >> 4) & 1) == (crSpec->epoch & 1)) { - return crSpec->epoch; - } - return crSpec->epoch - 1; + return crSpec->epoch - ((hdr[0] ^ crSpec->epoch) & 0x3); } /* dtls_GatherData should ensure that this works. */ @@ -1397,20 +1397,15 @@ dtls_ReadSequenceNumber(const ssl3CipherSpec *spec, const PRUint8 *hdr) * sequence number is replaced. If that causes the value to exceed the * maximum, subtract an entire range. */ - if ((hdr[0] & 0xe0) == 0x20) { - /* A 12-bit sequence number. */ - cap = spec->nextSeqNum + (1ULL << 11); - partial = (((sslSequenceNumber)hdr[0] & 0xf) << 8) | - (sslSequenceNumber)hdr[1]; - mask = (1ULL << 12) - 1; + if (hdr[0] & 0x08) { + cap = spec->nextSeqNum + (1ULL << 15); + partial = (((sslSequenceNumber)hdr[1]) << 8) | + (sslSequenceNumber)hdr[2]; + mask = (1ULL << 16) - 1; } else { - /* A 30-bit sequence number. */ - cap = spec->nextSeqNum + (1ULL << 29); - partial = (((sslSequenceNumber)hdr[1] & 0x3f) << 24) | - ((sslSequenceNumber)hdr[2] << 16) | - ((sslSequenceNumber)hdr[3] << 8) | - (sslSequenceNumber)hdr[4]; - mask = (1ULL << 30) - 1; + cap = spec->nextSeqNum + (1ULL << 7); + partial = (sslSequenceNumber)hdr[1]; + mask = (1ULL << 8) - 1; } seqNum = (cap & ~mask) | partial; /* The second check prevents the value from underflowing if we get a large diff --git a/security/nss/lib/ssl/dtlscon.h b/security/nss/lib/ssl/dtlscon.h index 4ede3c2ca..9d10aa248 100644 --- a/security/nss/lib/ssl/dtlscon.h +++ b/security/nss/lib/ssl/dtlscon.h @@ -47,4 +47,5 @@ extern PRBool dtls_IsRelevant(sslSocket *ss, const ssl3CipherSpec *spec, sslSequenceNumber *seqNum); void dtls_ReceivedFirstMessageInFlight(sslSocket *ss); PRBool dtls_IsLongHeader(SSL3ProtocolVersion version, PRUint8 firstOctet); +PRBool dtls_IsDtls13Ciphertext(SSL3ProtocolVersion version, PRUint8 firstOctet); #endif diff --git a/security/nss/lib/ssl/manifest.mn b/security/nss/lib/ssl/manifest.mn index 83df8c0b8..7e286f60c 100644 --- a/security/nss/lib/ssl/manifest.mn +++ b/security/nss/lib/ssl/manifest.mn @@ -5,6 +5,10 @@ CORE_DEPTH = ../.. # DEFINES = -DTRACE +ifdef ZLIB_INCLUDE_DIR +INCLUDES += -I$(ZLIB_INCLUDE_DIR) +endif + EXPORTS = \ ssl.h \ sslt.h \ @@ -52,6 +56,7 @@ CSRCS = \ tls13exthandle.c \ tls13hashstate.c \ tls13hkdf.c \ + tls13psk.c \ tls13replay.c \ sslcert.c \ sslgrp.c \ diff --git a/security/nss/lib/ssl/ssl.gyp b/security/nss/lib/ssl/ssl.gyp index 3e1b5531a..5c84a1f03 100644 --- a/security/nss/lib/ssl/ssl.gyp +++ b/security/nss/lib/ssl/ssl.gyp @@ -48,6 +48,7 @@ 'tls13exthandle.c', 'tls13hashstate.c', 'tls13hkdf.c', + 'tls13psk.c', 'tls13replay.c', 'tls13subcerts.c', ], diff --git a/security/nss/lib/ssl/ssl.h b/security/nss/lib/ssl/ssl.h index dc5a9d4cd..43a0f3228 100644 --- a/security/nss/lib/ssl/ssl.h +++ b/security/nss/lib/ssl/ssl.h @@ -312,7 +312,8 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd); /* Enables the delegated credentials extension (draft-ietf-tls-subcerts). When * enabled, a client that supports TLS 1.3 will indicate willingness to - * negotiate a delegated credential (DC). + * negotiate a delegated credential (DC). Note that client-delegated credentials + * are not currently supported. * * If support is indicated, the peer may use a DC to authenticate itself. The DC * is sent as an extension to the peer's end-entity certificate; the end-entity @@ -322,10 +323,29 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd); * mitigate the damage in case the secret key is compromised, the DC is only * valid for a short time (days, hours, or even minutes). * - * This library implements draft-03 of the protocol spec. + * This library implements draft-07 of the protocol spec. */ #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/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c index f3c723bbc..b652dcea3 100644 --- a/security/nss/lib/ssl/ssl3con.c +++ b/security/nss/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" @@ -65,6 +66,7 @@ static SECStatus ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags); static CK_MECHANISM_TYPE ssl3_GetHashMechanismByHashType(SSLHashType hashType); static CK_MECHANISM_TYPE ssl3_GetMgfMechanismByHashType(SSLHashType hash); PRBool ssl_IsRsaPssSignatureScheme(SSLSignatureScheme scheme); +PRBool ssl_IsRsaeSignatureScheme(SSLSignatureScheme scheme); PRBool ssl_IsRsaPkcs1SignatureScheme(SSLSignatureScheme scheme); PRBool ssl_IsDsaSignatureScheme(SSLSignatureScheme scheme); @@ -391,15 +393,15 @@ static const SSLCipher2Mech alg2Mech[] = { { ssl_calg_camellia, CKM_CAMELLIA_CBC }, { ssl_calg_seed, CKM_SEED_CBC }, { ssl_calg_aes_gcm, CKM_AES_GCM }, - { ssl_calg_chacha20, CKM_NSS_CHACHA20_POLY1305 }, + { ssl_calg_chacha20, CKM_CHACHA20_POLY1305 }, }; -const PRUint8 tls13_downgrade_random[] = { 0x44, 0x4F, 0x57, 0x4E, - 0x47, 0x52, 0x44, 0x01 }; const PRUint8 tls12_downgrade_random[] = { 0x44, 0x4F, 0x57, 0x4E, - 0x47, 0x52, 0x44, 0x00 }; -PR_STATIC_ASSERT(sizeof(tls13_downgrade_random) == - sizeof(tls13_downgrade_random)); + 0x47, 0x52, 0x44, 0x01 }; +const PRUint8 tls1_downgrade_random[] = { 0x44, 0x4F, 0x57, 0x4E, + 0x47, 0x52, 0x44, 0x00 }; +PR_STATIC_ASSERT(sizeof(tls12_downgrade_random) == + sizeof(tls1_downgrade_random)); /* The ECCWrappedKeyInfo structure defines how various pieces of * information are laid out within wrappedSymmetricWrappingkey @@ -517,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); @@ -782,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; } @@ -849,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; } } @@ -878,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; } } @@ -911,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. */ } @@ -1008,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); } @@ -1739,117 +1763,6 @@ ssl3_BuildRecordPseudoHeader(DTLSEpoch epoch, return SECSuccess; } -static SECStatus -ssl3_AESGCM(const ssl3KeyMaterial *keys, - PRBool doDecrypt, - unsigned char *out, - unsigned int *outlen, - unsigned int maxout, - const unsigned char *in, - unsigned int inlen, - const unsigned char *additionalData, - unsigned int additionalDataLen) -{ - SECItem param; - SECStatus rv = SECFailure; - unsigned char nonce[12]; - unsigned int uOutLen; - CK_GCM_PARAMS gcmParams; - - const int tagSize = 16; - const int explicitNonceLen = 8; - - /* See https://tools.ietf.org/html/rfc5288#section-3 for details of how the - * nonce is formed. */ - memcpy(nonce, keys->iv, 4); - if (doDecrypt) { - memcpy(nonce + 4, in, explicitNonceLen); - in += explicitNonceLen; - inlen -= explicitNonceLen; - *outlen = 0; - } else { - if (maxout < explicitNonceLen) { - PORT_SetError(SEC_ERROR_INPUT_LEN); - return SECFailure; - } - /* Use the 64-bit sequence number as the explicit nonce. */ - memcpy(nonce + 4, additionalData, explicitNonceLen); - memcpy(out, additionalData, explicitNonceLen); - out += explicitNonceLen; - maxout -= explicitNonceLen; - *outlen = explicitNonceLen; - } - - param.type = siBuffer; - param.data = (unsigned char *)&gcmParams; - param.len = sizeof(gcmParams); - gcmParams.pIv = nonce; - gcmParams.ulIvLen = sizeof(nonce); - gcmParams.pAAD = (unsigned char *)additionalData; /* const cast */ - gcmParams.ulAADLen = additionalDataLen; - gcmParams.ulTagBits = tagSize * 8; - - if (doDecrypt) { - rv = PK11_Decrypt(keys->key, CKM_AES_GCM, ¶m, out, &uOutLen, - maxout, in, inlen); - } else { - rv = PK11_Encrypt(keys->key, CKM_AES_GCM, ¶m, out, &uOutLen, - maxout, in, inlen); - } - *outlen += (int)uOutLen; - - return rv; -} - -static SECStatus -ssl3_ChaCha20Poly1305(const ssl3KeyMaterial *keys, PRBool doDecrypt, - unsigned char *out, unsigned int *outlen, unsigned int maxout, - const unsigned char *in, unsigned int inlen, - const unsigned char *additionalData, - unsigned int additionalDataLen) -{ - size_t i; - SECItem param; - SECStatus rv = SECFailure; - unsigned int uOutLen; - unsigned char nonce[12]; - CK_NSS_AEAD_PARAMS aeadParams; - - const int tagSize = 16; - - /* See - * https://tools.ietf.org/html/draft-ietf-tls-chacha20-poly1305-04#section-2 - * for details of how the nonce is formed. */ - PORT_Memcpy(nonce, keys->iv, 12); - - /* XOR the last 8 bytes of the IV with the sequence number. */ - PORT_Assert(additionalDataLen >= 8); - for (i = 0; i < 8; ++i) { - nonce[4 + i] ^= additionalData[i]; - } - - param.type = siBuffer; - param.len = sizeof(aeadParams); - param.data = (unsigned char *)&aeadParams; - memset(&aeadParams, 0, sizeof(aeadParams)); - aeadParams.pNonce = nonce; - aeadParams.ulNonceLen = sizeof(nonce); - aeadParams.pAAD = (unsigned char *)additionalData; - aeadParams.ulAADLen = additionalDataLen; - aeadParams.ulTagLen = tagSize; - - if (doDecrypt) { - rv = PK11_Decrypt(keys->key, CKM_NSS_CHACHA20_POLY1305, ¶m, - out, &uOutLen, maxout, in, inlen); - } else { - rv = PK11_Encrypt(keys->key, CKM_NSS_CHACHA20_POLY1305, ¶m, - out, &uOutLen, maxout, in, inlen); - } - *outlen = (int)uOutLen; - - return rv; -} - /* Initialize encryption and MAC contexts for pending spec. * Master Secret already is derived. * Caller holds Spec write lock. @@ -1867,40 +1780,26 @@ ssl3_InitPendingContexts(sslSocket *ss, ssl3CipherSpec *spec) PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); - macLength = spec->macDef->mac_size; calg = spec->cipherDef->calg; PORT_Assert(alg2Mech[calg].calg == calg); - if (spec->cipherDef->type == type_aead) { - spec->cipher = NULL; - spec->cipherContext = NULL; - switch (calg) { - case ssl_calg_aes_gcm: - spec->aead = ssl3_AESGCM; - break; - case ssl_calg_chacha20: - spec->aead = ssl3_ChaCha20Poly1305; - break; - default: - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - return SECSuccess; - } - - /* - ** Now setup the MAC contexts, - ** crypto contexts are setup below. - */ - macParam.data = (unsigned char *)&macLength; - macParam.len = sizeof(macLength); - macParam.type = siBuffer; + if (spec->cipherDef->type != type_aead) { + macLength = spec->macDef->mac_size; - spec->keyMaterial.macContext = PK11_CreateContextBySymKey( - spec->macDef->mmech, CKA_SIGN, spec->keyMaterial.macKey, &macParam); - if (!spec->keyMaterial.macContext) { - ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); - return SECFailure; + /* + ** Now setup the MAC contexts, + ** crypto contexts are setup below. + */ + macParam.data = (unsigned char *)&macLength; + macParam.len = sizeof(macLength); + macParam.type = siBuffer; + + spec->keyMaterial.macContext = PK11_CreateContextBySymKey( + spec->macDef->mmech, CKA_SIGN, spec->keyMaterial.macKey, &macParam); + if (!spec->keyMaterial.macContext) { + ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); + return SECFailure; + } } /* @@ -1911,15 +1810,21 @@ ssl3_InitPendingContexts(sslSocket *ss, ssl3CipherSpec *spec) return SECSuccess; } - spec->cipher = (SSLCipher)PK11_CipherOp; encMechanism = ssl3_Alg2Mech(calg); encMode = (spec->direction == ssl_secret_write) ? CKA_ENCRYPT : CKA_DECRYPT; + if (spec->cipherDef->type == type_aead) { + encMode |= CKA_NSS_MESSAGE; + iv.data = NULL; + iv.len = 0; + } else { + spec->cipher = (SSLCipher)PK11_CipherOp; + iv.data = spec->keyMaterial.iv; + iv.len = spec->cipherDef->iv_size; + } /* * build the context */ - iv.data = spec->keyMaterial.iv; - iv.len = spec->cipherDef->iv_size; spec->cipherContext = PK11_CreateContextBySymKey(encMechanism, encMode, spec->keyMaterial.key, &iv); @@ -2238,26 +2143,55 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec, isDTLS, contentLen, &pseudoHeader); PORT_Assert(rv == SECSuccess); if (cwSpec->cipherDef->type == type_aead) { - const int nonceLen = cwSpec->cipherDef->explicit_nonce_size; - const int tagLen = cwSpec->cipherDef->tag_size; + const unsigned int nonceLen = cwSpec->cipherDef->explicit_nonce_size; + const unsigned int tagLen = cwSpec->cipherDef->tag_size; + unsigned int ivOffset = 0; + CK_GENERATOR_FUNCTION gen; + /* ivOut includes the iv and the nonce and is the internal iv/nonce + * for the AEAD function. On Encrypt, this is an in/out parameter */ + unsigned char ivOut[MAX_IV_LENGTH]; + ivLen = cwSpec->cipherDef->iv_size; + + PORT_Assert((ivLen + nonceLen) <= MAX_IV_LENGTH); + PORT_Assert((ivLen + nonceLen) >= sizeof(sslSequenceNumber)); if (nonceLen + contentLen + tagLen > SSL_BUFFER_SPACE(wrBuf)) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - rv = cwSpec->aead( - &cwSpec->keyMaterial, - PR_FALSE, /* do encrypt */ - SSL_BUFFER_NEXT(wrBuf), /* output */ - &len, /* out len */ - SSL_BUFFER_SPACE(wrBuf), /* max out */ - pIn, contentLen, /* input */ - SSL_BUFFER_BASE(&pseudoHeader), SSL_BUFFER_LEN(&pseudoHeader)); + if (nonceLen == 0) { + ivOffset = ivLen - sizeof(sslSequenceNumber); + gen = CKG_GENERATE_COUNTER_XOR; + } else { + ivOffset = ivLen; + gen = CKG_GENERATE_COUNTER; + } + ivOffset = tls13_SetupAeadIv(isDTLS, ivOut, cwSpec->keyMaterial.iv, + ivOffset, ivLen, cwSpec->epoch); + rv = tls13_AEAD(cwSpec->cipherContext, + PR_FALSE, + gen, ivOffset * BPB, /* iv generator params */ + ivOut, /* iv in */ + ivOut, /* iv out */ + ivLen + nonceLen, /* full iv length */ + NULL, 0, /* nonce is generated*/ + SSL_BUFFER_BASE(&pseudoHeader), /* aad */ + SSL_BUFFER_LEN(&pseudoHeader), /* aadlen */ + SSL_BUFFER_NEXT(wrBuf) + nonceLen, /* output */ + &len, /* out len */ + SSL_BUFFER_SPACE(wrBuf) - nonceLen, /* max out */ + tagLen, + pIn, contentLen); /* input */ if (rv != SECSuccess) { PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE); return SECFailure; } + len += nonceLen; /* include the nonce at the beginning */ + /* copy out the generated iv if we are using explict nonces */ + if (nonceLen) { + PORT_Memcpy(SSL_BUFFER_NEXT(wrBuf), ivOut + ivLen, nonceLen); + } rv = sslBuffer_Skip(wrBuf, len, NULL); PORT_Assert(rv == SECSuccess); /* Can't fail. */ @@ -2406,7 +2340,6 @@ ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSLContentType ct, PORT_Assert(cwSpec->cipherDef->max_records <= RECORD_SEQ_MAX); if (cwSpec->nextSeqNum >= cwSpec->cipherDef->max_records) { - /* We should have automatically updated before here in TLS 1.3. */ PORT_Assert(cwSpec->version < SSL_LIBRARY_VERSION_TLS_1_3); SSL_TRC(3, ("%d: SSL[-]: write sequence number at limit 0x%0llx", SSL_GETPID(), cwSpec->nextSeqNum)); @@ -2438,7 +2371,18 @@ ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSLContentType ct, } #else if (cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_3) { + PRUint8 *cipherText = SSL_BUFFER_NEXT(wrBuf); + unsigned int bufLen = SSL_BUFFER_LEN(wrBuf); rv = tls13_ProtectRecord(ss, cwSpec, ct, pIn, contentLen, wrBuf); + if (rv != SECSuccess) { + return SECFailure; + } + if (IS_DTLS(ss)) { + bufLen = SSL_BUFFER_LEN(wrBuf) - bufLen; + rv = dtls13_MaskSequenceNumber(ss, cwSpec, + SSL_BUFFER_BASE(wrBuf), + cipherText, bufLen); + } } else { rv = ssl3_MACEncryptRecord(cwSpec, ss->sec.isServer, IS_DTLS(ss), ct, pIn, contentLen, wrBuf); @@ -4543,6 +4487,21 @@ ssl_IsRsaPssSignatureScheme(SSLSignatureScheme scheme) } PRBool +ssl_IsRsaeSignatureScheme(SSLSignatureScheme scheme) +{ + switch (scheme) { + case ssl_sig_rsa_pss_rsae_sha256: + case ssl_sig_rsa_pss_rsae_sha384: + case ssl_sig_rsa_pss_rsae_sha512: + return PR_TRUE; + + default: + return PR_FALSE; + } + return PR_FALSE; +} + +PRBool ssl_IsRsaPkcs1SignatureScheme(SSLSignatureScheme scheme) { switch (scheme) { @@ -5397,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); @@ -6663,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. */ @@ -6713,13 +6673,13 @@ ssl_CheckServerRandom(sslSocket *ss) /* Both sections use the same sentinel region. */ PRUint8 *downgrade_sentinel = ss->ssl3.hs.server_random + - SSL3_RANDOM_LENGTH - sizeof(tls13_downgrade_random); + SSL3_RANDOM_LENGTH - sizeof(tls12_downgrade_random); if (!PORT_Memcmp(downgrade_sentinel, - tls13_downgrade_random, - sizeof(tls13_downgrade_random)) || - !PORT_Memcmp(downgrade_sentinel, tls12_downgrade_random, - sizeof(tls12_downgrade_random))) { + sizeof(tls12_downgrade_random)) || + !PORT_Memcmp(downgrade_sentinel, + tls1_downgrade_random, + sizeof(tls1_downgrade_random))) { return SECFailure; } } @@ -7693,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 @@ -7712,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 { @@ -8169,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; @@ -8491,20 +8479,24 @@ ssl_GenerateServerRandom(sslSocket *ss) */ PRUint8 *downgradeSentinel = ss->ssl3.hs.server_random + - SSL3_RANDOM_LENGTH - sizeof(tls13_downgrade_random); - - switch (ss->vrange.max) { - case SSL_LIBRARY_VERSION_TLS_1_3: - PORT_Memcpy(downgradeSentinel, - tls13_downgrade_random, sizeof(tls13_downgrade_random)); - break; - case SSL_LIBRARY_VERSION_TLS_1_2: - PORT_Memcpy(downgradeSentinel, - tls12_downgrade_random, sizeof(tls12_downgrade_random)); - break; - default: - /* Do not change random. */ - break; + SSL3_RANDOM_LENGTH - sizeof(tls12_downgrade_random); + + if (ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_2) { + switch (ss->version) { + case SSL_LIBRARY_VERSION_TLS_1_2: + /* vrange.max > 1.2, since we didn't early exit above. */ + PORT_Memcpy(downgradeSentinel, + tls12_downgrade_random, sizeof(tls12_downgrade_random)); + break; + case SSL_LIBRARY_VERSION_TLS_1_1: + case SSL_LIBRARY_VERSION_TLS_1_0: + PORT_Memcpy(downgradeSentinel, + tls1_downgrade_random, sizeof(tls1_downgrade_random)); + break; + default: + /* Do not change random. */ + break; + } } return SECSuccess; @@ -8607,15 +8599,12 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length) goto loser; /* malformed */ } - /* Grab the client's cookie, if present. */ + /* Grab the client's cookie, if present. It is checked after version negotiation. */ if (IS_DTLS(ss)) { rv = ssl3_ConsumeHandshakeVariable(ss, &cookieBytes, 1, &b, &length); if (rv != SECSuccess) { goto loser; /* malformed */ } - if (cookieBytes.len != 0) { - goto loser; /* We never send cookies in DTLS 1.2. */ - } } /* Grab the list of cipher suites. */ @@ -8721,6 +8710,13 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length) errCode = SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER; goto alert_loser; } + + /* A DTLS 1.3-only client MUST set the legacy_cookie field to zero length. + * If a DTLS 1.3 ClientHello is received with any other value in this field, + * the server MUST abort the handshake with an "illegal_parameter" alert. */ + if (IS_DTLS(ss) && cookieBytes.len != 0) { + goto alert_loser; + } } else { /* HRR is TLS1.3-only. We ignore the Cookie extension here. */ if (ss->ssl3.hs.helloRetry) { @@ -8741,6 +8737,11 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length) !memchr(comps.data, ssl_compression_null, comps.len)) { goto alert_loser; } + + /* We never send cookies in DTLS 1.2. */ + if (IS_DTLS(ss) && cookieBytes.len != 0) { + goto loser; + } } /* Now parse the rest of the extensions. */ @@ -9808,10 +9809,31 @@ 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, forCert, + PR_ARRAY_SIZE(filtered), + filtered, &filteredCount); + if (rv != SECSuccess) { + return SECFailure; + } + return ssl3_EncodeFilteredSigAlgs(ss, filtered, filteredCount, buf); +} + +SECStatus +ssl3_EncodeFilteredSigAlgs(const sslSocket *ss, const SSLSignatureScheme *schemes, + PRUint32 numSchemes, sslBuffer *buf) +{ + if (!numSchemes) { + PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM); + return SECFailure; + } + unsigned int lengthOffset; - PRBool found = PR_FALSE; SECStatus rv; rv = sslBuffer_Skip(buf, 2, &lengthOffset); @@ -9819,23 +9841,68 @@ ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion, sslBuffer *buf) return SECFailure; } - for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) { - if (ssl_SignatureSchemeAccepted(minVersion, - ss->ssl3.signatureSchemes[i])) { - rv = sslBuffer_AppendNumber(buf, ss->ssl3.signatureSchemes[i], 2); - if (rv != SECSuccess) { - return SECFailure; - } - found = PR_TRUE; + for (unsigned int i = 0; i < numSchemes; ++i) { + rv = sslBuffer_AppendNumber(buf, schemes[i], 2); + if (rv != SECSuccess) { + return SECFailure; } } + return sslBuffer_InsertLength(buf, lengthOffset, 2); +} - if (!found) { - PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM); +/* + * 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) +{ + PORT_Assert(filteredSchemes); + PORT_Assert(numFilteredSchemes); + PORT_Assert(maxSchemes >= ss->ssl3.signatureSchemeCount); + if (maxSchemes < ss->ssl3.signatureSchemeCount) { return SECFailure; } - return sslBuffer_InsertLength(buf, lengthOffset, 2); + *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], + 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; } static SECStatus @@ -9871,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; } @@ -11232,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; } @@ -11324,9 +11393,9 @@ ssl3_ComputeTLSFinished(sslSocket *ss, ssl3CipherSpec *spec, } if (spec->version < SSL_LIBRARY_VERSION_TLS_1_2) { - tls_mac_params.prfMechanism = CKM_TLS_PRF; + tls_mac_params.prfHashMechanism = CKM_TLS_PRF; } else { - tls_mac_params.prfMechanism = ssl3_GetPrfHashMechanism(ss); + tls_mac_params.prfHashMechanism = ssl3_GetPrfHashMechanism(ss); } tls_mac_params.ulMacLength = 12; tls_mac_params.ulServerOrClient = isServer ? 1 : 2; @@ -11667,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; @@ -11811,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"); @@ -11884,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 */ @@ -12308,41 +12379,26 @@ loser : { return SECFailure; } -/* These macros return the given value with the MSB copied to all the other - * bits. They use the fact that arithmetic shift shifts-in the sign bit. - * However, this is not ensured by the C standard so you may need to replace - * them with something else for odd compilers. */ -#define DUPLICATE_MSB_TO_ALL(x) ((unsigned)((int)(x) >> (sizeof(int) * 8 - 1))) -#define DUPLICATE_MSB_TO_ALL_8(x) ((unsigned char)(DUPLICATE_MSB_TO_ALL(x))) - /* SECStatusToMask returns, in constant time, a mask value of all ones if * rv == SECSuccess. Otherwise it returns zero. */ static unsigned int SECStatusToMask(SECStatus rv) { - unsigned int good; - /* rv ^ SECSuccess is zero iff rv == SECSuccess. Subtracting one results - * in the MSB being set to one iff it was zero before. */ - good = rv ^ SECSuccess; - good--; - return DUPLICATE_MSB_TO_ALL(good); + return PORT_CT_EQ(rv, SECSuccess); } -/* ssl_ConstantTimeGE returns 0xff if a>=b and 0x00 otherwise. */ +/* ssl_ConstantTimeGE returns 0xffffffff if a>=b and 0x00 otherwise. */ static unsigned char ssl_ConstantTimeGE(unsigned int a, unsigned int b) { - a -= b; - return DUPLICATE_MSB_TO_ALL(~a); + return PORT_CT_GE(a, b); } -/* ssl_ConstantTimeEQ8 returns 0xff if a==b and 0x00 otherwise. */ +/* ssl_ConstantTimeEQ returns 0xffffffff if a==b and 0x00 otherwise. */ static unsigned char -ssl_ConstantTimeEQ8(unsigned char a, unsigned char b) +ssl_ConstantTimeEQ(unsigned char a, unsigned char b) { - unsigned int c = a ^ b; - c--; - return DUPLICATE_MSB_TO_ALL_8(c); + return PORT_CT_EQ(a, b); } /* ssl_constantTimeSelect return a if mask is 0xFF and b if mask is 0x00 */ @@ -12357,7 +12413,7 @@ ssl_RemoveSSLv3CBCPadding(sslBuffer *plaintext, unsigned int blockSize, unsigned int macSize) { - unsigned int paddingLength, good, t; + unsigned int paddingLength, good; const unsigned int overhead = 1 /* padding length byte */ + macSize; /* These lengths are all public so we can test them in non-constant @@ -12368,13 +12424,9 @@ ssl_RemoveSSLv3CBCPadding(sslBuffer *plaintext, paddingLength = plaintext->buf[plaintext->len - 1]; /* SSLv3 padding bytes are random and cannot be checked. */ - t = plaintext->len; - t -= paddingLength + overhead; - /* If len >= paddingLength+overhead then the MSB of t is zero. */ - good = DUPLICATE_MSB_TO_ALL(~t); + good = PORT_CT_GE(plaintext->len, paddingLength + overhead); /* SSLv3 requires that the padding is minimal. */ - t = blockSize - (paddingLength + 1); - good &= DUPLICATE_MSB_TO_ALL(~t); + good &= PORT_CT_GE(blockSize, paddingLength + 1); plaintext->len -= good & (paddingLength + 1); return (good & SECSuccess) | (~good & SECFailure); } @@ -12382,7 +12434,7 @@ ssl_RemoveSSLv3CBCPadding(sslBuffer *plaintext, SECStatus ssl_RemoveTLSCBCPadding(sslBuffer *plaintext, unsigned int macSize) { - unsigned int paddingLength, good, t, toCheck, i; + unsigned int paddingLength, good, toCheck, i; const unsigned int overhead = 1 /* padding length byte */ + macSize; /* These lengths are all public so we can test them in non-constant @@ -12392,10 +12444,7 @@ ssl_RemoveTLSCBCPadding(sslBuffer *plaintext, unsigned int macSize) } paddingLength = plaintext->buf[plaintext->len - 1]; - t = plaintext->len; - t -= paddingLength + overhead; - /* If len >= paddingLength+overhead then the MSB of t is zero. */ - good = DUPLICATE_MSB_TO_ALL(~t); + good = PORT_CT_GE(plaintext->len, paddingLength + overhead); /* The padding consists of a length byte at the end of the record and then * that many bytes of padding, all with the same value as the length byte. @@ -12412,10 +12461,9 @@ ssl_RemoveTLSCBCPadding(sslBuffer *plaintext, unsigned int macSize) } for (i = 0; i < toCheck; i++) { - t = paddingLength - i; /* If i <= paddingLength then the MSB of t is zero and mask is * 0xff. Otherwise, mask is 0. */ - unsigned char mask = DUPLICATE_MSB_TO_ALL(~t); + unsigned char mask = PORT_CT_LE(i, paddingLength); unsigned char b = plaintext->buf[plaintext->len - 1 - i]; /* The final |paddingLength+1| bytes should all have the value * |paddingLength|. Therefore the XOR should be zero. */ @@ -12430,7 +12478,7 @@ ssl_RemoveTLSCBCPadding(sslBuffer *plaintext, unsigned int macSize) good &= good >> 2; good &= good >> 1; good <<= sizeof(good) * 8 - 1; - good = DUPLICATE_MSB_TO_ALL(good); + good = PORT_CT_DUPLICATE_MSB_TO_ALL(good); plaintext->len -= good & (paddingLength + 1); return (good & SECSuccess) | (~good & SECFailure); @@ -12523,7 +12571,7 @@ ssl_CBCExtractMAC(sslBuffer *plaintext, 0, rotateOffset); for (i = 0; i < macSize; i++) { for (j = 0; j < macSize; j++) { - out[j] |= rotatedMac[i] & ssl_ConstantTimeEQ8(j, rotateOffset); + out[j] |= rotatedMac[i] & ssl_ConstantTimeEQ(j, rotateOffset); } rotateOffset++; rotateOffset = ssl_constantTimeSelect(ssl_ConstantTimeGE(rotateOffset, macSize), @@ -12633,21 +12681,50 @@ ssl3_UnprotectRecord(sslSocket *ss, * ciphertext by a fixed byte count, but it is not true in general. * Each AEAD cipher should provide a function that returns the * plaintext length for a given ciphertext. */ - unsigned int decryptedLen = - cText->buf->len - cipher_def->explicit_nonce_size - - cipher_def->tag_size; + const unsigned int explicitNonceLen = cipher_def->explicit_nonce_size; + const unsigned int tagLen = cipher_def->tag_size; + unsigned int nonceLen = explicitNonceLen; + unsigned int decryptedLen = cText->buf->len - nonceLen - tagLen; + /* even though read doesn't return and IV, we still need a space to put + * the combined iv/nonce n the gcm 1.2 case*/ + unsigned char ivOut[MAX_IV_LENGTH]; + unsigned char *iv = NULL; + unsigned char *nonce = NULL; + + ivLen = cipher_def->iv_size; + rv = ssl3_BuildRecordPseudoHeader( spec->epoch, cText->seqNum, rType, isTLS, rVersion, IS_DTLS(ss), decryptedLen, &header); PORT_Assert(rv == SECSuccess); - rv = spec->aead(&spec->keyMaterial, - PR_TRUE, /* do decrypt */ - plaintext->buf, /* out */ - &plaintext->len, /* outlen */ - plaintext->space, /* maxout */ - cText->buf->buf, /* in */ - cText->buf->len, /* inlen */ - SSL_BUFFER_BASE(&header), SSL_BUFFER_LEN(&header)); + + /* build the iv */ + if (explicitNonceLen == 0) { + nonceLen = sizeof(cText->seqNum); + iv = spec->keyMaterial.iv; + nonce = SSL_BUFFER_BASE(&header); + } else { + PORT_Memcpy(ivOut, spec->keyMaterial.iv, ivLen); + PORT_Memset(ivOut + ivLen, 0, explicitNonceLen); + iv = ivOut; + nonce = cText->buf->buf; + nonceLen = explicitNonceLen; + } + rv = tls13_AEAD(spec->cipherContext, PR_TRUE, + CKG_NO_GENERATE, 0, /* iv generator params + * (not used in decrypt)*/ + iv, /* iv in */ + NULL, /* iv out */ + ivLen + explicitNonceLen, /* full iv length */ + nonce, nonceLen, /* nonce in */ + SSL_BUFFER_BASE(&header), /* aad */ + SSL_BUFFER_LEN(&header), /* aadlen */ + plaintext->buf, /* output */ + &plaintext->len, /* out len */ + plaintext->space, /* max out */ + tagLen, + cText->buf->buf + explicitNonceLen, /* input */ + cText->buf->len - explicitNonceLen); /* input len */ if (rv != SECSuccess) { good = 0; } @@ -12895,6 +12972,12 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText) } isTLS = (PRBool)(spec->version > SSL_LIBRARY_VERSION_3_0); if (IS_DTLS(ss)) { + if (dtls13_MaskSequenceNumber(ss, spec, cText->hdr, + SSL_BUFFER_BASE(cText->buf), SSL_BUFFER_LEN(cText->buf)) != SECSuccess) { + ssl_ReleaseSpecReadLock(ss); /*****************************/ + /* code already set. */ + return SECFailure; + } if (!dtls_IsRelevant(ss, spec, cText, &cText->seqNum)) { ssl_ReleaseSpecReadLock(ss); /*****************************/ return SECSuccess; @@ -12936,7 +13019,10 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText) /* Encrypted application data records could arrive before the handshake * completes in DTLS 1.3. These can look like valid TLS 1.2 application_data * records in epoch 0, which is never valid. Pretend they didn't decrypt. */ - if (spec->epoch == 0 && rType == ssl_ct_application_data) { + + if (spec->epoch == 0 && ((IS_DTLS(ss) && + dtls_IsDtls13Ciphertext(0, rType)) || + rType == ssl_ct_application_data)) { PORT_SetError(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA); alert = unexpected_message; rv = SECFailure; @@ -12975,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) { @@ -13103,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; @@ -13477,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) @@ -13497,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) @@ -13517,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/security/nss/lib/ssl/ssl3ext.c b/security/nss/lib/ssl/ssl3ext.c index 7e674f0e0..65a69450d 100644 --- a/security/nss/lib/ssl/ssl3ext.c +++ b/security/nss/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 @@ -969,6 +971,8 @@ ssl3_DestroyExtensionData(TLSExtensionData *xtnData) { ssl3_FreeSniNameArray(xtnData); PORT_Free(xtnData->sigSchemes); + PORT_Free(xtnData->delegCredSigSchemes); + PORT_Free(xtnData->delegCredSigSchemesAdvertised); SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE); tls13_DestroyKeyShares(&xtnData->remoteKeyShares); SECITEM_FreeItem(&xtnData->certReqContext, PR_FALSE); diff --git a/security/nss/lib/ssl/ssl3ext.h b/security/nss/lib/ssl/ssl3ext.h index 97319c7d9..ff2f7c211 100644 --- a/security/nss/lib/ssl/ssl3ext.h +++ b/security/nss/lib/ssl/ssl3ext.h @@ -77,6 +77,16 @@ struct TLSExtensionDataStr { SSLSignatureScheme *sigSchemes; unsigned int numSigSchemes; + /* Keep track of signature schemes that the remote peer supports for + * Delegated Credentials signatures, as well was those we have + * advertised (for purposes of validating any received DC). + * This list may not be the same as those supported for certificates. + * Only valid for TLS 1.3. */ + SSLSignatureScheme *delegCredSigSchemes; + unsigned int numDelegCredSigSchemes; + SSLSignatureScheme *delegCredSigSchemesAdvertised; + unsigned int numDelegCredSigSchemesAdvertised; + SECItem certReqContext; CERTDistNames certReqAuthorities; @@ -124,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/security/nss/lib/ssl/ssl3exthandle.c b/security/nss/lib/ssl/ssl3exthandle.c index 206cb00e4..cb4698253 100644 --- a/security/nss/lib/ssl/ssl3exthandle.c +++ b/security/nss/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) @@ -1034,7 +1034,9 @@ ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket, PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - parsedTicket->timestamp = (PRTime)temp << 32; + + /* Cast to avoid undefined behavior if the top bit is set. */ + parsedTicket->timestamp = (PRTime)((PRUint64)temp << 32); rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len); if (rv != SECSuccess) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); @@ -1056,8 +1058,11 @@ ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket, PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } +#ifndef UNSAFE_FUZZER_MODE + /* A well-behaving server should only write 0 or 1. */ PORT_Assert(temp == PR_TRUE || temp == PR_FALSE); - parsedTicket->extendedMasterSecretUsed = (PRBool)temp; +#endif + parsedTicket->extendedMasterSecretUsed = temp ? PR_TRUE : PR_FALSE; rv = ssl3_ExtConsumeHandshake(ss, &temp, 4, &buffer, &len); if (rv != SECSuccess) { @@ -1647,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/security/nss/lib/ssl/ssl3gthr.c b/security/nss/lib/ssl/ssl3gthr.c index f9c741746..45cfb31bc 100644 --- a/security/nss/lib/ssl/ssl3gthr.c +++ b/security/nss/lib/ssl/ssl3gthr.c @@ -268,6 +268,7 @@ dtls_GatherData(sslSocket *ss, sslGather *gs, int flags) PRUint8 contentType; unsigned int headerLen; SECStatus rv; + PRBool dtlsLengthPresent = PR_TRUE; SSL_TRC(30, ("dtls_GatherData")); @@ -316,8 +317,20 @@ dtls_GatherData(sslSocket *ss, sslGather *gs, int flags) headerLen = 13; } else if (contentType == ssl_ct_application_data) { headerLen = 7; - } else if ((contentType & 0xe0) == 0x20) { - headerLen = 2; + } else if (dtls_IsDtls13Ciphertext(ss->version, contentType)) { + /* We don't support CIDs. */ + if (contentType & 0x10) { + PORT_Assert(PR_FALSE); + PORT_SetError(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE); + gs->dtlsPacketOffset = 0; + gs->dtlsPacket.len = 0; + return -1; + } + + dtlsLengthPresent = (contentType & 0x04) == 0x04; + PRUint8 dtlsSeqNoSize = (contentType & 0x08) ? 2 : 1; + PRUint8 dtlsLengthBytes = dtlsLengthPresent ? 2 : 0; + headerLen = 1 + dtlsSeqNoSize + dtlsLengthBytes; } else { SSL_DBG(("%d: SSL3[%d]: invalid first octet (%d) for DTLS", SSL_GETPID(), ss->fd, contentType)); @@ -345,12 +358,10 @@ dtls_GatherData(sslSocket *ss, sslGather *gs, int flags) gs->dtlsPacketOffset += headerLen; /* Have received SSL3 record header in gs->hdr. */ - if (headerLen == 13) { - gs->remainder = (gs->hdr[11] << 8) | gs->hdr[12]; - } else if (headerLen == 7) { - gs->remainder = (gs->hdr[5] << 8) | gs->hdr[6]; + if (dtlsLengthPresent) { + gs->remainder = (gs->hdr[headerLen - 2] << 8) | + gs->hdr[headerLen - 1]; } else { - PORT_Assert(headerLen == 2); gs->remainder = gs->dtlsPacket.len - gs->dtlsPacketOffset; } @@ -600,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, @@ -626,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; } @@ -638,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. */ } @@ -649,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/security/nss/lib/ssl/ssl3prot.h b/security/nss/lib/ssl/ssl3prot.h index ffe837301..edf459290 100644 --- a/security/nss/lib/ssl/ssl3prot.h +++ b/security/nss/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 28 +#define DTLS_1_3_DRAFT_VERSION 38 typedef PRUint16 ssl3CipherSuite; /* The cipher suites are defined in sslproto.h */ diff --git a/security/nss/lib/ssl/sslencode.c b/security/nss/lib/ssl/sslencode.c index e59e758ff..d07b544ab 100644 --- a/security/nss/lib/ssl/sslencode.c +++ b/security/nss/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/security/nss/lib/ssl/sslerr.h b/security/nss/lib/ssl/sslerr.h index 7100b0226..eb8f7c2da 100644 --- a/security/nss/lib/ssl/sslerr.h +++ b/security/nss/lib/ssl/sslerr.h @@ -274,6 +274,8 @@ typedef enum { SSL_ERROR_DC_BAD_SIGNATURE = (SSL_ERROR_BASE + 183), 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/security/nss/lib/ssl/sslexp.h b/security/nss/lib/ssl/sslexp.h index b734d86ca..8a92a39ad 100644 --- a/security/nss/lib/ssl/sslexp.h +++ b/security/nss/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 @@ -662,7 +667,11 @@ typedef SECStatus(PR_CALLBACK *SSLRecordWriteCallback)( * used in TLS. The lower bits of the IV are XORed with the 64-bit counter to * produce the nonce. Otherwise, this is an AEAD interface similar to that * described in RFC 5116. - */ + * + * Note: SSL_MakeAead internally calls SSL_MakeVariantAead with a variant of + * "stream", behaving as noted above. If "datagram" variant is passed instead, + * the Label prefix used in HKDF-Expand is "dtls13" instead of "tls13 ". See + * 7.1 of RFC 8446 and draft-ietf-tls-dtls13-34. */ typedef struct SSLAeadContextStr SSLAeadContext; #define SSL_MakeAead(version, cipherSuite, secret, \ @@ -676,6 +685,18 @@ typedef struct SSLAeadContextStr SSLAeadContext; (version, cipherSuite, secret, \ labelPrefix, labelPrefixLen, ctx)) +#define SSL_MakeVariantAead(version, cipherSuite, variant, secret, \ + labelPrefix, labelPrefixLen, ctx) \ + SSL_EXPERIMENTAL_API("SSL_MakeVariantAead", \ + (PRUint16 _version, PRUint16 _cipherSuite, \ + SSLProtocolVariant _variant, \ + PK11SymKey * _secret, \ + const char *_labelPrefix, \ + unsigned int _labelPrefixLen, \ + SSLAeadContext **_ctx), \ + (version, cipherSuite, variant, secret, \ + labelPrefix, labelPrefixLen, ctx)) + #define SSL_AeadEncrypt(ctx, counter, aad, aadLen, in, inLen, \ output, outputLen, maxOutputLen) \ SSL_EXPERIMENTAL_API("SSL_AeadEncrypt", \ @@ -716,8 +737,13 @@ typedef struct SSLAeadContextStr SSLAeadContext; PK11SymKey * *_keyp), \ (version, cipherSuite, salt, ikm, keyp)) -/* SSL_HkdfExpandLabel produces a key with a mechanism that is suitable for - * input to SSL_HkdfExpandLabel or SSL_MakeAead. */ +/* SSL_HkdfExpandLabel and SSL_HkdfVariantExpandLabel produce a key with a + * mechanism that is suitable for input to SSL_HkdfExpandLabel or SSL_MakeAead. + * + * Note: SSL_HkdfVariantExpandLabel internally calls SSL_HkdfExpandLabel with + * a default "stream" variant. If "datagram" variant is passed instead, the + * Label prefix used in HKDF-Expand is "dtls13" instead of "tls13 ". See 7.1 of + * RFC 8446 and draft-ietf-tls-dtls13-34. */ #define SSL_HkdfExpandLabel(version, cipherSuite, prk, \ hsHash, hsHashLen, label, labelLen, keyp) \ SSL_EXPERIMENTAL_API("SSL_HkdfExpandLabel", \ @@ -729,9 +755,28 @@ typedef struct SSLAeadContextStr SSLAeadContext; (version, cipherSuite, prk, \ hsHash, hsHashLen, label, labelLen, keyp)) -/* SSL_HkdfExpandLabelWithMech uses the KDF from the selected TLS version and - * cipher suite, as with the other calls, but the provided mechanism and key - * size. This allows the key to be used more widely. */ +#define SSL_HkdfVariantExpandLabel(version, cipherSuite, prk, \ + hsHash, hsHashLen, label, labelLen, variant, \ + keyp) \ + SSL_EXPERIMENTAL_API("SSL_HkdfVariantExpandLabel", \ + (PRUint16 _version, PRUint16 _cipherSuite, \ + PK11SymKey * _prk, \ + const PRUint8 *_hsHash, unsigned int _hsHashLen, \ + const char *_label, unsigned int _labelLen, \ + SSLProtocolVariant _variant, \ + PK11SymKey **_keyp), \ + (version, cipherSuite, prk, \ + hsHash, hsHashLen, label, labelLen, variant, \ + keyp)) + +/* SSL_HkdfExpandLabelWithMech and SSL_HkdfVariantExpandLabelWithMech use the KDF + * from the selected TLS version and cipher suite, as with the other calls, but + * the provided mechanism and key size. This allows the key to be used more widely. + * + * Note: SSL_HkdfExpandLabelWithMech internally calls SSL_HkdfVariantExpandLabelWithMech + * with a default "stream" variant. If "datagram" variant is passed instead, the + * Label prefix used in HKDF-Expand is "dtls13" instead of "tls13 ". See 7.1 of + * RFC 8446 and draft-ietf-tls-dtls13-34. */ #define SSL_HkdfExpandLabelWithMech(version, cipherSuite, prk, \ hsHash, hsHashLen, label, labelLen, \ mech, keySize, keyp) \ @@ -746,6 +791,21 @@ typedef struct SSLAeadContextStr SSLAeadContext; hsHash, hsHashLen, label, labelLen, \ mech, keySize, keyp)) +#define SSL_HkdfVariantExpandLabelWithMech(version, cipherSuite, prk, \ + hsHash, hsHashLen, label, labelLen, \ + mech, keySize, variant, keyp) \ + SSL_EXPERIMENTAL_API("SSL_HkdfVariantExpandLabelWithMech", \ + (PRUint16 _version, PRUint16 _cipherSuite, \ + PK11SymKey * _prk, \ + const PRUint8 *_hsHash, unsigned int _hsHashLen, \ + const char *_label, unsigned int _labelLen, \ + CK_MECHANISM_TYPE _mech, unsigned int _keySize, \ + SSLProtocolVariant _variant, \ + PK11SymKey **_keyp), \ + (version, cipherSuite, prk, \ + hsHash, hsHashLen, label, labelLen, \ + mech, keySize, variant, keyp)) + /* SSL_SetTimeFunc overrides the default time function (PR_Now()) and provides * an alternative source of time for the socket. This is used in testing, and in * applications that need better control over how the clock is accessed. Set the @@ -826,6 +886,117 @@ typedef PRTime(PR_CALLBACK *SSLTimeFunc)(void *arg); PRUint16 _numCiphers), \ (fd, cipherOrder, numCiphers)) +/* + * The following functions expose a masking primitive that uses ciphersuite and + * version information to set paramaters for the masking key and mask generation + * logic. This is only supported for TLS 1.3. + * + * The key and IV are generated using the TLS KDF with a custom label. That is + * HKDF-Expand-Label(secret, label, "", L), where |label| is an input to + * SSL_CreateMaskingContext. + * + * The mask generation logic in SSL_CreateMask is determined by the underlying + * symmetric cipher: + * - For AES-ECB, mask = AES-ECB(mask_key, sample). |len| must be <= 16 as + * the output is limited to a single block. + * - For CHACHA20, mask = ChaCha20(mask_key, sample[0..3], sample[4..15], {0}.len) + * That is, the low 4 bytes of |sample| used as the counter, the remaining 12 bytes + * the nonce. We encrypt |len| bytes of zeros, returning the raw key stream. + * + * The caller must pre-allocate at least |len| bytes for output. If the underlying + * cipher cannot produce the requested amount of data, SECFailure is returned. + */ + +typedef struct SSLMaskingContextStr { + CK_MECHANISM_TYPE mech; + PRUint16 version; + PRUint16 cipherSuite; + PK11SymKey *secret; +} SSLMaskingContext; + +#define SSL_CreateMaskingContext(version, cipherSuite, secret, \ + label, labelLen, ctx) \ + SSL_EXPERIMENTAL_API("SSL_CreateMaskingContext", \ + (PRUint16 _version, PRUint16 _cipherSuite, \ + PK11SymKey * _secret, \ + const char *_label, \ + unsigned int _labelLen, \ + SSLMaskingContext **_ctx), \ + (version, cipherSuite, secret, label, labelLen, ctx)) + +#define SSL_CreateVariantMaskingContext(version, cipherSuite, variant, \ + secret, label, labelLen, ctx) \ + SSL_EXPERIMENTAL_API("SSL_CreateVariantMaskingContext", \ + (PRUint16 _version, PRUint16 _cipherSuite, \ + SSLProtocolVariant _variant, \ + PK11SymKey * _secret, \ + const char *_label, \ + unsigned int _labelLen, \ + SSLMaskingContext **_ctx), \ + (version, cipherSuite, variant, secret, \ + label, labelLen, ctx)) + +#define SSL_DestroyMaskingContext(ctx) \ + SSL_EXPERIMENTAL_API("SSL_DestroyMaskingContext", \ + (SSLMaskingContext * _ctx), \ + (ctx)) + +#define SSL_CreateMask(ctx, sample, sampleLen, mask, maskLen) \ + SSL_EXPERIMENTAL_API("SSL_CreateMask", \ + (SSLMaskingContext * _ctx, const PRUint8 *_sample, \ + unsigned int _sampleLen, PRUint8 *_mask, \ + unsigned int _maskLen), \ + (ctx, sample, sampleLen, mask, maskLen)) + +#define SSL_SetDtls13VersionWorkaround(fd, enabled) \ + 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/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h index 4a393b281..35d0c2d6b 100644 --- a/security/nss/lib/ssl/sslimpl.h +++ b/security/nss/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; @@ -281,6 +282,8 @@ typedef struct sslOptionsStr { unsigned int enableV2CompatibleHello : 1; unsigned int enablePostHandshakeAuth : 1; unsigned int enableDelegatedCredentials : 1; + unsigned int enableDtls13VersionCompat : 1; + unsigned int suppressEndOfEarlyData : 1; } sslOptions; typedef enum { sslHandshakingUndetermined = 0, @@ -653,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. */ @@ -689,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. */ @@ -710,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) \ @@ -810,7 +818,7 @@ typedef struct { /* |seqNum| eventually contains the reconstructed sequence number. */ sslSequenceNumber seqNum; /* The header of the cipherText. */ - const PRUint8 *hdr; + PRUint8 *hdr; unsigned int hdrLen; /* |buf| is the payload of the ciphertext. */ @@ -1099,6 +1107,9 @@ struct sslSocketStr { /* Anti-replay for TLS 1.3 0-RTT. */ SSLAntiReplayContext *antiReplay; + + /* An out-of-band PSK. */ + sslPsk *psk; }; struct sslSelfEncryptKeysStr { @@ -1682,8 +1693,14 @@ 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, PRBool forCert, + unsigned int maxSchemes, SSLSignatureScheme *filteredSchemes, + unsigned int *numFilteredSchemes); SECStatus ssl_GetCertificateRequestCAs(const sslSocket *ss, unsigned int *calenp, const SECItem **namesp, @@ -1824,6 +1841,10 @@ SECStatus SSLExp_GetCurrentEpoch(PRFileDesc *fd, PRUint16 *readEpoch, SECStatus SSLExp_MakeAead(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *secret, const char *labelPrefix, unsigned int labelPrefixLen, SSLAeadContext **ctx); + +SECStatus SSLExp_MakeVariantAead(PRUint16 version, PRUint16 cipherSuite, SSLProtocolVariant variant, + PK11SymKey *secret, const char *labelPrefix, + unsigned int labelPrefixLen, SSLAeadContext **ctx); SECStatus SSLExp_DestroyAead(SSLAeadContext *ctx); SECStatus SSLExp_AeadEncrypt(const SSLAeadContext *ctx, PRUint64 counter, const PRUint8 *aad, unsigned int aadLen, @@ -1840,15 +1861,59 @@ SECStatus SSLExp_HkdfExpandLabel(PRUint16 version, PRUint16 cipherSuite, PK11Sym const PRUint8 *hsHash, unsigned int hsHashLen, const char *label, unsigned int labelLen, PK11SymKey **key); +SECStatus SSLExp_HkdfVariantExpandLabel(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk, + const PRUint8 *hsHash, unsigned int hsHashLen, + const char *label, unsigned int labelLen, + SSLProtocolVariant variant, PK11SymKey **key); SECStatus SSLExp_HkdfExpandLabelWithMech(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk, const PRUint8 *hsHash, unsigned int hsHashLen, const char *label, unsigned int labelLen, CK_MECHANISM_TYPE mech, unsigned int keySize, PK11SymKey **keyp); +SECStatus +SSLExp_HkdfVariantExpandLabelWithMech(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk, + const PRUint8 *hsHash, unsigned int hsHashLen, + const char *label, unsigned int labelLen, + CK_MECHANISM_TYPE mech, unsigned int keySize, + SSLProtocolVariant variant, PK11SymKey **keyp); + +SECStatus SSLExp_SetDtls13VersionWorkaround(PRFileDesc *fd, PRBool enabled); SECStatus SSLExp_SetTimeFunc(PRFileDesc *fd, SSLTimeFunc f, void *arg); +extern SECStatus ssl_CreateMaskingContextInner(PRUint16 version, PRUint16 cipherSuite, + SSLProtocolVariant variant, + PK11SymKey *secret, + const char *label, + unsigned int labelLen, + SSLMaskingContext **ctx); + +extern SECStatus ssl_CreateMaskInner(SSLMaskingContext *ctx, const PRUint8 *sample, + unsigned int sampleLen, PRUint8 *outMask, + unsigned int maskLen); + +extern SECStatus ssl_DestroyMaskingContextInner(SSLMaskingContext *ctx); + +SECStatus SSLExp_CreateMaskingContext(PRUint16 version, PRUint16 cipherSuite, + PK11SymKey *secret, + const char *label, + unsigned int labelLen, + SSLMaskingContext **ctx); + +SECStatus SSLExp_CreateVariantMaskingContext(PRUint16 version, PRUint16 cipherSuite, + SSLProtocolVariant variant, + PK11SymKey *secret, + const char *label, + unsigned int labelLen, + SSLMaskingContext **ctx); + +SECStatus SSLExp_CreateMask(SSLMaskingContext *ctx, const PRUint8 *sample, + unsigned int sampleLen, PRUint8 *mask, + unsigned int len); + +SECStatus SSLExp_DestroyMaskingContext(SSLMaskingContext *ctx); + SEC_END_PROTOS #if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS) diff --git a/security/nss/lib/ssl/sslinfo.c b/security/nss/lib/ssl/sslinfo.c index b069888e2..a92ed1604 100644 --- a/security/nss/lib/ssl/sslinfo.c +++ b/security/nss/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,24 +429,37 @@ 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), - out, outLen); + ss->protocolVariant, out, outLen); PK11_FreeSymKey(innerSecret); return rv; } diff --git a/security/nss/lib/ssl/sslnonce.c b/security/nss/lib/ssl/sslnonce.c index b7b5b7fe5..3daab4b75 100644 --- a/security/nss/lib/ssl/sslnonce.c +++ b/security/nss/lib/ssl/sslnonce.c @@ -537,6 +537,9 @@ ssl_DecodeResumptionToken(sslSessionID *sid, const PRUint8 *encodedToken, } if (readerBuffer.len) { PORT_Assert(readerBuffer.buf); + if (sid->peerID) { + PORT_Free((void *)sid->peerID); + } sid->peerID = PORT_Strdup((const char *)readerBuffer.buf); } @@ -1120,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; } @@ -1197,14 +1201,15 @@ ssl3_SetSIDSessionTicket(sslSessionID *sid, * anything yet, so no locking is needed. */ if (sid->u.ssl3.lock) { - PORT_Assert(sid->cached == in_client_cache); PR_RWLock_Wlock(sid->u.ssl3.lock); + /* Another thread may have evicted, or it may be in external cache. */ + PORT_Assert(sid->cached != never_cached); } /* If this was in the client cache, then we might have to free the old * ticket. In TLS 1.3, we might get a replacement ticket if the server * sends more than one ticket. */ if (sid->u.ssl3.locked.sessionTicket.ticket.data) { - PORT_Assert(sid->cached == in_client_cache || + PORT_Assert(sid->cached != never_cached || sid->version >= SSL_LIBRARY_VERSION_TLS_1_3); SECITEM_FreeItem(&sid->u.ssl3.locked.sessionTicket.ticket, PR_FALSE); diff --git a/security/nss/lib/ssl/sslprimitive.c b/security/nss/lib/ssl/sslprimitive.c index 540c17840..2afecfb16 100644 --- a/security/nss/lib/ssl/sslprimitive.c +++ b/security/nss/lib/ssl/sslprimitive.c @@ -6,6 +6,7 @@ * 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 "blapit.h" #include "keyhi.h" #include "pk11pub.h" #include "sechash.h" @@ -19,47 +20,28 @@ #include "tls13hkdf.h" struct SSLAeadContextStr { - CK_MECHANISM_TYPE mech; - ssl3KeyMaterial keys; + /* sigh, the API creates a single context, but then uses either encrypt + * and decrypt on that context. We should take an encrypt/decrypt + * variable here, but for now create two contexts. */ + PK11Context *encryptContext; + PK11Context *decryptContext; + int tagLen; + int ivLen; + unsigned char iv[MAX_IV_LENGTH]; }; -static SECStatus -tls13_GetHashAndCipher(PRUint16 version, PRUint16 cipherSuite, - SSLHashType *hash, const ssl3BulkCipherDef **cipher) -{ - if (version < SSL_LIBRARY_VERSION_TLS_1_3) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - // Lookup and check the suite. - SSLVersionRange vrange = { version, version }; - if (!ssl3_CipherSuiteAllowedForVersionRange(cipherSuite, &vrange)) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - const ssl3CipherSuiteDef *suiteDef = ssl_LookupCipherSuiteDef(cipherSuite); - const ssl3BulkCipherDef *cipherDef = ssl_GetBulkCipherDef(suiteDef); - if (cipherDef->type != type_aead) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - *hash = suiteDef->prf_hash; - if (cipher != NULL) { - *cipher = cipherDef; - } - return SECSuccess; -} - SECStatus -SSLExp_MakeAead(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *secret, - const char *labelPrefix, unsigned int labelPrefixLen, - SSLAeadContext **ctx) +SSLExp_MakeVariantAead(PRUint16 version, PRUint16 cipherSuite, SSLProtocolVariant variant, + PK11SymKey *secret, const char *labelPrefix, + unsigned int labelPrefixLen, SSLAeadContext **ctx) { SSLAeadContext *out = NULL; char label[255]; // Maximum length label. static const char *const keySuffix = "key"; static const char *const ivSuffix = "iv"; + CK_MECHANISM_TYPE mech; + SECItem nullParams = { siBuffer, NULL, 0 }; + PK11SymKey *key = NULL; PORT_Assert(strlen(keySuffix) >= strlen(ivSuffix)); if (secret == NULL || ctx == NULL || @@ -81,7 +63,9 @@ SSLExp_MakeAead(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *secret, if (out == NULL) { goto loser; } - out->mech = ssl3_Alg2Mech(cipher->calg); + mech = ssl3_Alg2Mech(cipher->calg); + out->ivLen = cipher->iv_size + cipher->explicit_nonce_size; + out->tagLen = cipher->tag_size; memcpy(label, labelPrefix, labelPrefixLen); memcpy(label + labelPrefixLen, ivSuffix, strlen(ivSuffix)); @@ -89,8 +73,8 @@ SSLExp_MakeAead(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *secret, unsigned int ivLen = cipher->iv_size + cipher->explicit_nonce_size; rv = tls13_HkdfExpandLabelRaw(secret, hash, NULL, 0, // Handshake hash. - label, labelLen, - out->keys.iv, ivLen); + label, labelLen, variant, + out->iv, ivLen); if (rv != SECSuccess) { goto loser; } @@ -99,91 +83,96 @@ SSLExp_MakeAead(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *secret, labelLen = labelPrefixLen + strlen(keySuffix); rv = tls13_HkdfExpandLabel(secret, hash, NULL, 0, // Handshake hash. - label, labelLen, - out->mech, cipher->key_size, &out->keys.key); + label, labelLen, mech, cipher->key_size, + variant, &key); if (rv != SECSuccess) { goto loser; } + /* We really need to change the API to Create a context for each + * encrypt and decrypt rather than a single call that does both. it's + * almost certain that the underlying application tries to use the same + * context for both. */ + out->encryptContext = PK11_CreateContextBySymKey(mech, + CKA_NSS_MESSAGE | CKA_ENCRYPT, + key, &nullParams); + if (out->encryptContext == NULL) { + goto loser; + } + + out->decryptContext = PK11_CreateContextBySymKey(mech, + CKA_NSS_MESSAGE | CKA_DECRYPT, + key, &nullParams); + if (out->decryptContext == NULL) { + goto loser; + } + + PK11_FreeSymKey(key); *ctx = out; return SECSuccess; loser: + PK11_FreeSymKey(key); SSLExp_DestroyAead(out); return SECFailure; } SECStatus +SSLExp_MakeAead(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *secret, + const char *labelPrefix, unsigned int labelPrefixLen, SSLAeadContext **ctx) +{ + return SSLExp_MakeVariantAead(version, cipherSuite, ssl_variant_stream, secret, + labelPrefix, labelPrefixLen, ctx); +} + +SECStatus SSLExp_DestroyAead(SSLAeadContext *ctx) { if (!ctx) { return SECSuccess; } + if (ctx->encryptContext) { + PK11_DestroyContext(ctx->encryptContext, PR_TRUE); + } + if (ctx->decryptContext) { + PK11_DestroyContext(ctx->decryptContext, PR_TRUE); + } - PK11_FreeSymKey(ctx->keys.key); PORT_ZFree(ctx, sizeof(*ctx)); return SECSuccess; } /* Bug 1529440 exists to refactor this and the other AEAD uses. */ static SECStatus -ssl_AeadInner(const SSLAeadContext *ctx, PRBool decrypt, PRUint64 counter, +ssl_AeadInner(const SSLAeadContext *ctx, PK11Context *context, + PRBool decrypt, PRUint64 counter, const PRUint8 *aad, unsigned int aadLen, - const PRUint8 *plaintext, unsigned int plaintextLen, + const PRUint8 *in, unsigned int inLen, PRUint8 *out, unsigned int *outLen, unsigned int maxOut) { - if (ctx == NULL || (aad == NULL && aadLen > 0) || plaintext == NULL || + if (ctx == NULL || (aad == NULL && aadLen > 0) || in == NULL || out == NULL || outLen == NULL) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } // Setup the nonce. - PRUint8 nonce[12] = { 0 }; - sslBuffer nonceBuf = SSL_BUFFER_FIXED(nonce + sizeof(nonce) - sizeof(counter), - sizeof(counter)); + PRUint8 nonce[sizeof(counter)] = { 0 }; + sslBuffer nonceBuf = SSL_BUFFER_FIXED(nonce, sizeof(counter)); SECStatus rv = sslBuffer_AppendNumber(&nonceBuf, counter, sizeof(counter)); if (rv != SECSuccess) { PORT_Assert(0); return SECFailure; } - for (int i = 0; i < sizeof(nonce); ++i) { - nonce[i] ^= ctx->keys.iv[i]; - } - - // Build AEAD parameters. - CK_GCM_PARAMS gcmParams = { 0 }; - CK_NSS_AEAD_PARAMS aeadParams = { 0 }; - unsigned char *params; - unsigned int paramsLen; - switch (ctx->mech) { - case CKM_AES_GCM: - gcmParams.pIv = nonce; - gcmParams.ulIvLen = sizeof(nonce); - gcmParams.pAAD = (unsigned char *)aad; // const cast :( - gcmParams.ulAADLen = aadLen; - gcmParams.ulTagBits = 128; // GCM measures in bits. - params = (unsigned char *)&gcmParams; - paramsLen = sizeof(gcmParams); - break; - - case CKM_NSS_CHACHA20_POLY1305: - aeadParams.pNonce = nonce; - aeadParams.ulNonceLen = sizeof(nonce); - aeadParams.pAAD = (unsigned char *)aad; // const cast :( - aeadParams.ulAADLen = aadLen; - aeadParams.ulTagLen = 16; // AEAD measures in octets. - params = (unsigned char *)&aeadParams; - paramsLen = sizeof(aeadParams); - break; - - default: - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - return tls13_AEAD(&ctx->keys, decrypt, out, outLen, maxOut, - plaintext, plaintextLen, ctx->mech, params, paramsLen); + /* at least on encrypt, we should not be using CKG_NO_GENERATE, but + * the current experimental API has the application tracking the counter + * rather than token. We should look at the QUIC code and see if the + * counter can be moved internally where it belongs. That would + * also get rid of the formatting code above and have the API + * call tls13_AEAD directly in SSLExp_Aead* */ + return tls13_AEAD(context, decrypt, CKG_NO_GENERATE, 0, ctx->iv, NULL, + ctx->ivLen, nonce, sizeof(counter), aad, aadLen, + out, outLen, maxOut, ctx->tagLen, in, inLen); } SECStatus @@ -193,19 +182,21 @@ SSLExp_AeadEncrypt(const SSLAeadContext *ctx, PRUint64 counter, PRUint8 *out, unsigned int *outLen, unsigned int maxOut) { // false == encrypt - return ssl_AeadInner(ctx, PR_FALSE, counter, aad, aadLen, - plaintext, plaintextLen, out, outLen, maxOut); + return ssl_AeadInner(ctx, ctx->encryptContext, PR_FALSE, counter, + aad, aadLen, plaintext, plaintextLen, + out, outLen, maxOut); } SECStatus SSLExp_AeadDecrypt(const SSLAeadContext *ctx, PRUint64 counter, const PRUint8 *aad, unsigned int aadLen, - const PRUint8 *plaintext, unsigned int plaintextLen, + const PRUint8 *ciphertext, unsigned int ciphertextLen, PRUint8 *out, unsigned int *outLen, unsigned int maxOut) { // true == decrypt - return ssl_AeadInner(ctx, PR_TRUE, counter, aad, aadLen, - plaintext, plaintextLen, out, outLen, maxOut); + return ssl_AeadInner(ctx, ctx->decryptContext, PR_TRUE, counter, + aad, aadLen, ciphertext, ciphertextLen, + out, outLen, maxOut); } SECStatus @@ -229,8 +220,17 @@ SSLExp_HkdfExtract(PRUint16 version, PRUint16 cipherSuite, SECStatus SSLExp_HkdfExpandLabel(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk, const PRUint8 *hsHash, unsigned int hsHashLen, - const char *label, unsigned int labelLen, - PK11SymKey **keyp) + const char *label, unsigned int labelLen, PK11SymKey **keyp) +{ + return SSLExp_HkdfVariantExpandLabel(version, cipherSuite, prk, hsHash, hsHashLen, + label, labelLen, ssl_variant_stream, keyp); +} + +SECStatus +SSLExp_HkdfVariantExpandLabel(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk, + const PRUint8 *hsHash, unsigned int hsHashLen, + const char *label, unsigned int labelLen, + SSLProtocolVariant variant, PK11SymKey **keyp) { if (prk == NULL || keyp == NULL || label == NULL || labelLen == 0) { @@ -245,8 +245,8 @@ SSLExp_HkdfExpandLabel(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk, return SECFailure; /* Code already set. */ } return tls13_HkdfExpandLabel(prk, hash, hsHash, hsHashLen, label, labelLen, - tls13_GetHkdfMechanismForHash(hash), - tls13_GetHashSizeForHash(hash), keyp); + CKM_HKDF_DERIVE, + tls13_GetHashSizeForHash(hash), variant, keyp); } SECStatus @@ -256,6 +256,18 @@ SSLExp_HkdfExpandLabelWithMech(PRUint16 version, PRUint16 cipherSuite, PK11SymKe CK_MECHANISM_TYPE mech, unsigned int keySize, PK11SymKey **keyp) { + return SSLExp_HkdfVariantExpandLabelWithMech(version, cipherSuite, prk, hsHash, hsHashLen, + label, labelLen, mech, keySize, + ssl_variant_stream, keyp); +} + +SECStatus +SSLExp_HkdfVariantExpandLabelWithMech(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk, + const PRUint8 *hsHash, unsigned int hsHashLen, + const char *label, unsigned int labelLen, + CK_MECHANISM_TYPE mech, unsigned int keySize, + SSLProtocolVariant variant, PK11SymKey **keyp) +{ if (prk == NULL || keyp == NULL || label == NULL || labelLen == 0 || mech == CKM_INVALID_MECHANISM || keySize == 0) { @@ -270,5 +282,201 @@ SSLExp_HkdfExpandLabelWithMech(PRUint16 version, PRUint16 cipherSuite, PK11SymKe return SECFailure; /* Code already set. */ } return tls13_HkdfExpandLabel(prk, hash, hsHash, hsHashLen, label, labelLen, - mech, keySize, keyp); + mech, keySize, variant, keyp); +} + +SECStatus +ssl_CreateMaskingContextInner(PRUint16 version, PRUint16 cipherSuite, + SSLProtocolVariant variant, + PK11SymKey *secret, + const char *label, + unsigned int labelLen, + SSLMaskingContext **ctx) +{ + if (!secret || !ctx || (!label && labelLen)) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + SSLMaskingContext *out = PORT_ZNew(SSLMaskingContext); + if (out == NULL) { + goto loser; + } + + SSLHashType hash; + const ssl3BulkCipherDef *cipher; + SECStatus rv = tls13_GetHashAndCipher(version, cipherSuite, + &hash, &cipher); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + goto loser; /* Code already set. */ + } + + out->mech = tls13_SequenceNumberEncryptionMechanism(cipher->calg); + if (out->mech == CKM_INVALID_MECHANISM) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + goto loser; + } + + // Derive the masking key + rv = tls13_HkdfExpandLabel(secret, hash, + NULL, 0, // Handshake hash. + label, labelLen, + out->mech, + cipher->key_size, variant, + &out->secret); + if (rv != SECSuccess) { + goto loser; + } + + out->version = version; + out->cipherSuite = cipherSuite; + + *ctx = out; + return SECSuccess; +loser: + SSLExp_DestroyMaskingContext(out); + return SECFailure; +} + +SECStatus +ssl_CreateMaskInner(SSLMaskingContext *ctx, const PRUint8 *sample, + unsigned int sampleLen, PRUint8 *outMask, + unsigned int maskLen) +{ + if (!ctx || !sample || !sampleLen || !outMask || !maskLen) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + if (ctx->secret == NULL) { + PORT_SetError(SEC_ERROR_NO_KEY); + return SECFailure; + } + + SECStatus rv = SECFailure; + unsigned int outMaskLen = 0; + int paramLen = 0; + + /* Internal output len/buf, for use if the caller allocated and requested + * less than one block of output. |oneBlock| should have size equal to the + * largest block size supported below. */ + PRUint8 oneBlock[AES_BLOCK_SIZE]; + PRUint8 *outMask_ = outMask; + unsigned int maskLen_ = maskLen; + + switch (ctx->mech) { + case CKM_AES_ECB: + if (sampleLen < AES_BLOCK_SIZE) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + if (maskLen_ < AES_BLOCK_SIZE) { + outMask_ = oneBlock; + maskLen_ = sizeof(oneBlock); + } + rv = PK11_Encrypt(ctx->secret, + ctx->mech, + NULL, + outMask_, &outMaskLen, maskLen_, + sample, AES_BLOCK_SIZE); + if (rv == SECSuccess && + maskLen < AES_BLOCK_SIZE) { + memcpy(outMask, outMask_, maskLen); + } + break; + case CKM_NSS_CHACHA20_CTR: + paramLen = 16; + /* fall through */ + case CKM_CHACHA20: + paramLen = (paramLen) ? paramLen : sizeof(CK_CHACHA20_PARAMS); + if (sampleLen < paramLen) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + SECItem param; + param.type = siBuffer; + param.len = paramLen; + param.data = (PRUint8 *)sample; // const-cast :( + unsigned char zeros[128] = { 0 }; + + if (maskLen > sizeof(zeros)) { + PORT_SetError(SEC_ERROR_OUTPUT_LEN); + return SECFailure; + } + + rv = PK11_Encrypt(ctx->secret, + ctx->mech, + ¶m, + outMask, &outMaskLen, + maskLen, + zeros, maskLen); + break; + default: + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_PKCS11_FUNCTION_FAILED); + return SECFailure; + } + + // Ensure we produced at least as much material as requested. + if (outMaskLen < maskLen) { + PORT_SetError(SEC_ERROR_OUTPUT_LEN); + return SECFailure; + } + + return SECSuccess; +} + +SECStatus +ssl_DestroyMaskingContextInner(SSLMaskingContext *ctx) +{ + if (!ctx) { + return SECSuccess; + } + + PK11_FreeSymKey(ctx->secret); + PORT_ZFree(ctx, sizeof(*ctx)); + return SECSuccess; +} + +SECStatus +SSLExp_CreateMask(SSLMaskingContext *ctx, const PRUint8 *sample, + unsigned int sampleLen, PRUint8 *outMask, + unsigned int maskLen) +{ + return ssl_CreateMaskInner(ctx, sample, sampleLen, outMask, maskLen); +} + +SECStatus +SSLExp_CreateMaskingContext(PRUint16 version, PRUint16 cipherSuite, + PK11SymKey *secret, + const char *label, + unsigned int labelLen, + SSLMaskingContext **ctx) +{ + return ssl_CreateMaskingContextInner(version, cipherSuite, ssl_variant_stream, secret, + label, labelLen, ctx); +} + +SECStatus +SSLExp_CreateVariantMaskingContext(PRUint16 version, PRUint16 cipherSuite, + SSLProtocolVariant variant, + PK11SymKey *secret, + const char *label, + unsigned int labelLen, + SSLMaskingContext **ctx) +{ + return ssl_CreateMaskingContextInner(version, cipherSuite, variant, secret, + label, labelLen, ctx); +} + +SECStatus +SSLExp_DestroyMaskingContext(SSLMaskingContext *ctx) +{ + return ssl_DestroyMaskingContextInner(ctx); } diff --git a/security/nss/lib/ssl/sslsecur.c b/security/nss/lib/ssl/sslsecur.c index 14320fa19..ef978c90a 100644 --- a/security/nss/lib/ssl/sslsecur.c +++ b/security/nss/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/security/nss/lib/ssl/sslsnce.c b/security/nss/lib/ssl/sslsnce.c index 36c82117e..acb51a145 100644 --- a/security/nss/lib/ssl/sslsnce.c +++ b/security/nss/lib/ssl/sslsnce.c @@ -276,6 +276,17 @@ typedef struct inheritanceStr inheritance; /************************************************************************/ +/* SSL Session Cache has a smaller set of functions to initialize than + * ssl does. some ssl_functions can't be initialized before NSS has been + * initialized, and the cache may be configured before NSS is initialized + * so thus the special init function */ +static SECStatus +ssl_InitSessionCache() +{ + /* currently only one function, which is itself idempotent */ + return ssl_InitializePRErrorTable(); +} + /* This is used to set locking times for the cache. It is not used to set the * PRTime attributes of sessions, which are driven by ss->now(). */ static PRUint32 @@ -692,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; } @@ -719,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; } @@ -1165,7 +1176,7 @@ ssl_ConfigServerSessionIDCacheInstanceWithOpt(cacheDesc *cache, { SECStatus rv; - rv = ssl_Init(); + rv = ssl_InitSessionCache(); if (rv != SECSuccess) { return rv; } @@ -1341,7 +1352,7 @@ SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char *envString) int locks_initialized = 0; int locks_to_initialize = 0; #endif - SECStatus status = ssl_Init(); + SECStatus status = ssl_InitSessionCache(); if (status != SECSuccess) { return status; @@ -1779,8 +1790,8 @@ ssl_GetSelfEncryptKeyPair(SECKEYPublicKey **pubKey, return SECFailure; } - SECKEYPublicKey *pubKeyCopy; - SECKEYPrivateKey *privKeyCopy; + SECKEYPublicKey *pubKeyCopy = NULL; + SECKEYPrivateKey *privKeyCopy = NULL; PRBool noKey = PR_FALSE; PR_RWLock_Rlock(ssl_self_encrypt_key_pair.lock); diff --git a/security/nss/lib/ssl/sslsock.c b/security/nss/lib/ssl/sslsock.c index aa0e76e3c..695f39c50 100644 --- a/security/nss/lib/ssl/sslsock.c +++ b/security/nss/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. */ @@ -86,10 +87,12 @@ static sslOptions ssl_defaults = { .requireDHENamedGroups = PR_FALSE, .enable0RttData = PR_FALSE, .enableTls13CompatMode = PR_FALSE, + .enableDtls13VersionCompat = PR_FALSE, .enableDtlsShortHeader = PR_FALSE, .enableHelloDowngradeCheck = PR_FALSE, .enableV2CompatibleHello = PR_FALSE, - .enablePostHandshakeAuth = PR_FALSE + .enablePostHandshakeAuth = PR_FALSE, + .suppressEndOfEarlyData = PR_FALSE }; /* @@ -381,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); @@ -467,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; + } } /* @@ -863,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; @@ -1017,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; @@ -1155,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; @@ -1366,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; @@ -1431,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); } @@ -1477,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); } @@ -1506,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); @@ -2452,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) @@ -4145,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); @@ -4215,13 +4263,19 @@ struct { void *function; } ssl_experimental_functions[] = { #ifndef SSL_DISABLE_EXPERIMENTAL_API + EXP(AddExternalPsk), + EXP(AddExternalPsk0Rtt), EXP(AeadDecrypt), EXP(AeadEncrypt), EXP(CipherSuiteOrderGet), EXP(CipherSuiteOrderSet), EXP(CreateAntiReplayContext), + EXP(CreateMask), + EXP(CreateMaskingContext), + EXP(CreateVariantMaskingContext), EXP(DelegateCredential), EXP(DestroyAead), + EXP(DestroyMaskingContext), EXP(DestroyResumptionTokenInfo), EXP(EnableESNI), EXP(EncodeESNIKeys), @@ -4233,15 +4287,20 @@ struct { EXP(HkdfExtract), EXP(HkdfExpandLabel), EXP(HkdfExpandLabelWithMech), + EXP(HkdfVariantExpandLabel), + EXP(HkdfVariantExpandLabelWithMech), EXP(KeyUpdate), EXP(MakeAead), + EXP(MakeVariantAead), EXP(RecordLayerData), EXP(RecordLayerWriteCallback), EXP(ReleaseAntiReplayContext), + EXP(RemoveExternalPsk), EXP(SecretCallback), EXP(SendCertificateRequest), EXP(SendSessionTicket), EXP(SetAntiReplayContext), + EXP(SetDtls13VersionWorkaround), EXP(SetESNIKeyPair), EXP(SetMaxEarlyDataSize), EXP(SetResumptionTokenCallback), @@ -4283,6 +4342,17 @@ ssl_ClearPRCList(PRCList *list, void (*f)(void *)) } SECStatus +SSLExp_SetDtls13VersionWorkaround(PRFileDesc *fd, PRBool enabled) +{ + sslSocket *ss = ssl_FindSocket(fd); + if (!ss) { + return SECFailure; + } + ss->opt.enableDtls13VersionCompat = enabled; + return SECSuccess; +} + +SECStatus SSLExp_SetTimeFunc(PRFileDesc *fd, SSLTimeFunc f, void *arg) { sslSocket *ss = ssl_FindSocket(fd); @@ -4437,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/security/nss/lib/ssl/sslspec.c b/security/nss/lib/ssl/sslspec.c index def3c6750..c5bedad7a 100644 --- a/security/nss/lib/ssl/sslspec.c +++ b/security/nss/lib/ssl/sslspec.c @@ -7,6 +7,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "ssl.h" +#include "sslexp.h" +#include "sslimpl.h" #include "sslproto.h" #include "pk11func.h" #include "secitem.h" @@ -227,6 +229,7 @@ ssl_FreeCipherSpec(ssl3CipherSpec *spec) } PK11_FreeSymKey(spec->masterSecret); ssl_DestroyKeyMaterial(&spec->keyMaterial); + ssl_DestroyMaskingContextInner(spec->maskContext); PORT_ZFree(spec, sizeof(*spec)); } diff --git a/security/nss/lib/ssl/sslspec.h b/security/nss/lib/ssl/sslspec.h index ca9ef540f..061d888ae 100644 --- a/security/nss/lib/ssl/sslspec.h +++ b/security/nss/lib/ssl/sslspec.h @@ -105,16 +105,16 @@ typedef SECStatus (*SSLCipher)(void *context, unsigned int maxout, const unsigned char *in, unsigned int inlen); -typedef SECStatus (*SSLAEADCipher)( - const ssl3KeyMaterial *keys, - PRBool doDecrypt, - unsigned char *out, - unsigned int *outlen, - unsigned int maxout, - const unsigned char *in, - unsigned int inlen, - const unsigned char *additionalData, - unsigned int additionalDataLen); +typedef SECStatus (*SSLAEADCipher)(PK11Context *context, + CK_GENERATOR_FUNCTION ivGen, + unsigned int fixedbits, + unsigned char *iv, unsigned int ivlen, + const unsigned char *aad, + unsigned int aadlen, + unsigned char *out, unsigned int *outlen, + unsigned int maxout, unsigned char *tag, + unsigned int taglen, + const unsigned char *in, unsigned int inlen); /* The DTLS anti-replay window in number of packets. Defined here because we * need it in the cipher spec. Note that this is a ring buffer but left and @@ -149,7 +149,6 @@ struct ssl3CipherSpecStr { const ssl3MACDef *macDef; SSLCipher cipher; - SSLAEADCipher aead; void *cipherContext; PK11SymKey *masterSecret; @@ -169,6 +168,12 @@ struct ssl3CipherSpecStr { * negotiated value for TLS 1.3; it is reduced by one to account for the * content type octet. */ PRUint16 recordSizeLimit; + + /* 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/security/nss/lib/ssl/sslt.h b/security/nss/lib/ssl/sslt.h index 47efa2e4d..eaf4133e3 100644 --- a/security/nss/lib/ssl/sslt.h +++ b/security/nss/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; @@ -507,6 +517,7 @@ typedef enum { ssl_padding_xtn = 21, ssl_extended_master_secret_xtn = 23, ssl_record_size_limit_xtn = 28, + ssl_delegated_credentials_xtn = 34, ssl_session_ticket_xtn = 35, /* 40 was used in draft versions of TLS 1.3; it is now reserved. */ ssl_tls13_pre_shared_key_xtn = 41, @@ -521,7 +532,6 @@ typedef enum { ssl_tls13_key_share_xtn = 51, ssl_next_proto_nego_xtn = 13172, /* Deprecated. */ ssl_renegotiation_info_xtn = 0xff01, - ssl_delegated_credentials_xtn = 0xff02, ssl_tls13_short_header_xtn = 0xff03, /* Deprecated. */ ssl_tls13_encrypted_sni_xtn = 0xffce, } SSLExtensionType; diff --git a/security/nss/lib/ssl/tls13con.c b/security/nss/lib/ssl/tls13con.c index c3528a52f..5d51d3c5c 100644 --- a/security/nss/lib/ssl/tls13con.c +++ b/security/nss/lib/ssl/tls13con.c @@ -25,28 +25,11 @@ #include "tls13exthandle.h" #include "tls13hashstate.h" #include "tls13subcerts.h" +#include "tls13psk.h" static SECStatus tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch, SSLSecretDirection install, PRBool deleteSecret); -static SECStatus tls13_AESGCM(const ssl3KeyMaterial *keys, - PRBool doDecrypt, - unsigned char *out, - unsigned int *outlen, - unsigned int maxout, - const unsigned char *in, - unsigned int inlen, - const unsigned char *additionalData, - unsigned int additionalDataLen); -static SECStatus tls13_ChaCha20Poly1305(const ssl3KeyMaterial *keys, - PRBool doDecrypt, - unsigned char *out, - unsigned int *outlen, - unsigned int maxout, - const unsigned char *in, - unsigned int inlen, - const unsigned char *additionalData, - unsigned int additionalDataLen); static SECStatus tls13_SendServerHelloSequence(sslSocket *ss); static SECStatus tls13_SendEncryptedExtensions(sslSocket *ss); static void tls13_SetKeyExchangeType(sslSocket *ss, const sslNamedGroupDef *group); @@ -83,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, @@ -103,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, @@ -120,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"; @@ -131,6 +117,7 @@ const char kHkdfLabelExporterMasterSecret[] = "exp master"; const char kHkdfLabelResumption[] = "resumption"; const char kHkdfLabelTrafficUpdate[] = "traffic upd"; const char kHkdfPurposeKey[] = "key"; +const char kHkdfPurposeSn[] = "sn"; const char kHkdfPurposeIv[] = "iv"; const char keylogLabelClientEarlyTrafficSecret[] = "CLIENT_EARLY_TRAFFIC_SECRET"; @@ -281,11 +268,49 @@ 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; } +SECStatus +tls13_GetHashAndCipher(PRUint16 version, PRUint16 cipherSuite, + SSLHashType *hash, const ssl3BulkCipherDef **cipher) +{ + if (version < SSL_LIBRARY_VERSION_TLS_1_3) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + // Lookup and check the suite. + SSLVersionRange vrange = { version, version }; + if (!ssl3_CipherSuiteAllowedForVersionRange(cipherSuite, &vrange)) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + const ssl3CipherSuiteDef *suiteDef = ssl_LookupCipherSuiteDef(cipherSuite); + const ssl3BulkCipherDef *cipherDef = ssl_GetBulkCipherDef(suiteDef); + if (cipherDef->type != type_aead) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + *hash = suiteDef->prf_hash; + if (cipher != NULL) { + *cipher = cipherDef; + } + return SECSuccess; +} + unsigned int tls13_GetHashSizeForHash(SSLHashType hash) { @@ -306,30 +331,10 @@ tls13_GetHashSize(const sslSocket *ss) return tls13_GetHashSizeForHash(tls13_GetHash(ss)); } -CK_MECHANISM_TYPE -tls13_GetHkdfMechanismForHash(SSLHashType hash) -{ - switch (hash) { - case ssl_hash_sha256: - return CKM_NSS_HKDF_SHA256; - case ssl_hash_sha384: - return CKM_NSS_HKDF_SHA384; - default: - PORT_Assert(0); - } - return CKM_NSS_HKDF_SHA256; -} - -CK_MECHANISM_TYPE -tls13_GetHkdfMechanism(sslSocket *ss) -{ - return tls13_GetHkdfMechanismForHash(tls13_GetHash(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: @@ -340,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; } @@ -470,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; @@ -595,7 +616,7 @@ tls13_HandleKeyShare(sslSocket *ss, key = PK11_PubDeriveWithKDF( keyPair->privKey, peerKey, PR_FALSE, NULL, NULL, mechanism, - tls13_GetHkdfMechanismForHash(hash), CKA_DERIVE, keySize, CKD_NULL, NULL, NULL); + CKM_HKDF_DERIVE, CKA_DERIVE, keySize, CKD_NULL, NULL, NULL); if (!key) { ssl_MapLowLevelError(SSL_ERROR_KEY_EXCHANGE_FAILURE); goto loser; @@ -641,6 +662,7 @@ tls13_UpdateTrafficKeys(sslSocket *ss, SSLSecretDirection direction) strlen(kHkdfLabelTrafficUpdate), tls13_GetHmacMechanism(ss), tls13_GetHashSize(ss), + ss->protocolVariant, &updatedSecret); if (rv != SECSuccess) { return SECFailure; @@ -884,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) { @@ -997,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; } @@ -1068,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; } @@ -1109,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, @@ -1147,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); @@ -1155,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; @@ -1214,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; @@ -1286,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, @@ -1327,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; } @@ -1347,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; @@ -1414,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; @@ -1466,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); @@ -1490,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) { @@ -1679,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. */ @@ -1862,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); @@ -1906,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. */ @@ -1961,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); } @@ -1991,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: @@ -2322,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; } @@ -2339,7 +2453,6 @@ tls13_ReinjectHandshakeTranscript(sslSocket *ss) return SECSuccess; } - static unsigned int ssl_ListCount(PRCList *list) { @@ -2462,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); @@ -2577,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; } @@ -2745,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; } @@ -2757,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) { @@ -2781,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) { @@ -2802,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. */ @@ -3113,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); @@ -3124,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)) { @@ -3139,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 */ @@ -3310,15 +3445,15 @@ 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, - tls13_GetHkdfMechanism(ss), - tls13_GetHashSize(ss), dest); + 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); return SECFailure; @@ -3331,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. */ @@ -3381,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; } @@ -3467,6 +3603,7 @@ tls13_DeriveTrafficKeys(sslSocket *ss, ssl3CipherSpec *spec, NULL, 0, kHkdfPurposeKey, strlen(kHkdfPurposeKey), bulkAlgorithm, keySize, + ss->protocolVariant, &spec->keyMaterial.key); if (rv != SECSuccess) { LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); @@ -3474,9 +3611,21 @@ tls13_DeriveTrafficKeys(sslSocket *ss, ssl3CipherSpec *spec, goto loser; } + if (IS_DTLS(ss) && spec->epoch > 0) { + rv = ssl_CreateMaskingContextInner(spec->version, ss->ssl3.hs.cipher_suite, + ss->protocolVariant, prk, kHkdfPurposeSn, + strlen(kHkdfPurposeSn), &spec->maskContext); + if (rv != SECSuccess) { + LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); + PORT_Assert(0); + goto loser; + } + } + rv = tls13_HkdfExpandLabelRaw(prk, tls13_GetHash(ss), NULL, 0, kHkdfPurposeIv, strlen(kHkdfPurposeIv), + ss->protocolVariant, spec->keyMaterial.iv, ivSize); if (rv != SECSuccess) { LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); @@ -3507,21 +3656,6 @@ tls13_SetSpecRecordVersion(sslSocket *ss, ssl3CipherSpec *spec) SSL_GETPID(), ss->fd, spec, spec->recordVersion)); } -SSLAEADCipher -tls13_GetAead(const ssl3BulkCipherDef *cipherDef) -{ - switch (cipherDef->calg) { - case ssl_calg_aes_gcm: - return tls13_AESGCM; - case ssl_calg_chacha20: - return tls13_ChaCha20Poly1305; - default: - PORT_Assert(PR_FALSE); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return NULL; - } -} - static SECStatus tls13_SetupPendingCipherSpec(sslSocket *ss, ssl3CipherSpec *spec) { @@ -3545,14 +3679,12 @@ tls13_SetupPendingCipherSpec(sslSocket *ss, ssl3CipherSpec *spec) SSL_GETPID(), ss->fd, suite)); spec->cipherDef = ssl_GetBulkCipherDef(ssl_LookupCipherSuiteDef(suite)); - spec->aead = tls13_GetAead(spec->cipherDef); - if (!spec->aead) { - return SECFailure; - } 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); @@ -3571,6 +3703,38 @@ tls13_SetupPendingCipherSpec(sslSocket *ss, ssl3CipherSpec *spec) } /* + * Initialize the cipher context. All TLS 1.3 operations are AEAD, + * so they are all message contexts. + */ +static SECStatus +tls13_InitPendingContext(sslSocket *ss, ssl3CipherSpec *spec) +{ + CK_MECHANISM_TYPE encMechanism; + CK_ATTRIBUTE_TYPE encMode; + SECItem iv; + SSLCipherAlgorithm calg; + + calg = spec->cipherDef->calg; + + encMechanism = ssl3_Alg2Mech(calg); + encMode = CKA_NSS_MESSAGE | ((spec->direction == ssl_secret_write) ? CKA_ENCRYPT : CKA_DECRYPT); + iv.data = NULL; + iv.len = 0; + + /* + * build the context + */ + spec->cipherContext = PK11_CreateContextBySymKey(encMechanism, encMode, + spec->keyMaterial.key, + &iv); + if (!spec->cipherContext) { + ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); + return SECFailure; + } + return SECSuccess; +} + +/* * Called before sending alerts to set up the right key on the client. * We might encounter errors during the handshake where the current * key is ClearText or EarlyApplicationData. This @@ -3649,6 +3813,11 @@ tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch, goto loser; } + rv = tls13_InitPendingContext(ss, spec); + if (rv != SECSuccess) { + goto loser; + } + /* Now that we've set almost everything up, finally cut over. */ specp = (direction == ssl_secret_read) ? &ss->ssl3.crSpec : &ss->ssl3.cwSpec; ssl_GetSpecWriteLock(ss); @@ -3811,100 +3980,113 @@ tls13_DestroyEarlyData(PRCList *list) * See RFC 5288 and https://tools.ietf.org/html/draft-ietf-tls-chacha20-poly1305-04#section-2 */ static void -tls13_WriteNonce(const ssl3KeyMaterial *keys, - const unsigned char *seqNumBuf, unsigned int seqNumLen, - unsigned char *nonce, unsigned int nonceLen) +tls13_WriteNonce(const unsigned char *ivIn, unsigned int ivInLen, + const unsigned char *nonce, unsigned int nonceLen, + unsigned char *ivOut, unsigned int ivOutLen) { size_t i; + unsigned int offset = ivOutLen - nonceLen; - PORT_Assert(nonceLen == 12); - memcpy(nonce, keys->iv, 12); + PORT_Assert(ivInLen <= ivOutLen); + PORT_Assert(nonceLen <= ivOutLen); + PORT_Memset(ivOut, 0, ivOutLen); + PORT_Memcpy(ivOut, ivIn, ivInLen); - /* XOR the last 8 bytes of the IV with the sequence number. */ - PORT_Assert(seqNumLen == 8); - for (i = 0; i < 8; ++i) { - nonce[4 + i] ^= seqNumBuf[i]; + /* XOR the last n bytes of the IV with the nonce (should be a counter). */ + for (i = 0; i < nonceLen; ++i) { + ivOut[offset + i] ^= nonce[i]; } - PRINT_BUF(50, (NULL, "Nonce", nonce, nonceLen)); + PRINT_BUF(50, (NULL, "Nonce", ivOut, ivOutLen)); } -/* Implement the SSLAEADCipher interface defined in sslimpl.h. - * - * That interface takes the additional data (see below) and reinterprets that as - * a sequence number. In TLS 1.3 there is no additional data so this value is - * just the encoded sequence number. +/* Setup the IV for AEAD encrypt. The PKCS #11 module will add the + * counter, but it doesn't know about the DTLS epic, so we add it here. */ -SECStatus -tls13_AEAD(const ssl3KeyMaterial *keys, PRBool doDecrypt, - unsigned char *out, unsigned int *outlen, unsigned int maxout, - const unsigned char *in, unsigned int inlen, - CK_MECHANISM_TYPE mechanism, - unsigned char *aeadParams, unsigned int aeadParamLength) +unsigned int +tls13_SetupAeadIv(PRBool isDTLS, unsigned char *ivOut, unsigned char *ivIn, + unsigned int offset, unsigned int ivLen, DTLSEpoch epoch) { - SECItem param = { - siBuffer, aeadParams, aeadParamLength - }; - - if (doDecrypt) { - return PK11_Decrypt(keys->key, mechanism, ¶m, - out, outlen, maxout, in, inlen); + PORT_Memcpy(ivOut, ivIn, ivLen); + if (isDTLS) { + /* handle the tls 1.2 counter mode case, the epoc is copied + * instead of xored. We accomplish this by clearing ivOut + * before running xor. */ + if (offset >= ivLen) { + ivOut[offset] = ivOut[offset + 1] = 0; + } + ivOut[offset] ^= (unsigned char)(epoch >> BPB) & 0xff; + ivOut[offset + 1] ^= (unsigned char)(epoch)&0xff; + offset += 2; } - return PK11_Encrypt(keys->key, mechanism, ¶m, - out, outlen, maxout, in, inlen); + return offset; } -static SECStatus -tls13_AESGCM(const ssl3KeyMaterial *keys, - PRBool doDecrypt, - unsigned char *out, - unsigned int *outlen, - unsigned int maxout, - const unsigned char *in, - unsigned int inlen, - const unsigned char *additionalData, - unsigned int additionalDataLen) +/* + * Do a single AEAD for TLS. This differs from PK11_AEADOp in the following + * ways. + * 1) If context is not supplied, it treats the operation as a single shot + * and creates a context from symKey and mech. + * 2) It always assumes the tag will be at the end of the buffer + * (in on decrypt, out on encrypt) just like the old single shot. + * 3) If we aren't generating an IV, it uses tls13_WriteNonce to create the + * nonce. + * NOTE is context is supplied, symKey and mech are ignored + */ +SECStatus +tls13_AEAD(PK11Context *context, PRBool decrypt, + CK_GENERATOR_FUNCTION ivGen, unsigned int fixedbits, + const unsigned char *ivIn, unsigned char *ivOut, unsigned int ivLen, + const unsigned char *nonceIn, unsigned int nonceLen, + const unsigned char *aad, unsigned int aadLen, + unsigned char *out, unsigned int *outLen, unsigned int maxout, + unsigned int tagLen, const unsigned char *in, unsigned int inLen) { - CK_GCM_PARAMS gcmParams; - unsigned char nonce[12]; - - PORT_Assert(additionalDataLen >= 8); - memset(&gcmParams, 0, sizeof(gcmParams)); - gcmParams.pIv = nonce; - gcmParams.ulIvLen = sizeof(nonce); - gcmParams.pAAD = (PRUint8 *)(additionalData + 8); - gcmParams.ulAADLen = additionalDataLen - 8; - gcmParams.ulTagBits = 128; /* GCM measures tag length in bits. */ - - tls13_WriteNonce(keys, additionalData, 8, - nonce, sizeof(nonce)); - return tls13_AEAD(keys, doDecrypt, out, outlen, maxout, in, inlen, - CKM_AES_GCM, - (unsigned char *)&gcmParams, sizeof(gcmParams)); -} + unsigned char *tag; + unsigned char iv[MAX_IV_LENGTH]; + unsigned char tagbuf[HASH_LENGTH_MAX]; + SECStatus rv; -static SECStatus -tls13_ChaCha20Poly1305(const ssl3KeyMaterial *keys, PRBool doDecrypt, - unsigned char *out, unsigned int *outlen, unsigned int maxout, - const unsigned char *in, unsigned int inlen, - const unsigned char *additionalData, - unsigned int additionalDataLen) -{ - CK_NSS_AEAD_PARAMS aeadParams; - unsigned char nonce[12]; - - PORT_Assert(additionalDataLen > 8); - memset(&aeadParams, 0, sizeof(aeadParams)); - aeadParams.pNonce = nonce; - aeadParams.ulNonceLen = sizeof(nonce); - aeadParams.pAAD = (PRUint8 *)(additionalData + 8); - aeadParams.ulAADLen = additionalDataLen - 8; - aeadParams.ulTagLen = 16; /* The Poly1305 tag is 16 octets. */ - - tls13_WriteNonce(keys, additionalData, 8, - nonce, sizeof(nonce)); - return tls13_AEAD(keys, doDecrypt, out, outlen, maxout, in, inlen, - CKM_NSS_CHACHA20_POLY1305, - (unsigned char *)&aeadParams, sizeof(aeadParams)); + /* must have either context or the symKey set */ + if (!context) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + PORT_Assert(ivLen <= MAX_IV_LENGTH); + PORT_Assert(tagLen <= HASH_LENGTH_MAX); + if (!ivOut) { + ivOut = iv; /* caller doesn't need a returned, iv */ + } + + if (ivGen == CKG_NO_GENERATE) { + tls13_WriteNonce(ivIn, ivLen, nonceIn, nonceLen, ivOut, ivLen); + } else if (ivIn != ivOut) { + PORT_Memcpy(ivOut, ivIn, ivLen); + } + if (decrypt) { + inLen = inLen - tagLen; + tag = (unsigned char *)in + inLen; + /* tag is const on decrypt, but returned on encrypt */ + } else { + /* tag is written to a separate buffer, then added to the end + * of the actual output buffer. This allows output buffer to be larger + * than the input buffer and everything still work */ + tag = tagbuf; + } + rv = PK11_AEADOp(context, ivGen, fixedbits, ivOut, ivLen, aad, aadLen, + out, (int *)outLen, maxout, tag, tagLen, in, inLen); + /* on encrypt SSL always puts the tag at the end of the buffer */ + if ((rv == SECSuccess) && !(decrypt)) { + unsigned int len = *outLen; + /* make sure there is still space */ + if (len + tagLen > maxout) { + PORT_SetError(SEC_ERROR_OUTPUT_LEN); + return SECFailure; + } + PORT_Memcpy(out + len, tag, tagLen); + *outLen += tagLen; + } + return rv; } static SECStatus @@ -3968,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); @@ -4006,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; } @@ -4285,7 +4471,7 @@ loser: static SECStatus tls13_ComputePskBinderHash(sslSocket *ss, unsigned int prefixLength, - SSL3Hashes *hashes) + SSL3Hashes *hashes, SSLHashType hashType) { SECStatus rv; @@ -4295,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; @@ -4320,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; @@ -4341,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) { @@ -4369,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; @@ -4387,17 +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), &secret); + 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) { @@ -4412,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; @@ -4456,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) { @@ -4493,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); @@ -4583,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); @@ -4646,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; @@ -4929,8 +5135,9 @@ tls13_SendNewSessionTicket(sslSocket *ss, const PRUint8 *appToken, ticketNonce, sizeof(ticketNonce), kHkdfLabelResumption, strlen(kHkdfLabelResumption), - tls13_GetHkdfMechanism(ss), - tls13_GetHashSize(ss), &secret); + CKM_HKDF_DERIVE, + tls13_GetHashSize(ss), + ss->protocolVariant, &secret); if (rv != SECSuccess) { goto loser; } @@ -5028,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); @@ -5163,8 +5378,9 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length) ticket_nonce.data, ticket_nonce.len, kHkdfLabelResumption, strlen(kHkdfLabelResumption), - tls13_GetHkdfMechanism(ss), - tls13_GetHashSize(ss), &secret); + CKM_HKDF_DERIVE, + tls13_GetHashSize(ss), + ss->protocolVariant, &secret); if (rv != SECSuccess) { return SECFailure; } @@ -5348,11 +5564,20 @@ tls13_ProtectRecord(sslSocket *ss, sslBuffer buf = SSL_BUFFER_FIXED(hdr, sizeof(hdr)); PRBool needsLength; PRUint8 aad[21]; + const int ivLen = cipher_def->iv_size + cipher_def->explicit_nonce_size; + unsigned int ivOffset = ivLen - sizeof(sslSequenceNumber); + unsigned char ivOut[MAX_IV_LENGTH]; + unsigned int aadLen; unsigned int len; PORT_Assert(cipher_def->type == type_aead); + /* If the following condition holds, we can skip the padding logic for + * DTLS 1.3 (4.2.3). This will be the case until we support a cipher + * with tag length < 15B. */ + PORT_Assert(tagLen + 1 /* cType */ >= 16); + /* Add the content type at the end. */ *(SSL_BUFFER_NEXT(wrBuf) + contentLen) = type; @@ -5363,9 +5588,7 @@ tls13_ProtectRecord(sslSocket *ss, return SECFailure; } if (needsLength) { - rv = sslBuffer_AppendNumber(&buf, contentLen + 1 + - cwSpec->cipherDef->tag_size, - 2); + rv = sslBuffer_AppendNumber(&buf, contentLen + 1 + tagLen, 2); if (rv != SECSuccess) { return SECFailure; } @@ -5376,14 +5599,22 @@ tls13_ProtectRecord(sslSocket *ss, if (rv != SECSuccess) { return SECFailure; } - rv = cwSpec->aead(&cwSpec->keyMaterial, - PR_FALSE, /* do encrypt */ - SSL_BUFFER_NEXT(wrBuf), /* output */ - &len, /* out len */ - SSL_BUFFER_SPACE(wrBuf), /* max out */ - SSL_BUFFER_NEXT(wrBuf), /* input */ - contentLen + 1, /* input len */ - aad, aadLen); + /* set up initial IV value */ + ivOffset = tls13_SetupAeadIv(IS_DTLS(ss), ivOut, cwSpec->keyMaterial.iv, + ivOffset, ivLen, cwSpec->epoch); + + rv = tls13_AEAD(cwSpec->cipherContext, PR_FALSE, + CKG_GENERATE_COUNTER_XOR, ivOffset * BPB, + ivOut, ivOut, ivLen, /* iv */ + NULL, 0, /* nonce */ + aad + sizeof(sslSequenceNumber), /* aad */ + aadLen - sizeof(sslSequenceNumber), + SSL_BUFFER_NEXT(wrBuf), /* output */ + &len, /* out len */ + SSL_BUFFER_SPACE(wrBuf), /* max out */ + tagLen, + SSL_BUFFER_NEXT(wrBuf), /* input */ + contentLen + 1); /* input len */ if (rv != SECSuccess) { PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE); return SECFailure; @@ -5413,6 +5644,9 @@ tls13_UnprotectRecord(sslSocket *ss, SSL3AlertDescription *alert) { const ssl3BulkCipherDef *cipher_def = spec->cipherDef; + const int ivLen = cipher_def->iv_size + cipher_def->explicit_nonce_size; + const int tagLen = cipher_def->tag_size; + PRUint8 aad[21]; unsigned int aadLen; SECStatus rv; @@ -5440,7 +5674,7 @@ tls13_UnprotectRecord(sslSocket *ss, /* We can perform this test in variable time because the record's total * length and the ciphersuite are both public knowledge. */ - if (cText->buf->len < cipher_def->tag_size) { + if (cText->buf->len < tagLen) { SSL_TRC(3, ("%d: TLS13[%d]: record too short to contain valid AEAD data", SSL_GETPID(), ss->fd)); @@ -5467,17 +5701,26 @@ tls13_UnprotectRecord(sslSocket *ss, spec->epoch, cText->seqNum, aad, &aadLen, sizeof(aad)); if (rv != SECSuccess) { + return SECFailure; } - rv = spec->aead(&spec->keyMaterial, - PR_TRUE, /* do decrypt */ - plaintext->buf, /* out */ + rv = tls13_AEAD(spec->cipherContext, PR_TRUE, + CKG_NO_GENERATE, 0, /* ignored for decrypt */ + spec->keyMaterial.iv, NULL, ivLen, /* iv */ + aad, sizeof(sslSequenceNumber), /* nonce */ + aad + sizeof(sslSequenceNumber), /* aad */ + aadLen - sizeof(sslSequenceNumber), + plaintext->buf, /* output */ &plaintext->len, /* outlen */ plaintext->space, /* maxout */ + tagLen, cText->buf->buf, /* in */ - cText->buf->len, /* inlen */ - aad, aadLen); + 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)); @@ -5538,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(). @@ -5550,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 @@ -5607,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; @@ -5618,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; } @@ -5672,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; @@ -5685,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; @@ -5728,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) { @@ -5763,14 +6047,26 @@ tls13_HandleEarlyApplicationData(sslSocket *ss, sslBuffer *origBuf) } PRUint16 -tls13_EncodeDraftVersion(SSL3ProtocolVersion version, SSLProtocolVariant variant) +tls13_EncodeVersion(SSL3ProtocolVersion version, SSLProtocolVariant variant) { + if (variant == ssl_variant_datagram) { + /* TODO: When DTLS 1.3 is out of draft, replace this with + * dtls_TLSVersionToDTLSVersion(). */ + switch (version) { #ifdef DTLS_1_3_DRAFT_VERSION - if (version == SSL_LIBRARY_VERSION_TLS_1_3 && - variant == ssl_variant_datagram) { - return 0x7f00 | DTLS_1_3_DRAFT_VERSION; - } + case SSL_LIBRARY_VERSION_TLS_1_3: + return 0x7f00 | DTLS_1_3_DRAFT_VERSION; #endif + case SSL_LIBRARY_VERSION_TLS_1_2: + return SSL_LIBRARY_VERSION_DTLS_1_2_WIRE; + case SSL_LIBRARY_VERSION_TLS_1_1: + /* TLS_1_1 maps to DTLS_1_0, see sslproto.h. */ + return SSL_LIBRARY_VERSION_DTLS_1_0_WIRE; + default: + PORT_Assert(0); + } + } + /* Stream-variant encodings do not change. */ return (PRUint16)version; } @@ -5800,8 +6096,8 @@ tls13_ClientReadSupportedVersion(sslSocket *ss) return SECFailure; } - if (temp != tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3, - ss->protocolVariant)) { + if (temp != tls13_EncodeVersion(SSL_LIBRARY_VERSION_TLS_1_3, + ss->protocolVariant)) { /* You cannot negotiate < TLS 1.3 with supported_versions. */ FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_SERVER_HELLO, illegal_parameter); return SECFailure; @@ -5840,7 +6136,7 @@ tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supportedVersions) return SECFailure; } - PRUint16 wire = tls13_EncodeDraftVersion(version, ss->protocolVariant); + PRUint16 wire = tls13_EncodeVersion(version, ss->protocolVariant); unsigned long offset; for (offset = 0; offset < versions.len; offset += 2) { diff --git a/security/nss/lib/ssl/tls13con.h b/security/nss/lib/ssl/tls13con.h index bd309419f..9a3cd14c1 100644 --- a/security/nss/lib/ssl/tls13con.h +++ b/security/nss/lib/ssl/tls13con.h @@ -44,20 +44,22 @@ PRBool tls13_InHsState(sslSocket *ss, ...); PRBool tls13_IsPostHandshake(const sslSocket *ss); -SSLHashType tls13_GetHashForCipherSuite(ssl3CipherSuite suite); SSLHashType tls13_GetHash(const sslSocket *ss); -unsigned int tls13_GetHashSizeForHash(SSLHashType hash); +SECStatus tls13_GetHashAndCipher(PRUint16 version, PRUint16 cipherSuite, + SSLHashType *hash, const ssl3BulkCipherDef **cipher); +SSLHashType tls13_GetHashForCipherSuite(ssl3CipherSuite suite); unsigned int tls13_GetHashSize(const sslSocket *ss); -CK_MECHANISM_TYPE tls13_GetHkdfMechanism(sslSocket *ss); -CK_MECHANISM_TYPE tls13_GetHkdfMechanismForHash(SSLHashType hash); +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); @@ -107,8 +109,8 @@ SECStatus tls13_ProtectRecord(sslSocket *ss, PRInt32 tls13_Read0RttData(sslSocket *ss, PRUint8 *buf, PRInt32 len); SECStatus tls13_HandleEarlyApplicationData(sslSocket *ss, sslBuffer *origBuf); PRBool tls13_ClientAllow0Rtt(const sslSocket *ss, const sslSessionID *sid); -PRUint16 tls13_EncodeDraftVersion(SSL3ProtocolVersion version, - SSLProtocolVariant variant); +PRUint16 tls13_EncodeVersion(SSL3ProtocolVersion version, + SSLProtocolVariant variant); SECStatus tls13_ClientReadSupportedVersion(sslSocket *ss); SECStatus tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supported_versions); @@ -133,12 +135,18 @@ SECStatus tls13_SendKeyUpdate(sslSocket *ss, tls13KeyUpdateRequest request, PRBool buffer); SECStatus SSLExp_KeyUpdate(PRFileDesc *fd, PRBool requestUpdate); PRBool tls13_MaybeTls13(sslSocket *ss); -SSLAEADCipher tls13_GetAead(const ssl3BulkCipherDef *cipherDef); -SECStatus tls13_AEAD(const ssl3KeyMaterial *keys, PRBool doDecrypt, - unsigned char *out, unsigned int *outlen, unsigned int maxout, - const unsigned char *in, unsigned int inlen, - CK_MECHANISM_TYPE mechanism, - unsigned char *aeadParams, unsigned int aeadParamLength); +unsigned int tls13_SetupAeadIv(PRBool isDTLS, unsigned char *ivOut, + unsigned char *ivIn, unsigned int offset, + unsigned int ivLen, DTLSEpoch epoch); +SECStatus tls13_AEAD(PK11Context *context, PRBool decrypt, + CK_GENERATOR_FUNCTION ivGen, unsigned int fixedbits, + const unsigned char *ivIn, unsigned char *ivOut, + unsigned int ivLen, + const unsigned char *nonceIn, unsigned int nonceLen, + const unsigned char *aad, unsigned int aadLen, + unsigned char *out, unsigned int *outLen, + unsigned int maxout, unsigned int tagLen, + const unsigned char *in, unsigned int inLen); void tls13_SetSpecRecordVersion(sslSocket *ss, ssl3CipherSpec *spec); SECStatus SSLExp_SendCertificateRequest(PRFileDesc *fd); diff --git a/security/nss/lib/ssl/tls13esni.c b/security/nss/lib/ssl/tls13esni.c index f2f8d0a9c..7182f22af 100644 --- a/security/nss/lib/ssl/tls13esni.c +++ b/security/nss/lib/ssl/tls13esni.c @@ -550,7 +550,7 @@ tls13_ComputeESNIKeys(const sslSocket *ss, hash, hashSize, kHkdfPurposeEsniKey, strlen(kHkdfPurposeEsniKey), ssl3_Alg2Mech(cipherDef->calg), - keySize, + keySize, ss->protocolVariant, &keyMat->key); if (rv != SECSuccess) { goto loser; @@ -558,7 +558,7 @@ tls13_ComputeESNIKeys(const sslSocket *ss, rv = tls13_HkdfExpandLabelRaw(Zx, suite->prf_hash, hash, hashSize, kHkdfPurposeEsniIv, strlen(kHkdfPurposeEsniIv), - keyMat->iv, ivSize); + ss->protocolVariant, keyMat->iv, ivSize); if (rv != SECSuccess) { goto loser; } @@ -662,12 +662,6 @@ tls13_FormatEsniAADInput(sslBuffer *aadInput, { SECStatus rv; - /* 8 bytes of 0 for the sequence number. */ - rv = sslBuffer_AppendNumber(aadInput, 0, 8); - if (rv != SECSuccess) { - return SECFailure; - } - /* Key share. */ PORT_Assert(keyShareLen > 0); rv = sslBuffer_Append(aadInput, keyShare, keyShareLen); @@ -680,12 +674,10 @@ tls13_FormatEsniAADInput(sslBuffer *aadInput, static SECStatus tls13_ServerGetEsniAEAD(const sslSocket *ss, PRUint64 suite, - const ssl3CipherSuiteDef **suiteDefp, - SSLAEADCipher *aeadp) + const ssl3CipherSuiteDef **suiteDefp) { SECStatus rv; const ssl3CipherSuiteDef *suiteDef; - SSLAEADCipher aead; /* Check against the suite list for ESNI */ PRBool csMatch = PR_FALSE; @@ -712,13 +704,8 @@ tls13_ServerGetEsniAEAD(const sslSocket *ss, PRUint64 suite, if (!suiteDef) { return SECFailure; } - aead = tls13_GetAead(ssl_GetBulkCipherDef(suiteDef)); - if (!aead) { - return SECFailure; - } *suiteDefp = suiteDef; - *aeadp = aead; return SECSuccess; } @@ -729,7 +716,6 @@ tls13_ServerDecryptEsniXtn(const sslSocket *ss, const PRUint8 *in, unsigned int sslReader rdr = SSL_READER(in, inLen); PRUint64 suite; const ssl3CipherSuiteDef *suiteDef = NULL; - SSLAEADCipher aead = NULL; TLSExtension *keyShareExtension; TLS13KeyShareEntry *entry = NULL; ssl3KeyMaterial keyMat = { NULL }; @@ -748,7 +734,7 @@ tls13_ServerDecryptEsniXtn(const sslSocket *ss, const PRUint8 *in, unsigned int } /* Find the AEAD */ - rv = tls13_ServerGetEsniAEAD(ss, suite, &suiteDef, &aead); + rv = tls13_ServerGetEsniAEAD(ss, suite, &suiteDef); if (rv != SECSuccess) { goto loser; } @@ -822,11 +808,25 @@ tls13_ServerDecryptEsniXtn(const sslSocket *ss, const PRUint8 *in, unsigned int goto loser; } - rv = aead(&keyMat, PR_TRUE /* Decrypt */, - out, outLen, maxLen, - buf.buf, buf.len, - SSL_BUFFER_BASE(&aadInput), - SSL_BUFFER_LEN(&aadInput)); + const ssl3BulkCipherDef *cipher_def = ssl_GetBulkCipherDef(suiteDef); + unsigned char *aad = SSL_BUFFER_BASE(&aadInput); + int aadLen = SSL_BUFFER_LEN(&aadInput); + int ivLen = cipher_def->iv_size + cipher_def->explicit_nonce_size; + SSLCipherAlgorithm calg = cipher_def->calg; + unsigned char zero[sizeof(sslSequenceNumber)] = { 0 }; + SECItem null_params = { siBuffer, NULL, 0 }; + PK11Context *ctxt = PK11_CreateContextBySymKey(ssl3_Alg2Mech(calg), + CKA_NSS_MESSAGE | CKA_DECRYPT, + keyMat.key, &null_params); + if (!ctxt) { + sslBuffer_Clear(&aadInput); + goto loser; + } + + rv = tls13_AEAD(ctxt, PR_TRUE /* Decrypt */, CKG_NO_GENERATE, 0, + keyMat.iv, NULL, ivLen, zero, sizeof(zero), aad, aadLen, + out, outLen, maxLen, cipher_def->tag_size, buf.buf, buf.len); + PK11_DestroyContext(ctxt, PR_TRUE); sslBuffer_Clear(&aadInput); if (rv != SECSuccess) { goto loser; diff --git a/security/nss/lib/ssl/tls13exthandle.c b/security/nss/lib/ssl/tls13exthandle.c index 1f88016a1..5c3930ac2 100644 --- a/security/nss/lib/ssl/tls13exthandle.c +++ b/security/nss/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; } @@ -789,12 +850,27 @@ tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnD } for (version = ss->vrange.max; version >= ss->vrange.min; --version) { - PRUint16 wire = tls13_EncodeDraftVersion(version, - ss->protocolVariant); + PRUint16 wire = tls13_EncodeVersion(version, + ss->protocolVariant); rv = sslBuffer_AppendNumber(buf, wire, 2); if (rv != SECSuccess) { return SECFailure; } + + if (ss->opt.enableDtls13VersionCompat && + ss->protocolVariant == ssl_variant_datagram) { + switch (version) { + case SSL_LIBRARY_VERSION_TLS_1_2: + case SSL_LIBRARY_VERSION_TLS_1_1: + rv = sslBuffer_AppendNumber(buf, (PRUint16)version, 2); + break; + default: + continue; + } + if (rv != SECSuccess) { + return SECFailure; + } + } } rv = sslBuffer_InsertLength(buf, lengthOffset, 1); @@ -819,8 +895,8 @@ tls13_ServerSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnD SSL_TRC(3, ("%d: TLS13[%d]: server send supported_versions extension", SSL_GETPID(), ss->fd)); - PRUint16 ver = tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3, - ss->protocolVariant); + PRUint16 ver = tls13_EncodeVersion(SSL_LIBRARY_VERSION_TLS_1_3, + ss->protocolVariant); rv = sslBuffer_AppendNumber(buf, ver, 2); if (rv != SECSuccess) { return SECFailure; @@ -921,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; } @@ -941,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; } @@ -1139,7 +1222,6 @@ tls13_ClientSendEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData, sslBuffer sni = SSL_BUFFER(sniBuf); const ssl3CipherSuiteDef *suiteDef; ssl3KeyMaterial keyMat; - SSLAEADCipher aead; PRUint8 outBuf[1024]; unsigned int outLen; unsigned int sniStart; @@ -1190,10 +1272,6 @@ tls13_ClientSendEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData, PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - aead = tls13_GetAead(ssl_GetBulkCipherDef(suiteDef)); - if (!aead) { - return SECFailure; - } /* Format the first part of the extension so we have the * encoded KeyShareEntry. */ @@ -1251,15 +1329,33 @@ tls13_ClientSendEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData, ssl_DestroyKeyMaterial(&keyMat); return SECFailure; } + /* Now encrypt. */ - rv = aead(&keyMat, PR_FALSE /* Encrypt */, - outBuf, &outLen, sizeof(outBuf), - SSL_BUFFER_BASE(&sni), - SSL_BUFFER_LEN(&sni), - SSL_BUFFER_BASE(&aadInput), - SSL_BUFFER_LEN(&aadInput)); + unsigned char *aad = SSL_BUFFER_BASE(&aadInput); + int aadLen = SSL_BUFFER_LEN(&aadInput); + const ssl3BulkCipherDef *cipher_def = ssl_GetBulkCipherDef(suiteDef); + int ivLen = cipher_def->iv_size + cipher_def->explicit_nonce_size; + unsigned char zero[sizeof(sslSequenceNumber)] = { 0 }; + SSLCipherAlgorithm calg = cipher_def->calg; + SECItem null_params = { siBuffer, NULL, 0 }; + PK11Context *ctxt = PK11_CreateContextBySymKey(ssl3_Alg2Mech(calg), + CKA_NSS_MESSAGE | CKA_ENCRYPT, + keyMat.key, &null_params); + if (!ctxt) { + ssl_DestroyKeyMaterial(&keyMat); + sslBuffer_Clear(&aadInput); + return SECFailure; + } + + /* This function is a single shot, with fresh/unique keys, no need to + * generate the IV internally */ + rv = tls13_AEAD(ctxt, PR_FALSE /* Encrypt */, CKG_NO_GENERATE, 0, + keyMat.iv, NULL, ivLen, zero, sizeof(zero), aad, aadLen, + outBuf, &outLen, sizeof(outBuf), cipher_def->tag_size, + SSL_BUFFER_BASE(&sni), SSL_BUFFER_LEN(&sni)); ssl_DestroyKeyMaterial(&keyMat); sslBuffer_Clear(&aadInput); + PK11_DestroyContext(ctxt, PR_TRUE); if (rv != SECSuccess) { return SECFailure; } @@ -1403,21 +1499,59 @@ tls13_ClientCheckEsniXtn(sslSocket *ss) } /* Indicates support for the delegated credentials extension. This should be - * hooked while processing the ClientHello. - */ + * hooked while processing the ClientHello. */ SECStatus tls13_ClientSendDelegatedCredentialsXtn(const sslSocket *ss, TLSExtensionData *xtnData, sslBuffer *buf, PRBool *added) { /* Only send the extension if support is enabled and the client can - * negotiate TLS 1.3. - */ + * negotiate TLS 1.3. */ if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3 || !ss->opt.enableDelegatedCredentials) { return SECSuccess; } + /* Filter the schemes that are enabled and acceptable. Save these in + * the "advertised" list, then encode them to be sent. If we receive + * a DC in response, validate that it matches one of the advertised + * schemes. */ + SSLSignatureScheme filtered[MAX_SIGNATURE_SCHEMES] = { 0 }; + unsigned int filteredCount = 0; + SECStatus rv = ssl3_FilterSigAlgs(ss, ss->vrange.max, + PR_TRUE /* disableRsae */, + PR_FALSE /* forCert */, + MAX_SIGNATURE_SCHEMES, + filtered, + &filteredCount); + if (rv != SECSuccess) { + return SECFailure; + } + + /* If no schemes available for the DC extension, don't send it. */ + if (!filteredCount) { + return SECSuccess; + } + + rv = ssl3_EncodeFilteredSigAlgs(ss, filtered, filteredCount, buf); + if (rv != SECSuccess) { + return SECFailure; + } + + SSLSignatureScheme *dcSchemesAdvertised = PORT_ZNewArray(SSLSignatureScheme, + filteredCount); + if (!dcSchemesAdvertised) { + return SECFailure; + } + for (unsigned int i = 0; i < filteredCount; i++) { + dcSchemesAdvertised[i] = filtered[i]; + } + + if (xtnData->delegCredSigSchemesAdvertised) { + PORT_Free(xtnData->delegCredSigSchemesAdvertised); + } + xtnData->delegCredSigSchemesAdvertised = dcSchemesAdvertised; + xtnData->numDelegCredSigSchemesAdvertised = filteredCount; *added = PR_TRUE; return SECSuccess; } @@ -1441,15 +1575,59 @@ tls13_ClientHandleDelegatedCredentialsXtn(const sslSocket *ss, return SECFailure; } - SECStatus rv = tls13_ReadDelegatedCredential(data->data, data->len, - &xtnData->peerDelegCred); + sslDelegatedCredential *dc = NULL; + SECStatus rv = tls13_ReadDelegatedCredential(data->data, data->len, &dc); if (rv != SECSuccess) { - return SECFailure; /* code already set */ + goto loser; /* code already set */ + } + + /* When using RSA, the public key MUST NOT use the rsaEncryption OID. */ + if (dc->expectedCertVerifyAlg == ssl_sig_rsa_pss_rsae_sha256 || + dc->expectedCertVerifyAlg == ssl_sig_rsa_pss_rsae_sha384 || + dc->expectedCertVerifyAlg == ssl_sig_rsa_pss_rsae_sha512) { + goto alert_loser; + } + + /* The algorithm and expected_cert_verify_algorithm fields MUST be of a + * type advertised by the client in the SignatureSchemeList and are + * considered invalid otherwise. Clients that receive invalid delegated + * credentials MUST terminate the connection with an "illegal_parameter" + * alert. */ + PRBool found = PR_FALSE; + for (unsigned int i = 0; i < ss->xtnData.numDelegCredSigSchemesAdvertised; ++i) { + if (dc->expectedCertVerifyAlg == ss->xtnData.delegCredSigSchemesAdvertised[i]) { + found = PR_TRUE; + break; + } + } + if (found == PR_FALSE) { + goto alert_loser; + } + + // Check the dc->alg, if necessary. + if (dc->alg != dc->expectedCertVerifyAlg) { + found = PR_FALSE; + for (unsigned int i = 0; i < ss->xtnData.numDelegCredSigSchemesAdvertised; ++i) { + if (dc->alg == ss->xtnData.delegCredSigSchemesAdvertised[i]) { + found = PR_TRUE; + break; + } + } + if (found == PR_FALSE) { + goto alert_loser; + } } + xtnData->peerDelegCred = dc; xtnData->negotiated[xtnData->numNegotiated++] = ssl_delegated_credentials_xtn; return SECSuccess; +alert_loser: + ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter); + PORT_SetError(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM); +loser: + tls13_DestroyDelegatedCredential(dc); + return SECFailure; } /* Adds the DC extension if we're committed to authenticating with a DC. */ @@ -1460,19 +1638,13 @@ tls13_ServerSendDelegatedCredentialsXtn(const sslSocket *ss, { if (tls13_IsSigningWithDelegatedCredential(ss)) { const SECItem *dc = &ss->sec.serverCert->delegCred; - - if (tls13_IsSigningWithDelegatedCredential(ss)) { - SECStatus rv; - rv = sslBuffer_Append(buf, dc->data, dc->len); - if (rv != SECSuccess) { - return SECFailure; - } + SECStatus rv; + rv = sslBuffer_Append(buf, dc->data, dc->len); + if (rv != SECSuccess) { + return SECFailure; } - *added = PR_TRUE; - return SECSuccess; } - return SECSuccess; } @@ -1484,6 +1656,33 @@ tls13_ServerHandleDelegatedCredentialsXtn(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data) { + if (xtnData->delegCredSigSchemes) { + PORT_Free(xtnData->delegCredSigSchemes); + xtnData->delegCredSigSchemes = NULL; + xtnData->numDelegCredSigSchemes = 0; + } + SECStatus rv = ssl_ParseSignatureSchemes(ss, NULL, + &xtnData->delegCredSigSchemes, + &xtnData->numDelegCredSigSchemes, + &data->data, &data->len); + if (rv != SECSuccess) { + ssl3_ExtSendAlert(ss, alert_fatal, decode_error); + PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); + return SECFailure; + } + if (xtnData->numDelegCredSigSchemes == 0) { + ssl3_ExtSendAlert(ss, alert_fatal, handshake_failure); + PORT_SetError(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM); + return SECFailure; + } + /* Check for trailing data. */ + if (data->len != 0) { + ssl3_ExtSendAlert(ss, alert_fatal, decode_error); + PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); + return SECFailure; + } + + /* Keep track of negotiated extensions. */ xtnData->peerRequestedDelegCred = PR_TRUE; xtnData->negotiated[xtnData->numNegotiated++] = ssl_delegated_credentials_xtn; diff --git a/security/nss/lib/ssl/tls13hkdf.c b/security/nss/lib/ssl/tls13hkdf.c index ab546e06f..ed6cdd559 100644 --- a/security/nss/lib/ssl/tls13hkdf.c +++ b/security/nss/lib/ssl/tls13hkdf.c @@ -25,52 +25,74 @@ static const struct { { ssl_hash_md5, 0, 0 }, { ssl_hash_sha1, 0, 0 }, { ssl_hash_sha224, 0 }, - { ssl_hash_sha256, CKM_NSS_HKDF_SHA256, 32 }, - { ssl_hash_sha384, CKM_NSS_HKDF_SHA384, 48 }, - { ssl_hash_sha512, CKM_NSS_HKDF_SHA512, 64 } + { ssl_hash_sha256, CKM_SHA256, 32 }, + { ssl_hash_sha384, CKM_SHA384, 48 }, + { ssl_hash_sha512, CKM_SHA512, 64 } }; SECStatus -tls13_HkdfExtract(PK11SymKey *ikm1, PK11SymKey *ikm2in, SSLHashType baseHash, +tls13_HkdfExtract(PK11SymKey *ikm1, PK11SymKey *ikm2, SSLHashType baseHash, PK11SymKey **prkp) { - CK_NSS_HKDFParams params; + CK_HKDF_PARAMS params; SECItem paramsi; - SECStatus rv; - SECItem *salt; PK11SymKey *prk; static const PRUint8 zeroKeyBuf[HASH_LENGTH_MAX]; - PK11SymKey *zeroKey = NULL; + SECItem zeroKeyItem = { siBuffer, CONST_CAST(PRUint8, zeroKeyBuf), kTlsHkdfInfo[baseHash].hashSize }; PK11SlotInfo *slot = NULL; - PK11SymKey *ikm2; + PK11SymKey *newIkm2 = NULL; + PK11SymKey *newIkm1 = NULL; + SECStatus rv; params.bExtract = CK_TRUE; params.bExpand = CK_FALSE; + params.prfHashMechanism = kTlsHkdfInfo[baseHash].pkcs11Mech; params.pInfo = NULL; params.ulInfoLen = 0UL; + params.pSalt = NULL; + params.ulSaltLen = 0UL; + params.hSaltKey = CK_INVALID_HANDLE; - if (ikm1) { - /* TODO(ekr@rtfm.com): This violates the PKCS#11 key boundary - * but is imposed on us by the present HKDF interface. */ - rv = PK11_ExtractKeyValue(ikm1); - if (rv != SECSuccess) - return rv; - - salt = PK11_GetKeyData(ikm1); - if (!salt) - return SECFailure; - - params.pSalt = salt->data; - params.ulSaltLen = salt->len; - PORT_Assert(salt->len > 0); + if (!ikm1) { + /* PKCS #11 v3.0 has and explict NULL value, which equates to + * a sequence of zeros equal in length to the HMAC. */ + params.ulSaltType = CKF_HKDF_SALT_NULL; } else { - /* Per documentation for CKM_NSS_HKDF_*: - * - * If the optional salt is given, it is used; otherwise, the salt is - * set to a sequence of zeros equal in length to the HMAC output. - */ - params.pSalt = NULL; - params.ulSaltLen = 0UL; + /* PKCS #11 v3.0 can take the salt as a key handle */ + params.hSaltKey = PK11_GetSymKeyHandle(ikm1); + params.ulSaltType = CKF_HKDF_SALT_KEY; + + /* if we have both keys, make sure they are in the same slot */ + if (ikm2) { + rv = PK11_SymKeysToSameSlot(CKM_HKDF_DERIVE, + CKA_DERIVE, CKA_DERIVE, + ikm2, ikm1, &newIkm2, &newIkm1); + if (rv != SECSuccess) { + SECItem *salt; + /* couldn't move the keys, try extracting the salt */ + rv = PK11_ExtractKeyValue(ikm1); + if (rv != SECSuccess) + return rv; + salt = PK11_GetKeyData(ikm1); + if (!salt) + return SECFailure; + PORT_Assert(salt->len > 0); + /* Set up for Salt as Data instead of Salt as key */ + params.pSalt = salt->data; + params.ulSaltLen = salt->len; + params.ulSaltType = CKF_HKDF_SALT_DATA; + } + /* use the new keys */ + if (newIkm1) { + /* we've moved the key, get the handle for the new key */ + params.hSaltKey = PK11_GetSymKeyHandle(newIkm1); + /* we don't use ikm1 after this, so don't bother setting it */ + } + if (newIkm2) { + /* new ikm2 key, use the new key */ + ikm2 = newIkm2; + } + } } paramsi.data = (unsigned char *)¶ms; paramsi.len = sizeof(params); @@ -80,40 +102,34 @@ tls13_HkdfExtract(PK11SymKey *ikm1, PK11SymKey *ikm2in, SSLHashType baseHash, PORT_Assert(kTlsHkdfInfo[baseHash].hash == baseHash); /* A zero ikm2 is a key of hash-length 0s. */ - if (!ikm2in) { - SECItem zeroItem = { - siBuffer, - (unsigned char *)zeroKeyBuf, - kTlsHkdfInfo[baseHash].hashSize - }; - slot = PK11_GetInternalSlot(); + if (!ikm2) { + /* 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; } - zeroKey = PK11_ImportSymKey(slot, - kTlsHkdfInfo[baseHash].pkcs11Mech, - PK11_OriginUnwrap, - CKA_DERIVE, &zeroItem, NULL); - if (!zeroKey) + + newIkm2 = PK11_ImportDataKey(slot, CKM_HKDF_DERIVE, PK11_OriginUnwrap, + CKA_DERIVE, &zeroKeyItem, NULL); + if (!newIkm2) { return SECFailure; - ikm2 = zeroKey; - } else { - ikm2 = ikm2in; + } + ikm2 = newIkm2; } PORT_Assert(ikm2); PRINT_BUF(50, (NULL, "HKDF Extract: IKM1/Salt", params.pSalt, params.ulSaltLen)); PRINT_KEY(50, (NULL, "HKDF Extract: IKM2", ikm2)); - prk = PK11_Derive(ikm2, kTlsHkdfInfo[baseHash].pkcs11Mech, - ¶msi, kTlsHkdfInfo[baseHash].pkcs11Mech, - CKA_DERIVE, kTlsHkdfInfo[baseHash].hashSize); - if (zeroKey) - PK11_FreeSymKey(zeroKey); + prk = PK11_Derive(ikm2, CKM_HKDF_DERIVE, ¶msi, CKM_HKDF_DERIVE, + CKA_DERIVE, 0); + PK11_FreeSymKey(newIkm2); + PK11_FreeSymKey(newIkm1); if (slot) PK11_FreeSlot(slot); - if (!prk) + if (!prk) { return SECFailure; + } PRINT_KEY(50, (NULL, "HKDF Extract", prk)); *prkp = prk; @@ -122,13 +138,14 @@ tls13_HkdfExtract(PK11SymKey *ikm1, PK11SymKey *ikm2in, SSLHashType baseHash, } SECStatus -tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash, - const PRUint8 *handshakeHash, unsigned int handshakeHashLen, - const char *label, unsigned int labelLen, - CK_MECHANISM_TYPE algorithm, unsigned int keySize, - PK11SymKey **keyp) +tls13_HkdfExpandLabelGeneral(CK_MECHANISM_TYPE deriveMech, PK11SymKey *prk, + SSLHashType baseHash, + const PRUint8 *handshakeHash, unsigned int handshakeHashLen, + const char *label, unsigned int labelLen, + CK_MECHANISM_TYPE algorithm, unsigned int keySize, + SSLProtocolVariant variant, PK11SymKey **keyp) { - CK_NSS_HKDFParams params; + CK_HKDF_PARAMS params; SECItem paramsi = { siBuffer, NULL, 0 }; /* Size of info array needs to be big enough to hold the maximum Prefix, * Label, plus HandshakeHash. If it's ever to small, the code will abort. @@ -137,8 +154,12 @@ tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash, sslBuffer infoBuf = SSL_BUFFER(info); PK11SymKey *derived; SECStatus rv; - const char *kLabelPrefix = "tls13 "; - const unsigned int kLabelPrefixLen = strlen(kLabelPrefix); + const char *kLabelPrefixTls = "tls13 "; + const char *kLabelPrefixDtls = "dtls13"; + const unsigned int kLabelPrefixLen = + (variant == ssl_variant_stream) ? strlen(kLabelPrefixTls) : strlen(kLabelPrefixDtls); + const char *kLabelPrefix = + (variant == ssl_variant_stream) ? kLabelPrefixTls : kLabelPrefixDtls; PORT_Assert(prk); PORT_Assert(keyp); @@ -192,17 +213,18 @@ tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash, params.bExtract = CK_FALSE; params.bExpand = CK_TRUE; + params.prfHashMechanism = kTlsHkdfInfo[baseHash].pkcs11Mech; params.pInfo = SSL_BUFFER_BASE(&infoBuf); params.ulInfoLen = SSL_BUFFER_LEN(&infoBuf); paramsi.data = (unsigned char *)¶ms; paramsi.len = sizeof(params); - - derived = PK11_DeriveWithFlags(prk, kTlsHkdfInfo[baseHash].pkcs11Mech, + derived = PK11_DeriveWithFlags(prk, deriveMech, ¶msi, algorithm, CKA_DERIVE, keySize, CKF_SIGN | CKF_VERIFY); - if (!derived) + if (!derived) { return SECFailure; + } *keyp = derived; @@ -226,19 +248,34 @@ tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash, } SECStatus +tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash, + const PRUint8 *handshakeHash, unsigned int handshakeHashLen, + const char *label, unsigned int labelLen, + CK_MECHANISM_TYPE algorithm, unsigned int keySize, + SSLProtocolVariant variant, PK11SymKey **keyp) +{ + return tls13_HkdfExpandLabelGeneral(CKM_HKDF_DERIVE, prk, baseHash, + handshakeHash, handshakeHashLen, + label, labelLen, algorithm, keySize, + variant, keyp); +} + +SECStatus tls13_HkdfExpandLabelRaw(PK11SymKey *prk, SSLHashType baseHash, const PRUint8 *handshakeHash, unsigned int handshakeHashLen, const char *label, unsigned int labelLen, - unsigned char *output, unsigned int outputLen) + SSLProtocolVariant variant, unsigned char *output, + unsigned int outputLen) { PK11SymKey *derived = NULL; SECItem *rawkey; SECStatus rv; - rv = tls13_HkdfExpandLabel(prk, baseHash, handshakeHash, handshakeHashLen, - label, labelLen, - kTlsHkdfInfo[baseHash].pkcs11Mech, outputLen, - &derived); + /* the result is not really a key, it's a data object */ + rv = tls13_HkdfExpandLabelGeneral(CKM_HKDF_DATA, prk, baseHash, + handshakeHash, handshakeHashLen, + label, labelLen, CKM_HKDF_DERIVE, outputLen, + variant, &derived); if (rv != SECSuccess || !derived) { goto abort; } diff --git a/security/nss/lib/ssl/tls13hkdf.h b/security/nss/lib/ssl/tls13hkdf.h index 78347a11d..00e5ff1dd 100644 --- a/security/nss/lib/ssl/tls13hkdf.h +++ b/security/nss/lib/ssl/tls13hkdf.h @@ -23,13 +23,14 @@ SECStatus tls13_HkdfExpandLabelRaw( PK11SymKey *prk, SSLHashType baseHash, const PRUint8 *handshakeHash, unsigned int handshakeHashLen, const char *label, unsigned int labelLen, - unsigned char *output, unsigned int outputLen); + SSLProtocolVariant variant, unsigned char *output, + unsigned int outputLen); SECStatus tls13_HkdfExpandLabel( PK11SymKey *prk, SSLHashType baseHash, const PRUint8 *handshakeHash, unsigned int handshakeHashLen, const char *label, unsigned int labelLen, CK_MECHANISM_TYPE algorithm, unsigned int keySize, - PK11SymKey **keyp); + SSLProtocolVariant variant, PK11SymKey **keyp); #ifdef __cplusplus } diff --git a/security/nss/lib/ssl/tls13psk.c b/security/nss/lib/ssl/tls13psk.c new file mode 100644 index 000000000..7343c5a6f --- /dev/null +++ b/security/nss/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/security/nss/lib/ssl/tls13psk.h b/security/nss/lib/ssl/tls13psk.h new file mode 100644 index 000000000..73013fb9b --- /dev/null +++ b/security/nss/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/security/nss/lib/ssl/tls13replay.c b/security/nss/lib/ssl/tls13replay.c index 628011144..7e00785e0 100644 --- a/security/nss/lib/ssl/tls13replay.c +++ b/security/nss/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) { @@ -75,26 +75,17 @@ tls13_RefAntiReplayContext(SSLAntiReplayContext *ctx) static SECStatus tls13_AntiReplayKeyGen(SSLAntiReplayContext *ctx) { - PRUint8 buf[32]; - SECItem keyItem = { siBuffer, buf, sizeof(buf) }; PK11SlotInfo *slot; - SECStatus rv; PORT_Assert(ctx); - slot = PK11_GetInternalSlot(); + slot = PK11_GetBestSlot(CKM_HKDF_DERIVE, NULL); if (!slot) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - rv = PK11_GenerateRandomOnSlot(slot, buf, sizeof(buf)); - if (rv != SECSuccess) { - goto loser; - } - ctx->key = PK11_ImportSymKey(slot, CKM_NSS_HKDF_SHA256, - PK11_OriginUnwrap, CKA_DERIVE, - &keyItem, NULL); + ctx->key = PK11_KeyGen(slot, CKM_HKDF_KEY_GEN, NULL, 32, NULL); if (!ctx->key) { goto loser; } @@ -259,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; } @@ -269,7 +262,7 @@ tls13_IsReplay(const sslSocket *ss, const sslSessionID *sid) ss->xtnData.pskBinder.data, ss->xtnData.pskBinder.len, label, strlen(label), - buf, size); + ss->protocolVariant, buf, size); if (rv != SECSuccess) { return PR_TRUE; } diff --git a/security/nss/lib/ssl/tls13subcerts.c b/security/nss/lib/ssl/tls13subcerts.c index 8ae5447f7..6f164c302 100644 --- a/security/nss/lib/ssl/tls13subcerts.c +++ b/security/nss/lib/ssl/tls13subcerts.c @@ -7,6 +7,7 @@ #include "nss.h" #include "pk11func.h" #include "secder.h" +#include "sechash.h" #include "ssl.h" #include "sslproto.h" #include "sslimpl.h" @@ -148,9 +149,7 @@ tls13_GetExpectedCertVerifyAlg(SECItem in, SSLSignatureScheme *certVerifyAlg) PRBool tls13_IsVerifyingWithDelegatedCredential(const sslSocket *ss) { - /* As of draft-ietf-subcerts-03, only the server may authenticate itself - * with a DC. - */ + /* We currently do not support client-delegated credentials. */ if (ss->sec.isServer || !ss->opt.enableDelegatedCredentials || !ss->xtnData.peerDelegCred) { @@ -191,20 +190,21 @@ tls13_MaybeSetDelegatedCredential(sslSocket *ss) SECKEYPrivateKey *priv; SSLSignatureScheme scheme; - /* Assert that the host is the server (as of draft-ietf-subcerts-03, only - * the server may authenticate itself with a DC), the certificate has been + /* Assert that the host is the server (we do not currently support + * client-delegated credentials), the certificate has been * chosen, TLS 1.3 or higher has been negotiated, and that the set of * signature schemes supported by the client is known. */ PORT_Assert(ss->sec.isServer); PORT_Assert(ss->sec.serverCert); PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); - PORT_Assert(ss->xtnData.sigSchemes); + PORT_Assert(ss->xtnData.peerRequestedDelegCred == !!ss->xtnData.delegCredSigSchemes); /* Check that the peer has indicated support and that a DC has been * configured for the selected certificate. */ if (!ss->xtnData.peerRequestedDelegCred || + !ss->xtnData.delegCredSigSchemes || !ss->sec.serverCert->delegCred.len || !ss->sec.serverCert->delegCredKeyPair) { return SECSuccess; @@ -227,8 +227,8 @@ tls13_MaybeSetDelegatedCredential(sslSocket *ss) if (!ssl_SignatureSchemeEnabled(ss, scheme) || !ssl_CanUseSignatureScheme(scheme, - ss->xtnData.sigSchemes, - ss->xtnData.numSigSchemes, + ss->xtnData.delegCredSigSchemes, + ss->xtnData.numDelegCredSigSchemes, PR_FALSE /* requireSha1 */, doesRsaPss)) { return SECSuccess; @@ -379,6 +379,12 @@ tls13_VerifyCredentialSignature(sslSocket *ss, sslDelegatedCredential *dc) goto loser; } + SECOidTag spkiAlg = SECOID_GetAlgorithmTag(&(dc->spki->algorithm)); + if (spkiAlg == SEC_OID_PKCS1_RSA_ENCRYPTION) { + FATAL_ERROR(ss, SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, illegal_parameter); + goto loser; + } + SECKEY_DestroyPublicKey(pubKey); sslBuffer_Clear(&dcBuf); return SECSuccess; @@ -434,8 +440,10 @@ static SECStatus tls13_CheckCredentialExpiration(sslSocket *ss, sslDelegatedCredential *dc) { SECStatus rv; - PRTime start, end /* microseconds */; CERTCertificate *cert = ss->sec.peerCert; + /* 7 days in microseconds */ + static const PRTime kMaxDcValidity = ((PRTime)7 * 24 * 60 * 60 * PR_USEC_PER_SEC); + PRTime start, now, end; /* microseconds */ rv = DER_DecodeTimeChoice(&start, &cert->validity.notBefore); if (rv != SECSuccess) { @@ -444,11 +452,18 @@ tls13_CheckCredentialExpiration(sslSocket *ss, sslDelegatedCredential *dc) } end = start + ((PRTime)dc->validTime * PR_USEC_PER_SEC); - if (ssl_Time(ss) > end) { + now = ssl_Time(ss); + if (now > end || end < 0) { FATAL_ERROR(ss, SSL_ERROR_DC_EXPIRED, illegal_parameter); return SECFailure; } + /* Not more than 7 days remaining in the validity period. */ + if (end - now > kMaxDcValidity) { + FATAL_ERROR(ss, SSL_ERROR_DC_INAPPROPRIATE_VALIDITY_PERIOD, illegal_parameter); + return SECFailure; + } + return SECSuccess; } @@ -456,7 +471,8 @@ tls13_CheckCredentialExpiration(sslSocket *ss, sslDelegatedCredential *dc) * returns SECFailure. A valid DC meets three requirements: (1) the signature * was produced by the peer's end-entity certificate, (2) the end-entity * certificate must have the correct key usage, and (3) the DC must not be - * expired. + * expired and its remaining TTL must be <= the maximum validity period (fixed + * as 7 days). * * This function calls FATAL_ERROR() when an error occurs. */ @@ -538,6 +554,15 @@ tls13_MakePssSpki(const SECKEYPublicKey *pub, SECOidTag hashOid) goto loser; /* Code already set. */ } + /* Always include saltLength: all hashes are larger than 20. */ + unsigned int saltLength = HASH_ResultLenByOidTag(hashOid); + PORT_Assert(saltLength > 20); + if (!SEC_ASN1EncodeInteger(arena, ¶ms.saltLength, saltLength)) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + goto loser; + } + /* Omit the trailerField always. */ + SECItem *algorithmItem = SEC_ASN1EncodeItem(arena, NULL, ¶ms, SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate)); @@ -551,8 +576,6 @@ tls13_MakePssSpki(const SECKEYPublicKey *pub, SECOidTag hashOid) goto loser; /* Code already set. */ } - PORT_Assert(pub->u.rsa.modulus.type == siUnsignedInteger); - PORT_Assert(pub->u.rsa.publicExponent.type == siUnsignedInteger); SECItem *pubItem = SEC_ASN1EncodeItem(arena, &spki->subjectPublicKey, pub, SEC_ASN1_GET(SECKEY_RSAPublicKeyTemplate)); if (!pubItem) { @@ -574,15 +597,13 @@ tls13_MakeDcSpki(const SECKEYPublicKey *dcPub, SSLSignatureScheme dcCertVerifyAl case rsaKey: { SECOidTag hashOid; switch (dcCertVerifyAlg) { - /* Though we might prefer to use a pure PSS SPKI here, we can't - * because we have to choose based on client preferences. And - * not all clients advertise the pss_pss schemes. So use the - * default SPKI construction for an RSAE SPKI. */ + /* Note: RSAE schemes are NOT permitted within DC SPKIs. However, + * support for their issuance remains so as to enable negative + * testing of client behavior. */ case ssl_sig_rsa_pss_rsae_sha256: case ssl_sig_rsa_pss_rsae_sha384: case ssl_sig_rsa_pss_rsae_sha512: return SECKEY_CreateSubjectPublicKeyInfo(dcPub); - case ssl_sig_rsa_pss_pss_sha256: hashOid = SEC_OID_SHA256; break; @@ -707,7 +728,10 @@ SSLExp_DelegateCredential(const CERTCertificate *cert, if (dc->alg == ssl_sig_none) { SECOidTag spkiOid = SECOID_GetAlgorithmTag(&cert->subjectPublicKeyInfo.algorithm); /* If the Cert SPKI contained an AlgorithmIdentifier of "rsaEncryption", set a - * default rsa_pss_rsae_sha256 scheme. */ + * default rsa_pss_rsae_sha256 scheme. NOTE: RSAE SPKIs are not permitted within + * "real" Delegated Credentials. However, since this function is primarily used for + * testing, we retain this support in order to verify that these DCs are rejected + * by tls13_VerifyDelegatedCredential. */ if (spkiOid == SEC_OID_PKCS1_RSA_ENCRYPTION) { SSLSignatureScheme scheme = ssl_sig_rsa_pss_rsae_sha256; if (ssl_SignatureSchemeValid(scheme, spkiOid, PR_TRUE /* isTls13 */)) { @@ -752,6 +776,8 @@ SSLExp_DelegateCredential(const CERTCertificate *cert, goto loser; } + PRINT_BUF(20, (NULL, "delegated credential", dcBuf.buf, dcBuf.len)); + SECKEY_DestroySubjectPublicKeyInfo(spki); SECKEY_DestroyPrivateKey(tmpPriv); tls13_DestroyDelegatedCredential(dc); |