Replace NSS with Pale Moon's

This commit is contained in:
wuggy 2026-06-29 21:29:25 +01:00
commit 8c2e376f94
2870 changed files with 1762232 additions and 1374220 deletions

View file

@ -61,5 +61,3 @@ include $(CORE_DEPTH)/coreconf/rules.mk
#######################################################################
# (7) Execute "local" rules. (OPTIONAL). #
#######################################################################
export:: private_export

View file

@ -582,3 +582,21 @@ 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.")
ER3(SSL_ERROR_FEATURE_DISABLED, (SSL_ERROR_BASE + 187),
"The requested feature is disabled.")
ER3(SSL_ERROR_ECH_RETRY_WITH_ECH, (SSL_ERROR_BASE + 188),
"TLS ECH was rejected, but verification succeeded and compatible retry_configs are available.")
ER3(SSL_ERROR_ECH_RETRY_WITHOUT_ECH, (SSL_ERROR_BASE + 189),
"TLS ECH was rejected, but verification succeeded and no compatible retry_configs were found.")
ER3(SSL_ERROR_ECH_FAILED, (SSL_ERROR_BASE + 190),
"TLS ECH was rejected and verification failed.")
ER3(SSL_ERROR_ECH_REQUIRED_ALERT, (SSL_ERROR_BASE + 191),
"SSL peer reported ECH required.")

View file

