Update minimum NDK used for building Chrome.
[chromium-blink-merge.git] / net / http / transport_security_state.cc
blobd92bd473c4bc315f79e8bc137a9dfa645af46061
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/logging.h"
23 #include "base/memory/scoped_ptr.h"
24 #include "base/metrics/histogram.h"
25 #include "base/metrics/sparse_histogram.h"
26 #include "base/sha1.h"
27 #include "base/strings/string_number_conversions.h"
28 #include "base/strings/string_util.h"
29 #include "base/strings/utf_string_conversions.h"
30 #include "base/time/time.h"
31 #include "base/values.h"
32 #include "crypto/sha2.h"
33 #include "net/base/dns_util.h"
34 #include "net/cert/x509_cert_types.h"
35 #include "net/cert/x509_certificate.h"
36 #include "net/http/http_security_headers.h"
37 #include "net/ssl/ssl_info.h"
38 #include "url/gurl.h"
40 #if defined(USE_OPENSSL)
41 #include "crypto/openssl_util.h"
42 #endif
44 namespace net {
46 namespace {
48 #include "net/http/transport_security_state_static.h"
50 std::string HashesToBase64String(const HashValueVector& hashes) {
51 std::string str;
52 for (size_t i = 0; i != hashes.size(); ++i) {
53 if (i != 0)
54 str += ",";
55 str += hashes[i].ToString();
57 return str;
60 std::string HashHost(const std::string& canonicalized_host) {
61 char hashed[crypto::kSHA256Length];
62 crypto::SHA256HashString(canonicalized_host, hashed, sizeof(hashed));
63 return std::string(hashed, sizeof(hashed));
66 // Returns true if the intersection of |a| and |b| is not empty. If either
67 // |a| or |b| is empty, returns false.
68 bool HashesIntersect(const HashValueVector& a,
69 const HashValueVector& b) {
70 for (HashValueVector::const_iterator i = a.begin(); i != a.end(); ++i) {
71 HashValueVector::const_iterator j =
72 std::find_if(b.begin(), b.end(), HashValuesEqual(*i));
73 if (j != b.end())
74 return true;
76 return false;
79 bool AddHash(const char* sha1_hash,
80 HashValueVector* out) {
81 HashValue hash(HASH_VALUE_SHA1);
82 memcpy(hash.data(), sha1_hash, hash.size());
83 out->push_back(hash);
84 return true;
87 // Converts |hostname| from dotted form ("www.google.com") to the form
88 // used in DNS: "\x03www\x06google\x03com", lowercases that, and returns
89 // the result.
90 std::string CanonicalizeHost(const std::string& host) {
91 // We cannot perform the operations as detailed in the spec here as |host|
92 // has already undergone IDN processing before it reached us. Thus, we check
93 // that there are no invalid characters in the host and lowercase the result.
94 std::string new_host;
95 if (!DNSDomainFromDot(host, &new_host)) {
96 // DNSDomainFromDot can fail if any label is > 63 bytes or if the whole
97 // name is >255 bytes. However, search terms can have those properties.
98 return std::string();
101 for (size_t i = 0; new_host[i]; i += new_host[i] + 1) {
102 const unsigned label_length = static_cast<unsigned>(new_host[i]);
103 if (!label_length)
104 break;
106 for (size_t j = 0; j < label_length; ++j) {
107 new_host[i + 1 + j] = static_cast<char>(tolower(new_host[i + 1 + j]));
111 return new_host;
114 // BitReader is a class that allows a bytestring to be read bit-by-bit.
115 class BitReader {
116 public:
117 BitReader(const uint8* bytes, size_t num_bits)
118 : bytes_(bytes),
119 num_bits_(num_bits),
120 num_bytes_((num_bits + 7) / 8),
121 current_byte_index_(0),
122 num_bits_used_(8) {}
124 // Next sets |*out| to the next bit from the input. It returns false if no
125 // more bits are available or true otherwise.
126 bool Next(bool* out) {
127 if (num_bits_used_ == 8) {
128 if (current_byte_index_ >= num_bytes_) {
129 return false;
131 current_byte_ = bytes_[current_byte_index_++];
132 num_bits_used_ = 0;
135 *out = 1 & (current_byte_ >> (7 - num_bits_used_));
136 num_bits_used_++;
137 return true;
140 // Read sets the |num_bits| least-significant bits of |*out| to the value of
141 // the next |num_bits| bits from the input. It returns false if there are
142 // insufficient bits in the input or true otherwise.
143 bool Read(unsigned num_bits, uint32* out) {
144 DCHECK_LE(num_bits, 32u);
146 uint32 ret = 0;
147 for (unsigned i = 0; i < num_bits; ++i) {
148 bool bit;
149 if (!Next(&bit)) {
150 return false;
152 ret |= static_cast<uint32>(bit) << (num_bits - 1 - i);
155 *out = ret;
156 return true;
159 // Unary sets |*out| to the result of decoding a unary value from the input.
160 // It returns false if there were insufficient bits in the input and true
161 // otherwise.
162 bool Unary(size_t* out) {
163 size_t ret = 0;
165 for (;;) {
166 bool bit;
167 if (!Next(&bit)) {
168 return false;
170 if (!bit) {
171 break;
173 ret++;
176 *out = ret;
177 return true;
180 // Seek sets the current offest in the input to bit number |offset|. It
181 // returns true if |offset| is within the range of the input and false
182 // otherwise.
183 bool Seek(size_t offset) {
184 if (offset >= num_bits_) {
185 return false;
187 current_byte_index_ = offset / 8;
188 current_byte_ = bytes_[current_byte_index_++];
189 num_bits_used_ = offset % 8;
190 return true;
193 private:
194 const uint8* const bytes_;
195 const size_t num_bits_;
196 const size_t num_bytes_;
197 // current_byte_index_ contains the current byte offset in |bytes_|.
198 size_t current_byte_index_;
199 // current_byte_ contains the current byte of the input.
200 uint8 current_byte_;
201 // num_bits_used_ contains the number of bits of |current_byte_| that have
202 // been read.
203 unsigned num_bits_used_;
206 // HuffmanDecoder is a very simple Huffman reader. The input Huffman tree is
207 // simply encoded as a series of two-byte structures. The first byte determines
208 // the "0" pointer for that node and the second the "1" pointer. Each byte
209 // either has the MSB set, in which case the bottom 7 bits are the value for
210 // that position, or else the bottom seven bits contain the index of a node.
212 // The tree is decoded by walking rather than a table-driven approach.
213 class HuffmanDecoder {
214 public:
215 HuffmanDecoder(const uint8* tree, size_t tree_bytes)
216 : tree_(tree),
217 tree_bytes_(tree_bytes) {}
219 bool Decode(BitReader* reader, char* out) {
220 const uint8* current = &tree_[tree_bytes_-2];
222 for (;;) {
223 bool bit;
224 if (!reader->Next(&bit)) {
225 return false;
228 uint8 b = current[bit];
229 if (b & 0x80) {
230 *out = static_cast<char>(b & 0x7f);
231 return true;
234 unsigned offset = static_cast<unsigned>(b) * 2;
235 DCHECK_LT(offset, tree_bytes_);
236 if (offset >= tree_bytes_) {
237 return false;
240 current = &tree_[offset];
244 private:
245 const uint8* const tree_;
246 const size_t tree_bytes_;
249 // PreloadResult is the result of resolving a specific name in the preloaded
250 // data.
251 struct PreloadResult {
252 uint32 pinset_id;
253 uint32 domain_id;
254 // hostname_offset contains the number of bytes from the start of the given
255 // hostname where the name of the matching entry starts.
256 size_t hostname_offset;
257 bool sts_include_subdomains;
258 bool pkp_include_subdomains;
259 bool force_https;
260 bool has_pins;
263 // DecodeHSTSPreloadRaw resolves |hostname| in the preloaded data. It returns
264 // false on internal error and true otherwise. After a successful return,
265 // |*out_found| is true iff a relevant entry has been found. If so, |*out|
266 // contains the details.
268 // Don't call this function, call DecodeHSTSPreload, below.
270 // Although this code should be robust, it never processes attacker-controlled
271 // data -- it only operates on the preloaded data built into the binary.
273 // The preloaded data is represented as a trie and matches the hostname
274 // backwards. Each node in the trie starts with a number of characters, which
275 // must match exactly. After that is a dispatch table which maps the next
276 // character in the hostname to another node in the trie.
278 // In the dispatch table, the zero character represents the "end of string"
279 // (which is the *beginning* of a hostname since we process it backwards). The
280 // value in that case is special -- rather than an offset to another trie node,
281 // it contains the HSTS information: whether subdomains are included, pinsets
282 // etc. If an "end of string" matches a period in the hostname then the
283 // information is remembered because, if no more specific node is found, then
284 // that information applies to the hostname.
286 // Dispatch tables are always given in order, but the "end of string" (zero)
287 // value always comes before an entry for '.'.
288 bool DecodeHSTSPreloadRaw(const std::string& search_hostname,
289 bool* out_found,
290 PreloadResult* out) {
291 HuffmanDecoder huffman(kHSTSHuffmanTree, sizeof(kHSTSHuffmanTree));
292 BitReader reader(kPreloadedHSTSData, kPreloadedHSTSBits);
293 size_t bit_offset = kHSTSRootPosition;
294 static const char kEndOfString = 0;
295 static const char kEndOfTable = 127;
297 *out_found = false;
299 // Ensure that |search_hostname| is a valid hostname before
300 // processing.
301 if (CanonicalizeHost(search_hostname).empty()) {
302 return true;
305 // Normalize any trailing '.' used for DNS suffix searches.
306 std::string hostname = search_hostname;
307 size_t found = hostname.find_last_not_of('.');
308 if (found != std::string::npos) {
309 hostname.erase(found + 1);
310 } else {
311 hostname.clear();
314 // |hostname| has already undergone IDN conversion, so should be
315 // entirely A-Labels. The preload data is entirely normalized to
316 // lower case.
317 base::StringToLowerASCII(&hostname);
319 if (hostname.empty()) {
320 return true;
323 // hostname_offset contains one more than the index of the current character
324 // in the hostname that is being considered. It's one greater so that we can
325 // represent the position just before the beginning (with zero).
326 size_t hostname_offset = hostname.size();
328 for (;;) {
329 // Seek to the desired location.
330 if (!reader.Seek(bit_offset)) {
331 return false;
334 // Decode the unary length of the common prefix.
335 size_t prefix_length;
336 if (!reader.Unary(&prefix_length)) {
337 return false;
340 // Match each character in the prefix.
341 for (size_t i = 0; i < prefix_length; ++i) {
342 if (hostname_offset == 0) {
343 // We can't match the terminator with a prefix string.
344 return true;
347 char c;
348 if (!huffman.Decode(&reader, &c)) {
349 return false;
351 if (hostname[hostname_offset - 1] != c) {
352 return true;
354 hostname_offset--;
357 bool is_first_offset = true;
358 size_t current_offset = 0;
360 // Next is the dispatch table.
361 for (;;) {
362 char c;
363 if (!huffman.Decode(&reader, &c)) {
364 return false;
366 if (c == kEndOfTable) {
367 // No exact match.
368 return true;
371 if (c == kEndOfString) {
372 PreloadResult tmp;
373 if (!reader.Next(&tmp.sts_include_subdomains) ||
374 !reader.Next(&tmp.force_https) ||
375 !reader.Next(&tmp.has_pins)) {
376 return false;
379 tmp.pkp_include_subdomains = tmp.sts_include_subdomains;
381 if (tmp.has_pins) {
382 if (!reader.Read(4, &tmp.pinset_id) ||
383 !reader.Read(9, &tmp.domain_id) ||
384 (!tmp.sts_include_subdomains &&
385 !reader.Next(&tmp.pkp_include_subdomains))) {
386 return false;
390 tmp.hostname_offset = hostname_offset;
392 if (hostname_offset == 0 || hostname[hostname_offset - 1] == '.') {
393 *out_found =
394 tmp.sts_include_subdomains || tmp.pkp_include_subdomains;
395 *out = tmp;
397 if (hostname_offset > 0) {
398 out->force_https &= tmp.sts_include_subdomains;
399 } else {
400 *out_found = true;
401 return true;
405 continue;
408 // The entries in a dispatch table are in order thus we can tell if there
409 // will be no match if the current character past the one that we want.
410 if (hostname_offset == 0 || hostname[hostname_offset-1] < c) {
411 return true;
414 if (is_first_offset) {
415 // The first offset is backwards from the current position.
416 uint32 jump_delta_bits;
417 uint32 jump_delta;
418 if (!reader.Read(5, &jump_delta_bits) ||
419 !reader.Read(jump_delta_bits, &jump_delta)) {
420 return false;
423 if (bit_offset < jump_delta) {
424 return false;
427 current_offset = bit_offset - jump_delta;
428 is_first_offset = false;
429 } else {
430 // Subsequent offsets are forward from the target of the first offset.
431 uint32 is_long_jump;
432 if (!reader.Read(1, &is_long_jump)) {
433 return false;
436 uint32 jump_delta;
437 if (!is_long_jump) {
438 if (!reader.Read(7, &jump_delta)) {
439 return false;
441 } else {
442 uint32 jump_delta_bits;
443 if (!reader.Read(4, &jump_delta_bits) ||
444 !reader.Read(jump_delta_bits + 8, &jump_delta)) {
445 return false;
449 current_offset += jump_delta;
450 if (current_offset >= bit_offset) {
451 return false;
455 DCHECK_LT(0u, hostname_offset);
456 if (hostname[hostname_offset - 1] == c) {
457 bit_offset = current_offset;
458 hostname_offset--;
459 break;
465 bool DecodeHSTSPreload(const std::string& hostname,
466 PreloadResult* out) {
467 bool found;
468 if (!DecodeHSTSPreloadRaw(hostname, &found, out)) {
469 DCHECK(false) << "Internal error in DecodeHSTSPreloadRaw for hostname "
470 << hostname;
471 return false;
474 return found;
477 } // namespace
479 TransportSecurityState::TransportSecurityState()
480 : delegate_(NULL), enable_static_pins_(true) {
481 // Static pinning is only enabled for official builds to make sure that
482 // others don't end up with pins that cannot be easily updated.
483 #if !defined(OFFICIAL_BUILD) || defined(OS_ANDROID) || defined(OS_IOS)
484 enable_static_pins_ = false;
485 #endif
486 DCHECK(CalledOnValidThread());
489 TransportSecurityState::Iterator::Iterator(const TransportSecurityState& state)
490 : iterator_(state.enabled_hosts_.begin()),
491 end_(state.enabled_hosts_.end()) {
494 TransportSecurityState::Iterator::~Iterator() {
497 bool TransportSecurityState::ShouldSSLErrorsBeFatal(const std::string& host) {
498 DomainState state;
499 if (GetStaticDomainState(host, &state))
500 return true;
501 return GetDynamicDomainState(host, &state);
504 bool TransportSecurityState::ShouldUpgradeToSSL(const std::string& host) {
505 DomainState dynamic_state;
506 if (GetDynamicDomainState(host, &dynamic_state))
507 return dynamic_state.ShouldUpgradeToSSL();
509 DomainState static_state;
510 if (GetStaticDomainState(host, &static_state) &&
511 static_state.ShouldUpgradeToSSL()) {
512 return true;
515 return false;
518 bool TransportSecurityState::CheckPublicKeyPins(
519 const std::string& host,
520 bool is_issued_by_known_root,
521 const HashValueVector& public_key_hashes,
522 std::string* pinning_failure_log) {
523 // Perform pin validation if, and only if, all these conditions obtain:
525 // * the server's certificate chain chains up to a known root (i.e. not a
526 // user-installed trust anchor); and
527 // * the server actually has public key pins.
528 if (!is_issued_by_known_root || !HasPublicKeyPins(host)) {
529 return true;
532 bool pins_are_valid =
533 CheckPublicKeyPinsImpl(host, public_key_hashes, pinning_failure_log);
534 if (!pins_are_valid) {
535 LOG(ERROR) << *pinning_failure_log;
536 ReportUMAOnPinFailure(host);
539 UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", pins_are_valid);
540 return pins_are_valid;
543 bool TransportSecurityState::HasPublicKeyPins(const std::string& host) {
544 DomainState dynamic_state;
545 if (GetDynamicDomainState(host, &dynamic_state))
546 return dynamic_state.HasPublicKeyPins();
548 DomainState static_state;
549 if (GetStaticDomainState(host, &static_state)) {
550 if (static_state.HasPublicKeyPins())
551 return true;
554 return false;
557 void TransportSecurityState::SetDelegate(
558 TransportSecurityState::Delegate* delegate) {
559 DCHECK(CalledOnValidThread());
560 delegate_ = delegate;
563 void TransportSecurityState::AddHSTSInternal(
564 const std::string& host,
565 TransportSecurityState::DomainState::UpgradeMode upgrade_mode,
566 const base::Time& expiry,
567 bool include_subdomains) {
568 DCHECK(CalledOnValidThread());
570 // Copy-and-modify the existing DomainState for this host (if any).
571 DomainState domain_state;
572 const std::string canonicalized_host = CanonicalizeHost(host);
573 const std::string hashed_host = HashHost(canonicalized_host);
574 DomainStateMap::const_iterator i = enabled_hosts_.find(hashed_host);
575 if (i != enabled_hosts_.end())
576 domain_state = i->second;
578 domain_state.sts.last_observed = base::Time::Now();
579 domain_state.sts.include_subdomains = include_subdomains;
580 domain_state.sts.expiry = expiry;
581 domain_state.sts.upgrade_mode = upgrade_mode;
582 EnableHost(host, domain_state);
585 void TransportSecurityState::AddHPKPInternal(const std::string& host,
586 const base::Time& last_observed,
587 const base::Time& expiry,
588 bool include_subdomains,
589 const HashValueVector& hashes) {
590 DCHECK(CalledOnValidThread());
592 // Copy-and-modify the existing DomainState for this host (if any).
593 DomainState domain_state;
594 const std::string canonicalized_host = CanonicalizeHost(host);
595 const std::string hashed_host = HashHost(canonicalized_host);
596 DomainStateMap::const_iterator i = enabled_hosts_.find(hashed_host);
597 if (i != enabled_hosts_.end())
598 domain_state = i->second;
600 domain_state.pkp.last_observed = last_observed;
601 domain_state.pkp.expiry = expiry;
602 domain_state.pkp.include_subdomains = include_subdomains;
603 domain_state.pkp.spki_hashes = hashes;
604 EnableHost(host, domain_state);
607 void TransportSecurityState::EnableHost(const std::string& host,
608 const DomainState& state) {
609 DCHECK(CalledOnValidThread());
611 const std::string canonicalized_host = CanonicalizeHost(host);
612 if (canonicalized_host.empty())
613 return;
615 DomainState state_copy(state);
616 // No need to store this value since it is redundant. (|canonicalized_host|
617 // is the map key.)
618 state_copy.sts.domain.clear();
619 state_copy.pkp.domain.clear();
621 enabled_hosts_[HashHost(canonicalized_host)] = state_copy;
622 DirtyNotify();
625 bool TransportSecurityState::DeleteDynamicDataForHost(const std::string& host) {
626 DCHECK(CalledOnValidThread());
628 const std::string canonicalized_host = CanonicalizeHost(host);
629 if (canonicalized_host.empty())
630 return false;
632 DomainStateMap::iterator i =
633 enabled_hosts_.find(HashHost(canonicalized_host));
634 if (i != enabled_hosts_.end()) {
635 enabled_hosts_.erase(i);
636 DirtyNotify();
637 return true;
639 return false;
642 void TransportSecurityState::ClearDynamicData() {
643 DCHECK(CalledOnValidThread());
644 enabled_hosts_.clear();
647 void TransportSecurityState::DeleteAllDynamicDataSince(const base::Time& time) {
648 DCHECK(CalledOnValidThread());
650 bool dirtied = false;
651 DomainStateMap::iterator i = enabled_hosts_.begin();
652 while (i != enabled_hosts_.end()) {
653 // Clear STS and PKP state independently.
654 if (i->second.sts.last_observed >= time) {
655 dirtied = true;
656 i->second.sts.upgrade_mode = DomainState::MODE_DEFAULT;
658 if (i->second.pkp.last_observed >= time) {
659 dirtied = true;
660 i->second.pkp.spki_hashes.clear();
661 i->second.pkp.expiry = base::Time();
664 // If both are now invalid, drop the entry altogether.
665 if (!i->second.ShouldUpgradeToSSL() && !i->second.HasPublicKeyPins()) {
666 dirtied = true;
667 enabled_hosts_.erase(i++);
668 continue;
671 ++i;
674 if (dirtied)
675 DirtyNotify();
678 TransportSecurityState::~TransportSecurityState() {
679 DCHECK(CalledOnValidThread());
682 void TransportSecurityState::DirtyNotify() {
683 DCHECK(CalledOnValidThread());
685 if (delegate_)
686 delegate_->StateIsDirty(this);
689 bool TransportSecurityState::AddHSTSHeader(const std::string& host,
690 const std::string& value) {
691 DCHECK(CalledOnValidThread());
693 base::Time now = base::Time::Now();
694 base::TimeDelta max_age;
695 bool include_subdomains;
696 if (!ParseHSTSHeader(value, &max_age, &include_subdomains)) {
697 return false;
700 // Handle max-age == 0.
701 DomainState::UpgradeMode upgrade_mode;
702 if (max_age.InSeconds() == 0) {
703 upgrade_mode = DomainState::MODE_DEFAULT;
704 } else {
705 upgrade_mode = DomainState::MODE_FORCE_HTTPS;
708 AddHSTSInternal(host, upgrade_mode, now + max_age, include_subdomains);
709 return true;
712 bool TransportSecurityState::AddHPKPHeader(const std::string& host,
713 const std::string& value,
714 const SSLInfo& ssl_info) {
715 DCHECK(CalledOnValidThread());
717 base::Time now = base::Time::Now();
718 base::TimeDelta max_age;
719 bool include_subdomains;
720 HashValueVector spki_hashes;
721 if (!ParseHPKPHeader(value, ssl_info.public_key_hashes, &max_age,
722 &include_subdomains, &spki_hashes)) {
723 return false;
725 // Handle max-age == 0.
726 if (max_age.InSeconds() == 0)
727 spki_hashes.clear();
728 AddHPKPInternal(host, now, now + max_age, include_subdomains, spki_hashes);
729 return true;
732 void TransportSecurityState::AddHSTS(const std::string& host,
733 const base::Time& expiry,
734 bool include_subdomains) {
735 DCHECK(CalledOnValidThread());
736 AddHSTSInternal(host, DomainState::MODE_FORCE_HTTPS, expiry,
737 include_subdomains);
740 void TransportSecurityState::AddHPKP(const std::string& host,
741 const base::Time& expiry,
742 bool include_subdomains,
743 const HashValueVector& hashes) {
744 DCHECK(CalledOnValidThread());
745 AddHPKPInternal(host, base::Time::Now(), expiry, include_subdomains, hashes);
748 // static
749 bool TransportSecurityState::IsGooglePinnedProperty(const std::string& host) {
750 PreloadResult result;
751 return DecodeHSTSPreload(host, &result) && result.has_pins &&
752 kPinsets[result.pinset_id].accepted_pins == kGoogleAcceptableCerts;
755 // static
756 void TransportSecurityState::ReportUMAOnPinFailure(const std::string& host) {
757 PreloadResult result;
758 if (!DecodeHSTSPreload(host, &result) ||
759 !result.has_pins) {
760 return;
763 DCHECK(result.domain_id != DOMAIN_NOT_PINNED);
765 UMA_HISTOGRAM_SPARSE_SLOWLY(
766 "Net.PublicKeyPinFailureDomain", result.domain_id);
769 // static
770 bool TransportSecurityState::IsBuildTimely() {
771 // If the build metadata aren't embedded in the binary then we can't use the
772 // build time to determine if the build is timely, return true by default. If
773 // we're building an official build then keep using the build time, even if
774 // it's invalid it'd be a date in the past and this function will return
775 // false.
776 #if defined(DONT_EMBED_BUILD_METADATA) && !defined(OFFICIAL_BUILD)
777 return true;
778 #else
779 const base::Time build_time = base::GetBuildTime();
780 // We consider built-in information to be timely for 10 weeks.
781 return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */;
782 #endif
785 bool TransportSecurityState::CheckPublicKeyPinsImpl(
786 const std::string& host,
787 const HashValueVector& hashes,
788 std::string* failure_log) {
789 DomainState dynamic_state;
790 if (GetDynamicDomainState(host, &dynamic_state))
791 return dynamic_state.CheckPublicKeyPins(hashes, failure_log);
793 DomainState static_state;
794 if (GetStaticDomainState(host, &static_state))
795 return static_state.CheckPublicKeyPins(hashes, failure_log);
797 // HasPublicKeyPins should have returned true in order for this method
798 // to have been called, so if we fall through to here, it's an error.
799 return false;
802 bool TransportSecurityState::GetStaticDomainState(const std::string& host,
803 DomainState* out) const {
804 DCHECK(CalledOnValidThread());
806 out->sts.upgrade_mode = DomainState::MODE_FORCE_HTTPS;
807 out->sts.include_subdomains = false;
808 out->pkp.include_subdomains = false;
810 if (!IsBuildTimely())
811 return false;
813 PreloadResult result;
814 if (!DecodeHSTSPreload(host, &result))
815 return false;
817 out->sts.domain = host.substr(result.hostname_offset);
818 out->pkp.domain = out->sts.domain;
819 out->sts.include_subdomains = result.sts_include_subdomains;
820 out->sts.last_observed = base::GetBuildTime();
821 out->sts.upgrade_mode =
822 TransportSecurityState::DomainState::MODE_DEFAULT;
823 if (result.force_https) {
824 out->sts.upgrade_mode =
825 TransportSecurityState::DomainState::MODE_FORCE_HTTPS;
828 if (enable_static_pins_ && result.has_pins) {
829 out->pkp.include_subdomains = result.pkp_include_subdomains;
830 out->pkp.last_observed = base::GetBuildTime();
832 if (result.pinset_id >= arraysize(kPinsets))
833 return false;
834 const Pinset *pinset = &kPinsets[result.pinset_id];
836 if (pinset->accepted_pins) {
837 const char* const* sha1_hash = pinset->accepted_pins;
838 while (*sha1_hash) {
839 AddHash(*sha1_hash, &out->pkp.spki_hashes);
840 sha1_hash++;
843 if (pinset->rejected_pins) {
844 const char* const* sha1_hash = pinset->rejected_pins;
845 while (*sha1_hash) {
846 AddHash(*sha1_hash, &out->pkp.bad_spki_hashes);
847 sha1_hash++;
852 return true;
855 bool TransportSecurityState::GetDynamicDomainState(const std::string& host,
856 DomainState* result) {
857 DCHECK(CalledOnValidThread());
859 DomainState state;
860 const std::string canonicalized_host = CanonicalizeHost(host);
861 if (canonicalized_host.empty())
862 return false;
864 base::Time current_time(base::Time::Now());
866 // Although STS and PKP states are completely independent, they are currently
867 // stored and processed together. This loop performs both independent queries
868 // together and combines the two results into a single output. See
869 // https://crbug.com/470295
870 bool found_sts = false;
871 bool found_pkp = false;
872 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) {
873 std::string host_sub_chunk(&canonicalized_host[i],
874 canonicalized_host.size() - i);
875 DomainStateMap::iterator j =
876 enabled_hosts_.find(HashHost(host_sub_chunk));
877 if (j == enabled_hosts_.end())
878 continue;
880 // If both halves of the entry are invalid, drop it.
881 if (current_time > j->second.sts.expiry &&
882 current_time > j->second.pkp.expiry) {
883 enabled_hosts_.erase(j);
884 DirtyNotify();
885 continue;
888 // If this is the most specific STS match, add it to the result. Note: a STS
889 // entry at a more specific domain overrides a less specific domain whether
890 // or not |include_subdomains| is set.
891 if (!found_sts && current_time <= j->second.sts.expiry &&
892 j->second.ShouldUpgradeToSSL()) {
893 found_sts = true;
894 if (i == 0 || j->second.sts.include_subdomains) {
895 state.sts = j->second.sts;
896 state.sts.domain = DNSDomainToString(host_sub_chunk);
900 // If this is the most specific PKP match, add it to the result. Note: a PKP
901 // entry at a more specific domain overrides a less specific domain whether
902 // or not |include_subdomains| is set.
903 if (!found_pkp && current_time <= j->second.pkp.expiry &&
904 j->second.HasPublicKeyPins()) {
905 found_pkp = true;
906 if (i == 0 || j->second.pkp.include_subdomains) {
907 state.pkp = j->second.pkp;
908 state.pkp.domain = DNSDomainToString(host_sub_chunk);
912 // Both queries have terminated. Abort the loop early.
913 if (found_sts && found_pkp)
914 break;
917 // If neither STS nor PKP state was found, do not return any DomainState. This
918 // determines whether ShouldSSLErrorsBeFatal returns true or false.
919 if (!state.ShouldUpgradeToSSL() && !state.HasPublicKeyPins())
920 return false;
922 *result = state;
923 return true;
926 void TransportSecurityState::AddOrUpdateEnabledHosts(
927 const std::string& hashed_host, const DomainState& state) {
928 DCHECK(CalledOnValidThread());
929 enabled_hosts_[hashed_host] = state;
932 TransportSecurityState::DomainState::DomainState() {
933 sts.upgrade_mode = MODE_DEFAULT;
934 sts.include_subdomains = false;
935 pkp.include_subdomains = false;
938 TransportSecurityState::DomainState::~DomainState() {
941 bool TransportSecurityState::DomainState::CheckPublicKeyPins(
942 const HashValueVector& hashes, std::string* failure_log) const {
943 // Validate that hashes is not empty. By the time this code is called (in
944 // production), that should never happen, but it's good to be defensive.
945 // And, hashes *can* be empty in some test scenarios.
946 if (hashes.empty()) {
947 failure_log->append(
948 "Rejecting empty public key chain for public-key-pinned domains: " +
949 pkp.domain);
950 return false;
953 if (HashesIntersect(pkp.bad_spki_hashes, hashes)) {
954 failure_log->append("Rejecting public key chain for domain " + pkp.domain +
955 ". Validated chain: " + HashesToBase64String(hashes) +
956 ", matches one or more bad hashes: " +
957 HashesToBase64String(pkp.bad_spki_hashes));
958 return false;
961 // If there are no pins, then any valid chain is acceptable.
962 if (pkp.spki_hashes.empty())
963 return true;
965 if (HashesIntersect(pkp.spki_hashes, hashes)) {
966 return true;
969 failure_log->append("Rejecting public key chain for domain " + pkp.domain +
970 ". Validated chain: " + HashesToBase64String(hashes) +
971 ", expected: " + HashesToBase64String(pkp.spki_hashes));
972 return false;
975 bool TransportSecurityState::DomainState::ShouldUpgradeToSSL() const {
976 return sts.upgrade_mode == MODE_FORCE_HTTPS;
979 bool TransportSecurityState::DomainState::ShouldSSLErrorsBeFatal() const {
980 // Both HSTS and HPKP cause fatal SSL errors, so enable this on the presense
981 // of either. (If neither is active, no DomainState will be returned from
982 // GetDynamicDomainState.)
983 return true;
986 bool TransportSecurityState::DomainState::HasPublicKeyPins() const {
987 return pkp.spki_hashes.size() > 0 || pkp.bad_spki_hashes.size() > 0;
990 TransportSecurityState::DomainState::STSState::STSState() {
993 TransportSecurityState::DomainState::STSState::~STSState() {
996 TransportSecurityState::DomainState::PKPState::PKPState() {
999 TransportSecurityState::DomainState::PKPState::~PKPState() {
1002 } // namespace