Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(138)

Unified Diff: net/base/x509_certificate_win.cc

Issue 4646001: Implement LoadTemporaryRoot for Windows (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/net/base
Patch Set: Feedback from phajdan.jr and bulach Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: net/base/x509_certificate_win.cc
diff --git a/net/base/x509_certificate_win.cc b/net/base/x509_certificate_win.cc
index 9e018fdde6564e76aee70b28754af7936de735b8..789766d0eb19f9b0daa4e4f6de9a5e42b5f47a5a 100644
--- a/net/base/x509_certificate_win.cc
+++ b/net/base/x509_certificate_win.cc
@@ -4,6 +4,7 @@
#include "net/base/x509_certificate.h"
+#include "base/crypto/scoped_capi_types.h"
#include "base/logging.h"
#include "base/pickle.h"
#include "base/string_tokenizer.h"
@@ -14,6 +15,7 @@
#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/temporary_root_certs.h"
#pragma comment(lib, "crypt32.lib")
@@ -23,6 +25,11 @@ namespace net {
namespace {
+typedef base::ScopedCAPIHandle<
+ HCERTSTORE,
+ base::CAPIDestroyerWithFlags<HCERTSTORE,
+ CertCloseStore, 0> > ScopedHCERTSTORE;
+
//-----------------------------------------------------------------------------
// TODO(wtc): This is a copy of the MapSecurityError function in
@@ -291,6 +298,58 @@ void GetCertChainInfo(PCCERT_CHAIN_CONTEXT chain_context,
}
}
+void FixTestRootTrust(PCERT_CHAIN_CONTEXT chain_context) {
bulach 2010/11/09 16:21:09 same as above, I think this should be exposed some
+ if ((chain_context->TrustStatus.dwErrorStatus &
+ CERT_TRUST_IS_UNTRUSTED_ROOT) == 0)
+ return; // Trusted certificate - nothing to fix.
+
+ TemporaryRootCerts* temporary_roots = TemporaryRootCerts::GetInstance();
+ if (temporary_roots->IsEmpty())
+ return; // No need to scan - no temporary trusted certificates.
+
+ // Windows does not support application-level trusts until Win 7, via
+ // CERT_CHAIN_ENGINE_CONFIG.hExclusiveRoot. Because of this, a messy,
+ // manual, brute-force method is used for unit tests. Look through every
+ // chain on |chain_context|, looking for a chain which contains one of the
+ // trusted certificates. If a matching certificate is found, unset the
+ // three status-bits that Windows sets when an untrusted root is found.
+ // Any other failure states are left unmodified, so that situations like
+ // name or date mismatches are properly reported.
+ for (DWORD chain_index = 0; chain_index < chain_context->cChain;
+ ++chain_index) {
+ PCERT_SIMPLE_CHAIN chain = chain_context->rgpChain[chain_index];
+ // Scan through all the certificates, rather than just the root, since
+ // an RFC 3280/5280 trust anchor may be any certificate in the chain, not
+ // just the root certificate.
+ for (DWORD element_index = 0; element_index < chain->cElement;
+ ++element_index) {
+ PCERT_CHAIN_ELEMENT element = chain->rgpElement[element_index];
+ PCCERT_CONTEXT cert = CertFindCertificateInStore(
+ temporary_roots->temporary_roots(),
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_EXISTING,
+ element->pCertContext, NULL);
+ if (cert != NULL) {
+ CertFreeCertificateContext(cert);
+
+ // Unset both the element status and the overall chain status, in the
+ // event a Windows function drills down into the chain.
+ if (element->TrustStatus.dwErrorStatus &
+ CERT_TRUST_IS_UNTRUSTED_ROOT) {
+ element->TrustStatus.dwErrorStatus &=
+ ~(CERT_TRUST_IS_UNTRUSTED_ROOT |
+ CERT_TRUST_REVOCATION_STATUS_UNKNOWN |
+ CERT_TRUST_IS_OFFLINE_REVOCATION);
+ chain_context->TrustStatus.dwErrorStatus &=
+ ~(CERT_TRUST_IS_UNTRUSTED_ROOT |
+ CERT_TRUST_REVOCATION_STATUS_UNKNOWN |
+ CERT_TRUST_IS_OFFLINE_REVOCATION);
+ return;
+ }
+ }
+ }
+ }
+}
+
// Decodes the cert's certificatePolicies extension into a CERT_POLICIES_INFO
// structure and stores it in *output.
void GetCertPoliciesInfo(PCCERT_CONTEXT cert,
@@ -605,6 +664,36 @@ int X509Certificate::Verify(const std::string& hostname,
}
}
+ // Temporary roots may not exist in any system store, and therefore may not
+ // be available for certificate chain building. Create a certificate store
+ // collection containing both the certificate chain (the cert_handle's
+ // HCERTSTORE) and the temporary root's HCERTSTORE, so that Windows will
+ // search both.
+ TemporaryRootCerts* temporary_roots = TemporaryRootCerts::GetInstance();
+ HCERTSTORE collection_store =
+ temporary_roots->IsEmpty() ? NULL :
+ CertOpenStore(CERT_STORE_PROV_COLLECTION,
+ 0, NULL, 0, NULL);
+ if (collection_store) {
+ // Add the temporary roots with priority 0, so that certificates from the
+ // temporary roots will be of a higher priority for chain building. If
+ // they were a lower priority, it's possible a different root certificate
+ // than the one in the temporary roots will be used, which would cause
+ // the detection logic in FixTestRootTrust() to fail.
+ BOOL ok = CertAddStoreToCollection(collection_store,
+ temporary_roots->temporary_roots(),
+ 0, 0);
+ if (ok)
+ ok = CertAddStoreToCollection(collection_store,
+ cert_handle_->hCertStore, 0, 1);
+ if (!ok) {
+ PLOG(ERROR) << "Unable to create temporary linked certificate store";
+ CertCloseStore(collection_store, 0);
+ collection_store = NULL;
+ }
+ }
+ ScopedHCERTSTORE scoped_collection_store(collection_store);
+
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
@@ -613,7 +702,8 @@ int X509Certificate::Verify(const std::string& hostname,
NULL, // default chain engine, HCCE_CURRENT_USER
cert_handle_,
NULL, // current system time
- cert_handle_->hCertStore, // search this store
+ scoped_collection_store ? scoped_collection_store :
wtc 2010/11/16 23:24:01 Nit: use a local variable for this, so that we don
+ cert_handle_->hCertStore,
&chain_para,
chain_flags,
NULL, // reserved
@@ -630,7 +720,8 @@ int X509Certificate::Verify(const std::string& hostname,
NULL, // default chain engine, HCCE_CURRENT_USER
cert_handle_,
NULL, // current system time
- cert_handle_->hCertStore, // search this store
+ scoped_collection_store ? scoped_collection_store :
+ cert_handle_->hCertStore,
&chain_para,
chain_flags,
NULL, // reserved
@@ -642,6 +733,8 @@ int X509Certificate::Verify(const std::string& hostname,
GetCertChainInfo(chain_context, verify_result);
+ FixTestRootTrust(const_cast<PCERT_CHAIN_CONTEXT>(chain_context));
wtc 2010/11/16 23:24:01 BUG: Move this up, so that we call FixTestRootTrus
+
verify_result->cert_status |= MapCertChainErrorStatusToCertStatus(
chain_context->TrustStatus.dwErrorStatus);

Powered by Google App Engine
This is Rietveld 408576698