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/sha1.h"
26 #include "base/strings/string_number_conversions.h"
27 #include "base/strings/string_util.h"
28 #include "base/strings/utf_string_conversions.h"
29 #include "base/time/time.h"
30 #include "base/values.h"
31 #include "crypto/sha2.h"
32 #include "net/base/dns_util.h"
33 #include "net/cert/x509_cert_types.h"
34 #include "net/cert/x509_certificate.h"
35 #include "net/http/http_security_headers.h"
36 #include "net/ssl/ssl_info.h"
39 #if defined(USE_OPENSSL)
40 #include "crypto/openssl_util.h"
47 std::string
HashesToBase64String(const HashValueVector
& hashes
) {
49 for (size_t i
= 0; i
!= hashes
.size(); ++i
) {
52 str
+= hashes
[i
].ToString();
57 std::string
HashHost(const std::string
& canonicalized_host
) {
58 char hashed
[crypto::kSHA256Length
];
59 crypto::SHA256HashString(canonicalized_host
, hashed
, sizeof(hashed
));
60 return std::string(hashed
, sizeof(hashed
));
63 // Returns true if the intersection of |a| and |b| is not empty. If either
64 // |a| or |b| is empty, returns false.
65 bool HashesIntersect(const HashValueVector
& a
,
66 const HashValueVector
& b
) {
67 for (HashValueVector::const_iterator i
= a
.begin(); i
!= a
.end(); ++i
) {
68 HashValueVector::const_iterator j
=
69 std::find_if(b
.begin(), b
.end(), HashValuesEqual(*i
));
76 bool AddHash(const char* sha1_hash
,
77 HashValueVector
* out
) {
78 HashValue
hash(HASH_VALUE_SHA1
);
79 memcpy(hash
.data(), sha1_hash
, hash
.size());
86 TransportSecurityState::TransportSecurityState()
87 : delegate_(NULL
), enable_static_pins_(true) {
88 // Static pinning is only enabled for official builds to make sure that
89 // others don't end up with pins that cannot be easily updated.
90 #if !defined(OFFICIAL_BUILD) || defined(OS_ANDROID) || defined(OS_IOS)
91 enable_static_pins_
= false;
93 DCHECK(CalledOnValidThread());
96 TransportSecurityState::Iterator::Iterator(const TransportSecurityState
& state
)
97 : iterator_(state
.enabled_hosts_
.begin()),
98 end_(state
.enabled_hosts_
.end()) {
101 TransportSecurityState::Iterator::~Iterator() {}
103 bool TransportSecurityState::ShouldSSLErrorsBeFatal(const std::string
& host
) {
105 if (GetStaticDomainState(host
, &state
))
107 return GetDynamicDomainState(host
, &state
);
110 bool TransportSecurityState::ShouldUpgradeToSSL(const std::string
& host
) {
111 DomainState dynamic_state
;
112 if (GetDynamicDomainState(host
, &dynamic_state
))
113 return dynamic_state
.ShouldUpgradeToSSL();
115 DomainState static_state
;
116 if (GetStaticDomainState(host
, &static_state
) &&
117 static_state
.ShouldUpgradeToSSL()) {
124 bool TransportSecurityState::CheckPublicKeyPins(
125 const std::string
& host
,
126 bool is_issued_by_known_root
,
127 const HashValueVector
& public_key_hashes
,
128 std::string
* pinning_failure_log
) {
129 // Perform pin validation if, and only if, all these conditions obtain:
131 // * the server's certificate chain chains up to a known root (i.e. not a
132 // user-installed trust anchor); and
133 // * the server actually has public key pins.
134 if (!is_issued_by_known_root
|| !HasPublicKeyPins(host
)) {
138 bool pins_are_valid
= CheckPublicKeyPinsImpl(
139 host
, public_key_hashes
, pinning_failure_log
);
140 if (!pins_are_valid
) {
141 LOG(ERROR
) << *pinning_failure_log
;
142 ReportUMAOnPinFailure(host
);
145 UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", pins_are_valid
);
146 return pins_are_valid
;
149 bool TransportSecurityState::HasPublicKeyPins(const std::string
& host
) {
150 DomainState dynamic_state
;
151 if (GetDynamicDomainState(host
, &dynamic_state
))
152 return dynamic_state
.HasPublicKeyPins();
154 DomainState static_state
;
155 if (GetStaticDomainState(host
, &static_state
)) {
156 if (static_state
.HasPublicKeyPins())
163 void TransportSecurityState::SetDelegate(
164 TransportSecurityState::Delegate
* delegate
) {
165 DCHECK(CalledOnValidThread());
166 delegate_
= delegate
;
169 void TransportSecurityState::EnableHost(const std::string
& host
,
170 const DomainState
& state
) {
171 DCHECK(CalledOnValidThread());
173 const std::string canonicalized_host
= CanonicalizeHost(host
);
174 if (canonicalized_host
.empty())
177 DomainState
state_copy(state
);
178 // No need to store this value since it is redundant. (|canonicalized_host|
180 state_copy
.domain
.clear();
182 enabled_hosts_
[HashHost(canonicalized_host
)] = state_copy
;
186 bool TransportSecurityState::DeleteDynamicDataForHost(const std::string
& host
) {
187 DCHECK(CalledOnValidThread());
189 const std::string canonicalized_host
= CanonicalizeHost(host
);
190 if (canonicalized_host
.empty())
193 DomainStateMap::iterator i
= enabled_hosts_
.find(
194 HashHost(canonicalized_host
));
195 if (i
!= enabled_hosts_
.end()) {
196 enabled_hosts_
.erase(i
);
203 void TransportSecurityState::ClearDynamicData() {
204 DCHECK(CalledOnValidThread());
205 enabled_hosts_
.clear();
208 void TransportSecurityState::DeleteAllDynamicDataSince(const base::Time
& time
) {
209 DCHECK(CalledOnValidThread());
211 bool dirtied
= false;
212 DomainStateMap::iterator i
= enabled_hosts_
.begin();
213 while (i
!= enabled_hosts_
.end()) {
214 if (i
->second
.sts
.last_observed
>= time
&&
215 i
->second
.pkp
.last_observed
>= time
) {
217 enabled_hosts_
.erase(i
++);
221 if (i
->second
.sts
.last_observed
>= time
) {
223 i
->second
.sts
.upgrade_mode
= DomainState::MODE_DEFAULT
;
224 } else if (i
->second
.pkp
.last_observed
>= time
) {
226 i
->second
.pkp
.spki_hashes
.clear();
227 i
->second
.pkp
.expiry
= base::Time();
236 TransportSecurityState::~TransportSecurityState() {
237 DCHECK(CalledOnValidThread());
240 void TransportSecurityState::DirtyNotify() {
241 DCHECK(CalledOnValidThread());
244 delegate_
->StateIsDirty(this);
248 std::string
TransportSecurityState::CanonicalizeHost(const std::string
& host
) {
249 // We cannot perform the operations as detailed in the spec here as |host|
250 // has already undergone IDN processing before it reached us. Thus, we check
251 // that there are no invalid characters in the host and lowercase the result.
253 std::string new_host
;
254 if (!DNSDomainFromDot(host
, &new_host
)) {
255 // DNSDomainFromDot can fail if any label is > 63 bytes or if the whole
256 // name is >255 bytes. However, search terms can have those properties.
257 return std::string();
260 for (size_t i
= 0; new_host
[i
]; i
+= new_host
[i
] + 1) {
261 const unsigned label_length
= static_cast<unsigned>(new_host
[i
]);
265 for (size_t j
= 0; j
< label_length
; ++j
) {
266 new_host
[i
+ 1 + j
] = tolower(new_host
[i
+ 1 + j
]);
273 // |ReportUMAOnPinFailure| uses these to report which domain was associated
274 // with the public key pinning failure.
276 // DO NOT CHANGE THE ORDERING OF THESE NAMES OR REMOVE ANY OF THEM. Add new
277 // domains at the END of the listing (but before DOMAIN_NUM_EVENTS).
278 enum SecondLevelDomainName
{
283 DOMAIN_GOOGLE_ANALYTICS_COM
,
284 DOMAIN_GOOGLEPLEX_COM
,
286 DOMAIN_GOOGLEUSERCONTENT_COM
,
288 DOMAIN_GOOGLEAPIS_COM
,
289 DOMAIN_GOOGLEADSERVICES_COM
,
290 DOMAIN_GOOGLECODE_COM
,
292 DOMAIN_GOOGLESYNDICATION_COM
,
293 DOMAIN_DOUBLECLICK_NET
,
296 DOMAIN_GOOGLEMAIL_COM
,
297 DOMAIN_GOOGLEGROUPS_COM
,
299 DOMAIN_TORPROJECT_ORG
,
309 DOMAIN_GOOGLECOMMERCE_COM
,
536 DOMAIN_GOOGLETAGMANAGER_COM
,
537 DOMAIN_GOOGLETAGSERVICES_COM
,
540 DOMAIN_YOUTUBE_NOCOOKIE_COM
,
543 // Boundary value for UMA_HISTOGRAM_ENUMERATION:
547 // PublicKeyPins contains a number of SubjectPublicKeyInfo hashes for a site.
548 // The validated certificate chain for the site must not include any of
549 // |excluded_hashes| and must include one or more of |required_hashes|.
550 struct PublicKeyPins
{
551 const char* const* required_hashes
;
552 const char* const* excluded_hashes
;
557 bool include_subdomains
;
561 SecondLevelDomainName second_level_domain_name
;
564 static bool HasPreload(const struct HSTSPreload
* entries
,
566 const std::string
& canonicalized_host
,
568 bool enable_static_pins
,
569 TransportSecurityState::DomainState
* out
,
571 for (size_t j
= 0; j
< num_entries
; j
++) {
572 if (entries
[j
].length
== canonicalized_host
.size() - i
&&
573 memcmp(entries
[j
].dns_name
, &canonicalized_host
[i
],
574 entries
[j
].length
) == 0) {
575 if (!entries
[j
].include_subdomains
&& i
!= 0) {
578 out
->sts
.include_subdomains
= entries
[j
].include_subdomains
;
579 out
->sts
.last_observed
= base::GetBuildTime();
581 out
->sts
.upgrade_mode
=
582 TransportSecurityState::DomainState::MODE_FORCE_HTTPS
;
583 if (!entries
[j
].https_required
)
584 out
->sts
.upgrade_mode
=
585 TransportSecurityState::DomainState::MODE_DEFAULT
;
587 if (enable_static_pins
) {
588 out
->pkp
.include_subdomains
= entries
[j
].include_subdomains
;
589 out
->pkp
.last_observed
= base::GetBuildTime();
590 if (entries
[j
].pins
.required_hashes
) {
591 const char* const* sha1_hash
= entries
[j
].pins
.required_hashes
;
593 AddHash(*sha1_hash
, &out
->pkp
.spki_hashes
);
597 if (entries
[j
].pins
.excluded_hashes
) {
598 const char* const* sha1_hash
= entries
[j
].pins
.excluded_hashes
;
600 AddHash(*sha1_hash
, &out
->pkp
.bad_spki_hashes
);
612 #include "net/http/transport_security_state_static.h"
614 // Returns the HSTSPreload entry for the |canonicalized_host| in |entries|,
615 // or NULL if there is none. Prefers exact hostname matches to those that
616 // match only because HSTSPreload.include_subdomains is true.
618 // |canonicalized_host| should be the hostname as canonicalized by
620 static const struct HSTSPreload
* GetHSTSPreload(
621 const std::string
& canonicalized_host
,
622 const struct HSTSPreload
* entries
,
623 size_t num_entries
) {
624 for (size_t i
= 0; canonicalized_host
[i
]; i
+= canonicalized_host
[i
] + 1) {
625 for (size_t j
= 0; j
< num_entries
; j
++) {
626 const struct HSTSPreload
* entry
= entries
+ j
;
628 if (i
!= 0 && !entry
->include_subdomains
)
631 if (entry
->length
== canonicalized_host
.size() - i
&&
632 memcmp(entry
->dns_name
, &canonicalized_host
[i
], entry
->length
) == 0) {
641 bool TransportSecurityState::AddHSTSHeader(const std::string
& host
,
642 const std::string
& value
) {
643 DCHECK(CalledOnValidThread());
645 base::Time now
= base::Time::Now();
646 base::TimeDelta max_age
;
647 TransportSecurityState::DomainState domain_state
;
648 GetDynamicDomainState(host
, &domain_state
);
649 if (ParseHSTSHeader(value
, &max_age
, &domain_state
.sts
.include_subdomains
)) {
650 // Handle max-age == 0.
651 if (max_age
.InSeconds() == 0)
652 domain_state
.sts
.upgrade_mode
= DomainState::MODE_DEFAULT
;
654 domain_state
.sts
.upgrade_mode
= DomainState::MODE_FORCE_HTTPS
;
655 domain_state
.sts
.last_observed
= now
;
656 domain_state
.sts
.expiry
= now
+ max_age
;
657 EnableHost(host
, domain_state
);
663 bool TransportSecurityState::AddHPKPHeader(const std::string
& host
,
664 const std::string
& value
,
665 const SSLInfo
& ssl_info
) {
666 DCHECK(CalledOnValidThread());
668 base::Time now
= base::Time::Now();
669 base::TimeDelta max_age
;
670 TransportSecurityState::DomainState domain_state
;
671 GetDynamicDomainState(host
, &domain_state
);
672 if (ParseHPKPHeader(value
,
673 ssl_info
.public_key_hashes
,
675 &domain_state
.pkp
.include_subdomains
,
676 &domain_state
.pkp
.spki_hashes
)) {
677 // Handle max-age == 0.
678 if (max_age
.InSeconds() == 0)
679 domain_state
.pkp
.spki_hashes
.clear();
680 domain_state
.pkp
.last_observed
= now
;
681 domain_state
.pkp
.expiry
= now
+ max_age
;
682 EnableHost(host
, domain_state
);
688 bool TransportSecurityState::AddHSTS(const std::string
& host
,
689 const base::Time
& expiry
,
690 bool include_subdomains
) {
691 DCHECK(CalledOnValidThread());
693 // Copy-and-modify the existing DomainState for this host (if any).
694 TransportSecurityState::DomainState domain_state
;
695 const std::string canonicalized_host
= CanonicalizeHost(host
);
696 const std::string hashed_host
= HashHost(canonicalized_host
);
697 DomainStateMap::const_iterator i
= enabled_hosts_
.find(
699 if (i
!= enabled_hosts_
.end())
700 domain_state
= i
->second
;
702 domain_state
.sts
.last_observed
= base::Time::Now();
703 domain_state
.sts
.include_subdomains
= include_subdomains
;
704 domain_state
.sts
.expiry
= expiry
;
705 domain_state
.sts
.upgrade_mode
= DomainState::MODE_FORCE_HTTPS
;
706 EnableHost(host
, domain_state
);
710 bool TransportSecurityState::AddHPKP(const std::string
& host
,
711 const base::Time
& expiry
,
712 bool include_subdomains
,
713 const HashValueVector
& hashes
) {
714 DCHECK(CalledOnValidThread());
716 // Copy-and-modify the existing DomainState for this host (if any).
717 TransportSecurityState::DomainState domain_state
;
718 const std::string canonicalized_host
= CanonicalizeHost(host
);
719 const std::string hashed_host
= HashHost(canonicalized_host
);
720 DomainStateMap::const_iterator i
= enabled_hosts_
.find(
722 if (i
!= enabled_hosts_
.end())
723 domain_state
= i
->second
;
725 domain_state
.pkp
.last_observed
= base::Time::Now();
726 domain_state
.pkp
.include_subdomains
= include_subdomains
;
727 domain_state
.pkp
.expiry
= expiry
;
728 domain_state
.pkp
.spki_hashes
= hashes
;
729 EnableHost(host
, domain_state
);
734 bool TransportSecurityState::IsGooglePinnedProperty(const std::string
& host
) {
735 std::string canonicalized_host
= CanonicalizeHost(host
);
736 const struct HSTSPreload
* entry
=
737 GetHSTSPreload(canonicalized_host
, kPreloadedSTS
, kNumPreloadedSTS
);
739 return entry
&& entry
->pins
.required_hashes
== kGoogleAcceptableCerts
;
743 void TransportSecurityState::ReportUMAOnPinFailure(const std::string
& host
) {
744 std::string canonicalized_host
= CanonicalizeHost(host
);
746 const struct HSTSPreload
* entry
=
747 GetHSTSPreload(canonicalized_host
, kPreloadedSTS
, kNumPreloadedSTS
);
750 // We don't care to report pin failures for dynamic pins.
755 DCHECK(entry
->pins
.required_hashes
);
756 DCHECK(entry
->second_level_domain_name
!= DOMAIN_NOT_PINNED
);
758 UMA_HISTOGRAM_ENUMERATION("Net.PublicKeyPinFailureDomain",
759 entry
->second_level_domain_name
, DOMAIN_NUM_EVENTS
);
763 bool TransportSecurityState::IsBuildTimely() {
764 const base::Time build_time
= base::GetBuildTime();
765 // We consider built-in information to be timely for 10 weeks.
766 return (base::Time::Now() - build_time
).InDays() < 70 /* 10 weeks */;
769 bool TransportSecurityState::CheckPublicKeyPinsImpl(
770 const std::string
& host
,
771 const HashValueVector
& hashes
,
772 std::string
* failure_log
) {
773 DomainState dynamic_state
;
774 if (GetDynamicDomainState(host
, &dynamic_state
))
775 return dynamic_state
.CheckPublicKeyPins(hashes
, failure_log
);
777 DomainState static_state
;
778 if (GetStaticDomainState(host
, &static_state
))
779 return static_state
.CheckPublicKeyPins(hashes
, failure_log
);
781 // HasPublicKeyPins should have returned true in order for this method
782 // to have been called, so if we fall through to here, it's an error.
786 bool TransportSecurityState::GetStaticDomainState(const std::string
& host
,
787 DomainState
* out
) const {
788 DCHECK(CalledOnValidThread());
790 const std::string canonicalized_host
= CanonicalizeHost(host
);
792 out
->sts
.upgrade_mode
= DomainState::MODE_FORCE_HTTPS
;
793 out
->sts
.include_subdomains
= false;
794 out
->pkp
.include_subdomains
= false;
796 const bool is_build_timely
= IsBuildTimely();
798 for (size_t i
= 0; canonicalized_host
[i
]; i
+= canonicalized_host
[i
] + 1) {
799 std::string
host_sub_chunk(&canonicalized_host
[i
],
800 canonicalized_host
.size() - i
);
801 out
->domain
= DNSDomainToString(host_sub_chunk
);
803 if (is_build_timely
&& HasPreload(kPreloadedSTS
,
817 bool TransportSecurityState::GetDynamicDomainState(const std::string
& host
,
818 DomainState
* result
) {
819 DCHECK(CalledOnValidThread());
822 const std::string canonicalized_host
= CanonicalizeHost(host
);
823 if (canonicalized_host
.empty())
826 base::Time
current_time(base::Time::Now());
828 for (size_t i
= 0; canonicalized_host
[i
]; i
+= canonicalized_host
[i
] + 1) {
829 std::string
host_sub_chunk(&canonicalized_host
[i
],
830 canonicalized_host
.size() - i
);
831 DomainStateMap::iterator j
=
832 enabled_hosts_
.find(HashHost(host_sub_chunk
));
833 if (j
== enabled_hosts_
.end())
836 if (current_time
> j
->second
.sts
.expiry
&&
837 current_time
> j
->second
.pkp
.expiry
) {
838 enabled_hosts_
.erase(j
);
844 state
.domain
= DNSDomainToString(host_sub_chunk
);
846 // Succeed if we matched the domain exactly or if subdomain matches are
848 if (i
== 0 || j
->second
.sts
.include_subdomains
||
849 j
->second
.pkp
.include_subdomains
) {
860 void TransportSecurityState::AddOrUpdateEnabledHosts(
861 const std::string
& hashed_host
, const DomainState
& state
) {
862 DCHECK(CalledOnValidThread());
863 enabled_hosts_
[hashed_host
] = state
;
866 TransportSecurityState::DomainState::DomainState() {
867 sts
.upgrade_mode
= MODE_DEFAULT
;
868 sts
.include_subdomains
= false;
869 pkp
.include_subdomains
= false;
872 TransportSecurityState::DomainState::~DomainState() {
875 bool TransportSecurityState::DomainState::CheckPublicKeyPins(
876 const HashValueVector
& hashes
, std::string
* failure_log
) const {
877 // Validate that hashes is not empty. By the time this code is called (in
878 // production), that should never happen, but it's good to be defensive.
879 // And, hashes *can* be empty in some test scenarios.
880 if (hashes
.empty()) {
882 "Rejecting empty public key chain for public-key-pinned domains: " +
887 if (HashesIntersect(pkp
.bad_spki_hashes
, hashes
)) {
888 failure_log
->append("Rejecting public key chain for domain " + domain
+
889 ". Validated chain: " + HashesToBase64String(hashes
) +
890 ", matches one or more bad hashes: " +
891 HashesToBase64String(pkp
.bad_spki_hashes
));
895 // If there are no pins, then any valid chain is acceptable.
896 if (pkp
.spki_hashes
.empty())
899 if (HashesIntersect(pkp
.spki_hashes
, hashes
)) {
903 failure_log
->append("Rejecting public key chain for domain " + domain
+
904 ". Validated chain: " + HashesToBase64String(hashes
) +
905 ", expected: " + HashesToBase64String(pkp
.spki_hashes
));
909 bool TransportSecurityState::DomainState::ShouldUpgradeToSSL() const {
910 return sts
.upgrade_mode
== MODE_FORCE_HTTPS
;
913 bool TransportSecurityState::DomainState::ShouldSSLErrorsBeFatal() const {
917 bool TransportSecurityState::DomainState::HasPublicKeyPins() const {
918 return pkp
.spki_hashes
.size() > 0 || pkp
.bad_spki_hashes
.size() > 0;
921 TransportSecurityState::DomainState::PKPState::PKPState() {
924 TransportSecurityState::DomainState::PKPState::~PKPState() {