@ -82,7 +82,7 @@ ssl_CertIsUsable(sslSocket *ss, CERTCertificate *cert)
* if (!ss->ssl3.hs.hashType == handshake_hash_record &&
* ss->ssl3.hs.hashType == handshake_hash_single) {
* return PR_TRUE;
* 2) assume if ss->peerSignatureSchemesCount == 0 we are using the
* 2) assume if ss->ss->ssl3.hs.clientAuthSignatureSchemesLen == 0 we are using the
* old handshake.
* There is one case where using 2 will be wrong: we somehow call this
* function outside the case where of out GetClientAuthData context.
@ -90,15 +90,15 @@ ssl_CertIsUsable(sslSocket *ss, CERTCertificate *cert)
* best we can do is either always assume good or always assume bad.
* I think the best results is to always assume good, so we use
* option 2 here to handle that case as well.*/
if (ss->peerSignatureSchemeCount == 0) {
if (ss->ssl3.hs.clientAuthSignatureSchemesLen == 0) {
return PR_TRUE;
}
if (ss->peerSignatureSchemes == NULL) {
if (ss->ssl3.hs.clientAuthSignatureSchemes == NULL) {
return PR_FALSE; /* should this really be an assert? */
}
rv = ssl_PickClientSignatureScheme(ss, cert, NULL,
ss->peerSignatureSchemes,
ss->peerSignatureSchemeCount,
ss->ssl3.hs.clientAuthSignatureSchemes,
ss->ssl3.hs.clientAuthSignatureSchemesLen,
&scheme);
if (rv != SECSuccess) {
return PR_FALSE;
@ -206,6 +206,9 @@ NSS_GetClientAuthData(void *arg,
certUsageSSLClient,
PR_FALSE, chosenNickName == NULL,
pw_arg);
if (certList == NULL) {
return SECFailure;
}
/* filter only the certs that meet the nickname requirements */
if (chosenNickName) {
rv = CERT_FilterCertListByNickname(certList, chosenNickName,
@ -219,13 +222,10 @@ NSS_GetClientAuthData(void *arg,
}
if ((rv != SECSuccess) || CERT_LIST_EMPTY(certList)) {
CERT_DestroyCertList(certList);
certList = NULL;
return SECFailure;
}
}
if (certList == NULL) {
/* no user certs meeting the nickname/usage requirements found */
return SECFailure;
}
/* now remove any certs that can't meet the connection requirements */
rv = ssl_FilterClientCertListBySSLSocket(ss, certList);
if ((rv != SECSuccess) || CERT_LIST_EMPTY(certList)) {

View file

@ -9,13 +9,6 @@ endif
ifeq (,$(filter-out WIN%,$(OS_TARGET)))
# don't want the 32 in the shared library name
SHARED_LIBRARY = $(OBJDIR)/$(DLL_PREFIX)$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX)
IMPORT_LIBRARY = $(OBJDIR)/$(IMPORT_LIB_PREFIX)$(LIBRARY_NAME)$(LIBRARY_VERSION)$(IMPORT_LIB_SUFFIX)
RES = $(OBJDIR)/ssl.res
RESNAME = ssl.rc
ifdef NS_USE_GCC
EXTRA_SHARED_LIBS += \
-L$(DIST)/lib \
@ -51,10 +44,6 @@ EXTRA_SHARED_LIBS += \
-lnspr4 \
$(NULL)
ifeq ($(OS_ARCH), BeOS)
EXTRA_SHARED_LIBS += -lbe
endif
endif
ifdef NSS_DISABLE_TLS_1_3

View file

@ -36,7 +36,7 @@ static const unsigned char ff_dhe_2048_p[] = {
0xC5, 0x8E, 0xF1, 0x83, 0x7D, 0x16, 0x83, 0xB2,
0xC6, 0xF3, 0x4A, 0x26, 0xC1, 0xB2, 0xEF, 0xFA,
0x88, 0x6B, 0x42, 0x38, 0x61, 0x28, 0x5C, 0x97,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
static const ssl3DHParams ff_dhe_2048_params = {
@ -93,7 +93,7 @@ static const unsigned char ff_dhe_3072_p[] = {
0x0A, 0xBC, 0xD0, 0x6B, 0xFA, 0x53, 0xDD, 0xEF,
0x3C, 0x1B, 0x20, 0xEE, 0x3F, 0xD5, 0x9D, 0x7C,
0x25, 0xE4, 0x1D, 0x2B, 0x66, 0xC6, 0x2E, 0x37,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
static const ssl3DHParams ff_dhe_3072_params = {
@ -166,7 +166,7 @@ static const unsigned char ff_dhe_4096_p[] = {
0x8E, 0xC9, 0xB5, 0x5A, 0x7F, 0x88, 0xA4, 0x6B,
0x4D, 0xB5, 0xA8, 0x51, 0xF4, 0x41, 0x82, 0xE1,
0xC6, 0x8A, 0x00, 0x7E, 0x5E, 0x65, 0x5F, 0x6A,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
static const ssl3DHParams ff_dhe_4096_params = {
@ -271,7 +271,7 @@ static const unsigned char ff_dhe_6144_p[] = {
0x62, 0xA6, 0x95, 0x26, 0xD4, 0x31, 0x61, 0xC1,
0xA4, 0x1D, 0x57, 0x0D, 0x79, 0x38, 0xDA, 0xD4,
0xA4, 0x0E, 0x32, 0x9C, 0xD0, 0xE4, 0x0E, 0x65,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
static const ssl3DHParams ff_dhe_6144_params = {
@ -408,7 +408,7 @@ static const unsigned char ff_dhe_8192_p[] = {
0x08, 0x22, 0xE5, 0x06, 0xA9, 0xF4, 0x61, 0x4E,
0x01, 0x1E, 0x2A, 0x94, 0x83, 0x8F, 0xF8, 0x8C,
0xD6, 0x8C, 0x8B, 0xB7, 0xC5, 0xC6, 0x42, 0x4C,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
static const ssl3DHParams ff_dhe_8192_params = {

View file

@ -10,44 +10,52 @@
#include "ssl.h"
#include "sslimpl.h"
#include "sslproto.h"
#include "keyhi.h"
#include "pk11func.h"
#ifdef _MSC_VER
#if _MSC_VER < 1900
#define inline
#endif
#endif
/*
* 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;
@ -177,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)
@ -384,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)) {
@ -432,11 +460,10 @@ dtls13_HandleAck(sslSocket *ss, sslBuffer *databuf)
SSL_TRC(10, ("%d: SSL3[%d]: Handling ACK", SSL_GETPID(), ss->fd));
rv = ssl3_ConsumeHandshakeNumber(ss, &length, 2, &b, &l);
if (rv != SECSuccess) {
return SECFailure;
goto loser;
}
if (length != l) {
tls13_FatalError(ss, SSL_ERROR_RX_MALFORMED_DTLS_ACK, decode_error);
return SECFailure;
goto loser;
}
while (l > 0) {
@ -445,7 +472,7 @@ dtls13_HandleAck(sslSocket *ss, sslBuffer *databuf)
rv = ssl3_ConsumeHandshakeNumber64(ss, &seq, 8, &b, &l);
if (rv != SECSuccess) {
return SECFailure;
goto loser;
}
for (cursor = PR_LIST_HEAD(&ss->ssl3.hs.dtlsSentHandshake);
@ -493,6 +520,14 @@ dtls13_HandleAck(sslSocket *ss, sslBuffer *databuf)
}
}
return SECSuccess;
loser:
/* Due to bug 1829391 we may incorrectly send an alert rather than
* ignore an invalid record here. */
SSL_TRC(11, ("%d: SSL3[%d]: Error processing DTLS1.3 ACK.",
SSL_GETPID(), ss->fd));
PORT_SetError(SSL_ERROR_RX_MALFORMED_DTLS_ACK);
return SECFailure;
}
/* Clean up the read timer for the handshake cipher suites on the
@ -518,3 +553,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;
}

View file

@ -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

View file

@ -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
@ -364,7 +359,7 @@ dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum,
rv = dtls_HandleHandshakeMessage(ss, buf.buf,
buf.len == fragment_length);
if (rv == SECFailure) {
if (rv != SECSuccess) {
goto loser;
}
} else {
@ -473,7 +468,7 @@ dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum,
rv = dtls_HandleHandshakeMessage(ss, ss->ssl3.hs.msg_body.buf,
buf.len == fragment_length);
if (rv == SECFailure) {
if (rv != SECSuccess) {
goto loser;
}
}
@ -485,7 +480,7 @@ dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum,
}
// This should never happen, but belt and suspenders.
if (rv == SECFailure) {
if (rv != SECSuccess) {
PORT_Assert(0);
goto loser;
}
@ -505,9 +500,6 @@ dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum,
loser:
origBuf->len = 0; /* So ssl3_GatherAppDataRecord will keep looping. */
/* XXX OK for now. In future handle rv == SECWouldBlock safely in order
* to deal with asynchronous certificate verification */
return rv;
}
@ -1335,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)
{
@ -1349,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. */
@ -1398,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

View file

@ -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

View file

@ -5,6 +5,10 @@ CORE_DEPTH = ../..
# DEFINES = -DTRACE
ifdef ZLIB_INCLUDE_DIR
INCLUDES += -I$(ZLIB_INCLUDE_DIR)
endif
EXPORTS = \
ssl.h \
sslt.h \
@ -15,27 +19,34 @@ EXPORTS = \
$(NULL)
MODULE = nss
MAPFILE = $(OBJDIR)/ssl.def
CSRCS = \
dtlscon.c \
authcert.c \
cmpcert.c \
dtls13con.c \
dtlscon.c \
prelib.c \
selfencrypt.c \
ssl3con.c \
ssl3ecc.c \
ssl3ext.c \
ssl3exthandle.c \
ssl3gthr.c \
sslauth.c \
sslbloom.c \
sslcert.c \
sslcon.c \
ssldef.c \
sslencode.c \
sslenum.c \
sslerr.c \
sslerrstrs.c \
sslgrp.c \
sslinfo.c \
sslinit.c \
ssl3ext.c \
ssl3exthandle.c \
sslmutex.c \
sslnonce.c \
sslprimitive.c \
sslreveal.c \
sslsecur.c \
sslsnce.c \
@ -43,25 +54,20 @@ CSRCS = \
sslspec.c \
ssltrace.c \
sslver.c \
authcert.c \
cmpcert.c \
selfencrypt.c \
sslinfo.c \
ssl3ecc.c \
tls13con.c \
tls13ech.c \
tls13echv.c \
tls13exthandle.c \
tls13hashstate.c \
tls13hkdf.c \
tls13psk.c \
tls13replay.c \
sslcert.c \
sslgrp.c \
sslprimitive.c \
tls13esni.c \
tls13subcerts.c \
$(NULL)
LIBRARY_NAME = ssl
LIBRARY_VERSION = 3
MAPFILE = $(OBJDIR)/$(LIBRARY_NAME).def
# This part of the code, including all sub-dirs, can be optimized for size
export ALLOW_OPT_CODE_SIZE = 1

View file

@ -247,3 +247,9 @@ SSL_FilterClientCertListBySocket;
;+ local:
;+*;
;+};
;+NSS_3.80 { # NSS 3.80 release
;+ global:
SSL_ClientCertCallbackComplete;
;+ local:
;+*;
;+};

View file

@ -44,10 +44,12 @@
'ssltrace.c',
'sslver.c',
'tls13con.c',
'tls13esni.c',
'tls13ech.c',
'tls13echv.c',
'tls13exthandle.c',
'tls13hashstate.c',
'tls13hkdf.c',
'tls13psk.c',
'tls13replay.c',
'tls13subcerts.c',
],
@ -70,11 +72,11 @@
'UNSAFE_FUZZER_MODE',
],
}],
# [ 'enable_sslkeylogfile==1', {
# 'defines': [
# 'NSS_ALLOW_SSLKEYLOGFILE',
# ],
# }],
[ 'enable_sslkeylogfile==1', {
'defines': [
'NSS_ALLOW_SSLKEYLOGFILE',
],
}],
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports',

View file

@ -175,7 +175,7 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd);
/* SSL_REUSE_SERVER_ECDHE_KEY controls whether the ECDHE server key is
* reused for multiple handshakes or generated each time.
* SSL_REUSE_SERVER_ECDHE_KEY is currently enabled by default.
* SSL_REUSE_SERVER_ECDHE_KEY is currently disabled by default.
* This socket option is for ECDHE, only. It is unrelated to DHE.
*/
#define SSL_REUSE_SERVER_ECDHE_KEY 27
@ -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,63 @@ 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
/* Enables TLS GREASE (specified in RFC8701, following Chrome 55 implementation
* decisions).
*
* If enabled and the client's ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3 or
* the server's ss->version >= SSL_LIBRARY_VERSION_TLS_1_3, this adds random
* GREASE values to:
* - ClientHello (Client):
* - A cipher_suite value to the cipher_suites field.
* - An empty and a 1B zeroed payload extension.
* - A named group value to the supported_groups extension and a
* KeyShareEntry value for the added named group.
* - A signature algorithm value to the signature_algorithms extension.
* - A version value to the supported_versions extension.
* - A PskKeyExchangeMode value to the psk_key_exchange_modes extension.
* - A alpn value to the application_layer_protocol_negotiation extension.
*
* - CertificateRequest (Server):
* - An empty extension.
* - A signature algorithm value to the signature_algorithms extension.
*
* - NewSessionTicket (Server):
* - An empty extension.
*
* GREASE values MUST nerver be negotiated but ignored.
*/
#define SSL_ENABLE_GREASE 42
/* Enables TLS ClientHello Extension Permutation.
*
* On a TLS ClientHello all extensions but the Psk extension
* (which MUST be last) will be sent in randomly shuffeld order.
*/
#define SSL_ENABLE_CH_EXTENSION_PERMUTATION 43
#ifdef SSL_DEPRECATED_FUNCTION
/* Old deprecated function names */
SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRIntn on);
@ -383,7 +437,14 @@ SSL_IMPORT SECStatus SSL_SetNextProtoCallback(PRFileDesc *fd,
* preferred. The other protocols should be in preference order.
*
* The supported protocols are specified in |data| in wire-format (8-bit
* length-prefixed). For example: "\010http/1.1\006spdy/2". */
* length-prefixed). For example: "\010http/1.1\006spdy/2".
*
* An empty value (i.e., where |length| is 0 and |data| is any value,
* including NULL) forcibly disables ALPN. In this mode, the server will
* reject any ClientHello that includes the ALPN extension.
*
* Calling this function overrides the callback previously set by
* SSL_SetNextProtoCallback. */
SSL_IMPORT SECStatus SSL_SetNextProtoNego(PRFileDesc *fd,
const unsigned char *data,
unsigned int length);
@ -829,6 +890,20 @@ SSL_IMPORT SECStatus SSL_AuthCertificate(void *arg, PRFileDesc *fd,
* caNames - pointer to distinguished names of CAs that the server likes
* pRetCert - pointer to pointer to cert, for return of cert
* pRetKey - pointer to key pointer, for return of key
* Return value can be one of {SECSuccess, SECFailure, SECWouldBlock}
*
* If SECSuccess, pRetCert and pRetKey should be set to the selected
* client cert and private key respectively. If SECFailure or SECWouldBlock
* they should not be changed.
*
* Ownership of pRetCert and pRetKey passes to NSS. The application must not
* mutate or free the structures after passing them to NSS.
*
* Returning SECWouldBlock will block the handshake until SSL_ClientCertCallbackComplete
* is called. Note that references to *caNames should not be kept after SSLGetClientAuthData
* returns. Instead, take a copy of the data.
*
* See also the comments for SSL_ClientCertCallbackComplete.
*/
typedef SECStatus(PR_CALLBACK *SSLGetClientAuthData)(void *arg,
PRFileDesc *fd,
@ -1478,6 +1553,50 @@ extern const char *NSSSSL_GetVersion(void);
SSL_IMPORT SECStatus SSL_AuthCertificateComplete(PRFileDesc *fd,
PRErrorCode error);
/* Restart an SSL connection which was paused to do asynchronous client
* certificate selection (when the client certificate hook returned SECWouldBlock).
*
* This function only works for non-blocking sockets; Do not use it for
* blocking sockets. This function works only for the client role of
* a connection; it does not work for the server role.
*
* If a certificate has been sucessfully selected, the application must call
* SSL_ClientCertCallbackComplete with:
* - SECSuccess (0) as the value of outcome
* - a valid SECKEYPrivateKey located at *clientPrivateKey
* - a valid CERTCertificate located at *clientCertificate
* The ownership of these latter structures will pass to NSS and the application
* MUST not retain any references to them or invalidate them.
*
* If a certificate has not been selected, the application must call
* SSL_ClientCertCallbackComplete with:
* - SECFailure (-1) as the value of outcome
* - *clientPrivateKey set to NULL.
* - *clientCertificate set to NULL
*
* Once the application has returned SECWouldBlock to getClientAuthData
* the handshake will not proceed until this function is called. It is an
* error to call this function when the handshake is not waiting on client
* certificate selection, or to call this function more than once.
* This function will not complete the entire handshake. The application must
* call SSL_ForceHandshake, PR_Recv, PR_Send, etc. after calling this function
* to force the handshake to complete.
*
* Be careful about converting an application from synchronous cert selection
* to asynchronous certificate selection. A naive conversion is likely to
* result in deadlocks; e.g. the application will wait in PR_Poll for network
* I/O on the connection while all network I/O on the connection is blocked
* waiting for this function to be called.
*
* Note that SSL_ClientCertCallbackComplete will (usually) return
* SECSuccess; SECFailure indicates that the function was invoked incorrectly or
* an error whilst processing the handshake. The return code does not indicate
* whether or not the provided private key and certificate were sucessfully loaded
* or accepted by the server.
*/
SSL_IMPORT SECStatus SSL_ClientCertCallbackComplete(PRFileDesc *fd, SECStatus outcome, SECKEYPrivateKey *clientPrivateKey, CERTCertificate *clientCertificate);
/*
* This is used to access experimental APIs. Don't call this directly. This is
* used to enable the experimental APIs that are defined in "sslexp.h".

File diff suppressed because it is too large Load diff

View file

@ -762,22 +762,18 @@ static const ssl3CipherSuite ssl_all_ec_suites[] = {
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256,
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
TLS_ECDHE_ECDSA_WITH_NULL_SHA,
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384,
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384,
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
TLS_ECDHE_RSA_WITH_NULL_SHA,
TLS_ECDHE_RSA_WITH_RC4_128_SHA,
@ -910,6 +906,20 @@ ssl_SendSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
}
}
/* GREASE SupportedGroups:
* A client MAY select one or more GREASE named group values and advertise
* them in the "supported_groups" extension, if sent [RFC8701, Section 3.1].
*/
if (!ss->sec.isServer &&
ss->opt.enableGrease &&
ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3) {
rv = sslBuffer_AppendNumber(buf, ss->ssl3.hs.grease->idx[grease_group], 2);
if (rv != SECSuccess) {
return SECFailure;
}
found = PR_TRUE;
}
if (!found) {
/* We added nothing, don't send the extension. */
return SECSuccess;

View file

@ -10,10 +10,12 @@
#include "nssrenam.h"
#include "nss.h"
#include "pk11pub.h"
#include "ssl.h"
#include "sslimpl.h"
#include "sslproto.h"
#include "ssl3exthandle.h"
#include "tls13ech.h"
#include "tls13err.h"
#include "tls13exthandle.h"
#include "tls13subcerts.h"
@ -43,6 +45,7 @@ static const ssl3ExtensionHandler clientHelloHandlers[] = {
{ ssl_app_layer_protocol_xtn, &ssl3_ServerHandleAppProtoXtn },
{ ssl_use_srtp_xtn, &ssl3_ServerHandleUseSRTPXtn },
{ ssl_cert_status_xtn, &ssl3_ServerHandleStatusRequestXtn },
{ ssl_tls13_certificate_authorities_xtn, &tls13_ServerHandleCertAuthoritiesXtn },
{ ssl_signature_algorithms_xtn, &ssl3_HandleSigAlgsXtn },
{ ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn },
{ ssl_signed_cert_timestamp_xtn, &ssl3_ServerHandleSignedCertTimestampXtn },
@ -52,7 +55,6 @@ static const ssl3ExtensionHandler clientHelloHandlers[] = {
{ ssl_tls13_early_data_xtn, &tls13_ServerHandleEarlyDataXtn },
{ ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ServerHandlePskModesXtn },
{ ssl_tls13_cookie_xtn, &tls13_ServerHandleCookieXtn },
{ ssl_tls13_encrypted_sni_xtn, &tls13_ServerHandleEsniXtn },
{ ssl_tls13_post_handshake_auth_xtn, &tls13_ServerHandlePostHandshakeAuthXtn },
{ ssl_record_size_limit_xtn, &ssl_HandleRecordSizeLimitXtn },
{ 0, NULL }
@ -73,6 +75,7 @@ static const ssl3ExtensionHandler serverHelloHandlersTLS[] = {
{ ssl_tls13_key_share_xtn, &tls13_ClientHandleKeyShareXtn },
{ ssl_tls13_pre_shared_key_xtn, &tls13_ClientHandlePreSharedKeyXtn },
{ ssl_tls13_early_data_xtn, &tls13_ClientHandleEarlyDataXtn },
{ ssl_tls13_encrypted_client_hello_xtn, &tls13_ClientHandleEchXtn },
{ ssl_record_size_limit_xtn, &ssl_HandleRecordSizeLimitXtn },
{ 0, NULL }
};
@ -80,6 +83,7 @@ static const ssl3ExtensionHandler serverHelloHandlersTLS[] = {
static const ssl3ExtensionHandler helloRetryRequestHandlers[] = {
{ ssl_tls13_key_share_xtn, tls13_ClientHandleKeyShareXtnHrr },
{ ssl_tls13_cookie_xtn, tls13_ClientHandleHrrCookie },
{ ssl_tls13_encrypted_client_hello_xtn, tls13_ClientHandleHrrEchXtn },
{ 0, NULL }
};
@ -119,36 +123,38 @@ static const ssl3ExtensionHandler certificateRequestHandlers[] = {
* the client hello is empty (for example, the extended master secret
* extension, if it were listed last). See bug 1243641.
*/
static const sslExtensionBuilder clientHelloSendersTLS[] =
{
{ ssl_server_name_xtn, &ssl3_ClientSendServerNameXtn },
{ ssl_extended_master_secret_xtn, &ssl3_SendExtendedMasterSecretXtn },
{ ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn },
{ ssl_supported_groups_xtn, &ssl_SendSupportedGroupsXtn },
{ ssl_ec_point_formats_xtn, &ssl3_SendSupportedPointFormatsXtn },
{ ssl_session_ticket_xtn, &ssl3_ClientSendSessionTicketXtn },
{ ssl_app_layer_protocol_xtn, &ssl3_ClientSendAppProtoXtn },
{ ssl_use_srtp_xtn, &ssl3_ClientSendUseSRTPXtn },
{ ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn },
{ ssl_delegated_credentials_xtn, &tls13_ClientSendDelegatedCredentialsXtn },
{ ssl_signed_cert_timestamp_xtn, &ssl3_ClientSendSignedCertTimestampXtn },
{ ssl_tls13_key_share_xtn, &tls13_ClientSendKeyShareXtn },
{ ssl_tls13_early_data_xtn, &tls13_ClientSendEarlyDataXtn },
/* Some servers (e.g. WebSphere Application Server 7.0 and Tomcat) will
static const sslExtensionBuilder clientHelloSendersTLS[] = {
/* TLS 1.3 GREASE extensions - empty. */
{ ssl_tls13_grease_xtn, &tls13_SendEmptyGreaseXtn },
{ ssl_server_name_xtn, &ssl3_ClientSendServerNameXtn },
{ ssl_extended_master_secret_xtn, &ssl3_SendExtendedMasterSecretXtn },
{ ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn },
{ ssl_supported_groups_xtn, &ssl_SendSupportedGroupsXtn },
{ ssl_ec_point_formats_xtn, &ssl3_SendSupportedPointFormatsXtn },
{ ssl_session_ticket_xtn, &ssl3_ClientSendSessionTicketXtn },
{ ssl_app_layer_protocol_xtn, &ssl3_ClientSendAppProtoXtn },
{ ssl_use_srtp_xtn, &ssl3_ClientSendUseSRTPXtn },
{ ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn },
{ ssl_delegated_credentials_xtn, &tls13_ClientSendDelegatedCredentialsXtn },
{ ssl_signed_cert_timestamp_xtn, &ssl3_ClientSendSignedCertTimestampXtn },
{ ssl_tls13_key_share_xtn, &tls13_ClientSendKeyShareXtn },
{ ssl_tls13_early_data_xtn, &tls13_ClientSendEarlyDataXtn },
/* Some servers (e.g. WebSphere Application Server 7.0 and Tomcat) will
* time out or terminate the connection if the last extension in the
* client hello is empty. They are not intolerant of TLS 1.2, so list
* signature_algorithms at the end. See bug 1243641. */
{ ssl_tls13_supported_versions_xtn, &tls13_ClientSendSupportedVersionsXtn },
{ ssl_signature_algorithms_xtn, &ssl3_SendSigAlgsXtn },
{ ssl_tls13_cookie_xtn, &tls13_ClientSendHrrCookieXtn },
{ ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ClientSendPskModesXtn },
{ ssl_tls13_encrypted_sni_xtn, &tls13_ClientSendEsniXtn },
{ ssl_tls13_post_handshake_auth_xtn, &tls13_ClientSendPostHandshakeAuthXtn },
{ ssl_record_size_limit_xtn, &ssl_SendRecordSizeLimitXtn },
/* The pre_shared_key extension MUST be last. */
{ ssl_tls13_pre_shared_key_xtn, &tls13_ClientSendPreSharedKeyXtn },
{ 0, NULL }
};
{ ssl_tls13_supported_versions_xtn, &tls13_ClientSendSupportedVersionsXtn },
{ ssl_signature_algorithms_xtn, &ssl3_SendSigAlgsXtn },
{ ssl_tls13_cookie_xtn, &tls13_ClientSendHrrCookieXtn },
{ ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ClientSendPskModesXtn },
{ ssl_tls13_post_handshake_auth_xtn, &tls13_ClientSendPostHandshakeAuthXtn },
{ ssl_record_size_limit_xtn, &ssl_SendRecordSizeLimitXtn },
/* TLS 1.3 GREASE extensions - 1 zero byte. */
{ ssl_tls13_grease_xtn, &tls13_SendGreaseXtn },
/* The pre_shared_key extension MUST be last. */
{ ssl_tls13_pre_shared_key_xtn, &tls13_ClientSendPreSharedKeyXtn },
{ 0, NULL }
};
static const sslExtensionBuilder clientHelloSendersSSL3[] = {
{ ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn },
@ -158,6 +164,8 @@ static const sslExtensionBuilder clientHelloSendersSSL3[] = {
static const sslExtensionBuilder tls13_cert_req_senders[] = {
{ ssl_signature_algorithms_xtn, &ssl3_SendSigAlgsXtn },
{ ssl_tls13_certificate_authorities_xtn, &tls13_SendCertAuthoritiesXtn },
/* TLS 1.3 GREASE extension. */
{ ssl_tls13_grease_xtn, &tls13_SendEmptyGreaseXtn },
{ 0, NULL }
};
@ -165,6 +173,7 @@ static const sslExtensionBuilder tls13_hrr_senders[] = {
{ ssl_tls13_key_share_xtn, &tls13_ServerSendHrrKeyShareXtn },
{ ssl_tls13_cookie_xtn, &tls13_ServerSendHrrCookieXtn },
{ ssl_tls13_supported_versions_xtn, &tls13_ServerSendSupportedVersionsXtn },
{ ssl_tls13_encrypted_client_hello_xtn, &tls13_ServerSendHrrEchXtn },
{ 0, NULL }
};
@ -192,7 +201,8 @@ static const struct {
{ ssl_tls13_psk_key_exchange_modes_xtn, ssl_ext_native_only },
{ ssl_tls13_ticket_early_data_info_xtn, ssl_ext_native_only },
{ ssl_tls13_certificate_authorities_xtn, ssl_ext_native },
{ ssl_renegotiation_info_xtn, ssl_ext_native }
{ ssl_renegotiation_info_xtn, ssl_ext_native },
{ ssl_tls13_encrypted_client_hello_xtn, ssl_ext_native_only },
};
static SSLExtensionSupport
@ -274,7 +284,7 @@ SSLExp_InstallExtensionHooks(PRFileDesc *fd, PRUint16 extension,
return SECSuccess;
}
static sslCustomExtensionHooks *
sslCustomExtensionHooks *
ssl_FindCustomExtensionHooks(sslSocket *ss, PRUint16 extension)
{
PRCList *cursor;
@ -321,6 +331,34 @@ ssl3_ExtensionAdvertised(const sslSocket *ss, PRUint16 ex_type)
xtnData->numAdvertised, ex_type);
}
void
ssl3_RecordExtensionNegotiated(const sslSocket *ss, TLSExtensionData *xtnData,
PRUint16 ex_type)
{
/* Record that an extension was negotiated during a full TLS handshake.
* This function must NOT be used to track extensions carried in
* post-handshake messages (e.g. CertificateRequest during PHA);
* their negotiation state should instead be stored in dedicated fields on
* TLSExtensionData or sslSocket (e.g. xtnData->compressionAlg for
* certificate compression). */
PORT_Assert(!ss->firstHsDone ||
ss->opt.enableRenegotiation != SSL_RENEGOTIATE_NEVER);
PORT_Assert(!arrayContainsExtension(xtnData->negotiated,
xtnData->numNegotiated, ex_type));
PORT_Assert(xtnData->numNegotiated < SSL_MAX_EXTENSIONS);
if (xtnData->numNegotiated < SSL_MAX_EXTENSIONS) {
xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
}
}
PRBool
ssl3_ExtensionAdvertisedClientHelloInner(const sslSocket *ss, PRUint16 ex_type)
{
const TLSExtensionData *xtnData = &ss->xtnData;
return arrayContainsExtension(xtnData->echAdvertised,
xtnData->echNumAdvertised, ex_type);
}
/* Go through hello extensions in |b| and deserialize
* them into the list in |ss->ssl3.hs.remoteExtensions|.
* The only checking we do in this point is for duplicates.
@ -511,11 +549,21 @@ ssl3_HandleParsedExtensions(sslSocket *ss, SSLHandshakeType message)
* do not have any response, so we rely on
* ssl3_ExtensionAdvertised to return false on the server. That
* results in the server only rejecting any extension. */
if (!allowNotOffered && (extension->type != ssl_tls13_cookie_xtn) &&
!ssl3_ExtensionAdvertised(ss, extension->type)) {
(void)SSL3_SendAlert(ss, alert_fatal, unsupported_extension);
PORT_SetError(SSL_ERROR_RX_UNEXPECTED_EXTENSION);
return SECFailure;
if (!allowNotOffered && (extension->type != ssl_tls13_cookie_xtn)) {
if (!ssl3_ExtensionAdvertised(ss, extension->type)) {
SSL_TRC(10, ("Server sent xtn type=%d which is invalid for the CHO", extension->type));
(void)SSL3_SendAlert(ss, alert_fatal, unsupported_extension);
PORT_SetError(SSL_ERROR_RX_UNEXPECTED_EXTENSION);
return SECFailure;
}
/* If we offered ECH, we also check whether the extension is compatible with
* the Client Hello Inner. We don't yet know whether the server accepted ECH,
* so we only store this for now. If we later accept, we check this boolean
* and reject with an unsupported_extension alert if it is set. */
if (ss->ssl3.hs.echHpkeCtx && !ssl3_ExtensionAdvertisedClientHelloInner(ss, extension->type)) {
SSL_TRC(10, ("Server sent xtn type=%d which is invalid for the CHI", extension->type));
ss->ssl3.hs.echInvalidExtension = PR_TRUE;
}
}
/* Check that this is a legal extension in TLS 1.3 */
@ -639,7 +687,7 @@ ssl3_RegisterExtensionSender(const sslSocket *ss,
return SECFailure;
}
static SECStatus
SECStatus
ssl_CallCustomExtensionSenders(sslSocket *ss, sslBuffer *buf,
SSLHandshakeType message)
{
@ -698,6 +746,7 @@ ssl_CallCustomExtensionSenders(sslSocket *ss, sslBuffer *buf,
buf->len += len;
if (message == ssl_hs_client_hello ||
message == ssl_hs_ech_outer_client_hello ||
message == ssl_hs_certificate_request) {
ss->xtnData.advertised[ss->xtnData.numAdvertised++] = hook->type;
}
@ -727,11 +776,17 @@ ssl_ConstructExtensions(sslSocket *ss, sslBuffer *buf, SSLHandshakeType message)
/* Clear out any extensions previously advertised */
ss->xtnData.numAdvertised = 0;
ss->xtnData.echNumAdvertised = 0;
switch (message) {
case ssl_hs_client_hello:
if (ss->vrange.max > SSL_LIBRARY_VERSION_3_0) {
sender = clientHelloSendersTLS;
/* Use TLS ClientHello Extension Permutation? */
if (ss->opt.enableChXtnPermutation) {
sender = ss->ssl3.hs.chExtensionPermutation;
} else {
sender = clientHelloSendersTLS;
}
} else {
sender = clientHelloSendersSSL3;
}
@ -768,6 +823,7 @@ ssl_ConstructExtensions(sslSocket *ss, sslBuffer *buf, SSLHandshakeType message)
}
for (; sender->ex_sender != NULL; ++sender) {
PRUint16 ex_type = sender->ex_type;
PRBool append = PR_FALSE;
unsigned int start = buf->len;
unsigned int length;
@ -791,8 +847,14 @@ ssl_ConstructExtensions(sslSocket *ss, sslBuffer *buf, SSLHandshakeType message)
continue;
}
buf->len = start;
rv = sslBuffer_AppendNumber(buf, sender->ex_type, 2);
/* If TLS 1.3 GREASE is enabled, replace ssl_tls13_grease_xtn dummy
* GREASE extension types with randomly generated GREASE value. */
rv = tls13_MaybeGreaseExtensionType(ss, message, &ex_type);
if (rv != SECSuccess) {
goto loser; /* Code already set. */
}
rv = sslBuffer_AppendNumber(buf, ex_type, 2);
if (rv != SECSuccess) {
goto loser; /* Code already set. */
}
@ -806,11 +868,14 @@ ssl_ConstructExtensions(sslSocket *ss, sslBuffer *buf, SSLHandshakeType message)
if (message == ssl_hs_client_hello ||
message == ssl_hs_certificate_request) {
ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
sender->ex_type;
ex_type;
}
}
if (!PR_CLIST_IS_EMPTY(&ss->extensionHooks)) {
if (message == ssl_hs_client_hello && ss->opt.callExtensionWriterOnEchInner) {
message = ssl_hs_ech_outer_client_hello;
}
rv = ssl_CallCustomExtensionSenders(ss, buf, message);
if (rv != SECSuccess) {
goto loser;
@ -845,9 +910,6 @@ ssl_SendEmptyExtension(const sslSocket *ss, TLSExtensionData *xtnData,
static unsigned int
ssl_CalculatePaddingExtLen(const sslSocket *ss, unsigned int clientHelloLength)
{
unsigned int recordLength = 1 /* handshake message type */ +
3 /* handshake message length */ +
clientHelloLength;
unsigned int extensionLen;
/* Don't pad for DTLS, for SSLv3, or for renegotiation. */
@ -861,11 +923,11 @@ ssl_CalculatePaddingExtLen(const sslSocket *ss, unsigned int clientHelloLength)
* the ClientHello doesn't have a length between 256 and 511 bytes
* (inclusive). Initial ClientHello records with such lengths trigger bugs
* in F5 devices. */
if (recordLength < 256 || recordLength >= 512) {
if (clientHelloLength < 256 || clientHelloLength >= 512) {
return 0;
}
extensionLen = 512 - recordLength;
extensionLen = 512 - clientHelloLength;
/* Extensions take at least four bytes to encode. Always include at least
* one byte of data if we are padding. Some servers will time out or
* terminate the connection if the last ClientHello extension is empty. */
@ -876,6 +938,58 @@ ssl_CalculatePaddingExtLen(const sslSocket *ss, unsigned int clientHelloLength)
return extensionLen - 4;
}
/* Manually insert an extension, retaining the position of the PSK
* extension, if present. */
SECStatus
ssl3_EmplaceExtension(sslSocket *ss, sslBuffer *buf, PRUint16 exType,
const PRUint8 *data, unsigned int len, PRBool advertise)
{
SECStatus rv;
unsigned int tailLen;
/* Move the tail if there is one. This only happens if we are sending the
* TLS 1.3 PSK extension, which needs to be at the end. */
if (ss->xtnData.lastXtnOffset) {
PORT_Assert(buf->len > ss->xtnData.lastXtnOffset);
tailLen = buf->len - ss->xtnData.lastXtnOffset;
rv = sslBuffer_Grow(buf, buf->len + 4 + len);
if (rv != SECSuccess) {
return SECFailure;
}
PORT_Memmove(buf->buf + ss->xtnData.lastXtnOffset + 4 + len,
buf->buf + ss->xtnData.lastXtnOffset,
tailLen);
buf->len = ss->xtnData.lastXtnOffset;
} else {
tailLen = 0;
}
if (exType == ssl_tls13_encrypted_client_hello_xtn) {
ss->xtnData.echXtnOffset = buf->len;
}
rv = sslBuffer_AppendNumber(buf, exType, 2);
if (rv != SECSuccess) {
return SECFailure; /* Code already set. */
}
rv = sslBuffer_AppendVariable(buf, data, len, 2);
if (rv != SECSuccess) {
return SECFailure; /* Code already set. */
}
if (ss->xtnData.lastXtnOffset) {
ss->xtnData.lastXtnOffset += 4 + len;
}
buf->len += tailLen;
/* False only to retain behavior with padding_xtn. Maybe
* we can just mark that advertised as well? TODO */
if (advertise) {
ss->xtnData.advertised[ss->xtnData.numAdvertised++] = exType;
}
return SECSuccess;
}
/* ssl3_SendPaddingExtension possibly adds an extension which ensures that a
* ClientHello record is either < 256 bytes or is >= 512 bytes. This ensures
* that we don't trigger bugs in F5 products.
@ -885,13 +999,16 @@ ssl_CalculatePaddingExtLen(const sslSocket *ss, unsigned int clientHelloLength)
* to insert padding at the right place.
*/
SECStatus
ssl_InsertPaddingExtension(const sslSocket *ss, unsigned int prefixLen,
ssl_InsertPaddingExtension(sslSocket *ss, unsigned int prefixLen,
sslBuffer *buf)
{
static unsigned char padding[252] = { 0 };
unsigned int paddingLen;
unsigned int tailLen;
SECStatus rv;
/* Exit early if an application-provided extension hook
* already added padding. */
if (ssl3_ExtensionAdvertised(ss, ssl_padding_xtn)) {
return SECSuccess;
}
/* Account for the size of the header, the length field of the extensions
* block and the size of the existing extensions. */
@ -900,35 +1017,18 @@ ssl_InsertPaddingExtension(const sslSocket *ss, unsigned int prefixLen,
return SECSuccess;
}
/* Move the tail if there is one. This only happens if we are sending the
* TLS 1.3 PSK extension, which needs to be at the end. */
if (ss->xtnData.lastXtnOffset) {
PORT_Assert(buf->len > ss->xtnData.lastXtnOffset);
tailLen = buf->len - ss->xtnData.lastXtnOffset;
rv = sslBuffer_Grow(buf, buf->len + 4 + paddingLen);
if (rv != SECSuccess) {
return SECFailure;
}
PORT_Memmove(buf->buf + ss->xtnData.lastXtnOffset + 4 + paddingLen,
buf->buf + ss->xtnData.lastXtnOffset,
tailLen);
buf->len = ss->xtnData.lastXtnOffset;
} else {
tailLen = 0;
}
return ssl3_EmplaceExtension(ss, buf, ssl_padding_xtn, padding, paddingLen, PR_FALSE);
}
rv = sslBuffer_AppendNumber(buf, ssl_padding_xtn, 2);
if (rv != SECSuccess) {
return SECFailure; /* Code already set. */
void
ssl3_MoveRemoteExtensions(PRCList *dst, PRCList *src)
{
PRCList *cur_p;
while (!PR_CLIST_IS_EMPTY(src)) {
cur_p = PR_LIST_TAIL(src);
PR_REMOVE_LINK(cur_p);
PR_INSERT_LINK(cur_p, dst);
}
rv = sslBuffer_AppendVariable(buf, padding, paddingLen, 2);
if (rv != SECSuccess) {
return SECFailure; /* Code already set. */
}
buf->len += tailLen;
return SECSuccess;
}
void
@ -970,9 +1070,12 @@ ssl3_InitExtensionData(TLSExtensionData *xtnData, const sslSocket *ss)
++advertisedMax;
}
xtnData->advertised = PORT_ZNewArray(PRUint16, advertisedMax);
xtnData->echAdvertised = PORT_ZNewArray(PRUint16, advertisedMax);
xtnData->peerDelegCred = NULL;
xtnData->peerRequestedDelegCred = PR_FALSE;
xtnData->sendingDelegCredToPeer = PR_FALSE;
xtnData->selectedPsk = NULL;
}
void
@ -980,6 +1083,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);
@ -989,9 +1094,11 @@ ssl3_DestroyExtensionData(TLSExtensionData *xtnData)
xtnData->certReqAuthorities.arena = NULL;
}
PORT_Free(xtnData->advertised);
ssl_FreeEphemeralKeyPair(xtnData->esniPrivateKey);
SECITEM_FreeItem(&xtnData->keyShareExtension, PR_FALSE);
PORT_Free(xtnData->echAdvertised);
tls13_DestroyDelegatedCredential(xtnData->peerDelegCred);
tls13_DestroyEchXtnState(xtnData->ech);
xtnData->ech = NULL;
}
/* Free everything that has been allocated and then reset back to
@ -1038,3 +1145,57 @@ ssl3_ExtConsumeHandshakeVariable(const sslSocket *ss, SECItem *i,
{
return ssl3_ConsumeHandshakeVariable((sslSocket *)ss, i, bytes, b, length);
}
SECStatus
tls_ClientHelloExtensionPermutationSetup(sslSocket *ss)
{
size_t buildersLen = PR_ARRAY_SIZE(clientHelloSendersTLS);
const size_t buildersSize = (sizeof(sslExtensionBuilder) * buildersLen);
/* Psk Extension and then NULL entry MUST be last. */
const size_t permutationLen = buildersLen - 2;
/* There shouldn't already be a stored permutation. */
PR_ASSERT(!ss->ssl3.hs.chExtensionPermutation);
/* This shuffle handles up to 256 extensions. */
PR_ASSERT(buildersLen < 256);
uint8_t permutation[256] = { 0 };
sslExtensionBuilder *builders = PORT_ZAlloc(buildersSize);
if (!builders) {
return SECFailure;
}
/* Get a working copy of default builders. */
PORT_Memcpy(builders, clientHelloSendersTLS, buildersSize);
/* Get permutation randoms. */
if (PK11_GenerateRandom(permutation, permutationLen) != SECSuccess) {
PORT_Free(builders);
return SECFailure;
}
/* Fisher-Yates Shuffle */
for (size_t i = permutationLen - 1; i > 0; i--) {
size_t idx = permutation[i - 1] % (i + 1);
sslExtensionBuilder tmp = builders[i];
builders[i] = builders[idx];
builders[idx] = tmp;
}
/* Make sure that Psk extension is penultimate (before NULL entry). */
PR_ASSERT(builders[buildersLen - 2].ex_type == ssl_tls13_pre_shared_key_xtn);
PR_ASSERT(builders[buildersLen - 2].ex_sender == clientHelloSendersTLS[buildersLen - 2].ex_sender);
ss->ssl3.hs.chExtensionPermutation = builders;
return SECSuccess;
}
void
tls_ClientHelloExtensionPermutationDestroy(sslSocket *ss)
{
if (ss->ssl3.hs.chExtensionPermutation) {
PORT_Free(ss->ssl3.hs.chExtensionPermutation);
ss->ssl3.hs.chExtensionPermutation = NULL;
}
}

View file

@ -9,10 +9,9 @@
#ifndef __ssl3ext_h_
#define __ssl3ext_h_
#include "pk11hpke.h"
#include "sslencode.h"
#define TLS13_ESNI_NONCE_SIZE 16
typedef enum {
sni_nametype_hostname
} SNINameType;
@ -39,7 +38,9 @@ struct TLSExtensionDataStr {
/* Keep track of the extensions that are advertised or negotiated. */
PRUint16 numAdvertised;
PRUint16 *advertised; /* Allocated dynamically. */
PRUint16 *advertised; /* Allocated dynamically. */
PRUint16 echNumAdvertised; /* Tracks Xtns offered in ClientHelloInner. */
PRUint16 *echAdvertised;
PRUint16 numNegotiated;
PRUint16 negotiated[SSL_MAX_EXTENSIONS];
@ -77,6 +78,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;
@ -88,7 +99,9 @@ struct TLSExtensionDataStr {
PRUint16 dtlsSRTPCipherSuite; /* 0 if not selected */
unsigned int lastXtnOffset; /* Where to insert padding. 0 = end. */
unsigned int echXtnOffset; /* The start of the ECH Xtn (if any) */
unsigned int lastXtnOffset; /* Where to insert any other extensions.
* 0 = end, otherwise base of PSK xtn. */
PRCList remoteKeyShares; /* The other side's public keys (TLS 1.3) */
/* The following are used by a TLS 1.3 server. */
@ -104,14 +117,6 @@ struct TLSExtensionDataStr {
/* The record size limit set by the peer. Our value is kept in ss->opt. */
PRUint16 recordSizeLimit;
/* ESNI working state */
SECItem keyShareExtension;
ssl3CipherSuite esniSuite;
sslEphemeralKeyPair *esniPrivateKey;
/* Pointer into |ss->esniKeys->keyShares| */
TLS13KeyShareEntry *peerEsniShare;
PRUint8 esniNonce[TLS13_ESNI_NONCE_SIZE];
/* Delegated credentials.
*
* The delegated credential sent by the peer. Set by
@ -124,6 +129,14 @@ 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;
/* ECH working state. Non-null when a valid Encrypted Client Hello extension
* was received. */
sslEchXtnState *ech;
};
typedef struct TLSExtensionStr {
@ -151,12 +164,16 @@ SECStatus ssl3_HandleParsedExtensions(sslSocket *ss,
TLSExtension *ssl3_FindExtension(sslSocket *ss,
SSLExtensionType extension_type);
void ssl3_DestroyRemoteExtensions(PRCList *list);
void ssl3_MoveRemoteExtensions(PRCList *dst, PRCList *src);
void ssl3_InitExtensionData(TLSExtensionData *xtnData, const sslSocket *ss);
void ssl3_DestroyExtensionData(TLSExtensionData *xtnData);
void ssl3_ResetExtensionData(TLSExtensionData *xtnData, const sslSocket *ss);
PRBool ssl3_ExtensionNegotiated(const sslSocket *ss, PRUint16 ex_type);
PRBool ssl3_ExtensionAdvertised(const sslSocket *ss, PRUint16 ex_type);
void ssl3_RecordExtensionNegotiated(const sslSocket *ss,
TLSExtensionData *xtnData,
PRUint16 ex_type);
SECStatus ssl3_RegisterExtensionSender(const sslSocket *ss,
TLSExtensionData *xtnData,
@ -166,7 +183,9 @@ SECStatus ssl_ConstructExtensions(sslSocket *ss, sslBuffer *buf,
SSLHandshakeType message);
SECStatus ssl_SendEmptyExtension(const sslSocket *ss, TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *append);
SECStatus ssl_InsertPaddingExtension(const sslSocket *ss, unsigned int prefixLen,
SECStatus ssl3_EmplaceExtension(sslSocket *ss, sslBuffer *buf, PRUint16 exType,
const PRUint8 *data, unsigned int len, PRBool advertise);
SECStatus ssl_InsertPaddingExtension(sslSocket *ss, unsigned int prefixLen,
sslBuffer *buf);
/* Thunks to let us operate on const sslSocket* objects. */
@ -187,5 +206,10 @@ SECStatus SSLExp_GetExtensionSupport(PRUint16 type,
SECStatus SSLExp_InstallExtensionHooks(
PRFileDesc *fd, PRUint16 extension, SSLExtensionWriter writer,
void *writerArg, SSLExtensionHandler handler, void *handlerArg);
sslCustomExtensionHooks *ssl_FindCustomExtensionHooks(sslSocket *ss, PRUint16 extension);
SECStatus ssl_CallCustomExtensionSenders(sslSocket *ss, sslBuffer *buf,
SSLHandshakeType message);
SECStatus tls_ClientHelloExtensionPermutationSetup(sslSocket *ss);
void tls_ClientHelloExtensionPermutationDestroy(sslSocket *ss);
#endif

View file

@ -15,7 +15,7 @@
#include "selfencrypt.h"
#include "ssl3ext.h"
#include "ssl3exthandle.h"
#include "tls13esni.h"
#include "tls13ech.h"
#include "tls13exthandle.h" /* For tls13_ServerSendStatusRequestXtn. */
PRBool
@ -42,13 +42,11 @@ ssl_ShouldSendSNIExtension(const sslSocket *ss, const char *url)
*/
SECStatus
ssl3_ClientFormatServerNameXtn(const sslSocket *ss, const char *url,
TLSExtensionData *xtnData,
unsigned int len, TLSExtensionData *xtnData,
sslBuffer *buf)
{
unsigned int len;
SECStatus rv;
len = PORT_Strlen(url);
/* length of server_name_list */
rv = sslBuffer_AppendNumber(buf, len + 3, 2);
if (rv != SECSuccess) {
@ -76,17 +74,15 @@ ssl3_ClientSendServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData,
const char *url = ss->url;
/* We only make an ESNI private key if we are going to
* send ESNI. */
if (ss->xtnData.esniPrivateKey != NULL) {
url = ss->esniKeys->dummySni;
}
if (!ssl_ShouldSendSNIExtension(ss, url)) {
return SECSuccess;
}
rv = ssl3_ClientFormatServerNameXtn(ss, url, xtnData, buf);
/* If ECH, write the public name. The real server name
* is emplaced while constructing CHInner extensions. */
sslEchConfig *cfg = (sslEchConfig *)PR_LIST_HEAD(&ss->echConfigs);
const char *sniContents = PR_CLIST_IS_EMPTY(&ss->echConfigs) ? url : cfg->contents.publicName;
rv = ssl3_ClientFormatServerNameXtn(ss, sniContents, strlen(sniContents), xtnData, buf);
if (rv != SECSuccess) {
return SECFailure;
}
@ -107,13 +103,6 @@ ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData,
return SECSuccess; /* ignore extension */
}
if (ssl3_ExtensionNegotiated(ss, ssl_tls13_encrypted_sni_xtn)) {
/* If we already have ESNI, make sure we don't overwrite
* the value. */
PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
return SECSuccess;
}
/* Server side - consume client data and register server sender. */
/* do not parse the data if don't have user extension handling function. */
if (!ss->sniSocketConfig) {
@ -176,7 +165,7 @@ ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData,
ssl3_FreeSniNameArray(xtnData);
xtnData->sniNameArr = names;
xtnData->sniNameArrSize = 1;
xtnData->negotiated[xtnData->numNegotiated++] = ssl_server_name_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_server_name_xtn);
}
return SECSuccess;
@ -212,7 +201,7 @@ ssl3_FreeSniNameArray(TLSExtensionData *xtnData)
* Clients sends a filled in session ticket if one is available, and otherwise
* sends an empty ticket. Servers always send empty tickets.
*/
PRInt32
SECStatus
ssl3_ClientSendSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added)
{
@ -319,15 +308,15 @@ ssl3_SelectAppProtocol(const sslSocket *ss, TLSExtensionData *xtnData,
if (rv != SECSuccess) {
ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
return rv;
return SECFailure;
}
PORT_Assert(ss->nextProtoCallback);
/* The cipher suite isn't selected yet. Note that extensions
/* Neither the cipher suite nor ECH are selected yet Note that extensions
* sometimes affect what cipher suite is selected, e.g., for ECC. */
PORT_Assert((ss->ssl3.hs.preliminaryInfo &
ssl_preinfo_all & ~ssl_preinfo_cipher_suite) ==
(ssl_preinfo_all & ~ssl_preinfo_cipher_suite));
ssl_preinfo_all & ~ssl_preinfo_cipher_suite & ~ssl_preinfo_ech) ==
(ssl_preinfo_all & ~ssl_preinfo_cipher_suite & ~ssl_preinfo_ech));
/* The callback has to make sure that either rv != SECSuccess or that result
* is not set if there is no common protocol. */
rv = ss->nextProtoCallback(ss->nextProtoArg, ss->fd, data->data, data->len,
@ -356,7 +345,7 @@ ssl3_SelectAppProtocol(const sslSocket *ss, TLSExtensionData *xtnData,
}
xtnData->nextProtoState = SSL_NEXT_PROTO_NEGOTIATED;
xtnData->negotiated[xtnData->numNegotiated++] = extension;
ssl3_RecordExtensionNegotiated(ss, xtnData, extension);
return SECITEM_CopyItem(NULL, &xtnData->nextProto, &result);
}
@ -458,7 +447,7 @@ ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE);
xtnData->nextProtoState = SSL_NEXT_PROTO_SELECTED;
xtnData->negotiated[xtnData->numNegotiated++] = ssl_app_layer_protocol_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_app_layer_protocol_xtn);
return SECITEM_CopyItem(NULL, &xtnData->nextProto, &protocol_name);
}
@ -467,20 +456,33 @@ ssl3_ClientSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added)
{
SECStatus rv;
const unsigned int len = ss->opt.nextProtoNego.len;
/* Renegotiations do not send this extension. */
if (!ss->opt.enableALPN || !ss->opt.nextProtoNego.data || ss->firstHsDone) {
if (!ss->opt.enableALPN || !ss->opt.nextProtoNego.len || ss->firstHsDone) {
PR_ASSERT(!ss->opt.nextProtoNego.data);
return SECSuccess;
}
PRBool addGrease = ss->opt.enableGrease && ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3;
if (len > 0) {
/* Each protocol string is prefixed with a single byte length. */
rv = sslBuffer_AppendNumber(buf, len, 2);
/* The list of protocol strings is prefixed with a 2-byte length */
rv = sslBuffer_AppendNumber(buf, ss->opt.nextProtoNego.len + (addGrease ? 3 : 0), 2);
if (rv != SECSuccess) {
return SECFailure;
}
/* The list of protocol strings */
rv = sslBuffer_Append(buf, ss->opt.nextProtoNego.data, ss->opt.nextProtoNego.len);
if (rv != SECSuccess) {
return SECFailure;
}
/* A client MAY select one or more GREASE ALPN identifiers and advertise
* them in the "application_layer_protocol_negotiation" extension, if sent
* [RFC8701, Section 3.1]. */
if (addGrease) {
rv = sslBuffer_AppendNumber(buf, 2, 1);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_Append(buf, ss->opt.nextProtoNego.data, len);
rv = sslBuffer_AppendNumber(buf, ss->ssl3.hs.grease->idx[grease_alpn], 2);
if (rv != SECSuccess) {
return SECFailure;
}
@ -526,7 +528,7 @@ ssl3_ServerHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData
PORT_Assert(ss->sec.isServer);
/* remember that we got this extension. */
xtnData->negotiated[xtnData->numNegotiated++] = ssl_cert_status_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_cert_status_xtn);
if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
sender = tls13_ServerSendStatusRequestXtn;
@ -604,7 +606,7 @@ ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData
}
/* Keep track of negotiated extensions. */
xtnData->negotiated[xtnData->numNegotiated++] = ssl_cert_status_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_cert_status_xtn);
return SECSuccess;
}
@ -796,7 +798,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)
@ -857,7 +859,7 @@ ssl3_ClientHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData
}
/* Keep track of negotiated extensions. */
xtnData->negotiated[xtnData->numNegotiated++] = ssl_session_ticket_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_session_ticket_xtn);
return SECSuccess;
}
@ -928,6 +930,13 @@ ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket,
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
#ifndef UNSAFE_FUZZER_MODE
PORT_Assert(temp < ssl_auth_size);
#else
temp %= (8 * sizeof(SSLAuthType)) - 1;
#endif
parsedTicket->authType = (SSLAuthType)temp;
rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len);
if (rv != SECSuccess) {
@ -1034,7 +1043,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 +1067,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) {
@ -1295,7 +1309,7 @@ ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData
}
/* Keep track of negotiated extensions. */
xtnData->negotiated[xtnData->numNegotiated++] = ssl_session_ticket_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_session_ticket_xtn);
/* Parse the received ticket sent in by the client. We are
* lenient about some parse errors, falling back to a fullshake
@ -1373,7 +1387,7 @@ ssl3_HandleRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
/* remember that we got this extension and it was correct. */
CONST_CAST(sslSocket, ss)
->peerRequestedProtection = 1;
xtnData->negotiated[xtnData->numNegotiated++] = ssl_renegotiation_info_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_renegotiation_info_xtn);
if (ss->sec.isServer) {
/* prepare to send back the appropriate response */
rv = ssl3_RegisterExtensionSender(ss, xtnData,
@ -1508,7 +1522,7 @@ ssl3_ClientHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData,
}
/* OK, this looks fine. */
xtnData->negotiated[xtnData->numNegotiated++] = ssl_use_srtp_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_use_srtp_xtn);
xtnData->dtlsSRTPCipherSuite = cipher;
return SECSuccess;
}
@ -1579,7 +1593,7 @@ ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData,
/* OK, we have a valid cipher and we've selected it */
xtnData->dtlsSRTPCipherSuite = cipher;
xtnData->negotiated[xtnData->numNegotiated++] = ssl_use_srtp_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_use_srtp_xtn);
return ssl3_RegisterExtensionSender(ss, xtnData,
ssl_use_srtp_xtn,
@ -1625,8 +1639,12 @@ ssl3_HandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
return SECFailure;
}
/* Keep track of negotiated extensions. */
xtnData->negotiated[xtnData->numNegotiated++] = ssl_signature_algorithms_xtn;
/* Keep track of negotiated extensions. Only the server consumes this
* entry; on the client, skipping prevents numNegotiated overflow
* during repeated post-handshake CertificateRequests. */
if (ss->sec.isServer) {
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_signature_algorithms_xtn);
}
return SECSuccess;
}
@ -1647,7 +1665,8 @@ 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 */,
ss->opt.enableGrease, buf);
if (rv != SECSuccess) {
return SECFailure;
}
@ -1696,7 +1715,7 @@ ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnDat
SSL_GETPID(), ss->fd));
/* Keep track of negotiated extensions. */
xtnData->negotiated[xtnData->numNegotiated++] = ssl_extended_master_secret_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_extended_master_secret_xtn);
if (ss->sec.isServer) {
return ssl3_RegisterExtensionSender(ss, xtnData,
@ -1743,7 +1762,7 @@ ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *x
}
*scts = *data;
/* Keep track of negotiated extensions. */
xtnData->negotiated[xtnData->numNegotiated++] = ssl_signed_cert_timestamp_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_signed_cert_timestamp_xtn);
return SECSuccess;
}
@ -1779,7 +1798,7 @@ ssl3_ServerHandleSignedCertTimestampXtn(const sslSocket *ss,
return SECFailure;
}
xtnData->negotiated[xtnData->numNegotiated++] = ssl_signed_cert_timestamp_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_signed_cert_timestamp_xtn);
PORT_Assert(ss->sec.isServer);
return ssl3_RegisterExtensionSender(ss, xtnData,
ssl_signed_cert_timestamp_xtn,
@ -1812,8 +1831,16 @@ ssl3_HandleSupportedPointFormatsXtn(const sslSocket *ss,
}
}
/* Poor client doesn't support uncompressed points. */
/* Poor client doesn't support uncompressed points.
*
* If the client sends the extension and the extension does not contain the
* uncompressed point format, and the client has used the Supported Groups
* extension to indicate support for any of the curves defined in this
* specification, then the server MUST abort the handshake and return an
* illegal_parameter alert. [RFC8422, Section 5.1.2] */
ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
return SECFailure;
}
@ -1911,7 +1938,7 @@ ssl_HandleSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
}
/* Remember that we negotiated this extension. */
xtnData->negotiated[xtnData->numNegotiated++] = ssl_supported_groups_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_supported_groups_xtn);
return SECSuccess;
}
@ -1952,7 +1979,7 @@ ssl_HandleRecordSizeLimitXtn(const sslSocket *ss, TLSExtensionData *xtnData,
/* We can't enforce the maximum on a server. But we do need to ensure
* that we don't apply a limit that is too large. */
xtnData->recordSizeLimit = PR_MIN(maxLimit, limit);
xtnData->negotiated[xtnData->numNegotiated++] = ssl_record_size_limit_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_record_size_limit_xtn);
return SECSuccess;
}

