Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(592)

Unified Diff: net/http/transport_security_state.cc

Issue 826423009: Treat HSTS and HPKP state independently. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rsleevi comments Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/http/transport_security_state.h ('k') | net/http/transport_security_state_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/http/transport_security_state.cc
diff --git a/net/http/transport_security_state.cc b/net/http/transport_security_state.cc
index a2d377e38813a365312823f4eea6e4d93042f605..a174e9875ad25b45e34c31cb4a3512e10dfa2736 100644
--- a/net/http/transport_security_state.cc
+++ b/net/http/transport_security_state.cc
@@ -167,6 +167,50 @@ void TransportSecurityState::SetDelegate(
delegate_ = delegate;
}
+void TransportSecurityState::AddHSTSInternal(
+ const std::string& host,
+ TransportSecurityState::DomainState::UpgradeMode upgrade_mode,
+ const base::Time& expiry,
+ bool include_subdomains) {
+ DCHECK(CalledOnValidThread());
+
+ // Copy-and-modify the existing DomainState for this host (if any).
+ DomainState domain_state;
+ const std::string canonicalized_host = CanonicalizeHost(host);
+ const std::string hashed_host = HashHost(canonicalized_host);
+ DomainStateMap::const_iterator i = enabled_hosts_.find(hashed_host);
+ if (i != enabled_hosts_.end())
+ domain_state = i->second;
+
+ 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 = upgrade_mode;
+ EnableHost(host, domain_state);
+}
+
+void TransportSecurityState::AddHPKPInternal(const std::string& host,
+ const base::Time& last_observed,
+ const base::Time& expiry,
+ bool include_subdomains,
+ const HashValueVector& hashes) {
+ DCHECK(CalledOnValidThread());
+
+ // Copy-and-modify the existing DomainState for this host (if any).
+ DomainState domain_state;
+ const std::string canonicalized_host = CanonicalizeHost(host);
+ const std::string hashed_host = HashHost(canonicalized_host);
+ DomainStateMap::const_iterator i = enabled_hosts_.find(hashed_host);
+ if (i != enabled_hosts_.end())
+ domain_state = i->second;
+
+ domain_state.pkp.last_observed = last_observed;
+ domain_state.pkp.expiry = expiry;
+ domain_state.pkp.include_subdomains = include_subdomains;
+ domain_state.pkp.spki_hashes = hashes;
+ EnableHost(host, domain_state);
+}
+
void TransportSecurityState::EnableHost(const std::string& host,
const DomainState& state) {
DCHECK(CalledOnValidThread());
@@ -178,7 +222,8 @@ void TransportSecurityState::EnableHost(const std::string& host,
DomainState state_copy(state);
// No need to store this value since it is redundant. (|canonicalized_host|
// is the map key.)
- state_copy.domain.clear();
+ state_copy.sts.domain.clear();
+ state_copy.pkp.domain.clear();
enabled_hosts_[HashHost(canonicalized_host)] = state_copy;
DirtyNotify();
@@ -212,21 +257,24 @@ void TransportSecurityState::DeleteAllDynamicDataSince(const base::Time& time) {
bool dirtied = false;
DomainStateMap::iterator i = enabled_hosts_.begin();
while (i != enabled_hosts_.end()) {
- if (i->second.sts.last_observed >= time &&
- i->second.pkp.last_observed >= time) {
- dirtied = true;
- enabled_hosts_.erase(i++);
- continue;
- }
-
+ // Clear STS and PKP state independently.
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) {
+ }
+ if (i->second.pkp.last_observed >= time) {
dirtied = true;
i->second.pkp.spki_hashes.clear();
i->second.pkp.expiry = base::Time();
}
+
+ // If both are now invalid, drop the entry altogether.
+ if (!i->second.ShouldUpgradeToSSL() && !i->second.HasPublicKeyPins()) {
+ dirtied = true;
+ enabled_hosts_.erase(i++);
+ continue;
+ }
+
++i;
}
@@ -621,20 +669,21 @@ bool TransportSecurityState::AddHSTSHeader(const std::string& host,
base::Time now = base::Time::Now();
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 (max_age.InSeconds() == 0)
- domain_state.sts.upgrade_mode = DomainState::MODE_DEFAULT;
- else
- 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;
+ bool include_subdomains;
+ if (!ParseHSTSHeader(value, &max_age, &include_subdomains)) {
+ return false;
}
- return false;
+
+ // Handle max-age == 0.
+ DomainState::UpgradeMode upgrade_mode;
+ if (max_age.InSeconds() == 0) {
+ upgrade_mode = DomainState::MODE_DEFAULT;
+ } else {
+ upgrade_mode = DomainState::MODE_FORCE_HTTPS;
+ }
+
+ AddHSTSInternal(host, upgrade_mode, now + max_age, include_subdomains);
+ return true;
}
bool TransportSecurityState::AddHPKPHeader(const std::string& host,
@@ -644,67 +693,33 @@ bool TransportSecurityState::AddHPKPHeader(const std::string& host,
base::Time now = base::Time::Now();
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.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;
+ bool include_subdomains;
+ HashValueVector spki_hashes;
+ if (!ParseHPKPHeader(value, ssl_info.public_key_hashes, &max_age,
+ &include_subdomains, &spki_hashes)) {
+ return false;
}
- return false;
+ // Handle max-age == 0.
+ if (max_age.InSeconds() == 0)
+ spki_hashes.clear();
+ AddHPKPInternal(host, now, now + max_age, include_subdomains, spki_hashes);
+ return true;
}
-bool TransportSecurityState::AddHSTS(const std::string& host,
+void TransportSecurityState::AddHSTS(const std::string& host,
const base::Time& expiry,
bool include_subdomains) {
DCHECK(CalledOnValidThread());
-
- // Copy-and-modify the existing DomainState for this host (if any).
- TransportSecurityState::DomainState domain_state;
- const std::string canonicalized_host = CanonicalizeHost(host);
- const std::string hashed_host = HashHost(canonicalized_host);
- DomainStateMap::const_iterator i = enabled_hosts_.find(
- hashed_host);
- if (i != enabled_hosts_.end())
- domain_state = i->second;
-
- 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;
+ AddHSTSInternal(host, DomainState::MODE_FORCE_HTTPS, expiry,
+ include_subdomains);
}
-bool TransportSecurityState::AddHPKP(const std::string& host,
+void TransportSecurityState::AddHPKP(const std::string& host,
const base::Time& expiry,
bool include_subdomains,
const HashValueVector& hashes) {
DCHECK(CalledOnValidThread());
-
- // Copy-and-modify the existing DomainState for this host (if any).
- TransportSecurityState::DomainState domain_state;
- const std::string canonicalized_host = CanonicalizeHost(host);
- const std::string hashed_host = HashHost(canonicalized_host);
- DomainStateMap::const_iterator i = enabled_hosts_.find(
- hashed_host);
- if (i != enabled_hosts_.end())
- domain_state = i->second;
-
- 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;
+ AddHPKPInternal(host, base::Time::Now(), expiry, include_subdomains, hashes);
}
// static
@@ -776,7 +791,8 @@ bool TransportSecurityState::GetStaticDomainState(const std::string& host,
if (!DecodeHSTSPreload(host, &result))
return false;
- out->domain = host.substr(result.hostname_offset);
+ out->sts.domain = host.substr(result.hostname_offset);
+ out->pkp.domain = out->sts.domain;
out->sts.include_subdomains = result.sts_include_subdomains;
out->sts.last_observed = base::GetBuildTime();
out->sts.upgrade_mode =
@@ -824,6 +840,8 @@ bool TransportSecurityState::GetDynamicDomainState(const std::string& host,
base::Time current_time(base::Time::Now());
+ bool found_sts = false;
+ bool found_pkp = false;
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);
@@ -832,6 +850,7 @@ bool TransportSecurityState::GetDynamicDomainState(const std::string& host,
if (j == enabled_hosts_.end())
continue;
+ // If both halves of the entry are invalid, drop it.
if (current_time > j->second.sts.expiry &&
current_time > j->second.pkp.expiry) {
enabled_hosts_.erase(j);
@@ -839,21 +858,32 @@ bool TransportSecurityState::GetDynamicDomainState(const std::string& host,
continue;
}
- state = j->second;
- state.domain = DNSDomainToString(host_sub_chunk);
+ // If this is the most specific STS match, add it to the result.
+ if (!found_sts && (i == 0 || j->second.sts.include_subdomains) &&
+ current_time <= j->second.sts.expiry &&
+ j->second.ShouldUpgradeToSSL()) {
+ found_sts = true;
+ state.sts = j->second.sts;
+ state.sts.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;
+ // If this is the most specific PKP match, add it to the result.
+ if (!found_pkp && (i == 0 || j->second.pkp.include_subdomains) &&
+ current_time <= j->second.pkp.expiry && j->second.HasPublicKeyPins()) {
+ found_pkp = true;
+ state.pkp = j->second.pkp;
+ state.pkp.domain = DNSDomainToString(host_sub_chunk);
}
- return false;
+ if (found_sts && found_pkp)
+ break;
}
- return false;
+ if (!found_sts && !found_pkp)
+ return false;
+
+ *result = state;
+ return true;
}
void TransportSecurityState::AddOrUpdateEnabledHosts(
@@ -879,12 +909,12 @@ bool TransportSecurityState::DomainState::CheckPublicKeyPins(
if (hashes.empty()) {
failure_log->append(
"Rejecting empty public key chain for public-key-pinned domains: " +
- domain);
+ pkp.domain);
return false;
}
if (HashesIntersect(pkp.bad_spki_hashes, hashes)) {
- failure_log->append("Rejecting public key chain for domain " + domain +
+ failure_log->append("Rejecting public key chain for domain " + pkp.domain +
". Validated chain: " + HashesToBase64String(hashes) +
", matches one or more bad hashes: " +
HashesToBase64String(pkp.bad_spki_hashes));
@@ -899,7 +929,7 @@ bool TransportSecurityState::DomainState::CheckPublicKeyPins(
return true;
}
- failure_log->append("Rejecting public key chain for domain " + domain +
+ failure_log->append("Rejecting public key chain for domain " + pkp.domain +
". Validated chain: " + HashesToBase64String(hashes) +
", expected: " + HashesToBase64String(pkp.spki_hashes));
return false;
@@ -910,6 +940,8 @@ bool TransportSecurityState::DomainState::ShouldUpgradeToSSL() const {
}
bool TransportSecurityState::DomainState::ShouldSSLErrorsBeFatal() const {
+ // Both HSTS and HPKP cause fatal SSL errors, so enable this on the presense
+ // of either. (If neither is active, no DomainState will be returned.)
return true;
}
@@ -917,6 +949,12 @@ bool TransportSecurityState::DomainState::HasPublicKeyPins() const {
return pkp.spki_hashes.size() > 0 || pkp.bad_spki_hashes.size() > 0;
}
+TransportSecurityState::DomainState::STSState::STSState() {
+}
+
+TransportSecurityState::DomainState::STSState::~STSState() {
+}
+
TransportSecurityState::DomainState::PKPState::PKPState() {
}
« no previous file with comments | « net/http/transport_security_state.h ('k') | net/http/transport_security_state_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698