summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/ssl
diff options
context:
space:
mode:
authorMoonchild <moonchild@palemoon.org>2020-12-23 19:02:52 +0000
committerMoonchild <moonchild@palemoon.org>2020-12-23 19:02:52 +0000
commit029bcfe189eae5eebbaf58ccff4e1200dd78b228 (patch)
tree1c226a334ea1a88e2d1c6f949c9320eb0c3bff59 /security/nss/lib/ssl
parent149d2ffa779826cb48a381099858e76e4624d471 (diff)
downloadUXP-029bcfe189eae5eebbaf58ccff4e1200dd78b228.tar
UXP-029bcfe189eae5eebbaf58ccff4e1200dd78b228.tar.gz
UXP-029bcfe189eae5eebbaf58ccff4e1200dd78b228.tar.lz
UXP-029bcfe189eae5eebbaf58ccff4e1200dd78b228.tar.xz
UXP-029bcfe189eae5eebbaf58ccff4e1200dd78b228.zip
Issue #1693 - Update NSS to 3.59.1.1
This updates to MoonchildProductions/NSS@bd49b2b88 in the repo created for our consumption of the library.
Diffstat (limited to 'security/nss/lib/ssl')
-rw-r--r--security/nss/lib/ssl/SSLerrs.h3
-rw-r--r--security/nss/lib/ssl/dtls13con.c129
-rw-r--r--security/nss/lib/ssl/dtls13con.h7
-rw-r--r--security/nss/lib/ssl/dtlscon.c59
-rw-r--r--security/nss/lib/ssl/dtlscon.h1
-rw-r--r--security/nss/lib/ssl/manifest.mn5
-rw-r--r--security/nss/lib/ssl/ssl.gyp1
-rw-r--r--security/nss/lib/ssl/ssl.h24
-rw-r--r--security/nss/lib/ssl/ssl3con.c804
-rw-r--r--security/nss/lib/ssl/ssl3ext.c4
-rw-r--r--security/nss/lib/ssl/ssl3ext.h14
-rw-r--r--security/nss/lib/ssl/ssl3exthandle.c13
-rw-r--r--security/nss/lib/ssl/ssl3gthr.c93
-rw-r--r--security/nss/lib/ssl/ssl3prot.h2
-rw-r--r--security/nss/lib/ssl/sslencode.c5
-rw-r--r--security/nss/lib/ssl/sslerr.h2
-rw-r--r--security/nss/lib/ssl/sslexp.h185
-rw-r--r--security/nss/lib/ssl/sslimpl.h81
-rw-r--r--security/nss/lib/ssl/sslinfo.c39
-rw-r--r--security/nss/lib/ssl/sslnonce.c11
-rw-r--r--security/nss/lib/ssl/sslprimitive.c392
-rw-r--r--security/nss/lib/ssl/sslsecur.c2
-rw-r--r--security/nss/lib/ssl/sslsnce.c23
-rw-r--r--security/nss/lib/ssl/sslsock.c79
-rw-r--r--security/nss/lib/ssl/sslspec.c3
-rw-r--r--security/nss/lib/ssl/sslspec.h27
-rw-r--r--security/nss/lib/ssl/sslt.h14
-rw-r--r--security/nss/lib/ssl/tls13con.c1048
-rw-r--r--security/nss/lib/ssl/tls13con.h36
-rw-r--r--security/nss/lib/ssl/tls13esni.c46
-rw-r--r--security/nss/lib/ssl/tls13exthandle.c395
-rw-r--r--security/nss/lib/ssl/tls13hkdf.c171
-rw-r--r--security/nss/lib/ssl/tls13hkdf.h5
-rw-r--r--security/nss/lib/ssl/tls13psk.c219
-rw-r--r--security/nss/lib/ssl/tls13psk.h58
-rw-r--r--security/nss/lib/ssl/tls13replay.c23
-rw-r--r--security/nss/lib/ssl/tls13subcerts.c64
37 files changed, 2932 insertions, 1155 deletions
diff --git a/security/nss/lib/ssl/SSLerrs.h b/security/nss/lib/ssl/SSLerrs.h
index 87b59b1e8..f9c36b7c1 100644
--- a/security/nss/lib/ssl/SSLerrs.h
+++ b/security/nss/lib/ssl/SSLerrs.h
@@ -582,3 +582,6 @@ ER3(SSL_ERROR_DC_INVALID_KEY_USAGE, (SSL_ERROR_BASE + 184),
ER3(SSL_ERROR_DC_EXPIRED, (SSL_ERROR_BASE + 185),
"SSL received a delegated credential that expired.")
+
+ER3(SSL_ERROR_DC_INAPPROPRIATE_VALIDITY_PERIOD, (SSL_ERROR_BASE + 186),
+ "SSL received a delegated credential with excessive TTL.")
diff --git a/security/nss/lib/ssl/dtls13con.c b/security/nss/lib/ssl/dtls13con.c
index 0c4fc7fcd..5307419b6 100644
--- a/security/nss/lib/ssl/dtls13con.c
+++ b/security/nss/lib/ssl/dtls13con.c
@@ -10,38 +10,52 @@
#include "ssl.h"
#include "sslimpl.h"
#include "sslproto.h"
+#include "keyhi.h"
+#include "pk11func.h"
+/*
+ * 0 1 2 3 4 5 6 7
+ * +-+-+-+-+-+-+-+-+
+ * |0|0|1|C|S|L|E E|
+ * +-+-+-+-+-+-+-+-+
+ * | Connection ID | Legend:
+ * | (if any, |
+ * / length as / C - CID present
+ * | negotiated) | S - Sequence number length
+ * +-+-+-+-+-+-+-+-+ L - Length present
+ * | 8 or 16 bit | E - Epoch
+ * |Sequence Number|
+ * +-+-+-+-+-+-+-+-+
+ * | 16 bit Length |
+ * | (if present) |
+ * +-+-+-+-+-+-+-+-+
+ */
SECStatus
-dtls13_InsertCipherTextHeader(const sslSocket *ss, ssl3CipherSpec *cwSpec,
+dtls13_InsertCipherTextHeader(const sslSocket *ss, const ssl3CipherSpec *cwSpec,
sslBuffer *wrBuf, PRBool *needsLength)
{
- PRUint32 seq;
- SECStatus rv;
-
/* Avoid using short records for the handshake. We pack multiple records
* into the one datagram for the handshake. */
if (ss->opt.enableDtlsShortHeader &&
- cwSpec->epoch != TrafficKeyHandshake) {
+ cwSpec->epoch > TrafficKeyHandshake) {
*needsLength = PR_FALSE;
/* The short header is comprised of two octets in the form
- * 0b001essssssssssss where 'e' is the low bit of the epoch and 's' is
- * the low 12 bits of the sequence number. */
- seq = 0x2000 |
- (((uint64_t)cwSpec->epoch & 1) << 12) |
- (cwSpec->nextSeqNum & 0xfff);
- return sslBuffer_AppendNumber(wrBuf, seq, 2);
+ * 0b001000eessssssss where 'e' is the low two bits of the
+ * epoch and 's' is the low 8 bits of the sequence number. */
+ PRUint8 ct = 0x20 | ((uint64_t)cwSpec->epoch & 0x3);
+ if (sslBuffer_AppendNumber(wrBuf, ct, 1) != SECSuccess) {
+ return SECFailure;
+ }
+ PRUint8 seq = cwSpec->nextSeqNum & 0xff;
+ return sslBuffer_AppendNumber(wrBuf, seq, 1);
}
- rv = sslBuffer_AppendNumber(wrBuf, ssl_ct_application_data, 1);
- if (rv != SECSuccess) {
+ PRUint8 ct = 0x2c | ((PRUint8)cwSpec->epoch & 0x3);
+ if (sslBuffer_AppendNumber(wrBuf, ct, 1) != SECSuccess) {
return SECFailure;
}
-
- /* The epoch and sequence number are encoded on 4 octets, with the epoch
- * consuming the first two bits. */
- seq = (((uint64_t)cwSpec->epoch & 3) << 30) | (cwSpec->nextSeqNum & 0x3fffffff);
- rv = sslBuffer_AppendNumber(wrBuf, seq, 4);
- if (rv != SECSuccess) {
+ if (sslBuffer_AppendNumber(wrBuf,
+ (cwSpec->nextSeqNum & 0xffff), 2) != SECSuccess) {
return SECFailure;
}
*needsLength = PR_TRUE;
@@ -171,6 +185,27 @@ dtls13_SendAckCb(sslSocket *ss)
(void)dtls13_SendAck(ss);
}
+/* Limits from draft-ietf-tls-dtls13-38; section 4.5.3. */
+PRBool
+dtls13_AeadLimitReached(ssl3CipherSpec *spec)
+{
+ if (spec->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ switch (spec->cipherDef->calg) {
+ case ssl_calg_chacha20:
+ case ssl_calg_aes_gcm:
+ return spec->deprotectionFailures >= (1ULL << 36);
+#ifdef UNSAFE_FUZZER_MODE
+ case ssl_calg_null:
+ return PR_FALSE;
+#endif
+ default:
+ PORT_Assert(0);
+ break;
+ }
+ }
+ return PR_FALSE;
+}
+
/* Zero length messages are very simple to check. */
static PRBool
dtls_IsEmptyMessageAcknowledged(sslSocket *ss, PRUint16 msgSeq, PRUint32 offset)
@@ -378,8 +413,7 @@ dtls13_HandleOutOfEpochRecord(sslSocket *ss, const ssl3CipherSpec *spec,
* server, we might have processed the client's Finished and
* moved on to application data keys, but the client has
* retransmitted Finished (e.g., because our ACK got lost.)
- * We just retransmit the previous Finished to let the client
- * complete. */
+ * We just retransmit the ACK to let the client complete. */
if (rType == ssl_ct_handshake) {
if ((ss->sec.isServer) &&
(ss->ssl3.hs.ws == idle_handshake)) {
@@ -512,3 +546,56 @@ dtls13_HolddownTimerCb(sslSocket *ss)
ssl_CipherSpecReleaseByEpoch(ss, ssl_secret_read, TrafficKeyHandshake);
ssl_ClearPRCList(&ss->ssl3.hs.dtlsRcvdHandshake, NULL);
}
+
+SECStatus
+dtls13_MaskSequenceNumber(sslSocket *ss, ssl3CipherSpec *spec,
+ PRUint8 *hdr, PRUint8 *cipherText, PRUint32 cipherTextLen)
+{
+ PORT_Assert(IS_DTLS(ss));
+ if (spec->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+ return SECSuccess;
+ }
+
+ if (spec->maskContext) {
+#ifdef UNSAFE_FUZZER_MODE
+ /* Use a null mask. */
+ PRUint8 mask[2] = { 0 };
+#else
+ /* "This procedure requires the ciphertext length be at least 16 bytes.
+ * Receivers MUST reject shorter records as if they had failed
+ * deprotection, as described in Section 4.5.2." */
+ if (cipherTextLen < 16) {
+ PORT_SetError(SSL_ERROR_BAD_MAC_READ);
+ return SECFailure;
+ }
+
+ PRUint8 mask[2];
+ SECStatus rv = ssl_CreateMaskInner(spec->maskContext, cipherText, cipherTextLen, mask, sizeof(mask));
+
+ if (rv != SECSuccess) {
+ PORT_SetError(SSL_ERROR_BAD_MAC_READ);
+ return SECFailure;
+ }
+#endif
+
+ hdr[1] ^= mask[0];
+ if (hdr[0] & 0x08) {
+ hdr[2] ^= mask[1];
+ }
+ }
+ return SECSuccess;
+}
+
+CK_MECHANISM_TYPE
+tls13_SequenceNumberEncryptionMechanism(SSLCipherAlgorithm bulkAlgorithm)
+{
+ switch (bulkAlgorithm) {
+ case ssl_calg_aes_gcm:
+ return CKM_AES_ECB;
+ case ssl_calg_chacha20:
+ return CKM_NSS_CHACHA20_CTR;
+ default:
+ PORT_Assert(PR_FALSE);
+ }
+ return CKM_INVALID_MECHANISM;
+}
diff --git a/security/nss/lib/ssl/dtls13con.h b/security/nss/lib/ssl/dtls13con.h
index ce92a8a55..bfe8d4020 100644
--- a/security/nss/lib/ssl/dtls13con.h
+++ b/security/nss/lib/ssl/dtls13con.h
@@ -10,7 +10,7 @@
#define __dtls13con_h_
SECStatus dtls13_InsertCipherTextHeader(const sslSocket *ss,
- ssl3CipherSpec *cwSpec,
+ const ssl3CipherSpec *cwSpec,
sslBuffer *wrBuf,
PRBool *needsLength);
SECStatus dtls13_RememberFragment(sslSocket *ss, PRCList *list,
@@ -29,5 +29,10 @@ SECStatus dtls13_SendAck(sslSocket *ss);
void dtls13_SendAckCb(sslSocket *ss);
void dtls13_HolddownTimerCb(sslSocket *ss);
void dtls_ReceivedFirstMessageInFlight(sslSocket *ss);
+SECStatus dtls13_MaskSequenceNumber(sslSocket *ss, ssl3CipherSpec *spec,
+ PRUint8 *hdr, PRUint8 *cipherText, PRUint32 cipherTextLen);
+PRBool dtls13_AeadLimitReached(ssl3CipherSpec *spec);
+
+CK_MECHANISM_TYPE tls13_SequenceNumberEncryptionMechanism(SSLCipherAlgorithm bulkAlgorithm);
#endif
diff --git a/security/nss/lib/ssl/dtlscon.c b/security/nss/lib/ssl/dtlscon.c
index bbd2f6d79..10e550e0f 100644
--- a/security/nss/lib/ssl/dtlscon.c
+++ b/security/nss/lib/ssl/dtlscon.c
@@ -53,7 +53,7 @@ static const ssl3CipherSuite nonDTLSSuites[] = {
* TLS DTLS
* 1.1 (0302) 1.0 (feff)
* 1.2 (0303) 1.2 (fefd)
- * 1.3 (0304) 1.3 (fefc)
+ * 1.3 (0304) 1.3 (0304)
*/
SSL3ProtocolVersion
dtls_TLSVersionToDTLSVersion(SSL3ProtocolVersion tlsv)
@@ -68,7 +68,7 @@ dtls_TLSVersionToDTLSVersion(SSL3ProtocolVersion tlsv)
return SSL_LIBRARY_VERSION_DTLS_1_3_WIRE;
}
- /* Anything other than TLS 1.1 or 1.2 is an error, so return
+ /* Anything else is an error, so return
* the invalid version 0xffff. */
return 0xffff;
}
@@ -270,12 +270,6 @@ SECStatus
dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum,
sslBuffer *origBuf)
{
- /* XXX OK for now.
- * This doesn't work properly with asynchronous certificate validation.
- * because that returns a WOULDBLOCK error. The current DTLS
- * applications do not need asynchronous validation, but in the
- * future we will need to add this.
- */
sslBuffer buf = *origBuf;
SECStatus rv = SECSuccess;
PRBool discarded = PR_FALSE;
@@ -310,7 +304,8 @@ dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum,
if (message_length > MAX_HANDSHAKE_MSG_LEN) {
(void)ssl3_DecodeError(ss);
PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
- return SECFailure;
+ rv = SECFailure;
+ goto loser;
}
#undef MAX_HANDSHAKE_MSG_LEN
@@ -343,6 +338,7 @@ dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum,
SSL_TRC(5, ("%d: DTLS[%d]: Received apparent 2nd ClientHello",
SSL_GETPID(), ss->fd));
ss->ssl3.hs.recvMessageSeq = 1;
+ ss->ssl3.hs.helloRetry = PR_TRUE;
}
/* There are three ways we could not be ready for this packet.
@@ -484,7 +480,7 @@ dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum,
}
// This should never happen, but belt and suspenders.
- if (rv == SECFailure) {
+ if (rv != SECSuccess) {
PORT_Assert(0);
goto loser;
}
@@ -504,9 +500,6 @@ dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum,
loser:
origBuf->len = 0; /* So ssl3_GatherAppDataRecord will keep looping. */
-
- /* XXX OK for now. In future handle rv == SECWouldBlock safely in order
- * to deal with asynchronous certificate verification */
return rv;
}
@@ -1334,6 +1327,14 @@ dtls_IsLongHeader(SSL3ProtocolVersion version, PRUint8 firstOctet)
#endif
}
+PRBool
+dtls_IsDtls13Ciphertext(SSL3ProtocolVersion version, PRUint8 firstOctet)
+{
+ // Allow no version in case we haven't negotiated one yet.
+ return (version == 0 || version >= SSL_LIBRARY_VERSION_TLS_1_3) &&
+ (firstOctet & 0xe0) == 0x20;
+}
+
DTLSEpoch
dtls_ReadEpoch(const ssl3CipherSpec *crSpec, const PRUint8 *hdr)
{
@@ -1348,13 +1349,12 @@ dtls_ReadEpoch(const ssl3CipherSpec *crSpec, const PRUint8 *hdr)
/* A lot of how we recover the epoch here will depend on how we plan to
* manage KeyUpdate. In the case that we decide to install a new read spec
* as a KeyUpdate is handled, crSpec will always be the highest epoch we can
- * possibly receive. That makes this easier to manage. */
- if ((hdr[0] & 0xe0) == 0x20) {
+ * possibly receive. That makes this easier to manage.
+ */
+ if (dtls_IsDtls13Ciphertext(crSpec->version, hdr[0])) {
+ /* TODO(ekr@rtfm.com: do something with the two-bit epoch. */
/* Use crSpec->epoch, or crSpec->epoch - 1 if the last bit differs. */
- if (((hdr[0] >> 4) & 1) == (crSpec->epoch & 1)) {
- return crSpec->epoch;
- }
- return crSpec->epoch - 1;
+ return crSpec->epoch - ((hdr[0] ^ crSpec->epoch) & 0x3);
}
/* dtls_GatherData should ensure that this works. */
@@ -1397,20 +1397,15 @@ dtls_ReadSequenceNumber(const ssl3CipherSpec *spec, const PRUint8 *hdr)
* sequence number is replaced. If that causes the value to exceed the
* maximum, subtract an entire range.
*/
- if ((hdr[0] & 0xe0) == 0x20) {
- /* A 12-bit sequence number. */
- cap = spec->nextSeqNum + (1ULL << 11);
- partial = (((sslSequenceNumber)hdr[0] & 0xf) << 8) |
- (sslSequenceNumber)hdr[1];
- mask = (1ULL << 12) - 1;
+ if (hdr[0] & 0x08) {
+ cap = spec->nextSeqNum + (1ULL << 15);
+ partial = (((sslSequenceNumber)hdr[1]) << 8) |
+ (sslSequenceNumber)hdr[2];
+ mask = (1ULL << 16) - 1;
} else {
- /* A 30-bit sequence number. */
- cap = spec->nextSeqNum + (1ULL << 29);
- partial = (((sslSequenceNumber)hdr[1] & 0x3f) << 24) |
- ((sslSequenceNumber)hdr[2] << 16) |
- ((sslSequenceNumber)hdr[3] << 8) |
- (sslSequenceNumber)hdr[4];
- mask = (1ULL << 30) - 1;
+ cap = spec->nextSeqNum + (1ULL << 7);
+ partial = (sslSequenceNumber)hdr[1];
+ mask = (1ULL << 8) - 1;
}
seqNum = (cap & ~mask) | partial;
/* The second check prevents the value from underflowing if we get a large
diff --git a/security/nss/lib/ssl/dtlscon.h b/security/nss/lib/ssl/dtlscon.h
index 4ede3c2ca..9d10aa248 100644
--- a/security/nss/lib/ssl/dtlscon.h
+++ b/security/nss/lib/ssl/dtlscon.h
@@ -47,4 +47,5 @@ extern PRBool dtls_IsRelevant(sslSocket *ss, const ssl3CipherSpec *spec,
sslSequenceNumber *seqNum);
void dtls_ReceivedFirstMessageInFlight(sslSocket *ss);
PRBool dtls_IsLongHeader(SSL3ProtocolVersion version, PRUint8 firstOctet);
+PRBool dtls_IsDtls13Ciphertext(SSL3ProtocolVersion version, PRUint8 firstOctet);
#endif
diff --git a/security/nss/lib/ssl/manifest.mn b/security/nss/lib/ssl/manifest.mn
index 83df8c0b8..7e286f60c 100644
--- a/security/nss/lib/ssl/manifest.mn
+++ b/security/nss/lib/ssl/manifest.mn
@@ -5,6 +5,10 @@ CORE_DEPTH = ../..
# DEFINES = -DTRACE
+ifdef ZLIB_INCLUDE_DIR
+INCLUDES += -I$(ZLIB_INCLUDE_DIR)
+endif
+
EXPORTS = \
ssl.h \
sslt.h \
@@ -52,6 +56,7 @@ CSRCS = \
tls13exthandle.c \
tls13hashstate.c \
tls13hkdf.c \
+ tls13psk.c \
tls13replay.c \
sslcert.c \
sslgrp.c \
diff --git a/security/nss/lib/ssl/ssl.gyp b/security/nss/lib/ssl/ssl.gyp
index 3e1b5531a..5c84a1f03 100644
--- a/security/nss/lib/ssl/ssl.gyp
+++ b/security/nss/lib/ssl/ssl.gyp
@@ -48,6 +48,7 @@
'tls13exthandle.c',
'tls13hashstate.c',
'tls13hkdf.c',
+ 'tls13psk.c',
'tls13replay.c',
'tls13subcerts.c',
],
diff --git a/security/nss/lib/ssl/ssl.h b/security/nss/lib/ssl/ssl.h
index dc5a9d4cd..43a0f3228 100644
--- a/security/nss/lib/ssl/ssl.h
+++ b/security/nss/lib/ssl/ssl.h
@@ -312,7 +312,8 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd);
/* Enables the delegated credentials extension (draft-ietf-tls-subcerts). When
* enabled, a client that supports TLS 1.3 will indicate willingness to
- * negotiate a delegated credential (DC).
+ * negotiate a delegated credential (DC). Note that client-delegated credentials
+ * are not currently supported.
*
* If support is indicated, the peer may use a DC to authenticate itself. The DC
* is sent as an extension to the peer's end-entity certificate; the end-entity
@@ -322,10 +323,29 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd);
* mitigate the damage in case the secret key is compromised, the DC is only
* valid for a short time (days, hours, or even minutes).
*
- * This library implements draft-03 of the protocol spec.
+ * This library implements draft-07 of the protocol spec.
*/
#define SSL_ENABLE_DELEGATED_CREDENTIALS 40
+/* Causes TLS (>=1.3) to suppress the EndOfEarlyData message in stream mode.
+ *
+ * This is not advisable in general, but the message only exists to delineate
+ * early data in a streamed connection. DTLS does not use this message as a
+ * result. The integration of TLS with QUIC, which uses a record/packet
+ * protection layer that is unreliable, also does not use this message.
+ *
+ * On the server, this requires that SSL_RecordLayerData be used.
+ * EndOfEarlyData is otherwise needed to drive key changes. Additionally,
+ * servers that use this API must check that handshake messages (Certificate,
+ * CertificateVerify, and Finished in particular) are only received in epoch 2
+ * (Handshake). SSL_RecordLayerData will accept these handshake messages if
+ * they are passed as epoch 1 (Early Data) in a single call.
+ *
+ * Using this option will cause connections to fail if early data is attempted
+ * and the peer expects this message.
+ */
+#define SSL_SUPPRESS_END_OF_EARLY_DATA 41
+
#ifdef SSL_DEPRECATED_FUNCTION
/* Old deprecated function names */
SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRIntn on);
diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c
index f3c723bbc..b652dcea3 100644
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -21,6 +21,7 @@
#include "sslerr.h"
#include "ssl3ext.h"
#include "ssl3exthandle.h"
+#include "tls13psk.h"
#include "tls13subcerts.h"
#include "prtime.h"
#include "prinrval.h"
@@ -65,6 +66,7 @@ static SECStatus ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags);
static CK_MECHANISM_TYPE ssl3_GetHashMechanismByHashType(SSLHashType hashType);
static CK_MECHANISM_TYPE ssl3_GetMgfMechanismByHashType(SSLHashType hash);
PRBool ssl_IsRsaPssSignatureScheme(SSLSignatureScheme scheme);
+PRBool ssl_IsRsaeSignatureScheme(SSLSignatureScheme scheme);
PRBool ssl_IsRsaPkcs1SignatureScheme(SSLSignatureScheme scheme);
PRBool ssl_IsDsaSignatureScheme(SSLSignatureScheme scheme);
@@ -391,15 +393,15 @@ static const SSLCipher2Mech alg2Mech[] = {
{ ssl_calg_camellia, CKM_CAMELLIA_CBC },
{ ssl_calg_seed, CKM_SEED_CBC },
{ ssl_calg_aes_gcm, CKM_AES_GCM },
- { ssl_calg_chacha20, CKM_NSS_CHACHA20_POLY1305 },
+ { ssl_calg_chacha20, CKM_CHACHA20_POLY1305 },
};
-const PRUint8 tls13_downgrade_random[] = { 0x44, 0x4F, 0x57, 0x4E,
- 0x47, 0x52, 0x44, 0x01 };
const PRUint8 tls12_downgrade_random[] = { 0x44, 0x4F, 0x57, 0x4E,
- 0x47, 0x52, 0x44, 0x00 };
-PR_STATIC_ASSERT(sizeof(tls13_downgrade_random) ==
- sizeof(tls13_downgrade_random));
+ 0x47, 0x52, 0x44, 0x01 };
+const PRUint8 tls1_downgrade_random[] = { 0x44, 0x4F, 0x57, 0x4E,
+ 0x47, 0x52, 0x44, 0x00 };
+PR_STATIC_ASSERT(sizeof(tls12_downgrade_random) ==
+ sizeof(tls1_downgrade_random));
/* The ECCWrappedKeyInfo structure defines how various pieces of
* information are laid out within wrappedSymmetricWrappingkey
@@ -517,7 +519,7 @@ ssl3_DecodeContentType(int msgType)
rv = "application_data (23)";
break;
case ssl_ct_ack:
- rv = "ack (25)";
+ rv = "ack (26)";
break;
default:
sprintf(line, "*UNKNOWN* record type! (%d)", msgType);
@@ -782,15 +784,19 @@ ssl_HasCert(const sslSocket *ss, PRUint16 maxVersion, SSLAuthType authType)
* Both by policy and by having a token that supports it. */
static PRBool
ssl_SignatureSchemeAccepted(PRUint16 minVersion,
- SSLSignatureScheme scheme)
+ SSLSignatureScheme scheme,
+ PRBool forCert)
{
/* Disable RSA-PSS schemes if there are no tokens to verify them. */
if (ssl_IsRsaPssSignatureScheme(scheme)) {
if (!PK11_TokenExists(auth_alg_defs[ssl_auth_rsa_pss])) {
return PR_FALSE;
}
- } else if (ssl_IsRsaPkcs1SignatureScheme(scheme)) {
- /* Disable PKCS#1 signatures if we are limited to TLS 1.3. */
+ } else if (!forCert && ssl_IsRsaPkcs1SignatureScheme(scheme)) {
+ /* Disable PKCS#1 signatures if we are limited to TLS 1.3.
+ * We still need to advertise PKCS#1 signatures in CH and CR
+ * for certificate signatures.
+ */
if (minVersion >= SSL_LIBRARY_VERSION_TLS_1_3) {
return PR_FALSE;
}
@@ -849,7 +855,8 @@ ssl_CheckSignatureSchemes(sslSocket *ss)
/* Ensure that there is a signature scheme that can be accepted.*/
for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
if (ssl_SignatureSchemeAccepted(ss->vrange.min,
- ss->ssl3.signatureSchemes[i])) {
+ ss->ssl3.signatureSchemes[i],
+ PR_FALSE /* forCert */)) {
return SECSuccess;
}
}
@@ -878,7 +885,7 @@ ssl_HasSignatureScheme(const sslSocket *ss, SSLAuthType authType)
PRBool acceptable = authType == schemeAuthType ||
(schemeAuthType == ssl_auth_rsa_pss &&
authType == ssl_auth_rsa_sign);
- if (acceptable && ssl_SignatureSchemeAccepted(ss->version, scheme)) {
+ if (acceptable && ssl_SignatureSchemeAccepted(ss->version, scheme, PR_FALSE /* forCert */)) {
return PR_TRUE;
}
}
@@ -911,6 +918,13 @@ ssl3_config_match_init(sslSocket *ss)
if (SSL_ALL_VERSIONS_DISABLED(&ss->vrange)) {
return 0;
}
+ if (ss->sec.isServer && ss->psk &&
+ PR_CLIST_IS_EMPTY(&ss->serverCerts) &&
+ (ss->opt.requestCertificate || ss->opt.requireCertificate)) {
+ /* PSK and certificate auth cannot be combined. */
+ PORT_SetError(SSL_ERROR_NO_CERTIFICATE);
+ return 0;
+ }
if (ssl_CheckSignatureSchemes(ss) != SECSuccess) {
return 0; /* Code already set. */
}
@@ -1008,6 +1022,16 @@ ssl3_config_match(const ssl3CipherSuiteCfg *suite, PRUint8 policy,
return PR_FALSE;
}
+ /* If a PSK is selected, disable suites that use a different hash than
+ * the PSK. We advertise non-PSK-compatible suites in the CH, as we could
+ * fallback to certificate auth. The client handler will check hash
+ * compatibility before committing to use the PSK. */
+ if (ss->xtnData.selectedPsk) {
+ if (ss->xtnData.selectedPsk->hash != cipher_def->prf_hash) {
+ return PR_FALSE;
+ }
+ }
+
return ssl3_CipherSuiteAllowedForVersionRange(suite->cipher_suite, vrange);
}
@@ -1739,117 +1763,6 @@ ssl3_BuildRecordPseudoHeader(DTLSEpoch epoch,
return SECSuccess;
}
-static SECStatus
-ssl3_AESGCM(const ssl3KeyMaterial *keys,
- PRBool doDecrypt,
- unsigned char *out,
- unsigned int *outlen,
- unsigned int maxout,
- const unsigned char *in,
- unsigned int inlen,
- const unsigned char *additionalData,
- unsigned int additionalDataLen)
-{
- SECItem param;
- SECStatus rv = SECFailure;
- unsigned char nonce[12];
- unsigned int uOutLen;
- CK_GCM_PARAMS gcmParams;
-
- const int tagSize = 16;
- const int explicitNonceLen = 8;
-
- /* See https://tools.ietf.org/html/rfc5288#section-3 for details of how the
- * nonce is formed. */
- memcpy(nonce, keys->iv, 4);
- if (doDecrypt) {
- memcpy(nonce + 4, in, explicitNonceLen);
- in += explicitNonceLen;
- inlen -= explicitNonceLen;
- *outlen = 0;
- } else {
- if (maxout < explicitNonceLen) {
- PORT_SetError(SEC_ERROR_INPUT_LEN);
- return SECFailure;
- }
- /* Use the 64-bit sequence number as the explicit nonce. */
- memcpy(nonce + 4, additionalData, explicitNonceLen);
- memcpy(out, additionalData, explicitNonceLen);
- out += explicitNonceLen;
- maxout -= explicitNonceLen;
- *outlen = explicitNonceLen;
- }
-
- param.type = siBuffer;
- param.data = (unsigned char *)&gcmParams;
- param.len = sizeof(gcmParams);
- gcmParams.pIv = nonce;
- gcmParams.ulIvLen = sizeof(nonce);
- gcmParams.pAAD = (unsigned char *)additionalData; /* const cast */
- gcmParams.ulAADLen = additionalDataLen;
- gcmParams.ulTagBits = tagSize * 8;
-
- if (doDecrypt) {
- rv = PK11_Decrypt(keys->key, CKM_AES_GCM, &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 +1780,26 @@ ssl3_InitPendingContexts(sslSocket *ss, ssl3CipherSpec *spec)
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSpecWriteLock(ss));
- macLength = spec->macDef->mac_size;
calg = spec->cipherDef->calg;
PORT_Assert(alg2Mech[calg].calg == calg);
- if (spec->cipherDef->type == type_aead) {
- spec->cipher = NULL;
- spec->cipherContext = NULL;
- switch (calg) {
- case ssl_calg_aes_gcm:
- spec->aead = ssl3_AESGCM;
- break;
- case ssl_calg_chacha20:
- spec->aead = ssl3_ChaCha20Poly1305;
- break;
- default:
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
- return SECSuccess;
- }
-
- /*
- ** Now setup the MAC contexts,
- ** crypto contexts are setup below.
- */
- macParam.data = (unsigned char *)&macLength;
- macParam.len = sizeof(macLength);
- macParam.type = siBuffer;
+ if (spec->cipherDef->type != type_aead) {
+ macLength = spec->macDef->mac_size;
- spec->keyMaterial.macContext = PK11_CreateContextBySymKey(
- spec->macDef->mmech, CKA_SIGN, spec->keyMaterial.macKey, &macParam);
- if (!spec->keyMaterial.macContext) {
- ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE);
- return SECFailure;
+ /*
+ ** Now setup the MAC contexts,
+ ** crypto contexts are setup below.
+ */
+ macParam.data = (unsigned char *)&macLength;
+ macParam.len = sizeof(macLength);
+ macParam.type = siBuffer;
+
+ spec->keyMaterial.macContext = PK11_CreateContextBySymKey(
+ spec->macDef->mmech, CKA_SIGN, spec->keyMaterial.macKey, &macParam);
+ if (!spec->keyMaterial.macContext) {
+ ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE);
+ return SECFailure;
+ }
}
/*
@@ -1911,15 +1810,21 @@ ssl3_InitPendingContexts(sslSocket *ss, ssl3CipherSpec *spec)
return SECSuccess;
}
- spec->cipher = (SSLCipher)PK11_CipherOp;
encMechanism = ssl3_Alg2Mech(calg);
encMode = (spec->direction == ssl_secret_write) ? CKA_ENCRYPT : CKA_DECRYPT;
+ if (spec->cipherDef->type == type_aead) {
+ encMode |= CKA_NSS_MESSAGE;
+ iv.data = NULL;
+ iv.len = 0;
+ } else {
+ spec->cipher = (SSLCipher)PK11_CipherOp;
+ iv.data = spec->keyMaterial.iv;
+ iv.len = spec->cipherDef->iv_size;
+ }
/*
* build the context
*/
- iv.data = spec->keyMaterial.iv;
- iv.len = spec->cipherDef->iv_size;
spec->cipherContext = PK11_CreateContextBySymKey(encMechanism, encMode,
spec->keyMaterial.key,
&iv);
@@ -2238,26 +2143,55 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec,
isDTLS, contentLen, &pseudoHeader);
PORT_Assert(rv == SECSuccess);
if (cwSpec->cipherDef->type == type_aead) {
- const int nonceLen = cwSpec->cipherDef->explicit_nonce_size;
- const int tagLen = cwSpec->cipherDef->tag_size;
+ const unsigned int nonceLen = cwSpec->cipherDef->explicit_nonce_size;
+ const unsigned int tagLen = cwSpec->cipherDef->tag_size;
+ unsigned int ivOffset = 0;
+ CK_GENERATOR_FUNCTION gen;
+ /* ivOut includes the iv and the nonce and is the internal iv/nonce
+ * for the AEAD function. On Encrypt, this is an in/out parameter */
+ unsigned char ivOut[MAX_IV_LENGTH];
+ ivLen = cwSpec->cipherDef->iv_size;
+
+ PORT_Assert((ivLen + nonceLen) <= MAX_IV_LENGTH);
+ PORT_Assert((ivLen + nonceLen) >= sizeof(sslSequenceNumber));
if (nonceLen + contentLen + tagLen > SSL_BUFFER_SPACE(wrBuf)) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
- rv = cwSpec->aead(
- &cwSpec->keyMaterial,
- PR_FALSE, /* do encrypt */
- SSL_BUFFER_NEXT(wrBuf), /* output */
- &len, /* out len */
- SSL_BUFFER_SPACE(wrBuf), /* max out */
- pIn, contentLen, /* input */
- SSL_BUFFER_BASE(&pseudoHeader), SSL_BUFFER_LEN(&pseudoHeader));
+ if (nonceLen == 0) {
+ ivOffset = ivLen - sizeof(sslSequenceNumber);
+ gen = CKG_GENERATE_COUNTER_XOR;
+ } else {
+ ivOffset = ivLen;
+ gen = CKG_GENERATE_COUNTER;
+ }
+ ivOffset = tls13_SetupAeadIv(isDTLS, ivOut, cwSpec->keyMaterial.iv,
+ ivOffset, ivLen, cwSpec->epoch);
+ rv = tls13_AEAD(cwSpec->cipherContext,
+ PR_FALSE,
+ gen, ivOffset * BPB, /* iv generator params */
+ ivOut, /* iv in */
+ ivOut, /* iv out */
+ ivLen + nonceLen, /* full iv length */
+ NULL, 0, /* nonce is generated*/
+ SSL_BUFFER_BASE(&pseudoHeader), /* aad */
+ SSL_BUFFER_LEN(&pseudoHeader), /* aadlen */
+ SSL_BUFFER_NEXT(wrBuf) + nonceLen, /* output */
+ &len, /* out len */
+ SSL_BUFFER_SPACE(wrBuf) - nonceLen, /* max out */
+ tagLen,
+ pIn, contentLen); /* input */
if (rv != SECSuccess) {
PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
return SECFailure;
}
+ len += nonceLen; /* include the nonce at the beginning */
+ /* copy out the generated iv if we are using explict nonces */
+ if (nonceLen) {
+ PORT_Memcpy(SSL_BUFFER_NEXT(wrBuf), ivOut + ivLen, nonceLen);
+ }
rv = sslBuffer_Skip(wrBuf, len, NULL);
PORT_Assert(rv == SECSuccess); /* Can't fail. */
@@ -2406,7 +2340,6 @@ ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSLContentType ct,
PORT_Assert(cwSpec->cipherDef->max_records <= RECORD_SEQ_MAX);
if (cwSpec->nextSeqNum >= cwSpec->cipherDef->max_records) {
- /* We should have automatically updated before here in TLS 1.3. */
PORT_Assert(cwSpec->version < SSL_LIBRARY_VERSION_TLS_1_3);
SSL_TRC(3, ("%d: SSL[-]: write sequence number at limit 0x%0llx",
SSL_GETPID(), cwSpec->nextSeqNum));
@@ -2438,7 +2371,18 @@ ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSLContentType ct,
}
#else
if (cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ PRUint8 *cipherText = SSL_BUFFER_NEXT(wrBuf);
+ unsigned int bufLen = SSL_BUFFER_LEN(wrBuf);
rv = tls13_ProtectRecord(ss, cwSpec, ct, pIn, contentLen, wrBuf);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ if (IS_DTLS(ss)) {
+ bufLen = SSL_BUFFER_LEN(wrBuf) - bufLen;
+ rv = dtls13_MaskSequenceNumber(ss, cwSpec,
+ SSL_BUFFER_BASE(wrBuf),
+ cipherText, bufLen);
+ }
} else {
rv = ssl3_MACEncryptRecord(cwSpec, ss->sec.isServer, IS_DTLS(ss), ct,
pIn, contentLen, wrBuf);
@@ -4543,6 +4487,21 @@ ssl_IsRsaPssSignatureScheme(SSLSignatureScheme scheme)
}
PRBool
+ssl_IsRsaeSignatureScheme(SSLSignatureScheme scheme)
+{
+ switch (scheme) {
+ case ssl_sig_rsa_pss_rsae_sha256:
+ case ssl_sig_rsa_pss_rsae_sha384:
+ case ssl_sig_rsa_pss_rsae_sha512:
+ return PR_TRUE;
+
+ default:
+ return PR_FALSE;
+ }
+ return PR_FALSE;
+}
+
+PRBool
ssl_IsRsaPkcs1SignatureScheme(SSLSignatureScheme scheme)
{
switch (scheme) {
@@ -5397,10 +5356,11 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
}
if (extensionBuf.len) {
- /* If we are sending a PSK binder, replace the dummy value. Note that
- * we only set statelessResume on the client in TLS 1.3. */
- if (ss->statelessResume &&
- ss->xtnData.sentSessionTicketInClientHello) {
+ /* If we are sending a PSK binder, replace the dummy value. */
+ if (ssl3_ExtensionAdvertised(ss, ssl_tls13_pre_shared_key_xtn)) {
+ PORT_Assert(ss->psk ||
+ (ss->statelessResume && ss->xtnData.sentSessionTicketInClientHello));
+ PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks));
rv = tls13_WriteExtensionsWithBinder(ss, &extensionBuf);
} else {
rv = ssl3_AppendBufferToHandshakeVariable(ss, &extensionBuf, 2);
@@ -6663,7 +6623,7 @@ ssl_CheckServerSessionIdCorrectness(sslSocket *ss, SECItem *sidBytes)
* fake. Check for the real value. */
if (sentRealSid) {
sidMatch = (sidBytes->len == sid->u.ssl3.sessionIDLength) &&
- PORT_Memcmp(sid->u.ssl3.sessionID, sidBytes->data, sidBytes->len) == 0;
+ (!sidBytes->len || PORT_Memcmp(sid->u.ssl3.sessionID, sidBytes->data, sidBytes->len) == 0);
} else {
/* Otherwise, the session ID was a fake if TLS 1.3 compat mode is
* enabled. If so, check for the fake value. */
@@ -6713,13 +6673,13 @@ ssl_CheckServerRandom(sslSocket *ss)
/* Both sections use the same sentinel region. */
PRUint8 *downgrade_sentinel =
ss->ssl3.hs.server_random +
- SSL3_RANDOM_LENGTH - sizeof(tls13_downgrade_random);
+ SSL3_RANDOM_LENGTH - sizeof(tls12_downgrade_random);
if (!PORT_Memcmp(downgrade_sentinel,
- tls13_downgrade_random,
- sizeof(tls13_downgrade_random)) ||
- !PORT_Memcmp(downgrade_sentinel,
tls12_downgrade_random,
- sizeof(tls12_downgrade_random))) {
+ sizeof(tls12_downgrade_random)) ||
+ !PORT_Memcmp(downgrade_sentinel,
+ tls1_downgrade_random,
+ sizeof(tls1_downgrade_random))) {
return SECFailure;
}
}
@@ -7693,16 +7653,6 @@ ssl3_CompleteHandleCertificateRequest(sslSocket *ss,
/* check what the callback function returned */
if ((!ss->ssl3.clientCertificate) || (!ss->ssl3.clientPrivateKey)) {
/* we are missing either the key or cert */
- if (ss->ssl3.clientCertificate) {
- /* got a cert, but no key - free it */
- CERT_DestroyCertificate(ss->ssl3.clientCertificate);
- ss->ssl3.clientCertificate = NULL;
- }
- if (ss->ssl3.clientPrivateKey) {
- /* got a key, but no cert - free it */
- SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
- ss->ssl3.clientPrivateKey = NULL;
- }
goto send_no_certificate;
}
/* Setting ssl3.clientCertChain non-NULL will cause
@@ -7712,22 +7662,33 @@ ssl3_CompleteHandleCertificateRequest(sslSocket *ss,
ss->ssl3.clientCertificate,
certUsageSSLClient, PR_FALSE);
if (ss->ssl3.clientCertChain == NULL) {
- CERT_DestroyCertificate(ss->ssl3.clientCertificate);
- ss->ssl3.clientCertificate = NULL;
- SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
- ss->ssl3.clientPrivateKey = NULL;
goto send_no_certificate;
}
if (ss->ssl3.hs.hashType == handshake_hash_record ||
ss->ssl3.hs.hashType == handshake_hash_single) {
rv = ssl_PickClientSignatureScheme(ss, signatureSchemes,
signatureSchemeCount);
+ if (rv != SECSuccess) {
+ /* This should only happen if our schemes changed or
+ * if an RSA-PSS cert was selected, but the token
+ * does not support PSS schemes. */
+ goto send_no_certificate;
+ }
}
break; /* not an error */
case SECFailure:
default:
send_no_certificate:
+ CERT_DestroyCertificate(ss->ssl3.clientCertificate);
+ SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
+ ss->ssl3.clientCertificate = NULL;
+ ss->ssl3.clientPrivateKey = NULL;
+ if (ss->ssl3.clientCertChain) {
+ CERT_DestroyCertificateList(ss->ssl3.clientCertChain);
+ ss->ssl3.clientCertChain = NULL;
+ }
+
if (ss->version > SSL_LIBRARY_VERSION_3_0) {
ss->ssl3.sendEmptyCert = PR_TRUE;
} else {
@@ -8169,26 +8130,53 @@ ssl3_KEASupportsTickets(const ssl3KEADef *kea_def)
return PR_TRUE;
}
+static PRBool
+ssl3_PeerSupportsCipherSuite(const SECItem *peerSuites, uint16_t suite)
+{
+ for (unsigned int i = 0; i + 1 < peerSuites->len; i += 2) {
+ PRUint16 suite_i = (peerSuites->data[i] << 8) | peerSuites->data[i + 1];
+ if (suite_i == suite) {
+ return PR_TRUE;
+ }
+ }
+ return PR_FALSE;
+}
+
SECStatus
ssl3_NegotiateCipherSuiteInner(sslSocket *ss, const SECItem *suites,
PRUint16 version, PRUint16 *suitep)
{
- unsigned int j;
unsigned int i;
+ SSLVersionRange vrange = { version, version };
- for (j = 0; j < ssl_V3_SUITES_IMPLEMENTED; j++) {
- ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j];
- SSLVersionRange vrange = { version, version };
+ /* If we negotiated an External PSK and that PSK has a ciphersuite
+ * configured, we need to constrain our choice. If the client does
+ * not support it, negotiate a certificate auth suite and fall back.
+ */
+ if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
+ ss->xtnData.selectedPsk &&
+ ss->xtnData.selectedPsk->type == ssl_psk_external &&
+ ss->xtnData.selectedPsk->zeroRttSuite != TLS_NULL_WITH_NULL_NULL) {
+ PRUint16 pskSuite = ss->xtnData.selectedPsk->zeroRttSuite;
+ ssl3CipherSuiteCfg *pskSuiteCfg = ssl_LookupCipherSuiteCfgMutable(pskSuite,
+ ss->cipherSuites);
+ if (ssl3_config_match(pskSuiteCfg, ss->ssl3.policy, &vrange, ss) &&
+ ssl3_PeerSupportsCipherSuite(suites, pskSuite)) {
+ *suitep = pskSuite;
+ return SECSuccess;
+ }
+ }
+
+ for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
+ ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i];
if (!ssl3_config_match(suite, ss->ssl3.policy, &vrange, ss)) {
continue;
}
- for (i = 0; i + 1 < suites->len; i += 2) {
- PRUint16 suite_i = (suites->data[i] << 8) | suites->data[i + 1];
- if (suite_i == suite->cipher_suite) {
- *suitep = suite_i;
- return SECSuccess;
- }
+ if (!ssl3_PeerSupportsCipherSuite(suites, suite->cipher_suite)) {
+ continue;
}
+ *suitep = suite->cipher_suite;
+ return SECSuccess;
}
PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
return SECFailure;
@@ -8491,20 +8479,24 @@ ssl_GenerateServerRandom(sslSocket *ss)
*/
PRUint8 *downgradeSentinel =
ss->ssl3.hs.server_random +
- SSL3_RANDOM_LENGTH - sizeof(tls13_downgrade_random);
-
- switch (ss->vrange.max) {
- case SSL_LIBRARY_VERSION_TLS_1_3:
- PORT_Memcpy(downgradeSentinel,
- tls13_downgrade_random, sizeof(tls13_downgrade_random));
- break;
- case SSL_LIBRARY_VERSION_TLS_1_2:
- PORT_Memcpy(downgradeSentinel,
- tls12_downgrade_random, sizeof(tls12_downgrade_random));
- break;
- default:
- /* Do not change random. */
- break;
+ SSL3_RANDOM_LENGTH - sizeof(tls12_downgrade_random);
+
+ if (ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_2) {
+ switch (ss->version) {
+ case SSL_LIBRARY_VERSION_TLS_1_2:
+ /* vrange.max > 1.2, since we didn't early exit above. */
+ PORT_Memcpy(downgradeSentinel,
+ tls12_downgrade_random, sizeof(tls12_downgrade_random));
+ break;
+ case SSL_LIBRARY_VERSION_TLS_1_1:
+ case SSL_LIBRARY_VERSION_TLS_1_0:
+ PORT_Memcpy(downgradeSentinel,
+ tls1_downgrade_random, sizeof(tls1_downgrade_random));
+ break;
+ default:
+ /* Do not change random. */
+ break;
+ }
}
return SECSuccess;
@@ -8607,15 +8599,12 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
goto loser; /* malformed */
}
- /* Grab the client's cookie, if present. */
+ /* Grab the client's cookie, if present. It is checked after version negotiation. */
if (IS_DTLS(ss)) {
rv = ssl3_ConsumeHandshakeVariable(ss, &cookieBytes, 1, &b, &length);
if (rv != SECSuccess) {
goto loser; /* malformed */
}
- if (cookieBytes.len != 0) {
- goto loser; /* We never send cookies in DTLS 1.2. */
- }
}
/* Grab the list of cipher suites. */
@@ -8721,6 +8710,13 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
errCode = SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER;
goto alert_loser;
}
+
+ /* A DTLS 1.3-only client MUST set the legacy_cookie field to zero length.
+ * If a DTLS 1.3 ClientHello is received with any other value in this field,
+ * the server MUST abort the handshake with an "illegal_parameter" alert. */
+ if (IS_DTLS(ss) && cookieBytes.len != 0) {
+ goto alert_loser;
+ }
} else {
/* HRR is TLS1.3-only. We ignore the Cookie extension here. */
if (ss->ssl3.hs.helloRetry) {
@@ -8741,6 +8737,11 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
!memchr(comps.data, ssl_compression_null, comps.len)) {
goto alert_loser;
}
+
+ /* We never send cookies in DTLS 1.2. */
+ if (IS_DTLS(ss) && cookieBytes.len != 0) {
+ goto loser;
+ }
}
/* Now parse the rest of the extensions. */
@@ -9808,10 +9809,31 @@ ssl3_SendServerKeyExchange(sslSocket *ss)
}
SECStatus
-ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion, sslBuffer *buf)
+ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRBool forCert,
+ sslBuffer *buf)
{
+ SSLSignatureScheme filtered[MAX_SIGNATURE_SCHEMES] = { 0 };
+ unsigned int filteredCount = 0;
+
+ SECStatus rv = ssl3_FilterSigAlgs(ss, minVersion, PR_FALSE, forCert,
+ PR_ARRAY_SIZE(filtered),
+ filtered, &filteredCount);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ return ssl3_EncodeFilteredSigAlgs(ss, filtered, filteredCount, buf);
+}
+
+SECStatus
+ssl3_EncodeFilteredSigAlgs(const sslSocket *ss, const SSLSignatureScheme *schemes,
+ PRUint32 numSchemes, sslBuffer *buf)
+{
+ if (!numSchemes) {
+ PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
+ return SECFailure;
+ }
+
unsigned int lengthOffset;
- PRBool found = PR_FALSE;
SECStatus rv;
rv = sslBuffer_Skip(buf, 2, &lengthOffset);
@@ -9819,23 +9841,68 @@ ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion, sslBuffer *buf)
return SECFailure;
}
- for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
- if (ssl_SignatureSchemeAccepted(minVersion,
- ss->ssl3.signatureSchemes[i])) {
- rv = sslBuffer_AppendNumber(buf, ss->ssl3.signatureSchemes[i], 2);
- if (rv != SECSuccess) {
- return SECFailure;
- }
- found = PR_TRUE;
+ for (unsigned int i = 0; i < numSchemes; ++i) {
+ rv = sslBuffer_AppendNumber(buf, schemes[i], 2);
+ if (rv != SECSuccess) {
+ return SECFailure;
}
}
+ return sslBuffer_InsertLength(buf, lengthOffset, 2);
+}
- if (!found) {
- PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
+/*
+ * In TLS 1.3 we are permitted to advertise support for PKCS#1
+ * schemes. This doesn't affect the signatures in TLS itself, just
+ * those on certificates. Not advertising PKCS#1 signatures creates a
+ * serious compatibility risk as it excludes many certificate chains
+ * that include PKCS#1. Hence, forCert is used to enable advertising
+ * PKCS#1 support. Note that we include these in signature_algorithms
+ * because we don't yet support signature_algorithms_cert. TLS 1.3
+ * requires that PKCS#1 schemes are placed last in the list if they
+ * are present. This sorting can be removed once we support
+ * signature_algorithms_cert.
+ */
+SECStatus
+ssl3_FilterSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRBool disableRsae,
+ PRBool forCert,
+ unsigned int maxSchemes, SSLSignatureScheme *filteredSchemes,
+ unsigned int *numFilteredSchemes)
+{
+ PORT_Assert(filteredSchemes);
+ PORT_Assert(numFilteredSchemes);
+ PORT_Assert(maxSchemes >= ss->ssl3.signatureSchemeCount);
+ if (maxSchemes < ss->ssl3.signatureSchemeCount) {
return SECFailure;
}
- return sslBuffer_InsertLength(buf, lengthOffset, 2);
+ *numFilteredSchemes = 0;
+ PRBool allowUnsortedPkcs1 = forCert && minVersion < SSL_LIBRARY_VERSION_TLS_1_3;
+ for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
+ if (disableRsae && ssl_IsRsaeSignatureScheme(ss->ssl3.signatureSchemes[i])) {
+ continue;
+ }
+ if (ssl_SignatureSchemeAccepted(minVersion,
+ ss->ssl3.signatureSchemes[i],
+ allowUnsortedPkcs1)) {
+ filteredSchemes[(*numFilteredSchemes)++] = ss->ssl3.signatureSchemes[i];
+ }
+ }
+ if (forCert && !allowUnsortedPkcs1) {
+ for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
+ if (disableRsae && ssl_IsRsaeSignatureScheme(ss->ssl3.signatureSchemes[i])) {
+ continue;
+ }
+ if (!ssl_SignatureSchemeAccepted(minVersion,
+ ss->ssl3.signatureSchemes[i],
+ PR_FALSE) &&
+ ssl_SignatureSchemeAccepted(minVersion,
+ ss->ssl3.signatureSchemes[i],
+ PR_TRUE)) {
+ filteredSchemes[(*numFilteredSchemes)++] = ss->ssl3.signatureSchemes[i];
+ }
+ }
+ }
+ return SECSuccess;
}
static SECStatus
@@ -9871,7 +9938,7 @@ ssl3_SendCertificateRequest(sslSocket *ss)
length = 1 + certTypesLength + 2 + calen;
if (isTLS12) {
- rv = ssl3_EncodeSigAlgs(ss, ss->version, &sigAlgsBuf);
+ rv = ssl3_EncodeSigAlgs(ss, ss->version, PR_TRUE /* forCert */, &sigAlgsBuf);
if (rv != SECSuccess) {
return rv;
}
@@ -11232,6 +11299,8 @@ static SECStatus ssl3_FinishHandshake(sslSocket *ss);
static SECStatus
ssl3_AlwaysFail(sslSocket *ss)
{
+ /* The caller should have cleared the callback. */
+ ss->ssl3.hs.restartTarget = ssl3_AlwaysFail;
PORT_SetError(PR_INVALID_STATE_ERROR);
return SECFailure;
}
@@ -11324,9 +11393,9 @@ ssl3_ComputeTLSFinished(sslSocket *ss, ssl3CipherSpec *spec,
}
if (spec->version < SSL_LIBRARY_VERSION_TLS_1_2) {
- tls_mac_params.prfMechanism = CKM_TLS_PRF;
+ tls_mac_params.prfHashMechanism = CKM_TLS_PRF;
} else {
- tls_mac_params.prfMechanism = ssl3_GetPrfHashMechanism(ss);
+ tls_mac_params.prfHashMechanism = ssl3_GetPrfHashMechanism(ss);
}
tls_mac_params.ulMacLength = 12;
tls_mac_params.ulServerOrClient = isServer ? 1 : 2;
@@ -11667,7 +11736,6 @@ ssl3_CacheWrappedSecret(sslSocket *ss, sslSessionID *sid,
static SECStatus
ssl3_HandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length)
{
- sslSessionID *sid = ss->sec.ci.sid;
SECStatus rv = SECSuccess;
PRBool isServer = ss->sec.isServer;
PRBool isTLS;
@@ -11811,15 +11879,6 @@ xmit_loser:
return rv;
}
- if (sid->cached == never_cached && !ss->opt.noCache) {
- rv = ssl3_FillInCachedSID(ss, sid, ss->ssl3.crSpec->masterSecret);
-
- /* If the wrap failed, we don't cache the sid.
- * The connection continues normally however.
- */
- ss->ssl3.hs.cacheSID = rv == SECSuccess;
- }
-
if (ss->ssl3.hs.authCertificatePending) {
if (ss->ssl3.hs.restartTarget) {
PR_NOT_REACHED("ssl3_HandleFinished: unexpected restartTarget");
@@ -11884,33 +11943,45 @@ ssl3_FinishHandshake(sslSocket *ss)
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(ss->ssl3.hs.restartTarget == NULL);
+ sslSessionID *sid = ss->sec.ci.sid;
+ SECStatus sidRv = SECFailure;
/* The first handshake is now completed. */
ss->handshake = NULL;
+ if (sid->cached == never_cached && !ss->opt.noCache) {
+ /* If the wrap fails, don't cache the sid. The connection proceeds
+ * normally, so the rv is only used to determine whether we cache. */
+ sidRv = ssl3_FillInCachedSID(ss, sid, ss->ssl3.crSpec->masterSecret);
+ }
+
/* RFC 5077 Section 3.3: "The client MUST NOT treat the ticket as valid
- * until it has verified the server's Finished message." When the server
- * sends a NewSessionTicket in a resumption handshake, we must wait until
- * the handshake is finished (we have verified the server's Finished
- * AND the server's certificate) before we update the ticket in the sid.
- *
- * This must be done before we call ssl_CacheSessionID(ss)
- * because CacheSID requires the session ticket to already be set, and also
- * because of the lazy lock creation scheme used by CacheSID and
- * ssl3_SetSIDSessionTicket.
- */
+ * until it has verified the server's Finished message." When the server
+ * sends a NewSessionTicket in a resumption handshake, we must wait until
+ * the handshake is finished (we have verified the server's Finished
+ * AND the server's certificate) before we update the ticket in the sid.
+ *
+ * This must be done before we call ssl_CacheSessionID(ss)
+ * because CacheSID requires the session ticket to already be set, and also
+ * because of the lazy lock creation scheme used by CacheSID and
+ * ssl3_SetSIDSessionTicket. */
if (ss->ssl3.hs.receivedNewSessionTicket) {
PORT_Assert(!ss->sec.isServer);
- ssl3_SetSIDSessionTicket(ss->sec.ci.sid, &ss->ssl3.hs.newSessionTicket);
- /* The sid took over the ticket data */
+ if (sidRv == SECSuccess) {
+ /* The sid takes over the ticket data */
+ ssl3_SetSIDSessionTicket(ss->sec.ci.sid,
+ &ss->ssl3.hs.newSessionTicket);
+ } else {
+ PORT_Assert(ss->ssl3.hs.newSessionTicket.ticket.data);
+ SECITEM_FreeItem(&ss->ssl3.hs.newSessionTicket.ticket,
+ PR_FALSE);
+ }
PORT_Assert(!ss->ssl3.hs.newSessionTicket.ticket.data);
ss->ssl3.hs.receivedNewSessionTicket = PR_FALSE;
}
-
- if (ss->ssl3.hs.cacheSID) {
+ if (sidRv == SECSuccess) {
PORT_Assert(ss->sec.ci.sid->cached == never_cached);
ssl_CacheSessionID(ss);
- ss->ssl3.hs.cacheSID = PR_FALSE;
}
ss->ssl3.hs.canFalseStart = PR_FALSE; /* False Start phase is complete */
@@ -12308,41 +12379,26 @@ loser : {
return SECFailure;
}
-/* These macros return the given value with the MSB copied to all the other
- * bits. They use the fact that arithmetic shift shifts-in the sign bit.
- * However, this is not ensured by the C standard so you may need to replace
- * them with something else for odd compilers. */
-#define DUPLICATE_MSB_TO_ALL(x) ((unsigned)((int)(x) >> (sizeof(int) * 8 - 1)))
-#define DUPLICATE_MSB_TO_ALL_8(x) ((unsigned char)(DUPLICATE_MSB_TO_ALL(x)))
-
/* SECStatusToMask returns, in constant time, a mask value of all ones if
* rv == SECSuccess. Otherwise it returns zero. */
static unsigned int
SECStatusToMask(SECStatus rv)
{
- unsigned int good;
- /* rv ^ SECSuccess is zero iff rv == SECSuccess. Subtracting one results
- * in the MSB being set to one iff it was zero before. */
- good = rv ^ SECSuccess;
- good--;
- return DUPLICATE_MSB_TO_ALL(good);
+ return PORT_CT_EQ(rv, SECSuccess);
}
-/* ssl_ConstantTimeGE returns 0xff if a>=b and 0x00 otherwise. */
+/* ssl_ConstantTimeGE returns 0xffffffff if a>=b and 0x00 otherwise. */
static unsigned char
ssl_ConstantTimeGE(unsigned int a, unsigned int b)
{
- a -= b;
- return DUPLICATE_MSB_TO_ALL(~a);
+ return PORT_CT_GE(a, b);
}
-/* ssl_ConstantTimeEQ8 returns 0xff if a==b and 0x00 otherwise. */
+/* ssl_ConstantTimeEQ returns 0xffffffff if a==b and 0x00 otherwise. */
static unsigned char
-ssl_ConstantTimeEQ8(unsigned char a, unsigned char b)
+ssl_ConstantTimeEQ(unsigned char a, unsigned char b)
{
- unsigned int c = a ^ b;
- c--;
- return DUPLICATE_MSB_TO_ALL_8(c);
+ return PORT_CT_EQ(a, b);
}
/* ssl_constantTimeSelect return a if mask is 0xFF and b if mask is 0x00 */
@@ -12357,7 +12413,7 @@ ssl_RemoveSSLv3CBCPadding(sslBuffer *plaintext,
unsigned int blockSize,
unsigned int macSize)
{
- unsigned int paddingLength, good, t;
+ unsigned int paddingLength, good;
const unsigned int overhead = 1 /* padding length byte */ + macSize;
/* These lengths are all public so we can test them in non-constant
@@ -12368,13 +12424,9 @@ ssl_RemoveSSLv3CBCPadding(sslBuffer *plaintext,
paddingLength = plaintext->buf[plaintext->len - 1];
/* SSLv3 padding bytes are random and cannot be checked. */
- t = plaintext->len;
- t -= paddingLength + overhead;
- /* If len >= paddingLength+overhead then the MSB of t is zero. */
- good = DUPLICATE_MSB_TO_ALL(~t);
+ good = PORT_CT_GE(plaintext->len, paddingLength + overhead);
/* SSLv3 requires that the padding is minimal. */
- t = blockSize - (paddingLength + 1);
- good &= DUPLICATE_MSB_TO_ALL(~t);
+ good &= PORT_CT_GE(blockSize, paddingLength + 1);
plaintext->len -= good & (paddingLength + 1);
return (good & SECSuccess) | (~good & SECFailure);
}
@@ -12382,7 +12434,7 @@ ssl_RemoveSSLv3CBCPadding(sslBuffer *plaintext,
SECStatus
ssl_RemoveTLSCBCPadding(sslBuffer *plaintext, unsigned int macSize)
{
- unsigned int paddingLength, good, t, toCheck, i;
+ unsigned int paddingLength, good, toCheck, i;
const unsigned int overhead = 1 /* padding length byte */ + macSize;
/* These lengths are all public so we can test them in non-constant
@@ -12392,10 +12444,7 @@ ssl_RemoveTLSCBCPadding(sslBuffer *plaintext, unsigned int macSize)
}
paddingLength = plaintext->buf[plaintext->len - 1];
- t = plaintext->len;
- t -= paddingLength + overhead;
- /* If len >= paddingLength+overhead then the MSB of t is zero. */
- good = DUPLICATE_MSB_TO_ALL(~t);
+ good = PORT_CT_GE(plaintext->len, paddingLength + overhead);
/* The padding consists of a length byte at the end of the record and then
* that many bytes of padding, all with the same value as the length byte.
@@ -12412,10 +12461,9 @@ ssl_RemoveTLSCBCPadding(sslBuffer *plaintext, unsigned int macSize)
}
for (i = 0; i < toCheck; i++) {
- t = paddingLength - i;
/* If i <= paddingLength then the MSB of t is zero and mask is
* 0xff. Otherwise, mask is 0. */
- unsigned char mask = DUPLICATE_MSB_TO_ALL(~t);
+ unsigned char mask = PORT_CT_LE(i, paddingLength);
unsigned char b = plaintext->buf[plaintext->len - 1 - i];
/* The final |paddingLength+1| bytes should all have the value
* |paddingLength|. Therefore the XOR should be zero. */
@@ -12430,7 +12478,7 @@ ssl_RemoveTLSCBCPadding(sslBuffer *plaintext, unsigned int macSize)
good &= good >> 2;
good &= good >> 1;
good <<= sizeof(good) * 8 - 1;
- good = DUPLICATE_MSB_TO_ALL(good);
+ good = PORT_CT_DUPLICATE_MSB_TO_ALL(good);
plaintext->len -= good & (paddingLength + 1);
return (good & SECSuccess) | (~good & SECFailure);
@@ -12523,7 +12571,7 @@ ssl_CBCExtractMAC(sslBuffer *plaintext,
0, rotateOffset);
for (i = 0; i < macSize; i++) {
for (j = 0; j < macSize; j++) {
- out[j] |= rotatedMac[i] & ssl_ConstantTimeEQ8(j, rotateOffset);
+ out[j] |= rotatedMac[i] & ssl_ConstantTimeEQ(j, rotateOffset);
}
rotateOffset++;
rotateOffset = ssl_constantTimeSelect(ssl_ConstantTimeGE(rotateOffset, macSize),
@@ -12633,21 +12681,50 @@ ssl3_UnprotectRecord(sslSocket *ss,
* ciphertext by a fixed byte count, but it is not true in general.
* Each AEAD cipher should provide a function that returns the
* plaintext length for a given ciphertext. */
- unsigned int decryptedLen =
- cText->buf->len - cipher_def->explicit_nonce_size -
- cipher_def->tag_size;
+ const unsigned int explicitNonceLen = cipher_def->explicit_nonce_size;
+ const unsigned int tagLen = cipher_def->tag_size;
+ unsigned int nonceLen = explicitNonceLen;
+ unsigned int decryptedLen = cText->buf->len - nonceLen - tagLen;
+ /* even though read doesn't return and IV, we still need a space to put
+ * the combined iv/nonce n the gcm 1.2 case*/
+ unsigned char ivOut[MAX_IV_LENGTH];
+ unsigned char *iv = NULL;
+ unsigned char *nonce = NULL;
+
+ ivLen = cipher_def->iv_size;
+
rv = ssl3_BuildRecordPseudoHeader(
spec->epoch, cText->seqNum,
rType, isTLS, rVersion, IS_DTLS(ss), decryptedLen, &header);
PORT_Assert(rv == SECSuccess);
- rv = spec->aead(&spec->keyMaterial,
- PR_TRUE, /* do decrypt */
- plaintext->buf, /* out */
- &plaintext->len, /* outlen */
- plaintext->space, /* maxout */
- cText->buf->buf, /* in */
- cText->buf->len, /* inlen */
- SSL_BUFFER_BASE(&header), SSL_BUFFER_LEN(&header));
+
+ /* build the iv */
+ if (explicitNonceLen == 0) {
+ nonceLen = sizeof(cText->seqNum);
+ iv = spec->keyMaterial.iv;
+ nonce = SSL_BUFFER_BASE(&header);
+ } else {
+ PORT_Memcpy(ivOut, spec->keyMaterial.iv, ivLen);
+ PORT_Memset(ivOut + ivLen, 0, explicitNonceLen);
+ iv = ivOut;
+ nonce = cText->buf->buf;
+ nonceLen = explicitNonceLen;
+ }
+ rv = tls13_AEAD(spec->cipherContext, PR_TRUE,
+ CKG_NO_GENERATE, 0, /* iv generator params
+ * (not used in decrypt)*/
+ iv, /* iv in */
+ NULL, /* iv out */
+ ivLen + explicitNonceLen, /* full iv length */
+ nonce, nonceLen, /* nonce in */
+ SSL_BUFFER_BASE(&header), /* aad */
+ SSL_BUFFER_LEN(&header), /* aadlen */
+ plaintext->buf, /* output */
+ &plaintext->len, /* out len */
+ plaintext->space, /* max out */
+ tagLen,
+ cText->buf->buf + explicitNonceLen, /* input */
+ cText->buf->len - explicitNonceLen); /* input len */
if (rv != SECSuccess) {
good = 0;
}
@@ -12895,6 +12972,12 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText)
}
isTLS = (PRBool)(spec->version > SSL_LIBRARY_VERSION_3_0);
if (IS_DTLS(ss)) {
+ if (dtls13_MaskSequenceNumber(ss, spec, cText->hdr,
+ SSL_BUFFER_BASE(cText->buf), SSL_BUFFER_LEN(cText->buf)) != SECSuccess) {
+ ssl_ReleaseSpecReadLock(ss); /*****************************/
+ /* code already set. */
+ return SECFailure;
+ }
if (!dtls_IsRelevant(ss, spec, cText, &cText->seqNum)) {
ssl_ReleaseSpecReadLock(ss); /*****************************/
return SECSuccess;
@@ -12936,7 +13019,10 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText)
/* Encrypted application data records could arrive before the handshake
* completes in DTLS 1.3. These can look like valid TLS 1.2 application_data
* records in epoch 0, which is never valid. Pretend they didn't decrypt. */
- if (spec->epoch == 0 && rType == ssl_ct_application_data) {
+
+ if (spec->epoch == 0 && ((IS_DTLS(ss) &&
+ dtls_IsDtls13Ciphertext(0, rType)) ||
+ rType == ssl_ct_application_data)) {
PORT_SetError(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA);
alert = unexpected_message;
rv = SECFailure;
@@ -12975,12 +13061,18 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText)
ss->ssl3.hs.ws != idle_handshake &&
cText->buf->len == 1 &&
cText->buf->buf[0] == change_cipher_spec_choice) {
- /* Ignore the CCS. */
- return SECSuccess;
+ if (!ss->ssl3.hs.rejectCcs) {
+ /* Allow only the first CCS. */
+ ss->ssl3.hs.rejectCcs = PR_TRUE;
+ return SECSuccess;
+ } else {
+ alert = unexpected_message;
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER);
+ }
}
- if (IS_DTLS(ss) ||
- (ss->sec.isServer &&
+ if ((IS_DTLS(ss) && !dtls13_AeadLimitReached(spec)) ||
+ (!IS_DTLS(ss) && ss->sec.isServer &&
ss->ssl3.hs.zeroRttIgnore == ssl_0rtt_ignore_trial)) {
/* Silently drop the packet unless we sent a fatal alert. */
if (ss->ssl3.fatalAlertSent) {
@@ -13103,7 +13195,6 @@ ssl3_InitState(sslSocket *ss)
ss->ssl3.hs.currentSecret = NULL;
ss->ssl3.hs.resumptionMasterSecret = NULL;
ss->ssl3.hs.dheSecret = NULL;
- ss->ssl3.hs.pskBinderKey = NULL;
ss->ssl3.hs.clientEarlyTrafficSecret = NULL;
ss->ssl3.hs.clientHsTrafficSecret = NULL;
ss->ssl3.hs.serverHsTrafficSecret = NULL;
@@ -13477,8 +13568,6 @@ ssl3_DestroySSL3Info(sslSocket *ss)
PK11_FreeSymKey(ss->ssl3.hs.resumptionMasterSecret);
if (ss->ssl3.hs.dheSecret)
PK11_FreeSymKey(ss->ssl3.hs.dheSecret);
- if (ss->ssl3.hs.pskBinderKey)
- PK11_FreeSymKey(ss->ssl3.hs.pskBinderKey);
if (ss->ssl3.hs.clientEarlyTrafficSecret)
PK11_FreeSymKey(ss->ssl3.hs.clientEarlyTrafficSecret);
if (ss->ssl3.hs.clientHsTrafficSecret)
@@ -13497,6 +13586,63 @@ ssl3_DestroySSL3Info(sslSocket *ss)
ss->ssl3.hs.zeroRttState = ssl_0rtt_none;
/* Destroy TLS 1.3 buffered early data. */
tls13_DestroyEarlyData(&ss->ssl3.hs.bufferedEarlyData);
+ /* Destroy TLS 1.3 PSKs */
+ tls13_DestroyPskList(&ss->ssl3.hs.psks);
+}
+
+/*
+ * parse the policy value for a single algorithm in a cipher_suite,
+ * return TRUE if we disallow by the cipher suite by policy
+ * (we don't have to parse any more algorithm policies on this cipher suite),
+ * otherwise return FALSE.
+ * 1. If we don't have the required policy, disable by default, disallow by
+ * policy and return TRUE (no more processing needed).
+ * 2. If we have the required policy, and we are disabled, return FALSE,
+ * (if we are disabled, we only need to parse policy, not default).
+ * 3. If we have the required policy, and we aren't adjusting the defaults
+ * return FALSE. (only parsing the policy, not default).
+ * 4. We have the required policy and we are adjusting the defaults.
+ * If we are setting default = FALSE, set isDisabled to true so that
+ * we don't try to re-enable the cipher suite based on a different
+ * algorithm.
+ */
+PRBool
+ssl_HandlePolicy(int cipher_suite, SECOidTag policyOid,
+ PRUint32 requiredPolicy, PRBool *isDisabled)
+{
+ PRUint32 policy;
+ SECStatus rv;
+
+ /* first fetch the policy for this algorithm */
+ rv = NSS_GetAlgorithmPolicy(policyOid, &policy);
+ if (rv != SECSuccess) {
+ return PR_FALSE; /* no policy value, continue to the next algorithm */
+ }
+ /* first, are we allowed by policy, if not turn off allow and disable */
+ if (!(policy & requiredPolicy)) {
+ ssl_CipherPrefSetDefault(cipher_suite, PR_FALSE);
+ ssl_CipherPolicySet(cipher_suite, SSL_NOT_ALLOWED);
+ return PR_TRUE;
+ }
+ /* If we are already disabled, or the policy isn't setting a default
+ * we are done processing this algorithm */
+ if (*isDisabled || (policy & NSS_USE_DEFAULT_NOT_VALID)) {
+ return PR_FALSE;
+ }
+ /* set the default value for the cipher suite. If we disable the cipher
+ * suite, remember that so we don't process the next default. This has
+ * the effect of disabling the whole cipher suite if any of the
+ * algorithms it uses are disabled by default. We still have to
+ * process the upper level because the cipher suite is still allowed
+ * by policy, and we may still have to disallow it based on other
+ * algorithms in the cipher suite. */
+ if (policy & NSS_USE_DEFAULT_SSL_ENABLE) {
+ ssl_CipherPrefSetDefault(cipher_suite, PR_TRUE);
+ } else {
+ *isDisabled = PR_TRUE;
+ ssl_CipherPrefSetDefault(cipher_suite, PR_FALSE);
+ }
+ return PR_FALSE;
}
#define MAP_NULL(x) (((x) != 0) ? (x) : SEC_OID_NULL_CIPHER)
@@ -13517,30 +13663,30 @@ ssl3_ApplyNSSPolicy(void)
for (i = 1; i < PR_ARRAY_SIZE(cipher_suite_defs); ++i) {
const ssl3CipherSuiteDef *suite = &cipher_suite_defs[i];
SECOidTag policyOid;
+ PRBool isDisabled = PR_FALSE;
+
+ /* if we haven't explicitly disabled it below enable by policy */
+ ssl_CipherPolicySet(suite->cipher_suite, SSL_ALLOWED);
+ /* now check the various key exchange, ciphers and macs and
+ * if we ever disallow by policy, we are done, go to the next cipher
+ */
policyOid = MAP_NULL(kea_defs[suite->key_exchange_alg].oid);
- rv = NSS_GetAlgorithmPolicy(policyOid, &policy);
- if (rv == SECSuccess && !(policy & NSS_USE_ALG_IN_SSL_KX)) {
- ssl_CipherPrefSetDefault(suite->cipher_suite, PR_FALSE);
- ssl_CipherPolicySet(suite->cipher_suite, SSL_NOT_ALLOWED);
+ if (ssl_HandlePolicy(suite->cipher_suite, policyOid,
+ NSS_USE_ALG_IN_SSL_KX, &isDisabled)) {
continue;
}
policyOid = MAP_NULL(ssl_GetBulkCipherDef(suite)->oid);
- rv = NSS_GetAlgorithmPolicy(policyOid, &policy);
- if (rv == SECSuccess && !(policy & NSS_USE_ALG_IN_SSL)) {
- ssl_CipherPrefSetDefault(suite->cipher_suite, PR_FALSE);
- ssl_CipherPolicySet(suite->cipher_suite, SSL_NOT_ALLOWED);
+ if (ssl_HandlePolicy(suite->cipher_suite, policyOid,
+ NSS_USE_ALG_IN_SSL, &isDisabled)) {
continue;
}
if (ssl_GetBulkCipherDef(suite)->type != type_aead) {
policyOid = MAP_NULL(ssl_GetMacDefByAlg(suite->mac_alg)->oid);
- rv = NSS_GetAlgorithmPolicy(policyOid, &policy);
- if (rv == SECSuccess && !(policy & NSS_USE_ALG_IN_SSL)) {
- ssl_CipherPrefSetDefault(suite->cipher_suite, PR_FALSE);
- ssl_CipherPolicySet(suite->cipher_suite,
- SSL_NOT_ALLOWED);
+ if (ssl_HandlePolicy(suite->cipher_suite, policyOid,
+ NSS_USE_ALG_IN_SSL, &isDisabled)) {
continue;
}
}
diff --git a/security/nss/lib/ssl/ssl3ext.c b/security/nss/lib/ssl/ssl3ext.c
index 7e674f0e0..65a69450d 100644
--- a/security/nss/lib/ssl/ssl3ext.c
+++ b/security/nss/lib/ssl/ssl3ext.c
@@ -10,6 +10,7 @@
#include "nssrenam.h"
#include "nss.h"
+#include "pk11pub.h"
#include "ssl.h"
#include "sslimpl.h"
#include "sslproto.h"
@@ -962,6 +963,7 @@ ssl3_InitExtensionData(TLSExtensionData *xtnData, const sslSocket *ss)
xtnData->peerDelegCred = NULL;
xtnData->peerRequestedDelegCred = PR_FALSE;
xtnData->sendingDelegCredToPeer = PR_FALSE;
+ xtnData->selectedPsk = NULL;
}
void
@@ -969,6 +971,8 @@ ssl3_DestroyExtensionData(TLSExtensionData *xtnData)
{
ssl3_FreeSniNameArray(xtnData);
PORT_Free(xtnData->sigSchemes);
+ PORT_Free(xtnData->delegCredSigSchemes);
+ PORT_Free(xtnData->delegCredSigSchemesAdvertised);
SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE);
tls13_DestroyKeyShares(&xtnData->remoteKeyShares);
SECITEM_FreeItem(&xtnData->certReqContext, PR_FALSE);
diff --git a/security/nss/lib/ssl/ssl3ext.h b/security/nss/lib/ssl/ssl3ext.h
index 97319c7d9..ff2f7c211 100644
--- a/security/nss/lib/ssl/ssl3ext.h
+++ b/security/nss/lib/ssl/ssl3ext.h
@@ -77,6 +77,16 @@ struct TLSExtensionDataStr {
SSLSignatureScheme *sigSchemes;
unsigned int numSigSchemes;
+ /* Keep track of signature schemes that the remote peer supports for
+ * Delegated Credentials signatures, as well was those we have
+ * advertised (for purposes of validating any received DC).
+ * This list may not be the same as those supported for certificates.
+ * Only valid for TLS 1.3. */
+ SSLSignatureScheme *delegCredSigSchemes;
+ unsigned int numDelegCredSigSchemes;
+ SSLSignatureScheme *delegCredSigSchemesAdvertised;
+ unsigned int numDelegCredSigSchemesAdvertised;
+
SECItem certReqContext;
CERTDistNames certReqAuthorities;
@@ -124,6 +134,10 @@ struct TLSExtensionDataStr {
* |tls13_MaybeSetDelegatedCredential|.
*/
PRBool sendingDelegCredToPeer;
+
+ /* A non-owning reference to the selected PSKs. MUST NOT be freed directly,
+ * rather through tls13_DestoryPskList(). */
+ sslPsk *selectedPsk;
};
typedef struct TLSExtensionStr {
diff --git a/security/nss/lib/ssl/ssl3exthandle.c b/security/nss/lib/ssl/ssl3exthandle.c
index 206cb00e4..cb4698253 100644
--- a/security/nss/lib/ssl/ssl3exthandle.c
+++ b/security/nss/lib/ssl/ssl3exthandle.c
@@ -796,7 +796,7 @@ ssl3_EncodeSessionTicket(sslSocket *ss, const NewSessionTicket *ticket,
* This is compared to the expected time, which should differ only as a
* result of clock errors or errors in the RTT estimate.
*/
- ticketAgeBaseline = (ssl_Time(ss) - ss->ssl3.hs.serverHelloTime) / PR_USEC_PER_MSEC;
+ ticketAgeBaseline = ss->ssl3.hs.rttEstimate / PR_USEC_PER_MSEC;
ticketAgeBaseline -= ticket->ticket_age_add;
rv = sslBuffer_AppendNumber(&plaintext, ticketAgeBaseline, 4);
if (rv != SECSuccess)
@@ -1034,7 +1034,9 @@ ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket,
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
- parsedTicket->timestamp = (PRTime)temp << 32;
+
+ /* Cast to avoid undefined behavior if the top bit is set. */
+ parsedTicket->timestamp = (PRTime)((PRUint64)temp << 32);
rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
@@ -1056,8 +1058,11 @@ ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket,
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
+#ifndef UNSAFE_FUZZER_MODE
+ /* A well-behaving server should only write 0 or 1. */
PORT_Assert(temp == PR_TRUE || temp == PR_FALSE);
- parsedTicket->extendedMasterSecretUsed = (PRBool)temp;
+#endif
+ parsedTicket->extendedMasterSecretUsed = temp ? PR_TRUE : PR_FALSE;
rv = ssl3_ExtConsumeHandshake(ss, &temp, 4, &buffer, &len);
if (rv != SECSuccess) {
@@ -1647,7 +1652,7 @@ ssl3_SendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
minVersion = ss->vrange.min; /* ClientHello */
}
- SECStatus rv = ssl3_EncodeSigAlgs(ss, minVersion, buf);
+ SECStatus rv = ssl3_EncodeSigAlgs(ss, minVersion, PR_TRUE /* forCert */, buf);
if (rv != SECSuccess) {
return SECFailure;
}
diff --git a/security/nss/lib/ssl/ssl3gthr.c b/security/nss/lib/ssl/ssl3gthr.c
index f9c741746..45cfb31bc 100644
--- a/security/nss/lib/ssl/ssl3gthr.c
+++ b/security/nss/lib/ssl/ssl3gthr.c
@@ -268,6 +268,7 @@ dtls_GatherData(sslSocket *ss, sslGather *gs, int flags)
PRUint8 contentType;
unsigned int headerLen;
SECStatus rv;
+ PRBool dtlsLengthPresent = PR_TRUE;
SSL_TRC(30, ("dtls_GatherData"));
@@ -316,8 +317,20 @@ dtls_GatherData(sslSocket *ss, sslGather *gs, int flags)
headerLen = 13;
} else if (contentType == ssl_ct_application_data) {
headerLen = 7;
- } else if ((contentType & 0xe0) == 0x20) {
- headerLen = 2;
+ } else if (dtls_IsDtls13Ciphertext(ss->version, contentType)) {
+ /* We don't support CIDs. */
+ if (contentType & 0x10) {
+ PORT_Assert(PR_FALSE);
+ PORT_SetError(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE);
+ gs->dtlsPacketOffset = 0;
+ gs->dtlsPacket.len = 0;
+ return -1;
+ }
+
+ dtlsLengthPresent = (contentType & 0x04) == 0x04;
+ PRUint8 dtlsSeqNoSize = (contentType & 0x08) ? 2 : 1;
+ PRUint8 dtlsLengthBytes = dtlsLengthPresent ? 2 : 0;
+ headerLen = 1 + dtlsSeqNoSize + dtlsLengthBytes;
} else {
SSL_DBG(("%d: SSL3[%d]: invalid first octet (%d) for DTLS",
SSL_GETPID(), ss->fd, contentType));
@@ -345,12 +358,10 @@ dtls_GatherData(sslSocket *ss, sslGather *gs, int flags)
gs->dtlsPacketOffset += headerLen;
/* Have received SSL3 record header in gs->hdr. */
- if (headerLen == 13) {
- gs->remainder = (gs->hdr[11] << 8) | gs->hdr[12];
- } else if (headerLen == 7) {
- gs->remainder = (gs->hdr[5] << 8) | gs->hdr[6];
+ if (dtlsLengthPresent) {
+ gs->remainder = (gs->hdr[headerLen - 2] << 8) |
+ gs->hdr[headerLen - 1];
} else {
- PORT_Assert(headerLen == 2);
gs->remainder = gs->dtlsPacket.len - gs->dtlsPacketOffset;
}
@@ -600,6 +611,46 @@ ssl3_GatherAppDataRecord(sslSocket *ss, int flags)
return rv;
}
+static SECStatus
+ssl_HandleZeroRttRecordData(sslSocket *ss, const PRUint8 *data, unsigned int len)
+{
+ PORT_Assert(ss->sec.isServer);
+ if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) {
+ sslBuffer buf = { CONST_CAST(PRUint8, data), len, len, PR_TRUE };
+ return tls13_HandleEarlyApplicationData(ss, &buf);
+ }
+ if (ss->ssl3.hs.zeroRttState == ssl_0rtt_ignored &&
+ ss->ssl3.hs.zeroRttIgnore != ssl_0rtt_ignore_none) {
+ /* We're ignoring 0-RTT so drop this record quietly. */
+ return SECSuccess;
+ }
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA);
+ return SECFailure;
+}
+
+/* Ensure that application data in the wrong epoch is blocked. */
+static PRBool
+ssl_IsApplicationDataPermitted(sslSocket *ss, PRUint16 epoch)
+{
+ /* Epoch 0 is never OK. */
+ if (epoch == 0) {
+ return PR_FALSE;
+ }
+ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+ return ss->firstHsDone;
+ }
+ /* TLS 1.3 application data. */
+ if (epoch >= TrafficKeyApplicationData) {
+ return ss->firstHsDone;
+ }
+ /* TLS 1.3 early data is server only. Further checks aren't needed
+ * as those are handled in ssl_HandleZeroRttRecordData. */
+ if (epoch == TrafficKeyEarlyApplicationData) {
+ return ss->sec.isServer;
+ }
+ return PR_FALSE;
+}
+
SECStatus
SSLExp_RecordLayerData(PRFileDesc *fd, PRUint16 epoch,
SSLContentType contentType,
@@ -626,8 +677,8 @@ SSLExp_RecordLayerData(PRFileDesc *fd, PRUint16 epoch,
goto early_loser; /* Rely on the existing code. */
}
- /* Don't allow application data before handshake completion. */
- if (contentType == ssl_ct_application_data && !ss->firstHsDone) {
+ if (contentType == ssl_ct_application_data &&
+ !ssl_IsApplicationDataPermitted(ss, epoch)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto early_loser;
}
@@ -638,7 +689,18 @@ SSLExp_RecordLayerData(PRFileDesc *fd, PRUint16 epoch,
if (epoch < ss->ssl3.crSpec->epoch) {
epochError = SEC_ERROR_INVALID_ARGS; /* Too c/old. */
} else if (epoch > ss->ssl3.crSpec->epoch) {
- epochError = PR_WOULD_BLOCK_ERROR; /* Too warm/new. */
+ /* If a TLS 1.3 server is not expecting EndOfEarlyData,
+ * moving from 1 to 2 is a signal to execute the code
+ * as though that message had been received. Let that pass. */
+ if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
+ ss->opt.suppressEndOfEarlyData &&
+ ss->sec.isServer &&
+ ss->ssl3.crSpec->epoch == TrafficKeyEarlyApplicationData &&
+ epoch == TrafficKeyHandshake) {
+ epochError = 0;
+ } else {
+ epochError = PR_WOULD_BLOCK_ERROR; /* Too warm/new. */
+ }
} else {
epochError = 0; /* Just right. */
}
@@ -649,11 +711,18 @@ SSLExp_RecordLayerData(PRFileDesc *fd, PRUint16 epoch,
}
/* If the handshake is still running, we need to run that. */
- ssl_Get1stHandshakeLock(ss);
rv = ssl_Do1stHandshake(ss);
if (rv != SECSuccess && PORT_GetError() != PR_WOULD_BLOCK_ERROR) {
+ goto early_loser;
+ }
+
+ /* 0-RTT needs its own special handling here. */
+ if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
+ epoch == TrafficKeyEarlyApplicationData &&
+ contentType == ssl_ct_application_data) {
+ rv = ssl_HandleZeroRttRecordData(ss, data, len);
ssl_Release1stHandshakeLock(ss);
- return SECFailure;
+ return rv;
}
/* Finally, save the data... */
diff --git a/security/nss/lib/ssl/ssl3prot.h b/security/nss/lib/ssl/ssl3prot.h
index ffe837301..edf459290 100644
--- a/security/nss/lib/ssl/ssl3prot.h
+++ b/security/nss/lib/ssl/ssl3prot.h
@@ -14,7 +14,7 @@ typedef PRUint16 SSL3ProtocolVersion;
/* version numbers are defined in sslproto.h */
/* DTLS 1.3 is still a draft. */
-#define DTLS_1_3_DRAFT_VERSION 28
+#define DTLS_1_3_DRAFT_VERSION 38
typedef PRUint16 ssl3CipherSuite;
/* The cipher suites are defined in sslproto.h */
diff --git a/security/nss/lib/ssl/sslencode.c b/security/nss/lib/ssl/sslencode.c
index e59e758ff..d07b544ab 100644
--- a/security/nss/lib/ssl/sslencode.c
+++ b/security/nss/lib/ssl/sslencode.c
@@ -64,7 +64,10 @@ sslBuffer_Append(sslBuffer *b, const void *data, unsigned int len)
if (rv != SECSuccess) {
return SECFailure; /* Code already set. */
}
- PORT_Memcpy(SSL_BUFFER_NEXT(b), data, len);
+ if (len > 0) {
+ PORT_Assert(data);
+ PORT_Memcpy(SSL_BUFFER_NEXT(b), data, len);
+ }
b->len += len;
return SECSuccess;
}
diff --git a/security/nss/lib/ssl/sslerr.h b/security/nss/lib/ssl/sslerr.h
index 7100b0226..eb8f7c2da 100644
--- a/security/nss/lib/ssl/sslerr.h
+++ b/security/nss/lib/ssl/sslerr.h
@@ -274,6 +274,8 @@ typedef enum {
SSL_ERROR_DC_BAD_SIGNATURE = (SSL_ERROR_BASE + 183),
SSL_ERROR_DC_INVALID_KEY_USAGE = (SSL_ERROR_BASE + 184),
SSL_ERROR_DC_EXPIRED = (SSL_ERROR_BASE + 185),
+ SSL_ERROR_DC_INAPPROPRIATE_VALIDITY_PERIOD = (SSL_ERROR_BASE + 186),
+ SSL_ERROR_FEATURE_DISABLED = (SSL_ERROR_BASE + 187),
SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
} SSLErrorCodes;
#endif /* NO_SECURITY_ERROR_ENUM */
diff --git a/security/nss/lib/ssl/sslexp.h b/security/nss/lib/ssl/sslexp.h
index b734d86ca..8a92a39ad 100644
--- a/security/nss/lib/ssl/sslexp.h
+++ b/security/nss/lib/ssl/sslexp.h
@@ -254,7 +254,8 @@ typedef struct SSLAntiReplayContextStr SSLAntiReplayContext;
*
* This function will fail unless the socket has an active TLS 1.3 session.
* Earlier versions of TLS do not support the spontaneous sending of the
- * NewSessionTicket message.
+ * NewSessionTicket message. It will also fail when external PSK
+ * authentication has been negotiated.
*/
#define SSL_SendSessionTicket(fd, appToken, appTokenLen) \
SSL_EXPERIMENTAL_API("SSL_SendSessionTicket", \
@@ -380,6 +381,10 @@ typedef SSLHelloRetryRequestAction(PR_CALLBACK *SSLHelloRetryRequestCallback)(
* a server. This can be called once at a time, and is not allowed
* until an answer is received.
*
+ * This function is not allowed for use with DTLS or when external
+ * PSK authentication has been negotiated. SECFailure is returned
+ * in both cases.
+ *
* The AuthCertificateCallback is called when the answer is received.
* If the answer is accepted by the server, the value returned by
* SSL_PeerCertificate() is replaced. If you need to remember all the
@@ -662,7 +667,11 @@ typedef SECStatus(PR_CALLBACK *SSLRecordWriteCallback)(
* used in TLS. The lower bits of the IV are XORed with the 64-bit counter to
* produce the nonce. Otherwise, this is an AEAD interface similar to that
* described in RFC 5116.
- */
+ *
+ * Note: SSL_MakeAead internally calls SSL_MakeVariantAead with a variant of
+ * "stream", behaving as noted above. If "datagram" variant is passed instead,
+ * the Label prefix used in HKDF-Expand is "dtls13" instead of "tls13 ". See
+ * 7.1 of RFC 8446 and draft-ietf-tls-dtls13-34. */
typedef struct SSLAeadContextStr SSLAeadContext;
#define SSL_MakeAead(version, cipherSuite, secret, \
@@ -676,6 +685,18 @@ typedef struct SSLAeadContextStr SSLAeadContext;
(version, cipherSuite, secret, \
labelPrefix, labelPrefixLen, ctx))
+#define SSL_MakeVariantAead(version, cipherSuite, variant, secret, \
+ labelPrefix, labelPrefixLen, ctx) \
+ SSL_EXPERIMENTAL_API("SSL_MakeVariantAead", \
+ (PRUint16 _version, PRUint16 _cipherSuite, \
+ SSLProtocolVariant _variant, \
+ PK11SymKey * _secret, \
+ const char *_labelPrefix, \
+ unsigned int _labelPrefixLen, \
+ SSLAeadContext **_ctx), \
+ (version, cipherSuite, variant, secret, \
+ labelPrefix, labelPrefixLen, ctx))
+
#define SSL_AeadEncrypt(ctx, counter, aad, aadLen, in, inLen, \
output, outputLen, maxOutputLen) \
SSL_EXPERIMENTAL_API("SSL_AeadEncrypt", \
@@ -716,8 +737,13 @@ typedef struct SSLAeadContextStr SSLAeadContext;
PK11SymKey * *_keyp), \
(version, cipherSuite, salt, ikm, keyp))
-/* SSL_HkdfExpandLabel produces a key with a mechanism that is suitable for
- * input to SSL_HkdfExpandLabel or SSL_MakeAead. */
+/* SSL_HkdfExpandLabel and SSL_HkdfVariantExpandLabel produce a key with a
+ * mechanism that is suitable for input to SSL_HkdfExpandLabel or SSL_MakeAead.
+ *
+ * Note: SSL_HkdfVariantExpandLabel internally calls SSL_HkdfExpandLabel with
+ * a default "stream" variant. If "datagram" variant is passed instead, the
+ * Label prefix used in HKDF-Expand is "dtls13" instead of "tls13 ". See 7.1 of
+ * RFC 8446 and draft-ietf-tls-dtls13-34. */
#define SSL_HkdfExpandLabel(version, cipherSuite, prk, \
hsHash, hsHashLen, label, labelLen, keyp) \
SSL_EXPERIMENTAL_API("SSL_HkdfExpandLabel", \
@@ -729,9 +755,28 @@ typedef struct SSLAeadContextStr SSLAeadContext;
(version, cipherSuite, prk, \
hsHash, hsHashLen, label, labelLen, keyp))
-/* SSL_HkdfExpandLabelWithMech uses the KDF from the selected TLS version and
- * cipher suite, as with the other calls, but the provided mechanism and key
- * size. This allows the key to be used more widely. */
+#define SSL_HkdfVariantExpandLabel(version, cipherSuite, prk, \
+ hsHash, hsHashLen, label, labelLen, variant, \
+ keyp) \
+ SSL_EXPERIMENTAL_API("SSL_HkdfVariantExpandLabel", \
+ (PRUint16 _version, PRUint16 _cipherSuite, \
+ PK11SymKey * _prk, \
+ const PRUint8 *_hsHash, unsigned int _hsHashLen, \
+ const char *_label, unsigned int _labelLen, \
+ SSLProtocolVariant _variant, \
+ PK11SymKey **_keyp), \
+ (version, cipherSuite, prk, \
+ hsHash, hsHashLen, label, labelLen, variant, \
+ keyp))
+
+/* SSL_HkdfExpandLabelWithMech and SSL_HkdfVariantExpandLabelWithMech use the KDF
+ * from the selected TLS version and cipher suite, as with the other calls, but
+ * the provided mechanism and key size. This allows the key to be used more widely.
+ *
+ * Note: SSL_HkdfExpandLabelWithMech internally calls SSL_HkdfVariantExpandLabelWithMech
+ * with a default "stream" variant. If "datagram" variant is passed instead, the
+ * Label prefix used in HKDF-Expand is "dtls13" instead of "tls13 ". See 7.1 of
+ * RFC 8446 and draft-ietf-tls-dtls13-34. */
#define SSL_HkdfExpandLabelWithMech(version, cipherSuite, prk, \
hsHash, hsHashLen, label, labelLen, \
mech, keySize, keyp) \
@@ -746,6 +791,21 @@ typedef struct SSLAeadContextStr SSLAeadContext;
hsHash, hsHashLen, label, labelLen, \
mech, keySize, keyp))
+#define SSL_HkdfVariantExpandLabelWithMech(version, cipherSuite, prk, \
+ hsHash, hsHashLen, label, labelLen, \
+ mech, keySize, variant, keyp) \
+ SSL_EXPERIMENTAL_API("SSL_HkdfVariantExpandLabelWithMech", \
+ (PRUint16 _version, PRUint16 _cipherSuite, \
+ PK11SymKey * _prk, \
+ const PRUint8 *_hsHash, unsigned int _hsHashLen, \
+ const char *_label, unsigned int _labelLen, \
+ CK_MECHANISM_TYPE _mech, unsigned int _keySize, \
+ SSLProtocolVariant _variant, \
+ PK11SymKey **_keyp), \
+ (version, cipherSuite, prk, \
+ hsHash, hsHashLen, label, labelLen, \
+ mech, keySize, variant, keyp))
+
/* SSL_SetTimeFunc overrides the default time function (PR_Now()) and provides
* an alternative source of time for the socket. This is used in testing, and in
* applications that need better control over how the clock is accessed. Set the
@@ -826,6 +886,117 @@ typedef PRTime(PR_CALLBACK *SSLTimeFunc)(void *arg);
PRUint16 _numCiphers), \
(fd, cipherOrder, numCiphers))
+/*
+ * The following functions expose a masking primitive that uses ciphersuite and
+ * version information to set paramaters for the masking key and mask generation
+ * logic. This is only supported for TLS 1.3.
+ *
+ * The key and IV are generated using the TLS KDF with a custom label. That is
+ * HKDF-Expand-Label(secret, label, "", L), where |label| is an input to
+ * SSL_CreateMaskingContext.
+ *
+ * The mask generation logic in SSL_CreateMask is determined by the underlying
+ * symmetric cipher:
+ * - For AES-ECB, mask = AES-ECB(mask_key, sample). |len| must be <= 16 as
+ * the output is limited to a single block.
+ * - For CHACHA20, mask = ChaCha20(mask_key, sample[0..3], sample[4..15], {0}.len)
+ * That is, the low 4 bytes of |sample| used as the counter, the remaining 12 bytes
+ * the nonce. We encrypt |len| bytes of zeros, returning the raw key stream.
+ *
+ * The caller must pre-allocate at least |len| bytes for output. If the underlying
+ * cipher cannot produce the requested amount of data, SECFailure is returned.
+ */
+
+typedef struct SSLMaskingContextStr {
+ CK_MECHANISM_TYPE mech;
+ PRUint16 version;
+ PRUint16 cipherSuite;
+ PK11SymKey *secret;
+} SSLMaskingContext;
+
+#define SSL_CreateMaskingContext(version, cipherSuite, secret, \
+ label, labelLen, ctx) \
+ SSL_EXPERIMENTAL_API("SSL_CreateMaskingContext", \
+ (PRUint16 _version, PRUint16 _cipherSuite, \
+ PK11SymKey * _secret, \
+ const char *_label, \
+ unsigned int _labelLen, \
+ SSLMaskingContext **_ctx), \
+ (version, cipherSuite, secret, label, labelLen, ctx))
+
+#define SSL_CreateVariantMaskingContext(version, cipherSuite, variant, \
+ secret, label, labelLen, ctx) \
+ SSL_EXPERIMENTAL_API("SSL_CreateVariantMaskingContext", \
+ (PRUint16 _version, PRUint16 _cipherSuite, \
+ SSLProtocolVariant _variant, \
+ PK11SymKey * _secret, \
+ const char *_label, \
+ unsigned int _labelLen, \
+ SSLMaskingContext **_ctx), \
+ (version, cipherSuite, variant, secret, \
+ label, labelLen, ctx))
+
+#define SSL_DestroyMaskingContext(ctx) \
+ SSL_EXPERIMENTAL_API("SSL_DestroyMaskingContext", \
+ (SSLMaskingContext * _ctx), \
+ (ctx))
+
+#define SSL_CreateMask(ctx, sample, sampleLen, mask, maskLen) \
+ SSL_EXPERIMENTAL_API("SSL_CreateMask", \
+ (SSLMaskingContext * _ctx, const PRUint8 *_sample, \
+ unsigned int _sampleLen, PRUint8 *_mask, \
+ unsigned int _maskLen), \
+ (ctx, sample, sampleLen, mask, maskLen))
+
+#define SSL_SetDtls13VersionWorkaround(fd, enabled) \
+ SSL_EXPERIMENTAL_API("SSL_SetDtls13VersionWorkaround", \
+ (PRFileDesc * _fd, PRBool _enabled), (fd, enabled))
+
+/* SSL_AddExternalPsk() and SSL_AddExternalPsk0Rtt() can be used to
+ * set an external PSK on a socket. If successful, this PSK will
+ * be used in all subsequent connection attempts for this socket.
+ * This has no effect if the maximum TLS version is < 1.3.
+ *
+ * This API currently only accepts a single PSK, so multiple calls to
+ * either function will fail. An EPSK can be replaced by calling
+ * SSL_RemoveExternalPsk followed by SSL_AddExternalPsk.
+ * For both functions, the label is expected to be a unique identifier
+ * for the external PSK. Should en external PSK have the same label
+ * as a configured resumption PSK identity, the external PSK will
+ * take precedence.
+ *
+ * If you want to enable early data, you need to also provide a
+ * cipher suite for 0-RTT and a limit for the early data using
+ * SSL_AddExternalPsk0Rtt(). If you want to explicitly disallow
+ * certificate authentication, use SSL_AuthCertificateHook to set
+ * a callback that rejects all certificate chains.
+ */
+#define SSL_AddExternalPsk(fd, psk, identity, identityLen, hash) \
+ SSL_EXPERIMENTAL_API("SSL_AddExternalPsk", \
+ (PRFileDesc * _fd, PK11SymKey * _psk, \
+ const PRUint8 *_identity, unsigned int _identityLen, \
+ SSLHashType _hash), \
+ (fd, psk, identity, identityLen, hash))
+
+#define SSL_AddExternalPsk0Rtt(fd, psk, identity, identityLen, hash, \
+ zeroRttSuite, maxEarlyData) \
+ SSL_EXPERIMENTAL_API("SSL_AddExternalPsk0Rtt", \
+ (PRFileDesc * _fd, PK11SymKey * _psk, \
+ const PRUint8 *_identity, unsigned int _identityLen, \
+ SSLHashType _hash, PRUint16 _zeroRttSuite, \
+ PRUint32 _maxEarlyData), \
+ (fd, psk, identity, identityLen, hash, \
+ zeroRttSuite, maxEarlyData))
+
+/* SSLExp_RemoveExternalPsk() removes an external PSK from socket
+ * configuration. Returns SECSuccess if the PSK was removed
+ * successfully, and SECFailure otherwise. */
+#define SSL_RemoveExternalPsk(fd, identity, identityLen) \
+ SSL_EXPERIMENTAL_API("SSL_RemoveExternalPsk", \
+ (PRFileDesc * _fd, const PRUint8 *_identity, \
+ unsigned int _identityLen), \
+ (fd, identity, identityLen))
+
/* Deprecated experimental APIs */
#define SSL_UseAltServerHelloType(fd, enable) SSL_DEPRECATED_EXPERIMENTAL_API
#define SSL_SetupAntiReplay(a, b, c) SSL_DEPRECATED_EXPERIMENTAL_API
diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h
index 4a393b281..35d0c2d6b 100644
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -37,6 +37,7 @@
typedef struct sslSocketStr sslSocket;
typedef struct sslNamedGroupDefStr sslNamedGroupDef;
typedef struct sslEsniKeysStr sslEsniKeys;
+typedef struct sslPskStr sslPsk;
typedef struct sslDelegatedCredentialStr sslDelegatedCredential;
typedef struct sslEphemeralKeyPairStr sslEphemeralKeyPair;
typedef struct TLS13KeyShareEntryStr TLS13KeyShareEntry;
@@ -281,6 +282,8 @@ typedef struct sslOptionsStr {
unsigned int enableV2CompatibleHello : 1;
unsigned int enablePostHandshakeAuth : 1;
unsigned int enableDelegatedCredentials : 1;
+ unsigned int enableDtls13VersionCompat : 1;
+ unsigned int suppressEndOfEarlyData : 1;
} sslOptions;
typedef enum { sslHandshakingUndetermined = 0,
@@ -653,8 +656,6 @@ typedef struct SSL3HandshakeStateStr {
* One of NULL, ssl3_SendClientSecondRound, ssl3_FinishHandshake,
* or ssl3_AlwaysFail */
sslRestartTarget restartTarget;
- /* Shared state between ssl3_HandleFinished and ssl3_FinishHandshake */
- PRBool cacheSID;
PRBool canFalseStart; /* Can/did we False Start */
/* Which preliminaryinfo values have been set. */
@@ -689,9 +690,8 @@ typedef struct SSL3HandshakeStateStr {
/* This group of values is used for TLS 1.3 and above */
PK11SymKey *currentSecret; /* The secret down the "left hand side"
* of the TLS 1.3 key schedule. */
- PK11SymKey *resumptionMasterSecret; /* The resumption PSK. */
+ PK11SymKey *resumptionMasterSecret; /* The resumption_master_secret. */
PK11SymKey *dheSecret; /* The (EC)DHE shared secret. */
- PK11SymKey *pskBinderKey; /* Used to compute the PSK binder. */
PK11SymKey *clientEarlyTrafficSecret; /* The secret we use for 0-RTT. */
PK11SymKey *clientHsTrafficSecret; /* The source keys for handshake */
PK11SymKey *serverHsTrafficSecret; /* traffic keys. */
@@ -710,18 +710,26 @@ typedef struct SSL3HandshakeStateStr {
* or received. */
PRBool receivedCcs; /* A server received ChangeCipherSpec
* before the handshake started. */
+ PRBool rejectCcs; /* Excessive ChangeCipherSpecs are rejected. */
PRBool clientCertRequested; /* True if CertificateRequest received. */
+ PRBool endOfFlight; /* Processed a full flight (DTLS 1.3). */
ssl3KEADef kea_def_mutable; /* Used to hold the writable kea_def
* we use for TLS 1.3 */
- PRTime serverHelloTime; /* Time the ServerHello flight was sent. */
PRUint16 ticketNonce; /* A counter we use for tickets. */
SECItem fakeSid; /* ... (server) the SID the client used. */
- PRBool endOfFlight; /* Processed a full flight (DTLS 1.3). */
+
+ /* rttEstimate is used to guess the round trip time between server and client.
+ * When the server sends ServerHello it sets this to the current time.
+ * Only after it receives a message from the client's second flight does it
+ * set the value to something resembling an RTT estimate. */
+ PRTime rttEstimate;
/* The following lists contain DTLSHandshakeRecordEntry */
PRCList dtlsSentHandshake; /* Used to map records to handshake fragments. */
PRCList dtlsRcvdHandshake; /* Handshake records we have received
* used to generate ACKs. */
+
+ PRCList psks; /* A list of PSKs, resumption and/or external. */
} SSL3HandshakeState;
#define SSL_ASSERT_HASHES_EMPTY(ss) \
@@ -810,7 +818,7 @@ typedef struct {
/* |seqNum| eventually contains the reconstructed sequence number. */
sslSequenceNumber seqNum;
/* The header of the cipherText. */
- const PRUint8 *hdr;
+ PRUint8 *hdr;
unsigned int hdrLen;
/* |buf| is the payload of the ciphertext. */
@@ -1099,6 +1107,9 @@ struct sslSocketStr {
/* Anti-replay for TLS 1.3 0-RTT. */
SSLAntiReplayContext *antiReplay;
+
+ /* An out-of-band PSK. */
+ sslPsk *psk;
};
struct sslSelfEncryptKeysStr {
@@ -1682,8 +1693,14 @@ SECStatus ssl3_HandleServerSpki(sslSocket *ss);
SECStatus ssl3_AuthCertificate(sslSocket *ss);
SECStatus ssl_ReadCertificateStatus(sslSocket *ss, PRUint8 *b,
PRUint32 length);
-SECStatus ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion,
+SECStatus ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRBool forCert,
sslBuffer *buf);
+SECStatus ssl3_EncodeFilteredSigAlgs(const sslSocket *ss,
+ const SSLSignatureScheme *schemes,
+ PRUint32 numSchemes, sslBuffer *buf);
+SECStatus ssl3_FilterSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRBool disableRsae, PRBool forCert,
+ unsigned int maxSchemes, SSLSignatureScheme *filteredSchemes,
+ unsigned int *numFilteredSchemes);
SECStatus ssl_GetCertificateRequestCAs(const sslSocket *ss,
unsigned int *calenp,
const SECItem **namesp,
@@ -1824,6 +1841,10 @@ SECStatus SSLExp_GetCurrentEpoch(PRFileDesc *fd, PRUint16 *readEpoch,
SECStatus SSLExp_MakeAead(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *secret,
const char *labelPrefix, unsigned int labelPrefixLen,
SSLAeadContext **ctx);
+
+SECStatus SSLExp_MakeVariantAead(PRUint16 version, PRUint16 cipherSuite, SSLProtocolVariant variant,
+ PK11SymKey *secret, const char *labelPrefix,
+ unsigned int labelPrefixLen, SSLAeadContext **ctx);
SECStatus SSLExp_DestroyAead(SSLAeadContext *ctx);
SECStatus SSLExp_AeadEncrypt(const SSLAeadContext *ctx, PRUint64 counter,
const PRUint8 *aad, unsigned int aadLen,
@@ -1840,15 +1861,59 @@ SECStatus SSLExp_HkdfExpandLabel(PRUint16 version, PRUint16 cipherSuite, PK11Sym
const PRUint8 *hsHash, unsigned int hsHashLen,
const char *label, unsigned int labelLen,
PK11SymKey **key);
+SECStatus SSLExp_HkdfVariantExpandLabel(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk,
+ const PRUint8 *hsHash, unsigned int hsHashLen,
+ const char *label, unsigned int labelLen,
+ SSLProtocolVariant variant, PK11SymKey **key);
SECStatus
SSLExp_HkdfExpandLabelWithMech(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk,
const PRUint8 *hsHash, unsigned int hsHashLen,
const char *label, unsigned int labelLen,
CK_MECHANISM_TYPE mech, unsigned int keySize,
PK11SymKey **keyp);
+SECStatus
+SSLExp_HkdfVariantExpandLabelWithMech(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk,
+ const PRUint8 *hsHash, unsigned int hsHashLen,
+ const char *label, unsigned int labelLen,
+ CK_MECHANISM_TYPE mech, unsigned int keySize,
+ SSLProtocolVariant variant, PK11SymKey **keyp);
+
+SECStatus SSLExp_SetDtls13VersionWorkaround(PRFileDesc *fd, PRBool enabled);
SECStatus SSLExp_SetTimeFunc(PRFileDesc *fd, SSLTimeFunc f, void *arg);
+extern SECStatus ssl_CreateMaskingContextInner(PRUint16 version, PRUint16 cipherSuite,
+ SSLProtocolVariant variant,
+ PK11SymKey *secret,
+ const char *label,
+ unsigned int labelLen,
+ SSLMaskingContext **ctx);
+
+extern SECStatus ssl_CreateMaskInner(SSLMaskingContext *ctx, const PRUint8 *sample,
+ unsigned int sampleLen, PRUint8 *outMask,
+ unsigned int maskLen);
+
+extern SECStatus ssl_DestroyMaskingContextInner(SSLMaskingContext *ctx);
+
+SECStatus SSLExp_CreateMaskingContext(PRUint16 version, PRUint16 cipherSuite,
+ PK11SymKey *secret,
+ const char *label,
+ unsigned int labelLen,
+ SSLMaskingContext **ctx);
+
+SECStatus SSLExp_CreateVariantMaskingContext(PRUint16 version, PRUint16 cipherSuite,
+ SSLProtocolVariant variant,
+ PK11SymKey *secret,
+ const char *label,
+ unsigned int labelLen,
+ SSLMaskingContext **ctx);
+
+SECStatus SSLExp_CreateMask(SSLMaskingContext *ctx, const PRUint8 *sample,
+ unsigned int sampleLen, PRUint8 *mask,
+ unsigned int len);
+
+SECStatus SSLExp_DestroyMaskingContext(SSLMaskingContext *ctx);
+
SEC_END_PROTOS
#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
diff --git a/security/nss/lib/ssl/sslinfo.c b/security/nss/lib/ssl/sslinfo.c
index b069888e2..a92ed1604 100644
--- a/security/nss/lib/ssl/sslinfo.c
+++ b/security/nss/lib/ssl/sslinfo.c
@@ -7,6 +7,7 @@
#include "sslimpl.h"
#include "sslproto.h"
#include "tls13hkdf.h"
+#include "tls13psk.h"
#include "tls13subcerts.h"
SECStatus
@@ -80,6 +81,13 @@ SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len)
inf.signatureScheme = sid->sigScheme;
}
inf.resumed = ss->statelessResume || ss->ssl3.hs.isResuming;
+ if (inf.resumed) {
+ inf.pskType = ssl_psk_resume;
+ } else if (inf.authType == ssl_auth_psk) {
+ inf.pskType = ssl_psk_external;
+ } else {
+ inf.pskType = ssl_psk_none;
+ }
inf.peerDelegCred = tls13_IsVerifyingWithDelegatedCredential(ss);
if (sid) {
@@ -147,8 +155,14 @@ SSL_GetPreliminaryChannelInfo(PRFileDesc *fd,
if (ss->sec.ci.sid &&
(ss->ssl3.hs.zeroRttState == ssl_0rtt_sent ||
ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted)) {
- inf.maxEarlyDataSize =
- ss->sec.ci.sid->u.ssl3.locked.sessionTicket.max_early_data_size;
+ if (ss->statelessResume) {
+ inf.maxEarlyDataSize =
+ ss->sec.ci.sid->u.ssl3.locked.sessionTicket.max_early_data_size;
+ } else if (ss->psk) {
+ /* We may have cleared the handshake list, so check the socket.
+ * This is permissable since we only support one EPSK at a time. */
+ inf.maxEarlyDataSize = ss->psk->maxEarlyData;
+ }
} else {
inf.maxEarlyDataSize = 0;
}
@@ -415,24 +429,37 @@ tls13_Exporter(sslSocket *ss, PK11SymKey *secret,
return SECFailure;
}
+ SSLHashType hashAlg;
+ /* Early export requires a PSK. As in 0-RTT, default
+ * to the first PSK if no suite is negotiated yet. */
+ if (secret == ss->ssl3.hs.earlyExporterSecret && !ss->ssl3.hs.suite_def) {
+ if (PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ hashAlg = ((sslPsk *)PR_LIST_HEAD(&ss->ssl3.hs.psks))->hash;
+ } else {
+ hashAlg = tls13_GetHash(ss);
+ }
+
/* Pre-hash the context. */
- rv = tls13_ComputeHash(ss, &contextHash, context, contextLen);
+ rv = tls13_ComputeHash(ss, &contextHash, context, contextLen, hashAlg);
if (rv != SECSuccess) {
return rv;
}
rv = tls13_DeriveSecretNullHash(ss, secret, label, labelLen,
- &innerSecret);
+ &innerSecret, hashAlg);
if (rv != SECSuccess) {
return rv;
}
rv = tls13_HkdfExpandLabelRaw(innerSecret,
- tls13_GetHash(ss),
+ hashAlg,
contextHash.u.raw, contextHash.len,
kExporterInnerLabel,
strlen(kExporterInnerLabel),
- out, outLen);
+ ss->protocolVariant, out, outLen);
PK11_FreeSymKey(innerSecret);
return rv;
}
diff --git a/security/nss/lib/ssl/sslnonce.c b/security/nss/lib/ssl/sslnonce.c
index b7b5b7fe5..3daab4b75 100644
--- a/security/nss/lib/ssl/sslnonce.c
+++ b/security/nss/lib/ssl/sslnonce.c
@@ -537,6 +537,9 @@ ssl_DecodeResumptionToken(sslSessionID *sid, const PRUint8 *encodedToken,
}
if (readerBuffer.len) {
PORT_Assert(readerBuffer.buf);
+ if (sid->peerID) {
+ PORT_Free((void *)sid->peerID);
+ }
sid->peerID = PORT_Strdup((const char *)readerBuffer.buf);
}
@@ -1120,12 +1123,13 @@ ssl_CacheSessionID(sslSocket *ss)
{
sslSecurityInfo *sec = &ss->sec;
PORT_Assert(sec);
+ PORT_Assert(sec->ci.sid->cached == never_cached);
if (sec->ci.sid && !sec->ci.sid->u.ssl3.keys.resumable) {
return;
}
- if (!ss->sec.isServer && ss->resumptionTokenCallback) {
+ if (!sec->isServer && ss->resumptionTokenCallback) {
ssl_CacheExternalToken(ss);
return;
}
@@ -1197,14 +1201,15 @@ ssl3_SetSIDSessionTicket(sslSessionID *sid,
* anything yet, so no locking is needed.
*/
if (sid->u.ssl3.lock) {
- PORT_Assert(sid->cached == in_client_cache);
PR_RWLock_Wlock(sid->u.ssl3.lock);
+ /* Another thread may have evicted, or it may be in external cache. */
+ PORT_Assert(sid->cached != never_cached);
}
/* If this was in the client cache, then we might have to free the old
* ticket. In TLS 1.3, we might get a replacement ticket if the server
* sends more than one ticket. */
if (sid->u.ssl3.locked.sessionTicket.ticket.data) {
- PORT_Assert(sid->cached == in_client_cache ||
+ PORT_Assert(sid->cached != never_cached ||
sid->version >= SSL_LIBRARY_VERSION_TLS_1_3);
SECITEM_FreeItem(&sid->u.ssl3.locked.sessionTicket.ticket,
PR_FALSE);
diff --git a/security/nss/lib/ssl/sslprimitive.c b/security/nss/lib/ssl/sslprimitive.c
index 540c17840..2afecfb16 100644
--- a/security/nss/lib/ssl/sslprimitive.c
+++ b/security/nss/lib/ssl/sslprimitive.c
@@ -6,6 +6,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "blapit.h"
#include "keyhi.h"
#include "pk11pub.h"
#include "sechash.h"
@@ -19,47 +20,28 @@
#include "tls13hkdf.h"
struct SSLAeadContextStr {
- CK_MECHANISM_TYPE mech;
- ssl3KeyMaterial keys;
+ /* sigh, the API creates a single context, but then uses either encrypt
+ * and decrypt on that context. We should take an encrypt/decrypt
+ * variable here, but for now create two contexts. */
+ PK11Context *encryptContext;
+ PK11Context *decryptContext;
+ int tagLen;
+ int ivLen;
+ unsigned char iv[MAX_IV_LENGTH];
};
-static SECStatus
-tls13_GetHashAndCipher(PRUint16 version, PRUint16 cipherSuite,
- SSLHashType *hash, const ssl3BulkCipherDef **cipher)
-{
- if (version < SSL_LIBRARY_VERSION_TLS_1_3) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
-
- // Lookup and check the suite.
- SSLVersionRange vrange = { version, version };
- if (!ssl3_CipherSuiteAllowedForVersionRange(cipherSuite, &vrange)) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
- const ssl3CipherSuiteDef *suiteDef = ssl_LookupCipherSuiteDef(cipherSuite);
- const ssl3BulkCipherDef *cipherDef = ssl_GetBulkCipherDef(suiteDef);
- if (cipherDef->type != type_aead) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
- *hash = suiteDef->prf_hash;
- if (cipher != NULL) {
- *cipher = cipherDef;
- }
- return SECSuccess;
-}
-
SECStatus
-SSLExp_MakeAead(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *secret,
- const char *labelPrefix, unsigned int labelPrefixLen,
- SSLAeadContext **ctx)
+SSLExp_MakeVariantAead(PRUint16 version, PRUint16 cipherSuite, SSLProtocolVariant variant,
+ PK11SymKey *secret, const char *labelPrefix,
+ unsigned int labelPrefixLen, SSLAeadContext **ctx)
{
SSLAeadContext *out = NULL;
char label[255]; // Maximum length label.
static const char *const keySuffix = "key";
static const char *const ivSuffix = "iv";
+ CK_MECHANISM_TYPE mech;
+ SECItem nullParams = { siBuffer, NULL, 0 };
+ PK11SymKey *key = NULL;
PORT_Assert(strlen(keySuffix) >= strlen(ivSuffix));
if (secret == NULL || ctx == NULL ||
@@ -81,7 +63,9 @@ SSLExp_MakeAead(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *secret,
if (out == NULL) {
goto loser;
}
- out->mech = ssl3_Alg2Mech(cipher->calg);
+ mech = ssl3_Alg2Mech(cipher->calg);
+ out->ivLen = cipher->iv_size + cipher->explicit_nonce_size;
+ out->tagLen = cipher->tag_size;
memcpy(label, labelPrefix, labelPrefixLen);
memcpy(label + labelPrefixLen, ivSuffix, strlen(ivSuffix));
@@ -89,8 +73,8 @@ SSLExp_MakeAead(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *secret,
unsigned int ivLen = cipher->iv_size + cipher->explicit_nonce_size;
rv = tls13_HkdfExpandLabelRaw(secret, hash,
NULL, 0, // Handshake hash.
- label, labelLen,
- out->keys.iv, ivLen);
+ label, labelLen, variant,
+ out->iv, ivLen);
if (rv != SECSuccess) {
goto loser;
}
@@ -99,91 +83,96 @@ SSLExp_MakeAead(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *secret,
labelLen = labelPrefixLen + strlen(keySuffix);
rv = tls13_HkdfExpandLabel(secret, hash,
NULL, 0, // Handshake hash.
- label, labelLen,
- out->mech, cipher->key_size, &out->keys.key);
+ label, labelLen, mech, cipher->key_size,
+ variant, &key);
if (rv != SECSuccess) {
goto loser;
}
+ /* We really need to change the API to Create a context for each
+ * encrypt and decrypt rather than a single call that does both. it's
+ * almost certain that the underlying application tries to use the same
+ * context for both. */
+ out->encryptContext = PK11_CreateContextBySymKey(mech,
+ CKA_NSS_MESSAGE | CKA_ENCRYPT,
+ key, &nullParams);
+ if (out->encryptContext == NULL) {
+ goto loser;
+ }
+
+ out->decryptContext = PK11_CreateContextBySymKey(mech,
+ CKA_NSS_MESSAGE | CKA_DECRYPT,
+ key, &nullParams);
+ if (out->decryptContext == NULL) {
+ goto loser;
+ }
+
+ PK11_FreeSymKey(key);
*ctx = out;
return SECSuccess;
loser:
+ PK11_FreeSymKey(key);
SSLExp_DestroyAead(out);
return SECFailure;
}
SECStatus
+SSLExp_MakeAead(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *secret,
+ const char *labelPrefix, unsigned int labelPrefixLen, SSLAeadContext **ctx)
+{
+ return SSLExp_MakeVariantAead(version, cipherSuite, ssl_variant_stream, secret,
+ labelPrefix, labelPrefixLen, ctx);
+}
+
+SECStatus
SSLExp_DestroyAead(SSLAeadContext *ctx)
{
if (!ctx) {
return SECSuccess;
}
+ if (ctx->encryptContext) {
+ PK11_DestroyContext(ctx->encryptContext, PR_TRUE);
+ }
+ if (ctx->decryptContext) {
+ PK11_DestroyContext(ctx->decryptContext, PR_TRUE);
+ }
- PK11_FreeSymKey(ctx->keys.key);
PORT_ZFree(ctx, sizeof(*ctx));
return SECSuccess;
}
/* Bug 1529440 exists to refactor this and the other AEAD uses. */
static SECStatus
-ssl_AeadInner(const SSLAeadContext *ctx, PRBool decrypt, PRUint64 counter,
+ssl_AeadInner(const SSLAeadContext *ctx, PK11Context *context,
+ PRBool decrypt, PRUint64 counter,
const PRUint8 *aad, unsigned int aadLen,
- const PRUint8 *plaintext, unsigned int plaintextLen,
+ const PRUint8 *in, unsigned int inLen,
PRUint8 *out, unsigned int *outLen, unsigned int maxOut)
{
- if (ctx == NULL || (aad == NULL && aadLen > 0) || plaintext == NULL ||
+ if (ctx == NULL || (aad == NULL && aadLen > 0) || in == NULL ||
out == NULL || outLen == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
// Setup the nonce.
- PRUint8 nonce[12] = { 0 };
- sslBuffer nonceBuf = SSL_BUFFER_FIXED(nonce + sizeof(nonce) - sizeof(counter),
- sizeof(counter));
+ PRUint8 nonce[sizeof(counter)] = { 0 };
+ sslBuffer nonceBuf = SSL_BUFFER_FIXED(nonce, sizeof(counter));
SECStatus rv = sslBuffer_AppendNumber(&nonceBuf, counter, sizeof(counter));
if (rv != SECSuccess) {
PORT_Assert(0);
return SECFailure;
}
- for (int i = 0; i < sizeof(nonce); ++i) {
- nonce[i] ^= ctx->keys.iv[i];
- }
-
- // Build AEAD parameters.
- CK_GCM_PARAMS gcmParams = { 0 };
- CK_NSS_AEAD_PARAMS aeadParams = { 0 };
- unsigned char *params;
- unsigned int paramsLen;
- switch (ctx->mech) {
- case CKM_AES_GCM:
- gcmParams.pIv = nonce;
- gcmParams.ulIvLen = sizeof(nonce);
- gcmParams.pAAD = (unsigned char *)aad; // const cast :(
- gcmParams.ulAADLen = aadLen;
- gcmParams.ulTagBits = 128; // GCM measures in bits.
- params = (unsigned char *)&gcmParams;
- paramsLen = sizeof(gcmParams);
- break;
-
- case CKM_NSS_CHACHA20_POLY1305:
- aeadParams.pNonce = nonce;
- aeadParams.ulNonceLen = sizeof(nonce);
- aeadParams.pAAD = (unsigned char *)aad; // const cast :(
- aeadParams.ulAADLen = aadLen;
- aeadParams.ulTagLen = 16; // AEAD measures in octets.
- params = (unsigned char *)&aeadParams;
- paramsLen = sizeof(aeadParams);
- break;
-
- default:
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
-
- return tls13_AEAD(&ctx->keys, decrypt, out, outLen, maxOut,
- plaintext, plaintextLen, ctx->mech, params, paramsLen);
+ /* at least on encrypt, we should not be using CKG_NO_GENERATE, but
+ * the current experimental API has the application tracking the counter
+ * rather than token. We should look at the QUIC code and see if the
+ * counter can be moved internally where it belongs. That would
+ * also get rid of the formatting code above and have the API
+ * call tls13_AEAD directly in SSLExp_Aead* */
+ return tls13_AEAD(context, decrypt, CKG_NO_GENERATE, 0, ctx->iv, NULL,
+ ctx->ivLen, nonce, sizeof(counter), aad, aadLen,
+ out, outLen, maxOut, ctx->tagLen, in, inLen);
}
SECStatus
@@ -193,19 +182,21 @@ SSLExp_AeadEncrypt(const SSLAeadContext *ctx, PRUint64 counter,
PRUint8 *out, unsigned int *outLen, unsigned int maxOut)
{
// false == encrypt
- return ssl_AeadInner(ctx, PR_FALSE, counter, aad, aadLen,
- plaintext, plaintextLen, out, outLen, maxOut);
+ return ssl_AeadInner(ctx, ctx->encryptContext, PR_FALSE, counter,
+ aad, aadLen, plaintext, plaintextLen,
+ out, outLen, maxOut);
}
SECStatus
SSLExp_AeadDecrypt(const SSLAeadContext *ctx, PRUint64 counter,
const PRUint8 *aad, unsigned int aadLen,
- const PRUint8 *plaintext, unsigned int plaintextLen,
+ const PRUint8 *ciphertext, unsigned int ciphertextLen,
PRUint8 *out, unsigned int *outLen, unsigned int maxOut)
{
// true == decrypt
- return ssl_AeadInner(ctx, PR_TRUE, counter, aad, aadLen,
- plaintext, plaintextLen, out, outLen, maxOut);
+ return ssl_AeadInner(ctx, ctx->decryptContext, PR_TRUE, counter,
+ aad, aadLen, ciphertext, ciphertextLen,
+ out, outLen, maxOut);
}
SECStatus
@@ -229,8 +220,17 @@ SSLExp_HkdfExtract(PRUint16 version, PRUint16 cipherSuite,
SECStatus
SSLExp_HkdfExpandLabel(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk,
const PRUint8 *hsHash, unsigned int hsHashLen,
- const char *label, unsigned int labelLen,
- PK11SymKey **keyp)
+ const char *label, unsigned int labelLen, PK11SymKey **keyp)
+{
+ return SSLExp_HkdfVariantExpandLabel(version, cipherSuite, prk, hsHash, hsHashLen,
+ label, labelLen, ssl_variant_stream, keyp);
+}
+
+SECStatus
+SSLExp_HkdfVariantExpandLabel(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk,
+ const PRUint8 *hsHash, unsigned int hsHashLen,
+ const char *label, unsigned int labelLen,
+ SSLProtocolVariant variant, PK11SymKey **keyp)
{
if (prk == NULL || keyp == NULL ||
label == NULL || labelLen == 0) {
@@ -245,8 +245,8 @@ SSLExp_HkdfExpandLabel(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk,
return SECFailure; /* Code already set. */
}
return tls13_HkdfExpandLabel(prk, hash, hsHash, hsHashLen, label, labelLen,
- tls13_GetHkdfMechanismForHash(hash),
- tls13_GetHashSizeForHash(hash), keyp);
+ CKM_HKDF_DERIVE,
+ tls13_GetHashSizeForHash(hash), variant, keyp);
}
SECStatus
@@ -256,6 +256,18 @@ SSLExp_HkdfExpandLabelWithMech(PRUint16 version, PRUint16 cipherSuite, PK11SymKe
CK_MECHANISM_TYPE mech, unsigned int keySize,
PK11SymKey **keyp)
{
+ return SSLExp_HkdfVariantExpandLabelWithMech(version, cipherSuite, prk, hsHash, hsHashLen,
+ label, labelLen, mech, keySize,
+ ssl_variant_stream, keyp);
+}
+
+SECStatus
+SSLExp_HkdfVariantExpandLabelWithMech(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk,
+ const PRUint8 *hsHash, unsigned int hsHashLen,
+ const char *label, unsigned int labelLen,
+ CK_MECHANISM_TYPE mech, unsigned int keySize,
+ SSLProtocolVariant variant, PK11SymKey **keyp)
+{
if (prk == NULL || keyp == NULL ||
label == NULL || labelLen == 0 ||
mech == CKM_INVALID_MECHANISM || keySize == 0) {
@@ -270,5 +282,201 @@ SSLExp_HkdfExpandLabelWithMech(PRUint16 version, PRUint16 cipherSuite, PK11SymKe
return SECFailure; /* Code already set. */
}
return tls13_HkdfExpandLabel(prk, hash, hsHash, hsHashLen, label, labelLen,
- mech, keySize, keyp);
+ mech, keySize, variant, keyp);
+}
+
+SECStatus
+ssl_CreateMaskingContextInner(PRUint16 version, PRUint16 cipherSuite,
+ SSLProtocolVariant variant,
+ PK11SymKey *secret,
+ const char *label,
+ unsigned int labelLen,
+ SSLMaskingContext **ctx)
+{
+ if (!secret || !ctx || (!label && labelLen)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ SSLMaskingContext *out = PORT_ZNew(SSLMaskingContext);
+ if (out == NULL) {
+ goto loser;
+ }
+
+ SSLHashType hash;
+ const ssl3BulkCipherDef *cipher;
+ SECStatus rv = tls13_GetHashAndCipher(version, cipherSuite,
+ &hash, &cipher);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ goto loser; /* Code already set. */
+ }
+
+ out->mech = tls13_SequenceNumberEncryptionMechanism(cipher->calg);
+ if (out->mech == CKM_INVALID_MECHANISM) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ goto loser;
+ }
+
+ // Derive the masking key
+ rv = tls13_HkdfExpandLabel(secret, hash,
+ NULL, 0, // Handshake hash.
+ label, labelLen,
+ out->mech,
+ cipher->key_size, variant,
+ &out->secret);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ out->version = version;
+ out->cipherSuite = cipherSuite;
+
+ *ctx = out;
+ return SECSuccess;
+loser:
+ SSLExp_DestroyMaskingContext(out);
+ return SECFailure;
+}
+
+SECStatus
+ssl_CreateMaskInner(SSLMaskingContext *ctx, const PRUint8 *sample,
+ unsigned int sampleLen, PRUint8 *outMask,
+ unsigned int maskLen)
+{
+ if (!ctx || !sample || !sampleLen || !outMask || !maskLen) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (ctx->secret == NULL) {
+ PORT_SetError(SEC_ERROR_NO_KEY);
+ return SECFailure;
+ }
+
+ SECStatus rv = SECFailure;
+ unsigned int outMaskLen = 0;
+ int paramLen = 0;
+
+ /* Internal output len/buf, for use if the caller allocated and requested
+ * less than one block of output. |oneBlock| should have size equal to the
+ * largest block size supported below. */
+ PRUint8 oneBlock[AES_BLOCK_SIZE];
+ PRUint8 *outMask_ = outMask;
+ unsigned int maskLen_ = maskLen;
+
+ switch (ctx->mech) {
+ case CKM_AES_ECB:
+ if (sampleLen < AES_BLOCK_SIZE) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (maskLen_ < AES_BLOCK_SIZE) {
+ outMask_ = oneBlock;
+ maskLen_ = sizeof(oneBlock);
+ }
+ rv = PK11_Encrypt(ctx->secret,
+ ctx->mech,
+ NULL,
+ outMask_, &outMaskLen, maskLen_,
+ sample, AES_BLOCK_SIZE);
+ if (rv == SECSuccess &&
+ maskLen < AES_BLOCK_SIZE) {
+ memcpy(outMask, outMask_, maskLen);
+ }
+ break;
+ case CKM_NSS_CHACHA20_CTR:
+ paramLen = 16;
+ /* fall through */
+ case CKM_CHACHA20:
+ paramLen = (paramLen) ? paramLen : sizeof(CK_CHACHA20_PARAMS);
+ if (sampleLen < paramLen) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ SECItem param;
+ param.type = siBuffer;
+ param.len = paramLen;
+ param.data = (PRUint8 *)sample; // const-cast :(
+ unsigned char zeros[128] = { 0 };
+
+ if (maskLen > sizeof(zeros)) {
+ PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+ return SECFailure;
+ }
+
+ rv = PK11_Encrypt(ctx->secret,
+ ctx->mech,
+ &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/sslsecur.c b/security/nss/lib/ssl/sslsecur.c
index 14320fa19..ef978c90a 100644
--- a/security/nss/lib/ssl/sslsecur.c
+++ b/security/nss/lib/ssl/sslsecur.c
@@ -15,6 +15,7 @@
#include "pk11func.h" /* for PK11_GenerateRandom */
#include "nss.h" /* for NSS_RegisterShutdown */
#include "prinit.h" /* for PR_CallOnceWithArg */
+#include "tls13psk.h"
/* Step through the handshake functions.
*
@@ -173,6 +174,7 @@ SSL_ResetHandshake(PRFileDesc *s, PRBool asServer)
ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions);
ssl3_ResetExtensionData(&ss->xtnData, ss);
+ tls13_ResetHandshakePsks(ss, &ss->ssl3.hs.psks);
if (!ss->TCPconnected)
ss->TCPconnected = (PR_SUCCESS == ssl_DefGetpeername(ss, &addr));
diff --git a/security/nss/lib/ssl/sslsnce.c b/security/nss/lib/ssl/sslsnce.c
index 36c82117e..acb51a145 100644
--- a/security/nss/lib/ssl/sslsnce.c
+++ b/security/nss/lib/ssl/sslsnce.c
@@ -276,6 +276,17 @@ typedef struct inheritanceStr inheritance;
/************************************************************************/
+/* SSL Session Cache has a smaller set of functions to initialize than
+ * ssl does. some ssl_functions can't be initialized before NSS has been
+ * initialized, and the cache may be configured before NSS is initialized
+ * so thus the special init function */
+static SECStatus
+ssl_InitSessionCache()
+{
+ /* currently only one function, which is itself idempotent */
+ return ssl_InitializePRErrorTable();
+}
+
/* This is used to set locking times for the cache. It is not used to set the
* PRTime attributes of sessions, which are driven by ss->now(). */
static PRUint32
@@ -692,7 +703,7 @@ ServerSessionIDLookup(PRTime sslNow, const PRIPv6Addr *addr,
/* what the ??. Didn't get the cert cache lock.
** Don't invalidate the SID cache entry, but don't find it.
*/
- PORT_Assert(!("Didn't get cert Cache Lock!"));
+ PORT_AssertNotReached("Didn't get cert Cache Lock!");
psce = 0;
pcce = 0;
}
@@ -719,7 +730,7 @@ ServerSessionIDLookup(PRTime sslNow, const PRIPv6Addr *addr,
/* what the ??. Didn't get the cert cache lock.
** Don't invalidate the SID cache entry, but don't find it.
*/
- PORT_Assert(!("Didn't get name Cache Lock!"));
+ PORT_AssertNotReached("Didn't get name Cache Lock!");
psce = 0;
psnce = 0;
}
@@ -1165,7 +1176,7 @@ ssl_ConfigServerSessionIDCacheInstanceWithOpt(cacheDesc *cache,
{
SECStatus rv;
- rv = ssl_Init();
+ rv = ssl_InitSessionCache();
if (rv != SECSuccess) {
return rv;
}
@@ -1341,7 +1352,7 @@ SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char *envString)
int locks_initialized = 0;
int locks_to_initialize = 0;
#endif
- SECStatus status = ssl_Init();
+ SECStatus status = ssl_InitSessionCache();
if (status != SECSuccess) {
return status;
@@ -1779,8 +1790,8 @@ ssl_GetSelfEncryptKeyPair(SECKEYPublicKey **pubKey,
return SECFailure;
}
- SECKEYPublicKey *pubKeyCopy;
- SECKEYPrivateKey *privKeyCopy;
+ SECKEYPublicKey *pubKeyCopy = NULL;
+ SECKEYPrivateKey *privKeyCopy = NULL;
PRBool noKey = PR_FALSE;
PR_RWLock_Rlock(ssl_self_encrypt_key_pair.lock);
diff --git a/security/nss/lib/ssl/sslsock.c b/security/nss/lib/ssl/sslsock.c
index aa0e76e3c..695f39c50 100644
--- a/security/nss/lib/ssl/sslsock.c
+++ b/security/nss/lib/ssl/sslsock.c
@@ -20,6 +20,7 @@
#include "pk11pqg.h"
#include "pk11pub.h"
#include "tls13esni.h"
+#include "tls13psk.h"
#include "tls13subcerts.h"
static const sslSocketOps ssl_default_ops = { /* No SSL. */
@@ -86,10 +87,12 @@ static sslOptions ssl_defaults = {
.requireDHENamedGroups = PR_FALSE,
.enable0RttData = PR_FALSE,
.enableTls13CompatMode = PR_FALSE,
+ .enableDtls13VersionCompat = PR_FALSE,
.enableDtlsShortHeader = PR_FALSE,
.enableHelloDowngradeCheck = PR_FALSE,
.enableV2CompatibleHello = PR_FALSE,
- .enablePostHandshakeAuth = PR_FALSE
+ .enablePostHandshakeAuth = PR_FALSE,
+ .suppressEndOfEarlyData = PR_FALSE
};
/*
@@ -381,6 +384,12 @@ ssl_DupSocket(sslSocket *os)
goto loser;
}
}
+ if (os->psk) {
+ ss->psk = tls13_CopyPsk(os->psk);
+ if (!ss->psk) {
+ goto loser;
+ }
+ }
/* Create security data */
rv = ssl_CopySecurityInfo(ss, os);
@@ -467,9 +476,15 @@ ssl_DestroySocketContents(sslSocket *ss)
ssl_ClearPRCList(&ss->ssl3.hs.dtlsSentHandshake, NULL);
ssl_ClearPRCList(&ss->ssl3.hs.dtlsRcvdHandshake, NULL);
+ tls13_DestroyPskList(&ss->ssl3.hs.psks);
tls13_DestroyESNIKeys(ss->esniKeys);
tls13_ReleaseAntiReplayContext(ss->antiReplay);
+
+ if (ss->psk) {
+ tls13_DestroyPsk(ss->psk);
+ ss->psk = NULL;
+ }
}
/*
@@ -863,6 +878,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRIntn val)
ss->opt.enablePostHandshakeAuth = val;
break;
+ case SSL_SUPPRESS_END_OF_EARLY_DATA:
+ ss->opt.suppressEndOfEarlyData = val;
+ break;
+
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
@@ -1017,6 +1036,9 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRIntn *pVal)
case SSL_ENABLE_POST_HANDSHAKE_AUTH:
val = ss->opt.enablePostHandshakeAuth;
break;
+ case SSL_SUPPRESS_END_OF_EARLY_DATA:
+ val = ss->opt.suppressEndOfEarlyData;
+ break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
@@ -1155,6 +1177,9 @@ SSL_OptionGetDefault(PRInt32 which, PRIntn *pVal)
case SSL_ENABLE_POST_HANDSHAKE_AUTH:
val = ssl_defaults.enablePostHandshakeAuth;
break;
+ case SSL_SUPPRESS_END_OF_EARLY_DATA:
+ val = ssl_defaults.suppressEndOfEarlyData;
+ break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
@@ -1366,6 +1391,10 @@ SSL_OptionSetDefault(PRInt32 which, PRIntn val)
ssl_defaults.enablePostHandshakeAuth = val;
break;
+ case SSL_SUPPRESS_END_OF_EARLY_DATA:
+ ssl_defaults.suppressEndOfEarlyData = val;
+ break;
+
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
@@ -1431,6 +1460,10 @@ SSL_CipherPolicySet(PRInt32 which, PRInt32 policy)
if (rv != SECSuccess) {
return rv;
}
+ if (NSS_IsPolicyLocked()) {
+ PORT_SetError(SEC_ERROR_POLICY_LOCKED);
+ return SECFailure;
+ }
return ssl_CipherPolicySet(which, policy);
}
@@ -1477,10 +1510,15 @@ SECStatus
SSL_CipherPrefSetDefault(PRInt32 which, PRBool enabled)
{
SECStatus rv = ssl_Init();
+ PRInt32 locks;
if (rv != SECSuccess) {
return rv;
}
+ rv = NSS_OptionGet(NSS_DEFAULT_LOCKS, &locks);
+ if ((rv == SECSuccess) && (locks & NSS_DEFAULT_SSL_LOCK)) {
+ return SECSuccess;
+ }
return ssl_CipherPrefSetDefault(which, enabled);
}
@@ -1506,11 +1544,17 @@ SECStatus
SSL_CipherPrefSet(PRFileDesc *fd, PRInt32 which, PRBool enabled)
{
sslSocket *ss = ssl_FindSocket(fd);
+ PRInt32 locks;
+ SECStatus rv;
if (!ss) {
SSL_DBG(("%d: SSL[%d]: bad socket in CipherPrefSet", SSL_GETPID(), fd));
return SECFailure;
}
+ rv = NSS_OptionGet(NSS_DEFAULT_LOCKS, &locks);
+ if ((rv == SECSuccess) && (locks & NSS_DEFAULT_SSL_LOCK)) {
+ return SECSuccess;
+ }
if (ssl_IsRemovedCipherSuite(which))
return SECSuccess;
return ssl3_CipherPrefSet(ss, (ssl3CipherSuite)which, enabled);
@@ -2452,6 +2496,8 @@ SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd)
}
}
+ tls13_ResetHandshakePsks(sm, &ss->ssl3.hs.psks);
+
if (sm->authCertificate)
ss->authCertificate = sm->authCertificate;
if (sm->authCertificateArg)
@@ -4145,10 +4191,12 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant)
ssl3_InitExtensionData(&ss->xtnData, ss);
PR_INIT_CLIST(&ss->ssl3.hs.dtlsSentHandshake);
PR_INIT_CLIST(&ss->ssl3.hs.dtlsRcvdHandshake);
+ PR_INIT_CLIST(&ss->ssl3.hs.psks);
dtls_InitTimers(ss);
ss->esniKeys = NULL;
ss->antiReplay = NULL;
+ ss->psk = NULL;
if (makeLocks) {
rv = ssl_MakeLocks(ss);
@@ -4215,13 +4263,19 @@ struct {
void *function;
} ssl_experimental_functions[] = {
#ifndef SSL_DISABLE_EXPERIMENTAL_API
+ EXP(AddExternalPsk),
+ EXP(AddExternalPsk0Rtt),
EXP(AeadDecrypt),
EXP(AeadEncrypt),
EXP(CipherSuiteOrderGet),
EXP(CipherSuiteOrderSet),
EXP(CreateAntiReplayContext),
+ EXP(CreateMask),
+ EXP(CreateMaskingContext),
+ EXP(CreateVariantMaskingContext),
EXP(DelegateCredential),
EXP(DestroyAead),
+ EXP(DestroyMaskingContext),
EXP(DestroyResumptionTokenInfo),
EXP(EnableESNI),
EXP(EncodeESNIKeys),
@@ -4233,15 +4287,20 @@ struct {
EXP(HkdfExtract),
EXP(HkdfExpandLabel),
EXP(HkdfExpandLabelWithMech),
+ EXP(HkdfVariantExpandLabel),
+ EXP(HkdfVariantExpandLabelWithMech),
EXP(KeyUpdate),
EXP(MakeAead),
+ EXP(MakeVariantAead),
EXP(RecordLayerData),
EXP(RecordLayerWriteCallback),
EXP(ReleaseAntiReplayContext),
+ EXP(RemoveExternalPsk),
EXP(SecretCallback),
EXP(SendCertificateRequest),
EXP(SendSessionTicket),
EXP(SetAntiReplayContext),
+ EXP(SetDtls13VersionWorkaround),
EXP(SetESNIKeyPair),
EXP(SetMaxEarlyDataSize),
EXP(SetResumptionTokenCallback),
@@ -4283,6 +4342,17 @@ ssl_ClearPRCList(PRCList *list, void (*f)(void *))
}
SECStatus
+SSLExp_SetDtls13VersionWorkaround(PRFileDesc *fd, PRBool enabled)
+{
+ sslSocket *ss = ssl_FindSocket(fd);
+ if (!ss) {
+ return SECFailure;
+ }
+ ss->opt.enableDtls13VersionCompat = enabled;
+ return SECSuccess;
+}
+
+SECStatus
SSLExp_SetTimeFunc(PRFileDesc *fd, SSLTimeFunc f, void *arg)
{
sslSocket *ss = ssl_FindSocket(fd);
@@ -4437,8 +4507,11 @@ SSLExp_GetResumptionTokenInfo(const PRUint8 *tokenData, unsigned int tokenLen,
if (!token.alpnSelection) {
return SECFailure;
}
- PORT_Memcpy(token.alpnSelection, sid.u.ssl3.alpnSelection.data,
- token.alpnSelectionLen);
+ if (token.alpnSelectionLen > 0) {
+ PORT_Assert(sid.u.ssl3.alpnSelection.data);
+ PORT_Memcpy(token.alpnSelection, sid.u.ssl3.alpnSelection.data,
+ token.alpnSelectionLen);
+ }
if (sid.u.ssl3.locked.sessionTicket.flags & ticket_allow_early_data) {
token.maxEarlyDataSize =
diff --git a/security/nss/lib/ssl/sslspec.c b/security/nss/lib/ssl/sslspec.c
index def3c6750..c5bedad7a 100644
--- a/security/nss/lib/ssl/sslspec.c
+++ b/security/nss/lib/ssl/sslspec.c
@@ -7,6 +7,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ssl.h"
+#include "sslexp.h"
+#include "sslimpl.h"
#include "sslproto.h"
#include "pk11func.h"
#include "secitem.h"
@@ -227,6 +229,7 @@ ssl_FreeCipherSpec(ssl3CipherSpec *spec)
}
PK11_FreeSymKey(spec->masterSecret);
ssl_DestroyKeyMaterial(&spec->keyMaterial);
+ ssl_DestroyMaskingContextInner(spec->maskContext);
PORT_ZFree(spec, sizeof(*spec));
}
diff --git a/security/nss/lib/ssl/sslspec.h b/security/nss/lib/ssl/sslspec.h
index ca9ef540f..061d888ae 100644
--- a/security/nss/lib/ssl/sslspec.h
+++ b/security/nss/lib/ssl/sslspec.h
@@ -105,16 +105,16 @@ typedef SECStatus (*SSLCipher)(void *context,
unsigned int maxout,
const unsigned char *in,
unsigned int inlen);
-typedef SECStatus (*SSLAEADCipher)(
- const ssl3KeyMaterial *keys,
- PRBool doDecrypt,
- unsigned char *out,
- unsigned int *outlen,
- unsigned int maxout,
- const unsigned char *in,
- unsigned int inlen,
- const unsigned char *additionalData,
- unsigned int additionalDataLen);
+typedef SECStatus (*SSLAEADCipher)(PK11Context *context,
+ CK_GENERATOR_FUNCTION ivGen,
+ unsigned int fixedbits,
+ unsigned char *iv, unsigned int ivlen,
+ const unsigned char *aad,
+ unsigned int aadlen,
+ unsigned char *out, unsigned int *outlen,
+ unsigned int maxout, unsigned char *tag,
+ unsigned int taglen,
+ const unsigned char *in, unsigned int inlen);
/* The DTLS anti-replay window in number of packets. Defined here because we
* need it in the cipher spec. Note that this is a ring buffer but left and
@@ -149,7 +149,6 @@ struct ssl3CipherSpecStr {
const ssl3MACDef *macDef;
SSLCipher cipher;
- SSLAEADCipher aead;
void *cipherContext;
PK11SymKey *masterSecret;
@@ -169,6 +168,12 @@ struct ssl3CipherSpecStr {
* negotiated value for TLS 1.3; it is reduced by one to account for the
* content type octet. */
PRUint16 recordSizeLimit;
+
+ /* DTLS 1.3: Sequence number masking context. */
+ SSLMaskingContext *maskContext;
+
+ /* DTLS 1.3: Count of decryption failures for the given key. */
+ PRUint64 deprotectionFailures;
};
typedef void (*sslCipherSpecChangedFunc)(void *arg,
diff --git a/security/nss/lib/ssl/sslt.h b/security/nss/lib/ssl/sslt.h
index 47efa2e4d..eaf4133e3 100644
--- a/security/nss/lib/ssl/sslt.h
+++ b/security/nss/lib/ssl/sslt.h
@@ -41,7 +41,7 @@ typedef enum {
ssl_ct_alert = 21,
ssl_ct_handshake = 22,
ssl_ct_application_data = 23,
- ssl_ct_ack = 25
+ ssl_ct_ack = 26
} SSLContentType;
typedef enum {
@@ -184,6 +184,12 @@ typedef enum {
ssl_auth_size /* number of authentication types */
} SSLAuthType;
+typedef enum {
+ ssl_psk_none = 0,
+ ssl_psk_resume = 1,
+ ssl_psk_external = 2,
+} SSLPskType;
+
/* This is defined for backward compatibility reasons */
#define ssl_auth_rsa ssl_auth_rsa_decrypt
@@ -358,6 +364,10 @@ typedef struct SSLChannelInfoStr {
*/
PRBool peerDelegCred;
+ /* The following fields were added in NSS 3.54. */
+ /* Indicates what type of PSK, if any, was used in a handshake. */
+ SSLPskType pskType;
+
/* When adding new fields to this structure, please document the
* NSS version in which they were added. */
} SSLChannelInfo;
@@ -507,6 +517,7 @@ typedef enum {
ssl_padding_xtn = 21,
ssl_extended_master_secret_xtn = 23,
ssl_record_size_limit_xtn = 28,
+ ssl_delegated_credentials_xtn = 34,
ssl_session_ticket_xtn = 35,
/* 40 was used in draft versions of TLS 1.3; it is now reserved. */
ssl_tls13_pre_shared_key_xtn = 41,
@@ -521,7 +532,6 @@ typedef enum {
ssl_tls13_key_share_xtn = 51,
ssl_next_proto_nego_xtn = 13172, /* Deprecated. */
ssl_renegotiation_info_xtn = 0xff01,
- ssl_delegated_credentials_xtn = 0xff02,
ssl_tls13_short_header_xtn = 0xff03, /* Deprecated. */
ssl_tls13_encrypted_sni_xtn = 0xffce,
} SSLExtensionType;
diff --git a/security/nss/lib/ssl/tls13con.c b/security/nss/lib/ssl/tls13con.c
index c3528a52f..5d51d3c5c 100644
--- a/security/nss/lib/ssl/tls13con.c
+++ b/security/nss/lib/ssl/tls13con.c
@@ -25,28 +25,11 @@
#include "tls13exthandle.h"
#include "tls13hashstate.h"
#include "tls13subcerts.h"
+#include "tls13psk.h"
static SECStatus tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch,
SSLSecretDirection install,
PRBool deleteSecret);
-static SECStatus tls13_AESGCM(const ssl3KeyMaterial *keys,
- PRBool doDecrypt,
- unsigned char *out,
- unsigned int *outlen,
- unsigned int maxout,
- const unsigned char *in,
- unsigned int inlen,
- const unsigned char *additionalData,
- unsigned int additionalDataLen);
-static SECStatus tls13_ChaCha20Poly1305(const ssl3KeyMaterial *keys,
- PRBool doDecrypt,
- unsigned char *out,
- unsigned int *outlen,
- unsigned int maxout,
- const unsigned char *in,
- unsigned int inlen,
- const unsigned char *additionalData,
- unsigned int additionalDataLen);
static SECStatus tls13_SendServerHelloSequence(sslSocket *ss);
static SECStatus tls13_SendEncryptedExtensions(sslSocket *ss);
static void tls13_SetKeyExchangeType(sslSocket *ss, const sslNamedGroupDef *group);
@@ -83,13 +66,15 @@ tls13_DeriveSecret(sslSocket *ss, PK11SymKey *key,
const char *label,
unsigned int labelLen,
const SSL3Hashes *hashes,
- PK11SymKey **dest);
+ PK11SymKey **dest,
+ SSLHashType hash);
static SECStatus tls13_SendEndOfEarlyData(sslSocket *ss);
-static SECStatus tls13_HandleEndOfEarlyData(sslSocket *ss, PRUint8 *b,
+static SECStatus tls13_HandleEndOfEarlyData(sslSocket *ss, const PRUint8 *b,
PRUint32 length);
+static SECStatus tls13_MaybeHandleSuppressedEndOfEarlyData(sslSocket *ss);
static SECStatus tls13_SendFinished(sslSocket *ss, PK11SymKey *baseKey);
static SECStatus tls13_ComputePskBinderHash(sslSocket *ss, unsigned int prefix,
- SSL3Hashes *hashes);
+ SSL3Hashes *hashes, SSLHashType type);
static SECStatus tls13_VerifyFinished(sslSocket *ss, SSLHandshakeType message,
PK11SymKey *secret,
PRUint8 *b, PRUint32 length,
@@ -103,14 +88,14 @@ static SECStatus tls13_SendNewSessionTicket(sslSocket *ss,
unsigned int appTokenLen);
static SECStatus tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b,
PRUint32 length);
-static SECStatus tls13_ComputeEarlySecrets(sslSocket *ss);
+static SECStatus tls13_ComputeEarlySecretsWithPsk(sslSocket *ss);
static SECStatus tls13_ComputeHandshakeSecrets(sslSocket *ss);
static SECStatus tls13_ComputeApplicationSecrets(sslSocket *ss);
static SECStatus tls13_ComputeFinalSecrets(sslSocket *ss);
static SECStatus tls13_ComputeFinished(
- sslSocket *ss, PK11SymKey *baseKey, const SSL3Hashes *hashes,
- PRBool sending, PRUint8 *output, unsigned int *outputLen,
- unsigned int maxOutputLen);
+ sslSocket *ss, PK11SymKey *baseKey, SSLHashType hashType,
+ const SSL3Hashes *hashes, PRBool sending, PRUint8 *output,
+ unsigned int *outputLen, unsigned int maxOutputLen);
static SECStatus tls13_SendClientSecondRound(sslSocket *ss);
static SECStatus tls13_SendClientSecondFlight(sslSocket *ss,
PRBool sendClientCert,
@@ -120,7 +105,8 @@ static SECStatus tls13_FinishHandshake(sslSocket *ss);
const char kHkdfLabelClient[] = "c";
const char kHkdfLabelServer[] = "s";
const char kHkdfLabelDerivedSecret[] = "derived";
-const char kHkdfLabelPskBinderKey[] = "res binder";
+const char kHkdfLabelResPskBinderKey[] = "res binder";
+const char kHkdfLabelExtPskBinderKey[] = "ext binder";
const char kHkdfLabelEarlyTrafficSecret[] = "e traffic";
const char kHkdfLabelEarlyExporterSecret[] = "e exp master";
const char kHkdfLabelHandshakeTrafficSecret[] = "hs traffic";
@@ -131,6 +117,7 @@ const char kHkdfLabelExporterMasterSecret[] = "exp master";
const char kHkdfLabelResumption[] = "resumption";
const char kHkdfLabelTrafficUpdate[] = "traffic upd";
const char kHkdfPurposeKey[] = "key";
+const char kHkdfPurposeSn[] = "sn";
const char kHkdfPurposeIv[] = "iv";
const char keylogLabelClientEarlyTrafficSecret[] = "CLIENT_EARLY_TRAFFIC_SECRET";
@@ -281,11 +268,49 @@ tls13_GetHashForCipherSuite(ssl3CipherSuite suite)
SSLHashType
tls13_GetHash(const sslSocket *ss)
{
+ /* suite_def may not be set yet when doing EPSK 0-Rtt. */
+ if (!ss->ssl3.hs.suite_def) {
+ if (ss->xtnData.selectedPsk) {
+ return ss->xtnData.selectedPsk->hash;
+ }
+ /* This should never happen. */
+ PORT_Assert(0);
+ return ssl_hash_none;
+ }
+
/* All TLS 1.3 cipher suites must have an explict PRF hash. */
PORT_Assert(ss->ssl3.hs.suite_def->prf_hash != ssl_hash_none);
return ss->ssl3.hs.suite_def->prf_hash;
}
+SECStatus
+tls13_GetHashAndCipher(PRUint16 version, PRUint16 cipherSuite,
+ SSLHashType *hash, const ssl3BulkCipherDef **cipher)
+{
+ if (version < SSL_LIBRARY_VERSION_TLS_1_3) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ // Lookup and check the suite.
+ SSLVersionRange vrange = { version, version };
+ if (!ssl3_CipherSuiteAllowedForVersionRange(cipherSuite, &vrange)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ const ssl3CipherSuiteDef *suiteDef = ssl_LookupCipherSuiteDef(cipherSuite);
+ const ssl3BulkCipherDef *cipherDef = ssl_GetBulkCipherDef(suiteDef);
+ if (cipherDef->type != type_aead) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ *hash = suiteDef->prf_hash;
+ if (cipher != NULL) {
+ *cipher = cipherDef;
+ }
+ return SECSuccess;
+}
+
unsigned int
tls13_GetHashSizeForHash(SSLHashType hash)
{
@@ -306,30 +331,10 @@ tls13_GetHashSize(const sslSocket *ss)
return tls13_GetHashSizeForHash(tls13_GetHash(ss));
}
-CK_MECHANISM_TYPE
-tls13_GetHkdfMechanismForHash(SSLHashType hash)
-{
- switch (hash) {
- case ssl_hash_sha256:
- return CKM_NSS_HKDF_SHA256;
- case ssl_hash_sha384:
- return CKM_NSS_HKDF_SHA384;
- default:
- PORT_Assert(0);
- }
- return CKM_NSS_HKDF_SHA256;
-}
-
-CK_MECHANISM_TYPE
-tls13_GetHkdfMechanism(sslSocket *ss)
-{
- return tls13_GetHkdfMechanismForHash(tls13_GetHash(ss));
-}
-
static CK_MECHANISM_TYPE
-tls13_GetHmacMechanism(sslSocket *ss)
+tls13_GetHmacMechanismFromHash(SSLHashType hashType)
{
- switch (tls13_GetHash(ss)) {
+ switch (hashType) {
case ssl_hash_sha256:
return CKM_SHA256_HMAC;
case ssl_hash_sha384:
@@ -340,19 +345,25 @@ tls13_GetHmacMechanism(sslSocket *ss)
return CKM_SHA256_HMAC;
}
+static CK_MECHANISM_TYPE
+tls13_GetHmacMechanism(const sslSocket *ss)
+{
+ return tls13_GetHmacMechanismFromHash(tls13_GetHash(ss));
+}
+
SECStatus
tls13_ComputeHash(sslSocket *ss, SSL3Hashes *hashes,
- const PRUint8 *buf, unsigned int len)
+ const PRUint8 *buf, unsigned int len,
+ SSLHashType hash)
{
SECStatus rv;
- rv = PK11_HashBuf(ssl3_HashTypeToOID(tls13_GetHash(ss)),
- hashes->u.raw, buf, len);
+ rv = PK11_HashBuf(ssl3_HashTypeToOID(hash), hashes->u.raw, buf, len);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
return SECFailure;
}
- hashes->len = tls13_GetHashSize(ss);
+ hashes->len = tls13_GetHashSizeForHash(hash);
return SECSuccess;
}
@@ -470,40 +481,50 @@ tls13_SetupClientHello(sslSocket *ss, sslClientHelloType chType)
return SECFailure;
}
- /* Below here checks if we can do stateless resumption. */
- if (sid->cached == never_cached ||
- sid->version < SSL_LIBRARY_VERSION_TLS_1_3) {
- return SECSuccess;
- }
+ /* Try to do stateless resumption, if we can. */
+ if (sid->cached != never_cached &&
+ sid->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ /* The caller must be holding sid->u.ssl3.lock for reading. */
+ session_ticket = &sid->u.ssl3.locked.sessionTicket;
+ PORT_Assert(session_ticket && session_ticket->ticket.data);
- /* The caller must be holding sid->u.ssl3.lock for reading. */
- session_ticket = &sid->u.ssl3.locked.sessionTicket;
- PORT_Assert(session_ticket && session_ticket->ticket.data);
+ if (ssl_TicketTimeValid(ss, session_ticket)) {
+ ss->statelessResume = PR_TRUE;
+ }
- if (ssl_TicketTimeValid(ss, session_ticket)) {
- ss->statelessResume = PR_TRUE;
- }
+ if (ss->statelessResume) {
+ PORT_Assert(ss->sec.ci.sid);
+ rv = tls13_RecoverWrappedSharedSecret(ss, ss->sec.ci.sid);
+ if (rv != SECSuccess) {
+ FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+ SSL_AtomicIncrementLong(&ssl3stats->sch_sid_cache_not_ok);
+ ssl_UncacheSessionID(ss);
+ ssl_FreeSID(ss->sec.ci.sid);
+ ss->sec.ci.sid = NULL;
+ return SECFailure;
+ }
- if (ss->statelessResume) {
- PORT_Assert(ss->sec.ci.sid);
- rv = tls13_RecoverWrappedSharedSecret(ss, ss->sec.ci.sid);
- if (rv != SECSuccess) {
- FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
- SSL_AtomicIncrementLong(&ssl3stats->sch_sid_cache_not_ok);
- ssl_UncacheSessionID(ss);
- ssl_FreeSID(ss->sec.ci.sid);
- ss->sec.ci.sid = NULL;
- return SECFailure;
+ ss->ssl3.hs.cipher_suite = ss->sec.ci.sid->u.ssl3.cipherSuite;
+ rv = ssl3_SetupCipherSuite(ss, PR_FALSE);
+ if (rv != SECSuccess) {
+ FATAL_ERROR(ss, PORT_GetError(), internal_error);
+ return SECFailure;
+ }
+ PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks));
}
+ }
- ss->ssl3.hs.cipher_suite = ss->sec.ci.sid->u.ssl3.cipherSuite;
- rv = ssl3_SetupCipherSuite(ss, PR_FALSE);
- if (rv != SECSuccess) {
- FATAL_ERROR(ss, PORT_GetError(), internal_error);
- return SECFailure;
+ /* Derive the binder keys if any PSKs. */
+ if (!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks)) {
+ /* If an External PSK specified a suite, use that. */
+ sslPsk *psk = (sslPsk *)PR_LIST_HEAD(&ss->ssl3.hs.psks);
+ if (!ss->statelessResume &&
+ psk->type == ssl_psk_external &&
+ psk->zeroRttSuite != TLS_NULL_WITH_NULL_NULL) {
+ ss->ssl3.hs.cipher_suite = psk->zeroRttSuite;
}
- rv = tls13_ComputeEarlySecrets(ss);
+ rv = tls13_ComputeEarlySecretsWithPsk(ss);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
return SECFailure;
@@ -595,7 +616,7 @@ tls13_HandleKeyShare(sslSocket *ss,
key = PK11_PubDeriveWithKDF(
keyPair->privKey, peerKey, PR_FALSE, NULL, NULL, mechanism,
- tls13_GetHkdfMechanismForHash(hash), CKA_DERIVE, keySize, CKD_NULL, NULL, NULL);
+ CKM_HKDF_DERIVE, CKA_DERIVE, keySize, CKD_NULL, NULL, NULL);
if (!key) {
ssl_MapLowLevelError(SSL_ERROR_KEY_EXCHANGE_FAILURE);
goto loser;
@@ -641,6 +662,7 @@ tls13_UpdateTrafficKeys(sslSocket *ss, SSLSecretDirection direction)
strlen(kHkdfLabelTrafficUpdate),
tls13_GetHmacMechanism(ss),
tls13_GetHashSize(ss),
+ ss->protocolVariant,
&updatedSecret);
if (rv != SECSuccess) {
return SECFailure;
@@ -884,6 +906,12 @@ SSLExp_SendCertificateRequest(PRFileDesc *fd)
return SECFailure;
}
+ /* Disallow a CertificateRequest if this connection uses an external PSK. */
+ if (ss->sec.authType == ssl_auth_psk) {
+ PORT_SetError(SSL_ERROR_FEATURE_DISABLED);
+ return SECFailure;
+ }
+
rv = TLS13_CHECK_HS_STATE(ss, SEC_ERROR_INVALID_ARGS,
idle_handshake);
if (rv != SECSuccess) {
@@ -997,20 +1025,34 @@ tls13_RecoverWrappedSharedSecret(sslSocket *ss, sslSessionID *sid)
wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret;
wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len;
- /* unwrap the "master secret" which is actually RMS. */
- ss->ssl3.hs.resumptionMasterSecret = ssl_unwrapSymKey(
- wrapKey, sid->u.ssl3.masterWrapMech,
- NULL, &wrappedMS,
- CKM_SSL3_MASTER_KEY_DERIVE,
- CKA_DERIVE,
- tls13_GetHashSizeForHash(hashType),
- CKF_SIGN | CKF_VERIFY, ss->pkcs11PinArg);
+ PK11SymKey *unwrappedPsk = ssl_unwrapSymKey(wrapKey, sid->u.ssl3.masterWrapMech,
+ NULL, &wrappedMS, CKM_SSL3_MASTER_KEY_DERIVE,
+ CKA_DERIVE, tls13_GetHashSizeForHash(hashType),
+ CKF_SIGN | CKF_VERIFY, ss->pkcs11PinArg);
PK11_FreeSymKey(wrapKey);
- if (!ss->ssl3.hs.resumptionMasterSecret) {
+ if (!unwrappedPsk) {
return SECFailure;
}
+ sslPsk *rpsk = tls13_MakePsk(unwrappedPsk, ssl_psk_resume, hashType, NULL);
+ if (!rpsk) {
+ PK11_FreeSymKey(unwrappedPsk);
+ return SECFailure;
+ }
+ if (sid->u.ssl3.locked.sessionTicket.flags & ticket_allow_early_data) {
+ rpsk->maxEarlyData = sid->u.ssl3.locked.sessionTicket.max_early_data_size;
+ rpsk->zeroRttSuite = sid->u.ssl3.cipherSuite;
+ }
+ PRINT_KEY(50, (ss, "Recovered RMS", rpsk->key));
+ PORT_Assert(PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks) ||
+ ((sslPsk *)PR_LIST_HEAD(&ss->ssl3.hs.psks))->type != ssl_psk_resume);
- PRINT_KEY(50, (ss, "Recovered RMS", ss->ssl3.hs.resumptionMasterSecret));
+ if (ss->sec.isServer) {
+ /* In server, we couldn't select the RPSK in the extension handler
+ * since it was not unwrapped yet. We're committed now, so select
+ * it and add it to the list (to ensure it is freed). */
+ ss->xtnData.selectedPsk = rpsk;
+ }
+ PR_APPEND_LINK(&rpsk->link, &ss->ssl3.hs.psks);
return SECSuccess;
}
@@ -1068,38 +1110,45 @@ tls13_RecoverWrappedSharedSecret(sslSocket *ss, sslSessionID *sid)
* = resumption_master_secret
*
*/
-
static SECStatus
-tls13_ComputeEarlySecrets(sslSocket *ss)
+tls13_ComputeEarlySecretsWithPsk(sslSocket *ss)
{
- SECStatus rv = SECSuccess;
+ SECStatus rv;
SSL_TRC(5, ("%d: TLS13[%d]: compute early secrets (%s)",
SSL_GETPID(), ss->fd, SSL_ROLE(ss)));
- /* Extract off the resumptionMasterSecret (if present), else pass the NULL
- * resumptionMasterSecret which will be internally translated to zeroes. */
PORT_Assert(!ss->ssl3.hs.currentSecret);
- rv = tls13_HkdfExtract(NULL, ss->ssl3.hs.resumptionMasterSecret,
- tls13_GetHash(ss), &ss->ssl3.hs.currentSecret);
+ sslPsk *psk = NULL;
+
+ if (ss->sec.isServer) {
+ psk = ss->xtnData.selectedPsk;
+ } else {
+ /* Client to use the first PSK for early secrets. */
+ PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks));
+ psk = (sslPsk *)PR_LIST_HEAD(&ss->ssl3.hs.psks);
+ }
+ PORT_Assert(psk && psk->key);
+ PORT_Assert(psk->hash != ssl_hash_none);
+
+ PK11SymKey *earlySecret = NULL;
+ rv = tls13_HkdfExtract(NULL, psk->key, psk->hash, &earlySecret);
if (rv != SECSuccess) {
return SECFailure;
}
- PORT_Assert(ss->statelessResume == (ss->ssl3.hs.resumptionMasterSecret != NULL));
- if (ss->statelessResume) {
- PK11_FreeSymKey(ss->ssl3.hs.resumptionMasterSecret);
- ss->ssl3.hs.resumptionMasterSecret = NULL;
-
- rv = tls13_DeriveSecretNullHash(ss, ss->ssl3.hs.currentSecret,
- kHkdfLabelPskBinderKey,
- strlen(kHkdfLabelPskBinderKey),
- &ss->ssl3.hs.pskBinderKey);
- if (rv != SECSuccess) {
- return SECFailure;
- }
+ /* No longer need the raw input key */
+ PK11_FreeSymKey(psk->key);
+ psk->key = NULL;
+ const char *label = (psk->type == ssl_psk_resume) ? kHkdfLabelResPskBinderKey : kHkdfLabelExtPskBinderKey;
+ rv = tls13_DeriveSecretNullHash(ss, earlySecret,
+ label, strlen(label),
+ &psk->binderKey, psk->hash);
+ if (rv != SECSuccess) {
+ PK11_FreeSymKey(earlySecret);
+ return SECFailure;
}
- PORT_Assert(!ss->ssl3.hs.resumptionMasterSecret);
+ ss->ssl3.hs.currentSecret = earlySecret;
return SECSuccess;
}
@@ -1109,7 +1158,7 @@ static SECStatus
tls13_DeriveEarlySecrets(sslSocket *ss)
{
SECStatus rv;
-
+ PORT_Assert(ss->ssl3.hs.currentSecret);
rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret,
kHkdfLabelClient,
kHkdfLabelEarlyTrafficSecret,
@@ -1147,7 +1196,15 @@ tls13_ComputeHandshakeSecrets(sslSocket *ss)
SSL_TRC(5, ("%d: TLS13[%d]: compute handshake secrets (%s)",
SSL_GETPID(), ss->fd, SSL_ROLE(ss)));
- /* First update |currentSecret| to add |dheSecret|, if any. */
+ /* If no PSK, generate the default early secret. */
+ if (!ss->ssl3.hs.currentSecret) {
+ PORT_Assert(!ss->xtnData.selectedPsk);
+ rv = tls13_HkdfExtract(NULL, NULL,
+ tls13_GetHash(ss), &ss->ssl3.hs.currentSecret);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ }
PORT_Assert(ss->ssl3.hs.currentSecret);
PORT_Assert(ss->ssl3.hs.dheSecret);
@@ -1155,7 +1212,7 @@ tls13_ComputeHandshakeSecrets(sslSocket *ss)
rv = tls13_DeriveSecretNullHash(ss, ss->ssl3.hs.currentSecret,
kHkdfLabelDerivedSecret,
strlen(kHkdfLabelDerivedSecret),
- &derivedSecret);
+ &derivedSecret, tls13_GetHash(ss));
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return rv;
@@ -1214,7 +1271,7 @@ tls13_ComputeHandshakeSecrets(sslSocket *ss)
rv = tls13_DeriveSecretNullHash(ss, ss->ssl3.hs.currentSecret,
kHkdfLabelDerivedSecret,
strlen(kHkdfLabelDerivedSecret),
- &derivedSecret);
+ &derivedSecret, tls13_GetHash(ss));
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return rv;
@@ -1286,7 +1343,7 @@ tls13_ComputeFinalSecrets(sslSocket *ss)
PORT_Assert(!ss->ssl3.crSpec->masterSecret);
PORT_Assert(!ss->ssl3.cwSpec->masterSecret);
-
+ PORT_Assert(ss->ssl3.hs.currentSecret);
rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret,
NULL, kHkdfLabelResumptionMasterSecret,
NULL,
@@ -1327,7 +1384,14 @@ tls13_CanResume(sslSocket *ss, const sslSessionID *sid)
return PR_FALSE;
}
+#ifdef UNSAFE_FUZZER_MODE
+ /* When fuzzing, sid could contain garbage that will crash tls13_GetHashForCipherSuite.
+ * Do a direct comparison of cipher suites. This makes us refuse to resume when the
+ * protocol allows it, but resumption is discretionary anyway. */
+ if (sid->u.ssl3.cipherSuite != ss->ssl3.hs.cipher_suite) {
+#else
if (tls13_GetHashForCipherSuite(sid->u.ssl3.cipherSuite) != tls13_GetHashForCipherSuite(ss->ssl3.hs.cipher_suite)) {
+#endif
return PR_FALSE;
}
@@ -1347,21 +1411,40 @@ static PRBool
tls13_CanNegotiateZeroRtt(sslSocket *ss, const sslSessionID *sid)
{
PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_sent);
+ sslPsk *psk = ss->xtnData.selectedPsk;
- if (!sid)
+ if (!ss->opt.enable0RttData) {
return PR_FALSE;
- PORT_Assert(ss->statelessResume);
- if (!ss->statelessResume)
+ }
+ if (!psk) {
return PR_FALSE;
- if (ss->ssl3.hs.cipher_suite != sid->u.ssl3.cipherSuite)
+ }
+ if (psk->zeroRttSuite == TLS_NULL_WITH_NULL_NULL) {
return PR_FALSE;
- if (!ss->opt.enable0RttData)
+ }
+ if (!psk->maxEarlyData) {
return PR_FALSE;
- if (!(sid->u.ssl3.locked.sessionTicket.flags & ticket_allow_early_data))
+ }
+ if (ss->ssl3.hs.cipher_suite != psk->zeroRttSuite) {
return PR_FALSE;
- if (SECITEM_CompareItem(&ss->xtnData.nextProto,
- &sid->u.ssl3.alpnSelection) != 0)
+ }
+ if (psk->type == ssl_psk_resume) {
+ if (!sid) {
+ return PR_FALSE;
+ }
+ PORT_Assert(sid->u.ssl3.locked.sessionTicket.flags & ticket_allow_early_data);
+ PORT_Assert(ss->statelessResume);
+ if (!ss->statelessResume) {
+ return PR_FALSE;
+ }
+ if (SECITEM_CompareItem(&ss->xtnData.nextProto,
+ &sid->u.ssl3.alpnSelection) != 0) {
+ return PR_FALSE;
+ }
+ } else if (psk->type != ssl_psk_external) {
+ PORT_Assert(0);
return PR_FALSE;
+ }
if (tls13_IsReplay(ss, sid)) {
return PR_FALSE;
@@ -1414,7 +1497,7 @@ tls13_NegotiateZeroRtt(sslSocket *ss, const sslSessionID *sid)
}
SSL_TRC(3, ("%d: TLS13[%d]: enable 0-RTT", SSL_GETPID(), ss->fd));
- PORT_Assert(ss->statelessResume);
+ PORT_Assert(ss->xtnData.selectedPsk);
ss->ssl3.hs.zeroRttState = ssl_0rtt_accepted;
ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_none;
ss->ssl3.hs.zeroRttSuite = ss->ssl3.hs.cipher_suite;
@@ -1466,7 +1549,7 @@ tls13_NegotiateKeyExchange(sslSocket *ss,
const sslNamedGroupDef *preferredGroup = NULL;
/* We insist on DHE. */
- if (ss->statelessResume) {
+ if (ssl3_ExtensionNegotiated(ss, ssl_tls13_pre_shared_key_xtn)) {
if (!ssl3_ExtensionNegotiated(ss, ssl_tls13_psk_key_exchange_modes_xtn)) {
FATAL_ERROR(ss, SSL_ERROR_MISSING_PSK_KEY_EXCHANGE_MODES,
missing_extension);
@@ -1490,8 +1573,8 @@ tls13_NegotiateKeyExchange(sslSocket *ss,
return SECFailure;
}
- SSL_TRC(3, ("%d: TLS13[%d]: selected KE = %s",
- SSL_GETPID(), ss->fd, ss->statelessResume ? "PSK + (EC)DHE" : "(EC)DHE"));
+ SSL_TRC(3, ("%d: TLS13[%d]: selected KE = %s", SSL_GETPID(),
+ ss->fd, ss->statelessResume || ss->xtnData.selectedPsk ? "PSK + (EC)DHE" : "(EC)DHE"));
/* Find the preferred group and an according client key share available. */
for (index = 0; index < SSL_NAMED_GROUP_COUNT; ++index) {
@@ -1679,26 +1762,42 @@ tls13_MaybeSendHelloRetry(sslSocket *ss, const sslNamedGroupDef *requestedGroup,
static SECStatus
tls13_NegotiateAuthentication(sslSocket *ss)
{
- SECStatus rv;
-
if (ss->statelessResume) {
- SSL_TRC(3, ("%d: TLS13[%d]: selected PSK authentication",
+ SSL_TRC(3, ("%d: TLS13[%d]: selected resumption PSK authentication",
SSL_GETPID(), ss->fd));
ss->ssl3.hs.signatureScheme = ssl_sig_none;
ss->ssl3.hs.kea_def_mutable.authKeyType = ssl_auth_psk;
+ /* Overwritten by tls13_RestoreCipherInfo. */
+ ss->sec.authType = ssl_auth_psk;
return SECSuccess;
+ } else if (ss->xtnData.selectedPsk) {
+ /* If the EPSK doesn't specify a suite, use what was negotiated.
+ * Else, only use the EPSK if we negotiated that suite. */
+ if (ss->xtnData.selectedPsk->zeroRttSuite == TLS_NULL_WITH_NULL_NULL ||
+ ss->ssl3.hs.cipher_suite == ss->xtnData.selectedPsk->zeroRttSuite) {
+ SSL_TRC(3, ("%d: TLS13[%d]: selected external PSK authentication",
+ SSL_GETPID(), ss->fd));
+ ss->ssl3.hs.signatureScheme = ssl_sig_none;
+ ss->ssl3.hs.kea_def_mutable.authKeyType = ssl_auth_psk;
+ ss->sec.authType = ssl_auth_psk;
+ return SECSuccess;
+ }
+ }
+
+ /* If there were PSKs, they are no longer needed. */
+ if (ss->xtnData.selectedPsk) {
+ tls13_DestroyPskList(&ss->ssl3.hs.psks);
+ ss->xtnData.selectedPsk = NULL;
}
SSL_TRC(3, ("%d: TLS13[%d]: selected certificate authentication",
SSL_GETPID(), ss->fd));
- /* We've now established that we need to sign.... */
- rv = tls13_SelectServerCert(ss);
+ SECStatus rv = tls13_SelectServerCert(ss);
if (rv != SECSuccess) {
return SECFailure;
}
return SECSuccess;
}
-
/* Called from ssl3_HandleClientHello after we have parsed the
* ClientHello and are sure that we are going to do TLS 1.3
* or fail. */
@@ -1862,40 +1961,51 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
goto loser;
}
- if (ss->statelessResume) {
- /* We are now committed to trying to resume. */
- PORT_Assert(sid);
-
- /* Check that the negotiated SNI and the cached SNI match. */
- if (SECITEM_CompareItem(&sid->u.ssl3.srvName,
- &ss->ssl3.hs.srvVirtName) != SECEqual) {
- FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO,
- handshake_failure);
- goto loser;
- }
+ if (ss->sec.authType == ssl_auth_psk) {
+ if (ss->statelessResume) {
+ /* We are now committed to trying to resume. */
+ PORT_Assert(sid);
+ /* Check that the negotiated SNI and the cached SNI match. */
+ if (SECITEM_CompareItem(&sid->u.ssl3.srvName,
+ &ss->ssl3.hs.srvVirtName) != SECEqual) {
+ FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO,
+ handshake_failure);
+ goto loser;
+ }
- ss->sec.serverCert = ssl_FindServerCert(ss, sid->authType,
- sid->namedCurve);
- PORT_Assert(ss->sec.serverCert);
+ ss->sec.serverCert = ssl_FindServerCert(ss, sid->authType,
+ sid->namedCurve);
+ PORT_Assert(ss->sec.serverCert);
- rv = tls13_RecoverWrappedSharedSecret(ss, sid);
- if (rv != SECSuccess) {
- SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_not_ok);
- FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
- goto loser;
- }
- tls13_RestoreCipherInfo(ss, sid);
+ rv = tls13_RecoverWrappedSharedSecret(ss, sid);
+ if (rv != SECSuccess) {
+ SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_not_ok);
+ FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+ goto loser;
+ }
+ tls13_RestoreCipherInfo(ss, sid);
- ss->sec.localCert = CERT_DupCertificate(ss->sec.serverCert->serverCert);
- if (sid->peerCert != NULL) {
- ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
+ ss->sec.localCert = CERT_DupCertificate(ss->sec.serverCert->serverCert);
+ if (sid->peerCert != NULL) {
+ ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
+ }
+ } else if (sid) {
+ /* We should never have a SID in the non-resumption case. */
+ PORT_Assert(0);
+ ssl_UncacheSessionID(ss);
+ ssl_FreeSID(sid);
+ sid = NULL;
}
-
ssl3_RegisterExtensionSender(
ss, &ss->xtnData,
ssl_tls13_pre_shared_key_xtn, tls13_ServerSendPreSharedKeyXtn);
-
tls13_NegotiateZeroRtt(ss, sid);
+
+ rv = tls13_ComputeEarlySecretsWithPsk(ss);
+ if (rv != SECSuccess) {
+ FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+ return SECFailure;
+ }
} else {
if (sid) { /* we had a sid, but it's no longer valid, free it */
SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_not_ok);
@@ -1906,35 +2016,34 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
tls13_NegotiateZeroRtt(ss, NULL);
}
- /* Need to compute early secrets. */
- rv = tls13_ComputeEarlySecrets(ss);
- if (rv != SECSuccess) {
- FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
- return SECFailure;
+ if (ss->statelessResume) {
+ PORT_Assert(ss->xtnData.selectedPsk);
+ PORT_Assert(ss->ssl3.hs.kea_def_mutable.authKeyType == ssl_auth_psk);
}
- /* Now that we have the binder key check the binder. */
- if (ss->statelessResume) {
+ /* Now that we have the binder key, check the binder. */
+ if (ss->xtnData.selectedPsk) {
SSL3Hashes hashes;
-
PORT_Assert(ss->ssl3.hs.messages.len > ss->xtnData.pskBindersLen);
rv = tls13_ComputePskBinderHash(
ss,
ss->ssl3.hs.messages.len - ss->xtnData.pskBindersLen,
- &hashes);
+ &hashes, tls13_GetHash(ss));
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
goto loser;
}
+ PORT_Assert(ss->xtnData.selectedPsk->hash == tls13_GetHash(ss));
+ PORT_Assert(ss->ssl3.hs.suite_def);
rv = tls13_VerifyFinished(ss, ssl_hs_client_hello,
- ss->ssl3.hs.pskBinderKey,
+ ss->xtnData.selectedPsk->binderKey,
ss->xtnData.pskBinder.data,
ss->xtnData.pskBinder.len,
&hashes);
- if (rv != SECSuccess) {
- goto loser;
- }
+ }
+ if (rv != SECSuccess) {
+ goto loser;
}
/* This needs to go after we verify the psk binder. */
@@ -1961,7 +2070,7 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_not_ok);
ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
- } else {
+ } else if (!ss->xtnData.selectedPsk) {
SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_misses);
}
@@ -1991,6 +2100,10 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
return SECFailure;
}
+ /* We're done with PSKs */
+ tls13_DestroyPskList(&ss->ssl3.hs.psks);
+ ss->xtnData.selectedPsk = NULL;
+
return SECSuccess;
loser:
@@ -2322,7 +2435,8 @@ tls13_ReinjectHandshakeTranscript(sslSocket *ss)
// First compute the hash.
rv = tls13_ComputeHash(ss, &hashes,
ss->ssl3.hs.messages.buf,
- ss->ssl3.hs.messages.len);
+ ss->ssl3.hs.messages.len,
+ tls13_GetHash(ss));
if (rv != SECSuccess) {
return SECFailure;
}
@@ -2339,7 +2453,6 @@ tls13_ReinjectHandshakeTranscript(sslSocket *ss)
return SECSuccess;
}
-
static unsigned int
ssl_ListCount(PRCList *list)
{
@@ -2462,6 +2575,12 @@ tls13_HandleCertificateRequest(sslSocket *ss, PRUint8 *b, PRUint32 length)
return SECFailure;
}
+ /* MUST NOT combine external PSKs with certificate authentication. */
+ if (ss->sec.authType == ssl_auth_psk) {
+ FATAL_ERROR(ss, SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST, unexpected_message);
+ return SECFailure;
+ }
+
if (tls13_IsPostHandshake(ss)) {
PORT_Assert(ss->ssl3.hs.shaPostHandshake == NULL);
ss->ssl3.hs.shaPostHandshake = PK11_CloneContext(ss->ssl3.hs.sha);
@@ -2577,6 +2696,8 @@ tls13_HandleCertificateRequest(sslSocket *ss, PRUint8 *b, PRUint32 length)
PRBool
tls13_ShouldRequestClientAuth(sslSocket *ss)
{
+ /* Even if we are configured to request a certificate, we can't
+ * if this handshake used a PSK, even when we are resuming. */
return ss->opt.requestCertificate &&
ss->ssl3.hs.kea_def->authKeyType != ssl_auth_psk;
}
@@ -2745,7 +2866,9 @@ tls13_SendServerHelloSequence(sslSocket *ss)
}
}
- ss->ssl3.hs.serverHelloTime = ssl_Time(ss);
+ /* Here we set a baseline value for our RTT estimation.
+ * This value is updated when we get a response from the client. */
+ ss->ssl3.hs.rttEstimate = ssl_Time(ss);
return SECSuccess;
}
@@ -2757,14 +2880,22 @@ tls13_HandleServerHelloPart2(sslSocket *ss)
SSL3Statistics *ssl3stats = SSL_GetStatistics();
if (ssl3_ExtensionNegotiated(ss, ssl_tls13_pre_shared_key_xtn)) {
- PORT_Assert(ss->statelessResume);
+ PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks));
+ PORT_Assert(ss->xtnData.selectedPsk);
+
+ if (ss->xtnData.selectedPsk->type != ssl_psk_resume) {
+ ss->statelessResume = PR_FALSE;
+ }
} else {
+ /* We may have offered a PSK. If the server didn't negotiate
+ * it, clear this state to re-extract the Early Secret. */
if (ss->ssl3.hs.currentSecret) {
- PORT_Assert(ss->statelessResume);
+ PORT_Assert(ssl3_ExtensionAdvertised(ss, ssl_tls13_pre_shared_key_xtn));
PK11_FreeSymKey(ss->ssl3.hs.currentSecret);
ss->ssl3.hs.currentSecret = NULL;
}
ss->statelessResume = PR_FALSE;
+ ss->xtnData.selectedPsk = NULL;
}
if (ss->statelessResume) {
@@ -2781,19 +2912,22 @@ tls13_HandleServerHelloPart2(sslSocket *ss)
ss->ssl3.hs.kea_def_mutable = *ss->ssl3.hs.kea_def;
ss->ssl3.hs.kea_def = &ss->ssl3.hs.kea_def_mutable;
- if (ss->statelessResume) {
- /* PSK */
+ if (ss->xtnData.selectedPsk) {
ss->ssl3.hs.kea_def_mutable.authKeyType = ssl_auth_psk;
- tls13_RestoreCipherInfo(ss, sid);
- if (sid->peerCert) {
- ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
- }
+ if (ss->statelessResume) {
+ tls13_RestoreCipherInfo(ss, sid);
+ if (sid->peerCert) {
+ ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
+ }
- SSL_AtomicIncrementLong(&ssl3stats->hsh_sid_cache_hits);
- SSL_AtomicIncrementLong(&ssl3stats->hsh_sid_stateless_resumes);
+ SSL_AtomicIncrementLong(&ssl3stats->hsh_sid_cache_hits);
+ SSL_AtomicIncrementLong(&ssl3stats->hsh_sid_stateless_resumes);
+ } else {
+ ss->sec.authType = ssl_auth_psk;
+ }
} else {
- /* !PSK */
- if (ssl3_ExtensionAdvertised(ss, ssl_tls13_pre_shared_key_xtn)) {
+ if (ss->statelessResume &&
+ ssl3_ExtensionAdvertised(ss, ssl_tls13_pre_shared_key_xtn)) {
SSL_AtomicIncrementLong(&ssl3stats->hsh_sid_cache_misses);
}
if (sid->cached == in_client_cache) {
@@ -2802,18 +2936,6 @@ tls13_HandleServerHelloPart2(sslSocket *ss)
}
}
- if (!ss->ssl3.hs.currentSecret) {
- PORT_Assert(!ss->statelessResume);
-
- /* If we don't already have the Early Secret we need to make it
- * now. */
- rv = tls13_ComputeEarlySecrets(ss);
- if (rv != SECSuccess) {
- FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
- return SECFailure;
- }
- }
-
/* Discard current SID and make a new one, though it may eventually
* end up looking a lot like the old one.
*/
@@ -3113,6 +3235,13 @@ tls13_HandleCertificate(sslSocket *ss, PRUint8 *b, PRUint32 length)
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
if (ss->sec.isServer) {
+ /* Receiving this message might be the first sign we have that
+ * early data is over, so pretend we received EOED. */
+ rv = tls13_MaybeHandleSuppressedEndOfEarlyData(ss);
+ if (rv != SECSuccess) {
+ return SECFailure; /* Code already set. */
+ }
+
if (ss->ssl3.clientCertRequested) {
rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERTIFICATE,
idle_handshake);
@@ -3124,8 +3253,9 @@ tls13_HandleCertificate(sslSocket *ss, PRUint8 *b, PRUint32 length)
rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERTIFICATE,
wait_cert_request, wait_server_cert);
}
- if (rv != SECSuccess)
+ if (rv != SECSuccess) {
return SECFailure;
+ }
/* We can ignore any other cleartext from the client. */
if (ss->sec.isServer && IS_DTLS(ss)) {
@@ -3139,6 +3269,11 @@ tls13_HandleCertificate(sslSocket *ss, PRUint8 *b, PRUint32 length)
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
+ } else if (ss->sec.isServer) {
+ /* Our first shot an getting an RTT estimate. If the client took extra
+ * time to fetch a certificate, this will be bad, but we can't do much
+ * about that. */
+ ss->ssl3.hs.rttEstimate = ssl_Time(ss) - ss->ssl3.hs.rttEstimate;
}
/* Process the context string */
@@ -3310,15 +3445,15 @@ tls13_DeriveSecret(sslSocket *ss, PK11SymKey *key,
const char *label,
unsigned int labelLen,
const SSL3Hashes *hashes,
- PK11SymKey **dest)
+ PK11SymKey **dest,
+ SSLHashType hash)
{
SECStatus rv;
- rv = tls13_HkdfExpandLabel(key, tls13_GetHash(ss),
- hashes->u.raw, hashes->len,
- label, labelLen,
- tls13_GetHkdfMechanism(ss),
- tls13_GetHashSize(ss), dest);
+ rv = tls13_HkdfExpandLabel(key, hash, hashes->u.raw, hashes->len,
+ label, labelLen, CKM_HKDF_DERIVE,
+ tls13_GetHashSizeForHash(hash),
+ ss->protocolVariant, dest);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
@@ -3331,18 +3466,19 @@ SECStatus
tls13_DeriveSecretNullHash(sslSocket *ss, PK11SymKey *key,
const char *label,
unsigned int labelLen,
- PK11SymKey **dest)
+ PK11SymKey **dest,
+ SSLHashType hash)
{
SSL3Hashes hashes;
SECStatus rv;
PRUint8 buf[] = { 0 };
- rv = tls13_ComputeHash(ss, &hashes, buf, 0);
+ rv = tls13_ComputeHash(ss, &hashes, buf, 0, hash);
if (rv != SECSuccess) {
return SECFailure;
}
- return tls13_DeriveSecret(ss, key, label, labelLen, &hashes, dest);
+ return tls13_DeriveSecret(ss, key, label, labelLen, &hashes, dest, hash);
}
/* Convenience wrapper that lets us supply a separate prefix and suffix. */
@@ -3381,7 +3517,7 @@ tls13_DeriveSecretWrap(sslSocket *ss, PK11SymKey *key,
}
rv = tls13_DeriveSecret(ss, key, label, strlen(label),
- &hashes, dest);
+ &hashes, dest, tls13_GetHash(ss));
if (rv != SECSuccess) {
return SECFailure;
}
@@ -3467,6 +3603,7 @@ tls13_DeriveTrafficKeys(sslSocket *ss, ssl3CipherSpec *spec,
NULL, 0,
kHkdfPurposeKey, strlen(kHkdfPurposeKey),
bulkAlgorithm, keySize,
+ ss->protocolVariant,
&spec->keyMaterial.key);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
@@ -3474,9 +3611,21 @@ tls13_DeriveTrafficKeys(sslSocket *ss, ssl3CipherSpec *spec,
goto loser;
}
+ if (IS_DTLS(ss) && spec->epoch > 0) {
+ rv = ssl_CreateMaskingContextInner(spec->version, ss->ssl3.hs.cipher_suite,
+ ss->protocolVariant, prk, kHkdfPurposeSn,
+ strlen(kHkdfPurposeSn), &spec->maskContext);
+ if (rv != SECSuccess) {
+ LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
+ PORT_Assert(0);
+ goto loser;
+ }
+ }
+
rv = tls13_HkdfExpandLabelRaw(prk, tls13_GetHash(ss),
NULL, 0,
kHkdfPurposeIv, strlen(kHkdfPurposeIv),
+ ss->protocolVariant,
spec->keyMaterial.iv, ivSize);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
@@ -3507,21 +3656,6 @@ tls13_SetSpecRecordVersion(sslSocket *ss, ssl3CipherSpec *spec)
SSL_GETPID(), ss->fd, spec, spec->recordVersion));
}
-SSLAEADCipher
-tls13_GetAead(const ssl3BulkCipherDef *cipherDef)
-{
- switch (cipherDef->calg) {
- case ssl_calg_aes_gcm:
- return tls13_AESGCM;
- case ssl_calg_chacha20:
- return tls13_ChaCha20Poly1305;
- default:
- PORT_Assert(PR_FALSE);
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return NULL;
- }
-}
-
static SECStatus
tls13_SetupPendingCipherSpec(sslSocket *ss, ssl3CipherSpec *spec)
{
@@ -3545,14 +3679,12 @@ tls13_SetupPendingCipherSpec(sslSocket *ss, ssl3CipherSpec *spec)
SSL_GETPID(), ss->fd, suite));
spec->cipherDef = ssl_GetBulkCipherDef(ssl_LookupCipherSuiteDef(suite));
- spec->aead = tls13_GetAead(spec->cipherDef);
- if (!spec->aead) {
- return SECFailure;
- }
if (spec->epoch == TrafficKeyEarlyApplicationData) {
- spec->earlyDataRemaining =
- ss->sec.ci.sid->u.ssl3.locked.sessionTicket.max_early_data_size;
+ if (ss->xtnData.selectedPsk &&
+ ss->xtnData.selectedPsk->zeroRttSuite != TLS_NULL_WITH_NULL_NULL) {
+ spec->earlyDataRemaining = ss->xtnData.selectedPsk->maxEarlyData;
+ }
}
tls13_SetSpecRecordVersion(ss, spec);
@@ -3571,6 +3703,38 @@ tls13_SetupPendingCipherSpec(sslSocket *ss, ssl3CipherSpec *spec)
}
/*
+ * Initialize the cipher context. All TLS 1.3 operations are AEAD,
+ * so they are all message contexts.
+ */
+static SECStatus
+tls13_InitPendingContext(sslSocket *ss, ssl3CipherSpec *spec)
+{
+ CK_MECHANISM_TYPE encMechanism;
+ CK_ATTRIBUTE_TYPE encMode;
+ SECItem iv;
+ SSLCipherAlgorithm calg;
+
+ calg = spec->cipherDef->calg;
+
+ encMechanism = ssl3_Alg2Mech(calg);
+ encMode = CKA_NSS_MESSAGE | ((spec->direction == ssl_secret_write) ? CKA_ENCRYPT : CKA_DECRYPT);
+ iv.data = NULL;
+ iv.len = 0;
+
+ /*
+ * build the context
+ */
+ spec->cipherContext = PK11_CreateContextBySymKey(encMechanism, encMode,
+ spec->keyMaterial.key,
+ &iv);
+ if (!spec->cipherContext) {
+ ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+/*
* Called before sending alerts to set up the right key on the client.
* We might encounter errors during the handshake where the current
* key is ClearText or EarlyApplicationData. This
@@ -3649,6 +3813,11 @@ tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch,
goto loser;
}
+ rv = tls13_InitPendingContext(ss, spec);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
/* Now that we've set almost everything up, finally cut over. */
specp = (direction == ssl_secret_read) ? &ss->ssl3.crSpec : &ss->ssl3.cwSpec;
ssl_GetSpecWriteLock(ss);
@@ -3811,100 +3980,113 @@ tls13_DestroyEarlyData(PRCList *list)
* See RFC 5288 and https://tools.ietf.org/html/draft-ietf-tls-chacha20-poly1305-04#section-2
*/
static void
-tls13_WriteNonce(const ssl3KeyMaterial *keys,
- const unsigned char *seqNumBuf, unsigned int seqNumLen,
- unsigned char *nonce, unsigned int nonceLen)
+tls13_WriteNonce(const unsigned char *ivIn, unsigned int ivInLen,
+ const unsigned char *nonce, unsigned int nonceLen,
+ unsigned char *ivOut, unsigned int ivOutLen)
{
size_t i;
+ unsigned int offset = ivOutLen - nonceLen;
- PORT_Assert(nonceLen == 12);
- memcpy(nonce, keys->iv, 12);
+ PORT_Assert(ivInLen <= ivOutLen);
+ PORT_Assert(nonceLen <= ivOutLen);
+ PORT_Memset(ivOut, 0, ivOutLen);
+ PORT_Memcpy(ivOut, ivIn, ivInLen);
- /* XOR the last 8 bytes of the IV with the sequence number. */
- PORT_Assert(seqNumLen == 8);
- for (i = 0; i < 8; ++i) {
- nonce[4 + i] ^= seqNumBuf[i];
+ /* XOR the last n bytes of the IV with the nonce (should be a counter). */
+ for (i = 0; i < nonceLen; ++i) {
+ ivOut[offset + i] ^= nonce[i];
}
- PRINT_BUF(50, (NULL, "Nonce", nonce, nonceLen));
+ PRINT_BUF(50, (NULL, "Nonce", ivOut, ivOutLen));
}
-/* Implement the SSLAEADCipher interface defined in sslimpl.h.
- *
- * That interface takes the additional data (see below) and reinterprets that as
- * a sequence number. In TLS 1.3 there is no additional data so this value is
- * just the encoded sequence number.
+/* Setup the IV for AEAD encrypt. The PKCS #11 module will add the
+ * counter, but it doesn't know about the DTLS epic, so we add it here.
*/
-SECStatus
-tls13_AEAD(const ssl3KeyMaterial *keys, PRBool doDecrypt,
- unsigned char *out, unsigned int *outlen, unsigned int maxout,
- const unsigned char *in, unsigned int inlen,
- CK_MECHANISM_TYPE mechanism,
- unsigned char *aeadParams, unsigned int aeadParamLength)
+unsigned int
+tls13_SetupAeadIv(PRBool isDTLS, unsigned char *ivOut, unsigned char *ivIn,
+ unsigned int offset, unsigned int ivLen, DTLSEpoch epoch)
{
- SECItem param = {
- siBuffer, aeadParams, aeadParamLength
- };
-
- if (doDecrypt) {
- return PK11_Decrypt(keys->key, mechanism, &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
@@ -3968,7 +4150,7 @@ tls13_HandleEncryptedExtensions(sslSocket *ss, PRUint8 *b, PRUint32 length)
/* We can only get here if we offered 0-RTT. */
if (ssl3_ExtensionNegotiated(ss, ssl_tls13_early_data_xtn)) {
PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_sent);
- if (!ss->statelessResume) {
+ if (!ss->xtnData.selectedPsk) {
/* Illegal to accept 0-RTT without also accepting PSK. */
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_ENCRYPTED_EXTENSIONS,
illegal_parameter);
@@ -4006,6 +4188,10 @@ tls13_HandleEncryptedExtensions(sslSocket *ss, PRUint8 *b, PRUint32 length)
TLS13_SET_HS_STATE(ss, wait_cert_request);
}
+ /* Client is done with any PSKs */
+ tls13_DestroyPskList(&ss->ssl3.hs.psks);
+ ss->xtnData.selectedPsk = NULL;
+
return SECSuccess;
}
@@ -4285,7 +4471,7 @@ loser:
static SECStatus
tls13_ComputePskBinderHash(sslSocket *ss, unsigned int prefixLength,
- SSL3Hashes *hashes)
+ SSL3Hashes *hashes, SSLHashType hashType)
{
SECStatus rv;
@@ -4295,14 +4481,14 @@ tls13_ComputePskBinderHash(sslSocket *ss, unsigned int prefixLength,
PRINT_BUF(10, (NULL, "Handshake hash computed over ClientHello prefix",
ss->ssl3.hs.messages.buf, prefixLength));
- rv = PK11_HashBuf(ssl3_HashTypeToOID(tls13_GetHash(ss)),
+ rv = PK11_HashBuf(ssl3_HashTypeToOID(hashType),
hashes->u.raw, ss->ssl3.hs.messages.buf, prefixLength);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
return SECFailure;
}
- hashes->len = tls13_GetHashSize(ss);
+ hashes->len = tls13_GetHashSizeForHash(hashType);
PRINT_BUF(10, (NULL, "PSK Binder hash", hashes->u.raw, hashes->len));
return SECSuccess;
@@ -4320,7 +4506,10 @@ tls13_WriteExtensionsWithBinder(sslSocket *ss, sslBuffer *extensions)
{
SSL3Hashes hashes;
SECStatus rv;
- unsigned int size = tls13_GetHashSize(ss);
+
+ PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks));
+ sslPsk *psk = (sslPsk *)PR_LIST_HEAD(&ss->ssl3.hs.psks);
+ unsigned int size = tls13_GetHashSizeForHash(psk->hash);
unsigned int prefixLen = extensions->len - size - 3;
unsigned int finishedLen;
@@ -4341,15 +4530,18 @@ tls13_WriteExtensionsWithBinder(sslSocket *ss, sslBuffer *extensions)
}
/* Calculate the binder based on what has been written out. */
- rv = tls13_ComputePskBinderHash(ss, ss->ssl3.hs.messages.len, &hashes);
+ rv = tls13_ComputePskBinderHash(ss, ss->ssl3.hs.messages.len,
+ &hashes, psk->hash);
if (rv != SECSuccess) {
return SECFailure;
}
/* Write the binder into the extensions buffer, over the zeros we reserved
- * previously. This avoids an allocation and means that we don't need a
+ * previously. This avoids an allocation and means that we don't need a
* separate write for the extra bits that precede the binder. */
- rv = tls13_ComputeFinished(ss, ss->ssl3.hs.pskBinderKey, &hashes, PR_TRUE,
+ PORT_Assert(psk->binderKey);
+ rv = tls13_ComputeFinished(ss, psk->binderKey,
+ psk->hash, &hashes, PR_TRUE,
extensions->buf + extensions->len - size,
&finishedLen, size);
if (rv != SECSuccess) {
@@ -4369,13 +4561,13 @@ tls13_WriteExtensionsWithBinder(sslSocket *ss, sslBuffer *extensions)
static SECStatus
tls13_ComputeFinished(sslSocket *ss, PK11SymKey *baseKey,
- const SSL3Hashes *hashes,
+ SSLHashType hashType, const SSL3Hashes *hashes,
PRBool sending, PRUint8 *output, unsigned int *outputLen,
unsigned int maxOutputLen)
{
SECStatus rv;
PK11Context *hmacCtx = NULL;
- CK_MECHANISM_TYPE macAlg = tls13_GetHmacMechanism(ss);
+ CK_MECHANISM_TYPE macAlg = tls13_GetHmacMechanismFromHash(hashType);
SECItem param = { siBuffer, NULL, 0 };
unsigned int outputLenUint;
const char *label = kHkdfLabelFinishedSecret;
@@ -4387,17 +4579,16 @@ tls13_ComputeFinished(sslSocket *ss, PK11SymKey *baseKey,
PRINT_BUF(50, (ss, "Handshake hash", hashes->u.raw, hashes->len));
/* Now derive the appropriate finished secret from the base secret. */
- rv = tls13_HkdfExpandLabel(baseKey,
- tls13_GetHash(ss),
- NULL, 0,
- label, strlen(label),
- tls13_GetHmacMechanism(ss),
- tls13_GetHashSize(ss), &secret);
+ rv = tls13_HkdfExpandLabel(baseKey, hashType,
+ NULL, 0, label, strlen(label),
+ tls13_GetHmacMechanismFromHash(hashType),
+ tls13_GetHashSizeForHash(hashType),
+ ss->protocolVariant, &secret);
if (rv != SECSuccess) {
goto abort;
}
- PORT_Assert(hashes->len == tls13_GetHashSize(ss));
+ PORT_Assert(hashes->len == tls13_GetHashSizeForHash(hashType));
hmacCtx = PK11_CreateContextBySymKey(macAlg, CKA_SIGN,
secret, &param);
if (!hmacCtx) {
@@ -4412,7 +4603,7 @@ tls13_ComputeFinished(sslSocket *ss, PK11SymKey *baseKey,
if (rv != SECSuccess)
goto abort;
- PORT_Assert(maxOutputLen >= tls13_GetHashSize(ss));
+ PORT_Assert(maxOutputLen >= tls13_GetHashSizeForHash(hashType));
rv = PK11_DigestFinal(hmacCtx, output, &outputLenUint, maxOutputLen);
if (rv != SECSuccess)
goto abort;
@@ -4456,7 +4647,7 @@ tls13_SendFinished(sslSocket *ss, PK11SymKey *baseKey)
}
ssl_GetSpecReadLock(ss);
- rv = tls13_ComputeFinished(ss, baseKey, &hashes, PR_TRUE,
+ rv = tls13_ComputeFinished(ss, baseKey, tls13_GetHash(ss), &hashes, PR_TRUE,
finishedBuf, &finishedLen, sizeof(finishedBuf));
ssl_ReleaseSpecReadLock(ss);
if (rv != SECSuccess) {
@@ -4493,7 +4684,7 @@ tls13_VerifyFinished(sslSocket *ss, SSLHandshakeType message,
return SECFailure;
}
- rv = tls13_ComputeFinished(ss, secret, hashes, PR_FALSE,
+ rv = tls13_ComputeFinished(ss, secret, tls13_GetHash(ss), hashes, PR_FALSE,
finishedBuf, &finishedLen, sizeof(finishedBuf));
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
@@ -4583,6 +4774,20 @@ tls13_ServerHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length)
SSL_TRC(3, ("%d: TLS13[%d]: server handle finished handshake",
SSL_GETPID(), ss->fd));
+ if (!tls13_ShouldRequestClientAuth(ss)) {
+ /* Receiving this message might be the first sign we have that
+ * early data is over, so pretend we received EOED. */
+ rv = tls13_MaybeHandleSuppressedEndOfEarlyData(ss);
+ if (rv != SECSuccess) {
+ return SECFailure; /* Code already set. */
+ }
+
+ if (!tls13_IsPostHandshake(ss)) {
+ /* Finalize the RTT estimate. */
+ ss->ssl3.hs.rttEstimate = ssl_Time(ss) - ss->ssl3.hs.rttEstimate;
+ }
+ }
+
rv = tls13_CommonHandleFinished(ss,
ss->firstHsDone ? ss->ssl3.hs.clientTrafficSecret : ss->ssl3.hs.clientHsTrafficSecret,
b, length);
@@ -4646,7 +4851,8 @@ tls13_ServerHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length)
}
ssl_GetXmitBufLock(ss);
- if (ss->opt.enableSessionTickets) {
+ /* If resumption, authType is the original value and not ssl_auth_psk. */
+ if (ss->opt.enableSessionTickets && ss->sec.authType != ssl_auth_psk) {
rv = tls13_SendNewSessionTicket(ss, NULL, 0);
if (rv != SECSuccess) {
goto loser;
@@ -4929,8 +5135,9 @@ tls13_SendNewSessionTicket(sslSocket *ss, const PRUint8 *appToken,
ticketNonce, sizeof(ticketNonce),
kHkdfLabelResumption,
strlen(kHkdfLabelResumption),
- tls13_GetHkdfMechanism(ss),
- tls13_GetHashSize(ss), &secret);
+ CKM_HKDF_DERIVE,
+ tls13_GetHashSize(ss),
+ ss->protocolVariant, &secret);
if (rv != SECSuccess) {
goto loser;
}
@@ -5028,6 +5235,14 @@ SSLExp_SendSessionTicket(PRFileDesc *fd, const PRUint8 *token,
return SECFailure;
}
+ /* Disable tickets if we can trace this connection back to a PSK.
+ * We aren't able to issue tickets (currently) without a certificate.
+ * As PSK =~ resumption, there is no reason to do this. */
+ if (ss->sec.authType == ssl_auth_psk) {
+ PORT_SetError(SSL_ERROR_FEATURE_DISABLED);
+ return SECFailure;
+ }
+
ssl_GetSSL3HandshakeLock(ss);
ssl_GetXmitBufLock(ss);
rv = tls13_SendNewSessionTicket(ss, token, tokenLen);
@@ -5163,8 +5378,9 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length)
ticket_nonce.data, ticket_nonce.len,
kHkdfLabelResumption,
strlen(kHkdfLabelResumption),
- tls13_GetHkdfMechanism(ss),
- tls13_GetHashSize(ss), &secret);
+ CKM_HKDF_DERIVE,
+ tls13_GetHashSize(ss),
+ ss->protocolVariant, &secret);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -5348,11 +5564,20 @@ tls13_ProtectRecord(sslSocket *ss,
sslBuffer buf = SSL_BUFFER_FIXED(hdr, sizeof(hdr));
PRBool needsLength;
PRUint8 aad[21];
+ const int ivLen = cipher_def->iv_size + cipher_def->explicit_nonce_size;
+ unsigned int ivOffset = ivLen - sizeof(sslSequenceNumber);
+ unsigned char ivOut[MAX_IV_LENGTH];
+
unsigned int aadLen;
unsigned int len;
PORT_Assert(cipher_def->type == type_aead);
+ /* If the following condition holds, we can skip the padding logic for
+ * DTLS 1.3 (4.2.3). This will be the case until we support a cipher
+ * with tag length < 15B. */
+ PORT_Assert(tagLen + 1 /* cType */ >= 16);
+
/* Add the content type at the end. */
*(SSL_BUFFER_NEXT(wrBuf) + contentLen) = type;
@@ -5363,9 +5588,7 @@ tls13_ProtectRecord(sslSocket *ss,
return SECFailure;
}
if (needsLength) {
- rv = sslBuffer_AppendNumber(&buf, contentLen + 1 +
- cwSpec->cipherDef->tag_size,
- 2);
+ rv = sslBuffer_AppendNumber(&buf, contentLen + 1 + tagLen, 2);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -5376,14 +5599,22 @@ tls13_ProtectRecord(sslSocket *ss,
if (rv != SECSuccess) {
return SECFailure;
}
- rv = cwSpec->aead(&cwSpec->keyMaterial,
- PR_FALSE, /* do encrypt */
- SSL_BUFFER_NEXT(wrBuf), /* output */
- &len, /* out len */
- SSL_BUFFER_SPACE(wrBuf), /* max out */
- SSL_BUFFER_NEXT(wrBuf), /* input */
- contentLen + 1, /* input len */
- aad, aadLen);
+ /* set up initial IV value */
+ ivOffset = tls13_SetupAeadIv(IS_DTLS(ss), ivOut, cwSpec->keyMaterial.iv,
+ ivOffset, ivLen, cwSpec->epoch);
+
+ rv = tls13_AEAD(cwSpec->cipherContext, PR_FALSE,
+ CKG_GENERATE_COUNTER_XOR, ivOffset * BPB,
+ ivOut, ivOut, ivLen, /* iv */
+ NULL, 0, /* nonce */
+ aad + sizeof(sslSequenceNumber), /* aad */
+ aadLen - sizeof(sslSequenceNumber),
+ SSL_BUFFER_NEXT(wrBuf), /* output */
+ &len, /* out len */
+ SSL_BUFFER_SPACE(wrBuf), /* max out */
+ tagLen,
+ SSL_BUFFER_NEXT(wrBuf), /* input */
+ contentLen + 1); /* input len */
if (rv != SECSuccess) {
PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
return SECFailure;
@@ -5413,6 +5644,9 @@ tls13_UnprotectRecord(sslSocket *ss,
SSL3AlertDescription *alert)
{
const ssl3BulkCipherDef *cipher_def = spec->cipherDef;
+ const int ivLen = cipher_def->iv_size + cipher_def->explicit_nonce_size;
+ const int tagLen = cipher_def->tag_size;
+
PRUint8 aad[21];
unsigned int aadLen;
SECStatus rv;
@@ -5440,7 +5674,7 @@ tls13_UnprotectRecord(sslSocket *ss,
/* We can perform this test in variable time because the record's total
* length and the ciphersuite are both public knowledge. */
- if (cText->buf->len < cipher_def->tag_size) {
+ if (cText->buf->len < tagLen) {
SSL_TRC(3,
("%d: TLS13[%d]: record too short to contain valid AEAD data",
SSL_GETPID(), ss->fd));
@@ -5467,17 +5701,26 @@ tls13_UnprotectRecord(sslSocket *ss,
spec->epoch, cText->seqNum,
aad, &aadLen, sizeof(aad));
if (rv != SECSuccess) {
+
return SECFailure;
}
- rv = spec->aead(&spec->keyMaterial,
- PR_TRUE, /* do decrypt */
- plaintext->buf, /* out */
+ rv = tls13_AEAD(spec->cipherContext, PR_TRUE,
+ CKG_NO_GENERATE, 0, /* ignored for decrypt */
+ spec->keyMaterial.iv, NULL, ivLen, /* iv */
+ aad, sizeof(sslSequenceNumber), /* nonce */
+ aad + sizeof(sslSequenceNumber), /* aad */
+ aadLen - sizeof(sslSequenceNumber),
+ plaintext->buf, /* output */
&plaintext->len, /* outlen */
plaintext->space, /* maxout */
+ tagLen,
cText->buf->buf, /* in */
- cText->buf->len, /* inlen */
- aad, aadLen);
+ cText->buf->len); /* inlen */
if (rv != SECSuccess) {
+ if (IS_DTLS(ss)) {
+ spec->deprotectionFailures++;
+ }
+
SSL_TRC(3,
("%d: TLS13[%d]: record has bogus MAC",
SSL_GETPID(), ss->fd));
@@ -5538,9 +5781,10 @@ tls13_UnprotectRecord(sslSocket *ss,
* 1. We are doing TLS 1.3
* 2. This isn't a second ClientHello (in response to HelloRetryRequest)
* 3. The 0-RTT option is set.
- * 4. We have a valid ticket.
- * 5. The server is willing to accept 0-RTT.
- * 6. We have not changed our ALPN settings to disallow the ALPN tag
+ * 4. We have a valid ticket or an External PSK.
+ * 5. If resuming:
+ * 5a. The server is willing to accept 0-RTT.
+ * 5b. We have not changed our ALPN settings to disallow the ALPN tag
* in the ticket.
*
* Called from tls13_ClientSendEarlyDataXtn().
@@ -5550,17 +5794,39 @@ tls13_ClientAllow0Rtt(const sslSocket *ss, const sslSessionID *sid)
{
/* We checked that the cipher suite was still allowed back in
* ssl3_SendClientHello. */
- if (sid->version < SSL_LIBRARY_VERSION_TLS_1_3)
+ if (sid->version < SSL_LIBRARY_VERSION_TLS_1_3) {
return PR_FALSE;
- if (ss->ssl3.hs.helloRetry)
+ }
+ if (ss->ssl3.hs.helloRetry) {
return PR_FALSE;
- if (!ss->opt.enable0RttData)
+ }
+ if (!ss->opt.enable0RttData) {
return PR_FALSE;
- if (!ss->statelessResume)
+ }
+ if (PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks)) {
return PR_FALSE;
- if ((sid->u.ssl3.locked.sessionTicket.flags & ticket_allow_early_data) == 0)
+ }
+ sslPsk *psk = (sslPsk *)PR_LIST_HEAD(&ss->ssl3.hs.psks);
+
+ if (psk->zeroRttSuite == TLS_NULL_WITH_NULL_NULL) {
return PR_FALSE;
- return ssl_AlpnTagAllowed(ss, &sid->u.ssl3.alpnSelection);
+ }
+ if (!psk->maxEarlyData) {
+ return PR_FALSE;
+ }
+
+ if (psk->type == ssl_psk_external) {
+ return psk->hash == tls13_GetHashForCipherSuite(psk->zeroRttSuite);
+ }
+ if (psk->type == ssl_psk_resume) {
+ if (!ss->statelessResume)
+ return PR_FALSE;
+ if ((sid->u.ssl3.locked.sessionTicket.flags & ticket_allow_early_data) == 0)
+ return PR_FALSE;
+ return ssl_AlpnTagAllowed(ss, &sid->u.ssl3.alpnSelection);
+ }
+ PORT_Assert(0);
+ return PR_FALSE;
}
SECStatus
@@ -5607,6 +5873,9 @@ tls13_MaybeDo0RTTHandshake(sslSocket *ss)
}
}
+ /* If we're trying 0-RTT, derive from the first PSK */
+ PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks) && !ss->xtnData.selectedPsk);
+ ss->xtnData.selectedPsk = (sslPsk *)PR_LIST_HEAD(&ss->ssl3.hs.psks);
rv = tls13_DeriveEarlySecrets(ss);
if (rv != SECSuccess) {
return SECFailure;
@@ -5618,6 +5887,7 @@ tls13_MaybeDo0RTTHandshake(sslSocket *ss)
rv = tls13_SetCipherSpec(ss, TrafficKeyEarlyApplicationData,
ssl_secret_write, PR_TRUE);
+ ss->xtnData.selectedPsk = NULL;
if (rv != SECSuccess) {
return SECFailure;
}
@@ -5672,12 +5942,14 @@ tls13_SendEndOfEarlyData(sslSocket *ss)
{
SECStatus rv;
- SSL_TRC(3, ("%d: TLS13[%d]: send EndOfEarlyData", SSL_GETPID(), ss->fd));
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
- rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_end_of_early_data, 0);
- if (rv != SECSuccess) {
- return rv; /* err set by AppendHandshake. */
+ if (!ss->opt.suppressEndOfEarlyData) {
+ SSL_TRC(3, ("%d: TLS13[%d]: send EndOfEarlyData", SSL_GETPID(), ss->fd));
+ rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_end_of_early_data, 0);
+ if (rv != SECSuccess) {
+ return rv; /* err set by AppendHandshake. */
+ }
}
ss->ssl3.hs.zeroRttState = ssl_0rtt_done;
@@ -5685,7 +5957,7 @@ tls13_SendEndOfEarlyData(sslSocket *ss)
}
static SECStatus
-tls13_HandleEndOfEarlyData(sslSocket *ss, PRUint8 *b, PRUint32 length)
+tls13_HandleEndOfEarlyData(sslSocket *ss, const PRUint8 *b, PRUint32 length)
{
SECStatus rv;
@@ -5728,6 +6000,18 @@ tls13_HandleEndOfEarlyData(sslSocket *ss, PRUint8 *b, PRUint32 length)
return SECSuccess;
}
+static SECStatus
+tls13_MaybeHandleSuppressedEndOfEarlyData(sslSocket *ss)
+{
+ PORT_Assert(ss->sec.isServer);
+ if (!ss->opt.suppressEndOfEarlyData ||
+ ss->ssl3.hs.zeroRttState != ssl_0rtt_accepted) {
+ return SECSuccess;
+ }
+
+ return tls13_HandleEndOfEarlyData(ss, NULL, 0);
+}
+
SECStatus
tls13_HandleEarlyApplicationData(sslSocket *ss, sslBuffer *origBuf)
{
@@ -5763,14 +6047,26 @@ tls13_HandleEarlyApplicationData(sslSocket *ss, sslBuffer *origBuf)
}
PRUint16
-tls13_EncodeDraftVersion(SSL3ProtocolVersion version, SSLProtocolVariant variant)
+tls13_EncodeVersion(SSL3ProtocolVersion version, SSLProtocolVariant variant)
{
+ if (variant == ssl_variant_datagram) {
+ /* TODO: When DTLS 1.3 is out of draft, replace this with
+ * dtls_TLSVersionToDTLSVersion(). */
+ switch (version) {
#ifdef DTLS_1_3_DRAFT_VERSION
- if (version == SSL_LIBRARY_VERSION_TLS_1_3 &&
- variant == ssl_variant_datagram) {
- return 0x7f00 | DTLS_1_3_DRAFT_VERSION;
- }
+ case SSL_LIBRARY_VERSION_TLS_1_3:
+ return 0x7f00 | DTLS_1_3_DRAFT_VERSION;
#endif
+ case SSL_LIBRARY_VERSION_TLS_1_2:
+ return SSL_LIBRARY_VERSION_DTLS_1_2_WIRE;
+ case SSL_LIBRARY_VERSION_TLS_1_1:
+ /* TLS_1_1 maps to DTLS_1_0, see sslproto.h. */
+ return SSL_LIBRARY_VERSION_DTLS_1_0_WIRE;
+ default:
+ PORT_Assert(0);
+ }
+ }
+ /* Stream-variant encodings do not change. */
return (PRUint16)version;
}
@@ -5800,8 +6096,8 @@ tls13_ClientReadSupportedVersion(sslSocket *ss)
return SECFailure;
}
- if (temp != tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3,
- ss->protocolVariant)) {
+ if (temp != tls13_EncodeVersion(SSL_LIBRARY_VERSION_TLS_1_3,
+ ss->protocolVariant)) {
/* You cannot negotiate < TLS 1.3 with supported_versions. */
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_SERVER_HELLO, illegal_parameter);
return SECFailure;
@@ -5840,7 +6136,7 @@ tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supportedVersions)
return SECFailure;
}
- PRUint16 wire = tls13_EncodeDraftVersion(version, ss->protocolVariant);
+ PRUint16 wire = tls13_EncodeVersion(version, ss->protocolVariant);
unsigned long offset;
for (offset = 0; offset < versions.len; offset += 2) {
diff --git a/security/nss/lib/ssl/tls13con.h b/security/nss/lib/ssl/tls13con.h
index bd309419f..9a3cd14c1 100644
--- a/security/nss/lib/ssl/tls13con.h
+++ b/security/nss/lib/ssl/tls13con.h
@@ -44,20 +44,22 @@ PRBool tls13_InHsState(sslSocket *ss, ...);
PRBool tls13_IsPostHandshake(const sslSocket *ss);
-SSLHashType tls13_GetHashForCipherSuite(ssl3CipherSuite suite);
SSLHashType tls13_GetHash(const sslSocket *ss);
-unsigned int tls13_GetHashSizeForHash(SSLHashType hash);
+SECStatus tls13_GetHashAndCipher(PRUint16 version, PRUint16 cipherSuite,
+ SSLHashType *hash, const ssl3BulkCipherDef **cipher);
+SSLHashType tls13_GetHashForCipherSuite(ssl3CipherSuite suite);
unsigned int tls13_GetHashSize(const sslSocket *ss);
-CK_MECHANISM_TYPE tls13_GetHkdfMechanism(sslSocket *ss);
-CK_MECHANISM_TYPE tls13_GetHkdfMechanismForHash(SSLHashType hash);
+unsigned int tls13_GetHashSizeForHash(SSLHashType hash);
SECStatus tls13_ComputeHash(sslSocket *ss, SSL3Hashes *hashes,
- const PRUint8 *buf, unsigned int len);
+ const PRUint8 *buf, unsigned int len,
+ SSLHashType hash);
SECStatus tls13_ComputeHandshakeHashes(sslSocket *ss,
SSL3Hashes *hashes);
SECStatus tls13_DeriveSecretNullHash(sslSocket *ss, PK11SymKey *key,
const char *label,
unsigned int labelLen,
- PK11SymKey **dest);
+ PK11SymKey **dest,
+ SSLHashType hash);
void tls13_FatalError(sslSocket *ss, PRErrorCode prError,
SSL3AlertDescription desc);
SECStatus tls13_SetupClientHello(sslSocket *ss, sslClientHelloType chType);
@@ -107,8 +109,8 @@ SECStatus tls13_ProtectRecord(sslSocket *ss,
PRInt32 tls13_Read0RttData(sslSocket *ss, PRUint8 *buf, PRInt32 len);
SECStatus tls13_HandleEarlyApplicationData(sslSocket *ss, sslBuffer *origBuf);
PRBool tls13_ClientAllow0Rtt(const sslSocket *ss, const sslSessionID *sid);
-PRUint16 tls13_EncodeDraftVersion(SSL3ProtocolVersion version,
- SSLProtocolVariant variant);
+PRUint16 tls13_EncodeVersion(SSL3ProtocolVersion version,
+ SSLProtocolVariant variant);
SECStatus tls13_ClientReadSupportedVersion(sslSocket *ss);
SECStatus tls13_NegotiateVersion(sslSocket *ss,
const TLSExtension *supported_versions);
@@ -133,12 +135,18 @@ SECStatus tls13_SendKeyUpdate(sslSocket *ss, tls13KeyUpdateRequest request,
PRBool buffer);
SECStatus SSLExp_KeyUpdate(PRFileDesc *fd, PRBool requestUpdate);
PRBool tls13_MaybeTls13(sslSocket *ss);
-SSLAEADCipher tls13_GetAead(const ssl3BulkCipherDef *cipherDef);
-SECStatus tls13_AEAD(const ssl3KeyMaterial *keys, PRBool doDecrypt,
- unsigned char *out, unsigned int *outlen, unsigned int maxout,
- const unsigned char *in, unsigned int inlen,
- CK_MECHANISM_TYPE mechanism,
- unsigned char *aeadParams, unsigned int aeadParamLength);
+unsigned int tls13_SetupAeadIv(PRBool isDTLS, unsigned char *ivOut,
+ unsigned char *ivIn, unsigned int offset,
+ unsigned int ivLen, DTLSEpoch epoch);
+SECStatus tls13_AEAD(PK11Context *context, PRBool decrypt,
+ CK_GENERATOR_FUNCTION ivGen, unsigned int fixedbits,
+ const unsigned char *ivIn, unsigned char *ivOut,
+ unsigned int ivLen,
+ const unsigned char *nonceIn, unsigned int nonceLen,
+ const unsigned char *aad, unsigned int aadLen,
+ unsigned char *out, unsigned int *outLen,
+ unsigned int maxout, unsigned int tagLen,
+ const unsigned char *in, unsigned int inLen);
void tls13_SetSpecRecordVersion(sslSocket *ss, ssl3CipherSpec *spec);
SECStatus SSLExp_SendCertificateRequest(PRFileDesc *fd);
diff --git a/security/nss/lib/ssl/tls13esni.c b/security/nss/lib/ssl/tls13esni.c
index f2f8d0a9c..7182f22af 100644
--- a/security/nss/lib/ssl/tls13esni.c
+++ b/security/nss/lib/ssl/tls13esni.c
@@ -550,7 +550,7 @@ tls13_ComputeESNIKeys(const sslSocket *ss,
hash, hashSize,
kHkdfPurposeEsniKey, strlen(kHkdfPurposeEsniKey),
ssl3_Alg2Mech(cipherDef->calg),
- keySize,
+ keySize, ss->protocolVariant,
&keyMat->key);
if (rv != SECSuccess) {
goto loser;
@@ -558,7 +558,7 @@ tls13_ComputeESNIKeys(const sslSocket *ss,
rv = tls13_HkdfExpandLabelRaw(Zx, suite->prf_hash,
hash, hashSize,
kHkdfPurposeEsniIv, strlen(kHkdfPurposeEsniIv),
- keyMat->iv, ivSize);
+ ss->protocolVariant, keyMat->iv, ivSize);
if (rv != SECSuccess) {
goto loser;
}
@@ -662,12 +662,6 @@ tls13_FormatEsniAADInput(sslBuffer *aadInput,
{
SECStatus rv;
- /* 8 bytes of 0 for the sequence number. */
- rv = sslBuffer_AppendNumber(aadInput, 0, 8);
- if (rv != SECSuccess) {
- return SECFailure;
- }
-
/* Key share. */
PORT_Assert(keyShareLen > 0);
rv = sslBuffer_Append(aadInput, keyShare, keyShareLen);
@@ -680,12 +674,10 @@ tls13_FormatEsniAADInput(sslBuffer *aadInput,
static SECStatus
tls13_ServerGetEsniAEAD(const sslSocket *ss, PRUint64 suite,
- const ssl3CipherSuiteDef **suiteDefp,
- SSLAEADCipher *aeadp)
+ const ssl3CipherSuiteDef **suiteDefp)
{
SECStatus rv;
const ssl3CipherSuiteDef *suiteDef;
- SSLAEADCipher aead;
/* Check against the suite list for ESNI */
PRBool csMatch = PR_FALSE;
@@ -712,13 +704,8 @@ tls13_ServerGetEsniAEAD(const sslSocket *ss, PRUint64 suite,
if (!suiteDef) {
return SECFailure;
}
- aead = tls13_GetAead(ssl_GetBulkCipherDef(suiteDef));
- if (!aead) {
- return SECFailure;
- }
*suiteDefp = suiteDef;
- *aeadp = aead;
return SECSuccess;
}
@@ -729,7 +716,6 @@ tls13_ServerDecryptEsniXtn(const sslSocket *ss, const PRUint8 *in, unsigned int
sslReader rdr = SSL_READER(in, inLen);
PRUint64 suite;
const ssl3CipherSuiteDef *suiteDef = NULL;
- SSLAEADCipher aead = NULL;
TLSExtension *keyShareExtension;
TLS13KeyShareEntry *entry = NULL;
ssl3KeyMaterial keyMat = { NULL };
@@ -748,7 +734,7 @@ tls13_ServerDecryptEsniXtn(const sslSocket *ss, const PRUint8 *in, unsigned int
}
/* Find the AEAD */
- rv = tls13_ServerGetEsniAEAD(ss, suite, &suiteDef, &aead);
+ rv = tls13_ServerGetEsniAEAD(ss, suite, &suiteDef);
if (rv != SECSuccess) {
goto loser;
}
@@ -822,11 +808,25 @@ tls13_ServerDecryptEsniXtn(const sslSocket *ss, const PRUint8 *in, unsigned int
goto loser;
}
- rv = aead(&keyMat, PR_TRUE /* Decrypt */,
- out, outLen, maxLen,
- buf.buf, buf.len,
- SSL_BUFFER_BASE(&aadInput),
- SSL_BUFFER_LEN(&aadInput));
+ const ssl3BulkCipherDef *cipher_def = ssl_GetBulkCipherDef(suiteDef);
+ unsigned char *aad = SSL_BUFFER_BASE(&aadInput);
+ int aadLen = SSL_BUFFER_LEN(&aadInput);
+ int ivLen = cipher_def->iv_size + cipher_def->explicit_nonce_size;
+ SSLCipherAlgorithm calg = cipher_def->calg;
+ unsigned char zero[sizeof(sslSequenceNumber)] = { 0 };
+ SECItem null_params = { siBuffer, NULL, 0 };
+ PK11Context *ctxt = PK11_CreateContextBySymKey(ssl3_Alg2Mech(calg),
+ CKA_NSS_MESSAGE | CKA_DECRYPT,
+ keyMat.key, &null_params);
+ if (!ctxt) {
+ sslBuffer_Clear(&aadInput);
+ goto loser;
+ }
+
+ rv = tls13_AEAD(ctxt, PR_TRUE /* Decrypt */, CKG_NO_GENERATE, 0,
+ keyMat.iv, NULL, ivLen, zero, sizeof(zero), aad, aadLen,
+ out, outLen, maxLen, cipher_def->tag_size, buf.buf, buf.len);
+ PK11_DestroyContext(ctxt, PR_TRUE);
sslBuffer_Clear(&aadInput);
if (rv != SECSuccess) {
goto loser;
diff --git a/security/nss/lib/ssl/tls13exthandle.c b/security/nss/lib/ssl/tls13exthandle.c
index 1f88016a1..5c3930ac2 100644
--- a/security/nss/lib/ssl/tls13exthandle.c
+++ b/security/nss/lib/ssl/tls13exthandle.c
@@ -14,6 +14,7 @@
#include "ssl3exthandle.h"
#include "tls13esni.h"
#include "tls13exthandle.h"
+#include "tls13psk.h"
#include "tls13subcerts.h"
SECStatus
@@ -408,69 +409,92 @@ tls13_ServerSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
* };
*
* } PreSharedKeyExtension;
-
- * Presently the only way to get a PSK is by resumption, so this is
- * really a ticket label and there will be at most one.
*/
SECStatus
tls13_ClientSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added)
{
- NewSessionTicket *session_ticket;
- PRTime age;
const static PRUint8 binder[TLS13_MAX_FINISHED_SIZE] = { 0 };
unsigned int binderLen;
+ unsigned int identityLen = 0;
+ const PRUint8 *identity = NULL;
+ PRTime age;
SECStatus rv;
- /* We only set statelessResume on the client in TLS 1.3 code. */
- if (!ss->statelessResume) {
+ /* Exit early if no PSKs or max version < 1.3. */
+ if (PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks) ||
+ ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) {
+ return SECSuccess;
+ }
+
+ /* ...or if PSK type is resumption, but we're not resuming. */
+ sslPsk *psk = (sslPsk *)PR_LIST_HEAD(&ss->ssl3.hs.psks);
+ if (psk->type == ssl_psk_resume && !ss->statelessResume) {
return SECSuccess;
}
/* Save where this extension starts so that if we have to add padding, it
- * can be inserted before this extension. */
+ * can be inserted before this extension. */
PORT_Assert(buf->len >= 4);
xtnData->lastXtnOffset = buf->len - 4;
+ PORT_Assert(psk->type == ssl_psk_resume || psk->type == ssl_psk_external);
+ binderLen = tls13_GetHashSizeForHash(psk->hash);
+ if (psk->type == ssl_psk_resume) {
+ /* Send a single ticket identity. */
+ NewSessionTicket *session_ticket = &ss->sec.ci.sid->u.ssl3.locked.sessionTicket;
+ identityLen = session_ticket->ticket.len;
+ identity = session_ticket->ticket.data;
+
+ /* Obfuscated age. */
+ age = ssl_Time(ss) - session_ticket->received_timestamp;
+ age /= PR_USEC_PER_MSEC;
+ age += session_ticket->ticket_age_add;
+ PRINT_BUF(50, (ss, "Sending Resumption PSK with identity", identity, identityLen));
+ } else if (psk->type == ssl_psk_external) {
+ identityLen = psk->label.len;
+ identity = psk->label.data;
+ age = 0;
+ PRINT_BUF(50, (ss, "Sending External PSK with label", identity, identityLen));
+ } else {
+ PORT_Assert(0);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
- PORT_Assert(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3);
- PORT_Assert(ss->sec.ci.sid->version >= SSL_LIBRARY_VERSION_TLS_1_3);
-
- /* Send a single ticket identity. */
- session_ticket = &ss->sec.ci.sid->u.ssl3.locked.sessionTicket;
- rv = sslBuffer_AppendNumber(buf, 2 + /* identity length */
- session_ticket->ticket.len + /* ticket */
- 4 /* obfuscated_ticket_age */,
- 2);
- if (rv != SECSuccess)
+ /* Length is len(identityLen) + identityLen + len(age) */
+ rv = sslBuffer_AppendNumber(buf, 2 + identityLen + 4, 2);
+ if (rv != SECSuccess) {
goto loser;
- rv = sslBuffer_AppendVariable(buf, session_ticket->ticket.data,
- session_ticket->ticket.len, 2);
- if (rv != SECSuccess)
+ }
+
+ rv = sslBuffer_AppendVariable(buf, identity,
+ identityLen, 2);
+ if (rv != SECSuccess) {
goto loser;
+ }
- /* Obfuscated age. */
- age = ssl_Time(ss) - session_ticket->received_timestamp;
- age /= PR_USEC_PER_MSEC;
- age += session_ticket->ticket_age_add;
rv = sslBuffer_AppendNumber(buf, age, 4);
- if (rv != SECSuccess)
+ if (rv != SECSuccess) {
goto loser;
+ }
/* Write out the binder list length. */
- binderLen = tls13_GetHashSize(ss);
rv = sslBuffer_AppendNumber(buf, binderLen + 1, 2);
- if (rv != SECSuccess)
+ if (rv != SECSuccess) {
goto loser;
- /* Write zeroes for the binder for the moment. */
+ }
+
+ /* Write zeroes for the binder for the moment. These
+ * are overwritten in tls13_WriteExtensionsWithBinder. */
rv = sslBuffer_AppendVariable(buf, binder, binderLen, 1);
- if (rv != SECSuccess)
+ if (rv != SECSuccess) {
goto loser;
+ }
- PRINT_BUF(50, (ss, "Sending PreSharedKey value",
- session_ticket->ticket.data,
- session_ticket->ticket.len));
+ if (psk->type == ssl_psk_resume) {
+ xtnData->sentSessionTicketInClientHello = PR_TRUE;
+ }
- xtnData->sentSessionTicketInClientHello = PR_TRUE;
*added = PR_TRUE;
return SECSuccess;
@@ -479,8 +503,7 @@ loser:
return SECFailure;
}
-/* Handle a TLS 1.3 PreSharedKey Extension. We only accept PSKs
- * that contain session tickets. */
+/* Handle a TLS 1.3 PreSharedKey Extension. */
SECStatus
tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
SECItem *data)
@@ -534,28 +557,52 @@ tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData
return rv;
if (!numIdentities) {
- PRINT_BUF(50, (ss, "Handling PreSharedKey value",
- label.data, label.len));
- rv = ssl3_ProcessSessionTicketCommon(
- CONST_CAST(sslSocket, ss), &label, appToken);
- /* This only happens if we have an internal error, not
- * a malformed ticket. Bogus tickets just don't resume
- * and return SECSuccess. */
- if (rv != SECSuccess)
- return SECFailure;
+ /* Check any configured external PSK for a matching label.
+ * If none exists, try to parse it as a ticket. */
+ PORT_Assert(!xtnData->selectedPsk);
+ for (PRCList *cur_p = PR_LIST_HEAD(&ss->ssl3.hs.psks);
+ cur_p != &ss->ssl3.hs.psks;
+ cur_p = PR_NEXT_LINK(cur_p)) {
+ sslPsk *psk = (sslPsk *)cur_p;
+ if (psk->type != ssl_psk_external ||
+ SECITEM_CompareItem(&psk->label, &label) != SECEqual) {
+ continue;
+ }
+ PRINT_BUF(50, (ss, "Using External PSK with label",
+ psk->label.data, psk->label.len));
+ xtnData->selectedPsk = psk;
+ }
- if (ss->sec.ci.sid) {
- /* xtnData->ticketAge contains the baseline we use for
- * calculating the ticket age (i.e., our RTT estimate less the
- * value of ticket_age_add).
- *
- * Add that to the obfuscated ticket age to recover the client's
- * view of the ticket age plus the estimated RTT.
- *
- * See ssl3_EncodeSessionTicket() for details. */
- xtnData->ticketAge += obfuscatedAge;
+ if (!xtnData->selectedPsk) {
+ PRINT_BUF(50, (ss, "Handling PreSharedKey value",
+ label.data, label.len));
+ rv = ssl3_ProcessSessionTicketCommon(
+ CONST_CAST(sslSocket, ss), &label, appToken);
+ /* This only happens if we have an internal error, not
+ * a malformed ticket. Bogus tickets just don't resume
+ * and return SECSuccess. */
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ if (ss->sec.ci.sid) {
+ /* xtnData->ticketAge contains the baseline we use for
+ * calculating the ticket age (i.e., our RTT estimate less the
+ * value of ticket_age_add).
+ *
+ * Add that to the obfuscated ticket age to recover the client's
+ * view of the ticket age plus the estimated RTT.
+ *
+ * See ssl3_EncodeSessionTicket() for details. */
+ xtnData->ticketAge += obfuscatedAge;
+
+ /* We are not committed to resumption until after unwrapping the
+ * RMS in tls13_HandleClientHelloPart2. The RPSK will be stored
+ * in ss->xtnData.selectedPsk at that point, so continue. */
+ }
}
}
+
++numIdentities;
}
@@ -589,10 +636,14 @@ tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData
if (numBinders != numIdentities)
goto alert_loser;
- /* Keep track of negotiated extensions. Note that this does not
- * mean we are resuming. */
- xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_pre_shared_key_xtn;
+ if (ss->statelessResume) {
+ PORT_Assert(!ss->xtnData.selectedPsk);
+ } else if (!xtnData->selectedPsk) {
+ /* No matching EPSK. */
+ return SECSuccess;
+ }
+ xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_pre_shared_key_xtn;
return SECSuccess;
alert_loser:
@@ -618,8 +669,7 @@ tls13_ServerSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
return SECSuccess;
}
-/* Handle a TLS 1.3 PreSharedKey Extension. We only accept PSKs
- * that contain session tickets. */
+/* Handle a TLS 1.3 PreSharedKey Extension. */
SECStatus
tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
SECItem *data)
@@ -648,12 +698,23 @@ tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData
/* We only sent one PSK label so index must be equal to 0 */
if (index) {
+ ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
PORT_SetError(SSL_ERROR_MALFORMED_PRE_SHARED_KEY);
return SECFailure;
}
+ PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.psks));
+ sslPsk *candidate = (sslPsk *)PR_LIST_HEAD(&ss->ssl3.hs.psks);
+
+ /* Check that the server-selected ciphersuite hash and PSK hash match. */
+ if (candidate->hash != tls13_GetHashForCipherSuite(ss->ssl3.hs.cipher_suite)) {
+ ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
+ return SECFailure;
+ }
+
/* Keep track of negotiated extensions. */
xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_pre_shared_key_xtn;
+ xtnData->selectedPsk = candidate;
return SECSuccess;
}
@@ -789,12 +850,27 @@ tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnD
}
for (version = ss->vrange.max; version >= ss->vrange.min; --version) {
- PRUint16 wire = tls13_EncodeDraftVersion(version,
- ss->protocolVariant);
+ PRUint16 wire = tls13_EncodeVersion(version,
+ ss->protocolVariant);
rv = sslBuffer_AppendNumber(buf, wire, 2);
if (rv != SECSuccess) {
return SECFailure;
}
+
+ if (ss->opt.enableDtls13VersionCompat &&
+ ss->protocolVariant == ssl_variant_datagram) {
+ switch (version) {
+ case SSL_LIBRARY_VERSION_TLS_1_2:
+ case SSL_LIBRARY_VERSION_TLS_1_1:
+ rv = sslBuffer_AppendNumber(buf, (PRUint16)version, 2);
+ break;
+ default:
+ continue;
+ }
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ }
}
rv = sslBuffer_InsertLength(buf, lengthOffset, 1);
@@ -819,8 +895,8 @@ tls13_ServerSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnD
SSL_TRC(3, ("%d: TLS13[%d]: server send supported_versions extension",
SSL_GETPID(), ss->fd));
- PRUint16 ver = tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3,
- ss->protocolVariant);
+ PRUint16 ver = tls13_EncodeVersion(SSL_LIBRARY_VERSION_TLS_1_3,
+ ss->protocolVariant);
rv = sslBuffer_AppendNumber(buf, ver, 2);
if (rv != SECSuccess) {
return SECFailure;
@@ -921,10 +997,13 @@ tls13_ClientSendPostHandshakeAuthXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added)
{
- SSL_TRC(3, ("%d: TLS13[%d]: send post_handshake_auth extension",
- SSL_GETPID(), ss->fd));
-
- *added = ss->opt.enablePostHandshakeAuth;
+ /* Only one post-handshake message is supported: a single
+ * NST immediately following the client Finished. */
+ if (!IS_DTLS(ss)) {
+ SSL_TRC(3, ("%d: TLS13[%d]: send post_handshake_auth extension",
+ SSL_GETPID(), ss->fd));
+ *added = ss->opt.enablePostHandshakeAuth;
+ }
return SECSuccess;
}
@@ -941,8 +1020,12 @@ tls13_ServerHandlePostHandshakeAuthXtn(const sslSocket *ss,
return SECFailure;
}
- /* Keep track of negotiated extensions. */
- xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_post_handshake_auth_xtn;
+ /* Only one post-handshake message is supported: a single
+ * NST immediately following the client Finished. */
+ if (!IS_DTLS(ss)) {
+ /* Keep track of negotiated extensions. */
+ xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_post_handshake_auth_xtn;
+ }
return SECSuccess;
}
@@ -1139,7 +1222,6 @@ tls13_ClientSendEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData,
sslBuffer sni = SSL_BUFFER(sniBuf);
const ssl3CipherSuiteDef *suiteDef;
ssl3KeyMaterial keyMat;
- SSLAEADCipher aead;
PRUint8 outBuf[1024];
unsigned int outLen;
unsigned int sniStart;
@@ -1190,10 +1272,6 @@ tls13_ClientSendEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData,
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
- aead = tls13_GetAead(ssl_GetBulkCipherDef(suiteDef));
- if (!aead) {
- return SECFailure;
- }
/* Format the first part of the extension so we have the
* encoded KeyShareEntry. */
@@ -1251,15 +1329,33 @@ tls13_ClientSendEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData,
ssl_DestroyKeyMaterial(&keyMat);
return SECFailure;
}
+
/* Now encrypt. */
- rv = aead(&keyMat, PR_FALSE /* Encrypt */,
- outBuf, &outLen, sizeof(outBuf),
- SSL_BUFFER_BASE(&sni),
- SSL_BUFFER_LEN(&sni),
- SSL_BUFFER_BASE(&aadInput),
- SSL_BUFFER_LEN(&aadInput));
+ unsigned char *aad = SSL_BUFFER_BASE(&aadInput);
+ int aadLen = SSL_BUFFER_LEN(&aadInput);
+ const ssl3BulkCipherDef *cipher_def = ssl_GetBulkCipherDef(suiteDef);
+ int ivLen = cipher_def->iv_size + cipher_def->explicit_nonce_size;
+ unsigned char zero[sizeof(sslSequenceNumber)] = { 0 };
+ SSLCipherAlgorithm calg = cipher_def->calg;
+ SECItem null_params = { siBuffer, NULL, 0 };
+ PK11Context *ctxt = PK11_CreateContextBySymKey(ssl3_Alg2Mech(calg),
+ CKA_NSS_MESSAGE | CKA_ENCRYPT,
+ keyMat.key, &null_params);
+ if (!ctxt) {
+ ssl_DestroyKeyMaterial(&keyMat);
+ sslBuffer_Clear(&aadInput);
+ return SECFailure;
+ }
+
+ /* This function is a single shot, with fresh/unique keys, no need to
+ * generate the IV internally */
+ rv = tls13_AEAD(ctxt, PR_FALSE /* Encrypt */, CKG_NO_GENERATE, 0,
+ keyMat.iv, NULL, ivLen, zero, sizeof(zero), aad, aadLen,
+ outBuf, &outLen, sizeof(outBuf), cipher_def->tag_size,
+ SSL_BUFFER_BASE(&sni), SSL_BUFFER_LEN(&sni));
ssl_DestroyKeyMaterial(&keyMat);
sslBuffer_Clear(&aadInput);
+ PK11_DestroyContext(ctxt, PR_TRUE);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -1403,21 +1499,59 @@ tls13_ClientCheckEsniXtn(sslSocket *ss)
}
/* Indicates support for the delegated credentials extension. This should be
- * hooked while processing the ClientHello.
- */
+ * hooked while processing the ClientHello. */
SECStatus
tls13_ClientSendDelegatedCredentialsXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added)
{
/* Only send the extension if support is enabled and the client can
- * negotiate TLS 1.3.
- */
+ * negotiate TLS 1.3. */
if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3 ||
!ss->opt.enableDelegatedCredentials) {
return SECSuccess;
}
+ /* Filter the schemes that are enabled and acceptable. Save these in
+ * the "advertised" list, then encode them to be sent. If we receive
+ * a DC in response, validate that it matches one of the advertised
+ * schemes. */
+ SSLSignatureScheme filtered[MAX_SIGNATURE_SCHEMES] = { 0 };
+ unsigned int filteredCount = 0;
+ SECStatus rv = ssl3_FilterSigAlgs(ss, ss->vrange.max,
+ PR_TRUE /* disableRsae */,
+ PR_FALSE /* forCert */,
+ MAX_SIGNATURE_SCHEMES,
+ filtered,
+ &filteredCount);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ /* If no schemes available for the DC extension, don't send it. */
+ if (!filteredCount) {
+ return SECSuccess;
+ }
+
+ rv = ssl3_EncodeFilteredSigAlgs(ss, filtered, filteredCount, buf);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ SSLSignatureScheme *dcSchemesAdvertised = PORT_ZNewArray(SSLSignatureScheme,
+ filteredCount);
+ if (!dcSchemesAdvertised) {
+ return SECFailure;
+ }
+ for (unsigned int i = 0; i < filteredCount; i++) {
+ dcSchemesAdvertised[i] = filtered[i];
+ }
+
+ if (xtnData->delegCredSigSchemesAdvertised) {
+ PORT_Free(xtnData->delegCredSigSchemesAdvertised);
+ }
+ xtnData->delegCredSigSchemesAdvertised = dcSchemesAdvertised;
+ xtnData->numDelegCredSigSchemesAdvertised = filteredCount;
*added = PR_TRUE;
return SECSuccess;
}
@@ -1441,15 +1575,59 @@ tls13_ClientHandleDelegatedCredentialsXtn(const sslSocket *ss,
return SECFailure;
}
- SECStatus rv = tls13_ReadDelegatedCredential(data->data, data->len,
- &xtnData->peerDelegCred);
+ sslDelegatedCredential *dc = NULL;
+ SECStatus rv = tls13_ReadDelegatedCredential(data->data, data->len, &dc);
if (rv != SECSuccess) {
- return SECFailure; /* code already set */
+ goto loser; /* code already set */
+ }
+
+ /* When using RSA, the public key MUST NOT use the rsaEncryption OID. */
+ if (dc->expectedCertVerifyAlg == ssl_sig_rsa_pss_rsae_sha256 ||
+ dc->expectedCertVerifyAlg == ssl_sig_rsa_pss_rsae_sha384 ||
+ dc->expectedCertVerifyAlg == ssl_sig_rsa_pss_rsae_sha512) {
+ goto alert_loser;
+ }
+
+ /* The algorithm and expected_cert_verify_algorithm fields MUST be of a
+ * type advertised by the client in the SignatureSchemeList and are
+ * considered invalid otherwise. Clients that receive invalid delegated
+ * credentials MUST terminate the connection with an "illegal_parameter"
+ * alert. */
+ PRBool found = PR_FALSE;
+ for (unsigned int i = 0; i < ss->xtnData.numDelegCredSigSchemesAdvertised; ++i) {
+ if (dc->expectedCertVerifyAlg == ss->xtnData.delegCredSigSchemesAdvertised[i]) {
+ found = PR_TRUE;
+ break;
+ }
+ }
+ if (found == PR_FALSE) {
+ goto alert_loser;
+ }
+
+ // Check the dc->alg, if necessary.
+ if (dc->alg != dc->expectedCertVerifyAlg) {
+ found = PR_FALSE;
+ for (unsigned int i = 0; i < ss->xtnData.numDelegCredSigSchemesAdvertised; ++i) {
+ if (dc->alg == ss->xtnData.delegCredSigSchemesAdvertised[i]) {
+ found = PR_TRUE;
+ break;
+ }
+ }
+ if (found == PR_FALSE) {
+ goto alert_loser;
+ }
}
+ xtnData->peerDelegCred = dc;
xtnData->negotiated[xtnData->numNegotiated++] =
ssl_delegated_credentials_xtn;
return SECSuccess;
+alert_loser:
+ ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
+loser:
+ tls13_DestroyDelegatedCredential(dc);
+ return SECFailure;
}
/* Adds the DC extension if we're committed to authenticating with a DC. */
@@ -1460,19 +1638,13 @@ tls13_ServerSendDelegatedCredentialsXtn(const sslSocket *ss,
{
if (tls13_IsSigningWithDelegatedCredential(ss)) {
const SECItem *dc = &ss->sec.serverCert->delegCred;
-
- if (tls13_IsSigningWithDelegatedCredential(ss)) {
- SECStatus rv;
- rv = sslBuffer_Append(buf, dc->data, dc->len);
- if (rv != SECSuccess) {
- return SECFailure;
- }
+ SECStatus rv;
+ rv = sslBuffer_Append(buf, dc->data, dc->len);
+ if (rv != SECSuccess) {
+ return SECFailure;
}
-
*added = PR_TRUE;
- return SECSuccess;
}
-
return SECSuccess;
}
@@ -1484,6 +1656,33 @@ tls13_ServerHandleDelegatedCredentialsXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data)
{
+ if (xtnData->delegCredSigSchemes) {
+ PORT_Free(xtnData->delegCredSigSchemes);
+ xtnData->delegCredSigSchemes = NULL;
+ xtnData->numDelegCredSigSchemes = 0;
+ }
+ SECStatus rv = ssl_ParseSignatureSchemes(ss, NULL,
+ &xtnData->delegCredSigSchemes,
+ &xtnData->numDelegCredSigSchemes,
+ &data->data, &data->len);
+ if (rv != SECSuccess) {
+ ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+ return SECFailure;
+ }
+ if (xtnData->numDelegCredSigSchemes == 0) {
+ ssl3_ExtSendAlert(ss, alert_fatal, handshake_failure);
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
+ return SECFailure;
+ }
+ /* Check for trailing data. */
+ if (data->len != 0) {
+ ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+ return SECFailure;
+ }
+
+ /* Keep track of negotiated extensions. */
xtnData->peerRequestedDelegCred = PR_TRUE;
xtnData->negotiated[xtnData->numNegotiated++] =
ssl_delegated_credentials_xtn;
diff --git a/security/nss/lib/ssl/tls13hkdf.c b/security/nss/lib/ssl/tls13hkdf.c
index ab546e06f..ed6cdd559 100644
--- a/security/nss/lib/ssl/tls13hkdf.c
+++ b/security/nss/lib/ssl/tls13hkdf.c
@@ -25,52 +25,74 @@ static const struct {
{ ssl_hash_md5, 0, 0 },
{ ssl_hash_sha1, 0, 0 },
{ ssl_hash_sha224, 0 },
- { ssl_hash_sha256, CKM_NSS_HKDF_SHA256, 32 },
- { ssl_hash_sha384, CKM_NSS_HKDF_SHA384, 48 },
- { ssl_hash_sha512, CKM_NSS_HKDF_SHA512, 64 }
+ { ssl_hash_sha256, CKM_SHA256, 32 },
+ { ssl_hash_sha384, CKM_SHA384, 48 },
+ { ssl_hash_sha512, CKM_SHA512, 64 }
};
SECStatus
-tls13_HkdfExtract(PK11SymKey *ikm1, PK11SymKey *ikm2in, SSLHashType baseHash,
+tls13_HkdfExtract(PK11SymKey *ikm1, PK11SymKey *ikm2, SSLHashType baseHash,
PK11SymKey **prkp)
{
- CK_NSS_HKDFParams params;
+ CK_HKDF_PARAMS params;
SECItem paramsi;
- SECStatus rv;
- SECItem *salt;
PK11SymKey *prk;
static const PRUint8 zeroKeyBuf[HASH_LENGTH_MAX];
- PK11SymKey *zeroKey = NULL;
+ SECItem zeroKeyItem = { siBuffer, CONST_CAST(PRUint8, zeroKeyBuf), kTlsHkdfInfo[baseHash].hashSize };
PK11SlotInfo *slot = NULL;
- PK11SymKey *ikm2;
+ PK11SymKey *newIkm2 = NULL;
+ PK11SymKey *newIkm1 = NULL;
+ SECStatus rv;
params.bExtract = CK_TRUE;
params.bExpand = CK_FALSE;
+ params.prfHashMechanism = kTlsHkdfInfo[baseHash].pkcs11Mech;
params.pInfo = NULL;
params.ulInfoLen = 0UL;
+ params.pSalt = NULL;
+ params.ulSaltLen = 0UL;
+ params.hSaltKey = CK_INVALID_HANDLE;
- if (ikm1) {
- /* TODO(ekr@rtfm.com): This violates the PKCS#11 key boundary
- * but is imposed on us by the present HKDF interface. */
- rv = PK11_ExtractKeyValue(ikm1);
- if (rv != SECSuccess)
- return rv;
-
- salt = PK11_GetKeyData(ikm1);
- if (!salt)
- return SECFailure;
-
- params.pSalt = salt->data;
- params.ulSaltLen = salt->len;
- PORT_Assert(salt->len > 0);
+ if (!ikm1) {
+ /* PKCS #11 v3.0 has and explict NULL value, which equates to
+ * a sequence of zeros equal in length to the HMAC. */
+ params.ulSaltType = CKF_HKDF_SALT_NULL;
} else {
- /* Per documentation for CKM_NSS_HKDF_*:
- *
- * If the optional salt is given, it is used; otherwise, the salt is
- * set to a sequence of zeros equal in length to the HMAC output.
- */
- params.pSalt = NULL;
- params.ulSaltLen = 0UL;
+ /* PKCS #11 v3.0 can take the salt as a key handle */
+ params.hSaltKey = PK11_GetSymKeyHandle(ikm1);
+ params.ulSaltType = CKF_HKDF_SALT_KEY;
+
+ /* if we have both keys, make sure they are in the same slot */
+ if (ikm2) {
+ rv = PK11_SymKeysToSameSlot(CKM_HKDF_DERIVE,
+ CKA_DERIVE, CKA_DERIVE,
+ ikm2, ikm1, &newIkm2, &newIkm1);
+ if (rv != SECSuccess) {
+ SECItem *salt;
+ /* couldn't move the keys, try extracting the salt */
+ rv = PK11_ExtractKeyValue(ikm1);
+ if (rv != SECSuccess)
+ return rv;
+ salt = PK11_GetKeyData(ikm1);
+ if (!salt)
+ return SECFailure;
+ PORT_Assert(salt->len > 0);
+ /* Set up for Salt as Data instead of Salt as key */
+ params.pSalt = salt->data;
+ params.ulSaltLen = salt->len;
+ params.ulSaltType = CKF_HKDF_SALT_DATA;
+ }
+ /* use the new keys */
+ if (newIkm1) {
+ /* we've moved the key, get the handle for the new key */
+ params.hSaltKey = PK11_GetSymKeyHandle(newIkm1);
+ /* we don't use ikm1 after this, so don't bother setting it */
+ }
+ if (newIkm2) {
+ /* new ikm2 key, use the new key */
+ ikm2 = newIkm2;
+ }
+ }
}
paramsi.data = (unsigned char *)&params;
paramsi.len = sizeof(params);
@@ -80,40 +102,34 @@ tls13_HkdfExtract(PK11SymKey *ikm1, PK11SymKey *ikm2in, SSLHashType baseHash,
PORT_Assert(kTlsHkdfInfo[baseHash].hash == baseHash);
/* A zero ikm2 is a key of hash-length 0s. */
- if (!ikm2in) {
- SECItem zeroItem = {
- siBuffer,
- (unsigned char *)zeroKeyBuf,
- kTlsHkdfInfo[baseHash].hashSize
- };
- slot = PK11_GetInternalSlot();
+ if (!ikm2) {
+ /* if we have ikm1, put the zero key in the same slot */
+ slot = ikm1 ? PK11_GetSlotFromKey(ikm1) : PK11_GetBestSlot(CKM_HKDF_DERIVE, NULL);
if (!slot) {
return SECFailure;
}
- zeroKey = PK11_ImportSymKey(slot,
- kTlsHkdfInfo[baseHash].pkcs11Mech,
- PK11_OriginUnwrap,
- CKA_DERIVE, &zeroItem, NULL);
- if (!zeroKey)
+
+ newIkm2 = PK11_ImportDataKey(slot, CKM_HKDF_DERIVE, PK11_OriginUnwrap,
+ CKA_DERIVE, &zeroKeyItem, NULL);
+ if (!newIkm2) {
return SECFailure;
- ikm2 = zeroKey;
- } else {
- ikm2 = ikm2in;
+ }
+ ikm2 = newIkm2;
}
PORT_Assert(ikm2);
PRINT_BUF(50, (NULL, "HKDF Extract: IKM1/Salt", params.pSalt, params.ulSaltLen));
PRINT_KEY(50, (NULL, "HKDF Extract: IKM2", ikm2));
- prk = PK11_Derive(ikm2, kTlsHkdfInfo[baseHash].pkcs11Mech,
- &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 +138,14 @@ tls13_HkdfExtract(PK11SymKey *ikm1, PK11SymKey *ikm2in, SSLHashType baseHash,
}
SECStatus
-tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash,
- const PRUint8 *handshakeHash, unsigned int handshakeHashLen,
- const char *label, unsigned int labelLen,
- CK_MECHANISM_TYPE algorithm, unsigned int keySize,
- PK11SymKey **keyp)
+tls13_HkdfExpandLabelGeneral(CK_MECHANISM_TYPE deriveMech, PK11SymKey *prk,
+ SSLHashType baseHash,
+ const PRUint8 *handshakeHash, unsigned int handshakeHashLen,
+ const char *label, unsigned int labelLen,
+ CK_MECHANISM_TYPE algorithm, unsigned int keySize,
+ SSLProtocolVariant variant, PK11SymKey **keyp)
{
- CK_NSS_HKDFParams params;
+ CK_HKDF_PARAMS params;
SECItem paramsi = { siBuffer, NULL, 0 };
/* Size of info array needs to be big enough to hold the maximum Prefix,
* Label, plus HandshakeHash. If it's ever to small, the code will abort.
@@ -137,8 +154,12 @@ tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash,
sslBuffer infoBuf = SSL_BUFFER(info);
PK11SymKey *derived;
SECStatus rv;
- const char *kLabelPrefix = "tls13 ";
- const unsigned int kLabelPrefixLen = strlen(kLabelPrefix);
+ const char *kLabelPrefixTls = "tls13 ";
+ const char *kLabelPrefixDtls = "dtls13";
+ const unsigned int kLabelPrefixLen =
+ (variant == ssl_variant_stream) ? strlen(kLabelPrefixTls) : strlen(kLabelPrefixDtls);
+ const char *kLabelPrefix =
+ (variant == ssl_variant_stream) ? kLabelPrefixTls : kLabelPrefixDtls;
PORT_Assert(prk);
PORT_Assert(keyp);
@@ -192,17 +213,18 @@ tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash,
params.bExtract = CK_FALSE;
params.bExpand = CK_TRUE;
+ params.prfHashMechanism = kTlsHkdfInfo[baseHash].pkcs11Mech;
params.pInfo = SSL_BUFFER_BASE(&infoBuf);
params.ulInfoLen = SSL_BUFFER_LEN(&infoBuf);
paramsi.data = (unsigned char *)&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 +248,34 @@ tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash,
}
SECStatus
+tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash,
+ const PRUint8 *handshakeHash, unsigned int handshakeHashLen,
+ const char *label, unsigned int labelLen,
+ CK_MECHANISM_TYPE algorithm, unsigned int keySize,
+ SSLProtocolVariant variant, PK11SymKey **keyp)
+{
+ return tls13_HkdfExpandLabelGeneral(CKM_HKDF_DERIVE, prk, baseHash,
+ handshakeHash, handshakeHashLen,
+ label, labelLen, algorithm, keySize,
+ variant, keyp);
+}
+
+SECStatus
tls13_HkdfExpandLabelRaw(PK11SymKey *prk, SSLHashType baseHash,
const PRUint8 *handshakeHash, unsigned int handshakeHashLen,
const char *label, unsigned int labelLen,
- unsigned char *output, unsigned int outputLen)
+ SSLProtocolVariant variant, unsigned char *output,
+ unsigned int outputLen)
{
PK11SymKey *derived = NULL;
SECItem *rawkey;
SECStatus rv;
- rv = tls13_HkdfExpandLabel(prk, baseHash, handshakeHash, handshakeHashLen,
- label, labelLen,
- kTlsHkdfInfo[baseHash].pkcs11Mech, outputLen,
- &derived);
+ /* the result is not really a key, it's a data object */
+ rv = tls13_HkdfExpandLabelGeneral(CKM_HKDF_DATA, prk, baseHash,
+ handshakeHash, handshakeHashLen,
+ label, labelLen, CKM_HKDF_DERIVE, outputLen,
+ variant, &derived);
if (rv != SECSuccess || !derived) {
goto abort;
}
diff --git a/security/nss/lib/ssl/tls13hkdf.h b/security/nss/lib/ssl/tls13hkdf.h
index 78347a11d..00e5ff1dd 100644
--- a/security/nss/lib/ssl/tls13hkdf.h
+++ b/security/nss/lib/ssl/tls13hkdf.h
@@ -23,13 +23,14 @@ SECStatus tls13_HkdfExpandLabelRaw(
PK11SymKey *prk, SSLHashType baseHash,
const PRUint8 *handshakeHash, unsigned int handshakeHashLen,
const char *label, unsigned int labelLen,
- unsigned char *output, unsigned int outputLen);
+ SSLProtocolVariant variant, unsigned char *output,
+ unsigned int outputLen);
SECStatus tls13_HkdfExpandLabel(
PK11SymKey *prk, SSLHashType baseHash,
const PRUint8 *handshakeHash, unsigned int handshakeHashLen,
const char *label, unsigned int labelLen,
CK_MECHANISM_TYPE algorithm, unsigned int keySize,
- PK11SymKey **keyp);
+ SSLProtocolVariant variant, PK11SymKey **keyp);
#ifdef __cplusplus
}
diff --git a/security/nss/lib/ssl/tls13psk.c b/security/nss/lib/ssl/tls13psk.c
new file mode 100644
index 000000000..7343c5a6f
--- /dev/null
+++ b/security/nss/lib/ssl/tls13psk.c
@@ -0,0 +1,219 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nss.h"
+#include "pk11func.h"
+#include "ssl.h"
+#include "sslproto.h"
+#include "sslimpl.h"
+#include "ssl3exthandle.h"
+#include "tls13exthandle.h"
+#include "tls13hkdf.h"
+#include "tls13psk.h"
+
+SECStatus
+SSLExp_AddExternalPsk0Rtt(PRFileDesc *fd, PK11SymKey *key, const PRUint8 *identity,
+ unsigned int identityLen, SSLHashType hash,
+ PRUint16 zeroRttSuite, PRUint32 maxEarlyData)
+{
+
+ sslSocket *ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSLExp_SetExternalPsk",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ if (!key || !identity || !identityLen || identityLen > 0xFFFF ||
+ (hash != ssl_hash_sha256 && hash != ssl_hash_sha384)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ SECItem label = { siBuffer, CONST_CAST(unsigned char, identity), identityLen };
+ sslPsk *psk = tls13_MakePsk(PK11_ReferenceSymKey(key), ssl_psk_external,
+ hash, &label);
+ if (!psk) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return SECFailure;
+ }
+ psk->zeroRttSuite = zeroRttSuite;
+ psk->maxEarlyData = maxEarlyData;
+ SECStatus rv = SECFailure;
+
+ ssl_Get1stHandshakeLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+
+ if (ss->psk) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ tls13_DestroyPsk(psk);
+ } else {
+ ss->psk = psk;
+ rv = SECSuccess;
+ tls13_ResetHandshakePsks(ss, &ss->ssl3.hs.psks);
+ }
+
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+
+ return rv;
+}
+
+SECStatus
+SSLExp_AddExternalPsk(PRFileDesc *fd, PK11SymKey *key, const PRUint8 *identity,
+ unsigned int identityLen, SSLHashType hash)
+{
+ return SSLExp_AddExternalPsk0Rtt(fd, key, identity, identityLen,
+ hash, TLS_NULL_WITH_NULL_NULL, 0);
+}
+
+SECStatus
+SSLExp_RemoveExternalPsk(PRFileDesc *fd, const PRUint8 *identity, unsigned int identityLen)
+{
+ if (!identity || !identityLen) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ sslSocket *ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetPSK",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ SECItem removeIdentity = { siBuffer,
+ (unsigned char *)identity,
+ identityLen };
+
+ SECStatus rv;
+ ssl_Get1stHandshakeLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+
+ if (!ss->psk || SECITEM_CompareItem(&ss->psk->label, &removeIdentity) != SECEqual) {
+ PORT_SetError(SEC_ERROR_NO_KEY);
+ rv = SECFailure;
+ } else {
+ tls13_DestroyPsk(ss->psk);
+ ss->psk = NULL;
+ tls13_ResetHandshakePsks(ss, &ss->ssl3.hs.psks);
+ rv = SECSuccess;
+ }
+
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+
+ return rv;
+}
+
+sslPsk *
+tls13_CopyPsk(sslPsk *opsk)
+{
+ if (!opsk || !opsk->key) {
+ return NULL;
+ }
+
+ sslPsk *psk = PORT_ZNew(sslPsk);
+ if (!psk) {
+ return NULL;
+ }
+
+ SECStatus rv = SECITEM_CopyItem(NULL, &psk->label, &opsk->label);
+ if (rv != SECSuccess) {
+ PORT_Free(psk);
+ return NULL;
+ }
+ /* We should only have the initial key. Binder keys
+ * are derived during the handshake. */
+ PORT_Assert(opsk->type == ssl_psk_external);
+ PORT_Assert(opsk->key);
+ PORT_Assert(!opsk->binderKey);
+ psk->hash = opsk->hash;
+ psk->type = opsk->type;
+ psk->key = opsk->key ? PK11_ReferenceSymKey(opsk->key) : NULL;
+ psk->binderKey = opsk->binderKey ? PK11_ReferenceSymKey(opsk->binderKey) : NULL;
+ return psk;
+}
+
+void
+tls13_DestroyPsk(sslPsk *psk)
+{
+ if (!psk) {
+ return;
+ }
+ if (psk->key) {
+ PK11_FreeSymKey(psk->key);
+ psk->key = NULL;
+ }
+ if (psk->binderKey) {
+ PK11_FreeSymKey(psk->binderKey);
+ psk->binderKey = NULL;
+ }
+ SECITEM_ZfreeItem(&psk->label, PR_FALSE);
+ PORT_ZFree(psk, sizeof(*psk));
+}
+
+void
+tls13_DestroyPskList(PRCList *list)
+{
+ PRCList *cur_p;
+ while (!PR_CLIST_IS_EMPTY(list)) {
+ cur_p = PR_LIST_TAIL(list);
+ PR_REMOVE_LINK(cur_p);
+ tls13_DestroyPsk((sslPsk *)cur_p);
+ }
+}
+
+sslPsk *
+tls13_MakePsk(PK11SymKey *key, SSLPskType pskType, SSLHashType hashType, const SECItem *label)
+{
+ sslPsk *psk = PORT_ZNew(sslPsk);
+ if (!psk) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return NULL;
+ }
+ psk->type = pskType;
+ psk->hash = hashType;
+ psk->key = key;
+
+ /* Label is NULL in the resumption case. */
+ if (label) {
+ PORT_Assert(psk->type != ssl_psk_resume);
+ SECStatus rv = SECITEM_CopyItem(NULL, &psk->label, label);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ tls13_DestroyPsk(psk);
+ return NULL;
+ }
+ }
+
+ return psk;
+}
+
+/* Destroy any existing PSKs in |list| then copy
+ * in the configured |ss->psk|, if any.*/
+SECStatus
+tls13_ResetHandshakePsks(sslSocket *ss, PRCList *list)
+{
+ tls13_DestroyPskList(list);
+ PORT_Assert(!ss->xtnData.selectedPsk);
+ ss->xtnData.selectedPsk = NULL;
+ if (ss->psk) {
+ PORT_Assert(ss->psk->type == ssl_psk_external);
+ PORT_Assert(ss->psk->key);
+ PORT_Assert(!ss->psk->binderKey);
+
+ sslPsk *epsk = tls13_MakePsk(PK11_ReferenceSymKey(ss->psk->key),
+ ss->psk->type, ss->psk->hash, &ss->psk->label);
+ if (!epsk) {
+ return SECFailure;
+ }
+ epsk->zeroRttSuite = ss->psk->zeroRttSuite;
+ epsk->maxEarlyData = ss->psk->maxEarlyData;
+ PR_APPEND_LINK(&epsk->link, list);
+ }
+ return SECSuccess;
+}
diff --git a/security/nss/lib/ssl/tls13psk.h b/security/nss/lib/ssl/tls13psk.h
new file mode 100644
index 000000000..73013fb9b
--- /dev/null
+++ b/security/nss/lib/ssl/tls13psk.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is PRIVATE to SSL.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef __tls13psk_h_
+#define __tls13psk_h_
+
+/*
+ * Internally, we have track sslPsk pointers in three locations:
+ * 1) An external PSK can be configured to the socket, in which case ss->psk will hold an owned reference.
+ * For now, this only holds one external PSK. The value will persist across handshake restarts.
+ * 2) When a handshake begins, the ss->psk value is deep-copied into ss->ssl3.hs.psks, which may also hold
+ * a resumption PSK. This is essentially a priority-sorted list (where a resumption PSK has higher
+ * priority than external), and we currently only send one PskIdentity and binder.
+ * 3) During negotiation, ss->xtnData.selectedPsk will either be NULL or it will hold a non-owning refernce
+ * to the PSK that has been (or is being) negotiated.
+ */
+
+/* Note: When holding a resumption PSK:
+ * 1. |hash| comes from the original connection.
+ * 2. |label| is ignored: The identity sent in the pre_shared_key_xtn
+ * comes from ss->sec.ci.sid->u.ssl3.locked.sessionTicket.
+ */
+struct sslPskStr {
+ PRCList link;
+ PK11SymKey *key; /* A raw PSK. */
+ PK11SymKey *binderKey; /* The binder key derived from |key|. |key| is NULL after derivation. */
+ SSLPskType type; /* none, resumption, or external. */
+ SECItem label; /* Label (identity) for an external PSK. */
+ SSLHashType hash; /* A hash algorithm associated with a PSK. */
+ ssl3CipherSuite zeroRttSuite; /* For EPSKs, an explicitly-configured ciphersuite for 0-Rtt. */
+ PRUint32 maxEarlyData; /* For EPSKs, a limit on early data. Must be > 0 for 0-Rtt. */
+};
+
+SECStatus SSLExp_AddExternalPsk(PRFileDesc *fd, PK11SymKey *psk, const PRUint8 *identity,
+ unsigned int identitylen, SSLHashType hash);
+
+SECStatus SSLExp_AddExternalPsk0Rtt(PRFileDesc *fd, PK11SymKey *psk, const PRUint8 *identity,
+ unsigned int identitylen, SSLHashType hash,
+ PRUint16 zeroRttSuite, PRUint32 maxEarlyData);
+
+SECStatus SSLExp_RemoveExternalPsk(PRFileDesc *fd, const PRUint8 *identity, unsigned int identitylen);
+
+sslPsk *tls13_CopyPsk(sslPsk *opsk);
+
+void tls13_DestroyPsk(sslPsk *psk);
+
+void tls13_DestroyPskList(PRCList *list);
+
+sslPsk *tls13_MakePsk(PK11SymKey *key, SSLPskType pskType, SSLHashType hashType, const SECItem *label);
+
+SECStatus tls13_ResetHandshakePsks(sslSocket *ss, PRCList *list);
+
+#endif
diff --git a/security/nss/lib/ssl/tls13replay.c b/security/nss/lib/ssl/tls13replay.c
index 628011144..7e00785e0 100644
--- a/security/nss/lib/ssl/tls13replay.c
+++ b/security/nss/lib/ssl/tls13replay.c
@@ -16,6 +16,7 @@
#include "sslbloom.h"
#include "sslimpl.h"
#include "tls13hkdf.h"
+#include "tls13psk.h"
struct SSLAntiReplayContextStr {
/* The number of outstanding references to this context. */
@@ -55,8 +56,7 @@ tls13_ReleaseAntiReplayContext(SSLAntiReplayContext *ctx)
PORT_Free(ctx);
}
-/* Clear the current state and free any resources we allocated. The signature
- * here is odd to allow this to be called during shutdown. */
+/* Clear the current state and free any resources we allocated. */
SECStatus
SSLExp_ReleaseAntiReplayContext(SSLAntiReplayContext *ctx)
{
@@ -75,26 +75,17 @@ tls13_RefAntiReplayContext(SSLAntiReplayContext *ctx)
static SECStatus
tls13_AntiReplayKeyGen(SSLAntiReplayContext *ctx)
{
- PRUint8 buf[32];
- SECItem keyItem = { siBuffer, buf, sizeof(buf) };
PK11SlotInfo *slot;
- SECStatus rv;
PORT_Assert(ctx);
- slot = PK11_GetInternalSlot();
+ slot = PK11_GetBestSlot(CKM_HKDF_DERIVE, NULL);
if (!slot) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
- rv = PK11_GenerateRandomOnSlot(slot, buf, sizeof(buf));
- if (rv != SECSuccess) {
- goto loser;
- }
- ctx->key = PK11_ImportSymKey(slot, CKM_NSS_HKDF_SHA256,
- PK11_OriginUnwrap, CKA_DERIVE,
- &keyItem, NULL);
+ ctx->key = PK11_KeyGen(slot, CKM_HKDF_KEY_GEN, NULL, 32, NULL);
if (!ctx->key) {
goto loser;
}
@@ -259,7 +250,9 @@ tls13_IsReplay(const sslSocket *ss, const sslSessionID *sid)
return PR_TRUE;
}
- if (!tls13_InWindow(ss, sid)) {
+ if (!sid) {
+ PORT_Assert(ss->xtnData.selectedPsk->type == ssl_psk_external);
+ } else if (!tls13_InWindow(ss, sid)) {
return PR_TRUE;
}
@@ -269,7 +262,7 @@ tls13_IsReplay(const sslSocket *ss, const sslSessionID *sid)
ss->xtnData.pskBinder.data,
ss->xtnData.pskBinder.len,
label, strlen(label),
- buf, size);
+ ss->protocolVariant, buf, size);
if (rv != SECSuccess) {
return PR_TRUE;
}
diff --git a/security/nss/lib/ssl/tls13subcerts.c b/security/nss/lib/ssl/tls13subcerts.c
index 8ae5447f7..6f164c302 100644
--- a/security/nss/lib/ssl/tls13subcerts.c
+++ b/security/nss/lib/ssl/tls13subcerts.c
@@ -7,6 +7,7 @@
#include "nss.h"
#include "pk11func.h"
#include "secder.h"
+#include "sechash.h"
#include "ssl.h"
#include "sslproto.h"
#include "sslimpl.h"
@@ -148,9 +149,7 @@ tls13_GetExpectedCertVerifyAlg(SECItem in, SSLSignatureScheme *certVerifyAlg)
PRBool
tls13_IsVerifyingWithDelegatedCredential(const sslSocket *ss)
{
- /* As of draft-ietf-subcerts-03, only the server may authenticate itself
- * with a DC.
- */
+ /* We currently do not support client-delegated credentials. */
if (ss->sec.isServer ||
!ss->opt.enableDelegatedCredentials ||
!ss->xtnData.peerDelegCred) {
@@ -191,20 +190,21 @@ tls13_MaybeSetDelegatedCredential(sslSocket *ss)
SECKEYPrivateKey *priv;
SSLSignatureScheme scheme;
- /* Assert that the host is the server (as of draft-ietf-subcerts-03, only
- * the server may authenticate itself with a DC), the certificate has been
+ /* Assert that the host is the server (we do not currently support
+ * client-delegated credentials), the certificate has been
* chosen, TLS 1.3 or higher has been negotiated, and that the set of
* signature schemes supported by the client is known.
*/
PORT_Assert(ss->sec.isServer);
PORT_Assert(ss->sec.serverCert);
PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
- PORT_Assert(ss->xtnData.sigSchemes);
+ PORT_Assert(ss->xtnData.peerRequestedDelegCred == !!ss->xtnData.delegCredSigSchemes);
/* Check that the peer has indicated support and that a DC has been
* configured for the selected certificate.
*/
if (!ss->xtnData.peerRequestedDelegCred ||
+ !ss->xtnData.delegCredSigSchemes ||
!ss->sec.serverCert->delegCred.len ||
!ss->sec.serverCert->delegCredKeyPair) {
return SECSuccess;
@@ -227,8 +227,8 @@ tls13_MaybeSetDelegatedCredential(sslSocket *ss)
if (!ssl_SignatureSchemeEnabled(ss, scheme) ||
!ssl_CanUseSignatureScheme(scheme,
- ss->xtnData.sigSchemes,
- ss->xtnData.numSigSchemes,
+ ss->xtnData.delegCredSigSchemes,
+ ss->xtnData.numDelegCredSigSchemes,
PR_FALSE /* requireSha1 */,
doesRsaPss)) {
return SECSuccess;
@@ -379,6 +379,12 @@ tls13_VerifyCredentialSignature(sslSocket *ss, sslDelegatedCredential *dc)
goto loser;
}
+ SECOidTag spkiAlg = SECOID_GetAlgorithmTag(&(dc->spki->algorithm));
+ if (spkiAlg == SEC_OID_PKCS1_RSA_ENCRYPTION) {
+ FATAL_ERROR(ss, SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, illegal_parameter);
+ goto loser;
+ }
+
SECKEY_DestroyPublicKey(pubKey);
sslBuffer_Clear(&dcBuf);
return SECSuccess;
@@ -434,8 +440,10 @@ static SECStatus
tls13_CheckCredentialExpiration(sslSocket *ss, sslDelegatedCredential *dc)
{
SECStatus rv;
- PRTime start, end /* microseconds */;
CERTCertificate *cert = ss->sec.peerCert;
+ /* 7 days in microseconds */
+ static const PRTime kMaxDcValidity = ((PRTime)7 * 24 * 60 * 60 * PR_USEC_PER_SEC);
+ PRTime start, now, end; /* microseconds */
rv = DER_DecodeTimeChoice(&start, &cert->validity.notBefore);
if (rv != SECSuccess) {
@@ -444,11 +452,18 @@ tls13_CheckCredentialExpiration(sslSocket *ss, sslDelegatedCredential *dc)
}
end = start + ((PRTime)dc->validTime * PR_USEC_PER_SEC);
- if (ssl_Time(ss) > end) {
+ now = ssl_Time(ss);
+ if (now > end || end < 0) {
FATAL_ERROR(ss, SSL_ERROR_DC_EXPIRED, illegal_parameter);
return SECFailure;
}
+ /* Not more than 7 days remaining in the validity period. */
+ if (end - now > kMaxDcValidity) {
+ FATAL_ERROR(ss, SSL_ERROR_DC_INAPPROPRIATE_VALIDITY_PERIOD, illegal_parameter);
+ return SECFailure;
+ }
+
return SECSuccess;
}
@@ -456,7 +471,8 @@ tls13_CheckCredentialExpiration(sslSocket *ss, sslDelegatedCredential *dc)
* returns SECFailure. A valid DC meets three requirements: (1) the signature
* was produced by the peer's end-entity certificate, (2) the end-entity
* certificate must have the correct key usage, and (3) the DC must not be
- * expired.
+ * expired and its remaining TTL must be <= the maximum validity period (fixed
+ * as 7 days).
*
* This function calls FATAL_ERROR() when an error occurs.
*/
@@ -538,6 +554,15 @@ tls13_MakePssSpki(const SECKEYPublicKey *pub, SECOidTag hashOid)
goto loser; /* Code already set. */
}
+ /* Always include saltLength: all hashes are larger than 20. */
+ unsigned int saltLength = HASH_ResultLenByOidTag(hashOid);
+ PORT_Assert(saltLength > 20);
+ if (!SEC_ASN1EncodeInteger(arena, &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);