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)
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"
40 #if defined(USE_OPENSSL)
41 #include "crypto/openssl_util.h"
48 std::string
HashesToBase64String(const HashValueVector
& hashes
) {
50 for (size_t i
= 0; i
!= hashes
.size(); ++i
) {
53 str
+= hashes
[i
].ToString();
58 std::string
HashHost(const std::string
& canonicalized_host
) {
59 char hashed
[crypto::kSHA256Length
];
60 crypto::SHA256HashString(canonicalized_host
, hashed
, sizeof(hashed
));
61 return std::string(hashed
, sizeof(hashed
));
64 // Returns true if the intersection of |a| and |b| is not empty. If either
65 // |a| or |b| is empty, returns false.
66 bool HashesIntersect(const HashValueVector
& a
,
67 const HashValueVector
& b
) {
68 for (HashValueVector::const_iterator i
= a
.begin(); i
!= a
.end(); ++i
) {
69 HashValueVector::const_iterator j
=
70 std::find_if(b
.begin(), b
.end(), HashValuesEqual(*i
));
77 bool AddHash(const char* sha1_hash
,
78 HashValueVector
* out
) {
79 HashValue
hash(HASH_VALUE_SHA1
);
80 memcpy(hash
.data(), sha1_hash
, hash
.size());
87 TransportSecurityState::TransportSecurityState()
88 : delegate_(NULL
), enable_static_pins_(true) {
89 // Static pinning is only enabled for official builds to make sure that
90 // others don't end up with pins that cannot be easily updated.
91 #if !defined(OFFICIAL_BUILD) || defined(OS_ANDROID) || defined(OS_IOS)
92 enable_static_pins_
= false;
94 DCHECK(CalledOnValidThread());
97 TransportSecurityState::Iterator::Iterator(const TransportSecurityState
& state
)
98 : iterator_(state
.enabled_hosts_
.begin()),
99 end_(state
.enabled_hosts_
.end()) {
102 TransportSecurityState::Iterator::~Iterator() {}
104 bool TransportSecurityState::ShouldSSLErrorsBeFatal(const std::string
& host
) {
106 if (GetStaticDomainState(host
, &state
))
108 return GetDynamicDomainState(host
, &state
);
111 bool TransportSecurityState::ShouldUpgradeToSSL(const std::string
& host
) {
112 DomainState dynamic_state
;
113 if (GetDynamicDomainState(host
, &dynamic_state
))
114 return dynamic_state
.ShouldUpgradeToSSL();
116 DomainState static_state
;
117 if (GetStaticDomainState(host
, &static_state
) &&
118 static_state
.ShouldUpgradeToSSL()) {
125 bool TransportSecurityState::CheckPublicKeyPins(
126 const std::string
& host
,
127 bool is_issued_by_known_root
,
128 const HashValueVector
& public_key_hashes
,
129 std::string
* pinning_failure_log
) {
130 // Perform pin validation if, and only if, all these conditions obtain:
132 // * the server's certificate chain chains up to a known root (i.e. not a
133 // user-installed trust anchor); and
134 // * the server actually has public key pins.
135 if (!is_issued_by_known_root
|| !HasPublicKeyPins(host
)) {
139 bool pins_are_valid
= CheckPublicKeyPinsImpl(
140 host
, public_key_hashes
, pinning_failure_log
);
141 if (!pins_are_valid
) {
142 LOG(ERROR
) << *pinning_failure_log
;
143 ReportUMAOnPinFailure(host
);
146 UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", pins_are_valid
);
147 return pins_are_valid
;
150 bool TransportSecurityState::HasPublicKeyPins(const std::string
& host
) {
151 DomainState dynamic_state
;
152 if (GetDynamicDomainState(host
, &dynamic_state
))
153 return dynamic_state
.HasPublicKeyPins();
155 DomainState static_state
;
156 if (GetStaticDomainState(host
, &static_state
)) {
157 if (static_state
.HasPublicKeyPins())
164 void TransportSecurityState::SetDelegate(
165 TransportSecurityState::Delegate
* delegate
) {
166 DCHECK(CalledOnValidThread());
167 delegate_
= delegate
;
170 void TransportSecurityState::AddHSTSInternal(
171 const std::string
& host
,
172 TransportSecurityState::DomainState::UpgradeMode upgrade_mode
,
173 const base::Time
& expiry
,
174 bool include_subdomains
) {
175 DCHECK(CalledOnValidThread());
177 // Copy-and-modify the existing DomainState for this host (if any).
178 DomainState domain_state
;
179 const std::string canonicalized_host
= CanonicalizeHost(host
);
180 const std::string hashed_host
= HashHost(canonicalized_host
);
181 DomainStateMap::const_iterator i
= enabled_hosts_
.find(hashed_host
);
182 if (i
!= enabled_hosts_
.end())
183 domain_state
= i
->second
;
185 domain_state
.sts
.last_observed
= base::Time::Now();
186 domain_state
.sts
.include_subdomains
= include_subdomains
;
187 domain_state
.sts
.expiry
= expiry
;
188 domain_state
.sts
.upgrade_mode
= upgrade_mode
;
189 EnableHost(host
, domain_state
);
192 void TransportSecurityState::AddHPKPInternal(const std::string
& host
,
193 const base::Time
& last_observed
,
194 const base::Time
& expiry
,
195 bool include_subdomains
,
196 const HashValueVector
& hashes
) {
197 DCHECK(CalledOnValidThread());
199 // Copy-and-modify the existing DomainState for this host (if any).
200 DomainState domain_state
;
201 const std::string canonicalized_host
= CanonicalizeHost(host
);
202 const std::string hashed_host
= HashHost(canonicalized_host
);
203 DomainStateMap::const_iterator i
= enabled_hosts_
.find(hashed_host
);
204 if (i
!= enabled_hosts_
.end())
205 domain_state
= i
->second
;
207 domain_state
.pkp
.last_observed
= last_observed
;
208 domain_state
.pkp
.expiry
= expiry
;
209 domain_state
.pkp
.include_subdomains
= include_subdomains
;
210 domain_state
.pkp
.spki_hashes
= hashes
;
211 EnableHost(host
, domain_state
);
214 void TransportSecurityState::EnableHost(const std::string
& host
,
215 const DomainState
& state
) {
216 DCHECK(CalledOnValidThread());
218 const std::string canonicalized_host
= CanonicalizeHost(host
);
219 if (canonicalized_host
.empty())
222 DomainState
state_copy(state
);
223 // No need to store this value since it is redundant. (|canonicalized_host|
225 state_copy
.sts
.domain
.clear();
226 state_copy
.pkp
.domain
.clear();
228 enabled_hosts_
[HashHost(canonicalized_host
)] = state_copy
;
232 bool TransportSecurityState::DeleteDynamicDataForHost(const std::string
& host
) {
233 DCHECK(CalledOnValidThread());
235 const std::string canonicalized_host
= CanonicalizeHost(host
);
236 if (canonicalized_host
.empty())
239 DomainStateMap::iterator i
= enabled_hosts_
.find(
240 HashHost(canonicalized_host
));
241 if (i
!= enabled_hosts_
.end()) {
242 enabled_hosts_
.erase(i
);
249 void TransportSecurityState::ClearDynamicData() {
250 DCHECK(CalledOnValidThread());
251 enabled_hosts_
.clear();
254 void TransportSecurityState::DeleteAllDynamicDataSince(const base::Time
& time
) {
255 DCHECK(CalledOnValidThread());
257 bool dirtied
= false;
258 DomainStateMap::iterator i
= enabled_hosts_
.begin();
259 while (i
!= enabled_hosts_
.end()) {
260 // Clear STS and PKP state independently.
261 if (i
->second
.sts
.last_observed
>= time
) {
263 i
->second
.sts
.upgrade_mode
= DomainState::MODE_DEFAULT
;
265 if (i
->second
.pkp
.last_observed
>= time
) {
267 i
->second
.pkp
.spki_hashes
.clear();
268 i
->second
.pkp
.expiry
= base::Time();
271 // If both are now invalid, drop the entry altogether.
272 if (!i
->second
.ShouldUpgradeToSSL() && !i
->second
.HasPublicKeyPins()) {
274 enabled_hosts_
.erase(i
++);
285 TransportSecurityState::~TransportSecurityState() {
286 DCHECK(CalledOnValidThread());
289 void TransportSecurityState::DirtyNotify() {
290 DCHECK(CalledOnValidThread());
293 delegate_
->StateIsDirty(this);
297 std::string
TransportSecurityState::CanonicalizeHost(const std::string
& host
) {
298 // We cannot perform the operations as detailed in the spec here as |host|
299 // has already undergone IDN processing before it reached us. Thus, we check
300 // that there are no invalid characters in the host and lowercase the result.
302 std::string new_host
;
303 if (!DNSDomainFromDot(host
, &new_host
)) {
304 // DNSDomainFromDot can fail if any label is > 63 bytes or if the whole
305 // name is >255 bytes. However, search terms can have those properties.
306 return std::string();
309 for (size_t i
= 0; new_host
[i
]; i
+= new_host
[i
] + 1) {
310 const unsigned label_length
= static_cast<unsigned>(new_host
[i
]);
314 for (size_t j
= 0; j
< label_length
; ++j
) {
315 new_host
[i
+ 1 + j
] = static_cast<char>(tolower(new_host
[i
+ 1 + j
]));
322 // BitReader is a class that allows a bytestring to be read bit-by-bit.
325 BitReader(const uint8
* bytes
, size_t num_bits
)
328 num_bytes_((num_bits
+ 7) / 8),
329 current_byte_index_(0),
332 // Next sets |*out| to the next bit from the input. It returns false if no
333 // more bits are available or true otherwise.
334 bool Next(bool* out
) {
335 if (num_bits_used_
== 8) {
336 if (current_byte_index_
>= num_bytes_
) {
339 current_byte_
= bytes_
[current_byte_index_
++];
343 *out
= 1 & (current_byte_
>> (7 - num_bits_used_
));
348 // Read sets the |num_bits| least-significant bits of |*out| to the value of
349 // the next |num_bits| bits from the input. It returns false if there are
350 // insufficient bits in the input or true otherwise.
351 bool Read(unsigned num_bits
, uint32
* out
) {
352 DCHECK_LE(num_bits
, 32u);
355 for (unsigned i
= 0; i
< num_bits
; ++i
) {
360 ret
|= static_cast<uint32
>(bit
) << (num_bits
- 1 - i
);
367 // Unary sets |*out| to the result of decoding a unary value from the input.
368 // It returns false if there were insufficient bits in the input and true
370 bool Unary(size_t* out
) {
388 // Seek sets the current offest in the input to bit number |offset|. It
389 // returns true if |offset| is within the range of the input and false
391 bool Seek(size_t offset
) {
392 if (offset
>= num_bits_
) {
395 current_byte_index_
= offset
/ 8;
396 current_byte_
= bytes_
[current_byte_index_
++];
397 num_bits_used_
= offset
% 8;
402 const uint8
* const bytes_
;
403 const size_t num_bits_
;
404 const size_t num_bytes_
;
405 // current_byte_index_ contains the current byte offset in |bytes_|.
406 size_t current_byte_index_
;
407 // current_byte_ contains the current byte of the input.
409 // num_bits_used_ contains the number of bits of |current_byte_| that have
411 unsigned num_bits_used_
;
414 // HuffmanDecoder is a very simple Huffman reader. The input Huffman tree is
415 // simply encoded as a series of two-byte structures. The first byte determines
416 // the "0" pointer for that node and the second the "1" pointer. Each byte
417 // either has the MSB set, in which case the bottom 7 bits are the value for
418 // that position, or else the bottom seven bits contain the index of a node.
420 // The tree is decoded by walking rather than a table-driven approach.
421 class HuffmanDecoder
{
423 HuffmanDecoder(const uint8
* tree
, size_t tree_bytes
)
425 tree_bytes_(tree_bytes
) {}
427 bool Decode(BitReader
* reader
, char* out
) {
428 const uint8
* current
= &tree_
[tree_bytes_
-2];
432 if (!reader
->Next(&bit
)) {
436 uint8 b
= current
[bit
];
438 *out
= static_cast<char>(b
& 0x7f);
442 unsigned offset
= static_cast<unsigned>(b
) * 2;
443 DCHECK_LT(offset
, tree_bytes_
);
444 if (offset
>= tree_bytes_
) {
448 current
= &tree_
[offset
];
453 const uint8
* const tree_
;
454 const size_t tree_bytes_
;
457 #include "net/http/transport_security_state_static.h"
459 // PreloadResult is the result of resolving a specific name in the preloaded
461 struct PreloadResult
{
464 // hostname_offset contains the number of bytes from the start of the given
465 // hostname where the name of the matching entry starts.
466 size_t hostname_offset
;
467 bool sts_include_subdomains
;
468 bool pkp_include_subdomains
;
473 // DecodeHSTSPreloadRaw resolves |hostname| in the preloaded data. It returns
474 // false on internal error and true otherwise. After a successful return,
475 // |*out_found| is true iff a relevant entry has been found. If so, |*out|
476 // contains the details.
478 // Don't call this function, call DecodeHSTSPreload, below.
480 // Although this code should be robust, it never processes attacker-controlled
481 // data -- it only operates on the preloaded data built into the binary.
483 // The preloaded data is represented as a trie and matches the hostname
484 // backwards. Each node in the trie starts with a number of characters, which
485 // must match exactly. After that is a dispatch table which maps the next
486 // character in the hostname to another node in the trie.
488 // In the dispatch table, the zero character represents the "end of string"
489 // (which is the *beginning* of a hostname since we process it backwards). The
490 // value in that case is special -- rather than an offset to another trie node,
491 // it contains the HSTS information: whether subdomains are included, pinsets
492 // etc. If an "end of string" matches a period in the hostname then the
493 // information is remembered because, if no more specific node is found, then
494 // that information applies to the hostname.
496 // Dispatch tables are always given in order, but the "end of string" (zero)
497 // value always comes before an entry for '.'.
498 bool DecodeHSTSPreloadRaw(const std::string
& hostname
,
500 PreloadResult
* out
) {
501 HuffmanDecoder
huffman(kHSTSHuffmanTree
, sizeof(kHSTSHuffmanTree
));
502 BitReader
reader(kPreloadedHSTSData
, kPreloadedHSTSBits
);
503 size_t bit_offset
= kHSTSRootPosition
;
504 static const char kEndOfString
= 0;
505 static const char kEndOfTable
= 127;
509 if (hostname
.empty()) {
512 // hostname_offset contains one more than the index of the current character
513 // in the hostname that is being considered. It's one greater so that we can
514 // represent the position just before the beginning (with zero).
515 size_t hostname_offset
= hostname
.size();
518 // Seek to the desired location.
519 if (!reader
.Seek(bit_offset
)) {
523 // Decode the unary length of the common prefix.
524 size_t prefix_length
;
525 if (!reader
.Unary(&prefix_length
)) {
529 // Match each character in the prefix.
530 for (size_t i
= 0; i
< prefix_length
; ++i
) {
531 if (hostname_offset
== 0) {
532 // We can't match the terminator with a prefix string.
537 if (!huffman
.Decode(&reader
, &c
)) {
540 if (hostname
[hostname_offset
- 1] != c
) {
546 bool is_first_offset
= true;
547 size_t current_offset
= 0;
549 // Next is the dispatch table.
552 if (!huffman
.Decode(&reader
, &c
)) {
555 if (c
== kEndOfTable
) {
560 if (c
== kEndOfString
) {
562 if (!reader
.Next(&tmp
.sts_include_subdomains
) ||
563 !reader
.Next(&tmp
.force_https
) ||
564 !reader
.Next(&tmp
.has_pins
)) {
568 tmp
.pkp_include_subdomains
= tmp
.sts_include_subdomains
;
571 if (!reader
.Read(4, &tmp
.pinset_id
) ||
572 !reader
.Read(9, &tmp
.domain_id
) ||
573 (!tmp
.sts_include_subdomains
&&
574 !reader
.Next(&tmp
.pkp_include_subdomains
))) {
579 tmp
.hostname_offset
= hostname_offset
;
581 if (hostname_offset
== 0 || hostname
[hostname_offset
- 1] == '.') {
583 tmp
.sts_include_subdomains
|| tmp
.pkp_include_subdomains
;
586 if (hostname_offset
> 0) {
587 out
->force_https
&= tmp
.sts_include_subdomains
;
597 // The entries in a dispatch table are in order thus we can tell if there
598 // will be no match if the current character past the one that we want.
599 if (hostname_offset
== 0 || hostname
[hostname_offset
-1] < c
) {
603 if (is_first_offset
) {
604 // The first offset is backwards from the current position.
605 uint32 jump_delta_bits
;
607 if (!reader
.Read(5, &jump_delta_bits
) ||
608 !reader
.Read(jump_delta_bits
, &jump_delta
)) {
612 if (bit_offset
< jump_delta
) {
616 current_offset
= bit_offset
- jump_delta
;
617 is_first_offset
= false;
619 // Subsequent offsets are forward from the target of the first offset.
621 if (!reader
.Read(1, &is_long_jump
)) {
627 if (!reader
.Read(7, &jump_delta
)) {
631 uint32 jump_delta_bits
;
632 if (!reader
.Read(4, &jump_delta_bits
) ||
633 !reader
.Read(jump_delta_bits
+ 8, &jump_delta
)) {
638 current_offset
+= jump_delta
;
639 if (current_offset
>= bit_offset
) {
644 DCHECK_LT(0u, hostname_offset
);
645 if (hostname
[hostname_offset
- 1] == c
) {
646 bit_offset
= current_offset
;
654 bool DecodeHSTSPreload(const std::string
& hostname
,
655 PreloadResult
* out
) {
657 if (!DecodeHSTSPreloadRaw(hostname
, &found
, out
)) {
658 DCHECK(false) << "Internal error in DecodeHSTSPreloadRaw for hostname "
666 bool TransportSecurityState::AddHSTSHeader(const std::string
& host
,
667 const std::string
& value
) {
668 DCHECK(CalledOnValidThread());
670 base::Time now
= base::Time::Now();
671 base::TimeDelta max_age
;
672 bool include_subdomains
;
673 if (!ParseHSTSHeader(value
, &max_age
, &include_subdomains
)) {
677 // Handle max-age == 0.
678 DomainState::UpgradeMode upgrade_mode
;
679 if (max_age
.InSeconds() == 0) {
680 upgrade_mode
= DomainState::MODE_DEFAULT
;
682 upgrade_mode
= DomainState::MODE_FORCE_HTTPS
;
685 AddHSTSInternal(host
, upgrade_mode
, now
+ max_age
, include_subdomains
);
689 bool TransportSecurityState::AddHPKPHeader(const std::string
& host
,
690 const std::string
& value
,
691 const SSLInfo
& ssl_info
) {
692 DCHECK(CalledOnValidThread());
694 base::Time now
= base::Time::Now();
695 base::TimeDelta max_age
;
696 bool include_subdomains
;
697 HashValueVector spki_hashes
;
698 if (!ParseHPKPHeader(value
, ssl_info
.public_key_hashes
, &max_age
,
699 &include_subdomains
, &spki_hashes
)) {
702 // Handle max-age == 0.
703 if (max_age
.InSeconds() == 0)
705 AddHPKPInternal(host
, now
, now
+ max_age
, include_subdomains
, spki_hashes
);
709 void TransportSecurityState::AddHSTS(const std::string
& host
,
710 const base::Time
& expiry
,
711 bool include_subdomains
) {
712 DCHECK(CalledOnValidThread());
713 AddHSTSInternal(host
, DomainState::MODE_FORCE_HTTPS
, expiry
,
717 void TransportSecurityState::AddHPKP(const std::string
& host
,
718 const base::Time
& expiry
,
719 bool include_subdomains
,
720 const HashValueVector
& hashes
) {
721 DCHECK(CalledOnValidThread());
722 AddHPKPInternal(host
, base::Time::Now(), expiry
, include_subdomains
, hashes
);
726 bool TransportSecurityState::IsGooglePinnedProperty(const std::string
& host
) {
727 PreloadResult result
;
728 return DecodeHSTSPreload(host
, &result
) && result
.has_pins
&&
729 kPinsets
[result
.pinset_id
].accepted_pins
== kGoogleAcceptableCerts
;
733 void TransportSecurityState::ReportUMAOnPinFailure(const std::string
& host
) {
734 PreloadResult result
;
735 if (!DecodeHSTSPreload(host
, &result
) ||
740 DCHECK(result
.domain_id
!= DOMAIN_NOT_PINNED
);
742 UMA_HISTOGRAM_SPARSE_SLOWLY(
743 "Net.PublicKeyPinFailureDomain", result
.domain_id
);
747 bool TransportSecurityState::IsBuildTimely() {
748 // If the build metadata aren't embedded in the binary then we can't use the
749 // build time to determine if the build is timely, return true by default. If
750 // we're building an official build then keep using the build time, even if
751 // it's invalid it'd be a date in the past and this function will return
753 #if defined(DONT_EMBED_BUILD_METADATA) && !defined(OFFICIAL_BUILD)
756 const base::Time build_time
= base::GetBuildTime();
757 // We consider built-in information to be timely for 10 weeks.
758 return (base::Time::Now() - build_time
).InDays() < 70 /* 10 weeks */;
762 bool TransportSecurityState::CheckPublicKeyPinsImpl(
763 const std::string
& host
,
764 const HashValueVector
& hashes
,
765 std::string
* failure_log
) {
766 DomainState dynamic_state
;
767 if (GetDynamicDomainState(host
, &dynamic_state
))
768 return dynamic_state
.CheckPublicKeyPins(hashes
, failure_log
);
770 DomainState static_state
;
771 if (GetStaticDomainState(host
, &static_state
))
772 return static_state
.CheckPublicKeyPins(hashes
, failure_log
);
774 // HasPublicKeyPins should have returned true in order for this method
775 // to have been called, so if we fall through to here, it's an error.
779 bool TransportSecurityState::GetStaticDomainState(const std::string
& host
,
780 DomainState
* out
) const {
781 DCHECK(CalledOnValidThread());
783 out
->sts
.upgrade_mode
= DomainState::MODE_FORCE_HTTPS
;
784 out
->sts
.include_subdomains
= false;
785 out
->pkp
.include_subdomains
= false;
787 if (!IsBuildTimely())
790 PreloadResult result
;
791 if (!DecodeHSTSPreload(host
, &result
))
794 out
->sts
.domain
= host
.substr(result
.hostname_offset
);
795 out
->pkp
.domain
= out
->sts
.domain
;
796 out
->sts
.include_subdomains
= result
.sts_include_subdomains
;
797 out
->sts
.last_observed
= base::GetBuildTime();
798 out
->sts
.upgrade_mode
=
799 TransportSecurityState::DomainState::MODE_DEFAULT
;
800 if (result
.force_https
) {
801 out
->sts
.upgrade_mode
=
802 TransportSecurityState::DomainState::MODE_FORCE_HTTPS
;
805 if (enable_static_pins_
&& result
.has_pins
) {
806 out
->pkp
.include_subdomains
= result
.pkp_include_subdomains
;
807 out
->pkp
.last_observed
= base::GetBuildTime();
809 if (result
.pinset_id
>= arraysize(kPinsets
))
811 const Pinset
*pinset
= &kPinsets
[result
.pinset_id
];
813 if (pinset
->accepted_pins
) {
814 const char* const* sha1_hash
= pinset
->accepted_pins
;
816 AddHash(*sha1_hash
, &out
->pkp
.spki_hashes
);
820 if (pinset
->rejected_pins
) {
821 const char* const* sha1_hash
= pinset
->rejected_pins
;
823 AddHash(*sha1_hash
, &out
->pkp
.bad_spki_hashes
);
832 bool TransportSecurityState::GetDynamicDomainState(const std::string
& host
,
833 DomainState
* result
) {
834 DCHECK(CalledOnValidThread());
837 const std::string canonicalized_host
= CanonicalizeHost(host
);
838 if (canonicalized_host
.empty())
841 base::Time
current_time(base::Time::Now());
843 // Although STS and PKP states are completely independent, they are currently
844 // stored and processed together. This loop performs both independent queries
845 // together and combines the two results into a single output. See
846 // https://crbug.com/470295
847 bool found_sts
= false;
848 bool found_pkp
= false;
849 for (size_t i
= 0; canonicalized_host
[i
]; i
+= canonicalized_host
[i
] + 1) {
850 std::string
host_sub_chunk(&canonicalized_host
[i
],
851 canonicalized_host
.size() - i
);
852 DomainStateMap::iterator j
=
853 enabled_hosts_
.find(HashHost(host_sub_chunk
));
854 if (j
== enabled_hosts_
.end())
857 // If both halves of the entry are invalid, drop it.
858 if (current_time
> j
->second
.sts
.expiry
&&
859 current_time
> j
->second
.pkp
.expiry
) {
860 enabled_hosts_
.erase(j
);
865 // If this is the most specific STS match, add it to the result. Note: a STS
866 // entry at a more specific domain overrides a less specific domain whether
867 // or not |include_subdomains| is set.
868 if (!found_sts
&& current_time
<= j
->second
.sts
.expiry
&&
869 j
->second
.ShouldUpgradeToSSL()) {
871 if (i
== 0 || j
->second
.sts
.include_subdomains
) {
872 state
.sts
= j
->second
.sts
;
873 state
.sts
.domain
= DNSDomainToString(host_sub_chunk
);
877 // If this is the most specific PKP match, add it to the result. Note: a PKP
878 // entry at a more specific domain overrides a less specific domain whether
879 // or not |include_subdomains| is set.
880 if (!found_pkp
&& current_time
<= j
->second
.pkp
.expiry
&&
881 j
->second
.HasPublicKeyPins()) {
883 if (i
== 0 || j
->second
.pkp
.include_subdomains
) {
884 state
.pkp
= j
->second
.pkp
;
885 state
.pkp
.domain
= DNSDomainToString(host_sub_chunk
);
889 // Both queries have terminated. Abort the loop early.
890 if (found_sts
&& found_pkp
)
894 // If neither STS nor PKP state was found, do not return any DomainState. This
895 // determines whether ShouldSSLErrorsBeFatal returns true or false.
896 if (!state
.ShouldUpgradeToSSL() && !state
.HasPublicKeyPins())
903 void TransportSecurityState::AddOrUpdateEnabledHosts(
904 const std::string
& hashed_host
, const DomainState
& state
) {
905 DCHECK(CalledOnValidThread());
906 enabled_hosts_
[hashed_host
] = state
;
909 TransportSecurityState::DomainState::DomainState() {
910 sts
.upgrade_mode
= MODE_DEFAULT
;
911 sts
.include_subdomains
= false;
912 pkp
.include_subdomains
= false;
915 TransportSecurityState::DomainState::~DomainState() {
918 bool TransportSecurityState::DomainState::CheckPublicKeyPins(
919 const HashValueVector
& hashes
, std::string
* failure_log
) const {
920 // Validate that hashes is not empty. By the time this code is called (in
921 // production), that should never happen, but it's good to be defensive.
922 // And, hashes *can* be empty in some test scenarios.
923 if (hashes
.empty()) {
925 "Rejecting empty public key chain for public-key-pinned domains: " +
930 if (HashesIntersect(pkp
.bad_spki_hashes
, hashes
)) {
931 failure_log
->append("Rejecting public key chain for domain " + pkp
.domain
+
932 ". Validated chain: " + HashesToBase64String(hashes
) +
933 ", matches one or more bad hashes: " +
934 HashesToBase64String(pkp
.bad_spki_hashes
));
938 // If there are no pins, then any valid chain is acceptable.
939 if (pkp
.spki_hashes
.empty())
942 if (HashesIntersect(pkp
.spki_hashes
, hashes
)) {
946 failure_log
->append("Rejecting public key chain for domain " + pkp
.domain
+
947 ". Validated chain: " + HashesToBase64String(hashes
) +
948 ", expected: " + HashesToBase64String(pkp
.spki_hashes
));
952 bool TransportSecurityState::DomainState::ShouldUpgradeToSSL() const {
953 return sts
.upgrade_mode
== MODE_FORCE_HTTPS
;
956 bool TransportSecurityState::DomainState::ShouldSSLErrorsBeFatal() const {
957 // Both HSTS and HPKP cause fatal SSL errors, so enable this on the presense
958 // of either. (If neither is active, no DomainState will be returned from
959 // GetDynamicDomainState.)
963 bool TransportSecurityState::DomainState::HasPublicKeyPins() const {
964 return pkp
.spki_hashes
.size() > 0 || pkp
.bad_spki_hashes
.size() > 0;
967 TransportSecurityState::DomainState::STSState::STSState() {
970 TransportSecurityState::DomainState::STSState::~STSState() {
973 TransportSecurityState::DomainState::PKPState::PKPState() {
976 TransportSecurityState::DomainState::PKPState::~PKPState() {