Index: net/socket/ssl_client_socket_win.cc |
diff --git a/net/socket/ssl_client_socket_win.cc b/net/socket/ssl_client_socket_win.cc |
index ae4d4b5905ed090246c7beec9b338c50cf704151..16d12dd0535d032ce0cca820b8d0674691b06f49 100644 |
--- a/net/socket/ssl_client_socket_win.cc |
+++ b/net/socket/ssl_client_socket_win.cc |
@@ -330,40 +330,6 @@ static BOOL WINAPI ClientCertFindCallback(PCCERT_CONTEXT cert_context, |
//----------------------------------------------------------------------------- |
-// A memory certificate store for client certificates. This allows us to |
-// close the "MY" system certificate store when we finish searching for |
-// client certificates. |
-class ClientCertStore { |
- public: |
- ClientCertStore() { |
- store_ = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, 0, NULL); |
- } |
- |
- ~ClientCertStore() { |
- if (store_) { |
- BOOL ok = CertCloseStore(store_, CERT_CLOSE_STORE_CHECK_FLAG); |
- DCHECK(ok); |
- } |
- } |
- |
- PCCERT_CONTEXT CopyCertContext(PCCERT_CONTEXT client_cert) { |
- PCCERT_CONTEXT copy; |
- BOOL ok = CertAddCertificateContextToStore(store_, client_cert, |
- CERT_STORE_ADD_USE_EXISTING, |
- ©); |
- DCHECK(ok); |
- return ok ? copy : NULL; |
- } |
- |
- private: |
- HCERTSTORE store_; |
-}; |
- |
-static base::LazyInstance<ClientCertStore> g_client_cert_store( |
- base::LINKER_INITIALIZED); |
- |
-//----------------------------------------------------------------------------- |
- |
// Size of recv_buffer_ |
// |
// Ciphertext is decrypted one SSL record at a time, so recv_buffer_ needs to |
@@ -512,19 +478,35 @@ void SSLClientSocketWin::GetSSLCertRequestInfo( |
// Get the leaf certificate. |
PCCERT_CONTEXT cert_context = |
chain_context->rgpChain[0]->rgpElement[0]->pCertContext; |
- // Copy it to our own certificate store, so that we can close the "MY" |
- // certificate store before returning from this function. |
- PCCERT_CONTEXT cert_context2 = |
- g_client_cert_store.Get().CopyCertContext(cert_context); |
- if (!cert_context2) { |
+ // Copy the certificate into a NULL store, so that we can close the "MY" |
+ // store before returning from this function. |
+ PCCERT_CONTEXT cert_context2 = NULL; |
+ BOOL ok = CertAddCertificateContextToStore(NULL, cert_context, |
+ CERT_STORE_ADD_USE_EXISTING, |
+ &cert_context2); |
+ if (!ok) { |
NOTREACHED(); |
continue; |
} |
+ |
+ // Grab the intermediates, if any. |
+ X509Certificate::OSCertHandles intermediates; |
+ for (DWORD i = 1; i < chain_context->rgpChain[0]->cElement; ++i) { |
+ PCCERT_CONTEXT chain_intermediate = |
+ chain_context->rgpChain[0]->rgpElement[i]->pCertContext; |
+ PCCERT_CONTEXT chain_intermediate2; |
+ ok = CertAddCertificateContextToStore(NULL, chain_intermediate, |
+ CERT_STORE_ADD_USE_EXISTING, |
+ &chain_intermediate2); |
+ if (ok) |
+ intermediates.push_back(chain_intermediate2); |
+ } |
scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle( |
- cert_context2, X509Certificate::SOURCE_LONE_CERT_IMPORT, |
- X509Certificate::OSCertHandles()); |
+ cert_context2, intermediates); |
cert_request_info->client_certs.push_back(cert); |
CertFreeCertificateContext(cert_context2); |
+ for (size_t i = 0; i < intermediates.size(); ++i) |
+ CertFreeCertificateContext(intermediates[i]); |
} |
FreeContextBuffer(issuer_list.aIssuers); |
@@ -1473,20 +1455,34 @@ int SSLClientSocketWin::DidCompleteHandshake() { |
LOG(ERROR) << "QueryContextAttributes (remote cert) failed: " << status; |
return MapSecurityError(status); |
} |
+ |
+ X509Certificate::OSCertHandles intermediates; |
+ PCCERT_CONTEXT intermediate = |
+ CertEnumCertificatesInStore(server_cert_handle->hCertStore, NULL); |
+ while (intermediate != NULL) { |
+ intermediates.push_back(CertDuplicateCertificateContext(intermediate)); |
+ intermediate = CertEnumCertificatesInStore(server_cert_handle->hCertStore, |
+ intermediate); |
+ } |
+ |
if (renegotiating_ && |
X509Certificate::IsSameOSCert(server_cert_->os_cert_handle(), |
- server_cert_handle)) { |
+ server_cert_handle) && |
+ server_cert_->HasIntermediateCertificates(intermediates) && |
+ server_cert_->GetIntermediateCertificates().size() == |
+ intermediates.size()) { |
// We already verified the server certificate. Either it is good or the |
// user has accepted the certificate error. |
DidCompleteRenegotiation(); |
} else { |
server_cert_ = X509Certificate::CreateFromHandle( |
- server_cert_handle, X509Certificate::SOURCE_FROM_NETWORK, |
- X509Certificate::OSCertHandles()); |
+ server_cert_handle, intermediates); |
next_state_ = STATE_VERIFY_CERT; |
} |
CertFreeCertificateContext(server_cert_handle); |
+ for (size_t i = 0; i < intermediates.size(); ++i) |
+ CertFreeCertificateContext(intermediates[i]); |
return OK; |
} |