Add paypal.com to the preloaded STS list.

TEST=Navigating to http://paypal.com should always be rewritten to https
BUG=none

http://codereview.chromium.org/815003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@41180 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/net/base/transport_security_state.cc b/net/base/transport_security_state.cc
index 54d8cceb..d033b94 100644
--- a/net/base/transport_security_state.cc
+++ b/net/base/transport_security_state.cc
@@ -27,6 +27,11 @@
   const std::string canonicalised_host = CanonicaliseHost(host);
   if (canonicalised_host.empty())
     return;
+
+  bool temp;
+  if (isPreloadedSTS(canonicalised_host, &temp))
+    return;
+
   char hashed[base::SHA256_LENGTH];
   base::SHA256HashString(canonicalised_host, hashed, sizeof(hashed));
 
@@ -48,6 +53,14 @@
   if (canonicalised_host.empty())
     return false;
 
+  bool include_subdomains;
+  if (isPreloadedSTS(canonicalised_host, &include_subdomains)) {
+    result->created = result->expiry = base::Time::FromTimeT(0);
+    result->mode = DomainState::MODE_STRICT;
+    result->include_subdomains = include_subdomains;
+    return true;
+  }
+
   base::Time current_time(base::Time::Now());
   AutoLock lock(lock_);
 
@@ -378,4 +391,36 @@
   return new_host;
 }
 
+// isPreloadedSTS returns true if the canonicalised hostname should always be
+// considered to have STS enabled.
+// static
+bool TransportSecurityState::isPreloadedSTS(
+    const std::string& canonicalised_host, bool *include_subdomains) {
+  // In the medium term this list is likely to just be hardcoded here. This,
+  // slightly odd, form removes the need for additional relocations records.
+  static const struct {
+    uint8 length;
+    bool include_subdomains;
+    char dns_name[30];
+  } preloadedSTS[] = {
+    {16, false, "\003www\006paypal\003com"},
+  };
+  static const size_t numPreloadedSTS =
+      sizeof(preloadedSTS) / sizeof(preloadedSTS[0]);
+
+  for (size_t i = 0; canonicalised_host[i]; i += canonicalised_host[i] + 1) {
+    for (size_t j = 0; j < numPreloadedSTS; j++) {
+      if (preloadedSTS[j].length == canonicalised_host.size() + 1 - i &&
+          (preloadedSTS[j].include_subdomains || i == 0) &&
+          memcmp(preloadedSTS[j].dns_name, &canonicalised_host[i],
+                 preloadedSTS[j].length) == 0) {
+        *include_subdomains = preloadedSTS[j].include_subdomains;
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
 }  // namespace
diff --git a/net/base/transport_security_state.h b/net/base/transport_security_state.h
index 523f28e..05a0fc1 100644
--- a/net/base/transport_security_state.h
+++ b/net/base/transport_security_state.h
@@ -12,6 +12,7 @@
 #include "base/lock.h"
 #include "base/ref_counted.h"
 #include "base/time.h"
+#include "testing/gtest/include/gtest/gtest_prod.h"
 
 class GURL;
 
@@ -88,6 +89,7 @@
 
  private:
   friend class base::RefCountedThreadSafe<TransportSecurityState>;
+  FRIEND_TEST(TransportSecurityStateTest, IsPreloaded);
 
   ~TransportSecurityState() {}
 
@@ -107,6 +109,8 @@
   Delegate* delegate_;
 
   static std::string CanonicaliseHost(const std::string& host);
+  static bool isPreloadedSTS(const std::string& canonicalised_host,
+                             bool* out_include_subdomains);
 
   DISALLOW_COPY_AND_ASSIGN(TransportSecurityState);
 };
diff --git a/net/base/transport_security_state_unittest.cc b/net/base/transport_security_state_unittest.cc
index 2561b0b..6250105 100644
--- a/net/base/transport_security_state_unittest.cc
+++ b/net/base/transport_security_state_unittest.cc
@@ -5,6 +5,8 @@
 #include "net/base/transport_security_state.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+namespace net {
+
 class TransportSecurityStateTest : public testing::Test {
 };
 
@@ -12,71 +14,71 @@
   int max_age = 42;
   bool include_subdomains = false;
 
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "    ", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "abc", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "  abc", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "  abc   ", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "max-age", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "  max-age", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "  max-age  ", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "max-age=", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "   max-age=", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "   max-age  =", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "   max-age=   ", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "   max-age  =     ", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "   max-age  =     xy", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "   max-age  =     3488a923", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "max-age=3488a923  ", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "max-ag=3488923", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "max-aged=3488923", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "max-age==3488923", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "amax-age=3488923", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "max-age=-3488923", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "max-age=3488923;", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "max-age=3488923     e", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "max-age=3488923     includesubdomain", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "max-age=3488923includesubdomains", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "max-age=3488923=includesubdomains", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "max-age=3488923 includesubdomainx", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "max-age=3488923 includesubdomain=", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "max-age=3488923 includesubdomain=true", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "max-age=3488923 includesubdomainsx", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "max-age=3488923 includesubdomains x", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "max-age=34889.23 includesubdomains", &max_age, &include_subdomains));
-  EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+  EXPECT_FALSE(TransportSecurityState::ParseHeader(
       "max-age=34889 includesubdomains", &max_age, &include_subdomains));
 
   EXPECT_EQ(max_age, 42);
