1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/http/transport_security_state.h"
6
7 #include <algorithm>
8 #include <cstdint>
9 #include <memory>
10 #include <tuple>
11 #include <utility>
12 #include <vector>
13
14 #include "base/base64.h"
15 #include "base/build_time.h"
16 #include "base/containers/contains.h"
17 #include "base/containers/span.h"
18 #include "base/feature_list.h"
19 #include "base/functional/bind.h"
20 #include "base/json/json_writer.h"
21 #include "base/logging.h"
22 #include "base/metrics/field_trial.h"
23 #include "base/metrics/field_trial_params.h"
24 #include "base/strings/string_number_conversions.h"
25 #include "base/strings/string_util.h"
26 #include "base/strings/stringprintf.h"
27 #include "base/strings/utf_string_conversions.h"
28 #include "base/time/time.h"
29 #include "base/values.h"
30 #include "build/branding_buildflags.h"
31 #include "build/build_config.h"
32 #include "crypto/sha2.h"
33 #include "net/base/features.h"
34 #include "net/base/hash_value.h"
35 #include "net/base/host_port_pair.h"
36 #include "net/cert/ct_policy_status.h"
37 #include "net/cert/x509_certificate.h"
38 #include "net/dns/dns_names_util.h"
39 #include "net/extras/preload_data/decoder.h"
40 #include "net/http/http_security_headers.h"
41 #include "net/net_buildflags.h"
42 #include "net/ssl/ssl_info.h"
43 #include "third_party/abseil-cpp/absl/types/optional.h"
44
45 namespace net {
46
47 namespace {
48
49 #if BUILDFLAG(INCLUDE_TRANSPORT_SECURITY_STATE_PRELOAD_LIST)
50 #include "net/http/transport_security_state_static.h" // nogncheck
51 // Points to the active transport security state source.
52 const TransportSecurityStateSource* const kDefaultHSTSSource = &kHSTSSource;
53 #else
54 const TransportSecurityStateSource* const kDefaultHSTSSource = nullptr;
55 #endif
56
57 const TransportSecurityStateSource* g_hsts_source = kDefaultHSTSSource;
58
59 // Parameters for remembering sent HPKP reports.
60 const size_t kMaxReportCacheEntries = 50;
61 const int kTimeToRememberReportsMins = 60;
62 const size_t kReportCacheKeyLength = 16;
63
64 // Override for CheckCTRequirements() for unit tests. Possible values:
65 // false: Use the default implementation (e.g. production)
66 // true: Unless a delegate says otherwise, require CT.
67 bool g_ct_required_for_testing = false;
68
GetPEMEncodedChainAsList(const net::X509Certificate * cert_chain)69 base::Value GetPEMEncodedChainAsList(const net::X509Certificate* cert_chain) {
70 if (!cert_chain)
71 return base::Value(base::Value::Type::LIST);
72
73 base::Value::List result;
74 std::vector<std::string> pem_encoded_chain;
75 cert_chain->GetPEMEncodedChain(&pem_encoded_chain);
76 for (const std::string& cert : pem_encoded_chain)
77 result.Append(cert);
78
79 return base::Value(std::move(result));
80 }
81
HashReportForCache(const base::Value::Dict & report,const GURL & report_uri,std::string * cache_key)82 bool HashReportForCache(const base::Value::Dict& report,
83 const GURL& report_uri,
84 std::string* cache_key) {
85 char hashed[crypto::kSHA256Length];
86 std::string to_hash;
87 if (!base::JSONWriter::Write(report, &to_hash))
88 return false;
89 to_hash += "," + report_uri.spec();
90 crypto::SHA256HashString(to_hash, hashed, sizeof(hashed));
91 static_assert(kReportCacheKeyLength <= sizeof(hashed),
92 "HPKP report cache key size is larger than hash size.");
93 *cache_key = std::string(hashed, kReportCacheKeyLength);
94 return true;
95 }
96
97 // Formats a time compliant to ISO 8601 in UTC, e.g. "2020-12-31T23:59:59.999Z".
98 //
99 // This behaves identically to the function in base/i18n/time_formatting.h. It
100 // is reimplemented here since net/ cannot depend on base/i18n/.
TimeFormatAsIso8601(const base::Time & time)101 std::string TimeFormatAsIso8601(const base::Time& time) {
102 base::Time::Exploded exploded;
103 time.UTCExplode(&exploded);
104 return base::StringPrintf(
105 "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", exploded.year, exploded.month,
106 exploded.day_of_month, exploded.hour, exploded.minute, exploded.second,
107 exploded.millisecond);
108 }
109
GetHPKPReport(const HostPortPair & host_port_pair,const TransportSecurityState::PKPState & pkp_state,const X509Certificate * served_certificate_chain,const X509Certificate * validated_certificate_chain,std::string * serialized_report,std::string * cache_key)110 bool GetHPKPReport(const HostPortPair& host_port_pair,
111 const TransportSecurityState::PKPState& pkp_state,
112 const X509Certificate* served_certificate_chain,
113 const X509Certificate* validated_certificate_chain,
114 std::string* serialized_report,
115 std::string* cache_key) {
116 if (pkp_state.report_uri.is_empty())
117 return false;
118
119 base::Value::Dict report;
120 base::Time now = base::Time::Now();
121 report.Set("hostname", host_port_pair.host());
122 report.Set("port", host_port_pair.port());
123 report.Set("include-subdomains", pkp_state.include_subdomains);
124 report.Set("noted-hostname", pkp_state.domain);
125
126 auto served_certificate_chain_list =
127 GetPEMEncodedChainAsList(served_certificate_chain);
128 auto validated_certificate_chain_list =
129 GetPEMEncodedChainAsList(validated_certificate_chain);
130 report.Set("served-certificate-chain",
131 std::move(served_certificate_chain_list));
132 report.Set("validated-certificate-chain",
133 std::move(validated_certificate_chain_list));
134
135 base::Value::List known_pin_list;
136 for (const auto& hash_value : pkp_state.spki_hashes) {
137 std::string known_pin;
138
139 switch (hash_value.tag()) {
140 case HASH_VALUE_SHA256:
141 known_pin += "pin-sha256=";
142 break;
143 default:
144 // Don't bother reporting about hash types we don't support. SHA-256 is
145 // the only standardized hash function for HPKP anyway.
146 continue;
147 }
148
149 std::string base64_value;
150 base::Base64Encode(
151 base::StringPiece(reinterpret_cast<const char*>(hash_value.data()),
152 hash_value.size()),
153 &base64_value);
154 known_pin += "\"" + base64_value + "\"";
155
156 known_pin_list.Append(known_pin);
157 }
158
159 report.Set("known-pins", std::move(known_pin_list));
160
161 // For the sent reports cache, do not include the effective expiration
162 // date. The expiration date will likely change every time the user
163 // visits the site, so it would prevent reports from being effectively
164 // deduplicated.
165 if (!HashReportForCache(report, pkp_state.report_uri, cache_key)) {
166 LOG(ERROR) << "Failed to compute cache key for HPKP violation report.";
167 return false;
168 }
169
170 report.Set("date-time", TimeFormatAsIso8601(now));
171 report.Set("effective-expiration-date",
172 TimeFormatAsIso8601(pkp_state.expiry));
173 if (!base::JSONWriter::Write(report, serialized_report)) {
174 LOG(ERROR) << "Failed to serialize HPKP violation report.";
175 return false;
176 }
177
178 return true;
179 }
180
181 // Do not send a report over HTTPS to the same host that set the
182 // pin. Such report URIs will result in loops. (A.com has a pinning
183 // violation which results in a report being sent to A.com, which
184 // results in a pinning violation which results in a report being sent
185 // to A.com, etc.)
IsReportUriValidForHost(const GURL & report_uri,const std::string & host)186 bool IsReportUriValidForHost(const GURL& report_uri, const std::string& host) {
187 return (report_uri.host_piece() != host ||
188 !report_uri.SchemeIsCryptographic());
189 }
190
HashesToBase64String(const HashValueVector & hashes)191 std::string HashesToBase64String(const HashValueVector& hashes) {
192 std::string str;
193 for (size_t i = 0; i != hashes.size(); ++i) {
194 if (i != 0)
195 str += ",";
196 str += hashes[i].ToString();
197 }
198 return str;
199 }
200
HashHost(base::span<const uint8_t> canonicalized_host)201 TransportSecurityState::HashedHost HashHost(
202 base::span<const uint8_t> canonicalized_host) {
203 return crypto::SHA256Hash(canonicalized_host);
204 }
205
206 // Returns true if the intersection of |a| and |b| is not empty. If either
207 // |a| or |b| is empty, returns false.
HashesIntersect(const HashValueVector & a,const HashValueVector & b)208 bool HashesIntersect(const HashValueVector& a, const HashValueVector& b) {
209 for (const auto& hash : a) {
210 if (base::Contains(b, hash))
211 return true;
212 }
213 return false;
214 }
215
AddHash(const char * sha256_hash,HashValueVector * out)216 bool AddHash(const char* sha256_hash, HashValueVector* out) {
217 HashValue hash(HASH_VALUE_SHA256);
218 memcpy(hash.data(), sha256_hash, hash.size());
219 out->push_back(hash);
220 return true;
221 }
222
223 // Converts |hostname| from dotted form ("www.google.com") to the form
224 // used in DNS: "\x03www\x06google\x03com", lowercases that, and returns
225 // the result.
CanonicalizeHost(const std::string & host)226 std::vector<uint8_t> CanonicalizeHost(const std::string& host) {
227 // We cannot perform the operations as detailed in the spec here as `host`
228 // has already undergone IDN processing before it reached us. Thus, we
229 // lowercase the input (probably redudnant since most input here has been
230 // lowercased through URL canonicalization) and check that there are no
231 // invalid characters in the host (via DNSDomainFromDot()).
232 std::string lowered_host = base::ToLowerASCII(host);
233
234 absl::optional<std::vector<uint8_t>> new_host =
235 dns_names_util::DottedNameToNetwork(
236 lowered_host,
237 /*require_valid_internet_hostname=*/true);
238 if (!new_host.has_value()) {
239 // DNSDomainFromDot can fail if any label is > 63 bytes or if the whole
240 // name is >255 bytes. However, search terms can have those properties.
241 return std::vector<uint8_t>();
242 }
243
244 return new_host.value();
245 }
246
247 // PreloadResult is the result of resolving a specific name in the preloaded
248 // data.
249 struct PreloadResult {
250 uint32_t pinset_id = 0;
251 // hostname_offset contains the number of bytes from the start of the given
252 // hostname where the name of the matching entry starts.
253 size_t hostname_offset = 0;
254 bool sts_include_subdomains = false;
255 bool pkp_include_subdomains = false;
256 bool force_https = false;
257 bool has_pins = false;
258 };
259
260 using net::extras::PreloadDecoder;
261
262 // Extracts the current PreloadResult entry from the given Huffman encoded trie.
263 // If an "end of string" matches a period in the hostname then the information
264 // is remembered because, if no more specific node is found, then that
265 // information applies to the hostname.
266 class HSTSPreloadDecoder : public net::extras::PreloadDecoder {
267 public:
268 using net::extras::PreloadDecoder::PreloadDecoder;
269
270 // net::extras::PreloadDecoder:
ReadEntry(net::extras::PreloadDecoder::BitReader * reader,const std::string & search,size_t current_search_offset,bool * out_found)271 bool ReadEntry(net::extras::PreloadDecoder::BitReader* reader,
272 const std::string& search,
273 size_t current_search_offset,
274 bool* out_found) override {
275 bool is_simple_entry;
276 if (!reader->Next(&is_simple_entry)) {
277 return false;
278 }
279 PreloadResult tmp;
280 // Simple entries only configure HSTS with IncludeSubdomains and use a
281 // compact serialization format where the other policy flags are
282 // omitted. The omitted flags are assumed to be 0 and the associated
283 // policies are disabled.
284 if (is_simple_entry) {
285 tmp.force_https = true;
286 tmp.sts_include_subdomains = true;
287 } else {
288 if (!reader->Next(&tmp.sts_include_subdomains) ||
289 !reader->Next(&tmp.force_https) || !reader->Next(&tmp.has_pins)) {
290 return false;
291 }
292
293 tmp.pkp_include_subdomains = tmp.sts_include_subdomains;
294
295 if (tmp.has_pins) {
296 if (!reader->Read(4, &tmp.pinset_id) ||
297 (!tmp.sts_include_subdomains &&
298 !reader->Next(&tmp.pkp_include_subdomains))) {
299 return false;
300 }
301 }
302 }
303
304 tmp.hostname_offset = current_search_offset;
305
306 if (current_search_offset == 0 ||
307 search[current_search_offset - 1] == '.') {
308 *out_found = tmp.sts_include_subdomains || tmp.pkp_include_subdomains;
309
310 result_ = tmp;
311
312 if (current_search_offset > 0) {
313 result_.force_https &= tmp.sts_include_subdomains;
314 } else {
315 *out_found = true;
316 return true;
317 }
318 }
319 return true;
320 }
321
result() const322 PreloadResult result() const { return result_; }
323
324 private:
325 PreloadResult result_;
326 };
327
DecodeHSTSPreload(const std::string & search_hostname,PreloadResult * out)328 bool DecodeHSTSPreload(const std::string& search_hostname, PreloadResult* out) {
329 #if !BUILDFLAG(INCLUDE_TRANSPORT_SECURITY_STATE_PRELOAD_LIST)
330 if (g_hsts_source == nullptr)
331 return false;
332 #endif
333 bool found = false;
334
335 // Ensure that |search_hostname| is a valid hostname before
336 // processing.
337 if (CanonicalizeHost(search_hostname).empty()) {
338 return false;
339 }
340 // Normalize any trailing '.' used for DNS suffix searches.
341 std::string hostname = search_hostname;
342 size_t trailing_dot_found = hostname.find_last_not_of('.');
343 if (trailing_dot_found != std::string::npos) {
344 hostname.erase(trailing_dot_found + 1);
345 } else {
346 hostname.clear();
347 }
348
349 // |hostname| has already undergone IDN conversion, so should be
350 // entirely A-Labels. The preload data is entirely normalized to
351 // lower case.
352 hostname = base::ToLowerASCII(hostname);
353 if (hostname.empty()) {
354 return false;
355 }
356
357 HSTSPreloadDecoder decoder(
358 g_hsts_source->huffman_tree, g_hsts_source->huffman_tree_size,
359 g_hsts_source->preloaded_data, g_hsts_source->preloaded_bits,
360 g_hsts_source->root_position);
361 if (!decoder.Decode(hostname, &found)) {
362 DCHECK(false) << "Internal error in DecodeHSTSPreload for hostname "
363 << hostname;
364 return false;
365 }
366 if (found)
367 *out = decoder.result();
368 return found;
369 }
370
371 } // namespace
372
373 // static
374 BASE_FEATURE(kCertificateTransparencyEnforcement,
375 "CertificateTransparencyEnforcement",
376 base::FEATURE_ENABLED_BY_DEFAULT);
377
SetTransportSecurityStateSourceForTesting(const TransportSecurityStateSource * source)378 void SetTransportSecurityStateSourceForTesting(
379 const TransportSecurityStateSource* source) {
380 g_hsts_source = source ? source : kDefaultHSTSSource;
381 }
382
TransportSecurityState()383 TransportSecurityState::TransportSecurityState()
384 : TransportSecurityState(std::vector<std::string>()) {}
385
TransportSecurityState(std::vector<std::string> hsts_host_bypass_list)386 TransportSecurityState::TransportSecurityState(
387 std::vector<std::string> hsts_host_bypass_list)
388 : sent_hpkp_reports_cache_(kMaxReportCacheEntries) {
389 // Static pinning is only enabled for official builds to make sure that
390 // others don't end up with pins that cannot be easily updated.
391 #if !BUILDFLAG(GOOGLE_CHROME_BRANDING) || BUILDFLAG(IS_IOS)
392 enable_static_pins_ = false;
393 #endif
394 // Check that there no invalid entries in the static HSTS bypass list.
395 for (auto& host : hsts_host_bypass_list) {
396 DCHECK(host.find('.') == std::string::npos);
397 hsts_host_bypass_list_.insert(host);
398 }
399 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
400 }
401
402 // Both HSTS and HPKP cause fatal SSL errors, so return true if a
403 // host has either.
ShouldSSLErrorsBeFatal(const std::string & host)404 bool TransportSecurityState::ShouldSSLErrorsBeFatal(const std::string& host) {
405 STSState unused_sts;
406 PKPState unused_pkp;
407 return GetSTSState(host, &unused_sts) || GetPKPState(host, &unused_pkp);
408 }
409
NetLogUpgradeToSSLParam(const std::string & host)410 base::Value::Dict TransportSecurityState::NetLogUpgradeToSSLParam(
411 const std::string& host) {
412 STSState sts_state;
413 base::Value::Dict dict;
414 dict.Set("host", host);
415 dict.Set("get_sts_state_result", GetSTSState(host, &sts_state));
416 dict.Set("should_upgrade_to_ssl", sts_state.ShouldUpgradeToSSL());
417 dict.Set("host_found_in_hsts_bypass_list",
418 hsts_host_bypass_list_.find(host) != hsts_host_bypass_list_.end());
419 return dict;
420 }
421
ShouldUpgradeToSSL(const std::string & host,const NetLogWithSource & net_log)422 bool TransportSecurityState::ShouldUpgradeToSSL(
423 const std::string& host,
424 const NetLogWithSource& net_log) {
425 STSState sts_state;
426 net_log.AddEvent(
427 NetLogEventType::TRANSPORT_SECURITY_STATE_SHOULD_UPGRADE_TO_SSL,
428 [&] { return NetLogUpgradeToSSLParam(host); });
429 return GetSTSState(host, &sts_state) && sts_state.ShouldUpgradeToSSL();
430 }
431
CheckPublicKeyPins(const HostPortPair & host_port_pair,bool is_issued_by_known_root,const HashValueVector & public_key_hashes,const X509Certificate * served_certificate_chain,const X509Certificate * validated_certificate_chain,const PublicKeyPinReportStatus report_status,const NetworkAnonymizationKey & network_anonymization_key,std::string * pinning_failure_log)432 TransportSecurityState::PKPStatus TransportSecurityState::CheckPublicKeyPins(
433 const HostPortPair& host_port_pair,
434 bool is_issued_by_known_root,
435 const HashValueVector& public_key_hashes,
436 const X509Certificate* served_certificate_chain,
437 const X509Certificate* validated_certificate_chain,
438 const PublicKeyPinReportStatus report_status,
439 const NetworkAnonymizationKey& network_anonymization_key,
440 std::string* pinning_failure_log) {
441 // Perform pin validation only if the server actually has public key pins.
442 if (!HasPublicKeyPins(host_port_pair.host())) {
443 return PKPStatus::OK;
444 }
445
446 return CheckPublicKeyPinsImpl(host_port_pair, is_issued_by_known_root,
447 public_key_hashes, served_certificate_chain,
448 validated_certificate_chain, report_status,
449 network_anonymization_key, pinning_failure_log);
450 }
451
HasPublicKeyPins(const std::string & host)452 bool TransportSecurityState::HasPublicKeyPins(const std::string& host) {
453 PKPState pkp_state;
454 return GetPKPState(host, &pkp_state) && pkp_state.HasPublicKeyPins();
455 }
456
457 TransportSecurityState::CTRequirementsStatus
CheckCTRequirements(const net::HostPortPair & host_port_pair,bool is_issued_by_known_root,const HashValueVector & public_key_hashes,const X509Certificate * validated_certificate_chain,const X509Certificate * served_certificate_chain,const SignedCertificateTimestampAndStatusList & signed_certificate_timestamps,ct::CTPolicyCompliance policy_compliance)458 TransportSecurityState::CheckCTRequirements(
459 const net::HostPortPair& host_port_pair,
460 bool is_issued_by_known_root,
461 const HashValueVector& public_key_hashes,
462 const X509Certificate* validated_certificate_chain,
463 const X509Certificate* served_certificate_chain,
464 const SignedCertificateTimestampAndStatusList&
465 signed_certificate_timestamps,
466 ct::CTPolicyCompliance policy_compliance) {
467 using CTRequirementLevel = RequireCTDelegate::CTRequirementLevel;
468 std::string hostname = host_port_pair.host();
469
470 // If CT is emergency disabled, either through a component updater set flag or
471 // through the feature flag, we don't require CT for any host.
472 if (ct_emergency_disable_ ||
473 !base::FeatureList::IsEnabled(kCertificateTransparencyEnforcement)) {
474 return CT_NOT_REQUIRED;
475 }
476
477 // CT is not required if the certificate does not chain to a publicly
478 // trusted root certificate. Testing can override this, as certain tests
479 // rely on using a non-publicly-trusted root.
480 if (!is_issued_by_known_root && !g_ct_required_for_testing)
481 return CT_NOT_REQUIRED;
482
483 // A connection is considered compliant if it has sufficient SCTs or if the
484 // build is outdated. Other statuses are not considered compliant; this
485 // includes COMPLIANCE_DETAILS_NOT_AVAILABLE because compliance must have been
486 // evaluated in order to determine that the connection is compliant.
487 bool complies =
488 (policy_compliance ==
489 ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS ||
490 policy_compliance == ct::CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY);
491
492 CTRequirementLevel ct_required = g_ct_required_for_testing
493 ? CTRequirementLevel::REQUIRED
494 : CTRequirementLevel::NOT_REQUIRED;
495 if (require_ct_delegate_) {
496 // Allow the delegate to override the CT requirement state.
497 ct_required = require_ct_delegate_->IsCTRequiredForHost(
498 hostname, validated_certificate_chain, public_key_hashes);
499 }
500 switch (ct_required) {
501 case CTRequirementLevel::REQUIRED:
502 return complies ? CT_REQUIREMENTS_MET : CT_REQUIREMENTS_NOT_MET;
503 case CTRequirementLevel::NOT_REQUIRED:
504 return CT_NOT_REQUIRED;
505 }
506 }
507
SetDelegate(TransportSecurityState::Delegate * delegate)508 void TransportSecurityState::SetDelegate(
509 TransportSecurityState::Delegate* delegate) {
510 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
511 delegate_ = delegate;
512 }
513
SetReportSender(TransportSecurityState::ReportSenderInterface * report_sender)514 void TransportSecurityState::SetReportSender(
515 TransportSecurityState::ReportSenderInterface* report_sender) {
516 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
517 report_sender_ = report_sender;
518 }
519
SetRequireCTDelegate(RequireCTDelegate * delegate)520 void TransportSecurityState::SetRequireCTDelegate(RequireCTDelegate* delegate) {
521 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
522 require_ct_delegate_ = delegate;
523 }
524
UpdatePinList(const std::vector<PinSet> & pinsets,const std::vector<PinSetInfo> & host_pins,base::Time update_time)525 void TransportSecurityState::UpdatePinList(
526 const std::vector<PinSet>& pinsets,
527 const std::vector<PinSetInfo>& host_pins,
528 base::Time update_time) {
529 pinsets_ = pinsets;
530 key_pins_list_last_update_time_ = update_time;
531 host_pins_.emplace();
532 std::map<std::string, PinSet const*> pinset_names_map;
533 for (const auto& pinset : pinsets_) {
534 pinset_names_map[pinset.name()] = &pinset;
535 }
536 for (const auto& pin : host_pins) {
537 if (!base::Contains(pinset_names_map, pin.pinset_name_)) {
538 // This should never happen, but if the component is bad and missing an
539 // entry, we will ignore that particular pin.
540 continue;
541 }
542 host_pins_.value()[pin.hostname_] = std::make_pair(
543 pinset_names_map[pin.pinset_name_], pin.include_subdomains_);
544 }
545 }
546
AddHSTSInternal(const std::string & host,TransportSecurityState::STSState::UpgradeMode upgrade_mode,const base::Time & expiry,bool include_subdomains)547 void TransportSecurityState::AddHSTSInternal(
548 const std::string& host,
549 TransportSecurityState::STSState::UpgradeMode upgrade_mode,
550 const base::Time& expiry,
551 bool include_subdomains) {
552 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
553 const std::vector<uint8_t> canonicalized_host = CanonicalizeHost(host);
554 if (canonicalized_host.empty())
555 return;
556
557 STSState sts_state;
558 // No need to store |sts_state.domain| since it is redundant.
559 // (|canonicalized_host| is the map key.)
560 sts_state.last_observed = base::Time::Now();
561 sts_state.include_subdomains = include_subdomains;
562 sts_state.expiry = expiry;
563 sts_state.upgrade_mode = upgrade_mode;
564
565 // Only store new state when HSTS is explicitly enabled. If it is
566 // disabled, remove the state from the enabled hosts.
567 if (sts_state.ShouldUpgradeToSSL()) {
568 enabled_sts_hosts_[HashHost(canonicalized_host)] = sts_state;
569 } else {
570 const HashedHost hashed_host = HashHost(canonicalized_host);
571 enabled_sts_hosts_.erase(hashed_host);
572 }
573
574 DirtyNotify();
575 }
576
AddHPKPInternal(const std::string & host,const base::Time & last_observed,const base::Time & expiry,bool include_subdomains,const HashValueVector & hashes,const GURL & report_uri)577 void TransportSecurityState::AddHPKPInternal(const std::string& host,
578 const base::Time& last_observed,
579 const base::Time& expiry,
580 bool include_subdomains,
581 const HashValueVector& hashes,
582 const GURL& report_uri) {
583 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
584 const std::vector<uint8_t> canonicalized_host = CanonicalizeHost(host);
585 if (canonicalized_host.empty())
586 return;
587
588 PKPState pkp_state;
589 // No need to store |pkp_state.domain| since it is redundant.
590 // (|canonicalized_host| is the map key.)
591 pkp_state.last_observed = last_observed;
592 pkp_state.expiry = expiry;
593 pkp_state.include_subdomains = include_subdomains;
594 pkp_state.spki_hashes = hashes;
595 pkp_state.report_uri = report_uri;
596
597 // Only store new state when HPKP is explicitly enabled. If it is
598 // disabled, remove the state from the enabled hosts.
599 if (pkp_state.HasPublicKeyPins()) {
600 enabled_pkp_hosts_[HashHost(canonicalized_host)] = pkp_state;
601 } else {
602 const HashedHost hashed_host = HashHost(canonicalized_host);
603 enabled_pkp_hosts_.erase(hashed_host);
604 }
605
606 DirtyNotify();
607 }
608
609 void TransportSecurityState::
SetEnablePublicKeyPinningBypassForLocalTrustAnchors(bool value)610 SetEnablePublicKeyPinningBypassForLocalTrustAnchors(bool value) {
611 enable_pkp_bypass_for_local_trust_anchors_ = value;
612 }
613
614 TransportSecurityState::PKPStatus
CheckPinsAndMaybeSendReport(const HostPortPair & host_port_pair,bool is_issued_by_known_root,const TransportSecurityState::PKPState & pkp_state,const HashValueVector & hashes,const X509Certificate * served_certificate_chain,const X509Certificate * validated_certificate_chain,const TransportSecurityState::PublicKeyPinReportStatus report_status,const net::NetworkAnonymizationKey & network_anonymization_key,std::string * failure_log)615 TransportSecurityState::CheckPinsAndMaybeSendReport(
616 const HostPortPair& host_port_pair,
617 bool is_issued_by_known_root,
618 const TransportSecurityState::PKPState& pkp_state,
619 const HashValueVector& hashes,
620 const X509Certificate* served_certificate_chain,
621 const X509Certificate* validated_certificate_chain,
622 const TransportSecurityState::PublicKeyPinReportStatus report_status,
623 const net::NetworkAnonymizationKey& network_anonymization_key,
624 std::string* failure_log) {
625 if (pkp_state.CheckPublicKeyPins(hashes, failure_log))
626 return PKPStatus::OK;
627
628 // Don't report violations for certificates that chain to local roots.
629 if (!is_issued_by_known_root && enable_pkp_bypass_for_local_trust_anchors_)
630 return PKPStatus::BYPASSED;
631
632 if (!report_sender_ ||
633 report_status != TransportSecurityState::ENABLE_PIN_REPORTS ||
634 pkp_state.report_uri.is_empty()) {
635 return PKPStatus::VIOLATED;
636 }
637
638 DCHECK(pkp_state.report_uri.is_valid());
639 // Report URIs should not be used if they are the same host as the pin
640 // and are HTTPS, to avoid going into a report-sending loop.
641 if (!IsReportUriValidForHost(pkp_state.report_uri, host_port_pair.host()))
642 return PKPStatus::VIOLATED;
643
644 std::string serialized_report;
645 std::string report_cache_key;
646 if (!GetHPKPReport(host_port_pair, pkp_state, served_certificate_chain,
647 validated_certificate_chain, &serialized_report,
648 &report_cache_key)) {
649 return PKPStatus::VIOLATED;
650 }
651
652 // Limit the rate at which duplicate reports are sent to the same
653 // report URI. The same report will not be sent within
654 // |kTimeToRememberReportsMins|, which reduces load on servers and
655 // also prevents accidental loops (a.com triggers a report to b.com
656 // which triggers a report to a.com). See section 2.1.4 of RFC 7469.
657 if (sent_hpkp_reports_cache_.Get(report_cache_key, base::TimeTicks::Now()))
658 return PKPStatus::VIOLATED;
659 sent_hpkp_reports_cache_.Put(
660 report_cache_key, true, base::TimeTicks::Now(),
661 base::TimeTicks::Now() + base::Minutes(kTimeToRememberReportsMins));
662
663 report_sender_->Send(pkp_state.report_uri, "application/json; charset=utf-8",
664 serialized_report, network_anonymization_key,
665 base::OnceCallback<void()>(),
666 base::OnceCallback<void(const GURL&, int, int)>());
667 return PKPStatus::VIOLATED;
668 }
669
DeleteDynamicDataForHost(const std::string & host)670 bool TransportSecurityState::DeleteDynamicDataForHost(const std::string& host) {
671 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
672
673 const std::vector<uint8_t> canonicalized_host = CanonicalizeHost(host);
674 if (canonicalized_host.empty())
675 return false;
676
677 const HashedHost hashed_host = HashHost(canonicalized_host);
678 bool deleted = false;
679 auto sts_interator = enabled_sts_hosts_.find(hashed_host);
680 if (sts_interator != enabled_sts_hosts_.end()) {
681 enabled_sts_hosts_.erase(sts_interator);
682 deleted = true;
683 }
684
685 auto pkp_iterator = enabled_pkp_hosts_.find(hashed_host);
686 if (pkp_iterator != enabled_pkp_hosts_.end()) {
687 enabled_pkp_hosts_.erase(pkp_iterator);
688 deleted = true;
689 }
690
691 if (deleted)
692 DirtyNotify();
693 return deleted;
694 }
695
ClearDynamicData()696 void TransportSecurityState::ClearDynamicData() {
697 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
698 enabled_sts_hosts_.clear();
699 enabled_pkp_hosts_.clear();
700 }
701
DeleteAllDynamicDataBetween(base::Time start_time,base::Time end_time,base::OnceClosure callback)702 void TransportSecurityState::DeleteAllDynamicDataBetween(
703 base::Time start_time,
704 base::Time end_time,
705 base::OnceClosure callback) {
706 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
707
708 bool dirtied = false;
709 auto sts_iterator = enabled_sts_hosts_.begin();
710 while (sts_iterator != enabled_sts_hosts_.end()) {
711 if (sts_iterator->second.last_observed >= start_time &&
712 sts_iterator->second.last_observed < end_time) {
713 dirtied = true;
714 enabled_sts_hosts_.erase(sts_iterator++);
715 continue;
716 }
717
718 ++sts_iterator;
719 }
720
721 auto pkp_iterator = enabled_pkp_hosts_.begin();
722 while (pkp_iterator != enabled_pkp_hosts_.end()) {
723 if (pkp_iterator->second.last_observed >= start_time &&
724 pkp_iterator->second.last_observed < end_time) {
725 dirtied = true;
726 enabled_pkp_hosts_.erase(pkp_iterator++);
727 continue;
728 }
729
730 ++pkp_iterator;
731 }
732
733 if (dirtied && delegate_)
734 delegate_->WriteNow(this, std::move(callback));
735 else
736 std::move(callback).Run();
737 }
738
~TransportSecurityState()739 TransportSecurityState::~TransportSecurityState() {
740 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
741 }
742
DirtyNotify()743 void TransportSecurityState::DirtyNotify() {
744 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
745
746 if (delegate_)
747 delegate_->StateIsDirty(this);
748 }
749
AddHSTSHeader(const std::string & host,const std::string & value)750 bool TransportSecurityState::AddHSTSHeader(const std::string& host,
751 const std::string& value) {
752 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
753
754 base::Time now = base::Time::Now();
755 base::TimeDelta max_age;
756 bool include_subdomains;
757 if (!ParseHSTSHeader(value, &max_age, &include_subdomains)) {
758 return false;
759 }
760
761 // Handle max-age == 0.
762 STSState::UpgradeMode upgrade_mode;
763 if (max_age.InSeconds() == 0) {
764 upgrade_mode = STSState::MODE_DEFAULT;
765 } else {
766 upgrade_mode = STSState::MODE_FORCE_HTTPS;
767 }
768
769 AddHSTSInternal(host, upgrade_mode, now + max_age, include_subdomains);
770 return true;
771 }
772
AddHSTS(const std::string & host,const base::Time & expiry,bool include_subdomains)773 void TransportSecurityState::AddHSTS(const std::string& host,
774 const base::Time& expiry,
775 bool include_subdomains) {
776 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
777 AddHSTSInternal(host, STSState::MODE_FORCE_HTTPS, expiry, include_subdomains);
778 }
779
AddHPKP(const std::string & host,const base::Time & expiry,bool include_subdomains,const HashValueVector & hashes,const GURL & report_uri)780 void TransportSecurityState::AddHPKP(const std::string& host,
781 const base::Time& expiry,
782 bool include_subdomains,
783 const HashValueVector& hashes,
784 const GURL& report_uri) {
785 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
786 AddHPKPInternal(host, base::Time::Now(), expiry, include_subdomains, hashes,
787 report_uri);
788 }
789
790 // static
SetRequireCTForTesting(bool required)791 void TransportSecurityState::SetRequireCTForTesting(bool required) {
792 g_ct_required_for_testing = required;
793 }
794
ClearReportCachesForTesting()795 void TransportSecurityState::ClearReportCachesForTesting() {
796 sent_hpkp_reports_cache_.Clear();
797 }
798
num_sts_entries() const799 size_t TransportSecurityState::num_sts_entries() const {
800 return enabled_sts_hosts_.size();
801 }
802
803 // static
IsBuildTimely()804 bool TransportSecurityState::IsBuildTimely() {
805 const base::Time build_time = base::GetBuildTime();
806 // We consider built-in information to be timely for 10 weeks.
807 return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */;
808 }
809
810 TransportSecurityState::PKPStatus
CheckPublicKeyPinsImpl(const HostPortPair & host_port_pair,bool is_issued_by_known_root,const HashValueVector & hashes,const X509Certificate * served_certificate_chain,const X509Certificate * validated_certificate_chain,const PublicKeyPinReportStatus report_status,const NetworkAnonymizationKey & network_anonymization_key,std::string * failure_log)811 TransportSecurityState::CheckPublicKeyPinsImpl(
812 const HostPortPair& host_port_pair,
813 bool is_issued_by_known_root,
814 const HashValueVector& hashes,
815 const X509Certificate* served_certificate_chain,
816 const X509Certificate* validated_certificate_chain,
817 const PublicKeyPinReportStatus report_status,
818 const NetworkAnonymizationKey& network_anonymization_key,
819 std::string* failure_log) {
820 PKPState pkp_state;
821 bool found_state = GetPKPState(host_port_pair.host(), &pkp_state);
822
823 // HasPublicKeyPins should have returned true in order for this method to have
824 // been called.
825 DCHECK(found_state);
826 return CheckPinsAndMaybeSendReport(
827 host_port_pair, is_issued_by_known_root, pkp_state, hashes,
828 served_certificate_chain, validated_certificate_chain, report_status,
829 network_anonymization_key, failure_log);
830 }
831
GetStaticSTSState(const std::string & host,STSState * sts_result) const832 bool TransportSecurityState::GetStaticSTSState(const std::string& host,
833 STSState* sts_result) const {
834 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
835
836 if (!IsBuildTimely())
837 return false;
838
839 PreloadResult result;
840 if (DecodeHSTSPreload(host, &result) &&
841 hsts_host_bypass_list_.find(host) == hsts_host_bypass_list_.end() &&
842 result.force_https) {
843 sts_result->domain = host.substr(result.hostname_offset);
844 sts_result->include_subdomains = result.sts_include_subdomains;
845 sts_result->last_observed = base::GetBuildTime();
846 sts_result->upgrade_mode = STSState::MODE_FORCE_HTTPS;
847 return true;
848 }
849
850 return false;
851 }
852
GetStaticPKPState(const std::string & host,PKPState * pkp_result) const853 bool TransportSecurityState::GetStaticPKPState(const std::string& host,
854 PKPState* pkp_result) const {
855 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
856
857 if (!enable_static_pins_ || !IsStaticPKPListTimely() ||
858 !base::FeatureList::IsEnabled(features::kStaticKeyPinningEnforcement)) {
859 return false;
860 }
861
862 PreloadResult result;
863 if (host_pins_.has_value()) {
864 // Ensure that |host| is a valid hostname before processing.
865 if (CanonicalizeHost(host).empty()) {
866 return false;
867 }
868 // Normalize any trailing '.' used for DNS suffix searches.
869 std::string normalized_host = host;
870 size_t trailing_dot_found = normalized_host.find_last_not_of('.');
871 if (trailing_dot_found == std::string::npos) {
872 // Hostname is either empty or all dots
873 return false;
874 }
875 normalized_host.erase(trailing_dot_found + 1);
876 normalized_host = base::ToLowerASCII(normalized_host);
877
878 base::StringPiece search_hostname = normalized_host;
879 while (true) {
880 auto iter = host_pins_->find(search_hostname);
881 // Only consider this a match if either include_subdomains is set, or
882 // this is an exact match of the full hostname.
883 if (iter != host_pins_->end() &&
884 (iter->second.second || search_hostname == normalized_host)) {
885 pkp_result->domain = std::string(search_hostname);
886 pkp_result->last_observed = key_pins_list_last_update_time_;
887 pkp_result->include_subdomains = iter->second.second;
888 const PinSet* pinset = iter->second.first;
889 if (!pinset->report_uri().empty()) {
890 pkp_result->report_uri = GURL(pinset->report_uri());
891 }
892 for (auto hash : pinset->static_spki_hashes()) {
893 // If the update is malformed, it's preferable to skip the hash than
894 // crash.
895 if (hash.size() == 32) {
896 AddHash(reinterpret_cast<const char*>(hash.data()),
897 &pkp_result->spki_hashes);
898 }
899 }
900 for (auto hash : pinset->bad_static_spki_hashes()) {
901 // If the update is malformed, it's preferable to skip the hash than
902 // crash.
903 if (hash.size() == 32) {
904 AddHash(reinterpret_cast<const char*>(hash.data()),
905 &pkp_result->bad_spki_hashes);
906 }
907 }
908 return true;
909 }
910 auto dot_pos = search_hostname.find(".");
911 if (dot_pos == std::string::npos) {
912 // If this was not a match, and there are no more dots in the string,
913 // there are no more domains to try.
914 return false;
915 }
916 // Try again in case this is a subdomain of a pinned domain that includes
917 // subdomains.
918 search_hostname = search_hostname.substr(dot_pos + 1);
919 }
920 } else if (DecodeHSTSPreload(host, &result) && result.has_pins) {
921 if (result.pinset_id >= g_hsts_source->pinsets_count)
922 return false;
923
924 pkp_result->domain = host.substr(result.hostname_offset);
925 pkp_result->include_subdomains = result.pkp_include_subdomains;
926 pkp_result->last_observed = base::GetBuildTime();
927
928 const TransportSecurityStateSource::Pinset* pinset =
929 &g_hsts_source->pinsets[result.pinset_id];
930 if (pinset->report_uri != kNoReportURI)
931 pkp_result->report_uri = GURL(pinset->report_uri);
932
933 if (pinset->accepted_pins) {
934 const char* const* sha256_hash = pinset->accepted_pins;
935 while (*sha256_hash) {
936 AddHash(*sha256_hash, &pkp_result->spki_hashes);
937 sha256_hash++;
938 }
939 }
940 if (pinset->rejected_pins) {
941 const char* const* sha256_hash = pinset->rejected_pins;
942 while (*sha256_hash) {
943 AddHash(*sha256_hash, &pkp_result->bad_spki_hashes);
944 sha256_hash++;
945 }
946 }
947 return true;
948 }
949
950 return false;
951 }
952
GetSTSState(const std::string & host,STSState * result)953 bool TransportSecurityState::GetSTSState(const std::string& host,
954 STSState* result) {
955 return GetDynamicSTSState(host, result) || GetStaticSTSState(host, result);
956 }
957
GetPKPState(const std::string & host,PKPState * result)958 bool TransportSecurityState::GetPKPState(const std::string& host,
959 PKPState* result) {
960 return GetDynamicPKPState(host, result) || GetStaticPKPState(host, result);
961 }
962
GetDynamicSTSState(const std::string & host,STSState * result)963 bool TransportSecurityState::GetDynamicSTSState(const std::string& host,
964 STSState* result) {
965 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
966
967 const std::vector<uint8_t> canonicalized_host = CanonicalizeHost(host);
968 if (canonicalized_host.empty())
969 return false;
970
971 base::Time current_time(base::Time::Now());
972
973 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) {
974 base::span<const uint8_t> host_sub_chunk =
975 base::make_span(canonicalized_host).subspan(i);
976 auto j = enabled_sts_hosts_.find(HashHost(host_sub_chunk));
977 if (j == enabled_sts_hosts_.end())
978 continue;
979
980 // If the entry is invalid, drop it.
981 if (current_time > j->second.expiry) {
982 enabled_sts_hosts_.erase(j);
983 DirtyNotify();
984 continue;
985 }
986
987 // An entry matches if it is either an exact match, or if it is a prefix
988 // match and the includeSubDomains directive was included.
989 if (i == 0 || j->second.include_subdomains) {
990 absl::optional<std::string> dotted_name =
991 dns_names_util::NetworkToDottedName(host_sub_chunk);
992 if (!dotted_name)
993 return false;
994
995 *result = j->second;
996 result->domain = std::move(dotted_name).value();
997 return true;
998 }
999 }
1000
1001 return false;
1002 }
1003
GetDynamicPKPState(const std::string & host,PKPState * result)1004 bool TransportSecurityState::GetDynamicPKPState(const std::string& host,
1005 PKPState* result) {
1006 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1007
1008 const std::vector<uint8_t> canonicalized_host = CanonicalizeHost(host);
1009 if (canonicalized_host.empty())
1010 return false;
1011
1012 base::Time current_time(base::Time::Now());
1013
1014 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) {
1015 base::span<const uint8_t> host_sub_chunk =
1016 base::make_span(canonicalized_host).subspan(i);
1017 auto j = enabled_pkp_hosts_.find(HashHost(host_sub_chunk));
1018 if (j == enabled_pkp_hosts_.end())
1019 continue;
1020
1021 // If the entry is invalid, drop it.
1022 if (current_time > j->second.expiry) {
1023 enabled_pkp_hosts_.erase(j);
1024 DirtyNotify();
1025 continue;
1026 }
1027
1028 // If this is the most specific PKP match, add it to the result. Note: a PKP
1029 // entry at a more specific domain overrides a less specific domain whether
1030 // or not |include_subdomains| is set.
1031 //
1032 // TODO(davidben): This does not match the HSTS behavior. We no longer
1033 // implement HPKP, so this logic is only used via AddHPKP(), reachable from
1034 // Cronet.
1035 if (i == 0 || j->second.include_subdomains) {
1036 absl::optional<std::string> dotted_name =
1037 dns_names_util::NetworkToDottedName(host_sub_chunk);
1038 if (!dotted_name)
1039 return false;
1040
1041 *result = j->second;
1042 result->domain = std::move(dotted_name).value();
1043 return true;
1044 }
1045
1046 break;
1047 }
1048
1049 return false;
1050 }
1051
AddOrUpdateEnabledSTSHosts(const HashedHost & hashed_host,const STSState & state)1052 void TransportSecurityState::AddOrUpdateEnabledSTSHosts(
1053 const HashedHost& hashed_host,
1054 const STSState& state) {
1055 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1056 DCHECK(state.ShouldUpgradeToSSL());
1057 enabled_sts_hosts_[hashed_host] = state;
1058 }
1059
1060 TransportSecurityState::STSState::STSState() = default;
1061
1062 TransportSecurityState::STSState::~STSState() = default;
1063
ShouldUpgradeToSSL() const1064 bool TransportSecurityState::STSState::ShouldUpgradeToSSL() const {
1065 return upgrade_mode == MODE_FORCE_HTTPS;
1066 }
1067
STSStateIterator(const TransportSecurityState & state)1068 TransportSecurityState::STSStateIterator::STSStateIterator(
1069 const TransportSecurityState& state)
1070 : iterator_(state.enabled_sts_hosts_.begin()),
1071 end_(state.enabled_sts_hosts_.end()) {}
1072
1073 TransportSecurityState::STSStateIterator::~STSStateIterator() = default;
1074
1075 TransportSecurityState::PKPState::PKPState() = default;
1076
1077 TransportSecurityState::PKPState::PKPState(const PKPState& other) = default;
1078
1079 TransportSecurityState::PKPState::~PKPState() = default;
1080
PinSet(std::string name,std::vector<std::vector<uint8_t>> static_spki_hashes,std::vector<std::vector<uint8_t>> bad_static_spki_hashes,std::string report_uri)1081 TransportSecurityState::PinSet::PinSet(
1082 std::string name,
1083 std::vector<std::vector<uint8_t>> static_spki_hashes,
1084 std::vector<std::vector<uint8_t>> bad_static_spki_hashes,
1085 std::string report_uri)
1086 : name_(std::move(name)),
1087 static_spki_hashes_(std::move(static_spki_hashes)),
1088 bad_static_spki_hashes_(std::move(bad_static_spki_hashes)),
1089 report_uri_(std::move(report_uri)) {}
1090
1091 TransportSecurityState::PinSet::PinSet(const PinSet& other) = default;
1092 TransportSecurityState::PinSet::~PinSet() = default;
1093
PinSetInfo(std::string hostname,std::string pinset_name,bool include_subdomains)1094 TransportSecurityState::PinSetInfo::PinSetInfo(std::string hostname,
1095 std::string pinset_name,
1096 bool include_subdomains)
1097 : hostname_(std::move(hostname)),
1098 pinset_name_(std::move(pinset_name)),
1099 include_subdomains_(std::move(include_subdomains)) {}
1100
CheckPublicKeyPins(const HashValueVector & hashes,std::string * failure_log) const1101 bool TransportSecurityState::PKPState::CheckPublicKeyPins(
1102 const HashValueVector& hashes,
1103 std::string* failure_log) const {
1104 // Validate that hashes is not empty. By the time this code is called (in
1105 // production), that should never happen, but it's good to be defensive.
1106 // And, hashes *can* be empty in some test scenarios.
1107 if (hashes.empty()) {
1108 failure_log->append(
1109 "Rejecting empty public key chain for public-key-pinned domains: " +
1110 domain);
1111 return false;
1112 }
1113
1114 if (HashesIntersect(bad_spki_hashes, hashes)) {
1115 failure_log->append("Rejecting public key chain for domain " + domain +
1116 ". Validated chain: " + HashesToBase64String(hashes) +
1117 ", matches one or more bad hashes: " +
1118 HashesToBase64String(bad_spki_hashes));
1119 return false;
1120 }
1121
1122 // If there are no pins, then any valid chain is acceptable.
1123 if (spki_hashes.empty())
1124 return true;
1125
1126 if (HashesIntersect(spki_hashes, hashes)) {
1127 return true;
1128 }
1129
1130 failure_log->append("Rejecting public key chain for domain " + domain +
1131 ". Validated chain: " + HashesToBase64String(hashes) +
1132 ", expected: " + HashesToBase64String(spki_hashes));
1133 return false;
1134 }
1135
HasPublicKeyPins() const1136 bool TransportSecurityState::PKPState::HasPublicKeyPins() const {
1137 return spki_hashes.size() > 0 || bad_spki_hashes.size() > 0;
1138 }
1139
IsStaticPKPListTimely() const1140 bool TransportSecurityState::IsStaticPKPListTimely() const {
1141 if (pins_list_always_timely_for_testing_) {
1142 return true;
1143 }
1144
1145 // If the list has not been updated via component updater, freshness depends
1146 // on the compiled-in list freshness.
1147 if (!host_pins_.has_value()) {
1148 #if BUILDFLAG(INCLUDE_TRANSPORT_SECURITY_STATE_PRELOAD_LIST)
1149 return (base::Time::Now() - kPinsListTimestamp).InDays() < 70;
1150 #else
1151 return false;
1152 #endif
1153 }
1154 DCHECK(!key_pins_list_last_update_time_.is_null());
1155 // Else, we use the last update time.
1156 return (base::Time::Now() - key_pins_list_last_update_time_).InDays() <
1157 70 /* 10 weeks */;
1158 }
1159
1160 } // namespace net
1161