diff options
author | Moonchild <moonchild@palemoon.org> | 2021-03-15 12:57:35 +0000 |
---|---|---|
committer | Moonchild <moonchild@palemoon.org> | 2021-03-15 12:57:35 +0000 |
commit | fd9fc4ea60a66e33a57826bac996e1d1128c0e40 (patch) | |
tree | 1cbaea27ade626a7f7eddaa08eadaf63e3e5f589 /security/nss/lib/ssl | |
parent | d830832cb9466d6ce5b16e5610d3defbc3ec8053 (diff) | |
download | uxp-fd9fc4ea60a66e33a57826bac996e1d1128c0e40.tar.gz |
Issue #1693 - Update NSS to 3.52.1-RTM
Diffstat (limited to 'security/nss/lib/ssl')
32 files changed, 1584 insertions, 754 deletions
diff --git a/security/nss/lib/ssl/SSLerrs.h b/security/nss/lib/ssl/SSLerrs.h index 87b59b1e8d..f9c36b7c1a 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 0c4fc7fcd1..daa5e2c7cd 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; @@ -512,3 +526,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 ce92a8a55b..057d63efb4 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,9 @@ 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); + +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 bbd2f6d79b..51530de82c 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; } @@ -343,6 +343,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. @@ -1334,6 +1335,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 +1357,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 +1405,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 4ede3c2ca9..9d10aa248d 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 83df8c0b87..ac37c8648c 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 \ diff --git a/security/nss/lib/ssl/ssl.h b/security/nss/lib/ssl/ssl.h index dc5a9d4cd5..a55ffcddce 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,7 +323,7 @@ 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 diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c index f3c723bbc2..7f581e7920 100644 --- a/security/nss/lib/ssl/ssl3con.c +++ b/security/nss/lib/ssl/ssl3con.c @@ -65,6 +65,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 +392,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 @@ -1739,117 +1740,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 +1757,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; - } + if (spec->cipherDef->type != type_aead) { + macLength = spec->macDef->mac_size; - /* - ** 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; + /* + ** 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 +1787,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 +2120,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 +2317,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 +2348,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 +4464,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) { @@ -6713,13 +6649,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; } } @@ -8491,20 +8427,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 +8547,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 +8658,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 +8685,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. */ @@ -9810,8 +9759,28 @@ ssl3_SendServerKeyExchange(sslSocket *ss) SECStatus ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion, sslBuffer *buf) { + SSLSignatureScheme filtered[MAX_SIGNATURE_SCHEMES] = { 0 }; + unsigned int filteredCount = 0; + + SECStatus rv = ssl3_FilterSigAlgs(ss, minVersion, PR_FALSE, + 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 +9788,38 @@ 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); +SECStatus +ssl3_FilterSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRBool disableRsae, + 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; + 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])) { + filteredSchemes[(*numFilteredSchemes)++] = ss->ssl3.signatureSchemes[i]; + } + } + return SECSuccess; } static SECStatus @@ -11324,9 +11308,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; @@ -12308,41 +12292,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 +12326,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 +12337,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 +12347,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 +12357,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 +12374,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 +12391,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 +12484,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 +12594,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 +12885,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 +12932,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; diff --git a/security/nss/lib/ssl/ssl3ext.c b/security/nss/lib/ssl/ssl3ext.c index 7e674f0e03..1cad98a7f8 100644 --- a/security/nss/lib/ssl/ssl3ext.c +++ b/security/nss/lib/ssl/ssl3ext.c @@ -969,6 +969,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 97319c7d9a..7f09e5fd74 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; diff --git a/security/nss/lib/ssl/ssl3exthandle.c b/security/nss/lib/ssl/ssl3exthandle.c index 206cb00e48..07565ba00d 100644 --- a/security/nss/lib/ssl/ssl3exthandle.c +++ b/security/nss/lib/ssl/ssl3exthandle.c @@ -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) { diff --git a/security/nss/lib/ssl/ssl3gthr.c b/security/nss/lib/ssl/ssl3gthr.c index f9c741746f..3bc6e8edcb 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; } diff --git a/security/nss/lib/ssl/ssl3prot.h b/security/nss/lib/ssl/ssl3prot.h index ffe8373011..d7375551fb 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 34 typedef PRUint16 ssl3CipherSuite; /* The cipher suites are defined in sslproto.h */ diff --git a/security/nss/lib/ssl/sslerr.h b/security/nss/lib/ssl/sslerr.h index 7100b0226e..bc2785f9a1 100644 --- a/security/nss/lib/ssl/sslerr.h +++ b/security/nss/lib/ssl/sslerr.h @@ -274,6 +274,7 @@ 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_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 b734d86ca3..fb3d612c19 100644 --- a/security/nss/lib/ssl/sslexp.h +++ b/security/nss/lib/ssl/sslexp.h @@ -662,7 +662,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 +680,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 +732,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 +750,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 +786,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 +881,72 @@ 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)) + /* 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 4a393b281c..62d253224b 100644 --- a/security/nss/lib/ssl/sslimpl.h +++ b/security/nss/lib/ssl/sslimpl.h @@ -281,6 +281,7 @@ typedef struct sslOptionsStr { unsigned int enableV2CompatibleHello : 1; unsigned int enablePostHandshakeAuth : 1; unsigned int enableDelegatedCredentials : 1; + unsigned int enableDtls13VersionCompat : 1; } sslOptions; typedef enum { sslHandshakingUndetermined = 0, @@ -810,7 +811,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. */ @@ -1684,6 +1685,12 @@ SECStatus ssl_ReadCertificateStatus(sslSocket *ss, PRUint8 *b, PRUint32 length); SECStatus ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion, 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, + unsigned int maxSchemes, SSLSignatureScheme *filteredSchemes, + unsigned int *numFilteredSchemes); SECStatus ssl_GetCertificateRequestCAs(const sslSocket *ss, unsigned int *calenp, const SECItem **namesp, @@ -1824,6 +1831,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 +1851,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 b069888e27..115c38dc1e 100644 --- a/security/nss/lib/ssl/sslinfo.c +++ b/security/nss/lib/ssl/sslinfo.c @@ -432,7 +432,7 @@ tls13_Exporter(sslSocket *ss, PK11SymKey *secret, 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 b7b5b7fe51..3c30d3aa09 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); } @@ -1197,14 +1200,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 540c178400..2afecfb165 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/sslsnce.c b/security/nss/lib/ssl/sslsnce.c index 36c82117e2..2f43c05c03 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 @@ -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 aa0e76e3ce..e932016471 100644 --- a/security/nss/lib/ssl/sslsock.c +++ b/security/nss/lib/ssl/sslsock.c @@ -86,6 +86,7 @@ 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, @@ -4220,8 +4221,12 @@ struct { 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,8 +4238,11 @@ struct { EXP(HkdfExtract), EXP(HkdfExpandLabel), EXP(HkdfExpandLabelWithMech), + EXP(HkdfVariantExpandLabel), + EXP(HkdfVariantExpandLabelWithMech), EXP(KeyUpdate), EXP(MakeAead), + EXP(MakeVariantAead), EXP(RecordLayerData), EXP(RecordLayerWriteCallback), EXP(ReleaseAntiReplayContext), @@ -4242,6 +4250,7 @@ struct { EXP(SendCertificateRequest), EXP(SendSessionTicket), EXP(SetAntiReplayContext), + EXP(SetDtls13VersionWorkaround), EXP(SetESNIKeyPair), EXP(SetMaxEarlyDataSize), EXP(SetResumptionTokenCallback), @@ -4283,6 +4292,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); diff --git a/security/nss/lib/ssl/sslspec.c b/security/nss/lib/ssl/sslspec.c index def3c67505..c5bedad7a6 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 ca9ef540fb..ad4176bb5e 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,9 @@ struct ssl3CipherSpecStr { * negotiated value for TLS 1.3; it is reduced by one to account for the * content type octet. */ PRUint16 recordSizeLimit; + + /* Masking context used for DTLS 1.3 */ + SSLMaskingContext *maskContext; }; typedef void (*sslCipherSpecChangedFunc)(void *arg, diff --git a/security/nss/lib/ssl/sslt.h b/security/nss/lib/ssl/sslt.h index 47efa2e4d0..63dc06c8a8 100644 --- a/security/nss/lib/ssl/sslt.h +++ b/security/nss/lib/ssl/sslt.h @@ -507,6 +507,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 +522,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 c3528a52f8..b8f31c3f03 100644 --- a/security/nss/lib/ssl/tls13con.c +++ b/security/nss/lib/ssl/tls13con.c @@ -29,24 +29,6 @@ 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); @@ -131,6 +113,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"; @@ -286,6 +269,34 @@ tls13_GetHash(const sslSocket *ss) 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,26 +317,6 @@ 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) { @@ -595,7 +586,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 +632,7 @@ tls13_UpdateTrafficKeys(sslSocket *ss, SSLSecretDirection direction) strlen(kHkdfLabelTrafficUpdate), tls13_GetHmacMechanism(ss), tls13_GetHashSize(ss), + ss->protocolVariant, &updatedSecret); if (rv != SECSuccess) { return SECFailure; @@ -3317,8 +3309,9 @@ tls13_DeriveSecret(sslSocket *ss, PK11SymKey *key, rv = tls13_HkdfExpandLabel(key, tls13_GetHash(ss), hashes->u.raw, hashes->len, label, labelLen, - tls13_GetHkdfMechanism(ss), - tls13_GetHashSize(ss), dest); + CKM_HKDF_DERIVE, + tls13_GetHashSize(ss), + ss->protocolVariant, dest); if (rv != SECSuccess) { LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); return SECFailure; @@ -3467,6 +3460,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 +3468,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 +3513,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,10 +3536,6 @@ 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 = @@ -3571,6 +3558,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 +3668,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 +3835,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 @@ -4392,7 +4429,8 @@ tls13_ComputeFinished(sslSocket *ss, PK11SymKey *baseKey, NULL, 0, label, strlen(label), tls13_GetHmacMechanism(ss), - tls13_GetHashSize(ss), &secret); + tls13_GetHashSize(ss), + ss->protocolVariant, &secret); if (rv != SECSuccess) { goto abort; } @@ -4929,8 +4967,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; } @@ -5163,8 +5202,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 +5388,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 +5412,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 +5423,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 +5468,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 +5498,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,16 +5525,21 @@ 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) { SSL_TRC(3, ("%d: TLS13[%d]: record has bogus MAC", @@ -5763,14 +5826,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 +5875,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 +5915,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 bd309419fe..dd693b3779 100644 --- a/security/nss/lib/ssl/tls13con.h +++ b/security/nss/lib/ssl/tls13con.h @@ -44,12 +44,12 @@ 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); SECStatus tls13_ComputeHandshakeHashes(sslSocket *ss, @@ -107,8 +107,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 +133,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 f2f8d0a9c3..7182f22af8 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 1f88016a1e..5768fbce5f 100644 --- a/security/nss/lib/ssl/tls13exthandle.c +++ b/security/nss/lib/ssl/tls13exthandle.c @@ -789,12 +789,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 +834,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; @@ -1139,7 +1154,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 +1204,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 +1261,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 +1431,58 @@ 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, + 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 +1506,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 +1569,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 +1587,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 ab546e06f6..9cf4d0fc07 100644 --- a/security/nss/lib/ssl/tls13hkdf.c +++ b/security/nss/lib/ssl/tls13hkdf.c @@ -25,52 +25,73 @@ 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; 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 +101,64 @@ 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 + if (!ikm2) { + CK_OBJECT_CLASS ckoData = CKO_DATA; + CK_ATTRIBUTE template[2] = { + { CKA_CLASS, (CK_BYTE_PTR)&ckoData, sizeof(ckoData) }, + { CKA_VALUE, (CK_BYTE_PTR)zeroKeyBuf, kTlsHkdfInfo[baseHash].hashSize } }; - slot = PK11_GetInternalSlot(); + CK_OBJECT_HANDLE handle; + PK11GenericObject *genObject; + + /* if we have ikm1, put the zero key in the same slot */ + slot = ikm1 ? PK11_GetSlotFromKey(ikm1) : PK11_GetBestSlot(CKM_HKDF_DERIVE, NULL); if (!slot) { return SECFailure; } - zeroKey = PK11_ImportSymKey(slot, - kTlsHkdfInfo[baseHash].pkcs11Mech, - PK11_OriginUnwrap, - CKA_DERIVE, &zeroItem, NULL); - if (!zeroKey) + genObject = PK11_CreateGenericObject(slot, template, + PR_ARRAY_SIZE(template), PR_FALSE); + if (genObject == NULL) { return SECFailure; - ikm2 = zeroKey; - } else { - ikm2 = ikm2in; + } + handle = PK11_GetObjectHandle(PK11_TypeGeneric, genObject, NULL); + if (handle == CK_INVALID_HANDLE) { + return SECFailure; + } + /* A note about ownership of the PKCS #11 handle. + * PK11_CreateGenericObject() will not destroy the object it creates + * on Free, For that you want PK11_CreateManagedGenericObject(). + * Below we import the handle into the symKey structure. We pass + * PR_TRUE as the owner so that the symKey will destroy the object + * once it's freed. This is way it's safe to free now */ + PK11_DestroyGenericObject(genObject); + + /* NOTE: we can't both be in this block, and the block above where + * we moved the keys (because this block requires ikm2 to be NULL and + * the other requires ikm2 to be non-NULL. It's therefore safe to + * use newIkm2 in both cases and have a single free at the end for + * both */ + PORT_Assert(newIkm2 == NULL); /* verify logic of the above statement */ + newIkm2 = PK11_SymKeyFromHandle(slot, NULL, PK11_OriginUnwrap, + CKM_HKDF_DERIVE, handle, PR_TRUE, NULL); + if (!newIkm2) { + return SECFailure; + } + 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 +167,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 +183,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 +242,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 +277,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 78347a11dc..00e5ff1dd3 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/tls13replay.c b/security/nss/lib/ssl/tls13replay.c index 6280111440..b6d1416f3a 100644 --- a/security/nss/lib/ssl/tls13replay.c +++ b/security/nss/lib/ssl/tls13replay.c @@ -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; } @@ -269,7 +260,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 8ae5447f7a..6f164c3028 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); |