summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authoragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-17 17:20:28 +0000
committeragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-17 17:20:28 +0000
commitf060be3754a92a80e2f4402bde51763663f444d9 (patch)
treed2805ea3f4600fcdad167345501e1f17111ec2f5 /net
parentf2e430a18f74fcb5972945c05cc08aa321ca6953 (diff)
downloadchromium_src-f060be3754a92a80e2f4402bde51763663f444d9.zip
chromium_src-f060be3754a92a80e2f4402bde51763663f444d9.tar.gz
chromium_src-f060be3754a92a80e2f4402bde51763663f444d9.tar.bz2
HSTS: add net-internals UI.
This change adds a simple DOMUI interface to the HSTS list. Since the list is stored, hashed in memory and on disk, there's no list of entries. But the set can be queried and we can provide insertion and deletion. BUG=none TEST=Open about:net-internals, goto HSTS tab. Review URL: http://codereview.chromium.org/6500010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@75282 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/base/dns_util.cc18
-rw-r--r--net/base/dns_util.h3
-rw-r--r--net/base/dns_util_unittest.cc15
-rw-r--r--net/base/transport_security_state.cc58
-rw-r--r--net/base/transport_security_state.h15
-rw-r--r--net/base/transport_security_state_unittest.cc34
6 files changed, 119 insertions, 24 deletions
diff --git a/net/base/dns_util.cc b/net/base/dns_util.cc
index f1e0de4..d97d3d2 100644
--- a/net/base/dns_util.cc
+++ b/net/base/dns_util.cc
@@ -56,6 +56,24 @@ bool DNSDomainFromDot(const std::string& dotted, std::string* out) {
return true;
}
+std::string DNSDomainToString(const std::string& domain) {
+ std::string ret;
+
+ for (unsigned i = 0; i < domain.size() && domain[i]; i += domain[i] + 1) {
+ if (domain[i] < 0 || domain[i] > 63)
+ return "";
+
+ if (i)
+ ret += ".";
+
+ if (static_cast<unsigned>(domain[i]) + i + 1 > domain.size())
+ return "";
+
+ ret += domain.substr(i + 1, domain[i]);
+ }
+ return ret;
+}
+
bool IsSTD3ASCIIValidCharacter(char c) {
if (c <= 0x2c)
return false;
diff --git a/net/base/dns_util.h b/net/base/dns_util.h
index d86fcb9..40e8736 100644
--- a/net/base/dns_util.h
+++ b/net/base/dns_util.h
@@ -19,6 +19,9 @@ namespace net {
// out: a result in DNS form: "\x03www\x06google\x03com\x00"
bool DNSDomainFromDot(const std::string& dotted, std::string* out);
+// DNSDomainToString coverts a domain in DNS format to a dotted string.
+std::string DNSDomainToString(const std::string& domain);
+
// Returns true iff the given character is in the set of valid DNS label
// characters as given in RFC 3490, 4.1, 3(a)
bool IsSTD3ASCIIValidCharacter(char c);
diff --git a/net/base/dns_util_unittest.cc b/net/base/dns_util_unittest.cc
index feeba55..103e9a7 100644
--- a/net/base/dns_util_unittest.cc
+++ b/net/base/dns_util_unittest.cc
@@ -53,6 +53,21 @@ TEST_F(DNSUtilTest, DNSDomainFromDot) {
EXPECT_EQ(out, IncludeNUL("\003www\006google\003com"));
}
+TEST_F(DNSUtilTest, DNSDomainToString) {
+ EXPECT_EQ("", DNSDomainToString(IncludeNUL("")));
+ EXPECT_EQ("foo", DNSDomainToString(IncludeNUL("\003foo")));
+ EXPECT_EQ("foo.bar", DNSDomainToString(IncludeNUL("\003foo\003bar")));
+ EXPECT_EQ("foo.bar.uk",
+ DNSDomainToString(IncludeNUL("\003foo\003bar\002uk")));
+
+ // It should cope with a lack of root label.
+ EXPECT_EQ("foo.bar", DNSDomainToString("\003foo\003bar"));
+
+ // Invalid inputs should return an empty string.
+ EXPECT_EQ("", DNSDomainToString(IncludeNUL("\x80")));
+ EXPECT_EQ("", DNSDomainToString("\x06"));
+}
+
TEST_F(DNSUtilTest, STD3ASCII) {
EXPECT_TRUE(IsSTD3ASCIIValidCharacter('a'));
EXPECT_TRUE(IsSTD3ASCIIValidCharacter('b'));
diff --git a/net/base/transport_security_state.cc b/net/base/transport_security_state.cc
index d4cea15..d2ec579 100644
--- a/net/base/transport_security_state.cc
+++ b/net/base/transport_security_state.cc
@@ -28,16 +28,16 @@ TransportSecurityState::TransportSecurityState()
void TransportSecurityState::EnableHost(const std::string& host,
const DomainState& state) {
- const std::string canonicalised_host = CanonicaliseHost(host);
- if (canonicalised_host.empty())
+ const std::string canonicalized_host = CanonicalizeHost(host);
+ if (canonicalized_host.empty())
return;
bool temp;
- if (IsPreloadedSTS(canonicalised_host, &temp))
+ if (IsPreloadedSTS(canonicalized_host, &temp))
return;
char hashed[base::SHA256_LENGTH];
- base::SHA256HashString(canonicalised_host, hashed, sizeof(hashed));
+ base::SHA256HashString(canonicalized_host, hashed, sizeof(hashed));
// Use the original creation date if we already have this host.
DomainState state_copy(state);
@@ -45,10 +45,32 @@ void TransportSecurityState::EnableHost(const std::string& host,
if (IsEnabledForHost(&existing_state, host))
state_copy.created = existing_state.created;
+ // We don't store these values.
+ state_copy.preloaded = false;
+ state_copy.domain.clear();
+
enabled_hosts_[std::string(hashed, sizeof(hashed))] = state_copy;
DirtyNotify();
}
+bool TransportSecurityState::DeleteHost(const std::string& host) {
+ const std::string canonicalized_host = CanonicalizeHost(host);
+ if (canonicalized_host.empty())
+ return false;
+
+ char hashed[base::SHA256_LENGTH];
+ base::SHA256HashString(canonicalized_host, hashed, sizeof(hashed));
+
+ std::map<std::string, DomainState>::iterator i = enabled_hosts_.find(
+ std::string(hashed, sizeof(hashed)));
+ if (i != enabled_hosts_.end()) {
+ enabled_hosts_.erase(i);
+ DirtyNotify();
+ return true;
+ }
+ return false;
+}
+
// IncludeNUL converts a char* to a std::string and includes the terminating
// NUL in the result.
static std::string IncludeNUL(const char* in) {
@@ -57,24 +79,28 @@ static std::string IncludeNUL(const char* in) {
bool TransportSecurityState::IsEnabledForHost(DomainState* result,
const std::string& host) {
- const std::string canonicalised_host = CanonicaliseHost(host);
- if (canonicalised_host.empty())
+ *result = DomainState();
+
+ const std::string canonicalized_host = CanonicalizeHost(host);
+ if (canonicalized_host.empty())
return false;
bool include_subdomains;
- if (IsPreloadedSTS(canonicalised_host, &include_subdomains)) {
+ if (IsPreloadedSTS(canonicalized_host, &include_subdomains)) {
result->created = result->expiry = base::Time::FromTimeT(0);
result->mode = DomainState::MODE_STRICT;
result->include_subdomains = include_subdomains;
+ result->preloaded = true;
return true;
}
+ result->preloaded = false;
base::Time current_time(base::Time::Now());
- for (size_t i = 0; canonicalised_host[i]; i += canonicalised_host[i] + 1) {
+ for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) {
char hashed_domain[base::SHA256_LENGTH];
- base::SHA256HashString(IncludeNUL(&canonicalised_host[i]), &hashed_domain,
+ base::SHA256HashString(IncludeNUL(&canonicalized_host[i]), &hashed_domain,
sizeof(hashed_domain));
std::map<std::string, DomainState>::iterator j =
enabled_hosts_.find(std::string(hashed_domain, sizeof(hashed_domain)));
@@ -88,6 +114,8 @@ bool TransportSecurityState::IsEnabledForHost(DomainState* result,
}
*result = j->second;
+ result->domain = DNSDomainToString(
+ canonicalized_host.substr(i, canonicalized_host.size() - i));
// If we matched the domain exactly, it doesn't matter what the value of
// include_subdomains is.
@@ -376,7 +404,7 @@ void TransportSecurityState::DirtyNotify() {
}
// static
-std::string TransportSecurityState::CanonicaliseHost(const std::string& host) {
+std::string TransportSecurityState::CanonicalizeHost(const std::string& host) {
// We cannot perform the operations as detailed in the spec here as |host|
// has already undergone IDN processing before it reached us. Thus, we check
// that there are no invalid characters in the host and lowercase the result.
@@ -411,11 +439,11 @@ std::string TransportSecurityState::CanonicaliseHost(const std::string& host) {
return new_host;
}
-// IsPreloadedSTS returns true if the canonicalised hostname should always be
+// IsPreloadedSTS returns true if the canonicalized hostname should always be
// considered to have STS enabled.
// static
bool TransportSecurityState::IsPreloadedSTS(
- const std::string& canonicalised_host, bool *include_subdomains) {
+ const std::string& canonicalized_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 {
@@ -442,11 +470,11 @@ bool TransportSecurityState::IsPreloadedSTS(
};
static const size_t kNumPreloadedSTS = ARRAYSIZE_UNSAFE(kPreloadedSTS);
- for (size_t i = 0; canonicalised_host[i]; i += canonicalised_host[i] + 1) {
+ for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) {
for (size_t j = 0; j < kNumPreloadedSTS; j++) {
- if (kPreloadedSTS[j].length == canonicalised_host.size() - i &&
+ if (kPreloadedSTS[j].length == canonicalized_host.size() - i &&
(kPreloadedSTS[j].include_subdomains || i == 0) &&
- memcmp(kPreloadedSTS[j].dns_name, &canonicalised_host[i],
+ memcmp(kPreloadedSTS[j].dns_name, &canonicalized_host[i],
kPreloadedSTS[j].length) == 0) {
*include_subdomains = kPreloadedSTS[j].include_subdomains;
return true;
diff --git a/net/base/transport_security_state.h b/net/base/transport_security_state.h
index 768ccbb..05061ca 100644
--- a/net/base/transport_security_state.h
+++ b/net/base/transport_security_state.h
@@ -47,17 +47,26 @@ class TransportSecurityState :
DomainState()
: mode(MODE_STRICT),
created(base::Time::Now()),
- include_subdomains(false) { }
+ include_subdomains(false),
+ preloaded(false) { }
Mode mode;
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?
+
+ // The follow members are not valid when stored in |enabled_hosts_|.
+ bool preloaded; // is this a preloaded entry?
+ std::string domain; // the domain which matched
};
// Enable TransportSecurity for |host|.
void EnableHost(const std::string& host, const DomainState& state);
+ // Delete any entry for |host|. If |host| doesn't have an exact entry then no
+ // action is taken. Returns true iff an entry was deleted.
+ bool DeleteHost(const std::string& host);
+
// Returns true if |host| has TransportSecurity enabled. If that case,
// *result is filled out.
bool IsEnabledForHost(DomainState* result, const std::string& host);
@@ -101,8 +110,8 @@ class TransportSecurityState :
// our state is dirty.
void DirtyNotify();
- static std::string CanonicaliseHost(const std::string& host);
- static bool IsPreloadedSTS(const std::string& canonicalised_host,
+ static std::string CanonicalizeHost(const std::string& host);
+ static bool IsPreloadedSTS(const std::string& canonicalized_host,
bool* out_include_subdomains);
// The set of hosts that have enabled TransportSecurity. The keys here
diff --git a/net/base/transport_security_state_unittest.cc b/net/base/transport_security_state_unittest.cc
index 3c81c69..3eabc06 100644
--- a/net/base/transport_security_state_unittest.cc
+++ b/net/base/transport_security_state_unittest.cc
@@ -281,6 +281,23 @@ TEST_F(TransportSecurityStateTest, DeleteSince) {
EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "google.com"));
}
+TEST_F(TransportSecurityStateTest, DeleteHost) {
+ 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);
+ domain_state.mode = TransportSecurityState::DomainState::MODE_STRICT;
+ domain_state.expiry = expiry;
+ state->EnableHost("google.com", domain_state);
+
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "google.com"));
+ EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "example.com"));
+ EXPECT_TRUE(state->DeleteHost("google.com"));
+ EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "google.com"));
+}
+
TEST_F(TransportSecurityStateTest, SerialiseOld) {
scoped_refptr<TransportSecurityState> state(
new TransportSecurityState);
@@ -301,17 +318,17 @@ TEST_F(TransportSecurityStateTest, SerialiseOld) {
TEST_F(TransportSecurityStateTest, IsPreloaded) {
const std::string paypal =
- TransportSecurityState::CanonicaliseHost("paypal.com");
+ TransportSecurityState::CanonicalizeHost("paypal.com");
const std::string www_paypal =
- TransportSecurityState::CanonicaliseHost("www.paypal.com");
+ TransportSecurityState::CanonicalizeHost("www.paypal.com");
const std::string a_www_paypal =
- TransportSecurityState::CanonicaliseHost("a.www.paypal.com");
+ TransportSecurityState::CanonicalizeHost("a.www.paypal.com");
const std::string abc_paypal =
- TransportSecurityState::CanonicaliseHost("a.b.c.paypal.com");
+ TransportSecurityState::CanonicalizeHost("a.b.c.paypal.com");
const std::string example =
- TransportSecurityState::CanonicaliseHost("example.com");
+ TransportSecurityState::CanonicalizeHost("example.com");
const std::string aypal =
- TransportSecurityState::CanonicaliseHost("aypal.com");
+ TransportSecurityState::CanonicalizeHost("aypal.com");
bool b;
EXPECT_FALSE(TransportSecurityState::IsPreloadedSTS(paypal, &b));
@@ -331,6 +348,7 @@ TEST_F(TransportSecurityStateTest, Preloaded) {
EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "www.paypal.com"));
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"));
EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "a.www.paypal.com"));
@@ -370,6 +388,10 @@ TEST_F(TransportSecurityStateTest, Preloaded) {
EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "splendidbacon.com"));
EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "www.splendidbacon.com"));
EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "foo.splendidbacon.com"));
+
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "chrome.google.com"));
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "checkout.google.com"));
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "health.google.com"));
}
TEST_F(TransportSecurityStateTest, LongNames) {