summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/net/crl_set_fetcher.cc15
-rw-r--r--chrome/browser/net/ssl_config_service_manager_pref.cc1
-rw-r--r--chrome/browser/ui/browser_init.cc12
-rw-r--r--chrome/common/chrome_switches.cc4
-rw-r--r--chrome/common/chrome_switches.h1
-rw-r--r--net/base/cert_database_nss_unittest.cc7
-rw-r--r--net/base/cert_verifier.cc14
-rw-r--r--net/base/cert_verifier.h6
-rw-r--r--net/base/cert_verifier_unittest.cc26
-rw-r--r--net/base/crl_set.h2
-rw-r--r--net/base/ssl_config_service.cc12
-rw-r--r--net/base/ssl_config_service.h1
-rw-r--r--net/base/ssl_config_service_defaults.cc3
-rw-r--r--net/base/x509_certificate.cc6
-rw-r--r--net/base/x509_certificate.h6
-rw-r--r--net/base/x509_certificate_mac.cc1
-rw-r--r--net/base/x509_certificate_nss.cc93
-rw-r--r--net/base/x509_certificate_unittest.cc37
-rw-r--r--net/base/x509_certificate_win.cc1
-rw-r--r--net/socket/ssl_client_socket_mac.cc1
-rw-r--r--net/socket/ssl_client_socket_nss.cc1
-rw-r--r--net/socket/ssl_client_socket_win.cc1
-rw-r--r--net/socket/ssl_host_info.cc2
-rw-r--r--net/socket/ssl_host_info.h4
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_;