diff options
-rw-r--r-- | chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc | 7 | ||||
-rw-r--r-- | net/base/transport_security_state.cc | 34 | ||||
-rw-r--r-- | net/base/transport_security_state.h | 29 | ||||
-rw-r--r-- | net/base/transport_security_state_unittest.cc | 713 | ||||
-rw-r--r-- | net/socket_stream/socket_stream_job.cc | 4 | ||||
-rw-r--r-- | net/url_request/url_request_http_job.cc | 27 | ||||
-rw-r--r-- | net/url_request/url_request_test_util.cc | 2 | ||||
-rw-r--r-- | net/url_request/url_request_test_util.h | 2 | ||||
-rw-r--r-- | net/url_request/url_request_unittest.cc | 42 |
9 files changed, 391 insertions, 469 deletions
diff --git a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc index 2ad3a5d..9f9bb41f 100644 --- a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc +++ b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc @@ -320,10 +320,9 @@ void ChromeResourceDispatcherHostDelegate::OnResponseStarted( net::TransportSecurityState::DomainState domain_state; bool has_sni = net::SSLConfigService::IsSNIAvailable( context->ssl_config_service()); - if (state->IsEnabledForHost( - &domain_state, request->url().host(), has_sni) || - state->HasPinsForHost( - &domain_state, request->url().host(), has_sni)) { + if (state->GetDomainState( + &domain_state, request->url().host(), has_sni) && + domain_state.ShouldMixedScriptingBeBlocked()) { filter->Send(new ChromeViewMsg_AddStrictSecurityHost( info->route_id(), request->url().host())); } diff --git a/net/base/transport_security_state.cc b/net/base/transport_security_state.cc index f80116c..6cc2252 100644 --- a/net/base/transport_security_state.cc +++ b/net/base/transport_security_state.cc @@ -80,8 +80,10 @@ void TransportSecurityState::EnableHost(const std::string& host, // Use the original creation date if we already have this host. DomainState state_copy(state); DomainState existing_state; - if (IsEnabledForHost(&existing_state, host, true)) + if (GetDomainState(&existing_state, host, true) && + !existing_state.created.is_null()) { state_copy.created = existing_state.created; + } // We don't store these values. state_copy.preloaded = false; @@ -117,13 +119,12 @@ bool TransportSecurityState::HasPinsForHost(DomainState* result, !result->public_key_hashes.empty(); } -bool TransportSecurityState::IsEnabledForHost(DomainState* result, - const std::string& host, - bool sni_available) { +bool TransportSecurityState::GetDomainState(DomainState* result, + const std::string& host, + bool sni_available) { DCHECK(CalledOnValidThread()); - return HasMetadata(result, host, sni_available) && - result->mode != DomainState::MODE_NONE; + return HasMetadata(result, host, sni_available); } bool TransportSecurityState::HasMetadata(DomainState* result, @@ -719,8 +720,8 @@ bool TransportSecurityState::Deserialise( mode = DomainState::MODE_STRICT; } else if (mode_string == "spdy-only") { mode = DomainState::MODE_SPDY_ONLY; - } else if (mode_string == "none") { - mode = DomainState::MODE_NONE; + } else if (mode_string == "pinning-only") { + mode = DomainState::MODE_PINNING_ONLY; } else { LOG(WARNING) << "Unknown TransportSecurityState mode string found: " << mode_string; @@ -876,7 +877,7 @@ static bool HasPreload(const struct HSTSPreload* entries, size_t num_entries, out->include_subdomains = entries[j].include_subdomains; *ret = true; if (!entries[j].https_required) - out->mode = TransportSecurityState::DomainState::MODE_NONE; + out->mode = TransportSecurityState::DomainState::MODE_PINNING_ONLY; if (entries[j].pins.required_hashes) { const char* const* hash = entries[j].pins.required_hashes; while (*hash) { @@ -1343,4 +1344,19 @@ bool TransportSecurityState::DomainState::IsChainOfPublicKeysPermitted( return false; } +bool TransportSecurityState::DomainState::ShouldCertificateErrorsBeFatal() + const { + return true; +} + +bool TransportSecurityState::DomainState::ShouldRedirectHTTPToHTTPS() + const { + return mode == MODE_STRICT; +} + +bool TransportSecurityState::DomainState::ShouldMixedScriptingBeBlocked() + const { + return true; +} + } // namespace diff --git a/net/base/transport_security_state.h b/net/base/transport_security_state.h index 07e7aa0..01c095b 100644 --- a/net/base/transport_security_state.h +++ b/net/base/transport_security_state.h @@ -47,8 +47,9 @@ class NET_EXPORT TransportSecurityState // * We'll request HTTP URLs over HTTPS iff we have SPDY support. // * Certificate issues are fatal. MODE_SPDY_ONLY = 2, - // None means there is no HSTS for this domain. - MODE_NONE = 3, + // Pinning means there are no HTTP -> HTTPS redirects, however certificate + // issues are still fatal and there may be public key pins. + MODE_PINNING_ONLY = 3, }; DomainState(); @@ -75,6 +76,20 @@ class NET_EXPORT TransportSecurityState bool IsChainOfPublicKeysPermitted( const std::vector<SHA1Fingerprint>& hashes); + // ShouldCertificateErrorsBeFatal returns true iff, given the |mode| of this + // DomainState, certificate errors on this domain should be fatal (i.e. no + // user bypass). + bool ShouldCertificateErrorsBeFatal() const; + + // ShouldRedirectHTTPToHTTPS returns true iff, given the |mode| of this + // DomainState, HTTP requests should be internally redirected to HTTPS. + bool ShouldRedirectHTTPToHTTPS() const; + + // ShouldMixedScriptingBeBlocked returns true iff, given the |mode| of this + // DomainState, mixed scripting (the loading of Javascript, CSS or plugins + // over HTTP for an HTTPS page) should be blocked. + bool ShouldMixedScriptingBeBlocked() const; + Mode mode; base::Time created; // when this host entry was first created base::Time expiry; // the absolute time (UTC) when this record expires @@ -107,11 +122,13 @@ class NET_EXPORT TransportSecurityState bool DeleteHost(const std::string& host); // Returns true if |host| has TransportSecurity enabled, in the context of - // |sni_available|. In that case, *result is filled out. + // |sni_available|. You should check |result->mode| before acting on this + // because the modes can be quite different. + // // Note that *result is always overwritten on every call. - bool IsEnabledForHost(DomainState* result, - const std::string& host, - bool sni_available); + bool GetDomainState(DomainState* result, + const std::string& host, + bool sni_available); // Returns true if |host| has any SSL certificate pinning, in the context of // |sni_available|. In that case, *result is filled out. diff --git a/net/base/transport_security_state_unittest.cc b/net/base/transport_security_state_unittest.cc index a751081..b5f3c4d 100644 --- a/net/base/transport_security_state_unittest.cc +++ b/net/base/transport_security_state_unittest.cc @@ -162,10 +162,10 @@ TEST_F(TransportSecurityStateTest, SimpleMatches) { const base::Time current_time(base::Time::Now()); const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "yahoo.com", true)); + EXPECT_FALSE(state.GetDomainState(&domain_state, "yahoo.com", true)); domain_state.expiry = expiry; state.EnableHost("yahoo.com", domain_state); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "yahoo.com", true)); + EXPECT_TRUE(state.GetDomainState(&domain_state, "yahoo.com", true)); } TEST_F(TransportSecurityStateTest, MatchesCase1) { @@ -174,10 +174,10 @@ TEST_F(TransportSecurityStateTest, MatchesCase1) { const base::Time current_time(base::Time::Now()); const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "yahoo.com", true)); + EXPECT_FALSE(state.GetDomainState(&domain_state, "yahoo.com", true)); domain_state.expiry = expiry; state.EnableHost("YAhoo.coM", domain_state); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "yahoo.com", true)); + EXPECT_TRUE(state.GetDomainState(&domain_state, "yahoo.com", true)); } TEST_F(TransportSecurityStateTest, MatchesCase2) { @@ -186,10 +186,10 @@ TEST_F(TransportSecurityStateTest, MatchesCase2) { const base::Time current_time(base::Time::Now()); const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "YAhoo.coM", true)); + EXPECT_FALSE(state.GetDomainState(&domain_state, "YAhoo.coM", true)); domain_state.expiry = expiry; state.EnableHost("yahoo.com", domain_state); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "YAhoo.coM", true)); + EXPECT_TRUE(state.GetDomainState(&domain_state, "YAhoo.coM", true)); } TEST_F(TransportSecurityStateTest, SubdomainMatches) { @@ -198,19 +198,19 @@ TEST_F(TransportSecurityStateTest, SubdomainMatches) { const base::Time current_time(base::Time::Now()); const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "yahoo.com", true)); + EXPECT_FALSE(state.GetDomainState(&domain_state, "yahoo.com", true)); domain_state.expiry = expiry; domain_state.include_subdomains = true; state.EnableHost("yahoo.com", domain_state); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "yahoo.com", true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "foo.yahoo.com", true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "foo.bar.yahoo.com", - true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "foo.bar.baz.yahoo.com", - true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "com", true)); + EXPECT_TRUE(state.GetDomainState(&domain_state, "yahoo.com", true)); + EXPECT_TRUE(state.GetDomainState(&domain_state, "foo.yahoo.com", true)); + EXPECT_TRUE(state.GetDomainState(&domain_state, + "foo.bar.yahoo.com", + true)); + EXPECT_TRUE(state.GetDomainState(&domain_state, + "foo.bar.baz.yahoo.com", + true)); + EXPECT_FALSE(state.GetDomainState(&domain_state, "com", true)); } TEST_F(TransportSecurityStateTest, Serialise1) { @@ -228,7 +228,7 @@ TEST_F(TransportSecurityStateTest, Serialise2) { const base::Time current_time(base::Time::Now()); const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "yahoo.com", true)); + EXPECT_FALSE(state.GetDomainState(&domain_state, "yahoo.com", true)); domain_state.mode = TransportSecurityState::DomainState::MODE_STRICT; domain_state.expiry = expiry; domain_state.include_subdomains = true; @@ -239,19 +239,19 @@ TEST_F(TransportSecurityStateTest, Serialise2) { state.Serialise(&output); EXPECT_TRUE(state.LoadEntries(output, &dirty)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "yahoo.com", true)); + EXPECT_TRUE(state.GetDomainState(&domain_state, "yahoo.com", true)); EXPECT_EQ(domain_state.mode, TransportSecurityState::DomainState::MODE_STRICT); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "foo.yahoo.com", true)); + EXPECT_TRUE(state.GetDomainState(&domain_state, "foo.yahoo.com", true)); EXPECT_EQ(domain_state.mode, TransportSecurityState::DomainState::MODE_STRICT); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "foo.bar.yahoo.com", - true)); + EXPECT_TRUE(state.GetDomainState(&domain_state, + "foo.bar.yahoo.com", + true)); EXPECT_EQ(domain_state.mode, TransportSecurityState::DomainState::MODE_STRICT); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "foo.bar.baz.yahoo.com", - true)); + EXPECT_TRUE(state.GetDomainState(&domain_state, + "foo.bar.baz.yahoo.com", + true)); EXPECT_EQ(domain_state.mode, TransportSecurityState::DomainState::MODE_STRICT); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "com", true)); + EXPECT_FALSE(state.GetDomainState(&domain_state, "com", true)); } TEST_F(TransportSecurityStateTest, DeleteSince) { @@ -261,15 +261,15 @@ TEST_F(TransportSecurityStateTest, DeleteSince) { 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, "yahoo.com", true)); + EXPECT_FALSE(state.GetDomainState(&domain_state, "yahoo.com", true)); domain_state.mode = TransportSecurityState::DomainState::MODE_STRICT; domain_state.expiry = expiry; state.EnableHost("yahoo.com", domain_state); state.DeleteSince(expiry); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "yahoo.com", true)); + EXPECT_TRUE(state.GetDomainState(&domain_state, "yahoo.com", true)); state.DeleteSince(older); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "yahoo.com", true)); + EXPECT_FALSE(state.GetDomainState(&domain_state, "yahoo.com", true)); } TEST_F(TransportSecurityStateTest, DeleteHost) { @@ -281,10 +281,10 @@ TEST_F(TransportSecurityStateTest, DeleteHost) { domain_state.expiry = expiry; state.EnableHost("yahoo.com", domain_state); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "yahoo.com", true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "example.com", true)); + EXPECT_TRUE(state.GetDomainState(&domain_state, "yahoo.com", true)); + EXPECT_FALSE(state.GetDomainState(&domain_state, "example.com", true)); EXPECT_TRUE(state.DeleteHost("yahoo.com")); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "yahoo.com", true)); + EXPECT_FALSE(state.GetDomainState(&domain_state, "yahoo.com", true)); } TEST_F(TransportSecurityStateTest, SerialiseOld) { @@ -330,414 +330,264 @@ TEST_F(TransportSecurityStateTest, IsPreloaded) { EXPECT_FALSE(state.IsPreloadedSTS(aypal, true, &domain_state)); } -TEST_F(TransportSecurityStateTest, Preloaded) { +TEST_F(TransportSecurityStateTest, PreloadedDomainSet) { TransportSecurityState state(""); TransportSecurityState::DomainState domain_state; - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "paypal.com", true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "www.paypal.com", true)); - EXPECT_EQ(domain_state.mode, - TransportSecurityState::DomainState::MODE_STRICT); - EXPECT_TRUE(domain_state.preloaded); - EXPECT_FALSE(domain_state.include_subdomains); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "www2.paypal.com", true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, - "a.www.paypal.com", - true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "elanex.biz", true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "www.elanex.biz", true)); - EXPECT_EQ(domain_state.mode, - TransportSecurityState::DomainState::MODE_STRICT); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "foo.elanex.biz", true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, - "a.foo.elanex.biz", - true)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "sunshinepress.org", - true)); - EXPECT_EQ(domain_state.mode, - TransportSecurityState::DomainState::MODE_STRICT); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "www.sunshinepress.org", - true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "a.b.sunshinepress.org", - true)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "www.noisebridge.net", - true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, - "noisebridge.net", - true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, - "foo.noisebridge.net", - true)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "neg9.org", true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "www.neg9.org", true)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "riseup.net", true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "foo.riseup.net", true)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "factor.cc", true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "www.factor.cc", true)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "members.mayfirst.org", - true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "support.mayfirst.org", - true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "id.mayfirst.org", true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "lists.mayfirst.org", - true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, - "www.mayfirst.org", - true)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "splendidbacon.com", - true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "www.splendidbacon.com", - true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "foo.splendidbacon.com", - true)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "chrome.google.com", - true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "checkout.google.com", - true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "health.google.com", - true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "aladdinschools.appspot.com", - true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "ottospora.nl", true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "www.ottospora.nl", true)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "docs.google.com", true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "sites.google.com", true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "drive.google.com", true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "spreadsheets.google.com", - true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "appengine.google.com", - true)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "www.paycheckrecords.com", - true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "market.android.com", - true)); // 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(&domain_state, + "market.android.com", + true)); EXPECT_EQ(domain_state.domain, "market.android.com"); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "sub.market.android.com", - true)); + EXPECT_TRUE(state.GetDomainState(&domain_state, + "sub.market.android.com", + true)); EXPECT_EQ(domain_state.domain, "market.android.com"); +} - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "lastpass.com", true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "www.lastpass.com", true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, - "blog.lastpass.com", - true)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "keyerror.com", true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "www.keyerror.com", true)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "encrypted.google.com", - true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "accounts.google.com", - true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "profiles.google.com", - true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "mail.google.com", true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "chatenabled.mail.google.com", - true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "talkgadget.google.com", - true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "hostedtalkgadget.google.com", - true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "talk.google.com", true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "plus.google.com", true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "groups.google.com", true)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "entropia.de", true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "www.entropia.de", true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "foo.entropia.de", true)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "ssl.google-analytics.com", - true)); - - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "www.google.com", true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "google.com", true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "www.youtube.com", true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "youtube.com", true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "i.ytimg.com", true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "ytimg.com", true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, - "googleusercontent.com", - true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, - "www.googleusercontent.com", - true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, - "www.google-analytics.com", - true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, - "google-analytics.com", - true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "googleapis.com", true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, - "googleadservices.com", - true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "googlecode.com", true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "appspot.com", true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, - "googlesyndication.com", - true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "doubleclick.net", true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, - "googlegroups.com", - true)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "gmail.com", true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "www.gmail.com", true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "m.gmail.com", true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "googlemail.com", true)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "www.googlemail.com", - true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, - "m.googlemail.com", - true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "gmail.com", false)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "www.gmail.com", false)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "m.gmail.com", false)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "googlemail.com", false)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, +static bool ShouldRedirect(const char* hostname) { + TransportSecurityState state(""); + TransportSecurityState::DomainState domain_state; + return state.GetDomainState(&domain_state, hostname, true /* SNI ok */) && + domain_state.ShouldRedirectHTTPToHTTPS(); +} + +static bool HasState(const char *hostname) { + TransportSecurityState state(""); + TransportSecurityState::DomainState domain_state; + return state.GetDomainState(&domain_state, hostname, true /* SNI ok */); +} + +static bool HasPins(const char *hostname) { + TransportSecurityState state(""); + TransportSecurityState::DomainState domain_state; + return state.HasPinsForHost(&domain_state, hostname, true /* SNI ok */); +} + +static bool OnlyPinning(const char *hostname) { + TransportSecurityState state(""); + TransportSecurityState::DomainState domain_state; + return state.HasPinsForHost(&domain_state, hostname, true /* SNI ok */) && + !domain_state.ShouldRedirectHTTPToHTTPS(); +} + +TEST_F(TransportSecurityStateTest, Preloaded) { + TransportSecurityState state(""); + TransportSecurityState::DomainState domain_state; + + // We do more extensive checks for the first domain. + EXPECT_TRUE(state.GetDomainState(&domain_state, "www.paypal.com", true)); + EXPECT_EQ(domain_state.mode, + TransportSecurityState::DomainState::MODE_STRICT); + EXPECT_TRUE(domain_state.preloaded); + 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("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_TRUE(ShouldRedirect("googleplex.com")); + EXPECT_TRUE(ShouldRedirect("www.googleplex.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(&domain_state, "gmail.com", false)); + EXPECT_FALSE(state.GetDomainState(&domain_state, "www.gmail.com", false)); + EXPECT_FALSE(state.GetDomainState(&domain_state, "m.gmail.com", false)); + EXPECT_FALSE(state.GetDomainState(&domain_state, "googlemail.com", false)); + EXPECT_FALSE(state.GetDomainState(&domain_state, "www.googlemail.com", false)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, + EXPECT_FALSE(state.GetDomainState(&domain_state, "m.googlemail.com", false)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "www.googleplex.com", - true)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "romab.com", false)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "www.romab.com", false)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "foo.romab.com", false)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "logentries.com", false)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "www.logentries.com", - false)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, - "foo.logentries.com", - false)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "stripe.com", false)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "foo.stripe.com", false)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "cloudsecurityalliance.org", - false)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "foo.cloudsecurityalliance.org", - false)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "login.sapo.pt", - false)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "foo.login.sapo.pt", - false)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "mattmccutchen.net", - false)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "foo.mattmccutchen.net", - false)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "betnet.fr", - false)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "foo.betnet.fr", - false)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "uprotect.it", - false)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "foo.uprotect.it", - false)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "squareup.com", - false)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, - "foo.squareup.com", - false)); + // Other hosts: - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "cert.se", - false)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "foo.cert.se", - false)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "crypto.is", - false)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "foo.crypto.is", - false)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "simon.butcher.name", - false)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "foo.simon.butcher.name", - false)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "linx.net", - false)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "foo.linx.net", - false)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "dropcam.com", - false)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "www.dropcam.com", - false)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, - "foo.dropcam.com", - false)); + EXPECT_TRUE(ShouldRedirect("aladdinschools.appspot.com")); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "ebanking.indovinabank.com.vn", - false)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "foo.ebanking.indovinabank.com.vn", - false)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "epoxate.com", - false)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, - "foo.epoxate.com", - false)); + EXPECT_TRUE(ShouldRedirect("ottospora.nl")); + EXPECT_TRUE(ShouldRedirect("www.ottospora.nl")); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "torproject.org", - false)); - EXPECT_TRUE(domain_state.public_key_hashes.size() != 0); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "www.torproject.org", - false)); - EXPECT_TRUE(domain_state.public_key_hashes.size() != 0); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "check.torproject.org", - false)); - EXPECT_TRUE(domain_state.public_key_hashes.size() != 0); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "blog.torproject.org", - false)); - EXPECT_TRUE(domain_state.public_key_hashes.size() != 0); - - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, - "foo.torproject.org", - false)); + EXPECT_TRUE(ShouldRedirect("www.paycheckrecords.com")); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "www.moneybookers.com", - false)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, - "moneybookers.com", - false)); + EXPECT_TRUE(ShouldRedirect("lastpass.com")); + EXPECT_TRUE(ShouldRedirect("www.lastpass.com")); + EXPECT_FALSE(HasState("blog.lastpass.com")); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "ledgerscope.net", - false)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "www.ledgerscope.net", - false)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, - "status.ledgerscope.net", - false)); + EXPECT_TRUE(ShouldRedirect("keyerror.com")); + EXPECT_TRUE(ShouldRedirect("www.keyerror.com")); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "kyps.net", - false)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "www.kyps.net", - false)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, - "foo.kyps.net", - false)); + EXPECT_TRUE(ShouldRedirect("entropia.de")); + EXPECT_TRUE(ShouldRedirect("www.entropia.de")); + EXPECT_FALSE(HasState("foo.entropia.de")); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "foo.app.recurly.com", - false)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "foo.api.recurly.com", - false)); - - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "greplin.com", - false)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "www.greplin.com", - false)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, - "foo.greplin.com", - false)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "luneta.nearbuysystems.com", - false)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "foo.luneta.nearbuysystems.com", - false)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "ubertt.org", - false)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "foo.ubertt.org", - false)); + 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("splendidbacon.com")); + EXPECT_TRUE(ShouldRedirect("www.splendidbacon.com")); + EXPECT_TRUE(ShouldRedirect("foo.splendidbacon.com")); + + 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(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")); #if 0 // Currently disabled to debug Twitter public key pins --agl #if defined(OS_CHROMEOS) - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "twitter.com", - false)); + EXPECT_TRUE(state.GetDomainState(&domain_state, + "twitter.com", + false)); #else - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, + EXPECT_FALSE(state.GetDomainState(&domain_state, "twitter.com", false)); #endif @@ -751,13 +601,13 @@ TEST_F(TransportSecurityStateTest, LongNames) { "WaveletIdDomainAndBlipBlipid"; TransportSecurityState::DomainState domain_state; // Just checks that we don't hit a NOTREACHED. - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, kLongName, true)); + EXPECT_FALSE(state.GetDomainState(&domain_state, kLongName, true)); } TEST_F(TransportSecurityStateTest, PublicKeyHashes) { TransportSecurityState state(""); TransportSecurityState::DomainState domain_state; - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "example.com", false)); + EXPECT_FALSE(state.GetDomainState(&domain_state, "example.com", false)); std::vector<SHA1Fingerprint> hashes; EXPECT_TRUE(domain_state.IsChainOfPublicKeysPermitted(hashes)); @@ -779,7 +629,7 @@ TEST_F(TransportSecurityStateTest, PublicKeyHashes) { EXPECT_TRUE(state.Serialise(&ser)); bool dirty; EXPECT_TRUE(state.LoadEntries(ser, &dirty)); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "example.com", false)); + EXPECT_TRUE(state.GetDomainState(&domain_state, "example.com", false)); EXPECT_EQ(1u, domain_state.public_key_hashes.size()); EXPECT_TRUE(0 == memcmp(domain_state.public_key_hashes[0].data, hash.data, sizeof(hash.data))); @@ -788,9 +638,9 @@ TEST_F(TransportSecurityStateTest, PublicKeyHashes) { TEST_F(TransportSecurityStateTest, BuiltinCertPins) { TransportSecurityState state(""); TransportSecurityState::DomainState domain_state; - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, - "chrome.google.com", - true)); + EXPECT_TRUE(state.GetDomainState(&domain_state, + "chrome.google.com", + true)); EXPECT_TRUE(state.HasPinsForHost(&domain_state, "chrome.google.com", true)); std::vector<SHA1Fingerprint> hashes; // This essential checks that a built-in list does exist. @@ -947,12 +797,7 @@ TEST_F(TransportSecurityStateTest, PinValidationWithoutRejectedCerts) { TEST_F(TransportSecurityStateTest, OptionalHSTSCertPins) { TransportSecurityState state(""); TransportSecurityState::DomainState domain_state; - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, - "www.google-analytics.com", - false)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, - "www.google-analytics.com", - true)); + EXPECT_FALSE(ShouldRedirect("www.google-analytics.com")); EXPECT_FALSE(state.HasPinsForHost(&domain_state, "www.google-analytics.com", false)); @@ -1002,29 +847,29 @@ TEST_F(TransportSecurityStateTest, ForcePreloads) { "\"created\": 0.0," "\"expiry\": 2000000000.0," "\"include_subdomains\": false," - "\"mode\": \"none\"" + "\"mode\": \"pinning-only\"" "}}"); TransportSecurityState state(preload); TransportSecurityState::DomainState domain_state; EXPECT_FALSE(state.HasPinsForHost(&domain_state, "docs.google.com", true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "docs.google.com", true)); + EXPECT_TRUE(state.GetDomainState(&domain_state, "docs.google.com", true)); + EXPECT_FALSE(domain_state.ShouldRedirectHTTPToHTTPS()); } TEST_F(TransportSecurityStateTest, OverrideBuiltins) { + EXPECT_TRUE(HasPins("google.com")); + EXPECT_FALSE(ShouldRedirect("google.com")); + EXPECT_FALSE(ShouldRedirect("www.google.com")); + TransportSecurityState state(""); TransportSecurityState::DomainState domain_state; - EXPECT_TRUE(state.HasPinsForHost(&domain_state, "google.com", true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "google.com", true)); - EXPECT_FALSE(state.IsEnabledForHost(&domain_state, "www.google.com", true)); - - domain_state = TransportSecurityState::DomainState(); const base::Time current_time(base::Time::Now()); const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); domain_state.expiry = expiry; state.EnableHost("www.google.com", domain_state); - EXPECT_TRUE(state.IsEnabledForHost(&domain_state, "www.google.com", true)); + EXPECT_TRUE(state.GetDomainState(&domain_state, "www.google.com", true)); } static const uint8 kSidePinLeafSPKI[] = { diff --git a/net/socket_stream/socket_stream_job.cc b/net/socket_stream/socket_stream_job.cc index 64386eb..b575109 100644 --- a/net/socket_stream/socket_stream_job.cc +++ b/net/socket_stream/socket_stream_job.cc @@ -27,9 +27,9 @@ SocketStreamJob* SocketStreamJob::CreateSocketStreamJob( SSLConfigService* ssl) { GURL socket_url(url); TransportSecurityState::DomainState domain_state; - if (url.scheme() == "ws" && sts && sts->IsEnabledForHost( + if (url.scheme() == "ws" && sts && sts->GetDomainState( &domain_state, url.host(), SSLConfigService::IsSNIAvailable(ssl)) && - domain_state.mode == TransportSecurityState::DomainState::MODE_STRICT) { + domain_state.ShouldRedirectHTTPToHTTPS()) { url_canon::Replacements<char> replacements; static const char kNewScheme[] = "wss"; replacements.SetScheme(kNewScheme, diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc index 5f405cd..b5ef12d 100644 --- a/net/url_request/url_request_http_job.cc +++ b/net/url_request/url_request_http_job.cc @@ -179,21 +179,19 @@ URLRequestJob* URLRequestHttpJob::Factory(URLRequest* request, TransportSecurityState::DomainState domain_state; if (scheme == "http" && request->context()->transport_security_state() && - request->context()->transport_security_state()->IsEnabledForHost( + request->context()->transport_security_state()->GetDomainState( &domain_state, request->url().host(), SSLConfigService::IsSNIAvailable( - request->context()->ssl_config_service()))) { - if (domain_state.mode == - TransportSecurityState::DomainState::MODE_STRICT) { - DCHECK_EQ(request->url().scheme(), "http"); - url_canon::Replacements<char> replacements; - static const char kNewScheme[] = "https"; - replacements.SetScheme(kNewScheme, - url_parse::Component(0, strlen(kNewScheme))); - GURL new_location = request->url().ReplaceComponents(replacements); - return new URLRequestRedirectJob(request, new_location); - } + request->context()->ssl_config_service())) && + domain_state.ShouldRedirectHTTPToHTTPS()) { + DCHECK_EQ(request->url().scheme(), "http"); + url_canon::Replacements<char> replacements; + static const char kNewScheme[] = "https"; + replacements.SetScheme(kNewScheme, + url_parse::Component(0, strlen(kNewScheme))); + GURL new_location = request->url().ReplaceComponents(replacements); + return new URLRequestRedirectJob(request, new_location); } return new URLRequestHttpJob(request); @@ -741,9 +739,10 @@ void URLRequestHttpJob::OnStartCompleted(int result) { TransportSecurityState::DomainState domain_state; const bool is_hsts_host = context_->transport_security_state() && - context_->transport_security_state()->IsEnabledForHost( + context_->transport_security_state()->GetDomainState( &domain_state, request_info_.url.host(), - SSLConfigService::IsSNIAvailable(context_->ssl_config_service())); + SSLConfigService::IsSNIAvailable(context_->ssl_config_service())) && + domain_state.ShouldCertificateErrorsBeFatal(); NotifySSLCertificateError(transaction_->GetResponseInfo()->ssl_info, is_hsts_host); } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) { diff --git a/net/url_request/url_request_test_util.cc b/net/url_request/url_request_test_util.cc index 3a75332..11d9e01 100644 --- a/net/url_request/url_request_test_util.cc +++ b/net/url_request/url_request_test_util.cc @@ -174,6 +174,7 @@ TestDelegate::TestDelegate() received_data_before_response_(false), request_failed_(false), have_certificate_errors_(false), + is_hsts_host_(false), auth_required_(false), buf_(new net::IOBuffer(kBufferSize)) { } @@ -209,6 +210,7 @@ void TestDelegate::OnSSLCertificateError(net::URLRequest* request, // independent of any possible errors, or whether it wants SSL errors to // cancel the request. have_certificate_errors_ = true; + is_hsts_host_ = is_hsts_host; if (allow_certificate_errors_) request->ContinueDespiteLastError(); else diff --git a/net/url_request/url_request_test_util.h b/net/url_request/url_request_test_util.h index 3407e12..11ab2b6 100644 --- a/net/url_request/url_request_test_util.h +++ b/net/url_request/url_request_test_util.h @@ -120,6 +120,7 @@ class TestDelegate : public net::URLRequest::Delegate { } bool request_failed() const { return request_failed_; } bool have_certificate_errors() const { return have_certificate_errors_; } + bool is_hsts_host() const { return is_hsts_host_; } bool auth_required_called() const { return auth_required_; } // net::URLRequest::Delegate: @@ -165,6 +166,7 @@ class TestDelegate : public net::URLRequest::Delegate { bool received_data_before_response_; bool request_failed_; bool have_certificate_errors_; + bool is_hsts_host_; bool auth_required_; std::string data_received_; diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index 86da221..e02c3fc 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc @@ -1079,6 +1079,48 @@ TEST_F(HTTPSRequestTest, HTTPSExpiredTest) { } } +// This tests that a load of www.google.com with a certificate error sets the +// is_hsts_host flag correctly. This flag will cause the interstitial to be +// fatal. +TEST_F(HTTPSRequestTest, HTTPSPreloadedHSTSTest) { + TestServer::HTTPSOptions https_options( + TestServer::HTTPSOptions::CERT_MISMATCHED_NAME); + TestServer test_server(https_options, + FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + ASSERT_TRUE(test_server.Start()); + + // We require that the URL be www.google.com in order to pick up the + // preloaded HSTS entries in the TransportSecurityState. This means that we + // have to use a MockHostResolver in order to direct www.google.com to the + // testserver. + + MockHostResolver host_resolver; + host_resolver.rules()->AddRule("www.google.com", "127.0.0.1"); + TestNetworkDelegate network_delegate; // must outlive URLRequest + scoped_refptr<TestURLRequestContext> context(new TestURLRequestContext(true)); + context->set_network_delegate(&network_delegate); + context->set_host_resolver(&host_resolver); + TransportSecurityState transport_security_state(""); + context->set_transport_security_state(&transport_security_state); + context->Init(); + + TestDelegate d; + TestURLRequest r(GURL(StringPrintf("https://www.google.com:%d", + test_server.host_port_pair().port())), + &d); + r.set_context(context); + + r.Start(); + EXPECT_TRUE(r.is_pending()); + + MessageLoop::current()->Run(); + + EXPECT_EQ(1, d.response_started_count()); + EXPECT_FALSE(d.received_data_before_response()); + EXPECT_TRUE(d.have_certificate_errors()); + EXPECT_TRUE(d.is_hsts_host()); +} + namespace { class SSLClientAuthTestDelegate : public TestDelegate { |