@@ -87,51 +89,51 @@
   int max_age = 42;
   bool include_subdomains = true;
 
-  EXPECT_TRUE(net::TransportSecurityState::ParseHeader(
+  EXPECT_TRUE(TransportSecurityState::ParseHeader(
       "max-age=243", &max_age, &include_subdomains));
   EXPECT_EQ(max_age, 243);
   EXPECT_FALSE(include_subdomains);
 
-  EXPECT_TRUE(net::TransportSecurityState::ParseHeader(
+  EXPECT_TRUE(TransportSecurityState::ParseHeader(
       "  Max-agE    = 567", &max_age, &include_subdomains));
   EXPECT_EQ(max_age, 567);
   EXPECT_FALSE(include_subdomains);
 
-  EXPECT_TRUE(net::TransportSecurityState::ParseHeader(
+  EXPECT_TRUE(TransportSecurityState::ParseHeader(
       "  mAx-aGe    = 890      ", &max_age, &include_subdomains));
   EXPECT_EQ(max_age, 890);
   EXPECT_FALSE(include_subdomains);
 
-  EXPECT_TRUE(net::TransportSecurityState::ParseHeader(
+  EXPECT_TRUE(TransportSecurityState::ParseHeader(
       "max-age=123;incLudesUbdOmains", &max_age, &include_subdomains));
   EXPECT_EQ(max_age, 123);
   EXPECT_TRUE(include_subdomains);
 
-  EXPECT_TRUE(net::TransportSecurityState::ParseHeader(
+  EXPECT_TRUE(TransportSecurityState::ParseHeader(
       "max-age=394082;  incLudesUbdOmains", &max_age, &include_subdomains));
   EXPECT_EQ(max_age, 394082);
   EXPECT_TRUE(include_subdomains);
 
-  EXPECT_TRUE(net::TransportSecurityState::ParseHeader(
+  EXPECT_TRUE(TransportSecurityState::ParseHeader(
       "max-age=39408299  ;incLudesUbdOmains", &max_age, &include_subdomains));
   EXPECT_EQ(max_age, 39408299);
   EXPECT_TRUE(include_subdomains);
 
-  EXPECT_TRUE(net::TransportSecurityState::ParseHeader(
+  EXPECT_TRUE(TransportSecurityState::ParseHeader(
       "max-age=394082038  ;  incLudesUbdOmains", &max_age, &include_subdomains));
   EXPECT_EQ(max_age, 394082038);
   EXPECT_TRUE(include_subdomains);
 
-  EXPECT_TRUE(net::TransportSecurityState::ParseHeader(
+  EXPECT_TRUE(TransportSecurityState::ParseHeader(
       "  max-age=0  ;  incLudesUbdOmains   ", &max_age, &include_subdomains));
   EXPECT_EQ(max_age, 0);
   EXPECT_TRUE(include_subdomains);
 }
 
 TEST_F(TransportSecurityStateTest, SimpleMatches) {
-  scoped_refptr<net::TransportSecurityState> state(
-      new net::TransportSecurityState);
-  net::TransportSecurityState::DomainState domain_state;
+  scoped_refptr<TransportSecurityState> state(
+      new TransportSecurityState);
+  TransportSecurityState::DomainState domain_state;
   const base::Time current_time(base::Time::Now());
   const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000);
 
@@ -142,9 +144,9 @@
 }
 
 TEST_F(TransportSecurityStateTest, MatchesCase1) {
-  scoped_refptr<net::TransportSecurityState> state(
-      new net::TransportSecurityState);
-  net::TransportSecurityState::DomainState domain_state;
+  scoped_refptr<TransportSecurityState> state(
+      new TransportSecurityState);
+  TransportSecurityState::DomainState domain_state;
   const base::Time current_time(base::Time::Now());
   const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000);
 
@@ -155,9 +157,9 @@
 }
 
 TEST_F(TransportSecurityStateTest, MatchesCase2) {
-  scoped_refptr<net::TransportSecurityState> state(
-      new net::TransportSecurityState);
-  net::TransportSecurityState::DomainState domain_state;
+  scoped_refptr<TransportSecurityState> state(
+      new TransportSecurityState);
+  TransportSecurityState::DomainState domain_state;
   const base::Time current_time(base::Time::Now());
   const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000);
 
@@ -168,9 +170,9 @@
 }
 
 TEST_F(TransportSecurityStateTest, SubdomainMatches) {
-  scoped_refptr<net::TransportSecurityState> state(
-      new net::TransportSecurityState);
-  net::TransportSecurityState::DomainState domain_state;
+  scoped_refptr<TransportSecurityState> state(
+      new TransportSecurityState);
+  TransportSecurityState::DomainState domain_state;
   const base::Time current_time(base::Time::Now());
   const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000);
 
@@ -187,8 +189,8 @@
 }
 
 TEST_F(TransportSecurityStateTest, Serialise1) {
-  scoped_refptr<net::TransportSecurityState> state(
-      new net::TransportSecurityState);
+  scoped_refptr<TransportSecurityState> state(
+      new TransportSecurityState);
   std::string output;
   bool dirty;
   state->Serialise(&output);
@@ -197,15 +199,15 @@
 }
 
 TEST_F(TransportSecurityStateTest, Serialise2) {
-  scoped_refptr<net::TransportSecurityState> state(
-      new net::TransportSecurityState);
+  scoped_refptr<TransportSecurityState> state(
+      new TransportSecurityState);
 
-  net::TransportSecurityState::DomainState domain_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->IsEnabledForHost(&domain_state, "google.com"));
-  domain_state.mode = net::TransportSecurityState::DomainState::MODE_STRICT;
+  domain_state.mode = TransportSecurityState::DomainState::MODE_STRICT;
   domain_state.expiry = expiry;
   domain_state.include_subdomains = true;
   state->EnableHost("google.com", domain_state);
@@ -216,27 +218,27 @@
   EXPECT_TRUE(state->Deserialise(output, &dirty));
 
   EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "google.com"));
-  EXPECT_EQ(domain_state.mode, net::TransportSecurityState::DomainState::MODE_STRICT);
+  EXPECT_EQ(domain_state.mode, TransportSecurityState::DomainState::MODE_STRICT);
   EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "foo.google.com"));
-  EXPECT_EQ(domain_state.mode, net::TransportSecurityState::DomainState::MODE_STRICT);
+  EXPECT_EQ(domain_state.mode, TransportSecurityState::DomainState::MODE_STRICT);
   EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "foo.bar.google.com"));
-  EXPECT_EQ(domain_state.mode, net::TransportSecurityState::DomainState::MODE_STRICT);
+  EXPECT_EQ(domain_state.mode, TransportSecurityState::DomainState::MODE_STRICT);
   EXPECT_TRUE(state->IsEnabledForHost(&domain_state,
                                       "foo.bar.baz.google.com"));
-  EXPECT_EQ(domain_state.mode, net::TransportSecurityState::DomainState::MODE_STRICT);
+  EXPECT_EQ(domain_state.mode, TransportSecurityState::DomainState::MODE_STRICT);
   EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "com"));
 }
 
 TEST_F(TransportSecurityStateTest, Serialise3) {
-  scoped_refptr<net::TransportSecurityState> state(
-      new net::TransportSecurityState);
+  scoped_refptr<TransportSecurityState> state(
+      new TransportSecurityState);
 
-  net::TransportSecurityState::DomainState domain_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->IsEnabledForHost(&domain_state, "google.com"));
-  domain_state.mode = net::TransportSecurityState::DomainState::MODE_OPPORTUNISTIC;
+  domain_state.mode = TransportSecurityState::DomainState::MODE_OPPORTUNISTIC;
   domain_state.expiry = expiry;
   state->EnableHost("google.com", domain_state);
 
@@ -247,20 +249,20 @@
 
   EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "google.com"));
   EXPECT_EQ(domain_state.mode,
-            net::TransportSecurityState::DomainState::MODE_OPPORTUNISTIC);
+            TransportSecurityState::DomainState::MODE_OPPORTUNISTIC);
 }
 
 TEST_F(TransportSecurityStateTest, DeleteSince) {
-  scoped_refptr<net::TransportSecurityState> state(
-      new net::TransportSecurityState);
+  scoped_refptr<TransportSecurityState> state(
+      new TransportSecurityState);
 
-  net::TransportSecurityState::DomainState domain_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->IsEnabledForHost(&domain_state, "google.com"));
-  domain_state.mode = net::TransportSecurityState::DomainState::MODE_STRICT;
+  domain_state.mode = TransportSecurityState::DomainState::MODE_STRICT;
   domain_state.expiry = expiry;
   state->EnableHost("google.com", domain_state);
 