View file

@ -93,7 +93,7 @@ SECStatus ssl3_ProcessSessionTicketCommon(sslSocket *ss, const SECItem *ticket,
/* out */ SECItem *appToken);
PRBool ssl_ShouldSendSNIExtension(const sslSocket *ss, const char *url);
SECStatus ssl3_ClientFormatServerNameXtn(const sslSocket *ss, const char *url,
TLSExtensionData *xtnData,
unsigned int len, TLSExtensionData *xtnData,
sslBuffer *buf);
SECStatus ssl3_ClientSendServerNameXtn(const sslSocket *ss,
TLSExtensionData *xtnData,

View file

@ -26,16 +26,16 @@ typedef struct ssl2GatherStr ssl2Gather;
SECStatus
ssl3_InitGather(sslGather *gs)
{
SECStatus status;
gs->state = GS_INIT;
gs->writeOffset = 0;
gs->readOffset = 0;
gs->dtlsPacketOffset = 0;
gs->dtlsPacket.len = 0;
gs->rejectV2Records = PR_FALSE;
status = sslBuffer_Grow(&gs->buf, 4096);
return status;
/* Allocate plaintext buffer to maximum possibly needed size. It needs to
* be larger than recordSizeLimit for TLS 1.0 and 1.1 compatability.
* The TLS 1.2 ciphertext is larger than the TLS 1.3 ciphertext. */
return sslBuffer_Grow(&gs->buf, TLS_1_2_MAX_CTEXT_LENGTH);
}
/* Caller must hold RecvBufLock. */
@ -174,13 +174,26 @@ ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags, ssl2Gather *ssl2gs)
}
}
/* This is the max length for an encrypted SSLv3+ fragment. */
if (!v2HdrLength &&
gs->remainder > (MAX_FRAGMENT_LENGTH + 2048)) {
SSL3_SendAlert(ss, alert_fatal, record_overflow);
gs->state = GS_INIT;
PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
return SECFailure;
/* If it is NOT an SSLv2 header */
if (!v2HdrLength) {
/* Check if default RFC specified max ciphertext/record
* limits are respected. Checks for used record size limit
* extension boundaries are done in
* ssl3con.c/ssl3_HandleRecord() for tls and dtls records.
*
* -> For TLS 1.2 records MUST NOT be longer than
* 2^14 + 2048 bytes.
* -> For TLS 1.3 records MUST NOT exceed 2^14 + 256 bytes.
* -> For older versions this MAY be enforced, we do it.
* [RFC8446 Section 5.2, RFC5246 Section 6.2.3]. */
if (gs->remainder > TLS_1_2_MAX_CTEXT_LENGTH ||
(gs->remainder > TLS_1_3_MAX_CTEXT_LENGTH &&
ss->version >= SSL_LIBRARY_VERSION_TLS_1_3)) {
SSL3_SendAlert(ss, alert_fatal, record_overflow);
gs->state = GS_INIT;
PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
return SECFailure;
}
}
gs->state = GS_DATA;
@ -218,7 +231,7 @@ ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags, ssl2Gather *ssl2gs)
break; /* End this case. Continue around the loop. */
}
/* FALL THROUGH if (gs->remainder == 0) as we just received
/* FALL THROUGH if (gs->remainder == 0) as we just received
* an empty record and there's really no point in calling
* ssl_DefRecv() with buf=NULL and len=0. */
@ -267,7 +280,8 @@ dtls_GatherData(sslSocket *ss, sslGather *gs, int flags)
int nb;
PRUint8 contentType;
unsigned int headerLen;
SECStatus rv;
SECStatus rv = SECSuccess;
PRBool dtlsLengthPresent = PR_TRUE;
SSL_TRC(30, ("dtls_GatherData"));
@ -280,18 +294,33 @@ dtls_GatherData(sslSocket *ss, sslGather *gs, int flags)
gs->dtlsPacketOffset = 0;
gs->dtlsPacket.len = 0;
/* Resize to the maximum possible size so we can fit a full datagram */
/* This is the max fragment length for an encrypted fragment
** plus the size of the record header.
** This magic constant is copied from ssl3_GatherData, with 5 changed
** to 13 (the size of the record header).
*/
if (gs->dtlsPacket.space < MAX_FRAGMENT_LENGTH + 2048 + 13) {
rv = sslBuffer_Grow(&gs->dtlsPacket,
MAX_FRAGMENT_LENGTH + 2048 + 13);
if (rv != SECSuccess) {
return -1; /* Code already set. */
/* Resize to the maximum possible size so we can fit a full datagram.
* This leads to record_overflow errors if records/ciphertexts greater
* than the buffer (= maximum record) size are to be received.
* DTLS Record errors are dropped silently. [RFC6347, Section 4.1.2.7].
* Checks for record size limit extension boundaries are performed in
* ssl3con.c/ssl3_HandleRecord() for tls and dtls records.
*
* -> For TLS 1.2 records MUST NOT be longer than 2^14 + 2048 bytes.
* -> For TLS 1.3 records MUST NOT exceed 2^14 + 256 bytes.
* -> For older versions this MAY be enforced, we do it.
* [RFC8446 Section 5.2, RFC5246 Section 6.2.3]. */
if (ss->version <= SSL_LIBRARY_VERSION_TLS_1_2) {
if (gs->dtlsPacket.space < DTLS_1_2_MAX_PACKET_LENGTH) {
rv = sslBuffer_Grow(&gs->dtlsPacket, DTLS_1_2_MAX_PACKET_LENGTH);
}
} else { /* version >= TLS 1.3 */
if (gs->dtlsPacket.space != DTLS_1_3_MAX_PACKET_LENGTH) {
/* During Hello and version negotiation older DTLS versions with
* greater possible packets are used. The buffer must therefore
* be "truncated" by clearing and reallocating it */
sslBuffer_Clear(&gs->dtlsPacket);
rv = sslBuffer_Grow(&gs->dtlsPacket, DTLS_1_3_MAX_PACKET_LENGTH);
}
}
if (rv != SECSuccess) {
return -1; /* Code already set. */
}
/* recv() needs to read a full datagram at a time */
@ -305,6 +334,8 @@ dtls_GatherData(sslSocket *ss, sslGather *gs, int flags)
} else /* if (nb < 0) */ {
SSL_DBG(("%d: SSL3[%d]: recv error %d", SSL_GETPID(), ss->fd,
PR_GetError()));
/* DTLS Record Errors, including overlong records, are silently
* dropped [RFC6347, Section 4.1.2.7]. */
return -1;
}
@ -316,8 +347,28 @@ 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.
*
* This condition is met on all invalid outer content types.
* For lower DTLS versions as well as the inner content types,
* this is checked in ssl3con.c/ssl3_HandleNonApplicationData().
*
* In DTLS generally invalid records SHOULD be silently discarded,
* no alert is sent [RFC6347, Section 4.1.2.7].
*/
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 +396,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;
}
@ -511,6 +560,15 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
cText.buf = &ss->gs.inbuf;
rv = ssl3_HandleRecord(ss, &cText);
}
#ifdef DEBUG
/* In Debug builds free gather ciphertext buffer after each decryption
* for advanced ASAN coverage/utilization. The buffer content has been
* used at this point, ssl3_HandleRecord() and thereby the decryption
* functions are only called from this point of the implementation. */
sslBuffer_Clear(&ss->gs.inbuf);
#endif
if (rv < 0) {
return ss->recvdCloseNotify ? 0 : rv;
}
@ -600,6 +658,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 +724,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 +736,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 +758,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... */

View file

