Index: net/base/transport_security_state.cc |
=================================================================== |
--- net/base/transport_security_state.cc (revision 82036) |
+++ net/base/transport_security_state.cc (working copy) |
@@ -5,12 +5,14 @@ |
#include "net/base/transport_security_state.h" |
#include "base/base64.h" |
+#include "base/command_line.h" |
#include "base/json/json_reader.h" |
#include "base/json/json_writer.h" |
#include "base/logging.h" |
#include "base/memory/scoped_ptr.h" |
#include "base/sha1.h" |
#include "base/string_number_conversions.h" |
+#include "base/string_split.h" |
#include "base/string_tokenizer.h" |
#include "base/string_util.h" |
#include "base/utf_string_conversions.h" |
@@ -18,6 +20,7 @@ |
#include "crypto/sha2.h" |
#include "googleurl/src/gurl.h" |
#include "net/base/dns_util.h" |
+#include "net/base/net_switches.h" |
namespace net { |
@@ -27,6 +30,12 @@ |
: delegate_(NULL) { |
} |
+static std::string HashHost(const std::string& canonicalized_host) { |
+ char hashed[crypto::SHA256_LENGTH]; |
+ crypto::SHA256HashString(canonicalized_host, hashed, sizeof(hashed)); |
+ return std::string(hashed, sizeof(hashed)); |
+} |
+ |
void TransportSecurityState::EnableHost(const std::string& host, |
const DomainState& state) { |
const std::string canonicalized_host = CanonicalizeHost(host); |
@@ -36,13 +45,10 @@ |
// TODO(cevans) -- we likely want to permit a host to override a built-in, |
// for at least the case where the override is stricter (i.e. includes |
// subdomains, or includes certificate pinning). |
- bool temp; |
+ DomainState temp; |
if (IsPreloadedSTS(canonicalized_host, true, &temp)) |
return; |
- char hashed[crypto::SHA256_LENGTH]; |
- crypto::SHA256HashString(canonicalized_host, hashed, sizeof(hashed)); |
- |
// Use the original creation date if we already have this host. |
DomainState state_copy(state); |
DomainState existing_state; |
@@ -53,7 +59,7 @@ |
state_copy.preloaded = false; |
state_copy.domain.clear(); |
- enabled_hosts_[std::string(hashed, sizeof(hashed))] = state_copy; |
+ enabled_hosts_[HashHost(canonicalized_host)] = state_copy; |
DirtyNotify(); |
} |
@@ -62,11 +68,8 @@ |
if (canonicalized_host.empty()) |
return false; |
- char hashed[crypto::SHA256_LENGTH]; |
- crypto::SHA256HashString(canonicalized_host, hashed, sizeof(hashed)); |
- |
std::map<std::string, DomainState>::iterator i = enabled_hosts_.find( |
- std::string(hashed, sizeof(hashed))); |
+ HashHost(canonicalized_host)); |
if (i != enabled_hosts_.end()) { |
enabled_hosts_.erase(i); |
DirtyNotify(); |
@@ -84,31 +87,22 @@ |
bool TransportSecurityState::IsEnabledForHost(DomainState* result, |
const std::string& host, |
bool sni_available) { |
- *result = DomainState(); |
- |
const std::string canonicalized_host = CanonicalizeHost(host); |
if (canonicalized_host.empty()) |
return false; |
- bool include_subdomains; |
- if (IsPreloadedSTS(canonicalized_host, sni_available, &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; |
- } |
+ if (IsPreloadedSTS(canonicalized_host, sni_available, result)) |
+ return result->mode != DomainState::MODE_NONE; |
- result->preloaded = false; |
+ *result = DomainState(); |
+ |
base::Time current_time(base::Time::Now()); |
for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { |
- char hashed_domain[crypto::SHA256_LENGTH]; |
+ std::string hashed_domain(HashHost(IncludeNUL(&canonicalized_host[i]))); |
- crypto::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))); |
+ enabled_hosts_.find(hashed_domain); |
if (j == enabled_hosts_.end()) |
continue; |
@@ -336,10 +330,17 @@ |
return true; |
} |
-bool TransportSecurityState::Deserialise(const std::string& input, |
+bool TransportSecurityState::LoadEntries(const std::string& input, |
bool* dirty) { |
enabled_hosts_.clear(); |
+ return Deserialise(input, dirty, &enabled_hosts_); |
+} |
+// static |
+bool TransportSecurityState::Deserialise( |
+ const std::string& input, |
+ bool* dirty, |
+ std::map<std::string, DomainState>* out) { |
scoped_ptr<Value> value( |
base::JSONReader::Read(input, false /* do not allow trailing commas */)); |
if (!value.get() || !value->IsType(Value::TYPE_DICTIONARY)) |
@@ -393,6 +394,8 @@ |
mode = DomainState::MODE_OPPORTUNISTIC; |
} else if (mode_string == "spdy-only") { |
mode = DomainState::MODE_SPDY_ONLY; |
+ } else if (mode_string == "none") { |
+ mode = DomainState::MODE_NONE; |
} else { |
LOG(WARNING) << "Unknown TransportSecurityState mode string found: " |
<< mode_string; |
@@ -428,7 +431,7 @@ |
new_state.expiry = expiry_time; |
new_state.include_subdomains = include_subdomains; |
new_state.public_key_hashes = public_key_hashes; |
- enabled_hosts_[hashed] = new_state; |
+ (*out)[hashed] = new_state; |
} |
*dirty = dirtied; |
@@ -485,7 +488,22 @@ |
bool TransportSecurityState::IsPreloadedSTS( |
const std::string& canonicalized_host, |
bool sni_available, |
- bool *include_subdomains) { |
+ DomainState* out) { |
+ out->preloaded = true; |
+ out->mode = DomainState::MODE_STRICT; |
+ out->created = base::Time::FromTimeT(0); |
+ out->expiry = out->created; |
+ out->include_subdomains = false; |
+ |
+ std::map<std::string, DomainState> hosts; |
+ std::string cmd_line_hsts = |
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
+ switches::kHstsHosts); |
+ if (!cmd_line_hsts.empty()) { |
+ bool dirty; |
+ Deserialise(cmd_line_hsts, &dirty, &hosts); |
+ } |
+ |
// 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 { |
@@ -547,13 +565,23 @@ |
static const size_t kNumPreloadedSNISTS = ARRAYSIZE_UNSAFE(kPreloadedSNISTS); |
for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { |
+ std::string host_sub_chunk(&canonicalized_host[i], |
+ canonicalized_host.size() - i); |
+ out->domain = DNSDomainToString(host_sub_chunk); |
+ std::string hashed_host(HashHost(host_sub_chunk)); |
+ if (hosts.find(hashed_host) != hosts.end()) { |
+ *out = hosts[hashed_host]; |
+ out->domain = DNSDomainToString(host_sub_chunk); |
+ out->preloaded = true; |
+ return true; |
+ } |
for (size_t j = 0; j < kNumPreloadedSTS; j++) { |
if (kPreloadedSTS[j].length == canonicalized_host.size() - i && |
memcmp(kPreloadedSTS[j].dns_name, &canonicalized_host[i], |
kPreloadedSTS[j].length) == 0) { |
if (!kPreloadedSTS[j].include_subdomains && i != 0) |
return false; |
- *include_subdomains = kPreloadedSTS[j].include_subdomains; |
+ out->include_subdomains = kPreloadedSTS[j].include_subdomains; |
return true; |
} |
} |
@@ -564,7 +592,7 @@ |
kPreloadedSNISTS[j].length) == 0) { |
if (!kPreloadedSNISTS[j].include_subdomains && i != 0) |
return false; |
- *include_subdomains = kPreloadedSNISTS[j].include_subdomains; |
+ out->include_subdomains = kPreloadedSNISTS[j].include_subdomains; |
return true; |
} |
} |
@@ -613,7 +641,6 @@ |
} |
} |
- |
LOG(ERROR) << "Rejecting public key chain for domain " << domain |
<< ". Validated chain: " << HashesToBase64String(hashes) |
<< ", expected: " << HashesToBase64String(public_key_hashes); |