Add long running gmail memory benchmark for background tab.
[chromium-blink-merge.git] / net / http / transport_security_state.cc
blob50e9c39d7454dd3887aa3bf1ab71bbe5f06aad9c
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/http/transport_security_state.h"
7 #if defined(USE_OPENSSL)
8 #include <openssl/ecdsa.h>
9 #include <openssl/ssl.h>
10 #else // !defined(USE_OPENSSL)
11 #include <cryptohi.h>
12 #include <hasht.h>
13 #include <keyhi.h>
14 #include <nspr.h>
15 #include <pk11pub.h>
16 #endif
18 #include <algorithm>
20 #include "base/base64.h"
21 #include "base/build_time.h"
22 #include "base/json/json_writer.h"
23 #include "base/logging.h"
24 #include "base/memory/scoped_ptr.h"
25 #include "base/metrics/histogram_macros.h"
26 #include "base/metrics/sparse_histogram.h"
27 #include "base/sha1.h"
28 #include "base/strings/string_number_conversions.h"
29 #include "base/strings/string_util.h"
30 #include "base/strings/stringprintf.h"
31 #include "base/strings/utf_string_conversions.h"
32 #include "base/time/time.h"
33 #include "base/values.h"
34 #include "crypto/sha2.h"
35 #include "net/base/dns_util.h"
36 #include "net/base/host_port_pair.h"
37 #include "net/cert/x509_cert_types.h"
38 #include "net/cert/x509_certificate.h"
39 #include "net/http/http_security_headers.h"
40 #include "net/ssl/ssl_info.h"
41 #include "url/gurl.h"
43 #if defined(USE_OPENSSL)
44 #include "crypto/openssl_util.h"
45 #endif
47 namespace net {
49 namespace {
51 #include "net/http/transport_security_state_static.h"
53 std::string TimeToISO8601(const base::Time& t) {
54 base::Time::Exploded exploded;
55 t.UTCExplode(&exploded);
56 return base::StringPrintf(
57 "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", exploded.year, exploded.month,
58 exploded.day_of_month, exploded.hour, exploded.minute, exploded.second,
59 exploded.millisecond);
62 scoped_ptr<base::ListValue> GetPEMEncodedChainAsList(
63 const net::X509Certificate* cert_chain) {
64 if (!cert_chain)
65 return make_scoped_ptr(new base::ListValue());
67 scoped_ptr<base::ListValue> result(new base::ListValue());
68 std::vector<std::string> pem_encoded_chain;
69 cert_chain->GetPEMEncodedChain(&pem_encoded_chain);
70 for (const std::string& cert : pem_encoded_chain)
71 result->Append(make_scoped_ptr(new base::StringValue(cert)));
73 return result.Pass();
76 bool GetHPKPReport(const HostPortPair& host_port_pair,
77 const TransportSecurityState::PKPState& pkp_state,
78 const X509Certificate* served_certificate_chain,
79 const X509Certificate* validated_certificate_chain,
80 std::string* serialized_report) {
81 // TODO(estark): keep track of reports already sent and rate-limit,
82 // break loops
83 if (pkp_state.report_uri.is_empty())
84 return false;
86 base::DictionaryValue report;
87 base::Time now = base::Time::Now();
88 report.SetString("date-time", TimeToISO8601(now));
89 report.SetString("hostname", host_port_pair.host());
90 report.SetInteger("port", host_port_pair.port());
91 report.SetString("effective-expiration-date",
92 TimeToISO8601(pkp_state.expiry));
93 report.SetBoolean("include-subdomains", pkp_state.include_subdomains);
94 report.SetString("noted-hostname", pkp_state.domain);
96 scoped_ptr<base::ListValue> served_certificate_chain_list =
97 GetPEMEncodedChainAsList(served_certificate_chain);
98 scoped_ptr<base::ListValue> validated_certificate_chain_list =
99 GetPEMEncodedChainAsList(validated_certificate_chain);
100 report.Set("served-certificate-chain", served_certificate_chain_list.Pass());
101 report.Set("validated-certificate-chain",
102 validated_certificate_chain_list.Pass());
104 scoped_ptr<base::ListValue> known_pin_list(new base::ListValue());
105 for (const auto& hash_value : pkp_state.spki_hashes) {
106 std::string known_pin;
108 switch (hash_value.tag) {
109 case HASH_VALUE_SHA1:
110 known_pin += "pin-sha1=";
111 break;
112 case HASH_VALUE_SHA256:
113 known_pin += "pin-sha256=";
114 break;
117 std::string base64_value;
118 base::Base64Encode(
119 base::StringPiece(reinterpret_cast<const char*>(hash_value.data()),
120 hash_value.size()),
121 &base64_value);
122 known_pin += "\"" + base64_value + "\"";
124 known_pin_list->Append(
125 scoped_ptr<base::Value>(new base::StringValue(known_pin)));
128 report.Set("known-pins", known_pin_list.Pass());
130 if (!base::JSONWriter::Write(report, serialized_report)) {
131 LOG(ERROR) << "Failed to serialize HPKP violation report.";
132 return false;
135 return true;
138 std::string HashesToBase64String(const HashValueVector& hashes) {
139 std::string str;
140 for (size_t i = 0; i != hashes.size(); ++i) {
141 if (i != 0)
142 str += ",";
143 str += hashes[i].ToString();
145 return str;
148 std::string HashHost(const std::string& canonicalized_host) {
149 char hashed[crypto::kSHA256Length];
150 crypto::SHA256HashString(canonicalized_host, hashed, sizeof(hashed));
151 return std::string(hashed, sizeof(hashed));
154 // Returns true if the intersection of |a| and |b| is not empty. If either
155 // |a| or |b| is empty, returns false.
156 bool HashesIntersect(const HashValueVector& a,
157 const HashValueVector& b) {
158 for (HashValueVector::const_iterator i = a.begin(); i != a.end(); ++i) {
159 HashValueVector::const_iterator j =
160 std::find_if(b.begin(), b.end(), HashValuesEqual(*i));
161 if (j != b.end())
162 return true;
164 return false;
167 bool AddHash(const char* sha1_hash,
168 HashValueVector* out) {
169 HashValue hash(HASH_VALUE_SHA1);
170 memcpy(hash.data(), sha1_hash, hash.size());
171 out->push_back(hash);
172 return true;
175 // Converts |hostname| from dotted form ("www.google.com") to the form
176 // used in DNS: "\x03www\x06google\x03com", lowercases that, and returns
177 // the result.
178 std::string CanonicalizeHost(const std::string& host) {
179 // We cannot perform the operations as detailed in the spec here as |host|
180 // has already undergone IDN processing before it reached us. Thus, we check
181 // that there are no invalid characters in the host and lowercase the result.
182 std::string new_host;
183 if (!DNSDomainFromDot(host, &new_host)) {
184 // DNSDomainFromDot can fail if any label is > 63 bytes or if the whole
185 // name is >255 bytes. However, search terms can have those properties.
186 return std::string();
189 for (size_t i = 0; new_host[i]; i += new_host[i] + 1) {
190 const unsigned label_length = static_cast<unsigned>(new_host[i]);
191 if (!label_length)
192 break;
194 for (size_t j = 0; j < label_length; ++j) {
195 new_host[i + 1 + j] = static_cast<char>(tolower(new_host[i + 1 + j]));
199 return new_host;
202 // BitReader is a class that allows a bytestring to be read bit-by-bit.
203 class BitReader {
204 public:
205 BitReader(const uint8* bytes, size_t num_bits)
206 : bytes_(bytes),
207 num_bits_(num_bits),
208 num_bytes_((num_bits + 7) / 8),
209 current_byte_index_(0),
210 num_bits_used_(8) {}
212 // Next sets |*out| to the next bit from the input. It returns false if no
213 // more bits are available or true otherwise.
214 bool Next(bool* out) {
215 if (num_bits_used_ == 8) {
216 if (current_byte_index_ >= num_bytes_) {
217 return false;
219 current_byte_ = bytes_[current_byte_index_++];
220 num_bits_used_ = 0;
223 *out = 1 & (current_byte_ >> (7 - num_bits_used_));
224 num_bits_used_++;
225 return true;
228 // Read sets the |num_bits| least-significant bits of |*out| to the value of
229 // the next |num_bits| bits from the input. It returns false if there are
230 // insufficient bits in the input or true otherwise.
231 bool Read(unsigned num_bits, uint32* out) {
232 DCHECK_LE(num_bits, 32u);
234 uint32 ret = 0;
235 for (unsigned i = 0; i < num_bits; ++i) {
236 bool bit;
237 if (!Next(&bit)) {
238 return false;
240 ret |= static_cast<uint32>(bit) << (num_bits - 1 - i);
243 *out = ret;
244 return true;
247 // Unary sets |*out| to the result of decoding a unary value from the input.
248 // It returns false if there were insufficient bits in the input and true
249 // otherwise.
250 bool Unary(size_t* out) {
251 size_t ret = 0;
253 for (;;) {
254 bool bit;
255 if (!Next(&bit)) {
256 return false;
258 if (!bit) {
259 break;
261 ret++;
264 *out = ret;
265 return true;
268 // Seek sets the current offest in the input to bit number |offset|. It
269 // returns true if |offset| is within the range of the input and false
270 // otherwise.
271 bool Seek(size_t offset) {
272 if (offset >= num_bits_) {
273 return false;
275 current_byte_index_ = offset / 8;
276 current_byte_ = bytes_[current_byte_index_++];
277 num_bits_used_ = offset % 8;
278 return true;
281 private:
282 const uint8* const bytes_;
283 const size_t num_bits_;
284 const size_t num_bytes_;
285 // current_byte_index_ contains the current byte offset in |bytes_|.
286 size_t current_byte_index_;
287 // current_byte_ contains the current byte of the input.
288 uint8 current_byte_;
289 // num_bits_used_ contains the number of bits of |current_byte_| that have
290 // been read.
291 unsigned num_bits_used_;
294 // HuffmanDecoder is a very simple Huffman reader. The input Huffman tree is
295 // simply encoded as a series of two-byte structures. The first byte determines
296 // the "0" pointer for that node and the second the "1" pointer. Each byte
297 // either has the MSB set, in which case the bottom 7 bits are the value for
298 // that position, or else the bottom seven bits contain the index of a node.
300 // The tree is decoded by walking rather than a table-driven approach.
301 class HuffmanDecoder {
302 public:
303 HuffmanDecoder(const uint8* tree, size_t tree_bytes)
304 : tree_(tree), tree_bytes_(tree_bytes) {}
306 bool Decode(BitReader* reader, char* out) {
307 const uint8* current = &tree_[tree_bytes_ - 2];
309 for (;;) {
310 bool bit;
311 if (!reader->Next(&bit)) {
312 return false;
315 uint8 b = current[bit];
316 if (b & 0x80) {
317 *out = static_cast<char>(b & 0x7f);
318 return true;
321 unsigned offset = static_cast<unsigned>(b) * 2;
322 DCHECK_LT(offset, tree_bytes_);
323 if (offset >= tree_bytes_) {
324 return false;
327 current = &tree_[offset];
331 private:
332 const uint8* const tree_;
333 const size_t tree_bytes_;
336 // PreloadResult is the result of resolving a specific name in the preloaded
337 // data.
338 struct PreloadResult {
339 uint32 pinset_id;
340 uint32 domain_id;
341 // hostname_offset contains the number of bytes from the start of the given
342 // hostname where the name of the matching entry starts.
343 size_t hostname_offset;
344 bool sts_include_subdomains;
345 bool pkp_include_subdomains;
346 bool force_https;
347 bool has_pins;
350 // DecodeHSTSPreloadRaw resolves |hostname| in the preloaded data. It returns
351 // false on internal error and true otherwise. After a successful return,
352 // |*out_found| is true iff a relevant entry has been found. If so, |*out|
353 // contains the details.
355 // Don't call this function, call DecodeHSTSPreload, below.
357 // Although this code should be robust, it never processes attacker-controlled
358 // data -- it only operates on the preloaded data built into the binary.
360 // The preloaded data is represented as a trie and matches the hostname
361 // backwards. Each node in the trie starts with a number of characters, which
362 // must match exactly. After that is a dispatch table which maps the next
363 // character in the hostname to another node in the trie.
365 // In the dispatch table, the zero character represents the "end of string"
366 // (which is the *beginning* of a hostname since we process it backwards). The
367 // value in that case is special -- rather than an offset to another trie node,
368 // it contains the HSTS information: whether subdomains are included, pinsets
369 // etc. If an "end of string" matches a period in the hostname then the
370 // information is remembered because, if no more specific node is found, then
371 // that information applies to the hostname.
373 // Dispatch tables are always given in order, but the "end of string" (zero)
374 // value always comes before an entry for '.'.
375 bool DecodeHSTSPreloadRaw(const std::string& search_hostname,
376 bool* out_found,
377 PreloadResult* out) {
378 HuffmanDecoder huffman(kHSTSHuffmanTree, sizeof(kHSTSHuffmanTree));
379 BitReader reader(kPreloadedHSTSData, kPreloadedHSTSBits);
380 size_t bit_offset = kHSTSRootPosition;
381 static const char kEndOfString = 0;
382 static const char kEndOfTable = 127;
384 *out_found = false;
386 // Ensure that |search_hostname| is a valid hostname before
387 // processing.
388 if (CanonicalizeHost(search_hostname).empty()) {
389 return true;
392 // Normalize any trailing '.' used for DNS suffix searches.
393 std::string hostname = search_hostname;
394 size_t found = hostname.find_last_not_of('.');
395 if (found != std::string::npos) {
396 hostname.erase(found + 1);
397 } else {
398 hostname.clear();
401 // |hostname| has already undergone IDN conversion, so should be
402 // entirely A-Labels. The preload data is entirely normalized to
403 // lower case.
404 base::StringToLowerASCII(&hostname);
406 if (hostname.empty()) {
407 return true;
410 // hostname_offset contains one more than the index of the current character
411 // in the hostname that is being considered. It's one greater so that we can
412 // represent the position just before the beginning (with zero).
413 size_t hostname_offset = hostname.size();
415 for (;;) {
416 // Seek to the desired location.
417 if (!reader.Seek(bit_offset)) {
418 return false;
421 // Decode the unary length of the common prefix.
422 size_t prefix_length;
423 if (!reader.Unary(&prefix_length)) {
424 return false;
427 // Match each character in the prefix.
428 for (size_t i = 0; i < prefix_length; ++i) {
429 if (hostname_offset == 0) {
430 // We can't match the terminator with a prefix string.
431 return true;
434 char c;
435 if (!huffman.Decode(&reader, &c)) {
436 return false;
438 if (hostname[hostname_offset - 1] != c) {
439 return true;
441 hostname_offset--;
444 bool is_first_offset = true;
445 size_t current_offset = 0;
447 // Next is the dispatch table.
448 for (;;) {
449 char c;
450 if (!huffman.Decode(&reader, &c)) {
451 return false;
453 if (c == kEndOfTable) {
454 // No exact match.
455 return true;
458 if (c == kEndOfString) {
459 PreloadResult tmp;
460 if (!reader.Next(&tmp.sts_include_subdomains) ||
461 !reader.Next(&tmp.force_https) || !reader.Next(&tmp.has_pins)) {
462 return false;
465 tmp.pkp_include_subdomains = tmp.sts_include_subdomains;
467 if (tmp.has_pins) {
468 if (!reader.Read(4, &tmp.pinset_id) ||
469 !reader.Read(9, &tmp.domain_id) ||
470 (!tmp.sts_include_subdomains &&
471 !reader.Next(&tmp.pkp_include_subdomains))) {
472 return false;
476 tmp.hostname_offset = hostname_offset;
478 if (hostname_offset == 0 || hostname[hostname_offset - 1] == '.') {
479 *out_found = tmp.sts_include_subdomains || tmp.pkp_include_subdomains;
480 *out = tmp;
482 if (hostname_offset > 0) {
483 out->force_https &= tmp.sts_include_subdomains;
484 } else {
485 *out_found = true;
486 return true;
490 continue;
493 // The entries in a dispatch table are in order thus we can tell if there
494 // will be no match if the current character past the one that we want.
495 if (hostname_offset == 0 || hostname[hostname_offset - 1] < c) {
496 return true;
499 if (is_first_offset) {
500 // The first offset is backwards from the current position.
501 uint32 jump_delta_bits;
502 uint32 jump_delta;
503 if (!reader.Read(5, &jump_delta_bits) ||
504 !reader.Read(jump_delta_bits, &jump_delta)) {
505 return false;
508 if (bit_offset < jump_delta) {
509 return false;
512 current_offset = bit_offset - jump_delta;
513 is_first_offset = false;
514 } else {
515 // Subsequent offsets are forward from the target of the first offset.
516 uint32 is_long_jump;
517 if (!reader.Read(1, &is_long_jump)) {
518 return false;
521 uint32 jump_delta;
522 if (!is_long_jump) {
523 if (!reader.Read(7, &jump_delta)) {
524 return false;
526 } else {
527 uint32 jump_delta_bits;
528 if (!reader.Read(4, &jump_delta_bits) ||
529 !reader.Read(jump_delta_bits + 8, &jump_delta)) {
530 return false;
534 current_offset += jump_delta;
535 if (current_offset >= bit_offset) {
536 return false;
540 DCHECK_LT(0u, hostname_offset);
541 if (hostname[hostname_offset - 1] == c) {
542 bit_offset = current_offset;
543 hostname_offset--;
544 break;
550 bool DecodeHSTSPreload(const std::string& hostname, PreloadResult* out) {
551 bool found;
552 if (!DecodeHSTSPreloadRaw(hostname, &found, out)) {
553 DCHECK(false) << "Internal error in DecodeHSTSPreloadRaw for hostname "
554 << hostname;
555 return false;
558 return found;
561 } // namespace
563 TransportSecurityState::TransportSecurityState()
564 : delegate_(nullptr), report_sender_(nullptr), enable_static_pins_(true) {
565 // Static pinning is only enabled for official builds to make sure that
566 // others don't end up with pins that cannot be easily updated.
567 #if !defined(OFFICIAL_BUILD) || defined(OS_ANDROID) || defined(OS_IOS)
568 enable_static_pins_ = false;
569 #endif
570 DCHECK(CalledOnValidThread());
573 // Both HSTS and HPKP cause fatal SSL errors, so return true if a
574 // host has either.
575 bool TransportSecurityState::ShouldSSLErrorsBeFatal(const std::string& host) {
576 STSState sts_state;
577 PKPState pkp_state;
578 if (GetStaticDomainState(host, &sts_state, &pkp_state))
579 return true;
580 if (GetDynamicSTSState(host, &sts_state))
581 return true;
582 return GetDynamicPKPState(host, &pkp_state);
585 bool TransportSecurityState::ShouldUpgradeToSSL(const std::string& host) {
586 STSState dynamic_sts_state;
587 if (GetDynamicSTSState(host, &dynamic_sts_state))
588 return dynamic_sts_state.ShouldUpgradeToSSL();
590 STSState static_sts_state;
591 PKPState unused;
592 if (GetStaticDomainState(host, &static_sts_state, &unused) &&
593 static_sts_state.ShouldUpgradeToSSL()) {
594 return true;
597 return false;
600 bool TransportSecurityState::CheckPublicKeyPins(
601 const HostPortPair& host_port_pair,
602 bool is_issued_by_known_root,
603 const HashValueVector& public_key_hashes,
604 const X509Certificate* served_certificate_chain,
605 const X509Certificate* validated_certificate_chain,
606 const PublicKeyPinReportStatus report_status,
607 std::string* pinning_failure_log) {
608 // Perform pin validation if, and only if, all these conditions obtain:
610 // * the server's certificate chain chains up to a known root (i.e. not a
611 // user-installed trust anchor); and
612 // * the server actually has public key pins.
613 if (!is_issued_by_known_root || !HasPublicKeyPins(host_port_pair.host())) {
614 return true;
617 bool pins_are_valid = CheckPublicKeyPinsImpl(
618 host_port_pair, public_key_hashes, served_certificate_chain,
619 validated_certificate_chain, report_status, pinning_failure_log);
620 if (!pins_are_valid) {
621 LOG(ERROR) << *pinning_failure_log;
622 ReportUMAOnPinFailure(host_port_pair.host());
625 UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", pins_are_valid);
626 return pins_are_valid;
629 bool TransportSecurityState::HasPublicKeyPins(const std::string& host) {
630 PKPState dynamic_state;
631 if (GetDynamicPKPState(host, &dynamic_state))
632 return dynamic_state.HasPublicKeyPins();
634 STSState unused;
635 PKPState static_pkp_state;
636 if (GetStaticDomainState(host, &unused, &static_pkp_state)) {
637 if (static_pkp_state.HasPublicKeyPins())
638 return true;
641 return false;
644 void TransportSecurityState::SetDelegate(
645 TransportSecurityState::Delegate* delegate) {
646 DCHECK(CalledOnValidThread());
647 delegate_ = delegate;
650 void TransportSecurityState::SetReportSender(
651 TransportSecurityState::ReportSender* report_sender) {
652 DCHECK(CalledOnValidThread());
653 report_sender_ = report_sender;
656 void TransportSecurityState::AddHSTSInternal(
657 const std::string& host,
658 TransportSecurityState::STSState::UpgradeMode upgrade_mode,
659 const base::Time& expiry,
660 bool include_subdomains) {
661 DCHECK(CalledOnValidThread());
663 STSState sts_state;
664 sts_state.last_observed = base::Time::Now();
665 sts_state.include_subdomains = include_subdomains;
666 sts_state.expiry = expiry;
667 sts_state.upgrade_mode = upgrade_mode;
669 EnableSTSHost(host, sts_state);
672 void TransportSecurityState::AddHPKPInternal(const std::string& host,
673 const base::Time& last_observed,
674 const base::Time& expiry,
675 bool include_subdomains,
676 const HashValueVector& hashes,
677 const GURL& report_uri) {
678 DCHECK(CalledOnValidThread());
680 PKPState pkp_state;
681 pkp_state.last_observed = last_observed;
682 pkp_state.expiry = expiry;
683 pkp_state.include_subdomains = include_subdomains;
684 pkp_state.spki_hashes = hashes;
685 pkp_state.report_uri = report_uri;
687 EnablePKPHost(host, pkp_state);
690 void TransportSecurityState::EnableSTSHost(const std::string& host,
691 const STSState& state) {
692 DCHECK(CalledOnValidThread());
694 const std::string canonicalized_host = CanonicalizeHost(host);
695 if (canonicalized_host.empty())
696 return;
698 // Only store new state when HSTS is explicitly enabled. If it is
699 // disabled, remove the state from the enabled hosts.
700 if (state.ShouldUpgradeToSSL()) {
701 STSState sts_state(state);
702 // No need to store this value since it is redundant. (|canonicalized_host|
703 // is the map key.)
704 sts_state.domain.clear();
706 enabled_sts_hosts_[HashHost(canonicalized_host)] = sts_state;
707 } else {
708 const std::string hashed_host = HashHost(canonicalized_host);
709 enabled_sts_hosts_.erase(hashed_host);
712 DirtyNotify();
715 void TransportSecurityState::EnablePKPHost(const std::string& host,
716 const PKPState& state) {
717 DCHECK(CalledOnValidThread());
719 const std::string canonicalized_host = CanonicalizeHost(host);
720 if (canonicalized_host.empty())
721 return;
723 // Only store new state when HPKP is explicitly enabled. If it is
724 // disabled, remove the state from the enabled hosts.
725 if (state.HasPublicKeyPins()) {
726 PKPState pkp_state(state);
727 // No need to store this value since it is redundant. (|canonicalized_host|
728 // is the map key.)
729 pkp_state.domain.clear();
731 enabled_pkp_hosts_[HashHost(canonicalized_host)] = pkp_state;
732 } else {
733 const std::string hashed_host = HashHost(canonicalized_host);
734 enabled_pkp_hosts_.erase(hashed_host);
737 DirtyNotify();
740 bool TransportSecurityState::DeleteDynamicDataForHost(const std::string& host) {
741 DCHECK(CalledOnValidThread());
743 const std::string canonicalized_host = CanonicalizeHost(host);
744 if (canonicalized_host.empty())
745 return false;
747 const std::string hashed_host = HashHost(canonicalized_host);
748 bool deleted = false;
749 STSStateMap::iterator sts_interator = enabled_sts_hosts_.find(hashed_host);
750 if (sts_interator != enabled_sts_hosts_.end()) {
751 enabled_sts_hosts_.erase(sts_interator);
752 deleted = true;
755 PKPStateMap::iterator pkp_iterator = enabled_pkp_hosts_.find(hashed_host);
756 if (pkp_iterator != enabled_pkp_hosts_.end()) {
757 enabled_pkp_hosts_.erase(pkp_iterator);
758 deleted = true;
761 if (deleted)
762 DirtyNotify();
763 return deleted;
766 void TransportSecurityState::ClearDynamicData() {
767 DCHECK(CalledOnValidThread());
768 enabled_sts_hosts_.clear();
769 enabled_pkp_hosts_.clear();
772 void TransportSecurityState::DeleteAllDynamicDataSince(const base::Time& time) {
773 DCHECK(CalledOnValidThread());
775 bool dirtied = false;
776 STSStateMap::iterator sts_iterator = enabled_sts_hosts_.begin();
777 while (sts_iterator != enabled_sts_hosts_.end()) {
778 if (sts_iterator->second.last_observed >= time) {
779 dirtied = true;
780 enabled_sts_hosts_.erase(sts_iterator++);
781 continue;
784 ++sts_iterator;
787 PKPStateMap::iterator pkp_iterator = enabled_pkp_hosts_.begin();
788 while (pkp_iterator != enabled_pkp_hosts_.end()) {
789 if (pkp_iterator->second.last_observed >= time) {
790 dirtied = true;
791 enabled_pkp_hosts_.erase(pkp_iterator++);
792 continue;
795 ++pkp_iterator;
798 if (dirtied)
799 DirtyNotify();
802 TransportSecurityState::~TransportSecurityState() {
803 DCHECK(CalledOnValidThread());
806 void TransportSecurityState::DirtyNotify() {
807 DCHECK(CalledOnValidThread());
809 if (delegate_)
810 delegate_->StateIsDirty(this);
813 bool TransportSecurityState::AddHSTSHeader(const std::string& host,
814 const std::string& value) {
815 DCHECK(CalledOnValidThread());
817 base::Time now = base::Time::Now();
818 base::TimeDelta max_age;
819 bool include_subdomains;
820 if (!ParseHSTSHeader(value, &max_age, &include_subdomains)) {
821 return false;
824 // Handle max-age == 0.
825 STSState::UpgradeMode upgrade_mode;
826 if (max_age.InSeconds() == 0) {
827 upgrade_mode = STSState::MODE_DEFAULT;
828 } else {
829 upgrade_mode = STSState::MODE_FORCE_HTTPS;
832 AddHSTSInternal(host, upgrade_mode, now + max_age, include_subdomains);
833 return true;
836 bool TransportSecurityState::AddHPKPHeader(const std::string& host,
837 const std::string& value,
838 const SSLInfo& ssl_info) {
839 DCHECK(CalledOnValidThread());
841 base::Time now = base::Time::Now();
842 base::TimeDelta max_age;
843 bool include_subdomains;
844 HashValueVector spki_hashes;
845 GURL report_uri;
847 if (!ParseHPKPHeader(value, ssl_info.public_key_hashes, &max_age,
848 &include_subdomains, &spki_hashes, &report_uri)) {
849 return false;
851 // Handle max-age == 0.
852 if (max_age.InSeconds() == 0)
853 spki_hashes.clear();
854 AddHPKPInternal(host, now, now + max_age, include_subdomains, spki_hashes,
855 report_uri);
856 return true;
859 void TransportSecurityState::AddHSTS(const std::string& host,
860 const base::Time& expiry,
861 bool include_subdomains) {
862 DCHECK(CalledOnValidThread());
863 AddHSTSInternal(host, STSState::MODE_FORCE_HTTPS, expiry, include_subdomains);
866 void TransportSecurityState::AddHPKP(const std::string& host,
867 const base::Time& expiry,
868 bool include_subdomains,
869 const HashValueVector& hashes,
870 const GURL& report_uri) {
871 DCHECK(CalledOnValidThread());
872 AddHPKPInternal(host, base::Time::Now(), expiry, include_subdomains, hashes,
873 report_uri);
876 // static
877 bool TransportSecurityState::IsGooglePinnedProperty(const std::string& host) {
878 PreloadResult result;
879 return DecodeHSTSPreload(host, &result) && result.has_pins &&
880 kPinsets[result.pinset_id].accepted_pins == kGoogleAcceptableCerts;
883 // static
884 void TransportSecurityState::ReportUMAOnPinFailure(const std::string& host) {
885 PreloadResult result;
886 if (!DecodeHSTSPreload(host, &result) ||
887 !result.has_pins) {
888 return;
891 DCHECK(result.domain_id != DOMAIN_NOT_PINNED);
893 UMA_HISTOGRAM_SPARSE_SLOWLY(
894 "Net.PublicKeyPinFailureDomain", result.domain_id);
897 // static
898 bool TransportSecurityState::IsBuildTimely() {
899 // If the build metadata aren't embedded in the binary then we can't use the
900 // build time to determine if the build is timely, return true by default. If
901 // we're building an official build then keep using the build time, even if
902 // it's invalid it'd be a date in the past and this function will return
903 // false.
904 #if defined(DONT_EMBED_BUILD_METADATA) && !defined(OFFICIAL_BUILD)
905 return true;
906 #else
907 const base::Time build_time = base::GetBuildTime();
908 // We consider built-in information to be timely for 10 weeks.
909 return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */;
910 #endif
913 bool TransportSecurityState::CheckPublicKeyPinsImpl(
914 const HostPortPair& host_port_pair,
915 const HashValueVector& hashes,
916 const X509Certificate* served_certificate_chain,
917 const X509Certificate* validated_certificate_chain,
918 const PublicKeyPinReportStatus report_status,
919 std::string* failure_log) {
920 PKPState pkp_state;
921 STSState unused;
923 if (!GetDynamicPKPState(host_port_pair.host(), &pkp_state) &&
924 !GetStaticDomainState(host_port_pair.host(), &unused, &pkp_state)) {
925 // HasPublicKeyPins should have returned true in order for this method
926 // to have been called, so if we fall through to here, it's an error.
927 return false;
930 if (pkp_state.CheckPublicKeyPins(hashes, failure_log))
931 return true;
933 if (!report_sender_ || report_status != ENABLE_PIN_REPORTS ||
934 pkp_state.report_uri.is_empty()) {
935 return false;
938 DCHECK(pkp_state.report_uri.is_valid());
940 std::string serialized_report;
942 if (!GetHPKPReport(host_port_pair, pkp_state, served_certificate_chain,
943 validated_certificate_chain, &serialized_report)) {
944 return false;
947 report_sender_->Send(pkp_state.report_uri, serialized_report);
949 return false;
952 bool TransportSecurityState::GetStaticDomainState(const std::string& host,
953 STSState* sts_state,
954 PKPState* pkp_state) const {
955 DCHECK(CalledOnValidThread());
957 sts_state->upgrade_mode = STSState::MODE_FORCE_HTTPS;
958 sts_state->include_subdomains = false;
959 pkp_state->include_subdomains = false;
961 if (!IsBuildTimely())
962 return false;
964 PreloadResult result;
965 if (!DecodeHSTSPreload(host, &result))
966 return false;
968 sts_state->domain = host.substr(result.hostname_offset);
969 pkp_state->domain = sts_state->domain;
970 sts_state->include_subdomains = result.sts_include_subdomains;
971 sts_state->last_observed = base::GetBuildTime();
972 sts_state->upgrade_mode = STSState::MODE_DEFAULT;
973 if (result.force_https) {
974 sts_state->upgrade_mode = STSState::MODE_FORCE_HTTPS;
977 if (enable_static_pins_ && result.has_pins) {
978 pkp_state->include_subdomains = result.pkp_include_subdomains;
979 pkp_state->last_observed = base::GetBuildTime();
981 if (result.pinset_id >= arraysize(kPinsets))
982 return false;
983 const Pinset *pinset = &kPinsets[result.pinset_id];
985 if (pinset->accepted_pins) {
986 const char* const* sha1_hash = pinset->accepted_pins;
987 while (*sha1_hash) {
988 AddHash(*sha1_hash, &pkp_state->spki_hashes);
989 sha1_hash++;
992 if (pinset->rejected_pins) {
993 const char* const* sha1_hash = pinset->rejected_pins;
994 while (*sha1_hash) {
995 AddHash(*sha1_hash, &pkp_state->bad_spki_hashes);
996 sha1_hash++;
1001 return true;
1004 bool TransportSecurityState::GetDynamicSTSState(const std::string& host,
1005 STSState* result) {
1006 DCHECK(CalledOnValidThread());
1008 const std::string canonicalized_host = CanonicalizeHost(host);
1009 if (canonicalized_host.empty())
1010 return false;
1012 base::Time current_time(base::Time::Now());
1014 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) {
1015 std::string host_sub_chunk(&canonicalized_host[i],
1016 canonicalized_host.size() - i);
1017 STSStateMap::iterator j = enabled_sts_hosts_.find(HashHost(host_sub_chunk));
1018 if (j == enabled_sts_hosts_.end())
1019 continue;
1021 // If the entry is invalid, drop it.
1022 if (current_time > j->second.expiry) {
1023 enabled_sts_hosts_.erase(j);
1024 DirtyNotify();
1025 continue;
1028 // If this is the most specific STS match, add it to the result. Note: a STS
1029 // entry at a more specific domain overrides a less specific domain whether
1030 // or not |include_subdomains| is set.
1031 if (current_time <= j->second.expiry) {
1032 if (i == 0 || j->second.include_subdomains) {
1033 *result = j->second;
1034 result->domain = DNSDomainToString(host_sub_chunk);
1035 return true;
1038 break;
1042 return false;
1045 bool TransportSecurityState::GetDynamicPKPState(const std::string& host,
1046 PKPState* result) {
1047 DCHECK(CalledOnValidThread());
1049 const std::string canonicalized_host = CanonicalizeHost(host);
1050 if (canonicalized_host.empty())
1051 return false;
1053 base::Time current_time(base::Time::Now());
1055 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) {
1056 std::string host_sub_chunk(&canonicalized_host[i],
1057 canonicalized_host.size() - i);
1058 PKPStateMap::iterator j = enabled_pkp_hosts_.find(HashHost(host_sub_chunk));
1059 if (j == enabled_pkp_hosts_.end())
1060 continue;
1062 // If the entry is invalid, drop it.
1063 if (current_time > j->second.expiry) {
1064 enabled_pkp_hosts_.erase(j);
1065 DirtyNotify();
1066 continue;
1069 // If this is the most specific PKP match, add it to the result. Note: a PKP
1070 // entry at a more specific domain overrides a less specific domain whether
1071 // or not |include_subdomains| is set.
1072 if (current_time <= j->second.expiry) {
1073 if (i == 0 || j->second.include_subdomains) {
1074 *result = j->second;
1075 result->domain = DNSDomainToString(host_sub_chunk);
1076 return true;
1079 break;
1083 return false;
1086 void TransportSecurityState::AddOrUpdateEnabledSTSHosts(
1087 const std::string& hashed_host,
1088 const STSState& state) {
1089 DCHECK(CalledOnValidThread());
1090 DCHECK(state.ShouldUpgradeToSSL());
1091 enabled_sts_hosts_[hashed_host] = state;
1094 void TransportSecurityState::AddOrUpdateEnabledPKPHosts(
1095 const std::string& hashed_host,
1096 const PKPState& state) {
1097 DCHECK(CalledOnValidThread());
1098 DCHECK(state.HasPublicKeyPins());
1099 enabled_pkp_hosts_[hashed_host] = state;
1102 TransportSecurityState::STSState::STSState()
1103 : upgrade_mode(MODE_DEFAULT), include_subdomains(false) {
1106 TransportSecurityState::STSState::~STSState() {
1109 bool TransportSecurityState::STSState::ShouldUpgradeToSSL() const {
1110 return upgrade_mode == MODE_FORCE_HTTPS;
1113 bool TransportSecurityState::STSState::ShouldSSLErrorsBeFatal() const {
1114 return true;
1117 TransportSecurityState::STSStateIterator::STSStateIterator(
1118 const TransportSecurityState& state)
1119 : iterator_(state.enabled_sts_hosts_.begin()),
1120 end_(state.enabled_sts_hosts_.end()) {
1123 TransportSecurityState::STSStateIterator::~STSStateIterator() {
1126 TransportSecurityState::PKPState::PKPState() : include_subdomains(false) {
1129 TransportSecurityState::PKPState::~PKPState() {
1132 bool TransportSecurityState::PKPState::CheckPublicKeyPins(
1133 const HashValueVector& hashes,
1134 std::string* failure_log) const {
1135 // Validate that hashes is not empty. By the time this code is called (in
1136 // production), that should never happen, but it's good to be defensive.
1137 // And, hashes *can* be empty in some test scenarios.
1138 if (hashes.empty()) {
1139 failure_log->append(
1140 "Rejecting empty public key chain for public-key-pinned domains: " +
1141 domain);
1142 return false;
1145 if (HashesIntersect(bad_spki_hashes, hashes)) {
1146 failure_log->append("Rejecting public key chain for domain " + domain +
1147 ". Validated chain: " + HashesToBase64String(hashes) +
1148 ", matches one or more bad hashes: " +
1149 HashesToBase64String(bad_spki_hashes));
1150 return false;
1153 // If there are no pins, then any valid chain is acceptable.
1154 if (spki_hashes.empty())
1155 return true;
1157 if (HashesIntersect(spki_hashes, hashes)) {
1158 return true;
1161 failure_log->append("Rejecting public key chain for domain " + domain +
1162 ". Validated chain: " + HashesToBase64String(hashes) +
1163 ", expected: " + HashesToBase64String(spki_hashes));
1164 return false;
1167 bool TransportSecurityState::PKPState::HasPublicKeyPins() const {
1168 return spki_hashes.size() > 0 || bad_spki_hashes.size() > 0;
1171 bool TransportSecurityState::PKPState::ShouldSSLErrorsBeFatal() const {
1172 return true;
1175 TransportSecurityState::PKPStateIterator::PKPStateIterator(
1176 const TransportSecurityState& state)
1177 : iterator_(state.enabled_pkp_hosts_.begin()),
1178 end_(state.enabled_pkp_hosts_.end()) {
1181 TransportSecurityState::PKPStateIterator::~PKPStateIterator() {
1184 } // namespace