diff options
24 files changed, 197 insertions, 60 deletions
diff --git a/chrome/browser/net/crl_set_fetcher.cc b/chrome/browser/net/crl_set_fetcher.cc index ef3558a..e3fa8d8 100644 --- a/chrome/browser/net/crl_set_fetcher.cc +++ b/chrome/browser/net/crl_set_fetcher.cc @@ -122,20 +122,21 @@ void CRLSetFetcher::SetCRLSetIfNewer( } } -// TODO(agl): this is a key for testing only. Replace with a real key. +// kPublicKeySHA256 is the SHA256 hash of the SubjectPublicKeyInfo of the key +// that's used to sign generated CRL sets. static const uint8 kPublicKeySHA256[32] = { - 0x0f, 0x0e, 0xa7, 0x94, 0x37, 0x6b, 0x60, 0x9a, - 0x90, 0x09, 0x3e, 0xbb, 0xce, 0xe8, 0xd7, 0x4b, - 0xc2, 0x78, 0x17, 0x43, 0x63, 0xd5, 0xb4, 0x43, - 0xc1, 0x49, 0xc6, 0x44, 0x40, 0x43, 0xae, 0x2a, + 0x75, 0xda, 0xf8, 0xcb, 0x77, 0x68, 0x40, 0x33, + 0x65, 0x4c, 0x97, 0xe5, 0xc5, 0x1b, 0xcd, 0x81, + 0x7b, 0x1e, 0xeb, 0x11, 0x2c, 0xe1, 0xa4, 0x33, + 0x8c, 0xf5, 0x72, 0x5e, 0xed, 0xb8, 0x43, 0x97, }; void CRLSetFetcher::RegisterComponent(uint32 sequence_of_loaded_crl) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); CrxComponent component; - component.pk_hash.assign(&kPublicKeySHA256[0], - &kPublicKeySHA256[0] + sizeof(kPublicKeySHA256)); + component.pk_hash.assign(kPublicKeySHA256, + kPublicKeySHA256 + sizeof(kPublicKeySHA256)); component.installer = this; component.name = "CRLSet"; component.version = Version(base::UintToString(sequence_of_loaded_crl)); diff --git a/chrome/browser/net/ssl_config_service_manager_pref.cc b/chrome/browser/net/ssl_config_service_manager_pref.cc index 8c538ba..fb11c82 100644 --- a/chrome/browser/net/ssl_config_service_manager_pref.cc +++ b/chrome/browser/net/ssl_config_service_manager_pref.cc @@ -93,6 +93,7 @@ class SSLConfigServicePref : public net::SSLConfigService { void SSLConfigServicePref::GetSSLConfig(net::SSLConfig* config) { *config = cached_config_; + config->crl_set = GetCRLSet(); } void SSLConfigServicePref::SetNewSSLConfig( diff --git a/chrome/browser/ui/browser_init.cc b/chrome/browser/ui/browser_init.cc index 779f025..e167a21 100644 --- a/chrome/browser/ui/browser_init.cc +++ b/chrome/browser/ui/browser_init.cc @@ -526,7 +526,7 @@ void RecordAppLaunches( } } -void RegisterComponentsForUpdate() { +void RegisterComponentsForUpdate(const CommandLine& command_line) { ComponentUpdateService* cus = g_browser_process->component_updater(); if (!cus) return; @@ -537,10 +537,10 @@ void RegisterComponentsForUpdate() { RegisterPepperFlashComponent(cus); RegisterNPAPIFlashComponent(cus); - // CRLSetFetcher attempts to load a CRL set from either the local disk - // or network. - // TODO(agl): this is disabled for now while it's plumbed in. - // g_browser_process->crl_set_fetcher()->StartInitialLoad(cus); + // CRLSetFetcher attempts to load a CRL set from either the local disk or + // network. + if (command_line.HasSwitch(switches::kEnableCRLSets)) + g_browser_process->crl_set_fetcher()->StartInitialLoad(cus); cus->Start(); } @@ -1389,7 +1389,7 @@ bool BrowserInit::ProcessCmdLineImpl(const CommandLine& command_line, if (command_line.HasSwitch(switches::kDisablePromptOnRepost)) NavigationController::DisablePromptOnRepost(); - RegisterComponentsForUpdate(); + RegisterComponentsForUpdate(command_line); // Look for the testing channel ID ONLY during process startup if (command_line.HasSwitch(switches::kTestingChannelID)) { diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 3cf9b30..772ffc7 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -434,6 +434,10 @@ const char kEnableCompositeToTexture[] = "enable-composite-to-texture"; // exceeded. const char kEnableConnectBackupJobs[] = "enable-connect-backup-jobs"; +// Enables establishing certificate revocation information by downloading a set +// of CRLs rather than performing on-line checks. +const char kEnableCRLSets[] = "enable-crl-sets"; + // Enables web developers to create apps for Chrome without using crx packages. const char kEnableCrxlessWebApps[] = "enable-crxless-web-apps"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 16a15d29..a7ec687 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -126,6 +126,7 @@ extern const char kEnableClickToPlay[]; extern const char kEnableCloudPrintProxy[]; extern const char kEnableCompositeToTexture[]; extern const char kEnableConnectBackupJobs[]; +extern const char kEnableCRLSets[]; extern const char kEnableCrxlessWebApps[]; extern const char kEnableExperimentalExtensionApis[]; extern const char kEnableExtensionAlerts[]; diff --git a/net/base/cert_database_nss_unittest.cc b/net/base/cert_database_nss_unittest.cc index 7dd1ffb..0b46906 100644 --- a/net/base/cert_database_nss_unittest.cc +++ b/net/base/cert_database_nss_unittest.cc @@ -540,7 +540,7 @@ TEST_F(CertDatabaseNSSTest, ImportServerCert) { int flags = 0; CertVerifyResult verify_result; - int error = goog_cert->Verify("www.google.com", flags, &verify_result); + int error = goog_cert->Verify("www.google.com", flags, NULL, &verify_result); EXPECT_EQ(OK, error); EXPECT_EQ(0U, verify_result.cert_status); } @@ -565,7 +565,8 @@ TEST_F(CertDatabaseNSSTest, ImportServerCert_SelfSigned) { int flags = 0; CertVerifyResult verify_result; - int error = puny_cert->Verify("xn--wgv71a119e.com", flags, &verify_result); + int error = puny_cert->Verify("xn--wgv71a119e.com", flags, NULL, + &verify_result); EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, error); EXPECT_EQ(CERT_STATUS_AUTHORITY_INVALID, verify_result.cert_status); @@ -576,7 +577,7 @@ TEST_F(CertDatabaseNSSTest, ImportServerCert_SelfSigned) { CertDatabase::TRUSTED_SSL | CertDatabase::TRUSTED_EMAIL)); verify_result.Reset(); - error = puny_cert->Verify("xn--wgv71a119e.com", flags, &verify_result); + error = puny_cert->Verify("xn--wgv71a119e.com", flags, NULL, &verify_result); EXPECT_EQ(OK, error); EXPECT_EQ(0U, verify_result.cert_status); } diff --git a/net/base/cert_verifier.cc b/net/base/cert_verifier.cc index 88d8c7a..90a728c 100644 --- a/net/base/cert_verifier.cc +++ b/net/base/cert_verifier.cc @@ -13,6 +13,7 @@ #include "base/synchronization/lock.h" #include "base/time.h" #include "base/threading/worker_pool.h" +#include "net/base/crl_set.h" #include "net/base/net_errors.h" #include "net/base/net_log.h" #include "net/base/x509_certificate.h" @@ -142,10 +143,12 @@ class CertVerifierWorker { CertVerifierWorker(X509Certificate* cert, const std::string& hostname, int flags, + CRLSet* crl_set, CertVerifier* cert_verifier) : cert_(cert), hostname_(hostname), flags_(flags), + crl_set_(crl_set), origin_loop_(MessageLoop::current()), cert_verifier_(cert_verifier), canceled_(false), @@ -171,7 +174,7 @@ class CertVerifierWorker { private: void Run() { // Runs on a worker thread. - error_ = cert_->Verify(hostname_, flags_, &verify_result_); + error_ = cert_->Verify(hostname_, flags_, crl_set_, &verify_result_); #if defined(USE_NSS) // Detach the thread from NSPR. // Calling NSS functions attaches the thread to NSPR, which stores @@ -231,6 +234,7 @@ class CertVerifierWorker { scoped_refptr<X509Certificate> cert_; const std::string hostname_; const int flags_; + scoped_refptr<CRLSet> crl_set_; MessageLoop* const origin_loop_; CertVerifier* const cert_verifier_; @@ -346,6 +350,7 @@ CertVerifier::~CertVerifier() { int CertVerifier::Verify(X509Certificate* cert, const std::string& hostname, int flags, + CRLSet* crl_set, CertVerifyResult* verify_result, const CompletionCallback& callback, RequestHandle* out_req, @@ -386,7 +391,7 @@ int CertVerifier::Verify(X509Certificate* cert, } else { // Need to make a new request. CertVerifierWorker* worker = new CertVerifierWorker(cert, hostname, flags, - this); + crl_set, this); job = new CertVerifierJob( worker, BoundNetLog::Make(net_log.net_log(), NetLog::SOURCE_CERT_VERIFIER_JOB)); @@ -503,6 +508,7 @@ SingleRequestCertVerifier::~SingleRequestCertVerifier() { int SingleRequestCertVerifier::Verify(X509Certificate* cert, const std::string& hostname, int flags, + CRLSet* crl_set, CertVerifyResult* verify_result, const CompletionCallback& callback, const BoundNetLog& net_log) { @@ -511,14 +517,14 @@ int SingleRequestCertVerifier::Verify(X509Certificate* cert, // Do a synchronous verification. if (callback.is_null()) - return cert->Verify(hostname, flags, verify_result); + return cert->Verify(hostname, flags, crl_set, verify_result); CertVerifier::RequestHandle request = NULL; // We need to be notified of completion before |callback| is called, so that // we can clear out |cur_request_*|. int rv = cert_verifier_->Verify( - cert, hostname, flags, verify_result, + cert, hostname, flags, crl_set, verify_result, base::Bind(&SingleRequestCertVerifier::OnVerifyCompletion, base::Unretained(this)), &request, net_log); diff --git a/net/base/cert_verifier.h b/net/base/cert_verifier.h index 5ad64b0..68000fe 100644 --- a/net/base/cert_verifier.h +++ b/net/base/cert_verifier.h @@ -24,6 +24,7 @@ namespace net { class BoundNetLog; class CertVerifierJob; class CertVerifierWorker; +class CRLSet; class X509Certificate; // CachedCertVerifyResult contains the result of a certificate verification. @@ -92,6 +93,9 @@ class NET_EXPORT CertVerifier : NON_EXPORTED_BASE(public base::NonThreadSafe), // VERIFY_REV_CHECKING_ENABLED is not set), EV certificate verification will // not be performed. // + // |crl_set| points to an optional CRLSet structure which can be used to + // avoid revocation checks over the network. + // // |callback| must not be null. ERR_IO_PENDING is returned if the operation // could not be completed synchronously, in which case the result code will // be passed to the callback when available. @@ -102,6 +106,7 @@ class NET_EXPORT CertVerifier : NON_EXPORTED_BASE(public base::NonThreadSafe), int Verify(X509Certificate* cert, const std::string& hostname, int flags, + CRLSet* crl_set, CertVerifyResult* verify_result, const CompletionCallback& callback, RequestHandle* out_req, @@ -202,6 +207,7 @@ class SingleRequestCertVerifier { int Verify(X509Certificate* cert, const std::string& hostname, int flags, + CRLSet* crl_set, CertVerifyResult* verify_result, const CompletionCallback& callback, const BoundNetLog& net_log); diff --git a/net/base/cert_verifier_unittest.cc b/net/base/cert_verifier_unittest.cc index 19dcc5c..8a026fb 100644 --- a/net/base/cert_verifier_unittest.cc +++ b/net/base/cert_verifier_unittest.cc @@ -50,7 +50,7 @@ TEST(CertVerifierTest, CacheHit) { TestCompletionCallback callback; CertVerifier::RequestHandle request_handle; - error = verifier.Verify(test_cert, "www.example.com", 0, &verify_result, + error = verifier.Verify(test_cert, "www.example.com", 0, NULL, &verify_result, callback.callback(), &request_handle, BoundNetLog()); ASSERT_EQ(ERR_IO_PENDING, error); ASSERT_TRUE(request_handle != NULL); @@ -60,7 +60,7 @@ TEST(CertVerifierTest, CacheHit) { ASSERT_EQ(0u, verifier.cache_hits()); ASSERT_EQ(0u, verifier.inflight_joins()); - error = verifier.Verify(test_cert, "www.example.com", 0, &verify_result, + error = verifier.Verify(test_cert, "www.example.com", 0, NULL, &verify_result, callback.callback(), &request_handle, BoundNetLog()); // Synchronous completion. ASSERT_NE(ERR_IO_PENDING, error); @@ -91,12 +91,12 @@ TEST(CertVerifierTest, InflightJoin) { TestCompletionCallback callback2; CertVerifier::RequestHandle request_handle2; - error = verifier.Verify(test_cert, "www.example.com", 0, &verify_result, + error = verifier.Verify(test_cert, "www.example.com", 0, NULL, &verify_result, callback.callback(), &request_handle, BoundNetLog()); ASSERT_EQ(ERR_IO_PENDING, error); ASSERT_TRUE(request_handle != NULL); error = verifier.Verify( - test_cert, "www.example.com", 0, &verify_result2, + test_cert, "www.example.com", 0, NULL, &verify_result2, callback2.callback(), &request_handle2, BoundNetLog()); ASSERT_EQ(ERR_IO_PENDING, error); ASSERT_TRUE(request_handle2 != NULL); @@ -127,7 +127,7 @@ TEST(CertVerifierTest, ExpiredCacheEntry) { CertVerifier::RequestHandle request_handle; error = verifier.Verify( - test_cert, "www.example.com", 0, &verify_result, + test_cert, "www.example.com", 0, NULL, &verify_result, callback.callback(), &request_handle, BoundNetLog()); ASSERT_EQ(ERR_IO_PENDING, error); ASSERT_TRUE(request_handle != NULL); @@ -139,7 +139,7 @@ TEST(CertVerifierTest, ExpiredCacheEntry) { // Before expiration, should have a cache hit. error = verifier.Verify( - test_cert, "www.example.com", 0, &verify_result, + test_cert, "www.example.com", 0, NULL, &verify_result, callback.callback(), &request_handle, BoundNetLog()); // Synchronous completion. ASSERT_NE(ERR_IO_PENDING, error); @@ -154,7 +154,7 @@ TEST(CertVerifierTest, ExpiredCacheEntry) { current_time += base::TimeDelta::FromMinutes(60); time_service->set_current_time(current_time); error = verifier.Verify( - test_cert, "www.example.com", 0, &verify_result, + test_cert, "www.example.com", 0, NULL, &verify_result, callback.callback(), &request_handle, BoundNetLog()); ASSERT_EQ(ERR_IO_PENDING, error); ASSERT_TRUE(request_handle != NULL); @@ -189,7 +189,7 @@ TEST(CertVerifierTest, FullCache) { CertVerifier::RequestHandle request_handle; error = verifier.Verify( - test_cert, "www.example.com", 0, &verify_result, + test_cert, "www.example.com", 0, NULL, &verify_result, callback.callback(), &request_handle, BoundNetLog()); ASSERT_EQ(ERR_IO_PENDING, error); ASSERT_TRUE(request_handle != NULL); @@ -202,7 +202,7 @@ TEST(CertVerifierTest, FullCache) { for (unsigned i = 0; i < kCacheSize; i++) { std::string hostname = base::StringPrintf("www%d.example.com", i + 1); error = verifier.Verify( - test_cert, hostname, 0, &verify_result, + test_cert, hostname, 0, NULL, &verify_result, callback.callback(), &request_handle, BoundNetLog()); ASSERT_EQ(ERR_IO_PENDING, error); ASSERT_TRUE(request_handle != NULL); @@ -217,7 +217,7 @@ TEST(CertVerifierTest, FullCache) { current_time += base::TimeDelta::FromMinutes(60); time_service->set_current_time(current_time); error = verifier.Verify( - test_cert, "www999.example.com", 0, &verify_result, + test_cert, "www999.example.com", 0, NULL, &verify_result, callback.callback(), &request_handle, BoundNetLog()); ASSERT_EQ(ERR_IO_PENDING, error); ASSERT_TRUE(request_handle != NULL); @@ -244,7 +244,7 @@ TEST(CertVerifierTest, CancelRequest) { CertVerifier::RequestHandle request_handle; error = verifier.Verify( - test_cert, "www.example.com", 0, &verify_result, + test_cert, "www.example.com", 0, NULL, &verify_result, base::Bind(&FailTest), &request_handle, BoundNetLog()); ASSERT_EQ(ERR_IO_PENDING, error); ASSERT_TRUE(request_handle != NULL); @@ -256,7 +256,7 @@ TEST(CertVerifierTest, CancelRequest) { TestCompletionCallback callback; for (int i = 0; i < 5; ++i) { error = verifier.Verify( - test_cert, "www2.example.com", 0, &verify_result, + test_cert, "www2.example.com", 0, NULL, &verify_result, callback.callback(), &request_handle, BoundNetLog()); ASSERT_EQ(ERR_IO_PENDING, error); ASSERT_TRUE(request_handle != NULL); @@ -279,7 +279,7 @@ TEST(CertVerifierTest, CancelRequestThenQuit) { TestCompletionCallback callback; CertVerifier::RequestHandle request_handle; - error = verifier.Verify(test_cert, "www.example.com", 0, &verify_result, + error = verifier.Verify(test_cert, "www.example.com", 0, NULL, &verify_result, callback.callback(), &request_handle, BoundNetLog()); ASSERT_EQ(ERR_IO_PENDING, error); ASSERT_TRUE(request_handle != NULL); diff --git a/net/base/crl_set.h b/net/base/crl_set.h index 1f5f143..14c4aa0 100644 --- a/net/base/crl_set.h +++ b/net/base/crl_set.h @@ -26,7 +26,7 @@ class NET_EXPORT CRLSet : public base::RefCountedThreadSafe<CRLSet> { public: enum Result { REVOKED, // the certificate should be rejected. - UNKNOWN, // there was an error in processing. + UNKNOWN, // the CRL for the certificate is not included in the set. GOOD, // the certificate is not listed. }; diff --git a/net/base/ssl_config_service.cc b/net/base/ssl_config_service.cc index c0110a9..27d3075 100644 --- a/net/base/ssl_config_service.cc +++ b/net/base/ssl_config_service.cc @@ -4,6 +4,9 @@ #include "net/base/ssl_config_service.h" +#include "base/lazy_instance.h" +#include "base/memory/ref_counted.h" +#include "net/base/crl_set.h" #include "net/base/ssl_config_service_defaults.h" #include "net/base/ssl_false_start_blacklist.h" @@ -59,6 +62,9 @@ static bool g_cached_info_enabled = false; static bool g_origin_bound_certs_enabled = false; static bool g_false_start_enabled = true; static bool g_dns_cert_provenance_checking = false; +base::LazyInstance<scoped_refptr<CRLSet>, + base::LeakyLazyInstanceTraits<scoped_refptr<CRLSet> > > + g_crl_set(base::LINKER_INITIALIZED); // static void SSLConfigService::DisableFalseStart() { @@ -82,14 +88,12 @@ bool SSLConfigService::dns_cert_provenance_checking_enabled() { // static void SSLConfigService::SetCRLSet(scoped_refptr<CRLSet> crl_set) { - // TODO(agl): not implemented yet. + g_crl_set.Get() = crl_set; } // static scoped_refptr<CRLSet> SSLConfigService::GetCRLSet() { - // TODO(agl): not implemented yet. - scoped_refptr<CRLSet> ret; - return ret; + return g_crl_set.Get(); } void SSLConfigService::EnableCachedInfo() { diff --git a/net/base/ssl_config_service.h b/net/base/ssl_config_service.h index 0746abf..cb317c7 100644 --- a/net/base/ssl_config_service.h +++ b/net/base/ssl_config_service.h @@ -151,7 +151,6 @@ class NET_EXPORT SSLConfigService static bool dns_cert_provenance_checking_enabled(); // Sets and gets the current, global CRL set. - // TODO(agl): currently unused. static void SetCRLSet(scoped_refptr<CRLSet> crl_set); static scoped_refptr<CRLSet> GetCRLSet(); diff --git a/net/base/ssl_config_service_defaults.cc b/net/base/ssl_config_service_defaults.cc index 9a3afa2..18918b9 100644 --- a/net/base/ssl_config_service_defaults.cc +++ b/net/base/ssl_config_service_defaults.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -12,6 +12,7 @@ SSLConfigServiceDefaults::SSLConfigServiceDefaults() { void SSLConfigServiceDefaults::GetSSLConfig(SSLConfig* config) { *config = default_config_; SetSSLConfigFlags(config); + config->crl_set = GetCRLSet(); } SSLConfigServiceDefaults::~SSLConfigServiceDefaults() { diff --git a/net/base/x509_certificate.cc b/net/base/x509_certificate.cc index 9158388..e144aad 100644 --- a/net/base/x509_certificate.cc +++ b/net/base/x509_certificate.cc @@ -584,7 +584,9 @@ bool X509Certificate::VerifyHostname( return false; } -int X509Certificate::Verify(const std::string& hostname, int flags, +int X509Certificate::Verify(const std::string& hostname, + int flags, + CRLSet* crl_set, CertVerifyResult* verify_result) const { verify_result->Reset(); verify_result->verified_cert = const_cast<X509Certificate*>(this); @@ -594,7 +596,7 @@ int X509Certificate::Verify(const std::string& hostname, int flags, return ERR_CERT_REVOKED; } - int rv = VerifyInternal(hostname, flags, verify_result); + int rv = VerifyInternal(hostname, flags, crl_set, verify_result); // This check is done after VerifyInternal so that VerifyInternal can fill in // the list of public key hashes. diff --git a/net/base/x509_certificate.h b/net/base/x509_certificate.h index 94a6f4a..b4677d2 100644 --- a/net/base/x509_certificate.h +++ b/net/base/x509_certificate.h @@ -44,6 +44,7 @@ class RSAPrivateKey; namespace net { +class CRLSet; class CertVerifyResult; typedef std::vector<scoped_refptr<X509Certificate> > CertificateList; @@ -320,8 +321,12 @@ class NET_EXPORT X509Certificate // If VERIFY_REV_CHECKING_ENABLED is set in |flags|, certificate revocation // checking is performed. If VERIFY_EV_CERT is set in |flags| too, // EV certificate verification is performed. + // + // |crl_set| points to an optional CRLSet structure which can be used to + // avoid revocation checks over the network. int Verify(const std::string& hostname, int flags, + CRLSet* crl_set, CertVerifyResult* verify_result) const; // Verifies that |hostname| matches this certificate. @@ -416,6 +421,7 @@ class NET_EXPORT X509Certificate // Parameters and return value are as per Verify(). int VerifyInternal(const std::string& hostname, int flags, + CRLSet* crl_set, CertVerifyResult* verify_result) const; // The serial number, DER encoded. diff --git a/net/base/x509_certificate_mac.cc b/net/base/x509_certificate_mac.cc index c47d1a5..dc7d4e9 100644 --- a/net/base/x509_certificate_mac.cc +++ b/net/base/x509_certificate_mac.cc @@ -738,6 +738,7 @@ void X509Certificate::GetSubjectAltName( int X509Certificate::VerifyInternal(const std::string& hostname, int flags, + CRLSet* crl_set, CertVerifyResult* verify_result) const { ScopedCFTypeRef<CFArrayRef> trust_policies; OSStatus status = CreateTrustPolicies(hostname, flags, &trust_policies); diff --git a/net/base/x509_certificate_nss.cc b/net/base/x509_certificate_nss.cc index 26b74c1..2ca31ba 100644 --- a/net/base/x509_certificate_nss.cc +++ b/net/base/x509_certificate_nss.cc @@ -21,8 +21,10 @@ #include "base/time.h" #include "crypto/nss_util.h" #include "crypto/rsa_private_key.h" +#include "net/base/asn1_util.h" #include "net/base/cert_status_flags.h" #include "net/base/cert_verify_result.h" +#include "net/base/crl_set.h" #include "net/base/ev_root_ca_metadata.h" #include "net/base/net_errors.h" #include "net/base/x509_util_nss.h" @@ -228,6 +230,67 @@ bool IsKnownRoot(CERTCertificate* root) { "NSS Builtin Objects"); } +enum CRLSetResult { + kCRLSetRevoked, + kCRLSetOk, + kCRLSetError, +}; + +// CheckRevocationWithCRLSet attempts to check each element of |cert_list| +// against |crl_set|. It returns: +// kCRLSetRevoked: if any element of the chain is known to have been revoked. +// kCRLSetError: if an error occurs in processing. +// kCRLSetOk: if no element in the chain is known to have been revoked. +CRLSetResult CheckRevocationWithCRLSet(CERTCertList* cert_list, + CERTCertificate* root, + CRLSet* crl_set) { + std::vector<CERTCertificate*> certs; + for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); + !CERT_LIST_END(node, cert_list); + node = CERT_LIST_NEXT(node)) { + certs.push_back(node->cert); + } + certs.push_back(root); + + CERTCertificate* prev = NULL; + for (std::vector<CERTCertificate*>::iterator i = certs.begin(); + i != certs.end(); ++i) { + CERTCertificate* cert = *i; + CERTCertificate* child = prev; + prev = cert; + if (child == NULL) + continue; + + base::StringPiece der(reinterpret_cast<char*>(cert->derCert.data), + cert->derCert.len); + + base::StringPiece spki; + if (!asn1::ExtractSPKIFromDERCert(der, &spki)) { + NOTREACHED(); + return kCRLSetError; + } + + std::string serial_number( + reinterpret_cast<char*>(child->serialNumber.data), + child->serialNumber.len); + + CRLSet::Result result = crl_set->CheckCertificate(serial_number, spki); + + switch (result) { + case CRLSet::REVOKED: + return kCRLSetRevoked; + case CRLSet::UNKNOWN: + case CRLSet::GOOD: + continue; + default: + NOTREACHED(); + return kCRLSetError; + } + } + + return kCRLSetOk; +} + void ParsePrincipal(CERTName* name, CertPrincipal* principal) { typedef char* (*CERTGetNameFunc)(CERTName* name); @@ -691,6 +754,7 @@ void X509Certificate::GetSubjectAltName( int X509Certificate::VerifyInternal(const std::string& hostname, int flags, + CRLSet* crl_set, CertVerifyResult* verify_result) const { // Make sure that the hostname matches with the common name of the cert. SECStatus status = CERT_VerifyCertName(cert_handle_, hostname.c_str()); @@ -723,7 +787,34 @@ int X509Certificate::VerifyInternal(const std::string& hostname, // EV requires revocation checking. flags &= ~VERIFY_EV_CERT; } - status = PKIXVerifyCert(cert_handle_, check_revocation, NULL, 0, cvout); + + if (check_revocation && crl_set) { + // We have a CRLSet so we build a chain without revocation checking in + // order to try and check it ourselves. + status = PKIXVerifyCert(cert_handle_, false /* no revocation checking */, + NULL, 0, cvout); + if (status == SECSuccess) { + CRLSetResult crl_set_result = CheckRevocationWithCRLSet( + cvout[cvout_cert_list_index].value.pointer.chain, + cvout[cvout_trust_anchor_index].value.pointer.cert, + crl_set); + if (crl_set_result == kCRLSetError) { + // An error occured during processing so we fall back to standard + // revocation checking. + status = PKIXVerifyCert(cert_handle_, check_revocation, NULL, 0, cvout); + } else { + DCHECK(crl_set_result == kCRLSetRevoked || crl_set_result == kCRLSetOk); + if (crl_set_result == kCRLSetRevoked) { + PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); + status = SECFailure; + } + } + } + } else { + status = PKIXVerifyCert(cert_handle_, check_revocation, + NULL, 0, cvout); + } + if (status != SECSuccess) { int err = PORT_GetError(); LOG(ERROR) << "CERT_PKIXVerifyCert for " << hostname diff --git a/net/base/x509_certificate_unittest.cc b/net/base/x509_certificate_unittest.cc index 9ba1124..6dab44f 100644 --- a/net/base/x509_certificate_unittest.cc +++ b/net/base/x509_certificate_unittest.cc @@ -233,7 +233,8 @@ void CheckGoogleCert(const scoped_refptr<X509Certificate>& google_cert, CertVerifyResult verify_result; int flags = X509Certificate::VERIFY_REV_CHECKING_ENABLED | X509Certificate::VERIFY_EV_CERT; - EXPECT_EQ(OK, google_cert->Verify("www.google.com", flags, &verify_result)); + EXPECT_EQ(OK, google_cert->Verify("www.google.com", flags, NULL, + &verify_result); EXPECT_FALSE(verify_result.cert_status & CERT_STATUS_IS_EV); #endif } @@ -299,7 +300,7 @@ TEST(X509CertificateTest, WebkitCertParsing) { int flags = X509Certificate::VERIFY_REV_CHECKING_ENABLED | X509Certificate::VERIFY_EV_CERT; CertVerifyResult verify_result; - EXPECT_EQ(OK, webkit_cert->Verify("webkit.org", flags, &verify_result)); + EXPECT_EQ(OK, webkit_cert->Verify("webkit.org", flags, NULL, &verify_result)); EXPECT_FALSE(verify_result.cert_status & CERT_STATUS_IS_EV); #endif @@ -362,12 +363,14 @@ TEST(X509CertificateTest, ThawteCertParsing) { X509Certificate::VERIFY_EV_CERT; CertVerifyResult verify_result; // EV cert verification requires revocation checking. - EXPECT_EQ(OK, thawte_cert->Verify("www.thawte.com", flags, &verify_result)); + EXPECT_EQ(OK, thawte_cert->Verify("www.thawte.com", flags, NULL, + &verify_result); EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_IS_EV); // Consequently, if we don't have revocation checking enabled, we can't claim // any cert is EV. flags = X509Certificate::VERIFY_EV_CERT; - EXPECT_EQ(OK, thawte_cert->Verify("www.thawte.com", flags, &verify_result)); + EXPECT_EQ(OK, thawte_cert->Verify("www.thawte.com", flags, NULL, + &verify_result)); EXPECT_FALSE(verify_result.cert_status & CERT_STATUS_IS_EV); #endif } @@ -387,7 +390,7 @@ TEST(X509CertificateTest, PaypalNullCertParsing) { int flags = 0; CertVerifyResult verify_result; - int error = paypal_null_cert->Verify("www.paypal.com", flags, + int error = paypal_null_cert->Verify("www.paypal.com", flags, NULL, &verify_result); #if defined(USE_OPENSSL) || defined(OS_MACOSX) || defined(OS_WIN) // TOOD(bulach): investigate why macosx and win aren't returning @@ -460,7 +463,8 @@ TEST(X509CertificateTest, IntermediateCARequireExplicitPolicy) { int flags = 0; CertVerifyResult verify_result; - int error = cert_chain->Verify("www.us.army.mil", flags, &verify_result); + int error = cert_chain->Verify("www.us.army.mil", flags, NULL, + &verify_result); EXPECT_EQ(OK, error); EXPECT_EQ(0U, verify_result.cert_status); root_certs->Clear(); @@ -495,7 +499,8 @@ TEST(X509CertificateTest, DISABLED_GlobalSignR3EVTest) { CertVerifyResult verify_result; int flags = X509Certificate::VERIFY_REV_CHECKING_ENABLED | X509Certificate::VERIFY_EV_CERT; - int error = cert_chain->Verify("2029.globalsign.com", flags, &verify_result); + int error = cert_chain->Verify("2029.globalsign.com", flags, NULL, + &verify_result); if (error == OK) EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_IS_EV); else @@ -522,13 +527,14 @@ TEST(X509CertificateTest, GoogleDigiNotarTest) { CertVerifyResult verify_result; int flags = X509Certificate::VERIFY_REV_CHECKING_ENABLED; - int error = cert_chain->Verify("mail.google.com", flags, &verify_result); + int error = cert_chain->Verify("mail.google.com", flags, NULL, + &verify_result); EXPECT_NE(OK, error); // Now turn off revocation checking. Certificate verification should still // fail. flags = 0; - error = cert_chain->Verify("mail.google.com", flags, &verify_result); + error = cert_chain->Verify("mail.google.com", flags, NULL, &verify_result); EXPECT_NE(OK, error); } @@ -588,7 +594,7 @@ TEST(X509CertificateTest, TestKnownRoot) { CertVerifyResult verify_result; // This is going to blow up in Feb 2012. Sorry! Disable and file a bug // against agl. Also see PublicKeyHashes in this file. - int error = cert_chain->Verify("www.nist.gov", flags, &verify_result); + int error = cert_chain->Verify("www.nist.gov", flags, NULL, &verify_result); EXPECT_EQ(OK, error); EXPECT_EQ(0U, verify_result.cert_status); EXPECT_TRUE(verify_result.is_issued_by_known_root); @@ -662,7 +668,7 @@ TEST(X509CertificateTest, PublicKeyHashes) { int flags = 0; CertVerifyResult verify_result; - int error = cert_chain->Verify("www.nist.gov", flags, &verify_result); + int error = cert_chain->Verify("www.nist.gov", flags, NULL, &verify_result); EXPECT_EQ(OK, error); EXPECT_EQ(0U, verify_result.cert_status); ASSERT_LE(2u, verify_result.public_key_hashes.size()); @@ -686,7 +692,8 @@ TEST(X509CertificateTest, InvalidKeyUsage) { int flags = 0; CertVerifyResult verify_result; - int error = server_cert->Verify("jira.aquameta.com", flags, &verify_result); + int error = server_cert->Verify("jira.aquameta.com", flags, NULL, + &verify_result); #if defined(USE_OPENSSL) // This certificate has two errors: "invalid key usage" and "untrusted CA". // However, OpenSSL returns only one (the latter), and we can't detect @@ -892,7 +899,7 @@ TEST(X509CertificateTest, VerifyReturnChainBasic) { CertVerifyResult verify_result; EXPECT_EQ(static_cast<X509Certificate*>(NULL), verify_result.verified_cert); - int error = google_full_chain->Verify("127.0.0.1", 0, &verify_result); + int error = google_full_chain->Verify("127.0.0.1", 0, NULL, &verify_result); EXPECT_EQ(OK, error); ASSERT_NE(static_cast<X509Certificate*>(NULL), verify_result.verified_cert); @@ -938,7 +945,7 @@ TEST(X509CertificateTest, VerifyReturnChainProperlyOrdered) { CertVerifyResult verify_result; EXPECT_EQ(static_cast<X509Certificate*>(NULL), verify_result.verified_cert); - int error = google_full_chain->Verify("127.0.0.1", 0, &verify_result); + int error = google_full_chain->Verify("127.0.0.1", 0, NULL, &verify_result); EXPECT_EQ(OK, error); ASSERT_NE(static_cast<X509Certificate*>(NULL), verify_result.verified_cert); @@ -989,7 +996,7 @@ TEST(X509CertificateTest, VerifyReturnChainFiltersUnrelatedCerts) { CertVerifyResult verify_result; EXPECT_EQ(static_cast<X509Certificate*>(NULL), verify_result.verified_cert); - int error = google_full_chain->Verify("127.0.0.1", 0, &verify_result); + int error = google_full_chain->Verify("127.0.0.1", 0, NULL, &verify_result); EXPECT_EQ(OK, error); ASSERT_NE(static_cast<X509Certificate*>(NULL), verify_result.verified_cert); diff --git a/net/base/x509_certificate_win.cc b/net/base/x509_certificate_win.cc index 5c53a15..d7b28a2 100644 --- a/net/base/x509_certificate_win.cc +++ b/net/base/x509_certificate_win.cc @@ -696,6 +696,7 @@ HCERTSTORE X509Certificate::cert_store() { int X509Certificate::VerifyInternal(const std::string& hostname, int flags, + CRLSet* crl_set, CertVerifyResult* verify_result) const { if (!cert_handle_) return ERR_UNEXPECTED; diff --git a/net/socket/ssl_client_socket_mac.cc b/net/socket/ssl_client_socket_mac.cc index b823265..ed6ec77 100644 --- a/net/socket/ssl_client_socket_mac.cc +++ b/net/socket/ssl_client_socket_mac.cc @@ -1158,6 +1158,7 @@ int SSLClientSocketMac::DoVerifyCert() { verifier_.reset(new SingleRequestCertVerifier(cert_verifier_)); return verifier_->Verify( server_cert_, host_and_port_.host(), flags, + NULL /* no CRL set */, &server_cert_verify_result_, base::Bind(&SSLClientSocketMac::OnHandshakeIOComplete, base::Unretained(this)), diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc index 1273940..81f172d 100644 --- a/net/socket/ssl_client_socket_nss.cc +++ b/net/socket/ssl_client_socket_nss.cc @@ -1664,6 +1664,7 @@ int SSLClientSocketNSS::DoVerifyCert(int result) { server_cert_verify_result_ = &local_server_cert_verify_result_; return verifier_->Verify( server_cert_, host_and_port_.host(), flags, + ssl_config_.crl_set, &local_server_cert_verify_result_, base::Bind(&SSLClientSocketNSS::OnHandshakeIOComplete, base::Unretained(this)), diff --git a/net/socket/ssl_client_socket_win.cc b/net/socket/ssl_client_socket_win.cc index 7235668..3baeffb 100644 --- a/net/socket/ssl_client_socket_win.cc +++ b/net/socket/ssl_client_socket_win.cc @@ -1175,6 +1175,7 @@ int SSLClientSocketWin::DoVerifyCert() { verifier_.reset(new SingleRequestCertVerifier(cert_verifier_)); return verifier_->Verify( server_cert_, host_and_port_.host(), flags, + NULL /* no CRL set */, &server_cert_verify_result_, base::Bind(&SSLClientSocketWin::OnHandshakeIOComplete, base::Unretained(this)), diff --git a/net/socket/ssl_host_info.cc b/net/socket/ssl_host_info.cc index 5b4b42dd..d792d43a 100644 --- a/net/socket/ssl_host_info.cc +++ b/net/socket/ssl_host_info.cc @@ -128,7 +128,7 @@ bool SSLHostInfo::ParseInner(const std::string& data) { verification_start_time_ = base::TimeTicks::Now(); verification_end_time_ = base::TimeTicks(); int rv = verifier_.Verify( - cert_.get(), hostname_, flags, &cert_verify_result_, + cert_.get(), hostname_, flags, crl_set_, &cert_verify_result_, base::Bind(&SSLHostInfo::VerifyCallback, weak_factory_.GetWeakPtr()), // TODO(willchan): Figure out how to use NetLog here. BoundNetLog()); diff --git a/net/socket/ssl_host_info.h b/net/socket/ssl_host_info.h index c8028d3..4011cc3 100644 --- a/net/socket/ssl_host_info.h +++ b/net/socket/ssl_host_info.h @@ -21,6 +21,7 @@ namespace net { +class CRLSet; class X509Certificate; struct SSLConfig; @@ -121,9 +122,10 @@ class NET_EXPORT_PRIVATE SSLHostInfo { const std::string hostname_; bool cert_parsing_failed_; OldCompletionCallback* cert_verification_callback_; - // These two members are taken from the SSLConfig. + // These three members are taken from the SSLConfig. bool rev_checking_enabled_; bool verify_ev_cert_; + scoped_refptr<CRLSet> crl_set_; base::TimeTicks verification_start_time_; base::TimeTicks verification_end_time_; CertVerifyResult cert_verify_result_; |