Chromium Code Reviews| Index: net/socket/ssl_client_socket_unittest.cc |
| diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc |
| index 6067721f84f3dc30e3b8125a3729ad2b3227341e..c6f81a91ef5a8d7b38d1c75ed2b6b4e133e24e25 100644 |
| --- a/net/socket/ssl_client_socket_unittest.cc |
| +++ b/net/socket/ssl_client_socket_unittest.cc |
| @@ -805,6 +805,50 @@ class AsyncFailingChannelIDStore : public ChannelIDStore { |
| bool IsEphemeral() override { return true; } |
| }; |
| +// 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 X509Certificate* served_certificate_chain, |
| + const X509Certificate* validated_certificate_chain, |
| + const SignedCertificateTimestampAndStatusList& |
| + signed_certificate_timestamps) override { |
| + num_failures_++; |
| + host_port_pair_ = host_port_pair; |
| + report_uri_ = report_uri; |
| + served_certificate_chain_ = served_certificate_chain; |
| + validated_certificate_chain_ = validated_certificate_chain; |
| + signed_certificate_timestamps_ = signed_certificate_timestamps; |
| + } |
| + |
| + const HostPortPair& host_port_pair() { return host_port_pair_; } |
| + const GURL& report_uri() { return report_uri_; } |
| + uint32_t num_failures() { return num_failures_; } |
| + const X509Certificate* served_certificate_chain() { |
| + return served_certificate_chain_; |
| + } |
| + const X509Certificate* validated_certificate_chain() { |
| + return validated_certificate_chain_; |
| + } |
| + const SignedCertificateTimestampAndStatusList& |
| + signed_certificate_timestamps() { |
| + return signed_certificate_timestamps_; |
| + } |
| + |
| + private: |
| + HostPortPair host_port_pair_; |
| + GURL report_uri_; |
| + uint32_t num_failures_; |
| + const X509Certificate* served_certificate_chain_; |
| + const X509Certificate* validated_certificate_chain_; |
| + SignedCertificateTimestampAndStatusList signed_certificate_timestamps_; |
| +}; |
| + |
| // A mock CTVerifier that records every call to Verify but doesn't verify |
| // anything. |
| class MockCTVerifier : public CTVerifier { |
| @@ -3478,6 +3522,58 @@ TEST_F(SSLClientSocketTest, CTIsRequired) { |
| EXPECT_TRUE(sock_->IsConnected()); |
| } |
| +// Test that when CT is required (in this case, by an Expect-CT opt-in), the |
| +// absence of CT information is a socket error. |
| +TEST_F(SSLClientSocketTest, CTIsRequiredByExpectCT) { |
|
mattm
2017/05/02 23:32:52
Test other combinations of having a header and dif
estark
2017/05/04 01:18:30
Done. The logic for checking compliance results is
|
| + base::test::ScopedFeatureList feature_list; |
| + feature_list.InitAndEnableFeature( |
| + TransportSecurityState::kDynamicExpectCTFeature); |
| + |
| + SpawnedTestServer::SSLOptions ssl_options; |
| + ASSERT_TRUE(StartTestServer(ssl_options)); |
| + scoped_refptr<X509Certificate> server_cert = |
| + spawned_test_server()->GetCertificate(); |
| + |
| + // Certificate is trusted and chains to a public root. |
| + CertVerifyResult verify_result; |
| + verify_result.is_issued_by_known_root = true; |
| + verify_result.verified_cert = server_cert; |
| + verify_result.public_key_hashes = MakeHashValueVector(0); |
| + cert_verifier_->AddResultForCert(server_cert.get(), verify_result, OK); |
| + |
| + // Set up the Expect-CT opt-in. |
| + const base::Time current_time(base::Time::Now()); |
| + const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); |
| + transport_security_state_->AddExpectCT( |
| + spawned_test_server()->host_port_pair().host(), expiry, |
| + true /* enforce */, GURL("https://example-report.test")); |
| + MockExpectCTReporter reporter; |
| + transport_security_state_->SetExpectCTReporter(&reporter); |
| + |
| + EXPECT_CALL(*ct_policy_enforcer_, |
| + DoesConformToCertPolicy(server_cert.get(), _, _)) |
| + .WillRepeatedly( |
| + Return(ct::CertPolicyCompliance::CERT_POLICY_NOT_ENOUGH_SCTS)); |
| + |
| + SSLConfig ssl_config; |
| + int rv; |
| + ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv)); |
| + SSLInfo ssl_info; |
| + ASSERT_TRUE(sock_->GetSSLInfo(&ssl_info)); |
| + |
| + EXPECT_THAT(rv, IsError(ERR_CERTIFICATE_TRANSPARENCY_REQUIRED)); |
| + EXPECT_TRUE(ssl_info.cert_status & |
| + CERT_STATUS_CERTIFICATE_TRANSPARENCY_REQUIRED); |
| + EXPECT_TRUE(sock_->IsConnected()); |
| + |
| + EXPECT_EQ(1u, reporter.num_failures()); |
| + EXPECT_EQ(GURL("https://example-report.test"), reporter.report_uri()); |
| + EXPECT_EQ(ssl_info.unverified_cert.get(), |
| + reporter.served_certificate_chain()); |
| + EXPECT_EQ(ssl_info.cert.get(), reporter.validated_certificate_chain()); |
| + EXPECT_EQ(0u, reporter.signed_certificate_timestamps().size()); |
| +} |
| + |
| // When both HPKP and CT are required for a host, and both fail, the more |
| // serious error is that the HPKP pin validation failed. |
| TEST_F(SSLClientSocketTest, PKPMoreImportantThanCT) { |