diff options
author | wolfbeast <mcwerewolf@wolfbeast.com> | 2020-01-02 21:06:40 +0100 |
---|---|---|
committer | wolfbeast <mcwerewolf@wolfbeast.com> | 2020-01-02 21:06:40 +0100 |
commit | f4a12fc67689a830e9da1c87fd11afe5bc09deb3 (patch) | |
tree | 211ae0cd022a6c11b0026ecc7761a550c584583c /security/nss/lib/ssl | |
parent | f7d30133221896638f7bf4f66c504255c4b14f48 (diff) | |
download | UXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.tar UXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.tar.gz UXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.tar.lz UXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.tar.xz UXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.zip |
Issue #1338 - Part 2: Update NSS to 3.48-RTM
Diffstat (limited to 'security/nss/lib/ssl')
44 files changed, 4177 insertions, 1106 deletions
diff --git a/security/nss/lib/ssl/SSLerrs.h b/security/nss/lib/ssl/SSLerrs.h index 9be219494..87b59b1e8 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 d05b30a72..737b4e797 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 b901a8830..d13613f78 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 81d196dee..0c4fc7fcd 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 a5c604bca..bbd2f6d79 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 fe9470bd0..83df8c0b8 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 2e28f6775..3e1b5531a 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 fc4a4a70c..dc5a9d4cd 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 d98521a52..f3c723bbc 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 52d5bb515..d5ad372e5 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 60b5889e7..7e674f0e0 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 d96b4cffe..97319c7d9 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 a2d83fa97..206cb00e4 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 64a1878f7..f9c741746 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 bfaa10d3f..ffe837301 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 5b5f672f0..f4c364251 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 878df761e..d2c9480d5 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 fb31d1389..8c2dadae4 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 bc63e1537..a6ef2a4a3 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 be5bcb269..3ed197950 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 e50880451..e59e758ff 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 a4aa27657..7100b0226 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 f450e528d..b734d86ca 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 35240d2fb..4a393b281 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 4e58c5ae7..b069888e2 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 f8fb5d50f..b7b5b7fe5 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 000000000..540c17840 --- /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 c011b66a1..14320fa19 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 d7abb3dc3..36c82117e 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 ae904e29b..aa0e76e3c 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 f2e72a4ec..def3c6750 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 b25601755..ca9ef540f 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 bd32a6e18..47efa2e4d 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 461cd2eb9..c3528a52f 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, ¶m, - out, &uOutLen, maxout, in, inlen); - } else { - rv = PK11_Encrypt(keys->key, mechanism, ¶m, - out, &uOutLen, maxout, in, inlen); + return PK11_Decrypt(keys->key, mechanism, ¶m, + out, outlen, maxout, in, inlen); } - *outlen = (int)uOutLen; - - return rv; + return PK11_Encrypt(keys->key, mechanism, ¶m, + 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 f3b2cb390..bd309419f 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 e2328769b..f2f8d0a9c 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 6c52c9952..0fb12d25e 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 8ed18f69c..1f88016a1 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 dd64b44ff..abc7f9deb 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 cc0ed286b..53d3738f0 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 8fa3375c6..ab546e06f 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 b090f9bca..628011144 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 000000000..8ae5447f7 --- /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, ¶ms, + 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 000000000..ce9996bb8 --- /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 |