mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-21 15:57:31 +09:00
Replace NSS with Pale Moon's
This commit is contained in:
parent
ff1e5e48bf
commit
8c2e376f94
2870 changed files with 1762232 additions and 1374220 deletions
|
|
@ -61,5 +61,3 @@ include $(CORE_DEPTH)/coreconf/rules.mk
|
|||
#######################################################################
|
||||
# (7) Execute "local" rules. (OPTIONAL). #
|
||||
#######################################################################
|
||||
|
||||
export:: private_export
|
||||
|
|
|
|||
|
|
@ -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.")
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -247,3 +247,9 @@ SSL_FilterClientCertListBySocket;
|
|||
;+ local:
|
||||
;+*;
|
||||
;+};
|
||||
;+NSS_3.80 { # NSS 3.80 release
|
||||
;+ global:
|
||||
SSL_ClientCertCallbackComplete;
|
||||
;+ local:
|
||||
;+*;
|
||||
;+};
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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... */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
¶m,
|
||||
outMask, &outMaskLen,
|
||||
maskLen,
|
||||
zeros, maskLen);
|
||||
break;
|
||||
default:
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
if (rv != SECSuccess) {
|
||||
PORT_SetError(SEC_ERROR_PKCS11_FUNCTION_FAILED);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
// Ensure we produced at least as much material as requested.
|
||||
if (outMaskLen < maskLen) {
|
||||
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
ssl_DestroyMaskingContextInner(SSLMaskingContext *ctx)
|
||||
{
|
||||
if (!ctx) {
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
PK11_FreeSymKey(ctx->secret);
|
||||
PORT_ZFree(ctx, sizeof(*ctx));
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
SSLExp_CreateMask(SSLMaskingContext *ctx, const PRUint8 *sample,
|
||||
unsigned int sampleLen, PRUint8 *outMask,
|
||||
unsigned int maskLen)
|
||||
{
|
||||
return ssl_CreateMaskInner(ctx, sample, sampleLen, outMask, maskLen);
|
||||
}
|
||||
|
||||
SECStatus
|
||||
SSLExp_CreateMaskingContext(PRUint16 version, PRUint16 cipherSuite,
|
||||
PK11SymKey *secret,
|
||||
const char *label,
|
||||
unsigned int labelLen,
|
||||
SSLMaskingContext **ctx)
|
||||
{
|
||||
return ssl_CreateMaskingContextInner(version, cipherSuite, ssl_variant_stream, secret,
|
||||
label, labelLen, ctx);
|
||||
}
|
||||
|
||||
SECStatus
|
||||
SSLExp_CreateVariantMaskingContext(PRUint16 version, PRUint16 cipherSuite,
|
||||
SSLProtocolVariant variant,
|
||||
PK11SymKey *secret,
|
||||
const char *label,
|
||||
unsigned int labelLen,
|
||||
SSLMaskingContext **ctx)
|
||||
{
|
||||
return ssl_CreateMaskingContextInner(version, cipherSuite, variant, secret,
|
||||
label, labelLen, ctx);
|
||||
}
|
||||
|
||||
SECStatus
|
||||
SSLExp_DestroyMaskingContext(SSLMaskingContext *ctx)
|
||||
{
|
||||
return ssl_DestroyMaskingContextInner(ctx);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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) \
|
||||
|
|
|
|||
2818
security/nss/lib/ssl/tls13ech.c
Normal file
2818
security/nss/lib/ssl/tls13ech.c
Normal file
File diff suppressed because it is too large
Load diff
125
security/nss/lib/ssl/tls13ech.h
Normal file
125
security/nss/lib/ssl/tls13ech.h
Normal 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
|
||||
167
security/nss/lib/ssl/tls13echv.c
Normal file
167
security/nss/lib/ssl/tls13echv.c
Normal 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;
|
||||
}
|
||||
|
|
@ -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(©->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, ©, 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(©, 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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -25,52 +25,74 @@ static const struct {
|
|||
{ ssl_hash_md5, 0, 0 },
|
||||
{ ssl_hash_sha1, 0, 0 },
|
||||
{ ssl_hash_sha224, 0 },
|
||||
{ ssl_hash_sha256, CKM_NSS_HKDF_SHA256, 32 },
|
||||
{ ssl_hash_sha384, CKM_NSS_HKDF_SHA384, 48 },
|
||||
{ ssl_hash_sha512, CKM_NSS_HKDF_SHA512, 64 }
|
||||
{ ssl_hash_sha256, CKM_SHA256, 32 },
|
||||
{ ssl_hash_sha384, CKM_SHA384, 48 },
|
||||
{ ssl_hash_sha512, CKM_SHA512, 64 }
|
||||
};
|
||||
|
||||
SECStatus
|
||||
tls13_HkdfExtract(PK11SymKey *ikm1, PK11SymKey *ikm2in, SSLHashType baseHash,
|
||||
tls13_HkdfExtract(PK11SymKey *ikm1, PK11SymKey *ikm2, SSLHashType baseHash,
|
||||
PK11SymKey **prkp)
|
||||
{
|
||||
CK_NSS_HKDFParams params;
|
||||
CK_HKDF_PARAMS params;
|
||||
SECItem paramsi;
|
||||
SECStatus rv;
|
||||
SECItem *salt;
|
||||
PK11SymKey *prk;
|
||||
static const PRUint8 zeroKeyBuf[HASH_LENGTH_MAX];
|
||||
PK11SymKey *zeroKey = NULL;
|
||||
SECItem zeroKeyItem = { siBuffer, CONST_CAST(PRUint8, zeroKeyBuf), kTlsHkdfInfo[baseHash].hashSize };
|
||||
PK11SlotInfo *slot = NULL;
|
||||
PK11SymKey *ikm2;
|
||||
PK11SymKey *newIkm2 = NULL;
|
||||
PK11SymKey *newIkm1 = NULL;
|
||||
SECStatus rv;
|
||||
|
||||
params.bExtract = CK_TRUE;
|
||||
params.bExpand = CK_FALSE;
|
||||
params.prfHashMechanism = kTlsHkdfInfo[baseHash].pkcs11Mech;
|
||||
params.pInfo = NULL;
|
||||
params.ulInfoLen = 0UL;
|
||||
params.pSalt = NULL;
|
||||
params.ulSaltLen = 0UL;
|
||||
params.hSaltKey = CK_INVALID_HANDLE;
|
||||
|
||||
if (ikm1) {
|
||||
/* TODO(ekr@rtfm.com): This violates the PKCS#11 key boundary
|
||||
* but is imposed on us by the present HKDF interface. */
|
||||
rv = PK11_ExtractKeyValue(ikm1);
|
||||
if (rv != SECSuccess)
|
||||
return rv;
|
||||
|
||||
salt = PK11_GetKeyData(ikm1);
|
||||
if (!salt)
|
||||
return SECFailure;
|
||||
|
||||
params.pSalt = salt->data;
|
||||
params.ulSaltLen = salt->len;
|
||||
PORT_Assert(salt->len > 0);
|
||||
if (!ikm1) {
|
||||
/* PKCS #11 v3.0 has and explict NULL value, which equates to
|
||||
* a sequence of zeros equal in length to the HMAC. */
|
||||
params.ulSaltType = CKF_HKDF_SALT_NULL;
|
||||
} else {
|
||||
/* Per documentation for CKM_NSS_HKDF_*:
|
||||
*
|
||||
* If the optional salt is given, it is used; otherwise, the salt is
|
||||
* set to a sequence of zeros equal in length to the HMAC output.
|
||||
*/
|
||||
params.pSalt = NULL;
|
||||
params.ulSaltLen = 0UL;
|
||||
/* PKCS #11 v3.0 can take the salt as a key handle */
|
||||
params.hSaltKey = PK11_GetSymKeyHandle(ikm1);
|
||||
params.ulSaltType = CKF_HKDF_SALT_KEY;
|
||||
|
||||
/* if we have both keys, make sure they are in the same slot */
|
||||
if (ikm2) {
|
||||
rv = PK11_SymKeysToSameSlot(CKM_HKDF_DERIVE,
|
||||
CKA_DERIVE, CKA_DERIVE,
|
||||
ikm2, ikm1, &newIkm2, &newIkm1);
|
||||
if (rv != SECSuccess) {
|
||||
SECItem *salt;
|
||||
/* couldn't move the keys, try extracting the salt */
|
||||
rv = PK11_ExtractKeyValue(ikm1);
|
||||
if (rv != SECSuccess)
|
||||
return rv;
|
||||
salt = PK11_GetKeyData(ikm1);
|
||||
if (!salt)
|
||||
return SECFailure;
|
||||
PORT_Assert(salt->len > 0);
|
||||
/* Set up for Salt as Data instead of Salt as key */
|
||||
params.pSalt = salt->data;
|
||||
params.ulSaltLen = salt->len;
|
||||
params.ulSaltType = CKF_HKDF_SALT_DATA;
|
||||
}
|
||||
/* use the new keys */
|
||||
if (newIkm1) {
|
||||
/* we've moved the key, get the handle for the new key */
|
||||
params.hSaltKey = PK11_GetSymKeyHandle(newIkm1);
|
||||
/* we don't use ikm1 after this, so don't bother setting it */
|
||||
}
|
||||
if (newIkm2) {
|
||||
/* new ikm2 key, use the new key */
|
||||
ikm2 = newIkm2;
|
||||
}
|
||||
}
|
||||
}
|
||||
paramsi.data = (unsigned char *)¶ms;
|
||||
paramsi.len = sizeof(params);
|
||||
|
|
@ -80,40 +102,34 @@ tls13_HkdfExtract(PK11SymKey *ikm1, PK11SymKey *ikm2in, SSLHashType baseHash,
|
|||
PORT_Assert(kTlsHkdfInfo[baseHash].hash == baseHash);
|
||||
|
||||
/* A zero ikm2 is a key of hash-length 0s. */
|
||||
if (!ikm2in) {
|
||||
SECItem zeroItem = {
|
||||
siBuffer,
|
||||
(unsigned char *)zeroKeyBuf,
|
||||
kTlsHkdfInfo[baseHash].hashSize
|
||||
};
|
||||
slot = PK11_GetInternalSlot();
|
||||
if (!ikm2) {
|
||||
/* if we have ikm1, put the zero key in the same slot */
|
||||
slot = ikm1 ? PK11_GetSlotFromKey(ikm1) : PK11_GetBestSlot(CKM_HKDF_DERIVE, NULL);
|
||||
if (!slot) {
|
||||
return SECFailure;
|
||||
}
|
||||
zeroKey = PK11_ImportSymKey(slot,
|
||||
kTlsHkdfInfo[baseHash].pkcs11Mech,
|
||||
PK11_OriginUnwrap,
|
||||
CKA_DERIVE, &zeroItem, NULL);
|
||||
if (!zeroKey)
|
||||
|
||||
newIkm2 = PK11_ImportDataKey(slot, CKM_HKDF_DERIVE, PK11_OriginUnwrap,
|
||||
CKA_DERIVE, &zeroKeyItem, NULL);
|
||||
if (!newIkm2) {
|
||||
return SECFailure;
|
||||
ikm2 = zeroKey;
|
||||
} else {
|
||||
ikm2 = ikm2in;
|
||||
}
|
||||
ikm2 = newIkm2;
|
||||
}
|
||||
PORT_Assert(ikm2);
|
||||
|
||||
PRINT_BUF(50, (NULL, "HKDF Extract: IKM1/Salt", params.pSalt, params.ulSaltLen));
|
||||
PRINT_KEY(50, (NULL, "HKDF Extract: IKM2", ikm2));
|
||||
|
||||
prk = PK11_Derive(ikm2, kTlsHkdfInfo[baseHash].pkcs11Mech,
|
||||
¶msi, kTlsHkdfInfo[baseHash].pkcs11Mech,
|
||||
CKA_DERIVE, kTlsHkdfInfo[baseHash].hashSize);
|
||||
if (zeroKey)
|
||||
PK11_FreeSymKey(zeroKey);
|
||||
prk = PK11_Derive(ikm2, CKM_HKDF_DERIVE, ¶msi, CKM_HKDF_DERIVE,
|
||||
CKA_DERIVE, 0);
|
||||
PK11_FreeSymKey(newIkm2);
|
||||
PK11_FreeSymKey(newIkm1);
|
||||
if (slot)
|
||||
PK11_FreeSlot(slot);
|
||||
if (!prk)
|
||||
if (!prk) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
PRINT_KEY(50, (NULL, "HKDF Extract", prk));
|
||||
*prkp = prk;
|
||||
|
|
@ -122,13 +138,14 @@ tls13_HkdfExtract(PK11SymKey *ikm1, PK11SymKey *ikm2in, SSLHashType baseHash,
|
|||
}
|
||||
|
||||
SECStatus
|
||||
tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash,
|
||||
const PRUint8 *handshakeHash, unsigned int handshakeHashLen,
|
||||
const char *label, unsigned int labelLen,
|
||||
CK_MECHANISM_TYPE algorithm, unsigned int keySize,
|
||||
PK11SymKey **keyp)
|
||||
tls13_HkdfExpandLabelGeneral(CK_MECHANISM_TYPE deriveMech, PK11SymKey *prk,
|
||||
SSLHashType baseHash,
|
||||
const PRUint8 *handshakeHash, unsigned int handshakeHashLen,
|
||||
const char *label, unsigned int labelLen,
|
||||
CK_MECHANISM_TYPE algorithm, unsigned int keySize,
|
||||
SSLProtocolVariant variant, PK11SymKey **keyp)
|
||||
{
|
||||
CK_NSS_HKDFParams params;
|
||||
CK_HKDF_PARAMS params;
|
||||
SECItem paramsi = { siBuffer, NULL, 0 };
|
||||
/* Size of info array needs to be big enough to hold the maximum Prefix,
|
||||
* Label, plus HandshakeHash. If it's ever to small, the code will abort.
|
||||
|
|
@ -137,8 +154,12 @@ tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash,
|
|||
sslBuffer infoBuf = SSL_BUFFER(info);
|
||||
PK11SymKey *derived;
|
||||
SECStatus rv;
|
||||
const char *kLabelPrefix = "tls13 ";
|
||||
const unsigned int kLabelPrefixLen = strlen(kLabelPrefix);
|
||||
const char *kLabelPrefixTls = "tls13 ";
|
||||
const char *kLabelPrefixDtls = "dtls13";
|
||||
const unsigned int kLabelPrefixLen =
|
||||
(variant == ssl_variant_stream) ? strlen(kLabelPrefixTls) : strlen(kLabelPrefixDtls);
|
||||
const char *kLabelPrefix =
|
||||
(variant == ssl_variant_stream) ? kLabelPrefixTls : kLabelPrefixDtls;
|
||||
|
||||
PORT_Assert(prk);
|
||||
PORT_Assert(keyp);
|
||||
|
|
@ -192,17 +213,18 @@ tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash,
|
|||
|
||||
params.bExtract = CK_FALSE;
|
||||
params.bExpand = CK_TRUE;
|
||||
params.prfHashMechanism = kTlsHkdfInfo[baseHash].pkcs11Mech;
|
||||
params.pInfo = SSL_BUFFER_BASE(&infoBuf);
|
||||
params.ulInfoLen = SSL_BUFFER_LEN(&infoBuf);
|
||||
paramsi.data = (unsigned char *)¶ms;
|
||||
paramsi.len = sizeof(params);
|
||||
|
||||
derived = PK11_DeriveWithFlags(prk, kTlsHkdfInfo[baseHash].pkcs11Mech,
|
||||
derived = PK11_DeriveWithFlags(prk, deriveMech,
|
||||
¶msi, algorithm,
|
||||
CKA_DERIVE, keySize,
|
||||
CKF_SIGN | CKF_VERIFY);
|
||||
if (!derived)
|
||||
if (!derived) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
*keyp = derived;
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
219
security/nss/lib/ssl/tls13psk.c
Normal file
219
security/nss/lib/ssl/tls13psk.c
Normal 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;
|
||||
}
|
||||
58
security/nss/lib/ssl/tls13psk.h
Normal file
58
security/nss/lib/ssl/tls13psk.h
Normal 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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */)) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue