|  | // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "net/base/transport_security_state.h" | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <string> | 
|  | #include <vector> | 
|  |  | 
|  | #include "base/base64.h" | 
|  | #include "base/file_path.h" | 
|  | #include "base/sha1.h" | 
|  | #include "base/string_piece.h" | 
|  | #include "crypto/sha2.h" | 
|  | #include "net/base/asn1_util.h" | 
|  | #include "net/base/cert_test_util.h" | 
|  | #include "net/base/cert_verifier.h" | 
|  | #include "net/base/cert_verify_result.h" | 
|  | #include "net/base/net_errors.h" | 
|  | #include "net/base/net_log.h" | 
|  | #include "net/base/ssl_info.h" | 
|  | #include "net/base/test_completion_callback.h" | 
|  | #include "net/base/test_data_directory.h" | 
|  | #include "net/base/test_root_certs.h" | 
|  | #include "net/base/x509_cert_types.h" | 
|  | #include "net/base/x509_certificate.h" | 
|  | #include "net/http/http_util.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | #if defined(USE_OPENSSL) | 
|  | #include "crypto/openssl_util.h" | 
|  | #else | 
|  | #include "crypto/nss_util.h" | 
|  | #endif | 
|  |  | 
|  | #if defined(__LB_SHELL__) | 
|  | // We don't support cert pinning, so it's not compiled in. | 
|  | // Disable all tests related to cert pins. | 
|  | #define MAYBE_IsPreloaded DISABLED_IsPreloaded | 
|  | #define MAYBE_PreloadedDomainSet DISABLED_PreloadedDomainSet | 
|  | #define MAYBE_Preloaded DISABLED_Preloaded | 
|  | #define MAYBE_BuiltinCertPins DISABLED_BuiltinCertPins | 
|  | #define MAYBE_PinValidationWithRejectedCerts DISABLED_PinValidationWithRejectedCerts | 
|  | #define MAYBE_PinValidationWithoutRejectedCerts DISABLED_PinValidationWithoutRejectedCerts | 
|  | #define MAYBE_PinValidationWithRejectedCertsMixedHashes DISABLED_PinValidationWithRejectedCertsMixedHashes | 
|  | #define MAYBE_OptionalHSTSCertPins DISABLED_OptionalHSTSCertPins | 
|  | #define MAYBE_OverrideBuiltins DISABLED_OverrideBuiltins | 
|  | #define MAYBE_GooglePinnedProperties DISABLED_GooglePinnedProperties | 
|  | #else | 
|  | #define MAYBE_IsPreloaded IsPreloaded | 
|  | #define MAYBE_PreloadedDomainSet PreloadedDomainSet | 
|  | #define MAYBE_Preloaded Preloaded | 
|  | #define MAYBE_BuiltinCertPins BuiltinCertPins | 
|  | #define MAYBE_PinValidationWithRejectedCerts PinValidationWithRejectedCerts | 
|  | #define MAYBE_PinValidationWithoutRejectedCerts PinValidationWithoutRejectedCerts | 
|  | #define MAYBE_PinValidationWithRejectedCertsMixedHashes PinValidationWithRejectedCertsMixedHashes | 
|  | #define MAYBE_OptionalHSTSCertPins OptionalHSTSCertPins | 
|  | #define MAYBE_OverrideBuiltins OverrideBuiltins | 
|  | #define MAYBE_GooglePinnedProperties GooglePinnedProperties | 
|  | #endif | 
|  |  | 
|  | namespace net { | 
|  |  | 
|  | class TransportSecurityStateTest : public testing::Test { | 
|  | virtual void SetUp() { | 
|  | #if defined(USE_OPENSSL) | 
|  | crypto::EnsureOpenSSLInit(); | 
|  | #else | 
|  | crypto::EnsureNSSInit(); | 
|  | #endif | 
|  | } | 
|  | }; | 
|  |  | 
|  | TEST_F(TransportSecurityStateTest, BogusHeaders) { | 
|  | TransportSecurityState::DomainState state; | 
|  | base::Time now = base::Time::Now(); | 
|  |  | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "    ")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "abc")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "  abc")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "  abc   ")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "max-age")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "  max-age")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "  max-age  ")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "   max-age=")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "   max-age  =")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "   max-age=   ")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "   max-age  =     ")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "   max-age  =     xy")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "   max-age  =     3488a923")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=3488a923  ")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "max-ag=3488923")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "max-aged=3488923")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "max-age==3488923")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "amax-age=3488923")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=-3488923")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=3488923;")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=3488923     e")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader( | 
|  | now, "max-age=3488923     includesubdomain")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=3488923includesubdomains")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=3488923=includesubdomains")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=3488923 includesubdomainx")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=3488923 includesubdomain=")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader( | 
|  | now, "max-age=3488923 includesubdomain=true")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=3488923 includesubdomainsx")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader( | 
|  | now, "max-age=3488923 includesubdomains x")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=34889.23 includesubdomains")); | 
|  | EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=34889 includesubdomains")); | 
|  |  | 
|  | // Check that |state| was not updated by expecting the default | 
|  | // values for its predictable fields. | 
|  | EXPECT_EQ(state.upgrade_mode, | 
|  | TransportSecurityState::DomainState::MODE_FORCE_HTTPS); | 
|  | EXPECT_FALSE(state.include_subdomains); | 
|  | } | 
|  |  | 
|  | static bool GetPublicKeyHash(const net::X509Certificate::OSCertHandle& cert, | 
|  | HashValue* hash) { | 
|  | std::string der_bytes; | 
|  | if (!net::X509Certificate::GetDEREncoded(cert, &der_bytes)) | 
|  | return false; | 
|  |  | 
|  | base::StringPiece spki; | 
|  | if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki)) | 
|  | return false; | 
|  |  | 
|  | switch (hash->tag) { | 
|  | case HASH_VALUE_SHA1: | 
|  | base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(spki.data()), | 
|  | spki.size(), hash->data()); | 
|  | break; | 
|  | case HASH_VALUE_SHA256: | 
|  | crypto::SHA256HashString(spki, hash->data(), crypto::kSHA256Length); | 
|  | break; | 
|  | default: | 
|  | NOTREACHED() << "Unknown HashValueTag " << hash->tag; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static std::string GetPinFromCert(X509Certificate* cert, HashValueTag tag) { | 
|  | HashValue spki_hash(tag); | 
|  | EXPECT_TRUE(GetPublicKeyHash(cert->os_cert_handle(), &spki_hash)); | 
|  |  | 
|  | std::string base64; | 
|  | base::Base64Encode(base::StringPiece( | 
|  | reinterpret_cast<char*>(spki_hash.data()), spki_hash.size()), &base64); | 
|  |  | 
|  | std::string label; | 
|  | switch (tag) { | 
|  | case HASH_VALUE_SHA1: | 
|  | label = "pin-sha1="; | 
|  | break; | 
|  | case HASH_VALUE_SHA256: | 
|  | label = "pin-sha256="; | 
|  | break; | 
|  | default: | 
|  | NOTREACHED() << "Unknown HashValueTag " << tag; | 
|  | } | 
|  |  | 
|  | return label + HttpUtil::Quote(base64); | 
|  | } | 
|  |  | 
|  | static void TestBogusPinsHeaders(HashValueTag tag) { | 
|  | TransportSecurityState::DomainState state; | 
|  | SSLInfo ssl_info; | 
|  | ssl_info.cert = | 
|  | ImportCertFromFile(GetTestCertsDirectory(), "test_mail_google_com.pem"); | 
|  | ASSERT_NE(static_cast<void*>(NULL), ssl_info.cert); | 
|  | std::string good_pin = GetPinFromCert(ssl_info.cert, tag); | 
|  | base::Time now = base::Time::Now(); | 
|  |  | 
|  | // The backup pin is fake --- it just has to not be in the chain. | 
|  | std::string backup_pin = "pin-sha1=" + | 
|  | HttpUtil::Quote("6dcfXufJLW3J6S/9rRe4vUlBj5g="); | 
|  |  | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, "", ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, "    ", ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, "abc", ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, "  abc", ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, "  abc   ", ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, "max-age", ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, "  max-age", ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, "  max-age  ", ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, "max-age=", ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, "   max-age=", ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, "   max-age  =", ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, "   max-age=   ", ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, "   max-age  =     ", ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, "   max-age  =     xy", ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader( | 
|  | now, | 
|  | "   max-age  =     3488a923", | 
|  | ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, "max-age=3488a923  ", ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, | 
|  | "max-ag=3488923pins=" + good_pin + "," + backup_pin, | 
|  | ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, "max-aged=3488923" + backup_pin, | 
|  | ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, "max-aged=3488923; " + backup_pin, | 
|  | ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, | 
|  | "max-aged=3488923; " + backup_pin + ";" + backup_pin, | 
|  | ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, | 
|  | "max-aged=3488923; " + good_pin + ";" + good_pin, | 
|  | ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, "max-aged=3488923; " + good_pin, | 
|  | ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, "max-age==3488923", ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, "amax-age=3488923", ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, "max-age=-3488923", ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, "max-age=3488923;", ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, "max-age=3488923     e", ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader( | 
|  | now, | 
|  | "max-age=3488923     includesubdomain", | 
|  | ssl_info)); | 
|  | EXPECT_FALSE(state.ParsePinsHeader(now, "max-age=34889.23", ssl_info)); | 
|  |  | 
|  | // Check that |state| was not updated by expecting the default | 
|  | // values for its predictable fields. | 
|  | EXPECT_EQ(state.upgrade_mode, | 
|  | TransportSecurityState::DomainState::MODE_FORCE_HTTPS); | 
|  | EXPECT_FALSE(state.include_subdomains); | 
|  | } | 
|  |  | 
|  | TEST_F(TransportSecurityStateTest, BogusPinsHeadersSHA1) { | 
|  | TestBogusPinsHeaders(HASH_VALUE_SHA1); | 
|  | } | 
|  |  | 
|  | TEST_F(TransportSecurityStateTest, BogusPinsHeadersSHA256) { | 
|  | TestBogusPinsHeaders(HASH_VALUE_SHA256); | 
|  | } | 
|  |  | 
|  | TEST_F(TransportSecurityStateTest, ValidSTSHeaders) { | 
|  | TransportSecurityState::DomainState state; | 
|  | base::Time expiry; | 
|  | base::Time now = base::Time::Now(); | 
|  |  | 
|  | EXPECT_TRUE(state.ParseSTSHeader(now, "max-age=243")); | 
|  | expiry = now + base::TimeDelta::FromSeconds(243); | 
|  | EXPECT_EQ(expiry, state.upgrade_expiry); | 
|  | EXPECT_FALSE(state.include_subdomains); | 
|  |  | 
|  | EXPECT_TRUE(state.ParseSTSHeader(now, "  Max-agE    = 567")); | 
|  | expiry = now + base::TimeDelta::FromSeconds(567); | 
|  | EXPECT_EQ(expiry, state.upgrade_expiry); | 
|  | EXPECT_FALSE(state.include_subdomains); | 
|  |  | 
|  | EXPECT_TRUE(state.ParseSTSHeader(now, "  mAx-aGe    = 890      ")); | 
|  | expiry = now + base::TimeDelta::FromSeconds(890); | 
|  | EXPECT_EQ(expiry, state.upgrade_expiry); | 
|  | EXPECT_FALSE(state.include_subdomains); | 
|  |  | 
|  | EXPECT_TRUE(state.ParseSTSHeader(now, "max-age=123;incLudesUbdOmains")); | 
|  | expiry = now + base::TimeDelta::FromSeconds(123); | 
|  | EXPECT_EQ(expiry, state.upgrade_expiry); | 
|  | EXPECT_TRUE(state.include_subdomains); | 
|  |  | 
|  | EXPECT_TRUE(state.ParseSTSHeader(now, "incLudesUbdOmains; max-age=123")); | 
|  | expiry = now + base::TimeDelta::FromSeconds(123); | 
|  | EXPECT_EQ(expiry, state.upgrade_expiry); | 
|  | EXPECT_TRUE(state.include_subdomains); | 
|  |  | 
|  | EXPECT_TRUE(state.ParseSTSHeader(now, "   incLudesUbdOmains; max-age=123")); | 
|  | expiry = now + base::TimeDelta::FromSeconds(123); | 
|  | EXPECT_EQ(expiry, state.upgrade_expiry); | 
|  | EXPECT_TRUE(state.include_subdomains); | 
|  |  | 
|  | EXPECT_TRUE(state.ParseSTSHeader(now, | 
|  | "   incLudesUbdOmains; max-age=123; pumpkin=kitten")); | 
|  | expiry = now + base::TimeDelta::FromSeconds(123); | 
|  | EXPECT_EQ(expiry, state.upgrade_expiry); | 
|  | EXPECT_TRUE(state.include_subdomains); | 
|  |  | 
|  | EXPECT_TRUE(state.ParseSTSHeader(now, | 
|  | "   pumpkin=894; incLudesUbdOmains; max-age=123  ")); | 
|  | expiry = now + base::TimeDelta::FromSeconds(123); | 
|  | EXPECT_EQ(expiry, state.upgrade_expiry); | 
|  | EXPECT_TRUE(state.include_subdomains); | 
|  |  | 
|  | EXPECT_TRUE(state.ParseSTSHeader(now, | 
|  | "   pumpkin; incLudesUbdOmains; max-age=123  ")); | 
|  | expiry = now + base::TimeDelta::FromSeconds(123); | 
|  | EXPECT_EQ(expiry, state.upgrade_expiry); | 
|  | EXPECT_TRUE(state.include_subdomains); | 
|  |  | 
|  | EXPECT_TRUE(state.ParseSTSHeader(now, | 
|  | "   pumpkin; incLudesUbdOmains; max-age=\"123\"  ")); | 
|  | expiry = now + base::TimeDelta::FromSeconds(123); | 
|  | EXPECT_EQ(expiry, state.upgrade_expiry); | 
|  | EXPECT_TRUE(state.include_subdomains); | 
|  |  | 
|  | EXPECT_TRUE(state.ParseSTSHeader(now, | 
|  | "animal=\"squirrel; distinguished\"; incLudesUbdOmains; max-age=123")); | 
|  | expiry = now + base::TimeDelta::FromSeconds(123); | 
|  | EXPECT_EQ(expiry, state.upgrade_expiry); | 
|  | EXPECT_TRUE(state.include_subdomains); | 
|  |  | 
|  | EXPECT_TRUE(state.ParseSTSHeader(now, "max-age=394082;  incLudesUbdOmains")); | 
|  | expiry = now + base::TimeDelta::FromSeconds(394082); | 
|  | EXPECT_EQ(expiry, state.upgrade_expiry); | 
|  | EXPECT_TRUE(state.include_subdomains); | 
|  |  | 
|  | EXPECT_TRUE(state.ParseSTSHeader( | 
|  | now, "max-age=39408299  ;incLudesUbdOmains")); | 
|  | expiry = now + base::TimeDelta::FromSeconds( | 
|  | std::min(TransportSecurityState::kMaxHSTSAgeSecs, 39408299l)); | 
|  | EXPECT_EQ(expiry, state.upgrade_expiry); | 
|  | EXPECT_TRUE(state.include_subdomains); | 
|  |  | 
|  | EXPECT_TRUE(state.ParseSTSHeader( | 
|  | now, "max-age=394082038  ; incLudesUbdOmains")); | 
|  | expiry = now + base::TimeDelta::FromSeconds( | 
|  | std::min(TransportSecurityState::kMaxHSTSAgeSecs, 394082038l)); | 
|  | EXPECT_EQ(expiry, state.upgrade_expiry); | 
|  | EXPECT_TRUE(state.include_subdomains); | 
|  |  | 
|  | EXPECT_TRUE(state.ParseSTSHeader( | 
|  | now, "  max-age=0  ;  incLudesUbdOmains   ")); | 
|  | expiry = now + base::TimeDelta::FromSeconds(0); | 
|  | EXPECT_EQ(expiry, state.upgrade_expiry); | 
|  | EXPECT_TRUE(state.include_subdomains); | 
|  | // When max-age == 0, we downgrade to MODE_DEFAULT rather than deleting | 
|  | // the entire DomainState. (That is because we currently overload | 
|  | // DomainState to also include pins, and we don't want to invalidate any | 
|  | // opportunistic pins that may be in place.) | 
|  | EXPECT_EQ(TransportSecurityState::DomainState::MODE_DEFAULT, | 
|  | state.upgrade_mode); | 
|  |  | 
|  | EXPECT_TRUE(state.ParseSTSHeader( | 
|  | now, | 
|  | "  max-age=999999999999999999999999999999999999999999999  ;" | 
|  | "  incLudesUbdOmains   ")); | 
|  | expiry = now + base::TimeDelta::FromSeconds( | 
|  | TransportSecurityState::kMaxHSTSAgeSecs); | 
|  | EXPECT_EQ(expiry, state.upgrade_expiry); | 
|  | EXPECT_TRUE(state.include_subdomains); | 
|  | } | 
|  |  | 
|  | static void TestValidPinsHeaders(HashValueTag tag) { | 
|  | TransportSecurityState::DomainState state; | 
|  | base::Time expiry; | 
|  | base::Time now = base::Time::Now(); | 
|  |  | 
|  | // Set up a realistic SSLInfo with a realistic cert chain. | 
|  | FilePath certs_dir = GetTestCertsDirectory(); | 
|  | scoped_refptr<X509Certificate> ee_cert = | 
|  | ImportCertFromFile(certs_dir, "2048-rsa-ee-by-2048-rsa-intermediate.pem"); | 
|  | ASSERT_NE(static_cast<X509Certificate*>(NULL), ee_cert); | 
|  | scoped_refptr<X509Certificate> intermediate = | 
|  | ImportCertFromFile(certs_dir, "2048-rsa-intermediate.pem"); | 
|  | ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate); | 
|  | X509Certificate::OSCertHandles intermediates; | 
|  | intermediates.push_back(intermediate->os_cert_handle()); | 
|  | SSLInfo ssl_info; | 
|  | ssl_info.cert = X509Certificate::CreateFromHandle(ee_cert->os_cert_handle(), | 
|  | intermediates); | 
|  |  | 
|  | // Add the root that signed the intermediate for this test. | 
|  | scoped_refptr<X509Certificate> root_cert = | 
|  | ImportCertFromFile(certs_dir, "2048-rsa-root.pem"); | 
|  | ASSERT_NE(static_cast<X509Certificate*>(NULL), root_cert); | 
|  | ScopedTestRoot scoped_root(root_cert); | 
|  |  | 
|  | // Verify has the side-effect of populating public_key_hashes, which | 
|  | // ParsePinsHeader needs. (It wants to check pins against the validated | 
|  | // chain, not just the presented chain.) | 
|  | int rv = ERR_FAILED; | 
|  | CertVerifyResult result; | 
|  | scoped_ptr<CertVerifier> verifier(CertVerifier::CreateDefault()); | 
|  | TestCompletionCallback callback; | 
|  | CertVerifier::RequestHandle handle = NULL; | 
|  | rv = verifier->Verify(ssl_info.cert, "127.0.0.1", 0, NULL, &result, | 
|  | callback.callback(), &handle, BoundNetLog()); | 
|  | rv = callback.GetResult(rv); | 
|  | ASSERT_EQ(OK, rv); | 
|  | // Normally, ssl_client_socket_nss would do this, but for a unit test we | 
|  | // fake it. | 
|  | ssl_info.public_key_hashes = result.public_key_hashes; | 
|  | std::string good_pin = GetPinFromCert(ssl_info.cert, /*tag*/HASH_VALUE_SHA1); | 
|  | DLOG(WARNING) << "good pin: " << good_pin; | 
|  |  | 
|  | // The backup pin is fake --- we just need an SPKI hash that does not match | 
|  | // the hash of any SPKI in the certificate chain. | 
|  | std::string backup_pin = "pin-sha1=" + | 
|  | HttpUtil::Quote("6dcfXufJLW3J6S/9rRe4vUlBj5g="); | 
|  |  | 
|  | EXPECT_TRUE(state.ParsePinsHeader( | 
|  | now, | 
|  | "max-age=243; " + good_pin + ";" + backup_pin, | 
|  | ssl_info)); | 
|  | expiry = now + base::TimeDelta::FromSeconds(243); | 
|  | EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); | 
|  |  | 
|  | EXPECT_TRUE(state.ParsePinsHeader( | 
|  | now, | 
|  | "   " + good_pin + "; " + backup_pin + "  ; Max-agE    = 567", | 
|  | ssl_info)); | 
|  | expiry = now + base::TimeDelta::FromSeconds(567); | 
|  | EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); | 
|  |  | 
|  | EXPECT_TRUE(state.ParsePinsHeader( | 
|  | now, | 
|  | good_pin + ";" + backup_pin + "  ; mAx-aGe    = 890      ", | 
|  | ssl_info)); | 
|  | expiry = now + base::TimeDelta::FromSeconds(890); | 
|  | EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); | 
|  |  | 
|  | EXPECT_TRUE(state.ParsePinsHeader( | 
|  | now, | 
|  | good_pin + ";" + backup_pin + "; max-age=123;IGNORED;", | 
|  | ssl_info)); | 
|  | expiry = now + base::TimeDelta::FromSeconds(123); | 
|  | EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); | 
|  |  | 
|  | EXPECT_TRUE(state.ParsePinsHeader( | 
|  | now, | 
|  | "max-age=394082;" + backup_pin + ";" + good_pin + ";  ", | 
|  | ssl_info)); | 
|  | expiry = now + base::TimeDelta::FromSeconds(394082); | 
|  | EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); | 
|  |  | 
|  | EXPECT_TRUE(state.ParsePinsHeader( | 
|  | now, | 
|  | "max-age=39408299  ;" + backup_pin + ";" + good_pin + ";  ", | 
|  | ssl_info)); | 
|  | expiry = now + base::TimeDelta::FromSeconds( | 
|  | std::min(TransportSecurityState::kMaxHSTSAgeSecs, 39408299l)); | 
|  | EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); | 
|  |  | 
|  | EXPECT_TRUE(state.ParsePinsHeader( | 
|  | now, | 
|  | "max-age=39408038  ;    cybers=39408038  ;  " + | 
|  | good_pin + ";" + backup_pin + ";   ", | 
|  | ssl_info)); | 
|  | expiry = now + base::TimeDelta::FromSeconds( | 
|  | std::min(TransportSecurityState::kMaxHSTSAgeSecs, 394082038l)); | 
|  | EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); | 
|  |  | 
|  | EXPECT_TRUE(state.ParsePinsHeader( | 
|  | now, | 
|  | "  max-age=0  ;  " + good_pin + ";" + backup_pin, | 
|  | ssl_info)); | 
|  | expiry = now + base::TimeDelta::FromSeconds(0); | 
|  | EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); | 
|  |  | 
|  | EXPECT_TRUE(state.ParsePinsHeader( | 
|  | now, | 
|  | "  max-age=999999999999999999999999999999999999999999999  ;  " + | 
|  | backup_pin + ";" + good_pin + ";   ", | 
|  | ssl_info)); | 
|  | expiry = now + | 
|  | base::TimeDelta::FromSeconds(TransportSecurityState::kMaxHSTSAgeSecs); | 
|  | EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); | 
|  | } | 
|  |  | 
|  | TEST_F(TransportSecurityStateTest, ValidPinsHeadersSHA1) { | 
|  | TestValidPinsHeaders(HASH_VALUE_SHA1); | 
|  | } | 
|  |  | 
|  | TEST_F(TransportSecurityStateTest, ValidPinsHeadersSHA256) { | 
|  | TestValidPinsHeaders(HASH_VALUE_SHA256); | 
|  | } | 
|  |  | 
|  | TEST_F(TransportSecurityStateTest, SimpleMatches) { | 
|  | TransportSecurityState state; | 
|  | TransportSecurityState::DomainState domain_state; | 
|  | const base::Time current_time(base::Time::Now()); | 
|  | const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); | 
|  |  | 
|  | EXPECT_FALSE(state.GetDomainState("yahoo.com", true, &domain_state)); | 
|  | domain_state.upgrade_expiry = expiry; | 
|  | state.EnableHost("yahoo.com", domain_state); | 
|  | EXPECT_TRUE(state.GetDomainState("yahoo.com", true, &domain_state)); | 
|  | } | 
|  |  | 
|  | TEST_F(TransportSecurityStateTest, MatchesCase1) { | 
|  | TransportSecurityState state; | 
|  | TransportSecurityState::DomainState domain_state; | 
|  | const base::Time current_time(base::Time::Now()); | 
|  | const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); | 
|  |  | 
|  | EXPECT_FALSE(state.GetDomainState("yahoo.com", true, &domain_state)); | 
|  | domain_state.upgrade_expiry = expiry; | 
|  | state.EnableHost("YAhoo.coM", domain_state); | 
|  | EXPECT_TRUE(state.GetDomainState("yahoo.com", true, &domain_state)); | 
|  | } | 
|  |  | 
|  | TEST_F(TransportSecurityStateTest, MatchesCase2) { | 
|  | TransportSecurityState state; | 
|  | TransportSecurityState::DomainState domain_state; | 
|  | const base::Time current_time(base::Time::Now()); | 
|  | const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); | 
|  |  | 
|  | EXPECT_FALSE(state.GetDomainState("YAhoo.coM", true, &domain_state)); | 
|  | domain_state.upgrade_expiry = expiry; | 
|  | state.EnableHost("yahoo.com", domain_state); | 
|  | EXPECT_TRUE(state.GetDomainState("YAhoo.coM", true, &domain_state)); | 
|  | } | 
|  |  | 
|  | TEST_F(TransportSecurityStateTest, SubdomainMatches) { | 
|  | TransportSecurityState state; | 
|  | TransportSecurityState::DomainState domain_state; | 
|  | const base::Time current_time(base::Time::Now()); | 
|  | const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); | 
|  |  | 
|  | EXPECT_FALSE(state.GetDomainState("yahoo.com", true, &domain_state)); | 
|  | domain_state.upgrade_expiry = expiry; | 
|  | domain_state.include_subdomains = true; | 
|  | state.EnableHost("yahoo.com", domain_state); | 
|  | EXPECT_TRUE(state.GetDomainState("yahoo.com", true, &domain_state)); | 
|  | EXPECT_TRUE(state.GetDomainState("foo.yahoo.com", true, &domain_state)); | 
|  | EXPECT_TRUE(state.GetDomainState("foo.bar.yahoo.com", true, &domain_state)); | 
|  | EXPECT_TRUE(state.GetDomainState("foo.bar.baz.yahoo.com", true, | 
|  | &domain_state)); | 
|  | EXPECT_FALSE(state.GetDomainState("com", true, &domain_state)); | 
|  | } | 
|  |  | 
|  | TEST_F(TransportSecurityStateTest, DeleteSince) { | 
|  | TransportSecurityState state; | 
|  | TransportSecurityState::DomainState domain_state; | 
|  | const base::Time current_time(base::Time::Now()); | 
|  | const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); | 
|  | const base::Time older = current_time - base::TimeDelta::FromSeconds(1000); | 
|  |  | 
|  | EXPECT_FALSE(state.GetDomainState("yahoo.com", true, &domain_state)); | 
|  | domain_state.upgrade_mode = | 
|  | TransportSecurityState::DomainState::MODE_FORCE_HTTPS; | 
|  | domain_state.upgrade_expiry = expiry; | 
|  | state.EnableHost("yahoo.com", domain_state); | 
|  |  | 
|  | state.DeleteSince(expiry); | 
|  | EXPECT_TRUE(state.GetDomainState("yahoo.com", true, &domain_state)); | 
|  | state.DeleteSince(older); | 
|  | EXPECT_FALSE(state.GetDomainState("yahoo.com", true, &domain_state)); | 
|  | } | 
|  |  | 
|  | TEST_F(TransportSecurityStateTest, DeleteHost) { | 
|  | TransportSecurityState state; | 
|  | TransportSecurityState::DomainState domain_state; | 
|  | const base::Time current_time(base::Time::Now()); | 
|  | const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); | 
|  | domain_state.upgrade_mode = | 
|  | TransportSecurityState::DomainState::MODE_FORCE_HTTPS; | 
|  | domain_state.upgrade_expiry = expiry; | 
|  | state.EnableHost("yahoo.com", domain_state); | 
|  |  | 
|  | EXPECT_TRUE(state.GetDomainState("yahoo.com", true, &domain_state)); | 
|  | EXPECT_FALSE(state.GetDomainState("example.com", true, &domain_state)); | 
|  | EXPECT_TRUE(state.DeleteHost("yahoo.com")); | 
|  | EXPECT_FALSE(state.GetDomainState("yahoo.com", true, &domain_state)); | 
|  | } | 
|  |  | 
|  | TEST_F(TransportSecurityStateTest, MAYBE_IsPreloaded) { | 
|  | const std::string paypal = | 
|  | TransportSecurityState::CanonicalizeHost("paypal.com"); | 
|  | const std::string www_paypal = | 
|  | TransportSecurityState::CanonicalizeHost("www.paypal.com"); | 
|  | const std::string a_www_paypal = | 
|  | TransportSecurityState::CanonicalizeHost("a.www.paypal.com"); | 
|  | const std::string abc_paypal = | 
|  | TransportSecurityState::CanonicalizeHost("a.b.c.paypal.com"); | 
|  | const std::string example = | 
|  | TransportSecurityState::CanonicalizeHost("example.com"); | 
|  | const std::string aypal = | 
|  | TransportSecurityState::CanonicalizeHost("aypal.com"); | 
|  |  | 
|  | TransportSecurityState state; | 
|  | TransportSecurityState::DomainState domain_state; | 
|  |  | 
|  | EXPECT_FALSE(state.GetStaticDomainState(paypal, true, &domain_state)); | 
|  | EXPECT_TRUE(state.GetStaticDomainState(www_paypal, true, &domain_state)); | 
|  | EXPECT_FALSE(domain_state.include_subdomains); | 
|  | EXPECT_FALSE(state.GetStaticDomainState(a_www_paypal, true, &domain_state)); | 
|  | EXPECT_FALSE(state.GetStaticDomainState(abc_paypal, true, &domain_state)); | 
|  | EXPECT_FALSE(state.GetStaticDomainState(example, true, &domain_state)); | 
|  | EXPECT_FALSE(state.GetStaticDomainState(aypal, true, &domain_state)); | 
|  | } | 
|  |  | 
|  | TEST_F(TransportSecurityStateTest, MAYBE_PreloadedDomainSet) { | 
|  | TransportSecurityState state; | 
|  | TransportSecurityState::DomainState domain_state; | 
|  |  | 
|  | // The domain wasn't being set, leading to a blank string in the | 
|  | // chrome://net-internals/#hsts UI. So test that. | 
|  | EXPECT_TRUE(state.GetDomainState("market.android.com", true, &domain_state)); | 
|  | EXPECT_EQ(domain_state.domain, "market.android.com"); | 
|  | EXPECT_TRUE(state.GetDomainState("sub.market.android.com", true, | 
|  | &domain_state)); | 
|  | EXPECT_EQ(domain_state.domain, "market.android.com"); | 
|  | } | 
|  |  | 
|  | static bool ShouldRedirect(const char* hostname) { | 
|  | TransportSecurityState state; | 
|  | TransportSecurityState::DomainState domain_state; | 
|  | return state.GetDomainState(hostname, true /* SNI ok */, &domain_state) && | 
|  | domain_state.ShouldRedirectHTTPToHTTPS(); | 
|  | } | 
|  |  | 
|  | static bool HasState(const char* hostname) { | 
|  | TransportSecurityState state; | 
|  | TransportSecurityState::DomainState domain_state; | 
|  | return state.GetDomainState(hostname, true /* SNI ok */, &domain_state); | 
|  | } | 
|  |  | 
|  | static bool HasPins(const char* hostname, bool sni_enabled) { | 
|  | TransportSecurityState state; | 
|  | TransportSecurityState::DomainState domain_state; | 
|  | if (!state.GetDomainState(hostname, sni_enabled, &domain_state)) | 
|  | return false; | 
|  |  | 
|  | return domain_state.HasPins(); | 
|  | } | 
|  |  | 
|  | static bool HasPins(const char* hostname) { | 
|  | return HasPins(hostname, true); | 
|  | } | 
|  |  | 
|  | static bool OnlyPinning(const char *hostname) { | 
|  | TransportSecurityState state; | 
|  | TransportSecurityState::DomainState domain_state; | 
|  | if (!state.GetDomainState(hostname, true /* SNI ok */, &domain_state)) | 
|  | return false; | 
|  |  | 
|  | return (domain_state.static_spki_hashes.size() > 0 || | 
|  | domain_state.bad_static_spki_hashes.size() > 0 || | 
|  | domain_state.dynamic_spki_hashes.size() > 0) && | 
|  | !domain_state.ShouldRedirectHTTPToHTTPS(); | 
|  | } | 
|  |  | 
|  | TEST_F(TransportSecurityStateTest, MAYBE_Preloaded) { | 
|  | TransportSecurityState state; | 
|  | TransportSecurityState::DomainState domain_state; | 
|  |  | 
|  | // We do more extensive checks for the first domain. | 
|  | EXPECT_TRUE(state.GetDomainState("www.paypal.com", true, &domain_state)); | 
|  | EXPECT_EQ(domain_state.upgrade_mode, | 
|  | TransportSecurityState::DomainState::MODE_FORCE_HTTPS); | 
|  | EXPECT_FALSE(domain_state.include_subdomains); | 
|  |  | 
|  | EXPECT_FALSE(HasState("paypal.com")); | 
|  | EXPECT_FALSE(HasState("www2.paypal.com")); | 
|  | EXPECT_FALSE(HasState("www2.paypal.com")); | 
|  |  | 
|  | // Google hosts: | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("chrome.google.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("checkout.google.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("health.google.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("docs.google.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("sites.google.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("drive.google.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("spreadsheets.google.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("appengine.google.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("market.android.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("encrypted.google.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("accounts.google.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("profiles.google.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("mail.google.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("chatenabled.mail.google.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("talkgadget.google.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("hostedtalkgadget.google.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("talk.google.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("plus.google.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("groups.google.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("apis.google.com")); | 
|  | EXPECT_FALSE(ShouldRedirect("chart.apis.google.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("ssl.google-analytics.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("gmail.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("www.gmail.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("googlemail.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("www.googlemail.com")); | 
|  | EXPECT_FALSE(HasState("m.gmail.com")); | 
|  | EXPECT_FALSE(HasState("m.googlemail.com")); | 
|  |  | 
|  | EXPECT_TRUE(OnlyPinning("www.google.com")); | 
|  | EXPECT_TRUE(OnlyPinning("foo.google.com")); | 
|  | EXPECT_TRUE(OnlyPinning("google.com")); | 
|  | EXPECT_TRUE(OnlyPinning("www.youtube.com")); | 
|  | EXPECT_TRUE(OnlyPinning("youtube.com")); | 
|  | EXPECT_TRUE(OnlyPinning("i.ytimg.com")); | 
|  | EXPECT_TRUE(OnlyPinning("ytimg.com")); | 
|  | EXPECT_TRUE(OnlyPinning("googleusercontent.com")); | 
|  | EXPECT_TRUE(OnlyPinning("www.googleusercontent.com")); | 
|  | EXPECT_TRUE(OnlyPinning("www.google-analytics.com")); | 
|  | EXPECT_TRUE(OnlyPinning("googleapis.com")); | 
|  | EXPECT_TRUE(OnlyPinning("googleadservices.com")); | 
|  | EXPECT_TRUE(OnlyPinning("googlecode.com")); | 
|  | EXPECT_TRUE(OnlyPinning("appspot.com")); | 
|  | EXPECT_TRUE(OnlyPinning("googlesyndication.com")); | 
|  | EXPECT_TRUE(OnlyPinning("doubleclick.net")); | 
|  | EXPECT_TRUE(OnlyPinning("googlegroups.com")); | 
|  |  | 
|  | // Tests for domains that don't work without SNI. | 
|  | EXPECT_FALSE(state.GetDomainState("gmail.com", false, &domain_state)); | 
|  | EXPECT_FALSE(state.GetDomainState("www.gmail.com", false, &domain_state)); | 
|  | EXPECT_FALSE(state.GetDomainState("m.gmail.com", false, &domain_state)); | 
|  | EXPECT_FALSE(state.GetDomainState("googlemail.com", false, &domain_state)); | 
|  | EXPECT_FALSE(state.GetDomainState("www.googlemail.com", false, | 
|  | &domain_state)); | 
|  | EXPECT_FALSE(state.GetDomainState("m.googlemail.com", false, &domain_state)); | 
|  |  | 
|  | // Other hosts: | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("aladdinschools.appspot.com")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("ottospora.nl")); | 
|  | EXPECT_TRUE(ShouldRedirect("www.ottospora.nl")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("www.paycheckrecords.com")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("lastpass.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("www.lastpass.com")); | 
|  | EXPECT_FALSE(HasState("blog.lastpass.com")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("keyerror.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("www.keyerror.com")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("entropia.de")); | 
|  | EXPECT_TRUE(ShouldRedirect("www.entropia.de")); | 
|  | EXPECT_FALSE(HasState("foo.entropia.de")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("www.elanex.biz")); | 
|  | EXPECT_FALSE(HasState("elanex.biz")); | 
|  | EXPECT_FALSE(HasState("foo.elanex.biz")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("sunshinepress.org")); | 
|  | EXPECT_TRUE(ShouldRedirect("www.sunshinepress.org")); | 
|  | EXPECT_TRUE(ShouldRedirect("a.b.sunshinepress.org")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("www.noisebridge.net")); | 
|  | EXPECT_FALSE(HasState("noisebridge.net")); | 
|  | EXPECT_FALSE(HasState("foo.noisebridge.net")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("neg9.org")); | 
|  | EXPECT_FALSE(HasState("www.neg9.org")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("riseup.net")); | 
|  | EXPECT_TRUE(ShouldRedirect("foo.riseup.net")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("factor.cc")); | 
|  | EXPECT_FALSE(HasState("www.factor.cc")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("members.mayfirst.org")); | 
|  | EXPECT_TRUE(ShouldRedirect("support.mayfirst.org")); | 
|  | EXPECT_TRUE(ShouldRedirect("id.mayfirst.org")); | 
|  | EXPECT_TRUE(ShouldRedirect("lists.mayfirst.org")); | 
|  | EXPECT_FALSE(HasState("www.mayfirst.org")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("romab.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("www.romab.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("foo.romab.com")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("logentries.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("www.logentries.com")); | 
|  | EXPECT_FALSE(HasState("foo.logentries.com")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("stripe.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("foo.stripe.com")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("cloudsecurityalliance.org")); | 
|  | EXPECT_TRUE(ShouldRedirect("foo.cloudsecurityalliance.org")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("login.sapo.pt")); | 
|  | EXPECT_TRUE(ShouldRedirect("foo.login.sapo.pt")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("mattmccutchen.net")); | 
|  | EXPECT_TRUE(ShouldRedirect("foo.mattmccutchen.net")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("betnet.fr")); | 
|  | EXPECT_TRUE(ShouldRedirect("foo.betnet.fr")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("uprotect.it")); | 
|  | EXPECT_TRUE(ShouldRedirect("foo.uprotect.it")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("squareup.com")); | 
|  | EXPECT_FALSE(HasState("foo.squareup.com")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("cert.se")); | 
|  | EXPECT_TRUE(ShouldRedirect("foo.cert.se")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("crypto.is")); | 
|  | EXPECT_TRUE(ShouldRedirect("foo.crypto.is")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("simon.butcher.name")); | 
|  | EXPECT_TRUE(ShouldRedirect("foo.simon.butcher.name")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("linx.net")); | 
|  | EXPECT_TRUE(ShouldRedirect("foo.linx.net")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("dropcam.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("www.dropcam.com")); | 
|  | EXPECT_FALSE(HasState("foo.dropcam.com")); | 
|  |  | 
|  | EXPECT_TRUE(state.GetDomainState("torproject.org", false, &domain_state)); | 
|  | EXPECT_FALSE(domain_state.static_spki_hashes.empty()); | 
|  | EXPECT_TRUE(state.GetDomainState("www.torproject.org", false, | 
|  | &domain_state)); | 
|  | EXPECT_FALSE(domain_state.static_spki_hashes.empty()); | 
|  | EXPECT_TRUE(state.GetDomainState("check.torproject.org", false, | 
|  | &domain_state)); | 
|  | EXPECT_FALSE(domain_state.static_spki_hashes.empty()); | 
|  | EXPECT_TRUE(state.GetDomainState("blog.torproject.org", false, | 
|  | &domain_state)); | 
|  | EXPECT_FALSE(domain_state.static_spki_hashes.empty()); | 
|  | EXPECT_TRUE(ShouldRedirect("ebanking.indovinabank.com.vn")); | 
|  | EXPECT_TRUE(ShouldRedirect("foo.ebanking.indovinabank.com.vn")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("epoxate.com")); | 
|  | EXPECT_FALSE(HasState("foo.epoxate.com")); | 
|  |  | 
|  | EXPECT_TRUE(HasPins("torproject.org")); | 
|  | EXPECT_TRUE(HasPins("www.torproject.org")); | 
|  | EXPECT_TRUE(HasPins("check.torproject.org")); | 
|  | EXPECT_TRUE(HasPins("blog.torproject.org")); | 
|  | EXPECT_FALSE(HasState("foo.torproject.org")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("www.moneybookers.com")); | 
|  | EXPECT_FALSE(HasState("moneybookers.com")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("ledgerscope.net")); | 
|  | EXPECT_TRUE(ShouldRedirect("www.ledgerscope.net")); | 
|  | EXPECT_FALSE(HasState("status.ledgerscope.net")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("kyps.net")); | 
|  | EXPECT_TRUE(ShouldRedirect("www.kyps.net")); | 
|  | EXPECT_FALSE(HasState("foo.kyps.net")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("foo.app.recurly.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("foo.api.recurly.com")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("greplin.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("www.greplin.com")); | 
|  | EXPECT_FALSE(HasState("foo.greplin.com")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("luneta.nearbuysystems.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("foo.luneta.nearbuysystems.com")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("ubertt.org")); | 
|  | EXPECT_TRUE(ShouldRedirect("foo.ubertt.org")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("pixi.me")); | 
|  | EXPECT_TRUE(ShouldRedirect("www.pixi.me")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("grepular.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("www.grepular.com")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("mydigipass.com")); | 
|  | EXPECT_FALSE(ShouldRedirect("foo.mydigipass.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("www.mydigipass.com")); | 
|  | EXPECT_FALSE(ShouldRedirect("foo.www.mydigipass.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("developer.mydigipass.com")); | 
|  | EXPECT_FALSE(ShouldRedirect("foo.developer.mydigipass.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("www.developer.mydigipass.com")); | 
|  | EXPECT_FALSE(ShouldRedirect("foo.www.developer.mydigipass.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("sandbox.mydigipass.com")); | 
|  | EXPECT_FALSE(ShouldRedirect("foo.sandbox.mydigipass.com")); | 
|  | EXPECT_TRUE(ShouldRedirect("www.sandbox.mydigipass.com")); | 
|  | EXPECT_FALSE(ShouldRedirect("foo.www.sandbox.mydigipass.com")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("crypto.cat")); | 
|  | EXPECT_TRUE(ShouldRedirect("foo.crypto.cat")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("bigshinylock.minazo.net")); | 
|  | EXPECT_TRUE(ShouldRedirect("foo.bigshinylock.minazo.net")); | 
|  |  | 
|  | EXPECT_TRUE(ShouldRedirect("crate.io")); | 
|  | EXPECT_TRUE(ShouldRedirect("foo.crate.io")); | 
|  |  | 
|  | EXPECT_TRUE(HasPins("www.twitter.com")); | 
|  | } | 
|  |  | 
|  | TEST_F(TransportSecurityStateTest, LongNames) { | 
|  | TransportSecurityState state; | 
|  | const char kLongName[] = | 
|  | "lookupByWaveIdHashAndWaveIdIdAndWaveIdDomainAndWaveletIdIdAnd" | 
|  | "WaveletIdDomainAndBlipBlipid"; | 
|  | TransportSecurityState::DomainState domain_state; | 
|  | // Just checks that we don't hit a NOTREACHED. | 
|  | EXPECT_FALSE(state.GetDomainState(kLongName, true, &domain_state)); | 
|  | } | 
|  |  | 
|  | TEST_F(TransportSecurityStateTest, MAYBE_BuiltinCertPins) { | 
|  | TransportSecurityState state; | 
|  | TransportSecurityState::DomainState domain_state; | 
|  |  | 
|  | EXPECT_TRUE(state.GetDomainState("chrome.google.com", true, &domain_state)); | 
|  | EXPECT_TRUE(HasPins("chrome.google.com")); | 
|  |  | 
|  | HashValueVector hashes; | 
|  | // Checks that a built-in list does exist. | 
|  | EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(hashes)); | 
|  | EXPECT_FALSE(HasPins("www.paypal.com")); | 
|  |  | 
|  | EXPECT_TRUE(HasPins("docs.google.com")); | 
|  | EXPECT_TRUE(HasPins("1.docs.google.com")); | 
|  | EXPECT_TRUE(HasPins("sites.google.com")); | 
|  | EXPECT_TRUE(HasPins("drive.google.com")); | 
|  | EXPECT_TRUE(HasPins("spreadsheets.google.com")); | 
|  | EXPECT_TRUE(HasPins("health.google.com")); | 
|  | EXPECT_TRUE(HasPins("checkout.google.com")); | 
|  | EXPECT_TRUE(HasPins("appengine.google.com")); | 
|  | EXPECT_TRUE(HasPins("market.android.com")); | 
|  | EXPECT_TRUE(HasPins("encrypted.google.com")); | 
|  | EXPECT_TRUE(HasPins("accounts.google.com")); | 
|  | EXPECT_TRUE(HasPins("profiles.google.com")); | 
|  | EXPECT_TRUE(HasPins("mail.google.com")); | 
|  | EXPECT_TRUE(HasPins("chatenabled.mail.google.com")); | 
|  | EXPECT_TRUE(HasPins("talkgadget.google.com")); | 
|  | EXPECT_TRUE(HasPins("hostedtalkgadget.google.com")); | 
|  | EXPECT_TRUE(HasPins("talk.google.com")); | 
|  | EXPECT_TRUE(HasPins("plus.google.com")); | 
|  | EXPECT_TRUE(HasPins("groups.google.com")); | 
|  | EXPECT_TRUE(HasPins("apis.google.com")); | 
|  |  | 
|  | EXPECT_TRUE(HasPins("ssl.gstatic.com")); | 
|  | EXPECT_FALSE(HasPins("www.gstatic.com")); | 
|  | EXPECT_TRUE(HasPins("ssl.google-analytics.com")); | 
|  |  | 
|  | // Disabled in order to help track down pinning failures --agl | 
|  | EXPECT_TRUE(HasPins("twitter.com")); | 
|  | EXPECT_FALSE(HasPins("foo.twitter.com")); | 
|  | EXPECT_TRUE(HasPins("www.twitter.com")); | 
|  | EXPECT_TRUE(HasPins("api.twitter.com")); | 
|  | EXPECT_TRUE(HasPins("oauth.twitter.com")); | 
|  | EXPECT_TRUE(HasPins("mobile.twitter.com")); | 
|  | EXPECT_TRUE(HasPins("dev.twitter.com")); | 
|  | EXPECT_TRUE(HasPins("business.twitter.com")); | 
|  | EXPECT_TRUE(HasPins("platform.twitter.com")); | 
|  | EXPECT_TRUE(HasPins("si0.twimg.com")); | 
|  | EXPECT_TRUE(HasPins("twimg0-a.akamaihd.net")); | 
|  | } | 
|  |  | 
|  | static bool AddHash(const std::string& type_and_base64, | 
|  | HashValueVector* out) { | 
|  | HashValue hash; | 
|  |  | 
|  | if (!TransportSecurityState::ParsePin(type_and_base64, &hash)) | 
|  | return false; | 
|  |  | 
|  | out->push_back(hash); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | TEST_F(TransportSecurityStateTest, MAYBE_PinValidationWithRejectedCerts) { | 
|  | // kGoodPath is plus.google.com via Google Internet Authority. | 
|  | static const char* kGoodPath[] = { | 
|  | "sha1/4BjDjn8v2lWeUFQnqSs0BgbIcrU=", | 
|  | "sha1/QMVAHW+MuvCLAO3vse6H0AWzuc0=", | 
|  | "sha1/SOZo+SvSspXXR9gjIBBPM5iQn9Q=", | 
|  | NULL, | 
|  | }; | 
|  |  | 
|  | // kBadPath is plus.google.com via Trustcenter, which contains a required | 
|  | // certificate (Equifax root), but also an excluded certificate | 
|  | // (Trustcenter). | 
|  | static const char* kBadPath[] = { | 
|  | "sha1/4BjDjn8v2lWeUFQnqSs0BgbIcrU=", | 
|  | "sha1/gzuEEAB/bkqdQS3EIjk2by7lW+k=", | 
|  | "sha1/SOZo+SvSspXXR9gjIBBPM5iQn9Q=", | 
|  | NULL, | 
|  | }; | 
|  |  | 
|  | HashValueVector good_hashes, bad_hashes; | 
|  |  | 
|  | for (size_t i = 0; kGoodPath[i]; i++) { | 
|  | EXPECT_TRUE(AddHash(kGoodPath[i], &good_hashes)); | 
|  | } | 
|  | for (size_t i = 0; kBadPath[i]; i++) { | 
|  | EXPECT_TRUE(AddHash(kBadPath[i], &bad_hashes)); | 
|  | } | 
|  |  | 
|  | TransportSecurityState state; | 
|  | TransportSecurityState::DomainState domain_state; | 
|  | EXPECT_TRUE(state.GetDomainState("plus.google.com", true, &domain_state)); | 
|  | EXPECT_TRUE(domain_state.HasPins()); | 
|  |  | 
|  | EXPECT_TRUE(domain_state.IsChainOfPublicKeysPermitted(good_hashes)); | 
|  | EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(bad_hashes)); | 
|  | } | 
|  |  | 
|  | TEST_F(TransportSecurityStateTest, MAYBE_PinValidationWithoutRejectedCerts) { | 
|  | // kGoodPath is blog.torproject.org. | 
|  | static const char* kGoodPath[] = { | 
|  | "sha1/m9lHYJYke9k0GtVZ+bXSQYE8nDI=", | 
|  | "sha1/o5OZxATDsgmwgcIfIWIneMJ0jkw=", | 
|  | "sha1/wHqYaI2J+6sFZAwRfap9ZbjKzE4=", | 
|  | NULL, | 
|  | }; | 
|  |  | 
|  | // kBadPath is plus.google.com via Trustcenter, which is utterly wrong for | 
|  | // torproject.org. | 
|  | static const char* kBadPath[] = { | 
|  | "sha1/4BjDjn8v2lWeUFQnqSs0BgbIcrU=", | 
|  | "sha1/gzuEEAB/bkqdQS3EIjk2by7lW+k=", | 
|  | "sha1/SOZo+SvSspXXR9gjIBBPM5iQn9Q=", | 
|  | NULL, | 
|  | }; | 
|  |  | 
|  | HashValueVector good_hashes, bad_hashes; | 
|  |  | 
|  | for (size_t i = 0; kGoodPath[i]; i++) { | 
|  | EXPECT_TRUE(AddHash(kGoodPath[i], &good_hashes)); | 
|  | } | 
|  | for (size_t i = 0; kBadPath[i]; i++) { | 
|  | EXPECT_TRUE(AddHash(kBadPath[i], &bad_hashes)); | 
|  | } | 
|  |  | 
|  | TransportSecurityState state; | 
|  | TransportSecurityState::DomainState domain_state; | 
|  | EXPECT_TRUE(state.GetDomainState("blog.torproject.org", true, &domain_state)); | 
|  | EXPECT_TRUE(domain_state.HasPins()); | 
|  |  | 
|  | EXPECT_TRUE(domain_state.IsChainOfPublicKeysPermitted(good_hashes)); | 
|  | EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(bad_hashes)); | 
|  | } | 
|  |  | 
|  | TEST_F(TransportSecurityStateTest, MAYBE_PinValidationWithRejectedCertsMixedHashes) { | 
|  | static const char* ee_sha1 = "sha1/4BjDjn8v2lWeUFQnqSs0BgbIcrU="; | 
|  | static const char* ee_sha256 = | 
|  | "sha256/sRJBQqWhpaKIGcc1NA7/jJ4vgWj+47oYfyU7waOS1+I="; | 
|  | static const char* google_1024_sha1 = "sha1/QMVAHW+MuvCLAO3vse6H0AWzuc0="; | 
|  | static const char* google_1024_sha256 = | 
|  | "sha256/trlUMquuV/4CDLK3T0+fkXPIxwivyecyrOIyeQR8bQU="; | 
|  | static const char* equifax_sha1 = "sha1/SOZo+SvSspXXR9gjIBBPM5iQn9Q="; | 
|  | static const char* equifax_sha256 = | 
|  | "sha256//1aAzXOlcD2gSBegdf1GJQanNQbEuBoVg+9UlHjSZHY="; | 
|  | static const char* trustcenter_sha1 = "sha1/gzuEEAB/bkqdQS3EIjk2by7lW+k="; | 
|  | static const char* trustcenter_sha256 = | 
|  | "sha256/Dq58KIA4NMLsboWMLU8/aTREzaAGEFW+EtUule8dd/M="; | 
|  |  | 
|  | // Good chains for plus.google.com chain up through google_1024_sha{1,256} | 
|  | // to equifax_sha{1,256}. Bad chains chain up to Equifax through | 
|  | // trustcenter_sha{1,256}, which is a blacklisted key. Even though Equifax | 
|  | // and Google1024 are known-good, the blacklistedness of Trustcenter | 
|  | // should override and cause pin validation failure. | 
|  |  | 
|  | TransportSecurityState state; | 
|  | TransportSecurityState::DomainState domain_state; | 
|  | EXPECT_TRUE(state.GetDomainState("plus.google.com", true, &domain_state)); | 
|  | EXPECT_TRUE(domain_state.HasPins()); | 
|  |  | 
|  | // The statically-defined pins are all SHA-1, so we add some SHA-256 pins | 
|  | // manually: | 
|  | EXPECT_TRUE(AddHash(google_1024_sha256, &domain_state.static_spki_hashes)); | 
|  | EXPECT_TRUE(AddHash(trustcenter_sha256, | 
|  | &domain_state.bad_static_spki_hashes)); | 
|  |  | 
|  | // Try an all-good SHA1 chain. | 
|  | HashValueVector validated_chain; | 
|  | EXPECT_TRUE(AddHash(ee_sha1, &validated_chain)); | 
|  | EXPECT_TRUE(AddHash(google_1024_sha1, &validated_chain)); | 
|  | EXPECT_TRUE(AddHash(equifax_sha1, &validated_chain)); | 
|  | EXPECT_TRUE(domain_state.IsChainOfPublicKeysPermitted(validated_chain)); | 
|  |  | 
|  | // Try an all-bad SHA1 chain. | 
|  | validated_chain.clear(); | 
|  | EXPECT_TRUE(AddHash(ee_sha1, &validated_chain)); | 
|  | EXPECT_TRUE(AddHash(trustcenter_sha1, &validated_chain)); | 
|  | EXPECT_TRUE(AddHash(equifax_sha1, &validated_chain)); | 
|  | EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(validated_chain)); | 
|  |  | 
|  | // Try an all-good SHA-256 chain. | 
|  | validated_chain.clear(); | 
|  | EXPECT_TRUE(AddHash(ee_sha256, &validated_chain)); | 
|  | EXPECT_TRUE(AddHash(google_1024_sha256, &validated_chain)); | 
|  | EXPECT_TRUE(AddHash(equifax_sha256, &validated_chain)); | 
|  | EXPECT_TRUE(domain_state.IsChainOfPublicKeysPermitted(validated_chain)); | 
|  |  | 
|  | // Try an all-bad SHA-256 chain. | 
|  | validated_chain.clear(); | 
|  | EXPECT_TRUE(AddHash(ee_sha256, &validated_chain)); | 
|  | EXPECT_TRUE(AddHash(trustcenter_sha256, &validated_chain)); | 
|  | EXPECT_TRUE(AddHash(equifax_sha256, &validated_chain)); | 
|  | EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(validated_chain)); | 
|  |  | 
|  | // Try a mixed-hash good chain. | 
|  | validated_chain.clear(); | 
|  | EXPECT_TRUE(AddHash(ee_sha256, &validated_chain)); | 
|  | EXPECT_TRUE(AddHash(google_1024_sha1, &validated_chain)); | 
|  | EXPECT_TRUE(AddHash(equifax_sha256, &validated_chain)); | 
|  | EXPECT_TRUE(domain_state.IsChainOfPublicKeysPermitted(validated_chain)); | 
|  |  | 
|  | // Try a mixed-hash bad chain. | 
|  | validated_chain.clear(); | 
|  | EXPECT_TRUE(AddHash(ee_sha1, &validated_chain)); | 
|  | EXPECT_TRUE(AddHash(trustcenter_sha256, &validated_chain)); | 
|  | EXPECT_TRUE(AddHash(equifax_sha1, &validated_chain)); | 
|  | EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(validated_chain)); | 
|  |  | 
|  | // Try a chain with all good hashes. | 
|  | validated_chain.clear(); | 
|  | EXPECT_TRUE(AddHash(ee_sha1, &validated_chain)); | 
|  | EXPECT_TRUE(AddHash(google_1024_sha1, &validated_chain)); | 
|  | EXPECT_TRUE(AddHash(equifax_sha1, &validated_chain)); | 
|  | EXPECT_TRUE(AddHash(ee_sha256, &validated_chain)); | 
|  | EXPECT_TRUE(AddHash(google_1024_sha256, &validated_chain)); | 
|  | EXPECT_TRUE(AddHash(equifax_sha256, &validated_chain)); | 
|  | EXPECT_TRUE(domain_state.IsChainOfPublicKeysPermitted(validated_chain)); | 
|  |  | 
|  | // Try a chain with all bad hashes. | 
|  | validated_chain.clear(); | 
|  | EXPECT_TRUE(AddHash(ee_sha1, &validated_chain)); | 
|  | EXPECT_TRUE(AddHash(trustcenter_sha1, &validated_chain)); | 
|  | EXPECT_TRUE(AddHash(equifax_sha1, &validated_chain)); | 
|  | EXPECT_TRUE(AddHash(ee_sha256, &validated_chain)); | 
|  | EXPECT_TRUE(AddHash(trustcenter_sha256, &validated_chain)); | 
|  | EXPECT_TRUE(AddHash(equifax_sha256, &validated_chain)); | 
|  | EXPECT_FALSE(domain_state.IsChainOfPublicKeysPermitted(validated_chain)); | 
|  | } | 
|  |  | 
|  | TEST_F(TransportSecurityStateTest, MAYBE_OptionalHSTSCertPins) { | 
|  | TransportSecurityState state; | 
|  | TransportSecurityState::DomainState domain_state; | 
|  |  | 
|  | EXPECT_FALSE(ShouldRedirect("www.google-analytics.com")); | 
|  |  | 
|  | EXPECT_FALSE(HasPins("www.google-analytics.com", false)); | 
|  | EXPECT_TRUE(HasPins("www.google-analytics.com")); | 
|  | EXPECT_TRUE(HasPins("google.com")); | 
|  | EXPECT_TRUE(HasPins("www.google.com")); | 
|  | EXPECT_TRUE(HasPins("mail-attachment.googleusercontent.com")); | 
|  | EXPECT_TRUE(HasPins("www.youtube.com")); | 
|  | EXPECT_TRUE(HasPins("i.ytimg.com")); | 
|  | EXPECT_TRUE(HasPins("googleapis.com")); | 
|  | EXPECT_TRUE(HasPins("ajax.googleapis.com")); | 
|  | EXPECT_TRUE(HasPins("googleadservices.com")); | 
|  | EXPECT_TRUE(HasPins("pagead2.googleadservices.com")); | 
|  | EXPECT_TRUE(HasPins("googlecode.com")); | 
|  | EXPECT_TRUE(HasPins("kibbles.googlecode.com")); | 
|  | EXPECT_TRUE(HasPins("appspot.com")); | 
|  | EXPECT_TRUE(HasPins("googlesyndication.com")); | 
|  | EXPECT_TRUE(HasPins("doubleclick.net")); | 
|  | EXPECT_TRUE(HasPins("ad.doubleclick.net")); | 
|  | EXPECT_FALSE(HasPins("learn.doubleclick.net")); | 
|  | EXPECT_TRUE(HasPins("a.googlegroups.com")); | 
|  | EXPECT_FALSE(HasPins("a.googlegroups.com", false)); | 
|  | } | 
|  |  | 
|  | TEST_F(TransportSecurityStateTest, MAYBE_OverrideBuiltins) { | 
|  | EXPECT_TRUE(HasPins("google.com")); | 
|  | EXPECT_FALSE(ShouldRedirect("google.com")); | 
|  | EXPECT_FALSE(ShouldRedirect("www.google.com")); | 
|  |  | 
|  | TransportSecurityState state; | 
|  | TransportSecurityState::DomainState domain_state; | 
|  | const base::Time current_time(base::Time::Now()); | 
|  | const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); | 
|  | domain_state.upgrade_expiry = expiry; | 
|  | state.EnableHost("www.google.com", domain_state); | 
|  |  | 
|  | EXPECT_TRUE(state.GetDomainState("www.google.com", true, &domain_state)); | 
|  | } | 
|  |  | 
|  | TEST_F(TransportSecurityStateTest, MAYBE_GooglePinnedProperties) { | 
|  | EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty( | 
|  | "www.example.com", true)); | 
|  | EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty( | 
|  | "www.paypal.com", true)); | 
|  | EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty( | 
|  | "mail.twitter.com", true)); | 
|  | EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty( | 
|  | "www.google.com.int", true)); | 
|  | EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty( | 
|  | "jottit.com", true)); | 
|  | // learn.doubleclick.net has a more specific match than | 
|  | // *.doubleclick.com, and has 0 or NULL for its required certs. | 
|  | // This test ensures that the exact-match-preferred behavior | 
|  | // works. | 
|  | EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty( | 
|  | "learn.doubleclick.net", true)); | 
|  |  | 
|  | EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty( | 
|  | "encrypted.google.com", true)); | 
|  | EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty( | 
|  | "mail.google.com", true)); | 
|  | EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty( | 
|  | "accounts.google.com", true)); | 
|  | EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty( | 
|  | "doubleclick.net", true)); | 
|  | EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty( | 
|  | "ad.doubleclick.net", true)); | 
|  | EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty( | 
|  | "youtube.com", true)); | 
|  | EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty( | 
|  | "www.profiles.google.com", true)); | 
|  | EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty( | 
|  | "checkout.google.com", true)); | 
|  | EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty( | 
|  | "googleadservices.com", true)); | 
|  |  | 
|  | // Test with sni_enabled false: | 
|  | EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty( | 
|  | "www.example.com", false)); | 
|  | EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty( | 
|  | "www.paypal.com", false)); | 
|  | EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty( | 
|  | "checkout.google.com", false)); | 
|  | EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty( | 
|  | "googleadservices.com", false)); | 
|  |  | 
|  | // Test some SNI hosts: | 
|  | EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty( | 
|  | "gmail.com", true)); | 
|  | EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty( | 
|  | "googlegroups.com", true)); | 
|  | EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty( | 
|  | "www.googlegroups.com", true)); | 
|  | // Expect to fail for SNI hosts when not searching the SNI list: | 
|  | EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty( | 
|  | "gmail.com", false)); | 
|  | EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty( | 
|  | "googlegroups.com", false)); | 
|  | EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty( | 
|  | "www.googlegroups.com", false)); | 
|  | } | 
|  |  | 
|  | }  // namespace net |