| 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/base/transport_security_state.h" | 5 #include "net/base/transport_security_state.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <vector> |
| 9 | 10 |
| 10 #include "base/base64.h" | 11 #include "base/base64.h" |
| 11 #include "base/file_path.h" | 12 #include "base/file_path.h" |
| 12 #include "base/sha1.h" | 13 #include "base/sha1.h" |
| 13 #include "base/string_piece.h" | 14 #include "base/string_piece.h" |
| 15 #include "crypto/sha2.h" |
| 14 #include "net/base/asn1_util.h" | 16 #include "net/base/asn1_util.h" |
| 15 #include "net/base/cert_test_util.h" | 17 #include "net/base/cert_test_util.h" |
| 16 #include "net/base/cert_verifier.h" | 18 #include "net/base/cert_verifier.h" |
| 17 #include "net/base/cert_verify_result.h" | 19 #include "net/base/cert_verify_result.h" |
| 18 #include "net/base/net_errors.h" | 20 #include "net/base/net_errors.h" |
| 19 #include "net/base/net_log.h" | 21 #include "net/base/net_log.h" |
| 20 #include "net/base/ssl_info.h" | 22 #include "net/base/ssl_info.h" |
| 21 #include "net/base/test_completion_callback.h" | 23 #include "net/base/test_completion_callback.h" |
| 22 #include "net/base/test_root_certs.h" | 24 #include "net/base/test_root_certs.h" |
| 25 #include "net/base/x509_cert_types.h" |
| 23 #include "net/base/x509_certificate.h" | 26 #include "net/base/x509_certificate.h" |
| 24 #include "net/http/http_util.h" | 27 #include "net/http/http_util.h" |
| 25 #include "testing/gtest/include/gtest/gtest.h" | 28 #include "testing/gtest/include/gtest/gtest.h" |
| 26 | 29 |
| 27 #if defined(USE_OPENSSL) | 30 #if defined(USE_OPENSSL) |
| 28 #include "crypto/openssl_util.h" | 31 #include "crypto/openssl_util.h" |
| 29 #else | 32 #else |
| 30 #include "crypto/nss_util.h" | 33 #include "crypto/nss_util.h" |
| 31 #endif | 34 #endif |
| 32 | 35 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 84 EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=34889 includesubdomains")); | 87 EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=34889 includesubdomains")); |
| 85 | 88 |
| 86 // Check that |state| was not updated by expecting the default | 89 // Check that |state| was not updated by expecting the default |
| 87 // values for its predictable fields. | 90 // values for its predictable fields. |
| 88 EXPECT_EQ(state.upgrade_mode, | 91 EXPECT_EQ(state.upgrade_mode, |
| 89 TransportSecurityState::DomainState::MODE_FORCE_HTTPS); | 92 TransportSecurityState::DomainState::MODE_FORCE_HTTPS); |
| 90 EXPECT_FALSE(state.include_subdomains); | 93 EXPECT_FALSE(state.include_subdomains); |
| 91 } | 94 } |
| 92 | 95 |
| 93 static bool GetPublicKeyHash(const net::X509Certificate::OSCertHandle& cert, | 96 static bool GetPublicKeyHash(const net::X509Certificate::OSCertHandle& cert, |
| 94 SHA1Fingerprint* fingerprint) { | 97 HashValue* fingerprint, |
| 98 HashValueTag tag) { |
| 95 std::string der_bytes; | 99 std::string der_bytes; |
| 96 if (!net::X509Certificate::GetDEREncoded(cert, &der_bytes)) | 100 if (!net::X509Certificate::GetDEREncoded(cert, &der_bytes)) |
| 97 return false; | 101 return false; |
| 98 | 102 |
| 99 base::StringPiece spki; | 103 base::StringPiece spki; |
| 100 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki)) | 104 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki)) |
| 101 return false; | 105 return false; |
| 102 | 106 |
| 103 base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(spki.data()), | 107 fingerprint->tag = tag; |
| 104 spki.size(), fingerprint->data); | 108 switch (tag) { |
| 109 case HASH_VALUE_SHA1: |
| 110 base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(spki.data()), |
| 111 spki.size(), fingerprint->data()); |
| 112 break; |
| 113 case HASH_VALUE_SHA256: |
| 114 crypto::SHA256HashString(spki, fingerprint->data(), |
| 115 crypto::kSHA256Length); |
| 116 break; |
| 117 default: |
| 118 NOTREACHED() << "Unknown HashValueTag " << tag; |
| 119 } |
| 120 |
| 105 return true; | 121 return true; |
| 106 } | 122 } |
| 107 | 123 |
| 108 static std::string GetPinFromCert(X509Certificate* cert) { | 124 static std::string GetPinFromCert(X509Certificate* cert, HashValueTag tag) { |
| 109 SHA1Fingerprint spki_hash; | 125 HashValue spki_hash; |
| 110 EXPECT_TRUE(GetPublicKeyHash(cert->os_cert_handle(), &spki_hash)); | 126 EXPECT_TRUE(GetPublicKeyHash(cert->os_cert_handle(), &spki_hash, tag)); |
| 111 | 127 |
| 112 std::string base64; | 128 std::string base64; |
| 113 base::Base64Encode(base::StringPiece(reinterpret_cast<char*>(spki_hash.data), | 129 base::Base64Encode(base::StringPiece( |
| 114 sizeof(spki_hash.data)), | 130 reinterpret_cast<char*>(spki_hash.data()), spki_hash.size()), &base64); |
| 115 &base64); | 131 |
| 116 return "pin-sha1=" + HttpUtil::Quote(base64); | 132 std::string label; |
| 133 switch (tag) { |
| 134 case HASH_VALUE_SHA1: |
| 135 label = "pin-sha1="; |
| 136 break; |
| 137 case HASH_VALUE_SHA256: |
| 138 label = "pin-sha256="; |
| 139 break; |
| 140 default: |
| 141 NOTREACHED() << "Unknown HashValueTag " << tag; |
| 142 } |
| 143 |
| 144 return label + HttpUtil::Quote(base64); |
| 117 } | 145 } |
| 118 | 146 |
| 119 TEST_F(TransportSecurityStateTest, BogusPinsHeaders) { | 147 static void TestBogusPinsHeaders(HashValueTag tag) { |
| 120 TransportSecurityState::DomainState state; | 148 TransportSecurityState::DomainState state; |
| 121 SSLInfo ssl_info; | 149 SSLInfo ssl_info; |
| 122 ssl_info.cert = | 150 ssl_info.cert = |
| 123 ImportCertFromFile(GetTestCertsDirectory(), "test_mail_google_com.pem"); | 151 ImportCertFromFile(GetTestCertsDirectory(), "test_mail_google_com.pem"); |
| 124 std::string good_pin = GetPinFromCert(ssl_info.cert); | 152 std::string good_pin = GetPinFromCert(ssl_info.cert, tag); |
| 125 base::Time now = base::Time::Now(); | 153 base::Time now = base::Time::Now(); |
| 126 | 154 |
| 127 // The backup pin is fake --- it just has to not be in the chain. | 155 // The backup pin is fake --- it just has to not be in the chain. |
| 128 std::string backup_pin = "pin-sha1=" + | 156 std::string backup_pin = "pin-sha1=" + |
| 129 HttpUtil::Quote("6dcfXufJLW3J6S/9rRe4vUlBj5g="); | 157 HttpUtil::Quote("6dcfXufJLW3J6S/9rRe4vUlBj5g="); |
| 130 | 158 |
| 131 EXPECT_FALSE(state.ParsePinsHeader(now, "", ssl_info)); | 159 EXPECT_FALSE(state.ParsePinsHeader(now, "", ssl_info)); |
| 132 EXPECT_FALSE(state.ParsePinsHeader(now, " ", ssl_info)); | 160 EXPECT_FALSE(state.ParsePinsHeader(now, " ", ssl_info)); |
| 133 EXPECT_FALSE(state.ParsePinsHeader(now, "abc", ssl_info)); | 161 EXPECT_FALSE(state.ParsePinsHeader(now, "abc", ssl_info)); |
| 134 EXPECT_FALSE(state.ParsePinsHeader(now, " abc", ssl_info)); | 162 EXPECT_FALSE(state.ParsePinsHeader(now, " abc", ssl_info)); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 173 ssl_info)); | 201 ssl_info)); |
| 174 EXPECT_FALSE(state.ParsePinsHeader(now, "max-age=34889.23", ssl_info)); | 202 EXPECT_FALSE(state.ParsePinsHeader(now, "max-age=34889.23", ssl_info)); |
| 175 | 203 |
| 176 // Check that |state| was not updated by expecting the default | 204 // Check that |state| was not updated by expecting the default |
| 177 // values for its predictable fields. | 205 // values for its predictable fields. |
| 178 EXPECT_EQ(state.upgrade_mode, | 206 EXPECT_EQ(state.upgrade_mode, |
| 179 TransportSecurityState::DomainState::MODE_FORCE_HTTPS); | 207 TransportSecurityState::DomainState::MODE_FORCE_HTTPS); |
| 180 EXPECT_FALSE(state.include_subdomains); | 208 EXPECT_FALSE(state.include_subdomains); |
| 181 } | 209 } |
| 182 | 210 |
| 211 TEST_F(TransportSecurityStateTest, BogusPinsHeadersSHA1) { |
| 212 TestBogusPinsHeaders(HASH_VALUE_SHA1); |
| 213 } |
| 214 |
| 215 TEST_F(TransportSecurityStateTest, BogusPinsHeadersSHA256) { |
| 216 TestBogusPinsHeaders(HASH_VALUE_SHA256); |
| 217 } |
| 218 |
| 183 TEST_F(TransportSecurityStateTest, ValidSTSHeaders) { | 219 TEST_F(TransportSecurityStateTest, ValidSTSHeaders) { |
| 184 TransportSecurityState::DomainState state; | 220 TransportSecurityState::DomainState state; |
| 185 base::Time expiry; | 221 base::Time expiry; |
| 186 base::Time now = base::Time::Now(); | 222 base::Time now = base::Time::Now(); |
| 187 | 223 |
| 188 EXPECT_TRUE(state.ParseSTSHeader(now, "max-age=243")); | 224 EXPECT_TRUE(state.ParseSTSHeader(now, "max-age=243")); |
| 189 expiry = now + base::TimeDelta::FromSeconds(243); | 225 expiry = now + base::TimeDelta::FromSeconds(243); |
| 190 EXPECT_EQ(expiry, state.upgrade_expiry); | 226 EXPECT_EQ(expiry, state.upgrade_expiry); |
| 191 EXPECT_FALSE(state.include_subdomains); | 227 EXPECT_FALSE(state.include_subdomains); |
| 192 | 228 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 233 EXPECT_TRUE(state.ParseSTSHeader( | 269 EXPECT_TRUE(state.ParseSTSHeader( |
| 234 now, | 270 now, |
| 235 " max-age=999999999999999999999999999999999999999999999 ;" | 271 " max-age=999999999999999999999999999999999999999999999 ;" |
| 236 " incLudesUbdOmains ")); | 272 " incLudesUbdOmains ")); |
| 237 expiry = now + base::TimeDelta::FromSeconds( | 273 expiry = now + base::TimeDelta::FromSeconds( |
| 238 TransportSecurityState::kMaxHSTSAgeSecs); | 274 TransportSecurityState::kMaxHSTSAgeSecs); |
| 239 EXPECT_EQ(expiry, state.upgrade_expiry); | 275 EXPECT_EQ(expiry, state.upgrade_expiry); |
| 240 EXPECT_TRUE(state.include_subdomains); | 276 EXPECT_TRUE(state.include_subdomains); |
| 241 } | 277 } |
| 242 | 278 |
| 243 TEST_F(TransportSecurityStateTest, ValidPinsHeaders) { | 279 static void TestValidPinsHeaders(HashValueTag tag) { |
| 244 TransportSecurityState::DomainState state; | 280 TransportSecurityState::DomainState state; |
| 245 base::Time expiry; | 281 base::Time expiry; |
| 246 base::Time now = base::Time::Now(); | 282 base::Time now = base::Time::Now(); |
| 247 | 283 |
| 248 // Set up a realistic SSLInfo with a realistic cert chain. | 284 // Set up a realistic SSLInfo with a realistic cert chain. |
| 249 FilePath certs_dir = GetTestCertsDirectory(); | 285 FilePath certs_dir = GetTestCertsDirectory(); |
| 250 scoped_refptr<X509Certificate> ee_cert = | 286 scoped_refptr<X509Certificate> ee_cert = |
| 251 ImportCertFromFile(certs_dir, "2048-rsa-ee-by-2048-rsa-intermediate.pem"); | 287 ImportCertFromFile(certs_dir, "2048-rsa-ee-by-2048-rsa-intermediate.pem"); |
| 252 ASSERT_NE(static_cast<X509Certificate*>(NULL), ee_cert); | 288 ASSERT_NE(static_cast<X509Certificate*>(NULL), ee_cert); |
| 253 scoped_refptr<X509Certificate> intermediate = | 289 scoped_refptr<X509Certificate> intermediate = |
| (...skipping 19 matching lines...) Expand all Loading... |
| 273 scoped_ptr<CertVerifier> verifier(CertVerifier::CreateDefault()); | 309 scoped_ptr<CertVerifier> verifier(CertVerifier::CreateDefault()); |
| 274 TestCompletionCallback callback; | 310 TestCompletionCallback callback; |
| 275 CertVerifier::RequestHandle handle = NULL; | 311 CertVerifier::RequestHandle handle = NULL; |
| 276 rv = verifier->Verify(ssl_info.cert, "127.0.0.1", 0, NULL, &result, | 312 rv = verifier->Verify(ssl_info.cert, "127.0.0.1", 0, NULL, &result, |
| 277 callback.callback(), &handle, BoundNetLog()); | 313 callback.callback(), &handle, BoundNetLog()); |
| 278 rv = callback.GetResult(rv); | 314 rv = callback.GetResult(rv); |
| 279 ASSERT_EQ(OK, rv); | 315 ASSERT_EQ(OK, rv); |
| 280 // Normally, ssl_client_socket_nss would do this, but for a unit test we | 316 // Normally, ssl_client_socket_nss would do this, but for a unit test we |
| 281 // fake it. | 317 // fake it. |
| 282 ssl_info.public_key_hashes = result.public_key_hashes; | 318 ssl_info.public_key_hashes = result.public_key_hashes; |
| 283 std::string good_pin = GetPinFromCert(ssl_info.cert); | 319 std::string good_pin = GetPinFromCert(ssl_info.cert, /*tag*/HASH_VALUE_SHA1); |
| 320 DLOG(WARNING) << "good pin: " << good_pin; |
| 284 | 321 |
| 285 // The backup pin is fake --- we just need an SPKI hash that does not match | 322 // The backup pin is fake --- we just need an SPKI hash that does not match |
| 286 // the hash of any SPKI in the certificate chain. | 323 // the hash of any SPKI in the certificate chain. |
| 287 std::string backup_pin = "pin-sha1=" + | 324 std::string backup_pin = "pin-sha1=" + |
| 288 HttpUtil::Quote("6dcfXufJLW3J6S/9rRe4vUlBj5g="); | 325 HttpUtil::Quote("6dcfXufJLW3J6S/9rRe4vUlBj5g="); |
| 289 | 326 |
| 290 EXPECT_TRUE(state.ParsePinsHeader( | 327 EXPECT_TRUE(state.ParsePinsHeader( |
| 291 now, | 328 now, |
| 292 "max-age=243; " + good_pin + ";" + backup_pin, | 329 "max-age=243; " + good_pin + ";" + backup_pin, |
| 293 ssl_info)); | 330 ssl_info)); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 349 EXPECT_TRUE(state.ParsePinsHeader( | 386 EXPECT_TRUE(state.ParsePinsHeader( |
| 350 now, | 387 now, |
| 351 " max-age=999999999999999999999999999999999999999999999 ; " + | 388 " max-age=999999999999999999999999999999999999999999999 ; " + |
| 352 backup_pin + ";" + good_pin + "; ", | 389 backup_pin + ";" + good_pin + "; ", |
| 353 ssl_info)); | 390 ssl_info)); |
| 354 expiry = now + | 391 expiry = now + |
| 355 base::TimeDelta::FromSeconds(TransportSecurityState::kMaxHSTSAgeSecs); | 392 base::TimeDelta::FromSeconds(TransportSecurityState::kMaxHSTSAgeSecs); |
| 356 EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); | 393 EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); |
| 357 } | 394 } |
| 358 | 395 |
| 396 TEST_F(TransportSecurityStateTest, ValidPinsHeadersSHA1) { |
| 397 TestValidPinsHeaders(HASH_VALUE_SHA1); |
| 398 } |
| 399 |
| 400 TEST_F(TransportSecurityStateTest, ValidPinsHeadersSHA256) { |
| 401 TestValidPinsHeaders(HASH_VALUE_SHA256); |
| 402 } |
| 403 |
| 359 TEST_F(TransportSecurityStateTest, SimpleMatches) { | 404 TEST_F(TransportSecurityStateTest, SimpleMatches) { |
| 360 TransportSecurityState state; | 405 TransportSecurityState state; |
| 361 TransportSecurityState::DomainState domain_state; | 406 TransportSecurityState::DomainState domain_state; |
| 362 const base::Time current_time(base::Time::Now()); | 407 const base::Time current_time(base::Time::Now()); |
| 363 const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); | 408 const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); |
| 364 | 409 |
| 365 EXPECT_FALSE(state.GetDomainState("yahoo.com", true, &domain_state)); | 410 EXPECT_FALSE(state.GetDomainState("yahoo.com", true, &domain_state)); |
| 366 domain_state.upgrade_expiry = expiry; | 411 domain_state.upgrade_expiry = expiry; |
| 367 state.EnableHost("yahoo.com", domain_state); | 412 state.EnableHost("yahoo.com", domain_state); |
| 368 EXPECT_TRUE(state.GetDomainState("yahoo.com", true, &domain_state)); | 413 EXPECT_TRUE(state.GetDomainState("yahoo.com", true, &domain_state)); |
| (...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 776 EXPECT_FALSE(state.GetDomainState(kLongName, true, &domain_state)); | 821 EXPECT_FALSE(state.GetDomainState(kLongName, true, &domain_state)); |
| 777 } | 822 } |
| 778 | 823 |
| 779 TEST_F(TransportSecurityStateTest, BuiltinCertPins) { | 824 TEST_F(TransportSecurityStateTest, BuiltinCertPins) { |
| 780 TransportSecurityState state; | 825 TransportSecurityState state; |
| 781 TransportSecurityState::DomainState domain_state; | 826 TransportSecurityState::DomainState domain_state; |
| 782 | 827 |
| 783 EXPECT_TRUE(state.GetDomainState("chrome.google.com", true, &domain_state)); | 828 EXPECT_TRUE(state.GetDomainState("chrome.google.com", true, &domain_state)); |
| 784 EXPECT_TRUE(HasPins("chrome.google.com")); | 829 EXPECT_TRUE(HasPins("chrome.google.com")); |
| 785 | 830 |
| 786 FingerprintVector hashes; | 831 HashValueVector hashes; |
| 787 // Checks that a built-in list does exist. | 832 // Checks that a built-in list does exist. |
| 788 EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(hashes)); | 833 EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(hashes)); |
| 789 EXPECT_FALSE(HasPins("www.paypal.com")); | 834 EXPECT_FALSE(HasPins("www.paypal.com")); |
| 790 | 835 |
| 791 EXPECT_TRUE(HasPins("docs.google.com")); | 836 EXPECT_TRUE(HasPins("docs.google.com")); |
| 792 EXPECT_TRUE(HasPins("1.docs.google.com")); | 837 EXPECT_TRUE(HasPins("1.docs.google.com")); |
| 793 EXPECT_TRUE(HasPins("sites.google.com")); | 838 EXPECT_TRUE(HasPins("sites.google.com")); |
| 794 EXPECT_TRUE(HasPins("drive.google.com")); | 839 EXPECT_TRUE(HasPins("drive.google.com")); |
| 795 EXPECT_TRUE(HasPins("spreadsheets.google.com")); | 840 EXPECT_TRUE(HasPins("spreadsheets.google.com")); |
| 796 EXPECT_TRUE(HasPins("health.google.com")); | 841 EXPECT_TRUE(HasPins("health.google.com")); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 822 EXPECT_TRUE(HasPins("oauth.twitter.com")); | 867 EXPECT_TRUE(HasPins("oauth.twitter.com")); |
| 823 EXPECT_TRUE(HasPins("mobile.twitter.com")); | 868 EXPECT_TRUE(HasPins("mobile.twitter.com")); |
| 824 EXPECT_TRUE(HasPins("dev.twitter.com")); | 869 EXPECT_TRUE(HasPins("dev.twitter.com")); |
| 825 EXPECT_TRUE(HasPins("business.twitter.com")); | 870 EXPECT_TRUE(HasPins("business.twitter.com")); |
| 826 EXPECT_TRUE(HasPins("platform.twitter.com")); | 871 EXPECT_TRUE(HasPins("platform.twitter.com")); |
| 827 EXPECT_TRUE(HasPins("si0.twimg.com")); | 872 EXPECT_TRUE(HasPins("si0.twimg.com")); |
| 828 EXPECT_TRUE(HasPins("twimg0-a.akamaihd.net")); | 873 EXPECT_TRUE(HasPins("twimg0-a.akamaihd.net")); |
| 829 } | 874 } |
| 830 | 875 |
| 831 static bool AddHash(const std::string& type_and_base64, | 876 static bool AddHash(const std::string& type_and_base64, |
| 832 FingerprintVector* out) { | 877 HashValueVector* out) { |
| 833 std::string hash_str; | 878 HashValue hash; |
| 834 if (type_and_base64.find("sha1/") == 0 && | 879 |
| 835 base::Base64Decode(type_and_base64.substr(5, type_and_base64.size() - 5), | 880 if (!TransportSecurityState::ParsePin(type_and_base64, &hash)) |
| 836 &hash_str) && | 881 return false; |
| 837 hash_str.size() == base::kSHA1Length) { | 882 |
| 838 SHA1Fingerprint hash; | 883 out->push_back(hash); |
| 839 memcpy(hash.data, hash_str.data(), sizeof(hash.data)); | 884 return true; |
| 840 out->push_back(hash); | |
| 841 return true; | |
| 842 } | |
| 843 return false; | |
| 844 } | 885 } |
| 845 | 886 |
| 846 TEST_F(TransportSecurityStateTest, PinValidationWithRejectedCerts) { | 887 TEST_F(TransportSecurityStateTest, PinValidationWithRejectedCerts) { |
| 847 // kGoodPath is plus.google.com via Google Internet Authority. | 888 // kGoodPath is plus.google.com via Google Internet Authority. |
| 848 static const char* kGoodPath[] = { | 889 static const char* kGoodPath[] = { |
| 849 "sha1/4BjDjn8v2lWeUFQnqSs0BgbIcrU=", | 890 "sha1/4BjDjn8v2lWeUFQnqSs0BgbIcrU=", |
| 850 "sha1/QMVAHW+MuvCLAO3vse6H0AWzuc0=", | 891 "sha1/QMVAHW+MuvCLAO3vse6H0AWzuc0=", |
| 851 "sha1/SOZo+SvSspXXR9gjIBBPM5iQn9Q=", | 892 "sha1/SOZo+SvSspXXR9gjIBBPM5iQn9Q=", |
| 852 NULL, | 893 NULL, |
| 853 }; | 894 }; |
| 854 | 895 |
| 855 // kBadPath is plus.google.com via Trustcenter, which contains a required | 896 // kBadPath is plus.google.com via Trustcenter, which contains a required |
| 856 // certificate (Equifax root), but also an excluded certificate | 897 // certificate (Equifax root), but also an excluded certificate |
| 857 // (Trustcenter). | 898 // (Trustcenter). |
| 858 static const char* kBadPath[] = { | 899 static const char* kBadPath[] = { |
| 859 "sha1/4BjDjn8v2lWeUFQnqSs0BgbIcrU=", | 900 "sha1/4BjDjn8v2lWeUFQnqSs0BgbIcrU=", |
| 860 "sha1/gzuEEAB/bkqdQS3EIjk2by7lW+k=", | 901 "sha1/gzuEEAB/bkqdQS3EIjk2by7lW+k=", |
| 861 "sha1/SOZo+SvSspXXR9gjIBBPM5iQn9Q=", | 902 "sha1/SOZo+SvSspXXR9gjIBBPM5iQn9Q=", |
| 862 NULL, | 903 NULL, |
| 863 }; | 904 }; |
| 864 | 905 |
| 865 std::vector<net::SHA1Fingerprint> good_hashes, bad_hashes; | 906 HashValueVector good_hashes, bad_hashes; |
| 866 | 907 |
| 867 for (size_t i = 0; kGoodPath[i]; i++) { | 908 for (size_t i = 0; kGoodPath[i]; i++) { |
| 868 EXPECT_TRUE(AddHash(kGoodPath[i], &good_hashes)); | 909 EXPECT_TRUE(AddHash(kGoodPath[i], &good_hashes)); |
| 869 } | 910 } |
| 870 for (size_t i = 0; kBadPath[i]; i++) { | 911 for (size_t i = 0; kBadPath[i]; i++) { |
| 871 EXPECT_TRUE(AddHash(kBadPath[i], &bad_hashes)); | 912 EXPECT_TRUE(AddHash(kBadPath[i], &bad_hashes)); |
| 872 } | 913 } |
| 873 | 914 |
| 874 TransportSecurityState state; | 915 TransportSecurityState state; |
| 875 TransportSecurityState::DomainState domain_state; | 916 TransportSecurityState::DomainState domain_state; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 891 | 932 |
| 892 // kBadPath is plus.google.com via Trustcenter, which is utterly wrong for | 933 // kBadPath is plus.google.com via Trustcenter, which is utterly wrong for |
| 893 // torproject.org. | 934 // torproject.org. |
| 894 static const char* kBadPath[] = { | 935 static const char* kBadPath[] = { |
| 895 "sha1/4BjDjn8v2lWeUFQnqSs0BgbIcrU=", | 936 "sha1/4BjDjn8v2lWeUFQnqSs0BgbIcrU=", |
| 896 "sha1/gzuEEAB/bkqdQS3EIjk2by7lW+k=", | 937 "sha1/gzuEEAB/bkqdQS3EIjk2by7lW+k=", |
| 897 "sha1/SOZo+SvSspXXR9gjIBBPM5iQn9Q=", | 938 "sha1/SOZo+SvSspXXR9gjIBBPM5iQn9Q=", |
| 898 NULL, | 939 NULL, |
| 899 }; | 940 }; |
| 900 | 941 |
| 901 std::vector<net::SHA1Fingerprint> good_hashes, bad_hashes; | 942 HashValueVector good_hashes, bad_hashes; |
| 902 | 943 |
| 903 for (size_t i = 0; kGoodPath[i]; i++) { | 944 for (size_t i = 0; kGoodPath[i]; i++) { |
| 904 EXPECT_TRUE(AddHash(kGoodPath[i], &good_hashes)); | 945 EXPECT_TRUE(AddHash(kGoodPath[i], &good_hashes)); |
| 905 } | 946 } |
| 906 for (size_t i = 0; kBadPath[i]; i++) { | 947 for (size_t i = 0; kBadPath[i]; i++) { |
| 907 EXPECT_TRUE(AddHash(kBadPath[i], &bad_hashes)); | 948 EXPECT_TRUE(AddHash(kBadPath[i], &bad_hashes)); |
| 908 } | 949 } |
| 909 | 950 |
| 910 TransportSecurityState state; | 951 TransportSecurityState state; |
| 911 TransportSecurityState::DomainState domain_state; | 952 TransportSecurityState::DomainState domain_state; |
| 912 EXPECT_TRUE(state.GetDomainState("blog.torproject.org", true, &domain_state)); | 953 EXPECT_TRUE(state.GetDomainState("blog.torproject.org", true, &domain_state)); |
| 913 EXPECT_TRUE(domain_state.HasPins()); | 954 EXPECT_TRUE(domain_state.HasPins()); |
| 914 | 955 |
| 915 EXPECT_TRUE(domain_state.IsChainOfPublicKeysPermitted(good_hashes)); | 956 EXPECT_TRUE(domain_state.IsChainOfPublicKeysPermitted(good_hashes)); |
| 916 EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(bad_hashes)); | 957 EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(bad_hashes)); |
| 917 } | 958 } |
| 918 | 959 |
| 960 TEST_F(TransportSecurityStateTest, PinValidationWithRejectedCertsMixedHashes) { |
| 961 static const char* ee_sha1 = "sha1/4BjDjn8v2lWeUFQnqSs0BgbIcrU="; |
| 962 static const char* ee_sha256 = |
| 963 "sha256/sRJBQqWhpaKIGcc1NA7/jJ4vgWj+47oYfyU7waOS1+I="; |
| 964 static const char* google_1024_sha1 = "sha1/QMVAHW+MuvCLAO3vse6H0AWzuc0="; |
| 965 static const char* google_1024_sha256 = |
| 966 "sha256/trlUMquuV/4CDLK3T0+fkXPIxwivyecyrOIyeQR8bQU="; |
| 967 static const char* equifax_sha1 = "sha1/SOZo+SvSspXXR9gjIBBPM5iQn9Q="; |
| 968 static const char* equifax_sha256 = |
| 969 "sha256//1aAzXOlcD2gSBegdf1GJQanNQbEuBoVg+9UlHjSZHY="; |
| 970 static const char* trustcenter_sha1 = "sha1/gzuEEAB/bkqdQS3EIjk2by7lW+k="; |
| 971 static const char* trustcenter_sha256 = |
| 972 "sha256/Dq58KIA4NMLsboWMLU8/aTREzaAGEFW+EtUule8dd/M="; |
| 973 |
| 974 // Good chains for plus.google.com chain up through google_1024_sha{1,256} |
| 975 // to equifax_sha{1,256}. Bad chains chain up to equifa through |
| 976 // trustcenter_sha{1,256}, which is a blacklisted key. Even though Equifax |
| 977 // and Google1024 are known-good, the blacklistedness of Trustcenter |
| 978 // should override and cause pin validation failure. |
| 979 |
| 980 TransportSecurityState state; |
| 981 TransportSecurityState::DomainState domain_state; |
| 982 EXPECT_TRUE(state.GetDomainState("plus.google.com", true, &domain_state)); |
| 983 EXPECT_TRUE(domain_state.HasPins()); |
| 984 |
| 985 // The statically-defined pins are all SHA-1, so we add some SHA-256 pins |
| 986 // manually: |
| 987 EXPECT_TRUE(AddHash(google_1024_sha256, &domain_state.static_spki_hashes)); |
| 988 EXPECT_TRUE(AddHash(trustcenter_sha256, |
| 989 &domain_state.bad_static_spki_hashes)); |
| 990 |
| 991 // Try an all-good SHA1 chain. |
| 992 HashValueVector validated_chain; |
| 993 EXPECT_TRUE(AddHash(ee_sha1, &validated_chain)); |
| 994 EXPECT_TRUE(AddHash(google_1024_sha1, &validated_chain)); |
| 995 EXPECT_TRUE(AddHash(equifax_sha1, &validated_chain)); |
| 996 EXPECT_TRUE(domain_state.IsChainOfPublicKeysPermitted(validated_chain)); |
| 997 |
| 998 // Try an all-bad SHA1 chain. |
| 999 validated_chain.clear(); |
| 1000 EXPECT_TRUE(AddHash(ee_sha1, &validated_chain)); |
| 1001 EXPECT_TRUE(AddHash(trustcenter_sha1, &validated_chain)); |
| 1002 EXPECT_TRUE(AddHash(equifax_sha1, &validated_chain)); |
| 1003 EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(validated_chain)); |
| 1004 |
| 1005 // Try an all-good SHA-256 chain. |
| 1006 validated_chain.clear(); |
| 1007 EXPECT_TRUE(AddHash(ee_sha256, &validated_chain)); |
| 1008 EXPECT_TRUE(AddHash(google_1024_sha256, &validated_chain)); |
| 1009 EXPECT_TRUE(AddHash(equifax_sha256, &validated_chain)); |
| 1010 EXPECT_TRUE(domain_state.IsChainOfPublicKeysPermitted(validated_chain)); |
| 1011 |
| 1012 // Try an all-bad SHA-256 chain. |
| 1013 validated_chain.clear(); |
| 1014 EXPECT_TRUE(AddHash(ee_sha256, &validated_chain)); |
| 1015 EXPECT_TRUE(AddHash(trustcenter_sha256, &validated_chain)); |
| 1016 EXPECT_TRUE(AddHash(equifax_sha256, &validated_chain)); |
| 1017 EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(validated_chain)); |
| 1018 |
| 1019 // Try a mixed-hash good chain. |
| 1020 validated_chain.clear(); |
| 1021 EXPECT_TRUE(AddHash(ee_sha256, &validated_chain)); |
| 1022 EXPECT_TRUE(AddHash(google_1024_sha1, &validated_chain)); |
| 1023 EXPECT_TRUE(AddHash(equifax_sha256, &validated_chain)); |
| 1024 EXPECT_TRUE(domain_state.IsChainOfPublicKeysPermitted(validated_chain)); |
| 1025 |
| 1026 // Try a mixed-hash bad chain. |
| 1027 validated_chain.clear(); |
| 1028 EXPECT_TRUE(AddHash(ee_sha1, &validated_chain)); |
| 1029 EXPECT_TRUE(AddHash(trustcenter_sha256, &validated_chain)); |
| 1030 EXPECT_TRUE(AddHash(equifax_sha1, &validated_chain)); |
| 1031 EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(validated_chain)); |
| 1032 |
| 1033 // Try a chain with all good hashes. |
| 1034 validated_chain.clear(); |
| 1035 EXPECT_TRUE(AddHash(ee_sha1, &validated_chain)); |
| 1036 EXPECT_TRUE(AddHash(google_1024_sha1, &validated_chain)); |
| 1037 EXPECT_TRUE(AddHash(equifax_sha1, &validated_chain)); |
| 1038 EXPECT_TRUE(AddHash(ee_sha256, &validated_chain)); |
| 1039 EXPECT_TRUE(AddHash(google_1024_sha256, &validated_chain)); |
| 1040 EXPECT_TRUE(AddHash(equifax_sha256, &validated_chain)); |
| 1041 EXPECT_TRUE(domain_state.IsChainOfPublicKeysPermitted(validated_chain)); |
| 1042 |
| 1043 // Try a chain with all bad hashes. |
| 1044 validated_chain.clear(); |
| 1045 EXPECT_TRUE(AddHash(ee_sha1, &validated_chain)); |
| 1046 EXPECT_TRUE(AddHash(trustcenter_sha1, &validated_chain)); |
| 1047 EXPECT_TRUE(AddHash(equifax_sha1, &validated_chain)); |
| 1048 EXPECT_TRUE(AddHash(ee_sha256, &validated_chain)); |
| 1049 EXPECT_TRUE(AddHash(trustcenter_sha256, &validated_chain)); |
| 1050 EXPECT_TRUE(AddHash(equifax_sha256, &validated_chain)); |
| 1051 EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(validated_chain)); |
| 1052 } |
| 1053 |
| 919 TEST_F(TransportSecurityStateTest, OptionalHSTSCertPins) { | 1054 TEST_F(TransportSecurityStateTest, OptionalHSTSCertPins) { |
| 920 TransportSecurityState state; | 1055 TransportSecurityState state; |
| 921 TransportSecurityState::DomainState domain_state; | 1056 TransportSecurityState::DomainState domain_state; |
| 922 | 1057 |
| 923 EXPECT_FALSE(ShouldRedirect("www.google-analytics.com")); | 1058 EXPECT_FALSE(ShouldRedirect("www.google-analytics.com")); |
| 924 | 1059 |
| 925 EXPECT_FALSE(HasPins("www.google-analytics.com", false)); | 1060 EXPECT_FALSE(HasPins("www.google-analytics.com", false)); |
| 926 EXPECT_TRUE(HasPins("www.google-analytics.com")); | 1061 EXPECT_TRUE(HasPins("www.google-analytics.com")); |
| 927 EXPECT_TRUE(HasPins("google.com")); | 1062 EXPECT_TRUE(HasPins("google.com")); |
| 928 EXPECT_TRUE(HasPins("www.google.com")); | 1063 EXPECT_TRUE(HasPins("www.google.com")); |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1048 // Expect to fail for SNI hosts when not searching the SNI list: | 1183 // Expect to fail for SNI hosts when not searching the SNI list: |
| 1049 EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty( | 1184 EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty( |
| 1050 "gmail.com", false)); | 1185 "gmail.com", false)); |
| 1051 EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty( | 1186 EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty( |
| 1052 "googlegroups.com", false)); | 1187 "googlegroups.com", false)); |
| 1053 EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty( | 1188 EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty( |
| 1054 "www.googlegroups.com", false)); | 1189 "www.googlegroups.com", false)); |
| 1055 } | 1190 } |
| 1056 | 1191 |
| 1057 } // namespace net | 1192 } // namespace net |
| OLD | NEW |