@ -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 43
typedef PRUint16 ssl3CipherSuite;
/* The cipher suites are defined in sslproto.h */
@ -31,7 +31,20 @@ typedef PRUint16 ssl3CipherSuite;
/* SSL3_RECORD_HEADER_LENGTH + epoch/sequence_number */
#define DTLS_RECORD_HEADER_LENGTH 13
/* Max values for TLS records/ciphertexts
* For TLS 1.2 records MUST NOT be longer than 2^14 + 2048
* For TLS 1.3 records MUST NOT exceed 2^14 + 256 bytes.
* [RFC8446 Section 5.2, RFC5246 Section 6.2.3]. */
#define MAX_FRAGMENT_LENGTH 16384
#define TLS_1_2_MAX_EXPANSION 2048
#define TLS_1_3_MAX_EXPANSION (255 + 1)
#define TLS_1_3_MAX_CTEXT_LENGTH ((MAX_FRAGMENT_LENGTH) + (TLS_1_3_MAX_EXPANSION))
#define TLS_1_2_MAX_CTEXT_LENGTH ((MAX_FRAGMENT_LENGTH) + (TLS_1_2_MAX_EXPANSION))
/* DTLS_X_X_MAX_PACKET_LENGTH = TLS_X_X_MAX_RECORD_LENGTH + HEADER_LENGTH,
* used for DTLS datagram buffer size setting. We do not support DTLS CID! */
#define DTLS_1_3_MAX_PACKET_LENGTH ((TLS_1_3_MAX_CTEXT_LENGTH) + (SSL3_RECORD_HEADER_LENGTH))
#define DTLS_1_2_MAX_PACKET_LENGTH ((TLS_1_2_MAX_CTEXT_LENGTH) + (DTLS_RECORD_HEADER_LENGTH))
typedef enum { change_cipher_spec_choice = 1 } SSL3ChangeCipherSpecChoice;
@ -76,6 +89,7 @@ typedef enum {
bad_certificate_hash_value = 114,
certificate_required = 116,
no_application_protocol = 120,
ech_required = 121,
/* invalid alert */
no_alert = 256

View file

@ -10,12 +10,6 @@
#include "prnetdb.h"
#include "secport.h"
#ifdef _MSC_VER
#if _MSC_VER < 1900
#define inline
#endif
#endif
static inline unsigned int
sslBloom_Size(unsigned int bits)
{

View file

@ -205,6 +205,11 @@ ssl_FindServerCert(const sslSocket *ss, SSLAuthType authType,
{
PRCList *cursor;
/* Bug 1749475: avoid UB while fuzzing session tickets */
if ((unsigned)authType >= ssl_auth_size) {
return NULL;
}
for (cursor = PR_NEXT_LINK(&ss->serverCerts);
cursor != &ss->serverCerts;
cursor = PR_NEXT_LINK(cursor)) {

View file

@ -40,6 +40,9 @@ sslBuffer_Grow(sslBuffer *b, unsigned int newLen)
return SECSuccess;
}
/* If buf is non-NULL, space must be non-zero;
* if buf is NULL, space must be zero. */
PORT_Assert((b->buf && b->space) || (!b->buf && !b->space));
newLen = PR_MAX(newLen, b->len + 1024);
if (newLen > b->space) {
unsigned char *newBuf;
@ -57,6 +60,22 @@ sslBuffer_Grow(sslBuffer *b, unsigned int newLen)
return SECSuccess;
}
/* Appends len copies of c to b */
SECStatus
sslBuffer_Fill(sslBuffer *b, PRUint8 c, size_t len)
{
PORT_Assert(b);
SECStatus rv = sslBuffer_Grow(b, b->len + len);
if (rv != SECSuccess) {
return SECFailure;
}
if (len > 0) {
memset(SSL_BUFFER_NEXT(b), c, len);
}
b->len += len;
return SECSuccess;
}
SECStatus
sslBuffer_Append(sslBuffer *b, const void *data, unsigned int len)
{
@ -64,7 +83,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;
}
@ -162,6 +184,23 @@ sslBuffer_InsertLength(sslBuffer *b, unsigned int at, unsigned int size)
return SECSuccess;
}
SECStatus
sslBuffer_InsertNumber(sslBuffer *b, unsigned int at,
PRUint64 v, unsigned int size)
{
PORT_Assert(b->len >= at + size);
PORT_Assert(b->space >= at + size);
PORT_Assert(size <= 4 && size > 0);
if (v >= (1ULL << (8 * size))) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
ssl_EncodeUintX(SSL_BUFFER_BASE(b) + at, v, size);
return SECSuccess;
}
void
sslBuffer_Clear(sslBuffer *b)
{
@ -244,8 +283,8 @@ sslRead_ReadNumber(sslReader *reader, unsigned int bytes, PRUint64 *num)
#define MAX_SEND_BUF_LENGTH 32000 /* watch for 16-bit integer overflow */
#define MIN_SEND_BUF_LENGTH 4000
SECStatus
ssl3_AppendHandshake(sslSocket *ss, const void *void_src, unsigned int bytes)
static SECStatus
ssl3_AppendHandshakeInternal(sslSocket *ss, const void *void_src, unsigned int bytes, PRBool suppressHash)
{
unsigned char *src = (unsigned char *)void_src;
int room = ss->sec.ci.sendBuf.space - ss->sec.ci.sendBuf.len;
@ -264,7 +303,8 @@ ssl3_AppendHandshake(sslSocket *ss, const void *void_src, unsigned int bytes)
}
PRINT_BUF(60, (ss, "Append to Handshake", (unsigned char *)void_src, bytes));
if (!ss->firstHsDone || ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
// TODO: Move firstHsDone and version check into callers as a suppression.
if (!suppressHash && (!ss->firstHsDone || ss->version < SSL_LIBRARY_VERSION_TLS_1_3)) {
rv = ssl3_UpdateHandshakeHashes(ss, src, bytes);
if (rv != SECSuccess)
return SECFailure; /* error code set by ssl3_UpdateHandshakeHashes */
@ -289,6 +329,18 @@ ssl3_AppendHandshake(sslSocket *ss, const void *void_src, unsigned int bytes)
return SECSuccess;
}
SECStatus
ssl3_AppendHandshakeSuppressHash(sslSocket *ss, const void *void_src, unsigned int bytes)
{
return ssl3_AppendHandshakeInternal(ss, void_src, bytes, PR_TRUE);
}
SECStatus
ssl3_AppendHandshake(sslSocket *ss, const void *void_src, unsigned int bytes)
{
return ssl3_AppendHandshakeInternal(ss, void_src, bytes, PR_FALSE);
}
SECStatus
ssl3_AppendHandshakeNumber(sslSocket *ss, PRUint64 num, unsigned int lenSize)
{

View file

@ -27,6 +27,10 @@ typedef struct sslBufferStr {
{ \
b, 0, maxlen, PR_TRUE \
}
#define SSL_BUFFER_FIXED_LEN(b, len) \
{ \
b, len, 0, PR_TRUE \
}
#define SSL_BUFFER(b) SSL_BUFFER_FIXED(b, sizeof(b))
#define SSL_BUFFER_BASE(b) ((b)->buf)
#define SSL_BUFFER_LEN(b) ((b)->len)
@ -34,6 +38,7 @@ typedef struct sslBufferStr {
#define SSL_BUFFER_SPACE(b) ((b)->space - (b)->len)
SECStatus sslBuffer_Grow(sslBuffer *b, unsigned int newLen);
SECStatus sslBuffer_Fill(sslBuffer *b, PRUint8 c, size_t len);
SECStatus sslBuffer_Append(sslBuffer *b, const void *data, unsigned int len);
SECStatus sslBuffer_AppendNumber(sslBuffer *b, PRUint64 v, unsigned int size);
SECStatus sslBuffer_AppendVariable(sslBuffer *b, const PRUint8 *data,
@ -45,10 +50,14 @@ SECStatus sslBuffer_Skip(sslBuffer *b, unsigned int size,
unsigned int *savedOffset);
SECStatus sslBuffer_InsertLength(sslBuffer *b, unsigned int at,
unsigned int size);
SECStatus sslBuffer_InsertNumber(sslBuffer *b, unsigned int at,
PRUint64 v, unsigned int size);
void sslBuffer_Clear(sslBuffer *b);
SECStatus ssl3_AppendHandshake(sslSocket *ss, const void *void_src,
unsigned int bytes);
SECStatus ssl3_AppendHandshakeSuppressHash(sslSocket *ss, const void *void_src,
unsigned int bytes);
SECStatus ssl3_AppendHandshakeHeader(sslSocket *ss,
SSLHandshakeType t, unsigned int length);
SECStatus ssl3_AppendHandshakeNumber(sslSocket *ss, PRUint64 num,

View file

@ -76,10 +76,6 @@ const PRUint16 SSL_ImplementedCiphers[] = {
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256,
TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384,
TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384,
TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,

View file

@ -274,8 +274,23 @@ 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),
/* ECH rejected, public name authentication succeeded,
* and at least one of the retry_configs is compatible. */
SSL_ERROR_ECH_RETRY_WITH_ECH = (SSL_ERROR_BASE + 188),
/* ECH rejected, public name authentication succeeded,
* but none of the retry_configs are compatible. */
SSL_ERROR_ECH_RETRY_WITHOUT_ECH = (SSL_ERROR_BASE + 189),
/* ECH rejected and public name authentication failed. */
SSL_ERROR_ECH_FAILED = (SSL_ERROR_BASE + 190),
SSL_ERROR_ECH_REQUIRED_ALERT = (SSL_ERROR_BASE + 191),
SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
} SSLErrorCodes;
#define SSL_ERROR_RX_MALFORMED_ECH_CONFIG SSL_ERROR_RX_MALFORMED_ESNI_KEYS
#define SSL_ERROR_RX_MALFORMED_ECH_EXTENSION SSL_ERROR_RX_MALFORMED_ESNI_EXTENSION
#define SSL_ERROR_MISSING_ECH_EXTENSION SSL_ERROR_MISSING_ESNI_EXTENSION
#endif /* NO_SECURITY_ERROR_ENUM */
/* clang-format on */

View file

@ -10,6 +10,7 @@
#include "ssl.h"
#include "sslerr.h"
#include "pk11hpke.h"
SEC_BEGIN_PROTOS
@ -254,7 +255,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 +382,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
@ -497,62 +503,137 @@ typedef SECStatus(PR_CALLBACK *SSLResumptionTokenCallback)(
(PRFileDesc * _fd, PRUint32 _size), \
(fd, size))
/* Set the ESNI key pair on a socket (server side)
/* Client:
* If |enabled|, a GREASE ECH extension will be sent in every ClientHello,
* unless a valid and supported ECHConfig is configured to the socket
* (in which case real ECH takes precedence). If |!enabled|, it is not sent.
*
* fd -- the socket
* record/recordLen -- the encoded DNS record (not base64)
*
* Important: the suites that are advertised in the record must
* be configured on, or this call will fail.
* Server:
* If |enabled|, a GREASE ECH extensions will be sent in every HelloRetryRequest,
* provided that the corresponding ClientHello contained an ECH extension. If ECH
* is enabled, the real ECH HRR extension takes precedence.
*/
#define SSL_SetESNIKeyPair(fd, \
privKey, record, recordLen) \
SSL_EXPERIMENTAL_API("SSL_SetESNIKeyPair", \
(PRFileDesc * _fd, \
SECKEYPrivateKey * _privKey, \
const PRUint8 *_record, unsigned int _recordLen), \
(fd, privKey, \
record, recordLen))
/* Set the ESNI keys on a client
*
* fd -- the socket
* ensikeys/esniKeysLen -- the ESNI key structure (not base64)
* dummyESNI -- the dummy ESNI to use (if any)
*/
#define SSL_EnableESNI(fd, esniKeys, esniKeysLen, dummySNI) \
SSL_EXPERIMENTAL_API("SSL_EnableESNI", \
(PRFileDesc * _fd, \
const PRUint8 *_esniKeys, \
unsigned int _esniKeysLen, \
const char *_dummySNI), \
(fd, esniKeys, esniKeysLen, dummySNI))
#define SSL_EnableTls13GreaseEch(fd, enabled) \
SSL_EXPERIMENTAL_API("SSL_EnableTls13GreaseEch", \
(PRFileDesc * _fd, PRBool _enabled), (fd, enabled))
/*
* Generate an encoded ESNIKeys structure (presumably server side).
* Client:
* When sending a GREASE ECH extension in a ClientHello, pad it as though the
* hypothetical ECHConfig had |maximum_name_length| equal to |size|. |size| may
* vary between 1 and 255 and defaults to 100.
*
* cipherSuites -- the cipher suites that can be used
* cipherSuitesCount -- the number of suites in cipherSuites
* group -- the named group this key corresponds to
* Server:
* Has no effect.
*/
#define SSL_SetTls13GreaseEchSize(fd, size) \
SSL_EXPERIMENTAL_API("SSL_SetTls13GreaseEchSize", \
(PRFileDesc * _fd, PRUint8 _size), (fd, size))
/* If |enabled|, a server receiving a Client Hello containing an encrypted_client_hello
* of type inner will respond with the ECH
* acceptance signal. This signals the client to continue with the inner
* transcript rather than outer. */
#define SSL_EnableTls13BackendEch(fd, enabled) \
SSL_EXPERIMENTAL_API("SSL_EnableTls13BackendEch", \
(PRFileDesc * _fd, PRBool _enabled), (fd, enabled))
/* This allows an extension writer to supply different values for inner and
* outer ClientHello when using encrypted ClientHello.
*
* When enabled, each extension writer can be called more than once for the same
* message; it must provide the same response when called for the same message
* type. When calling the writer to construct the outer ClientHello, the
* function will be called with ssl_hs_ech_outer_client_hello as the message
* type (a value from outside the range of valid TLS handshake messages).
*
* When disabled, the extension writer is called once for the outer ClientHello
* and the value is copied to the inner ClientHello.
*
* Enabling this affects all extension writers. The order in which extension
* writers are added is also important. Any extension writer that writes
* different values for inner and outer ClientHello will prevent later
* extensions from being compressed.
*/
#define SSL_CallExtensionWriterOnEchInner(fd, enabled) \
SSL_EXPERIMENTAL_API("SSL_CallExtensionWriterOnEchInner", \
(PRFileDesc * _fd, PRBool _enabled), (fd, enabled))
/* Called by the client after an initial ECH connection fails with
* SSL_ERROR_ECH_RETRY_WITH_ECH. Returns compatible ECHConfigs, which
* are configured via SetClientEchConfigs for an ECH retry attempt.
* These configs MUST NOT be used for more than the single retry
* attempt. Subsequent connections MUST use advertised ECHConfigs. */
#define SSL_GetEchRetryConfigs(fd, out) \
SSL_EXPERIMENTAL_API("SSL_GetEchRetryConfigs", \
(PRFileDesc * _fd, \
SECItem * _out), \
(fd, out))
/* Called to remove all ECHConfigs from a socket (fd). */
#define SSL_RemoveEchConfigs(fd) \
SSL_EXPERIMENTAL_API("SSL_RemoveEchConfigs", \
(PRFileDesc * _fd), \
(fd))
/* Set the ECHConfig and key pair on a socket (server side)
*
* fd -- the socket
* pubKey -- the server's SECKEYPublicKey for HPKE/ECH.
* privateKey -- the server's SECKEYPrivateKey for HPKE/ECH.
* record/recordLen -- the encoded DNS record (not base64)
*/
#define SSL_SetServerEchConfigs(fd, pubKey, \
privKey, record, recordLen) \
SSL_EXPERIMENTAL_API("SSL_SetServerEchConfigs", \
(PRFileDesc * _fd, \
const SECKEYPublicKey *_pubKey, \
const SECKEYPrivateKey *_privKey, \
const PRUint8 *_record, unsigned int _recordLen), \
(fd, pubKey, privKey, \
record, recordLen))
/* Set ECHConfig(s) on a client. The first supported ECHConfig will be used.
*
* fd -- the socket
* echConfigs/echConfigsLen -- the ECHConfigs structure (not base64)
*/
#define SSL_SetClientEchConfigs(fd, echConfigs, echConfigsLen) \
SSL_EXPERIMENTAL_API("SSL_SetClientEchConfigs", \
(PRFileDesc * _fd, \
const PRUint8 *_echConfigs, \
unsigned int _echConfigsLen), \
(fd, echConfigs, echConfigsLen))
/*
* Generate an encoded ECHConfig structure (presumably server side).
*
* configId -- an identifier for the configuration.
* publicName -- the public_name value to be placed in SNI.
* maxNameLen -- the maximum length of protected names
* kemId -- the HKPE KEM ID value
* pubKey -- the public key for the key pair
* pad -- the length to pad to
* notBefore/notAfter -- validity range in seconds since epoch
* hpkeSuites -- the HPKE cipher suites that can be used
* hpkeSuitesCount -- the number of suites in hpkeSuites
* out/outlen/maxlen -- where to output the data
*/
#define SSL_EncodeESNIKeys(cipherSuites, cipherSuiteCount, \
group, pubKey, pad, notBefore, notAfter, \
out, outlen, maxlen) \
SSL_EXPERIMENTAL_API("SSL_EncodeESNIKeys", \
(PRUint16 * _cipherSuites, \
unsigned int _cipherSuiteCount, \
SSLNamedGroup _group, \
SECKEYPublicKey *_pubKey, \
PRUint16 _pad, \
PRUint64 _notBefore, PRUint64 _notAfter, \
PRUint8 *_out, unsigned int *_outlen, \
unsigned int _maxlen), \
(cipherSuites, cipherSuiteCount, \
group, pubKey, pad, notBefore, notAfter, \
typedef struct HpkeSymmetricSuiteStr {
HpkeKdfId kdfId;
HpkeAeadId aeadId;
} HpkeSymmetricSuite;
#define SSL_EncodeEchConfigId(configId, publicName, maxNameLen, \
kemId, pubKey, hpkeSuites, hpkeSuiteCount, \
out, outlen, maxlen) \
SSL_EXPERIMENTAL_API("SSL_EncodeEchConfigId", \
(PRUint8 _configId, const char *_publicName, \
unsigned int _maxNameLen, HpkeKemId _kemId, \
const SECKEYPublicKey *_pubKey, \
const HpkeSymmetricSuite *_hpkeSuites, \
unsigned int _hpkeSuiteCount, \
PRUint8 *_out, unsigned int *_outlen, \
unsigned int _maxlen), \
(configId, publicName, maxNameLen, \
kemId, pubKey, hpkeSuites, hpkeSuiteCount, \
out, outlen, maxlen))
/* SSL_SetSecretCallback installs a callback that TLS calls when it installs new
@ -662,7 +743,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 +761,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 +813,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 +831,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 +867,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,10 +962,125 @@ 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
#define SSL_InitAntiReplay(a, b, c) SSL_DEPRECATED_EXPERIMENTAL_API
#define SSL_EnableESNI(a, b, c, d) SSL_DEPRECATED_EXPERIMENTAL_API
#define SSL_EncodeESNIKeys(a, b, c, d, e, f, g, h, i, j) SSL_DEPRECATED_EXPERIMENTAL_API
#define SSL_SetESNIKeyPair(a, b, c, d) SSL_DEPRECATED_EXPERIMENTAL_API
#define SSL_EncodeEchConfig(a, b, c, d, e, f, g, h, i) SSL_DEPRECATED_EXPERIMENTAL_API
SEC_END_PROTOS

View file

@ -24,7 +24,7 @@
#include "hasht.h"
#include "nssilock.h"
#include "pkcs11t.h"
#if defined(XP_UNIX) || defined(XP_BEOS)
#if defined(XP_UNIX)
#include "unistd.h"
#endif
#include "nssrwlk.h"
@ -36,7 +36,11 @@
typedef struct sslSocketStr sslSocket;
typedef struct sslNamedGroupDefStr sslNamedGroupDef;
typedef struct sslEsniKeysStr sslEsniKeys;
typedef struct sslEchConfigStr sslEchConfig;
typedef struct sslEchConfigContentsStr sslEchConfigContents;
typedef struct sslEchCookieDataStr sslEchCookieData;
typedef struct sslEchXtnStateStr sslEchXtnState;
typedef struct sslPskStr sslPsk;
typedef struct sslDelegatedCredentialStr sslDelegatedCredential;
typedef struct sslEphemeralKeyPairStr sslEphemeralKeyPair;
typedef struct TLS13KeyShareEntryStr TLS13KeyShareEntry;
@ -236,7 +240,7 @@ typedef struct {
#endif
} ssl3CipherSuiteCfg;
#define ssl_V3_SUITES_IMPLEMENTED 75
#define ssl_V3_SUITES_IMPLEMENTED 71
#define MAX_DTLS_SRTP_CIPHER_SUITES 4
@ -281,6 +285,13 @@ typedef struct sslOptionsStr {
unsigned int enableV2CompatibleHello : 1;
unsigned int enablePostHandshakeAuth : 1;
unsigned int enableDelegatedCredentials : 1;
unsigned int enableDtls13VersionCompat : 1;
unsigned int suppressEndOfEarlyData : 1;
unsigned int enableTls13GreaseEch : 1;
unsigned int enableTls13BackendEch : 1;
unsigned int callExtensionWriterOnEchInner : 1;
unsigned int enableGrease : 1;
unsigned int enableChXtnPermutation : 1;
} sslOptions;
typedef enum { sslHandshakingUndetermined = 0,
@ -601,6 +612,24 @@ typedef struct {
PRUint32 timeout;
} dtlsTimer;
/* TLS 1.3 client GREASE entry indices. */
typedef enum {
grease_cipher,
grease_extension1,
grease_extension2,
grease_group,
grease_sigalg,
grease_version,
grease_alpn,
grease_entries
} tls13ClientGreaseEntry;
/* TLS 1.3 client GREASE values struct. */
typedef struct tls13ClientGreaseStr {
PRUint16 idx[grease_entries];
PRUint8 pskKem;
} tls13ClientGrease;
/*
** This is the "hs" member of the "ssl3" struct.
** This entire struct is protected by ssl3HandshakeLock
@ -608,17 +637,26 @@ typedef struct {
typedef struct SSL3HandshakeStateStr {
SSL3Random server_random;
SSL3Random client_random;
SSL3WaitState ws; /* May also contain SSL3WaitState | 0x80 for TLS 1.3 */
SSL3Random client_inner_random; /* TLS 1.3 ECH Inner. */
SSL3WaitState ws; /* May also contain SSL3WaitState | 0x80 for TLS 1.3 */
/* This group of members is used for handshake running hashes. */
SSL3HandshakeHashType hashType;
sslBuffer messages; /* Accumulated handshake messages */
sslBuffer messages; /* Accumulated handshake messages */
sslBuffer echInnerMessages; /* Accumulated ECH Inner handshake messages */
/* PKCS #11 mode:
* SSL 3.0 - TLS 1.1 use both |md5| and |sha|. |md5| is used for MD5 and
* |sha| for SHA-1.
* TLS 1.2 and later use only |sha|, for SHA-256. */
* TLS 1.2 and later use only |sha| variants, for SHA-256.
* Under normal (non-1.3 ECH) handshakes, only |sha| and |shaPostHandshake|
* are used. When doing 1.3 ECH, |sha| contains the transcript hash
* corresponding to the outer Client Hello. To facilitate secure retry and
* disablement, |shaEchInner|, tracks, in parallel, the transcript hash
* corresponding to the inner Client Hello. Once we process the SH
* extensions, coalesce into |sha|. */
PK11Context *md5;
PK11Context *sha;
PK11Context *shaEchInner;
PK11Context *shaPostHandshake;
SSLSignatureScheme signatureScheme;
const ssl3KEADef *kea_def;
@ -648,20 +686,25 @@ typedef struct SSL3HandshakeStateStr {
PRUint8 data[72];
} finishedMsgs;
/* True when handshake is blocked on client certificate selection */
PRBool clientCertificatePending;
/* Parameters stored whilst waiting for client certificate */
SSLSignatureScheme *clientAuthSignatureSchemes;
unsigned int clientAuthSignatureSchemesLen;
PRBool authCertificatePending;
/* Which function should SSL_RestartHandshake* call if we're blocked?
* 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. */
PRUint32 preliminaryInfo;
/* Parsed extensions */
PRCList remoteExtensions; /* Parsed incoming extensions */
PRCList remoteExtensions; /* Parsed incoming extensions */
PRCList echOuterExtensions; /* If ECH, hold CHOuter extensions for decompression. */
/* This group of values is used for DTLS */
PRUint16 sendMessageSeq; /* The sending message sequence
@ -689,9 +732,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. */
@ -712,23 +754,47 @@ typedef struct SSL3HandshakeStateStr {
* 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). */
PRCList psks; /* A list of PSKs, resumption and/or external. */
/* 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. */
/* TLS 1.3 ECH state. */
PRUint8 greaseEchSize;
PRBool echAccepted; /* Client/Server: True if we've commited to using CHInner. */
PRBool echDecided;
HpkeContext *echHpkeCtx; /* Client/Server: HPKE context for ECH. */
const char *echPublicName; /* Client: If rejected, the ECHConfig.publicName to
* use for certificate verification. */
sslBuffer greaseEchBuf; /* Client: Remember GREASE ECH, as advertised, for CH2 (HRR case).
Server: Remember HRR Grease Value, for transcript calculations */
PRBool echInvalidExtension; /* Client: True if the server offered an invalid extension for the ClientHelloInner */
/* TLS 1.3 GREASE state. */
tls13ClientGrease *grease;
/* ClientHello Extension Permutation state. */
sslExtensionBuilder *chExtensionPermutation;
} SSL3HandshakeState;
#define SSL_ASSERT_HASHES_EMPTY(ss) \
do { \
PORT_Assert(ss->ssl3.hs.hashType == handshake_hash_unknown); \
PORT_Assert(ss->ssl3.hs.messages.len == 0); \
PORT_Assert(ss->ssl3.hs.echInnerMessages.len == 0); \
} while (0)
/*
@ -811,7 +877,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. */
@ -1094,16 +1160,17 @@ struct sslSocketStr {
/* Whether we are doing stream or datagram mode */
SSLProtocolVariant protocolVariant;
/* The information from the ESNI keys record
* (also the private key for the server). */
sslEsniKeys *esniKeys;
/* TLS 1.3 Encrypted Client Hello. */
PRCList echConfigs; /* Client/server: Must not change while hs
* is in-progress. */
SECKEYPublicKey *echPubKey; /* Server: The ECH keypair used in HPKE. */
SECKEYPrivateKey *echPrivKey; /* As above. */
/* Anti-replay for TLS 1.3 0-RTT. */
SSLAntiReplayContext *antiReplay;
/* peer data passed in during getClientAuthData */
const SSLSignatureScheme *peerSignatureSchemes;
unsigned int peerSignatureSchemeCount;
/* An out-of-band PSK. */
sslPsk *psk;
};
struct sslSelfEncryptKeysStr {
@ -1227,7 +1294,7 @@ extern void ssl3_SetAlwaysBlock(sslSocket *ss);
extern SECStatus ssl_EnableNagleDelay(sslSocket *ss, PRBool enabled);
extern void ssl_FinishHandshake(sslSocket *ss);
extern SECStatus ssl_FinishHandshake(sslSocket *ss);
extern SECStatus ssl_CipherPolicySet(PRInt32 which, PRInt32 policy);
@ -1256,6 +1323,10 @@ ssl_HashHandshakeMessageInt(sslSocket *ss, SSLHandshakeType type,
sslUpdateHandshakeHashes cb);
SECStatus ssl_HashHandshakeMessage(sslSocket *ss, SSLHandshakeType type,
const PRUint8 *b, PRUint32 length);
SECStatus ssl_HashHandshakeMessageEchInner(sslSocket *ss, SSLHandshakeType type,
const PRUint8 *b, PRUint32 length);
SECStatus ssl_HashHandshakeMessageDefault(sslSocket *ss, SSLHandshakeType type,
const PRUint8 *b, PRUint32 length);
SECStatus ssl_HashPostHandshakeMessage(sslSocket *ss, SSLHandshakeType type,
const PRUint8 *b, PRUint32 length);
@ -1425,6 +1496,7 @@ extern SECStatus SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level,
extern SECStatus ssl3_DecodeError(sslSocket *ss);
extern SECStatus ssl3_AuthCertificateComplete(sslSocket *ss, PRErrorCode error);
extern SECStatus ssl3_ClientCertCallbackComplete(sslSocket *ss, SECStatus outcome, SECKEYPrivateKey *clientPrivateKey, CERTCertificate *clientCertificate);
/*
* for dealing with SSL 3.0 clients sending SSL 2.0 format hellos
@ -1432,6 +1504,11 @@ extern SECStatus ssl3_AuthCertificateComplete(sslSocket *ss, PRErrorCode error);
extern SECStatus ssl3_HandleV2ClientHello(
sslSocket *ss, unsigned char *buffer, unsigned int length, PRUint8 padding);
SECStatus
ssl3_CreateClientHelloPreamble(sslSocket *ss, const sslSessionID *sid,
PRBool realSid, PRUint16 version, PRBool isEchInner,
const sslBuffer *extensions, sslBuffer *preamble);
SECStatus ssl3_InsertChHeaderSize(const sslSocket *ss, sslBuffer *preamble, const sslBuffer *extensions);
SECStatus ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type);
/*
@ -1673,6 +1750,7 @@ SECStatus ssl3_NegotiateCipherSuiteInner(sslSocket *ss, const SECItem *suites,
SECStatus ssl3_NegotiateCipherSuite(sslSocket *ss, const SECItem *suites,
PRBool initHashes);
SECStatus ssl3_InitHandshakeHashes(sslSocket *ss);
void ssl3_CoalesceEchHandshakeHashes(sslSocket *ss);
SECStatus ssl3_ServerCallSNICallback(sslSocket *ss);
SECStatus ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags);
SECStatus ssl3_CompleteHandleCertificate(sslSocket *ss,
@ -1687,15 +1765,21 @@ 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,
sslBuffer *buf);
SECStatus ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRBool forCert,
PRBool grease, sslBuffer *buf);
SECStatus ssl3_EncodeFilteredSigAlgs(const sslSocket *ss,
const SSLSignatureScheme *schemes,
PRUint32 numSchemes, PRBool grease, 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,
unsigned int *nnamesp);
SECStatus ssl3_ParseCertificateRequestCAs(sslSocket *ss, PRUint8 **b,
PRUint32 *length, CERTDistNames *ca_list);
SECStatus ssl3_CompleteHandleCertificateRequest(
SECStatus ssl3_BeginHandleCertificateRequest(
sslSocket *ss, const SSLSignatureScheme *signatureSchemes,
unsigned int signatureSchemeCount, CERTDistNames *ca_list);
SECStatus ssl_ConstructServerHello(sslSocket *ss, PRBool helloRetry,
@ -1713,6 +1797,7 @@ SECStatus ssl_CreateECDHEphemeralKeyPair(const sslSocket *ss,
SECStatus ssl_CreateStaticECDHEKey(sslSocket *ss,
const sslNamedGroupDef *ecGroup);
SECStatus ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags);
SECStatus ssl3_GetNewRandom(SSL3Random random);
PK11SymKey *ssl3_GetWrappingKey(sslSocket *ss,
PK11SlotInfo *masterSecretSlot,
CK_MECHANISM_TYPE masterWrapMech,
@ -1745,6 +1830,7 @@ SECStatus ssl_PickClientSignatureScheme(sslSocket *ss,
unsigned int numSchemes,
SSLSignatureScheme *schemePtr);
SECOidTag ssl3_HashTypeToOID(SSLHashType hashType);
SECOidTag ssl3_AuthTypeToOID(SSLAuthType hashType);
SSLHashType ssl_SignatureSchemeToHashType(SSLSignatureScheme scheme);
SSLAuthType ssl_SignatureSchemeToAuthType(SSLSignatureScheme scheme);
@ -1809,6 +1895,9 @@ PK11SymKey *ssl_unwrapSymKey(PK11SymKey *wrapKey,
CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
int keySize, CK_FLAGS keyFlags, void *pinArg);
/* determine if the current ssl connection is operating in FIPS mode */
PRBool ssl_isFIPS(sslSocket *ss);
/* Experimental APIs. Remove when stable. */
SECStatus SSLExp_SetResumptionTokenCallback(PRFileDesc *fd,
@ -1838,6 +1927,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,
@ -1854,18 +1947,68 @@ 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);
SECStatus SSLExp_EnableTls13GreaseEch(PRFileDesc *fd, PRBool enabled);
SECStatus SSLExp_SetTls13GreaseEchSize(PRFileDesc *fd, PRUint8 size);
SECStatus SSLExp_EnableTls13BackendEch(PRFileDesc *fd, PRBool enabled);
SECStatus SSLExp_CallExtensionWriterOnEchInner(PRFileDesc *fd, PRBool enabled);
SEC_END_PROTOS
#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
#if defined(XP_UNIX) || defined(XP_OS2)
#define SSL_GETPID getpid
#elif defined(WIN32)
extern int __cdecl _getpid(void);

View file

@ -7,6 +7,7 @@
#include "sslimpl.h"
#include "sslproto.h"
#include "tls13hkdf.h"
#include "tls13psk.h"
#include "tls13subcerts.h"
SECStatus
@ -80,7 +81,15 @@ 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);
inf.echAccepted = ss->ssl3.hs.echAccepted;
if (sid) {
unsigned int sidLen;
@ -101,6 +110,7 @@ SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len)
sidLen = PR_MIN(sidLen, sizeof inf.sessionID);
inf.sessionIDLength = sidLen;
memcpy(inf.sessionID, sid->u.ssl3.sessionID, sidLen);
inf.isFIPS = ssl_isFIPS(ss);
}
}
@ -132,6 +142,7 @@ SSL_GetPreliminaryChannelInfo(PRFileDesc *fd,
return SECFailure;
}
/* All fields MUST be zero initialized! */
memset(&inf, 0, sizeof(inf));
inf.length = PR_MIN(sizeof(inf), len);
@ -144,19 +155,32 @@ SSL_GetPreliminaryChannelInfo(PRFileDesc *fd,
/* We shouldn't be able to send early data if the handshake is done. */
PORT_Assert(!ss->firstHsDone || !inf.canSendEarlyData);
if (ss->sec.ci.sid &&
(ss->ssl3.hs.zeroRttState == ssl_0rtt_sent ||
ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted)) {
inf.maxEarlyDataSize =
if (ss->sec.ci.sid) {
PRUint32 ticketMaxEarlyData =
ss->sec.ci.sid->u.ssl3.locked.sessionTicket.max_early_data_size;
} else {
inf.maxEarlyDataSize = 0;
/* Resumption token info. */
inf.ticketSupportsEarlyData = (ticketMaxEarlyData > 0);
if (ss->ssl3.hs.zeroRttState == ssl_0rtt_sent ||
ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) {
if (ss->statelessResume) {
inf.maxEarlyDataSize = ticketMaxEarlyData;
} 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;
}
}
}
inf.zeroRttCipherSuite = ss->ssl3.hs.zeroRttSuite;
inf.peerDelegCred = tls13_IsVerifyingWithDelegatedCredential(ss);
inf.authKeyBits = ss->sec.authKeyBits;
inf.signatureScheme = ss->sec.signatureScheme;
inf.echAccepted = ss->ssl3.hs.echAccepted;
/* Only expose this if the application should use it for verification. */
inf.echPublicName = (inf.echAccepted == PR_FALSE) ? ss->ssl3.hs.echPublicName : NULL;
memcpy(info, &inf, inf.length);
return SECSuccess;
@ -300,10 +324,8 @@ static const SSLCipherSuiteInfo suiteInfo[] = {
{ 0, CS(ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA), S_ECDSA, K_ECDHE, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_ECDSA, ssl_hash_none },
{ 0, CS(ECDHE_ECDSA_WITH_AES_128_CBC_SHA), S_ECDSA, K_ECDHE, C_AES, B_128, M_SHA, F_FIPS_STD, A_ECDSA, ssl_hash_none },
{ 0, CS(ECDHE_ECDSA_WITH_AES_128_CBC_SHA256), S_ECDSA, K_ECDHE, C_AES, B_128, M_SHA256, F_FIPS_STD, A_ECDSA, ssl_hash_sha256 },
{ 0, CS(ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256), S_ECDSA, K_ECDHE, C_CAMELLIA, B_128, M_SHA256, F_NFIPS_STD, A_ECDSA, ssl_hash_sha256 },
{ 0, CS(ECDHE_ECDSA_WITH_AES_256_CBC_SHA), S_ECDSA, K_ECDHE, C_AES, B_256, M_SHA, F_FIPS_STD, A_ECDSA, ssl_hash_none },
{ 0, CS(ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256), S_ECDSA, K_ECDHE, C_CHACHA20, B_256, M_AEAD_128, F_NFIPS_STD, A_ECDSA, ssl_hash_sha256 },
{ 0, CS(ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384), S_ECDSA, K_ECDHE, C_CAMELLIA, B_256, M_SHA384, F_NFIPS_STD, A_ECDSA, ssl_hash_sha384 },
{ 0, CS(ECDH_RSA_WITH_NULL_SHA), S_RSA, K_ECDH, C_NULL, B_0, M_SHA, F_NFIPS_STD, A_ECDH_R, ssl_hash_none },
{ 0, CS(ECDH_RSA_WITH_RC4_128_SHA), S_RSA, K_ECDH, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_ECDH_R, ssl_hash_none },
@ -316,14 +338,12 @@ static const SSLCipherSuiteInfo suiteInfo[] = {
{ 0, CS(ECDHE_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_ECDHE, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_RSAS, ssl_hash_none },
{ 0, CS(ECDHE_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_ECDHE, C_AES, B_128, M_SHA, F_FIPS_STD, A_RSAS, ssl_hash_none },
{ 0, CS(ECDHE_RSA_WITH_AES_128_CBC_SHA256), S_RSA, K_ECDHE, C_AES, B_128, M_SHA256, F_FIPS_STD, A_RSAS, ssl_hash_sha256 },
{ 0, CS(ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256), S_RSA, K_ECDHE, C_CAMELLIA, B_128, M_SHA256, F_NFIPS_STD, A_RSAS, ssl_hash_sha256 },
{ 0, CS(ECDHE_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_ECDHE, C_AES, B_256, M_SHA, F_FIPS_STD, A_RSAS, ssl_hash_none },
{ 0, CS(ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256), S_RSA, K_ECDHE, C_CHACHA20, B_256, M_AEAD_128, F_NFIPS_STD, A_RSAS, ssl_hash_sha256 },
{ 0, CS(ECDHE_RSA_WITH_AES_256_CBC_SHA384), S_RSA, K_ECDHE, C_AES, B_256, M_SHA384, F_FIPS_STD, A_RSAS, ssl_hash_sha384 },
{ 0, CS(ECDHE_ECDSA_WITH_AES_256_CBC_SHA384), S_ECDSA, K_ECDHE, C_AES, B_256, M_SHA384, F_FIPS_STD, A_ECDSA, ssl_hash_sha384 },
{ 0, CS(ECDHE_ECDSA_WITH_AES_256_GCM_SHA384), S_ECDSA, K_ECDHE, C_AESGCM, B_256, M_AEAD_128, F_FIPS_STD, A_ECDSA, ssl_hash_sha384 },
{ 0, CS(ECDHE_RSA_WITH_AES_256_GCM_SHA384), S_RSA, K_ECDHE, C_AESGCM, B_256, M_AEAD_128, F_FIPS_STD, A_RSAS, ssl_hash_sha384 },
{ 0, CS(ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384), S_RSA, K_ECDHE, C_CAMELLIA, B_256, M_SHA384, F_NFIPS_STD, A_RSAS, ssl_hash_sha384 },
{ 0, CS(DHE_DSS_WITH_AES_256_GCM_SHA384), S_DSA, K_DHE, C_AESGCM, B_256, M_AEAD_128, F_FIPS_STD, A_DSA, ssl_hash_sha384 },
{ 0, CS(DHE_RSA_WITH_AES_256_GCM_SHA384), S_RSA, K_DHE, C_AESGCM, B_256, M_AEAD_128, F_FIPS_STD, A_RSAS, ssl_hash_sha384 },
@ -419,24 +439,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;
}

View file

@ -4,7 +4,7 @@
#include "seccomon.h"
/* This ifdef should match the one in sslsnce.c */
#if defined(XP_UNIX) || defined(XP_WIN32) || defined(XP_OS2) || defined(XP_BEOS)
#if defined(XP_UNIX) || defined(XP_WIN32) || defined(XP_OS2)
#include "sslmutex.h"
#include "prerr.h"
@ -60,7 +60,7 @@ single_process_sslMutex_Lock(sslMutex* pMutex)
return SECSuccess;
}
#if defined(LINUX) || defined(AIX) || defined(BEOS) || defined(BSDI) || \
#if defined(LINUX) || defined(AIX) || defined(BSDI) || \
(defined(NETBSD) && __NetBSD_Version__ < 500000000) || defined(OPENBSD) || defined(__GLIBC__)
#include <unistd.h>
@ -350,8 +350,7 @@ sslMutex_Init(sslMutex *pMutex, int shared)
SECStatus retvalue;
#endif
HANDLE hMutex;
SECURITY_ATTRIBUTES attributes =
{ sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
SECURITY_ATTRIBUTES attributes = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
PR_ASSERT(pMutex != 0 && (pMutex->u.sslMutx == 0 ||
pMutex->u.sslMutx ==
@ -504,7 +503,7 @@ sslMutex_Lock(sslMutex *pMutex)
case WAIT_IO_COMPLETION:
#endif
default: /* should never happen. nothing we can do. */
PR_ASSERT(!("WaitForSingleObject returned invalid value."));
PR_ASSERT(PR_FALSE && "WaitForSingleObject returned invalid value.");
PORT_SetError(PR_UNKNOWN_ERROR);
rv = SECFailure;
break;
@ -613,7 +612,7 @@ sslMutex_Init(sslMutex* pMutex, int shared)
if (!shared) {
return single_process_sslMutex_Init(pMutex);
}
PORT_Assert(!("sslMutex_Init not implemented for multi-process applications !"));
PORT_Assert(PR_FALSE && "sslMutex_Init not implemented for multi-process applications !");
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
return SECFailure;
}
@ -625,7 +624,7 @@ sslMutex_Destroy(sslMutex* pMutex, PRBool processLocal)
if (PR_FALSE == pMutex->isMultiProcess) {
return single_process_sslMutex_Destroy(pMutex);
}
PORT_Assert(!("sslMutex_Destroy not implemented for multi-process applications !"));
PORT_Assert(PR_FALSE && "sslMutex_Destroy not implemented for multi-process applications !");
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
return SECFailure;
}
@ -637,7 +636,7 @@ sslMutex_Unlock(sslMutex* pMutex)
if (PR_FALSE == pMutex->isMultiProcess) {
return single_process_sslMutex_Unlock(pMutex);
}
PORT_Assert(!("sslMutex_Unlock not implemented for multi-process applications !"));
PORT_Assert(PR_FALSE && "sslMutex_Unlock not implemented for multi-process applications !");
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
return SECFailure;
}
@ -649,7 +648,7 @@ sslMutex_Lock(sslMutex* pMutex)
if (PR_FALSE == pMutex->isMultiProcess) {
return single_process_sslMutex_Lock(pMutex);
}
PORT_Assert(!("sslMutex_Lock not implemented for multi-process applications !"));
PORT_Assert(PR_FALSE && "sslMutex_Lock not implemented for multi-process applications !");
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
return SECFailure;
}

View file

@ -49,7 +49,7 @@ typedef struct {
typedef int sslPID;
#elif defined(LINUX) || defined(AIX) || defined(BEOS) || defined(BSDI) || \
#elif defined(LINUX) || defined(AIX) || defined(BSDI) || \
(defined(NETBSD) && __NetBSD_Version__ < 500000000) || defined(OPENBSD) || defined(__GLIBC__)
#include <sys/types.h>

View file

@ -16,7 +16,7 @@
#include "sslproto.h"
#include "nssilock.h"
#include "sslencode.h"
#if defined(XP_UNIX) || defined(XP_WIN) || defined(_WINDOWS) || defined(XP_BEOS)
#if defined(XP_UNIX) || defined(XP_WIN) || defined(_WINDOWS)
#include <time.h>
#endif
@ -528,7 +528,9 @@ ssl_DecodeResumptionToken(sslSessionID *sid, const PRUint8 *encodedToken,
}
SECItem tempItem = { siBuffer, (unsigned char *)readerBuffer.buf,
readerBuffer.len };
SECITEM_CopyItem(NULL, &sid->peerCertStatus.items[0], &tempItem);
if (SECITEM_CopyItem(NULL, &sid->peerCertStatus.items[0], &tempItem) != SECSuccess) {
return SECFailure;
}
}
if (sslRead_ReadVariable(&reader, 1, &readerBuffer) != SECSuccess) {
@ -540,7 +542,11 @@ ssl_DecodeResumptionToken(sslSessionID *sid, const PRUint8 *encodedToken,
if (sid->peerID) {
PORT_Free((void *)sid->peerID);
}
sid->peerID = PORT_Strdup((const char *)readerBuffer.buf);
sid->peerID = PORT_ZAlloc(readerBuffer.len + 1);
if (!sid->peerID) {
return SECFailure;
}
PORT_Memcpy((void *)sid->peerID, readerBuffer.buf, readerBuffer.len);
}
if (sslRead_ReadVariable(&reader, 1, &readerBuffer) != SECSuccess) {
@ -552,7 +558,11 @@ ssl_DecodeResumptionToken(sslSessionID *sid, const PRUint8 *encodedToken,
PORT_Free((void *)sid->urlSvrName);
}
PORT_Assert(readerBuffer.buf);
sid->urlSvrName = PORT_Strdup((const char *)readerBuffer.buf);
sid->urlSvrName = PORT_ZAlloc(readerBuffer.len + 1);
if (!sid->urlSvrName) {
return SECFailure;
}
PORT_Memcpy((void *)sid->urlSvrName, readerBuffer.buf, readerBuffer.len);
}
if (sslRead_ReadVariable(&reader, 3, &readerBuffer) != SECSuccess) {
@ -566,6 +576,9 @@ ssl_DecodeResumptionToken(sslSessionID *sid, const PRUint8 *encodedToken,
sid->localCert = CERT_NewTempCertificate(NULL, /* dbHandle */
&tempItem,
NULL, PR_FALSE, PR_TRUE);
if (!sid->localCert) {
return SECFailure;
}
}
if (sslRead_ReadNumber(&reader, 8, &sid->addr.pr_s6_addr64[0]) != SECSuccess) {
@ -1123,12 +1136,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;
}

View file

@ -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
@ -255,6 +255,18 @@ SSLExp_HkdfExpandLabelWithMech(PRUint16 version, PRUint16 cipherSuite, PK11SymKe
const char *label, unsigned int labelLen,
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 ||
@ -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);
}

View file

@ -31,7 +31,7 @@
/* The DTLS versions used in the spec */
#define SSL_LIBRARY_VERSION_DTLS_1_0_WIRE ((~0x0100) & 0xffff)
#define SSL_LIBRARY_VERSION_DTLS_1_2_WIRE ((~0x0102) & 0xffff)
#define SSL_LIBRARY_VERSION_DTLS_1_3_WIRE SSL_LIBRARY_VERSION_DTLS_1_3
#define SSL_LIBRARY_VERSION_DTLS_1_3_WIRE ((~0x0103) & 0xffff)
/* Certificate types */
#define SSL_CT_X509_CERTIFICATE 0x01
@ -199,12 +199,6 @@
#define TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 0xC030
#define TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 0xC031
/* RFC 6367 2.1 HMAC, ephemeral only */
#define TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 0xC072
#define TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 0xC073
#define TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 0xC076
#define TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 0xC077
/* draft-ietf-tls-chacha20-poly1305-04 */
#define TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 0xCCA8
#define TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 0xCCA9

View file

@ -15,6 +15,8 @@
#include "pk11func.h" /* for PK11_GenerateRandom */
#include "nss.h" /* for NSS_RegisterShutdown */
#include "prinit.h" /* for PR_CallOnceWithArg */
#include "tls13ech.h"
#include "tls13psk.h"
/* Step through the handshake functions.
*
@ -48,11 +50,34 @@ ssl_Do1stHandshake(sslSocket *ss)
return rv;
}
void
SECStatus
ssl_FinishHandshake(sslSocket *ss)
{
PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->ssl3.hs.echAccepted ||
(ss->opt.enableTls13BackendEch &&
ss->xtnData.ech &&
ss->xtnData.ech->receivedInnerXtn) ==
ssl3_ExtensionNegotiated(ss, ssl_tls13_encrypted_client_hello_xtn));
/* If ECH was OFFERED to (echHpkeCtx is set on the client) DISABLED by the
* server through negotiation of a TLS version < 1.3, an 'ech_required'
* alert MUST be sent to inform the server about the intention / possible
* misconfiguration. */
if (!ss->sec.isServer && ss->ssl3.hs.echHpkeCtx && !ss->ssl3.hs.echAccepted) {
SSL3_SendAlert(ss, alert_fatal, ech_required);
/* "If [one, none] of the retry_configs contains a supported version,
* the client can regard ECH as securely [replaced, disabled] by the
* server." */
if (ss->xtnData.ech && ss->xtnData.ech->retryConfigs.len) {
PORT_SetError(SSL_ERROR_ECH_RETRY_WITH_ECH);
ss->xtnData.ech->retryConfigsValid = PR_TRUE;
} else {
PORT_SetError(SSL_ERROR_ECH_RETRY_WITHOUT_ECH);
}
return SECFailure;
}
SSL_TRC(3, ("%d: SSL[%d]: handshake is completed", SSL_GETPID(), ss->fd));
@ -68,6 +93,8 @@ ssl_FinishHandshake(sslSocket *ss)
}
ssl_FreeEphemeralKeyPairs(ss);
return SECSuccess;
}
/*
@ -172,7 +199,27 @@ SSL_ResetHandshake(PRFileDesc *s, PRBool asServer)
ssl_Release1stHandshakeLock(ss);
ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions);
ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.echOuterExtensions);
ssl3_ResetExtensionData(&ss->xtnData, ss);
tls13_ResetHandshakePsks(ss, &ss->ssl3.hs.psks);
if (ss->ssl3.hs.echHpkeCtx) {
PK11_HPKE_DestroyContext(ss->ssl3.hs.echHpkeCtx, PR_TRUE);
ss->ssl3.hs.echHpkeCtx = NULL;
PORT_Assert(ss->ssl3.hs.echPublicName);
PORT_Free((void *)ss->ssl3.hs.echPublicName); /* CONST */
ss->ssl3.hs.echPublicName = NULL;
}
/* Make sure greaseEchBuf is freed in ECH setups without echHpkeCtx. */
if (ss->ssl3.hs.echHpkeCtx ||
ss->opt.enableTls13BackendEch ||
ss->opt.enableTls13GreaseEch) {
sslBuffer_Clear(&ss->ssl3.hs.greaseEchBuf);
}
tls13_ClientGreaseDestroy(ss);
tls_ClientHelloExtensionPermutationDestroy(ss);
if (!ss->TCPconnected)
ss->TCPconnected = (PR_SUCCESS == ssl_DefGetpeername(ss, &addr));
@ -544,6 +591,17 @@ DoRecv(sslSocket *ss, unsigned char *out, int len, int flags)
PORT_Assert(ss->gs.readOffset <= ss->gs.writeOffset);
rv = amount;
#ifdef DEBUG
/* In Debug builds free and zero gather plaintext buffer after its content
* has been used/copied for advanced ASAN coverage/utilization.
* This frees the buffer after reception of application data,
* non-application data is freed at the end of
* ssl3con.c/ssl3_HandleRecord(). */
if (ss->gs.writeOffset == ss->gs.readOffset) {
sslBuffer_Clear(&ss->gs.buf);
}
#endif
SSL_TRC(30, ("%d: SSL[%d]: amount=%d available=%d",
SSL_GETPID(), ss->fd, amount, available));
PRINT_BUF(4, (ss, "DoRecv receiving plaintext:", out, amount));
@ -1275,6 +1333,43 @@ SSL_AuthCertificateComplete(PRFileDesc *fd, PRErrorCode error)
return rv;
}
SECStatus
SSL_ClientCertCallbackComplete(PRFileDesc *fd, SECStatus outcome, SECKEYPrivateKey *clientPrivateKey,
CERTCertificate *clientCertificate)
{
SECStatus rv;
sslSocket *ss = ssl_FindSocket(fd);
if (!ss) {
SSL_DBG(("%d: SSL[%d]: bad socket in SSL_ClientCertCallbackComplete",
SSL_GETPID(), fd));
return SECFailure;
}
/* There exists a codepath which exercises each lock.
* Socket is blocked whilst waiting on this callback anyway. */
ssl_Get1stHandshakeLock(ss);
ssl_GetRecvBufLock(ss);
ssl_GetSSL3HandshakeLock(ss);
if (!ss->ssl3.hs.clientCertificatePending) {
/* Application invoked callback at wrong time */
SSL_DBG(("%d: SSL[%d]: socket not waiting for SSL_ClientCertCallbackComplete",
SSL_GETPID(), fd));
PORT_SetError(PR_INVALID_STATE_ERROR);
rv = SECFailure;
goto cleanup;
}
rv = ssl3_ClientCertCallbackComplete(ss, outcome, clientPrivateKey, clientCertificate);
cleanup:
ssl_ReleaseRecvBufLock(ss);
ssl_ReleaseSSL3HandshakeLock(ss);
ssl_Release1stHandshakeLock(ss);
return rv;
}
/* For more info see ssl.h */
SECStatus
SSL_SNISocketConfigHook(PRFileDesc *fd, SSLSNISocketConfig func,

View file

@ -45,7 +45,7 @@
*/
#include "seccomon.h"
#if defined(XP_UNIX) || defined(XP_WIN32) || defined(XP_OS2) || defined(XP_BEOS)
#if defined(XP_UNIX) || defined(XP_WIN32) || defined(XP_OS2)
#include "cert.h"
#include "ssl.h"
@ -60,7 +60,7 @@
#include "selfencrypt.h"
#include <stdio.h>
#if defined(XP_UNIX) || defined(XP_BEOS)
#if defined(XP_UNIX)
#include <syslog.h>
#include <fcntl.h>
@ -237,8 +237,6 @@ static PRBool isMultiProcess = PR_FALSE;
#if defined(AIX) || defined(LINUX) || defined(NETBSD) || defined(OPENBSD)
#define MAX_SID_CACHE_LOCKS 8 /* two FDs per lock */
#elif defined(OSF1)
#define MAX_SID_CACHE_LOCKS 16 /* one FD per lock */
#else
#define MAX_SID_CACHE_LOCKS 256
#endif
@ -252,8 +250,10 @@ static PRUint32 ssl_max_sid_cache_locks = MAX_SID_CACHE_LOCKS;
/* forward static function declarations */
static PRUint32 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s,
unsigned nl);
#if defined(XP_UNIX)
static SECStatus LaunchLockPoller(cacheDesc *cache);
static SECStatus StopLockPoller(cacheDesc *cache);
#endif
struct inheritanceStr {
PRUint32 cacheMemSize;
@ -268,14 +268,25 @@ typedef struct inheritanceStr inheritance;
#endif /* _win32 */
#if defined(XP_UNIX) || defined(XP_BEOS)
#if defined(XP_UNIX)
#define DEFAULT_CACHE_DIRECTORY "/tmp"
#endif /* XP_UNIX || XP_BEOS */
#endif /* XP_UNIX */
/************************************************************************/
/* 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;
}
@ -1036,7 +1047,7 @@ InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries,
if (shared) {
/* Create file names */
#if defined(XP_UNIX) || defined(XP_BEOS)
#if defined(XP_UNIX)
/* there's some confusion here about whether PR_OpenAnonFileMap wants
** a directory name or a file name for its first argument.
cfn = PR_smprintf("%s/.sslsvrcache.%d", directory, myPid);
@ -1165,7 +1176,7 @@ ssl_ConfigServerSessionIDCacheInstanceWithOpt(cacheDesc *cache,
{
SECStatus rv;
rv = ssl_Init();
rv = ssl_InitSessionCache();
if (rv != SECSuccess) {
return rv;
}
@ -1220,7 +1231,7 @@ SSL_ShutdownServerSessionIDCacheInstance(cacheDesc *cache)
SECStatus
SSL_ShutdownServerSessionIDCache(void)
{
#if defined(XP_UNIX) || defined(XP_BEOS)
#if defined(XP_UNIX)
/* Stop the thread that polls cache for expired locks on Unix */
StopLockPoller(&globalCache);
#endif
@ -1284,7 +1295,7 @@ ssl_ConfigMPServerSIDCacheWithOpt(PRUint32 ssl3_timeout,
result = SECFailure;
}
#if defined(XP_UNIX) || defined(XP_BEOS)
#if defined(XP_UNIX)
/* Launch thread to poll cache for expired locks on Unix */
LaunchLockPoller(cache);
#endif
@ -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;
@ -1508,7 +1519,7 @@ SSL_InheritMPServerSIDCache(const char *envString)
return SSL_InheritMPServerSIDCacheInstance(&globalCache, envString);
}
#if defined(XP_UNIX) || defined(XP_BEOS)
#if defined(XP_UNIX)
#define SID_LOCK_EXPIRATION_TIMEOUT 30 /* seconds */
@ -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);
@ -1809,7 +1820,7 @@ ssl_GetSelfEncryptKeyPair(SECKEYPublicKey **pubKey,
return SECSuccess;
}
static PRBool
static SECStatus
ssl_GenerateSelfEncryptKeys(void *pwArg, PRUint8 *keyName,
PK11SymKey **aesKey, PK11SymKey **macKey);

View file

@ -19,7 +19,8 @@
#include "nss.h"
#include "pk11pqg.h"
#include "pk11pub.h"
#include "tls13esni.h"
#include "tls13ech.h"
#include "tls13psk.h"
#include "tls13subcerts.h"
static const sslSocketOps ssl_default_ops = { /* No SSL. */
@ -78,7 +79,7 @@ static sslOptions ssl_defaults = {
.enableOCSPStapling = PR_FALSE,
.enableDelegatedCredentials = PR_FALSE,
.enableALPN = PR_TRUE,
.reuseServerECDHEKey = PR_TRUE,
.reuseServerECDHEKey = PR_FALSE,
.enableFallbackSCSV = PR_FALSE,
.enableServerDhe = PR_TRUE,
.enableExtendedMS = PR_TRUE,
@ -86,22 +87,29 @@ static sslOptions ssl_defaults = {
.requireDHENamedGroups = PR_FALSE,
.enable0RttData = PR_FALSE,
.enableTls13CompatMode = PR_FALSE,
.enableDtls13VersionCompat = PR_FALSE,
.enableDtlsShortHeader = PR_FALSE,
.enableHelloDowngradeCheck = PR_FALSE,
.enableHelloDowngradeCheck = PR_TRUE,
.enableV2CompatibleHello = PR_FALSE,
.enablePostHandshakeAuth = PR_FALSE
.enablePostHandshakeAuth = PR_FALSE,
.suppressEndOfEarlyData = PR_FALSE,
.enableTls13GreaseEch = PR_FALSE,
.enableTls13BackendEch = PR_FALSE,
.callExtensionWriterOnEchInner = PR_FALSE,
.enableGrease = PR_FALSE,
.enableChXtnPermutation = PR_FALSE
};
/*
* default range of enabled SSL/TLS protocols
*/
static SSLVersionRange versions_defaults_stream = {
SSL_LIBRARY_VERSION_TLS_1_0,
SSL_LIBRARY_VERSION_TLS_1_2,
SSL_LIBRARY_VERSION_TLS_1_3
};
static SSLVersionRange versions_defaults_datagram = {
SSL_LIBRARY_VERSION_TLS_1_1,
SSL_LIBRARY_VERSION_TLS_1_2,
SSL_LIBRARY_VERSION_TLS_1_2
};
@ -368,12 +376,18 @@ ssl_DupSocket(sslSocket *os)
ss->resumptionTokenCallback = os->resumptionTokenCallback;
ss->resumptionTokenContext = os->resumptionTokenContext;
if (os->esniKeys) {
ss->esniKeys = tls13_CopyESNIKeys(os->esniKeys);
if (!ss->esniKeys) {
rv = tls13_CopyEchConfigs(&os->echConfigs, &ss->echConfigs);
if (rv != SECSuccess) {
goto loser;
}
if (os->echPrivKey && os->echPubKey) {
ss->echPrivKey = SECKEY_CopyPrivateKey(os->echPrivKey);
ss->echPubKey = SECKEY_CopyPublicKey(os->echPubKey);
if (!ss->echPrivKey || !ss->echPubKey) {
goto loser;
}
}
if (os->antiReplay) {
ss->antiReplay = tls13_RefAntiReplayContext(os->antiReplay);
PORT_Assert(ss->antiReplay); /* Can't fail. */
@ -381,10 +395,12 @@ ssl_DupSocket(sslSocket *os)
goto loser;
}
}
/* The original socket 'owns' the copy of these, so
* just set the target copies to zero */
ss->peerSignatureSchemes = NULL;
ss->peerSignatureSchemeCount = 0;
if (os->psk) {
ss->psk = tls13_CopyPsk(os->psk);
if (!ss->psk) {
goto loser;
}
}
/* Create security data */
rv = ssl_CopySecurityInfo(ss, os);
@ -471,14 +487,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);
/* data in peer Signature schemes comes from the buffer system,
* so there is nothing to free here. Make sure that's the case */
PORT_Assert(ss->peerSignatureSchemes == NULL);
PORT_Assert(ss->peerSignatureSchemeCount == 0);
tls13_DestroyESNIKeys(ss->esniKeys);
tls13_ReleaseAntiReplayContext(ss->antiReplay);
tls13_DestroyPsk(ss->psk);
tls13_DestroyEchConfigs(&ss->echConfigs);
SECKEY_DestroyPrivateKey(ss->echPrivKey);
SECKEY_DestroyPublicKey(ss->echPubKey);
}
/*
@ -872,6 +889,18 @@ 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;
case SSL_ENABLE_GREASE:
ss->opt.enableGrease = val;
break;
case SSL_ENABLE_CH_EXTENSION_PERMUTATION:
ss->opt.enableChXtnPermutation = val;
break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
@ -1026,6 +1055,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;
@ -1164,6 +1196,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;
@ -1375,6 +1410,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;
@ -1440,6 +1479,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);
}
@ -1486,10 +1529,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);
}
@ -1515,11 +1563,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);
@ -1673,7 +1727,7 @@ NSS_SetDomesticPolicy(void)
/* If we've already defined some policy oids, skip changing them */
rv = NSS_GetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, &policy);
if ((rv == SECSuccess) && (policy & NSS_USE_POLICY_IN_SSL)) {
return ssl_Init(); /* make sure the policies have bee loaded */
return ssl_Init(); /* make sure the policies have been loaded */
}
for (cipher = SSL_ImplementedCiphers; *cipher != 0; ++cipher) {
@ -2053,23 +2107,35 @@ ssl_SelectDHEGroup(sslSocket *ss, const sslNamedGroupDef **groupDef)
ssl_grp_ffdhe_custom, WEAK_DHE_SIZE, ssl_kea_dh,
SEC_OID_TLS_DHE_CUSTOM, PR_TRUE
};
PRInt32 minDH;
SECStatus rv;
// make sure we select a group consistent with our
// current policy policy
rv = NSS_OptionGet(NSS_DH_MIN_KEY_SIZE, &minDH);
if (rv != SECSuccess || minDH <= 0) {
minDH = DH_MIN_P_BITS;
}
/* Only select weak groups in TLS 1.2 and earlier, but not if the client has
* indicated that it supports an FFDHE named group. */
if (ss->ssl3.dheWeakGroupEnabled &&
ss->version < SSL_LIBRARY_VERSION_TLS_1_3 &&
!ss->xtnData.peerSupportsFfdheGroups) {
!ss->xtnData.peerSupportsFfdheGroups &&
weak_group_def.bits >= minDH) {
*groupDef = &weak_group_def;
return SECSuccess;
}
if (ss->ssl3.dhePreferredGroup &&
ssl_NamedGroupEnabled(ss, ss->ssl3.dhePreferredGroup)) {
ssl_NamedGroupEnabled(ss, ss->ssl3.dhePreferredGroup) &&
ss->ssl3.dhePreferredGroup->bits >= minDH) {
*groupDef = ss->ssl3.dhePreferredGroup;
return SECSuccess;
}
for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
if (ss->namedGroupPreferences[i] &&
ss->namedGroupPreferences[i]->keaType == ssl_kea_dh) {
ss->namedGroupPreferences[i]->keaType == ssl_kea_dh &&
ss->namedGroupPreferences[i]->bits >= minDH) {
*groupDef = ss->namedGroupPreferences[i];
return SECSuccess;
}
@ -2169,12 +2235,18 @@ ssl_NextProtoNegoCallback(void *arg, PRFileDesc *fd,
{
unsigned int i, j;
sslSocket *ss = ssl_FindSocket(fd);
if (!ss) {
SSL_DBG(("%d: SSL[%d]: bad socket in ssl_NextProtoNegoCallback",
SSL_GETPID(), fd));
return SECFailure;
}
if (ss->opt.nextProtoNego.len == 0) {
SSL_DBG(("%d: SSL[%d]: ssl_NextProtoNegoCallback ALPN disabled",
SSL_GETPID(), fd));
SSL3_SendAlert(ss, alert_fatal, unsupported_extension);
return SECFailure;
}
PORT_Assert(protoMaxLen <= 255);
if (protoMaxLen > 255) {
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
@ -2214,7 +2286,7 @@ SSL_SetNextProtoNego(PRFileDesc *fd, const unsigned char *data,
return SECFailure;
}
if (ssl3_ValidateAppProtocol(data, length) != SECSuccess) {
if (length > 0 && ssl3_ValidateAppProtocol(data, length) != SECSuccess) {
return SECFailure;
}
@ -2223,11 +2295,13 @@ SSL_SetNextProtoNego(PRFileDesc *fd, const unsigned char *data,
* first protocol to the end of the list. */
ssl_GetSSL3HandshakeLock(ss);
SECITEM_FreeItem(&ss->opt.nextProtoNego, PR_FALSE);
SECITEM_AllocItem(NULL, &ss->opt.nextProtoNego, length);
size_t firstLen = data[0] + 1;
/* firstLen <= length is ensured by ssl3_ValidateAppProtocol. */
PORT_Memcpy(ss->opt.nextProtoNego.data + (length - firstLen), data, firstLen);
PORT_Memcpy(ss->opt.nextProtoNego.data, data + firstLen, length - firstLen);
if (length > 0) {
SECITEM_AllocItem(NULL, &ss->opt.nextProtoNego, length);
size_t firstLen = data[0] + 1;
/* firstLen <= length is ensured by ssl3_ValidateAppProtocol. */
PORT_Memcpy(ss->opt.nextProtoNego.data + (length - firstLen), data, firstLen);
PORT_Memcpy(ss->opt.nextProtoNego.data, data + firstLen, length - firstLen);
}
ssl_ReleaseSSL3HandshakeLock(ss);
return SSL_SetNextProtoCallback(fd, ssl_NextProtoNegoCallback, NULL);
@ -2343,6 +2417,7 @@ SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd)
{
sslSocket *sm = NULL, *ss = NULL;
PRCList *cursor;
SECStatus rv;
if (model == NULL) {
PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
@ -2412,7 +2487,6 @@ SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd)
for (cursor = PR_NEXT_LINK(&sm->extensionHooks);
cursor != &sm->extensionHooks;
cursor = PR_NEXT_LINK(cursor)) {
SECStatus rv;
sslCustomExtensionHooks *hook = (sslCustomExtensionHooks *)cursor;
rv = SSL_InstallExtensionHooks(ss->fd, hook->type,
hook->writer, hook->writerArg,
@ -2438,12 +2512,19 @@ SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd)
}
}
/* Copy ESNI. */
tls13_DestroyESNIKeys(ss->esniKeys);
ss->esniKeys = NULL;
if (sm->esniKeys) {
ss->esniKeys = tls13_CopyESNIKeys(sm->esniKeys);
if (!ss->esniKeys) {
/* Copy ECH. */
tls13_DestroyEchConfigs(&ss->echConfigs);
SECKEY_DestroyPrivateKey(ss->echPrivKey);
SECKEY_DestroyPublicKey(ss->echPubKey);
rv = tls13_CopyEchConfigs(&sm->echConfigs, &ss->echConfigs);
if (rv != SECSuccess) {
return NULL;
}
if (sm->echPrivKey && sm->echPubKey) {
/* Might be client (no keys). */
ss->echPrivKey = SECKEY_CopyPrivateKey(sm->echPrivKey);
ss->echPubKey = SECKEY_CopyPublicKey(sm->echPubKey);
if (!ss->echPrivKey || !ss->echPubKey) {
return NULL;
}
}
@ -2461,6 +2542,8 @@ SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd)
}
}
tls13_ResetHandshakePsks(sm, &ss->ssl3.hs.psks);
if (sm->authCertificate)
ss->authCertificate = sm->authCertificate;
if (sm->authCertificateArg)
@ -2491,8 +2574,7 @@ SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd)
ss->handshakeCallbackData = sm->handshakeCallbackData;
if (sm->pkcs11PinArg)
ss->pkcs11PinArg = sm->pkcs11PinArg;
ss->peerSignatureSchemes = NULL;
ss->peerSignatureSchemeCount = 0;
return fd;
}
@ -3818,7 +3900,7 @@ loser:
return SECFailure;
}
#if defined(XP_UNIX) || defined(XP_WIN32) || defined(XP_BEOS)
#if defined(XP_UNIX) || defined(XP_WIN32)
#define NSS_HAVE_GETENV 1
#endif
@ -4126,6 +4208,7 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant)
PR_INIT_CLIST(&ss->serverCerts);
PR_INIT_CLIST(&ss->ephemeralKeyPairs);
PR_INIT_CLIST(&ss->extensionHooks);
PR_INIT_CLIST(&ss->echConfigs);
ss->dbHandle = CERT_GetDefaultCertDB();
@ -4156,12 +4239,13 @@ 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->echPrivKey = NULL;
ss->echPubKey = NULL;
ss->antiReplay = NULL;
ss->peerSignatureSchemes = NULL;
ss->peerSignatureSchemeCount = 0;
ss->psk = NULL;
if (makeLocks) {
rv = ssl_MakeLocks(ss);
@ -4228,17 +4312,27 @@ struct {
void *function;
} ssl_experimental_functions[] = {
#ifndef SSL_DISABLE_EXPERIMENTAL_API
EXP(AddExternalPsk),
EXP(AddExternalPsk0Rtt),
EXP(AeadDecrypt),
EXP(AeadEncrypt),
EXP(CallExtensionWriterOnEchInner),
EXP(CipherSuiteOrderGet),
EXP(CipherSuiteOrderSet),
EXP(CreateAntiReplayContext),
EXP(CreateMask),
EXP(CreateMaskingContext),
EXP(CreateVariantMaskingContext),
EXP(DelegateCredential),
EXP(DestroyAead),
EXP(DestroyMaskingContext),
EXP(DestroyResumptionTokenInfo),
EXP(EnableESNI),
EXP(EncodeESNIKeys),
EXP(EnableTls13BackendEch),
EXP(EnableTls13GreaseEch),
EXP(SetTls13GreaseEchSize),
EXP(EncodeEchConfigId),
EXP(GetCurrentEpoch),
EXP(GetEchRetryConfigs),
EXP(GetExtensionSupport),
EXP(GetResumptionTokenInfo),
EXP(HelloRetryRequestCallback),
@ -4246,19 +4340,26 @@ struct {
EXP(HkdfExtract),
EXP(HkdfExpandLabel),
EXP(HkdfExpandLabelWithMech),
EXP(HkdfVariantExpandLabel),
EXP(HkdfVariantExpandLabelWithMech),
EXP(KeyUpdate),
EXP(MakeAead),
EXP(MakeVariantAead),
EXP(RecordLayerData),
EXP(RecordLayerWriteCallback),
EXP(ReleaseAntiReplayContext),
EXP(RemoveEchConfigs),
EXP(RemoveExternalPsk),
EXP(SecretCallback),
EXP(SendCertificateRequest),
EXP(SendSessionTicket),
EXP(SetAntiReplayContext),
EXP(SetESNIKeyPair),
EXP(SetClientEchConfigs),
EXP(SetDtls13VersionWorkaround),
EXP(SetMaxEarlyDataSize),
EXP(SetResumptionTokenCallback),
EXP(SetResumptionToken),
EXP(SetServerEchConfigs),
EXP(SetTimeFunc),
#endif
{ "", NULL }
@ -4295,6 +4396,68 @@ ssl_ClearPRCList(PRCList *list, void (*f)(void *))
}
}
SECStatus
SSLExp_EnableTls13GreaseEch(PRFileDesc *fd, PRBool enabled)
{
sslSocket *ss = ssl_FindSocket(fd);
if (!ss) {
return SECFailure;
}
ss->opt.enableTls13GreaseEch = enabled;
return SECSuccess;
}
SECStatus
SSLExp_SetTls13GreaseEchSize(PRFileDesc *fd, PRUint8 size)
{
sslSocket *ss = ssl_FindSocket(fd);
if (!ss || size == 0) {
return SECFailure;
}
ssl_Get1stHandshakeLock(ss);
ssl_GetSSL3HandshakeLock(ss);
ss->ssl3.hs.greaseEchSize = size;
ssl_ReleaseSSL3HandshakeLock(ss);
ssl_Release1stHandshakeLock(ss);
return SECSuccess;
}
SECStatus
SSLExp_EnableTls13BackendEch(PRFileDesc *fd, PRBool enabled)
{
sslSocket *ss = ssl_FindSocket(fd);
if (!ss) {
return SECFailure;
}
ss->opt.enableTls13BackendEch = enabled;
return SECSuccess;
}
SECStatus
SSLExp_CallExtensionWriterOnEchInner(PRFileDesc *fd, PRBool enabled)
{
sslSocket *ss = ssl_FindSocket(fd);
if (!ss) {
return SECFailure;
}
ss->opt.callExtensionWriterOnEchInner = enabled;
return SECSuccess;
}
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)
{
@ -4450,8 +4613,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 =

View file

@ -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));
}

