| 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 b0530783057032e98d9bea7a36d83126af4a310b..2da0913a5a0efdf6b97b90845577c5cbccd22117 100644
|
| --- a/net/socket/ssl_client_socket_unittest.cc
|
| +++ b/net/socket/ssl_client_socket_unittest.cc
|
| @@ -708,6 +708,12 @@ class MockCTPolicyEnforcer : public CTPolicyEnforcer {
|
| const BoundNetLog&));
|
| };
|
|
|
| +class MockRequireCTDelegate : public TransportSecurityState::RequireCTDelegate {
|
| + public:
|
| + MOCK_METHOD1(IsCTRequiredForHost,
|
| + CTRequirementLevel(const std::string& host));
|
| +};
|
| +
|
| class SSLClientSocketTest : public PlatformTest {
|
| public:
|
| SSLClientSocketTest()
|
| @@ -3353,4 +3359,99 @@ TEST_F(SSLClientSocketTest, PKPEnforced) {
|
| EXPECT_FALSE(ssl_info.pkp_bypassed);
|
| }
|
|
|
| +// Test that when CT is required (in this case, by the delegate), the
|
| +// absence of CT information is a socket error.
|
| +TEST_F(SSLClientSocketTest, CTIsRequired) {
|
| + 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 CT
|
| + MockRequireCTDelegate require_ct_delegate;
|
| + transport_security_state_->SetRequireCTDelegate(&require_ct_delegate);
|
| + EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(_))
|
| + .WillRepeatedly(Return(TransportSecurityState::RequireCTDelegate::
|
| + CTRequirementLevel::NOT_REQUIRED));
|
| + EXPECT_CALL(
|
| + require_ct_delegate,
|
| + IsCTRequiredForHost(spawned_test_server()->host_port_pair().host()))
|
| + .WillRepeatedly(Return(TransportSecurityState::RequireCTDelegate::
|
| + CTRequirementLevel::REQUIRED));
|
| + 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_EQ(ERR_CERTIFICATE_TRANSPARENCY_REQUIRED, rv);
|
| + EXPECT_TRUE(ssl_info.cert_status &
|
| + CERT_STATUS_CERTIFICATE_TRANSPARENCY_REQUIRED);
|
| + EXPECT_TRUE(sock_->IsConnected());
|
| +}
|
| +
|
| +// 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) {
|
| + SpawnedTestServer::SSLOptions ssl_options;
|
| + ASSERT_TRUE(StartTestServer(ssl_options));
|
| + scoped_refptr<X509Certificate> server_cert =
|
| + spawned_test_server()->GetCertificate();
|
| +
|
| + // Certificate is trusted, but chains to a public root that doesn't match the
|
| + // pin hashes.
|
| + 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 HPKP.
|
| + HashValueVector expected_hashes = MakeHashValueVector(1);
|
| + context_.transport_security_state->AddHPKP(
|
| + spawned_test_server()->host_port_pair().host(),
|
| + base::Time::Now() + base::TimeDelta::FromSeconds(10000), true,
|
| + expected_hashes, GURL());
|
| +
|
| + // Set up CT.
|
| + MockRequireCTDelegate require_ct_delegate;
|
| + transport_security_state_->SetRequireCTDelegate(&require_ct_delegate);
|
| + EXPECT_CALL(require_ct_delegate, IsCTRequiredForHost(_))
|
| + .WillRepeatedly(Return(TransportSecurityState::RequireCTDelegate::
|
| + CTRequirementLevel::NOT_REQUIRED));
|
| + EXPECT_CALL(
|
| + require_ct_delegate,
|
| + IsCTRequiredForHost(spawned_test_server()->host_port_pair().host()))
|
| + .WillRepeatedly(Return(TransportSecurityState::RequireCTDelegate::
|
| + CTRequirementLevel::REQUIRED));
|
| + 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_EQ(ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN, rv);
|
| + EXPECT_TRUE(ssl_info.cert_status & CERT_STATUS_PINNED_KEY_MISSING);
|
| + EXPECT_TRUE(ssl_info.cert_status &
|
| + CERT_STATUS_CERTIFICATE_TRANSPARENCY_REQUIRED);
|
| + EXPECT_TRUE(sock_->IsConnected());
|
| +}
|
| +
|
| } // namespace net
|
|
|