Index: net/socket/ssl_client_socket_nss.cc |
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc |
index 879689ad6dd149d58a656858cf558d424074efd1..56597b135ed248bcd3e6e10e36b5c600f422dc32 100644 |
--- a/net/socket/ssl_client_socket_nss.cc |
+++ b/net/socket/ssl_client_socket_nss.cc |
@@ -2137,24 +2137,19 @@ SECStatus SSLClientSocketNSS::PlatformClientAuthHandler( |
if (that->ssl_config_.client_cert) { |
PCCERT_CONTEXT cert_context = |
that->ssl_config_.client_cert->os_cert_handle(); |
- PCERT_KEY_CONTEXT key_context = reinterpret_cast<PCERT_KEY_CONTEXT>( |
- PORT_ZAlloc(sizeof(CERT_KEY_CONTEXT))); |
- if (!key_context) |
- return SECFailure; |
- key_context->cbSize = sizeof(*key_context); |
+ HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv = INVALID_HANDLE; |
+ DWORD dwKeySpec = 0; |
wtc
2011/09/23 19:53:34
I haven't seen the INVALID_HANDLE macro before. S
|
BOOL must_free = FALSE; |
BOOL acquired_key = CryptAcquireCertificatePrivateKey( |
cert_context, CRYPT_ACQUIRE_CACHE_FLAG, NULL, |
- &key_context->hCryptProv, &key_context->dwKeySpec, &must_free); |
- if (acquired_key && key_context->hCryptProv) { |
- DCHECK_NE(key_context->dwKeySpec, CERT_NCRYPT_KEY_SPEC); |
+ &hCryptProv, &dwKeySpec, &must_free); |
+ // Since we passed CRYPT_ACQUIRE_CACHE_FLAG, |must_free| must be false |
+ // according to the MSDN documentation. |
+ DCHECK(must_free == FALSE); |
wtc
2011/09/23 19:53:34
You can use DCHECK_EQ here. cpplint probably will
Ryan Sleevi
2011/09/23 22:33:50
Double checked my notes from disassembling this fu
|
- // The certificate cache may have been updated/used, in which case, |
- // duplicate the existing handle, since NSS will free it when no |
- // longer in use. |
- if (!must_free) |
- CryptContextAddRef(key_context->hCryptProv, NULL, 0); |
+ if (acquired_key && hCryptProv != INVALID_HANDLE) { |
+ DCHECK_NE(dwKeySpec, CERT_NCRYPT_KEY_SPEC); |
SECItem der_cert; |
der_cert.type = siDERCertBuffer; |
@@ -2162,11 +2157,16 @@ SECStatus SSLClientSocketNSS::PlatformClientAuthHandler( |
der_cert.len = cert_context->cbCertEncoded; |
// TODO(rsleevi): Error checking for NSS allocation errors. |
- *result_certs = CERT_NewCertList(); |
CERTCertDBHandle* db_handle = CERT_GetDefaultCertDB(); |
CERTCertificate* user_cert = CERT_NewTempCertificate( |
db_handle, &der_cert, NULL, PR_FALSE, PR_TRUE); |
- CERT_AddCertToListTail(*result_certs, user_cert); |
+ if (!user_cert) { |
+ // Importing the certificate can fail for reasons including a serial |
+ // number collision. See crbug.com/97355. |
+ return SECFailure; |
+ } |
+ CERTCertList* cert_chain = CERT_NewCertList(); |
+ CERT_AddCertToListTail(cert_chain, user_cert); |
// Add the intermediates. |
X509Certificate::OSCertHandles intermediates = |
@@ -2178,12 +2178,26 @@ SECStatus SSLClientSocketNSS::PlatformClientAuthHandler( |
CERTCertificate* intermediate = CERT_NewTempCertificate( |
db_handle, &der_cert, NULL, PR_FALSE, PR_TRUE); |
- CERT_AddCertToListTail(*result_certs, intermediate); |
+ if (!intermediate) { |
+ CERT_DestroyCertList(cert_chain); |
+ return SECFailure; |
+ } |
+ CERT_AddCertToListTail(cert_chain, intermediate); |
} |
+ PCERT_KEY_CONTEXT key_context = reinterpret_cast<PCERT_KEY_CONTEXT>( |
+ PORT_ZAlloc(sizeof(CERT_KEY_CONTEXT)); |
+ key_context->cbSize = sizeof(*key_context); |
+ // NSS will free this context when no longer in use, but the |
+ // |must_free| result from CryptAcquireCertificatePrivateKey was false |
+ // so we increment the refcount to negate NSS's future decrement. |
+ CryptContextAddRef(hCryptProv, NULL, 0); |
+ key_context->hCryptProv = hCryptProv; |
+ key_context->dwKeySpec = dwKeySpec; |
*result_private_key = key_context; |
+ *result_certs = cert_chain; |
+ |
return SECSuccess; |
} |
- PORT_Free(key_context); |
LOG(WARNING) << "Client cert found without private key"; |
} |
// Send no client certificate. |
@@ -2320,6 +2334,12 @@ SECStatus SSLClientSocketNSS::PlatformClientAuthHandler( |
der_cert.len = cert_data.Length; |
CERTCertificate* nss_cert = CERT_NewTempCertificate( |
CERT_GetDefaultCertDB(), &der_cert, NULL, PR_FALSE, PR_TRUE); |
+ if (!nss_cert) { |
+ // In the event of an NSS error we make up an OS error and reuse |
+ // the error handling, below. |
+ os_error = errKCCreateChainFailed; |
+ break; |
+ } |
CERT_AddCertToListTail(*result_certs, nss_cert); |
} |
} |