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