Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/http/transport_security_state.h" | 5 #include "net/http/transport_security_state.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 233 ASSERT_NO_FATAL_FAILURE(CompareCertificateChainWithList( | 233 ASSERT_NO_FATAL_FAILURE(CompareCertificateChainWithList( |
| 234 served_certificate_chain, report_served_certificate_chain)); | 234 served_certificate_chain, report_served_certificate_chain)); |
| 235 | 235 |
| 236 base::ListValue* report_validated_certificate_chain; | 236 base::ListValue* report_validated_certificate_chain; |
| 237 EXPECT_TRUE(report_dict->GetList("validated-certificate-chain", | 237 EXPECT_TRUE(report_dict->GetList("validated-certificate-chain", |
| 238 &report_validated_certificate_chain)); | 238 &report_validated_certificate_chain)); |
| 239 ASSERT_NO_FATAL_FAILURE(CompareCertificateChainWithList( | 239 ASSERT_NO_FATAL_FAILURE(CompareCertificateChainWithList( |
| 240 validated_certificate_chain, report_validated_certificate_chain)); | 240 validated_certificate_chain, report_validated_certificate_chain)); |
| 241 } | 241 } |
| 242 | 242 |
| 243 bool ResponseStatusFromString(std::string in, | |
|
Ryan Sleevi
2016/07/19 00:02:49
From a testing design standpoint, it doesn't seem
dadrian
2016/07/19 00:18:54
I did it this way since the reverse function is in
Ryan Sleevi
2016/07/19 01:17:22
Unfortunately, I'm having a lot of trouble underst
dadrian
2016/07/19 18:48:40
I reworked the tests to be table-driven with TEST_
| |
| 244 OCSPVerifyResult::ResponseStatus* status) { | |
| 245 if (in == "MISSING") { | |
| 246 *status = OCSPVerifyResult::MISSING; | |
| 247 } else if (in == "PROVIDED") { | |
| 248 *status = OCSPVerifyResult::PROVIDED; | |
| 249 } else if (in == "ERROR_RESPONSE") { | |
| 250 *status = OCSPVerifyResult::ERROR_RESPONSE; | |
| 251 } else if (in == "BAD_PRODUCED_AT") { | |
| 252 *status = OCSPVerifyResult::BAD_PRODUCED_AT; | |
| 253 } else if (in == "NO_MATCHING_RESPONSE") { | |
| 254 *status = OCSPVerifyResult::NO_MATCHING_RESPONSE; | |
| 255 } else if (in == "INVALID_DATE") { | |
| 256 *status = OCSPVerifyResult::INVALID_DATE; | |
| 257 } else if (in == "PARSE_RESPONSE_ERROR") { | |
| 258 *status = OCSPVerifyResult::PARSE_RESPONSE_ERROR; | |
| 259 } else if (in == "PARSE_RESPONSE_DATA_ERROR") { | |
| 260 *status = OCSPVerifyResult::PARSE_RESPONSE_DATA_ERROR; | |
| 261 } else { | |
| 262 return false; | |
| 263 } | |
| 264 return true; | |
| 265 } | |
| 266 | |
| 267 bool RevocationStatusFromString(std::string in, OCSPRevocationStatus* status) { | |
|
Ryan Sleevi
2016/07/19 00:02:49
Same remarks
dadrian
2016/07/19 18:48:39
Done.
| |
| 268 if (in == "GOOD") { | |
| 269 *status = OCSPRevocationStatus::GOOD; | |
| 270 } else if (in == "REVOKED") { | |
| 271 *status = OCSPRevocationStatus::REVOKED; | |
| 272 } else if (in == "UNKNOWN") { | |
| 273 *status = OCSPRevocationStatus::UNKNOWN; | |
| 274 } else { | |
| 275 return false; | |
| 276 } | |
| 277 return true; | |
| 278 } | |
| 279 | |
| 280 void CheckExpectStapleReport(const std::string& report, | |
| 281 const HostPortPair& host_port_pair, | |
| 282 const SSLInfo& ssl_info, | |
| 283 const std::string& ocsp_response) { | |
| 284 std::unique_ptr<base::Value> value(base::JSONReader::Read(report)); | |
| 285 ASSERT_TRUE(value); | |
| 286 ASSERT_TRUE(value->IsType(base::Value::TYPE_DICTIONARY)); | |
| 287 | |
| 288 base::DictionaryValue* report_dict; | |
| 289 ASSERT_TRUE(value->GetAsDictionary(&report_dict)); | |
| 290 | |
| 291 std::string report_hostname; | |
| 292 EXPECT_TRUE(report_dict->GetString("hostname", &report_hostname)); | |
| 293 EXPECT_EQ(host_port_pair.host(), report_hostname); | |
| 294 | |
| 295 int report_port; | |
| 296 EXPECT_TRUE(report_dict->GetInteger("port", &report_port)); | |
| 297 EXPECT_EQ(host_port_pair.port(), report_port); | |
| 298 | |
| 299 std::string report_response_status; | |
| 300 EXPECT_TRUE( | |
| 301 report_dict->GetString("response-status", &report_response_status)); | |
| 302 OCSPVerifyResult::ResponseStatus response_status; | |
| 303 EXPECT_TRUE( | |
| 304 ResponseStatusFromString(report_response_status, &response_status)); | |
| 305 EXPECT_EQ(ssl_info.ocsp_result.response_status, response_status); | |
| 306 | |
| 307 std::string report_ocsp_response; | |
| 308 bool has_ocsp_response = | |
| 309 report_dict->GetString("ocsp-response", &report_ocsp_response); | |
| 310 | |
| 311 if (!ocsp_response.empty()) { | |
| 312 EXPECT_TRUE(has_ocsp_response); | |
| 313 std::string decoded_ocsp_response; | |
| 314 EXPECT_TRUE( | |
| 315 base::Base64Decode(report_ocsp_response, &decoded_ocsp_response)); | |
| 316 EXPECT_EQ(ocsp_response, decoded_ocsp_response); | |
| 317 } else { | |
| 318 EXPECT_FALSE(has_ocsp_response); | |
| 319 } | |
| 320 | |
| 321 std::string report_cert_status; | |
| 322 bool has_cert_status = | |
| 323 report_dict->GetString("cert-status", &report_cert_status); | |
| 324 if (ssl_info.ocsp_result.response_status == OCSPVerifyResult::PROVIDED) { | |
| 325 EXPECT_TRUE(has_cert_status); | |
| 326 OCSPRevocationStatus revocation_status; | |
| 327 EXPECT_TRUE( | |
| 328 RevocationStatusFromString(report_cert_status, &revocation_status)); | |
| 329 EXPECT_EQ(ssl_info.ocsp_result.revocation_status, revocation_status); | |
| 330 } else { | |
| 331 EXPECT_FALSE(has_cert_status); | |
| 332 } | |
| 333 | |
| 334 base::ListValue* report_served_certificate_chain; | |
| 335 bool has_served_chain = report_dict->GetList( | |
| 336 "served-certificate-chain", &report_served_certificate_chain); | |
| 337 | |
| 338 base::ListValue* report_validated_certificate_chain; | |
| 339 bool has_validated_chain = report_dict->GetList( | |
| 340 "validated-certificate-chain", &report_validated_certificate_chain); | |
| 341 | |
| 342 if (ssl_info.is_issued_by_known_root) { | |
| 343 EXPECT_TRUE(has_served_chain); | |
| 344 ASSERT_NO_FATAL_FAILURE(CompareCertificateChainWithList( | |
| 345 ssl_info.unverified_cert, report_served_certificate_chain)); | |
| 346 | |
| 347 EXPECT_TRUE(has_validated_chain); | |
| 348 ASSERT_NO_FATAL_FAILURE(CompareCertificateChainWithList( | |
| 349 ssl_info.cert, report_validated_certificate_chain)); | |
| 350 } else { | |
| 351 EXPECT_FALSE(has_served_chain); | |
| 352 EXPECT_FALSE(has_validated_chain); | |
| 353 } | |
| 354 } | |
| 355 | |
| 356 void CheckExpectStaple(TransportSecurityState* state, | |
| 357 MockCertificateReportSender* reporter, | |
| 358 const SSLInfo& ssl_info, | |
| 359 const std::string ocsp_response) { | |
| 360 HostPortPair host_port(kExpectStapleStaticHostname, 443); | |
| 361 state->SetReportSender(reporter); | |
| 362 state->ProcessExpectStaple(host_port, ssl_info, ocsp_response); | |
| 363 EXPECT_EQ(GURL(kExpectStapleStaticReportURI), reporter->latest_report_uri()); | |
| 364 std::string serialized_report = reporter->latest_report(); | |
| 365 EXPECT_NO_FATAL_FAILURE(CheckExpectStapleReport(serialized_report, host_port, | |
| 366 ssl_info, ocsp_response)); | |
| 367 } | |
| 368 | |
| 243 } // namespace | 369 } // namespace |
| 244 | 370 |
| 245 class TransportSecurityStateTest : public testing::Test { | 371 class TransportSecurityStateTest : public testing::Test { |
| 246 public: | 372 public: |
| 247 void SetUp() override { | 373 void SetUp() override { |
| 248 crypto::EnsureOpenSSLInit(); | 374 crypto::EnsureOpenSSLInit(); |
| 249 } | 375 } |
| 250 | 376 |
| 251 static void DisableStaticPins(TransportSecurityState* state) { | 377 static void DisableStaticPins(TransportSecurityState* state) { |
| 252 state->enable_static_pins_ = false; | 378 state->enable_static_pins_ = false; |
| (...skipping 1642 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1895 state.ProcessExpectCTHeader("preload", host_port, ssl_info); | 2021 state.ProcessExpectCTHeader("preload", host_port, ssl_info); |
| 1896 EXPECT_EQ(1u, reporter.num_failures()); | 2022 EXPECT_EQ(1u, reporter.num_failures()); |
| 1897 EXPECT_TRUE(reporter.ssl_info().ct_compliance_details_available); | 2023 EXPECT_TRUE(reporter.ssl_info().ct_compliance_details_available); |
| 1898 EXPECT_EQ(ssl_info.ct_cert_policy_compliance, | 2024 EXPECT_EQ(ssl_info.ct_cert_policy_compliance, |
| 1899 reporter.ssl_info().ct_cert_policy_compliance); | 2025 reporter.ssl_info().ct_cert_policy_compliance); |
| 1900 EXPECT_EQ(host_port.host(), reporter.host_port_pair().host()); | 2026 EXPECT_EQ(host_port.host(), reporter.host_port_pair().host()); |
| 1901 EXPECT_EQ(host_port.port(), reporter.host_port_pair().port()); | 2027 EXPECT_EQ(host_port.port(), reporter.host_port_pair().port()); |
| 1902 EXPECT_EQ(GURL(kExpectCTStaticReportURI), reporter.report_uri()); | 2028 EXPECT_EQ(GURL(kExpectCTStaticReportURI), reporter.report_uri()); |
| 1903 } | 2029 } |
| 1904 | 2030 |
| 2031 TEST_F(TransportSecurityStateTest, ExpectStapleReporter) { | |
| 2032 TransportSecurityState state; | |
| 2033 TransportSecurityStateTest::EnableStaticExpectStaple(&state); | |
| 2034 MockCertificateReportSender reporter; | |
| 2035 | |
| 2036 std::string ocsp_response; | |
| 2037 | |
| 2038 // Two dummy certs to use as the server-sent and validated chains. The | |
| 2039 // contents don't matter. | |
| 2040 scoped_refptr<X509Certificate> cert1 = | |
| 2041 ImportCertFromFile(GetTestCertsDirectory(), "test_mail_google_com.pem"); | |
| 2042 scoped_refptr<X509Certificate> cert2 = | |
| 2043 ImportCertFromFile(GetTestCertsDirectory(), "expired_cert.pem"); | |
| 2044 | |
| 2045 SSLInfo ssl_info; | |
| 2046 ssl_info.is_issued_by_known_root = true; | |
| 2047 ssl_info.cert = cert1; | |
| 2048 ssl_info.unverified_cert = cert2; | |
| 2049 ssl_info.ocsp_result.response_status = OCSPVerifyResult::MISSING; | |
| 2050 | |
| 2051 ASSERT_NO_FATAL_FAILURE( | |
| 2052 CheckExpectStaple(&state, &reporter, ssl_info, ocsp_response)); | |
| 2053 | |
| 2054 // Certs should not be included for non-public roots. | |
| 2055 ssl_info.is_issued_by_known_root = false; | |
| 2056 ASSERT_NO_FATAL_FAILURE( | |
| 2057 CheckExpectStaple(&state, &reporter, ssl_info, ocsp_response)); | |
| 2058 | |
| 2059 // Check response statuses that correspond with a stapled response, but not | |
| 2060 // revocation status. | |
| 2061 ocsp_response = "dummy response"; | |
| 2062 ssl_info.is_issued_by_known_root = true; | |
| 2063 std::vector<OCSPVerifyResult::ResponseStatus> response_statuses{ | |
| 2064 OCSPVerifyResult::ERROR_RESPONSE, | |
| 2065 OCSPVerifyResult::BAD_PRODUCED_AT, | |
| 2066 OCSPVerifyResult::NO_MATCHING_RESPONSE, | |
| 2067 OCSPVerifyResult::INVALID_DATE, | |
| 2068 OCSPVerifyResult::PARSE_RESPONSE_ERROR, | |
| 2069 OCSPVerifyResult::PARSE_RESPONSE_DATA_ERROR, | |
| 2070 }; | |
| 2071 for (const auto& response_status : response_statuses) { | |
| 2072 ssl_info.ocsp_result.response_status = response_status; | |
| 2073 ASSERT_NO_FATAL_FAILURE( | |
| 2074 CheckExpectStaple(&state, &reporter, ssl_info, ocsp_response)); | |
| 2075 } | |
| 2076 | |
| 2077 // Check each revocation status that should trigger a report. | |
| 2078 ssl_info.ocsp_result.response_status = OCSPVerifyResult::PROVIDED; | |
| 2079 std::vector<OCSPRevocationStatus> cert_statuses{ | |
| 2080 OCSPRevocationStatus::REVOKED, OCSPRevocationStatus::UNKNOWN, | |
| 2081 }; | |
| 2082 for (const auto& cert_status : cert_statuses) { | |
| 2083 ssl_info.ocsp_result.revocation_status = cert_status; | |
| 2084 ASSERT_NO_FATAL_FAILURE( | |
| 2085 CheckExpectStaple(&state, &reporter, ssl_info, ocsp_response)); | |
| 2086 } | |
| 2087 } | |
| 2088 | |
| 2089 TEST_F(TransportSecurityStateTest, ExpectStapleDoesNotReportValidStaple) { | |
| 2090 TransportSecurityState state; | |
| 2091 TransportSecurityStateTest::EnableStaticExpectStaple(&state); | |
| 2092 MockCertificateReportSender reporter; | |
| 2093 state.SetReportSender(&reporter); | |
| 2094 | |
| 2095 HostPortPair host_port(kExpectStapleStaticHostname, 443); | |
| 2096 | |
| 2097 // Two dummy certs to use as the server-sent and validated chains. The | |
| 2098 // contents don't matter. | |
| 2099 scoped_refptr<X509Certificate> cert1 = | |
| 2100 ImportCertFromFile(GetTestCertsDirectory(), "test_mail_google_com.pem"); | |
| 2101 scoped_refptr<X509Certificate> cert2 = | |
| 2102 ImportCertFromFile(GetTestCertsDirectory(), "expired_cert.pem"); | |
| 2103 | |
| 2104 SSLInfo ssl_info; | |
| 2105 ssl_info.is_issued_by_known_root = true; | |
| 2106 ssl_info.cert = cert1; | |
| 2107 ssl_info.unverified_cert = cert2; | |
| 2108 ssl_info.ocsp_result.response_status = OCSPVerifyResult::PROVIDED; | |
| 2109 ssl_info.ocsp_result.revocation_status = OCSPRevocationStatus::GOOD; | |
| 2110 | |
| 2111 std::string ocsp_response = "dummy response"; | |
| 2112 | |
| 2113 state.ProcessExpectStaple(host_port, ssl_info, ocsp_response); | |
| 2114 EXPECT_EQ(GURL(), reporter.latest_report_uri()); | |
| 2115 EXPECT_TRUE(reporter.latest_report().empty()); | |
| 2116 } | |
| 2117 | |
| 2118 TEST_F(TransportSecurityStateTest, ExpectStapleRequiresPreload) { | |
| 2119 TransportSecurityState state; | |
| 2120 TransportSecurityStateTest::EnableStaticExpectStaple(&state); | |
| 2121 MockCertificateReportSender reporter; | |
| 2122 state.SetReportSender(&reporter); | |
| 2123 | |
| 2124 HostPortPair host_port("not-preloaded.badssl.com", 443); | |
| 2125 | |
| 2126 // Two dummy certs to use as the server-sent and validated chains. The | |
| 2127 // contents don't matter. | |
| 2128 scoped_refptr<X509Certificate> cert1 = | |
| 2129 ImportCertFromFile(GetTestCertsDirectory(), "test_mail_google_com.pem"); | |
| 2130 scoped_refptr<X509Certificate> cert2 = | |
| 2131 ImportCertFromFile(GetTestCertsDirectory(), "expired_cert.pem"); | |
| 2132 | |
| 2133 SSLInfo ssl_info; | |
| 2134 ssl_info.is_issued_by_known_root = true; | |
| 2135 ssl_info.cert = cert1; | |
| 2136 ssl_info.unverified_cert = cert2; | |
| 2137 ssl_info.ocsp_result.response_status = OCSPVerifyResult::MISSING; | |
| 2138 | |
| 2139 // Empty response | |
| 2140 std::string ocsp_response; | |
| 2141 | |
| 2142 state.ProcessExpectStaple(host_port, ssl_info, ocsp_response); | |
| 2143 EXPECT_EQ(GURL(), reporter.latest_report_uri()); | |
| 2144 EXPECT_TRUE(reporter.latest_report().empty()); | |
| 2145 } | |
| 2146 | |
| 1905 // Tests that TransportSecurityState always consults the RequireCTDelegate, | 2147 // Tests that TransportSecurityState always consults the RequireCTDelegate, |
| 1906 // if supplied. | 2148 // if supplied. |
| 1907 TEST_F(TransportSecurityStateTest, RequireCTConsultsDelegate) { | 2149 TEST_F(TransportSecurityStateTest, RequireCTConsultsDelegate) { |
| 1908 using ::testing::_; | 2150 using ::testing::_; |
| 1909 using ::testing::Return; | 2151 using ::testing::Return; |
| 1910 using CTRequirementLevel = | 2152 using CTRequirementLevel = |
| 1911 TransportSecurityState::RequireCTDelegate::CTRequirementLevel; | 2153 TransportSecurityState::RequireCTDelegate::CTRequirementLevel; |
| 1912 | 2154 |
| 1913 // Dummy cert to use as the validate chain. The contents do not matter. | 2155 // Dummy cert to use as the validate chain. The contents do not matter. |
| 1914 scoped_refptr<X509Certificate> cert = | 2156 scoped_refptr<X509Certificate> cert = |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2029 base::FieldTrialList::CreateFieldTrial("EnforceCTForProblematicRoots", | 2271 base::FieldTrialList::CreateFieldTrial("EnforceCTForProblematicRoots", |
| 2030 "disabled"); | 2272 "disabled"); |
| 2031 | 2273 |
| 2032 EXPECT_FALSE( | 2274 EXPECT_FALSE( |
| 2033 state.ShouldRequireCT("www.example.com", before_cert.get(), hashes)); | 2275 state.ShouldRequireCT("www.example.com", before_cert.get(), hashes)); |
| 2034 EXPECT_FALSE( | 2276 EXPECT_FALSE( |
| 2035 state.ShouldRequireCT("www.example.com", after_cert.get(), hashes)); | 2277 state.ShouldRequireCT("www.example.com", after_cert.get(), hashes)); |
| 2036 } | 2278 } |
| 2037 | 2279 |
| 2038 } // namespace net | 2280 } // namespace net |
| OLD | NEW |