summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorcevans@chromium.org <cevans@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-23 01:03:10 +0000
committercevans@chromium.org <cevans@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-23 01:03:10 +0000
commit4d0d808d8a3d9bc767d01aa1c04c739ea4e22ec8 (patch)
tree6963f6ea74f16a8d15f288b6d8d8292ac33133f9 /net
parentf76850951b5929898b36d9f61284ca2d7972e6ec (diff)
downloadchromium_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.cc50
-rw-r--r--net/base/transport_security_state.h7
-rw-r--r--net/base/transport_security_state_unittest.cc49
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);
+}
+