• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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