View file

@ -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,

View file

@ -33,7 +33,8 @@ typedef enum {
ssl_hs_certificate_status = 22,
ssl_hs_key_update = 24,
ssl_hs_next_proto = 67,
ssl_hs_message_hash = 254, /* Not a real message. */
ssl_hs_message_hash = 254, /* Not a real message. */
ssl_hs_ech_outer_client_hello = 257, /* Not a real message. */
} SSLHandshakeType;
typedef enum {
@ -41,7 +42,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 +185,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 +365,20 @@ 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;
/* The following fields were added in NSS 3.60 */
/* This field is PR_TRUE when the connection is established
* with TLS 1.3 Encrypted Client Hello. */
PRBool echAccepted;
/* The following field was added in NSS 3.66 */
/* This filed is PR_TRUE if the FIPS indicator is true for the
* current connection */
PRBool isFIPS;
/* When adding new fields to this structure, please document the
* NSS version in which they were added. */
} SSLChannelInfo;
@ -366,12 +387,13 @@ typedef struct SSLChannelInfoStr {
#define ssl_preinfo_version (1U << 0)
#define ssl_preinfo_cipher_suite (1U << 1)
#define ssl_preinfo_0rtt_cipher_suite (1U << 2)
/* ssl_preinfo_peer_auth covers peerDelegCred, authKeyBits, and scheme. Not
* included in ssl_preinfo_all as it is client-only. */
/* ssl_preinfo_peer_auth covers peerDelegCred, authKeyBits,
* and scheme. Not included in ssl_preinfo_all as it is client-only. */
#define ssl_preinfo_peer_auth (1U << 3)
#define ssl_preinfo_ech (1U << 4)
/* ssl_preinfo_all doesn't contain ssl_preinfo_0rtt_cipher_suite because that
* field is only set if 0-RTT is sent (client) or accepted (server). */
#define ssl_preinfo_all (ssl_preinfo_version | ssl_preinfo_cipher_suite)
#define ssl_preinfo_all (ssl_preinfo_version | ssl_preinfo_cipher_suite | ssl_preinfo_ech)
typedef struct SSLPreliminaryChannelInfoStr {
/* On return, SSL_GetPreliminaryChannelInfo sets |length| to the smaller of
@ -419,6 +441,15 @@ typedef struct SSLPreliminaryChannelInfoStr {
PRUint32 authKeyBits;
SSLSignatureScheme signatureScheme;
/* The following fields were added in NSS 3.60. */
PRBool echAccepted;
/* If the application configured ECH but |!echAccepted|, authCertificate
* should use the following hostname extracted from the ECHConfig. */
const char* echPublicName;
/* The following field was added in NSS 3.85. */
PRBool ticketSupportsEarlyData;
/* When adding new fields to this structure, please document the
* NSS version in which they were added. */
} SSLPreliminaryChannelInfo;
@ -507,6 +538,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,
@ -519,11 +551,14 @@ typedef enum {
ssl_tls13_post_handshake_auth_xtn = 49,
ssl_signature_algorithms_cert_xtn = 50,
ssl_tls13_key_share_xtn = 51,
/* TLS 1.3 GREASE extension dummy type for builders. */
ssl_tls13_grease_xtn = 0x0a0a,
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,
ssl_tls13_outer_extensions_xtn = 0xfd00,
ssl_tls13_encrypted_client_hello_xtn = 0xfe0d,
ssl_tls13_encrypted_sni_xtn = 0xffce, /* Deprecated. */
} SSLExtensionType;
/* This is the old name for the supported_groups extensions. */

File diff suppressed because it is too large Load diff

View file

@ -19,6 +19,7 @@ typedef enum {
} tls13ExtensionStatus;
#define TLS13_MAX_FINISHED_SIZE 64
#define TLS13_COOKIE_SENTINEL 0xff
SECStatus tls13_UnprotectRecord(
sslSocket *ss, ssl3CipherSpec *spec,
@ -44,20 +45,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);
@ -66,13 +69,14 @@ PRInt32 tls13_LimitEarlyData(sslSocket *ss, SSLContentType type, PRInt32 toSend)
PRBool tls13_AllowPskCipher(const sslSocket *ss,
const ssl3CipherSuiteDef *cipher_def);
PRBool tls13_PskSuiteEnabled(sslSocket *ss);
SECStatus tls13_WriteExtensionsWithBinder(sslSocket *ss, sslBuffer *extensions);
SECStatus tls13_WriteExtensionsWithBinder(sslSocket *ss, sslBuffer *extensions,
sslBuffer *chBuf);
SECStatus tls13_HandleClientHelloPart2(sslSocket *ss,
const SECItem *suites,
sslSessionID *sid,
const PRUint8 *msg,
unsigned int len);
SECStatus tls13_HandleServerHelloPart2(sslSocket *ss);
SECStatus tls13_HandleServerHelloPart2(sslSocket *ss, const PRUint8 *savedMsg, PRUint32 savedLength);
SECStatus tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b,
PRUint32 length);
SECStatus tls13_ConstructHelloRetryRequest(sslSocket *ss,
@ -80,6 +84,7 @@ SECStatus tls13_ConstructHelloRetryRequest(sslSocket *ss,
const sslNamedGroupDef *selectedGroup,
PRUint8 *cookie,
unsigned int cookieLen,
const PRUint8 *cookieGreaseEchSignal,
sslBuffer *buffer);
SECStatus tls13_HandleHelloRetryRequest(sslSocket *ss, const PRUint8 *b,
PRUint32 length);
@ -107,8 +112,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,14 +138,26 @@ 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);
SECStatus tls13_ClientGreaseSetup(sslSocket *ss);
void tls13_ClientGreaseDestroy(sslSocket *ss);
SECStatus tls13_RandomGreaseValue(PRUint16 *out);
SECStatus tls13_MaybeGreaseExtensionType(const sslSocket *ss,
const SSLHandshakeType message,
PRUint16 *exType);
/* Use this instead of FATAL_ERROR when no alert shall be sent. */
#define LOG_ERROR(ss, prError) \

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,125 @@
/* -*- 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 __tls13ech_h_
#define __tls13ech_h_
#include "pk11hpke.h"
/* draft-09, supporting shared-mode and split-mode as a backend server only.
* Notes on the implementation status:
* - Padding (https://tools.ietf.org/html/draft-ietf-tls-esni-08#section-6.2),
* is not implemented (see bug 1677181).
* - When multiple ECHConfigs are provided by the server, the first compatible
* config is selected by the client. Ciphersuite choices are limited and only
* the AEAD may vary (AES-128-GCM or ChaCha20Poly1305).
* - Some of the buffering (construction/compression/decompression) could likely
* be optimized, but the spec is still evolving so that work is deferred.
*/
#define TLS13_ECH_VERSION 0xfe0d
#define TLS13_ECH_SIGNAL_LEN 8
#define TLS13_ECH_AEAD_TAG_LEN 16
static const char kHpkeInfoEch[] = "tls ech";
static const char hHkdfInfoEchConfigID[] = "tls ech config id";
static const char kHkdfInfoEchConfirm[] = "ech accept confirmation";
static const char kHkdfInfoEchHrrConfirm[] = "hrr ech accept confirmation";
typedef enum {
ech_xtn_type_outer = 0,
ech_xtn_type_inner = 1,
} EchXtnType;
struct sslEchConfigContentsStr {
PRUint8 configId;
HpkeKemId kemId;
SECItem publicKey; /* NULL on server. Use the keypair in sslEchConfig instead. */
HpkeKdfId kdfId;
HpkeAeadId aeadId;
SECItem suites; /* One or more HpkeCipherSuites. The selected s
* suite is placed in kdfId and aeadId. */
PRUint8 maxNameLen;
char *publicName;
/* No supported extensions. */
};
/* ECH Information needed by a server to process a second CH after a
* HelloRetryRequest is sent. This data is stored in the cookie.
*/
struct sslEchCookieDataStr {
PRBool previouslyOffered;
PRUint8 configId;
HpkeKdfId kdfId;
HpkeAeadId aeadId;
HpkeContext *hpkeCtx;
PRUint8 signal[TLS13_ECH_SIGNAL_LEN];
};
struct sslEchConfigStr {
PRCList link;
SECItem raw;
PRUint16 version;
sslEchConfigContents contents;
};
struct sslEchXtnStateStr {
SECItem innerCh; /* Server: ClientECH.payload */
SECItem senderPubKey; /* Server: ClientECH.enc */
PRUint8 configId; /* Server: ClientECH.config_id */
HpkeKdfId kdfId; /* Server: ClientECH.cipher_suite.kdf */
HpkeAeadId aeadId; /* Server: ClientECH.cipher_suite.aead */
SECItem retryConfigs; /* Client: ServerECH.retry_configs*/
PRBool retryConfigsValid; /* Client: Extraction of retry_configss is allowed.
* This is set once the handshake completes (having
* verified to the ECHConfig public name). */
PRUint8 *hrrConfirmation; /* Client/Server: HRR Confirmation Location */
PRBool receivedInnerXtn; /* Server: Handled ECH Xtn with Inner Enum */
PRUint8 *payloadStart; /* Server: Start of ECH Payload*/
};
SEC_BEGIN_PROTOS
SECStatus SSLExp_EncodeEchConfigId(PRUint8 configId, const char *publicName, unsigned int maxNameLen,
HpkeKemId kemId, const SECKEYPublicKey *pubKey,
const HpkeSymmetricSuite *hpkeSuites, unsigned int hpkeSuiteCount,
PRUint8 *out, unsigned int *outlen, unsigned int maxlen);
SECStatus SSLExp_GetEchRetryConfigs(PRFileDesc *fd, SECItem *retryConfigs);
SECStatus SSLExp_SetClientEchConfigs(PRFileDesc *fd, const PRUint8 *echConfigs,
unsigned int echConfigsLen);
SECStatus SSLExp_SetServerEchConfigs(PRFileDesc *fd,
const SECKEYPublicKey *pubKey, const SECKEYPrivateKey *privKey,
const PRUint8 *echConfigs, unsigned int numEchConfigs);
SECStatus SSLExp_RemoveEchConfigs(PRFileDesc *fd);
SEC_END_PROTOS
SECStatus tls13_ClientSetupEch(sslSocket *ss, sslClientHelloType type);
SECStatus tls13_ConstructClientHelloWithEch(sslSocket *ss, const sslSessionID *sid,
PRBool freshSid, sslBuffer *chOuterBuf,
sslBuffer *chInnerXtnsBuf);
SECStatus tls13_CopyEchConfigs(PRCList *oconfigs, PRCList *configs);
SECStatus tls13_DecodeEchConfigs(const SECItem *data, PRCList *configs);
void tls13_DestroyEchConfigs(PRCList *list);
void tls13_DestroyEchXtnState(sslEchXtnState *state);
SECStatus tls13_GetMatchingEchConfig(const sslSocket *ss, HpkeKdfId kdf, HpkeAeadId aead,
const SECItem *configId, sslEchConfig **cfg);
SECStatus tls13_MaybeHandleEch(sslSocket *ss, const PRUint8 *msg, PRUint32 msgLen, SECItem *sidBytes,
SECItem *comps, SECItem *cookieBytes, SECItem *suites, SECItem **echInner);
SECStatus tls13_MaybeHandleEchSignal(sslSocket *ss, const PRUint8 *savedMsg, PRUint32 savedLength, PRBool isHrr);
SECStatus tls13_MaybeAcceptEch(sslSocket *ss, const SECItem *sidBytes, const PRUint8 *chOuter,
unsigned int chOuterLen, SECItem **chInner);
SECStatus tls13_MaybeGreaseEch(sslSocket *ss, const sslBuffer *preamble, sslBuffer *buf);
SECStatus tls13_WriteServerEchSignal(sslSocket *ss, PRUint8 *sh, unsigned int shLen);
SECStatus tls13_WriteServerEchHrrSignal(sslSocket *ss, PRUint8 *sh, unsigned int shLen);
SECStatus tls13_DeriveEchSecret(const sslSocket *ss, PK11SymKey **output);
SECStatus tls13_ComputeEchSignal(sslSocket *ss, PRBool isHrr, const PRUint8 *sh, unsigned int shLen, PRUint8 *out);
PRBool tls13_IsIp(const PRUint8 *str, unsigned int len);
PRBool tls13_IsLDH(const PRUint8 *str, unsigned int len);
#endif

