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 #include "net/http/transport_security_state_static.h"
50 std::string
HashesToBase64String(const HashValueVector
& hashes
) {
52 for (size_t i
= 0; i
!= hashes
.size(); ++i
) {
55 str
+= hashes
[i
].ToString();
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
));
79 bool AddHash(const char* sha1_hash
,
80 HashValueVector
* out
) {
81 HashValue
hash(HASH_VALUE_SHA1
);
82 memcpy(hash
.data(), sha1_hash
, hash
.size());
87 // Converts |hostname| from dotted form ("www.google.com") to the form
88 // used in DNS: "\x03www\x06google\x03com", lowercases that, and returns
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.
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.
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
]);
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
]));
114 // BitReader is a class that allows a bytestring to be read bit-by-bit.
117 BitReader(const uint8
* bytes
, size_t num_bits
)
120 num_bytes_((num_bits
+ 7) / 8),
121 current_byte_index_(0),
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_
) {
131 current_byte_
= bytes_
[current_byte_index_
++];
135 *out
= 1 & (current_byte_
>> (7 - num_bits_used_
));
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);
147 for (unsigned i
= 0; i
< num_bits
; ++i
) {
152 ret
|= static_cast<uint32
>(bit
) << (num_bits
- 1 - i
);
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
162 bool Unary(size_t* out
) {
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
183 bool Seek(size_t offset
) {
184 if (offset
>= num_bits_
) {
187 current_byte_index_
= offset
/ 8;
188 current_byte_
= bytes_
[current_byte_index_
++];
189 num_bits_used_
= offset
% 8;
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.
201 // num_bits_used_ contains the number of bits of |current_byte_| that have
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
{
215 HuffmanDecoder(const uint8
* tree
, size_t tree_bytes
)
217 tree_bytes_(tree_bytes
) {}
219 bool Decode(BitReader
* reader
, char* out
) {
220 const uint8
* current
= &tree_
[tree_bytes_
-2];
224 if (!reader
->Next(&bit
)) {
228 uint8 b
= current
[bit
];
230 *out
= static_cast<char>(b
& 0x7f);
234 unsigned offset
= static_cast<unsigned>(b
) * 2;
235 DCHECK_LT(offset
, tree_bytes_
);
236 if (offset
>= tree_bytes_
) {
240 current
= &tree_
[offset
];
245 const uint8
* const tree_
;
246 const size_t tree_bytes_
;
249 // PreloadResult is the result of resolving a specific name in the preloaded
251 struct PreloadResult
{
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
;
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
,
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;
299 // Ensure that |search_hostname| is a valid hostname before
301 if (CanonicalizeHost(search_hostname
).empty()) {
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);
314 // |hostname| has already undergone IDN conversion, so should be
315 // entirely A-Labels. The preload data is entirely normalized to
317 base::StringToLowerASCII(&hostname
);
319 if (hostname
.empty()) {
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();
329 // Seek to the desired location.
330 if (!reader
.Seek(bit_offset
)) {
334 // Decode the unary length of the common prefix.
335 size_t prefix_length
;
336 if (!reader
.Unary(&prefix_length
)) {
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.
348 if (!huffman
.Decode(&reader
, &c
)) {
351 if (hostname
[hostname_offset
- 1] != c
) {
357 bool is_first_offset
= true;
358 size_t current_offset
= 0;
360 // Next is the dispatch table.
363 if (!huffman
.Decode(&reader
, &c
)) {
366 if (c
== kEndOfTable
) {
371 if (c
== kEndOfString
) {
373 if (!reader
.Next(&tmp
.sts_include_subdomains
) ||
374 !reader
.Next(&tmp
.force_https
) ||
375 !reader
.Next(&tmp
.has_pins
)) {
379 tmp
.pkp_include_subdomains
= tmp
.sts_include_subdomains
;
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
))) {
390 tmp
.hostname_offset
= hostname_offset
;
392 if (hostname_offset
== 0 || hostname
[hostname_offset
- 1] == '.') {
394 tmp
.sts_include_subdomains
|| tmp
.pkp_include_subdomains
;
397 if (hostname_offset
> 0) {
398 out
->force_https
&= tmp
.sts_include_subdomains
;
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
) {
414 if (is_first_offset
) {
415 // The first offset is backwards from the current position.
416 uint32 jump_delta_bits
;
418 if (!reader
.Read(5, &jump_delta_bits
) ||
419 !reader
.Read(jump_delta_bits
, &jump_delta
)) {
423 if (bit_offset
< jump_delta
) {
427 current_offset
= bit_offset
- jump_delta
;
428 is_first_offset
= false;
430 // Subsequent offsets are forward from the target of the first offset.
432 if (!reader
.Read(1, &is_long_jump
)) {
438 if (!reader
.Read(7, &jump_delta
)) {
442 uint32 jump_delta_bits
;
443 if (!reader
.Read(4, &jump_delta_bits
) ||
444 !reader
.Read(jump_delta_bits
+ 8, &jump_delta
)) {
449 current_offset
+= jump_delta
;
450 if (current_offset
>= bit_offset
) {
455 DCHECK_LT(0u, hostname_offset
);
456 if (hostname
[hostname_offset
- 1] == c
) {
457 bit_offset
= current_offset
;
465 bool DecodeHSTSPreload(const std::string
& hostname
,
466 PreloadResult
* out
) {
468 if (!DecodeHSTSPreloadRaw(hostname
, &found
, out
)) {
469 DCHECK(false) << "Internal error in DecodeHSTSPreloadRaw for hostname "
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;
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
) {
499 if (GetStaticDomainState(host
, &state
))
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()) {
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
)) {
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())
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())
615 DomainState
state_copy(state
);
616 // No need to store this value since it is redundant. (|canonicalized_host|
618 state_copy
.sts
.domain
.clear();
619 state_copy
.pkp
.domain
.clear();
621 enabled_hosts_
[HashHost(canonicalized_host
)] = state_copy
;
625 bool TransportSecurityState::DeleteDynamicDataForHost(const std::string
& host
) {
626 DCHECK(CalledOnValidThread());
628 const std::string canonicalized_host
= CanonicalizeHost(host
);
629 if (canonicalized_host
.empty())
632 DomainStateMap::iterator i
=
633 enabled_hosts_
.find(HashHost(canonicalized_host
));
634 if (i
!= enabled_hosts_
.end()) {
635 enabled_hosts_
.erase(i
);
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
) {
656 i
->second
.sts
.upgrade_mode
= DomainState::MODE_DEFAULT
;
658 if (i
->second
.pkp
.last_observed
>= time
) {
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()) {
667 enabled_hosts_
.erase(i
++);
678 TransportSecurityState::~TransportSecurityState() {
679 DCHECK(CalledOnValidThread());
682 void TransportSecurityState::DirtyNotify() {
683 DCHECK(CalledOnValidThread());
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
)) {
700 // Handle max-age == 0.
701 DomainState::UpgradeMode upgrade_mode
;
702 if (max_age
.InSeconds() == 0) {
703 upgrade_mode
= DomainState::MODE_DEFAULT
;
705 upgrade_mode
= DomainState::MODE_FORCE_HTTPS
;
708 AddHSTSInternal(host
, upgrade_mode
, now
+ max_age
, include_subdomains
);
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
)) {
725 // Handle max-age == 0.
726 if (max_age
.InSeconds() == 0)
728 AddHPKPInternal(host
, now
, now
+ max_age
, include_subdomains
, spki_hashes
);
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
,
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
);
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
;
756 void TransportSecurityState::ReportUMAOnPinFailure(const std::string
& host
) {
757 PreloadResult result
;
758 if (!DecodeHSTSPreload(host
, &result
) ||
763 DCHECK(result
.domain_id
!= DOMAIN_NOT_PINNED
);
765 UMA_HISTOGRAM_SPARSE_SLOWLY(
766 "Net.PublicKeyPinFailureDomain", result
.domain_id
);
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
776 #if defined(DONT_EMBED_BUILD_METADATA) && !defined(OFFICIAL_BUILD)
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 */;
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.
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())
813 PreloadResult result
;
814 if (!DecodeHSTSPreload(host
, &result
))
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
))
834 const Pinset
*pinset
= &kPinsets
[result
.pinset_id
];
836 if (pinset
->accepted_pins
) {
837 const char* const* sha1_hash
= pinset
->accepted_pins
;
839 AddHash(*sha1_hash
, &out
->pkp
.spki_hashes
);
843 if (pinset
->rejected_pins
) {
844 const char* const* sha1_hash
= pinset
->rejected_pins
;
846 AddHash(*sha1_hash
, &out
->pkp
.bad_spki_hashes
);
855 bool TransportSecurityState::GetDynamicDomainState(const std::string
& host
,
856 DomainState
* result
) {
857 DCHECK(CalledOnValidThread());
860 const std::string canonicalized_host
= CanonicalizeHost(host
);
861 if (canonicalized_host
.empty())
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())
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
);
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()) {
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()) {
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
)
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())
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()) {
948 "Rejecting empty public key chain for public-key-pinned domains: " +
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
));
961 // If there are no pins, then any valid chain is acceptable.
962 if (pkp
.spki_hashes
.empty())
965 if (HashesIntersect(pkp
.spki_hashes
, hashes
)) {
969 failure_log
->append("Rejecting public key chain for domain " + pkp
.domain
+
970 ". Validated chain: " + HashesToBase64String(hashes
) +
971 ", expected: " + HashesToBase64String(pkp
.spki_hashes
));
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.)
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() {