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