Index: net/http/transport_security_state_unittest.cc |
diff --git a/net/http/transport_security_state_unittest.cc b/net/http/transport_security_state_unittest.cc |
index e657f013b3abeb29922e8e63cee4d701e8714e69..2b16f21421459fd31b7275de4a373af2262df10e 100644 |
--- a/net/http/transport_security_state_unittest.cc |
+++ b/net/http/transport_security_state_unittest.cc |
@@ -2096,6 +2096,40 @@ TEST_F(TransportSecurityStateTest, ExpectCTReporter) { |
reporter.signed_certificate_timestamps()[0].sct); |
} |
+// Tests that the Expect CT reporter is not notified for repeated noncompliant |
+// connections to the same preloaded host. |
+TEST_F(TransportSecurityStateTest, RepeatedExpectCTReportsForStaticExpectCT) { |
+ HostPortPair host_port(kExpectCTStaticHostname, 443); |
+ SSLInfo ssl_info; |
+ ssl_info.ct_compliance_details_available = true; |
+ ssl_info.ct_cert_policy_compliance = |
+ ct::CertPolicyCompliance::CERT_POLICY_NOT_DIVERSE_SCTS; |
+ ssl_info.is_issued_by_known_root = true; |
+ scoped_refptr<X509Certificate> cert1 = |
+ ImportCertFromFile(GetTestCertsDirectory(), "test_mail_google_com.pem"); |
+ scoped_refptr<X509Certificate> cert2 = |
+ ImportCertFromFile(GetTestCertsDirectory(), "expired_cert.pem"); |
+ ASSERT_TRUE(cert1); |
+ ASSERT_TRUE(cert2); |
+ ssl_info.unverified_cert = cert1; |
+ ssl_info.cert = cert2; |
+ MakeTestSCTAndStatus(ct::SignedCertificateTimestamp::SCT_EMBEDDED, "test_log", |
+ std::string(), std::string(), base::Time::Now(), |
+ ct::SCT_STATUS_INVALID_SIGNATURE, |
+ &ssl_info.signed_certificate_timestamps); |
+ |
+ TransportSecurityState state; |
+ TransportSecurityStateTest::EnableStaticExpectCT(&state); |
+ MockExpectCTReporter reporter; |
+ state.SetExpectCTReporter(&reporter); |
+ state.ProcessExpectCTHeader("preload", host_port, ssl_info); |
+ EXPECT_EQ(1u, reporter.num_failures()); |
+ |
+ // After processing a second header, the report should not be sent again. |
+ state.ProcessExpectCTHeader("preload", host_port, ssl_info); |
+ EXPECT_EQ(1u, reporter.num_failures()); |
+} |
+ |
// Simple test for the HSTS preload process. The trie (generated from |
// transport_security_state_static_unittest1.json) contains 1 entry. Test that |
// the lookup methods can find the entry and correctly decode the different |
@@ -2865,6 +2899,89 @@ TEST_F(TransportSecurityStateTest, DynamicExpectCTState) { |
EXPECT_FALSE(state.GetDynamicExpectCTState(host, &expect_ct_state)); |
} |
+// Tests that the Expect-CT reporter is not notified for repeated dynamic |
+// Expect-CT violations for the same host/port. |
+TEST_F(TransportSecurityStateTest, DynamicExpectCTDeduping) { |
+ const char kHeader[] = "max-age=123,enforce,report-uri=\"http://foo.test\""; |
+ SSLInfo ssl; |
+ ssl.is_issued_by_known_root = true; |
+ ssl.ct_compliance_details_available = true; |
+ ssl.ct_cert_policy_compliance = |
+ ct::CertPolicyCompliance::CERT_POLICY_COMPLIES_VIA_SCTS; |
+ scoped_refptr<X509Certificate> cert1 = |
+ ImportCertFromFile(GetTestCertsDirectory(), "test_mail_google_com.pem"); |
+ scoped_refptr<X509Certificate> cert2 = |
+ ImportCertFromFile(GetTestCertsDirectory(), "expired_cert.pem"); |
+ ASSERT_TRUE(cert1); |
+ ASSERT_TRUE(cert2); |
+ SignedCertificateTimestampAndStatusList sct_list; |
+ |
+ base::test::ScopedFeatureList feature_list; |
+ feature_list.InitAndEnableFeature( |
+ TransportSecurityState::kDynamicExpectCTFeature); |
+ base::Time now = base::Time::Now(); |
+ TransportSecurityState state; |
+ MockExpectCTReporter reporter; |
+ state.SetExpectCTReporter(&reporter); |
+ state.ProcessExpectCTHeader(kHeader, HostPortPair("example.test", 443), ssl); |
+ TransportSecurityState::ExpectCTState expect_ct_state; |
+ EXPECT_TRUE(state.GetDynamicExpectCTState("example.test", &expect_ct_state)); |
+ EXPECT_EQ(GURL("http://foo.test"), expect_ct_state.report_uri); |
+ EXPECT_TRUE(expect_ct_state.enforce); |
+ EXPECT_LT(now, expect_ct_state.expiry); |
+ // No report should be sent when the header was processed over a connection |
+ // that complied with CT policy. |
+ EXPECT_EQ(0u, reporter.num_failures()); |
+ |
+ // The first time the host fails to meet CT requirements, a report should be |
+ // sent. |
+ EXPECT_EQ(TransportSecurityState::CT_REQUIREMENTS_NOT_MET, |
+ state.CheckCTRequirements( |
+ HostPortPair("example.test", 443), true, HashValueVector(), |
+ cert1.get(), cert2.get(), sct_list, |
+ TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, |
+ ct::CertPolicyCompliance::CERT_POLICY_NOT_ENOUGH_SCTS)); |
+ EXPECT_EQ(1u, reporter.num_failures()); |
+ |
+ // The second time it fails to meet CT requirements, a report should not be |
+ // sent. |
+ EXPECT_EQ(TransportSecurityState::CT_REQUIREMENTS_NOT_MET, |
+ state.CheckCTRequirements( |
+ HostPortPair("example.test", 443), true, HashValueVector(), |
+ cert1.get(), cert2.get(), sct_list, |
+ TransportSecurityState::ENABLE_EXPECT_CT_REPORTS, |
+ ct::CertPolicyCompliance::CERT_POLICY_NOT_ENOUGH_SCTS)); |
+ EXPECT_EQ(1u, reporter.num_failures()); |
+} |
+ |
+// Tests that the Expect-CT reporter is not notified when the Expect-CT header |
+// is received repeatedly over non-compliant connections. |
+TEST_F(TransportSecurityStateTest, DynamicExpectCTHeaderProcessingDeduping) { |
+ const char kHeader[] = "max-age=123,enforce,report-uri=\"http://foo.test\""; |
+ SSLInfo ssl; |
+ ssl.is_issued_by_known_root = true; |
+ ssl.ct_compliance_details_available = true; |
+ ssl.ct_cert_policy_compliance = |
+ ct::CertPolicyCompliance::CERT_POLICY_NOT_ENOUGH_SCTS; |
+ |
+ base::test::ScopedFeatureList feature_list; |
+ feature_list.InitAndEnableFeature( |
+ TransportSecurityState::kDynamicExpectCTFeature); |
+ TransportSecurityState state; |
+ MockExpectCTReporter reporter; |
+ state.SetExpectCTReporter(&reporter); |
+ state.ProcessExpectCTHeader(kHeader, HostPortPair("example.test", 443), ssl); |
+ TransportSecurityState::ExpectCTState expect_ct_state; |
+ EXPECT_FALSE(state.GetDynamicExpectCTState("example.test", &expect_ct_state)); |
+ // The first time the header was received over a connection that failed to |
+ // meet CT requirements, a report should be sent. |
+ EXPECT_EQ(1u, reporter.num_failures()); |
+ |
+ // The second time the header was received, no report should be sent. |
+ state.ProcessExpectCTHeader(kHeader, HostPortPair("example.test", 443), ssl); |
+ EXPECT_EQ(1u, reporter.num_failures()); |
+} |
+ |
// Tests that dynamic Expect-CT state cannot be added when the feature is not |
// enabled. |
TEST_F(TransportSecurityStateTest, DynamicExpectCTStateDisabled) { |