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/ssl3con.c | |
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/ssl3con.c')
-rw-r--r-- | security/nss/lib/ssl/ssl3con.c | 1088 |
1 files changed, 726 insertions, 362 deletions
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); } |