Index: net/base/x509_certificate_win.cc |
diff --git a/net/base/x509_certificate_win.cc b/net/base/x509_certificate_win.cc |
index 0c355b60f1eb4dfac21b5d3f9fec9abe77112070..efa5e5c33bd6993822bb6e3abf41202560a387d6 100644 |
--- a/net/base/x509_certificate_win.cc |
+++ b/net/base/x509_certificate_win.cc |
@@ -9,6 +9,7 @@ |
#include "base/lazy_instance.h" |
#include "base/logging.h" |
+#include "base/memory/scoped_ptr.h" |
#include "base/pickle.h" |
#include "base/sha1.h" |
#include "base/string_tokenizer.h" |
@@ -21,7 +22,6 @@ |
#include "net/base/cert_verify_result.h" |
#include "net/base/ev_root_ca_metadata.h" |
#include "net/base/net_errors.h" |
-#include "net/base/scoped_cert_chain_context.h" |
#include "net/base/test_root_certs.h" |
#include "net/base/x509_certificate_known_roots_win.h" |
@@ -33,11 +33,6 @@ namespace net { |
namespace { |
-typedef crypto::ScopedCAPIHandle< |
- HCERTSTORE, |
- crypto::CAPIDestroyerWithFlags<HCERTSTORE, |
- CertCloseStore, 0> > ScopedHCERTSTORE; |
- |
struct FreeChainEngineFunctor { |
void operator()(HCERTCHAINENGINE engine) const { |
if (engine) |
@@ -45,9 +40,35 @@ struct FreeChainEngineFunctor { |
} |
}; |
+struct FreeCertContextFunctor { |
+ void operator()(PCCERT_CONTEXT context) const { |
+ if (context) |
+ CertFreeCertificateContext(context); |
+ } |
+}; |
+ |
+struct FreeCertChainContextFunctor { |
+ void operator()(PCCERT_CHAIN_CONTEXT chain_context) const { |
+ if (chain_context) |
+ CertFreeCertificateChain(chain_context); |
+ } |
+}; |
+ |
typedef crypto::ScopedCAPIHandle<HCERTCHAINENGINE, FreeChainEngineFunctor> |
ScopedHCERTCHAINENGINE; |
+typedef crypto::ScopedCAPIHandle< |
+ HCERTSTORE, |
+ crypto::CAPIDestroyerWithFlags<HCERTSTORE, |
+ CertCloseStore, 0> > ScopedHCERTSTORE; |
+ |
+typedef scoped_ptr_malloc<const CERT_CONTEXT, |
+ FreeCertContextFunctor> ScopedPCCERT_CONTEXT; |
+ |
+typedef scoped_ptr_malloc<const CERT_CHAIN_CONTEXT, |
+ FreeCertChainContextFunctor> |
+ ScopedPCCERT_CHAIN_CONTEXT; |
+ |
//----------------------------------------------------------------------------- |
// TODO(wtc): This is a copy of the MapSecurityError function in |
@@ -695,6 +716,40 @@ HCERTSTORE X509Certificate::cert_store() { |
return g_cert_store.Get().cert_store(); |
} |
+PCCERT_CONTEXT X509Certificate::CreateOSCertChainForCert() const { |
+ // Create an in-memory certificate store to hold this certificate and |
+ // any intermediate certificates in |intermediate_ca_certs_|. The store |
+ // will be referenced in the returned PCCERT_CONTEXT, and will not be freed |
+ // until the PCCERT_CONTEXT is freed. |
+ ScopedHCERTSTORE store(CertOpenStore( |
+ CERT_STORE_PROV_MEMORY, 0, NULL, |
+ CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, NULL)); |
+ if (!store.get()) |
+ return NULL; |
+ |
+ // NOTE: This preserves all of the properties of |os_cert_handle()| except |
+ // for CERT_KEY_PROV_HANDLE_PROP_ID and CERT_KEY_CONTEXT_PROP_ID - the two |
+ // properties that hold access to already-opened private keys. If a handle |
+ // has already been unlocked (eg: PIN prompt), then the first time that the |
+ // identity is used for client auth, it may prompt the user again. |
+ PCCERT_CONTEXT primary_cert; |
+ BOOL ok = CertAddCertificateContextToStore(store.get(), os_cert_handle(), |
+ CERT_STORE_ADD_ALWAYS, |
+ &primary_cert); |
+ if (!ok || !primary_cert) |
+ return NULL; |
+ |
+ for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) { |
+ CertAddCertificateContextToStore(store.get(), intermediate_ca_certs_[i], |
+ CERT_STORE_ADD_ALWAYS, NULL); |
+ } |
+ |
+ // Note: |store| is explicitly not released, as the call to CertCloseStore() |
+ // when |store| goes out of scope will not actually free the store. Instead, |
+ // the store will be freed when |primary_cert| is freed. |
+ return primary_cert; |
+} |
+ |
int X509Certificate::VerifyInternal(const std::string& hostname, |
int flags, |
CRLSet* crl_set, |
@@ -762,21 +817,23 @@ int X509Certificate::VerifyInternal(const std::string& hostname, |
if (TestRootCerts::HasInstance()) |
chain_engine.reset(TestRootCerts::GetInstance()->GetChainEngine()); |
+ ScopedPCCERT_CONTEXT cert_list(CreateOSCertChainForCert()); |
PCCERT_CHAIN_CONTEXT chain_context; |
// IE passes a non-NULL pTime argument that specifies the current system |
// time. IE passes CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT as the |
// chain_flags argument. |
if (!CertGetCertificateChain( |
chain_engine, |
- cert_handle_, |
+ cert_list.get(), |
NULL, // current system time |
- cert_handle_->hCertStore, |
+ cert_list->hCertStore, |
&chain_para, |
chain_flags, |
NULL, // reserved |
&chain_context)) { |
return MapSecurityError(GetLastError()); |
} |
+ |
if (chain_context->TrustStatus.dwErrorStatus & |
CERT_TRUST_IS_NOT_VALID_FOR_USAGE) { |
ev_policy_oid = NULL; |
@@ -785,9 +842,9 @@ int X509Certificate::VerifyInternal(const std::string& hostname, |
CertFreeCertificateChain(chain_context); |
if (!CertGetCertificateChain( |
chain_engine, |
- cert_handle_, |
+ cert_list.get(), |
NULL, // current system time |
- cert_handle_->hCertStore, |
+ cert_list->hCertStore, |
&chain_para, |
chain_flags, |
NULL, // reserved |
@@ -795,7 +852,8 @@ int X509Certificate::VerifyInternal(const std::string& hostname, |
return MapSecurityError(GetLastError()); |
} |
} |
- ScopedCertChainContext scoped_chain_context(chain_context); |
+ |
+ ScopedPCCERT_CHAIN_CONTEXT scoped_chain_context(chain_context); |
GetCertChainInfo(chain_context, verify_result); |
verify_result->cert_status |= MapCertChainErrorStatusToCertStatus( |