summaryrefslogtreecommitdiff
path: root/security/nss/lib/ssl
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/ssl')
-rw-r--r--security/nss/lib/ssl/SSLerrs.h3
-rw-r--r--security/nss/lib/ssl/dtls13con.c105
-rw-r--r--security/nss/lib/ssl/dtls13con.h6
-rw-r--r--security/nss/lib/ssl/dtlscon.c45
-rw-r--r--security/nss/lib/ssl/dtlscon.h1
-rw-r--r--security/nss/lib/ssl/manifest.mn4
-rw-r--r--security/nss/lib/ssl/ssl.h5
-rw-r--r--security/nss/lib/ssl/ssl3con.c493
-rw-r--r--security/nss/lib/ssl/ssl3ext.c2
-rw-r--r--security/nss/lib/ssl/ssl3ext.h10
-rw-r--r--security/nss/lib/ssl/ssl3exthandle.c9
-rw-r--r--security/nss/lib/ssl/ssl3gthr.c25
-rw-r--r--security/nss/lib/ssl/ssl3prot.h2
-rw-r--r--security/nss/lib/ssl/sslerr.h1
-rw-r--r--security/nss/lib/ssl/sslexp.h133
-rw-r--r--security/nss/lib/ssl/sslimpl.h57
-rw-r--r--security/nss/lib/ssl/sslinfo.c2
-rw-r--r--security/nss/lib/ssl/sslnonce.c8
-rw-r--r--security/nss/lib/ssl/sslprimitive.c392
-rw-r--r--security/nss/lib/ssl/sslsnce.c19
-rw-r--r--security/nss/lib/ssl/sslsock.c20
-rw-r--r--security/nss/lib/ssl/sslspec.c3
-rw-r--r--security/nss/lib/ssl/sslspec.h24
-rw-r--r--security/nss/lib/ssl/sslt.h2
-rw-r--r--security/nss/lib/ssl/tls13con.c415
-rw-r--r--security/nss/lib/ssl/tls13con.h30
-rw-r--r--security/nss/lib/ssl/tls13esni.c46
-rw-r--r--security/nss/lib/ssl/tls13exthandle.c194
-rw-r--r--security/nss/lib/ssl/tls13hkdf.c198
-rw-r--r--security/nss/lib/ssl/tls13hkdf.h5
-rw-r--r--security/nss/lib/ssl/tls13replay.c15
-rw-r--r--security/nss/lib/ssl/tls13subcerts.c64
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, &param, out, &uOutLen,
- maxout, in, inlen);
- } else {
- rv = PK11_Encrypt(keys->key, CKM_AES_GCM, &param, 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, &param,
- out, &uOutLen, maxout, in, inlen);
- } else {
- rv = PK11_Encrypt(keys->key, CKM_NSS_CHACHA20_POLY1305, &param,
- 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,
+ &param,
+ 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, &param,
- 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, &param,
- 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 *)&params;
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,
- &paramsi, kTlsHkdfInfo[baseHash].pkcs11Mech,
- CKA_DERIVE, kTlsHkdfInfo[baseHash].hashSize);
- if (zeroKey)
- PK11_FreeSymKey(zeroKey);
+ prk = PK11_Derive(ikm2, CKM_HKDF_DERIVE, &paramsi, 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 *)&params;
paramsi.len = sizeof(params);
-
- derived = PK11_DeriveWithFlags(prk, kTlsHkdfInfo[baseHash].pkcs11Mech,
+ derived = PK11_DeriveWithFlags(prk, deriveMech,
&paramsi, 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, &params.saltLength, saltLength)) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ goto loser;
+ }
+ /* Omit the trailerField always. */
+
SECItem *algorithmItem =
SEC_ASN1EncodeItem(arena, NULL, &params,
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);