summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/ssl/ssl3con.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/ssl/ssl3con.c')
-rw-r--r--security/nss/lib/ssl/ssl3con.c1088
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);
}