From b87f56880e2fe4c30518be34d4ab7f62c28f5cf0 Mon Sep 17 00:00:00 2001 From: Carlos IL Date: Wed, 26 May 2021 17:19:15 +0000 Subject: [PATCH] Implement CT component updater killswitch Bug: 1211535 Change-Id: Ibf6b5d6ac6cc0afd98c9ff38c57f1568d2e0c897 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2910898 Reviewed-by: Yutaka Hirano Reviewed-by: David Benjamin Commit-Queue: Carlos IL Cr-Commit-Position: refs/heads/master@{#886778} --- net/http/transport_security_state.cc | 4 ++ net/http/transport_security_state.h | 9 +++ net/http/transport_security_state_unittest.cc | 65 +++++++++++++++++++ services/network/network_service.cc | 6 +- 4 files changed, 83 insertions(+), 1 deletion(-) diff --git a/net/http/transport_security_state.cc b/net/http/transport_security_state.cc index 857a7b4d0cb292..1a13b0e6883a46 100644 --- a/net/http/transport_security_state.cc +++ b/net/http/transport_security_state.cc @@ -482,6 +482,10 @@ TransportSecurityState::CheckCTRequirements( using CTRequirementLevel = RequireCTDelegate::CTRequirementLevel; std::string hostname = host_port_pair.host(); + // If CT emergency disable flag is set, we don't require CT for any host. + if (ct_emergency_disable_) + return CT_NOT_REQUIRED; + // CT is not required if the certificate does not chain to a publicly // trusted root certificate. Testing can override this, as certain tests // rely on using a non-publicly-trusted root. diff --git a/net/http/transport_security_state.h b/net/http/transport_security_state.h index aa1c8372b3cc52..7ad4218dac0469 100644 --- a/net/http/transport_security_state.h +++ b/net/http/transport_security_state.h @@ -433,6 +433,13 @@ class NET_EXPORT TransportSecurityState { // occurs first. void SetRequireCTDelegate(RequireCTDelegate* delegate); + // If |emergency_disable| is set to true, will stop requiring CT + // compliance on any further requests regardless of host or certificate + // status. + void SetCTEmergencyDisabled(bool emergency_disable) { + ct_emergency_disable_ = emergency_disable; + } + // Clears all dynamic data (e.g. HSTS and HPKP data). // // Does NOT persist changes using the Delegate, as this function is only @@ -727,6 +734,8 @@ class NET_EXPORT TransportSecurityState { std::set hsts_host_bypass_list_; + bool ct_emergency_disable_ = false; + THREAD_CHECKER(thread_checker_); DISALLOW_COPY_AND_ASSIGN(TransportSecurityState); diff --git a/net/http/transport_security_state_unittest.cc b/net/http/transport_security_state_unittest.cc index 6d6cff5ee827dc..ceb5add822ac79 100644 --- a/net/http/transport_security_state_unittest.cc +++ b/net/http/transport_security_state_unittest.cc @@ -1739,6 +1739,71 @@ TEST_F(TransportSecurityStateTest, RequireCTConsultsDelegate) { } } +// Tests that the emergency disable flag causes CT to stop being required +// regardless of host or delegate status. +TEST_F(TransportSecurityStateTest, CTEmergencyDisable) { + using ::testing::_; + using ::testing::Return; + using CTRequirementLevel = + TransportSecurityState::RequireCTDelegate::CTRequirementLevel; + + // Dummy cert to use as the validation chain. The contents do not matter. + scoped_refptr cert = + ImportCertFromFile(GetTestCertsDirectory(), "expired_cert.pem"); + ASSERT_TRUE(cert); + + HashValueVector hashes; + hashes.push_back( + HashValue(X509Certificate::CalculateFingerprint256(cert->cert_buffer()))); + + TransportSecurityState state; + + // Set CT emergency disable flag. + state.SetCTEmergencyDisabled(true); + + MockRequireCTDelegate always_require_delegate; + EXPECT_CALL(always_require_delegate, IsCTRequiredForHost(_, _, _)) + .WillRepeatedly(Return(CTRequirementLevel::REQUIRED)); + state.SetRequireCTDelegate(&always_require_delegate); + EXPECT_EQ(TransportSecurityState::CT_NOT_REQUIRED, + state.CheckCTRequirements( + HostPortPair("www.example.com", 443), true, hashes, cert.get(), + cert.get(), SignedCertificateTimestampAndStatusList(), + TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + NetworkIsolationKey())); + EXPECT_EQ(TransportSecurityState::CT_NOT_REQUIRED, + state.CheckCTRequirements( + HostPortPair("www.example.com", 443), true, hashes, cert.get(), + cert.get(), SignedCertificateTimestampAndStatusList(), + TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, + ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS, + NetworkIsolationKey())); + EXPECT_EQ(TransportSecurityState::CT_NOT_REQUIRED, + state.CheckCTRequirements( + HostPortPair("www.example.com", 443), true, hashes, cert.get(), + cert.get(), SignedCertificateTimestampAndStatusList(), + TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, + ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS, + NetworkIsolationKey())); + EXPECT_EQ(TransportSecurityState::CT_NOT_REQUIRED, + state.CheckCTRequirements( + HostPortPair("www.example.com", 443), true, hashes, cert.get(), + cert.get(), SignedCertificateTimestampAndStatusList(), + TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, + ct::CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY, + NetworkIsolationKey())); + + state.SetRequireCTDelegate(nullptr); + EXPECT_EQ(TransportSecurityState::CT_NOT_REQUIRED, + state.CheckCTRequirements( + HostPortPair("www.example.com", 443), true, hashes, cert.get(), + cert.get(), SignedCertificateTimestampAndStatusList(), + TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, + ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS, + NetworkIsolationKey())); +} + // Tests that Certificate Transparency is required for Symantec-issued // certificates, unless the certificate was issued prior to 1 June 2016 // or the issuing CA is permitted as independently operated. diff --git a/services/network/network_service.cc b/services/network/network_service.cc index b2bd0ad1228333..259cd52b7b2273 100644 --- a/services/network/network_service.cc +++ b/services/network/network_service.cc @@ -733,10 +733,14 @@ void NetworkService::UpdateCtLogList( } void NetworkService::SetCtEnforcementEnabled(bool enabled) { - // TODO(crbug.com/1211535): Implement Certificate Transparency killswitch. DCHECK(base::FeatureList::IsEnabled( certificate_transparency::features:: kCertificateTransparencyComponentUpdater)); + for (auto* context : network_contexts_) { + context->url_request_context() + ->transport_security_state() + ->SetCTEmergencyDisabled(!enabled); + } } #endif // BUILDFLAG(IS_CT_SUPPORTED)