summaryrefslogtreecommitdiffstats
path: root/chromium/net/http/transport_security_state.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/http/transport_security_state.cc')
-rw-r--r--chromium/net/http/transport_security_state.cc261
1 files changed, 141 insertions, 120 deletions
diff --git a/chromium/net/http/transport_security_state.cc b/chromium/net/http/transport_security_state.cc
index f9ba807ff79..f50b26483d1 100644
--- a/chromium/net/http/transport_security_state.cc
+++ b/chromium/net/http/transport_security_state.cc
@@ -95,6 +95,61 @@ TransportSecurityState::Iterator::Iterator(const TransportSecurityState& state)
TransportSecurityState::Iterator::~Iterator() {}
+bool TransportSecurityState::ShouldSSLErrorsBeFatal(const std::string& host,
+ bool sni_enabled) {
+ DomainState state;
+ if (GetStaticDomainState(host, sni_enabled, &state))
+ return true;
+ return GetDynamicDomainState(host, &state);
+}
+
+bool TransportSecurityState::ShouldUpgradeToSSL(const std::string& host,
+ bool sni_enabled) {
+ DomainState dynamic_state;
+ if (GetDynamicDomainState(host, &dynamic_state))
+ return dynamic_state.ShouldUpgradeToSSL();
+
+ DomainState static_state;
+ if (GetStaticDomainState(host, sni_enabled, &static_state) &&
+ static_state.ShouldUpgradeToSSL()) {
+ return true;
+ }
+
+ return false;
+}
+
+bool TransportSecurityState::CheckPublicKeyPins(const std::string& host,
+ bool sni_enabled,
+ const HashValueVector& hashes,
+ std::string* failure_log) {
+ DomainState dynamic_state;
+ if (GetDynamicDomainState(host, &dynamic_state))
+ return dynamic_state.CheckPublicKeyPins(hashes, failure_log);
+
+ DomainState static_state;
+ if (GetStaticDomainState(host, sni_enabled, &static_state) &&
+ static_state.CheckPublicKeyPins(hashes, failure_log)) {
+ return true;
+ }
+
+ return false;
+}
+
+bool TransportSecurityState::HasPublicKeyPins(const std::string& host,
+ bool sni_enabled) {
+ DomainState dynamic_state;
+ if (GetDynamicDomainState(host, &dynamic_state))
+ return dynamic_state.HasPublicKeyPins();
+
+ DomainState static_state;
+ if (GetStaticDomainState(host, sni_enabled, &static_state)) {
+ if (static_state.HasPublicKeyPins())
+ return true;
+ }
+
+ return false;
+}
+
void TransportSecurityState::SetDelegate(
TransportSecurityState::Delegate* delegate) {
DCHECK(CalledOnValidThread());
@@ -135,61 +190,6 @@ bool TransportSecurityState::DeleteDynamicDataForHost(const std::string& host) {
return false;
}
-bool TransportSecurityState::GetDomainState(const std::string& host,
- bool sni_enabled,
- DomainState* result) {
- DCHECK(CalledOnValidThread());
-
- DomainState state;
- const std::string canonicalized_host = CanonicalizeHost(host);
- if (canonicalized_host.empty())
- return false;
-
- bool has_preload = GetStaticDomainState(canonicalized_host, sni_enabled,
- &state);
- std::string canonicalized_preload = CanonicalizeHost(state.domain);
- GetDynamicDomainState(host, &state);
-
- base::Time current_time(base::Time::Now());
-
- 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);
- // Exact match of a preload always wins.
- if (has_preload && host_sub_chunk == canonicalized_preload) {
- *result = state;
- return true;
- }
-
- DomainStateMap::iterator j =
- enabled_hosts_.find(HashHost(host_sub_chunk));
- if (j == enabled_hosts_.end())
- continue;
-
- if (current_time > j->second.upgrade_expiry &&
- current_time > j->second.dynamic_spki_hashes_expiry) {
- enabled_hosts_.erase(j);
- DirtyNotify();
- continue;
- }
-
- state = j->second;
- state.domain = DNSDomainToString(host_sub_chunk);
-
- // Succeed if we matched the domain exactly or if subdomain matches are
- // allowed.
- if (i == 0 || j->second.sts_include_subdomains ||
- j->second.pkp_include_subdomains) {
- *result = state;
- return true;
- }
-
- return false;
- }
-
- return false;
-}
-
void TransportSecurityState::ClearDynamicData() {
DCHECK(CalledOnValidThread());
enabled_hosts_.clear();
@@ -199,15 +199,24 @@ void TransportSecurityState::DeleteAllDynamicDataSince(const base::Time& time) {
DCHECK(CalledOnValidThread());
bool dirtied = false;
-
DomainStateMap::iterator i = enabled_hosts_.begin();
while (i != enabled_hosts_.end()) {
- if (i->second.created >= time) {
+ if (i->second.sts.last_observed >= time &&
+ i->second.pkp.last_observed >= time) {
dirtied = true;
enabled_hosts_.erase(i++);
- } else {
- i++;
+ continue;
+ }
+
+ if (i->second.sts.last_observed >= time) {
+ dirtied = true;
+ i->second.sts.upgrade_mode = DomainState::MODE_DEFAULT;
+ } else if (i->second.pkp.last_observed >= time) {
+ dirtied = true;
+ i->second.pkp.spki_hashes.clear();
+ i->second.pkp.expiry = base::Time();
}
+ ++i;
}
if (dirtied)
@@ -515,6 +524,7 @@ enum SecondLevelDomainName {
DOMAIN_LAVABIT_COM,
DOMAIN_GOOGLETAGMANAGER_COM,
+ DOMAIN_GOOGLETAGSERVICES_COM,
// Boundary value for UMA_HISTOGRAM_ENUMERATION:
DOMAIN_NUM_EVENTS
@@ -547,22 +557,27 @@ static bool HasPreload(const struct HSTSPreload* entries, size_t num_entries,
if (!entries[j].include_subdomains && i != 0) {
*ret = false;
} else {
- out->sts_include_subdomains = entries[j].include_subdomains;
- out->pkp_include_subdomains = entries[j].include_subdomains;
+ out->sts.include_subdomains = entries[j].include_subdomains;
+ out->sts.last_observed = base::GetBuildTime();
+ out->pkp.include_subdomains = entries[j].include_subdomains;
+ out->pkp.last_observed = base::GetBuildTime();
*ret = true;
+ out->sts.upgrade_mode =
+ TransportSecurityState::DomainState::MODE_FORCE_HTTPS;
if (!entries[j].https_required)
- out->upgrade_mode = TransportSecurityState::DomainState::MODE_DEFAULT;
+ out->sts.upgrade_mode =
+ TransportSecurityState::DomainState::MODE_DEFAULT;
if (entries[j].pins.required_hashes) {
const char* const* sha1_hash = entries[j].pins.required_hashes;
while (*sha1_hash) {
- AddHash(*sha1_hash, &out->static_spki_hashes);
+ AddHash(*sha1_hash, &out->pkp.spki_hashes);
sha1_hash++;
}
}
if (entries[j].pins.excluded_hashes) {
const char* const* sha1_hash = entries[j].pins.excluded_hashes;
while (*sha1_hash) {
- AddHash(*sha1_hash, &out->bad_static_spki_hashes);
+ AddHash(*sha1_hash, &out->pkp.bad_spki_hashes);
sha1_hash++;
}
}
@@ -610,14 +625,14 @@ bool TransportSecurityState::AddHSTSHeader(const std::string& host,
base::TimeDelta max_age;
TransportSecurityState::DomainState domain_state;
GetDynamicDomainState(host, &domain_state);
- if (ParseHSTSHeader(value, &max_age, &domain_state.sts_include_subdomains)) {
- // Handle max-age == 0
+ if (ParseHSTSHeader(value, &max_age, &domain_state.sts.include_subdomains)) {
+ // Handle max-age == 0.
if (max_age.InSeconds() == 0)
- domain_state.upgrade_mode = DomainState::MODE_DEFAULT;
+ domain_state.sts.upgrade_mode = DomainState::MODE_DEFAULT;
else
- domain_state.upgrade_mode = DomainState::MODE_FORCE_HTTPS;
- domain_state.created = now;
- domain_state.upgrade_expiry = now + max_age;
+ domain_state.sts.upgrade_mode = DomainState::MODE_FORCE_HTTPS;
+ domain_state.sts.last_observed = now;
+ domain_state.sts.expiry = now + max_age;
EnableHost(host, domain_state);
return true;
}
@@ -633,12 +648,16 @@ bool TransportSecurityState::AddHPKPHeader(const std::string& host,
base::TimeDelta max_age;
TransportSecurityState::DomainState domain_state;
GetDynamicDomainState(host, &domain_state);
- if (ParseHPKPHeader(value, ssl_info.public_key_hashes,
- &max_age, &domain_state.pkp_include_subdomains,
- &domain_state.dynamic_spki_hashes)) {
- // TODO(palmer): http://crbug.com/243865 handle max-age == 0.
- domain_state.created = now;
- domain_state.dynamic_spki_hashes_expiry = now + max_age;
+ if (ParseHPKPHeader(value,
+ ssl_info.public_key_hashes,
+ &max_age,
+ &domain_state.pkp.include_subdomains,
+ &domain_state.pkp.spki_hashes)) {
+ // Handle max-age == 0.
+ if (max_age.InSeconds() == 0)
+ domain_state.pkp.spki_hashes.clear();
+ domain_state.pkp.last_observed = now;
+ domain_state.pkp.expiry = now + max_age;
EnableHost(host, domain_state);
return true;
}
@@ -659,10 +678,10 @@ bool TransportSecurityState::AddHSTS(const std::string& host,
if (i != enabled_hosts_.end())
domain_state = i->second;
- domain_state.created = base::Time::Now();
- domain_state.sts_include_subdomains = include_subdomains;
- domain_state.upgrade_expiry = expiry;
- domain_state.upgrade_mode = DomainState::MODE_FORCE_HTTPS;
+ domain_state.sts.last_observed = base::Time::Now();
+ domain_state.sts.include_subdomains = include_subdomains;
+ domain_state.sts.expiry = expiry;
+ domain_state.sts.upgrade_mode = DomainState::MODE_FORCE_HTTPS;
EnableHost(host, domain_state);
return true;
}
@@ -682,10 +701,10 @@ bool TransportSecurityState::AddHPKP(const std::string& host,
if (i != enabled_hosts_.end())
domain_state = i->second;
- domain_state.created = base::Time::Now();
- domain_state.pkp_include_subdomains = include_subdomains;
- domain_state.dynamic_spki_hashes_expiry = expiry;
- domain_state.dynamic_spki_hashes = hashes;
+ domain_state.pkp.last_observed = base::Time::Now();
+ domain_state.pkp.include_subdomains = include_subdomains;
+ domain_state.pkp.expiry = expiry;
+ domain_state.pkp.spki_hashes = hashes;
EnableHost(host, domain_state);
return true;
}
@@ -742,15 +761,16 @@ bool TransportSecurityState::IsBuildTimely() {
return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */;
}
-bool TransportSecurityState::GetStaticDomainState(
- const std::string& canonicalized_host,
- bool sni_enabled,
- DomainState* out) {
+bool TransportSecurityState::GetStaticDomainState(const std::string& host,
+ bool sni_enabled,
+ DomainState* out) const {
DCHECK(CalledOnValidThread());
- out->upgrade_mode = DomainState::MODE_FORCE_HTTPS;
- out->sts_include_subdomains = false;
- out->pkp_include_subdomains = false;
+ const std::string canonicalized_host = CanonicalizeHost(host);
+
+ out->sts.upgrade_mode = DomainState::MODE_FORCE_HTTPS;
+ out->sts.include_subdomains = false;
+ out->pkp.include_subdomains = false;
const bool is_build_timely = IsBuildTimely();
@@ -794,8 +814,8 @@ bool TransportSecurityState::GetDynamicDomainState(const std::string& host,
if (j == enabled_hosts_.end())
continue;
- if (current_time > j->second.upgrade_expiry &&
- current_time > j->second.dynamic_spki_hashes_expiry) {
+ if (current_time > j->second.sts.expiry &&
+ current_time > j->second.pkp.expiry) {
enabled_hosts_.erase(j);
DirtyNotify();
continue;
@@ -806,8 +826,8 @@ bool TransportSecurityState::GetDynamicDomainState(const std::string& host,
// Succeed if we matched the domain exactly or if subdomain matches are
// allowed.
- if (i == 0 || j->second.sts_include_subdomains ||
- j->second.pkp_include_subdomains) {
+ if (i == 0 || j->second.sts.include_subdomains ||
+ j->second.pkp.include_subdomains) {
*result = state;
return true;
}
@@ -818,60 +838,57 @@ bool TransportSecurityState::GetDynamicDomainState(const std::string& host,
return false;
}
-
void TransportSecurityState::AddOrUpdateEnabledHosts(
const std::string& hashed_host, const DomainState& state) {
DCHECK(CalledOnValidThread());
enabled_hosts_[hashed_host] = state;
}
-TransportSecurityState::DomainState::DomainState()
- : upgrade_mode(MODE_DEFAULT),
- created(base::Time::Now()),
- sts_include_subdomains(false),
- pkp_include_subdomains(false) {
+TransportSecurityState::DomainState::DomainState() {
+ sts.upgrade_mode = MODE_DEFAULT;
+ sts.include_subdomains = false;
+ pkp.include_subdomains = false;
}
TransportSecurityState::DomainState::~DomainState() {
}
bool TransportSecurityState::DomainState::CheckPublicKeyPins(
- const HashValueVector& hashes) const {
+ const HashValueVector& hashes, std::string* failure_log) const {
// Validate that hashes is not empty. By the time this code is called (in
// production), that should never happen, but it's good to be defensive.
// And, hashes *can* be empty in some test scenarios.
if (hashes.empty()) {
- LOG(ERROR) << "Rejecting empty public key chain for public-key-pinned "
- "domain " << domain;
+ failure_log->append(
+ "Rejecting empty public key chain for public-key-pinned domains: " +
+ domain);
return false;
}
- if (HashesIntersect(bad_static_spki_hashes, hashes)) {
- LOG(ERROR) << "Rejecting public key chain for domain " << domain
- << ". Validated chain: " << HashesToBase64String(hashes)
- << ", matches one or more bad hashes: "
- << HashesToBase64String(bad_static_spki_hashes);
+ if (HashesIntersect(pkp.bad_spki_hashes, hashes)) {
+ failure_log->append("Rejecting public key chain for domain " + domain +
+ ". Validated chain: " + HashesToBase64String(hashes) +
+ ", matches one or more bad hashes: " +
+ HashesToBase64String(pkp.bad_spki_hashes));
return false;
}
// If there are no pins, then any valid chain is acceptable.
- if (dynamic_spki_hashes.empty() && static_spki_hashes.empty())
+ if (pkp.spki_hashes.empty())
return true;
- if (HashesIntersect(dynamic_spki_hashes, hashes) ||
- HashesIntersect(static_spki_hashes, hashes)) {
+ if (HashesIntersect(pkp.spki_hashes, hashes)) {
return true;
}
- LOG(ERROR) << "Rejecting public key chain for domain " << domain
- << ". Validated chain: " << HashesToBase64String(hashes)
- << ", expected: " << HashesToBase64String(dynamic_spki_hashes)
- << " or: " << HashesToBase64String(static_spki_hashes);
+ failure_log->append("Rejecting public key chain for domain " + domain +
+ ". Validated chain: " + HashesToBase64String(hashes) +
+ ", expected: " + HashesToBase64String(pkp.spki_hashes));
return false;
}
bool TransportSecurityState::DomainState::ShouldUpgradeToSSL() const {
- return upgrade_mode == MODE_FORCE_HTTPS;
+ return sts.upgrade_mode == MODE_FORCE_HTTPS;
}
bool TransportSecurityState::DomainState::ShouldSSLErrorsBeFatal() const {
@@ -879,9 +896,13 @@ bool TransportSecurityState::DomainState::ShouldSSLErrorsBeFatal() const {
}
bool TransportSecurityState::DomainState::HasPublicKeyPins() const {
- return static_spki_hashes.size() > 0 ||
- bad_static_spki_hashes.size() > 0 ||
- dynamic_spki_hashes.size() > 0;
+ return pkp.spki_hashes.size() > 0 || pkp.bad_spki_hashes.size() > 0;
+}
+
+TransportSecurityState::DomainState::PKPState::PKPState() {
+}
+
+TransportSecurityState::DomainState::PKPState::~PKPState() {
}
} // namespace