Chromium Code Reviews| Index: net/third_party/nss/ssl/ssl3con.c |
| =================================================================== |
| --- net/third_party/nss/ssl/ssl3con.c (revision 219612) |
| +++ net/third_party/nss/ssl/ssl3con.c (working copy) |
| @@ -3933,6 +3933,22 @@ |
| ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); |
| return SECFailure; |
| } |
| + |
| +#ifdef _WIN32 |
| + /* A backup SHA-1 hash for a potential client auth signature. */ |
| + if (!ss->sec.isServer) { |
| + ss->ssl3.hs.md5 = PK11_CreateDigestContext(SEC_OID_SHA1); |
| + if (ss->ssl3.hs.md5 == NULL) { |
| + ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); |
| + return SECFailure; |
| + } |
| + |
| + if (PK11_DigestBegin(ss->ssl3.hs.md5) != SECSuccess) { |
| + ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); |
| + return SECFailure; |
| + } |
| + } |
| +#endif |
| } else { |
| /* Both ss->ssl3.hs.md5 and ss->ssl3.hs.sha should be NULL or |
| * created successfully. */ |
| @@ -4043,6 +4059,13 @@ |
| ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); |
| return rv; |
| } |
| + if (ss->ssl3.hs.md5) { |
| + rv = PK11_DigestOp(ss->ssl3.hs.md5, 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) { |
| @@ -4791,6 +4814,30 @@ |
| 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->ssl3.hs.hashType == handshake_hash_single ); |
| + |
| + rv = PK11_DigestFinal(ss->ssl3.hs.md5, 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 = SEC_OID_SHA1; |
| + |
| +loser: |
| + PK11_DestroyContext(ss->ssl3.hs.md5, PR_TRUE); |
| + ss->ssl3.hs.md5 = NULL; |
| + return rv; |
| +} |
| + |
| /* |
| * SSL 2 based implementations pass in the initial outbound buffer |
| * so that the handshake hash can contain the included information. |
| @@ -6044,7 +6091,17 @@ |
| SSL_GETPID(), ss->fd)); |
| ssl_GetSpecReadLock(ss); |
| - rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.pwSpec, &hashes, 0); |
| + /* 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->ssl3.hs.hashType == handshake_hash_single && ss->ssl3.hs.md5) { |
| + rv = ssl3_ComputeBackupHandshakeHashes(ss, &hashes); |
|
agl
2013/08/28 22:16:03
(doesn't matter): here you are using tabs rather t
|
| + PORT_Assert(ss->ssl3.hs.md5 == NULL); |
| + } else { |
| + rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.pwSpec, &hashes, 0); |
| + } |
| ssl_ReleaseSpecReadLock(ss); |
| if (rv != SECSuccess) { |
| goto done; /* err code was set by ssl3_ComputeHandshakeHashes */ |
| @@ -6098,11 +6155,6 @@ |
| if (rv != SECSuccess) { |
| goto done; |
| } |
| - /* We always sign using the handshake hash function. It's possible that |
| - * a server could support SHA-256 as the handshake hash but not as a |
| - * signature hash. In that case we wouldn't be able to do client |
| - * certificates with it. The alternative is to buffer all handshake |
| - * messages. */ |
| sigAndHash.hashAlg = hashes.hashAlg; |
| rv = ssl3_AppendSignatureAndHashAlgorithm(ss, &sigAndHash); |
| @@ -6994,6 +7046,35 @@ |
| } |
| goto send_no_certificate; |
| } |
| + |
| + if (isTLS12 && ss->ssl3.hs.md5) { |
| + PRBool need_backup_hash = PR_FALSE; |
| +#ifdef _WIN32 |
| + /* If the key is in CAPI, check if the CAPI service provider |
| + * supports SHA-256. Use SHA-1 if it doesn't. */ |
| + if (ss->ssl3.platformClientKey->dwKeySpec != |
| + CERT_NCRYPT_KEY_SPEC) { |
| + HCRYPTPROV prov = ss->ssl3.platformClientKey->hCryptProv; |
| + PROV_ENUMALGS alg_info; |
| + DWORD size = sizeof(alg_info); |
| + DWORD flags = CRYPT_FIRST; |
| + need_backup_hash = PR_TRUE; |
| + while (CryptGetProvParam(prov, PP_ENUMALGS, |
|
wtc
2013/08/28 22:05:45
It may be cheaper to check SHA-256 support by tryi
|
| + (BYTE *)&alg_info, &size, flags)) { |
| + if (alg_info.aiAlgid == CALG_SHA_256) { |
| + need_backup_hash = PR_FALSE; |
| + break; |
| + } |
| + size = sizeof(alg_info); |
| + flags = CRYPT_NEXT; |
| + } |
| + } |
| +#endif /* _WIN32 */ |
| + if (!need_backup_hash) { |
| + PK11_DestroyContext(ss->ssl3.hs.md5, PR_TRUE); |
| + ss->ssl3.hs.md5 = NULL; |
| + } |
| + } |
| break; /* not an error */ |
| } |
| #endif /* NSS_PLATFORM_CLIENT_AUTH */ |
| @@ -7227,6 +7308,13 @@ |
| (ss->ssl3.platformClientKey || |
| ss->ssl3.clientPrivateKey != NULL); |
| + if (!sendClientCert && |
| + ss->ssl3.hs.hashType == handshake_hash_single && ss->ssl3.hs.md5) { |
| + /* Don't need the backup handshake hash. */ |
| + PK11_DestroyContext(ss->ssl3.hs.md5, PR_TRUE); |
| + ss->ssl3.hs.md5 = 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 |