diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/base/transport_security_state.cc | 55 | ||||
-rw-r--r-- | net/base/transport_security_state.h | 144 | ||||
-rw-r--r-- | net/base/transport_security_state_unittest.cc | 83 | ||||
-rw-r--r-- | net/url_request/url_request_unittest.cc | 8 | ||||
-rw-r--r-- | net/websockets/websocket_job_spdy2_unittest.cc | 8 | ||||
-rw-r--r-- | net/websockets/websocket_job_spdy3_unittest.cc | 8 |
6 files changed, 196 insertions, 110 deletions
diff --git a/net/base/transport_security_state.cc b/net/base/transport_security_state.cc index d61c0fb..50b4dac 100644 --- a/net/base/transport_security_state.cc +++ b/net/base/transport_security_state.cc @@ -126,14 +126,14 @@ void TransportSecurityState::EnableHost(const std::string& host, DirtyNotify(); } -bool TransportSecurityState::DeleteHost(const std::string& host) { +bool TransportSecurityState::DeleteDynamicDataForHost(const std::string& host) { DCHECK(CalledOnValidThread()); const std::string canonicalized_host = CanonicalizeHost(host); if (canonicalized_host.empty()) return false; - std::map<std::string, DomainState>::iterator i = enabled_hosts_.find( + DomainStateMap::iterator i = enabled_hosts_.find( HashHost(canonicalized_host)); if (i != enabled_hosts_.end()) { enabled_hosts_.erase(i); @@ -168,7 +168,7 @@ bool TransportSecurityState::GetDomainState(const std::string& host, return true; } - std::map<std::string, DomainState>::iterator j = + DomainStateMap::iterator j = enabled_hosts_.find(HashHost(host_sub_chunk)); if (j == enabled_hosts_.end()) continue; @@ -196,12 +196,16 @@ bool TransportSecurityState::GetDomainState(const std::string& host, return false; } -void TransportSecurityState::DeleteSince(const base::Time& time) { +void TransportSecurityState::ClearDynamicData() { + enabled_hosts_.clear(); +} + +void TransportSecurityState::DeleteAllDynamicDataSince(const base::Time& time) { DCHECK(CalledOnValidThread()); bool dirtied = false; - std::map<std::string, DomainState>::iterator i = enabled_hosts_.begin(); + DomainStateMap::iterator i = enabled_hosts_.begin(); while (i != enabled_hosts_.end()) { if (i->second.created >= time) { dirtied = true; @@ -641,6 +645,47 @@ bool TransportSecurityState::AddHPKPHeader(const std::string& host, return false; } +bool TransportSecurityState::AddHSTS(const std::string& host, + const base::Time& expiry, + bool include_subdomains) { + // Copy-and-modify the existing DomainState for this host (if any). + TransportSecurityState::DomainState domain_state; + const std::string canonicalized_host = CanonicalizeHost(host); + const std::string hashed_host = HashHost(canonicalized_host); + DomainStateMap::const_iterator i = enabled_hosts_.find( + hashed_host); + if (i != enabled_hosts_.end()) + domain_state = i->second; + + domain_state.created = base::Time::Now(); + domain_state.include_subdomains = include_subdomains; + domain_state.upgrade_expiry = expiry; + domain_state.upgrade_mode = DomainState::MODE_FORCE_HTTPS; + EnableHost(host, domain_state); + return true; +} + +bool TransportSecurityState::AddHPKP(const std::string& host, + const base::Time& expiry, + bool include_subdomains, + const HashValueVector& hashes) { + // Copy-and-modify the existing DomainState for this host (if any). + TransportSecurityState::DomainState domain_state; + const std::string canonicalized_host = CanonicalizeHost(host); + const std::string hashed_host = HashHost(canonicalized_host); + DomainStateMap::const_iterator i = enabled_hosts_.find( + hashed_host); + if (i != enabled_hosts_.end()) + domain_state = i->second; + + domain_state.created = base::Time::Now(); + domain_state.include_subdomains = include_subdomains; + domain_state.dynamic_spki_hashes_expiry = expiry; + domain_state.dynamic_spki_hashes = hashes; + EnableHost(host, domain_state); + return true; +} + // static bool TransportSecurityState::IsGooglePinnedProperty(const std::string& host, bool sni_enabled) { diff --git a/net/base/transport_security_state.h b/net/base/transport_security_state.h index ca9dec4..8eb76d1 100644 --- a/net/base/transport_security_state.h +++ b/net/base/transport_security_state.h @@ -158,24 +158,51 @@ class NET_EXPORT TransportSecurityState }; // Assign a |Delegate| for persisting the transport security state. If - // |NULL|, state will not be persisted. Caller owns |delegate|. + // |NULL|, state will not be persisted. The caller retains + // ownership of |delegate|. + // Note: This is only used for serializing/deserializing the + // TransportSecurityState. void SetDelegate(Delegate* delegate); - // Enable TransportSecurity for |host|. |state| supercedes any previous - // state for the |host|, including static entries. + // Clears all dynamic data (e.g. HSTS and HPKP data). // - // The new state for |host| is persisted using the Delegate (if any). - void EnableHost(const std::string& host, const DomainState& state); + // Does NOT persist changes using the Delegate, as this function is only + // used to clear any dynamic data prior to re-loading it from a file. + // Note: This is only used for serializing/deserializing the + // TransportSecurityState. + void ClearDynamicData(); - // Delete any entry for |host|. If |host| doesn't have an exact entry then - // no action is taken. Does not delete static entries. Returns true iff an - // entry was deleted. - // - // The new state for |host| is persisted using the Delegate (if any). - bool DeleteHost(const std::string& host); + // Inserts |state| into |enabled_hosts_| under the key |hashed_host|. + // |hashed_host| is already in the internal representation + // HashHost(CanonicalizeHost(host)). + // Note: This is only used for serializing/deserializing the + // TransportSecurityState. + void AddOrUpdateEnabledHosts(const std::string& hashed_host, + const DomainState& state); + + // Inserts |state| into |forced_hosts_| under the key |hashed_host|. + // |hashed_host| is already in the internal representation + // HashHost(CanonicalizeHost(host)). + // Note: This is only used for serializing/deserializing the + // TransportSecurityState. + void AddOrUpdateForcedHosts(const std::string& hashed_host, + const DomainState& state); - // Deletes all records created since a given time. - void DeleteSince(const base::Time& time); + // Deletes all dynamic data (e.g. HSTS or HPKP data) created since a given + // time. + // + // If any entries are deleted, the new state will be persisted through + // the Delegate (if any). + void DeleteAllDynamicDataSince(const base::Time& time); + + // Deletes any dynamic data stored for |host| (e.g. HSTS or HPKP data). + // If |host| doesn't have an exact entry then no action is taken. Does + // not delete static (i.e. preloaded) data. Returns true iff an entry + // was deleted. + // + // If an entry is deleted, the new state will be persisted through + // the Delegate (if any). + bool DeleteDynamicDataForHost(const std::string& host); // Returns true and updates |*result| iff there is a DomainState for // |host|. @@ -192,42 +219,6 @@ class NET_EXPORT TransportSecurityState bool sni_enabled, DomainState* result); - // Returns true and updates |*result| iff there is a static DomainState for - // |host|. - // - // |GetStaticDomainState| is identical to |GetDomainState| except that it - // searches only the statically-defined transport security state, ignoring - // all dynamically-added DomainStates. - // - // If |sni_enabled| is true, searches the static pins defined for - // SNI-using hosts as well as the rest of the pins. - // - // If |host| matches both an exact entry and is a subdomain of another - // entry, the exact match determines the return value. - // - // Note that this method is not const because it opportunistically removes - // entries that have expired. - bool GetStaticDomainState(const std::string& host, - bool sni_enabled, - DomainState* result); - - // Removed all DomainState records. - void Clear() { enabled_hosts_.clear(); } - - // Inserts |state| into |enabled_hosts_| under the key |hashed_host|. - // |hashed_host| is already in the internal representation - // HashHost(CanonicalizeHost(host)); thus, most callers will use - // |EnableHost|. - void AddOrUpdateEnabledHosts(const std::string& hashed_host, - const DomainState& state); - - // Inserts |state| into |forced_hosts_| under the key |hashed_host|. - // |hashed_host| is already in the internal representation - // HashHost(CanonicalizeHost(host)); thus, most callers will use - // |EnableHost|. - void AddOrUpdateForcedHosts(const std::string& hashed_host, - const DomainState& state); - // Processes an HSTS header value from the host, adding entries to // dynamic state if necessary. bool AddHSTSHeader(const std::string& host, const std::string& value); @@ -238,6 +229,16 @@ class NET_EXPORT TransportSecurityState bool AddHPKPHeader(const std::string& host, const std::string& value, const SSLInfo& ssl_info); + // Adds explicitly-specified data as if it was processed from an + // HSTS header (used for net-internals and unit tests). + bool AddHSTS(const std::string& host, const base::Time& expiry, + bool include_subdomains); + + // Adds explicitly-specified data as if it was processed from an + // HPKP header (used for net-internals and unit tests). + bool AddHPKP(const std::string& host, const base::Time& expiry, + bool include_subdomains, const HashValueVector& hashes); + // Returns true iff we have any static public key pins for the |host| and // iff its set of required pins is the set we expect for Google // properties. @@ -253,11 +254,6 @@ class NET_EXPORT TransportSecurityState // The maximum number of seconds for which we'll cache an HSTS request. static const long int kMaxHSTSAgeSecs; - // Converts |hostname| from dotted form ("www.google.com") to the form - // used in DNS: "\x03www\x06google\x03com", lowercases that, and returns - // the result. - static std::string CanonicalizeHost(const std::string& hostname); - // Send an UMA report on pin validation failure, if the host is in a // statically-defined list of domains. // @@ -268,24 +264,56 @@ class NET_EXPORT TransportSecurityState // to the caller with |GetStaticDomainState|. static void ReportUMAOnPinFailure(const std::string& host); - static const char* HashValueLabel(const HashValue& hash_value); - // IsBuildTimely returns true if the current build is new enough ensure that // built in security information (i.e. HSTS preloading and pinning // information) is timely. static bool IsBuildTimely(); private: + friend class TransportSecurityStateTest; + + typedef std::map<std::string, DomainState> DomainStateMap; + // If a Delegate is present, notify it that the internal state has // changed. void DirtyNotify(); + // Enable TransportSecurity for |host|. |state| supercedes any previous + // state for the |host|, including static entries. + // + // The new state for |host| is persisted using the Delegate (if any). + void EnableHost(const std::string& host, const DomainState& state); + + // Converts |hostname| from dotted form ("www.google.com") to the form + // used in DNS: "\x03www\x06google\x03com", lowercases that, and returns + // the result. + static std::string CanonicalizeHost(const std::string& hostname); + + // Returns true and updates |*result| iff there is a static DomainState for + // |host|. + // + // |GetStaticDomainState| is identical to |GetDomainState| except that it + // searches only the statically-defined transport security state, ignoring + // all dynamically-added DomainStates. + // + // If |sni_enabled| is true, searches the static pins defined for + // SNI-using hosts as well as the rest of the pins. + // + // If |host| matches both an exact entry and is a subdomain of another + // entry, the exact match determines the return value. + // + // Note that this method is not const because it opportunistically removes + // entries that have expired. + bool GetStaticDomainState(const std::string& host, + bool sni_enabled, + DomainState* result); + // The set of hosts that have enabled TransportSecurity. - std::map<std::string, DomainState> enabled_hosts_; + DomainStateMap enabled_hosts_; // Extra entries, provided by the user at run-time, to treat as if they // were static. - std::map<std::string, DomainState> forced_hosts_; + DomainStateMap forced_hosts_; Delegate* delegate_; diff --git a/net/base/transport_security_state_unittest.cc b/net/base/transport_security_state_unittest.cc index 025faea..0d0a58f 100644 --- a/net/base/transport_security_state_unittest.cc +++ b/net/base/transport_security_state_unittest.cc @@ -44,6 +44,24 @@ class TransportSecurityStateTest : public testing::Test { crypto::EnsureNSSInit(); #endif } + + protected: + std::string CanonicalizeHost(const std::string& host) { + return TransportSecurityState::CanonicalizeHost(host); + } + + bool GetStaticDomainState(TransportSecurityState* state, + const std::string& host, + bool sni_enabled, + TransportSecurityState::DomainState* result) { + return state->GetStaticDomainState(host, sni_enabled, result); + } + + void EnableHost(TransportSecurityState* state, + const std::string& host, + const TransportSecurityState::DomainState& domain_state) { + return state->EnableHost(host, domain_state); + } }; TEST_F(TransportSecurityStateTest, SimpleMatches) { @@ -53,8 +71,8 @@ TEST_F(TransportSecurityStateTest, SimpleMatches) { 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); + bool include_subdomains = false; + state.AddHSTS("yahoo.com", expiry, include_subdomains); EXPECT_TRUE(state.GetDomainState("yahoo.com", true, &domain_state)); } @@ -65,8 +83,8 @@ TEST_F(TransportSecurityStateTest, MatchesCase1) { 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); + bool include_subdomains = false; + state.AddHSTS("YAhoo.coM", expiry, include_subdomains); EXPECT_TRUE(state.GetDomainState("yahoo.com", true, &domain_state)); } @@ -77,8 +95,8 @@ TEST_F(TransportSecurityStateTest, MatchesCase2) { 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); + bool include_subdomains = false; + state.AddHSTS("yahoo.com", expiry, include_subdomains); EXPECT_TRUE(state.GetDomainState("YAhoo.coM", true, &domain_state)); } @@ -89,9 +107,8 @@ TEST_F(TransportSecurityStateTest, SubdomainMatches) { 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); + bool include_subdomains = true; + state.AddHSTS("yahoo.com", expiry, include_subdomains); 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)); @@ -100,7 +117,7 @@ TEST_F(TransportSecurityStateTest, SubdomainMatches) { EXPECT_FALSE(state.GetDomainState("com", true, &domain_state)); } -TEST_F(TransportSecurityStateTest, DeleteSince) { +TEST_F(TransportSecurityStateTest, DeleteAllDynamicDataSince) { TransportSecurityState state; TransportSecurityState::DomainState domain_state; const base::Time current_time(base::Time::Now()); @@ -108,57 +125,53 @@ TEST_F(TransportSecurityStateTest, DeleteSince) { 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); + bool include_subdomains = false; + state.AddHSTS("yahoo.com", expiry, include_subdomains); - state.DeleteSince(expiry); + state.DeleteAllDynamicDataSince(expiry); EXPECT_TRUE(state.GetDomainState("yahoo.com", true, &domain_state)); - state.DeleteSince(older); + state.DeleteAllDynamicDataSince(older); EXPECT_FALSE(state.GetDomainState("yahoo.com", true, &domain_state)); } -TEST_F(TransportSecurityStateTest, DeleteHost) { +TEST_F(TransportSecurityStateTest, DeleteDynamicDataForHost) { 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); + bool include_subdomains = false; + state.AddHSTS("yahoo.com", expiry, include_subdomains); 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_TRUE(state.DeleteDynamicDataForHost("yahoo.com")); EXPECT_FALSE(state.GetDomainState("yahoo.com", true, &domain_state)); } TEST_F(TransportSecurityStateTest, IsPreloaded) { const std::string paypal = - TransportSecurityState::CanonicalizeHost("paypal.com"); + CanonicalizeHost("paypal.com"); const std::string www_paypal = - TransportSecurityState::CanonicalizeHost("www.paypal.com"); + CanonicalizeHost("www.paypal.com"); const std::string a_www_paypal = - TransportSecurityState::CanonicalizeHost("a.www.paypal.com"); + CanonicalizeHost("a.www.paypal.com"); const std::string abc_paypal = - TransportSecurityState::CanonicalizeHost("a.b.c.paypal.com"); + CanonicalizeHost("a.b.c.paypal.com"); const std::string example = - TransportSecurityState::CanonicalizeHost("example.com"); + CanonicalizeHost("example.com"); const std::string aypal = - TransportSecurityState::CanonicalizeHost("aypal.com"); + 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(GetStaticDomainState(&state, paypal, true, &domain_state)); + EXPECT_TRUE(GetStaticDomainState(&state, 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)); + EXPECT_FALSE(GetStaticDomainState(&state, a_www_paypal, true, &domain_state)); + EXPECT_FALSE(GetStaticDomainState(&state, abc_paypal, true, &domain_state)); + EXPECT_FALSE(GetStaticDomainState(&state, example, true, &domain_state)); + EXPECT_FALSE(GetStaticDomainState(&state, aypal, true, &domain_state)); } TEST_F(TransportSecurityStateTest, PreloadedDomainSet) { @@ -733,7 +746,7 @@ TEST_F(TransportSecurityStateTest, OverrideBuiltins) { 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); + EnableHost(&state, "www.google.com", domain_state); EXPECT_TRUE(state.GetDomainState("www.google.com", true, &domain_state)); } diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index 28df2a1..0967bd9 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc @@ -4393,10 +4393,10 @@ TEST_F(HTTPSRequestTest, HSTSPreservesPosts) { // Force https for www.somewhere.com. TransportSecurityState transport_security_state; - net::TransportSecurityState::DomainState domain_state; - domain_state.upgrade_expiry = - domain_state.created + base::TimeDelta::FromDays(1000); - transport_security_state.EnableHost("www.somewhere.com", domain_state); + base::Time expiry = base::Time::Now() + base::TimeDelta::FromDays(1000); + bool include_subdomains = false; + transport_security_state.AddHSTS("www.somewhere.com", expiry, + include_subdomains); TestNetworkDelegate network_delegate; // Must outlive URLRequest. diff --git a/net/websockets/websocket_job_spdy2_unittest.cc b/net/websockets/websocket_job_spdy2_unittest.cc index ee7c6fd..df5fe21 100644 --- a/net/websockets/websocket_job_spdy2_unittest.cc +++ b/net/websockets/websocket_job_spdy2_unittest.cc @@ -245,10 +245,10 @@ class MockURLRequestContext : public net::URLRequestContext { : transport_security_state_() { set_cookie_store(cookie_store); set_transport_security_state(&transport_security_state_); - net::TransportSecurityState::DomainState state; - state.upgrade_expiry = base::Time::Now() + - base::TimeDelta::FromSeconds(1000); - transport_security_state_.EnableHost("upgrademe.com", state); + base::Time expiry = base::Time::Now() + base::TimeDelta::FromDays(1000); + bool include_subdomains = false; + transport_security_state_.AddHSTS("upgrademe.com", expiry, + include_subdomains); } virtual ~MockURLRequestContext() {} diff --git a/net/websockets/websocket_job_spdy3_unittest.cc b/net/websockets/websocket_job_spdy3_unittest.cc index b4f0e55..9027808 100644 --- a/net/websockets/websocket_job_spdy3_unittest.cc +++ b/net/websockets/websocket_job_spdy3_unittest.cc @@ -249,10 +249,10 @@ class MockURLRequestContext : public net::URLRequestContext { : transport_security_state_() { set_cookie_store(cookie_store); set_transport_security_state(&transport_security_state_); - net::TransportSecurityState::DomainState state; - state.upgrade_expiry = base::Time::Now() + - base::TimeDelta::FromSeconds(1000); - transport_security_state_.EnableHost("upgrademe.com", state); + base::Time expiry = base::Time::Now() + base::TimeDelta::FromDays(1000); + bool include_subdomains = false; + transport_security_state_.AddHSTS("upgrademe.com", expiry, + include_subdomains); } virtual ~MockURLRequestContext() {} |