View file

@ -0,0 +1,167 @@
/* -*- 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/. */
/* Validation functions for ECH public names. */
#include "seccomon.h"
/* Convert a single character `c` into a number `*d` with the given radix.
* Fails if the character isn't valid for the radix.
*/
static SECStatus
tls13_IpDigit(PRUint8 c, PRUint8 radix, PRUint8 *d)
{
PRUint8 v = 0xff;
if (c >= '0' && c <= '9') {
v = c - '0';
} else if (radix > 10) {
if (c >= 'a' && c <= 'f') {
v = c - 'a';
} else if (c >= 'A' && c <= 'F') {
v = c - 'A';
}
}
if (v >= radix) {
return SECFailure;
}
*d = v;
return SECSuccess;
}
/* This function takes the first couple of characters from `str`, starting at offset
* `*i` and calculates a radix. If it starts with "0x" or "0X", then `*i` is moved up
* by two and `*radix` is set to 16 (hexadecimal). If it starts with "0", then `*i` is
* moved up by one and `*radix` is set to 8 (octal). Otherwise, `*i` is left alone and
* `*radix` is set to 10 (decimal).
* Fails if there are no characters remaining or the next character is '.', either at
* the start or after "0x".
*/
static SECStatus
tls13_IpRadix(const PRUint8 *str, unsigned int len, unsigned int *i, PRUint8 *radix)
{
if (*i == len || str[*i] == '.') {
return SECFailure;
}
if (str[*i] == '0') {
(*i)++;
if (*i < len && (str[*i] == 'x' || str[*i] == 'X')) {
(*i)++;
if (*i == len || str[*i] == '.') {
return SECFailure;
}
*radix = 16;
} else {
*radix = 8;
}
} else {
*radix = 10;
}
return SECSuccess;
}
/* Take a number from `str` from offset `*i` and put the value in `*v`.
* This calculates the radix and returns a value between 0 and 2^32-1, using all
* of the digits up to the end of the string (determined by `len`) or a period ('.').
* Fails if there is no value, if there a non-digit characters, or if the value is
* too large.
*/
static SECStatus
tls13_IpValue(const PRUint8 *str, unsigned int len, unsigned int *i, PRUint32 *v)
{
PRUint8 radix;
SECStatus rv = tls13_IpRadix(str, len, i, &radix);
if (rv != SECSuccess) {
return SECFailure;
}
PRUint64 part = 0;
while (*i < len) {
PRUint8 d;
rv = tls13_IpDigit(str[*i], radix, &d);
if (rv != SECSuccess) {
if (str[*i] != '.') {
return SECFailure;
}
break;
}
part = part * radix + d;
if (part > PR_UINT32_MAX) {
return SECFailure;
}
(*i)++;
}
*v = part;
return SECSuccess;
}
/* Returns true if `end` is true and `v` is within the `limit`. Used to validate the
* last part of an IPv4 address, which can hold larger numbers if there are fewer then
* four parts. */
static PRBool
tls13_IpLastPart(PRBool end, PRUint32 v, PRUint32 limit)
{
if (!end) {
return PR_FALSE;
}
return v <= limit;
}
/* Returns true if `str` contains an IPv4 address. */
PRBool
tls13_IsIp(const PRUint8 *str, unsigned int len)
{
PRUint32 part;
PRUint32 v;
unsigned int i = 0;
for (part = 0; part < 4; part++) {
SECStatus rv = tls13_IpValue(str, len, &i, &v);
if (rv != SECSuccess) {
return PR_FALSE;
}
if (v > 0xff || i == len) {
return tls13_IpLastPart(i == len, v, PR_UINT32_MAX >> (part * 8));
}
PORT_Assert(str[i] == '.');
i++;
}
return tls13_IpLastPart(i == len, v, 0xff);
}
static PRBool
tls13_IsLD(PRUint8 c)
{
return (c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') ||
c == '_'; /* not in spec, but in the world; bug 1136616 */
}
/* Is this a valid dotted LDH string (that is, an A-Label domain name)?
* This does not tolerate a trailing '.', where the DNS generally does.
*/
PRBool
tls13_IsLDH(const PRUint8 *str, unsigned int len)
{
unsigned int i = 0;
while (i < len && tls13_IsLD(str[i])) {
unsigned int labelEnd = PR_MIN(len, i + 63);
i++;
while (i < labelEnd && (tls13_IsLD(str[i]) || str[i] == '-')) {
i++;
}
if (str[i - 1] == '-') {
/* labels cannot end in a hyphen */
return PR_FALSE;
}
if (i == len) {
return PR_TRUE;
}
if (str[i] != '.') {
return PR_FALSE;
}
i++;
}
return PR_FALSE;
}

View file

@ -1,846 +0,0 @@
/* -*- 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/. */
#define TLS13_ESNI_VERSION 0xff01
/*
* struct {
* uint16 version;
* uint8 checksum[4];
* KeyShareEntry keys<4..2^16-1>;
* CipherSuite cipher_suites<2..2^16-2>;
* uint16 padded_length;
* uint64 not_before;
* uint64 not_after;
* Extension extensions<0..2^16-1>;
* } ESNIKeys;
*/
#include "nss.h"
#include "pk11func.h"
#include "ssl.h"
#include "sslproto.h"
#include "sslimpl.h"
#include "ssl3exthandle.h"
#include "tls13esni.h"
#include "tls13exthandle.h"
#include "tls13hkdf.h"
const char kHkdfPurposeEsniKey[] = "esni key";
const char kHkdfPurposeEsniIv[] = "esni iv";
void
tls13_DestroyESNIKeys(sslEsniKeys *keys)
{
if (!keys) {
return;
}
SECITEM_FreeItem(&keys->data, PR_FALSE);
PORT_Free((void *)keys->dummySni);
tls13_DestroyKeyShares(&keys->keyShares);
ssl_FreeEphemeralKeyPair(keys->privKey);
SECITEM_FreeItem(&keys->suites, PR_FALSE);
PORT_ZFree(keys, sizeof(sslEsniKeys));
}
sslEsniKeys *
tls13_CopyESNIKeys(sslEsniKeys *okeys)
{
sslEsniKeys *nkeys;
SECStatus rv;
PORT_Assert(okeys);
nkeys = PORT_ZNew(sslEsniKeys);
if (!nkeys) {
return NULL;
}
PR_INIT_CLIST(&nkeys->keyShares);
rv = SECITEM_CopyItem(NULL, &nkeys->data, &okeys->data);
if (rv != SECSuccess) {
goto loser;
}
if (okeys->dummySni) {
nkeys->dummySni = PORT_Strdup(okeys->dummySni);
if (!nkeys->dummySni) {
goto loser;
}
}
for (PRCList *cur_p = PR_LIST_HEAD(&okeys->keyShares);
cur_p != &okeys->keyShares;
cur_p = PR_NEXT_LINK(cur_p)) {
TLS13KeyShareEntry *copy = tls13_CopyKeyShareEntry(
(TLS13KeyShareEntry *)cur_p);
if (!copy) {
goto loser;
}
PR_APPEND_LINK(&copy->link, &nkeys->keyShares);
}
if (okeys->privKey) {
nkeys->privKey = ssl_CopyEphemeralKeyPair(okeys->privKey);
if (!nkeys->privKey) {
goto loser;
}
}
rv = SECITEM_CopyItem(NULL, &nkeys->suites, &okeys->suites);
if (rv != SECSuccess) {
goto loser;
}
nkeys->paddedLength = okeys->paddedLength;
nkeys->notBefore = okeys->notBefore;
nkeys->notAfter = okeys->notAfter;
return nkeys;
loser:
tls13_DestroyESNIKeys(nkeys);
return NULL;
}
/* Checksum is a 4-byte array. */
static SECStatus
tls13_ComputeESNIKeysChecksum(const PRUint8 *buf, unsigned int len,
PRUint8 *checksum)
{
SECItem copy;
SECStatus rv;
PRUint8 sha256[32];
rv = SECITEM_MakeItem(NULL, &copy, buf, len);
if (rv != SECSuccess) {
return SECFailure;
}
/* Stomp the checksum. */
PORT_Memset(copy.data + 2, 0, 4);
rv = PK11_HashBuf(ssl3_HashTypeToOID(ssl_hash_sha256),
sha256,
copy.data, copy.len);
SECITEM_FreeItem(&copy, PR_FALSE);
if (rv != SECSuccess) {
return SECFailure;
}
PORT_Memcpy(checksum, sha256, 4);
return SECSuccess;
}
static SECStatus
tls13_DecodeESNIKeys(SECItem *data, sslEsniKeys **keysp)
{
SECStatus rv;
sslReadBuffer tmp;
PRUint64 tmpn;
sslEsniKeys *keys;
PRUint8 checksum[4];
sslReader rdr = SSL_READER(data->data, data->len);
rv = sslRead_ReadNumber(&rdr, 2, &tmpn);
if (rv != SECSuccess) {
return SECFailure;
}
if (tmpn != TLS13_ESNI_VERSION) {
PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION);
return SECFailure;
}
keys = PORT_ZNew(sslEsniKeys);
if (!keys) {
return SECFailure;
}
PR_INIT_CLIST(&keys->keyShares);
/* Make a copy. */
rv = SECITEM_CopyItem(NULL, &keys->data, data);
if (rv != SECSuccess) {
goto loser;
}
rv = tls13_ComputeESNIKeysChecksum(data->data, data->len, checksum);
if (rv != SECSuccess) {
goto loser;
}
/* Read and check checksum. */
rv = sslRead_Read(&rdr, 4, &tmp);
if (rv != SECSuccess) {
goto loser;
}
if (0 != NSS_SecureMemcmp(tmp.buf, checksum, 4)) {
goto loser;
}
/* Parse the key shares. */
rv = sslRead_ReadVariable(&rdr, 2, &tmp);
if (rv != SECSuccess) {
goto loser;
}
sslReader rdr2 = SSL_READER(tmp.buf, tmp.len);
while (SSL_READER_REMAINING(&rdr2)) {
TLS13KeyShareEntry *ks = NULL;
rv = tls13_DecodeKeyShareEntry(&rdr2, &ks);
if (rv != SECSuccess) {
goto loser;
}
if (ks) {
PR_APPEND_LINK(&ks->link, &keys->keyShares);
}
}
/* Parse cipher suites. */
rv = sslRead_ReadVariable(&rdr, 2, &tmp);
if (rv != SECSuccess) {
goto loser;
}
/* This can't be odd. */
if (tmp.len & 1) {
goto loser;
}
rv = SECITEM_MakeItem(NULL, &keys->suites, (PRUint8 *)tmp.buf, tmp.len);
if (rv != SECSuccess) {
goto loser;
}
/* Padded Length */
rv = sslRead_ReadNumber(&rdr, 2, &tmpn);
if (rv != SECSuccess) {
goto loser;
}
keys->paddedLength = (PRUint16)tmpn;
/* Not Before */
rv = sslRead_ReadNumber(&rdr, 8, &keys->notBefore);
if (rv != SECSuccess) {
goto loser;
}
/* Not After */
rv = sslRead_ReadNumber(&rdr, 8, &keys->notAfter);
if (rv != SECSuccess) {
goto loser;
}
/* Extensions, which we ignore. */
rv = sslRead_ReadVariable(&rdr, 2, &tmp);
if (rv != SECSuccess) {
goto loser;
}
/* Check that this is empty. */
if (SSL_READER_REMAINING(&rdr) > 0) {
goto loser;
}
*keysp = keys;
return SECSuccess;
loser:
tls13_DestroyESNIKeys(keys);
PORT_SetError(SSL_ERROR_RX_MALFORMED_ESNI_KEYS);
return SECFailure;
}
/* Encode an ESNI keys structure. We only allow one key
* share. */
SECStatus
SSLExp_EncodeESNIKeys(PRUint16 *cipherSuites, unsigned int cipherSuiteCount,
SSLNamedGroup group, SECKEYPublicKey *pubKey,
PRUint16 pad, PRUint64 notBefore, PRUint64 notAfter,
PRUint8 *out, unsigned int *outlen, unsigned int maxlen)
{
unsigned int savedOffset;
SECStatus rv;
sslBuffer b = SSL_BUFFER_EMPTY;
rv = sslBuffer_AppendNumber(&b, TLS13_ESNI_VERSION, 2);
if (rv != SECSuccess) {
goto loser;
}
rv = sslBuffer_Skip(&b, 4, &savedOffset);
if (rv != SECSuccess) {
goto loser;
}
/* Length of vector. */
rv = sslBuffer_AppendNumber(
&b, tls13_SizeOfKeyShareEntry(pubKey), 2);
if (rv != SECSuccess) {
goto loser;
}
/* Our one key share. */
rv = tls13_EncodeKeyShareEntry(&b, group, pubKey);
if (rv != SECSuccess) {
goto loser;
}
/* Cipher suites. */
rv = sslBuffer_AppendNumber(&b, cipherSuiteCount * 2, 2);
if (rv != SECSuccess) {
goto loser;
}
for (unsigned int i = 0; i < cipherSuiteCount; i++) {
rv = sslBuffer_AppendNumber(&b, cipherSuites[i], 2);
if (rv != SECSuccess) {
goto loser;
}
}
/* Padding Length. Fixed for now. */
rv = sslBuffer_AppendNumber(&b, pad, 2);
if (rv != SECSuccess) {
goto loser;
}
/* Start time. */
rv = sslBuffer_AppendNumber(&b, notBefore, 8);
if (rv != SECSuccess) {
goto loser;
}
/* End time. */
rv = sslBuffer_AppendNumber(&b, notAfter, 8);
if (rv != SECSuccess) {
goto loser;
}
/* No extensions. */
rv = sslBuffer_AppendNumber(&b, 0, 2);
if (rv != SECSuccess) {
goto loser;
}
rv = tls13_ComputeESNIKeysChecksum(SSL_BUFFER_BASE(&b),
SSL_BUFFER_LEN(&b),
SSL_BUFFER_BASE(&b) + 2);
if (rv != SECSuccess) {
PORT_Assert(PR_FALSE);
goto loser;
}
if (SSL_BUFFER_LEN(&b) > maxlen) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
PORT_Memcpy(out, SSL_BUFFER_BASE(&b), SSL_BUFFER_LEN(&b));
*outlen = SSL_BUFFER_LEN(&b);
sslBuffer_Clear(&b);
return SECSuccess;
loser:
sslBuffer_Clear(&b);
return SECFailure;
}
SECStatus
SSLExp_SetESNIKeyPair(PRFileDesc *fd,
SECKEYPrivateKey *privKey,
const PRUint8 *record, unsigned int recordLen)
{
sslSocket *ss;
SECStatus rv;
sslEsniKeys *keys = NULL;
SECKEYPublicKey *pubKey = NULL;
SECItem data = { siBuffer, CONST_CAST(PRUint8, record), recordLen };
PLArenaPool *arena = NULL;
ss = ssl_FindSocket(fd);
if (!ss) {
SSL_DBG(("%d: SSL[%d]: bad socket in %s",
SSL_GETPID(), fd, __FUNCTION__));
return SECFailure;
}
rv = tls13_DecodeESNIKeys(&data, &keys);
if (rv != SECSuccess) {
return SECFailure;
}
/* Check the cipher suites. */
(void)ssl3_config_match_init(ss);
/* Make sure the cipher suite is OK. */
SSLVersionRange vrange = { SSL_LIBRARY_VERSION_TLS_1_3,
SSL_LIBRARY_VERSION_TLS_1_3 };
sslReader csrdr = SSL_READER(keys->suites.data,
keys->suites.len);
while (SSL_READER_REMAINING(&csrdr)) {
PRUint64 asuite;
rv = sslRead_ReadNumber(&csrdr, 2, &asuite);
if (rv != SECSuccess) {
goto loser;
}
const ssl3CipherSuiteCfg *suiteCfg =
ssl_LookupCipherSuiteCfg(asuite, ss->cipherSuites);
if (!ssl3_config_match(suiteCfg, ss->ssl3.policy, &vrange, ss)) {
/* Illegal suite. */
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
}
if (PR_CLIST_IS_EMPTY(&keys->keyShares)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
if (PR_PREV_LINK(&keys->keyShares) != PR_NEXT_LINK(&keys->keyShares)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
TLS13KeyShareEntry *entry = (TLS13KeyShareEntry *)PR_LIST_HEAD(
&keys->keyShares);
if (entry->group->keaType != ssl_kea_ecdh) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (!arena) {
goto loser;
}
pubKey = PORT_ArenaZNew(arena, SECKEYPublicKey);
if (!pubKey) {
goto loser;
}
pubKey->arena = arena;
arena = NULL; /* From here, this will be destroyed with the pubkey. */
/* Dummy PKCS11 values because this key isn't on a slot. */
pubKey->pkcs11Slot = NULL;
pubKey->pkcs11ID = CK_INVALID_HANDLE;
rv = ssl_ImportECDHKeyShare(pubKey,
entry->key_exchange.data,
entry->key_exchange.len,
entry->group);
if (rv != SECSuccess) {
goto loser;
}
privKey = SECKEY_CopyPrivateKey(privKey);
if (!privKey) {
goto loser;
}
keys->privKey = ssl_NewEphemeralKeyPair(entry->group, privKey, pubKey);
if (!keys->privKey) {
goto loser;
}
pubKey = NULL;
ss->esniKeys = keys;
return SECSuccess;
loser:
PORT_FreeArena(arena, PR_FALSE);
SECKEY_DestroyPublicKey(pubKey);
tls13_DestroyESNIKeys(keys);
return SECFailure;
}
SECStatus
SSLExp_EnableESNI(PRFileDesc *fd,
const PRUint8 *esniKeys,
unsigned int esniKeysLen,
const char *dummySNI)
{
sslSocket *ss;
sslEsniKeys *keys = NULL;
SECItem data = { siBuffer, CONST_CAST(PRUint8, esniKeys), esniKeysLen };
SECStatus rv;
ss = ssl_FindSocket(fd);
if (!ss) {
SSL_DBG(("%d: SSL[%d]: bad socket in %s",
SSL_GETPID(), fd, __FUNCTION__));
return SECFailure;
}
rv = tls13_DecodeESNIKeys(&data, &keys);
if (rv != SECSuccess) {
return SECFailure;
}
if (dummySNI) {
keys->dummySni = PORT_Strdup(dummySNI);
if (!keys->dummySni) {
tls13_DestroyESNIKeys(keys);
return SECFailure;
}
}
/* Delete in case it was set before. */
tls13_DestroyESNIKeys(ss->esniKeys);
ss->esniKeys = keys;
return SECSuccess;
}
/*
* struct {
* opaque record_digest<0..2^16-1>;
* KeyShareEntry esni_key_share;
* Random client_hello_random;
* } ESNIContents;
*/
SECStatus
tls13_ComputeESNIKeys(const sslSocket *ss,
TLS13KeyShareEntry *entry,
sslKeyPair *keyPair,
const ssl3CipherSuiteDef *suite,
const PRUint8 *esniKeysHash,
const PRUint8 *keyShareBuf,
unsigned int keyShareBufLen,
const PRUint8 *clientRandom,
ssl3KeyMaterial *keyMat)
{
PK11SymKey *Z = NULL;
PK11SymKey *Zx = NULL;
SECStatus ret = SECFailure;
PRUint8 esniContentsBuf[256]; /* Just big enough. */
sslBuffer esniContents = SSL_BUFFER(esniContentsBuf);
PRUint8 hash[64];
const ssl3BulkCipherDef *cipherDef = ssl_GetBulkCipherDef(suite);
size_t keySize = cipherDef->key_size;
size_t ivSize = cipherDef->iv_size +
cipherDef->explicit_nonce_size; /* This isn't always going to
* work, but it does for
* AES-GCM */
unsigned int hashSize = tls13_GetHashSizeForHash(suite->prf_hash);
SECStatus rv;
rv = tls13_HandleKeyShare(CONST_CAST(sslSocket, ss), entry, keyPair,
suite->prf_hash, &Z);
if (rv != SECSuccess) {
goto loser;
}
rv = tls13_HkdfExtract(NULL, Z, suite->prf_hash, &Zx);
if (rv != SECSuccess) {
goto loser;
}
/* Encode ESNIContents. */
rv = sslBuffer_AppendVariable(&esniContents,
esniKeysHash, hashSize, 2);
if (rv != SECSuccess) {
goto loser;
}
rv = sslBuffer_Append(&esniContents, keyShareBuf, keyShareBufLen);
if (rv != SECSuccess) {
goto loser;
}
rv = sslBuffer_Append(&esniContents, clientRandom, SSL3_RANDOM_LENGTH);
if (rv != SECSuccess) {
goto loser;
}
PORT_Assert(hashSize <= sizeof(hash));
rv = PK11_HashBuf(ssl3_HashTypeToOID(suite->prf_hash),
hash,
SSL_BUFFER_BASE(&esniContents),
SSL_BUFFER_LEN(&esniContents));
;
if (rv != SECSuccess) {
goto loser;
}
rv = tls13_HkdfExpandLabel(Zx, suite->prf_hash,
hash, hashSize,
kHkdfPurposeEsniKey, strlen(kHkdfPurposeEsniKey),
ssl3_Alg2Mech(cipherDef->calg),
keySize,
&keyMat->key);
if (rv != SECSuccess) {
goto loser;
}
rv = tls13_HkdfExpandLabelRaw(Zx, suite->prf_hash,
hash, hashSize,
kHkdfPurposeEsniIv, strlen(kHkdfPurposeEsniIv),
keyMat->iv, ivSize);
if (rv != SECSuccess) {
goto loser;
}
ret = SECSuccess;
loser:
PK11_FreeSymKey(Z);
PK11_FreeSymKey(Zx);
return ret;
}
/* Set up ESNI. This generates a private key as a side effect. */
SECStatus
tls13_ClientSetupESNI(sslSocket *ss)
{
ssl3CipherSuite suite;
sslEphemeralKeyPair *keyPair;
size_t i;
PRCList *cur;
SECStatus rv;
TLS13KeyShareEntry *share = NULL;
const sslNamedGroupDef *group = NULL;
PRTime now = ssl_Time(ss) / PR_USEC_PER_SEC;
PORT_Assert(!ss->xtnData.esniPrivateKey);
if (!ss->esniKeys) {
return SECSuccess;
}
if ((ss->esniKeys->notBefore > now) || (ss->esniKeys->notAfter < now)) {
return SECSuccess;
}
/* If we're not sending SNI, don't send ESNI. */
if (!ssl_ShouldSendSNIExtension(ss, ss->url)) {
return SECSuccess;
}
/* Pick the group. */
for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
for (cur = PR_NEXT_LINK(&ss->esniKeys->keyShares);
cur != &ss->esniKeys->keyShares;
cur = PR_NEXT_LINK(cur)) {
if (!ss->namedGroupPreferences[i]) {
continue;
}
share = (TLS13KeyShareEntry *)cur;
if (share->group->name == ss->namedGroupPreferences[i]->name) {
group = ss->namedGroupPreferences[i];
break;
}
}
}
if (!group) {
/* No compatible group. */
return SECSuccess;
}
rv = ssl3_NegotiateCipherSuiteInner(ss, &ss->esniKeys->suites,
SSL_LIBRARY_VERSION_TLS_1_3, &suite);
if (rv != SECSuccess) {
return SECSuccess;
}
rv = tls13_CreateKeyShare(ss, group, &keyPair);
if (rv != SECSuccess) {
return SECFailure;
}
ss->xtnData.esniPrivateKey = keyPair;
ss->xtnData.esniSuite = suite;
ss->xtnData.peerEsniShare = share;
return SECSuccess;
}
/*
* struct {
* CipherSuite suite;
* KeyShareEntry key_share;
* opaque record_digest<0..2^16-1>;
* opaque encrypted_sni<0..2^16-1>;
* } ClientEncryptedSNI;
*
* struct {
* ServerNameList sni;
* opaque zeros[ESNIKeys.padded_length - length(sni)];
* } PaddedServerNameList;
*
* struct {
* uint8 nonce[16];
* PaddedServerNameList realSNI;
* } ClientESNIInner;
*/
SECStatus
tls13_FormatEsniAADInput(sslBuffer *aadInput,
PRUint8 *keyShare, unsigned int keyShareLen)
{
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);
if (rv != SECSuccess) {
return SECFailure;
}
return SECSuccess;
}
static SECStatus
tls13_ServerGetEsniAEAD(const sslSocket *ss, PRUint64 suite,
const ssl3CipherSuiteDef **suiteDefp,
SSLAEADCipher *aeadp)
{
SECStatus rv;
const ssl3CipherSuiteDef *suiteDef;
SSLAEADCipher aead;
/* Check against the suite list for ESNI */
PRBool csMatch = PR_FALSE;
sslReader csrdr = SSL_READER(ss->esniKeys->suites.data,
ss->esniKeys->suites.len);
while (SSL_READER_REMAINING(&csrdr)) {
PRUint64 asuite;
rv = sslRead_ReadNumber(&csrdr, 2, &asuite);
if (rv != SECSuccess) {
return SECFailure;
}
if (asuite == suite) {
csMatch = PR_TRUE;
break;
}
}
if (!csMatch) {
return SECFailure;
}
suiteDef = ssl_LookupCipherSuiteDef(suite);
PORT_Assert(suiteDef);
if (!suiteDef) {
return SECFailure;
}
aead = tls13_GetAead(ssl_GetBulkCipherDef(suiteDef));
if (!aead) {
return SECFailure;
}
*suiteDefp = suiteDef;
*aeadp = aead;
return SECSuccess;
}
SECStatus
tls13_ServerDecryptEsniXtn(const sslSocket *ss, const PRUint8 *in, unsigned int inLen,
PRUint8 *out, unsigned int *outLen, unsigned int maxLen)
{
sslReader rdr = SSL_READER(in, inLen);
PRUint64 suite;
const ssl3CipherSuiteDef *suiteDef = NULL;
SSLAEADCipher aead = NULL;
TLSExtension *keyShareExtension;
TLS13KeyShareEntry *entry = NULL;
ssl3KeyMaterial keyMat = { NULL };
sslBuffer aadInput = SSL_BUFFER_EMPTY;
const PRUint8 *keyShareBuf;
sslReadBuffer buf;
unsigned int keyShareBufLen;
PRUint8 hash[64];
SECStatus rv;
/* Read the cipher suite. */
rv = sslRead_ReadNumber(&rdr, 2, &suite);
if (rv != SECSuccess) {
goto loser;
}
/* Find the AEAD */
rv = tls13_ServerGetEsniAEAD(ss, suite, &suiteDef, &aead);
if (rv != SECSuccess) {
goto loser;
}
/* Note where the KeyShare starts. */
keyShareBuf = SSL_READER_CURRENT(&rdr);
rv = tls13_DecodeKeyShareEntry(&rdr, &entry);
if (rv != SECSuccess) {
goto loser;
}
keyShareBufLen = SSL_READER_CURRENT(&rdr) - keyShareBuf;
if (!entry || entry->group->name != ss->esniKeys->privKey->group->name) {
goto loser;
}
/* The hash of the ESNIKeys structure. */
rv = sslRead_ReadVariable(&rdr, 2, &buf);
if (rv != SECSuccess) {
goto loser;
}
/* Check that the hash matches. */
unsigned int hashLen = tls13_GetHashSizeForHash(suiteDef->prf_hash);
PORT_Assert(hashLen <= sizeof(hash));
rv = PK11_HashBuf(ssl3_HashTypeToOID(suiteDef->prf_hash),
hash,
ss->esniKeys->data.data, ss->esniKeys->data.len);
if (rv != SECSuccess) {
goto loser;
}
if (buf.len != hashLen) {
/* This is malformed. */
goto loser;
}
if (0 != NSS_SecureMemcmp(hash, buf.buf, hashLen)) {
goto loser;
}
rv = tls13_ComputeESNIKeys(ss, entry,
ss->esniKeys->privKey->keys,
suiteDef,
hash, keyShareBuf, keyShareBufLen,
((sslSocket *)ss)->ssl3.hs.client_random,
&keyMat);
if (rv != SECSuccess) {
goto loser;
}
/* Read the ciphertext. */
rv = sslRead_ReadVariable(&rdr, 2, &buf);
if (rv != SECSuccess) {
goto loser;
}
/* Check that this is empty. */
if (SSL_READER_REMAINING(&rdr) > 0) {
goto loser;
}
/* Find the key share extension. */
keyShareExtension = ssl3_FindExtension(CONST_CAST(sslSocket, ss),
ssl_tls13_key_share_xtn);
if (!keyShareExtension) {
goto loser;
}
rv = tls13_FormatEsniAADInput(&aadInput,
keyShareExtension->data.data,
keyShareExtension->data.len);
if (rv != SECSuccess) {
goto loser;
}
rv = aead(&keyMat, PR_TRUE /* Decrypt */,
out, outLen, maxLen,
buf.buf, buf.len,
SSL_BUFFER_BASE(&aadInput),
SSL_BUFFER_LEN(&aadInput));
sslBuffer_Clear(&aadInput);
if (rv != SECSuccess) {
goto loser;
}
ssl_DestroyKeyMaterial(&keyMat);
tls13_DestroyKeyShareEntry(entry);
return SECSuccess;
loser:
FATAL_ERROR(CONST_CAST(sslSocket, ss), SSL_ERROR_RX_MALFORMED_ESNI_EXTENSION, illegal_parameter);
ssl_DestroyKeyMaterial(&keyMat); /* Safe because zeroed. */
if (entry) {
tls13_DestroyKeyShareEntry(entry);
}
return SECFailure;
}

View file

@ -1,51 +0,0 @@
/* -*- 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 __tls13esni_h_
#define __tls13esni_h_
struct sslEsniKeysStr {
SECItem data; /* The encoded record. */
sslEphemeralKeyPair *privKey;
const char *dummySni;
PRCList keyShares; /* List of TLS13KeyShareEntry */
SECItem suites;
PRUint16 paddedLength;
PRUint64 notBefore;
PRUint64 notAfter;
};
SECStatus SSLExp_SetESNIKeyPair(PRFileDesc *fd,
SECKEYPrivateKey *privKey,
const PRUint8 *record, unsigned int recordLen);
SECStatus SSLExp_EnableESNI(PRFileDesc *fd, const PRUint8 *esniKeys,
unsigned int esniKeysLen, const char *dummySNI);
SECStatus SSLExp_EncodeESNIKeys(PRUint16 *cipherSuites, unsigned int cipherSuiteCount,
SSLNamedGroup group, SECKEYPublicKey *pubKey,
PRUint16 pad, PRUint64 notBefore, PRUint64 notAfter,
PRUint8 *out, unsigned int *outlen, unsigned int maxlen);
sslEsniKeys *tls13_CopyESNIKeys(sslEsniKeys *okeys);
void tls13_DestroyESNIKeys(sslEsniKeys *keys);
SECStatus tls13_ClientSetupESNI(sslSocket *ss);
SECStatus tls13_ComputeESNIKeys(const sslSocket *ss,
TLS13KeyShareEntry *entry,
sslKeyPair *keyPair,
const ssl3CipherSuiteDef *suite,
const PRUint8 *esniKeysHash,
const PRUint8 *keyShareBuf,
unsigned int keyShareBufLen,
const PRUint8 *clientRandom,
ssl3KeyMaterial *keyMat);
SECStatus tls13_FormatEsniAADInput(sslBuffer *aadInput,
PRUint8 *keyShare, unsigned int keyShareLen);
SECStatus tls13_ServerDecryptEsniXtn(const sslSocket *ss, const PRUint8 *in, unsigned int inLen,
PRUint8 *out, unsigned int *outLen, unsigned int maxLen);
#endif

