diff options
author | cevans@chromium.org <cevans@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-23 01:03:10 +0000 |
---|---|---|
committer | cevans@chromium.org <cevans@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-23 01:03:10 +0000 |
commit | 4d0d808d8a3d9bc767d01aa1c04c739ea4e22ec8 (patch) | |
tree | 6963f6ea74f16a8d15f288b6d8d8292ac33133f9 /net | |
parent | f76850951b5929898b36d9f61284ca2d7972e6ec (diff) | |
download | chromium_src-4d0d808d8a3d9bc767d01aa1c04c739ea4e22ec8.zip chromium_src-4d0d808d8a3d9bc767d01aa1c04c739ea4e22ec8.tar.gz chromium_src-4d0d808d8a3d9bc767d01aa1c04c739ea4e22ec8.tar.bz2 |
Tie the lifetime of persisted transport-security metatdata to clearing cookies,
thus giving the user control over it.
This involved adding in a "creation" date to the metadata so we can respect the
user's choice of how far back to go when deleting browsing data. Care is taken
to handle older metadata without the creation date set.
Also fix a bug whereby we weren't making sure to persist the removed metadata
when it expires.
BUG=33445
TEST=TransportSecurityStateTest.DeleteSince, TransportSecurityStateTest.SerializeOld
Review URL: http://codereview.chromium.org/652035
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@39684 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/base/transport_security_state.cc | 50 | ||||
-rw-r--r-- | net/base/transport_security_state.h | 7 | ||||
-rw-r--r-- | net/base/transport_security_state_unittest.cc | 49 |
3 files changed, 99 insertions, 7 deletions
diff --git a/net/base/transport_security_state.cc b/net/base/transport_security_state.cc index 35b930c..54d8cce 100644 --- a/net/base/transport_security_state.cc +++ b/net/base/transport_security_state.cc @@ -30,9 +30,15 @@ void TransportSecurityState::EnableHost(const std::string& host, char hashed[base::SHA256_LENGTH]; base::SHA256HashString(canonicalised_host, hashed, sizeof(hashed)); + // Use the original creation date if we already have this host. + DomainState state_copy(state); + DomainState existing_state; + if (IsEnabledForHost(&existing_state, host)) + state_copy.created = existing_state.created; + AutoLock lock(lock_); - enabled_hosts_[std::string(hashed, sizeof(hashed))] = state; + enabled_hosts_[std::string(hashed, sizeof(hashed))] = state_copy; DirtyNotify(); } @@ -209,6 +215,7 @@ bool TransportSecurityState::Serialise(std::string* output) { i = enabled_hosts_.begin(); i != enabled_hosts_.end(); ++i) { DictionaryValue* state = new DictionaryValue; state->SetBoolean(L"include_subdomains", i->second.include_subdomains); + state->SetReal(L"created", i->second.created.ToDoubleT()); state->SetReal(L"expiry", i->second.expiry.ToDoubleT()); switch (i->second.mode) { @@ -234,7 +241,8 @@ bool TransportSecurityState::Serialise(std::string* output) { return true; } -bool TransportSecurityState::Deserialise(const std::string& input) { +bool TransportSecurityState::Deserialise(const std::string& input, + bool* dirty) { AutoLock lock(lock_); enabled_hosts_.clear(); @@ -246,6 +254,7 @@ bool TransportSecurityState::Deserialise(const std::string& input) { DictionaryValue* dict_value = reinterpret_cast<DictionaryValue*>(value.get()); const base::Time current_time(base::Time::Now()); + bool dirtied = false; for (DictionaryValue::key_iterator i = dict_value->begin_keys(); i != dict_value->end_keys(); ++i) { @@ -255,6 +264,7 @@ bool TransportSecurityState::Deserialise(const std::string& input) { bool include_subdomains; std::string mode_string; + double created; double expiry; if (!state->GetBoolean(L"include_subdomains", &include_subdomains) || @@ -277,8 +287,21 @@ bool TransportSecurityState::Deserialise(const std::string& input) { } base::Time expiry_time = base::Time::FromDoubleT(expiry); - if (expiry_time <= current_time) + base::Time created_time; + if (state->GetReal(L"created", &created)) { + created_time = base::Time::FromDoubleT(created); + } else { + // We're migrating an old entry with no creation date. Make sure we + // write the new date back in a reasonable time frame. + dirtied = true; + created_time = base::Time::Now(); + } + + if (expiry_time <= current_time) { + // Make sure we dirty the state if we drop an entry. + dirtied = true; continue; + } std::string hashed = ExternalStringToHashedDomain(*i); if (hashed.empty()) @@ -286,14 +309,35 @@ bool TransportSecurityState::Deserialise(const std::string& input) { DomainState new_state; new_state.mode = mode; + new_state.created = created_time; new_state.expiry = expiry_time; new_state.include_subdomains = include_subdomains; enabled_hosts_[hashed] = new_state; } + *dirty = dirtied; return true; } +void TransportSecurityState::DeleteSince(const base::Time& time) { + bool dirtied = false; + + AutoLock lock(lock_); + + std::map<std::string, DomainState>::iterator i = enabled_hosts_.begin(); + while (i != enabled_hosts_.end()) { + if (i->second.created >= time) { + dirtied = true; + enabled_hosts_.erase(i++); + } else { + i++; + } + } + + if (dirtied) + DirtyNotify(); +} + void TransportSecurityState::DirtyNotify() { if (delegate_) delegate_->StateIsDirty(this); diff --git a/net/base/transport_security_state.h b/net/base/transport_security_state.h index 360eb0b..523f28e 100644 --- a/net/base/transport_security_state.h +++ b/net/base/transport_security_state.h @@ -48,8 +48,10 @@ class TransportSecurityState : DomainState() : mode(MODE_STRICT), + created(base::Time::Now()), include_subdomains(false) { } + base::Time created; // when this host entry was first created base::Time expiry; // the absolute time (UTC) when this record expires bool include_subdomains; // subdomains included? }; @@ -61,6 +63,9 @@ class TransportSecurityState : // *result is filled out. bool IsEnabledForHost(DomainState* result, const std::string& host); + // Deletes all records created since a given time. + void DeleteSince(const base::Time& time); + // Returns |true| if |value| parses as a valid *-Transport-Security // header value. The values of max-age and and includeSubDomains are // returned in |max_age| and |include_subdomains|, respectively. The out @@ -79,7 +84,7 @@ class TransportSecurityState : void SetDelegate(Delegate*); bool Serialise(std::string* output); - bool Deserialise(const std::string& state); + bool Deserialise(const std::string& state, bool* dirty); private: friend class base::RefCountedThreadSafe<TransportSecurityState>; diff --git a/net/base/transport_security_state_unittest.cc b/net/base/transport_security_state_unittest.cc index f52912c..2561b0b 100644 --- a/net/base/transport_security_state_unittest.cc +++ b/net/base/transport_security_state_unittest.cc @@ -190,8 +190,10 @@ TEST_F(TransportSecurityStateTest, Serialise1) { scoped_refptr<net::TransportSecurityState> state( new net::TransportSecurityState); std::string output; + bool dirty; state->Serialise(&output); - EXPECT_TRUE(state->Deserialise(output)); + EXPECT_TRUE(state->Deserialise(output, &dirty)); + EXPECT_FALSE(dirty); } TEST_F(TransportSecurityStateTest, Serialise2) { @@ -209,8 +211,9 @@ TEST_F(TransportSecurityStateTest, Serialise2) { state->EnableHost("google.com", domain_state); std::string output; + bool dirty; state->Serialise(&output); - EXPECT_TRUE(state->Deserialise(output)); + EXPECT_TRUE(state->Deserialise(output, &dirty)); EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "google.com")); EXPECT_EQ(domain_state.mode, net::TransportSecurityState::DomainState::MODE_STRICT); @@ -238,10 +241,50 @@ TEST_F(TransportSecurityStateTest, Serialise3) { state->EnableHost("google.com", domain_state); std::string output; + bool dirty; state->Serialise(&output); - EXPECT_TRUE(state->Deserialise(output)); + EXPECT_TRUE(state->Deserialise(output, &dirty)); EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "google.com")); EXPECT_EQ(domain_state.mode, net::TransportSecurityState::DomainState::MODE_OPPORTUNISTIC); } + +TEST_F(TransportSecurityStateTest, DeleteSince) { + scoped_refptr<net::TransportSecurityState> state( + new net::TransportSecurityState); + + net::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.expiry = expiry; + state->EnableHost("google.com", domain_state); + + state->DeleteSince(expiry); + EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "google.com")); + state->DeleteSince(older); + EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "google.com")); +} + +TEST_F(TransportSecurityStateTest, SerialiseOld) { + scoped_refptr<net::TransportSecurityState> state( + new net::TransportSecurityState); + // This is an old-style piece of transport state JSON, which has no creation + // date. + std::string output = + "{ " + "\"NiyD+3J1r6z1wjl2n1ALBu94Zj9OsEAMo0kCN8js0Uk=\": {" + "\"expiry\": 1266815027.983453, " + "\"include_subdomains\": false, " + "\"mode\": \"strict\" " + "}" + "}"; + bool dirty; + EXPECT_TRUE(state->Deserialise(output, &dirty)); + EXPECT_TRUE(dirty); +} + |