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 75c7c751904df00fa823ac82646c9a4ef42b22ea..c31f0951ac16307617e9495fa78ea80e1cb14d4b 100644 |
--- a/net/http/transport_security_state_unittest.cc |
+++ b/net/http/transport_security_state_unittest.cc |
@@ -23,6 +23,7 @@ |
#include "net/cert/asn1_util.h" |
#include "net/cert/cert_verifier.h" |
#include "net/cert/cert_verify_result.h" |
+#include "net/cert/ct_policy_status.h" |
#include "net/cert/test_root_certs.h" |
#include "net/cert/x509_cert_types.h" |
#include "net/cert/x509_certificate.h" |
@@ -46,6 +47,8 @@ const char kHost[] = "example.test"; |
const char kSubdomain[] = "foo.example.test"; |
const uint16_t kPort = 443; |
const char kReportUri[] = "http://report-example.test/test"; |
+const char kExpectCTStaticHostname[] = "preloaded-expect-ct.badssl.com"; |
+const char kExpectCTStaticReportURI[] = "https://report.badssl.com/expect-ct"; |
// kGoodPath is blog.torproject.org. |
const char* const kGoodPath[] = { |
@@ -100,6 +103,34 @@ class MockCertificateReportSender |
std::string latest_report_; |
}; |
+// A mock ExpectCTReporter that remembers the latest violation that was |
+// reported and the number of violations reported. |
+class MockExpectCTReporter : public TransportSecurityState::ExpectCTReporter { |
+ public: |
+ MockExpectCTReporter() : num_failures_(0) {} |
+ ~MockExpectCTReporter() override {} |
+ |
+ void OnExpectCTFailed(const HostPortPair& host_port_pair, |
+ const GURL& report_uri, |
+ const net::SSLInfo& ssl_info) override { |
+ num_failures_++; |
+ host_port_pair_ = host_port_pair; |
+ report_uri_ = report_uri; |
+ ssl_info_ = ssl_info; |
+ } |
+ |
+ const HostPortPair& host_port_pair() { return host_port_pair_; } |
+ const GURL& report_uri() { return report_uri_; } |
+ const SSLInfo& ssl_info() { return ssl_info_; } |
+ uint32_t num_failures() { return num_failures_; } |
+ |
+ private: |
+ HostPortPair host_port_pair_; |
+ GURL report_uri_; |
+ SSLInfo ssl_info_; |
+ uint32_t num_failures_; |
+}; |
+ |
void CompareCertificateChainWithList( |
const scoped_refptr<X509Certificate>& cert_chain, |
const base::ListValue* cert_list) { |
@@ -210,6 +241,12 @@ class TransportSecurityStateTest : public testing::Test { |
TransportSecurityState::PKPState* pkp_result) { |
return state->GetStaticDomainState(host, sts_result, pkp_result); |
} |
+ |
+ bool GetExpectCTState(TransportSecurityState* state, |
+ const std::string& host, |
+ TransportSecurityState::ExpectCTState* result) { |
+ return state->GetStaticExpectCTState(host, result); |
+ } |
}; |
TEST_F(TransportSecurityStateTest, DomainNameOddities) { |
@@ -1553,16 +1590,152 @@ TEST_F(TransportSecurityStateTest, HPKPReportRateLimiting) { |
// Tests that static (preloaded) expect CT state is read correctly. |
TEST_F(TransportSecurityStateTest, PreloadedExpectCT) { |
- const char kHostname[] = "preloaded-expect-ct.badssl.com"; |
TransportSecurityState state; |
TransportSecurityStateTest::EnableStaticExpectCT(&state); |
TransportSecurityState::ExpectCTState expect_ct_state; |
- EXPECT_TRUE(state.GetStaticExpectCTState(kHostname, &expect_ct_state)); |
- EXPECT_EQ(kHostname, expect_ct_state.domain); |
- EXPECT_EQ(GURL("https://report.badssl.com/expect-ct"), |
- expect_ct_state.report_uri); |
- EXPECT_FALSE(state.GetStaticExpectCTState("pinning-test.badssl.com", |
- &expect_ct_state)); |
+ EXPECT_TRUE( |
+ GetExpectCTState(&state, kExpectCTStaticHostname, &expect_ct_state)); |
+ EXPECT_EQ(kExpectCTStaticHostname, expect_ct_state.domain); |
+ EXPECT_EQ(GURL(kExpectCTStaticReportURI), expect_ct_state.report_uri); |
+ EXPECT_FALSE( |
+ GetExpectCTState(&state, "pinning-test.badssl.com", &expect_ct_state)); |
+} |
+ |
+// Tests that the Expect CT reporter is not notified for invalid or absent |
+// header values. |
+TEST_F(TransportSecurityStateTest, InvalidExpectCTHeader) { |
+ 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_ENOUGH_SCTS; |
+ ssl_info.is_issued_by_known_root = true; |
+ |
+ TransportSecurityState state; |
+ TransportSecurityStateTest::EnableStaticExpectCT(&state); |
+ MockExpectCTReporter reporter; |
+ state.SetExpectCTReporter(&reporter); |
+ state.ProcessExpectCTHeader("", host_port, ssl_info); |
+ EXPECT_EQ(0u, reporter.num_failures()); |
+ |
+ state.ProcessExpectCTHeader("blah blah", host_port, ssl_info); |
+ EXPECT_EQ(0u, reporter.num_failures()); |
+ |
+ state.ProcessExpectCTHeader("preload", host_port, ssl_info); |
+ EXPECT_EQ(1u, reporter.num_failures()); |
+} |
+ |
+// Tests that the Expect CT reporter is only notified about certificates |
+// chaining to public roots. |
+TEST_F(TransportSecurityStateTest, ExpectCTNonPublicRoot) { |
+ 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_ENOUGH_SCTS; |
+ ssl_info.is_issued_by_known_root = false; |
+ |
+ TransportSecurityState state; |
+ TransportSecurityStateTest::EnableStaticExpectCT(&state); |
+ MockExpectCTReporter reporter; |
+ state.SetExpectCTReporter(&reporter); |
+ state.ProcessExpectCTHeader("preload", host_port, ssl_info); |
+ EXPECT_EQ(0u, reporter.num_failures()); |
+ |
+ ssl_info.is_issued_by_known_root = true; |
+ state.ProcessExpectCTHeader("preload", host_port, ssl_info); |
+ EXPECT_EQ(1u, reporter.num_failures()); |
+} |
+ |
+// Tests that the Expect CT reporter is not notified when compliance |
+// details aren't available. |
+TEST_F(TransportSecurityStateTest, ExpectCTComplianceNotAvailable) { |
+ HostPortPair host_port(kExpectCTStaticHostname, 443); |
+ SSLInfo ssl_info; |
+ ssl_info.ct_compliance_details_available = false; |
+ ssl_info.ct_cert_policy_compliance = |
+ ct::CertPolicyCompliance::CERT_POLICY_NOT_ENOUGH_SCTS; |
+ ssl_info.is_issued_by_known_root = true; |
+ |
+ TransportSecurityState state; |
+ TransportSecurityStateTest::EnableStaticExpectCT(&state); |
+ MockExpectCTReporter reporter; |
+ state.SetExpectCTReporter(&reporter); |
+ state.ProcessExpectCTHeader("preload", host_port, ssl_info); |
+ EXPECT_EQ(0u, reporter.num_failures()); |
+ |
+ ssl_info.ct_compliance_details_available = true; |
+ state.ProcessExpectCTHeader("preload", host_port, ssl_info); |
+ EXPECT_EQ(1u, reporter.num_failures()); |
+} |
+ |
+// Tests that the Expect CT reporter is not notified about compliant |
+// connections. |
+TEST_F(TransportSecurityStateTest, ExpectCTCompliantCert) { |
+ 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_COMPLIES_VIA_SCTS; |
+ ssl_info.is_issued_by_known_root = true; |
+ |
+ TransportSecurityState state; |
+ TransportSecurityStateTest::EnableStaticExpectCT(&state); |
+ MockExpectCTReporter reporter; |
+ state.SetExpectCTReporter(&reporter); |
+ state.ProcessExpectCTHeader("preload", host_port, ssl_info); |
+ EXPECT_EQ(0u, reporter.num_failures()); |
+ |
+ ssl_info.ct_cert_policy_compliance = |
+ ct::CertPolicyCompliance::CERT_POLICY_NOT_DIVERSE_SCTS; |
+ state.ProcessExpectCTHeader("preload", host_port, ssl_info); |
+ EXPECT_EQ(1u, reporter.num_failures()); |
+} |
+ |
+// Tests that the Expect CT reporter is not notified for a site that |
+// isn't preloaded. |
+TEST_F(TransportSecurityStateTest, ExpectCTNotPreloaded) { |
+ HostPortPair host_port("not-expect-ct-preloaded.test", 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; |
+ |
+ TransportSecurityState state; |
+ TransportSecurityStateTest::EnableStaticExpectCT(&state); |
+ MockExpectCTReporter reporter; |
+ state.SetExpectCTReporter(&reporter); |
+ state.ProcessExpectCTHeader("preload", host_port, ssl_info); |
+ EXPECT_EQ(0u, reporter.num_failures()); |
+ |
+ host_port.set_host(kExpectCTStaticHostname); |
+ state.ProcessExpectCTHeader("preload", host_port, ssl_info); |
+ EXPECT_EQ(1u, reporter.num_failures()); |
+} |
+ |
+// Tests that the Expect CT reporter is notified for noncompliant |
+// connections. |
+TEST_F(TransportSecurityStateTest, ExpectCTReporter) { |
+ 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; |
+ |
+ TransportSecurityState state; |
+ TransportSecurityStateTest::EnableStaticExpectCT(&state); |
+ MockExpectCTReporter reporter; |
+ state.SetExpectCTReporter(&reporter); |
+ state.ProcessExpectCTHeader("preload", host_port, ssl_info); |
+ EXPECT_EQ(1u, reporter.num_failures()); |
+ EXPECT_TRUE(reporter.ssl_info().ct_compliance_details_available); |
+ EXPECT_EQ(ssl_info.ct_cert_policy_compliance, |
+ reporter.ssl_info().ct_cert_policy_compliance); |
+ EXPECT_EQ(host_port.host(), reporter.host_port_pair().host()); |
+ EXPECT_EQ(host_port.port(), reporter.host_port_pair().port()); |
+ EXPECT_EQ(GURL(kExpectCTStaticReportURI), reporter.report_uri()); |
} |
} // namespace net |