File diff suppressed because it is too large Load diff

View file

@ -75,6 +75,8 @@ SECStatus tls13_SendCertAuthoritiesXtn(const sslSocket *ss,
SECStatus tls13_ClientHandleCertAuthoritiesXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
SECStatus tls13_ServerHandleCertAuthoritiesXtn(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data);
SECStatus tls13_ServerHandleCookieXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
@ -88,11 +90,18 @@ SECStatus tls13_DecodeKeyShareEntry(sslReader *rdr, TLS13KeyShareEntry **ksp);
PRUint32 tls13_SizeOfKeyShareEntry(const SECKEYPublicKey *pubKey);
SECStatus tls13_EncodeKeyShareEntry(sslBuffer *buf, SSLNamedGroup group,
SECKEYPublicKey *pubKey);
SECStatus tls13_ClientSendEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
SECStatus tls13_ServerHandleEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData,
SECItem *data);
SECStatus tls13_ClientCheckEsniXtn(sslSocket *ss);
SECStatus tls13_ServerHandleInnerEchXtn(const sslSocket *ss, TLSExtensionData *xtnData,
SECItem *data);
SECStatus tls13_ServerHandleOuterEchXtn(const sslSocket *ss, TLSExtensionData *xtnData,
SECItem *data);
SECStatus tls13_ServerSendHrrEchXtn(const sslSocket *ss, TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
SECStatus tls13_ServerSendEchXtn(const sslSocket *ss, TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
SECStatus tls13_ClientHandleHrrEchXtn(const sslSocket *ss, TLSExtensionData *xtnData,
SECItem *data);
SECStatus tls13_ClientHandleEchXtn(const sslSocket *ss, TLSExtensionData *xtnData,
SECItem *data);
SECStatus tls13_ClientSendPostHandshakeAuthXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
@ -108,5 +117,11 @@ SECStatus tls13_ClientSendDelegatedCredentialsXtn(const sslSocket *ss,
SECStatus tls13_ServerHandleDelegatedCredentialsXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
SECStatus tls13_SendEmptyGreaseXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
SECStatus tls13_SendGreaseXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
#endif

View file

@ -12,6 +12,7 @@
#include "sslimpl.h"
#include "selfencrypt.h"
#include "tls13con.h"
#include "tls13ech.h"
#include "tls13err.h"
#include "tls13hashstate.h"
@ -23,9 +24,16 @@
* uint8 indicator = 0xff; // To disambiguate from tickets.
* uint16 cipherSuite; // Selected cipher suite.
* uint16 keyShare; // Requested key share group (0=none)
* PRUint8 echConfigId; // ECH config_id
* HpkeKdfId kdfId; // ECH KDF (uint16)
* HpkeAeadId aeadId; // ECH AEAD (uint16)
* opaque echHpkeCtx<0..65535>; // ECH serialized HPKE context
* opaque applicationToken<0..65535>; // Application token
* opaque ch_hash[rest_of_buffer]; // H(ClientHello)
* } CookieInner;
*
* An empty echConfigId means that ECH was not offered in the first ClientHello.
* An empty echHrrPsk means that ECH was not accepted in CH1.
*/
SECStatus
tls13_MakeHrrCookie(sslSocket *ss, const sslNamedGroupDef *selectedGroup,
@ -37,6 +45,7 @@ tls13_MakeHrrCookie(sslSocket *ss, const sslNamedGroupDef *selectedGroup,
PRUint8 cookie[1024];
sslBuffer cookieBuf = SSL_BUFFER(cookie);
static const PRUint8 indicator = 0xff;
SECItem *echHpkeCtx = NULL;
/* Encode header. */
rv = sslBuffer_Append(&cookieBuf, &indicator, 1);
@ -53,6 +62,60 @@ tls13_MakeHrrCookie(sslSocket *ss, const sslNamedGroupDef *selectedGroup,
return SECFailure;
}
if (ss->xtnData.ech) {
/* Record that we received ECH. See sslEchCookieData */
rv = sslBuffer_AppendNumber(&cookieBuf, PR_TRUE, 1);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_AppendNumber(&cookieBuf, ss->xtnData.ech->configId,
1);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_AppendNumber(&cookieBuf, ss->xtnData.ech->kdfId, 2);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_AppendNumber(&cookieBuf, ss->xtnData.ech->aeadId, 2);
if (rv != SECSuccess) {
return SECFailure;
}
/* We need to send a ECH HRR Extension containing a signal for the client,
* we must store the signal in the cookie so we can reconstruct the transcript
* later. To avoid leaking whether ECH was accepted in the length of the cookie
* we include the empty signal in the cookie regardless.
*/
PR_ASSERT(SSL_BUFFER_LEN(&ss->ssl3.hs.greaseEchBuf) == TLS13_ECH_SIGNAL_LEN);
rv = sslBuffer_AppendBuffer(&cookieBuf, &ss->ssl3.hs.greaseEchBuf);
if (rv != SECSuccess) {
return SECFailure;
}
/* There might be no HPKE Context, e.g. when we lack a matching ECHConfig. */
if (ss->ssl3.hs.echHpkeCtx) {
rv = PK11_HPKE_ExportContext(ss->ssl3.hs.echHpkeCtx, NULL, &echHpkeCtx);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_AppendVariable(&cookieBuf, echHpkeCtx->data, echHpkeCtx->len, 2);
SECITEM_ZfreeItem(echHpkeCtx, PR_TRUE);
} else {
/* Zero length HPKE context. */
rv = sslBuffer_AppendNumber(&cookieBuf, 0, 2);
}
if (rv != SECSuccess) {
return SECFailure;
}
} else {
rv = sslBuffer_AppendNumber(&cookieBuf, PR_FALSE, 1);
if (rv != SECSuccess) {
return SECFailure;
}
}
/* Application token. */
rv = sslBuffer_AppendVariable(&cookieBuf, appToken, appTokenLen, 2);
if (rv != SECSuccess) {
@ -79,34 +142,48 @@ tls13_MakeHrrCookie(sslSocket *ss, const sslNamedGroupDef *selectedGroup,
return SECSuccess;
}
/* Recover the hash state from the cookie. */
/* Given a cookie and cookieLen, decrypt and parse, returning
* any values that were requested via the "previous_" params. If
* recoverState is true, the transcript state and application
* token are restored. Note that previousEchKdfId, previousEchAeadId,
* previousEchConfigId, and previousEchHpkeCtx are not modified if ECH was not
* previously negotiated (i.e., previousEchOffered is PR_FALSE). */
SECStatus
tls13_RecoverHashState(sslSocket *ss,
unsigned char *cookie, unsigned int cookieLen,
ssl3CipherSuite *previousCipherSuite,
const sslNamedGroupDef **previousGroup)
tls13_HandleHrrCookie(sslSocket *ss,
unsigned char *cookie, unsigned int cookieLen,
ssl3CipherSuite *previousCipherSuite,
const sslNamedGroupDef **previousGroup,
PRBool *previousOfferedEch,
sslEchCookieData *echData,
PRBool recoverState)
{
SECStatus rv;
unsigned char plaintext[1024];
unsigned int plaintextLen = 0;
sslBuffer messageBuf = SSL_BUFFER_EMPTY;
sslReadBuffer echHpkeBuf = { 0 };
PRBool receivedEch;
PRUint64 sentinel;
PRUint64 cipherSuite;
sslEchCookieData parsedEchData = { 0 };
sslReadBuffer greaseReadBuf = { 0 };
PRUint64 group;
PRUint64 tmp64;
const sslNamedGroupDef *selectedGroup;
PRUint64 appTokenLen;
rv = ssl_SelfEncryptUnprotect(ss, cookie, cookieLen,
plaintext, &plaintextLen, sizeof(plaintext));
if (rv != SECSuccess) {
SSL_TRC(100, ("Error decrypting cookie."));
return SECFailure;
}
sslReader reader = SSL_READER(plaintext, plaintextLen);
/* Should start with 0xff. */
/* Should start with the sentinel value. */
rv = sslRead_ReadNumber(&reader, 1, &sentinel);
if ((rv != SECSuccess) || (sentinel != 0xff)) {
if ((rv != SECSuccess) || (sentinel != TLS13_COOKIE_SENTINEL)) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
@ -125,19 +202,69 @@ tls13_RecoverHashState(sslSocket *ss,
}
selectedGroup = ssl_LookupNamedGroup(group);
/* Was ECH received. */
rv = sslRead_ReadNumber(&reader, 1, &tmp64);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
receivedEch = tmp64 == PR_TRUE;
*previousOfferedEch = receivedEch;
if (receivedEch) {
/* ECH config ID */
rv = sslRead_ReadNumber(&reader, 1, &tmp64);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
parsedEchData.configId = (PRUint8)tmp64;
/* ECH Ciphersuite */
rv = sslRead_ReadNumber(&reader, 2, &tmp64);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
parsedEchData.kdfId = (HpkeKdfId)tmp64;
rv = sslRead_ReadNumber(&reader, 2, &tmp64);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
parsedEchData.aeadId = (HpkeAeadId)tmp64;
/* ECH accept_confirmation signal. */
rv = sslRead_Read(&reader, TLS13_ECH_SIGNAL_LEN, &greaseReadBuf);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
PORT_Memcpy(parsedEchData.signal, greaseReadBuf.buf, TLS13_ECH_SIGNAL_LEN);
/* ECH HPKE context may be empty. */
rv = sslRead_ReadVariable(&reader, 2, &echHpkeBuf);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
if (echData && echHpkeBuf.len) {
const SECItem hpkeItem = { siBuffer, CONST_CAST(unsigned char, echHpkeBuf.buf),
echHpkeBuf.len };
parsedEchData.hpkeCtx = PK11_HPKE_ImportContext(&hpkeItem, NULL);
if (!parsedEchData.hpkeCtx) {
FATAL_ERROR(ss, PORT_GetError(), illegal_parameter);
return SECFailure;
}
}
}
/* Application token. */
PORT_Assert(ss->xtnData.applicationToken.len == 0);
rv = sslRead_ReadNumber(&reader, 2, &appTokenLen);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
if (SECITEM_AllocItem(NULL, &ss->xtnData.applicationToken,
appTokenLen) == NULL) {
FATAL_ERROR(ss, PORT_GetError(), internal_error);
return SECFailure;
}
ss->xtnData.applicationToken.len = appTokenLen;
sslReadBuffer appTokenReader = { 0 };
rv = sslRead_Read(&reader, appTokenLen, &appTokenReader);
if (rv != SECSuccess) {
@ -145,43 +272,61 @@ tls13_RecoverHashState(sslSocket *ss,
return SECFailure;
}
PORT_Assert(appTokenReader.len == appTokenLen);
PORT_Memcpy(ss->xtnData.applicationToken.data, appTokenReader.buf, appTokenLen);
/* The remainder is the hash. */
unsigned int hashLen = SSL_READER_REMAINING(&reader);
if (hashLen != tls13_GetHashSize(ss)) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
if (recoverState) {
PORT_Assert(ss->xtnData.applicationToken.len == 0);
if (SECITEM_AllocItem(NULL, &ss->xtnData.applicationToken,
appTokenLen) == NULL) {
FATAL_ERROR(ss, PORT_GetError(), internal_error);
return SECFailure;
}
PORT_Memcpy(ss->xtnData.applicationToken.data, appTokenReader.buf, appTokenLen);
ss->xtnData.applicationToken.len = appTokenLen;
/* The remainder is the hash. */
unsigned int hashLen = SSL_READER_REMAINING(&reader);
if (hashLen != tls13_GetHashSize(ss)) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
/* Now reinject the message. */
SSL_ASSERT_HASHES_EMPTY(ss);
rv = ssl_HashHandshakeMessageInt(ss, ssl_hs_message_hash, 0,
SSL_READER_CURRENT(&reader), hashLen,
ssl3_UpdateHandshakeHashes);
if (rv != SECSuccess) {
return SECFailure;
}
/* And finally reinject the HRR. */
rv = tls13_ConstructHelloRetryRequest(ss, cipherSuite,
selectedGroup,
cookie, cookieLen,
parsedEchData.signal,
&messageBuf);
if (rv != SECSuccess) {
return SECFailure;
}
rv = ssl_HashHandshakeMessageInt(ss, ssl_hs_server_hello, 0,
SSL_BUFFER_BASE(&messageBuf),
SSL_BUFFER_LEN(&messageBuf),
ssl3_UpdateHandshakeHashes);
sslBuffer_Clear(&messageBuf);
if (rv != SECSuccess) {
return SECFailure;
}
}
/* Now reinject the message. */
SSL_ASSERT_HASHES_EMPTY(ss);
rv = ssl_HashHandshakeMessageInt(ss, ssl_hs_message_hash, 0,
SSL_READER_CURRENT(&reader), hashLen,
ssl3_UpdateHandshakeHashes);
if (rv != SECSuccess) {
return SECFailure;
if (previousCipherSuite) {
*previousCipherSuite = cipherSuite;
}
/* And finally reinject the HRR. */
rv = tls13_ConstructHelloRetryRequest(ss, cipherSuite,
selectedGroup,
cookie, cookieLen,
&messageBuf);
if (rv != SECSuccess) {
return SECFailure;
if (previousGroup) {
*previousGroup = selectedGroup;
}
rv = ssl_HashHandshakeMessageInt(ss, ssl_hs_server_hello, 0,
SSL_BUFFER_BASE(&messageBuf),
SSL_BUFFER_LEN(&messageBuf),
ssl3_UpdateHandshakeHashes);
sslBuffer_Clear(&messageBuf);
if (rv != SECSuccess) {
return SECFailure;
if (echData) {
PORT_Memcpy(echData, &parsedEchData, sizeof(parsedEchData));
}
*previousCipherSuite = cipherSuite;
*previousGroup = selectedGroup;
return SECSuccess;
}

View file

@ -17,9 +17,11 @@ SECStatus tls13_MakeHrrCookie(sslSocket *ss, const sslNamedGroupDef *selectedGro
const PRUint8 *appToken, unsigned int appTokenLen,
PRUint8 *buf, unsigned int *len, unsigned int maxlen);
SECStatus tls13_GetHrrCookieLength(sslSocket *ss, unsigned int *length);
SECStatus tls13_RecoverHashState(sslSocket *ss,
unsigned char *cookie,
unsigned int cookieLen,
ssl3CipherSuite *previousCipherSuite,
const sslNamedGroupDef **previousGroup);
SECStatus tls13_HandleHrrCookie(sslSocket *ss,
unsigned char *cookie, unsigned int cookieLen,
ssl3CipherSuite *previousCipherSuite,
const sslNamedGroupDef **previousGroup,
PRBool *previousOfferedEch,
sslEchCookieData *echData,
PRBool recoverState);
#endif

View file

@ -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;
@ -225,20 +247,35 @@ tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash,
return SECSuccess;
}
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;
}

View file

@ -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
}

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -149,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) {
@ -192,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;
@ -228,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;
@ -312,7 +311,7 @@ tls13_HashCredentialSignatureMessage(SSL3Hashes *hash,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20
};
static const PRUint8 kCtxStr[] = "TLS, server delegated credentials";
@ -380,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;
@ -402,7 +407,15 @@ tls13_CheckCertDelegationUsage(sslSocket *ss)
/* 1.3.6.1.4.1.44363.44, as defined in draft-ietf-tls-subcerts. */
static unsigned char kDelegationUsageOid[] = {
0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xda, 0x4b, 0x2c,
0x2b,
0x06,
0x01,
0x04,
0x01,
0x82,
0xda,
0x4b,
0x2c
};
delegUsageOid.data = kDelegationUsageOid;
@ -435,8 +448,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) {
@ -445,11 +460,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;
}
@ -457,7 +479,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.
*/
@ -561,8 +584,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) {
@ -584,15 +605,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;
@ -717,7 +736,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 */)) {

View file

@ -18,7 +18,7 @@
#include "prerror.h"
#endif
#if defined(__bsdi__) || defined(NTO) || defined(DARWIN) || defined(BEOS)
#if defined(__bsdi__) || defined(NTO) || defined(DARWIN)
#undef _PR_POLL_AVAILABLE
#endif