@@ -271,8 +273,8 @@
 }
 
 TEST_F(TransportSecurityStateTest, SerialiseOld) {
-  scoped_refptr<net::TransportSecurityState> state(
-      new net::TransportSecurityState);
+  scoped_refptr<TransportSecurityState> state(
+      new TransportSecurityState);
   // This is an old-style piece of transport state JSON, which has no creation
   // date.
   std::string output =
@@ -288,3 +290,41 @@
   EXPECT_TRUE(dirty);
 }
 
+TEST_F(TransportSecurityStateTest, IsPreloaded) {
+  const std::string paypal =
+      TransportSecurityState::CanonicaliseHost("paypal.com");
+  const std::string www_paypal =
+      TransportSecurityState::CanonicaliseHost("www.paypal.com");
+  const std::string a_www_paypal =
+      TransportSecurityState::CanonicaliseHost("a.www.paypal.com");
+  const std::string abc_paypal =
+      TransportSecurityState::CanonicaliseHost("a.b.c.paypal.com");
+  const std::string example =
+      TransportSecurityState::CanonicaliseHost("example.com");
+  const std::string aypal =
+      TransportSecurityState::CanonicaliseHost("aypal.com");
+
+  bool b;
+  EXPECT_FALSE(TransportSecurityState::isPreloadedSTS(paypal, &b));
+  EXPECT_TRUE(TransportSecurityState::isPreloadedSTS(www_paypal, &b));
+  EXPECT_FALSE(b);
+  EXPECT_FALSE(TransportSecurityState::isPreloadedSTS(a_www_paypal, &b));
+  EXPECT_FALSE(TransportSecurityState::isPreloadedSTS(abc_paypal, &b));
+  EXPECT_FALSE(TransportSecurityState::isPreloadedSTS(example, &b));
+  EXPECT_FALSE(TransportSecurityState::isPreloadedSTS(aypal, &b));
+}
+
+TEST_F(TransportSecurityStateTest, Preloaded) {
+  scoped_refptr<TransportSecurityState> state(
+      new TransportSecurityState);
+  TransportSecurityState::DomainState domain_state;
+  EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "paypal.com"));
+  EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "www.paypal.com"));
+  EXPECT_EQ(domain_state.mode,
+            TransportSecurityState::DomainState::MODE_STRICT);
+  EXPECT_FALSE(domain_state.include_subdomains);
+  EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "www2.paypal.com"));
+  EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "a.www.paypal.com"));
+}
+
+}  // namespace net