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 // Checks the following hold for |report| such that it is a valid Expect-Staple |
| 244 // report: |
| 245 // 1. |report| is a JSON dictionary. |
| 246 // 2. The "hostname" and "port" fields match |host_port_pair|. |
| 247 // 3. The "response-status" field matches |response_status| |
| 248 // 4. The "ocsp-response" field is a base64-encoded verson of |ocsp_response|, |
| 249 // and is not present when |ocsp_response| is empty. |
| 250 // 5. The "cert-status" field matches |cert_status|, and is not present when |
| 251 // |cert_status| is empty. |
| 252 // 6. The "validated-chain" and "serverd-chain" fields match those in |
| 253 // |ssl_info|, and are only present when |ssl_info.is_issued_by_known_root| |
| 254 // is true. |
| 255 void CheckSerializedExpectStapleReport(const std::string& report, |
| 256 const HostPortPair& host_port_pair, |
| 257 const SSLInfo& ssl_info, |
| 258 const std::string& ocsp_response, |
| 259 const std::string& response_status, |
| 260 const std::string& cert_status) { |
| 261 std::unique_ptr<base::Value> value(base::JSONReader::Read(report)); |
| 262 ASSERT_TRUE(value); |
| 263 ASSERT_TRUE(value->IsType(base::Value::TYPE_DICTIONARY)); |
| 264 |
| 265 base::DictionaryValue* report_dict; |
| 266 ASSERT_TRUE(value->GetAsDictionary(&report_dict)); |
| 267 |
| 268 std::string report_hostname; |
| 269 EXPECT_TRUE(report_dict->GetString("hostname", &report_hostname)); |
| 270 EXPECT_EQ(host_port_pair.host(), report_hostname); |
| 271 |
| 272 int report_port; |
| 273 EXPECT_TRUE(report_dict->GetInteger("port", &report_port)); |
| 274 EXPECT_EQ(host_port_pair.port(), report_port); |
| 275 |
| 276 std::string report_response_status; |
| 277 EXPECT_TRUE( |
| 278 report_dict->GetString("response-status", &report_response_status)); |
| 279 EXPECT_EQ(response_status, report_response_status); |
| 280 |
| 281 std::string report_ocsp_response; |
| 282 bool has_ocsp_response = |
| 283 report_dict->GetString("ocsp-response", &report_ocsp_response); |
| 284 |
| 285 if (!ocsp_response.empty()) { |
| 286 EXPECT_TRUE(has_ocsp_response); |
| 287 std::string decoded_ocsp_response; |
| 288 EXPECT_TRUE( |
| 289 base::Base64Decode(report_ocsp_response, &decoded_ocsp_response)); |
| 290 EXPECT_EQ(ocsp_response, decoded_ocsp_response); |
| 291 } else { |
| 292 EXPECT_FALSE(has_ocsp_response); |
| 293 } |
| 294 |
| 295 std::string report_cert_status; |
| 296 bool has_cert_status = |
| 297 report_dict->GetString("cert-status", &report_cert_status); |
| 298 if (!cert_status.empty()) { |
| 299 EXPECT_TRUE(has_cert_status); |
| 300 EXPECT_EQ(cert_status, report_cert_status); |
| 301 } else { |
| 302 EXPECT_FALSE(has_cert_status); |
| 303 } |
| 304 |
| 305 base::ListValue* report_served_certificate_chain; |
| 306 bool has_served_chain = report_dict->GetList( |
| 307 "served-certificate-chain", &report_served_certificate_chain); |
| 308 |
| 309 base::ListValue* report_validated_certificate_chain; |
| 310 bool has_validated_chain = report_dict->GetList( |
| 311 "validated-certificate-chain", &report_validated_certificate_chain); |
| 312 |
| 313 if (ssl_info.is_issued_by_known_root) { |
| 314 EXPECT_TRUE(has_served_chain); |
| 315 EXPECT_NO_FATAL_FAILURE(CompareCertificateChainWithList( |
| 316 ssl_info.unverified_cert, report_served_certificate_chain)); |
| 317 |
| 318 EXPECT_TRUE(has_validated_chain); |
| 319 EXPECT_NO_FATAL_FAILURE(CompareCertificateChainWithList( |
| 320 ssl_info.cert, report_validated_certificate_chain)); |
| 321 } else { |
| 322 EXPECT_FALSE(has_served_chain); |
| 323 EXPECT_FALSE(has_validated_chain); |
| 324 } |
| 325 } |
| 326 |
| 327 // Set up |state| for ExpectStaple, call CheckExpectStaple(), and verify the |
| 328 // serialized report caught by |reporter|. |
| 329 void CheckExpectStapleReport(TransportSecurityState* state, |
| 330 MockCertificateReportSender* reporter, |
| 331 const SSLInfo& ssl_info, |
| 332 const std::string& ocsp_response, |
| 333 const std::string& response_status, |
| 334 const std::string& cert_status) { |
| 335 // Expect-Staple is preload list based, so we use the baked-in test hostname |
| 336 // from the list ("preloaded-expect-staple.badssl.com"). |
| 337 HostPortPair host_port(kExpectStapleStaticHostname, 443); |
| 338 state->SetReportSender(reporter); |
| 339 state->CheckExpectStaple(host_port, ssl_info, ocsp_response); |
| 340 EXPECT_EQ(GURL(kExpectStapleStaticReportURI), reporter->latest_report_uri()); |
| 341 std::string serialized_report = reporter->latest_report(); |
| 342 EXPECT_NO_FATAL_FAILURE(CheckSerializedExpectStapleReport( |
| 343 serialized_report, host_port, ssl_info, ocsp_response, response_status, |
| 344 cert_status)); |
| 345 } |
| 346 |
243 } // namespace | 347 } // namespace |
244 | 348 |
245 class TransportSecurityStateTest : public testing::Test { | 349 class TransportSecurityStateTest : public testing::Test { |
246 public: | 350 public: |
247 void SetUp() override { | 351 void SetUp() override { |
248 crypto::EnsureOpenSSLInit(); | 352 crypto::EnsureOpenSSLInit(); |
249 } | 353 } |
250 | 354 |
251 static void DisableStaticPins(TransportSecurityState* state) { | 355 static void DisableStaticPins(TransportSecurityState* state) { |
252 state->enable_static_pins_ = false; | 356 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); | 1999 state.ProcessExpectCTHeader("preload", host_port, ssl_info); |
1896 EXPECT_EQ(1u, reporter.num_failures()); | 2000 EXPECT_EQ(1u, reporter.num_failures()); |
1897 EXPECT_TRUE(reporter.ssl_info().ct_compliance_details_available); | 2001 EXPECT_TRUE(reporter.ssl_info().ct_compliance_details_available); |
1898 EXPECT_EQ(ssl_info.ct_cert_policy_compliance, | 2002 EXPECT_EQ(ssl_info.ct_cert_policy_compliance, |
1899 reporter.ssl_info().ct_cert_policy_compliance); | 2003 reporter.ssl_info().ct_cert_policy_compliance); |
1900 EXPECT_EQ(host_port.host(), reporter.host_port_pair().host()); | 2004 EXPECT_EQ(host_port.host(), reporter.host_port_pair().host()); |
1901 EXPECT_EQ(host_port.port(), reporter.host_port_pair().port()); | 2005 EXPECT_EQ(host_port.port(), reporter.host_port_pair().port()); |
1902 EXPECT_EQ(GURL(kExpectCTStaticReportURI), reporter.report_uri()); | 2006 EXPECT_EQ(GURL(kExpectCTStaticReportURI), reporter.report_uri()); |
1903 } | 2007 } |
1904 | 2008 |
| 2009 static const struct ExpectStapleErrorResponseData { |
| 2010 OCSPVerifyResult::ResponseStatus response_status; |
| 2011 std::string response_status_string; |
| 2012 } kExpectStapleReportData[] = { |
| 2013 {OCSPVerifyResult::MISSING, "MISSING"}, |
| 2014 {OCSPVerifyResult::ERROR_RESPONSE, "ERROR_RESPONSE"}, |
| 2015 {OCSPVerifyResult::BAD_PRODUCED_AT, "BAD_PRODUCED_AT"}, |
| 2016 {OCSPVerifyResult::NO_MATCHING_RESPONSE, "NO_MATCHING_RESPONSE"}, |
| 2017 {OCSPVerifyResult::INVALID_DATE, "INVALID_DATE"}, |
| 2018 {OCSPVerifyResult::PARSE_RESPONSE_ERROR, "PARSE_RESPONSE_ERROR"}, |
| 2019 {OCSPVerifyResult::PARSE_RESPONSE_DATA_ERROR, "PARSE_RESPONSE_DATA_ERROR"}, |
| 2020 }; |
| 2021 |
| 2022 class ExpectStapleErrorResponseTest |
| 2023 : public TransportSecurityStateTest, |
| 2024 public testing::WithParamInterface<ExpectStapleErrorResponseData> {}; |
| 2025 |
| 2026 // For every |response_status| indicating an OCSP response was provided, but had |
| 2027 // some sort of parsing/validation error, test that the ExpectStaple report is |
| 2028 // serialized correctly. |
| 2029 TEST_P(ExpectStapleErrorResponseTest, CheckResponseStatusSerialization) { |
| 2030 TransportSecurityState state; |
| 2031 TransportSecurityStateTest::EnableStaticExpectStaple(&state); |
| 2032 MockCertificateReportSender reporter; |
| 2033 ExpectStapleErrorResponseData test = GetParam(); |
| 2034 |
| 2035 std::string ocsp_response; |
| 2036 if (test.response_status != OCSPVerifyResult::MISSING) |
| 2037 ocsp_response = "dummy_response"; |
| 2038 |
| 2039 // Two dummy certs to use as the server-sent and validated chains. The |
| 2040 // contents don't matter. |
| 2041 scoped_refptr<X509Certificate> cert1 = |
| 2042 ImportCertFromFile(GetTestCertsDirectory(), "test_mail_google_com.pem"); |
| 2043 scoped_refptr<X509Certificate> cert2 = |
| 2044 ImportCertFromFile(GetTestCertsDirectory(), "expired_cert.pem"); |
| 2045 |
| 2046 SSLInfo ssl_info; |
| 2047 ssl_info.cert = cert1; |
| 2048 ssl_info.unverified_cert = cert2; |
| 2049 ssl_info.ocsp_result.response_status = test.response_status; |
| 2050 |
| 2051 // Certificate chains should only be included when |is_issued_by_known_root| |
| 2052 // is true. |
| 2053 ssl_info.is_issued_by_known_root = true; |
| 2054 ASSERT_NO_FATAL_FAILURE( |
| 2055 CheckExpectStapleReport(&state, &reporter, ssl_info, ocsp_response, |
| 2056 test.response_status_string, std::string())); |
| 2057 |
| 2058 // No certificate chains should be included in the report. |
| 2059 ssl_info.is_issued_by_known_root = false; |
| 2060 ASSERT_NO_FATAL_FAILURE( |
| 2061 CheckExpectStapleReport(&state, &reporter, ssl_info, ocsp_response, |
| 2062 test.response_status_string, std::string())); |
| 2063 } |
| 2064 |
| 2065 INSTANTIATE_TEST_CASE_P(ExpectStaple, |
| 2066 ExpectStapleErrorResponseTest, |
| 2067 testing::ValuesIn(kExpectStapleReportData)); |
| 2068 |
| 2069 static const struct ExpectStapleErrorCertStatusData { |
| 2070 OCSPRevocationStatus revocation_status; |
| 2071 std::string cert_status_string; |
| 2072 } kExpectStapleErrorCertStatusData[] = { |
| 2073 {OCSPRevocationStatus::REVOKED, "REVOKED"}, |
| 2074 {OCSPRevocationStatus::UNKNOWN, "UNKNOWN"}, |
| 2075 }; |
| 2076 |
| 2077 class ExpectStapleErrorCertStatusTest |
| 2078 : public TransportSecurityStateTest, |
| 2079 public testing::WithParamInterface<ExpectStapleErrorCertStatusData> {}; |
| 2080 |
| 2081 // Test that |revocation_status| is serialized into the |cert-status| field of |
| 2082 // the Expect-Staple report whenever |response_status| is PROVIDED and |
| 2083 // |revocation_status| != GOOD. |
| 2084 TEST_P(ExpectStapleErrorCertStatusTest, CheckCertStatusSerialization) { |
| 2085 TransportSecurityState state; |
| 2086 TransportSecurityStateTest::EnableStaticExpectStaple(&state); |
| 2087 MockCertificateReportSender reporter; |
| 2088 ExpectStapleErrorCertStatusData test = GetParam(); |
| 2089 std::string ocsp_response = "dummy_response"; |
| 2090 |
| 2091 // Two dummy certs to use as the server-sent and validated chains. The |
| 2092 // contents don't matter. |
| 2093 scoped_refptr<X509Certificate> cert1 = |
| 2094 ImportCertFromFile(GetTestCertsDirectory(), "test_mail_google_com.pem"); |
| 2095 scoped_refptr<X509Certificate> cert2 = |
| 2096 ImportCertFromFile(GetTestCertsDirectory(), "expired_cert.pem"); |
| 2097 |
| 2098 SSLInfo ssl_info; |
| 2099 ssl_info.cert = cert1; |
| 2100 ssl_info.unverified_cert = cert2; |
| 2101 // |response_status| must be set to PROVIDED for |revocation_status| to have |
| 2102 // meaning. |
| 2103 ssl_info.ocsp_result.response_status = OCSPVerifyResult::PROVIDED; |
| 2104 ssl_info.ocsp_result.revocation_status = test.revocation_status; |
| 2105 |
| 2106 // Certificate chains should only be included when |is_issued_by_known_root| |
| 2107 // is true. |
| 2108 ssl_info.is_issued_by_known_root = true; |
| 2109 ASSERT_NO_FATAL_FAILURE(CheckExpectStapleReport(&state, &reporter, ssl_info, |
| 2110 ocsp_response, "PROVIDED", |
| 2111 test.cert_status_string)); |
| 2112 |
| 2113 // No certificate chains should be included in the report. |
| 2114 ssl_info.is_issued_by_known_root = false; |
| 2115 ASSERT_NO_FATAL_FAILURE(CheckExpectStapleReport(&state, &reporter, ssl_info, |
| 2116 ocsp_response, "PROVIDED", |
| 2117 test.cert_status_string)); |
| 2118 }; |
| 2119 |
| 2120 INSTANTIATE_TEST_CASE_P(ExpectStaple, |
| 2121 ExpectStapleErrorCertStatusTest, |
| 2122 testing::ValuesIn(kExpectStapleErrorCertStatusData)); |
| 2123 |
| 2124 TEST_F(TransportSecurityStateTest, ExpectStapleDoesNotReportValidStaple) { |
| 2125 TransportSecurityState state; |
| 2126 TransportSecurityStateTest::EnableStaticExpectStaple(&state); |
| 2127 MockCertificateReportSender reporter; |
| 2128 state.SetReportSender(&reporter); |
| 2129 |
| 2130 // Baked-in preloaded Expect-Staple test hosts. |
| 2131 HostPortPair host_port(kExpectStapleStaticHostname, 443); |
| 2132 |
| 2133 // Two dummy certs to use as the server-sent and validated chains. The |
| 2134 // contents don't matter. |
| 2135 scoped_refptr<X509Certificate> cert1 = |
| 2136 ImportCertFromFile(GetTestCertsDirectory(), "test_mail_google_com.pem"); |
| 2137 scoped_refptr<X509Certificate> cert2 = |
| 2138 ImportCertFromFile(GetTestCertsDirectory(), "expired_cert.pem"); |
| 2139 |
| 2140 SSLInfo ssl_info; |
| 2141 ssl_info.cert = cert1; |
| 2142 ssl_info.unverified_cert = cert2; |
| 2143 ssl_info.ocsp_result.response_status = OCSPVerifyResult::PROVIDED; |
| 2144 ssl_info.ocsp_result.revocation_status = OCSPRevocationStatus::GOOD; |
| 2145 |
| 2146 std::string ocsp_response = "dummy response"; |
| 2147 |
| 2148 ssl_info.is_issued_by_known_root = true; |
| 2149 state.CheckExpectStaple(host_port, ssl_info, ocsp_response); |
| 2150 EXPECT_EQ(GURL(), reporter.latest_report_uri()); |
| 2151 EXPECT_TRUE(reporter.latest_report().empty()); |
| 2152 |
| 2153 ssl_info.is_issued_by_known_root = false; |
| 2154 state.CheckExpectStaple(host_port, ssl_info, ocsp_response); |
| 2155 EXPECT_EQ(GURL(), reporter.latest_report_uri()); |
| 2156 EXPECT_TRUE(reporter.latest_report().empty()); |
| 2157 } |
| 2158 |
| 2159 TEST_F(TransportSecurityStateTest, ExpectStapleRequiresPreload) { |
| 2160 TransportSecurityState state; |
| 2161 TransportSecurityStateTest::EnableStaticExpectStaple(&state); |
| 2162 MockCertificateReportSender reporter; |
| 2163 state.SetReportSender(&reporter); |
| 2164 |
| 2165 HostPortPair host_port("not-preloaded.host.example", 443); |
| 2166 |
| 2167 // Two dummy certs to use as the server-sent and validated chains. The |
| 2168 // contents don't matter. |
| 2169 scoped_refptr<X509Certificate> cert1 = |
| 2170 ImportCertFromFile(GetTestCertsDirectory(), "test_mail_google_com.pem"); |
| 2171 scoped_refptr<X509Certificate> cert2 = |
| 2172 ImportCertFromFile(GetTestCertsDirectory(), "expired_cert.pem"); |
| 2173 |
| 2174 SSLInfo ssl_info; |
| 2175 ssl_info.cert = cert1; |
| 2176 ssl_info.unverified_cert = cert2; |
| 2177 ssl_info.ocsp_result.response_status = OCSPVerifyResult::MISSING; |
| 2178 |
| 2179 // Empty response |
| 2180 std::string ocsp_response; |
| 2181 |
| 2182 ssl_info.is_issued_by_known_root = true; |
| 2183 state.CheckExpectStaple(host_port, ssl_info, ocsp_response); |
| 2184 EXPECT_EQ(GURL(), reporter.latest_report_uri()); |
| 2185 EXPECT_TRUE(reporter.latest_report().empty()); |
| 2186 |
| 2187 ssl_info.is_issued_by_known_root = false; |
| 2188 state.CheckExpectStaple(host_port, ssl_info, ocsp_response); |
| 2189 EXPECT_EQ(GURL(), reporter.latest_report_uri()); |
| 2190 EXPECT_TRUE(reporter.latest_report().empty()); |
| 2191 } |
| 2192 |
1905 // Tests that TransportSecurityState always consults the RequireCTDelegate, | 2193 // Tests that TransportSecurityState always consults the RequireCTDelegate, |
1906 // if supplied. | 2194 // if supplied. |
1907 TEST_F(TransportSecurityStateTest, RequireCTConsultsDelegate) { | 2195 TEST_F(TransportSecurityStateTest, RequireCTConsultsDelegate) { |
1908 using ::testing::_; | 2196 using ::testing::_; |
1909 using ::testing::Return; | 2197 using ::testing::Return; |
1910 using CTRequirementLevel = | 2198 using CTRequirementLevel = |
1911 TransportSecurityState::RequireCTDelegate::CTRequirementLevel; | 2199 TransportSecurityState::RequireCTDelegate::CTRequirementLevel; |
1912 | 2200 |
1913 // Dummy cert to use as the validate chain. The contents do not matter. | 2201 // Dummy cert to use as the validate chain. The contents do not matter. |
1914 scoped_refptr<X509Certificate> cert = | 2202 scoped_refptr<X509Certificate> cert = |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2029 base::FieldTrialList::CreateFieldTrial("EnforceCTForProblematicRoots", | 2317 base::FieldTrialList::CreateFieldTrial("EnforceCTForProblematicRoots", |
2030 "disabled"); | 2318 "disabled"); |
2031 | 2319 |
2032 EXPECT_FALSE( | 2320 EXPECT_FALSE( |
2033 state.ShouldRequireCT("www.example.com", before_cert.get(), hashes)); | 2321 state.ShouldRequireCT("www.example.com", before_cert.get(), hashes)); |
2034 EXPECT_FALSE( | 2322 EXPECT_FALSE( |
2035 state.ShouldRequireCT("www.example.com", after_cert.get(), hashes)); | 2323 state.ShouldRequireCT("www.example.com", after_cert.get(), hashes)); |
2036 } | 2324 } |
2037 | 2325 |
2038 } // namespace net | 2326 } // namespace net |
OLD | NEW |