diff options
author | Carlos IL <carlosil@chromium.org> | 2023-01-26 20:32:33 +0000 |
---|---|---|
committer | Michael BrĂ¼ning <michael.bruning@qt.io> | 2023-02-17 12:54:36 +0000 |
commit | 19ddfb039984262e389e8e4de3852c44d0d4be05 (patch) | |
tree | 8e0c70c7fc630b172ba28531e026f827893829e0 | |
parent | 4468b016ee2d512246051b5b196350a65c203d11 (diff) | |
download | qtwebengine-chromium-19ddfb039984262e389e8e4de3852c44d0d4be05.tar.gz |
[Backport] Security bug 1404811
Cherry-pick of patch originally reviewed on
https://chromium-review.googlesource.com/c/chromium/src/+/4171564:
Fix include_subdomains handling with PKI Metadata pins list
M102 merge issues:
net/http/transport_security_state_unittest.cc:
- Conflicting names for network_anonymization_key
(network_isolation_key in 102).
- The kStaticKeyPinningEnforcement feature flag isn't present in
102, but removing its init/activation from the test didn't affect
test results
Previously include_subdomains was ignored once the pinning list was
loaded from a component (due to the find() call for the map using the
full domain). This fixes this by calling it again with the url substring
starting at the next . if the full domain is not found.
(cherry picked from commit ca9cbe0aad4e4070b1e3c1ca530ede8a8a52cc4f)
Bug: 1404811
Change-Id: I2d487401711a8a44e9cedb4b91c84ae5553c6932
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4137286
Commit-Queue: Carlos IL <carlosil@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1091464}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4171564
Commit-Queue: Roger Felipe Zanoni da Silva <rzanoni@google.com>
Owners-Override: Achuith Bhandarkar <achuith@chromium.org>
Reviewed-by: Achuith Bhandarkar <achuith@chromium.org>
Cr-Commit-Position: refs/branch-heads/5005@{#1427}
Cr-Branched-From: 5b4d9450fee01f821b6400e947b3839727643a71-refs/heads/main@{#992738}
Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/460489
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
-rw-r--r-- | chromium/net/http/transport_security_state.cc | 78 | ||||
-rw-r--r-- | chromium/net/http/transport_security_state.h | 3 |
2 files changed, 55 insertions, 26 deletions
diff --git a/chromium/net/http/transport_security_state.cc b/chromium/net/http/transport_security_state.cc index ecaeaba37f8..de3084675bb 100644 --- a/chromium/net/http/transport_security_state.cc +++ b/chromium/net/http/transport_security_state.cc @@ -643,8 +643,7 @@ void TransportSecurityState::UpdatePinList( base::Time update_time) { pinsets_ = pinsets; key_pins_list_last_update_time_ = update_time; - host_pins_ = absl::make_optional( - std::map<std::string, std::pair<PinSet const*, bool>>()); + host_pins_.emplace(); std::map<std::string, PinSet const*> pinset_names_map; for (const auto& pinset : pinsets_) { pinset_names_map[pinset.name()] = &pinset; @@ -1186,32 +1185,61 @@ bool TransportSecurityState::GetStaticPKPState(const std::string& host, PreloadResult result; if (host_pins_.has_value()) { - auto iter = host_pins_->find(host); - if (iter != host_pins_->end()) { - pkp_result->domain = host; - pkp_result->last_observed = key_pins_list_last_update_time_; - pkp_result->include_subdomains = iter->second.second; - const PinSet* pinset = iter->second.first; - if (!pinset->report_uri().empty()) { - pkp_result->report_uri = GURL(pinset->report_uri()); - } - for (auto hash : pinset->static_spki_hashes()) { - // If the update is malformed, it's preferable to skip the hash than - // crash. - if (hash.size() == 32) { - AddHash(reinterpret_cast<const char*>(hash.data()), - &pkp_result->spki_hashes); + // Ensure that |host| is a valid hostname before processing. + if (CanonicalizeHost(host).empty()) { + return false; + } + // Normalize any trailing '.' used for DNS suffix searches. + std::string normalized_host = host; + size_t trailing_dot_found = normalized_host.find_last_not_of('.'); + if (trailing_dot_found == std::string::npos) { + // Hostname is either empty or all dots + return false; + } + normalized_host.erase(trailing_dot_found + 1); + normalized_host = base::ToLowerASCII(normalized_host); + + base::StringPiece search_hostname = normalized_host; + while (true) { + auto iter = host_pins_->find(search_hostname); + // Only consider this a match if either include_subdomains is set, or + // this is an exact match of the full hostname. + if (iter != host_pins_->end() && + (iter->second.second || search_hostname == normalized_host)) { + pkp_result->domain = std::string(search_hostname); + pkp_result->last_observed = key_pins_list_last_update_time_; + pkp_result->include_subdomains = iter->second.second; + const PinSet* pinset = iter->second.first; + if (!pinset->report_uri().empty()) { + pkp_result->report_uri = GURL(pinset->report_uri()); } - } - for (auto hash : pinset->bad_static_spki_hashes()) { - // If the update is malformed, it's preferable to skip the hash than - // crash. - if (hash.size() == 32) { - AddHash(reinterpret_cast<const char*>(hash.data()), - &pkp_result->bad_spki_hashes); + for (auto hash : pinset->static_spki_hashes()) { + // If the update is malformed, it's preferable to skip the hash than + // crash. + if (hash.size() == 32) { + AddHash(reinterpret_cast<const char*>(hash.data()), + &pkp_result->spki_hashes); + } } + for (auto hash : pinset->bad_static_spki_hashes()) { + // If the update is malformed, it's preferable to skip the hash than + // crash. + if (hash.size() == 32) { + AddHash(reinterpret_cast<const char*>(hash.data()), + &pkp_result->bad_spki_hashes); + } + } + return true; } - return true; + auto dot_pos = search_hostname.find("."); + if (dot_pos == std::string::npos) { + // If this was not a match, and there are no more dots in the string, + // there are no more domains to try. + return false; + } + // Try again in case this is a subdomain of a pinned domain that includes + // subdomains. + search_hostname = search_hostname.substr(dot_pos + 1); } } else if (DecodeHSTSPreload(host, &result) && result.has_pins) { if (result.pinset_id >= g_hsts_source->pinsets_count) diff --git a/chromium/net/http/transport_security_state.h b/chromium/net/http/transport_security_state.h index e8d50dbf23a..45c1765ed65 100644 --- a/chromium/net/http/transport_security_state.h +++ b/chromium/net/http/transport_security_state.h @@ -808,7 +808,8 @@ class NET_EXPORT TransportSecurityState { // The values in host_pins_ maps are references to PinSet objects in the // pinsets_ vector. - absl::optional<std::map<std::string, std::pair<const PinSet*, bool>>> + absl::optional< + std::map<std::string, std::pair<const PinSet*, bool>, std::less<>>> host_pins_; base::Time key_pins_list_last_update_time_; std::vector<PinSet> pinsets_; |