| // 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 |