diff --git a/external_tests/ssl_gtest/ssl_loopback_unittest.cc b/external_tests/ssl_gtest/ssl_loopback_unittest.cc
--- a/external_tests/ssl_gtest/ssl_loopback_unittest.cc
+++ b/external_tests/ssl_gtest/ssl_loopback_unittest.cc
@@ -318,23 +318,21 @@ TEST_P(TlsConnectPre12, SignatureAlgorit
ResetEcdsa();
client_->SetSignatureAlgorithms(SignatureEcdsaSha384,
PR_ARRAY_SIZE(SignatureEcdsaSha384));
server_->SetSignatureAlgorithms(SignatureEcdsaSha256,
PR_ARRAY_SIZE(SignatureEcdsaSha256));
Connect();
}
-// The server requests client auth but doesn't offer a SHA-256 option.
-// This fails because NSS only uses SHA-256 for handshake transcript hashes.
-TEST_P(TlsConnectTls12, RequestClientAuthWithoutSha256) {
+TEST_P(TlsConnectTls12, RequestClientAuthWithSha384) {
server_->SetSignatureAlgorithms(SignatureRsaSha384,
PR_ARRAY_SIZE(SignatureRsaSha384));
server_->RequestClientAuth(false);
- ConnectExpectFail();
+ Connect();
}
TEST_P(TlsConnectGeneric, ConnectAlpn) {
EnableAlpn();
Connect();
client_->CheckAlpn(SSL_NEXT_PROTO_SELECTED, "a");
server_->CheckAlpn(SSL_NEXT_PROTO_NEGOTIATED, "a");
}
diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c
--- a/lib/ssl/ssl3con.c
+++ b/lib/ssl/ssl3con.c
@@ -3636,16 +3636,29 @@ ssl3_GetPrfHashMechanism(sslSocket *ss)
SSL3PRF prf_alg = ss->ssl3.hs.suite_def->prf_alg;
if (prf_alg == 0)
return CKM_SHA256;
return prf_alg;
}
+static SSLHashType
+ssl3_GetSuitePrfHash(sslSocket *ss)
+{
+ switch (ss->ssl3.hs.suite_def->prf_alg) {
+ case CKM_SHA384:
+ return ssl_hash_sha384;
+ case 0:
+ case CKM_SHA256:
+ default:
+ return ssl_hash_sha256;
+ }
+}
+
/* This method completes the derivation of the MS from the PMS.
**
** 1. Derive the MS, if possible, else return an error.
**
** 2. Check the version if |pms_version| is non-zero and if wrong,
** return an error.
**
@@ -3813,17 +3826,17 @@ tls_ComputeExtendedMasterSecretInt(sslSo
master_derive = CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_DH;
} else {
master_derive = CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE;
pms_version_ptr = &pms_version;
}
if (pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
/* TLS 1.2 */
- extended_master_params.prfHashMechanism = CKM_SHA256;
+ extended_master_params.prfHashMechanism = ssl3_GetPrfHashMechanism(ss);
key_derive = CKM_TLS12_KEY_AND_MAC_DERIVE;
} else {
/* TLS < 1.2 */
extended_master_params.prfHashMechanism = CKM_TLS_PRF;
key_derive = CKM_TLS_KEY_AND_MAC_DERIVE;
}
extended_master_params.pVersion = pms_version_ptr;
@@ -4071,20 +4084,23 @@ loser:
/* ssl3_InitHandshakeHashes creates handshake hash contexts and hashes in
* buffered messages in ss->ssl3.hs.messages. */
static SECStatus
ssl3_InitHandshakeHashes(sslSocket *ss)
{
SSL_TRC(30,("%d: SSL3[%d]: start handshake hashes", SSL_GETPID(), ss->fd));
PORT_Assert(ss->ssl3.hs.hashType == handshake_hash_unknown);
+ if (ss->version == SSL_LIBRARY_VERSION_TLS_1_2) {
+ ss->ssl3.hs.hashType = handshake_hash_record;
+ } else
#ifndef NO_PKCS11_BYPASS
if (ss->opt.bypassPKCS11) {
PORT_Assert(!ss->ssl3.hs.sha_obj && !ss->ssl3.hs.sha_clone);
- if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
+ if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
/* If we ever support ciphersuites where the PRF hash isn't SHA-256
* then this will need to be updated. */
HASH_HashType ht;
CK_MECHANISM_TYPE hm;
SECOidTag ot;
SECOidData *hashOid;
hm = ssl3_GetPrfHashMechanism(ss);
@@ -4112,17 +4128,17 @@ ssl3_InitHandshakeHashes(sslSocket *ss)
#endif
{
PORT_Assert(!ss->ssl3.hs.md5 && !ss->ssl3.hs.sha);
/*
* note: We should probably lookup an SSL3 slot for these
* handshake hashes in hopes that we wind up with the same slots
* that the master secret will wind up in ...
*/
- if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
+ if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
/* determine the hash from the prf */
const SECOidData *hash_oid;
PORT_Assert(ss->ssl3.hs.suite_def);
/* Get the PKCS #11 mechanism for the Hash from the cipher suite (prf_alg)
* Convert that to the OidTag. We can then use that OidTag to create our
* PK11Context */
hash_oid = SECOID_FindOIDByMechanism(ssl3_GetPrfHashMechanism(ss));
@@ -4137,38 +4153,16 @@ ssl3_InitHandshakeHashes(sslSocket *ss)
return SECFailure;
}
ss->ssl3.hs.hashType = handshake_hash_single;
if (PK11_DigestBegin(ss->ssl3.hs.sha) != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
return SECFailure;
}
-
- /* Create a backup SHA-1 hash for a potential client auth
- * signature.
- *
- * In TLS 1.2, ssl3_ComputeHandshakeHashes always uses the
- * handshake hash function (SHA-256). If the server or the client
- * does not support SHA-256 as a signature hash, we can either
- * maintain a backup SHA-1 handshake hash or buffer all handshake
- * messages.
- */
- if (!ss->sec.isServer) {
- ss->ssl3.hs.backupHash = PK11_CreateDigestContext(SEC_OID_SHA1);
- if (ss->ssl3.hs.backupHash == NULL) {
- ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
- return SECFailure;
- }
-
- if (PK11_DigestBegin(ss->ssl3.hs.backupHash) != SECSuccess) {
- ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
- return SECFailure;
- }
- }
} else {
/* Both ss->ssl3.hs.md5 and ss->ssl3.hs.sha should be NULL or
* created successfully. */
ss->ssl3.hs.md5 = PK11_CreateDigestContext(SEC_OID_MD5);
if (ss->ssl3.hs.md5 == NULL) {
ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
return SECFailure;
}
@@ -4187,26 +4181,23 @@ ssl3_InitHandshakeHashes(sslSocket *ss)
}
if (PK11_DigestBegin(ss->ssl3.hs.sha) != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
return SECFailure;
}
}
}
- if (ss->ssl3.hs.messages.len > 0) {
- if (ssl3_UpdateHandshakeHashes(ss, ss->ssl3.hs.messages.buf,
- ss->ssl3.hs.messages.len) !=
- SECSuccess) {
- return SECFailure;
- }
- PORT_Free(ss->ssl3.hs.messages.buf);
- ss->ssl3.hs.messages.buf = NULL;
- ss->ssl3.hs.messages.len = 0;
- ss->ssl3.hs.messages.space = 0;
+ if (ss->ssl3.hs.hashType != handshake_hash_record &&
+ ss->ssl3.hs.messages.len > 0) {
+ if (ssl3_UpdateHandshakeHashes(ss, ss->ssl3.hs.messages.buf,
+ ss->ssl3.hs.messages.len) != SECSuccess) {
+ return SECFailure;
+ }
+ sslBuffer_Clear(&ss->ssl3.hs.messages);
}
return SECSuccess;
}
static SECStatus
ssl3_RestartHandshakeHashes(sslSocket *ss)
{
@@ -4237,66 +4228,71 @@ ssl3_RestartHandshakeHashes(sslSocket *s
/* Called from ssl3_InitHandshakeHashes()
** ssl3_AppendHandshake()
** ssl3_StartHandshakeHash()
** ssl3_HandleV2ClientHello()
** ssl3_HandleHandshakeMessage()
** Caller must hold the ssl3Handshake lock.
*/
static SECStatus
-ssl3_UpdateHandshakeHashes(sslSocket *ss, const unsigned char *b,
- unsigned int l)
+ssl3_UpdateHandshakeHashes(sslSocket *ss, const unsigned char *b, unsigned int l)
{
SECStatus rv = SECSuccess;
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
- /* We need to buffer the handshake messages until we have established
- * which handshake hash function to use. */
- if (ss->ssl3.hs.hashType == handshake_hash_unknown) {
- return sslBuffer_Append(&ss->ssl3.hs.messages, b, l);
+ /* With TLS 1.3, and versions TLS.1.1 and older, we keep the hash(es)
+ * always up to date. However, we must initially buffer the handshake
+ * messages, until we know what to do.
+ * If ss->ssl3.hs.hashType != handshake_hash_unknown,
+ * it means we know what to do. We calculate (hash our input),
+ * and we stop appending to the buffer.
+ *
+ * With TLS 1.2, we always append all handshake messages,
+ * and never update the hash, because the hash function we must use for
+ * certificate_verify might be different from the hash function we use
+ * when signing other handshake hashes. */
+
+ if (ss->ssl3.hs.hashType == handshake_hash_unknown ||
+ ss->ssl3.hs.hashType == handshake_hash_record) {
+ return sslBuffer_Append(&ss->ssl3.hs.messages, b, l);
}
PRINT_BUF(90, (NULL, "handshake hash input:", b, l));
#ifndef NO_PKCS11_BYPASS
if (ss->opt.bypassPKCS11) {
if (ss->ssl3.hs.hashType == handshake_hash_single) {
- ss->ssl3.hs.sha_obj->update(ss->ssl3.hs.sha_cx, b, l);
- } else {
+ PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
+ ss->ssl3.hs.sha_obj->update(ss->ssl3.hs.sha_cx, b, l);
+ } else if (ss->ssl3.hs.hashType == handshake_hash_combo) {
MD5_Update((MD5Context *)ss->ssl3.hs.md5_cx, b, l);
SHA1_Update((SHA1Context *)ss->ssl3.hs.sha_cx, b, l);
}
return rv;
}
#endif
if (ss->ssl3.hs.hashType == handshake_hash_single) {
- rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l);
- if (rv != SECSuccess) {
- ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
- return rv;
- }
- if (ss->ssl3.hs.backupHash) {
- rv = PK11_DigestOp(ss->ssl3.hs.backupHash, b, l);
- if (rv != SECSuccess) {
- ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
- return rv;
- }
- }
- } else {
- rv = PK11_DigestOp(ss->ssl3.hs.md5, b, l);
- if (rv != SECSuccess) {
- ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
- return rv;
- }
- rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l);
- if (rv != SECSuccess) {
- ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
- return rv;
- }
+ PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
+ rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l);
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
+ return rv;
+ }
+ } else if (ss->ssl3.hs.hashType == handshake_hash_combo) {
+ rv = PK11_DigestOp(ss->ssl3.hs.md5, b, l);
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
+ return rv;
+ }
+ rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l);
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
+ return rv;
+ }
}
return rv;
}
/**************************************************************************
* Append Handshake functions.
* All these functions set appropriate error codes.
* Most rely on ssl3_AppendHandshake to set the error code.
@@ -4759,16 +4755,68 @@ ssl3_ConsumeSignatureAndHashAlgorithm(ss
}
return SECSuccess;
}
/**************************************************************************
* end of Consume Handshake functions.
**************************************************************************/
+#ifndef NO_PKCS11_BYPASS
+static SECStatus
+ssl3_ComputeBypassHandshakeHash(unsigned char *buf, unsigned int len,
+ SSLHashType hashAlg, SSL3Hashes *hashes)
+{
+ const SECHashObject *h_obj = NULL;
+ PRUint64 h_cx[MAX_MAC_CONTEXT_LLONGS];
+ const SECOidData *hashOid =
+ SECOID_FindOIDByMechanism(ssl3_GetHashMechanismByHashType(hashAlg));
+
+ if (hashOid) {
+ h_obj = HASH_GetRawHashObject(HASH_GetHashTypeByOidTag(hashOid->offset));
+ }
+ if (!h_obj) {
+ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
+ return SECFailure;
+ }
+ h_obj->begin(h_cx);
+ h_obj->update(h_cx, buf, len);
+ h_obj->end(h_cx, hashes->u.raw, &hashes->len, sizeof(hashes->u.raw));
+ PRINT_BUF(60, (NULL, "HASH: result", hashes->u.raw, hashes->len));
+ hashes->hashAlg = hashAlg;
+ return SECSuccess;
+}
+#endif
+
+static SECStatus
+ssl3_ComputePkcs11HandshakeHash(unsigned char *buf, unsigned int len,
+ SSLHashType hashAlg, SSL3Hashes *hashes)
+{
+ SECStatus rv = SECFailure;
+ PK11Context *hashContext = PK11_CreateDigestContext(
+ ssl3_TLSHashAlgorithmToOID(hashAlg));
+
+ if (!hashContext) {
+ return rv;
+ }
+ rv = PK11_DigestBegin(hashContext);
+ if (rv == SECSuccess) {
+ rv = PK11_DigestOp(hashContext, buf, len);
+ }
+ if (rv == SECSuccess) {
+ rv = PK11_DigestFinal(hashContext, hashes->u.raw, &hashes->len,
+ sizeof(hashes->u.raw));
+ }
+ if (rv == SECSuccess) {
+ hashes->hashAlg = hashAlg;
+ }
+ PK11_DestroyContext(hashContext, PR_TRUE);
+ return rv;
+}
+
/* Extract the hashes of handshake messages to this point.
* Called from ssl3_SendCertificateVerify
* ssl3_SendFinished
* ssl3_HandleHandshakeMessage
*
* Caller must hold the SSL3HandshakeLock.
* Caller must hold a read or write lock on the Spec R/W lock.
* (There is presently no way to assert on a Read lock.)
@@ -4798,23 +4846,27 @@ ssl3_ComputeHandshakeHashes(sslSocket *
ss->ssl3.hs.hashType == handshake_hash_single) {
/* compute them without PKCS11 */
PRUint64 sha_cx[MAX_MAC_CONTEXT_LLONGS];
ss->ssl3.hs.sha_clone(sha_cx, ss->ssl3.hs.sha_cx);
ss->ssl3.hs.sha_obj->end(sha_cx, hashes->u.raw, &hashes->len,
sizeof(hashes->u.raw));
- PRINT_BUF(60, (NULL, "SHA-256: result", hashes->u.raw, hashes->len));
-
- /* If we ever support ciphersuites where the PRF hash isn't SHA-256
- * then this will need to be updated. */
- hashes->hashAlg = ssl_hash_sha256;
+ PRINT_BUF(60, (NULL, "HASH: result", hashes->u.raw, hashes->len));
+
+ hashes->hashAlg = ssl3_GetSuitePrfHash(ss);
rv = SECSuccess;
- } else if (ss->opt.bypassPKCS11) {
+ } else if (ss->opt.bypassPKCS11 &&
+ ss->ssl3.hs.hashType == handshake_hash_record) {
+ rv = ssl3_ComputeBypassHandshakeHash(ss->ssl3.hs.messages.buf,
+ ss->ssl3.hs.messages.len,
+ ssl3_GetSuitePrfHash(ss),
+ hashes);
+ } else if (ss->opt.bypassPKCS11) { /* TLS 1.1 or lower */
/* compute them without PKCS11 */
PRUint64 md5_cx[MAX_MAC_CONTEXT_LLONGS];
PRUint64 sha_cx[MAX_MAC_CONTEXT_LLONGS];
#define md5cx ((MD5Context *)md5_cx)
#define shacx ((SHA1Context *)sha_cx)
MD5_Clone (md5cx, (MD5Context *)ss->ssl3.hs.md5_cx);
@@ -4942,16 +4994,21 @@ tls12_loser:
if (PK11_RestoreContext(h, stateBuf, stateLen) != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
rv = SECFailure;
}
if (stateBuf != stackBuf) {
PORT_ZFree(stateBuf, stateLen);
}
}
+ } else if (ss->ssl3.hs.hashType == handshake_hash_record) {
+ rv = ssl3_ComputePkcs11HandshakeHash(ss->ssl3.hs.messages.buf,
+ ss->ssl3.hs.messages.len,
+ ssl3_GetSuitePrfHash(ss),
+ hashes);
} else {
/* compute hashes with PKCS11 */
PK11Context * md5;
PK11Context * sha = NULL;
unsigned char *md5StateBuf = NULL;
unsigned char *shaStateBuf = NULL;
unsigned int md5StateLen, shaStateLen;
unsigned char md5StackBuf[256];
@@ -5096,41 +5153,16 @@ tls12_loser:
if (shaStateBuf != shaStackBuf) {
PORT_ZFree(shaStateBuf, shaStateLen);
}
}
}
return rv;
}
-static SECStatus
-ssl3_ComputeBackupHandshakeHashes(sslSocket * ss,
- SSL3Hashes * hashes) /* output goes here. */
-{
- SECStatus rv = SECSuccess;
-
- PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
- PORT_Assert( !ss->sec.isServer );
- PORT_Assert( ss->ssl3.hs.hashType == handshake_hash_single );
-
- rv = PK11_DigestFinal(ss->ssl3.hs.backupHash, hashes->u.raw, &hashes->len,
- sizeof(hashes->u.raw));
- if (rv != SECSuccess) {
- ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
- rv = SECFailure;
- goto loser;
- }
- hashes->hashAlg = ssl_hash_sha1;
-
-loser:
- PK11_DestroyContext(ss->ssl3.hs.backupHash, PR_TRUE);
- ss->ssl3.hs.backupHash = NULL;
- return rv;
-}
-
/*
* SSL 2 based implementations pass in the initial outbound buffer
* so that the handshake hash can contain the included information.
*
* Called from ssl2_BeginClientHandshake() in sslcon.c
*/
SECStatus
ssl3_StartHandshakeHash(sslSocket *ss, unsigned char * buf, int length)
@@ -6451,26 +6483,44 @@ ssl3_SendCertificateVerify(sslSocket *ss
PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
SSL_TRC(3, ("%d: SSL3[%d]: send certificate_verify handshake",
SSL_GETPID(), ss->fd));
ssl_GetSpecReadLock(ss);
- if (ss->ssl3.hs.hashType == handshake_hash_single &&
- ss->ssl3.hs.backupHash) {
- rv = ssl3_ComputeBackupHandshakeHashes(ss, &hashes);
- PORT_Assert(!ss->ssl3.hs.backupHash);
+
+ if (ss->ssl3.hs.hashType == handshake_hash_record &&
+ ss->ssl3.hs.tls12CertVerifyHash != ssl3_GetSuitePrfHash(ss)) {
+#ifndef NO_PKCS11_BYPASS
+ if (ss->opt.bypassPKCS11) {
+ rv = ssl3_ComputeBypassHandshakeHash(ss->ssl3.hs.messages.buf,
+ ss->ssl3.hs.messages.len,
+ ss->ssl3.hs.tls12CertVerifyHash,
+ &hashes);
+ } else
+#endif
+ {
+ rv = ssl3_ComputePkcs11HandshakeHash(ss->ssl3.hs.messages.buf,
+ ss->ssl3.hs.messages.len,
+ ss->ssl3.hs.tls12CertVerifyHash,
+ &hashes);
+ }
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
+ goto done;
+ }
} else {
- rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.pwSpec, &hashes, 0);
- }
+ rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.pwSpec, &hashes, 0);
+ }
+
ssl_ReleaseSpecReadLock(ss);
if (rv != SECSuccess) {
- goto done; /* err code was set by ssl3_ComputeHandshakeHashes */
+ goto done; /* err code was set by ssl3_ComputeHandshakeHashes */
}
isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
keyType = ss->ssl3.clientPrivateKey->keyType;
rv = ssl3_SignHashes(&hashes, ss->ssl3.clientPrivateKey, &buf, isTLS);
if (rv == SECSuccess) {
PK11SlotInfo * slot;
@@ -7249,88 +7299,18 @@ ssl3_ExtractClientKeyInfo(sslSocket *ss,
}
done:
if (pubk)
SECKEY_DestroyPublicKey(pubk);
return rv;
}
-/* Destroys the backup handshake hash context if we don't need it. Note that
- * this function selects the hash algorithm for client authentication
- * signatures; ssl3_SendCertificateVerify uses the presence of the backup hash
- * to determine whether to use SHA-1, or the PRF hash of the cipher suite. */
static void
-ssl3_DestroyBackupHandshakeHashIfNotNeeded(sslSocket *ss,
- const SECItem *algorithms)
-{
- SECStatus rv;
- SSLSignType sigAlg;
- PRBool preferSha1;
- PRBool supportsSha1 = PR_FALSE;
- PRBool supportsHandshakeHash = PR_FALSE;
- PRBool needBackupHash = PR_FALSE;
- unsigned int i;
- SECOidData *hashOid;
- TLSHashAlgorithm suitePRFHash;
- PRBool suitePRFIs256Or384 = PR_FALSE;
-
-#ifndef NO_PKCS11_BYPASS
- /* Backup handshake hash is not supported in PKCS #11 bypass mode. */
- if (ss->opt.bypassPKCS11) {
- PORT_Assert(!ss->ssl3.hs.backupHash);
- return;
- }
-#endif
- PORT_Assert(ss->ssl3.hs.backupHash);
-
- /* Determine the key's signature algorithm and whether it prefers SHA-1. */
- rv = ssl3_ExtractClientKeyInfo(ss, &sigAlg, &preferSha1);
- if (rv != SECSuccess) {
- goto done;
- }
-
- hashOid = SECOID_FindOIDByMechanism(ssl3_GetPrfHashMechanism(ss));
- if (hashOid == NULL) {
- rv = SECFailure;
- goto done;
- }
-
- if (hashOid->offset == SEC_OID_SHA256) {
- suitePRFHash = tls_hash_sha256;
- suitePRFIs256Or384 = PR_TRUE;
- } else if (hashOid->offset == SEC_OID_SHA384) {
- suitePRFHash = tls_hash_sha384;
- suitePRFIs256Or384 = PR_TRUE;
- }
-
- /* Determine the server's hash support for that signature algorithm. */
- for (i = 0; i < algorithms->len; i += 2) {
- if (algorithms->data[i+1] == sigAlg) {
- if (algorithms->data[i] == ssl_hash_sha1) {
- supportsSha1 = PR_TRUE;
- } else if (suitePRFIs256Or384 &&
- algorithms->data[i] == suitePRFHash) {
- supportsHandshakeHash = PR_TRUE;
- }
- }
- }
-
- /* If either the server does not support SHA-256 or the client key prefers
- * SHA-1, leave the backup hash. */
- if (supportsSha1 && (preferSha1 || !supportsHandshakeHash)) {
- needBackupHash = PR_TRUE;
- }
-
-done:
- if (!needBackupHash) {
- PK11_DestroyContext(ss->ssl3.hs.backupHash, PR_TRUE);
- ss->ssl3.hs.backupHash = NULL;
- }
-}
+ssl3_DecideTls12CertVerifyHash(sslSocket *ss, const SECItem *algorithms);
typedef struct dnameNode {
struct dnameNode *next;
SECItem name;
} dnameNode;
/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
* ssl3 Certificate Request message.
@@ -7486,19 +7466,20 @@ ssl3_HandleCertificateRequest(sslSocket
certUsageSSLClient, PR_FALSE);
if (ss->ssl3.clientCertChain == NULL) {
CERT_DestroyCertificate(ss->ssl3.clientCertificate);
ss->ssl3.clientCertificate = NULL;
SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
ss->ssl3.clientPrivateKey = NULL;
goto send_no_certificate;
}
- if (ss->ssl3.hs.hashType == handshake_hash_single) {
- ssl3_DestroyBackupHandshakeHashIfNotNeeded(ss, &algorithms);
- }
+ if (ss->ssl3.hs.hashType == handshake_hash_record ||
+ ss->ssl3.hs.hashType == handshake_hash_single) {
+ ssl3_DecideTls12CertVerifyHash(ss, &algorithms);
+ }
break; /* not an error */
case SECFailure:
default:
send_no_certificate:
if (isTLS) {
ss->ssl3.sendEmptyCert = PR_TRUE;
} else {
@@ -7639,24 +7620,16 @@ ssl3_SendClientSecondRound(sslSocket *ss
PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
sendClientCert = !ss->ssl3.sendEmptyCert &&
ss->ssl3.clientCertChain != NULL &&
ss->ssl3.clientPrivateKey != NULL;
- if (!sendClientCert &&
- ss->ssl3.hs.hashType == handshake_hash_single &&
- ss->ssl3.hs.backupHash) {
- /* Don't need the backup handshake hash. */
- PK11_DestroyContext(ss->ssl3.hs.backupHash, PR_TRUE);
- ss->ssl3.hs.backupHash = NULL;
- }
-
/* We must wait for the server's certificate to be authenticated before
* sending the client certificate in order to disclosing the client
* certificate to an attacker that does not have a valid cert for the
* domain we are connecting to.
*
* XXX: We should do the same for the NPN extension, but for that we
* need an option to give the application the ability to leak the NPN
* information to get better performance.
@@ -9415,16 +9388,69 @@ ssl3_PickSignatureHashAlgorithm(sslSocke
}
}
}
PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
return SECFailure;
}
+static void
+ssl3_DecideTls12CertVerifyHash(sslSocket *ss, const SECItem *algorithms)
+{
+ SECStatus rv;
+ SSLSignType sigAlg;
+ PRBool preferSha1 = PR_FALSE;
+ PRBool supportsSha1 = PR_FALSE;
+ PRBool supportsHandshakeHash = PR_FALSE;
+ unsigned int i;
+ SSLHashType otherHashAlg = ssl_hash_none;
+
+ /* Determine the key's signature algorithm and whether it prefers SHA-1. */
+ rv = ssl3_ExtractClientKeyInfo(ss, &sigAlg, &preferSha1);
+ if (rv != SECSuccess) {
+ return;
+ }
+
+ /* Determine the server's hash support for that signature algorithm. */
+ for (i = 0; i < algorithms->len; i += 2) {
+ if (algorithms->data[i + 1] == sigAlg) {
+ SSLHashType hashAlg = algorithms->data[i];
+ SECOidTag hashOID;
+ PRUint32 policy;
+ if (hashAlg == ssl_hash_sha1 &&
+ ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ /* TLS 1.3 explicitly forbids using SHA-1 with certificate_verify. */
+ continue;
+ }
+ hashOID = ssl3_TLSHashAlgorithmToOID(hashAlg);
+ if ((NSS_GetAlgorithmPolicy(hashOID, &policy) == SECSuccess) &&
+ !(policy & NSS_USE_ALG_IN_SSL_KX)) {
+ /* we ignore hashes we don't support */
+ continue;
+ }
+ if (hashAlg == ssl_hash_sha1) {
+ supportsSha1 = PR_TRUE;
+ } else if (hashAlg == ssl3_GetSuitePrfHash(ss)) {
+ supportsHandshakeHash = PR_TRUE;
+ }
+ if (otherHashAlg == ssl_hash_none) {
+ otherHashAlg = hashAlg;
+ }
+ }
+ }
+
+ if (supportsSha1 && preferSha1) {
+ ss->ssl3.hs.tls12CertVerifyHash = ssl_hash_sha1;
+ } else if (supportsHandshakeHash) {
+ ss->ssl3.hs.tls12CertVerifyHash = ssl3_GetSuitePrfHash(ss); /* Use suite PRF hash. */
+ } else {
+ ss->ssl3.hs.tls12CertVerifyHash = otherHashAlg;
+ }
+}
static SECStatus
ssl3_SendServerKeyExchange(sslSocket *ss)
{
const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def;
SECStatus rv = SECFailure;
int length;
PRBool isTLS;
@@ -9534,38 +9560,32 @@ ssl3_SendServerKeyExchange(sslSocket *ss
}
loser:
if (signed_hash.data != NULL)
PORT_Free(signed_hash.data);
return SECFailure;
}
static SECStatus
-ssl3_EncodeCertificateRequestSigAlgs(sslSocket *ss, PRUint8 allowedHashAlg,
- PRUint8 *buf,
+ssl3_EncodeCertificateRequestSigAlgs(sslSocket *ss, PRUint8 *buf,
unsigned maxLen, PRUint32 *len)
{
unsigned int i;
PORT_Assert(maxLen >= ss->ssl3.signatureAlgorithmCount * 2);
if (maxLen < ss->ssl3.signatureAlgorithmCount * 2) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
*len = 0;
for (i = 0; i < ss->ssl3.signatureAlgorithmCount; ++i) {
const SSLSignatureAndHashAlg *alg = &ss->ssl3.signatureAlgorithms[i];
- /* Note that we don't support a handshake hash with anything other than
- * SHA-256, so asking for a signature from clients for something else
- * would be inviting disaster. */
- if (alg->hashAlg == allowedHashAlg) {
- buf[(*len)++] = (PRUint8)alg->hashAlg;
- buf[(*len)++] = (PRUint8)alg->sigAlg;
- }
+ buf[(*len)++] = (PRUint8)alg->hashAlg;
+ buf[(*len)++] = (PRUint8)alg->sigAlg;
}
if (*len == 0) {
PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
return SECFailure;
}
return SECSuccess;
}
@@ -9582,17 +9602,16 @@ ssl3_SendCertificateRequest(sslSocket *s
int length;
int i;
int calen = 0;
int nnames = 0;
int certTypesLength;
PRUint8 sigAlgs[MAX_SIGNATURE_ALGORITHMS * 2];
unsigned int sigAlgsLength = 0;
SECOidData *hashOid;
- PRUint8 allowedHashAlg;
SSL_TRC(3, ("%d: SSL3[%d]: send certificate_request handshake",
SSL_GETPID(), ss->fd));
PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
@@ -9615,27 +9634,19 @@ ssl3_SendCertificateRequest(sslSocket *s
certTypes = certificate_types;
certTypesLength = sizeof certificate_types;
hashOid = SECOID_FindOIDByMechanism(ssl3_GetPrfHashMechanism(ss));
if (hashOid == NULL) {
return SECFailure; /* err set by AppendHandshake. */
}
- if (hashOid->offset == SEC_OID_SHA256) {
- allowedHashAlg = ssl_hash_sha256;
- } else if (hashOid->offset == SEC_OID_SHA384) {
- allowedHashAlg = ssl_hash_sha384;
- } else {
- return SECFailure; /* err set by AppendHandshake. */
- }
-
length = 1 + certTypesLength + 2 + calen;
if (isTLS12) {
- rv = ssl3_EncodeCertificateRequestSigAlgs(ss, allowedHashAlg,
+ rv = ssl3_EncodeCertificateRequestSigAlgs(ss,
sigAlgs, sizeof(sigAlgs),
&sigAlgsLength);
if (rv != SECSuccess) {
return rv;
}
length += 2 + sigAlgsLength;
}
@@ -9696,70 +9707,89 @@ ssl3_SendServerHelloDone(sslSocket *ss)
static SECStatus
ssl3_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
SSL3Hashes *hashes)
{
SECItem signed_hash = {siBuffer, NULL, 0};
SECStatus rv;
int errCode = SSL_ERROR_RX_MALFORMED_CERT_VERIFY;
SSL3AlertDescription desc = handshake_failure;
- PRBool isTLS, isTLS12;
+ PRBool isTLS;
SSLSignatureAndHashAlg sigAndHash;
+ SSL3Hashes localHashes;
+ SSL3Hashes *hashesForVerify = NULL;
SSL_TRC(3, ("%d: SSL3[%d]: handle certificate_verify handshake",
SSL_GETPID(), ss->fd));
PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+ /* TLS 1.3 is handled by tls13_HandleCertificateVerify */
+ PORT_Assert(ss->ssl3.prSpec->version <= SSL_LIBRARY_VERSION_TLS_1_2);
+
isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
- isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
if (ss->ssl3.hs.ws != wait_cert_verify) {
desc = unexpected_message;
errCode = SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY;
goto alert_loser;
}
- if (!hashes) {
- PORT_Assert(0);
- desc = internal_error;
- errCode = SEC_ERROR_LIBRARY_FAILURE;
- goto alert_loser;
- }
-
- if (isTLS12) {
+ if (ss->ssl3.hs.hashType != handshake_hash_record) {
+ if (!hashes) {
+ PORT_Assert(0);
+ desc = internal_error;
+ errCode = SEC_ERROR_LIBRARY_FAILURE;
+ goto alert_loser;
+ }
+ hashesForVerify = hashes;
+ } else {
rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length,
&sigAndHash);
if (rv != SECSuccess) {
goto loser; /* malformed or unsupported. */
}
rv = ssl3_CheckSignatureAndHashAlgorithmConsistency(
ss, &sigAndHash, ss->sec.peerCert);
if (rv != SECSuccess) {
errCode = PORT_GetError();
desc = decrypt_error;
goto alert_loser;
}
- /* We only support CertificateVerify messages that use the handshake
- * hash. */
- if (sigAndHash.hashAlg != hashes->hashAlg) {
- errCode = SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM;
+#ifndef NO_PKCS11_BYPASS
+ if (ss->opt.bypassPKCS11) {
+ rv = ssl3_ComputeBypassHandshakeHash(hashes->u.pointer_to_hash_input.data,
+ hashes->u.pointer_to_hash_input.len,
+ sigAndHash.hashAlg,
+ &localHashes);
+ } else
+#endif
+ {
+ rv = ssl3_ComputePkcs11HandshakeHash(hashes->u.pointer_to_hash_input.data,
+ hashes->u.pointer_to_hash_input.len,
+ sigAndHash.hashAlg,
+ &localHashes);
+ }
+ if (rv == SECSuccess) {
+ hashesForVerify = &localHashes;
+ } else {
+ errCode = SSL_ERROR_DIGEST_FAILURE;
desc = decrypt_error;
goto alert_loser;
}
}
rv = ssl3_ConsumeHandshakeVariable(ss, &signed_hash, 2, &b, &length);
if (rv != SECSuccess) {
goto loser; /* malformed. */
}
/* XXX verify that the key & kea match */
- rv = ssl3_VerifySignedHashes(hashes, ss->sec.peerCert, &signed_hash,
+ rv = ssl3_VerifySignedHashes(hashesForVerify, ss->sec.peerCert, &signed_hash,
isTLS, ss->pkcs11PinArg);
if (rv != SECSuccess) {
errCode = PORT_GetError();
desc = isTLS ? decrypt_error : handshake_failure;
goto alert_loser;
}
signed_hash.data = NULL;
@@ -11638,34 +11668,63 @@ SECStatus
ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
{
SECStatus rv = SECSuccess;
SSL3HandshakeType type = ss->ssl3.hs.msg_type;
SSL3Hashes hashes; /* computed hashes are put here. */
SSL3Hashes *hashesPtr = NULL; /* Set when hashes are computed */
PRUint8 hdr[4];
PRUint8 dtlsData[8];
+ PRBool computeHashes = PR_FALSE;
PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
/*
* We have to compute the hashes before we update them with the
* current message.
*/
ssl_GetSpecReadLock(ss); /************************************/
- if(((type == finished) && (ss->ssl3.hs.ws == wait_finished)) ||
- ((type == certificate_verify) && (ss->ssl3.hs.ws == wait_cert_verify))) {
- SSL3Sender sender = (SSL3Sender)0;
- ssl3CipherSpec *rSpec = ss->ssl3.prSpec;
-
- if (type == finished) {
- sender = ss->sec.isServer ? sender_client : sender_server;
- rSpec = ss->ssl3.crSpec;
- }
- rv = ssl3_ComputeHandshakeHashes(ss, rSpec, &hashes, sender);
+
+ if ((type == finished) && (ss->ssl3.hs.ws == wait_finished)) {
+ computeHashes = PR_TRUE;
+ } else if ((type == certificate_verify) && (ss->ssl3.hs.ws == wait_cert_verify)) {
+ if (ss->ssl3.hs.hashType == handshake_hash_record) {
+ /* We cannot compute the hash yet. We must wait until we have
+ * decoded the certificate_verify message in
+ * ssl3_HandleCertificateVerify, which will tell us which
+ * hash function we must use.
+ *
+ * (ssl3_HandleCertificateVerify cannot simply look at the
+ * buffer length itself, because at the time we reach it,
+ * additional handshake messages will have been added to the
+ * buffer, e.g. the certificate_verify message itself.)
+ *
+ * Therefore, we use SSL3Hashes.u.pointer_to_hash_input
+ * to signal the current state of the buffer.
+ *
+ * ssl3_HandleCertificateVerify will detect
+ * hashType == handshake_hash_record
+ * and use that information to calculate the hash.
+ */
+ hashes.u.pointer_to_hash_input.data = ss->ssl3.hs.messages.buf;
+ hashes.u.pointer_to_hash_input.len = ss->ssl3.hs.messages.len;
+ hashesPtr = &hashes;
+ } else {
+ computeHashes = PR_TRUE;
+ }
+ }
+ if (computeHashes) {
+ SSL3Sender sender = (SSL3Sender)0;
+ ssl3CipherSpec *rSpec = ss->ssl3.prSpec;
+
+ if (type == finished) {
+ sender = ss->sec.isServer ? sender_client : sender_server;
+ rSpec = ss->ssl3.crSpec;
+ }
+ rv = ssl3_ComputeHandshakeHashes(ss, rSpec, &hashes, sender);
if (rv == SECSuccess) {
hashesPtr = &hashes;
}
}
ssl_ReleaseSpecReadLock(ss); /************************************/
if (rv != SECSuccess) {
return rv; /* error code was set by ssl3_ComputeHandshakeHashes*/
}
@@ -13080,20 +13139,17 @@ ssl3_DestroySSL3Info(sslSocket *ss)
}
if (ss->ssl3.hs.sha) {
PK11_DestroyContext(ss->ssl3.hs.sha,PR_TRUE);
}
if (ss->ssl3.hs.clientSigAndHash) {
PORT_Free(ss->ssl3.hs.clientSigAndHash);
}
if (ss->ssl3.hs.messages.buf) {
- PORT_Free(ss->ssl3.hs.messages.buf);
- ss->ssl3.hs.messages.buf = NULL;
- ss->ssl3.hs.messages.len = 0;
- ss->ssl3.hs.messages.space = 0;
+ sslBuffer_Clear(&ss->ssl3.hs.messages);
}
/* free the SSL3Buffer (msg_body) */
PORT_Free(ss->ssl3.hs.msg_body.buf);
SECITEM_FreeItem(&ss->ssl3.hs.newSessionTicket.ticket, PR_FALSE);
/* free up the CipherSpecs */
diff --git a/lib/ssl/ssl3prot.h b/lib/ssl/ssl3prot.h
--- a/lib/ssl/ssl3prot.h
+++ b/lib/ssl/ssl3prot.h
@@ -254,16 +254,17 @@ typedef struct {
* which, if |hashAlg==ssl_hash_none| is also a SSL3HashesIndividually
* struct. */
typedef struct {
unsigned int len;
SSLHashType hashAlg;
union {
PRUint8 raw[64];
SSL3HashesIndividually s;
+ SECItem pointer_to_hash_input;
} u;
} SSL3Hashes;
typedef struct {
union {
SSL3Opaque anonymous;
SSL3Hashes certified;
} u;
diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h
--- a/lib/ssl/sslimpl.h
+++ b/lib/ssl/sslimpl.h
@@ -847,17 +847,18 @@ typedef struct DTLSQueuedMessageStr {
SSL3ContentType type; /* The message type */
unsigned char *data; /* The data */
PRUint16 len; /* The data length */
} DTLSQueuedMessage;
typedef enum {
handshake_hash_unknown = 0,
handshake_hash_combo = 1, /* The MD5/SHA-1 combination */
- handshake_hash_single = 2 /* A single hash */
+ handshake_hash_single = 2, /* A single hash */
+ handshake_hash_record
} SSL3HandshakeHashType;
/*
** This is the "hs" member of the "ssl3" struct.
** This entire struct is protected by ssl3HandshakeLock
*/
typedef struct SSL3HandshakeStateStr {
SSL3Random server_random;
@@ -880,22 +881,19 @@ typedef struct SSL3HandshakeStateStr {
* of the freebl <HASH>_Clone functions, so we need a dedicated function
* pointer for the <HASH>_Clone function. */
void (*sha_clone)(void *dest, void *src);
#endif
/* PKCS #11 mode:
* SSL 3.0 - TLS 1.1 use both |md5| and |sha|. |md5| is used for MD5 and
* |sha| for SHA-1.
* TLS 1.2 and later use only |sha|, for SHA-256. */
- /* NOTE: On the client side, TLS 1.2 and later use |md5| as a backup
- * handshake hash for generating client auth signatures. Confusingly, the
- * backup hash function is SHA-1. */
-#define backupHash md5
PK11Context * md5;
PK11Context * sha;
+ SSLHashType tls12CertVerifyHash;
const ssl3KEADef * kea_def;
ssl3CipherSuite cipher_suite;
const ssl3CipherSuiteDef *suite_def;
SSLCompressionMethod compression;
sslBuffer msg_body; /* protected by recvBufLock */
/* partial handshake message from record layer */
unsigned int header_bytes;
@@ -1452,16 +1450,17 @@ extern SECStatus ssl_SaveWriteData(sslSo
const void* p, unsigned int l);
extern SECStatus ssl2_BeginClientHandshake(sslSocket *ss);
extern SECStatus ssl2_BeginServerHandshake(sslSocket *ss);
extern int ssl_Do1stHandshake(sslSocket *ss);
extern SECStatus sslBuffer_Grow(sslBuffer *b, unsigned int newLen);
extern SECStatus sslBuffer_Append(sslBuffer *b, const void * data,
unsigned int len);
+extern void sslBuffer_Clear(sslBuffer *b);
extern void ssl2_UseClearSendFunc(sslSocket *ss);
extern void ssl_ChooseSessionIDProcs(sslSecurityInfo *sec);
extern sslSessionID *ssl3_NewSessionID(sslSocket *ss, PRBool is_server);
extern sslSessionID *ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port,
const char *peerID, const char *urlSvrName);
extern void ssl_FreeSID(sslSessionID *sid);
diff --git a/lib/ssl/sslsecur.c b/lib/ssl/sslsecur.c
--- a/lib/ssl/sslsecur.c
+++ b/lib/ssl/sslsecur.c
@@ -528,16 +528,27 @@ sslBuffer_Append(sslBuffer *b, const voi
rv = sslBuffer_Grow(b, newLen);
if (rv != SECSuccess)
return rv;
PORT_Memcpy(b->buf + b->len, data, len);
b->len += len;
return SECSuccess;
}
+void
+sslBuffer_Clear(sslBuffer *b)
+{
+ if (b->len > 0) {
+ PORT_Free(b->buf);
+ b->buf = NULL;
+ b->len = 0;
+ b->space = 0;
+ }
+}
+
/*
** Save away write data that is trying to be written before the security
** handshake has been completed. When the handshake is completed, we will
** flush this data out.
** Caller must hold xmitBufLock
*/
SECStatus
ssl_SaveWriteData(sslSocket *ss, const void *data, unsigned int len)