summaryrefslogtreecommitdiff
path: root/security/nss/lib/ssl
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@wolfbeast.com>2020-01-02 21:06:40 +0100
committerwolfbeast <mcwerewolf@wolfbeast.com>2020-01-02 21:06:40 +0100
commitf4a12fc67689a830e9da1c87fd11afe5bc09deb3 (patch)
tree211ae0cd022a6c11b0026ecc7761a550c584583c /security/nss/lib/ssl
parentf7d30133221896638f7bf4f66c504255c4b14f48 (diff)
downloaduxp-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.tar.gz
Issue #1338 - Part 2: Update NSS to 3.48-RTM
Diffstat (limited to 'security/nss/lib/ssl')
-rw-r--r--security/nss/lib/ssl/SSLerrs.h26
-rw-r--r--security/nss/lib/ssl/authcert.c14
-rw-r--r--security/nss/lib/ssl/config.mk4
-rw-r--r--security/nss/lib/ssl/dtls13con.c4
-rw-r--r--security/nss/lib/ssl/dtlscon.c1
-rw-r--r--security/nss/lib/ssl/manifest.mn2
-rw-r--r--security/nss/lib/ssl/ssl.gyp13
-rw-r--r--security/nss/lib/ssl/ssl.h29
-rw-r--r--security/nss/lib/ssl/ssl3con.c1088
-rw-r--r--security/nss/lib/ssl/ssl3ecc.c4
-rw-r--r--security/nss/lib/ssl/ssl3ext.c14
-rw-r--r--security/nss/lib/ssl/ssl3ext.h13
-rw-r--r--security/nss/lib/ssl/ssl3exthandle.c24
-rw-r--r--security/nss/lib/ssl/ssl3gthr.c251
-rw-r--r--security/nss/lib/ssl/ssl3prot.h1
-rw-r--r--security/nss/lib/ssl/sslauth.c2
-rw-r--r--security/nss/lib/ssl/sslcert.c109
-rw-r--r--security/nss/lib/ssl/sslcert.h7
-rw-r--r--security/nss/lib/ssl/sslcon.c37
-rw-r--r--security/nss/lib/ssl/ssldef.c2
-rw-r--r--security/nss/lib/ssl/sslencode.c9
-rw-r--r--security/nss/lib/ssl/sslerr.h6
-rw-r--r--security/nss/lib/ssl/sslexp.h347
-rw-r--r--security/nss/lib/ssl/sslimpl.h167
-rw-r--r--security/nss/lib/ssl/sslinfo.c169
-rw-r--r--security/nss/lib/ssl/sslnonce.c69
-rw-r--r--security/nss/lib/ssl/sslprimitive.c274
-rw-r--r--security/nss/lib/ssl/sslsecur.c105
-rw-r--r--security/nss/lib/ssl/sslsnce.c128
-rw-r--r--security/nss/lib/ssl/sslsock.c246
-rw-r--r--security/nss/lib/ssl/sslspec.c12
-rw-r--r--security/nss/lib/ssl/sslspec.h33
-rw-r--r--security/nss/lib/ssl/sslt.h72
-rw-r--r--security/nss/lib/ssl/tls13con.c773
-rw-r--r--security/nss/lib/ssl/tls13con.h30
-rw-r--r--security/nss/lib/ssl/tls13esni.c12
-rw-r--r--security/nss/lib/ssl/tls13esni.h4
-rw-r--r--security/nss/lib/ssl/tls13exthandle.c129
-rw-r--r--security/nss/lib/ssl/tls13exthandle.h15
-rw-r--r--security/nss/lib/ssl/tls13hashstate.c6
-rw-r--r--security/nss/lib/ssl/tls13hkdf.c17
-rw-r--r--security/nss/lib/ssl/tls13replay.c192
-rw-r--r--security/nss/lib/ssl/tls13subcerts.c767
-rw-r--r--security/nss/lib/ssl/tls13subcerts.h56
44 files changed, 4177 insertions, 1106 deletions
diff --git a/security/nss/lib/ssl/SSLerrs.h b/security/nss/lib/ssl/SSLerrs.h
index 9be2194949..87b59b1e8d 100644
--- a/security/nss/lib/ssl/SSLerrs.h
+++ b/security/nss/lib/ssl/SSLerrs.h
@@ -5,14 +5,14 @@
#define UNUSED_ERROR(x) ER3(SSL_ERROR_UNUSED_##x, (SSL_ERROR_BASE + x), \
"Unrecognized SSL error_code.")
-/* SSL-specific security error codes */
+/* SSL-specific security error codes */
/* caller must include "sslerr.h" */
ER3(SSL_ERROR_EXPORT_ONLY_SERVER, SSL_ERROR_BASE + 0,
- "Unable to communicate securely. Peer does not support high-grade encryption.")
+ "Unable to communicate securely. Peer does not support high-grade encryption.")
ER3(SSL_ERROR_US_ONLY_SERVER, SSL_ERROR_BASE + 1,
- "Unable to communicate securely. Peer requires high-grade encryption which is not supported.")
+ "Unable to communicate securely. Peer requires high-grade encryption which is not supported.")
ER3(SSL_ERROR_NO_CYPHER_OVERLAP, SSL_ERROR_BASE + 2,
"Cannot communicate securely with peer: no common encryption algorithm(s).")
@@ -197,7 +197,7 @@ ER3(SSL_ERROR_RX_UNKNOWN_ALERT, (SSL_ERROR_BASE + 57),
"SSL received an alert record with an unknown alert description.")
/*
- * Received an alert reporting what we did wrong. (more alerts above)
+ * Received an alert reporting what we did wrong. (more alerts above)
*/
ER3(SSL_ERROR_CLOSE_NOTIFY_ALERT, (SSL_ERROR_BASE + 58),
"SSL peer has closed this connection.")
@@ -564,3 +564,21 @@ ER3(SSL_ERROR_MISSING_ESNI_EXTENSION, (SSL_ERROR_BASE + 178),
ER3(SSL_ERROR_RX_UNEXPECTED_RECORD_TYPE, (SSL_ERROR_BASE + 179),
"SSL received an unexpected record type.")
+
+ER3(SSL_ERROR_MISSING_POST_HANDSHAKE_AUTH_EXTENSION, (SSL_ERROR_BASE + 180),
+ "SSL cannot send a CertificateRequest because the client doesn't support post-handshake authentication.")
+
+ER3(SSL_ERROR_RX_CERTIFICATE_REQUIRED_ALERT, (SSL_ERROR_BASE + 181),
+ "SSL received a certificate_required alert.")
+
+ER3(SSL_ERROR_DC_CERT_VERIFY_ALG_MISMATCH, (SSL_ERROR_BASE + 182),
+ "SSL received a delegated credential with unexpected certificate verification algorithm.")
+
+ER3(SSL_ERROR_DC_BAD_SIGNATURE, (SSL_ERROR_BASE + 183),
+ "SSL received a delegated credential with an invalid signature.")
+
+ER3(SSL_ERROR_DC_INVALID_KEY_USAGE, (SSL_ERROR_BASE + 184),
+ "SSL received a delegated credential from a certificate with invalid key usage.")
+
+ER3(SSL_ERROR_DC_EXPIRED, (SSL_ERROR_BASE + 185),
+ "SSL received a delegated credential that expired.")
diff --git a/security/nss/lib/ssl/authcert.c b/security/nss/lib/ssl/authcert.c
index d05b30a72c..737b4e797d 100644
--- a/security/nss/lib/ssl/authcert.c
+++ b/security/nss/lib/ssl/authcert.c
@@ -20,12 +20,12 @@
#include "sslimpl.h"
/*
- * This callback used by SSL to pull client sertificate upon
+ * This callback used by SSL to pull client certificate upon
* server request
*/
SECStatus
NSS_GetClientAuthData(void *arg,
- PRFileDesc *socket,
+ PRFileDesc *fd,
struct CERTDistNamesStr *caNames,
struct CERTCertificateStr **pRetCert,
struct SECKEYPrivateKeyStr **pRetKey)
@@ -33,10 +33,14 @@ NSS_GetClientAuthData(void *arg,
CERTCertificate *cert = NULL;
SECKEYPrivateKey *privkey = NULL;
char *chosenNickName = (char *)arg; /* CONST */
- void *proto_win = NULL;
SECStatus rv = SECFailure;
- proto_win = SSL_RevealPinArg(socket);
+ sslSocket *ss = ssl_FindSocket(fd);
+ if (!ss) {
+ return SECFailure;
+ }
+ void *proto_win = SSL_RevealPinArg(fd);
+ PRTime now = ssl_Time(ss);
if (chosenNickName) {
cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(),
@@ -64,7 +68,7 @@ NSS_GetClientAuthData(void *arg,
if (!cert)
continue;
/* Only check unexpired certs */
- if (CERT_CheckCertValidTimes(cert, ssl_TimeUsec(), PR_TRUE) !=
+ if (CERT_CheckCertValidTimes(cert, now, PR_TRUE) !=
secCertTimeValid) {
CERT_DestroyCertificate(cert);
continue;
diff --git a/security/nss/lib/ssl/config.mk b/security/nss/lib/ssl/config.mk
index b901a8830d..d13613f78c 100644
--- a/security/nss/lib/ssl/config.mk
+++ b/security/nss/lib/ssl/config.mk
@@ -60,7 +60,3 @@ endif
ifdef NSS_DISABLE_TLS_1_3
DEFINES += -DNSS_DISABLE_TLS_1_3
endif
-
-ifeq (,$(filter-out DragonFly FreeBSD Linux NetBSD OpenBSD, $(OS_TARGET)))
-CFLAGS += -std=gnu99
-endif
diff --git a/security/nss/lib/ssl/dtls13con.c b/security/nss/lib/ssl/dtls13con.c
index 81d196deee..0c4fc7fcd1 100644
--- a/security/nss/lib/ssl/dtls13con.c
+++ b/security/nss/lib/ssl/dtls13con.c
@@ -482,7 +482,7 @@ dtls13_HandleAck(sslSocket *ss, sslBuffer *databuf)
* for the holddown period to process retransmitted Finisheds.
*/
if (!ss->sec.isServer && (ss->ssl3.hs.ws == idle_handshake)) {
- ssl_CipherSpecReleaseByEpoch(ss, CipherSpecRead,
+ ssl_CipherSpecReleaseByEpoch(ss, ssl_secret_read,
TrafficKeyHandshake);
}
}
@@ -509,6 +509,6 @@ dtls13_HolddownTimerCb(sslSocket *ss)
{
SSL_TRC(10, ("%d: SSL3[%d]: holddown timer fired",
SSL_GETPID(), ss->fd));
- ssl_CipherSpecReleaseByEpoch(ss, CipherSpecRead, TrafficKeyHandshake);
+ ssl_CipherSpecReleaseByEpoch(ss, ssl_secret_read, TrafficKeyHandshake);
ssl_ClearPRCList(&ss->ssl3.hs.dtlsRcvdHandshake, NULL);
}
diff --git a/security/nss/lib/ssl/dtlscon.c b/security/nss/lib/ssl/dtlscon.c
index a5c604bca3..bbd2f6d79b 100644
--- a/security/nss/lib/ssl/dtlscon.c
+++ b/security/nss/lib/ssl/dtlscon.c
@@ -542,7 +542,6 @@ dtls_QueueMessage(sslSocket *ss, SSLContentType ct,
/* Add DTLS handshake message to the pending queue
* Empty the sendBuf buffer.
- * This function returns SECSuccess or SECFailure, never SECWouldBlock.
* Always set sendBuf.len to 0, even when returning SECFailure.
*
* Called from:
diff --git a/security/nss/lib/ssl/manifest.mn b/security/nss/lib/ssl/manifest.mn
index fe9470bd01..83df8c0b87 100644
--- a/security/nss/lib/ssl/manifest.mn
+++ b/security/nss/lib/ssl/manifest.mn
@@ -55,7 +55,9 @@ CSRCS = \
tls13replay.c \
sslcert.c \
sslgrp.c \
+ sslprimitive.c \
tls13esni.c \
+ tls13subcerts.c \
$(NULL)
LIBRARY_NAME = ssl
diff --git a/security/nss/lib/ssl/ssl.gyp b/security/nss/lib/ssl/ssl.gyp
index 2e28f67757..3e1b5531a6 100644
--- a/security/nss/lib/ssl/ssl.gyp
+++ b/security/nss/lib/ssl/ssl.gyp
@@ -35,6 +35,7 @@
'sslinit.c',
'sslmutex.c',
'sslnonce.c',
+ 'sslprimitive.c',
'sslreveal.c',
'sslsecur.c',
'sslsnce.c',
@@ -48,6 +49,7 @@
'tls13hashstate.c',
'tls13hkdf.c',
'tls13replay.c',
+ 'tls13subcerts.c',
],
'conditions': [
[ 'OS=="win"', {
@@ -68,9 +70,9 @@
'UNSAFE_FUZZER_MODE',
],
}],
- [ 'OS=="dragonfly" or OS=="freebsd" or OS=="netbsd" or OS=="openbsd" or OS=="linux"', {
- 'cflags': [
- '-std=gnu99',
+ [ 'enable_sslkeylogfile==1', {
+ 'defines': [
+ 'NSS_ALLOW_SSLKEYLOGFILE',
],
}],
],
@@ -92,11 +94,6 @@
}
}
],
- 'target_defaults': {
- 'defines': [
- 'NSS_ALLOW_SSLKEYLOGFILE=1'
- ]
- },
'variables': {
'module': 'nss'
}
diff --git a/security/nss/lib/ssl/ssl.h b/security/nss/lib/ssl/ssl.h
index fc4a4a70cb..dc5a9d4cd5 100644
--- a/security/nss/lib/ssl/ssl.h
+++ b/security/nss/lib/ssl/ssl.h
@@ -190,7 +190,7 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd);
/* Use draft-ietf-tls-session-hash. Controls whether we offer the
* extended_master_secret extension which, when accepted, hashes
* the handshake transcript into the master secret. This option is
- * disabled by default.
+ * enabled by default.
*/
#define SSL_ENABLE_EXTENDED_MASTER_SECRET 30
@@ -299,6 +299,33 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd);
* This is disabled by default and will be removed in a future version. */
#define SSL_ENABLE_V2_COMPATIBLE_HELLO 38
+/* Enables the post-handshake authentication in TLS 1.3. If it is set
+ * to PR_TRUE, the client will send the "post_handshake_auth"
+ * extension to indicate that it will process CertificateRequest
+ * messages after handshake.
+ *
+ * This option applies only to clients. For a server, the
+ * SSL_SendCertificateRequest can be used to request post-handshake
+ * authentication.
+ */
+#define SSL_ENABLE_POST_HANDSHAKE_AUTH 39
+
+/* 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).
+ *
+ * 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
+ * certificate is used to verify the DC, which in turn is used to verify the
+ * handshake. DCs effectively extend the certificate chain by one, but only
+ * within the context of TLS. Once issued, DCs can't be revoked; in order to
+ * 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.
+ */
+#define SSL_ENABLE_DELEGATED_CREDENTIALS 40
+
#ifdef SSL_DEPRECATED_FUNCTION
/* Old deprecated function names */
SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRIntn on);
diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c
index d98521a526..f3c723bbc2 100644
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -21,6 +21,7 @@
#include "sslerr.h"
#include "ssl3ext.h"
#include "ssl3exthandle.h"
+#include "tls13subcerts.h"
#include "prtime.h"
#include "prinrval.h"
#include "prerror.h"
@@ -65,6 +66,7 @@ static CK_MECHANISM_TYPE ssl3_GetHashMechanismByHashType(SSLHashType hashType);
static CK_MECHANISM_TYPE ssl3_GetMgfMechanismByHashType(SSLHashType hash);
PRBool ssl_IsRsaPssSignatureScheme(SSLSignatureScheme scheme);
PRBool ssl_IsRsaPkcs1SignatureScheme(SSLSignatureScheme scheme);
+PRBool ssl_IsDsaSignatureScheme(SSLSignatureScheme scheme);
const PRUint8 ssl_hello_retry_random[] = {
0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11,
@@ -554,10 +556,9 @@ SSL_AtomicIncrementLong(long *x)
}
}
-static PRBool
-ssl3_CipherSuiteAllowedForVersionRange(
- ssl3CipherSuite cipherSuite,
- const SSLVersionRange *vrange)
+PRBool
+ssl3_CipherSuiteAllowedForVersionRange(ssl3CipherSuite cipherSuite,
+ const SSLVersionRange *vrange)
{
switch (cipherSuite) {
case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
@@ -737,7 +738,7 @@ ssl_KEAEnabled(const sslSocket *ss, SSLKEAType keaType)
}
static PRBool
-ssl_HasCert(const sslSocket *ss, SSLAuthType authType)
+ssl_HasCert(const sslSocket *ss, PRUint16 maxVersion, SSLAuthType authType)
{
PRCList *cursor;
if (authType == ssl_auth_null || authType == ssl_auth_psk || authType == ssl_auth_tls13_any) {
@@ -757,8 +758,13 @@ ssl_HasCert(const sslSocket *ss, SSLAuthType authType)
* enabled, so this will essentially do nothing (unless we implement
* curve configuration). However, once we have seen the
* supported_groups extension and this is called from config_match(),
- * this will filter out certificates with an unsupported curve. */
- if ((authType == ssl_auth_ecdsa ||
+ * this will filter out certificates with an unsupported curve.
+ *
+ * If we might negotiate TLS 1.3, skip this test as group configuration
+ * doesn't affect choices in TLS 1.3.
+ */
+ if (maxVersion < SSL_LIBRARY_VERSION_TLS_1_3 &&
+ (authType == ssl_auth_ecdsa ||
authType == ssl_auth_ecdh_ecdsa ||
authType == ssl_auth_ecdh_rsa) &&
!ssl_NamedGroupEnabled(ss, cert->namedCurve)) {
@@ -767,7 +773,114 @@ ssl_HasCert(const sslSocket *ss, SSLAuthType authType)
return PR_TRUE;
}
if (authType == ssl_auth_rsa_sign) {
- return ssl_HasCert(ss, ssl_auth_rsa_pss);
+ return ssl_HasCert(ss, maxVersion, ssl_auth_rsa_pss);
+ }
+ return PR_FALSE;
+}
+
+/* Check that a signature scheme is accepted.
+ * Both by policy and by having a token that supports it. */
+static PRBool
+ssl_SignatureSchemeAccepted(PRUint16 minVersion,
+ SSLSignatureScheme scheme)
+{
+ /* Disable RSA-PSS schemes if there are no tokens to verify them. */
+ if (ssl_IsRsaPssSignatureScheme(scheme)) {
+ if (!PK11_TokenExists(auth_alg_defs[ssl_auth_rsa_pss])) {
+ return PR_FALSE;
+ }
+ } else if (ssl_IsRsaPkcs1SignatureScheme(scheme)) {
+ /* Disable PKCS#1 signatures if we are limited to TLS 1.3. */
+ if (minVersion >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ return PR_FALSE;
+ }
+ } else if (ssl_IsDsaSignatureScheme(scheme)) {
+ /* DSA: not in TLS 1.3, and check policy. */
+ if (minVersion >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ return PR_FALSE;
+ }
+ PRUint32 dsaPolicy;
+ SECStatus rv = NSS_GetAlgorithmPolicy(SEC_OID_ANSIX9_DSA_SIGNATURE,
+ &dsaPolicy);
+ if (rv == SECSuccess && (dsaPolicy & NSS_USE_ALG_IN_SSL_KX) == 0) {
+ return PR_FALSE;
+ }
+ }
+
+ /* Hash policy. */
+ PRUint32 hashPolicy;
+ SSLHashType hashType = ssl_SignatureSchemeToHashType(scheme);
+ SECOidTag hashOID = ssl3_HashTypeToOID(hashType);
+ SECStatus rv = NSS_GetAlgorithmPolicy(hashOID, &hashPolicy);
+ if (rv == SECSuccess && (hashPolicy & NSS_USE_ALG_IN_SSL_KX) == 0) {
+ return PR_FALSE;
+ }
+ return PR_TRUE;
+}
+
+static SECStatus
+ssl_CheckSignatureSchemes(sslSocket *ss)
+{
+ if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_2) {
+ return SECSuccess;
+ }
+
+ /* If this is a server using TLS 1.3, we just need to have one signature
+ * scheme for which we have a usable certificate.
+ *
+ * Note: Certificates for earlier TLS versions are checked along with the
+ * cipher suite in ssl3_config_match_init. */
+ if (ss->sec.isServer && ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ PRBool foundCert = PR_FALSE;
+ for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
+ SSLAuthType authType =
+ ssl_SignatureSchemeToAuthType(ss->ssl3.signatureSchemes[i]);
+ if (ssl_HasCert(ss, ss->vrange.max, authType)) {
+ foundCert = PR_TRUE;
+ break;
+ }
+ }
+ if (!foundCert) {
+ PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
+ return SECFailure;
+ }
+ }
+
+ /* Ensure that there is a signature scheme that can be accepted.*/
+ for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
+ if (ssl_SignatureSchemeAccepted(ss->vrange.min,
+ ss->ssl3.signatureSchemes[i])) {
+ return SECSuccess;
+ }
+ }
+ PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
+ return SECFailure;
+}
+
+/* For a server, check that a signature scheme that can be used with the
+ * provided authType is both enabled and usable. */
+static PRBool
+ssl_HasSignatureScheme(const sslSocket *ss, SSLAuthType authType)
+{
+ PORT_Assert(ss->sec.isServer);
+ PORT_Assert(ss->ssl3.hs.preliminaryInfo & ssl_preinfo_version);
+ PORT_Assert(authType != ssl_auth_null);
+ PORT_Assert(authType != ssl_auth_tls13_any);
+ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_2 ||
+ authType == ssl_auth_rsa_decrypt ||
+ authType == ssl_auth_ecdh_rsa ||
+ authType == ssl_auth_ecdh_ecdsa) {
+ return PR_TRUE;
+ }
+ for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
+ SSLSignatureScheme scheme = ss->ssl3.signatureSchemes[i];
+ SSLAuthType schemeAuthType = ssl_SignatureSchemeToAuthType(scheme);
+ PRBool acceptable = authType == schemeAuthType ||
+ (schemeAuthType == ssl_auth_rsa_pss &&
+ authType == ssl_auth_rsa_sign);
+ if (acceptable && ssl_SignatureSchemeAccepted(ss->version, scheme)) {
+ return PR_TRUE;
+ }
}
return PR_FALSE;
}
@@ -798,6 +911,9 @@ ssl3_config_match_init(sslSocket *ss)
if (SSL_ALL_VERSIONS_DISABLED(&ss->vrange)) {
return 0;
}
+ if (ssl_CheckSignatureSchemes(ss) != SECSuccess) {
+ return 0; /* Code already set. */
+ }
ssl_FilterSupportedGroups(ss);
for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
@@ -820,10 +936,11 @@ ssl3_config_match_init(sslSocket *ss)
authType = kea_defs[cipher_def->key_exchange_alg].authKeyType;
if (authType != ssl_auth_null && authType != ssl_auth_tls13_any) {
- if (ss->sec.isServer && !ssl_HasCert(ss, authType)) {
+ if (ss->sec.isServer &&
+ !(ssl_HasCert(ss, ss->vrange.max, authType) &&
+ ssl_HasSignatureScheme(ss, authType))) {
suite->isPresent = PR_FALSE;
- }
- if (!PK11_TokenExists(auth_alg_defs[authType])) {
+ } else if (!PK11_TokenExists(auth_alg_defs[authType])) {
suite->isPresent = PR_FALSE;
}
}
@@ -862,6 +979,11 @@ ssl3_config_match(const ssl3CipherSuiteCfg *suite, PRUint8 policy,
const ssl3CipherSuiteDef *cipher_def;
const ssl3KEADef *kea_def;
+ if (!suite) {
+ PORT_Assert(suite);
+ return PR_FALSE;
+ }
+
PORT_Assert(policy != SSL_NOT_ALLOWED);
if (policy == SSL_NOT_ALLOWED)
return PR_FALSE;
@@ -882,7 +1004,7 @@ ssl3_config_match(const ssl3CipherSuiteCfg *suite, PRUint8 policy,
return PR_FALSE;
}
- if (ss->sec.isServer && !ssl_HasCert(ss, kea_def->authKeyType)) {
+ if (ss->sec.isServer && !ssl_HasCert(ss, vrange->max, kea_def->authKeyType)) {
return PR_FALSE;
}
@@ -900,8 +1022,9 @@ count_cipher_suites(sslSocket *ss, PRUint8 policy)
return 0;
}
for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
- if (ssl3_config_match(&ss->cipherSuites[i], policy, &ss->vrange, ss))
+ if (ssl3_config_match(&ss->cipherSuites[i], policy, &ss->vrange, ss)) {
count++;
+ }
}
if (count == 0) {
PORT_SetError(SSL_ERROR_SSL_DISABLED);
@@ -909,12 +1032,33 @@ count_cipher_suites(sslSocket *ss, PRUint8 policy)
return count;
}
+/* For TLS 1.3, when resuming, check for a ciphersuite that is both compatible
+ * with the identified ciphersuite and enabled. */
+static PRBool
+tls13_ResumptionCompatible(sslSocket *ss, ssl3CipherSuite suite)
+{
+ SSLVersionRange vrange = { SSL_LIBRARY_VERSION_TLS_1_3,
+ SSL_LIBRARY_VERSION_TLS_1_3 };
+ SSLHashType hash = tls13_GetHashForCipherSuite(suite);
+ for (unsigned int i = 0; i < PR_ARRAY_SIZE(cipher_suite_defs); i++) {
+ if (cipher_suite_defs[i].prf_hash == hash) {
+ const ssl3CipherSuiteCfg *suiteCfg =
+ ssl_LookupCipherSuiteCfg(cipher_suite_defs[i].cipher_suite,
+ ss->cipherSuites);
+ if (suite && ssl3_config_match(suiteCfg, ss->ssl3.policy, &vrange, ss)) {
+ return PR_TRUE;
+ }
+ }
+ }
+ return PR_FALSE;
+}
+
/*
* Null compression, mac and encryption functions
*/
SECStatus
-Null_Cipher(void *ctx, unsigned char *output, int *outputLen, int maxOutputLen,
- const unsigned char *input, int inputLen)
+Null_Cipher(void *ctx, unsigned char *output, unsigned int *outputLen, unsigned int maxOutputLen,
+ const unsigned char *input, unsigned int inputLen)
{
if (inputLen > maxOutputLen) {
*outputLen = 0; /* Match PK11_CipherOp in setting outputLen */
@@ -958,6 +1102,12 @@ ssl3_NegotiateVersion(sslSocket *ss, SSL3ProtocolVersion peerVersion,
{
SSL3ProtocolVersion negotiated;
+ /* Prevent negotiating to a lower version in response to a TLS 1.3 HRR. */
+ if (ss->ssl3.hs.helloRetry) {
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION);
+ return SECFailure;
+ }
+
if (SSL_ALL_VERSIONS_DISABLED(&ss->vrange)) {
PORT_SetError(SSL_ERROR_SSL_DISABLED);
return SECFailure;
@@ -1026,15 +1176,13 @@ ssl3_GetNewRandom(SSL3Random random)
return rv;
}
-/* Called by ssl3_SendServerKeyExchange and ssl3_SendCertificateVerify */
SECStatus
-ssl3_SignHashes(sslSocket *ss, SSL3Hashes *hash, SECKEYPrivateKey *key,
- SECItem *buf)
+ssl3_SignHashesWithPrivKey(SSL3Hashes *hash, SECKEYPrivateKey *key,
+ SSLSignatureScheme scheme, PRBool isTls, SECItem *buf)
{
SECStatus rv = SECFailure;
PRBool doDerEncode = PR_FALSE;
- PRBool isTLS = (PRBool)(ss->version > SSL_LIBRARY_VERSION_3_0);
- PRBool useRsaPss = ssl_IsRsaPssSignatureScheme(ss->ssl3.hs.signatureScheme);
+ PRBool useRsaPss = ssl_IsRsaPssSignatureScheme(scheme);
SECItem hashItem;
buf->data = NULL;
@@ -1045,7 +1193,7 @@ ssl3_SignHashes(sslSocket *ss, SSL3Hashes *hash, SECKEYPrivateKey *key,
hashItem.len = hash->len;
break;
case dsaKey:
- doDerEncode = isTLS;
+ doDerEncode = isTls;
/* ssl_hash_none is used to specify the MD5/SHA1 concatenated hash.
* In that case, we use just the SHA1 part. */
if (hash->hashAlg == ssl_hash_none) {
@@ -1122,11 +1270,6 @@ ssl3_SignHashes(sslSocket *ss, SSL3Hashes *hash, SECKEYPrivateKey *key,
}
}
- if (ss->sec.isServer) {
- ss->sec.signatureScheme = ss->ssl3.hs.signatureScheme;
- ss->sec.authType =
- ssl_SignatureSchemeToAuthType(ss->ssl3.hs.signatureScheme);
- }
PRINT_BUF(60, (NULL, "signed hashes", (unsigned char *)buf->data, buf->len));
done:
if (rv != SECSuccess && buf->data) {
@@ -1136,12 +1279,34 @@ done:
return rv;
}
-/* Called from ssl3_HandleServerKeyExchange, ssl3_HandleCertificateVerify */
+/* Called by ssl3_SendServerKeyExchange and ssl3_SendCertificateVerify */
SECStatus
-ssl3_VerifySignedHashes(sslSocket *ss, SSLSignatureScheme scheme, SSL3Hashes *hash,
- SECItem *buf)
+ssl3_SignHashes(sslSocket *ss, SSL3Hashes *hash, SECKEYPrivateKey *key,
+ SECItem *buf)
+{
+ SECStatus rv = SECFailure;
+ PRBool isTLS = (PRBool)(ss->version > SSL_LIBRARY_VERSION_3_0);
+ SSLSignatureScheme scheme = ss->ssl3.hs.signatureScheme;
+
+ rv = ssl3_SignHashesWithPrivKey(hash, key, scheme, isTLS, buf);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ if (ss->sec.isServer) {
+ ss->sec.signatureScheme = scheme;
+ ss->sec.authType = ssl_SignatureSchemeToAuthType(scheme);
+ }
+
+ return SECSuccess;
+}
+
+/* Called from ssl3_VerifySignedHashes and tls13_HandleCertificateVerify. */
+SECStatus
+ssl_VerifySignedHashesWithPubKey(sslSocket *ss, SECKEYPublicKey *key,
+ SSLSignatureScheme scheme,
+ SSL3Hashes *hash, SECItem *buf)
{
- SECKEYPublicKey *key;
SECItem *signature = NULL;
SECStatus rv = SECFailure;
SECItem hashItem;
@@ -1150,14 +1315,7 @@ ssl3_VerifySignedHashes(sslSocket *ss, SSLSignatureScheme scheme, SSL3Hashes *ha
void *pwArg = ss->pkcs11PinArg;
PRBool isRsaPssScheme = ssl_IsRsaPssSignatureScheme(scheme);
- PRINT_BUF(60, (NULL, "check signed hashes",
- buf->data, buf->len));
-
- key = CERT_ExtractPublicKey(ss->sec.peerCert);
- if (key == NULL) {
- ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
- return SECFailure;
- }
+ PRINT_BUF(60, (NULL, "check signed hashes", buf->data, buf->len));
hashAlg = ssl3_HashTypeToOID(hash->hashAlg);
switch (SECKEY_GetPublicKeyType(key)) {
@@ -1265,7 +1423,6 @@ ssl3_VerifySignedHashes(sslSocket *ss, SSLSignatureScheme scheme, SSL3Hashes *ha
}
loser:
- SECKEY_DestroyPublicKey(key);
#ifdef UNSAFE_FUZZER_MODE
rv = SECSuccess;
PORT_SetError(0);
@@ -1273,6 +1430,23 @@ loser:
return rv;
}
+/* Called from ssl3_HandleServerKeyExchange, ssl3_HandleCertificateVerify */
+SECStatus
+ssl3_VerifySignedHashes(sslSocket *ss, SSLSignatureScheme scheme, SSL3Hashes *hash,
+ SECItem *buf)
+{
+ SECKEYPublicKey *pubKey =
+ SECKEY_ExtractPublicKey(&ss->sec.peerCert->subjectPublicKeyInfo);
+ if (pubKey == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
+ return SECFailure;
+ }
+ SECStatus rv = ssl_VerifySignedHashesWithPubKey(ss, pubKey, scheme,
+ hash, buf);
+ SECKEY_DestroyPublicKey(pubKey);
+ return rv;
+}
+
/* Caller must set hiLevel error code. */
/* Called from ssl3_ComputeDHKeyHash
* which are called from ssl3_HandleServerKeyExchange.
@@ -1286,8 +1460,14 @@ ssl3_ComputeCommonKeyHash(SSLHashType hashAlg,
{
SECStatus rv;
SECOidTag hashOID;
+ PRUint32 policy;
if (hashAlg == ssl_hash_none) {
+ if ((NSS_GetAlgorithmPolicy(SEC_OID_SHA1, &policy) == SECSuccess) &&
+ !(policy & NSS_USE_ALG_IN_SSL_KX)) {
+ ssl_MapLowLevelError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
+ return SECFailure;
+ }
rv = PK11_HashBuf(SEC_OID_MD5, hashes->u.s.md5, hashBuf, bufLen);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
@@ -1301,6 +1481,11 @@ ssl3_ComputeCommonKeyHash(SSLHashType hashAlg,
hashes->len = MD5_LENGTH + SHA1_LENGTH;
} else {
hashOID = ssl3_HashTypeToOID(hashAlg);
+ if ((NSS_GetAlgorithmPolicy(hashOID, &policy) == SECSuccess) &&
+ !(policy & NSS_USE_ALG_IN_SSL_KX)) {
+ ssl_MapLowLevelError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
+ return SECFailure;
+ }
hashes->len = HASH_ResultLenByOidTag(hashOID);
if (hashes->len == 0 || hashes->len > sizeof(hashes->u.raw)) {
ssl_MapLowLevelError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
@@ -1395,14 +1580,14 @@ loser:
}
static SECStatus
-ssl3_SetupPendingCipherSpec(sslSocket *ss, CipherSpecDirection direction,
+ssl3_SetupPendingCipherSpec(sslSocket *ss, SSLSecretDirection direction,
const ssl3CipherSuiteDef *suiteDef,
ssl3CipherSpec **specp)
{
ssl3CipherSpec *spec;
const ssl3CipherSpec *prev;
- prev = (direction == CipherSpecWrite) ? ss->ssl3.cwSpec : ss->ssl3.crSpec;
+ prev = (direction == ssl_secret_write) ? ss->ssl3.cwSpec : ss->ssl3.crSpec;
if (prev->epoch == PR_UINT16_MAX) {
PORT_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED);
return SECFailure;
@@ -1418,7 +1603,7 @@ ssl3_SetupPendingCipherSpec(sslSocket *ss, CipherSpecDirection direction,
spec->epoch = prev->epoch + 1;
spec->nextSeqNum = 0;
- if (IS_DTLS(ss) && direction == CipherSpecRead) {
+ if (IS_DTLS(ss) && direction == ssl_secret_read) {
dtls_InitRecvdRecords(&spec->recvdRecords);
}
ssl_SetSpecVersions(ss, spec);
@@ -1472,12 +1657,12 @@ ssl3_SetupBothPendingCipherSpecs(sslSocket *ss)
ss->ssl3.hs.kea_def = &kea_defs[kea];
PORT_Assert(ss->ssl3.hs.kea_def->kea == kea);
- rv = ssl3_SetupPendingCipherSpec(ss, CipherSpecRead, suiteDef,
+ rv = ssl3_SetupPendingCipherSpec(ss, ssl_secret_read, suiteDef,
&ss->ssl3.prSpec);
if (rv != SECSuccess) {
goto loser;
}
- rv = ssl3_SetupPendingCipherSpec(ss, CipherSpecWrite, suiteDef,
+ rv = ssl3_SetupPendingCipherSpec(ss, ssl_secret_write, suiteDef,
&ss->ssl3.pwSpec);
if (rv != SECSuccess) {
goto loser;
@@ -1555,15 +1740,15 @@ ssl3_BuildRecordPseudoHeader(DTLSEpoch epoch,
}
static SECStatus
-ssl3_AESGCM(ssl3KeyMaterial *keys,
+ssl3_AESGCM(const ssl3KeyMaterial *keys,
PRBool doDecrypt,
unsigned char *out,
- int *outlen,
- int maxout,
+ unsigned int *outlen,
+ unsigned int maxout,
const unsigned char *in,
- int inlen,
+ unsigned int inlen,
const unsigned char *additionalData,
- int additionalDataLen)
+ unsigned int additionalDataLen)
{
SECItem param;
SECStatus rv = SECFailure;
@@ -1617,11 +1802,11 @@ ssl3_AESGCM(ssl3KeyMaterial *keys,
}
static SECStatus
-ssl3_ChaCha20Poly1305(ssl3KeyMaterial *keys, PRBool doDecrypt,
- unsigned char *out, int *outlen, int maxout,
- const unsigned char *in, int inlen,
+ssl3_ChaCha20Poly1305(const ssl3KeyMaterial *keys, PRBool doDecrypt,
+ unsigned char *out, unsigned int *outlen, unsigned int maxout,
+ const unsigned char *in, unsigned int inlen,
const unsigned char *additionalData,
- int additionalDataLen)
+ unsigned int additionalDataLen)
{
size_t i;
SECItem param;
@@ -1728,7 +1913,7 @@ ssl3_InitPendingContexts(sslSocket *ss, ssl3CipherSpec *spec)
spec->cipher = (SSLCipher)PK11_CipherOp;
encMechanism = ssl3_Alg2Mech(calg);
- encMode = (spec->direction == CipherSpecWrite) ? CKA_ENCRYPT : CKA_DECRYPT;
+ encMode = (spec->direction == ssl_secret_write) ? CKA_ENCRYPT : CKA_DECRYPT;
/*
* build the context
@@ -2013,7 +2198,7 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec,
unsigned int ivLen = 0;
unsigned char pseudoHeaderBuf[13];
sslBuffer pseudoHeader = SSL_BUFFER(pseudoHeaderBuf);
- int len;
+ unsigned int len;
if (cwSpec->cipherDef->type == type_block &&
cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) {
@@ -2131,15 +2316,15 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec,
memmove(SSL_BUFFER_NEXT(wrBuf) + p1Len, pIn + p1Len, oddLen);
}
if (p1Len > 0) {
- int cipherBytesPart1 = -1;
+ unsigned int cipherBytesPart1 = 0;
rv = cwSpec->cipher(cwSpec->cipherContext,
SSL_BUFFER_NEXT(wrBuf), /* output */
&cipherBytesPart1, /* actual outlen */
p1Len, /* max outlen */
pIn,
p1Len); /* input, and inputlen */
- PORT_Assert(rv == SECSuccess && cipherBytesPart1 == (int)p1Len);
- if (rv != SECSuccess || cipherBytesPart1 != (int)p1Len) {
+ PORT_Assert(rv == SECSuccess && cipherBytesPart1 == p1Len);
+ if (rv != SECSuccess || cipherBytesPart1 != p1Len) {
PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
return SECFailure;
}
@@ -2147,15 +2332,15 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec,
PORT_Assert(rv == SECSuccess);
}
if (p2Len > 0) {
- int cipherBytesPart2 = -1;
+ unsigned int cipherBytesPart2 = 0;
rv = cwSpec->cipher(cwSpec->cipherContext,
SSL_BUFFER_NEXT(wrBuf),
&cipherBytesPart2, /* output and actual outLen */
p2Len, /* max outlen */
SSL_BUFFER_NEXT(wrBuf),
p2Len); /* input and inputLen*/
- PORT_Assert(rv == SECSuccess && cipherBytesPart2 == (int)p2Len);
- if (rv != SECSuccess || cipherBytesPart2 != (int)p2Len) {
+ PORT_Assert(rv == SECSuccess && cipherBytesPart2 == p2Len);
+ if (rv != SECSuccess || cipherBytesPart2 != p2Len) {
PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
return SECFailure;
}
@@ -2216,7 +2401,7 @@ ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSLContentType ct,
unsigned int lenOffset;
SECStatus rv;
- PORT_Assert(cwSpec->direction == CipherSpecWrite);
+ PORT_Assert(cwSpec->direction == ssl_secret_write);
PORT_Assert(SSL_BUFFER_LEN(wrBuf) == 0);
PORT_Assert(cwSpec->cipherDef->max_records <= RECORD_SEQ_MAX);
@@ -2242,7 +2427,7 @@ ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSLContentType ct,
#ifdef UNSAFE_FUZZER_MODE
{
- int len;
+ unsigned int len;
rv = Null_Cipher(NULL, SSL_BUFFER_NEXT(wrBuf), &len,
SSL_BUFFER_SPACE(wrBuf), pIn, contentLen);
if (rv != SECSuccess) {
@@ -2315,8 +2500,8 @@ ssl_ProtectNextRecord(sslSocket *ss, ssl3CipherSpec *spec, SSLContentType ct,
* Returns the number of bytes of plaintext that were successfully sent
* plus the number of bytes of plaintext that were copied into the
* output (write) buffer.
- * Returns SECFailure on a hard IO error, memory error, or crypto error.
- * Does NOT return SECWouldBlock.
+ * Returns -1 on an error. PR_WOULD_BLOCK_ERROR is set if the error is blocking
+ * and not terminal.
*
* Notes on the use of the private ssl flags:
* (no private SSL flags)
@@ -2361,13 +2546,26 @@ ssl3_SendRecord(sslSocket *ss,
* error, so don't overwrite. */
PORT_SetError(SSL_ERROR_HANDSHAKE_FAILED);
}
- return SECFailure;
+ return -1;
}
/* check for Token Presence */
if (!ssl3_ClientAuthTokenPresent(ss->sec.ci.sid)) {
PORT_SetError(SSL_ERROR_TOKEN_INSERTION_REMOVAL);
- return SECFailure;
+ return -1;
+ }
+
+ if (ss->recordWriteCallback) {
+ PRUint16 epoch;
+ ssl_GetSpecReadLock(ss);
+ epoch = ss->ssl3.cwSpec->epoch;
+ ssl_ReleaseSpecReadLock(ss);
+ rv = ss->recordWriteCallback(ss->fd, epoch, ct, pIn, nIn,
+ ss->recordWriteCallbackArg);
+ if (rv != SECSuccess) {
+ return -1;
+ }
+ return nIn;
}
if (cwSpec) {
@@ -2471,7 +2669,7 @@ loser:
#define SSL3_PENDING_HIGH_WATER 1024
/* Attempt to send the content of "in" in an SSL application_data record.
- * Returns "len" or SECFailure, never SECWouldBlock, nor SECSuccess.
+ * Returns "len" or -1 on failure.
*/
int
ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in,
@@ -2486,21 +2684,21 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in,
PORT_Assert(!(flags & ssl_SEND_FLAG_NO_RETRANSMIT));
if (len < 0 || !in) {
PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
- return SECFailure;
+ return -1;
}
if (ss->pendingBuf.len > SSL3_PENDING_HIGH_WATER &&
!ssl_SocketIsBlocking(ss)) {
PORT_Assert(!ssl_SocketIsBlocking(ss));
PORT_SetError(PR_WOULD_BLOCK_ERROR);
- return SECFailure;
+ return -1;
}
if (ss->appDataBuffered && len) {
PORT_Assert(in[0] == (unsigned char)(ss->appDataBuffered));
if (in[0] != (unsigned char)(ss->appDataBuffered)) {
PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
- return SECFailure;
+ return -1;
}
in++;
len--;
@@ -2549,7 +2747,7 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in,
PORT_Assert(ss->lastWriteBlocked);
break;
}
- return SECFailure; /* error code set by ssl3_SendRecord */
+ return -1; /* error code set by ssl3_SendRecord */
}
totalSent += sent;
if (ss->pendingBuf.len) {
@@ -2578,7 +2776,6 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in,
}
/* Attempt to send buffered handshake messages.
- * This function returns SECSuccess or SECFailure, never SECWouldBlock.
* Always set sendBuf.len to 0, even when returning SECFailure.
*
* Depending on whether we are doing DTLS or not, this either calls
@@ -2601,7 +2798,6 @@ ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags)
}
/* Attempt to send the content of sendBuf buffer in an SSL handshake record.
- * This function returns SECSuccess or SECFailure, never SECWouldBlock.
* Always set sendBuf.len to 0, even when returning SECFailure.
*
* Called from ssl3_FlushHandshake
@@ -2673,7 +2869,12 @@ ssl3_HandleNoCertificate(sslSocket *ss)
PRFileDesc *lower;
ssl_UncacheSessionID(ss);
- SSL3_SendAlert(ss, alert_fatal, bad_certificate);
+
+ if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ SSL3_SendAlert(ss, alert_fatal, certificate_required);
+ } else {
+ SSL3_SendAlert(ss, alert_fatal, bad_certificate);
+ }
lower = ss->fd->lower;
#ifdef _WIN32
@@ -2909,6 +3110,9 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf)
case no_certificate:
error = SSL_ERROR_NO_CERTIFICATE;
break;
+ case certificate_required:
+ error = SSL_ERROR_RX_CERTIFICATE_REQUIRED_ALERT;
+ break;
case bad_certificate:
error = SSL_ERROR_BAD_CERT_ALERT;
break;
@@ -3709,6 +3913,10 @@ ssl3_RestartHandshakeHashes(sslSocket *ss)
PK11_DestroyContext(ss->ssl3.hs.sha, PR_TRUE);
ss->ssl3.hs.sha = NULL;
}
+ if (ss->ssl3.hs.shaPostHandshake) {
+ PK11_DestroyContext(ss->ssl3.hs.shaPostHandshake, PR_TRUE);
+ ss->ssl3.hs.shaPostHandshake = NULL;
+ }
}
/*
@@ -3769,6 +3977,24 @@ ssl3_UpdateHandshakeHashes(sslSocket *ss, const unsigned char *b, unsigned int l
}
SECStatus
+ssl3_UpdatePostHandshakeHashes(sslSocket *ss, const unsigned char *b, unsigned int l)
+{
+ SECStatus rv = SECSuccess;
+
+ PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+
+ PRINT_BUF(90, (ss, "post handshake hash input:", b, l));
+
+ PORT_Assert(ss->ssl3.hs.hashType == handshake_hash_single);
+ PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
+ rv = PK11_DigestOp(ss->ssl3.hs.shaPostHandshake, b, l);
+ if (rv != SECSuccess) {
+ PORT_SetError(SSL_ERROR_DIGEST_FAILURE);
+ }
+ return rv;
+}
+
+SECStatus
ssl3_AppendHandshakeHeader(sslSocket *ss, SSLHandshakeType t, PRUint32 length)
{
SECStatus rv;
@@ -4047,7 +4273,7 @@ ssl_SignatureSchemeMatchesSpkiOid(SSLSignatureScheme scheme, SECOidTag spkiOid)
}
/* Validate that the signature scheme works for the given key type. */
-static PRBool
+PRBool
ssl_SignatureSchemeValid(SSLSignatureScheme scheme, SECOidTag spkiOid,
PRBool isTls13)
{
@@ -4064,6 +4290,9 @@ ssl_SignatureSchemeValid(SSLSignatureScheme scheme, SECOidTag spkiOid,
if (ssl_IsRsaPkcs1SignatureScheme(scheme)) {
return PR_FALSE;
}
+ if (ssl_IsDsaSignatureScheme(scheme)) {
+ return PR_FALSE;
+ }
/* With TLS 1.3, EC keys should have been selected based on calling
* ssl_SignatureSchemeFromSpki(), reject them otherwise. */
return spkiOid != SEC_OID_ANSIX962_EC_PUBLIC_KEY;
@@ -4072,7 +4301,7 @@ ssl_SignatureSchemeValid(SSLSignatureScheme scheme, SECOidTag spkiOid,
}
static SECStatus
-ssl_SignatureSchemeFromPssSpki(CERTSubjectPublicKeyInfo *spki,
+ssl_SignatureSchemeFromPssSpki(const CERTSubjectPublicKeyInfo *spki,
SSLSignatureScheme *scheme)
{
SECKEYRSAPSSParams pssParam = { 0 };
@@ -4120,7 +4349,7 @@ loser:
}
static SECStatus
-ssl_SignatureSchemeFromEcSpki(CERTSubjectPublicKeyInfo *spki,
+ssl_SignatureSchemeFromEcSpki(const CERTSubjectPublicKeyInfo *spki,
SSLSignatureScheme *scheme)
{
const sslNamedGroupDef *group;
@@ -4157,8 +4386,8 @@ ssl_SignatureSchemeFromEcSpki(CERTSubjectPublicKeyInfo *spki,
/* Newer signature schemes are designed so that a single SPKI can be used with
* that scheme. This determines that scheme from the SPKI. If the SPKI doesn't
* have a single scheme, |*scheme| is set to ssl_sig_none. */
-static SECStatus
-ssl_SignatureSchemeFromSpki(CERTSubjectPublicKeyInfo *spki,
+SECStatus
+ssl_SignatureSchemeFromSpki(const CERTSubjectPublicKeyInfo *spki,
PRBool isTls13, SSLSignatureScheme *scheme)
{
SECOidTag spkiOid = SECOID_GetAlgorithmTag(&spki->algorithm);
@@ -4178,8 +4407,9 @@ ssl_SignatureSchemeFromSpki(CERTSubjectPublicKeyInfo *spki,
return SECSuccess;
}
-static PRBool
-ssl_SignatureSchemeEnabled(sslSocket *ss, SSLSignatureScheme scheme)
+/* Check that a signature scheme is enabled by configuration. */
+PRBool
+ssl_SignatureSchemeEnabled(const sslSocket *ss, SSLSignatureScheme scheme)
{
unsigned int i;
for (i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
@@ -4209,21 +4439,20 @@ ssl_SignatureKeyMatchesSpkiOid(const ssl3KEADef *keaDef, SECOidTag spkiOid)
}
/* ssl3_CheckSignatureSchemeConsistency checks that the signature algorithm
- * identifier in |scheme| is consistent with the public key in |cert|. It also
+ * identifier in |scheme| is consistent with the public key in |spki|. It also
* checks the hash algorithm against the configured signature algorithms. If
* all the tests pass, SECSuccess is returned. Otherwise, PORT_SetError is
* called and SECFailure is returned. */
SECStatus
ssl_CheckSignatureSchemeConsistency(sslSocket *ss, SSLSignatureScheme scheme,
- CERTCertificate *cert)
+ CERTSubjectPublicKeyInfo *spki)
{
SSLSignatureScheme spkiScheme;
PRBool isTLS13 = ss->version == SSL_LIBRARY_VERSION_TLS_1_3;
SECOidTag spkiOid;
SECStatus rv;
- rv = ssl_SignatureSchemeFromSpki(&cert->subjectPublicKeyInfo, isTLS13,
- &spkiScheme);
+ rv = ssl_SignatureSchemeFromSpki(spki, isTLS13, &spkiScheme);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -4237,7 +4466,7 @@ ssl_CheckSignatureSchemeConsistency(sslSocket *ss, SSLSignatureScheme scheme,
return SECSuccess;
}
- spkiOid = SECOID_GetAlgorithmTag(&cert->subjectPublicKeyInfo.algorithm);
+ spkiOid = SECOID_GetAlgorithmTag(&spki->algorithm);
/* If we're a client, check that the signature algorithm matches the signing
* key type of the cipher suite. */
@@ -4329,6 +4558,22 @@ ssl_IsRsaPkcs1SignatureScheme(SSLSignatureScheme scheme)
return PR_FALSE;
}
+PRBool
+ssl_IsDsaSignatureScheme(SSLSignatureScheme scheme)
+{
+ switch (scheme) {
+ case ssl_sig_dsa_sha256:
+ case ssl_sig_dsa_sha384:
+ case ssl_sig_dsa_sha512:
+ case ssl_sig_dsa_sha1:
+ return PR_TRUE;
+
+ default:
+ return PR_FALSE;
+ }
+ return PR_FALSE;
+}
+
SSLAuthType
ssl_SignatureSchemeToAuthType(SSLSignatureScheme scheme)
{
@@ -4804,7 +5049,8 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
* XXX If we've been called from ssl_BeginClientHandshake, then
* this lookup is duplicative and wasteful.
*/
- sid = ssl_LookupSID(&ss->sec.ci.peer, ss->sec.ci.port, ss->peerID, ss->url);
+ sid = ssl_LookupSID(ssl_Time(ss), &ss->sec.ci.peer,
+ ss->sec.ci.port, ss->peerID, ss->url);
} else {
sid = NULL;
}
@@ -4816,14 +5062,20 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
*/
if (sid) {
PRBool sidOK = PR_TRUE;
- const ssl3CipherSuiteCfg *suite;
- /* Check that the cipher suite we need is enabled. */
- suite = ssl_LookupCipherSuiteCfg(sid->u.ssl3.cipherSuite,
+ if (sid->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ if (!tls13_ResumptionCompatible(ss, sid->u.ssl3.cipherSuite)) {
+ sidOK = PR_FALSE;
+ }
+ } else {
+ /* Check that the cipher suite we need is enabled. */
+ const ssl3CipherSuiteCfg *suite =
+ ssl_LookupCipherSuiteCfg(sid->u.ssl3.cipherSuite,
ss->cipherSuites);
- PORT_Assert(suite);
- if (!suite || !ssl3_config_match(suite, ss->ssl3.policy, &ss->vrange, ss)) {
- sidOK = PR_FALSE;
+ SSLVersionRange vrange = { sid->version, sid->version };
+ if (!suite || !ssl3_config_match(suite, ss->ssl3.policy, &vrange, ss)) {
+ sidOK = PR_FALSE;
+ }
}
/* Check that we can recover the master secret. */
@@ -4968,17 +5220,17 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
PR_RWLock_Rlock(sid->u.ssl3.lock);
}
- /* Generate a new random if this is the first attempt. */
- if (type == client_hello_initial) {
+ /* Generate a new random if this is the first attempt or renegotiation. */
+ if (type == client_hello_initial ||
+ type == client_hello_renegotiation) {
rv = ssl3_GetNewRandom(ss->ssl3.hs.client_random);
if (rv != SECSuccess) {
goto loser; /* err set by GetNewRandom. */
}
}
- if (ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3 &&
- type == client_hello_initial) {
- rv = tls13_SetupClientHello(ss);
+ if (ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ rv = tls13_SetupClientHello(ss, type);
if (rv != SECSuccess) {
goto loser;
}
@@ -5107,6 +5359,7 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
}
actual_count++;
}
+ /* CipherSuites are appended to Hello message here */
for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i];
if (ssl3_config_match(suite, ss->ssl3.policy, &ss->vrange, ss)) {
@@ -6023,7 +6276,7 @@ ssl3_SendClientKeyExchange(sslSocket *ss)
}
/* Used by ssl_PickSignatureScheme(). */
-static PRBool
+PRBool
ssl_CanUseSignatureScheme(SSLSignatureScheme scheme,
const SSLSignatureScheme *peerSchemes,
unsigned int peerSchemeCount,
@@ -6041,6 +6294,13 @@ ssl_CanUseSignatureScheme(SSLSignatureScheme scheme,
return PR_FALSE;
}
+ if (ssl_IsDsaSignatureScheme(scheme) &&
+ (NSS_GetAlgorithmPolicy(SEC_OID_ANSIX9_DSA_SIGNATURE, &policy) ==
+ SECSuccess) &&
+ !(policy & NSS_USE_ALG_IN_SSL_KX)) {
+ return PR_FALSE;
+ }
+
hashType = ssl_SignatureSchemeToHashType(scheme);
if (requireSha1 && (hashType != ssl_hash_sha1)) {
return PR_FALSE;
@@ -6060,6 +6320,21 @@ ssl_CanUseSignatureScheme(SSLSignatureScheme scheme,
}
SECStatus
+ssl_PrivateKeySupportsRsaPss(SECKEYPrivateKey *privKey,
+ PRBool *supportsRsaPss)
+{
+ PK11SlotInfo *slot;
+ slot = PK11_GetSlotFromPrivateKey(privKey);
+ if (!slot) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ *supportsRsaPss = PK11_DoesMechanism(slot, auth_alg_defs[ssl_auth_rsa_pss]);
+ PK11_FreeSlot(slot);
+ return SECSuccess;
+}
+
+SECStatus
ssl_PickSignatureScheme(sslSocket *ss,
CERTCertificate *cert,
SECKEYPublicKey *pubKey,
@@ -6069,8 +6344,7 @@ ssl_PickSignatureScheme(sslSocket *ss,
PRBool requireSha1)
{
unsigned int i;
- PK11SlotInfo *slot;
- PRBool slotDoesPss;
+ PRBool doesRsaPss;
PRBool isTLS13 = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3;
SECStatus rv;
SSLSignatureScheme scheme;
@@ -6084,13 +6358,10 @@ ssl_PickSignatureScheme(sslSocket *ss,
return SECFailure;
}
- slot = PK11_GetSlotFromPrivateKey(privKey);
- if (!slot) {
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ rv = ssl_PrivateKeySupportsRsaPss(privKey, &doesRsaPss);
+ if (rv != SECSuccess) {
return SECFailure;
}
- slotDoesPss = PK11_DoesMechanism(slot, auth_alg_defs[ssl_auth_rsa_pss]);
- PK11_FreeSlot(slot);
/* If the certificate SPKI indicates a single scheme, don't search. */
rv = ssl_SignatureSchemeFromSpki(&cert->subjectPublicKeyInfo,
@@ -6101,7 +6372,7 @@ ssl_PickSignatureScheme(sslSocket *ss,
if (scheme != ssl_sig_none) {
if (!ssl_SignatureSchemeEnabled(ss, scheme) ||
!ssl_CanUseSignatureScheme(scheme, peerSchemes, peerSchemeCount,
- requireSha1, slotDoesPss)) {
+ requireSha1, doesRsaPss)) {
PORT_SetError(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
return SECFailure;
}
@@ -6118,7 +6389,7 @@ ssl_PickSignatureScheme(sslSocket *ss,
if (ssl_SignatureSchemeValid(scheme, spkiOid, isTLS13) &&
ssl_CanUseSignatureScheme(scheme, peerSchemes, peerSchemeCount,
- requireSha1, slotDoesPss)) {
+ requireSha1, doesRsaPss)) {
ss->ssl3.hs.signatureScheme = scheme;
return SECSuccess;
}
@@ -7009,8 +7280,8 @@ ssl_HandleDHServerKeyExchange(sslSocket *ss, PRUint8 *b, PRUint32 length)
if (rv != SECSuccess) {
goto alert_loser; /* malformed or unsupported. */
}
- rv = ssl_CheckSignatureSchemeConsistency(ss, sigScheme,
- ss->sec.peerCert);
+ rv = ssl_CheckSignatureSchemeConsistency(
+ ss, sigScheme, &ss->sec.peerCert->subjectPublicKeyInfo);
if (rv != SECSuccess) {
goto alert_loser;
}
@@ -7402,6 +7673,9 @@ ssl3_CompleteHandleCertificateRequest(sslSocket *ss,
if (ss->getClientAuthData != NULL) {
PORT_Assert((ss->ssl3.hs.preliminaryInfo & ssl_preinfo_all) ==
ssl_preinfo_all);
+ PORT_Assert(ss->ssl3.clientPrivateKey == NULL);
+ PORT_Assert(ss->ssl3.clientCertificate == NULL);
+ PORT_Assert(ss->ssl3.clientCertChain == NULL);
/* XXX Should pass cert_types and algorithms in this call!! */
rv = (SECStatus)(*ss->getClientAuthData)(ss->getClientAuthDataArg,
ss->fd, ca_list,
@@ -7623,7 +7897,8 @@ ssl3_SendClientSecondRound(sslSocket *ss)
" certificate authentication is still pending.",
SSL_GETPID(), ss->fd));
ss->ssl3.hs.restartTarget = ssl3_SendClientSecondRound;
- return SECWouldBlock;
+ PORT_SetError(PR_WOULD_BLOCK_ERROR);
+ return SECFailure;
}
ssl_GetXmitBufLock(ss); /*******************************/
@@ -7915,6 +8190,7 @@ ssl3_NegotiateCipherSuiteInner(sslSocket *ss, const SECItem *suites,
}
}
}
+ PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
return SECFailure;
}
@@ -7939,6 +8215,14 @@ ssl3_NegotiateCipherSuite(sslSocket *ss, const SECItem *suites,
PRUint16 selected;
SECStatus rv;
+ /* Ensure that only valid cipher suites are enabled. */
+ if (ssl3_config_match_init(ss) == 0) {
+ /* No configured cipher is both supported by PK11 and allowed.
+ * This is a configuration error, so report handshake failure.*/
+ FATAL_ERROR(ss, PORT_GetError(), handshake_failure);
+ return SECFailure;
+ }
+
rv = ssl3_NegotiateCipherSuiteInner(ss, suites, ss->version, &selected);
if (rv != SECSuccess) {
return SECFailure;
@@ -8068,13 +8352,6 @@ ssl3_ServerCallSNICallback(sslSocket *ss)
ret = SSL_SNI_SEND_ALERT;
break;
}
- if (ssl3_config_match_init(ss) == 0) {
- /* no ciphers are working/supported */
- errCode = PORT_GetError();
- desc = handshake_failure;
- ret = SSL_SNI_SEND_ALERT;
- break;
- }
/* Need to tell the client that application has picked
* the name from the offered list and reconfigured the socket.
* Don't do this if we negotiated ESNI.
@@ -8401,15 +8678,8 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
goto alert_loser;
}
}
-
- if (ss->firstHsDone && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
- desc = unexpected_message;
- errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED;
- goto alert_loser;
- }
-
- isTLS13 = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3;
ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version;
+
/* Update the write spec to match the selected version. */
if (!ss->firstHsDone) {
ssl_GetSpecWriteLock(ss);
@@ -8417,30 +8687,60 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
ssl_ReleaseSpecWriteLock(ss);
}
- if (isTLS13 && sidBytes.len > 0 && !IS_DTLS(ss)) {
- SECITEM_FreeItem(&ss->ssl3.hs.fakeSid, PR_FALSE);
- rv = SECITEM_CopyItem(NULL, &ss->ssl3.hs.fakeSid, &sidBytes);
- if (rv != SECSuccess) {
- desc = internal_error;
- errCode = PORT_GetError();
+ isTLS13 = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3;
+ if (isTLS13) {
+ if (ss->firstHsDone) {
+ desc = unexpected_message;
+ errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED;
goto alert_loser;
}
- }
- /* If there is a cookie, then this is a second ClientHello (TLS 1.3). */
- if (ssl3_FindExtension(ss, ssl_tls13_cookie_xtn)) {
- ss->ssl3.hs.helloRetry = PR_TRUE;
- }
+ if (sidBytes.len > 0 && !IS_DTLS(ss)) {
+ SECITEM_FreeItem(&ss->ssl3.hs.fakeSid, PR_FALSE);
+ rv = SECITEM_CopyItem(NULL, &ss->ssl3.hs.fakeSid, &sidBytes);
+ if (rv != SECSuccess) {
+ desc = internal_error;
+ errCode = PORT_GetError();
+ goto alert_loser;
+ }
+ }
- if (ss->ssl3.hs.receivedCcs) {
- /* This is only valid if we sent HelloRetryRequest, so we should have
- * negotiated TLS 1.3 and there should be a cookie extension. */
- if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3 ||
- !ss->ssl3.hs.helloRetry) {
+ /* TLS 1.3 requires that compression include only null. */
+ if (comps.len != 1 || comps.data[0] != ssl_compression_null) {
+ goto alert_loser;
+ }
+
+ /* If there is a cookie, then this is a second ClientHello (TLS 1.3). */
+ if (ssl3_FindExtension(ss, ssl_tls13_cookie_xtn)) {
+ ss->ssl3.hs.helloRetry = PR_TRUE;
+ }
+
+ /* receivedCcs is only valid if we sent an HRR. */
+ if (ss->ssl3.hs.receivedCcs && !ss->ssl3.hs.helloRetry) {
desc = unexpected_message;
errCode = SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER;
goto alert_loser;
}
+ } else {
+ /* HRR is TLS1.3-only. We ignore the Cookie extension here. */
+ if (ss->ssl3.hs.helloRetry) {
+ desc = protocol_version;
+ errCode = SSL_ERROR_UNSUPPORTED_VERSION;
+ goto alert_loser;
+ }
+
+ /* receivedCcs is only valid if we sent an HRR. */
+ if (ss->ssl3.hs.receivedCcs) {
+ desc = unexpected_message;
+ errCode = SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER;
+ goto alert_loser;
+ }
+
+ /* TLS versions prior to 1.3 must include null somewhere. */
+ if (comps.len < 1 ||
+ !memchr(comps.data, ssl_compression_null, comps.len)) {
+ goto alert_loser;
+ }
}
/* Now parse the rest of the extensions. */
@@ -8466,19 +8766,6 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
}
}
- /* TLS 1.3 requires that compression only include null. */
- if (isTLS13) {
- if (comps.len != 1 || comps.data[0] != ssl_compression_null) {
- goto alert_loser;
- }
- } else {
- /* Other versions need to include null somewhere. */
- if (comps.len < 1 ||
- !memchr(comps.data, ssl_compression_null, comps.len)) {
- goto alert_loser;
- }
- }
-
if (!ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) {
/* If we didn't receive an RI extension, look for the SCSV,
* and if found, treat it just like an empty RI extension
@@ -8496,7 +8783,7 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
}
/* The check for renegotiation in TLS 1.3 is earlier. */
- if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+ if (!isTLS13) {
if (ss->firstHsDone &&
(ss->opt.enableRenegotiation == SSL_RENEGOTIATE_REQUIRES_XTN ||
ss->opt.enableRenegotiation == SSL_RENEGOTIATE_TRANSITIONAL) &&
@@ -8521,7 +8808,7 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
* (2) the client support the session ticket extension, but sent an
* empty ticket.
*/
- if ((ss->version < SSL_LIBRARY_VERSION_TLS_1_3) &&
+ if (!isTLS13 &&
(!ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn) ||
ss->xtnData.emptySessionTicket)) {
if (sidBytes.len > 0 && !ss->opt.noCache) {
@@ -8531,8 +8818,8 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
ss->sec.ci.peer.pr_s6_addr32[2],
ss->sec.ci.peer.pr_s6_addr32[3]));
if (ssl_sid_lookup) {
- sid = (*ssl_sid_lookup)(&ss->sec.ci.peer, sidBytes.data,
- sidBytes.len, ss->dbHandle);
+ sid = (*ssl_sid_lookup)(ssl_Time(ss), &ss->sec.ci.peer,
+ sidBytes.data, sidBytes.len, ss->dbHandle);
} else {
errCode = SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED;
goto loser;
@@ -8577,9 +8864,9 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
!ss->firstHsDone))) {
SSL_AtomicIncrementLong(&ssl3stats.hch_sid_cache_not_ok);
- ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
sid = NULL;
+ ss->statelessResume = PR_FALSE;
}
}
@@ -8588,7 +8875,7 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
dtls_ReceivedFirstMessageInFlight(ss);
}
- if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ if (isTLS13) {
rv = tls13_HandleClientHelloPart2(ss, &suites, sid, savedMsg, savedLen);
} else {
rv = ssl3_HandleClientHelloPart2(ss, &suites, sid,
@@ -8608,6 +8895,45 @@ loser:
return SECFailure;
}
+/* unwrap helper function to handle the case where the wrapKey doesn't wind
+ * up in the correct token for the master secret */
+PK11SymKey *
+ssl_unwrapSymKey(PK11SymKey *wrapKey,
+ CK_MECHANISM_TYPE wrapType, SECItem *param,
+ SECItem *wrappedKey,
+ CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
+ int keySize, CK_FLAGS keyFlags, void *pinArg)
+{
+ PK11SymKey *unwrappedKey;
+
+ /* unwrap the master secret. */
+ unwrappedKey = PK11_UnwrapSymKeyWithFlags(wrapKey, wrapType, param,
+ wrappedKey, target, operation, keySize,
+ keyFlags);
+ if (!unwrappedKey) {
+ PK11SlotInfo *targetSlot = PK11_GetBestSlot(target, pinArg);
+ PK11SymKey *newWrapKey;
+
+ /* it's possible that we failed to unwrap because the wrapKey is in
+ * a slot that can't handle target. Move the wrapKey to a slot that
+ * can handle this mechanism and retry the operation */
+ if (targetSlot == NULL) {
+ return NULL;
+ }
+ newWrapKey = PK11_MoveSymKey(targetSlot, CKA_UNWRAP, 0,
+ PR_FALSE, wrapKey);
+ PK11_FreeSlot(targetSlot);
+ if (newWrapKey == NULL) {
+ return NULL;
+ }
+ unwrappedKey = PK11_UnwrapSymKeyWithFlags(newWrapKey, wrapType, param,
+ wrappedKey, target, operation, keySize,
+ keyFlags);
+ PK11_FreeSymKey(newWrapKey);
+ }
+ return unwrappedKey;
+}
+
static SECStatus
ssl3_UnwrapMasterSecretServer(sslSocket *ss, sslSessionID *sid, PK11SymKey **ms)
{
@@ -8629,12 +8955,14 @@ ssl3_UnwrapMasterSecretServer(sslSocket *ss, sslSessionID *sid, PK11SymKey **ms)
keyFlags = CKF_SIGN | CKF_VERIFY;
}
- /* unwrap the master secret. */
- *ms = PK11_UnwrapSymKeyWithFlags(wrapKey, sid->u.ssl3.masterWrapMech,
- NULL, &wrappedMS, CKM_SSL3_MASTER_KEY_DERIVE,
- CKA_DERIVE, SSL3_MASTER_SECRET_LENGTH, keyFlags);
+ *ms = ssl_unwrapSymKey(wrapKey, sid->u.ssl3.masterWrapMech, NULL,
+ &wrappedMS, CKM_SSL3_MASTER_KEY_DERIVE,
+ CKA_DERIVE, SSL3_MASTER_SECRET_LENGTH,
+ keyFlags, ss->pkcs11PinArg);
PK11_FreeSymKey(wrapKey);
if (!*ms) {
+ SSL_TRC(10, ("%d: SSL3[%d]: server wrapping key found, but couldn't unwrap MasterSecret. wrapMech=0x%0lx",
+ SSL_GETPID(), ss->fd, sid->u.ssl3.masterWrapMech));
return SECFailure;
}
return SECSuccess;
@@ -8667,9 +8995,7 @@ ssl3_HandleClientHelloPart2(sslSocket *ss,
if (sid)
do {
ssl3CipherSuiteCfg *suite;
-#ifdef PARANOID
SSLVersionRange vrange = { ss->version, ss->version };
-#endif
suite = ss->cipherSuites;
/* Find the entry for the cipher suite used in the cached session. */
@@ -8680,18 +9006,18 @@ ssl3_HandleClientHelloPart2(sslSocket *ss,
PORT_Assert(j > 0);
if (j == 0)
break;
-#ifdef PARANOID
+
/* Double check that the cached cipher suite is still enabled,
* implemented, and allowed by policy. Might have been disabled.
- * The product policy won't change during the process lifetime.
- * Implemented ("isPresent") shouldn't change for servers.
*/
+ if (ssl3_config_match_init(ss) == 0) {
+ desc = handshake_failure;
+ errCode = PORT_GetError();
+ goto alert_loser;
+ }
if (!ssl3_config_match(suite, ss->ssl3.policy, &vrange, ss))
break;
-#else
- if (!suite->enabled)
- break;
-#endif
+
/* Double check that the cached cipher suite is in the client's
* list. If it isn't, fall through and start a new session. */
for (i = 0; i + 1 < suites->len; i += 2) {
@@ -8709,21 +9035,12 @@ ssl3_HandleClientHelloPart2(sslSocket *ss,
}
}
} while (0);
-/* START A NEW SESSION */
-
-#ifndef PARANOID
- /* Look for a matching cipher suite. */
- if (ssl3_config_match_init(ss) == 0) {
- desc = internal_error;
- errCode = PORT_GetError(); /* error code is already set. */
- goto alert_loser;
- }
-#endif
+ /* START A NEW SESSION */
rv = ssl3_NegotiateCipherSuite(ss, suites, PR_TRUE);
if (rv != SECSuccess) {
desc = handshake_failure;
- errCode = SSL_ERROR_NO_CYPHER_OVERLAP;
+ errCode = PORT_GetError();
goto alert_loser;
}
@@ -9491,10 +9808,9 @@ ssl3_SendServerKeyExchange(sslSocket *ss)
}
SECStatus
-ssl3_EncodeSigAlgs(const sslSocket *ss, sslBuffer *buf)
+ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion, sslBuffer *buf)
{
unsigned int lengthOffset;
- unsigned int i;
PRBool found = PR_FALSE;
SECStatus rv;
@@ -9503,25 +9819,13 @@ ssl3_EncodeSigAlgs(const sslSocket *ss, sslBuffer *buf)
return SECFailure;
}
- for (i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
- PRUint32 policy = 0;
- SSLHashType hashType = ssl_SignatureSchemeToHashType(
- ss->ssl3.signatureSchemes[i]);
- SECOidTag hashOID = ssl3_HashTypeToOID(hashType);
-
- /* Skip RSA-PSS schemes if there are no tokens to verify them. */
- if (ssl_IsRsaPssSignatureScheme(ss->ssl3.signatureSchemes[i]) &&
- !PK11_TokenExists(auth_alg_defs[ssl_auth_rsa_pss])) {
- continue;
- }
-
- if ((NSS_GetAlgorithmPolicy(hashOID, &policy) != SECSuccess) ||
- (policy & NSS_USE_ALG_IN_SSL_KX)) {
+ for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
+ if (ssl_SignatureSchemeAccepted(minVersion,
+ ss->ssl3.signatureSchemes[i])) {
rv = sslBuffer_AppendNumber(buf, ss->ssl3.signatureSchemes[i], 2);
if (rv != SECSuccess) {
return SECFailure;
}
-
found = PR_TRUE;
}
}
@@ -9567,7 +9871,7 @@ ssl3_SendCertificateRequest(sslSocket *ss)
length = 1 + certTypesLength + 2 + calen;
if (isTLS12) {
- rv = ssl3_EncodeSigAlgs(ss, &sigAlgsBuf);
+ rv = ssl3_EncodeSigAlgs(ss, ss->version, &sigAlgsBuf);
if (rv != SECSuccess) {
return rv;
}
@@ -9662,8 +9966,8 @@ ssl3_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length)
if (rv != SECSuccess) {
goto loser; /* malformed or unsupported. */
}
- rv = ssl_CheckSignatureSchemeConsistency(ss, sigScheme,
- ss->sec.peerCert);
+ rv = ssl_CheckSignatureSchemeConsistency(
+ ss, sigScheme, &ss->sec.peerCert->subjectPublicKeyInfo);
if (rv != SECSuccess) {
errCode = PORT_GetError();
desc = illegal_parameter;
@@ -10180,7 +10484,7 @@ ssl3_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length)
* until it has verified the server's Finished message." See the comment in
* ssl3_FinishHandshake for more details.
*/
- ss->ssl3.hs.newSessionTicket.received_timestamp = ssl_TimeUsec();
+ ss->ssl3.hs.newSessionTicket.received_timestamp = ssl_Time(ss);
if (length < 4) {
(void)SSL3_SendAlert(ss, alert_fatal, decode_error);
PORT_SetError(SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET);
@@ -10715,6 +11019,107 @@ loser:
}
SECStatus
+ssl_SetAuthKeyBits(sslSocket *ss, const SECKEYPublicKey *pubKey)
+{
+ SECStatus rv;
+ PRUint32 minKey;
+ PRInt32 optval;
+
+ ss->sec.authKeyBits = SECKEY_PublicKeyStrengthInBits(pubKey);
+ switch (SECKEY_GetPublicKeyType(pubKey)) {
+ case rsaKey:
+ case rsaPssKey:
+ case rsaOaepKey:
+ rv = NSS_OptionGet(NSS_RSA_MIN_KEY_SIZE, &optval);
+ if (rv == SECSuccess && optval > 0) {
+ minKey = (PRUint32)optval;
+ } else {
+ minKey = SSL_RSA_MIN_MODULUS_BITS;
+ }
+ break;
+
+ case dsaKey:
+ rv = NSS_OptionGet(NSS_DSA_MIN_KEY_SIZE, &optval);
+ if (rv == SECSuccess && optval > 0) {
+ minKey = (PRUint32)optval;
+ } else {
+ minKey = SSL_DSA_MIN_P_BITS;
+ }
+ break;
+
+ case dhKey:
+ rv = NSS_OptionGet(NSS_DH_MIN_KEY_SIZE, &optval);
+ if (rv == SECSuccess && optval > 0) {
+ minKey = (PRUint32)optval;
+ } else {
+ minKey = SSL_DH_MIN_P_BITS;
+ }
+ break;
+
+ case ecKey:
+ /* Don't check EC strength here on the understanding that we only
+ * support curves we like. */
+ minKey = ss->sec.authKeyBits;
+ break;
+
+ default:
+ FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+ return SECFailure;
+ }
+
+ /* Too small: not good enough. Send a fatal alert. */
+ if (ss->sec.authKeyBits < minKey) {
+ FATAL_ERROR(ss, SSL_ERROR_WEAK_SERVER_CERT_KEY,
+ ss->version >= SSL_LIBRARY_VERSION_TLS_1_0
+ ? insufficient_security
+ : illegal_parameter);
+ return SECFailure;
+ }
+
+ /* PreliminaryChannelInfo.authKeyBits, scheme, and peerDelegCred are now valid. */
+ ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_peer_auth;
+
+ return SECSuccess;
+}
+
+SECStatus
+ssl3_HandleServerSpki(sslSocket *ss)
+{
+ PORT_Assert(!ss->sec.isServer);
+ SECKEYPublicKey *pubKey;
+
+ if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
+ tls13_IsVerifyingWithDelegatedCredential(ss)) {
+ sslDelegatedCredential *dc = ss->xtnData.peerDelegCred;
+ pubKey = SECKEY_ExtractPublicKey(dc->spki);
+ if (!pubKey) {
+ PORT_SetError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
+ return SECFailure;
+ }
+
+ /* Because we have only a single authType (ssl_auth_tls13_any)
+ * for TLS 1.3 at this point, set the scheme so that the
+ * callback can interpret |authKeyBits| correctly.
+ */
+ ss->sec.signatureScheme = dc->expectedCertVerifyAlg;
+ } else {
+ pubKey = CERT_ExtractPublicKey(ss->sec.peerCert);
+ if (!pubKey) {
+ PORT_SetError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
+ return SECFailure;
+ }
+ }
+
+ SECStatus rv = ssl_SetAuthKeyBits(ss, pubKey);
+ SECKEY_DestroyPublicKey(pubKey);
+ if (rv != SECSuccess) {
+ return rv; /* Alert sent and code set. */
+ }
+
+ return SECSuccess;
+}
+
+SECStatus
ssl3_AuthCertificate(sslSocket *ss)
{
SECStatus rv;
@@ -10725,6 +11130,26 @@ ssl3_AuthCertificate(sslSocket *ss)
PORT_Assert((ss->ssl3.hs.preliminaryInfo & ssl_preinfo_all) ==
ssl_preinfo_all);
+
+ if (!ss->sec.isServer) {
+ /* Set the |spki| used to verify the handshake. When verifying with a
+ * delegated credential (DC), this corresponds to the DC public key;
+ * otherwise it correspond to the public key of the peer's end-entity
+ * certificate. */
+ rv = ssl3_HandleServerSpki(ss);
+ if (rv != SECSuccess) {
+ /* Alert sent and code set (if not SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE).
+ * In either case, we're done here. */
+ errCode = PORT_GetError();
+ goto loser;
+ }
+
+ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+ ss->sec.authType = ss->ssl3.hs.kea_def->authKeyType;
+ ss->sec.keaType = ss->ssl3.hs.kea_def->exchKeyType;
+ }
+ }
+
/*
* Ask caller-supplied callback function to validate cert chain.
*/
@@ -10757,79 +11182,12 @@ ssl3_AuthCertificate(sslSocket *ss)
}
}
+ if (ss->sec.ci.sid->peerCert) {
+ CERT_DestroyCertificate(ss->sec.ci.sid->peerCert);
+ }
ss->sec.ci.sid->peerCert = CERT_DupCertificate(ss->sec.peerCert);
if (!ss->sec.isServer) {
- CERTCertificate *cert = ss->sec.peerCert;
-
- /* set the server authentication type and size from the value
- ** in the cert. */
- SECKEYPublicKey *pubKey = CERT_ExtractPublicKey(cert);
- if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
- /* These are filled in in tls13_HandleCertificateVerify and
- * tls13_HandleServerKeyShare. */
- ss->sec.authType = ss->ssl3.hs.kea_def->authKeyType;
- ss->sec.keaType = ss->ssl3.hs.kea_def->exchKeyType;
- }
- if (pubKey) {
- KeyType pubKeyType;
- PRUint32 minKey;
- PRInt32 optval;
- /* This partly fixes Bug 124230 and may cause problems for
- * callers which depend on the old (wrong) behavior. */
- ss->sec.authKeyBits = SECKEY_PublicKeyStrengthInBits(pubKey);
- pubKeyType = SECKEY_GetPublicKeyType(pubKey);
- minKey = ss->sec.authKeyBits;
- switch (pubKeyType) {
- case rsaKey:
- case rsaPssKey:
- case rsaOaepKey:
- rv =
- NSS_OptionGet(NSS_RSA_MIN_KEY_SIZE, &optval);
- if (rv == SECSuccess && optval > 0) {
- minKey = (PRUint32)optval;
- } else {
- minKey = SSL_RSA_MIN_MODULUS_BITS;
- }
- break;
- case dsaKey:
- rv =
- NSS_OptionGet(NSS_DSA_MIN_KEY_SIZE, &optval);
- if (rv == SECSuccess && optval > 0) {
- minKey = (PRUint32)optval;
- } else {
- minKey = SSL_DSA_MIN_P_BITS;
- }
- break;
- case dhKey:
- rv =
- NSS_OptionGet(NSS_DH_MIN_KEY_SIZE, &optval);
- if (rv == SECSuccess && optval > 0) {
- minKey = (PRUint32)optval;
- } else {
- minKey = SSL_DH_MIN_P_BITS;
- }
- break;
- default:
- break;
- }
-
- /* Too small: not good enough. Send a fatal alert. */
- /* We aren't checking EC here on the understanding that we only
- * support curves we like, a decision that might need revisiting. */
- if (ss->sec.authKeyBits < minKey) {
- PORT_SetError(SSL_ERROR_WEAK_SERVER_CERT_KEY);
- (void)SSL3_SendAlert(ss, alert_fatal,
- ss->version >= SSL_LIBRARY_VERSION_TLS_1_0
- ? insufficient_security
- : illegal_parameter);
- SECKEY_DestroyPublicKey(pubKey);
- return SECFailure;
- }
- SECKEY_DestroyPublicKey(pubKey);
- pubKey = NULL;
- }
-
if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
TLS13_SET_HS_STATE(ss, wait_cert_verify);
} else {
@@ -10918,13 +11276,6 @@ ssl3_AuthCertificateComplete(sslSocket *ss, PRErrorCode error)
}
rv = target(ss);
- /* Even if we blocked here, we have accomplished enough to claim
- * success. Any remaining work will be taken care of by subsequent
- * calls to SSL_ForceHandshake/PR_Send/PR_Read/etc.
- */
- if (rv == SECWouldBlock) {
- rv = SECSuccess;
- }
} else {
SSL_TRC(3, ("%d: SSL3[%p]: certificate authentication won the race with"
" peer's finished message",
@@ -11265,7 +11616,19 @@ ssl3_CacheWrappedSecret(sslSocket *ss, sslSessionID *sid,
wrappingKey = PK11_KeyGen(symKeySlot, mechanism, NULL,
keyLength, pwArg);
if (wrappingKey) {
+ /* The thread safety characteristics of PK11_[SG]etWrapKey is
+ * abominable. This protects against races in calling
+ * PK11_SetWrapKey by dropping and re-acquiring the canonical
+ * value once it is set. The mutex in PK11_[SG]etWrapKey will
+ * ensure that races produce the same value in the end. */
PK11_SetWrapKey(symKeySlot, wrapKeyIndex, wrappingKey);
+ PK11_FreeSymKey(wrappingKey);
+ wrappingKey = PK11_GetWrapKey(symKeySlot, wrapKeyIndex,
+ CKM_INVALID_MECHANISM, incarnation, pwArg);
+ if (!wrappingKey) {
+ PK11_FreeSlot(symKeySlot);
+ return SECFailure;
+ }
}
}
} else {
@@ -11465,7 +11828,8 @@ xmit_loser:
}
ss->ssl3.hs.restartTarget = ssl3_FinishHandshake;
- return SECWouldBlock;
+ PORT_SetError(PR_WOULD_BLOCK_ERROR);
+ return SECFailure;
}
rv = ssl3_FinishHandshake(ss);
@@ -11491,8 +11855,8 @@ ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid, PK11SymKey *secret)
sid->keaGroup = ssl_grp_none;
}
sid->sigScheme = ss->sec.signatureScheme;
- sid->lastAccessTime = sid->creationTime = ssl_TimeUsec();
- sid->expirationTime = sid->creationTime + ssl3_sid_timeout * PR_USEC_PER_SEC;
+ sid->lastAccessTime = sid->creationTime = ssl_Time(ss);
+ sid->expirationTime = sid->creationTime + (ssl_ticket_lifetime * PR_USEC_PER_SEC);
sid->localCert = CERT_DupCertificate(ss->sec.localCert);
if (ss->sec.isServer) {
sid->namedCurve = ss->sec.serverCert->namedCurve;
@@ -11560,7 +11924,8 @@ ssl3_FinishHandshake(sslSocket *ss)
SECStatus
ssl_HashHandshakeMessageInt(sslSocket *ss, SSLHandshakeType ct,
PRUint32 dtlsSeq,
- const PRUint8 *b, PRUint32 length)
+ const PRUint8 *b, PRUint32 length,
+ sslUpdateHandshakeHashes updateHashes)
{
PRUint8 hdr[4];
PRUint8 dtlsData[8];
@@ -11573,7 +11938,7 @@ ssl_HashHandshakeMessageInt(sslSocket *ss, SSLHandshakeType ct,
hdr[2] = (PRUint8)(length >> 8);
hdr[3] = (PRUint8)(length);
- rv = ssl3_UpdateHandshakeHashes(ss, (unsigned char *)hdr, 4);
+ rv = updateHashes(ss, (unsigned char *)hdr, 4);
if (rv != SECSuccess)
return rv; /* err code already set. */
@@ -11593,14 +11958,13 @@ ssl_HashHandshakeMessageInt(sslSocket *ss, SSLHandshakeType ct,
dtlsData[6] = (PRUint8)(length >> 8);
dtlsData[7] = (PRUint8)(length);
- rv = ssl3_UpdateHandshakeHashes(ss, (unsigned char *)dtlsData,
- sizeof(dtlsData));
+ rv = updateHashes(ss, (unsigned char *)dtlsData, sizeof(dtlsData));
if (rv != SECSuccess)
return rv; /* err code already set. */
}
/* The message body */
- rv = ssl3_UpdateHandshakeHashes(ss, b, length);
+ rv = updateHashes(ss, b, length);
if (rv != SECSuccess)
return rv; /* err code already set. */
@@ -11612,7 +11976,15 @@ ssl_HashHandshakeMessage(sslSocket *ss, SSLHandshakeType ct,
const PRUint8 *b, PRUint32 length)
{
return ssl_HashHandshakeMessageInt(ss, ct, ss->ssl3.hs.recvMessageSeq,
- b, length);
+ b, length, ssl3_UpdateHandshakeHashes);
+}
+
+SECStatus
+ssl_HashPostHandshakeMessage(sslSocket *ss, SSLHandshakeType ct,
+ const PRUint8 *b, PRUint32 length)
+{
+ return ssl_HashHandshakeMessageInt(ss, ct, ss->ssl3.hs.recvMessageSeq,
+ b, length, ssl3_UpdatePostHandshakeHashes);
}
/* Called from ssl3_HandleHandshake() when it has gathered a complete ssl3
@@ -11651,9 +12023,11 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length,
break;
default:
- rv = ssl_HashHandshakeMessage(ss, ss->ssl3.hs.msg_type, b, length);
- if (rv != SECSuccess) {
- return SECFailure;
+ if (!tls13_IsPostHandshake(ss)) {
+ rv = ssl_HashHandshakeMessage(ss, ss->ssl3.hs.msg_type, b, length);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
}
}
@@ -11669,9 +12043,10 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length,
* authenticate the certificate in ssl3_HandleCertificateStatus.
*/
rv = ssl3_AuthCertificate(ss); /* sets ss->ssl3.hs.ws */
- PORT_Assert(rv != SECWouldBlock);
if (rv != SECSuccess) {
- return rv;
+ /* This can't block. */
+ PORT_Assert(PORT_GetError() != PR_WOULD_BLOCK_ERROR);
+ return SECFailure;
}
}
@@ -11829,28 +12204,17 @@ ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b,
static SECStatus
ssl3_HandleHandshake(sslSocket *ss, sslBuffer *origBuf)
{
- /*
- * There may be a partial handshake message already in the handshake
- * state. The incoming buffer may contain another portion, or a
- * complete message or several messages followed by another portion.
- *
- * Each message is made contiguous before being passed to the actual
- * message parser.
- */
- sslBuffer *buf = &ss->ssl3.hs.msgState; /* do not lose the original buffer pointer */
+ sslBuffer buf = *origBuf; /* Work from a copy. */
SECStatus rv;
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
- if (buf->buf == NULL) {
- *buf = *origBuf;
- }
- while (buf->len > 0) {
+ while (buf.len > 0) {
if (ss->ssl3.hs.header_bytes < 4) {
PRUint8 t;
- t = *(buf->buf++);
- buf->len--;
+ t = *(buf.buf++);
+ buf.len--;
if (ss->ssl3.hs.header_bytes++ == 0)
ss->ssl3.hs.msg_type = (SSLHandshakeType)t;
else
@@ -11862,12 +12226,12 @@ ssl3_HandleHandshake(sslSocket *ss, sslBuffer *origBuf)
if (ss->ssl3.hs.msg_len > MAX_HANDSHAKE_MSG_LEN) {
(void)ssl3_DecodeError(ss);
PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
- return SECFailure;
+ goto loser;
}
#undef MAX_HANDSHAKE_MSG_LEN
/* If msg_len is zero, be sure we fall through,
- ** even if buf->len is zero.
+ ** even if buf.len is zero.
*/
if (ss->ssl3.hs.msg_len > 0)
continue;
@@ -11878,43 +12242,36 @@ ssl3_HandleHandshake(sslSocket *ss, sslBuffer *origBuf)
* data available for this message. If it can be done right out
* of the original buffer, then use it from there.
*/
- if (ss->ssl3.hs.msg_body.len == 0 && buf->len >= ss->ssl3.hs.msg_len) {
+ if (ss->ssl3.hs.msg_body.len == 0 && buf.len >= ss->ssl3.hs.msg_len) {
/* handle it from input buffer */
- rv = ssl3_HandleHandshakeMessage(ss, buf->buf, ss->ssl3.hs.msg_len,
- buf->len == ss->ssl3.hs.msg_len);
- if (rv == SECFailure) {
- /* This test wants to fall through on either
- * SECSuccess or SECWouldBlock.
- * ssl3_HandleHandshakeMessage MUST set the error code.
- */
- return rv;
- }
- buf->buf += ss->ssl3.hs.msg_len;
- buf->len -= ss->ssl3.hs.msg_len;
+ rv = ssl3_HandleHandshakeMessage(ss, buf.buf, ss->ssl3.hs.msg_len,
+ buf.len == ss->ssl3.hs.msg_len);
+ buf.buf += ss->ssl3.hs.msg_len;
+ buf.len -= ss->ssl3.hs.msg_len;
ss->ssl3.hs.msg_len = 0;
ss->ssl3.hs.header_bytes = 0;
- if (rv != SECSuccess) { /* return if SECWouldBlock. */
- return rv;
+ if (rv != SECSuccess) {
+ goto loser;
}
} else {
/* must be copied to msg_body and dealt with from there */
unsigned int bytes;
PORT_Assert(ss->ssl3.hs.msg_body.len < ss->ssl3.hs.msg_len);
- bytes = PR_MIN(buf->len, ss->ssl3.hs.msg_len - ss->ssl3.hs.msg_body.len);
+ bytes = PR_MIN(buf.len, ss->ssl3.hs.msg_len - ss->ssl3.hs.msg_body.len);
/* Grow the buffer if needed */
rv = sslBuffer_Grow(&ss->ssl3.hs.msg_body, ss->ssl3.hs.msg_len);
if (rv != SECSuccess) {
/* sslBuffer_Grow has set a memory error code. */
- return SECFailure;
+ goto loser;
}
PORT_Memcpy(ss->ssl3.hs.msg_body.buf + ss->ssl3.hs.msg_body.len,
- buf->buf, bytes);
+ buf.buf, bytes);
ss->ssl3.hs.msg_body.len += bytes;
- buf->buf += bytes;
- buf->len -= bytes;
+ buf.buf += bytes;
+ buf.len -= bytes;
PORT_Assert(ss->ssl3.hs.msg_body.len <= ss->ssl3.hs.msg_len);
@@ -11922,30 +12279,33 @@ ssl3_HandleHandshake(sslSocket *ss, sslBuffer *origBuf)
if (ss->ssl3.hs.msg_body.len == ss->ssl3.hs.msg_len) {
rv = ssl3_HandleHandshakeMessage(
ss, ss->ssl3.hs.msg_body.buf, ss->ssl3.hs.msg_len,
- buf->len == 0);
- if (rv == SECFailure) {
- /* This test wants to fall through on either
- * SECSuccess or SECWouldBlock.
- * ssl3_HandleHandshakeMessage MUST set error code.
- */
- return rv;
- }
+ buf.len == 0);
ss->ssl3.hs.msg_body.len = 0;
ss->ssl3.hs.msg_len = 0;
ss->ssl3.hs.header_bytes = 0;
- if (rv != SECSuccess) { /* return if SECWouldBlock. */
- return rv;
+ if (rv != SECSuccess) {
+ goto loser;
}
} else {
- PORT_Assert(buf->len == 0);
+ PORT_Assert(buf.len == 0);
break;
}
}
} /* end loop */
origBuf->len = 0; /* So ssl3_GatherAppDataRecord will keep looping. */
- buf->buf = NULL; /* not a leak. */
return SECSuccess;
+
+loser : {
+ /* Make sure to remove any data that was consumed. */
+ unsigned int consumed = origBuf->len - buf.len;
+ PORT_Assert(consumed == buf.buf - origBuf->buf);
+ if (consumed > 0) {
+ memmove(origBuf->buf, origBuf->buf + consumed, buf.len);
+ origBuf->len = buf.len;
+ }
+}
+ return SECFailure;
}
/* These macros return the given value with the MSB copied to all the other
@@ -12203,7 +12563,7 @@ ssl3_UnprotectRecord(sslSocket *ss,
unsigned int hashBytes = MAX_MAC_LENGTH + 1;
SECStatus rv;
- PORT_Assert(spec->direction == CipherSpecRead);
+ PORT_Assert(spec->direction == ssl_secret_read);
good = ~0U;
minLength = spec->macDef->mac_size;
@@ -12233,7 +12593,7 @@ ssl3_UnprotectRecord(sslSocket *ss,
* discard it before decrypting the rest.
*/
PRUint8 iv[MAX_IV_LENGTH];
- int decoded;
+ unsigned int decoded;
ivLen = cipher_def->iv_size;
if (ivLen < 8 || ivLen > sizeof(iv)) {
@@ -12281,12 +12641,12 @@ ssl3_UnprotectRecord(sslSocket *ss,
rType, isTLS, rVersion, IS_DTLS(ss), decryptedLen, &header);
PORT_Assert(rv == SECSuccess);
rv = spec->aead(&spec->keyMaterial,
- PR_TRUE, /* do decrypt */
- plaintext->buf, /* out */
- (int *)&plaintext->len, /* outlen */
- plaintext->space, /* maxout */
- cText->buf->buf, /* in */
- cText->buf->len, /* inlen */
+ PR_TRUE, /* do decrypt */
+ plaintext->buf, /* out */
+ &plaintext->len, /* outlen */
+ plaintext->space, /* maxout */
+ cText->buf->buf, /* in */
+ cText->buf->len, /* inlen */
SSL_BUFFER_BASE(&header), SSL_BUFFER_LEN(&header));
if (rv != SECSuccess) {
good = 0;
@@ -12299,7 +12659,7 @@ ssl3_UnprotectRecord(sslSocket *ss,
/* decrypt from cText buf to plaintext. */
rv = spec->cipher(
- spec->cipherContext, plaintext->buf, (int *)&plaintext->len,
+ spec->cipherContext, plaintext->buf, &plaintext->len,
plaintext->space, cText->buf->buf + ivLen, cText->buf->len - ivLen);
if (rv != SECSuccess) {
goto decrypt_loser;
@@ -12392,7 +12752,7 @@ ssl3_HandleNonApplicationData(sslSocket *ss, SSLContentType rType,
ssl_GetSSL3HandshakeLock(ss);
/* All the functions called in this switch MUST set error code if
- ** they return SECFailure or SECWouldBlock.
+ ** they return SECFailure.
*/
switch (rType) {
case ssl_ct_change_cipher_spec:
@@ -12449,7 +12809,7 @@ ssl3_GetCipherSpec(sslSocket *ss, SSL3Ciphertext *cText)
}
if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
/* Try to find the cipher spec. */
- newSpec = ssl_FindCipherSpecByEpoch(ss, CipherSpecRead,
+ newSpec = ssl_FindCipherSpecByEpoch(ss, ssl_secret_read,
epoch);
if (newSpec != NULL) {
return newSpec;
@@ -12462,8 +12822,9 @@ ssl3_GetCipherSpec(sslSocket *ss, SSL3Ciphertext *cText)
/* MAX_EXPANSION is the amount by which a record might plausibly be expanded
* when protected. It's the worst case estimate, so the sum of block cipher
- * padding (up to 256 octets) and HMAC (48 octets for SHA-384). */
-#define MAX_EXPANSION (256 + 48)
+ * padding (up to 256 octets), HMAC (48 octets for SHA-384), and IV (16
+ * octets for AES). */
+#define MAX_EXPANSION (256 + 48 + 16)
/* if cText is non-null, then decipher and check the MAC of the
* SSL record from cText->buf (typically gs->inbuf)
@@ -12581,7 +12942,7 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText)
rv = SECFailure;
} else {
#ifdef UNSAFE_FUZZER_MODE
- rv = Null_Cipher(NULL, plaintext->buf, (int *)&plaintext->len,
+ rv = Null_Cipher(NULL, plaintext->buf, &plaintext->len,
plaintext->space, cText->buf->buf, cText->buf->len);
#else
/* IMPORTANT: Unprotect functions MUST NOT send alerts
@@ -12714,8 +13075,8 @@ ssl3_InitState(sslSocket *ss)
ssl_GetSpecWriteLock(ss);
PR_INIT_CLIST(&ss->ssl3.hs.cipherSpecs);
- rv = ssl_SetupNullCipherSpec(ss, CipherSpecRead);
- rv |= ssl_SetupNullCipherSpec(ss, CipherSpecWrite);
+ rv = ssl_SetupNullCipherSpec(ss, ssl_secret_read);
+ rv |= ssl_SetupNullCipherSpec(ss, ssl_secret_write);
ss->ssl3.pwSpec = ss->ssl3.prSpec = NULL;
ssl_ReleaseSpecWriteLock(ss);
if (rv != SECSuccess) {
@@ -13080,6 +13441,9 @@ ssl3_DestroySSL3Info(sslSocket *ss)
if (ss->ssl3.hs.sha) {
PK11_DestroyContext(ss->ssl3.hs.sha, PR_TRUE);
}
+ if (ss->ssl3.hs.shaPostHandshake) {
+ PK11_DestroyContext(ss->ssl3.hs.shaPostHandshake, PR_TRUE);
+ }
if (ss->ssl3.hs.messages.buf) {
sslBuffer_Clear(&ss->ssl3.hs.messages);
}
diff --git a/security/nss/lib/ssl/ssl3ecc.c b/security/nss/lib/ssl/ssl3ecc.c
index 52d5bb5152..d5ad372e55 100644
--- a/security/nss/lib/ssl/ssl3ecc.c
+++ b/security/nss/lib/ssl/ssl3ecc.c
@@ -548,8 +548,8 @@ ssl3_HandleECDHServerKeyExchange(sslSocket *ss, PRUint8 *b, PRUint32 length)
errCode = PORT_GetError();
goto alert_loser; /* malformed or unsupported. */
}
- rv = ssl_CheckSignatureSchemeConsistency(ss, sigScheme,
- ss->sec.peerCert);
+ rv = ssl_CheckSignatureSchemeConsistency(
+ ss, sigScheme, &ss->sec.peerCert->subjectPublicKeyInfo);
if (rv != SECSuccess) {
errCode = PORT_GetError();
goto alert_loser;
diff --git a/security/nss/lib/ssl/ssl3ext.c b/security/nss/lib/ssl/ssl3ext.c
index 60b5889e72..7e674f0e03 100644
--- a/security/nss/lib/ssl/ssl3ext.c
+++ b/security/nss/lib/ssl/ssl3ext.c
@@ -16,6 +16,7 @@
#include "ssl3exthandle.h"
#include "tls13err.h"
#include "tls13exthandle.h"
+#include "tls13subcerts.h"
/* Callback function that handles a received extension. */
typedef SECStatus (*ssl3ExtensionHandlerFunc)(const sslSocket *ss,
@@ -45,12 +46,14 @@ static const ssl3ExtensionHandler clientHelloHandlers[] = {
{ ssl_signature_algorithms_xtn, &ssl3_HandleSigAlgsXtn },
{ ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn },
{ ssl_signed_cert_timestamp_xtn, &ssl3_ServerHandleSignedCertTimestampXtn },
+ { ssl_delegated_credentials_xtn, &tls13_ServerHandleDelegatedCredentialsXtn },
{ ssl_tls13_key_share_xtn, &tls13_ServerHandleKeyShareXtn },
{ ssl_tls13_pre_shared_key_xtn, &tls13_ServerHandlePreSharedKeyXtn },
{ 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 }
};
@@ -95,6 +98,7 @@ static const ssl3ExtensionHandler newSessionTicketHandlers[] = {
static const ssl3ExtensionHandler serverCertificateHandlers[] = {
{ ssl_signed_cert_timestamp_xtn, &ssl3_ClientHandleSignedCertTimestampXtn },
{ ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn },
+ { ssl_delegated_credentials_xtn, &tls13_ClientHandleDelegatedCredentialsXtn },
{ 0, NULL }
};
@@ -126,6 +130,7 @@ static const sslExtensionBuilder clientHelloSendersTLS[] =
{ 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 },
@@ -138,6 +143,7 @@ static const sslExtensionBuilder clientHelloSendersTLS[] =
{ 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 },
@@ -168,6 +174,7 @@ static const struct {
} ssl_supported_extensions[] = {
{ ssl_server_name_xtn, ssl_ext_native_only },
{ ssl_cert_status_xtn, ssl_ext_native },
+ { ssl_delegated_credentials_xtn, ssl_ext_native },
{ ssl_supported_groups_xtn, ssl_ext_native_only },
{ ssl_ec_point_formats_xtn, ssl_ext_native },
{ ssl_signature_algorithms_xtn, ssl_ext_native_only },
@@ -707,6 +714,9 @@ ssl_ConstructExtensions(sslSocket *ss, sslBuffer *buf, SSLHandshakeType message)
PORT_Assert(buf->len == 0);
+ /* Clear out any extensions previously advertised */
+ ss->xtnData.numAdvertised = 0;
+
switch (message) {
case ssl_hs_client_hello:
if (ss->vrange.max > SSL_LIBRARY_VERSION_3_0) {
@@ -949,6 +959,9 @@ ssl3_InitExtensionData(TLSExtensionData *xtnData, const sslSocket *ss)
++advertisedMax;
}
xtnData->advertised = PORT_ZNewArray(PRUint16, advertisedMax);
+ xtnData->peerDelegCred = NULL;
+ xtnData->peerRequestedDelegCred = PR_FALSE;
+ xtnData->sendingDelegCredToPeer = PR_FALSE;
}
void
@@ -967,6 +980,7 @@ ssl3_DestroyExtensionData(TLSExtensionData *xtnData)
PORT_Free(xtnData->advertised);
ssl_FreeEphemeralKeyPair(xtnData->esniPrivateKey);
SECITEM_FreeItem(&xtnData->keyShareExtension, PR_FALSE);
+ tls13_DestroyDelegatedCredential(xtnData->peerDelegCred);
}
/* Free everything that has been allocated and then reset back to
diff --git a/security/nss/lib/ssl/ssl3ext.h b/security/nss/lib/ssl/ssl3ext.h
index d96b4cffe6..97319c7d9a 100644
--- a/security/nss/lib/ssl/ssl3ext.h
+++ b/security/nss/lib/ssl/ssl3ext.h
@@ -111,6 +111,19 @@ struct TLSExtensionDataStr {
/* Pointer into |ss->esniKeys->keyShares| */
TLS13KeyShareEntry *peerEsniShare;
PRUint8 esniNonce[TLS13_ESNI_NONCE_SIZE];
+
+ /* Delegated credentials.
+ *
+ * The delegated credential sent by the peer. Set by
+ * |tls13_ReadDelegatedCredential|.
+ */
+ sslDelegatedCredential *peerDelegCred;
+ /* Whether the peer requested a delegated credential. */
+ PRBool peerRequestedDelegCred;
+ /* Whether the host is committed to using a delegated credential. Set by
+ * |tls13_MaybeSetDelegatedCredential|.
+ */
+ PRBool sendingDelegCredToPeer;
};
typedef struct TLSExtensionStr {
diff --git a/security/nss/lib/ssl/ssl3exthandle.c b/security/nss/lib/ssl/ssl3exthandle.c
index a2d83fa97a..206cb00e48 100644
--- a/security/nss/lib/ssl/ssl3exthandle.c
+++ b/security/nss/lib/ssl/ssl3exthandle.c
@@ -246,7 +246,7 @@ ssl3_ClientSendSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData,
session_ticket = &sid->u.ssl3.locked.sessionTicket;
if (session_ticket->ticket.data &&
(xtnData->ticketTimestampVerified ||
- ssl_TicketTimeValid(session_ticket))) {
+ ssl_TicketTimeValid(ss, session_ticket))) {
xtnData->ticketTimestampVerified = PR_FALSE;
@@ -608,7 +608,6 @@ ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData
return SECSuccess;
}
-PRUint32 ssl_ticket_lifetime = 2 * 24 * 60 * 60; /* 2 days in seconds */
#define TLS_EX_SESS_TICKET_VERSION (0x010a)
/*
@@ -742,7 +741,7 @@ ssl3_EncodeSessionTicket(sslSocket *ss, const NewSessionTicket *ticket,
}
/* timestamp */
- now = ssl_TimeUsec();
+ now = ssl_Time(ss);
PORT_Assert(sizeof(now) == 8);
rv = sslBuffer_AppendNumber(&plaintext, now, 8);
if (rv != SECSuccess)
@@ -797,7 +796,7 @@ ssl3_EncodeSessionTicket(sslSocket *ss, const NewSessionTicket *ticket,
* This is compared to the expected time, which should differ only as a
* result of clock errors or errors in the RTT estimate.
*/
- ticketAgeBaseline = (ssl_TimeUsec() - ss->ssl3.hs.serverHelloTime) / PR_USEC_PER_MSEC;
+ ticketAgeBaseline = (ssl_Time(ss) - ss->ssl3.hs.serverHelloTime) / PR_USEC_PER_MSEC;
ticketAgeBaseline -= ticket->ticket_age_add;
rv = sslBuffer_AppendNumber(&plaintext, ticketAgeBaseline, 4);
if (rv != SECSuccess)
@@ -1242,8 +1241,8 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, const SECItem *ticket,
}
/* Use the ticket if it is valid and unexpired. */
- if (parsedTicket.timestamp + ssl_ticket_lifetime * PR_USEC_PER_SEC >
- ssl_TimeUsec()) {
+ PRTime end = parsedTicket.timestamp + (ssl_ticket_lifetime * PR_USEC_PER_SEC);
+ if (end > ssl_Time(ss)) {
rv = ssl_CreateSIDFromTicket(ss, ticket, &parsedTicket, &sid);
if (rv != SECSuccess) {
@@ -1637,13 +1636,18 @@ SECStatus
ssl3_SendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added)
{
- SECStatus rv;
-
if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_2) {
return SECSuccess;
}
- rv = ssl3_EncodeSigAlgs(ss, buf);
+ PRUint16 minVersion;
+ if (ss->sec.isServer) {
+ minVersion = ss->version; /* CertificateRequest */
+ } else {
+ minVersion = ss->vrange.min; /* ClientHello */
+ }
+
+ SECStatus rv = ssl3_EncodeSigAlgs(ss, minVersion, buf);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -1927,7 +1931,7 @@ ssl_HandleRecordSizeLimitXtn(const sslSocket *ss, TLSExtensionData *xtnData,
return SECFailure;
}
if (data->len != 0 || limit < 64) {
- ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
+ ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
return SECFailure;
}
diff --git a/security/nss/lib/ssl/ssl3gthr.c b/security/nss/lib/ssl/ssl3gthr.c
index 64a1878f76..f9c741746f 100644
--- a/security/nss/lib/ssl/ssl3gthr.c
+++ b/security/nss/lib/ssl/ssl3gthr.c
@@ -389,7 +389,6 @@ dtls_GatherData(sslSocket *ss, sslGather *gs, int flags)
* application data is available.
* Returns 0 if ssl3_GatherData hits EOF.
* Returns -1 on read error, or PR_WOULD_BLOCK_ERROR, or handleRecord error.
- * Returns -2 on SECWouldBlock return from ssl3_HandleRecord.
*
* Called from ssl_GatherRecord1stHandshake in sslcon.c,
* and from SSL_ForceHandshake in sslsecur.c
@@ -408,7 +407,7 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
SSL_TRC(3, ("%d: SSL3[%d] Cannot gather data; fatal alert already sent",
SSL_GETPID(), ss->fd));
PORT_SetError(SSL_ERROR_HANDSHAKE_FAILED);
- return SECFailure;
+ return -1;
}
SSL_TRC(30, ("%d: SSL3[%d]: ssl3_GatherCompleteHandshake",
@@ -422,7 +421,6 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
do {
- PRBool handleRecordNow = PR_FALSE;
PRBool processingEarlyData;
ssl_GetSSL3HandshakeLock(ss);
@@ -436,96 +434,82 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
if (ss->ssl3.hs.restartTarget) {
ssl_ReleaseSSL3HandshakeLock(ss);
PORT_SetError(PR_WOULD_BLOCK_ERROR);
- return (int)SECFailure;
+ return -1;
}
- /* Treat an empty msgState like a NULL msgState. (Most of the time
- * when ssl3_HandleHandshake returns SECWouldBlock, it leaves
- * behind a non-NULL but zero-length msgState).
- * Test: async_cert_restart_server_sends_hello_request_first_in_separate_record
- */
- if (ss->ssl3.hs.msgState.buf) {
- if (ss->ssl3.hs.msgState.len == 0) {
- ss->ssl3.hs.msgState.buf = NULL;
- } else {
- handleRecordNow = PR_TRUE;
+ /* If we have a detached record layer, don't ever gather. */
+ if (ss->recordWriteCallback) {
+ PRBool done = ss->firstHsDone;
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ if (done) {
+ return 1;
}
+ PORT_SetError(PR_WOULD_BLOCK_ERROR);
+ return -1;
}
ssl_ReleaseSSL3HandshakeLock(ss);
- if (handleRecordNow) {
- /* ssl3_HandleHandshake previously returned SECWouldBlock and the
- * as-yet-unprocessed plaintext of that previous handshake record.
- * We need to process it now before we overwrite it with the next
- * handshake record.
- */
- SSL_DBG(("%d: SSL3[%d]: resuming handshake",
- SSL_GETPID(), ss->fd));
- PORT_Assert(!IS_DTLS(ss));
- rv = ssl3_HandleNonApplicationData(ss, ssl_ct_handshake,
- 0, 0, &ss->gs.buf);
- } else {
- /* State for SSLv2 client hello support. */
- ssl2Gather ssl2gs = { PR_FALSE, 0 };
- ssl2Gather *ssl2gs_ptr = NULL;
+ /* State for SSLv2 client hello support. */
+ ssl2Gather ssl2gs = { PR_FALSE, 0 };
+ ssl2Gather *ssl2gs_ptr = NULL;
- if (ss->sec.isServer && ss->opt.enableV2CompatibleHello &&
- ss->ssl3.hs.ws == wait_client_hello) {
- ssl2gs_ptr = &ssl2gs;
- }
+ /* If we're a server and waiting for a client hello, accept v2. */
+ if (ss->sec.isServer && ss->opt.enableV2CompatibleHello &&
+ ss->ssl3.hs.ws == wait_client_hello) {
+ ssl2gs_ptr = &ssl2gs;
+ }
- /* bring in the next sslv3 record. */
- if (ss->recvdCloseNotify) {
- /* RFC 5246 Section 7.2.1:
- * Any data received after a closure alert is ignored.
- */
- return 0;
- }
+ /* bring in the next sslv3 record. */
+ if (ss->recvdCloseNotify) {
+ /* RFC 5246 Section 7.2.1:
+ * Any data received after a closure alert is ignored.
+ */
+ return 0;
+ }
- if (!IS_DTLS(ss)) {
- /* Passing a non-NULL ssl2gs here enables detection of
- * SSLv2-compatible ClientHello messages. */
- rv = ssl3_GatherData(ss, &ss->gs, flags, ssl2gs_ptr);
- } else {
- rv = dtls_GatherData(ss, &ss->gs, flags);
-
- /* If we got a would block error, that means that no data was
- * available, so we check the timer to see if it's time to
- * retransmit */
- if (rv == SECFailure &&
- (PORT_GetError() == PR_WOULD_BLOCK_ERROR)) {
- dtls_CheckTimer(ss);
- /* Restore the error in case something succeeded */
- PORT_SetError(PR_WOULD_BLOCK_ERROR);
- }
+ if (!IS_DTLS(ss)) {
+ /* If we're a server waiting for a ClientHello then pass
+ * ssl2gs to support SSLv2 ClientHello messages. */
+ rv = ssl3_GatherData(ss, &ss->gs, flags, ssl2gs_ptr);
+ } else {
+ rv = dtls_GatherData(ss, &ss->gs, flags);
+
+ /* If we got a would block error, that means that no data was
+ * available, so we check the timer to see if it's time to
+ * retransmit */
+ if (rv == SECFailure &&
+ (PORT_GetError() == PR_WOULD_BLOCK_ERROR)) {
+ dtls_CheckTimer(ss);
+ /* Restore the error in case something succeeded */
+ PORT_SetError(PR_WOULD_BLOCK_ERROR);
}
+ }
- if (rv <= 0) {
- return rv;
- }
+ if (rv <= 0) {
+ return rv;
+ }
- if (ssl2gs.isV2) {
- rv = ssl3_HandleV2ClientHello(ss, ss->gs.inbuf.buf,
- ss->gs.inbuf.len,
- ssl2gs.padding);
- if (rv < 0) {
- return rv;
- }
- } else {
- /* decipher it, and handle it if it's a handshake.
- * If it's application data, ss->gs.buf will not be empty upon return.
- * If it's a change cipher spec, alert, or handshake message,
- * ss->gs.buf.len will be 0 when ssl3_HandleRecord returns SECSuccess.
- *
- * cText only needs to be valid for this next function call, so
- * it can borrow gs.hdr.
- */
- cText.hdr = ss->gs.hdr;
- cText.hdrLen = ss->gs.hdrLen;
- cText.buf = &ss->gs.inbuf;
- rv = ssl3_HandleRecord(ss, &cText);
+ if (ssl2gs.isV2) {
+ rv = ssl3_HandleV2ClientHello(ss, ss->gs.inbuf.buf,
+ ss->gs.inbuf.len,
+ ssl2gs.padding);
+ if (rv < 0) {
+ return rv;
}
+ } else {
+ /* decipher it, and handle it if it's a handshake.
+ * If it's application data, ss->gs.buf will not be empty upon return.
+ * If it's a change cipher spec, alert, or handshake message,
+ * ss->gs.buf.len will be 0 when ssl3_HandleRecord returns SECSuccess.
+ *
+ * cText only needs to be valid for this next function call, so
+ * it can borrow gs.hdr.
+ */
+ cText.hdr = ss->gs.hdr;
+ cText.hdrLen = ss->gs.hdrLen;
+ cText.buf = &ss->gs.inbuf;
+ rv = ssl3_HandleRecord(ss, &cText);
}
if (rv < 0) {
return ss->recvdCloseNotify ? 0 : rv;
@@ -575,7 +559,7 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
* delivered to the application before the handshake completes. */
ssl_ReleaseSSL3HandshakeLock(ss);
PORT_SetError(PR_WOULD_BLOCK_ERROR);
- return SECWouldBlock;
+ return -1;
}
ssl_ReleaseSSL3HandshakeLock(ss);
} while (keepGoing);
@@ -596,7 +580,6 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
* Returns 1 when application data is available.
* Returns 0 if ssl3_GatherData hits EOF.
* Returns -1 on read error, or PR_WOULD_BLOCK_ERROR, or handleRecord error.
- * Returns -2 on SECWouldBlock return from ssl3_HandleRecord.
*
* Called from DoRecv in sslsecur.c
* Caller must hold the recv buf lock.
@@ -616,3 +599,109 @@ ssl3_GatherAppDataRecord(sslSocket *ss, int flags)
return rv;
}
+
+SECStatus
+SSLExp_RecordLayerData(PRFileDesc *fd, PRUint16 epoch,
+ SSLContentType contentType,
+ const PRUint8 *data, unsigned int len)
+{
+ SECStatus rv;
+ sslSocket *ss = ssl_FindSocket(fd);
+ if (!ss) {
+ return SECFailure;
+ }
+ if (IS_DTLS(ss) || data == NULL || len == 0) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ /* Run any handshake function. If SSL_RecordLayerData is the only way that
+ * the handshake is driven, then this is necessary to ensure that
+ * ssl_BeginClientHandshake or ssl_BeginServerHandshake is called. Note that
+ * the other function that might be set to ss->handshake,
+ * ssl3_GatherCompleteHandshake, does nothing when this function is used. */
+ ssl_Get1stHandshakeLock(ss);
+ rv = ssl_Do1stHandshake(ss);
+ if (rv != SECSuccess && PORT_GetError() != PR_WOULD_BLOCK_ERROR) {
+ goto early_loser; /* Rely on the existing code. */
+ }
+
+ /* Don't allow application data before handshake completion. */
+ if (contentType == ssl_ct_application_data && !ss->firstHsDone) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ goto early_loser;
+ }
+
+ /* Then we can validate the epoch. */
+ PRErrorCode epochError;
+ ssl_GetSpecReadLock(ss);
+ 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. */
+ } else {
+ epochError = 0; /* Just right. */
+ }
+ ssl_ReleaseSpecReadLock(ss);
+ if (epochError) {
+ PORT_SetError(epochError);
+ goto early_loser;
+ }
+
+ /* 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) {
+ ssl_Release1stHandshakeLock(ss);
+ return SECFailure;
+ }
+
+ /* Finally, save the data... */
+ ssl_GetRecvBufLock(ss);
+ rv = sslBuffer_Append(&ss->gs.buf, data, len);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* ...and process it. Just saving application data is enough for it to be
+ * available to PR_Read(). */
+ if (contentType != ssl_ct_application_data) {
+ rv = ssl3_HandleNonApplicationData(ss, contentType, 0, 0, &ss->gs.buf);
+ /* This occasionally blocks, but that's OK here. */
+ if (rv != SECSuccess && PORT_GetError() != PR_WOULD_BLOCK_ERROR) {
+ goto loser;
+ }
+ }
+
+ ssl_ReleaseRecvBufLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+ return SECSuccess;
+
+loser:
+ /* Make sure that any data is not used again. */
+ ss->gs.buf.len = 0;
+ ssl_ReleaseRecvBufLock(ss);
+early_loser:
+ ssl_Release1stHandshakeLock(ss);
+ return SECFailure;
+}
+
+SECStatus
+SSLExp_GetCurrentEpoch(PRFileDesc *fd, PRUint16 *readEpoch,
+ PRUint16 *writeEpoch)
+{
+ sslSocket *ss = ssl_FindSocket(fd);
+ if (!ss) {
+ return SECFailure;
+ }
+
+ ssl_GetSpecReadLock(ss);
+ if (readEpoch) {
+ *readEpoch = ss->ssl3.crSpec->epoch;
+ }
+ if (writeEpoch) {
+ *writeEpoch = ss->ssl3.cwSpec->epoch;
+ }
+ ssl_ReleaseSpecReadLock(ss);
+ return SECSuccess;
+}
diff --git a/security/nss/lib/ssl/ssl3prot.h b/security/nss/lib/ssl/ssl3prot.h
index bfaa10d3fb..ffe8373011 100644
--- a/security/nss/lib/ssl/ssl3prot.h
+++ b/security/nss/lib/ssl/ssl3prot.h
@@ -74,6 +74,7 @@ typedef enum {
unrecognized_name = 112,
bad_certificate_status_response = 113,
bad_certificate_hash_value = 114,
+ certificate_required = 116,
no_application_protocol = 120,
/* invalid alert */
diff --git a/security/nss/lib/ssl/sslauth.c b/security/nss/lib/ssl/sslauth.c
index 5b5f672f08..f4c3642513 100644
--- a/security/nss/lib/ssl/sslauth.c
+++ b/security/nss/lib/ssl/sslauth.c
@@ -245,7 +245,6 @@ SSL_AuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer)
sslSocket *ss;
SECCertUsage certUsage;
const char *hostname = NULL;
- PRTime now = PR_Now();
SECItemArray *certStatusArray;
ss = ssl_FindSocket(fd);
@@ -257,6 +256,7 @@ SSL_AuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer)
handle = (CERTCertDBHandle *)arg;
certStatusArray = &ss->sec.ci.sid->peerCertStatus;
+ PRTime now = ssl_Time(ss);
if (certStatusArray->len) {
PORT_SetError(0);
if (CERT_CacheOCSPResponseFromSideChannel(handle, ss->sec.peerCert, now,
diff --git a/security/nss/lib/ssl/sslcert.c b/security/nss/lib/ssl/sslcert.c
index 878df761ed..d2c9480d57 100644
--- a/security/nss/lib/ssl/sslcert.c
+++ b/security/nss/lib/ssl/sslcert.c
@@ -8,10 +8,11 @@
#include "ssl.h"
#include "sslimpl.h"
-#include "secoid.h" /* for SECOID_GetAlgorithmTag */
-#include "pk11func.h" /* for PK11_ReferenceSlot */
-#include "nss.h" /* for NSS_RegisterShutdown */
-#include "prinit.h" /* for PR_CallOnceWithArg */
+#include "secoid.h" /* for SECOID_GetAlgorithmTag */
+#include "pk11func.h" /* for PK11_ReferenceSlot */
+#include "nss.h" /* for NSS_RegisterShutdown */
+#include "prinit.h" /* for PR_CallOnceWithArg */
+#include "tls13subcerts.h" /* for tls13_ReadDelegatedCredential */
/* This global item is used only in servers. It is is initialized by
* SSL_ConfigSecureServer(), and is used in ssl3_SendCertificateRequest().
@@ -102,6 +103,8 @@ ssl_NewServerCert()
sc->serverCertChain = NULL;
sc->certStatusArray = NULL;
sc->signedCertTimestamps.len = 0;
+ sc->delegCred.len = 0;
+ sc->delegCredKeyPair = NULL;
return sc;
}
@@ -148,8 +151,17 @@ ssl_CopyServerCert(const sslServerCert *oc)
}
if (SECITEM_CopyItem(NULL, &sc->signedCertTimestamps,
- &oc->signedCertTimestamps) != SECSuccess)
+ &oc->signedCertTimestamps) != SECSuccess) {
goto loser;
+ }
+
+ if (SECITEM_CopyItem(NULL, &sc->delegCred, &oc->delegCred) != SECSuccess) {
+ goto loser;
+ }
+ if (oc->delegCredKeyPair) {
+ sc->delegCredKeyPair = ssl_GetKeyPairRef(oc->delegCredKeyPair);
+ }
+
return sc;
loser:
ssl_FreeServerCert(sc);
@@ -178,6 +190,12 @@ ssl_FreeServerCert(sslServerCert *sc)
if (sc->signedCertTimestamps.len) {
SECITEM_FreeItem(&sc->signedCertTimestamps, PR_FALSE);
}
+ if (sc->delegCred.len) {
+ SECITEM_FreeItem(&sc->delegCred, PR_FALSE);
+ }
+ if (sc->delegCredKeyPair) {
+ ssl_FreeKeyPair(sc->delegCredKeyPair);
+ }
PORT_ZFree(sc, sizeof(*sc));
}
@@ -309,6 +327,79 @@ ssl_PopulateSignedCertTimestamps(sslServerCert *sc,
return SECSuccess;
}
+/* Installs the given delegated credential (DC) and DC private key into the
+ * certificate.
+ *
+ * It's the caller's responsibility to ensure that the DC is well-formed and
+ * that the DC public key matches the DC private key.
+ */
+static SECStatus
+ssl_PopulateDelegatedCredential(sslServerCert *sc,
+ const SECItem *delegCred,
+ const SECKEYPrivateKey *delegCredPrivKey)
+{
+ sslDelegatedCredential *dc = NULL;
+
+ if (sc->delegCred.len) {
+ SECITEM_FreeItem(&sc->delegCred, PR_FALSE);
+ }
+
+ if (sc->delegCredKeyPair) {
+ ssl_FreeKeyPair(sc->delegCredKeyPair);
+ sc->delegCredKeyPair = NULL;
+ }
+
+ /* Both the DC and its private are present. */
+ if (delegCred && delegCredPrivKey) {
+ SECStatus rv;
+ SECKEYPublicKey *pub;
+ SECKEYPrivateKey *priv;
+
+ if (!delegCred->data || delegCred->len == 0) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ goto loser;
+ }
+
+ /* Parse the DC. */
+ rv = tls13_ReadDelegatedCredential(delegCred->data, delegCred->len, &dc);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Make a copy of the DC. */
+ rv = SECITEM_CopyItem(NULL, &sc->delegCred, delegCred);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Make a copy of the DC private key. */
+ priv = SECKEY_CopyPrivateKey(delegCredPrivKey);
+ if (!priv) {
+ goto loser;
+ }
+
+ /* parse public key from the DC. */
+ pub = SECKEY_ExtractPublicKey(dc->spki);
+ if (!pub) {
+ goto loser;
+ }
+
+ sc->delegCredKeyPair = ssl_NewKeyPair(priv, pub);
+
+ /* Attempting to configure either the DC or DC private key, but not both. */
+ } else if (delegCred || delegCredPrivKey) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ goto loser;
+ }
+
+ tls13_DestroyDelegatedCredential(dc);
+ return SECSuccess;
+
+loser:
+ tls13_DestroyDelegatedCredential(dc);
+ return SECFailure;
+}
+
/* Find any existing certificates that overlap with the new certificate and
* either remove any supported authentication types that overlap with the new
* certificate or - if they have no types left - remove them entirely. */
@@ -379,6 +470,12 @@ ssl_ConfigCert(sslSocket *ss, sslAuthTypeMask authTypes,
if (rv != SECSuccess) {
goto loser;
}
+ rv = ssl_PopulateDelegatedCredential(sc, data->delegCred,
+ data->delegCredPrivKey);
+ if (rv != SECSuccess) {
+ error_code = PORT_GetError();
+ goto loser;
+ }
ssl_ClearMatchingCerts(ss, sc->authTypes, sc->namedCurve);
PR_APPEND_LINK(&sc->link, &ss->serverCerts);
return SECSuccess;
@@ -548,7 +645,7 @@ SSL_ConfigServerCert(PRFileDesc *fd, CERTCertificate *cert,
sslKeyPair *keyPair;
SECStatus rv;
SSLExtraServerCertData dataCopy = {
- ssl_auth_null, NULL, NULL, NULL
+ ssl_auth_null, NULL, NULL, NULL, NULL, NULL
};
sslAuthTypeMask authTypes;
diff --git a/security/nss/lib/ssl/sslcert.h b/security/nss/lib/ssl/sslcert.h
index fb31d1389d..8c2dadae46 100644
--- a/security/nss/lib/ssl/sslcert.h
+++ b/security/nss/lib/ssl/sslcert.h
@@ -41,6 +41,13 @@ typedef struct sslServerCertStr {
** timestamps item.
*/
SECItem signedCertTimestamps;
+
+ /* The delegated credential (DC) to send to clients who indicate support for
+ * the ietf-draft-tls-subcerts extension.
+ */
+ SECItem delegCred;
+ /* The key pair used to sign the handshake when serving a DC. */
+ sslKeyPair *delegCredKeyPair;
} sslServerCert;
#define SSL_CERT_IS(c, t) ((c)->authTypes & (1 << (t)))
diff --git a/security/nss/lib/ssl/sslcon.c b/security/nss/lib/ssl/sslcon.c
index bc63e15371..a6ef2a4a34 100644
--- a/security/nss/lib/ssl/sslcon.c
+++ b/security/nss/lib/ssl/sslcon.c
@@ -18,7 +18,6 @@
#include "sslerr.h"
#include "pk11func.h"
#include "prinit.h"
-#include "prtime.h" /* for PR_Now() */
/*
** Put a string tag in the library so that we can examine an executable
@@ -44,17 +43,13 @@ const char *ssl_version = "SECURITY_VERSION:"
* This function acquires and releases the RecvBufLock.
*
* returns SECSuccess for success.
- * returns SECWouldBlock when that value is returned by
- * ssl3_GatherCompleteHandshake().
- * returns SECFailure on all other errors.
+ * returns SECFailure on error, setting PR_WOULD_BLOCK_ERROR if only blocked.
*
* The gather functions called by ssl_GatherRecord1stHandshake are expected
* to return values interpreted as follows:
* 1 : the function completed without error.
* 0 : the function read EOF.
* -1 : read error, or PR_WOULD_BLOCK_ERROR, or handleRecord error.
- * -2 : the function wants ssl_GatherRecord1stHandshake to be called again
- * immediately, by ssl_Do1stHandshake.
*
* This code is similar to, and easily confused with, DoRecv() in sslsecur.c
*
@@ -82,16 +77,14 @@ ssl_GatherRecord1stHandshake(sslSocket *ss)
ssl_ReleaseRecvBufLock(ss);
if (rv <= 0) {
- if (rv == SECWouldBlock) {
- /* Progress is blocked waiting for callback completion. */
- SSL_TRC(10, ("%d: SSL[%d]: handshake blocked (need %d)",
- SSL_GETPID(), ss->fd, ss->gs.remainder));
- return SECWouldBlock;
- }
if (rv == 0) {
/* EOF. Loser */
PORT_SetError(PR_END_OF_FILE_ERROR);
}
+ if (PORT_GetError() == PR_WOULD_BLOCK_ERROR) {
+ SSL_TRC(10, ("%d: SSL[%d]: handshake blocked (need %d)",
+ SSL_GETPID(), ss->fd, ss->gs.remainder));
+ }
return SECFailure; /* rv is < 0 here. */
}
@@ -161,8 +154,8 @@ ssl_BeginClientHandshake(sslSocket *ss)
SSL_TRC(3, ("%d: SSL[%d]: using external token", SSL_GETPID(), ss->fd));
} else if (!ss->opt.noCache) {
/* Try to find server in our session-id cache */
- sid = ssl_LookupSID(&ss->sec.ci.peer, ss->sec.ci.port, ss->peerID,
- ss->url);
+ sid = ssl_LookupSID(ssl_Time(ss), &ss->sec.ci.peer,
+ ss->sec.ci.port, ss->peerID, ss->url);
}
if (sid) {
@@ -176,25 +169,15 @@ ssl_BeginClientHandshake(sslSocket *ss)
}
}
if (!sid) {
- sid = PORT_ZNew(sslSessionID);
+ sid = ssl3_NewSessionID(ss, PR_FALSE);
if (!sid) {
goto loser;
}
- sid->references = 1;
- sid->cached = never_cached;
- sid->addr = ss->sec.ci.peer;
- sid->port = ss->sec.ci.port;
- if (ss->peerID != NULL) {
- sid->peerID = PORT_Strdup(ss->peerID);
- }
- if (ss->url != NULL) {
- sid->urlSvrName = PORT_Strdup(ss->url);
- }
+ /* This session is a dummy, which we don't want to resume. */
+ sid->u.ssl3.keys.resumable = PR_FALSE;
}
ss->sec.ci.sid = sid;
- PORT_Assert(sid != NULL);
-
ss->gs.state = GS_INIT;
ss->handshake = ssl_GatherRecord1stHandshake;
diff --git a/security/nss/lib/ssl/ssldef.c b/security/nss/lib/ssl/ssldef.c
index be5bcb2694..3ed1979507 100644
--- a/security/nss/lib/ssl/ssldef.c
+++ b/security/nss/lib/ssl/ssldef.c
@@ -84,7 +84,7 @@ ssl_DefRecv(sslSocket *ss, unsigned char *buf, int len, int flags)
* For blocking sockets, always returns len or SECFailure, no short writes.
* For non-blocking sockets:
* Returns positive count if any data was written, else returns SECFailure.
- * Short writes may occur. Does not return SECWouldBlock.
+ * Short writes may occur.
*/
int
ssl_DefSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
diff --git a/security/nss/lib/ssl/sslencode.c b/security/nss/lib/ssl/sslencode.c
index e508804515..e59e758ff9 100644
--- a/security/nss/lib/ssl/sslencode.c
+++ b/security/nss/lib/ssl/sslencode.c
@@ -10,6 +10,7 @@
#include "prnetdb.h"
#include "ssl.h"
#include "sslimpl.h"
+#include "sslproto.h"
/* Helper function to encode an unsigned integer into a buffer. */
static void
@@ -263,9 +264,11 @@ ssl3_AppendHandshake(sslSocket *ss, const void *void_src, unsigned int bytes)
}
PRINT_BUF(60, (ss, "Append to Handshake", (unsigned char *)void_src, bytes));
- rv = ssl3_UpdateHandshakeHashes(ss, src, bytes);
- if (rv != SECSuccess)
- return SECFailure; /* error code set by ssl3_UpdateHandshakeHashes */
+ if (!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 */
+ }
while (bytes > room) {
if (room > 0)
diff --git a/security/nss/lib/ssl/sslerr.h b/security/nss/lib/ssl/sslerr.h
index a4aa276576..7100b0226e 100644
--- a/security/nss/lib/ssl/sslerr.h
+++ b/security/nss/lib/ssl/sslerr.h
@@ -268,6 +268,12 @@ typedef enum {
SSL_ERROR_RX_MALFORMED_ESNI_EXTENSION = (SSL_ERROR_BASE + 177),
SSL_ERROR_MISSING_ESNI_EXTENSION = (SSL_ERROR_BASE + 178),
SSL_ERROR_RX_UNEXPECTED_RECORD_TYPE = (SSL_ERROR_BASE + 179),
+ SSL_ERROR_MISSING_POST_HANDSHAKE_AUTH_EXTENSION = (SSL_ERROR_BASE + 180),
+ SSL_ERROR_RX_CERTIFICATE_REQUIRED_ALERT = (SSL_ERROR_BASE + 181),
+ SSL_ERROR_DC_CERT_VERIFY_ALG_MISMATCH = (SSL_ERROR_BASE + 182),
+ 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_END_OF_LIST /* let the c compiler determine the value of this. */
} SSLErrorCodes;
#endif /* NO_SECURITY_ERROR_ENUM */
diff --git a/security/nss/lib/ssl/sslexp.h b/security/nss/lib/ssl/sslexp.h
index f450e528dc..b734d86ca3 100644
--- a/security/nss/lib/ssl/sslexp.h
+++ b/security/nss/lib/ssl/sslexp.h
@@ -159,11 +159,16 @@ typedef SECStatus(PR_CALLBACK *SSLExtensionHandler)(
handler, handlerArg))
/*
- * Setup the anti-replay buffer for supporting 0-RTT in TLS 1.3 on servers.
+ * Create an anti-replay context for supporting 0-RTT in TLS 1.3 on servers.
*
- * To use 0-RTT on a server, you must call this function. Failing to call this
- * function will result in all 0-RTT being rejected. Connections will complete,
- * but early data will be rejected.
+ * To use 0-RTT on a server, you must create an anti-replay context using
+ * SSL_CreateAntiReplayContext and set that on the socket with
+ * SSL_SetAntiReplayContext. Failing to set a context on the server will result
+ * in all 0-RTT being rejected. Connections will complete, but early data will
+ * be rejected.
+ *
+ * Anti-replay contexts are reference counted and are released with
+ * SSL_ReleaseAntiReplayContext.
*
* NSS uses a Bloom filter to track the ClientHello messages that it receives
* (specifically, it uses the PSK binder). This function initializes a pair of
@@ -181,11 +186,11 @@ typedef SECStatus(PR_CALLBACK *SSLExtensionHandler)(
* The first tuning parameter to consider is |window|, which determines the
* window over which ClientHello messages will be tracked. This also causes
* early data to be rejected if a ClientHello contains a ticket age parameter
- * that is outside of this window (see Section 4.2.10.4 of
- * draft-ietf-tls-tls13-20 for details). Set |window| to account for any
- * potential sources of clock error. |window| is the entire width of the
- * window, which is symmetrical. Therefore to allow 5 seconds of clock error in
- * both directions, set the value to 10 seconds (i.e., 10 * PR_USEC_PER_SEC).
+ * that is outside of this window (see Section 8.3 of RFC 8446 for details).
+ * Set |window| to account for any potential sources of clock error. |window|
+ * is the entire width of the window, which is symmetrical. Therefore to allow
+ * 5 seconds of clock error in both directions, set the value to 10 seconds
+ * (i.e., 10 * PR_USEC_PER_SEC).
*
* After calling this function, early data will be rejected until |window|
* elapses. This prevents replay across crashes and restarts. Only call this
@@ -219,10 +224,23 @@ typedef SECStatus(PR_CALLBACK *SSLExtensionHandler)(
* Early data can be replayed at least once with every server instance that will
* accept tickets that are encrypted with the same key.
*/
-#define SSL_SetupAntiReplay(window, k, bits) \
- SSL_EXPERIMENTAL_API("SSL_SetupAntiReplay", \
- (PRTime _window, unsigned int _k, unsigned int _bits), \
- (window, k, bits))
+typedef struct SSLAntiReplayContextStr SSLAntiReplayContext;
+#define SSL_CreateAntiReplayContext(now, window, k, bits, ctx) \
+ SSL_EXPERIMENTAL_API("SSL_CreateAntiReplayContext", \
+ (PRTime _now, PRTime _window, \
+ unsigned int _k, unsigned int _bits, \
+ SSLAntiReplayContext **_ctx), \
+ (now, window, k, bits, ctx))
+
+#define SSL_SetAntiReplayContext(fd, ctx) \
+ SSL_EXPERIMENTAL_API("SSL_SetAntiReplayContext", \
+ (PRFileDesc * _fd, SSLAntiReplayContext * _ctx), \
+ (fd, ctx))
+
+#define SSL_ReleaseAntiReplayContext(ctx) \
+ SSL_EXPERIMENTAL_API("SSL_ReleaseAntiReplayContext", \
+ (SSLAntiReplayContext * _ctx), \
+ (ctx))
/*
* This function allows a server application to generate a session ticket that
@@ -307,6 +325,10 @@ typedef SECStatus(PR_CALLBACK *SSLExtensionHandler)(
* reject a second ClientHello (i.e., when firstHello is PR_FALSE); NSS will
* abort the handshake if this value is returned from a second call.
*
+ * - Returning ssl_hello_retry_reject_0rtt causes NSS to proceed normally, but
+ * to reject 0-RTT. Use this if there is something in the token that
+ * indicates that 0-RTT might be unsafe.
+ *
* An application that chooses to perform a stateless retry can discard the
* server socket. All necessary state to continue the TLS handshake will be
* included in the cookie extension. This makes it possible to use a new socket
@@ -326,7 +348,8 @@ typedef SECStatus(PR_CALLBACK *SSLExtensionHandler)(
typedef enum {
ssl_hello_retry_fail,
ssl_hello_retry_accept,
- ssl_hello_retry_request
+ ssl_hello_retry_request,
+ ssl_hello_retry_reject_0rtt
} SSLHelloRetryRequestAction;
typedef SSLHelloRetryRequestAction(PR_CALLBACK *SSLHelloRetryRequestCallback)(
@@ -350,6 +373,27 @@ typedef SSLHelloRetryRequestAction(PR_CALLBACK *SSLHelloRetryRequestCallback)(
(PRFileDesc * _fd, PRBool _requestUpdate), \
(fd, requestUpdate))
+/* This function allows a server application to trigger
+ * re-authentication (TLS 1.3 only) after handshake.
+ *
+ * This function will cause a CertificateRequest message to be sent by
+ * a server. This can be called once at a time, and is not allowed
+ * until an answer is received.
+ *
+ * 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
+ * certificates, you will need to call SSL_PeerCertificate() and save
+ * what you get before calling this.
+ *
+ * If the AuthCertificateCallback returns SECFailure, the connection
+ * is aborted.
+ */
+#define SSL_SendCertificateRequest(fd) \
+ SSL_EXPERIMENTAL_API("SSL_SendCertificateRequest", \
+ (PRFileDesc * _fd), \
+ (fd))
+
/*
* Session cache API.
*/
@@ -492,7 +536,7 @@ typedef SECStatus(PR_CALLBACK *SSLResumptionTokenCallback)(
* group -- the named group this key corresponds to
* pubKey -- the public key for the key pair
* pad -- the length to pad to
- * notBefore/notAfter -- validity range
+ * notBefore/notAfter -- validity range in seconds since epoch
* out/outlen/maxlen -- where to output the data
*/
#define SSL_EncodeESNIKeys(cipherSuites, cipherSuiteCount, \
@@ -511,8 +555,281 @@ typedef SECStatus(PR_CALLBACK *SSLResumptionTokenCallback)(
group, pubKey, pad, notBefore, notAfter, \
out, outlen, maxlen))
+/* SSL_SetSecretCallback installs a callback that TLS calls when it installs new
+ * traffic secrets.
+ *
+ * SSLSecretCallback is called with the current epoch and the corresponding
+ * secret; this matches the epoch used in DTLS 1.3, even if the socket is
+ * operating in stream mode:
+ *
+ * - client_early_traffic_secret corresponds to epoch 1
+ * - {client|server}_handshake_traffic_secret is epoch 2
+ * - {client|server}_application_traffic_secret_{N} is epoch 3+N
+ *
+ * The callback is invoked separately for read secrets (client secrets on the
+ * server; server secrets on the client), and write secrets.
+ *
+ * This callback is only called if (D)TLS 1.3 is negotiated.
+ */
+typedef void(PR_CALLBACK *SSLSecretCallback)(
+ PRFileDesc *fd, PRUint16 epoch, SSLSecretDirection dir, PK11SymKey *secret,
+ void *arg);
+
+#define SSL_SecretCallback(fd, cb, arg) \
+ SSL_EXPERIMENTAL_API("SSL_SecretCallback", \
+ (PRFileDesc * _fd, SSLSecretCallback _cb, void *_arg), \
+ (fd, cb, arg))
+
+/* SSL_RecordLayerWriteCallback() is used to replace the TLS record layer. This
+ * function installs a callback that TLS calls when it would otherwise encrypt
+ * and write a record to the underlying NSPR IO layer. The application is
+ * responsible for ensuring that these records are encrypted and written.
+ *
+ * Calling this API also disables reads from the underlying NSPR layer. The
+ * application is expected to push data when it is available using
+ * SSL_RecordLayerData().
+ *
+ * When data would be written, the provided SSLRecordWriteCallback with the
+ * epoch, TLS content type, and the data. The data provided to the callback is
+ * not split into record-sized writes. If the callback returns SECFailure, the
+ * write will be considered to have failed; in particular, PR_WOULD_BLOCK_ERROR
+ * is not handled specially.
+ *
+ * If TLS 1.3 is in use, the epoch indicates the expected level of protection
+ * that the record would receive, this matches that used in DTLS 1.3:
+ *
+ * - epoch 0 corresponds to no record protection
+ * - epoch 1 corresponds to 0-RTT
+ * - epoch 2 corresponds to TLS handshake
+ * - epoch 3 and higher are application data
+ *
+ * Prior versions of TLS use epoch 1 and higher for application data.
+ *
+ * This API is not supported for DTLS.
+ */
+typedef SECStatus(PR_CALLBACK *SSLRecordWriteCallback)(
+ PRFileDesc *fd, PRUint16 epoch, SSLContentType contentType,
+ const PRUint8 *data, unsigned int len, void *arg);
+
+#define SSL_RecordLayerWriteCallback(fd, writeCb, arg) \
+ SSL_EXPERIMENTAL_API("SSL_RecordLayerWriteCallback", \
+ (PRFileDesc * _fd, SSLRecordWriteCallback _wCb, \
+ void *_arg), \
+ (fd, writeCb, arg))
+
+/* SSL_RecordLayerData() is used to provide new data to TLS. The application
+ * indicates the epoch (see the description of SSL_RecordLayerWriteCallback()),
+ * content type, and the data that was received. The application is responsible
+ * for removing any encryption or other protection before passing data to this
+ * function.
+ *
+ * This returns SECSuccess if the data was successfully processed. If this
+ * function is used to drive the handshake and the caller needs to know when the
+ * handshake is complete, a call to SSL_ForceHandshake will return SECSuccess
+ * when the handshake is complete.
+ *
+ * This API is not supported for DTLS sockets.
+ */
+#define SSL_RecordLayerData(fd, epoch, ct, data, len) \
+ SSL_EXPERIMENTAL_API("SSL_RecordLayerData", \
+ (PRFileDesc * _fd, PRUint16 _epoch, \
+ SSLContentType _contentType, \
+ const PRUint8 *_data, unsigned int _len), \
+ (fd, epoch, ct, data, len))
+
+/*
+ * SSL_GetCurrentEpoch() returns the read and write epochs that the socket is
+ * currently using. NULL values for readEpoch or writeEpoch are ignored.
+ *
+ * See SSL_RecordLayerWriteCallback() for details on epochs.
+ */
+#define SSL_GetCurrentEpoch(fd, readEpoch, writeEpoch) \
+ SSL_EXPERIMENTAL_API("SSL_GetCurrentEpoch", \
+ (PRFileDesc * _fd, PRUint16 * _readEpoch, \
+ PRUint16 * _writeEpoch), \
+ (fd, readEpoch, writeEpoch))
+
+/*
+ * The following AEAD functions expose an AEAD primitive that uses a ciphersuite
+ * to set parameters. The ciphersuite determines the Hash function used by
+ * HKDF, the AEAD function, and the size of key and IV. 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, labelPrefix + " key" or " iv", "", L).
+ *
+ * The encrypt and decrypt functions use a nonce construction identical to that
+ * 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.
+ */
+typedef struct SSLAeadContextStr SSLAeadContext;
+
+#define SSL_MakeAead(version, cipherSuite, secret, \
+ labelPrefix, labelPrefixLen, ctx) \
+ SSL_EXPERIMENTAL_API("SSL_MakeAead", \
+ (PRUint16 _version, PRUint16 _cipherSuite, \
+ PK11SymKey * _secret, \
+ const char *_labelPrefix, \
+ unsigned int _labelPrefixLen, \
+ SSLAeadContext **_ctx), \
+ (version, cipherSuite, secret, \
+ labelPrefix, labelPrefixLen, ctx))
+
+#define SSL_AeadEncrypt(ctx, counter, aad, aadLen, in, inLen, \
+ output, outputLen, maxOutputLen) \
+ SSL_EXPERIMENTAL_API("SSL_AeadEncrypt", \
+ (const SSLAeadContext *_ctx, PRUint64 _counter, \
+ const PRUint8 *_aad, unsigned int _aadLen, \
+ const PRUint8 *_in, unsigned int _inLen, \
+ PRUint8 *_out, unsigned int *_outLen, \
+ unsigned int _maxOut), \
+ (ctx, counter, aad, aadLen, in, inLen, \
+ output, outputLen, maxOutputLen))
+
+#define SSL_AeadDecrypt(ctx, counter, aad, aadLen, in, inLen, \
+ output, outputLen, maxOutputLen) \
+ SSL_EXPERIMENTAL_API("SSL_AeadDecrypt", \
+ (const SSLAeadContext *_ctx, PRUint64 _counter, \
+ const PRUint8 *_aad, unsigned int _aadLen, \
+ const PRUint8 *_in, unsigned int _inLen, \
+ PRUint8 *_output, unsigned int *_outLen, \
+ unsigned int _maxOut), \
+ (ctx, counter, aad, aadLen, in, inLen, \
+ output, outputLen, maxOutputLen))
+
+#define SSL_DestroyAead(ctx) \
+ SSL_EXPERIMENTAL_API("SSL_DestroyAead", \
+ (SSLAeadContext * _ctx), \
+ (ctx))
+
+/* SSL_HkdfExtract and SSL_HkdfExpandLabel implement the functions from TLS,
+ * using the version and ciphersuite to set parameters. This allows callers to
+ * use these TLS functions as a KDF. This is only supported for TLS 1.3.
+ *
+ * SSL_HkdfExtract produces a key with a mechanism that is suitable for input to
+ * SSL_HkdfExpandLabel (and SSL_HkdfExpandLabelWithMech). */
+#define SSL_HkdfExtract(version, cipherSuite, salt, ikm, keyp) \
+ SSL_EXPERIMENTAL_API("SSL_HkdfExtract", \
+ (PRUint16 _version, PRUint16 _cipherSuite, \
+ PK11SymKey * _salt, PK11SymKey * _ikm, \
+ 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. */
+#define SSL_HkdfExpandLabel(version, cipherSuite, prk, \
+ hsHash, hsHashLen, label, labelLen, keyp) \
+ SSL_EXPERIMENTAL_API("SSL_HkdfExpandLabel", \
+ (PRUint16 _version, PRUint16 _cipherSuite, \
+ PK11SymKey * _prk, \
+ const PRUint8 *_hsHash, unsigned int _hsHashLen, \
+ const char *_label, unsigned int _labelLen, \
+ PK11SymKey **_keyp), \
+ (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_HkdfExpandLabelWithMech(version, cipherSuite, prk, \
+ hsHash, hsHashLen, label, labelLen, \
+ mech, keySize, keyp) \
+ SSL_EXPERIMENTAL_API("SSL_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), \
+ (version, cipherSuite, prk, \
+ hsHash, hsHashLen, label, labelLen, \
+ mech, keySize, 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
+ * function to NULL to use PR_Now().*/
+typedef PRTime(PR_CALLBACK *SSLTimeFunc)(void *arg);
+
+#define SSL_SetTimeFunc(fd, f, arg) \
+ SSL_EXPERIMENTAL_API("SSL_SetTimeFunc", \
+ (PRFileDesc * _fd, SSLTimeFunc _f, void *_arg), \
+ (fd, f, arg))
+
+/* Create a delegated credential (DC) for the draft-ietf-tls-subcerts extension
+ * using the given certificate |cert| and its signing key |certPriv| and write
+ * the serialized DC to |out|. The
+ * parameters are:
+ * - the DC public key |dcPub|;
+ * - the DC signature scheme |dcCertVerifyAlg|, used to verify the handshake.
+ * - the DC time-to-live |dcValidFor|, the number of seconds from now for which
+ * the DC should be valid; and
+ * - the current time |now|.
+ *
+ * The signing algorithm used to verify the DC signature is deduced from
+ * |cert|.
+ *
+ * It's the caller's responsibility to ensure the input parameters are all
+ * valid. This procedure is meant primarily for testing; for this purpose it is
+ * useful to do no validation.
+ */
+#define SSL_DelegateCredential(cert, certPriv, dcPub, dcCertVerifyAlg, \
+ dcValidFor, now, out) \
+ SSL_EXPERIMENTAL_API("SSL_DelegateCredential", \
+ (const CERTCertificate *_cert, \
+ const SECKEYPrivateKey *_certPriv, \
+ const SECKEYPublicKey *_dcPub, \
+ SSLSignatureScheme _dcCertVerifyAlg, \
+ PRUint32 _dcValidFor, \
+ PRTime _now, \
+ SECItem *_out), \
+ (cert, certPriv, dcPub, dcCertVerifyAlg, dcValidFor, \
+ now, out))
+
+/* New functions created to permit get/set the CipherSuites Order for the
+ * handshake (Client Hello).
+ *
+ * The *Get function puts the current set of active (enabled and policy set as
+ * PR_TRUE) cipher suites in the cipherOrder outparam. Cipher suites that
+ * aren't active aren't included. The paramenters are:
+ * - PRFileDesc *fd = FileDescriptor to get information.
+ * - PRUint16 *cipherOrder = The memory allocated for cipherOrder needs to be
+ * SSL_GetNumImplementedCiphers() * sizeof(PRUint16) or more.
+ * - PRUint16 numCiphers = The number of active ciphersuites listed in
+ * *cipherOrder is written here.
+ *
+ * The *Set function permits reorder the CipherSuites list for the Handshake
+ * (Client Hello). The default ordering defined in ssl3con.c is enough in
+ * almost all cases. But, if the client needs some hardening or performance
+ * adjusts related to CipherSuites, this can be done with this function.
+ * The caller has to be aware about the risk of call this function while a
+ * handshake are being processed in this fd/socket. For example, if you disable
+ * a cipher after the handshake and this cipher was choosen for that
+ * connection, something bad will happen.
+ * The parameters are:
+ * - PRFileDesc *fd = FileDescriptor to change.
+ * - const PRUint16 *cipherOrder = Must receive all ciphers to be ordered, in
+ * the desired order. They will be set in the begin of the list. Only
+ * suites listed by SSL_ImplementedCiphers() can be included.
+ * - PRUint16 numCiphers = Must receive the number of items in *cipherOrder.
+ * */
+#define SSL_CipherSuiteOrderGet(fd, cipherOrder, numCiphers) \
+ SSL_EXPERIMENTAL_API("SSL_CipherSuiteOrderGet", \
+ (PRFileDesc * _fd, PRUint16 * _cipherOrder, \
+ unsigned int *_numCiphers), \
+ (fd, cipherOrder, numCiphers))
+
+#define SSL_CipherSuiteOrderSet(fd, cipherOrder, numCiphers) \
+ SSL_EXPERIMENTAL_API("SSL_CipherSuiteOrderSet", \
+ (PRFileDesc * _fd, const PRUint16 *_cipherOrder, \
+ PRUint16 _numCiphers), \
+ (fd, cipherOrder, numCiphers))
+
/* 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
SEC_END_PROTOS
diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h
index 35240d2fba..4a393b281c 100644
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -37,6 +37,7 @@
typedef struct sslSocketStr sslSocket;
typedef struct sslNamedGroupDefStr sslNamedGroupDef;
typedef struct sslEsniKeysStr sslEsniKeys;
+typedef struct sslDelegatedCredentialStr sslDelegatedCredential;
typedef struct sslEphemeralKeyPairStr sslEphemeralKeyPair;
typedef struct TLS13KeyShareEntryStr TLS13KeyShareEntry;
@@ -144,6 +145,11 @@ typedef enum {
ticket_allow_psk_sign_auth = 16
} TLS13SessionTicketFlags;
+typedef enum {
+ update_not_requested = 0,
+ update_requested = 1
+} tls13KeyUpdateRequest;
+
struct sslNamedGroupDefStr {
/* The name is the value that is encoded on the wire in TLS. */
SSLNamedGroup name;
@@ -178,10 +184,11 @@ typedef SECStatus (*sslHandshakeFunc)(sslSocket *ss);
void ssl_CacheSessionID(sslSocket *ss);
void ssl_UncacheSessionID(sslSocket *ss);
-void ssl_ServerCacheSessionID(sslSessionID *sid);
+void ssl_ServerCacheSessionID(sslSessionID *sid, PRTime creationTime);
void ssl_ServerUncacheSessionID(sslSessionID *sid);
-typedef sslSessionID *(*sslSessionIDLookupFunc)(const PRIPv6Addr *addr,
+typedef sslSessionID *(*sslSessionIDLookupFunc)(PRTime ssl_now,
+ const PRIPv6Addr *addr,
unsigned char *sid,
unsigned int sidLen,
CERTCertDBHandle *dbHandle);
@@ -272,6 +279,8 @@ typedef struct sslOptionsStr {
unsigned int enableDtlsShortHeader : 1;
unsigned int enableHelloDowngradeCheck : 1;
unsigned int enableV2CompatibleHello : 1;
+ unsigned int enablePostHandshakeAuth : 1;
+ unsigned int enableDelegatedCredentials : 1;
} sslOptions;
typedef enum { sslHandshakingUndetermined = 0,
@@ -570,8 +579,9 @@ struct TLS13KeyShareEntryStr {
};
typedef struct TLS13EarlyDataStr {
- PRCList link; /* The linked list link */
- SECItem data; /* The data */
+ PRCList link; /* The linked list link */
+ unsigned int consumed; /* How much has been read. */
+ SECItem data; /* The data */
} TLS13EarlyData;
typedef enum {
@@ -609,6 +619,7 @@ typedef struct SSL3HandshakeStateStr {
* TLS 1.2 and later use only |sha|, for SHA-256. */
PK11Context *md5;
PK11Context *sha;
+ PK11Context *shaPostHandshake;
SSLSignatureScheme signatureScheme;
const ssl3KEADef *kea_def;
ssl3CipherSuite cipher_suite;
@@ -622,8 +633,6 @@ typedef struct SSL3HandshakeStateStr {
unsigned long msg_len;
PRBool isResuming; /* we are resuming (not used in TLS 1.3) */
PRBool sendingSCSV; /* instead of empty RI */
- sslBuffer msgState; /* current state for handshake messages*/
- /* protected by recvBufLock */
/* The session ticket received in a NewSessionTicket message is temporarily
* stored in newSessionTicket until the handshake is finished; then it is
@@ -744,10 +753,15 @@ struct ssl3StateStr {
* update is initiated locally. */
PRBool peerRequestedKeyUpdate;
- /* Internal callback for when we do a cipher suite change. Used for
- * debugging in TLS 1.3. This can only be set by non-public functions. */
- sslCipherSpecChangedFunc changedCipherSpecFunc;
- void *changedCipherSpecArg;
+ /* This is true if we deferred sending a key update as
+ * post-handshake auth is in progress. */
+ PRBool keyUpdateDeferred;
+ tls13KeyUpdateRequest deferredKeyUpdateRequest;
+
+ /* This is true after the server requests client certificate;
+ * false after the client certificate is received. Used by the
+ * server. */
+ PRBool clientCertRequested;
CERTCertificate *clientCertificate; /* used by client */
SECKEYPrivateKey *clientPrivateKey; /* used by client */
@@ -935,6 +949,10 @@ struct sslSocketStr {
/* Enabled version range */
SSLVersionRange vrange;
+ /* A function that returns the current time. */
+ SSLTimeFunc now;
+ void *nowArg;
+
/* State flags */
unsigned long clientAuthRequested;
unsigned long delayDisabled; /* Nagle delay disabled */
@@ -994,6 +1012,10 @@ struct sslSocketStr {
PRCList extensionHooks;
SSLResumptionTokenCallback resumptionTokenCallback;
void *resumptionTokenContext;
+ SSLSecretCallback secretCallback;
+ void *secretCallbackArg;
+ SSLRecordWriteCallback recordWriteCallback;
+ void *recordWriteCallbackArg;
PRIntervalTime rTimeout; /* timeout for NSPR I/O */
PRIntervalTime wTimeout; /* timeout for NSPR I/O */
@@ -1074,6 +1096,9 @@ struct sslSocketStr {
/* The information from the ESNI keys record
* (also the private key for the server). */
sslEsniKeys *esniKeys;
+
+ /* Anti-replay for TLS 1.3 0-RTT. */
+ SSLAntiReplayContext *antiReplay;
};
struct sslSelfEncryptKeysStr {
@@ -1089,8 +1114,7 @@ extern char ssl_trace;
extern FILE *ssl_trace_iob;
extern FILE *ssl_keylog_iob;
extern PZLock *ssl_keylog_lock;
-extern PRUint32 ssl3_sid_timeout;
-extern PRUint32 ssl_ticket_lifetime;
+static const PRUint32 ssl_ticket_lifetime = 2 * 24 * 60 * 60; // 2 days.
extern const char *const ssl3_cipherName[];
@@ -1174,14 +1198,15 @@ extern SECStatus ssl_SaveWriteData(sslSocket *ss,
const void *p, unsigned int l);
extern SECStatus ssl_BeginClientHandshake(sslSocket *ss);
extern SECStatus ssl_BeginServerHandshake(sslSocket *ss);
-extern int ssl_Do1stHandshake(sslSocket *ss);
+extern SECStatus ssl_Do1stHandshake(sslSocket *ss);
extern SECStatus ssl3_InitPendingCipherSpecs(sslSocket *ss, PK11SymKey *secret,
PRBool derive);
extern void ssl_DestroyKeyMaterial(ssl3KeyMaterial *keyMaterial);
extern sslSessionID *ssl3_NewSessionID(sslSocket *ss, PRBool is_server);
-extern sslSessionID *ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port,
- const char *peerID, const char *urlSvrName);
+extern sslSessionID *ssl_LookupSID(PRTime now, const PRIPv6Addr *addr,
+ PRUint16 port, const char *peerID,
+ const char *urlSvrName);
extern void ssl_FreeSID(sslSessionID *sid);
extern void ssl_DestroySID(sslSessionID *sid, PRBool freeIt);
extern sslSessionID *ssl_ReferenceSID(sslSessionID *sid);
@@ -1206,19 +1231,28 @@ extern SECStatus ssl_CipherPrefSetDefault(PRInt32 which, PRBool enabled);
extern SECStatus ssl3_ConstrainRangeByPolicy(void);
extern SECStatus ssl3_InitState(sslSocket *ss);
-extern SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen,
- int maxOutputLen, const unsigned char *input,
- int inputLen);
+extern SECStatus Null_Cipher(void *ctx, unsigned char *output, unsigned int *outputLen,
+ unsigned int maxOutputLen, const unsigned char *input,
+ unsigned int inputLen);
extern void ssl3_RestartHandshakeHashes(sslSocket *ss);
+typedef SECStatus (*sslUpdateHandshakeHashes)(sslSocket *ss,
+ const unsigned char *b,
+ unsigned int l);
extern SECStatus ssl3_UpdateHandshakeHashes(sslSocket *ss,
const unsigned char *b,
unsigned int l);
+extern SECStatus ssl3_UpdatePostHandshakeHashes(sslSocket *ss,
+ const unsigned char *b,
+ unsigned int l);
SECStatus
ssl_HashHandshakeMessageInt(sslSocket *ss, SSLHandshakeType type,
PRUint32 dtlsSeq,
- const PRUint8 *b, PRUint32 length);
+ const PRUint8 *b, PRUint32 length,
+ sslUpdateHandshakeHashes cb);
SECStatus ssl_HashHandshakeMessage(sslSocket *ss, SSLHandshakeType type,
const PRUint8 *b, PRUint32 length);
+SECStatus ssl_HashPostHandshakeMessage(sslSocket *ss, SSLHandshakeType type,
+ const PRUint8 *b, PRUint32 length);
/* Returns PR_TRUE if we are still waiting for the server to complete its
* response to our client second round. Once we've received the Finished from
@@ -1433,6 +1467,11 @@ extern void ssl_FreeEphemeralKeyPairs(sslSocket *ss);
extern SECStatus ssl_AppendPaddedDHKeyShare(sslBuffer *buf,
const SECKEYPublicKey *pubKey,
PRBool appendLength);
+extern PRBool ssl_CanUseSignatureScheme(SSLSignatureScheme scheme,
+ const SSLSignatureScheme *peerSchemes,
+ unsigned int peerSchemeCount,
+ PRBool requireSha1,
+ PRBool slotDoesPss);
extern const ssl3DHParams *ssl_GetDHEParams(const sslNamedGroupDef *groupDef);
extern SECStatus ssl_SelectDHEGroup(sslSocket *ss,
const sslNamedGroupDef **groupDef);
@@ -1529,9 +1568,14 @@ extern SECStatus ssl3_ConsumeHandshakeNumber64(sslSocket *ss, PRUint64 *num,
extern SECStatus ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i,
PRUint32 bytes, PRUint8 **b,
PRUint32 *length);
+extern SECStatus ssl_SignatureSchemeFromSpki(const CERTSubjectPublicKeyInfo *spki,
+ PRBool isTls13,
+ SSLSignatureScheme *scheme);
+extern PRBool ssl_SignatureSchemeEnabled(const sslSocket *ss,
+ SSLSignatureScheme scheme);
extern PRBool ssl_IsSupportedSignatureScheme(SSLSignatureScheme scheme);
extern SECStatus ssl_CheckSignatureSchemeConsistency(
- sslSocket *ss, SSLSignatureScheme scheme, CERTCertificate *cert);
+ sslSocket *ss, SSLSignatureScheme scheme, CERTSubjectPublicKeyInfo *spki);
extern SECStatus ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *arena,
SSLSignatureScheme **schemesOut,
unsigned int *numSchemesOut,
@@ -1539,8 +1583,18 @@ extern SECStatus ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *are
unsigned int *len);
extern SECStatus ssl_ConsumeSignatureScheme(
sslSocket *ss, PRUint8 **b, PRUint32 *length, SSLSignatureScheme *out);
+extern SECStatus ssl3_SignHashesWithPrivKey(SSL3Hashes *hash,
+ SECKEYPrivateKey *key,
+ SSLSignatureScheme scheme,
+ PRBool isTls,
+ SECItem *buf);
extern SECStatus ssl3_SignHashes(sslSocket *ss, SSL3Hashes *hash,
SECKEYPrivateKey *key, SECItem *buf);
+extern SECStatus ssl_VerifySignedHashesWithPubKey(sslSocket *ss,
+ SECKEYPublicKey *spki,
+ SSLSignatureScheme scheme,
+ SSL3Hashes *hash,
+ SECItem *buf);
extern SECStatus ssl3_VerifySignedHashes(sslSocket *ss, SSLSignatureScheme scheme,
SSL3Hashes *hash, SECItem *buf);
extern SECStatus ssl3_CacheWrappedSecret(sslSocket *ss, sslSessionID *sid,
@@ -1582,8 +1636,8 @@ PRBool ssl3_config_match(const ssl3CipherSuiteCfg *suite, PRUint8 policy,
/* calls for accessing wrapping keys across processes. */
extern SECStatus
-ssl_GetWrappingKey(unsigned int symWrapMechIndex, unsigned int wrapKeyIndex,
- SSLWrappedSymWrappingKey *wswk);
+ssl_GetWrappingKey(unsigned int symWrapMechIndex,
+ unsigned int wrapKeyIndex, SSLWrappedSymWrappingKey *wswk);
/* The caller passes in the new value it wants
* to set. This code tests the wrapped sym key entry in the file on disk.
@@ -1623,10 +1677,13 @@ SECStatus ssl3_HandleNoCertificate(sslSocket *ss);
SECStatus ssl3_SendEmptyCertificate(sslSocket *ss);
void ssl3_CleanupPeerCerts(sslSocket *ss);
SECStatus ssl3_SendCertificateStatus(sslSocket *ss);
+SECStatus ssl_SetAuthKeyBits(sslSocket *ss, const SECKEYPublicKey *pubKey);
+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, sslBuffer *buf);
+SECStatus ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion,
+ sslBuffer *buf);
SECStatus ssl_GetCertificateRequestCAs(const sslSocket *ss,
unsigned int *calenp,
const SECItem **namesp,
@@ -1660,8 +1717,12 @@ SECStatus ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid,
const ssl3CipherSuiteDef *ssl_LookupCipherSuiteDef(ssl3CipherSuite suite);
const ssl3CipherSuiteCfg *ssl_LookupCipherSuiteCfg(ssl3CipherSuite suite,
const ssl3CipherSuiteCfg *suites);
+PRBool ssl3_CipherSuiteAllowedForVersionRange(ssl3CipherSuite cipherSuite,
+ const SSLVersionRange *vrange);
SECStatus ssl3_SelectServerCert(sslSocket *ss);
+SECStatus ssl_PrivateKeySupportsRsaPss(SECKEYPrivateKey *privKey,
+ PRBool *supportsRsaPss);
SECStatus ssl_PickSignatureScheme(sslSocket *ss,
CERTCertificate *cert,
SECKEYPublicKey *pubKey,
@@ -1677,6 +1738,8 @@ SECStatus ssl3_SetupCipherSuite(sslSocket *ss, PRBool initHashes);
SECStatus ssl_InsertRecordHeader(const sslSocket *ss, ssl3CipherSpec *cwSpec,
SSLContentType contentType, sslBuffer *wrBuf,
PRBool *needsLength);
+PRBool ssl_SignatureSchemeValid(SSLSignatureScheme scheme, SECOidTag spkiOid,
+ PRBool isTls13);
/* Pull in DTLS functions */
#include "dtlscon.h"
@@ -1693,13 +1756,8 @@ extern void ssl3_CheckCipherSuiteOrderConsistency();
extern int ssl_MapLowLevelError(int hiLevelError);
-extern PRUint32 ssl_TimeSec(void);
-#ifdef UNSAFE_FUZZER_MODE
-#define ssl_TimeUsec() ((PRTime)12345678)
-#else
-#define ssl_TimeUsec() (PR_Now())
-#endif
-extern PRBool ssl_TicketTimeValid(const NewSessionTicket *ticket);
+PRTime ssl_Time(const sslSocket *ss);
+PRBool ssl_TicketTimeValid(const sslSocket *ss, const NewSessionTicket *ticket);
extern void SSL_AtomicIncrementLong(long *x);
@@ -1729,7 +1787,15 @@ SECStatus ssl_DecodeResumptionToken(sslSessionID *sid, const PRUint8 *encodedTic
PRUint32 encodedTicketLen);
PRBool ssl_IsResumptionTokenUsable(sslSocket *ss, sslSessionID *sid);
-/* Remove when stable. */
+/* unwrap helper function to handle the case where the wrapKey doesn't wind
+ * * up in the correct token for the master secret */
+PK11SymKey *ssl_unwrapSymKey(PK11SymKey *wrapKey,
+ CK_MECHANISM_TYPE wrapType, SECItem *param,
+ SECItem *wrappedKey,
+ CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
+ int keySize, CK_FLAGS keyFlags, void *pinArg);
+
+/* Experimental APIs. Remove when stable. */
SECStatus SSLExp_SetResumptionTokenCallback(PRFileDesc *fd,
SSLResumptionTokenCallback cb,
@@ -1742,8 +1808,47 @@ SECStatus SSLExp_GetResumptionTokenInfo(const PRUint8 *tokenData, unsigned int t
SECStatus SSLExp_DestroyResumptionTokenInfo(SSLResumptionTokenInfo *token);
+SECStatus SSLExp_SecretCallback(PRFileDesc *fd, SSLSecretCallback cb,
+ void *arg);
+SECStatus SSLExp_RecordLayerWriteCallback(PRFileDesc *fd,
+ SSLRecordWriteCallback write,
+ void *arg);
+SECStatus SSLExp_RecordLayerData(PRFileDesc *fd, PRUint16 epoch,
+ SSLContentType contentType,
+ const PRUint8 *data, unsigned int len);
+SECStatus SSLExp_GetCurrentEpoch(PRFileDesc *fd, PRUint16 *readEpoch,
+ PRUint16 *writeEpoch);
+
#define SSLResumptionTokenVersion 2
+SECStatus SSLExp_MakeAead(PRUint16 version, PRUint16 cipherSuite, 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,
+ const PRUint8 *plaintext, unsigned int plaintextLen,
+ PRUint8 *out, unsigned int *outLen, unsigned int maxOut);
+SECStatus SSLExp_AeadDecrypt(const SSLAeadContext *ctx, PRUint64 counter,
+ const PRUint8 *aad, unsigned int aadLen,
+ const PRUint8 *plaintext, unsigned int plaintextLen,
+ PRUint8 *out, unsigned int *outLen, unsigned int maxOut);
+
+SECStatus SSLExp_HkdfExtract(PRUint16 version, PRUint16 cipherSuite,
+ PK11SymKey *salt, PK11SymKey *ikm, PK11SymKey **keyp);
+SECStatus SSLExp_HkdfExpandLabel(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk,
+ const PRUint8 *hsHash, unsigned int hsHashLen,
+ const char *label, unsigned int labelLen,
+ 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_SetTimeFunc(PRFileDesc *fd, SSLTimeFunc f, void *arg);
+
SEC_END_PROTOS
#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
diff --git a/security/nss/lib/ssl/sslinfo.c b/security/nss/lib/ssl/sslinfo.c
index 4e58c5ae7c..b069888e27 100644
--- a/security/nss/lib/ssl/sslinfo.c
+++ b/security/nss/lib/ssl/sslinfo.c
@@ -7,6 +7,7 @@
#include "sslimpl.h"
#include "sslproto.h"
#include "tls13hkdf.h"
+#include "tls13subcerts.h"
SECStatus
SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len)
@@ -79,6 +80,7 @@ SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len)
inf.signatureScheme = sid->sigScheme;
}
inf.resumed = ss->statelessResume || ss->ssl3.hs.isResuming;
+ inf.peerDelegCred = tls13_IsVerifyingWithDelegatedCredential(ss);
if (sid) {
unsigned int sidLen;
@@ -150,6 +152,11 @@ SSL_GetPreliminaryChannelInfo(PRFileDesc *fd,
} else {
inf.maxEarlyDataSize = 0;
}
+ inf.zeroRttCipherSuite = ss->ssl3.hs.zeroRttSuite;
+
+ inf.peerDelegCred = tls13_IsVerifyingWithDelegatedCredential(ss);
+ inf.authKeyBits = ss->sec.authKeyBits;
+ inf.signatureScheme = ss->sec.signatureScheme;
memcpy(info, &inf, inf.length);
return SECSuccess;
@@ -234,89 +241,89 @@ SSL_GetPreliminaryChannelInfo(PRFileDesc *fd,
static const SSLCipherSuiteInfo suiteInfo[] = {
/* <------ Cipher suite --------------------> <auth> <KEA> <bulk cipher> <MAC> <FIPS> */
- { 0, CS_(TLS_AES_128_GCM_SHA256), S_ANY, K_ANY, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_ANY },
- { 0, CS_(TLS_CHACHA20_POLY1305_SHA256), S_ANY, K_ANY, C_CHACHA20, B_256, M_AEAD_128, F_NFIPS_STD, A_ANY },
- { 0, CS_(TLS_AES_256_GCM_SHA384), S_ANY, K_ANY, C_AESGCM, B_256, M_AEAD_128, F_NFIPS_STD, A_ANY },
-
- { 0, CS(RSA_WITH_AES_128_GCM_SHA256), S_RSA, K_RSA, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_RSAD },
- { 0, CS(DHE_RSA_WITH_CHACHA20_POLY1305_SHA256), S_RSA, K_DHE, C_CHACHA20, B_256, M_AEAD_128, F_NFIPS_STD, A_RSAS },
-
- { 0, CS(DHE_RSA_WITH_CAMELLIA_256_CBC_SHA), S_RSA, K_DHE, C_CAMELLIA, B_256, M_SHA, F_NFIPS_STD, A_RSAS },
- { 0, CS(DHE_DSS_WITH_CAMELLIA_256_CBC_SHA), S_DSA, K_DHE, C_CAMELLIA, B_256, M_SHA, F_NFIPS_STD, A_DSA },
- { 0, CS(DHE_RSA_WITH_AES_256_CBC_SHA256), S_RSA, K_DHE, C_AES, B_256, M_SHA256, F_FIPS_STD, A_RSAS },
- { 0, CS(DHE_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_DHE, C_AES, B_256, M_SHA, F_FIPS_STD, A_RSAS },
- { 0, CS(DHE_DSS_WITH_AES_256_CBC_SHA), S_DSA, K_DHE, C_AES, B_256, M_SHA, F_FIPS_STD, A_DSA },
- { 0, CS(DHE_DSS_WITH_AES_256_CBC_SHA256), S_DSA, K_DHE, C_AES, B_256, M_SHA256, F_FIPS_STD, A_DSA },
- { 0, CS(RSA_WITH_CAMELLIA_256_CBC_SHA), S_RSA, K_RSA, C_CAMELLIA, B_256, M_SHA, F_NFIPS_STD, A_RSAD },
- { 0, CS(RSA_WITH_AES_256_CBC_SHA256), S_RSA, K_RSA, C_AES, B_256, M_SHA256, F_FIPS_STD, A_RSAD },
- { 0, CS(RSA_WITH_AES_256_CBC_SHA), S_RSA, K_RSA, C_AES, B_256, M_SHA, F_FIPS_STD, A_RSAD },
-
- { 0, CS(DHE_RSA_WITH_CAMELLIA_128_CBC_SHA), S_RSA, K_DHE, C_CAMELLIA, B_128, M_SHA, F_NFIPS_STD, A_RSAS },
- { 0, CS(DHE_DSS_WITH_CAMELLIA_128_CBC_SHA), S_DSA, K_DHE, C_CAMELLIA, B_128, M_SHA, F_NFIPS_STD, A_DSA },
- { 0, CS(DHE_DSS_WITH_RC4_128_SHA), S_DSA, K_DHE, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_DSA },
- { 0, CS(DHE_RSA_WITH_AES_128_CBC_SHA256), S_RSA, K_DHE, C_AES, B_128, M_SHA256, F_FIPS_STD, A_RSAS },
- { 0, CS(DHE_RSA_WITH_AES_128_GCM_SHA256), S_RSA, K_DHE, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_RSAS },
- { 0, CS(DHE_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_DHE, C_AES, B_128, M_SHA, F_FIPS_STD, A_RSAS },
- { 0, CS(DHE_DSS_WITH_AES_128_GCM_SHA256), S_DSA, K_DHE, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_DSA },
- { 0, CS(DHE_DSS_WITH_AES_128_CBC_SHA), S_DSA, K_DHE, C_AES, B_128, M_SHA, F_FIPS_STD, A_DSA },
- { 0, CS(DHE_DSS_WITH_AES_128_CBC_SHA256), S_DSA, K_DHE, C_AES, B_128, M_SHA256, F_FIPS_STD, A_DSA },
- { 0, CS(RSA_WITH_SEED_CBC_SHA), S_RSA, K_RSA, C_SEED, B_128, M_SHA, F_FIPS_STD, A_RSAD },
- { 0, CS(RSA_WITH_CAMELLIA_128_CBC_SHA), S_RSA, K_RSA, C_CAMELLIA, B_128, M_SHA, F_NFIPS_STD, A_RSAD },
- { 0, CS(RSA_WITH_RC4_128_SHA), S_RSA, K_RSA, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_RSAD },
- { 0, CS(RSA_WITH_RC4_128_MD5), S_RSA, K_RSA, C_RC4, B_128, M_MD5, F_NFIPS_STD, A_RSAD },
- { 0, CS(RSA_WITH_AES_128_CBC_SHA256), S_RSA, K_RSA, C_AES, B_128, M_SHA256, F_FIPS_STD, A_RSAD },
- { 0, CS(RSA_WITH_AES_128_CBC_SHA), S_RSA, K_RSA, C_AES, B_128, M_SHA, F_FIPS_STD, A_RSAD },
-
- { 0, CS(DHE_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_DHE, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_RSAS },
- { 0, CS(DHE_DSS_WITH_3DES_EDE_CBC_SHA), S_DSA, K_DHE, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_DSA },
- { 0, CS(RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_RSA, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_RSAD },
-
- { 0, CS(DHE_RSA_WITH_DES_CBC_SHA), S_RSA, K_DHE, C_DES, B_DES, M_SHA, F_NFIPS_STD, A_RSAS },
- { 0, CS(DHE_DSS_WITH_DES_CBC_SHA), S_DSA, K_DHE, C_DES, B_DES, M_SHA, F_NFIPS_STD, A_DSA },
- { 0, CS(RSA_WITH_DES_CBC_SHA), S_RSA, K_RSA, C_DES, B_DES, M_SHA, F_NFIPS_STD, A_RSAD },
-
- { 0, CS(RSA_WITH_NULL_SHA256), S_RSA, K_RSA, C_NULL, B_0, M_SHA256, F_EXPORT, A_RSAD },
- { 0, CS(RSA_WITH_NULL_SHA), S_RSA, K_RSA, C_NULL, B_0, M_SHA, F_EXPORT, A_RSAD },
- { 0, CS(RSA_WITH_NULL_MD5), S_RSA, K_RSA, C_NULL, B_0, M_MD5, F_EXPORT, A_RSAD },
+ { 0, CS_(TLS_AES_128_GCM_SHA256), S_ANY, K_ANY, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_ANY, ssl_hash_sha256 },
+ { 0, CS_(TLS_CHACHA20_POLY1305_SHA256), S_ANY, K_ANY, C_CHACHA20, B_256, M_AEAD_128, F_NFIPS_STD, A_ANY, ssl_hash_sha256 },
+ { 0, CS_(TLS_AES_256_GCM_SHA384), S_ANY, K_ANY, C_AESGCM, B_256, M_AEAD_128, F_FIPS_STD, A_ANY, ssl_hash_sha384 },
+
+ { 0, CS(RSA_WITH_AES_128_GCM_SHA256), S_RSA, K_RSA, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_RSAD, ssl_hash_sha256 },
+ { 0, CS(DHE_RSA_WITH_CHACHA20_POLY1305_SHA256), S_RSA, K_DHE, C_CHACHA20, B_256, M_AEAD_128, F_NFIPS_STD, A_RSAS, ssl_hash_sha256 },
+
+ { 0, CS(DHE_RSA_WITH_CAMELLIA_256_CBC_SHA), S_RSA, K_DHE, C_CAMELLIA, B_256, M_SHA, F_NFIPS_STD, A_RSAS, ssl_hash_none },
+ { 0, CS(DHE_DSS_WITH_CAMELLIA_256_CBC_SHA), S_DSA, K_DHE, C_CAMELLIA, B_256, M_SHA, F_NFIPS_STD, A_DSA, ssl_hash_none },
+ { 0, CS(DHE_RSA_WITH_AES_256_CBC_SHA256), S_RSA, K_DHE, C_AES, B_256, M_SHA256, F_FIPS_STD, A_RSAS, ssl_hash_sha256 },
+ { 0, CS(DHE_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_DHE, C_AES, B_256, M_SHA, F_FIPS_STD, A_RSAS, ssl_hash_none },
+ { 0, CS(DHE_DSS_WITH_AES_256_CBC_SHA), S_DSA, K_DHE, C_AES, B_256, M_SHA, F_FIPS_STD, A_DSA, ssl_hash_none },
+ { 0, CS(DHE_DSS_WITH_AES_256_CBC_SHA256), S_DSA, K_DHE, C_AES, B_256, M_SHA256, F_FIPS_STD, A_DSA, ssl_hash_sha256 },
+ { 0, CS(RSA_WITH_CAMELLIA_256_CBC_SHA), S_RSA, K_RSA, C_CAMELLIA, B_256, M_SHA, F_NFIPS_STD, A_RSAD, ssl_hash_none },
+ { 0, CS(RSA_WITH_AES_256_CBC_SHA256), S_RSA, K_RSA, C_AES, B_256, M_SHA256, F_FIPS_STD, A_RSAD, ssl_hash_sha256 },
+ { 0, CS(RSA_WITH_AES_256_CBC_SHA), S_RSA, K_RSA, C_AES, B_256, M_SHA, F_FIPS_STD, A_RSAD, ssl_hash_none },
+
+ { 0, CS(DHE_RSA_WITH_CAMELLIA_128_CBC_SHA), S_RSA, K_DHE, C_CAMELLIA, B_128, M_SHA, F_NFIPS_STD, A_RSAS, ssl_hash_none },
+ { 0, CS(DHE_DSS_WITH_CAMELLIA_128_CBC_SHA), S_DSA, K_DHE, C_CAMELLIA, B_128, M_SHA, F_NFIPS_STD, A_DSA, ssl_hash_none },
+ { 0, CS(DHE_DSS_WITH_RC4_128_SHA), S_DSA, K_DHE, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_DSA, ssl_hash_none },
+ { 0, CS(DHE_RSA_WITH_AES_128_CBC_SHA256), S_RSA, K_DHE, C_AES, B_128, M_SHA256, F_FIPS_STD, A_RSAS, ssl_hash_sha256 },
+ { 0, CS(DHE_RSA_WITH_AES_128_GCM_SHA256), S_RSA, K_DHE, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_RSAS, ssl_hash_sha256 },
+ { 0, CS(DHE_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_DHE, C_AES, B_128, M_SHA, F_FIPS_STD, A_RSAS, ssl_hash_none },
+ { 0, CS(DHE_DSS_WITH_AES_128_GCM_SHA256), S_DSA, K_DHE, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_DSA, ssl_hash_sha256 },
+ { 0, CS(DHE_DSS_WITH_AES_128_CBC_SHA), S_DSA, K_DHE, C_AES, B_128, M_SHA, F_FIPS_STD, A_DSA, ssl_hash_none },
+ { 0, CS(DHE_DSS_WITH_AES_128_CBC_SHA256), S_DSA, K_DHE, C_AES, B_128, M_SHA256, F_FIPS_STD, A_DSA, ssl_hash_sha256 },
+ { 0, CS(RSA_WITH_SEED_CBC_SHA), S_RSA, K_RSA, C_SEED, B_128, M_SHA, F_FIPS_STD, A_RSAD, ssl_hash_none },
+ { 0, CS(RSA_WITH_CAMELLIA_128_CBC_SHA), S_RSA, K_RSA, C_CAMELLIA, B_128, M_SHA, F_NFIPS_STD, A_RSAD, ssl_hash_none },
+ { 0, CS(RSA_WITH_RC4_128_SHA), S_RSA, K_RSA, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_RSAD, ssl_hash_none },
+ { 0, CS(RSA_WITH_RC4_128_MD5), S_RSA, K_RSA, C_RC4, B_128, M_MD5, F_NFIPS_STD, A_RSAD, ssl_hash_none },
+ { 0, CS(RSA_WITH_AES_128_CBC_SHA256), S_RSA, K_RSA, C_AES, B_128, M_SHA256, F_FIPS_STD, A_RSAD, ssl_hash_sha256 },
+ { 0, CS(RSA_WITH_AES_128_CBC_SHA), S_RSA, K_RSA, C_AES, B_128, M_SHA, F_FIPS_STD, A_RSAD, ssl_hash_none },
+
+ { 0, CS(DHE_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_DHE, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_RSAS, ssl_hash_none },
+ { 0, CS(DHE_DSS_WITH_3DES_EDE_CBC_SHA), S_DSA, K_DHE, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_DSA, ssl_hash_none },
+ { 0, CS(RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_RSA, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_RSAD, ssl_hash_none },
+
+ { 0, CS(DHE_RSA_WITH_DES_CBC_SHA), S_RSA, K_DHE, C_DES, B_DES, M_SHA, F_NFIPS_STD, A_RSAS, ssl_hash_none },
+ { 0, CS(DHE_DSS_WITH_DES_CBC_SHA), S_DSA, K_DHE, C_DES, B_DES, M_SHA, F_NFIPS_STD, A_DSA, ssl_hash_none },
+ { 0, CS(RSA_WITH_DES_CBC_SHA), S_RSA, K_RSA, C_DES, B_DES, M_SHA, F_NFIPS_STD, A_RSAD, ssl_hash_none },
+
+ { 0, CS(RSA_WITH_NULL_SHA256), S_RSA, K_RSA, C_NULL, B_0, M_SHA256, F_EXPORT, A_RSAD, ssl_hash_sha256 },
+ { 0, CS(RSA_WITH_NULL_SHA), S_RSA, K_RSA, C_NULL, B_0, M_SHA, F_EXPORT, A_RSAD, ssl_hash_none },
+ { 0, CS(RSA_WITH_NULL_MD5), S_RSA, K_RSA, C_NULL, B_0, M_MD5, F_EXPORT, A_RSAD, ssl_hash_none },
/* ECC cipher suites */
- { 0, CS(ECDHE_RSA_WITH_AES_128_GCM_SHA256), S_RSA, K_ECDHE, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_RSAS },
- { 0, CS(ECDHE_ECDSA_WITH_AES_128_GCM_SHA256), S_ECDSA, K_ECDHE, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_ECDSA },
- { 0, CS(ECDH_ECDSA_WITH_NULL_SHA), S_ECDSA, K_ECDH, C_NULL, B_0, M_SHA, F_NFIPS_STD, A_ECDH_E },
- { 0, CS(ECDH_ECDSA_WITH_RC4_128_SHA), S_ECDSA, K_ECDH, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_ECDH_E },
- { 0, CS(ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA), S_ECDSA, K_ECDH, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_ECDH_E },
- { 0, CS(ECDH_ECDSA_WITH_AES_128_CBC_SHA), S_ECDSA, K_ECDH, C_AES, B_128, M_SHA, F_FIPS_STD, A_ECDH_E },
- { 0, CS(ECDH_ECDSA_WITH_AES_256_CBC_SHA), S_ECDSA, K_ECDH, C_AES, B_256, M_SHA, F_FIPS_STD, A_ECDH_E },
-
- { 0, CS(ECDHE_ECDSA_WITH_NULL_SHA), S_ECDSA, K_ECDHE, C_NULL, B_0, M_SHA, F_NFIPS_STD, A_ECDSA },
- { 0, CS(ECDHE_ECDSA_WITH_RC4_128_SHA), S_ECDSA, K_ECDHE, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_ECDSA },
- { 0, CS(ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA), S_ECDSA, K_ECDHE, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_ECDSA },
- { 0, CS(ECDHE_ECDSA_WITH_AES_128_CBC_SHA), S_ECDSA, K_ECDHE, C_AES, B_128, M_SHA, F_FIPS_STD, A_ECDSA },
- { 0, CS(ECDHE_ECDSA_WITH_AES_128_CBC_SHA256), S_ECDSA, K_ECDHE, C_AES, B_128, M_SHA256, F_FIPS_STD, A_ECDSA },
- { 0, CS(ECDHE_ECDSA_WITH_AES_256_CBC_SHA), S_ECDSA, K_ECDHE, C_AES, B_256, M_SHA, F_FIPS_STD, A_ECDSA },
- { 0, CS(ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256), S_ECDSA, K_ECDHE, C_CHACHA20, B_256, M_AEAD_128, F_NFIPS_STD, A_ECDSA },
-
- { 0, CS(ECDH_RSA_WITH_NULL_SHA), S_RSA, K_ECDH, C_NULL, B_0, M_SHA, F_NFIPS_STD, A_ECDH_R },
- { 0, CS(ECDH_RSA_WITH_RC4_128_SHA), S_RSA, K_ECDH, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_ECDH_R },
- { 0, CS(ECDH_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_ECDH, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_ECDH_R },
- { 0, CS(ECDH_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_ECDH, C_AES, B_128, M_SHA, F_FIPS_STD, A_ECDH_R },
- { 0, CS(ECDH_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_ECDH, C_AES, B_256, M_SHA, F_FIPS_STD, A_ECDH_R },
-
- { 0, CS(ECDHE_RSA_WITH_NULL_SHA), S_RSA, K_ECDHE, C_NULL, B_0, M_SHA, F_NFIPS_STD, A_RSAS },
- { 0, CS(ECDHE_RSA_WITH_RC4_128_SHA), S_RSA, K_ECDHE, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_RSAS },
- { 0, CS(ECDHE_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_ECDHE, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_RSAS },
- { 0, CS(ECDHE_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_ECDHE, C_AES, B_128, M_SHA, F_FIPS_STD, A_RSAS },
- { 0, CS(ECDHE_RSA_WITH_AES_128_CBC_SHA256), S_RSA, K_ECDHE, C_AES, B_128, M_SHA256, F_FIPS_STD, A_RSAS },
- { 0, CS(ECDHE_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_ECDHE, C_AES, B_256, M_SHA, F_FIPS_STD, A_RSAS },
- { 0, CS(ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256), S_RSA, K_ECDHE, C_CHACHA20, B_256, M_AEAD_128, F_NFIPS_STD, A_RSAS },
- { 0, CS(ECDHE_RSA_WITH_AES_256_CBC_SHA384), S_RSA, K_ECDHE, C_AES, B_256, M_SHA384, F_FIPS_STD, A_RSAS },
- { 0, CS(ECDHE_ECDSA_WITH_AES_256_CBC_SHA384), S_ECDSA, K_ECDHE, C_AES, B_256, M_SHA384, F_FIPS_STD, A_ECDSA },
- { 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 },
- { 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 },
-
- { 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 },
- { 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 },
- { 0, CS(RSA_WITH_AES_256_GCM_SHA384), S_RSA, K_RSA, C_AESGCM, B_256, M_AEAD_128, F_FIPS_STD, A_RSAD },
+ { 0, CS(ECDHE_RSA_WITH_AES_128_GCM_SHA256), S_RSA, K_ECDHE, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_RSAS, ssl_hash_sha256 },
+ { 0, CS(ECDHE_ECDSA_WITH_AES_128_GCM_SHA256), S_ECDSA, K_ECDHE, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_ECDSA, ssl_hash_sha256 },
+ { 0, CS(ECDH_ECDSA_WITH_NULL_SHA), S_ECDSA, K_ECDH, C_NULL, B_0, M_SHA, F_NFIPS_STD, A_ECDH_E, ssl_hash_none },
+ { 0, CS(ECDH_ECDSA_WITH_RC4_128_SHA), S_ECDSA, K_ECDH, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_ECDH_E, ssl_hash_none },
+ { 0, CS(ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA), S_ECDSA, K_ECDH, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_ECDH_E, ssl_hash_none },
+ { 0, CS(ECDH_ECDSA_WITH_AES_128_CBC_SHA), S_ECDSA, K_ECDH, C_AES, B_128, M_SHA, F_FIPS_STD, A_ECDH_E, ssl_hash_none },
+ { 0, CS(ECDH_ECDSA_WITH_AES_256_CBC_SHA), S_ECDSA, K_ECDH, C_AES, B_256, M_SHA, F_FIPS_STD, A_ECDH_E, ssl_hash_none },
+
+ { 0, CS(ECDHE_ECDSA_WITH_NULL_SHA), S_ECDSA, K_ECDHE, C_NULL, B_0, M_SHA, F_NFIPS_STD, A_ECDSA, ssl_hash_none },
+ { 0, CS(ECDHE_ECDSA_WITH_RC4_128_SHA), S_ECDSA, K_ECDHE, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_ECDSA, ssl_hash_none },
+ { 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_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(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 },
+ { 0, CS(ECDH_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_ECDH, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_ECDH_R, ssl_hash_none },
+ { 0, CS(ECDH_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_ECDH, C_AES, B_128, M_SHA, F_FIPS_STD, A_ECDH_R, ssl_hash_none },
+ { 0, CS(ECDH_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_ECDH, C_AES, B_256, M_SHA, F_FIPS_STD, A_ECDH_R, ssl_hash_none },
+
+ { 0, CS(ECDHE_RSA_WITH_NULL_SHA), S_RSA, K_ECDHE, C_NULL, B_0, M_SHA, F_NFIPS_STD, A_RSAS, ssl_hash_none },
+ { 0, CS(ECDHE_RSA_WITH_RC4_128_SHA), S_RSA, K_ECDHE, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_RSAS, ssl_hash_none },
+ { 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_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(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 },
+ { 0, CS(RSA_WITH_AES_256_GCM_SHA384), S_RSA, K_RSA, C_AESGCM, B_256, M_AEAD_128, F_FIPS_STD, A_RSAD, ssl_hash_sha384 },
};
#define NUM_SUITEINFOS ((sizeof suiteInfo) / (sizeof suiteInfo[0]))
diff --git a/security/nss/lib/ssl/sslnonce.c b/security/nss/lib/ssl/sslnonce.c
index f8fb5d50f1..b7b5b7fe51 100644
--- a/security/nss/lib/ssl/sslnonce.c
+++ b/security/nss/lib/ssl/sslnonce.c
@@ -20,8 +20,6 @@
#include <time.h>
#endif
-PRUint32 ssl3_sid_timeout = 86400L; /* 24 hours */
-
static sslSessionID *cache = NULL;
static PZLock *cacheLock = NULL;
@@ -259,30 +257,28 @@ ssl_ReferenceSID(sslSessionID *sid)
*/
sslSessionID *
-ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID,
+ssl_LookupSID(PRTime now, const PRIPv6Addr *addr, PRUint16 port, const char *peerID,
const char *urlSvrName)
{
sslSessionID **sidp;
sslSessionID *sid;
- PRUint32 now;
if (!urlSvrName)
return NULL;
- now = ssl_TimeSec();
LOCK_CACHE;
sidp = &cache;
while ((sid = *sidp) != 0) {
PORT_Assert(sid->cached == in_client_cache);
PORT_Assert(sid->references >= 1);
- SSL_TRC(8, ("SSL: Lookup1: sid=0x%x", sid));
+ SSL_TRC(8, ("SSL: lookup: sid=0x%x", sid));
if (sid->expirationTime < now) {
/*
** This session-id timed out.
** Don't even care who it belongs to, blow it out of our cache.
*/
- SSL_TRC(7, ("SSL: lookup1, throwing sid out, age=%d refs=%d",
+ SSL_TRC(7, ("SSL: lookup, throwing sid out, age=%d refs=%d",
now - sid->creationTime, sid->references));
*sidp = sid->next; /* delink it from the list. */
@@ -316,7 +312,7 @@ ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID,
** Although this is static, it is called via ss->sec.cache().
*/
static void
-CacheSID(sslSessionID *sid)
+CacheSID(sslSessionID *sid, PRTime creationTime)
{
PORT_Assert(sid);
PORT_Assert(sid->cached == never_cached);
@@ -353,11 +349,16 @@ CacheSID(sslSessionID *sid)
if (!sid->u.ssl3.lock) {
return;
}
- PORT_Assert(sid->creationTime != 0 && sid->expirationTime != 0);
- if (!sid->creationTime)
- sid->lastAccessTime = sid->creationTime = ssl_TimeUsec();
- if (!sid->expirationTime)
- sid->expirationTime = sid->creationTime + ssl3_sid_timeout * PR_USEC_PER_SEC;
+ PORT_Assert(sid->creationTime != 0);
+ if (!sid->creationTime) {
+ sid->lastAccessTime = sid->creationTime = creationTime;
+ }
+ PORT_Assert(sid->expirationTime != 0);
+ if (!sid->expirationTime) {
+ sid->expirationTime = sid->creationTime + (PR_MIN(ssl_ticket_lifetime,
+ sid->u.ssl3.locked.sessionTicket.ticket_lifetime_hint) *
+ PR_USEC_PER_SEC);
+ }
/*
* Put sid into the cache. Bump reference count to indicate that
@@ -726,13 +727,13 @@ ssl_IsResumptionTokenUsable(sslSocket *ss, sslSessionID *sid)
if (ticket->ticket_lifetime_hint != 0) {
endTime = ticket->received_timestamp +
(PRTime)(ticket->ticket_lifetime_hint * PR_USEC_PER_SEC);
- if (endTime < ssl_TimeUsec()) {
+ if (endTime <= ssl_Time(ss)) {
return PR_FALSE;
}
}
// Check that the session entry didn't expire.
- if (sid->expirationTime < ssl_TimeUsec()) {
+ if (sid->expirationTime < ssl_Time(ss)) {
return PR_FALSE;
}
@@ -1087,10 +1088,12 @@ ssl_CacheExternalToken(sslSocket *ss)
}
if (!sid->creationTime) {
- sid->lastAccessTime = sid->creationTime = ssl_TimeUsec();
+ sid->lastAccessTime = sid->creationTime = ssl_Time(ss);
}
if (!sid->expirationTime) {
- sid->expirationTime = sid->creationTime + ssl3_sid_timeout;
+ sid->expirationTime = sid->creationTime + (PR_MIN(ssl_ticket_lifetime,
+ sid->u.ssl3.locked.sessionTicket.ticket_lifetime_hint) *
+ PR_USEC_PER_SEC);
}
sslBuffer encodedToken = SSL_BUFFER_EMPTY;
@@ -1129,11 +1132,11 @@ ssl_CacheSessionID(sslSocket *ss)
PORT_Assert(!ss->resumptionTokenCallback);
if (sec->isServer) {
- ssl_ServerCacheSessionID(sec->ci.sid);
+ ssl_ServerCacheSessionID(sec->ci.sid, ssl_Time(ss));
return;
}
- CacheSID(sec->ci.sid);
+ CacheSID(sec->ci.sid, ssl_Time(ss));
}
void
@@ -1165,32 +1168,8 @@ SSL_ClearSessionCache(void)
UNLOCK_CACHE;
}
-/* returns an unsigned int containing the number of seconds in PR_Now() */
-PRUint32
-ssl_TimeSec(void)
-{
-#ifdef UNSAFE_FUZZER_MODE
- return 1234;
-#endif
-
- PRUint32 myTime;
-#if defined(XP_UNIX) || defined(XP_WIN) || defined(_WINDOWS) || defined(XP_BEOS)
- myTime = time(NULL); /* accurate until the year 2038. */
-#else
- /* portable, but possibly slower */
- PRTime now;
- PRInt64 ll;
-
- now = PR_Now();
- LL_I2L(ll, 1000000L);
- LL_DIV(now, now, ll);
- LL_L2UI(myTime, now);
-#endif
- return myTime;
-}
-
PRBool
-ssl_TicketTimeValid(const NewSessionTicket *ticket)
+ssl_TicketTimeValid(const sslSocket *ss, const NewSessionTicket *ticket)
{
PRTime endTime;
@@ -1200,7 +1179,7 @@ ssl_TicketTimeValid(const NewSessionTicket *ticket)
endTime = ticket->received_timestamp +
(PRTime)(ticket->ticket_lifetime_hint * PR_USEC_PER_SEC);
- return endTime > ssl_TimeUsec();
+ return endTime > ssl_Time(ss);
}
void
diff --git a/security/nss/lib/ssl/sslprimitive.c b/security/nss/lib/ssl/sslprimitive.c
new file mode 100644
index 0000000000..540c178400
--- /dev/null
+++ b/security/nss/lib/ssl/sslprimitive.c
@@ -0,0 +1,274 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * SSL Primitives: Public HKDF and AEAD Functions
+ *
+ * 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 "keyhi.h"
+#include "pk11pub.h"
+#include "sechash.h"
+#include "ssl.h"
+#include "sslexp.h"
+#include "sslerr.h"
+#include "sslproto.h"
+
+#include "sslimpl.h"
+#include "tls13con.h"
+#include "tls13hkdf.h"
+
+struct SSLAeadContextStr {
+ CK_MECHANISM_TYPE mech;
+ ssl3KeyMaterial keys;
+};
+
+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)
+{
+ SSLAeadContext *out = NULL;
+ char label[255]; // Maximum length label.
+ static const char *const keySuffix = "key";
+ static const char *const ivSuffix = "iv";
+
+ PORT_Assert(strlen(keySuffix) >= strlen(ivSuffix));
+ if (secret == NULL || ctx == NULL ||
+ (labelPrefix == NULL && labelPrefixLen > 0) ||
+ labelPrefixLen + strlen(keySuffix) > sizeof(label)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ goto loser;
+ }
+
+ SSLHashType hash;
+ const ssl3BulkCipherDef *cipher;
+ SECStatus rv = tls13_GetHashAndCipher(version, cipherSuite,
+ &hash, &cipher);
+ if (rv != SECSuccess) {
+ goto loser; /* Code already set. */
+ }
+
+ out = PORT_ZNew(SSLAeadContext);
+ if (out == NULL) {
+ goto loser;
+ }
+ out->mech = ssl3_Alg2Mech(cipher->calg);
+
+ memcpy(label, labelPrefix, labelPrefixLen);
+ memcpy(label + labelPrefixLen, ivSuffix, strlen(ivSuffix));
+ unsigned int labelLen = labelPrefixLen + strlen(ivSuffix);
+ 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);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ memcpy(label + labelPrefixLen, keySuffix, strlen(keySuffix));
+ labelLen = labelPrefixLen + strlen(keySuffix);
+ rv = tls13_HkdfExpandLabel(secret, hash,
+ NULL, 0, // Handshake hash.
+ label, labelLen,
+ out->mech, cipher->key_size, &out->keys.key);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ *ctx = out;
+ return SECSuccess;
+
+loser:
+ SSLExp_DestroyAead(out);
+ return SECFailure;
+}
+
+SECStatus
+SSLExp_DestroyAead(SSLAeadContext *ctx)
+{
+ if (!ctx) {
+ return SECSuccess;
+ }
+
+ 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,
+ const PRUint8 *aad, unsigned int aadLen,
+ const PRUint8 *plaintext, unsigned int plaintextLen,
+ PRUint8 *out, unsigned int *outLen, unsigned int maxOut)
+{
+ if (ctx == NULL || (aad == NULL && aadLen > 0) || plaintext == 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));
+ 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);
+}
+
+SECStatus
+SSLExp_AeadEncrypt(const SSLAeadContext *ctx, PRUint64 counter,
+ const PRUint8 *aad, unsigned int aadLen,
+ const PRUint8 *plaintext, unsigned int plaintextLen,
+ PRUint8 *out, unsigned int *outLen, unsigned int maxOut)
+{
+ // false == encrypt
+ return ssl_AeadInner(ctx, 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,
+ PRUint8 *out, unsigned int *outLen, unsigned int maxOut)
+{
+ // true == decrypt
+ return ssl_AeadInner(ctx, PR_TRUE, counter, aad, aadLen,
+ plaintext, plaintextLen, out, outLen, maxOut);
+}
+
+SECStatus
+SSLExp_HkdfExtract(PRUint16 version, PRUint16 cipherSuite,
+ PK11SymKey *salt, PK11SymKey *ikm, PK11SymKey **keyp)
+{
+ if (keyp == NULL) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ SSLHashType hash;
+ SECStatus rv = tls13_GetHashAndCipher(version, cipherSuite,
+ &hash, NULL);
+ if (rv != SECSuccess) {
+ return SECFailure; /* Code already set. */
+ }
+ return tls13_HkdfExtract(salt, ikm, hash, keyp);
+}
+
+SECStatus
+SSLExp_HkdfExpandLabel(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk,
+ const PRUint8 *hsHash, unsigned int hsHashLen,
+ const char *label, unsigned int labelLen,
+ PK11SymKey **keyp)
+{
+ if (prk == NULL || keyp == NULL ||
+ label == NULL || labelLen == 0) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ SSLHashType hash;
+ SECStatus rv = tls13_GetHashAndCipher(version, cipherSuite,
+ &hash, NULL);
+ if (rv != SECSuccess) {
+ return SECFailure; /* Code already set. */
+ }
+ return tls13_HkdfExpandLabel(prk, hash, hsHash, hsHashLen, label, labelLen,
+ tls13_GetHkdfMechanismForHash(hash),
+ tls13_GetHashSizeForHash(hash), keyp);
+}
+
+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)
+{
+ if (prk == NULL || keyp == NULL ||
+ label == NULL || labelLen == 0 ||
+ mech == CKM_INVALID_MECHANISM || keySize == 0) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ SSLHashType hash;
+ SECStatus rv = tls13_GetHashAndCipher(version, cipherSuite,
+ &hash, NULL);
+ if (rv != SECSuccess) {
+ return SECFailure; /* Code already set. */
+ }
+ return tls13_HkdfExpandLabel(prk, hash, hsHash, hsHashLen, label, labelLen,
+ mech, keySize, keyp);
+}
diff --git a/security/nss/lib/ssl/sslsecur.c b/security/nss/lib/ssl/sslsecur.c
index c011b66a11..14320fa190 100644
--- a/security/nss/lib/ssl/sslsecur.c
+++ b/security/nss/lib/ssl/sslsecur.c
@@ -16,32 +16,7 @@
#include "nss.h" /* for NSS_RegisterShutdown */
#include "prinit.h" /* for PR_CallOnceWithArg */
-/* Returns a SECStatus: SECSuccess or SECFailure, NOT SECWouldBlock.
- *
- * Currently, the list of functions called through ss->handshake is:
- *
- * In sslsocks.c:
- * SocksGatherRecord
- * SocksHandleReply
- * SocksStartGather
- *
- * In sslcon.c:
- * ssl_GatherRecord1stHandshake
- * ssl_BeginClientHandshake
- * ssl_BeginServerHandshake
- *
- * The ss->handshake function returns SECWouldBlock if it was returned by
- * one of the callback functions, via one of these paths:
- *
- * - ssl_GatherRecord1stHandshake() -> ssl3_GatherCompleteHandshake() ->
- * ssl3_HandleRecord() -> ssl3_HandleHandshake() ->
- * ssl3_HandleHandshakeMessage() -> ssl3_HandleCertificate() ->
- * ss->handleBadCert()
- *
- * - ssl_GatherRecord1stHandshake() -> ssl3_GatherCompleteHandshake() ->
- * ssl3_HandleRecord() -> ssl3_HandleHandshake() ->
- * ssl3_HandleHandshakeMessage() -> ssl3_HandleCertificateRequest() ->
- * ss->getClientAuthData()
+/* Step through the handshake functions.
*
* Called from: SSL_ForceHandshake (below),
* ssl_SecureRecv (below) and
@@ -52,10 +27,10 @@
*
* Caller must hold the (write) handshakeLock.
*/
-int
+SECStatus
ssl_Do1stHandshake(sslSocket *ss)
{
- int rv = SECSuccess;
+ SECStatus rv = SECSuccess;
while (ss->handshake && rv == SECSuccess) {
PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss));
@@ -70,10 +45,6 @@ ssl_Do1stHandshake(sslSocket *ss)
PORT_Assert(ss->opt.noLocks || !ssl_HaveXmitBufLock(ss));
PORT_Assert(ss->opt.noLocks || !ssl_HaveSSL3HandshakeLock(ss));
- if (rv == SECWouldBlock) {
- PORT_SetError(PR_WOULD_BLOCK_ERROR);
- rv = SECFailure;
- }
return rv;
}
@@ -106,8 +77,8 @@ ssl_FinishHandshake(sslSocket *ss)
static SECStatus
ssl3_AlwaysBlock(sslSocket *ss)
{
- PORT_SetError(PR_WOULD_BLOCK_ERROR); /* perhaps redundant. */
- return SECWouldBlock;
+ PORT_SetError(PR_WOULD_BLOCK_ERROR);
+ return SECFailure;
}
/*
@@ -400,10 +371,13 @@ SSL_ForceHandshake(PRFileDesc *fd)
ssl_ReleaseRecvBufLock(ss);
if (gatherResult > 0) {
rv = SECSuccess;
- } else if (gatherResult == 0) {
- PORT_SetError(PR_END_OF_FILE_ERROR);
- } else if (gatherResult == SECWouldBlock) {
- PORT_SetError(PR_WOULD_BLOCK_ERROR);
+ } else {
+ if (gatherResult == 0) {
+ PORT_SetError(PR_END_OF_FILE_ERROR);
+ }
+ /* We can rely on ssl3_GatherCompleteHandshake to set
+ * PR_WOULD_BLOCK_ERROR as needed here. */
+ rv = SECFailure;
}
} else {
PORT_Assert(!ss->firstHsDone);
@@ -515,8 +489,7 @@ DoRecv(sslSocket *ss, unsigned char *out, int len, int flags)
SSL_GETPID(), ss->fd));
goto done;
}
- if ((rv != SECWouldBlock) &&
- (PR_GetError() != PR_WOULD_BLOCK_ERROR)) {
+ if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
/* Some random error */
goto done;
}
@@ -741,13 +714,14 @@ ssl_SecureShutdown(sslSocket *ss, int nsprHow)
/************************************************************************/
static SECStatus
-tls13_CheckKeyUpdate(sslSocket *ss, CipherSpecDirection dir)
+tls13_CheckKeyUpdate(sslSocket *ss, SSLSecretDirection dir)
{
PRBool keyUpdate;
ssl3CipherSpec *spec;
sslSequenceNumber seqNum;
sslSequenceNumber margin;
- SECStatus rv;
+ tls13KeyUpdateRequest keyUpdateRequest;
+ SECStatus rv = SECSuccess;
/* Bug 1413368: enable for DTLS */
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3 || IS_DTLS(ss)) {
@@ -765,7 +739,7 @@ tls13_CheckKeyUpdate(sslSocket *ss, CipherSpecDirection dir)
* having the write margin larger reduces the number of times that a
* KeyUpdate is sent by a reader. */
ssl_GetSpecReadLock(ss);
- if (dir == CipherSpecRead) {
+ if (dir == ssl_secret_read) {
spec = ss->ssl3.crSpec;
margin = spec->cipherDef->max_records / 8;
} else {
@@ -781,10 +755,16 @@ tls13_CheckKeyUpdate(sslSocket *ss, CipherSpecDirection dir)
SSL_TRC(5, ("%d: SSL[%d]: automatic key update at %llx for %s cipher spec",
SSL_GETPID(), ss->fd, seqNum,
- (dir == CipherSpecRead) ? "read" : "write"));
+ (dir == ssl_secret_read) ? "read" : "write"));
+ keyUpdateRequest = (dir == ssl_secret_read) ? update_requested : update_not_requested;
ssl_GetSSL3HandshakeLock(ss);
- rv = tls13_SendKeyUpdate(ss, (dir == CipherSpecRead) ? update_requested : update_not_requested,
- dir == CipherSpecWrite /* buffer */);
+ if (ss->ssl3.clientCertRequested) {
+ ss->ssl3.keyUpdateDeferred = PR_TRUE;
+ ss->ssl3.deferredKeyUpdateRequest = keyUpdateRequest;
+ } else {
+ rv = tls13_SendKeyUpdate(ss, keyUpdateRequest,
+ dir == ssl_secret_write /* buffer */);
+ }
ssl_ReleaseSSL3HandshakeLock(ss);
return rv;
}
@@ -829,7 +809,7 @@ ssl_SecureRecv(sslSocket *ss, unsigned char *buf, int len, int flags)
}
ssl_Release1stHandshakeLock(ss);
} else {
- if (tls13_CheckKeyUpdate(ss, CipherSpecRead) != SECSuccess) {
+ if (tls13_CheckKeyUpdate(ss, ssl_secret_read) != SECSuccess) {
rv = PR_FAILURE;
}
}
@@ -955,7 +935,7 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
}
if (ss->firstHsDone) {
- if (tls13_CheckKeyUpdate(ss, CipherSpecWrite) != SECSuccess) {
+ if (tls13_CheckKeyUpdate(ss, ssl_secret_write) != SECSuccess) {
rv = PR_FAILURE;
goto done;
}
@@ -1011,6 +991,35 @@ ssl_SecureWrite(sslSocket *ss, const unsigned char *buf, int len)
}
SECStatus
+SSLExp_RecordLayerWriteCallback(PRFileDesc *fd, SSLRecordWriteCallback cb,
+ void *arg)
+{
+ sslSocket *ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: invalid socket for SSL_RecordLayerWriteCallback",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+ if (IS_DTLS(ss)) {
+ SSL_DBG(("%d: SSL[%d]: DTLS socket for SSL_RecordLayerWriteCallback",
+ SSL_GETPID(), fd));
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ /* This needs both HS and Xmit locks because this value is checked under
+ * both locks. HS to disable reading from the underlying IO layer; Xmit to
+ * prevent writing. */
+ ssl_GetSSL3HandshakeLock(ss);
+ ssl_GetXmitBufLock(ss);
+ ss->recordWriteCallback = cb;
+ ss->recordWriteCallbackArg = arg;
+ ssl_ReleaseXmitBufLock(ss);
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ return SECSuccess;
+}
+
+SECStatus
SSL_AlertReceivedCallback(PRFileDesc *fd, SSLAlertCallback cb, void *arg)
{
sslSocket *ss;
diff --git a/security/nss/lib/ssl/sslsnce.c b/security/nss/lib/ssl/sslsnce.c
index d7abb3dc32..36c82117e2 100644
--- a/security/nss/lib/ssl/sslsnce.c
+++ b/security/nss/lib/ssl/sslsnce.c
@@ -276,14 +276,24 @@ typedef struct inheritanceStr inheritance;
/************************************************************************/
+/* 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
+ssl_CacheNow()
+{
+ return PR_Now() / PR_USEC_PER_SEC;
+}
+
static PRUint32
LockSidCacheLock(sidCacheLock *lock, PRUint32 now)
{
SECStatus rv = sslMutex_Lock(&lock->mutex);
if (rv != SECSuccess)
return 0;
- if (!now)
- now = ssl_TimeSec();
+ if (!now) {
+ now = ssl_CacheNow();
+ }
+
lock->timeStamp = now;
lock->pid = myPid;
return now;
@@ -299,7 +309,7 @@ UnlockSidCacheLock(sidCacheLock *lock)
return rv;
}
-/* returns the value of ssl_TimeSec on success, zero on failure. */
+/* Returns non-zero |now| or ssl_CacheNow() on success, zero on failure. */
static PRUint32
LockSet(cacheDesc *cache, PRUint32 set, PRUint32 now)
{
@@ -630,9 +640,12 @@ FindSID(cacheDesc *cache, PRUint32 setNum, PRUint32 now,
/* This is the primary function for finding entries in the server's sid cache.
* Although it is static, this function is called via the global function
* pointer ssl_sid_lookup.
+ *
+ * sslNow is the time that the calling socket understands, which might be
+ * different than what the cache uses to maintain its locks.
*/
static sslSessionID *
-ServerSessionIDLookup(const PRIPv6Addr *addr,
+ServerSessionIDLookup(PRTime sslNow, const PRIPv6Addr *addr,
unsigned char *sessionID,
unsigned int sessionIDLength,
CERTCertDBHandle *dbHandle)
@@ -712,7 +725,7 @@ ServerSessionIDLookup(const PRIPv6Addr *addr,
}
}
if (psce) {
- psce->lastAccessTime = now;
+ psce->lastAccessTime = sslNow;
sce = *psce; /* grab a copy while holding the lock */
}
}
@@ -730,7 +743,7 @@ ServerSessionIDLookup(const PRIPv6Addr *addr,
** Place a sid into the cache, if it isn't already there.
*/
void
-ssl_ServerCacheSessionID(sslSessionID *sid)
+ssl_ServerCacheSessionID(sslSessionID *sid, PRTime creationTime)
{
PORT_Assert(sid);
@@ -748,7 +761,7 @@ ssl_ServerCacheSessionID(sslSessionID *sid)
PORT_Assert(sid->creationTime != 0);
if (!sid->creationTime)
- sid->lastAccessTime = sid->creationTime = ssl_TimeUsec();
+ sid->lastAccessTime = sid->creationTime = creationTime;
/* override caller's expiration time, which uses client timeout
* duration, not server timeout duration.
*/
@@ -1089,7 +1102,7 @@ InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries,
cache->srvNameCacheData = (srvNameCacheEntry *)(cache->cacheMem + (ptrdiff_t)cache->srvNameCacheData);
/* initialize the locks */
- init_time = ssl_TimeSec();
+ init_time = ssl_CacheNow();
pLock = cache->sidCacheLocks;
for (locks_to_initialize = cache->numSIDCacheLocks + 3;
locks_initialized < locks_to_initialize;
@@ -1518,7 +1531,7 @@ LockPoller(void *arg)
if (sharedCache->stopPolling)
break;
- now = ssl_TimeSec();
+ now = ssl_CacheNow();
then = now - expiration;
for (pLock = cache->sidCacheLocks, locks_polled = 0;
locks_to_poll > locks_polled && !sharedCache->stopPolling;
@@ -1680,30 +1693,34 @@ ssl_SetSelfEncryptKeyPair(SECKEYPublicKey *pubKey,
SECKEYPrivateKey *privKey,
PRBool explicitConfig)
{
- SECKEYPublicKey *pubKeyCopy;
- SECKEYPrivateKey *privKeyCopy;
+ SECKEYPublicKey *pubKeyCopy, *oldPubKey;
+ SECKEYPrivateKey *privKeyCopy, *oldPrivKey;
PORT_Assert(ssl_self_encrypt_key_pair.lock);
-
pubKeyCopy = SECKEY_CopyPublicKey(pubKey);
- if (!pubKeyCopy) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return SECFailure;
- }
-
privKeyCopy = SECKEY_CopyPrivateKey(privKey);
- if (!privKeyCopy) {
+
+ if (!pubKeyCopy || !privKeyCopy) {
SECKEY_DestroyPublicKey(pubKeyCopy);
+ SECKEY_DestroyPrivateKey(privKeyCopy);
PORT_SetError(SEC_ERROR_NO_MEMORY);
return SECFailure;
}
PR_RWLock_Wlock(ssl_self_encrypt_key_pair.lock);
- ssl_CleanupSelfEncryptKeyPair();
+ oldPubKey = ssl_self_encrypt_key_pair.pubKey;
+ oldPrivKey = ssl_self_encrypt_key_pair.privKey;
ssl_self_encrypt_key_pair.pubKey = pubKeyCopy;
ssl_self_encrypt_key_pair.privKey = privKeyCopy;
ssl_self_encrypt_key_pair.configured = explicitConfig;
PR_RWLock_Unlock(ssl_self_encrypt_key_pair.lock);
+
+ if (oldPubKey) {
+ PORT_Assert(oldPrivKey);
+ SECKEY_DestroyPublicKey(oldPubKey);
+ SECKEY_DestroyPrivateKey(oldPrivKey);
+ }
+
return SECSuccess;
}
@@ -1762,16 +1779,33 @@ ssl_GetSelfEncryptKeyPair(SECKEYPublicKey **pubKey,
return SECFailure;
}
+ SECKEYPublicKey *pubKeyCopy;
+ SECKEYPrivateKey *privKeyCopy;
+ PRBool noKey = PR_FALSE;
+
PR_RWLock_Rlock(ssl_self_encrypt_key_pair.lock);
- *pubKey = ssl_self_encrypt_key_pair.pubKey;
- *privKey = ssl_self_encrypt_key_pair.privKey;
+ if (ssl_self_encrypt_key_pair.pubKey && ssl_self_encrypt_key_pair.privKey) {
+ pubKeyCopy = SECKEY_CopyPublicKey(ssl_self_encrypt_key_pair.pubKey);
+ privKeyCopy = SECKEY_CopyPrivateKey(ssl_self_encrypt_key_pair.privKey);
+ } else {
+ noKey = PR_TRUE;
+ }
PR_RWLock_Unlock(ssl_self_encrypt_key_pair.lock);
- if (!*pubKey) {
- PORT_Assert(!*privKey);
+
+ if (noKey) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
- PORT_Assert(*privKey);
+
+ if (!pubKeyCopy || !privKeyCopy) {
+ SECKEY_DestroyPublicKey(pubKeyCopy);
+ SECKEY_DestroyPrivateKey(privKeyCopy);
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return SECFailure;
+ }
+
+ *pubKey = pubKeyCopy;
+ *privKey = privKeyCopy;
return SECSuccess;
}
@@ -2040,35 +2074,43 @@ static SECStatus
ssl_GenerateSelfEncryptKeys(void *pwArg, PRUint8 *keyName,
PK11SymKey **encKey, PK11SymKey **macKey)
{
- SECKEYPrivateKey *svrPrivKey;
- SECKEYPublicKey *svrPubKey;
+ SECKEYPrivateKey *svrPrivKey = NULL;
+ SECKEYPublicKey *svrPubKey = NULL;
PRUint32 now;
- SECStatus rv;
cacheDesc *cache = &globalCache;
- rv = ssl_GetSelfEncryptKeyPair(&svrPubKey, &svrPrivKey);
+ SECStatus rv = ssl_GetSelfEncryptKeyPair(&svrPubKey, &svrPrivKey);
if (rv != SECSuccess || !cache->cacheMem) {
/* No key pair for wrapping, or the cache is uninitialized. Generate
* keys and return them without caching. */
- return GenerateSelfEncryptKeys(pwArg, keyName, encKey, macKey);
- }
-
- now = LockSidCacheLock(cache->keyCacheLock, 0);
- if (!now)
- return SECFailure;
-
- if (*(cache->ticketKeysValid)) {
- rv = UnwrapCachedSelfEncryptKeys(svrPrivKey, keyName, encKey, macKey);
+ rv = GenerateSelfEncryptKeys(pwArg, keyName, encKey, macKey);
} else {
- /* Keys do not exist, create them. */
- rv = GenerateAndWrapSelfEncryptKeys(svrPubKey, pwArg, keyName,
- encKey, macKey);
- if (rv == SECSuccess) {
- *(cache->ticketKeysValid) = 1;
+ now = LockSidCacheLock(cache->keyCacheLock, 0);
+ if (!now) {
+ goto loser;
+ }
+
+ if (*(cache->ticketKeysValid)) {
+ rv = UnwrapCachedSelfEncryptKeys(svrPrivKey, keyName, encKey, macKey);
+ } else {
+ /* Keys do not exist, create them. */
+ rv = GenerateAndWrapSelfEncryptKeys(svrPubKey, pwArg, keyName,
+ encKey, macKey);
+ if (rv == SECSuccess) {
+ *(cache->ticketKeysValid) = 1;
+ }
}
+ UnlockSidCacheLock(cache->keyCacheLock);
}
- UnlockSidCacheLock(cache->keyCacheLock);
+ SECKEY_DestroyPublicKey(svrPubKey);
+ SECKEY_DestroyPrivateKey(svrPrivKey);
return rv;
+
+loser:
+ UnlockSidCacheLock(cache->keyCacheLock);
+ SECKEY_DestroyPublicKey(svrPubKey);
+ SECKEY_DestroyPrivateKey(svrPrivKey);
+ return SECFailure;
}
/* The caller passes in the new value it wants
diff --git a/security/nss/lib/ssl/sslsock.c b/security/nss/lib/ssl/sslsock.c
index ae904e29b8..aa0e76e3ce 100644
--- a/security/nss/lib/ssl/sslsock.c
+++ b/security/nss/lib/ssl/sslsock.c
@@ -20,6 +20,7 @@
#include "pk11pqg.h"
#include "pk11pub.h"
#include "tls13esni.h"
+#include "tls13subcerts.h"
static const sslSocketOps ssl_default_ops = { /* No SSL. */
ssl_DefConnect,
@@ -75,18 +76,20 @@ static sslOptions ssl_defaults = {
.enableFalseStart = PR_FALSE,
.cbcRandomIV = PR_TRUE,
.enableOCSPStapling = PR_FALSE,
+ .enableDelegatedCredentials = PR_FALSE,
.enableALPN = PR_TRUE,
.reuseServerECDHEKey = PR_TRUE,
.enableFallbackSCSV = PR_FALSE,
.enableServerDhe = PR_TRUE,
- .enableExtendedMS = PR_FALSE,
+ .enableExtendedMS = PR_TRUE,
.enableSignedCertTimestamps = PR_FALSE,
.requireDHENamedGroups = PR_FALSE,
.enable0RttData = PR_FALSE,
.enableTls13CompatMode = PR_FALSE,
.enableDtlsShortHeader = PR_FALSE,
.enableHelloDowngradeCheck = PR_FALSE,
- .enableV2CompatibleHello = PR_FALSE
+ .enableV2CompatibleHello = PR_FALSE,
+ .enablePostHandshakeAuth = PR_FALSE
};
/*
@@ -94,7 +97,7 @@ static sslOptions ssl_defaults = {
*/
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 = {
@@ -276,6 +279,8 @@ ssl_DupSocket(sslSocket *os)
goto loser;
}
ss->vrange = os->vrange;
+ ss->now = os->now;
+ ss->nowArg = os->nowArg;
ss->peerID = !os->peerID ? NULL : PORT_Strdup(os->peerID);
ss->url = !os->url ? NULL : PORT_Strdup(os->url);
@@ -369,6 +374,13 @@ ssl_DupSocket(sslSocket *os)
goto loser;
}
}
+ if (os->antiReplay) {
+ ss->antiReplay = tls13_RefAntiReplayContext(os->antiReplay);
+ PORT_Assert(ss->antiReplay); /* Can't fail. */
+ if (!ss->antiReplay) {
+ goto loser;
+ }
+ }
/* Create security data */
rv = ssl_CopySecurityInfo(ss, os);
@@ -457,6 +469,7 @@ ssl_DestroySocketContents(sslSocket *ss)
ssl_ClearPRCList(&ss->ssl3.hs.dtlsRcvdHandshake, NULL);
tls13_DestroyESNIKeys(ss->esniKeys);
+ tls13_ReleaseAntiReplayContext(ss->antiReplay);
}
/*
@@ -782,6 +795,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRIntn val)
ss->opt.enableOCSPStapling = val;
break;
+ case SSL_ENABLE_DELEGATED_CREDENTIALS:
+ ss->opt.enableDelegatedCredentials = val;
+ break;
+
case SSL_ENABLE_NPN:
break;
@@ -842,6 +859,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRIntn val)
ss->opt.enableV2CompatibleHello = val;
break;
+ case SSL_ENABLE_POST_HANDSHAKE_AUTH:
+ ss->opt.enablePostHandshakeAuth = val;
+ break;
+
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
@@ -948,6 +969,9 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRIntn *pVal)
case SSL_ENABLE_OCSP_STAPLING:
val = ss->opt.enableOCSPStapling;
break;
+ case SSL_ENABLE_DELEGATED_CREDENTIALS:
+ val = ss->opt.enableDelegatedCredentials;
+ break;
case SSL_ENABLE_NPN:
val = PR_FALSE;
break;
@@ -990,6 +1014,9 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRIntn *pVal)
case SSL_ENABLE_V2_COMPATIBLE_HELLO:
val = ss->opt.enableV2CompatibleHello;
break;
+ case SSL_ENABLE_POST_HANDSHAKE_AUTH:
+ val = ss->opt.enablePostHandshakeAuth;
+ break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
@@ -1083,6 +1110,9 @@ SSL_OptionGetDefault(PRInt32 which, PRIntn *pVal)
case SSL_ENABLE_OCSP_STAPLING:
val = ssl_defaults.enableOCSPStapling;
break;
+ case SSL_ENABLE_DELEGATED_CREDENTIALS:
+ val = ssl_defaults.enableDelegatedCredentials;
+ break;
case SSL_ENABLE_NPN:
val = PR_FALSE;
break;
@@ -1122,6 +1152,9 @@ SSL_OptionGetDefault(PRInt32 which, PRIntn *pVal)
case SSL_ENABLE_V2_COMPATIBLE_HELLO:
val = ssl_defaults.enableV2CompatibleHello;
break;
+ case SSL_ENABLE_POST_HANDSHAKE_AUTH:
+ val = ssl_defaults.enablePostHandshakeAuth;
+ break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
@@ -1270,6 +1303,10 @@ SSL_OptionSetDefault(PRInt32 which, PRIntn val)
ssl_defaults.enableOCSPStapling = val;
break;
+ case SSL_ENABLE_DELEGATED_CREDENTIALS:
+ ssl_defaults.enableDelegatedCredentials = val;
+ break;
+
case SSL_ENABLE_NPN:
break;
@@ -1325,6 +1362,10 @@ SSL_OptionSetDefault(PRInt32 which, PRIntn val)
ssl_defaults.enableV2CompatibleHello = val;
break;
+ case SSL_ENABLE_POST_HANDSHAKE_AUTH:
+ ssl_defaults.enablePostHandshakeAuth = val;
+ break;
+
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
@@ -1499,6 +1540,119 @@ SSL_CipherPrefGet(PRFileDesc *fd, PRInt32 which, PRBool *enabled)
return rv;
}
+/* The client can call this function to be aware of the current
+ * CipherSuites order. */
+SECStatus
+SSLExp_CipherSuiteOrderGet(PRFileDesc *fd, PRUint16 *cipherOrder,
+ unsigned int *numCiphers)
+{
+ if (!fd) {
+ SSL_DBG(("%d: SSL: file descriptor in CipherSuiteOrderGet is null",
+ SSL_GETPID()));
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (!cipherOrder || !numCiphers) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ sslSocket *ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in CipherSuiteOrderGet", SSL_GETPID(),
+ fd));
+ return SECFailure; /* Error code already set. */
+ }
+
+ unsigned int enabled = 0;
+ ssl_Get1stHandshakeLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+ for (unsigned int i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
+ const ssl3CipherSuiteCfg *suiteCfg = &ss->cipherSuites[i];
+ if (suiteCfg && suiteCfg->enabled &&
+ suiteCfg->policy != SSL_NOT_ALLOWED) {
+ cipherOrder[enabled++] = suiteCfg->cipher_suite;
+ }
+ }
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+ *numCiphers = enabled;
+ return SECSuccess;
+}
+
+/* This function permits reorder the CipherSuites List for the Handshake
+ * (Client Hello). */
+SECStatus
+SSLExp_CipherSuiteOrderSet(PRFileDesc *fd, const PRUint16 *cipherOrder,
+ unsigned int numCiphers)
+{
+ if (!fd) {
+ SSL_DBG(("%d: SSL: file descriptor in CipherSuiteOrderGet is null",
+ SSL_GETPID()));
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (!cipherOrder || !numCiphers || numCiphers > ssl_V3_SUITES_IMPLEMENTED) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ sslSocket *ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in CipherSuiteOrderSet", SSL_GETPID(),
+ fd));
+ return SECFailure; /* Error code already set. */
+ }
+ ssl3CipherSuiteCfg tmpSuiteCfg[ssl_V3_SUITES_IMPLEMENTED];
+ ssl_Get1stHandshakeLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+ /* For each cipherSuite given as input, verify that it is
+ * known to NSS and only present in the list once. */
+ for (unsigned int i = 0; i < numCiphers; i++) {
+ const ssl3CipherSuiteCfg *suiteCfg =
+ ssl_LookupCipherSuiteCfg(cipherOrder[i], ss->cipherSuites);
+ if (!suiteCfg) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+ return SECFailure;
+ }
+ for (unsigned int j = i + 1; j < numCiphers; j++) {
+ /* This is a duplicate entry. */
+ if (cipherOrder[i] == cipherOrder[j]) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+ return SECFailure;
+ }
+ }
+ tmpSuiteCfg[i] = *suiteCfg;
+ tmpSuiteCfg[i].enabled = PR_TRUE;
+ }
+ /* Find all defined ciphersuites not present in the input list and append
+ * them after the preferred. This guarantees that the socket will always
+ * have a complete list of size ssl_V3_SUITES_IMPLEMENTED */
+ unsigned int cfgIdx = numCiphers;
+ for (unsigned int i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
+ PRBool received = PR_FALSE;
+ for (unsigned int j = 0; j < numCiphers; j++) {
+ if (ss->cipherSuites[i].cipher_suite ==
+ tmpSuiteCfg[j].cipher_suite) {
+ received = PR_TRUE;
+ break;
+ }
+ }
+ if (!received) {
+ tmpSuiteCfg[cfgIdx] = ss->cipherSuites[i];
+ tmpSuiteCfg[cfgIdx++].enabled = PR_FALSE;
+ }
+ }
+ PORT_Assert(cfgIdx == ssl_V3_SUITES_IMPLEMENTED);
+ /* now we can rewrite the socket with the desired order */
+ PORT_Memcpy(ss->cipherSuites, tmpSuiteCfg, sizeof(tmpSuiteCfg));
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+ return SECSuccess;
+}
+
SECStatus
NSS_SetDomesticPolicy(void)
{
@@ -2200,6 +2354,8 @@ SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd)
ss->opt = sm->opt;
ss->vrange = sm->vrange;
+ ss->now = sm->now;
+ ss->nowArg = sm->nowArg;
PORT_Memcpy(ss->cipherSuites, sm->cipherSuites, sizeof sm->cipherSuites);
PORT_Memcpy(ss->ssl3.dtlsSRTPCiphers, sm->ssl3.dtlsSRTPCiphers,
sizeof(PRUint16) * sm->ssl3.dtlsSRTPCipherCount);
@@ -2273,6 +2429,29 @@ 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) {
+ return NULL;
+ }
+ }
+
+ /* Copy anti-replay context. */
+ if (ss->antiReplay) {
+ tls13_ReleaseAntiReplayContext(ss->antiReplay);
+ ss->antiReplay = NULL;
+ }
+ if (sm->antiReplay) {
+ ss->antiReplay = tls13_RefAntiReplayContext(sm->antiReplay);
+ PORT_Assert(ss->antiReplay);
+ if (!ss->antiReplay) {
+ return NULL;
+ }
+ }
+
if (sm->authCertificate)
ss->authCertificate = sm->authCertificate;
if (sm->authCertificateArg)
@@ -3644,6 +3823,7 @@ ssl_SetDefaultsFromEnvironment(void)
char *ev;
firsttime = 0;
#ifdef DEBUG
+ ssl_trace_iob = NULL;
ev = PR_GetEnvSecure("SSLDEBUGFILE");
if (ev && ev[0]) {
ssl_trace_iob = fopen(ev, "w");
@@ -3665,6 +3845,7 @@ ssl_SetDefaultsFromEnvironment(void)
}
#endif /* DEBUG */
#ifdef NSS_ALLOW_SSLKEYLOGFILE
+ ssl_keylog_iob = NULL;
ev = PR_GetEnvSecure("SSLKEYLOGFILE");
if (ev && ev[0]) {
ssl_keylog_iob = fopen(ev, "a");
@@ -3885,6 +4066,15 @@ ssl_FreeEphemeralKeyPairs(sslSocket *ss)
}
}
+PRTime
+ssl_Time(const sslSocket *ss)
+{
+ if (!ss->now) {
+ return PR_Now();
+ }
+ return ss->now(ss->nowArg);
+}
+
/*
** Create a newsocket structure for a file descriptor.
*/
@@ -3900,7 +4090,7 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant)
makeLocks = PR_TRUE;
/* Make a new socket and get it ready */
- ss = (sslSocket *)PORT_ZAlloc(sizeof(sslSocket));
+ ss = PORT_ZNew(sslSocket);
if (!ss) {
return NULL;
}
@@ -3958,6 +4148,7 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant)
dtls_InitTimers(ss);
ss->esniKeys = NULL;
+ ss->antiReplay = NULL;
if (makeLocks) {
rv = ssl_MakeLocks(ss);
@@ -4024,20 +4215,38 @@ struct {
void *function;
} ssl_experimental_functions[] = {
#ifndef SSL_DISABLE_EXPERIMENTAL_API
+ EXP(AeadDecrypt),
+ EXP(AeadEncrypt),
+ EXP(CipherSuiteOrderGet),
+ EXP(CipherSuiteOrderSet),
+ EXP(CreateAntiReplayContext),
+ EXP(DelegateCredential),
+ EXP(DestroyAead),
+ EXP(DestroyResumptionTokenInfo),
+ EXP(EnableESNI),
+ EXP(EncodeESNIKeys),
+ EXP(GetCurrentEpoch),
EXP(GetExtensionSupport),
+ EXP(GetResumptionTokenInfo),
EXP(HelloRetryRequestCallback),
EXP(InstallExtensionHooks),
+ EXP(HkdfExtract),
+ EXP(HkdfExpandLabel),
+ EXP(HkdfExpandLabelWithMech),
EXP(KeyUpdate),
+ EXP(MakeAead),
+ EXP(RecordLayerData),
+ EXP(RecordLayerWriteCallback),
+ EXP(ReleaseAntiReplayContext),
+ EXP(SecretCallback),
+ EXP(SendCertificateRequest),
EXP(SendSessionTicket),
+ EXP(SetAntiReplayContext),
+ EXP(SetESNIKeyPair),
EXP(SetMaxEarlyDataSize),
- EXP(SetupAntiReplay),
EXP(SetResumptionTokenCallback),
EXP(SetResumptionToken),
- EXP(GetResumptionTokenInfo),
- EXP(DestroyResumptionTokenInfo),
- EXP(SetESNIKeyPair),
- EXP(EncodeESNIKeys),
- EXP(EnableESNI),
+ EXP(SetTimeFunc),
#endif
{ "", NULL }
};
@@ -4073,6 +4282,21 @@ ssl_ClearPRCList(PRCList *list, void (*f)(void *))
}
}
+SECStatus
+SSLExp_SetTimeFunc(PRFileDesc *fd, SSLTimeFunc f, void *arg)
+{
+ sslSocket *ss = ssl_FindSocket(fd);
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetTimeFunc",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+ ss->now = f;
+ ss->nowArg = arg;
+ return SECSuccess;
+}
+
/* Experimental APIs for session cache handling. */
SECStatus
@@ -4156,7 +4380,7 @@ SSLExp_SetResumptionToken(PRFileDesc *fd, const PRUint8 *token,
/* Use the sid->cached as marker that this is from an external cache and
* we don't have to look up anything in the NSS internal cache. */
sid->cached = in_external_cache;
- sid->lastAccessTime = ssl_TimeSec();
+ sid->lastAccessTime = ssl_Time(ss);
ss->sec.ci.sid = sid;
diff --git a/security/nss/lib/ssl/sslspec.c b/security/nss/lib/ssl/sslspec.c
index f2e72a4ec4..def3c67505 100644
--- a/security/nss/lib/ssl/sslspec.c
+++ b/security/nss/lib/ssl/sslspec.c
@@ -113,7 +113,7 @@ ssl_GetMacDef(const sslSocket *ss, const ssl3CipherSuiteDef *suiteDef)
}
ssl3CipherSpec *
-ssl_FindCipherSpecByEpoch(sslSocket *ss, CipherSpecDirection direction,
+ssl_FindCipherSpecByEpoch(sslSocket *ss, SSLSecretDirection direction,
DTLSEpoch epoch)
{
PRCList *cur_p;
@@ -134,7 +134,7 @@ ssl_FindCipherSpecByEpoch(sslSocket *ss, CipherSpecDirection direction,
}
ssl3CipherSpec *
-ssl_CreateCipherSpec(sslSocket *ss, CipherSpecDirection direction)
+ssl_CreateCipherSpec(sslSocket *ss, SSLSecretDirection direction)
{
ssl3CipherSpec *spec = PORT_ZNew(ssl3CipherSpec);
if (!spec) {
@@ -159,7 +159,7 @@ ssl_SaveCipherSpec(sslSocket *ss, ssl3CipherSpec *spec)
/* Called from ssl3_InitState. */
/* Caller must hold the SpecWriteLock. */
SECStatus
-ssl_SetupNullCipherSpec(sslSocket *ss, CipherSpecDirection dir)
+ssl_SetupNullCipherSpec(sslSocket *ss, SSLSecretDirection dir)
{
ssl3CipherSpec *spec;
@@ -187,7 +187,7 @@ ssl_SetupNullCipherSpec(sslSocket *ss, CipherSpecDirection dir)
dtls_InitRecvdRecords(&spec->recvdRecords);
ssl_SaveCipherSpec(ss, spec);
- if (dir == CipherSpecRead) {
+ if (dir == ssl_secret_read) {
ss->ssl3.crSpec = spec;
} else {
ss->ssl3.cwSpec = spec;
@@ -259,13 +259,13 @@ ssl_DestroyCipherSpecs(PRCList *list)
}
void
-ssl_CipherSpecReleaseByEpoch(sslSocket *ss, CipherSpecDirection dir,
+ssl_CipherSpecReleaseByEpoch(sslSocket *ss, SSLSecretDirection dir,
DTLSEpoch epoch)
{
ssl3CipherSpec *spec;
SSL_TRC(10, ("%d: SSL[%d]: releasing %s cipher spec for epoch %d",
SSL_GETPID(), ss->fd,
- (dir == CipherSpecRead) ? "read" : "write", epoch));
+ (dir == ssl_secret_read) ? "read" : "write", epoch));
spec = ssl_FindCipherSpecByEpoch(ss, dir, epoch);
if (spec) {
diff --git a/security/nss/lib/ssl/sslspec.h b/security/nss/lib/ssl/sslspec.h
index b256017553..ca9ef540fb 100644
--- a/security/nss/lib/ssl/sslspec.h
+++ b/security/nss/lib/ssl/sslspec.h
@@ -19,13 +19,8 @@ typedef enum {
TrafficKeyApplicationData = 3
} TrafficKeyType;
-typedef enum {
- CipherSpecRead,
- CipherSpecWrite,
-} CipherSpecDirection;
-
#define SPEC_DIR(spec) \
- ((spec->direction == CipherSpecRead) ? "read" : "write")
+ ((spec->direction == ssl_secret_read) ? "read" : "write")
typedef struct ssl3CipherSpecStr ssl3CipherSpec;
typedef struct ssl3BulkCipherDefStr ssl3BulkCipherDef;
@@ -106,20 +101,20 @@ typedef struct {
typedef SECStatus (*SSLCipher)(void *context,
unsigned char *out,
- int *outlen,
- int maxout,
+ unsigned int *outlen,
+ unsigned int maxout,
const unsigned char *in,
- int inlen);
+ unsigned int inlen);
typedef SECStatus (*SSLAEADCipher)(
- ssl3KeyMaterial *keys,
+ const ssl3KeyMaterial *keys,
PRBool doDecrypt,
unsigned char *out,
- int *outlen,
- int maxout,
+ unsigned int *outlen,
+ unsigned int maxout,
const unsigned char *in,
- int inlen,
+ unsigned int inlen,
const unsigned char *additionalData,
- int additionalDataLen);
+ unsigned int additionalDataLen);
/* 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
@@ -146,7 +141,7 @@ struct ssl3CipherSpecStr {
PRCList link;
PRUint8 refCt;
- CipherSpecDirection direction;
+ SSLSecretDirection direction;
SSL3ProtocolVersion version;
SSL3ProtocolVersion recordVersion;
@@ -184,17 +179,17 @@ const ssl3BulkCipherDef *ssl_GetBulkCipherDef(const ssl3CipherSuiteDef *cipher_d
const ssl3MACDef *ssl_GetMacDefByAlg(SSL3MACAlgorithm mac);
const ssl3MACDef *ssl_GetMacDef(const sslSocket *ss, const ssl3CipherSuiteDef *suiteDef);
-ssl3CipherSpec *ssl_CreateCipherSpec(sslSocket *ss, CipherSpecDirection direction);
+ssl3CipherSpec *ssl_CreateCipherSpec(sslSocket *ss, SSLSecretDirection direction);
void ssl_SaveCipherSpec(sslSocket *ss, ssl3CipherSpec *spec);
void ssl_CipherSpecAddRef(ssl3CipherSpec *spec);
void ssl_CipherSpecRelease(ssl3CipherSpec *spec);
void ssl_DestroyCipherSpecs(PRCList *list);
-SECStatus ssl_SetupNullCipherSpec(sslSocket *ss, CipherSpecDirection dir);
+SECStatus ssl_SetupNullCipherSpec(sslSocket *ss, SSLSecretDirection dir);
ssl3CipherSpec *ssl_FindCipherSpecByEpoch(sslSocket *ss,
- CipherSpecDirection direction,
+ SSLSecretDirection direction,
DTLSEpoch epoch);
-void ssl_CipherSpecReleaseByEpoch(sslSocket *ss, CipherSpecDirection direction,
+void ssl_CipherSpecReleaseByEpoch(sslSocket *ss, SSLSecretDirection direction,
DTLSEpoch epoch);
#endif /* __sslspec_h_ */
diff --git a/security/nss/lib/ssl/sslt.h b/security/nss/lib/ssl/sslt.h
index bd32a6e180..47efa2e4d0 100644
--- a/security/nss/lib/ssl/sslt.h
+++ b/security/nss/lib/ssl/sslt.h
@@ -9,9 +9,10 @@
#ifndef __sslt_h_
#define __sslt_h_
+#include "certt.h"
+#include "keyhi.h"
#include "prtypes.h"
#include "secitem.h"
-#include "certt.h"
typedef enum {
ssl_hs_hello_request = 0,
@@ -43,6 +44,11 @@ typedef enum {
ssl_ct_ack = 25
} SSLContentType;
+typedef enum {
+ ssl_secret_read = 1,
+ ssl_secret_write = 2,
+} SSLSecretDirection;
+
typedef struct SSL3StatisticsStr {
/* statistics from ssl3_SendClientHello (sch) */
long sch_sid_cache_hits;
@@ -262,6 +268,26 @@ typedef struct SSLExtraServerCertDataStr {
/* A serialized sign_certificate_timestamp extension, used to answer
* requests from clients for this data. */
const SECItem* signedCertTimestamps;
+
+ /* Delegated credentials.
+ *
+ * A serialized delegated credential (DC) to use for authentication to peers
+ * who indicate support for this extension (ietf-drafts-tls-subcerts). DCs
+ * are used opportunistically if (1) the client indicates support, (2) TLS
+ * 1.3 or higher is negotiated, and (3) the selected certificate is
+ * configured with a DC.
+ *
+ * Note that it's the caller's responsibility to ensure that the DC is
+ * well-formed.
+ */
+ const SECItem* delegCred;
+
+ /* The secret key corresponding to the |delegCred|.
+ *
+ * Note that it's the caller's responsibility to ensure that this matches
+ * the DC public key.
+ */
+ const SECKEYPrivateKey* delegCredPrivKey;
} SSLExtraServerCertData;
typedef struct SSLChannelInfoStr {
@@ -273,7 +299,13 @@ typedef struct SSLChannelInfoStr {
PRUint16 protocolVersion;
PRUint16 cipherSuite;
- /* server authentication info */
+ /* The strength of the key used to authenticate the peer. Before
+ * interpreting this value, check authType, signatureScheme, and
+ * peerDelegCred, to determine the type of the key and how it was used.
+ *
+ * Typically, this is the length of the key from the peer's end-entity
+ * certificate. If delegated credentials are used (i.e., peerDelegCred is
+ * PR_TRUE), then this is the strength of the delegated credential key. */
PRUint32 authKeyBits;
/* key exchange algorithm info */
@@ -321,6 +353,11 @@ typedef struct SSLChannelInfoStr {
* otherwise. */
PRBool resumed;
+ /* Indicates whether the peer used a delegated credential (DC) for
+ * authentication.
+ */
+ PRBool peerDelegCred;
+
/* When adding new fields to this structure, please document the
* NSS version in which they were added. */
} SSLChannelInfo;
@@ -328,6 +365,12 @@ typedef struct SSLChannelInfoStr {
/* Preliminary channel info */
#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. */
+#define ssl_preinfo_peer_auth (1U << 3)
+/* 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)
typedef struct SSLPreliminaryChannelInfoStr {
@@ -359,6 +402,23 @@ typedef struct SSLPreliminaryChannelInfoStr {
* resume this session. */
PRUint32 maxEarlyDataSize;
+ /* The following fields were added in NSS 3.43. */
+ /* This reports the cipher suite used for 0-RTT if it sent or accepted. For
+ * a client, this is set earlier than |cipherSuite|, and will match that
+ * value if 0-RTT is accepted by the server. The server only sets this
+ * after accepting 0-RTT, so this will contain the same value. */
+ PRUint16 zeroRttCipherSuite;
+
+ /* The following fields were added in NSS 3.48. */
+ /* These fields contain information about the key that will be used in
+ * the CertificateVerify message. If Delegated Credentials are being used,
+ * this is the DC-contained SPKI, else the EE-cert SPKI. These fields are
+ * valid only after the Certificate message is handled. This can be determined
+ * by checking the valuesSet field against |ssl_preinfo_peer_auth|. */
+ PRBool peerDelegCred;
+ PRUint32 authKeyBits;
+ SSLSignatureScheme signatureScheme;
+
/* When adding new fields to this structure, please document the
* NSS version in which they were added. */
} SSLPreliminaryChannelInfo;
@@ -407,6 +467,12 @@ typedef struct SSLCipherSuiteInfoStr {
* this instead of |authAlgorithm|. */
SSLAuthType authType;
+ /* The following fields were added in NSS 3.43. */
+ /* This reports the hash function used in the TLS KDF, or HKDF for TLS 1.3.
+ * For suites defined for versions of TLS earlier than TLS 1.2, this reports
+ * ssl_hash_none. */
+ SSLHashType kdfHash;
+
/* When adding new fields to this structure, please document the
* NSS version in which they were added. */
} SSLCipherSuiteInfo;
@@ -450,10 +516,12 @@ typedef enum {
ssl_tls13_psk_key_exchange_modes_xtn = 45,
ssl_tls13_ticket_early_data_info_xtn = 46, /* Deprecated. */
ssl_tls13_certificate_authorities_xtn = 47,
+ ssl_tls13_post_handshake_auth_xtn = 49,
ssl_signature_algorithms_cert_xtn = 50,
ssl_tls13_key_share_xtn = 51,
ssl_next_proto_nego_xtn = 13172, /* Deprecated. */
ssl_renegotiation_info_xtn = 0xff01,
+ ssl_delegated_credentials_xtn = 0xff02,
ssl_tls13_short_header_xtn = 0xff03, /* Deprecated. */
ssl_tls13_encrypted_sni_xtn = 0xffce,
} SSLExtensionType;
diff --git a/security/nss/lib/ssl/tls13con.c b/security/nss/lib/ssl/tls13con.c
index 461cd2eb9c..c3528a52f8 100644
--- a/security/nss/lib/ssl/tls13con.c
+++ b/security/nss/lib/ssl/tls13con.c
@@ -24,22 +24,29 @@
#include "tls13esni.h"
#include "tls13exthandle.h"
#include "tls13hashstate.h"
+#include "tls13subcerts.h"
static SECStatus tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch,
- CipherSpecDirection install,
+ SSLSecretDirection install,
PRBool deleteSecret);
-static SECStatus tls13_AESGCM(
- ssl3KeyMaterial *keys,
- PRBool doDecrypt,
- unsigned char *out, int *outlen, int maxout,
- const unsigned char *in, int inlen,
- const unsigned char *additionalData, int additionalDataLen);
-static SECStatus tls13_ChaCha20Poly1305(
- ssl3KeyMaterial *keys,
- PRBool doDecrypt,
- unsigned char *out, int *outlen, int maxout,
- const unsigned char *in, int inlen,
- const unsigned char *additionalData, int additionalDataLen);
+static SECStatus tls13_AESGCM(const ssl3KeyMaterial *keys,
+ PRBool doDecrypt,
+ unsigned char *out,
+ unsigned int *outlen,
+ unsigned int maxout,
+ const unsigned char *in,
+ unsigned int inlen,
+ const unsigned char *additionalData,
+ unsigned int additionalDataLen);
+static SECStatus tls13_ChaCha20Poly1305(const ssl3KeyMaterial *keys,
+ PRBool doDecrypt,
+ unsigned char *out,
+ unsigned int *outlen,
+ unsigned int maxout,
+ const unsigned char *in,
+ unsigned int inlen,
+ const unsigned char *additionalData,
+ unsigned int additionalDataLen);
static SECStatus tls13_SendServerHelloSequence(sslSocket *ss);
static SECStatus tls13_SendEncryptedExtensions(sslSocket *ss);
static void tls13_SetKeyExchangeType(sslSocket *ss, const sslNamedGroupDef *group);
@@ -56,6 +63,7 @@ static SECStatus tls13_SendCertificate(sslSocket *ss);
static SECStatus tls13_HandleCertificate(
sslSocket *ss, PRUint8 *b, PRUint32 length);
static SECStatus tls13_ReinjectHandshakeTranscript(sslSocket *ss);
+static SECStatus tls13_SendCertificateRequest(sslSocket *ss);
static SECStatus tls13_HandleCertificateRequest(sslSocket *ss, PRUint8 *b,
PRUint32 length);
static SECStatus
@@ -104,6 +112,9 @@ static SECStatus tls13_ComputeFinished(
PRBool sending, PRUint8 *output, unsigned int *outputLen,
unsigned int maxOutputLen);
static SECStatus tls13_SendClientSecondRound(sslSocket *ss);
+static SECStatus tls13_SendClientSecondFlight(sslSocket *ss,
+ PRBool sendClientCert,
+ SSL3AlertDescription *sendAlert);
static SECStatus tls13_FinishHandshake(sslSocket *ss);
const char kHkdfLabelClient[] = "c";
@@ -249,6 +260,12 @@ tls13_CheckHsState(sslSocket *ss, int err, const char *error_name,
return SECFailure;
}
+PRBool
+tls13_IsPostHandshake(const sslSocket *ss)
+{
+ return ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 && ss->firstHsDone;
+}
+
SSLHashType
tls13_GetHashForCipherSuite(ssl3CipherSuite suite)
{
@@ -289,7 +306,7 @@ tls13_GetHashSize(const sslSocket *ss)
return tls13_GetHashSizeForHash(tls13_GetHash(ss));
}
-static CK_MECHANISM_TYPE
+CK_MECHANISM_TYPE
tls13_GetHkdfMechanismForHash(SSLHashType hash)
{
switch (hash) {
@@ -406,7 +423,7 @@ SSL_SendAdditionalKeyShares(PRFileDesc *fd, unsigned int count)
* Called from ssl3_SendClientHello.
*/
SECStatus
-tls13_SetupClientHello(sslSocket *ss)
+tls13_SetupClientHello(sslSocket *ss, sslClientHelloType chType)
{
unsigned int i;
SSL3Statistics *ssl3stats = SSL_GetStatistics();
@@ -417,17 +434,24 @@ tls13_SetupClientHello(sslSocket *ss)
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
- PORT_Assert(PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs));
- /* Do encrypted SNI. This may create a key share as a side effect. */
+ /* Do encrypted SNI.
+ * Note: this makes a new key even though we don't need one.
+ * Maybe remove this in future for efficiency. */
rv = tls13_ClientSetupESNI(ss);
if (rv != SECSuccess) {
return SECFailure;
}
+ /* Everything below here is only run on the first CH. */
+ if (chType != client_hello_initial) {
+ return SECSuccess;
+ }
+
/* Select the first enabled group.
* TODO(ekr@rtfm.com): be smarter about offering the group
* that the other side negotiated if we are resuming. */
+ PORT_Assert(PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs));
for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
if (!ss->namedGroupPreferences[i]) {
continue;
@@ -456,7 +480,7 @@ tls13_SetupClientHello(sslSocket *ss)
session_ticket = &sid->u.ssl3.locked.sessionTicket;
PORT_Assert(session_ticket && session_ticket->ticket.data);
- if (ssl_TicketTimeValid(session_ticket)) {
+ if (ssl_TicketTimeValid(ss, session_ticket)) {
ss->statelessResume = PR_TRUE;
}
@@ -588,13 +612,13 @@ loser:
}
static PRBool
-tls13_UseServerSecret(sslSocket *ss, CipherSpecDirection direction)
+tls13_UseServerSecret(sslSocket *ss, SSLSecretDirection direction)
{
- return ss->sec.isServer == (direction == CipherSpecWrite);
+ return ss->sec.isServer == (direction == ssl_secret_write);
}
static PK11SymKey **
-tls13_TrafficSecretRef(sslSocket *ss, CipherSpecDirection direction)
+tls13_TrafficSecretRef(sslSocket *ss, SSLSecretDirection direction)
{
if (tls13_UseServerSecret(ss, direction)) {
return &ss->ssl3.hs.serverTrafficSecret;
@@ -603,7 +627,7 @@ tls13_TrafficSecretRef(sslSocket *ss, CipherSpecDirection direction)
}
SECStatus
-tls13_UpdateTrafficKeys(sslSocket *ss, CipherSpecDirection direction)
+tls13_UpdateTrafficKeys(sslSocket *ss, SSLSecretDirection direction)
{
PK11SymKey **secret;
PK11SymKey *updatedSecret;
@@ -626,7 +650,7 @@ tls13_UpdateTrafficKeys(sslSocket *ss, CipherSpecDirection direction)
*secret = updatedSecret;
ssl_GetSpecReadLock(ss);
- if (direction == CipherSpecRead) {
+ if (direction == ssl_secret_read) {
epoch = ss->ssl3.crSpec->epoch;
} else {
epoch = ss->ssl3.cwSpec->epoch;
@@ -640,6 +664,11 @@ tls13_UpdateTrafficKeys(sslSocket *ss, CipherSpecDirection direction)
}
++epoch;
+ if (ss->secretCallback) {
+ ss->secretCallback(ss->fd, epoch, direction, updatedSecret,
+ ss->secretCallbackArg);
+ }
+
rv = tls13_SetCipherSpec(ss, epoch, direction, PR_FALSE);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
@@ -660,8 +689,9 @@ tls13_SendKeyUpdate(sslSocket *ss, tls13KeyUpdateRequest request, PRBool buffer)
: "not requested"));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+ PORT_Assert(!ss->sec.isServer || !ss->ssl3.clientCertRequested);
- if (!ss->firstHsDone) {
+ if (!tls13_IsPostHandshake(ss)) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
@@ -698,7 +728,7 @@ tls13_SendKeyUpdate(sslSocket *ss, tls13KeyUpdateRequest request, PRBool buffer)
}
ssl_ReleaseXmitBufLock(ss);
- rv = tls13_UpdateTrafficKeys(ss, CipherSpecWrite);
+ rv = tls13_UpdateTrafficKeys(ss, ssl_secret_write);
if (rv != SECSuccess) {
goto loser; /* error code set by tls13_UpdateTrafficKeys */
}
@@ -719,11 +749,16 @@ SSLExp_KeyUpdate(PRFileDesc *fd, PRBool requestUpdate)
return SECFailure;
}
- if (!ss->firstHsDone) {
+ if (!tls13_IsPostHandshake(ss)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
+ if (ss->ssl3.clientCertRequested) {
+ PORT_SetError(PR_WOULD_BLOCK_ERROR);
+ return SECFailure;
+ }
+
rv = TLS13_CHECK_HS_STATE(ss, SEC_ERROR_INVALID_ARGS,
idle_handshake);
if (rv != SECSuccess) {
@@ -763,8 +798,7 @@ tls13_HandleKeyUpdate(sslSocket *ss, PRUint8 *b, unsigned int length)
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
- PORT_Assert(ss->firstHsDone);
- if (!ss->firstHsDone) {
+ if (!tls13_IsPostHandshake(ss)) {
FATAL_ERROR(ss, SSL_ERROR_RX_UNEXPECTED_KEY_UPDATE, unexpected_message);
return SECFailure;
}
@@ -791,14 +825,19 @@ tls13_HandleKeyUpdate(sslSocket *ss, PRUint8 *b, unsigned int length)
return SECFailure;
}
- rv = tls13_UpdateTrafficKeys(ss, CipherSpecRead);
+ rv = tls13_UpdateTrafficKeys(ss, ssl_secret_read);
if (rv != SECSuccess) {
return SECFailure; /* Error code set by tls13_UpdateTrafficKeys. */
}
if (update == update_requested) {
PRBool sendUpdate;
- if (ss->ssl3.peerRequestedKeyUpdate) {
+ if (ss->ssl3.clientCertRequested) {
+ /* Post-handshake auth is in progress; defer sending a key update. */
+ ss->ssl3.keyUpdateDeferred = PR_TRUE;
+ ss->ssl3.deferredKeyUpdateRequest = update_not_requested;
+ sendUpdate = PR_FALSE;
+ } else if (ss->ssl3.peerRequestedKeyUpdate) {
/* Only send an update if we have sent with the current spec. This
* prevents us from being forced to crank forward pointlessly. */
ssl_GetSpecReadLock(ss);
@@ -821,10 +860,60 @@ tls13_HandleKeyUpdate(sslSocket *ss, PRUint8 *b, unsigned int length)
}
SECStatus
+SSLExp_SendCertificateRequest(PRFileDesc *fd)
+{
+ SECStatus rv;
+ sslSocket *ss = ssl_FindSocket(fd);
+ if (!ss) {
+ return SECFailure;
+ }
+
+ /* Not supported. */
+ if (IS_DTLS(ss)) {
+ PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION);
+ return SECFailure;
+ }
+
+ if (!tls13_IsPostHandshake(ss)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (ss->ssl3.clientCertRequested) {
+ PORT_SetError(PR_WOULD_BLOCK_ERROR);
+ return SECFailure;
+ }
+
+ rv = TLS13_CHECK_HS_STATE(ss, SEC_ERROR_INVALID_ARGS,
+ idle_handshake);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ if (!ssl3_ExtensionNegotiated(ss, ssl_tls13_post_handshake_auth_xtn)) {
+ PORT_SetError(SSL_ERROR_MISSING_POST_HANDSHAKE_AUTH_EXTENSION);
+ return SECFailure;
+ }
+
+ ssl_GetSSL3HandshakeLock(ss);
+
+ rv = tls13_SendCertificateRequest(ss);
+ if (rv == SECSuccess) {
+ ssl_GetXmitBufLock(ss);
+ rv = ssl3_FlushHandshake(ss, 0);
+ ssl_ReleaseXmitBufLock(ss);
+ ss->ssl3.clientCertRequested = PR_TRUE;
+ }
+
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ return rv;
+}
+
+SECStatus
tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length)
{
if (ss->sec.isServer && ss->ssl3.hs.zeroRttIgnore != ssl_0rtt_ignore_none) {
- SSL_TRC(3, ("%d: TLS13[%d]: %s successfully decrypted handshake after"
+ SSL_TRC(3, ("%d: TLS13[%d]: successfully decrypted handshake after "
"failed 0-RTT",
SSL_GETPID(), ss->fd));
ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_none;
@@ -909,13 +998,13 @@ tls13_RecoverWrappedSharedSecret(sslSocket *ss, sslSessionID *sid)
wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len;
/* unwrap the "master secret" which is actually RMS. */
- ss->ssl3.hs.resumptionMasterSecret = PK11_UnwrapSymKeyWithFlags(
+ ss->ssl3.hs.resumptionMasterSecret = ssl_unwrapSymKey(
wrapKey, sid->u.ssl3.masterWrapMech,
NULL, &wrappedMS,
CKM_SSL3_MASTER_KEY_DERIVE,
CKA_DERIVE,
tls13_GetHashSizeForHash(hashType),
- CKF_SIGN | CKF_VERIFY);
+ CKF_SIGN | CKF_VERIFY, ss->pkcs11PinArg);
PK11_FreeSymKey(wrapKey);
if (!ss->ssl3.hs.resumptionMasterSecret) {
return SECFailure;
@@ -1030,6 +1119,13 @@ tls13_DeriveEarlySecrets(sslSocket *ss)
return SECFailure;
}
+ if (ss->secretCallback) {
+ ss->secretCallback(ss->fd, (PRUint16)TrafficKeyEarlyApplicationData,
+ ss->sec.isServer ? ssl_secret_read : ssl_secret_write,
+ ss->ssl3.hs.clientEarlyTrafficSecret,
+ ss->secretCallbackArg);
+ }
+
rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret,
NULL, kHkdfLabelEarlyExporterSecret,
keylogLabelEarlyExporterSecret,
@@ -1098,6 +1194,18 @@ tls13_ComputeHandshakeSecrets(sslSocket *ss)
return rv;
}
+ if (ss->secretCallback) {
+ SSLSecretDirection dir =
+ ss->sec.isServer ? ssl_secret_read : ssl_secret_write;
+ ss->secretCallback(ss->fd, (PRUint16)TrafficKeyHandshake, dir,
+ ss->ssl3.hs.clientHsTrafficSecret,
+ ss->secretCallbackArg);
+ dir = ss->sec.isServer ? ssl_secret_write : ssl_secret_read;
+ ss->secretCallback(ss->fd, (PRUint16)TrafficKeyHandshake, dir,
+ ss->ssl3.hs.serverHsTrafficSecret,
+ ss->secretCallbackArg);
+ }
+
SSL_TRC(5, ("%d: TLS13[%d]: compute master secret (%s)",
SSL_GETPID(), ss->fd, SSL_ROLE(ss)));
@@ -1148,6 +1256,18 @@ tls13_ComputeApplicationSecrets(sslSocket *ss)
return SECFailure;
}
+ if (ss->secretCallback) {
+ SSLSecretDirection dir =
+ ss->sec.isServer ? ssl_secret_read : ssl_secret_write;
+ ss->secretCallback(ss->fd, (PRUint16)TrafficKeyApplicationData,
+ dir, ss->ssl3.hs.clientTrafficSecret,
+ ss->secretCallbackArg);
+ dir = ss->sec.isServer ? ssl_secret_write : ssl_secret_read;
+ ss->secretCallback(ss->fd, (PRUint16)TrafficKeyApplicationData,
+ dir, ss->ssl3.hs.serverTrafficSecret,
+ ss->secretCallbackArg);
+ }
+
rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret,
NULL, kHkdfLabelExporterMasterSecret,
keylogLabelExporterSecret,
@@ -1271,29 +1391,34 @@ tls13_NegotiateZeroRtt(sslSocket *ss, const sslSessionID *sid)
return;
}
- /* If we rejected 0-RTT on the first ClientHello, then we can just say that
- * there is no 0-RTT for the second. We shouldn't get any more. Reset the
- * ignore state so that we treat decryption failure normally. */
- if (ss->ssl3.hs.zeroRttIgnore == ssl_0rtt_ignore_hrr) {
- PORT_Assert(ss->ssl3.hs.helloRetry);
- ss->ssl3.hs.zeroRttState = ssl_0rtt_none;
- ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_none;
+ if (ss->ssl3.hs.zeroRttState == ssl_0rtt_ignored) {
+ /* HelloRetryRequest causes 0-RTT to be ignored. On the second
+ * ClientHello, reset the ignore state so that decryption failure is
+ * handled normally. */
+ if (ss->ssl3.hs.zeroRttIgnore == ssl_0rtt_ignore_hrr) {
+ PORT_Assert(ss->ssl3.hs.helloRetry);
+ ss->ssl3.hs.zeroRttState = ssl_0rtt_none;
+ ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_none;
+ } else {
+ SSL_TRC(3, ("%d: TLS13[%d]: application ignored 0-RTT",
+ SSL_GETPID(), ss->fd));
+ }
return;
}
if (!tls13_CanNegotiateZeroRtt(ss, sid)) {
- SSL_TRC(3, ("%d: TLS13[%d]: ignore 0-RTT",
- SSL_GETPID(), ss->fd));
+ SSL_TRC(3, ("%d: TLS13[%d]: ignore 0-RTT", SSL_GETPID(), ss->fd));
ss->ssl3.hs.zeroRttState = ssl_0rtt_ignored;
ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_trial;
return;
}
- SSL_TRC(3, ("%d: TLS13[%d]: enable 0-RTT",
- SSL_GETPID(), ss->fd));
+ SSL_TRC(3, ("%d: TLS13[%d]: enable 0-RTT", SSL_GETPID(), ss->fd));
PORT_Assert(ss->statelessResume);
ss->ssl3.hs.zeroRttState = ssl_0rtt_accepted;
ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_none;
+ ss->ssl3.hs.zeroRttSuite = ss->ssl3.hs.cipher_suite;
+ ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_0rtt_cipher_suite;
}
/* Check if the offered group is acceptable. */
@@ -1464,6 +1589,20 @@ tls13_SelectServerCert(sslSocket *ss)
if (rv == SECSuccess) {
/* Found one. */
ss->sec.serverCert = cert;
+
+ /* If we can use a delegated credential (DC) for authentication in
+ * the current handshake, then commit to using it now. We'll send a
+ * DC as an extension and use the DC private key to sign the
+ * handshake.
+ *
+ * This sets the signature scheme to be the signature scheme
+ * indicated by the DC.
+ */
+ rv = tls13_MaybeSetDelegatedCredential(ss);
+ if (rv != SECSuccess) {
+ return SECFailure; /* Failure indicates an internal error. */
+ }
+
ss->sec.authType = ss->ssl3.hs.kea_def_mutable.authKeyType =
ssl_SignatureSchemeToAuthType(ss->ssl3.hs.signatureScheme);
ss->sec.authKeyBits = cert->serverKeyBits;
@@ -1519,6 +1658,11 @@ tls13_MaybeSendHelloRetry(sslSocket *ss, const sslNamedGroupDef *requestedGroup,
return SECFailure;
}
+ if (action == ssl_hello_retry_reject_0rtt) {
+ ss->ssl3.hs.zeroRttState = ssl_0rtt_ignored;
+ ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_trial;
+ }
+
if (!requestedGroup && action != ssl_hello_retry_request) {
return SECSuccess;
}
@@ -1573,24 +1717,23 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
const sslNamedGroupDef *previousGroup = NULL;
PRBool hrr = PR_FALSE;
+ /* If the legacy_version field is set to 0x300 or smaller,
+ * reject the connection with protocol_version alert. */
+ if (ss->clientHelloVersion <= SSL_LIBRARY_VERSION_3_0) {
+ FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, protocol_version);
+ goto loser;
+ }
+
ss->ssl3.hs.endOfFlight = PR_TRUE;
if (ssl3_ExtensionNegotiated(ss, ssl_tls13_early_data_xtn)) {
ss->ssl3.hs.zeroRttState = ssl_0rtt_sent;
}
-#ifndef PARANOID
- /* Look for a matching cipher suite. */
- if (ssl3_config_match_init(ss) == 0) { /* no ciphers are working/supported by PK11 */
- FATAL_ERROR(ss, PORT_GetError(), internal_error);
- goto loser;
- }
-#endif
-
/* Negotiate cipher suite. */
rv = ssl3_NegotiateCipherSuite(ss, suites, PR_FALSE);
if (rv != SECSuccess) {
- FATAL_ERROR(ss, SSL_ERROR_NO_CYPHER_OVERLAP, handshake_failure);
+ FATAL_ERROR(ss, PORT_GetError(), handshake_failure);
goto loser;
}
@@ -2083,10 +2226,20 @@ tls13_SendCertificateRequest(sslSocket *ss)
{
SECStatus rv;
sslBuffer extensionBuf = SSL_BUFFER_EMPTY;
+ unsigned int offset = 0;
SSL_TRC(3, ("%d: TLS13[%d]: begin send certificate_request",
SSL_GETPID(), ss->fd));
+ if (ss->firstHsDone) {
+ PORT_Assert(ss->ssl3.hs.shaPostHandshake == NULL);
+ ss->ssl3.hs.shaPostHandshake = PK11_CloneContext(ss->ssl3.hs.sha);
+ if (ss->ssl3.hs.shaPostHandshake == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
+ return SECFailure;
+ }
+ }
+
rv = ssl_ConstructExtensions(ss, &extensionBuf, ssl_hs_certificate_request);
if (rv != SECSuccess) {
return SECFailure; /* Code already set. */
@@ -2094,8 +2247,29 @@ tls13_SendCertificateRequest(sslSocket *ss)
/* We should always have at least one of these. */
PORT_Assert(SSL_BUFFER_LEN(&extensionBuf) > 0);
+ /* Create a new request context for post-handshake authentication */
+ if (ss->firstHsDone) {
+ PRUint8 context[16];
+ SECItem contextItem = { siBuffer, context, sizeof(context) };
+
+ rv = PK11_GenerateRandom(context, sizeof(context));
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ SECITEM_FreeItem(&ss->xtnData.certReqContext, PR_FALSE);
+ rv = SECITEM_CopyItem(NULL, &ss->xtnData.certReqContext, &contextItem);
+ if (rv != SECSuccess) {
+ FATAL_ERROR(ss, SEC_ERROR_NO_MEMORY, internal_error);
+ goto loser;
+ }
+
+ offset = SSL_BUFFER_LEN(&ss->sec.ci.sendBuf);
+ }
+
rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate_request,
- 1 + 0 + /* empty request context */
+ 1 + /* request context length */
+ ss->xtnData.certReqContext.len +
2 + /* extension length */
SSL_BUFFER_LEN(&extensionBuf));
if (rv != SECSuccess) {
@@ -2103,7 +2277,8 @@ tls13_SendCertificateRequest(sslSocket *ss)
}
/* Context. */
- rv = ssl3_AppendHandshakeNumber(ss, 0, 1);
+ rv = ssl3_AppendHandshakeVariable(ss, ss->xtnData.certReqContext.data,
+ ss->xtnData.certReqContext.len, 1);
if (rv != SECSuccess) {
goto loser; /* err set by AppendHandshake. */
}
@@ -2113,6 +2288,15 @@ tls13_SendCertificateRequest(sslSocket *ss)
goto loser; /* err set by AppendHandshake. */
}
+ if (ss->firstHsDone) {
+ rv = ssl3_UpdatePostHandshakeHashes(ss,
+ SSL_BUFFER_BASE(&ss->sec.ci.sendBuf) + offset,
+ SSL_BUFFER_LEN(&ss->sec.ci.sendBuf) - offset);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+
sslBuffer_Clear(&extensionBuf);
return SECSuccess;
@@ -2191,7 +2375,7 @@ tls13_HandleHelloRetryRequest(sslSocket *ss, const PRUint8 *savedMsg,
/* Restore the null cipher spec for writing. */
ssl_GetSpecWriteLock(ss);
ssl_CipherSpecRelease(ss->ssl3.cwSpec);
- ss->ssl3.cwSpec = ssl_FindCipherSpecByEpoch(ss, CipherSpecWrite,
+ ss->ssl3.cwSpec = ssl_FindCipherSpecByEpoch(ss, ssl_secret_write,
TrafficKeyClearText);
PORT_Assert(ss->ssl3.cwSpec);
ssl_ReleaseSpecWriteLock(ss);
@@ -2267,25 +2451,61 @@ tls13_HandleCertificateRequest(sslSocket *ss, PRUint8 *b, PRUint32 length)
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
/* Client */
- rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST,
- wait_cert_request);
+ if (ss->opt.enablePostHandshakeAuth) {
+ rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST,
+ wait_cert_request, idle_handshake);
+ } else {
+ rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST,
+ wait_cert_request);
+ }
if (rv != SECSuccess) {
return SECFailure;
}
- PORT_Assert(ss->ssl3.clientCertChain == NULL);
- PORT_Assert(ss->ssl3.clientCertificate == NULL);
- PORT_Assert(ss->ssl3.clientPrivateKey == NULL);
- PORT_Assert(!ss->ssl3.hs.clientCertRequested);
+ if (tls13_IsPostHandshake(ss)) {
+ PORT_Assert(ss->ssl3.hs.shaPostHandshake == NULL);
+ ss->ssl3.hs.shaPostHandshake = PK11_CloneContext(ss->ssl3.hs.sha);
+ if (ss->ssl3.hs.shaPostHandshake == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
+ return SECFailure;
+ }
+ rv = ssl_HashPostHandshakeMessage(ss, ssl_hs_certificate_request, b, length);
+ if (rv != SECSuccess) {
+ FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+ return SECFailure;
+ }
+
+ /* clean up anything left from previous handshake. */
+ if (ss->ssl3.clientCertChain != NULL) {
+ CERT_DestroyCertificateList(ss->ssl3.clientCertChain);
+ ss->ssl3.clientCertChain = NULL;
+ }
+ if (ss->ssl3.clientCertificate != NULL) {
+ CERT_DestroyCertificate(ss->ssl3.clientCertificate);
+ ss->ssl3.clientCertificate = NULL;
+ }
+ if (ss->ssl3.clientPrivateKey != NULL) {
+ SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
+ ss->ssl3.clientPrivateKey = NULL;
+ }
+ SECITEM_FreeItem(&ss->xtnData.certReqContext, PR_FALSE);
+ ss->xtnData.certReqContext.data = NULL;
+ } else {
+ PORT_Assert(ss->ssl3.clientCertChain == NULL);
+ PORT_Assert(ss->ssl3.clientCertificate == NULL);
+ PORT_Assert(ss->ssl3.clientPrivateKey == NULL);
+ PORT_Assert(!ss->ssl3.hs.clientCertRequested);
+ PORT_Assert(ss->xtnData.certReqContext.data == NULL);
+ }
rv = ssl3_ConsumeHandshakeVariable(ss, &context, 1, &b, &length);
if (rv != SECSuccess) {
return SECFailure;
}
- /* We don't support post-handshake client auth, the certificate request
- * context must always be empty. */
- if (context.len > 0) {
+ /* Unless it is a post-handshake client auth, the certificate
+ * request context must be empty. */
+ if (!tls13_IsPostHandshake(ss) && context.len > 0) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST, illegal_parameter);
return SECFailure;
}
@@ -2319,7 +2539,38 @@ tls13_HandleCertificateRequest(sslSocket *ss, PRUint8 *b, PRUint32 length)
}
ss->ssl3.hs.clientCertRequested = PR_TRUE;
- TLS13_SET_HS_STATE(ss, wait_server_cert);
+
+ if (ss->firstHsDone) {
+ SSL3AlertDescription sendAlert = no_alert;
+
+ /* Request a client certificate. */
+ rv = ssl3_CompleteHandleCertificateRequest(
+ ss, ss->xtnData.sigSchemes, ss->xtnData.numSigSchemes,
+ &ss->xtnData.certReqAuthorities);
+ if (rv != SECSuccess) {
+ FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+ return rv;
+ }
+
+ ssl_GetXmitBufLock(ss);
+ rv = tls13_SendClientSecondFlight(ss, !ss->ssl3.sendEmptyCert,
+ &sendAlert);
+ ssl_ReleaseXmitBufLock(ss);
+ if (rv != SECSuccess) {
+ if (sendAlert != no_alert) {
+ FATAL_ERROR(ss, PORT_GetError(), sendAlert);
+ } else {
+ LOG_ERROR(ss, PORT_GetError());
+ }
+ return SECFailure;
+ }
+ PORT_Assert(ss->ssl3.hs.ws == idle_handshake);
+ PORT_Assert(ss->ssl3.hs.shaPostHandshake != NULL);
+ PK11_DestroyContext(ss->ssl3.hs.shaPostHandshake, PR_TRUE);
+ ss->ssl3.hs.shaPostHandshake = NULL;
+ } else {
+ TLS13_SET_HS_STATE(ss, wait_server_cert);
+ }
return SECSuccess;
}
@@ -2341,7 +2592,7 @@ tls13_SendEncryptedServerSequence(sslSocket *ss)
}
rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
- CipherSpecWrite, PR_FALSE);
+ ssl_secret_write, PR_FALSE);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
@@ -2375,7 +2626,14 @@ tls13_SendEncryptedServerSequence(sslSocket *ss)
return SECFailure; /* error code is set. */
}
- svrPrivKey = ss->sec.serverCert->serverKeyPair->privKey;
+ if (tls13_IsSigningWithDelegatedCredential(ss)) {
+ SSL_TRC(3, ("%d: TLS13[%d]: Signing with delegated credential",
+ SSL_GETPID(), ss->fd));
+ svrPrivKey = ss->sec.serverCert->delegCredKeyPair->privKey;
+ } else {
+ svrPrivKey = ss->sec.serverCert->serverKeyPair->privKey;
+ }
+
rv = tls13_SendCertificateVerify(ss, svrPrivKey);
if (rv != SECSuccess) {
return SECFailure; /* err code is set. */
@@ -2451,7 +2709,7 @@ tls13_SendServerHelloSequence(sslSocket *ss)
}
rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData,
- CipherSpecWrite, PR_FALSE);
+ ssl_secret_write, PR_FALSE);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
@@ -2463,7 +2721,7 @@ tls13_SendServerHelloSequence(sslSocket *ss)
}
if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) {
rv = tls13_SetCipherSpec(ss, TrafficKeyEarlyApplicationData,
- CipherSpecRead, PR_TRUE);
+ ssl_secret_read, PR_TRUE);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
@@ -2475,7 +2733,7 @@ tls13_SendServerHelloSequence(sslSocket *ss)
rv = tls13_SetCipherSpec(ss,
TrafficKeyHandshake,
- CipherSpecRead, PR_FALSE);
+ ssl_secret_read, PR_FALSE);
if (rv != SECSuccess) {
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
@@ -2487,7 +2745,7 @@ tls13_SendServerHelloSequence(sslSocket *ss)
}
}
- ss->ssl3.hs.serverHelloTime = ssl_TimeUsec();
+ ss->ssl3.hs.serverHelloTime = ssl_Time(ss);
return SECSuccess;
}
@@ -2584,11 +2842,11 @@ tls13_HandleServerHelloPart2(sslSocket *ss)
/* When we send 0-RTT, we saved the null spec in case we needed it to
* send another ClientHello in response to a HelloRetryRequest. Now
* that we won't be receiving a HelloRetryRequest, release the spec. */
- ssl_CipherSpecReleaseByEpoch(ss, CipherSpecWrite, TrafficKeyClearText);
+ ssl_CipherSpecReleaseByEpoch(ss, ssl_secret_write, TrafficKeyClearText);
}
rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
- CipherSpecRead, PR_FALSE);
+ ssl_secret_read, PR_FALSE);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_INIT_CIPHER_SUITE_FAILURE, internal_error);
return SECFailure;
@@ -2855,8 +3113,13 @@ tls13_HandleCertificate(sslSocket *ss, PRUint8 *b, PRUint32 length)
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
if (ss->sec.isServer) {
- rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERTIFICATE,
- wait_client_cert);
+ if (ss->ssl3.clientCertRequested) {
+ rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERTIFICATE,
+ idle_handshake);
+ } else {
+ rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERTIFICATE,
+ wait_client_cert);
+ }
} else {
rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERTIFICATE,
wait_cert_request, wait_server_cert);
@@ -2866,18 +3129,29 @@ tls13_HandleCertificate(sslSocket *ss, PRUint8 *b, PRUint32 length)
/* We can ignore any other cleartext from the client. */
if (ss->sec.isServer && IS_DTLS(ss)) {
- ssl_CipherSpecReleaseByEpoch(ss, CipherSpecRead, TrafficKeyClearText);
+ ssl_CipherSpecReleaseByEpoch(ss, ssl_secret_read, TrafficKeyClearText);
dtls_ReceivedFirstMessageInFlight(ss);
}
+
+ if (ss->firstHsDone) {
+ rv = ssl_HashPostHandshakeMessage(ss, ssl_hs_certificate, b, length);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ }
+
/* Process the context string */
rv = ssl3_ConsumeHandshakeVariable(ss, &context, 1, &b, &length);
if (rv != SECSuccess)
return SECFailure;
- if (context.len) {
- /* The context string MUST be empty */
- FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERTIFICATE, illegal_parameter);
- return SECFailure;
+ if (ss->ssl3.clientCertRequested) {
+ PORT_Assert(ss->sec.isServer);
+ if (SECITEM_CompareItem(&context, &ss->xtnData.certReqContext) != 0) {
+ FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERTIFICATE, illegal_parameter);
+ return SECFailure;
+ }
}
rv = ssl3_ConsumeHandshakeVariable(ss, &certList, 3, &b, &length);
@@ -3118,6 +3392,25 @@ tls13_DeriveSecretWrap(sslSocket *ss, PK11SymKey *key,
return SECSuccess;
}
+SECStatus
+SSLExp_SecretCallback(PRFileDesc *fd, SSLSecretCallback cb, void *arg)
+{
+ sslSocket *ss = ssl_FindSocket(fd);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SecretCallback",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ ssl_Get1stHandshakeLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+ ss->secretCallback = cb;
+ ss->secretCallbackArg = arg;
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+ return SECSuccess;
+}
+
/* Derive traffic keys for the next cipher spec in the queue. */
static SECStatus
tls13_DeriveTrafficKeys(sslSocket *ss, ssl3CipherSpec *spec,
@@ -3244,7 +3537,7 @@ tls13_SetupPendingCipherSpec(sslSocket *ss, ssl3CipherSpec *spec)
/* We want to keep read cipher specs around longer because
* there are cases where we might get either epoch N or
* epoch N+1. */
- if (IS_DTLS(ss) && spec->direction == CipherSpecRead) {
+ if (IS_DTLS(ss) && spec->direction == ssl_secret_read) {
ssl_CipherSpecAddRef(spec);
}
@@ -3267,7 +3560,7 @@ tls13_SetupPendingCipherSpec(sslSocket *ss, ssl3CipherSpec *spec)
/* The record size limit is reduced by one so that the remainder of the
* record handling code can use the same checks for all versions. */
if (ssl3_ExtensionNegotiated(ss, ssl_record_size_limit_xtn)) {
- spec->recordSizeLimit = ((spec->direction == CipherSpecRead)
+ spec->recordSizeLimit = ((spec->direction == ssl_secret_read)
? ss->opt.recordSizeLimit
: ss->xtnData.recordSizeLimit) -
1;
@@ -3303,7 +3596,7 @@ tls13_SetAlertCipherSpec(sslSocket *ss)
}
rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
- CipherSpecWrite, PR_FALSE);
+ ssl_secret_write, PR_FALSE);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
@@ -3318,7 +3611,7 @@ tls13_SetAlertCipherSpec(sslSocket *ss)
*/
static SECStatus
tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch,
- CipherSpecDirection direction, PRBool deleteSecret)
+ SSLSecretDirection direction, PRBool deleteSecret)
{
TrafficKeyType type;
SECStatus rv;
@@ -3357,7 +3650,7 @@ tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch,
}
/* Now that we've set almost everything up, finally cut over. */
- specp = (direction == CipherSpecRead) ? &ss->ssl3.crSpec : &ss->ssl3.cwSpec;
+ specp = (direction == ssl_secret_read) ? &ss->ssl3.crSpec : &ss->ssl3.cwSpec;
ssl_GetSpecWriteLock(ss);
ssl_CipherSpecRelease(*specp); /* May delete old cipher. */
*specp = spec; /* Overwrite. */
@@ -3366,11 +3659,6 @@ tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch,
SSL_TRC(3, ("%d: TLS13[%d]: %s installed key for epoch=%d (%s) dir=%s",
SSL_GETPID(), ss->fd, SSL_ROLE(ss), spec->epoch,
spec->phase, SPEC_DIR(spec)));
-
- if (ss->ssl3.changedCipherSpecFunc) {
- ss->ssl3.changedCipherSpecFunc(ss->ssl3.changedCipherSpecArg,
- direction == CipherSpecWrite, spec);
- }
return SECSuccess;
loser:
@@ -3410,7 +3698,11 @@ tls13_ComputeHandshakeHashes(sslSocket *ss, SSL3Hashes *hashes)
goto loser;
}
} else {
- ctx = PK11_CloneContext(ss->ssl3.hs.sha);
+ if (ss->firstHsDone) {
+ ctx = PK11_CloneContext(ss->ssl3.hs.shaPostHandshake);
+ } else {
+ ctx = PK11_CloneContext(ss->ssl3.hs.sha);
+ }
if (!ctx) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
return SECFailure;
@@ -3519,7 +3811,7 @@ tls13_DestroyEarlyData(PRCList *list)
* See RFC 5288 and https://tools.ietf.org/html/draft-ietf-tls-chacha20-poly1305-04#section-2
*/
static void
-tls13_WriteNonce(ssl3KeyMaterial *keys,
+tls13_WriteNonce(const ssl3KeyMaterial *keys,
const unsigned char *seqNumBuf, unsigned int seqNumLen,
unsigned char *nonce, unsigned int nonceLen)
{
@@ -3542,41 +3834,35 @@ tls13_WriteNonce(ssl3KeyMaterial *keys,
* a sequence number. In TLS 1.3 there is no additional data so this value is
* just the encoded sequence number.
*/
-static SECStatus
-tls13_AEAD(ssl3KeyMaterial *keys, PRBool doDecrypt,
- unsigned char *out, int *outlen, int maxout,
- const unsigned char *in, int inlen,
+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)
{
- SECStatus rv;
- unsigned int uOutLen = 0;
SECItem param = {
siBuffer, aeadParams, aeadParamLength
};
if (doDecrypt) {
- rv = PK11_Decrypt(keys->key, mechanism, &param,
- out, &uOutLen, maxout, in, inlen);
- } else {
- rv = PK11_Encrypt(keys->key, mechanism, &param,
- out, &uOutLen, maxout, in, inlen);
+ return PK11_Decrypt(keys->key, mechanism, &param,
+ out, outlen, maxout, in, inlen);
}
- *outlen = (int)uOutLen;
-
- return rv;
+ return PK11_Encrypt(keys->key, mechanism, &param,
+ out, outlen, maxout, in, inlen);
}
static SECStatus
-tls13_AESGCM(ssl3KeyMaterial *keys,
+tls13_AESGCM(const ssl3KeyMaterial *keys,
PRBool doDecrypt,
unsigned char *out,
- int *outlen,
- int maxout,
+ unsigned int *outlen,
+ unsigned int maxout,
const unsigned char *in,
- int inlen,
+ unsigned int inlen,
const unsigned char *additionalData,
- int additionalDataLen)
+ unsigned int additionalDataLen)
{
CK_GCM_PARAMS gcmParams;
unsigned char nonce[12];
@@ -3597,11 +3883,11 @@ tls13_AESGCM(ssl3KeyMaterial *keys,
}
static SECStatus
-tls13_ChaCha20Poly1305(ssl3KeyMaterial *keys, PRBool doDecrypt,
- unsigned char *out, int *outlen, int maxout,
- const unsigned char *in, int inlen,
+tls13_ChaCha20Poly1305(const ssl3KeyMaterial *keys, PRBool doDecrypt,
+ unsigned char *out, unsigned int *outlen, unsigned int maxout,
+ const unsigned char *in, unsigned int inlen,
const unsigned char *additionalData,
- int additionalDataLen)
+ unsigned int additionalDataLen)
{
CK_NSS_AEAD_PARAMS aeadParams;
unsigned char nonce[12];
@@ -3847,6 +4133,9 @@ done:
SECStatus
tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length)
{
+ sslDelegatedCredential *dc = ss->xtnData.peerDelegCred;
+ CERTSubjectPublicKeyInfo *spki;
+ SECKEYPublicKey *pubKey = NULL;
SECItem signed_hash = { siBuffer, NULL, 0 };
SECStatus rv;
SSLSignatureScheme sigScheme;
@@ -3870,7 +4159,11 @@ tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length)
return SECFailure;
}
- rv = ssl_HashHandshakeMessage(ss, ssl_hs_certificate_verify, b, length);
+ if (ss->firstHsDone) {
+ rv = ssl_HashPostHandshakeMessage(ss, ssl_hs_certificate_verify, b, length);
+ } else {
+ rv = ssl_HashHandshakeMessage(ss, ssl_hs_certificate_verify, b, length);
+ }
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
@@ -3882,7 +4175,40 @@ tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length)
return SECFailure;
}
- rv = ssl_CheckSignatureSchemeConsistency(ss, sigScheme, ss->sec.peerCert);
+ /* Set the |spki| used to verify the handshake. When verifying with a
+ * delegated credential (DC), this corresponds to the DC public key;
+ * otherwise it correspond to the public key of the peer's end-entity
+ * certificate.
+ */
+ if (tls13_IsVerifyingWithDelegatedCredential(ss)) {
+ /* DelegatedCredential.cred.expected_cert_verify_algorithm is expected
+ * to match CertificateVerify.scheme.
+ * DelegatedCredential.cred.expected_cert_verify_algorithm must also be
+ * the same as was reported in ssl3_AuthCertificate.
+ */
+ if (sigScheme != dc->expectedCertVerifyAlg || sigScheme != ss->sec.signatureScheme) {
+ FATAL_ERROR(ss, SSL_ERROR_DC_CERT_VERIFY_ALG_MISMATCH, illegal_parameter);
+ return SECFailure;
+ }
+
+ /* Verify the DC has three steps: (1) use the peer's end-entity
+ * certificate to verify DelegatedCredential.signature, (2) check that
+ * the certificate has the correct key usage, and (3) check that the DC
+ * hasn't expired.
+ */
+ rv = tls13_VerifyDelegatedCredential(ss, dc);
+ if (rv != SECSuccess) { /* Calls FATAL_ERROR() */
+ return SECFailure;
+ }
+
+ SSL_TRC(3, ("%d: TLS13[%d]: Verifying with delegated credential",
+ SSL_GETPID(), ss->fd));
+ spki = dc->spki;
+ } else {
+ spki = &ss->sec.peerCert->subjectPublicKeyInfo;
+ }
+
+ rv = ssl_CheckSignatureSchemeConsistency(ss, sigScheme, spki);
if (rv != SECSuccess) {
/* Error set already */
FATAL_ERROR(ss, PORT_GetError(), illegal_parameter);
@@ -3907,15 +4233,33 @@ tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length)
return SECFailure;
}
- rv = ssl3_VerifySignedHashes(ss, sigScheme, &tbsHash, &signed_hash);
+ pubKey = SECKEY_ExtractPublicKey(spki);
+ if (pubKey == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
+ return SECFailure;
+ }
+
+ rv = ssl_VerifySignedHashesWithPubKey(ss, pubKey, sigScheme,
+ &tbsHash, &signed_hash);
if (rv != SECSuccess) {
FATAL_ERROR(ss, PORT_GetError(), decrypt_error);
- return SECFailure;
+ goto loser;
}
- /* Set the auth type. */
+ /* Set the auth type and verify it is what we captured in ssl3_AuthCertificate */
if (!ss->sec.isServer) {
ss->sec.authType = ssl_SignatureSchemeToAuthType(sigScheme);
+
+ uint32_t prelimAuthKeyBits = ss->sec.authKeyBits;
+ rv = ssl_SetAuthKeyBits(ss, pubKey);
+ if (rv != SECSuccess) {
+ goto loser; /* Alert sent and code set. */
+ }
+
+ if (prelimAuthKeyBits != ss->sec.authKeyBits) {
+ FATAL_ERROR(ss, SSL_ERROR_DC_CERT_VERIFY_ALG_MISMATCH, illegal_parameter);
+ goto loser;
+ }
}
/* Request a client certificate now if one was requested. */
@@ -3926,13 +4270,17 @@ tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length)
&ss->xtnData.certReqAuthorities);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
- return rv;
+ goto loser;
}
}
+ SECKEY_DestroyPublicKey(pubKey);
TLS13_SET_HS_STATE(ss, wait_finished);
-
return SECSuccess;
+
+loser:
+ SECKEY_DestroyPublicKey(pubKey);
+ return SECFailure;
}
static SECStatus
@@ -4190,7 +4538,11 @@ tls13_CommonHandleFinished(sslSocket *ss, PK11SymKey *key,
return SECFailure;
}
- rv = ssl_HashHandshakeMessage(ss, ssl_hs_finished, b, length);
+ if (ss->firstHsDone) {
+ rv = ssl_HashPostHandshakeMessage(ss, ssl_hs_finished, b, length);
+ } else {
+ rv = ssl_HashHandshakeMessage(ss, ssl_hs_finished, b, length);
+ }
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
@@ -4231,26 +4583,48 @@ tls13_ServerHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length)
SSL_TRC(3, ("%d: TLS13[%d]: server handle finished handshake",
SSL_GETPID(), ss->fd));
- rv = tls13_CommonHandleFinished(ss, ss->ssl3.hs.clientHsTrafficSecret,
+ rv = tls13_CommonHandleFinished(ss,
+ ss->firstHsDone ? ss->ssl3.hs.clientTrafficSecret : ss->ssl3.hs.clientHsTrafficSecret,
b, length);
if (rv != SECSuccess) {
return SECFailure;
}
+ if (ss->firstHsDone) {
+ TLS13_SET_HS_STATE(ss, idle_handshake);
+
+ PORT_Assert(ss->ssl3.hs.shaPostHandshake != NULL);
+ PK11_DestroyContext(ss->ssl3.hs.shaPostHandshake, PR_TRUE);
+ ss->ssl3.hs.shaPostHandshake = NULL;
+
+ ss->ssl3.clientCertRequested = PR_FALSE;
+
+ if (ss->ssl3.keyUpdateDeferred) {
+ rv = tls13_SendKeyUpdate(ss, ss->ssl3.deferredKeyUpdateRequest,
+ PR_FALSE);
+ if (rv != SECSuccess) {
+ return SECFailure; /* error is set. */
+ }
+ ss->ssl3.keyUpdateDeferred = PR_FALSE;
+ }
+
+ return SECSuccess;
+ }
+
if (!tls13_ShouldRequestClientAuth(ss) &&
(ss->ssl3.hs.zeroRttState != ssl_0rtt_done)) {
dtls_ReceivedFirstMessageInFlight(ss);
}
rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData,
- CipherSpecRead, PR_FALSE);
+ ssl_secret_read, PR_FALSE);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
return SECFailure;
}
if (IS_DTLS(ss)) {
- ssl_CipherSpecReleaseByEpoch(ss, CipherSpecRead, TrafficKeyClearText);
+ ssl_CipherSpecReleaseByEpoch(ss, ssl_secret_read, TrafficKeyClearText);
/* We need to keep the handshake cipher spec so we can
* read re-transmitted client Finished. */
rv = dtls_StartTimer(ss, ss->ssl3.hs.hdTimer,
@@ -4266,6 +4640,11 @@ tls13_ServerHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length)
return SECFailure;
}
+ rv = tls13_FinishHandshake(ss);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
ssl_GetXmitBufLock(ss);
if (ss->opt.enableSessionTickets) {
rv = tls13_SendNewSessionTicket(ss, NULL, 0);
@@ -4278,8 +4657,7 @@ tls13_ServerHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length)
}
}
ssl_ReleaseXmitBufLock(ss);
-
- return tls13_FinishHandshake(ss);
+ return SECSuccess;
loser:
ssl_ReleaseXmitBufLock(ss);
@@ -4316,11 +4694,16 @@ tls13_SendClientSecondFlight(sslSocket *ss, PRBool sendClientCert,
SSL3AlertDescription *sendAlert)
{
SECStatus rv;
+ unsigned int offset = 0;
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
*sendAlert = internal_error;
+ if (ss->firstHsDone) {
+ offset = SSL_BUFFER_LEN(&ss->sec.ci.sendBuf);
+ }
+
if (ss->ssl3.sendEmptyCert) {
ss->ssl3.sendEmptyCert = PR_FALSE;
rv = ssl3_SendEmptyCertificate(ss);
@@ -4334,6 +4717,16 @@ tls13_SendClientSecondFlight(sslSocket *ss, PRBool sendClientCert,
return SECFailure; /* error code is set. */
}
}
+
+ if (ss->firstHsDone) {
+ rv = ssl3_UpdatePostHandshakeHashes(ss,
+ SSL_BUFFER_BASE(&ss->sec.ci.sendBuf) + offset,
+ SSL_BUFFER_LEN(&ss->sec.ci.sendBuf) - offset);
+ if (rv != SECSuccess) {
+ return SECFailure; /* error code is set. */
+ }
+ }
+
if (ss->ssl3.hs.clientCertRequested) {
SECITEM_FreeItem(&ss->xtnData.certReqContext, PR_FALSE);
if (ss->xtnData.certReqAuthorities.arena) {
@@ -4346,15 +4739,28 @@ tls13_SendClientSecondFlight(sslSocket *ss, PRBool sendClientCert,
}
if (sendClientCert) {
+ if (ss->firstHsDone) {
+ offset = SSL_BUFFER_LEN(&ss->sec.ci.sendBuf);
+ }
+
rv = tls13_SendCertificateVerify(ss, ss->ssl3.clientPrivateKey);
SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
ss->ssl3.clientPrivateKey = NULL;
if (rv != SECSuccess) {
return SECFailure; /* err is set. */
}
+
+ if (ss->firstHsDone) {
+ rv = ssl3_UpdatePostHandshakeHashes(ss,
+ SSL_BUFFER_BASE(&ss->sec.ci.sendBuf) + offset,
+ SSL_BUFFER_LEN(&ss->sec.ci.sendBuf) - offset);
+ if (rv != SECSuccess) {
+ return SECFailure; /* error is set. */
+ }
+ }
}
- rv = tls13_SendFinished(ss, ss->ssl3.hs.clientHsTrafficSecret);
+ rv = tls13_SendFinished(ss, ss->firstHsDone ? ss->ssl3.hs.clientTrafficSecret : ss->ssl3.hs.clientHsTrafficSecret);
if (rv != SECSuccess) {
return SECFailure; /* err code was set. */
}
@@ -4397,7 +4803,8 @@ tls13_SendClientSecondRound(sslSocket *ss)
" certificate authentication is still pending.",
SSL_GETPID(), ss->fd));
ss->ssl3.hs.restartTarget = tls13_SendClientSecondRound;
- return SECWouldBlock;
+ PORT_SetError(PR_WOULD_BLOCK_ERROR);
+ return SECFailure;
}
rv = tls13_ComputeApplicationSecrets(ss);
@@ -4425,14 +4832,14 @@ tls13_SendClientSecondRound(sslSocket *ss)
}
rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
- CipherSpecWrite, PR_FALSE);
+ ssl_secret_write, PR_FALSE);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_INIT_CIPHER_SUITE_FAILURE, internal_error);
return SECFailure;
}
rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData,
- CipherSpecRead, PR_FALSE);
+ ssl_secret_read, PR_FALSE);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
return SECFailure;
@@ -4450,7 +4857,7 @@ tls13_SendClientSecondRound(sslSocket *ss)
return SECFailure;
}
rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData,
- CipherSpecWrite, PR_FALSE);
+ ssl_secret_write, PR_FALSE);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
@@ -4615,8 +5022,7 @@ SSLExp_SendSessionTicket(PRFileDesc *fd, const PRUint8 *token,
return SECFailure;
}
- if (!ss->sec.isServer || !ss->firstHsDone ||
- ss->version < SSL_LIBRARY_VERSION_TLS_1_3 ||
+ if (!ss->sec.isServer || !tls13_IsPostHandshake(ss) ||
tokenLen > 0xffff) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
@@ -4652,13 +5058,13 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length)
if (rv != SECSuccess) {
return SECFailure;
}
- if (!ss->firstHsDone || ss->sec.isServer) {
+ if (!tls13_IsPostHandshake(ss) || ss->sec.isServer) {
FATAL_ERROR(ss, SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET,
unexpected_message);
return SECFailure;
}
- ticket.received_timestamp = ssl_TimeUsec();
+ ticket.received_timestamp = ssl_Time(ss);
rv = ssl3_ConsumeHandshakeNumber(ss, &ticket.ticket_lifetime_hint, 4, &b,
&length);
if (rv != SECSuccess) {
@@ -4803,12 +5209,14 @@ static const struct {
certificate) },
{ ssl_cert_status_xtn, _M3(client_hello, certificate_request,
certificate) },
+ { ssl_delegated_credentials_xtn, _M2(client_hello, certificate) },
{ ssl_tls13_cookie_xtn, _M2(client_hello, hello_retry_request) },
{ ssl_tls13_certificate_authorities_xtn, _M1(certificate_request) },
{ ssl_tls13_supported_versions_xtn, _M3(client_hello, server_hello,
hello_retry_request) },
{ ssl_record_size_limit_xtn, _M2(client_hello, encrypted_extensions) },
- { ssl_tls13_encrypted_sni_xtn, _M2(client_hello, encrypted_extensions) }
+ { ssl_tls13_encrypted_sni_xtn, _M2(client_hello, encrypted_extensions) },
+ { ssl_tls13_post_handshake_auth_xtn, _M1(client_hello) }
};
tls13ExtensionStatus
@@ -4917,7 +5325,7 @@ tls13_ProtectRecord(sslSocket *ss,
const int tagLen = cipher_def->tag_size;
SECStatus rv;
- PORT_Assert(cwSpec->direction == CipherSpecWrite);
+ PORT_Assert(cwSpec->direction == ssl_secret_write);
SSL_TRC(3, ("%d: TLS13[%d]: spec=%d epoch=%d (%s) protect 0x%0llx len=%u",
SSL_GETPID(), ss->fd, cwSpec, cwSpec->epoch, cwSpec->phase,
cwSpec->nextSeqNum, contentLen));
@@ -4941,7 +5349,7 @@ tls13_ProtectRecord(sslSocket *ss,
PRBool needsLength;
PRUint8 aad[21];
unsigned int aadLen;
- int len;
+ unsigned int len;
PORT_Assert(cipher_def->type == type_aead);
@@ -5011,7 +5419,7 @@ tls13_UnprotectRecord(sslSocket *ss,
*alert = bad_record_mac; /* Default alert for most issues. */
- PORT_Assert(spec->direction == CipherSpecRead);
+ PORT_Assert(spec->direction == ssl_secret_read);
SSL_TRC(3, ("%d: TLS13[%d]: spec=%d epoch=%d (%s) unprotect 0x%0llx len=%u",
SSL_GETPID(), ss->fd, spec, spec->epoch, spec->phase,
cText->seqNum, cText->buf->len));
@@ -5062,12 +5470,12 @@ tls13_UnprotectRecord(sslSocket *ss,
return SECFailure;
}
rv = spec->aead(&spec->keyMaterial,
- PR_TRUE, /* do decrypt */
- plaintext->buf, /* out */
- (int *)&plaintext->len, /* outlen */
- plaintext->space, /* maxout */
- cText->buf->buf, /* in */
- cText->buf->len, /* inlen */
+ PR_TRUE, /* do decrypt */
+ plaintext->buf, /* out */
+ &plaintext->len, /* outlen */
+ plaintext->space, /* maxout */
+ cText->buf->buf, /* in */
+ cText->buf->len, /* inlen */
aad, aadLen);
if (rv != SECSuccess) {
SSL_TRC(3,
@@ -5168,6 +5576,9 @@ tls13_MaybeDo0RTTHandshake(sslSocket *ss)
ss->ssl3.hs.zeroRttState = ssl_0rtt_sent;
ss->ssl3.hs.zeroRttSuite = ss->ssl3.hs.cipher_suite;
+ /* Note: Reset the preliminary info here rather than just add 0-RTT. We are
+ * only guessing what might happen at this point.*/
+ ss->ssl3.hs.preliminaryInfo = ssl_preinfo_0rtt_cipher_suite;
SSL_TRC(3, ("%d: TLS13[%d]: in 0-RTT mode", SSL_GETPID(), ss->fd));
@@ -5196,9 +5607,6 @@ tls13_MaybeDo0RTTHandshake(sslSocket *ss)
}
}
- /* Cipher suite already set in tls13_SetupClientHello. */
- ss->ssl3.hs.preliminaryInfo = 0;
-
rv = tls13_DeriveEarlySecrets(ss);
if (rv != SECSuccess) {
return SECFailure;
@@ -5209,7 +5617,7 @@ tls13_MaybeDo0RTTHandshake(sslSocket *ss)
ssl_CipherSpecAddRef(ss->ssl3.cwSpec);
rv = tls13_SetCipherSpec(ss, TrafficKeyEarlyApplicationData,
- CipherSpecWrite, PR_TRUE);
+ ssl_secret_write, PR_TRUE);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -5218,25 +5626,45 @@ tls13_MaybeDo0RTTHandshake(sslSocket *ss)
}
PRInt32
-tls13_Read0RttData(sslSocket *ss, void *buf, PRInt32 len)
+tls13_Read0RttData(sslSocket *ss, PRUint8 *buf, PRInt32 len)
{
- TLS13EarlyData *msg;
-
PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.bufferedEarlyData));
- msg = (TLS13EarlyData *)PR_NEXT_LINK(&ss->ssl3.hs.bufferedEarlyData);
+ PRInt32 offset = 0;
+ while (!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.bufferedEarlyData)) {
+ TLS13EarlyData *msg =
+ (TLS13EarlyData *)PR_NEXT_LINK(&ss->ssl3.hs.bufferedEarlyData);
+ unsigned int tocpy = msg->data.len - msg->consumed;
+
+ if (tocpy > (len - offset)) {
+ if (IS_DTLS(ss)) {
+ /* In DTLS, we only return entire records.
+ * So offset and consumed are always zero. */
+ PORT_Assert(offset == 0);
+ PORT_Assert(msg->consumed == 0);
+ PORT_SetError(SSL_ERROR_RX_SHORT_DTLS_READ);
+ return -1;
+ }
- PR_REMOVE_LINK(&msg->link);
- if (msg->data.len > len) {
- PORT_SetError(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
- return SECFailure;
- }
- len = msg->data.len;
+ tocpy = len - offset;
+ }
+
+ PORT_Memcpy(buf + offset, msg->data.data + msg->consumed, tocpy);
+ offset += tocpy;
+ msg->consumed += tocpy;
- PORT_Memcpy(buf, msg->data.data, msg->data.len);
- SECITEM_ZfreeItem(&msg->data, PR_FALSE);
- PORT_ZFree(msg, sizeof(*msg));
+ if (msg->consumed == msg->data.len) {
+ PR_REMOVE_LINK(&msg->link);
+ SECITEM_ZfreeItem(&msg->data, PR_FALSE);
+ PORT_ZFree(msg, sizeof(*msg));
+ }
+
+ /* We are done after one record for DTLS; otherwise, when the buffer fills up. */
+ if (IS_DTLS(ss) || offset == len) {
+ break;
+ }
+ }
- return len;
+ return offset;
}
static SECStatus
@@ -5272,7 +5700,7 @@ tls13_HandleEndOfEarlyData(sslSocket *ss, PRUint8 *b, PRUint32 length)
/* We shouldn't be getting any more early data, and if we do,
* it is because of reordering and we drop it. */
if (IS_DTLS(ss)) {
- ssl_CipherSpecReleaseByEpoch(ss, CipherSpecRead,
+ ssl_CipherSpecReleaseByEpoch(ss, ssl_secret_read,
TrafficKeyEarlyApplicationData);
dtls_ReceivedFirstMessageInFlight(ss);
}
@@ -5285,7 +5713,7 @@ tls13_HandleEndOfEarlyData(sslSocket *ss, PRUint8 *b, PRUint32 length)
}
rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
- CipherSpecRead, PR_FALSE);
+ ssl_secret_read, PR_FALSE);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
@@ -5403,6 +5831,15 @@ tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supportedVersions)
return SECFailure;
}
for (version = ss->vrange.max; version >= ss->vrange.min; --version) {
+ if (ss->ssl3.hs.helloRetry && version < SSL_LIBRARY_VERSION_TLS_1_3) {
+ /* Prevent negotiating to a lower version in response to a TLS 1.3 HRR.
+ * Since we check in descending (local) order, this will only fail if
+ * our vrange has changed or the client didn't offer 1.3 in response. */
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION);
+ FATAL_ERROR(ss, SSL_ERROR_UNSUPPORTED_VERSION, protocol_version);
+ return SECFailure;
+ }
+
PRUint16 wire = tls13_EncodeDraftVersion(version, ss->protocolVariant);
unsigned long offset;
diff --git a/security/nss/lib/ssl/tls13con.h b/security/nss/lib/ssl/tls13con.h
index f3b2cb3905..bd309419fe 100644
--- a/security/nss/lib/ssl/tls13con.h
+++ b/security/nss/lib/ssl/tls13con.h
@@ -18,11 +18,6 @@ typedef enum {
tls13_extension_unknown
} tls13ExtensionStatus;
-typedef enum {
- update_not_requested = 0,
- update_requested = 1
-} tls13KeyUpdateRequest;
-
#define TLS13_MAX_FINISHED_SIZE 64
SECStatus tls13_UnprotectRecord(
@@ -47,11 +42,14 @@ PRBool tls13_InHsState(sslSocket *ss, ...);
#define TLS13_IN_HS_STATE(ss, ...) \
tls13_InHsState(ss, __VA_ARGS__, wait_invalid)
+PRBool tls13_IsPostHandshake(const sslSocket *ss);
+
SSLHashType tls13_GetHashForCipherSuite(ssl3CipherSuite suite);
SSLHashType tls13_GetHash(const sslSocket *ss);
unsigned int tls13_GetHashSizeForHash(SSLHashType hash);
unsigned int tls13_GetHashSize(const sslSocket *ss);
CK_MECHANISM_TYPE tls13_GetHkdfMechanism(sslSocket *ss);
+CK_MECHANISM_TYPE tls13_GetHkdfMechanismForHash(SSLHashType hash);
SECStatus tls13_ComputeHash(sslSocket *ss, SSL3Hashes *hashes,
const PRUint8 *buf, unsigned int len);
SECStatus tls13_ComputeHandshakeHashes(sslSocket *ss,
@@ -62,7 +60,7 @@ SECStatus tls13_DeriveSecretNullHash(sslSocket *ss, PK11SymKey *key,
PK11SymKey **dest);
void tls13_FatalError(sslSocket *ss, PRErrorCode prError,
SSL3AlertDescription desc);
-SECStatus tls13_SetupClientHello(sslSocket *ss);
+SECStatus tls13_SetupClientHello(sslSocket *ss, sslClientHelloType chType);
SECStatus tls13_MaybeDo0RTTHandshake(sslSocket *ss);
PRInt32 tls13_LimitEarlyData(sslSocket *ss, SSLContentType type, PRInt32 toSend);
PRBool tls13_AllowPskCipher(const sslSocket *ss,
@@ -106,7 +104,7 @@ SECStatus tls13_ProtectRecord(sslSocket *ss,
const PRUint8 *pIn,
PRUint32 contentLen,
sslBuffer *wrBuf);
-PRInt32 tls13_Read0RttData(sslSocket *ss, void *buf, PRInt32 len);
+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,
@@ -117,10 +115,16 @@ SECStatus tls13_NegotiateVersion(sslSocket *ss,
PRBool tls13_ShouldRequestClientAuth(sslSocket *ss);
PRBool tls13_IsReplay(const sslSocket *ss, const sslSessionID *sid);
-void tls13_AntiReplayRollover(PRTime now);
+void tls13_AntiReplayRollover(SSLAntiReplayContext *ctx, PRTime now);
+SSLAntiReplayContext *tls13_RefAntiReplayContext(SSLAntiReplayContext *ctx);
+void tls13_ReleaseAntiReplayContext(SSLAntiReplayContext *ctx);
-SECStatus SSLExp_SetupAntiReplay(PRTime window, unsigned int k,
- unsigned int bits);
+SECStatus SSLExp_CreateAntiReplayContext(
+ PRTime now, PRTime window, unsigned int k, unsigned int bits,
+ SSLAntiReplayContext **ctx);
+SECStatus SSLExp_SetAntiReplayContext(PRFileDesc *fd,
+ SSLAntiReplayContext *ctx);
+SECStatus SSLExp_ReleaseAntiReplayContext(SSLAntiReplayContext *ctx);
SECStatus SSLExp_HelloRetryRequestCallback(PRFileDesc *fd,
SSLHelloRetryRequestCallback cb,
@@ -130,7 +134,13 @@ SECStatus tls13_SendKeyUpdate(sslSocket *ss, tls13KeyUpdateRequest request,
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);
void tls13_SetSpecRecordVersion(sslSocket *ss, ssl3CipherSpec *spec);
+SECStatus SSLExp_SendCertificateRequest(PRFileDesc *fd);
/* Use this instead of FATAL_ERROR when no alert shall be sent. */
#define LOG_ERROR(ss, prError) \
diff --git a/security/nss/lib/ssl/tls13esni.c b/security/nss/lib/ssl/tls13esni.c
index e2328769bc..f2f8d0a9c3 100644
--- a/security/nss/lib/ssl/tls13esni.c
+++ b/security/nss/lib/ssl/tls13esni.c
@@ -580,9 +580,11 @@ tls13_ClientSetupESNI(sslSocket *ss)
size_t i;
PRCList *cur;
SECStatus rv;
- TLS13KeyShareEntry *share;
+ TLS13KeyShareEntry *share = NULL;
const sslNamedGroupDef *group = NULL;
- PRTime now = PR_Now() / PR_USEC_PER_SEC;
+ PRTime now = ssl_Time(ss) / PR_USEC_PER_SEC;
+
+ PORT_Assert(!ss->xtnData.esniPrivateKey);
if (!ss->esniKeys) {
return SECSuccess;
@@ -721,12 +723,12 @@ tls13_ServerGetEsniAEAD(const sslSocket *ss, PRUint64 suite,
}
SECStatus
-tls13_ServerDecryptEsniXtn(const sslSocket *ss, PRUint8 *in, unsigned int inLen,
- PRUint8 *out, int *outLen, int maxLen)
+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;
+ const ssl3CipherSuiteDef *suiteDef = NULL;
SSLAEADCipher aead = NULL;
TLSExtension *keyShareExtension;
TLS13KeyShareEntry *entry = NULL;
diff --git a/security/nss/lib/ssl/tls13esni.h b/security/nss/lib/ssl/tls13esni.h
index 6c52c99525..0fb12d25e3 100644
--- a/security/nss/lib/ssl/tls13esni.h
+++ b/security/nss/lib/ssl/tls13esni.h
@@ -45,7 +45,7 @@ SECStatus tls13_ComputeESNIKeys(const sslSocket *ss,
SECStatus tls13_FormatEsniAADInput(sslBuffer *aadInput,
PRUint8 *keyShare, unsigned int keyShareLen);
-SECStatus tls13_ServerDecryptEsniXtn(const sslSocket *ss, PRUint8 *in, unsigned int inLen,
- PRUint8 *out, int *outLen, int maxLen);
+SECStatus tls13_ServerDecryptEsniXtn(const sslSocket *ss, const PRUint8 *in, unsigned int inLen,
+ PRUint8 *out, unsigned int *outLen, unsigned int maxLen);
#endif
diff --git a/security/nss/lib/ssl/tls13exthandle.c b/security/nss/lib/ssl/tls13exthandle.c
index 8ed18f69cd..1f88016a1e 100644
--- a/security/nss/lib/ssl/tls13exthandle.c
+++ b/security/nss/lib/ssl/tls13exthandle.c
@@ -14,6 +14,7 @@
#include "ssl3exthandle.h"
#include "tls13esni.h"
#include "tls13exthandle.h"
+#include "tls13subcerts.h"
SECStatus
tls13_ServerSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData,
@@ -448,7 +449,7 @@ tls13_ClientSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
goto loser;
/* Obfuscated age. */
- age = ssl_TimeUsec() - session_ticket->received_timestamp;
+ age = ssl_Time(ss) - session_ticket->received_timestamp;
age /= PR_USEC_PER_MSEC;
age += session_ticket->ticket_age_add;
rv = sslBuffer_AppendNumber(buf, age, 4);
@@ -915,6 +916,37 @@ tls13_ServerHandleCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData,
return SECSuccess;
}
+SECStatus
+tls13_ClientSendPostHandshakeAuthXtn(const sslSocket *ss,
+ TLSExtensionData *xtnData,
+ sslBuffer *buf, PRBool *added)
+{
+ SSL_TRC(3, ("%d: TLS13[%d]: send post_handshake_auth extension",
+ SSL_GETPID(), ss->fd));
+
+ *added = ss->opt.enablePostHandshakeAuth;
+ return SECSuccess;
+}
+
+SECStatus
+tls13_ServerHandlePostHandshakeAuthXtn(const sslSocket *ss,
+ TLSExtensionData *xtnData,
+ SECItem *data)
+{
+ SSL_TRC(3, ("%d: TLS13[%d]: handle post_handshake_auth extension",
+ SSL_GETPID(), ss->fd));
+
+ if (data->len) {
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+ return SECFailure;
+ }
+
+ /* Keep track of negotiated extensions. */
+ xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_post_handshake_auth_xtn;
+
+ return SECSuccess;
+}
+
/*
* enum { psk_ke(0), psk_dhe_ke(1), (255) } PskKeyExchangeMode;
*
@@ -1109,7 +1141,7 @@ tls13_ClientSendEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData,
ssl3KeyMaterial keyMat;
SSLAEADCipher aead;
PRUint8 outBuf[1024];
- int outLen;
+ unsigned int outLen;
unsigned int sniStart;
unsigned int sniLen;
sslBuffer aadInput = SSL_BUFFER_EMPTY;
@@ -1263,7 +1295,7 @@ tls13_ServerHandleEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData,
{
sslReadBuffer buf;
PRUint8 *plainText = NULL;
- int ptLen;
+ unsigned int ptLen;
SECStatus rv;
/* If we are doing < TLS 1.3, then ignore this. */
@@ -1369,3 +1401,94 @@ tls13_ClientCheckEsniXtn(sslSocket *ss)
return SECSuccess;
}
+
+/* Indicates support for the delegated credentials extension. This should be
+ * hooked while processing the ClientHello.
+ */
+SECStatus
+tls13_ClientSendDelegatedCredentialsXtn(const sslSocket *ss,
+ TLSExtensionData *xtnData,
+ sslBuffer *buf, PRBool *added)
+{
+ /* Only send the extension if support is enabled and the client can
+ * negotiate TLS 1.3.
+ */
+ if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3 ||
+ !ss->opt.enableDelegatedCredentials) {
+ return SECSuccess;
+ }
+
+ *added = PR_TRUE;
+ return SECSuccess;
+}
+
+/* Parses the delegated credential (DC) offered by the server. This should be
+ * hooked while processing the server's CertificateVerify.
+ *
+ * Only the DC sent with the end-entity certificate is to be parsed. This is
+ * ensured by |tls13_HandleCertificateEntry|, which only processes extensions
+ * for the first certificate in the chain.
+ */
+SECStatus
+tls13_ClientHandleDelegatedCredentialsXtn(const sslSocket *ss,
+ TLSExtensionData *xtnData,
+ SECItem *data)
+{
+ if (!ss->opt.enableDelegatedCredentials ||
+ ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+ ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_EXTENSION);
+ return SECFailure;
+ }
+
+ SECStatus rv = tls13_ReadDelegatedCredential(data->data, data->len,
+ &xtnData->peerDelegCred);
+ if (rv != SECSuccess) {
+ return SECFailure; /* code already set */
+ }
+
+ xtnData->negotiated[xtnData->numNegotiated++] =
+ ssl_delegated_credentials_xtn;
+ return SECSuccess;
+}
+
+/* Adds the DC extension if we're committed to authenticating with a DC. */
+static SECStatus
+tls13_ServerSendDelegatedCredentialsXtn(const sslSocket *ss,
+ TLSExtensionData *xtnData,
+ sslBuffer *buf, PRBool *added)
+{
+ if (tls13_IsSigningWithDelegatedCredential(ss)) {
+ const SECItem *dc = &ss->sec.serverCert->delegCred;
+
+ if (tls13_IsSigningWithDelegatedCredential(ss)) {
+ SECStatus rv;
+ rv = sslBuffer_Append(buf, dc->data, dc->len);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ }
+
+ *added = PR_TRUE;
+ return SECSuccess;
+ }
+
+ return SECSuccess;
+}
+
+/* The client has indicated support of DCs. We can't act on this information
+ * until we've committed to signing with a DC, so just set a callback for
+ * sending the DC extension later. */
+SECStatus
+tls13_ServerHandleDelegatedCredentialsXtn(const sslSocket *ss,
+ TLSExtensionData *xtnData,
+ SECItem *data)
+{
+ xtnData->peerRequestedDelegCred = PR_TRUE;
+ xtnData->negotiated[xtnData->numNegotiated++] =
+ ssl_delegated_credentials_xtn;
+
+ return ssl3_RegisterExtensionSender(
+ ss, xtnData, ssl_delegated_credentials_xtn,
+ tls13_ServerSendDelegatedCredentialsXtn);
+}
diff --git a/security/nss/lib/ssl/tls13exthandle.h b/security/nss/lib/ssl/tls13exthandle.h
index dd64b44ff4..abc7f9debd 100644
--- a/security/nss/lib/ssl/tls13exthandle.h
+++ b/security/nss/lib/ssl/tls13exthandle.h
@@ -93,5 +93,20 @@ SECStatus tls13_ClientSendEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData
SECStatus tls13_ServerHandleEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData,
SECItem *data);
SECStatus tls13_ClientCheckEsniXtn(sslSocket *ss);
+SECStatus tls13_ClientSendPostHandshakeAuthXtn(const sslSocket *ss,
+ TLSExtensionData *xtnData,
+ sslBuffer *buf, PRBool *added);
+SECStatus tls13_ServerHandlePostHandshakeAuthXtn(const sslSocket *ss,
+ TLSExtensionData *xtnData,
+ SECItem *data);
+SECStatus tls13_ClientHandleDelegatedCredentialsXtn(const sslSocket *ss,
+ TLSExtensionData *xtnData,
+ SECItem *data);
+SECStatus tls13_ClientSendDelegatedCredentialsXtn(const sslSocket *ss,
+ TLSExtensionData *xtnData,
+ sslBuffer *buf, PRBool *added);
+SECStatus tls13_ServerHandleDelegatedCredentialsXtn(const sslSocket *ss,
+ TLSExtensionData *xtnData,
+ SECItem *data);
#endif
diff --git a/security/nss/lib/ssl/tls13hashstate.c b/security/nss/lib/ssl/tls13hashstate.c
index cc0ed286b0..53d3738f0c 100644
--- a/security/nss/lib/ssl/tls13hashstate.c
+++ b/security/nss/lib/ssl/tls13hashstate.c
@@ -157,7 +157,8 @@ tls13_RecoverHashState(sslSocket *ss,
/* Now reinject the message. */
SSL_ASSERT_HASHES_EMPTY(ss);
rv = ssl_HashHandshakeMessageInt(ss, ssl_hs_message_hash, 0,
- SSL_READER_CURRENT(&reader), hashLen);
+ SSL_READER_CURRENT(&reader), hashLen,
+ ssl3_UpdateHandshakeHashes);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -173,7 +174,8 @@ tls13_RecoverHashState(sslSocket *ss,
rv = ssl_HashHandshakeMessageInt(ss, ssl_hs_server_hello, 0,
SSL_BUFFER_BASE(&messageBuf),
- SSL_BUFFER_LEN(&messageBuf));
+ SSL_BUFFER_LEN(&messageBuf),
+ ssl3_UpdateHandshakeHashes);
sslBuffer_Clear(&messageBuf);
if (rv != SECSuccess) {
return SECFailure;
diff --git a/security/nss/lib/ssl/tls13hkdf.c b/security/nss/lib/ssl/tls13hkdf.c
index 8fa3375c63..ab546e06f6 100644
--- a/security/nss/lib/ssl/tls13hkdf.c
+++ b/security/nss/lib/ssl/tls13hkdf.c
@@ -140,14 +140,13 @@ tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash,
const char *kLabelPrefix = "tls13 ";
const unsigned int kLabelPrefixLen = strlen(kLabelPrefix);
- if (handshakeHash) {
- if (handshakeHashLen > 255) {
- PORT_Assert(0);
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
- } else {
- PORT_Assert(!handshakeHashLen);
+ PORT_Assert(prk);
+ PORT_Assert(keyp);
+ if ((handshakeHashLen > 255) ||
+ (handshakeHash == NULL && handshakeHashLen > 0) ||
+ (labelLen + kLabelPrefixLen > 255)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
}
/*
@@ -208,7 +207,7 @@ tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash,
*keyp = derived;
#ifdef TRACE
- if (ssl_trace >= 10) {
+ if (ssl_trace >= 50) {
/* Make sure the label is null terminated. */
char labelStr[100];
PORT_Memcpy(labelStr, label, labelLen);
diff --git a/security/nss/lib/ssl/tls13replay.c b/security/nss/lib/ssl/tls13replay.c
index b090f9bca7..6280111440 100644
--- a/security/nss/lib/ssl/tls13replay.c
+++ b/security/nss/lib/ssl/tls13replay.c
@@ -9,7 +9,6 @@
#include "nss.h" /* for NSS_RegisterShutdown */
#include "nssilock.h" /* for PZMonitor */
#include "pk11pub.h"
-#include "prinit.h" /* for PR_CallOnce */
#include "prmon.h"
#include "prtime.h"
#include "secerr.h"
@@ -18,10 +17,10 @@
#include "sslimpl.h"
#include "tls13hkdf.h"
-static struct {
- /* Used to ensure that we only initialize the cleanup function once. */
- PRCallOnceType init;
- /* Used to serialize access to the filters. */
+struct SSLAntiReplayContextStr {
+ /* The number of outstanding references to this context. */
+ PRInt32 refCount;
+ /* Used to serialize access. */
PZMonitor *lock;
/* The filters, use of which alternates. */
sslBloomFilter filters[2];
@@ -33,44 +32,56 @@ static struct {
PRTime window;
/* This key ensures that the bloom filter index is unpredictable. */
PK11SymKey *key;
-} ssl_anti_replay;
+};
-/* Clear the current state and free any resources we allocated. The signature
- * here is odd to allow this to be called during shutdown. */
-static SECStatus
-tls13_AntiReplayReset(void *appData, void *nssData)
+void
+tls13_ReleaseAntiReplayContext(SSLAntiReplayContext *ctx)
{
- if (ssl_anti_replay.key) {
- PK11_FreeSymKey(ssl_anti_replay.key);
- ssl_anti_replay.key = NULL;
+ if (!ctx) {
+ return;
+ }
+ if (PR_ATOMIC_DECREMENT(&ctx->refCount) >= 1) {
+ return;
}
- if (ssl_anti_replay.lock) {
- PZ_DestroyMonitor(ssl_anti_replay.lock);
- ssl_anti_replay.lock = NULL;
+
+ if (ctx->lock) {
+ PZ_DestroyMonitor(ctx->lock);
+ ctx->lock = NULL;
}
- sslBloom_Destroy(&ssl_anti_replay.filters[0]);
- sslBloom_Destroy(&ssl_anti_replay.filters[1]);
+ PK11_FreeSymKey(ctx->key);
+ ctx->key = NULL;
+ sslBloom_Destroy(&ctx->filters[0]);
+ sslBloom_Destroy(&ctx->filters[1]);
+ 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. */
+SECStatus
+SSLExp_ReleaseAntiReplayContext(SSLAntiReplayContext *ctx)
+{
+ tls13_ReleaseAntiReplayContext(ctx);
return SECSuccess;
}
-static PRStatus
-tls13_AntiReplayInit(void)
+SSLAntiReplayContext *
+tls13_RefAntiReplayContext(SSLAntiReplayContext *ctx)
{
- SECStatus rv = NSS_RegisterShutdown(tls13_AntiReplayReset, NULL);
- if (rv != SECSuccess) {
- return PR_FAILURE;
- }
- return PR_SUCCESS;
+ PORT_Assert(ctx);
+ PR_ATOMIC_INCREMENT(&ctx->refCount);
+ return ctx;
}
static SECStatus
-tls13_AntiReplayKeyGen()
+tls13_AntiReplayKeyGen(SSLAntiReplayContext *ctx)
{
PRUint8 buf[32];
SECItem keyItem = { siBuffer, buf, sizeof(buf) };
PK11SlotInfo *slot;
SECStatus rv;
+ PORT_Assert(ctx);
+
slot = PK11_GetInternalSlot();
if (!slot) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
@@ -81,10 +92,10 @@ tls13_AntiReplayKeyGen()
goto loser;
}
- ssl_anti_replay.key = PK11_ImportSymKey(slot, CKM_NSS_HKDF_SHA256,
- PK11_OriginUnwrap, CKA_DERIVE,
- &keyItem, NULL);
- if (!ssl_anti_replay.key) {
+ ctx->key = PK11_ImportSymKey(slot, CKM_NSS_HKDF_SHA256,
+ PK11_OriginUnwrap, CKA_DERIVE,
+ &keyItem, NULL);
+ if (!ctx->key) {
goto loser;
}
@@ -100,20 +111,18 @@ loser:
#define SSL_MAX_BLOOM_FILTER_SIZE 64
/*
- * The structures created by this function can be called concurrently on
- * multiple threads if the server is multi-threaded. A monitor is used to
- * ensure that only one thread can access the structures that change over time,
- * but no such guarantee is provided for configuration data.
- *
- * Functions that read from static configuration data depend on there being a
- * memory barrier between the setup and use of this function.
+ * The context created by this function can be called concurrently on multiple
+ * threads if the server is multi-threaded. A monitor is used to ensure that
+ * only one thread can access the structures that change over time, but no such
+ * guarantee is provided for configuration data.
*/
SECStatus
-SSLExp_SetupAntiReplay(PRTime window, unsigned int k, unsigned int bits)
+SSLExp_CreateAntiReplayContext(PRTime now, PRTime window, unsigned int k,
+ unsigned int bits, SSLAntiReplayContext **pctx)
{
SECStatus rv;
- if (k == 0 || bits == 0) {
+ if (window <= 0 || k == 0 || bits == 0 || pctx == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
@@ -122,69 +131,70 @@ SSLExp_SetupAntiReplay(PRTime window, unsigned int k, unsigned int bits)
return SECFailure;
}
- if (PR_SUCCESS != PR_CallOnce(&ssl_anti_replay.init,
- tls13_AntiReplayInit)) {
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
+ SSLAntiReplayContext *ctx = PORT_ZNew(SSLAntiReplayContext);
+ if (!ctx) {
+ return SECFailure; /* Code already set. */
}
- (void)tls13_AntiReplayReset(NULL, NULL);
-
- ssl_anti_replay.lock = PZ_NewMonitor(nssILockSSL);
- if (!ssl_anti_replay.lock) {
+ ctx->refCount = 1;
+ ctx->lock = PZ_NewMonitor(nssILockSSL);
+ if (!ctx->lock) {
goto loser; /* Code already set. */
}
- rv = tls13_AntiReplayKeyGen();
+ rv = tls13_AntiReplayKeyGen(ctx);
if (rv != SECSuccess) {
goto loser; /* Code already set. */
}
- rv = sslBloom_Init(&ssl_anti_replay.filters[0], k, bits);
+ rv = sslBloom_Init(&ctx->filters[0], k, bits);
if (rv != SECSuccess) {
goto loser; /* Code already set. */
}
- rv = sslBloom_Init(&ssl_anti_replay.filters[1], k, bits);
+ rv = sslBloom_Init(&ctx->filters[1], k, bits);
if (rv != SECSuccess) {
goto loser; /* Code already set. */
}
/* When starting out, ensure that 0-RTT is not accepted until the window is
* updated. A ClientHello might have been accepted prior to a restart. */
- sslBloom_Fill(&ssl_anti_replay.filters[1]);
+ sslBloom_Fill(&ctx->filters[1]);
- ssl_anti_replay.current = 0;
- ssl_anti_replay.nextUpdate = ssl_TimeUsec() + window;
- ssl_anti_replay.window = window;
+ ctx->current = 0;
+ ctx->nextUpdate = now + window;
+ ctx->window = window;
+ *pctx = ctx;
return SECSuccess;
loser:
- (void)tls13_AntiReplayReset(NULL, NULL);
+ tls13_ReleaseAntiReplayContext(ctx);
return SECFailure;
}
-/* This is exposed to tests. Though it could, this doesn't take the lock on the
- * basis that those tests use thread confinement. */
-void
-tls13_AntiReplayRollover(PRTime now)
+SECStatus
+SSLExp_SetAntiReplayContext(PRFileDesc *fd, SSLAntiReplayContext *ctx)
{
- ssl_anti_replay.current ^= 1;
- ssl_anti_replay.nextUpdate = now + ssl_anti_replay.window;
- sslBloom_Zero(ssl_anti_replay.filters + ssl_anti_replay.current);
+ sslSocket *ss = ssl_FindSocket(fd);
+ if (!ss) {
+ return SECFailure; /* Code already set. */
+ }
+ tls13_ReleaseAntiReplayContext(ss->antiReplay);
+ if (ctx != NULL) {
+ ss->antiReplay = tls13_RefAntiReplayContext(ctx);
+ } else {
+ ss->antiReplay = NULL;
+ }
+ return SECSuccess;
}
static void
-tls13_AntiReplayUpdate()
+tls13_AntiReplayUpdate(SSLAntiReplayContext *ctx, PRTime now)
{
- PRTime now;
-
- PR_ASSERT_CURRENT_THREAD_IN_MONITOR(ssl_anti_replay.lock);
-
- now = ssl_TimeUsec();
- if (now < ssl_anti_replay.nextUpdate) {
- return;
+ PR_ASSERT_CURRENT_THREAD_IN_MONITOR(ctx->lock);
+ if (now >= ctx->nextUpdate) {
+ ctx->current ^= 1;
+ ctx->nextUpdate = now + ctx->window;
+ sslBloom_Zero(ctx->filters + ctx->current);
}
-
- tls13_AntiReplayRollover(now);
}
PRBool
@@ -197,7 +207,7 @@ tls13_InWindow(const sslSocket *ss, const sslSessionID *sid)
* calculate. The result should be close to zero. timeDelta is signed to
* make the comparisons below easier. */
timeDelta = ss->xtnData.ticketAge -
- ((ssl_TimeUsec() - sid->creationTime) / PR_USEC_PER_MSEC);
+ ((ssl_Time(ss) - sid->creationTime) / PR_USEC_PER_MSEC);
/* Only allow the time delta to be at most half of our window. This is
* symmetrical, though it doesn't need to be; this assumes that clock errors
@@ -221,7 +231,10 @@ tls13_InWindow(const sslSocket *ss, const sslSessionID *sid)
* prevent the same 0-RTT attempt from being accepted during window 1 and
* later window 3.
*/
- return PR_ABS(timeDelta) < (ssl_anti_replay.window / 2);
+ PRInt32 allowance = ss->antiReplay->window / (PR_USEC_PER_MSEC * 2);
+ SSL_TRC(10, ("%d: TLS13[%d]: replay check time delta=%d, allow=%d",
+ SSL_GETPID(), ss->fd, timeDelta, allowance));
+ return PR_ABS(timeDelta) < allowance;
}
/* Checks for a duplicate in the two filters we have. Performs maintenance on
@@ -236,12 +249,13 @@ tls13_IsReplay(const sslSocket *ss, const sslSessionID *sid)
unsigned int size;
PRUint8 index;
SECStatus rv;
- static const char *label = "tls13 anti-replay";
+ static const char *label = "anti-replay";
PRUint8 buf[SSL_MAX_BLOOM_FILTER_SIZE];
+ SSLAntiReplayContext *ctx = ss->antiReplay;
- /* If SSL_SetupAntiReplay hasn't been called, then treat all attempts at
- * 0-RTT as a replay. */
- if (!ssl_anti_replay.init.initialized) {
+ /* If SSL_SetAntiReplayContext hasn't been called with a valid context, then
+ * treat all attempts at 0-RTT as a replay. */
+ if (ctx == NULL) {
return PR_TRUE;
}
@@ -249,10 +263,9 @@ tls13_IsReplay(const sslSocket *ss, const sslSessionID *sid)
return PR_TRUE;
}
- size = ssl_anti_replay.filters[0].k *
- (ssl_anti_replay.filters[0].bits + 7) / 8;
+ size = ctx->filters[0].k * (ctx->filters[0].bits + 7) / 8;
PORT_Assert(size <= SSL_MAX_BLOOM_FILTER_SIZE);
- rv = tls13_HkdfExpandLabelRaw(ssl_anti_replay.key, ssl_hash_sha256,
+ rv = tls13_HkdfExpandLabelRaw(ctx->key, ssl_hash_sha256,
ss->xtnData.pskBinder.data,
ss->xtnData.pskBinder.len,
label, strlen(label),
@@ -261,16 +274,19 @@ tls13_IsReplay(const sslSocket *ss, const sslSessionID *sid)
return PR_TRUE;
}
- PZ_EnterMonitor(ssl_anti_replay.lock);
- tls13_AntiReplayUpdate();
+ PZ_EnterMonitor(ctx->lock);
+ tls13_AntiReplayUpdate(ctx, ssl_Time(ss));
- index = ssl_anti_replay.current;
- replay = sslBloom_Add(&ssl_anti_replay.filters[index], buf);
+ index = ctx->current;
+ replay = sslBloom_Add(&ctx->filters[index], buf);
+ SSL_TRC(10, ("%d: TLS13[%d]: replay check current window: %s",
+ SSL_GETPID(), ss->fd, replay ? "replay" : "ok"));
if (!replay) {
- replay = sslBloom_Check(&ssl_anti_replay.filters[index ^ 1],
- buf);
+ replay = sslBloom_Check(&ctx->filters[index ^ 1], buf);
+ SSL_TRC(10, ("%d: TLS13[%d]: replay check previous window: %s",
+ SSL_GETPID(), ss->fd, replay ? "replay" : "ok"));
}
- PZ_ExitMonitor(ssl_anti_replay.lock);
+ PZ_ExitMonitor(ctx->lock);
return replay;
}
diff --git a/security/nss/lib/ssl/tls13subcerts.c b/security/nss/lib/ssl/tls13subcerts.c
new file mode 100644
index 0000000000..8ae5447f7a
--- /dev/null
+++ b/security/nss/lib/ssl/tls13subcerts.c
@@ -0,0 +1,767 @@
+/* -*- 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 "secder.h"
+#include "ssl.h"
+#include "sslproto.h"
+#include "sslimpl.h"
+#include "ssl3exthandle.h"
+#include "tls13exthandle.h"
+#include "tls13hkdf.h"
+#include "tls13subcerts.h"
+
+/* Parses the delegated credential (DC) from the raw extension |b| of length
+ * |length|. Memory for the DC is allocated and set to |*dcp|.
+ *
+ * It's the caller's responsibility to invoke |tls13_DestroyDelegatedCredential|
+ * when this data is no longer needed.
+ */
+SECStatus
+tls13_ReadDelegatedCredential(PRUint8 *b, PRUint32 length,
+ sslDelegatedCredential **dcp)
+{
+ sslDelegatedCredential *dc = NULL;
+ SECStatus rv;
+ PRUint64 n;
+ sslReadBuffer tmp;
+ sslReader rdr = SSL_READER(b, length);
+
+ PORT_Assert(!*dcp);
+
+ dc = PORT_ZNew(sslDelegatedCredential);
+ if (!dc) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ goto loser;
+ }
+
+ /* Read the valid_time field of DelegatedCredential.cred. */
+ rv = sslRead_ReadNumber(&rdr, 4, &n);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ dc->validTime = n;
+
+ /* Read the expected_cert_verify_algorithm field of
+ * DelegatedCredential.cred. */
+ rv = sslRead_ReadNumber(&rdr, 2, &n);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ dc->expectedCertVerifyAlg = n;
+
+ /* Read the ASN1_subjectPublicKeyInfo field of DelegatedCredential.cred. */
+ rv = sslRead_ReadVariable(&rdr, 3, &tmp);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = SECITEM_MakeItem(NULL, &dc->derSpki, tmp.buf, tmp.len);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Parse the DER-encoded SubjectPublicKeyInfo. */
+ dc->spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&dc->derSpki);
+ if (!dc->spki) {
+ goto loser;
+ }
+
+ /* Read the algorithm field of the DelegatedCredential. */
+ rv = sslRead_ReadNumber(&rdr, 2, &n);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ dc->alg = n;
+
+ /* Read the signature field of the DelegatedCredential. */
+ rv = sslRead_ReadVariable(&rdr, 2, &tmp);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = SECITEM_MakeItem(NULL, &dc->signature, tmp.buf, tmp.len);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* There should be nothing left to read. */
+ if (SSL_READER_REMAINING(&rdr) > 0) {
+ goto loser;
+ }
+
+ *dcp = dc;
+ return SECSuccess;
+
+loser:
+ tls13_DestroyDelegatedCredential(dc);
+ *dcp = NULL;
+ return SECFailure;
+}
+
+/* Frees |dc| from the heap. */
+void
+tls13_DestroyDelegatedCredential(sslDelegatedCredential *dc)
+{
+ if (!dc) {
+ return;
+ }
+
+ SECKEY_DestroySubjectPublicKeyInfo(dc->spki);
+ SECITEM_FreeItem(&dc->derSpki, PR_FALSE);
+ SECITEM_FreeItem(&dc->signature, PR_FALSE);
+ PORT_ZFree(dc, sizeof(sslDelegatedCredential));
+}
+
+/* Sets |*certVerifyAlg| to the expected_cert_verify_algorithm field from the
+ * serialized DC |in|. Returns SECSuccess upon success; SECFailure indicates a
+ * decoding failure or the input wasn't long enough.
+ */
+static SECStatus
+tls13_GetExpectedCertVerifyAlg(SECItem in, SSLSignatureScheme *certVerifyAlg)
+{
+ SECStatus rv;
+ PRUint64 n;
+ sslReader rdr = SSL_READER(in.data, in.len);
+
+ if (in.len < 6) { /* Buffer too short to contain the first two params. */
+ return SECFailure;
+ }
+
+ rv = sslRead_ReadNumber(&rdr, 4, &n);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ rv = sslRead_ReadNumber(&rdr, 2, &n);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ *certVerifyAlg = n;
+
+ return SECSuccess;
+}
+
+/* Returns PR_TRUE if the host is verifying the handshake with a DC. */
+PRBool
+tls13_IsVerifyingWithDelegatedCredential(const sslSocket *ss)
+{
+ /* As of draft-ietf-subcerts-03, only the server may authenticate itself
+ * with a DC.
+ */
+ if (ss->sec.isServer ||
+ !ss->opt.enableDelegatedCredentials ||
+ !ss->xtnData.peerDelegCred) {
+ return PR_FALSE;
+ }
+
+ return PR_TRUE;
+}
+
+/* Returns PR_TRUE if the host is signing the handshake with a DC. */
+PRBool
+tls13_IsSigningWithDelegatedCredential(const sslSocket *ss)
+{
+ if (!ss->sec.isServer ||
+ !ss->xtnData.sendingDelegCredToPeer ||
+ !ss->xtnData.peerRequestedDelegCred) {
+ return PR_FALSE;
+ }
+
+ return PR_TRUE;
+}
+
+/* Commits to authenticating with a DC if all of the following conditions hold:
+ * - the negotiated protocol is TLS 1.3 or newer;
+ * - the selected certificate has a DC configured;
+ * - the peer has indicated support for this extension;
+ * - the peer has indicated support for the DC signature scheme; and
+ * - the host supports the DC signature scheme.
+ *
+ * It's the caller's responsibility to ensure that the version has been
+ * negotiated and the certificate has been selected.
+ */
+SECStatus
+tls13_MaybeSetDelegatedCredential(sslSocket *ss)
+{
+ SECStatus rv;
+ PRBool doesRsaPss;
+ 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
+ * 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);
+
+ /* Check that the peer has indicated support and that a DC has been
+ * configured for the selected certificate.
+ */
+ if (!ss->xtnData.peerRequestedDelegCred ||
+ !ss->sec.serverCert->delegCred.len ||
+ !ss->sec.serverCert->delegCredKeyPair) {
+ return SECSuccess;
+ }
+
+ /* Check that the host and peer both support the signing algorithm used with
+ * the DC.
+ */
+ rv = tls13_GetExpectedCertVerifyAlg(ss->sec.serverCert->delegCred,
+ &scheme);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ priv = ss->sec.serverCert->delegCredKeyPair->privKey;
+ rv = ssl_PrivateKeySupportsRsaPss(priv, &doesRsaPss);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ if (!ssl_SignatureSchemeEnabled(ss, scheme) ||
+ !ssl_CanUseSignatureScheme(scheme,
+ ss->xtnData.sigSchemes,
+ ss->xtnData.numSigSchemes,
+ PR_FALSE /* requireSha1 */,
+ doesRsaPss)) {
+ return SECSuccess;
+ }
+
+ /* Commit to sending a DC and set the handshake signature scheme to the
+ * indicated algorithm.
+ */
+ ss->xtnData.sendingDelegCredToPeer = PR_TRUE;
+ ss->ssl3.hs.signatureScheme = scheme;
+ return SECSuccess;
+}
+
+/* Serializes the DC up to the signature. */
+static SECStatus
+tls13_AppendCredentialParams(sslBuffer *buf, sslDelegatedCredential *dc)
+{
+ SECStatus rv;
+ rv = sslBuffer_AppendNumber(buf, dc->validTime, 4);
+ if (rv != SECSuccess) {
+ return SECFailure; /* Error set by caller. */
+ }
+
+ rv = sslBuffer_AppendNumber(buf, dc->expectedCertVerifyAlg, 2);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ rv = sslBuffer_AppendVariable(buf, dc->derSpki.data, dc->derSpki.len, 3);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ rv = sslBuffer_AppendNumber(buf, dc->alg, 2);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}
+
+/* Serializes the DC signature. */
+static SECStatus
+tls13_AppendCredentialSignature(sslBuffer *buf, sslDelegatedCredential *dc)
+{
+ SECStatus rv;
+ rv = sslBuffer_AppendVariable(buf, dc->signature.data,
+ dc->signature.len, 2);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}
+
+/* Hashes the message used to sign/verify the DC. */
+static SECStatus
+tls13_HashCredentialSignatureMessage(SSL3Hashes *hash,
+ SSLSignatureScheme scheme,
+ const CERTCertificate *cert,
+ const sslBuffer *dcBuf)
+{
+ SECStatus rv;
+ PK11Context *ctx = NULL;
+ unsigned int hashLen;
+
+ /* Set up hash context. */
+ hash->hashAlg = ssl_SignatureSchemeToHashType(scheme);
+ ctx = PK11_CreateDigestContext(ssl3_HashTypeToOID(hash->hashAlg));
+ if (!ctx) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ goto loser;
+ }
+
+ static const PRUint8 kCtxStrPadding[64] = {
+ 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,
+ 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";
+
+ /* Hash the message signed by the peer. */
+ rv = SECSuccess;
+ rv |= PK11_DigestBegin(ctx);
+ rv |= PK11_DigestOp(ctx, kCtxStrPadding, sizeof kCtxStrPadding);
+ rv |= PK11_DigestOp(ctx, kCtxStr, 1 /* 0-byte */ + strlen((const char *)kCtxStr));
+ rv |= PK11_DigestOp(ctx, cert->derCert.data, cert->derCert.len);
+ rv |= PK11_DigestOp(ctx, dcBuf->buf, dcBuf->len);
+ rv |= PK11_DigestFinal(ctx, hash->u.raw, &hashLen, sizeof hash->u.raw);
+ if (rv != SECSuccess) {
+ PORT_SetError(SSL_ERROR_SHA_DIGEST_FAILURE);
+ goto loser;
+ }
+
+ hash->len = hashLen;
+ if (ctx) {
+ PK11_DestroyContext(ctx, PR_TRUE);
+ }
+ return SECSuccess;
+
+loser:
+ if (ctx) {
+ PK11_DestroyContext(ctx, PR_TRUE);
+ }
+ return SECFailure;
+}
+
+/* Verifies the DC signature. */
+static SECStatus
+tls13_VerifyCredentialSignature(sslSocket *ss, sslDelegatedCredential *dc)
+{
+ SECStatus rv = SECSuccess;
+ SSL3Hashes hash;
+ sslBuffer dcBuf = SSL_BUFFER_EMPTY;
+ CERTCertificate *cert = ss->sec.peerCert;
+ SECKEYPublicKey *pubKey = NULL;
+
+ /* Serialize the DC parameters. */
+ rv = tls13_AppendCredentialParams(&dcBuf, dc);
+ if (rv != SECSuccess) {
+ goto loser; /* Error set by caller. */
+ }
+
+ /* Hash the message that was signed by the delegator. */
+ rv = tls13_HashCredentialSignatureMessage(&hash, dc->alg, cert, &dcBuf);
+ if (rv != SECSuccess) {
+ FATAL_ERROR(ss, PORT_GetError(), internal_error);
+ goto loser;
+ }
+
+ pubKey = SECKEY_ExtractPublicKey(&cert->subjectPublicKeyInfo);
+ if (pubKey == NULL) {
+ FATAL_ERROR(ss, SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE, internal_error);
+ goto loser;
+ }
+
+ /* Verify the signature of the message. */
+ rv = ssl_VerifySignedHashesWithPubKey(ss, pubKey, dc->alg,
+ &hash, &dc->signature);
+ if (rv != SECSuccess) {
+ FATAL_ERROR(ss, SSL_ERROR_DC_BAD_SIGNATURE, illegal_parameter);
+ goto loser;
+ }
+
+ SECKEY_DestroyPublicKey(pubKey);
+ sslBuffer_Clear(&dcBuf);
+ return SECSuccess;
+
+loser:
+ SECKEY_DestroyPublicKey(pubKey);
+ sslBuffer_Clear(&dcBuf);
+ return SECFailure;
+}
+
+/* Checks that the peer's end-entity certificate has the correct key usage. */
+static SECStatus
+tls13_CheckCertDelegationUsage(sslSocket *ss)
+{
+ int i;
+ PRBool found;
+ CERTCertExtension *ext;
+ SECItem delegUsageOid = { siBuffer, NULL, 0 };
+ const CERTCertificate *cert = ss->sec.peerCert;
+
+ /* 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,
+ };
+
+ delegUsageOid.data = kDelegationUsageOid;
+ delegUsageOid.len = sizeof kDelegationUsageOid;
+
+ /* The certificate must have the delegationUsage extension that authorizes
+ * it to negotiate delegated credentials.
+ */
+ found = PR_FALSE;
+ for (i = 0; cert->extensions[i] != NULL; i++) {
+ ext = cert->extensions[i];
+ if (SECITEM_CompareItem(&ext->id, &delegUsageOid) == SECEqual) {
+ found = PR_TRUE;
+ break;
+ }
+ }
+
+ /* The certificate must also have the digitalSignature keyUsage set. */
+ if (!found ||
+ !cert->keyUsagePresent ||
+ !(cert->keyUsage & KU_DIGITAL_SIGNATURE)) {
+ FATAL_ERROR(ss, SSL_ERROR_DC_INVALID_KEY_USAGE, illegal_parameter);
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}
+
+static SECStatus
+tls13_CheckCredentialExpiration(sslSocket *ss, sslDelegatedCredential *dc)
+{
+ SECStatus rv;
+ PRTime start, end /* microseconds */;
+ CERTCertificate *cert = ss->sec.peerCert;
+
+ rv = DER_DecodeTimeChoice(&start, &cert->validity.notBefore);
+ if (rv != SECSuccess) {
+ FATAL_ERROR(ss, PORT_GetError(), internal_error);
+ return SECFailure;
+ }
+
+ end = start + ((PRTime)dc->validTime * PR_USEC_PER_SEC);
+ if (ssl_Time(ss) > end) {
+ FATAL_ERROR(ss, SSL_ERROR_DC_EXPIRED, illegal_parameter);
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}
+
+/* Returns SECSucces if |dc| is a DC for the current handshake; otherwise it
+ * 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.
+ *
+ * This function calls FATAL_ERROR() when an error occurs.
+ */
+SECStatus
+tls13_VerifyDelegatedCredential(sslSocket *ss,
+ sslDelegatedCredential *dc)
+{
+ SECStatus rv;
+ PRTime start;
+ PRExplodedTime end;
+ CERTCertificate *cert = ss->sec.peerCert;
+ char endStr[256];
+
+ rv = DER_DecodeTimeChoice(&start, &cert->validity.notBefore);
+ if (rv != SECSuccess) {
+ FATAL_ERROR(ss, PORT_GetError(), internal_error);
+ return SECFailure;
+ }
+
+ PR_ExplodeTime(start + (dc->validTime * PR_USEC_PER_SEC),
+ PR_GMTParameters, &end);
+ if (PR_FormatTime(endStr, sizeof(endStr), "%a %b %d %H:%M:%S %Y", &end)) {
+ SSL_TRC(20, ("%d: TLS13[%d]: Received delegated credential (expires %s)",
+ SSL_GETPID(), ss->fd, endStr));
+ } else {
+ SSL_TRC(20, ("%d: TLS13[%d]: Received delegated credential",
+ SSL_GETPID(), ss->fd));
+ }
+
+ rv = SECSuccess;
+ rv |= tls13_VerifyCredentialSignature(ss, dc);
+ rv |= tls13_CheckCertDelegationUsage(ss);
+ rv |= tls13_CheckCredentialExpiration(ss, dc);
+ return rv;
+}
+
+static CERTSubjectPublicKeyInfo *
+tls13_MakePssSpki(const SECKEYPublicKey *pub, SECOidTag hashOid)
+{
+ SECStatus rv;
+ PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (!arena) {
+ goto loser; /* Code already set. */
+ }
+ CERTSubjectPublicKeyInfo *spki = PORT_ArenaZNew(arena, CERTSubjectPublicKeyInfo);
+ if (!spki) {
+ goto loser; /* Code already set. */
+ }
+ spki->arena = arena;
+
+ SECKEYRSAPSSParams params = { 0 };
+ params.hashAlg = PORT_ArenaZNew(arena, SECAlgorithmID);
+ rv = SECOID_SetAlgorithmID(arena, params.hashAlg, hashOid, NULL);
+ if (rv != SECSuccess) {
+ goto loser; /* Code already set. */
+ }
+
+ /* Set the mask hash algorithm too, which is an argument to
+ * a SEC_OID_PKCS1_MGF1 value. */
+ SECAlgorithmID maskHashAlg;
+ memset(&maskHashAlg, 0, sizeof(maskHashAlg));
+ rv = SECOID_SetAlgorithmID(arena, &maskHashAlg, hashOid, NULL);
+ if (rv != SECSuccess) {
+ goto loser; /* Code already set. */
+ }
+ SECItem *maskHashAlgItem =
+ SEC_ASN1EncodeItem(arena, NULL, &maskHashAlg,
+ SEC_ASN1_GET(SECOID_AlgorithmIDTemplate));
+ if (!maskHashAlgItem) {
+ /* Probably OOM, but not certain. */
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ goto loser;
+ }
+
+ params.maskAlg = PORT_ArenaZNew(arena, SECAlgorithmID);
+ rv = SECOID_SetAlgorithmID(arena, params.maskAlg, SEC_OID_PKCS1_MGF1,
+ maskHashAlgItem);
+ if (rv != SECSuccess) {
+ goto loser; /* Code already set. */
+ }
+
+ SECItem *algorithmItem =
+ SEC_ASN1EncodeItem(arena, NULL, &params,
+ SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate));
+ if (!algorithmItem) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ goto loser; /* Code already set. */
+ }
+ rv = SECOID_SetAlgorithmID(arena, &spki->algorithm,
+ SEC_OID_PKCS1_RSA_PSS_SIGNATURE, algorithmItem);
+ if (rv != SECSuccess) {
+ 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) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ goto loser;
+ }
+ spki->subjectPublicKey.len *= 8; /* Key length is in bits. */
+ return spki;
+
+loser:
+ PORT_FreeArena(arena, PR_FALSE);
+ return NULL;
+}
+
+static CERTSubjectPublicKeyInfo *
+tls13_MakeDcSpki(const SECKEYPublicKey *dcPub, SSLSignatureScheme dcCertVerifyAlg)
+{
+ switch (SECKEY_GetPublicKeyType(dcPub)) {
+ 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. */
+ 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;
+ case ssl_sig_rsa_pss_pss_sha384:
+ hashOid = SEC_OID_SHA384;
+ break;
+ case ssl_sig_rsa_pss_pss_sha512:
+ hashOid = SEC_OID_SHA512;
+ break;
+
+ default:
+ PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
+ return NULL;
+ }
+ return tls13_MakePssSpki(dcPub, hashOid);
+ }
+
+ case ecKey: {
+ const sslNamedGroupDef *group = ssl_ECPubKey2NamedGroup(dcPub);
+ if (!group) {
+ PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
+ return NULL;
+ }
+ SSLSignatureScheme keyScheme;
+ switch (group->name) {
+ case ssl_grp_ec_secp256r1:
+ keyScheme = ssl_sig_ecdsa_secp256r1_sha256;
+ break;
+ case ssl_grp_ec_secp384r1:
+ keyScheme = ssl_sig_ecdsa_secp384r1_sha384;
+ break;
+ case ssl_grp_ec_secp521r1:
+ keyScheme = ssl_sig_ecdsa_secp521r1_sha512;
+ break;
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_KEY);
+ return NULL;
+ }
+ if (keyScheme != dcCertVerifyAlg) {
+ PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
+ return NULL;
+ }
+ return SECKEY_CreateSubjectPublicKeyInfo(dcPub);
+ }
+
+ default:
+ break;
+ }
+
+ PORT_SetError(SEC_ERROR_INVALID_KEY);
+ return NULL;
+}
+
+/* Returns a serialized DC with the given parameters.
+ *
+ * Note that this function is meant primarily for testing. In particular, it
+ * DOES NOT verify any of the following:
+ * - |certPriv| is the private key corresponding to |cert|;
+ * - that |checkCertKeyUsage(cert) == SECSuccess|;
+ * - |dcValidFor| is less than 7 days (the maximum permitted by the spec); or
+ * - validTime doesn't overflow a PRUint32.
+ *
+ * These conditions are things we want to test for, which is why we allow them
+ * here. A real API for creating DCs would want to explicitly check ALL of these
+ * conditions are met.
+ */
+SECStatus
+SSLExp_DelegateCredential(const CERTCertificate *cert,
+ const SECKEYPrivateKey *certPriv,
+ const SECKEYPublicKey *dcPub,
+ SSLSignatureScheme dcCertVerifyAlg,
+ PRUint32 dcValidFor,
+ PRTime now,
+ SECItem *out)
+{
+ SECStatus rv;
+ SSL3Hashes hash;
+ CERTSubjectPublicKeyInfo *spki = NULL;
+ SECKEYPrivateKey *tmpPriv = NULL;
+ sslDelegatedCredential *dc = NULL;
+ sslBuffer dcBuf = SSL_BUFFER_EMPTY;
+
+ if (!cert || !certPriv || !dcPub || !out) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ dc = PORT_ZNew(sslDelegatedCredential);
+ if (!dc) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ goto loser;
+ }
+
+ /* Serialize the DC parameters. */
+ PRTime start;
+ rv = DER_DecodeTimeChoice(&start, &cert->validity.notBefore);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ dc->validTime = ((now - start) / PR_USEC_PER_SEC) + dcValidFor;
+
+ /* Building the SPKI also validates |dcCertVerifyAlg|. */
+ spki = tls13_MakeDcSpki(dcPub, dcCertVerifyAlg);
+ if (!spki) {
+ goto loser;
+ }
+ dc->expectedCertVerifyAlg = dcCertVerifyAlg;
+
+ SECItem *spkiDer =
+ SEC_ASN1EncodeItem(NULL /*arena*/, &dc->derSpki, spki,
+ SEC_ASN1_GET(CERT_SubjectPublicKeyInfoTemplate));
+ if (!spkiDer) {
+ goto loser;
+ }
+
+ rv = ssl_SignatureSchemeFromSpki(&cert->subjectPublicKeyInfo,
+ PR_TRUE /* isTls13 */, &dc->alg);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ 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. */
+ if (spkiOid == SEC_OID_PKCS1_RSA_ENCRYPTION) {
+ SSLSignatureScheme scheme = ssl_sig_rsa_pss_rsae_sha256;
+ if (ssl_SignatureSchemeValid(scheme, spkiOid, PR_TRUE /* isTls13 */)) {
+ dc->alg = scheme;
+ }
+ }
+ }
+ PORT_Assert(dc->alg != ssl_sig_none);
+
+ rv = tls13_AppendCredentialParams(&dcBuf, dc);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Hash signature message. */
+ rv = tls13_HashCredentialSignatureMessage(&hash, dc->alg, cert, &dcBuf);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Sign the hash with the delegation key.
+ *
+ * The PK11 API discards const qualifiers, so we have to make a copy of
+ * |certPriv| and pass the copy to |ssl3_SignHashesWithPrivKey|.
+ */
+ tmpPriv = SECKEY_CopyPrivateKey(certPriv);
+ rv = ssl3_SignHashesWithPrivKey(&hash, tmpPriv, dc->alg,
+ PR_TRUE /* isTls */, &dc->signature);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Serialize the DC signature. */
+ rv = tls13_AppendCredentialSignature(&dcBuf, dc);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Copy the serialized DC to |out|. */
+ rv = SECITEM_MakeItem(NULL, out, dcBuf.buf, dcBuf.len);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ SECKEY_DestroySubjectPublicKeyInfo(spki);
+ SECKEY_DestroyPrivateKey(tmpPriv);
+ tls13_DestroyDelegatedCredential(dc);
+ sslBuffer_Clear(&dcBuf);
+ return SECSuccess;
+
+loser:
+ SECKEY_DestroySubjectPublicKeyInfo(spki);
+ SECKEY_DestroyPrivateKey(tmpPriv);
+ tls13_DestroyDelegatedCredential(dc);
+ sslBuffer_Clear(&dcBuf);
+ return SECFailure;
+}
diff --git a/security/nss/lib/ssl/tls13subcerts.h b/security/nss/lib/ssl/tls13subcerts.h
new file mode 100644
index 0000000000..ce9996bb80
--- /dev/null
+++ b/security/nss/lib/ssl/tls13subcerts.h
@@ -0,0 +1,56 @@
+/* -*- 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 __tls13subcerts_h_
+#define __tls13subcerts_h_
+
+struct sslDelegatedCredentialStr {
+ /* The number of seconds for which the delegated credential (DC) is valid
+ * following the notBefore parameter of the delegation certificate.
+ */
+ PRUint32 validTime;
+
+ /* The signature algorithm of the DC public key. This expected to the same
+ * as CertificateVerify.scheme.
+ */
+ SSLSignatureScheme expectedCertVerifyAlg;
+
+ /* The DER-encoded SubjectPublicKeyInfo, the DC public key.
+ */
+ SECItem derSpki;
+
+ /* The decoded SubjectPublicKeyInfo parsed from |derSpki|. */
+ CERTSubjectPublicKeyInfo *spki;
+
+ /* The signature algorithm used to verify the DC signature. */
+ SSLSignatureScheme alg;
+
+ /* The DC signature. */
+ SECItem signature;
+};
+
+SECStatus tls13_ReadDelegatedCredential(PRUint8 *b,
+ PRUint32 length,
+ sslDelegatedCredential **dcp);
+void tls13_DestroyDelegatedCredential(sslDelegatedCredential *dc);
+
+PRBool tls13_IsVerifyingWithDelegatedCredential(const sslSocket *ss);
+PRBool tls13_IsSigningWithDelegatedCredential(const sslSocket *ss);
+SECStatus tls13_MaybeSetDelegatedCredential(sslSocket *ss);
+SECStatus tls13_VerifyDelegatedCredential(sslSocket *ss,
+ sslDelegatedCredential *dc);
+
+SECStatus SSLExp_DelegateCredential(const CERTCertificate *cert,
+ const SECKEYPrivateKey *certPriv,
+ const SECKEYPublicKey *dcPub,
+ SSLSignatureScheme dcCertVerifyAlg,
+ PRUint32 dcValidFor,
+ PRTime now,
+ SECItem *out);
+
+#endif