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 |