summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoreranm <eranm@chromium.org>2014-12-03 07:53:23 -0800
committerCommit bot <commit-bot@chromium.org>2014-12-03 15:53:46 +0000
commit6571b2b68658337e301c074763383e0b5c231aea (patch)
treebf97e15557650b703fe7fc4be8146a2ce36c13d8
parentc4c9cc88986c37bebe988fecf3b64a53b7070874 (diff)
downloadchromium_src-6571b2b68658337e301c074763383e0b5c231aea.zip
chromium_src-6571b2b68658337e301c074763383e0b5c231aea.tar.gz
chromium_src-6571b2b68658337e301c074763383e0b5c231aea.tar.bz2
Certificate Transparency: Require SCTs for EV certificates.
Add a flag to enforce the policy detailed here: http://dev.chromium.org/Home/chromium-security/certificate-transparency BUG=397458 Review URL: https://codereview.chromium.org/422063004 Cr-Commit-Position: refs/heads/master@{#306612}
-rw-r--r--chrome/browser/io_thread.cc12
-rw-r--r--chrome/browser/io_thread.h2
-rw-r--r--chrome/common/chrome_switches.cc5
-rw-r--r--chrome/common/chrome_switches.h1
-rw-r--r--net/cert/cert_policy_enforcer.cc165
-rw-r--r--net/cert/cert_policy_enforcer.h56
-rw-r--r--net/cert/cert_policy_enforcer_unittest.cc212
-rw-r--r--net/http/http_network_session.cc24
-rw-r--r--net/http/http_network_session.h2
-rw-r--r--net/http/http_network_transaction_unittest.cc1
-rw-r--r--net/http/http_proxy_client_socket_pool_unittest.cc1
-rw-r--r--net/http/http_stream_factory_impl_unittest.cc13
-rw-r--r--net/net.gypi3
-rw-r--r--net/socket/client_socket_pool_manager_impl.cc49
-rw-r--r--net/socket/client_socket_pool_manager_impl.h2
-rw-r--r--net/socket/ssl_client_socket.h7
-rw-r--r--net/socket/ssl_client_socket_nss.cc46
-rw-r--r--net/socket/ssl_client_socket_nss.h3
-rw-r--r--net/socket/ssl_client_socket_openssl.cc48
-rw-r--r--net/socket/ssl_client_socket_openssl.h2
-rw-r--r--net/socket/ssl_client_socket_pool.cc3
-rw-r--r--net/socket/ssl_client_socket_pool.h2
-rw-r--r--net/socket/ssl_client_socket_pool_unittest.cc21
-rw-r--r--tools/metrics/histograms/histograms.xml23
24 files changed, 590 insertions, 113 deletions
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index 7cbcf7b..4fa4eb5 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -53,9 +53,11 @@
#include "content/public/browser/cookie_store_factory.h"
#include "net/base/host_mapping_rules.h"
#include "net/base/net_util.h"
+#include "net/cert/cert_policy_enforcer.h"
#include "net/cert/cert_verifier.h"
#include "net/cert/cert_verify_proc.h"
#include "net/cert/ct_known_logs.h"
+#include "net/cert/ct_known_logs_static.h"
#include "net/cert/ct_log_verifier.h"
#include "net/cert/ct_verifier.h"
#include "net/cert/multi_log_ct_verifier.h"
@@ -642,6 +644,15 @@ void IOThread::InitAsync() {
}
}
+ net::CertPolicyEnforcer* policy_enforcer = NULL;
+ // TODO(eranm): Control with Finch, crbug.com/437766
+ if (command_line.HasSwitch(switches::kRequireCTForEV)) {
+ policy_enforcer = new net::CertPolicyEnforcer(kNumKnownCTLogs, true);
+ } else {
+ policy_enforcer = new net::CertPolicyEnforcer(kNumKnownCTLogs, false);
+ }
+ globals_->cert_policy_enforcer.reset(policy_enforcer);
+
globals_->ssl_config_service = GetSSLConfigService();
SetupDataReductionProxy(network_delegate);
@@ -988,6 +999,7 @@ void IOThread::InitializeNetworkSessionParamsFromGlobals(
net::HttpNetworkSession::Params* params) {
params->host_resolver = globals.host_resolver.get();
params->cert_verifier = globals.cert_verifier.get();
+ params->cert_policy_enforcer = globals.cert_policy_enforcer.get();
params->channel_id_service = globals.system_channel_id_service.get();
params->transport_security_state = globals.transport_security_state.get();
params->ssl_config_service = globals.ssl_config_service.get();
diff --git a/chrome/browser/io_thread.h b/chrome/browser/io_thread.h
index 897d2aa..690306f 100644
--- a/chrome/browser/io_thread.h
+++ b/chrome/browser/io_thread.h
@@ -49,6 +49,7 @@ class EventRouterForwarder;
}
namespace net {
+class CertPolicyEnforcer;
class CertVerifier;
class ChannelIDService;
class CookieStore;
@@ -132,6 +133,7 @@ class IOThread : public content::BrowserThreadDelegate {
// pins.
scoped_ptr<net::TransportSecurityState> transport_security_state;
scoped_ptr<net::CTVerifier> cert_transparency_verifier;
+ scoped_ptr<net::CertPolicyEnforcer> cert_policy_enforcer;
scoped_refptr<net::SSLConfigService> ssl_config_service;
scoped_ptr<net::HttpAuthHandlerFactory> http_auth_handler_factory;
scoped_ptr<net::HttpServerProperties> http_server_properties;
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 31dcf37..967c85e 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -1019,6 +1019,11 @@ const char kRecordMode[] = "record-mode";
// time delta to remember certificates should be specified in seconds.
const char kRememberCertErrorDecisions[] = "remember-cert-error-decisions";
+// Requires presence of Certificate Transparency for Extended Validation
+// certificates. Enforce the policy detailed at:
+// http://dev.chromium.org/Home/chromium-security/certificate-transparency
+const char kRequireCTForEV[] = "require-ct-for-ev";
+
// If set, the app list will forget it has been installed on startup. Note this
// doesn't prevent the app list from running, it just makes Chrome think the app
// list hasn't been enabled (as in kEnableAppList) yet.
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 814f8ca..876564c 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -283,6 +283,7 @@ extern const char kQuicMaxPacketLength[];
extern const char kQuicVersion[];
extern const char kRecordMode[];
extern const char kRememberCertErrorDecisions[];
+extern const char kRequireCTForEV[];
extern const char kResetAppListInstallState[];
extern const char kRestoreLastSession[];
extern const char kSavePageAsMHTML[];
diff --git a/net/cert/cert_policy_enforcer.cc b/net/cert/cert_policy_enforcer.cc
new file mode 100644
index 0000000..c9ce7cc
--- /dev/null
+++ b/net/cert/cert_policy_enforcer.cc
@@ -0,0 +1,165 @@
+// Copyright 2014 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.
+
+#include "net/cert/cert_policy_enforcer.h"
+
+#include <algorithm>
+
+#include "base/build_time.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/histogram.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/string_number_conversions.h"
+#include "net/cert/ct_ev_whitelist.h"
+#include "net/cert/ct_verify_result.h"
+#include "net/cert/signed_certificate_timestamp.h"
+#include "net/cert/x509_certificate.h"
+
+namespace net {
+
+namespace {
+
+bool IsEmbeddedSCT(const scoped_refptr<ct::SignedCertificateTimestamp>& sct) {
+ return sct->origin == ct::SignedCertificateTimestamp::SCT_EMBEDDED;
+}
+
+// Returns true if the current build is recent enough to ensure that
+// built-in security information (e.g. CT Logs) is fresh enough.
+// TODO(eranm): Move to base or net/base
+bool IsBuildTimely() {
+#if defined(DONT_EMBED_BUILD_METADATA) && !defined(OFFICIAL_BUILD)
+ return true;
+#else
+ const base::Time build_time = base::GetBuildTime();
+ // We consider built-in information to be timely for 10 weeks.
+ return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */;
+#endif
+}
+
+uint32_t ApproximateMonthDifference(const base::Time& start,
+ const base::Time& end) {
+ base::Time::Exploded exploded_start;
+ base::Time::Exploded exploded_expiry;
+ start.UTCExplode(&exploded_start);
+ end.UTCExplode(&exploded_expiry);
+ uint32_t month_diff = (exploded_expiry.year - exploded_start.year) * 12 +
+ (exploded_expiry.month - exploded_start.month);
+
+ // Add any remainder as a full month.
+ if (exploded_expiry.day_of_month > exploded_start.day_of_month)
+ ++month_diff;
+
+ return month_diff;
+}
+
+enum CTComplianceStatus {
+ CT_NOT_COMPLIANT = 0,
+ CT_IN_WHITELIST = 1,
+ CT_ENOUGH_SCTS = 2,
+ CT_COMPLIANCE_MAX,
+};
+
+void LogCTComplianceStatusToUMA(CTComplianceStatus status) {
+ UMA_HISTOGRAM_ENUMERATION("Net.SSL_EVCertificateCTCompliance", status,
+ CT_COMPLIANCE_MAX);
+}
+
+} // namespace
+
+CertPolicyEnforcer::CertPolicyEnforcer(size_t num_ct_logs,
+ bool require_ct_for_ev)
+ : num_ct_logs_(num_ct_logs), require_ct_for_ev_(require_ct_for_ev) {
+}
+
+CertPolicyEnforcer::~CertPolicyEnforcer() {
+}
+
+bool CertPolicyEnforcer::DoesConformToCTEVPolicy(
+ X509Certificate* cert,
+ const ct::EVCertsWhitelist* ev_whitelist,
+ const ct::CTVerifyResult& ct_result) {
+ if (!require_ct_for_ev_)
+ return true;
+
+ if (!IsBuildTimely())
+ return false;
+
+ if (IsCertificateInWhitelist(cert, ev_whitelist)) {
+ LogCTComplianceStatusToUMA(CT_IN_WHITELIST);
+ return true;
+ }
+
+ if (HasRequiredNumberOfSCTs(cert, ct_result)) {
+ LogCTComplianceStatusToUMA(CT_ENOUGH_SCTS);
+ return true;
+ }
+
+ LogCTComplianceStatusToUMA(CT_NOT_COMPLIANT);
+ return false;
+}
+
+bool CertPolicyEnforcer::IsCertificateInWhitelist(
+ X509Certificate* cert,
+ const ct::EVCertsWhitelist* ev_whitelist) {
+ bool cert_in_ev_whitelist = false;
+ if (ev_whitelist && ev_whitelist->IsValid()) {
+ const SHA256HashValue fingerprint(
+ X509Certificate::CalculateFingerprint256(cert->os_cert_handle()));
+
+ std::string truncated_fp =
+ std::string(reinterpret_cast<const char*>(fingerprint.data), 8);
+ cert_in_ev_whitelist = ev_whitelist->ContainsCertificateHash(truncated_fp);
+
+ UMA_HISTOGRAM_BOOLEAN("Net.SSL_EVCertificateInWhitelist",
+ cert_in_ev_whitelist);
+ }
+ return cert_in_ev_whitelist;
+}
+
+bool CertPolicyEnforcer::HasRequiredNumberOfSCTs(
+ X509Certificate* cert,
+ const ct::CTVerifyResult& ct_result) {
+ // TODO(eranm): Count the number of *independent* SCTs once the information
+ // about log operators is available, crbug.com/425174
+ size_t num_valid_scts = ct_result.verified_scts.size();
+ size_t num_embedded_scts =
+ std::count_if(ct_result.verified_scts.begin(),
+ ct_result.verified_scts.end(), IsEmbeddedSCT);
+
+ size_t num_non_embedded_scts = num_valid_scts - num_embedded_scts;
+ // If at least two valid SCTs were delivered by means other than embedding
+ // (i.e. in a TLS extension or OCSP), then the certificate conforms to bullet
+ // number 3 of the "Qualifying Certificate" section of the CT/EV policy.
+ if (num_non_embedded_scts >= 2)
+ return true;
+
+ if (cert->valid_start().is_null() || cert->valid_expiry().is_null() ||
+ cert->valid_start().is_max() || cert->valid_expiry().is_max()) {
+ // Will not be able to calculate the certificate's validity period.
+ return false;
+ }
+
+ uint32_t expiry_in_months_approx =
+ ApproximateMonthDifference(cert->valid_start(), cert->valid_expiry());
+
+ // For embedded SCTs, if the certificate has the number of SCTs specified in
+ // table 1 of the "Qualifying Certificate" section of the CT/EV policy, then
+ // it qualifies.
+ size_t num_required_embedded_scts;
+ if (expiry_in_months_approx > 39) {
+ num_required_embedded_scts = 5;
+ } else if (expiry_in_months_approx > 27) {
+ num_required_embedded_scts = 4;
+ } else if (expiry_in_months_approx >= 15) {
+ num_required_embedded_scts = 3;
+ } else {
+ num_required_embedded_scts = 2;
+ }
+
+ size_t min_acceptable_logs = std::max(num_ct_logs_, static_cast<size_t>(2u));
+ return num_embedded_scts >=
+ std::min(num_required_embedded_scts, min_acceptable_logs);
+}
+
+} // namespace net
diff --git a/net/cert/cert_policy_enforcer.h b/net/cert/cert_policy_enforcer.h
new file mode 100644
index 0000000..68039b3
--- /dev/null
+++ b/net/cert/cert_policy_enforcer.h
@@ -0,0 +1,56 @@
+// Copyright 2014 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.
+#ifndef NET_CERT_CERT_POLICY_ENFORCER_H
+#define NET_CERT_CERT_POLICY_ENFORCER_H
+
+#include <stddef.h>
+
+#include "net/base/net_export.h"
+
+namespace net {
+
+namespace ct {
+
+struct CTVerifyResult;
+class EVCertsWhitelist;
+
+} // namespace ct
+
+class X509Certificate;
+
+// Class for checking that a given certificate conforms to security-related
+// policies.
+class NET_EXPORT CertPolicyEnforcer {
+ public:
+ // Set the parameters for this policy enforcer:
+ // |num_ct_logs| is the number of Certificate Transparency log currently
+ // known to Chrome.
+ // |require_ct_for_ev| indicates whether Certificate Transparency presence
+ // is required for EV certificates.
+ CertPolicyEnforcer(size_t num_ct_logs, bool require_ct_for_ev);
+ virtual ~CertPolicyEnforcer();
+
+ // Returns true if the collection of SCTs for the given certificate
+ // conforms with the CT/EV policy.
+ // |cert| is the certificate for which the SCTs apply.
+ // |ct_result| must contain the result of verifying any SCTs associated with
+ // |cert| prior to invoking this method.
+ bool DoesConformToCTEVPolicy(X509Certificate* cert,
+ const ct::EVCertsWhitelist* ev_whitelist,
+ const ct::CTVerifyResult& ct_result);
+
+ private:
+ bool IsCertificateInWhitelist(X509Certificate* cert,
+ const ct::EVCertsWhitelist* ev_whitelist);
+
+ bool HasRequiredNumberOfSCTs(X509Certificate* cert,
+ const ct::CTVerifyResult& ct_result);
+
+ size_t num_ct_logs_;
+ bool require_ct_for_ev_;
+};
+
+} // namespace net
+
+#endif // NET_CERT_CERT_POLICY_ENFORCER_H
diff --git a/net/cert/cert_policy_enforcer_unittest.cc b/net/cert/cert_policy_enforcer_unittest.cc
new file mode 100644
index 0000000..45a2e6a
--- /dev/null
+++ b/net/cert/cert_policy_enforcer_unittest.cc
@@ -0,0 +1,212 @@
+// Copyright 2014 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.
+
+#include "net/cert/cert_policy_enforcer.h"
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "net/base/test_data_directory.h"
+#include "net/cert/ct_ev_whitelist.h"
+#include "net/cert/ct_verify_result.h"
+#include "net/cert/x509_certificate.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/ct_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace {
+
+class DummyEVCertsWhitelist : public ct::EVCertsWhitelist {
+ public:
+ DummyEVCertsWhitelist(bool is_valid_response, bool contains_hash_response)
+ : canned_is_valid_(is_valid_response),
+ canned_contains_response_(contains_hash_response) {}
+
+ bool IsValid() const override { return canned_is_valid_; }
+
+ bool ContainsCertificateHash(
+ const std::string& certificate_hash) const override {
+ return canned_contains_response_;
+ }
+
+ protected:
+ ~DummyEVCertsWhitelist() override {}
+
+ private:
+ bool canned_is_valid_;
+ bool canned_contains_response_;
+};
+
+class CertPolicyEnforcerTest : public ::testing::Test {
+ public:
+ virtual void SetUp() override {
+ policy_enforcer_.reset(new CertPolicyEnforcer(5, true));
+
+ std::string der_test_cert(ct::GetDerEncodedX509Cert());
+ chain_ = X509Certificate::CreateFromBytes(der_test_cert.data(),
+ der_test_cert.size());
+ ASSERT_TRUE(chain_.get());
+ }
+
+ void FillResultWithSCTsOfOrigin(
+ ct::SignedCertificateTimestamp::Origin desired_origin,
+ int num_scts,
+ ct::CTVerifyResult* result) {
+ for (int i = 0; i < num_scts; ++i) {
+ scoped_refptr<ct::SignedCertificateTimestamp> sct(
+ new ct::SignedCertificateTimestamp());
+ sct->origin = desired_origin;
+ result->verified_scts.push_back(sct);
+ }
+ }
+
+ protected:
+ scoped_ptr<CertPolicyEnforcer> policy_enforcer_;
+ scoped_refptr<X509Certificate> chain_;
+};
+
+TEST_F(CertPolicyEnforcerTest, ConformsToCTEVPolicyWithNonEmbeddedSCTs) {
+ ct::CTVerifyResult result;
+ FillResultWithSCTsOfOrigin(
+ ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION, 2, &result);
+
+ EXPECT_TRUE(
+ policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr, result));
+}
+
+TEST_F(CertPolicyEnforcerTest, ConformsToCTEVPolicyWithEmbeddedSCTs) {
+ // This chain_ is valid for 10 years - over 121 months - so requires 5 SCTs.
+ ct::CTVerifyResult result;
+ FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 5,
+ &result);
+
+ EXPECT_TRUE(
+ policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr, result));
+}
+
+TEST_F(CertPolicyEnforcerTest, DoesNotConformToCTEVPolicyNotEnoughSCTs) {
+ scoped_refptr<ct::EVCertsWhitelist> non_including_whitelist(
+ new DummyEVCertsWhitelist(true, false));
+ // This chain_ is valid for 10 years - over 121 months - so requires 5 SCTs.
+ // However, as there are only two logs, two SCTs will be required - supply one
+ // to guarantee the test fails.
+ ct::CTVerifyResult result;
+ FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 1,
+ &result);
+
+ EXPECT_FALSE(policy_enforcer_->DoesConformToCTEVPolicy(
+ chain_.get(), non_including_whitelist.get(), result));
+
+ // ... but should be OK if whitelisted.
+ scoped_refptr<ct::EVCertsWhitelist> whitelist(
+ new DummyEVCertsWhitelist(true, true));
+ EXPECT_TRUE(policy_enforcer_->DoesConformToCTEVPolicy(
+ chain_.get(), whitelist.get(), result));
+}
+
+TEST_F(CertPolicyEnforcerTest, DoesNotEnforceCTPolicyIfNotRequired) {
+ scoped_ptr<CertPolicyEnforcer> enforcer(new CertPolicyEnforcer(3, false));
+
+ ct::CTVerifyResult result;
+ FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 1,
+ &result);
+ // Expect true despite the chain not having enough SCTs as the policy
+ // is not enforced.
+ EXPECT_TRUE(enforcer->DoesConformToCTEVPolicy(chain_.get(), nullptr, result));
+}
+
+TEST_F(CertPolicyEnforcerTest, DoesNotConformToPolicyInvalidDates) {
+ scoped_refptr<X509Certificate> no_valid_dates_cert(new X509Certificate(
+ "subject", "issuer", base::Time(), base::Time::Now()));
+ ct::CTVerifyResult result;
+ FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 5,
+ &result);
+ EXPECT_FALSE(policy_enforcer_->DoesConformToCTEVPolicy(
+ no_valid_dates_cert.get(), nullptr, result));
+ // ... but should be OK if whitelisted.
+ scoped_refptr<ct::EVCertsWhitelist> whitelist(
+ new DummyEVCertsWhitelist(true, true));
+ EXPECT_TRUE(policy_enforcer_->DoesConformToCTEVPolicy(
+ chain_.get(), whitelist.get(), result));
+}
+
+TEST_F(CertPolicyEnforcerTest,
+ ConformsToPolicyExactNumberOfSCTsForValidityPeriod) {
+ // Test multiple validity periods: Over 27 months, Over 15 months (but less
+ // than 27 months),
+ // Less than 15 months.
+ const size_t validity_period[] = {12, 19, 30, 50};
+ const size_t needed_scts[] = {2, 3, 4, 5};
+
+ for (int i = 0; i < 3; ++i) {
+ size_t curr_validity = validity_period[i];
+ scoped_refptr<X509Certificate> cert(new X509Certificate(
+ "subject", "issuer", base::Time::Now(),
+ base::Time::Now() + base::TimeDelta::FromDays(31 * curr_validity)));
+ size_t curr_required_scts = needed_scts[i];
+ ct::CTVerifyResult result;
+ for (size_t j = 0; j < curr_required_scts - 1; ++j) {
+ FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED,
+ 1, &result);
+ EXPECT_FALSE(policy_enforcer_->DoesConformToCTEVPolicy(cert.get(),
+ nullptr, result))
+ << " for: " << curr_validity << " and " << curr_required_scts
+ << " scts=" << result.verified_scts.size() << " j=" << j;
+ }
+ FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 1,
+ &result);
+ EXPECT_TRUE(
+ policy_enforcer_->DoesConformToCTEVPolicy(cert.get(), nullptr, result));
+ }
+}
+
+TEST_F(CertPolicyEnforcerTest,
+ ConformsToPolicyButDoesNotRequireMoreThanNumLogs) {
+ scoped_ptr<CertPolicyEnforcer> enforcer(new CertPolicyEnforcer(2, true));
+
+ ct::CTVerifyResult result;
+ FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 2,
+ &result);
+ // Expect true despite the chain not having enough SCTs according to the
+ // policy
+ // since we only have 2 logs.
+ EXPECT_TRUE(enforcer->DoesConformToCTEVPolicy(chain_.get(), nullptr, result));
+}
+
+TEST_F(CertPolicyEnforcerTest, ConformsToPolicyByEVWhitelistPresence) {
+ scoped_refptr<ct::EVCertsWhitelist> whitelist(
+ new DummyEVCertsWhitelist(true, true));
+
+ ct::CTVerifyResult result;
+ FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 1,
+ &result);
+ EXPECT_TRUE(policy_enforcer_->DoesConformToCTEVPolicy(
+ chain_.get(), whitelist.get(), result));
+}
+
+TEST_F(CertPolicyEnforcerTest, IgnoresInvalidEVWhitelist) {
+ scoped_refptr<ct::EVCertsWhitelist> whitelist(
+ new DummyEVCertsWhitelist(false, true));
+
+ ct::CTVerifyResult result;
+ FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 1,
+ &result);
+ EXPECT_FALSE(policy_enforcer_->DoesConformToCTEVPolicy(
+ chain_.get(), whitelist.get(), result));
+}
+
+TEST_F(CertPolicyEnforcerTest, IgnoresNullEVWhitelist) {
+ ct::CTVerifyResult result;
+ FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 1,
+ &result);
+ EXPECT_FALSE(
+ policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr, result));
+}
+
+} // namespace
+
+} // namespace net
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index 28b3b22..656db54 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -37,21 +37,14 @@ net::ClientSocketPoolManager* CreateSocketPoolManager(
// TODO(yutak): Differentiate WebSocket pool manager and allow more
// simultaneous connections for WebSockets.
return new net::ClientSocketPoolManagerImpl(
- params.net_log,
- params.client_socket_factory
- ? params.client_socket_factory
- : net::ClientSocketFactory::GetDefaultFactory(),
- params.host_resolver,
- params.cert_verifier,
- params.channel_id_service,
- params.transport_security_state,
- params.cert_transparency_verifier,
- params.ssl_session_cache_shard,
- params.proxy_service,
- params.ssl_config_service,
- params.enable_ssl_connect_job_waiting,
- params.proxy_delegate,
- pool_type);
+ params.net_log, params.client_socket_factory
+ ? params.client_socket_factory
+ : net::ClientSocketFactory::GetDefaultFactory(),
+ params.host_resolver, params.cert_verifier, params.channel_id_service,
+ params.transport_security_state, params.cert_transparency_verifier,
+ params.cert_policy_enforcer, params.ssl_session_cache_shard,
+ params.proxy_service, params.ssl_config_service,
+ params.enable_ssl_connect_job_waiting, params.proxy_delegate, pool_type);
}
} // unnamed namespace
@@ -62,6 +55,7 @@ HttpNetworkSession::Params::Params()
: client_socket_factory(NULL),
host_resolver(NULL),
cert_verifier(NULL),
+ cert_policy_enforcer(NULL),
channel_id_service(NULL),
transport_security_state(NULL),
cert_transparency_verifier(NULL),
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index 557b84e..bf93c83 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -29,6 +29,7 @@ class Value;
namespace net {
+class CertPolicyEnforcer;
class CertVerifier;
class ChannelIDService;
class ClientSocketFactory;
@@ -66,6 +67,7 @@ class NET_EXPORT HttpNetworkSession
ClientSocketFactory* client_socket_factory;
HostResolver* host_resolver;
CertVerifier* cert_verifier;
+ CertPolicyEnforcer* cert_policy_enforcer;
ChannelIDService* channel_id_service;
TransportSecurityState* transport_security_state;
CTVerifier* cert_transparency_verifier;
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 878406e..eacd06c 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -583,6 +583,7 @@ CaptureGroupNameSSLSocketPool::CaptureGroupNameSocketPool(
NULL,
NULL,
NULL,
+ NULL,
std::string(),
NULL,
NULL,
diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc
index bdaf57f..f818432 100644
--- a/net/http/http_proxy_client_socket_pool_unittest.cc
+++ b/net/http/http_proxy_client_socket_pool_unittest.cc
@@ -171,6 +171,7 @@ class HttpProxyClientSocketPoolTest
NULL /* channel_id_store */,
NULL /* transport_security_state */,
NULL /* cert_transparency_verifier */,
+ NULL /* cert_policy_enforcer */,
std::string() /* ssl_session_cache_shard */,
session_deps_.deterministic_socket_factory.get(),
&transport_socket_pool_,
diff --git a/net/http/http_stream_factory_impl_unittest.cc b/net/http/http_stream_factory_impl_unittest.cc
index 4ac5467..beac733 100644
--- a/net/http/http_stream_factory_impl_unittest.cc
+++ b/net/http/http_stream_factory_impl_unittest.cc
@@ -403,16 +403,17 @@ CapturePreconnectsSSLSocketPool::CapturePreconnectsSocketPool(
nullptr, // ssl_histograms
host_resolver,
cert_verifier,
- nullptr, // channel_id_store
- nullptr, // transport_security_state
- nullptr, // cert_transparency_verifier
+ nullptr, // channel_id_store
+ nullptr, // transport_security_state
+ nullptr, // cert_transparency_verifier
+ nullptr, // cert_policy_enforcer
std::string(), // ssl_session_cache_shard
- nullptr, // deterministic_socket_factory
- nullptr, // transport_socket_pool
+ nullptr, // deterministic_socket_factory
+ nullptr, // transport_socket_pool
nullptr,
nullptr,
nullptr, // ssl_config_service
- false, // enable_ssl_connect_job_waiting
+ false, // enable_ssl_connect_job_waiting
nullptr), // net_log
last_num_streams_(-1) {
}
diff --git a/net/net.gypi b/net/net.gypi
index cc9ff357..89a0503 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -64,6 +64,8 @@
'cert/cert_database.cc',
'cert/cert_database.h',
'cert/cert_database_openssl.cc',
+ 'cert/cert_policy_enforcer.cc',
+ 'cert/cert_policy_enforcer.h',
'cert/cert_status_flags.cc',
'cert/cert_status_flags.h',
'cert/cert_verifier.cc',
@@ -1297,6 +1299,7 @@
'base/upload_bytes_element_reader_unittest.cc',
'base/upload_file_element_reader_unittest.cc',
'base/url_util_unittest.cc',
+ 'cert/cert_policy_enforcer_unittest.cc',
'cert/cert_verify_proc_unittest.cc',
'cert/crl_set_unittest.cc',
'cert/ct_log_response_parser_unittest.cc',
diff --git a/net/socket/client_socket_pool_manager_impl.cc b/net/socket/client_socket_pool_manager_impl.cc
index 5ed31fc..190023c 100644
--- a/net/socket/client_socket_pool_manager_impl.cc
+++ b/net/socket/client_socket_pool_manager_impl.cc
@@ -42,6 +42,7 @@ ClientSocketPoolManagerImpl::ClientSocketPoolManagerImpl(
ChannelIDService* channel_id_service,
TransportSecurityState* transport_security_state,
CTVerifier* cert_transparency_verifier,
+ CertPolicyEnforcer* cert_policy_enforcer,
const std::string& ssl_session_cache_shard,
ProxyService* proxy_service,
SSLConfigService* ssl_config_service,
@@ -55,6 +56,7 @@ ClientSocketPoolManagerImpl::ClientSocketPoolManagerImpl(
channel_id_service_(channel_id_service),
transport_security_state_(transport_security_state),
cert_transparency_verifier_(cert_transparency_verifier),
+ cert_policy_enforcer_(cert_policy_enforcer),
ssl_session_cache_shard_(ssl_session_cache_shard),
proxy_service_(proxy_service),
ssl_config_service_(ssl_config_service),
@@ -85,6 +87,7 @@ ClientSocketPoolManagerImpl::ClientSocketPoolManagerImpl(
channel_id_service,
transport_security_state,
cert_transparency_verifier,
+ cert_policy_enforcer,
ssl_session_cache_shard,
socket_factory,
transport_socket_pool_.get(),
@@ -297,22 +300,17 @@ ClientSocketPoolManagerImpl::GetSocketPoolForHTTPProxy(
std::pair<SSLSocketPoolMap::iterator, bool> ssl_https_ret =
ssl_socket_pools_for_https_proxies_.insert(std::make_pair(
http_proxy,
- new SSLClientSocketPool(max_sockets_per_proxy_server(pool_type_),
- max_sockets_per_group(pool_type_),
- &ssl_for_https_proxy_pool_histograms_,
- host_resolver_,
- cert_verifier_,
- channel_id_service_,
- transport_security_state_,
- cert_transparency_verifier_,
- ssl_session_cache_shard_,
- socket_factory_,
- tcp_https_ret.first->second /* https proxy */,
- NULL /* no socks proxy */,
- NULL /* no http proxy */,
- ssl_config_service_.get(),
- enable_ssl_connect_job_waiting_,
- net_log_)));
+ new SSLClientSocketPool(
+ max_sockets_per_proxy_server(pool_type_),
+ max_sockets_per_group(pool_type_),
+ &ssl_for_https_proxy_pool_histograms_, host_resolver_,
+ cert_verifier_, channel_id_service_, transport_security_state_,
+ cert_transparency_verifier_, cert_policy_enforcer_,
+ ssl_session_cache_shard_, socket_factory_,
+ tcp_https_ret.first->second /* https proxy */,
+ NULL /* no socks proxy */, NULL /* no http proxy */,
+ ssl_config_service_.get(), enable_ssl_connect_job_waiting_,
+ net_log_)));
DCHECK(tcp_https_ret.second);
std::pair<HTTPProxySocketPoolMap::iterator, bool> ret =
@@ -341,21 +339,14 @@ SSLClientSocketPool* ClientSocketPoolManagerImpl::GetSocketPoolForSSLWithProxy(
SSLClientSocketPool* new_pool = new SSLClientSocketPool(
max_sockets_per_proxy_server(pool_type_),
- max_sockets_per_group(pool_type_),
- &ssl_pool_histograms_,
- host_resolver_,
- cert_verifier_,
- channel_id_service_,
- transport_security_state_,
- cert_transparency_verifier_,
- ssl_session_cache_shard_,
- socket_factory_,
+ max_sockets_per_group(pool_type_), &ssl_pool_histograms_, host_resolver_,
+ cert_verifier_, channel_id_service_, transport_security_state_,
+ cert_transparency_verifier_, cert_policy_enforcer_,
+ ssl_session_cache_shard_, socket_factory_,
NULL, /* no tcp pool, we always go through a proxy */
GetSocketPoolForSOCKSProxy(proxy_server),
- GetSocketPoolForHTTPProxy(proxy_server),
- ssl_config_service_.get(),
- enable_ssl_connect_job_waiting_,
- net_log_);
+ GetSocketPoolForHTTPProxy(proxy_server), ssl_config_service_.get(),
+ enable_ssl_connect_job_waiting_, net_log_);
std::pair<SSLSocketPoolMap::iterator, bool> ret =
ssl_socket_pools_for_proxies_.insert(std::make_pair(proxy_server,
diff --git a/net/socket/client_socket_pool_manager_impl.h b/net/socket/client_socket_pool_manager_impl.h
index f9f8d3b..ca609d5 100644
--- a/net/socket/client_socket_pool_manager_impl.h
+++ b/net/socket/client_socket_pool_manager_impl.h
@@ -65,6 +65,7 @@ class ClientSocketPoolManagerImpl : public base::NonThreadSafe,
ChannelIDService* channel_id_service,
TransportSecurityState* transport_security_state,
CTVerifier* cert_transparency_verifier,
+ CertPolicyEnforcer* cert_policy_enforcer,
const std::string& ssl_session_cache_shard,
ProxyService* proxy_service,
SSLConfigService* ssl_config_service,
@@ -114,6 +115,7 @@ class ClientSocketPoolManagerImpl : public base::NonThreadSafe,
ChannelIDService* const channel_id_service_;
TransportSecurityState* const transport_security_state_;
CTVerifier* const cert_transparency_verifier_;
+ CertPolicyEnforcer* const cert_policy_enforcer_;
const std::string ssl_session_cache_shard_;
ProxyService* const proxy_service_;
const scoped_refptr<SSLConfigService> ssl_config_service_;
diff --git a/net/socket/ssl_client_socket.h b/net/socket/ssl_client_socket.h
index af4f3ba..11b19a1 100644
--- a/net/socket/ssl_client_socket.h
+++ b/net/socket/ssl_client_socket.h
@@ -16,6 +16,7 @@
namespace net {
+class CertPolicyEnforcer;
class CertVerifier;
class ChannelIDService;
class CTVerifier;
@@ -34,23 +35,27 @@ struct SSLClientSocketContext {
: cert_verifier(NULL),
channel_id_service(NULL),
transport_security_state(NULL),
- cert_transparency_verifier(NULL) {}
+ cert_transparency_verifier(NULL),
+ cert_policy_enforcer(NULL) {}
SSLClientSocketContext(CertVerifier* cert_verifier_arg,
ChannelIDService* channel_id_service_arg,
TransportSecurityState* transport_security_state_arg,
CTVerifier* cert_transparency_verifier_arg,
+ CertPolicyEnforcer* cert_policy_enforcer_arg,
const std::string& ssl_session_cache_shard_arg)
: cert_verifier(cert_verifier_arg),
channel_id_service(channel_id_service_arg),
transport_security_state(transport_security_state_arg),
cert_transparency_verifier(cert_transparency_verifier_arg),
+ cert_policy_enforcer(cert_policy_enforcer_arg),
ssl_session_cache_shard(ssl_session_cache_shard_arg) {}
CertVerifier* cert_verifier;
ChannelIDService* channel_id_service;
TransportSecurityState* transport_security_state;
CTVerifier* cert_transparency_verifier;
+ CertPolicyEnforcer* cert_policy_enforcer;
// ssl_session_cache_shard is an opaque string that identifies a shard of the
// SSL session cache. SSL sockets with the same ssl_session_cache_shard may
// resume each other's SSL sessions but we'll never sessions between shards.
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index 1319e4b..3651e8d 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -91,6 +91,7 @@
#include "net/base/net_errors.h"
#include "net/base/net_log.h"
#include "net/cert/asn1_util.h"
+#include "net/cert/cert_policy_enforcer.h"
#include "net/cert/cert_status_flags.h"
#include "net/cert/cert_verifier.h"
#include "net/cert/ct_ev_whitelist.h"
@@ -2831,6 +2832,7 @@ SSLClientSocketNSS::SSLClientSocketNSS(
nss_fd_(NULL),
net_log_(transport_->socket()->NetLog()),
transport_security_state_(context.transport_security_state),
+ policy_enforcer_(context.cert_policy_enforcer),
valid_thread_id_(base::kInvalidThreadId) {
EnterFunction("");
InitCore();
@@ -3528,21 +3530,6 @@ int SSLClientSocketNSS::DoVerifyCertComplete(int result) {
result = ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN;
}
- scoped_refptr<ct::EVCertsWhitelist> ev_whitelist =
- SSLConfigService::GetEVCertsWhitelist();
- if (server_cert_verify_result_.cert_status & CERT_STATUS_IS_EV) {
- if (ev_whitelist.get() && ev_whitelist->IsValid()) {
- const SHA256HashValue fingerprint(
- X509Certificate::CalculateFingerprint256(
- server_cert_verify_result_.verified_cert->os_cert_handle()));
-
- UMA_HISTOGRAM_BOOLEAN(
- "Net.SSL_EVCertificateInWhitelist",
- ev_whitelist->ContainsCertificateHash(
- std::string(reinterpret_cast<const char*>(fingerprint.data), 8)));
- }
- }
-
if (result == OK) {
// Only check Certificate Transparency if there were no other errors with
// the connection.
@@ -3566,20 +3553,31 @@ void SSLClientSocketNSS::VerifyCT() {
// Note that this is a completely synchronous operation: The CT Log Verifier
// gets all the data it needs for SCT verification and does not do any
// external communication.
- int result = cert_transparency_verifier_->Verify(
+ cert_transparency_verifier_->Verify(
server_cert_verify_result_.verified_cert.get(),
core_->state().stapled_ocsp_response,
- core_->state().sct_list_from_tls_extension,
- &ct_verify_result_,
- net_log_);
+ core_->state().sct_list_from_tls_extension, &ct_verify_result_, net_log_);
// TODO(ekasper): wipe stapled_ocsp_response and sct_list_from_tls_extension
// from the state after verification is complete, to conserve memory.
- VLOG(1) << "CT Verification complete: result " << result
- << " Invalid scts: " << ct_verify_result_.invalid_scts.size()
- << " Verified scts: " << ct_verify_result_.verified_scts.size()
- << " scts from unknown logs: "
- << ct_verify_result_.unknown_logs_scts.size();
+ if (!policy_enforcer_) {
+ server_cert_verify_result_.cert_status &= ~CERT_STATUS_IS_EV;
+ } else {
+ if (server_cert_verify_result_.cert_status & CERT_STATUS_IS_EV) {
+ scoped_refptr<ct::EVCertsWhitelist> ev_whitelist =
+ SSLConfigService::GetEVCertsWhitelist();
+ if (!policy_enforcer_->DoesConformToCTEVPolicy(
+ server_cert_verify_result_.verified_cert.get(),
+ ev_whitelist.get(), ct_verify_result_)) {
+ // TODO(eranm): Log via the BoundNetLog, see crbug.com/437766
+ VLOG(1) << "EV certificate for "
+ << server_cert_verify_result_.verified_cert->subject()
+ .GetDisplayName()
+ << " does not conform to CT policy, removing EV status.";
+ server_cert_verify_result_.cert_status &= ~CERT_STATUS_IS_EV;
+ }
+ }
+ }
}
void SSLClientSocketNSS::EnsureThreadIdAssigned() const {
diff --git a/net/socket/ssl_client_socket_nss.h b/net/socket/ssl_client_socket_nss.h
index 71f09c0..10bb57f 100644
--- a/net/socket/ssl_client_socket_nss.h
+++ b/net/socket/ssl_client_socket_nss.h
@@ -36,6 +36,7 @@ class SequencedTaskRunner;
namespace net {
class BoundNetLog;
+class CertPolicyEnforcer;
class CertVerifier;
class ChannelIDService;
class CTVerifier;
@@ -199,6 +200,8 @@ class SSLClientSocketNSS : public SSLClientSocket {
TransportSecurityState* transport_security_state_;
+ CertPolicyEnforcer* const policy_enforcer_;
+
// pinning_failure_log contains a message produced by
// TransportSecurityState::CheckPublicKeyPins in the event of a
// pinning failure. It is a (somewhat) human-readable string.
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc
index b417e13..4e86c05 100644
--- a/net/socket/ssl_client_socket_openssl.cc
+++ b/net/socket/ssl_client_socket_openssl.cc
@@ -24,6 +24,7 @@
#include "crypto/openssl_util.h"
#include "crypto/scoped_openssl_types.h"
#include "net/base/net_errors.h"
+#include "net/cert/cert_policy_enforcer.h"
#include "net/cert/cert_verifier.h"
#include "net/cert/ct_ev_whitelist.h"
#include "net/cert/ct_verifier.h"
@@ -380,6 +381,7 @@ SSLClientSocketOpenSSL::SSLClientSocketOpenSSL(
handshake_succeeded_(false),
marked_session_as_good_(false),
transport_security_state_(context.transport_security_state),
+ policy_enforcer_(context.cert_policy_enforcer),
net_log_(transport_->socket()->NetLog()),
weak_factory_(this) {
}
@@ -1144,21 +1146,6 @@ int SSLClientSocketOpenSSL::DoVerifyCertComplete(int result) {
result = ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN;
}
- scoped_refptr<ct::EVCertsWhitelist> ev_whitelist =
- SSLConfigService::GetEVCertsWhitelist();
- if (server_cert_verify_result_.cert_status & CERT_STATUS_IS_EV) {
- if (ev_whitelist.get() && ev_whitelist->IsValid()) {
- const SHA256HashValue fingerprint(
- X509Certificate::CalculateFingerprint256(
- server_cert_verify_result_.verified_cert->os_cert_handle()));
-
- UMA_HISTOGRAM_BOOLEAN(
- "Net.SSL_EVCertificateInWhitelist",
- ev_whitelist->ContainsCertificateHash(
- std::string(reinterpret_cast<const char*>(fingerprint.data), 8)));
- }
- }
-
if (result == OK) {
// Only check Certificate Transparency if there were no other errors with
// the connection.
@@ -1251,15 +1238,28 @@ void SSLClientSocketOpenSSL::VerifyCT() {
// Note that this is a completely synchronous operation: The CT Log Verifier
// gets all the data it needs for SCT verification and does not do any
// external communication.
- int result = cert_transparency_verifier_->Verify(
- server_cert_verify_result_.verified_cert.get(),
- ocsp_response, sct_list, &ct_verify_result_, net_log_);
-
- VLOG(1) << "CT Verification complete: result " << result
- << " Invalid scts: " << ct_verify_result_.invalid_scts.size()
- << " Verified scts: " << ct_verify_result_.verified_scts.size()
- << " scts from unknown logs: "
- << ct_verify_result_.unknown_logs_scts.size();
+ cert_transparency_verifier_->Verify(
+ server_cert_verify_result_.verified_cert.get(), ocsp_response, sct_list,
+ &ct_verify_result_, net_log_);
+
+ if (!policy_enforcer_) {
+ server_cert_verify_result_.cert_status &= ~CERT_STATUS_IS_EV;
+ } else {
+ if (server_cert_verify_result_.cert_status & CERT_STATUS_IS_EV) {
+ scoped_refptr<ct::EVCertsWhitelist> ev_whitelist =
+ SSLConfigService::GetEVCertsWhitelist();
+ if (!policy_enforcer_->DoesConformToCTEVPolicy(
+ server_cert_verify_result_.verified_cert.get(),
+ ev_whitelist.get(), ct_verify_result_)) {
+ // TODO(eranm): Log via the BoundNetLog, see crbug.com/437766
+ VLOG(1) << "EV certificate for "
+ << server_cert_verify_result_.verified_cert->subject()
+ .GetDisplayName()
+ << " does not conform to CT policy, removing EV status.";
+ server_cert_verify_result_.cert_status &= ~CERT_STATUS_IS_EV;
+ }
+ }
+ }
}
void SSLClientSocketOpenSSL::OnHandshakeIOComplete(int result) {
diff --git a/net/socket/ssl_client_socket_openssl.h b/net/socket/ssl_client_socket_openssl.h
index 53d33c4..6343cb7 100644
--- a/net/socket/ssl_client_socket_openssl.h
+++ b/net/socket/ssl_client_socket_openssl.h
@@ -304,6 +304,8 @@ class SSLClientSocketOpenSSL : public SSLClientSocket {
TransportSecurityState* transport_security_state_;
+ CertPolicyEnforcer* const policy_enforcer_;
+
// pinning_failure_log contains a message produced by
// TransportSecurityState::CheckPublicKeyPins in the event of a
// pinning failure. It is a (somewhat) human-readable string.
diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc
index 56df1d8..c3b98b8 100644
--- a/net/socket/ssl_client_socket_pool.cc
+++ b/net/socket/ssl_client_socket_pool.cc
@@ -197,6 +197,7 @@ SSLConnectJob::SSLConnectJob(const std::string& group_name,
context.channel_id_service,
context.transport_security_state,
context.cert_transparency_verifier,
+ context.cert_policy_enforcer,
(params->privacy_mode() == PRIVACY_MODE_ENABLED
? "pm/" + context.ssl_session_cache_shard
: context.ssl_session_cache_shard)),
@@ -634,6 +635,7 @@ SSLClientSocketPool::SSLClientSocketPool(
ChannelIDService* channel_id_service,
TransportSecurityState* transport_security_state,
CTVerifier* cert_transparency_verifier,
+ CertPolicyEnforcer* cert_policy_enforcer,
const std::string& ssl_session_cache_shard,
ClientSocketFactory* client_socket_factory,
TransportClientSocketPool* transport_pool,
@@ -661,6 +663,7 @@ SSLClientSocketPool::SSLClientSocketPool(
channel_id_service,
transport_security_state,
cert_transparency_verifier,
+ cert_policy_enforcer,
ssl_session_cache_shard),
base::Bind(
&SSLClientSocketPool::GetOrCreateSSLConnectJobMessenger,
diff --git a/net/socket/ssl_client_socket_pool.h b/net/socket/ssl_client_socket_pool.h
index c7f613e..59e754a 100644
--- a/net/socket/ssl_client_socket_pool.h
+++ b/net/socket/ssl_client_socket_pool.h
@@ -23,6 +23,7 @@
namespace net {
+class CertPolicyEnforcer;
class CertVerifier;
class ClientSocketFactory;
class ConnectJobFactory;
@@ -285,6 +286,7 @@ class NET_EXPORT_PRIVATE SSLClientSocketPool
ChannelIDService* channel_id_service,
TransportSecurityState* transport_security_state,
CTVerifier* cert_transparency_verifier,
+ CertPolicyEnforcer* cert_policy_enforcer,
const std::string& ssl_session_cache_shard,
ClientSocketFactory* client_socket_factory,
TransportClientSocketPool* transport_pool,
diff --git a/net/socket/ssl_client_socket_pool_unittest.cc b/net/socket/ssl_client_socket_pool_unittest.cc
index 23bb111..1e4a14f 100644
--- a/net/socket/ssl_client_socket_pool_unittest.cc
+++ b/net/socket/ssl_client_socket_pool_unittest.cc
@@ -143,22 +143,15 @@ class SSLClientSocketPoolTest
void CreatePool(bool transport_pool, bool http_proxy_pool, bool socks_pool) {
ssl_histograms_.reset(new ClientSocketPoolHistograms("SSLUnitTest"));
pool_.reset(new SSLClientSocketPool(
- kMaxSockets,
- kMaxSocketsPerGroup,
- ssl_histograms_.get(),
- NULL /* host_resolver */,
- NULL /* cert_verifier */,
- NULL /* channel_id_service */,
- NULL /* transport_security_state */,
- NULL /* cert_transparency_verifier */,
- std::string() /* ssl_session_cache_shard */,
- &socket_factory_,
+ kMaxSockets, kMaxSocketsPerGroup, ssl_histograms_.get(),
+ NULL /* host_resolver */, NULL /* cert_verifier */,
+ NULL /* channel_id_service */, NULL /* transport_security_state */,
+ NULL /* cert_transparency_verifier */, NULL /* cert_policy_enforcer */,
+ std::string() /* ssl_session_cache_shard */, &socket_factory_,
transport_pool ? &transport_socket_pool_ : NULL,
socks_pool ? &socks_socket_pool_ : NULL,
- http_proxy_pool ? &http_proxy_socket_pool_ : NULL,
- NULL,
- enable_ssl_connect_job_waiting_,
- NULL));
+ http_proxy_pool ? &http_proxy_socket_pool_ : NULL, NULL,
+ enable_ssl_connect_job_waiting_, NULL));
}
scoped_refptr<SSLSocketParams> SSLParams(ProxyServer::Scheme proxy,
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index c1a6e07..1241bc9 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -18801,6 +18801,23 @@ Therefore, the affected-histogram name has to have at least one dot in it.
</summary>
</histogram>
+<histogram name="Net.SSL_EVCertificateCTCompliance"
+ enum="CTRequirementCompliance">
+ <owner>eranm@chromium.org</owner>
+ <owner>rsleevi@chromium.org</owner>
+ <summary>
+ The state of compliance with Certificate Transparency presence requirements
+ for each EV certificate. An EV certificate could be non-compliant (in which
+ case it loses the EV status), comply through inclusion in the EV whitelist
+ or have the required number of Signed Certificate Timestamps. This metric
+ will gauge adoption rate of Certificate Transparency and will help identify
+ when the EV whitelist is no longer needed. Emitted during every SSL
+ connection establishment, but only if the client is checking compliance with
+ Certificate Transparency requirements (currently guarded by a Finch
+ experiment).
+ </summary>
+</histogram>
+
<histogram name="Net.SSL_EVCertificateInWhitelist" enum="Boolean">
<owner>eranm@chromium.org</owner>
<owner>rsleevi@chromium.org</owner>
@@ -42809,6 +42826,12 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="8" label="PlayMusic"/>
</enum>
+<enum name="CTRequirementCompliance" type="int">
+ <int value="0" label="Not Compliant"/>
+ <int value="1" label="Whitelisted"/>
+ <int value="2" label="Has enough SCTs"/>
+</enum>
+
<enum name="DailyEventIntervalType" type="int">
<int value="0" label="First Run"/>
<int value="1" label="Day Elapsed"/>