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
,
106 if (GetStaticDomainState(host
, sni_enabled
, &state
))
108 return GetDynamicDomainState(host
, &state
);
111 bool TransportSecurityState::ShouldUpgradeToSSL(const std::string
& host
,
113 DomainState dynamic_state
;
114 if (GetDynamicDomainState(host
, &dynamic_state
))
115 return dynamic_state
.ShouldUpgradeToSSL();
117 DomainState static_state
;
118 if (GetStaticDomainState(host
, sni_enabled
, &static_state
) &&
119 static_state
.ShouldUpgradeToSSL()) {
126 bool TransportSecurityState::CheckPublicKeyPins(
127 const std::string
& host
,
129 bool is_issued_by_known_root
,
130 const HashValueVector
& public_key_hashes
,
131 std::string
* pinning_failure_log
) {
132 // Perform pin validation if, and only if, all these conditions obtain:
134 // * the server's certificate chain chains up to a known root (i.e. not a
135 // user-installed trust anchor); and
136 // * the server actually has public key pins.
137 if (!is_issued_by_known_root
|| !HasPublicKeyPins(host
, sni_available
)) {
141 bool pins_are_valid
= CheckPublicKeyPinsImpl(
142 host
, sni_available
, public_key_hashes
, pinning_failure_log
);
143 if (!pins_are_valid
) {
144 LOG(ERROR
) << *pinning_failure_log
;
145 ReportUMAOnPinFailure(host
);
148 UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", pins_are_valid
);
149 return pins_are_valid
;
152 bool TransportSecurityState::HasPublicKeyPins(const std::string
& host
,
154 DomainState dynamic_state
;
155 if (GetDynamicDomainState(host
, &dynamic_state
))
156 return dynamic_state
.HasPublicKeyPins();
158 DomainState static_state
;
159 if (GetStaticDomainState(host
, sni_enabled
, &static_state
)) {
160 if (static_state
.HasPublicKeyPins())
167 void TransportSecurityState::SetDelegate(
168 TransportSecurityState::Delegate
* delegate
) {
169 DCHECK(CalledOnValidThread());
170 delegate_
= delegate
;
173 void TransportSecurityState::EnableHost(const std::string
& host
,
174 const DomainState
& state
) {
175 DCHECK(CalledOnValidThread());
177 const std::string canonicalized_host
= CanonicalizeHost(host
);
178 if (canonicalized_host
.empty())
181 DomainState
state_copy(state
);
182 // No need to store this value since it is redundant. (|canonicalized_host|
184 state_copy
.domain
.clear();
186 enabled_hosts_
[HashHost(canonicalized_host
)] = state_copy
;
190 bool TransportSecurityState::DeleteDynamicDataForHost(const std::string
& host
) {
191 DCHECK(CalledOnValidThread());
193 const std::string canonicalized_host
= CanonicalizeHost(host
);
194 if (canonicalized_host
.empty())
197 DomainStateMap::iterator i
= enabled_hosts_
.find(
198 HashHost(canonicalized_host
));
199 if (i
!= enabled_hosts_
.end()) {
200 enabled_hosts_
.erase(i
);
207 void TransportSecurityState::ClearDynamicData() {
208 DCHECK(CalledOnValidThread());
209 enabled_hosts_
.clear();
212 void TransportSecurityState::DeleteAllDynamicDataSince(const base::Time
& time
) {
213 DCHECK(CalledOnValidThread());
215 bool dirtied
= false;
216 DomainStateMap::iterator i
= enabled_hosts_
.begin();
217 while (i
!= enabled_hosts_
.end()) {
218 if (i
->second
.sts
.last_observed
>= time
&&
219 i
->second
.pkp
.last_observed
>= time
) {
221 enabled_hosts_
.erase(i
++);
225 if (i
->second
.sts
.last_observed
>= time
) {
227 i
->second
.sts
.upgrade_mode
= DomainState::MODE_DEFAULT
;
228 } else if (i
->second
.pkp
.last_observed
>= time
) {
230 i
->second
.pkp
.spki_hashes
.clear();
231 i
->second
.pkp
.expiry
= base::Time();
240 TransportSecurityState::~TransportSecurityState() {
241 DCHECK(CalledOnValidThread());
244 void TransportSecurityState::DirtyNotify() {
245 DCHECK(CalledOnValidThread());
248 delegate_
->StateIsDirty(this);
252 std::string
TransportSecurityState::CanonicalizeHost(const std::string
& host
) {
253 // We cannot perform the operations as detailed in the spec here as |host|
254 // has already undergone IDN processing before it reached us. Thus, we check
255 // that there are no invalid characters in the host and lowercase the result.
257 std::string new_host
;
258 if (!DNSDomainFromDot(host
, &new_host
)) {
259 // DNSDomainFromDot can fail if any label is > 63 bytes or if the whole
260 // name is >255 bytes. However, search terms can have those properties.
261 return std::string();
264 for (size_t i
= 0; new_host
[i
]; i
+= new_host
[i
] + 1) {
265 const unsigned label_length
= static_cast<unsigned>(new_host
[i
]);
269 for (size_t j
= 0; j
< label_length
; ++j
) {
270 new_host
[i
+ 1 + j
] = tolower(new_host
[i
+ 1 + j
]);
277 // |ReportUMAOnPinFailure| uses these to report which domain was associated
278 // with the public key pinning failure.
280 // DO NOT CHANGE THE ORDERING OF THESE NAMES OR REMOVE ANY OF THEM. Add new
281 // domains at the END of the listing (but before DOMAIN_NUM_EVENTS).
282 enum SecondLevelDomainName
{
287 DOMAIN_GOOGLE_ANALYTICS_COM
,
288 DOMAIN_GOOGLEPLEX_COM
,
290 DOMAIN_GOOGLEUSERCONTENT_COM
,
292 DOMAIN_GOOGLEAPIS_COM
,
293 DOMAIN_GOOGLEADSERVICES_COM
,
294 DOMAIN_GOOGLECODE_COM
,
296 DOMAIN_GOOGLESYNDICATION_COM
,
297 DOMAIN_DOUBLECLICK_NET
,
300 DOMAIN_GOOGLEMAIL_COM
,
301 DOMAIN_GOOGLEGROUPS_COM
,
303 DOMAIN_TORPROJECT_ORG
,
313 DOMAIN_GOOGLECOMMERCE_COM
,
540 DOMAIN_GOOGLETAGMANAGER_COM
,
541 DOMAIN_GOOGLETAGSERVICES_COM
,
544 DOMAIN_YOUTUBE_NOCOOKIE_COM
,
547 // Boundary value for UMA_HISTOGRAM_ENUMERATION:
551 // PublicKeyPins contains a number of SubjectPublicKeyInfo hashes for a site.
552 // The validated certificate chain for the site must not include any of
553 // |excluded_hashes| and must include one or more of |required_hashes|.
554 struct PublicKeyPins
{
555 const char* const* required_hashes
;
556 const char* const* excluded_hashes
;
561 bool include_subdomains
;
565 SecondLevelDomainName second_level_domain_name
;
568 static bool HasPreload(const struct HSTSPreload
* entries
,
570 const std::string
& canonicalized_host
,
572 bool enable_static_pins
,
573 TransportSecurityState::DomainState
* out
,
575 for (size_t j
= 0; j
< num_entries
; j
++) {
576 if (entries
[j
].length
== canonicalized_host
.size() - i
&&
577 memcmp(entries
[j
].dns_name
, &canonicalized_host
[i
],
578 entries
[j
].length
) == 0) {
579 if (!entries
[j
].include_subdomains
&& i
!= 0) {
582 out
->sts
.include_subdomains
= entries
[j
].include_subdomains
;
583 out
->sts
.last_observed
= base::GetBuildTime();
585 out
->sts
.upgrade_mode
=
586 TransportSecurityState::DomainState::MODE_FORCE_HTTPS
;
587 if (!entries
[j
].https_required
)
588 out
->sts
.upgrade_mode
=
589 TransportSecurityState::DomainState::MODE_DEFAULT
;
591 if (enable_static_pins
) {
592 out
->pkp
.include_subdomains
= entries
[j
].include_subdomains
;
593 out
->pkp
.last_observed
= base::GetBuildTime();
594 if (entries
[j
].pins
.required_hashes
) {
595 const char* const* sha1_hash
= entries
[j
].pins
.required_hashes
;
597 AddHash(*sha1_hash
, &out
->pkp
.spki_hashes
);
601 if (entries
[j
].pins
.excluded_hashes
) {
602 const char* const* sha1_hash
= entries
[j
].pins
.excluded_hashes
;
604 AddHash(*sha1_hash
, &out
->pkp
.bad_spki_hashes
);
616 #include "net/http/transport_security_state_static.h"
618 // Returns the HSTSPreload entry for the |canonicalized_host| in |entries|,
619 // or NULL if there is none. Prefers exact hostname matches to those that
620 // match only because HSTSPreload.include_subdomains is true.
622 // |canonicalized_host| should be the hostname as canonicalized by
624 static const struct HSTSPreload
* GetHSTSPreload(
625 const std::string
& canonicalized_host
,
626 const struct HSTSPreload
* entries
,
627 size_t num_entries
) {
628 for (size_t i
= 0; canonicalized_host
[i
]; i
+= canonicalized_host
[i
] + 1) {
629 for (size_t j
= 0; j
< num_entries
; j
++) {
630 const struct HSTSPreload
* entry
= entries
+ j
;
632 if (i
!= 0 && !entry
->include_subdomains
)
635 if (entry
->length
== canonicalized_host
.size() - i
&&
636 memcmp(entry
->dns_name
, &canonicalized_host
[i
], entry
->length
) == 0) {
645 bool TransportSecurityState::AddHSTSHeader(const std::string
& host
,
646 const std::string
& value
) {
647 DCHECK(CalledOnValidThread());
649 base::Time now
= base::Time::Now();
650 base::TimeDelta max_age
;
651 TransportSecurityState::DomainState domain_state
;
652 GetDynamicDomainState(host
, &domain_state
);
653 if (ParseHSTSHeader(value
, &max_age
, &domain_state
.sts
.include_subdomains
)) {
654 // Handle max-age == 0.
655 if (max_age
.InSeconds() == 0)
656 domain_state
.sts
.upgrade_mode
= DomainState::MODE_DEFAULT
;
658 domain_state
.sts
.upgrade_mode
= DomainState::MODE_FORCE_HTTPS
;
659 domain_state
.sts
.last_observed
= now
;
660 domain_state
.sts
.expiry
= now
+ max_age
;
661 EnableHost(host
, domain_state
);
667 bool TransportSecurityState::AddHPKPHeader(const std::string
& host
,
668 const std::string
& value
,
669 const SSLInfo
& ssl_info
) {
670 DCHECK(CalledOnValidThread());
672 base::Time now
= base::Time::Now();
673 base::TimeDelta max_age
;
674 TransportSecurityState::DomainState domain_state
;
675 GetDynamicDomainState(host
, &domain_state
);
676 if (ParseHPKPHeader(value
,
677 ssl_info
.public_key_hashes
,
679 &domain_state
.pkp
.include_subdomains
,
680 &domain_state
.pkp
.spki_hashes
)) {
681 // Handle max-age == 0.
682 if (max_age
.InSeconds() == 0)
683 domain_state
.pkp
.spki_hashes
.clear();
684 domain_state
.pkp
.last_observed
= now
;
685 domain_state
.pkp
.expiry
= now
+ max_age
;
686 EnableHost(host
, domain_state
);
692 bool TransportSecurityState::AddHSTS(const std::string
& host
,
693 const base::Time
& expiry
,
694 bool include_subdomains
) {
695 DCHECK(CalledOnValidThread());
697 // Copy-and-modify the existing DomainState for this host (if any).
698 TransportSecurityState::DomainState domain_state
;
699 const std::string canonicalized_host
= CanonicalizeHost(host
);
700 const std::string hashed_host
= HashHost(canonicalized_host
);
701 DomainStateMap::const_iterator i
= enabled_hosts_
.find(
703 if (i
!= enabled_hosts_
.end())
704 domain_state
= i
->second
;
706 domain_state
.sts
.last_observed
= base::Time::Now();
707 domain_state
.sts
.include_subdomains
= include_subdomains
;
708 domain_state
.sts
.expiry
= expiry
;
709 domain_state
.sts
.upgrade_mode
= DomainState::MODE_FORCE_HTTPS
;
710 EnableHost(host
, domain_state
);
714 bool TransportSecurityState::AddHPKP(const std::string
& host
,
715 const base::Time
& expiry
,
716 bool include_subdomains
,
717 const HashValueVector
& hashes
) {
718 DCHECK(CalledOnValidThread());
720 // Copy-and-modify the existing DomainState for this host (if any).
721 TransportSecurityState::DomainState domain_state
;
722 const std::string canonicalized_host
= CanonicalizeHost(host
);
723 const std::string hashed_host
= HashHost(canonicalized_host
);
724 DomainStateMap::const_iterator i
= enabled_hosts_
.find(
726 if (i
!= enabled_hosts_
.end())
727 domain_state
= i
->second
;
729 domain_state
.pkp
.last_observed
= base::Time::Now();
730 domain_state
.pkp
.include_subdomains
= include_subdomains
;
731 domain_state
.pkp
.expiry
= expiry
;
732 domain_state
.pkp
.spki_hashes
= hashes
;
733 EnableHost(host
, domain_state
);
738 bool TransportSecurityState::IsGooglePinnedProperty(const std::string
& host
,
740 std::string canonicalized_host
= CanonicalizeHost(host
);
741 const struct HSTSPreload
* entry
=
742 GetHSTSPreload(canonicalized_host
, kPreloadedSTS
, kNumPreloadedSTS
);
744 if (entry
&& entry
->pins
.required_hashes
== kGoogleAcceptableCerts
)
748 entry
= GetHSTSPreload(canonicalized_host
, kPreloadedSNISTS
,
749 kNumPreloadedSNISTS
);
750 if (entry
&& entry
->pins
.required_hashes
== kGoogleAcceptableCerts
)
758 void TransportSecurityState::ReportUMAOnPinFailure(const std::string
& host
) {
759 std::string canonicalized_host
= CanonicalizeHost(host
);
761 const struct HSTSPreload
* entry
=
762 GetHSTSPreload(canonicalized_host
, kPreloadedSTS
, kNumPreloadedSTS
);
765 entry
= GetHSTSPreload(canonicalized_host
, kPreloadedSNISTS
,
766 kNumPreloadedSNISTS
);
770 // We don't care to report pin failures for dynamic pins.
775 DCHECK(entry
->pins
.required_hashes
);
776 DCHECK(entry
->second_level_domain_name
!= DOMAIN_NOT_PINNED
);
778 UMA_HISTOGRAM_ENUMERATION("Net.PublicKeyPinFailureDomain",
779 entry
->second_level_domain_name
, DOMAIN_NUM_EVENTS
);
783 bool TransportSecurityState::IsBuildTimely() {
784 const base::Time build_time
= base::GetBuildTime();
785 // We consider built-in information to be timely for 10 weeks.
786 return (base::Time::Now() - build_time
).InDays() < 70 /* 10 weeks */;
789 bool TransportSecurityState::CheckPublicKeyPinsImpl(
790 const std::string
& host
,
792 const HashValueVector
& hashes
,
793 std::string
* failure_log
) {
794 DomainState dynamic_state
;
795 if (GetDynamicDomainState(host
, &dynamic_state
))
796 return dynamic_state
.CheckPublicKeyPins(hashes
, failure_log
);
798 DomainState static_state
;
799 if (GetStaticDomainState(host
, sni_enabled
, &static_state
))
800 return static_state
.CheckPublicKeyPins(hashes
, failure_log
);
802 // HasPublicKeyPins should have returned true in order for this method
803 // to have been called, so if we fall through to here, it's an error.
807 bool TransportSecurityState::GetStaticDomainState(const std::string
& host
,
809 DomainState
* out
) const {
810 DCHECK(CalledOnValidThread());
812 const std::string canonicalized_host
= CanonicalizeHost(host
);
814 out
->sts
.upgrade_mode
= DomainState::MODE_FORCE_HTTPS
;
815 out
->sts
.include_subdomains
= false;
816 out
->pkp
.include_subdomains
= false;
818 const bool is_build_timely
= IsBuildTimely();
820 for (size_t i
= 0; canonicalized_host
[i
]; i
+= canonicalized_host
[i
] + 1) {
821 std::string
host_sub_chunk(&canonicalized_host
[i
],
822 canonicalized_host
.size() - i
);
823 out
->domain
= DNSDomainToString(host_sub_chunk
);
825 if (is_build_timely
&& HasPreload(kPreloadedSTS
,
834 if (sni_enabled
&& is_build_timely
&& HasPreload(kPreloadedSNISTS
,
848 bool TransportSecurityState::GetDynamicDomainState(const std::string
& host
,
849 DomainState
* result
) {
850 DCHECK(CalledOnValidThread());
853 const std::string canonicalized_host
= CanonicalizeHost(host
);
854 if (canonicalized_host
.empty())
857 base::Time
current_time(base::Time::Now());
859 for (size_t i
= 0; canonicalized_host
[i
]; i
+= canonicalized_host
[i
] + 1) {
860 std::string
host_sub_chunk(&canonicalized_host
[i
],
861 canonicalized_host
.size() - i
);
862 DomainStateMap::iterator j
=
863 enabled_hosts_
.find(HashHost(host_sub_chunk
));
864 if (j
== enabled_hosts_
.end())
867 if (current_time
> j
->second
.sts
.expiry
&&
868 current_time
> j
->second
.pkp
.expiry
) {
869 enabled_hosts_
.erase(j
);
875 state
.domain
= DNSDomainToString(host_sub_chunk
);
877 // Succeed if we matched the domain exactly or if subdomain matches are
879 if (i
== 0 || j
->second
.sts
.include_subdomains
||
880 j
->second
.pkp
.include_subdomains
) {
891 void TransportSecurityState::AddOrUpdateEnabledHosts(
892 const std::string
& hashed_host
, const DomainState
& state
) {
893 DCHECK(CalledOnValidThread());
894 enabled_hosts_
[hashed_host
] = state
;
897 TransportSecurityState::DomainState::DomainState() {
898 sts
.upgrade_mode
= MODE_DEFAULT
;
899 sts
.include_subdomains
= false;
900 pkp
.include_subdomains
= false;
903 TransportSecurityState::DomainState::~DomainState() {
906 bool TransportSecurityState::DomainState::CheckPublicKeyPins(
907 const HashValueVector
& hashes
, std::string
* failure_log
) const {
908 // Validate that hashes is not empty. By the time this code is called (in
909 // production), that should never happen, but it's good to be defensive.
910 // And, hashes *can* be empty in some test scenarios.
911 if (hashes
.empty()) {
913 "Rejecting empty public key chain for public-key-pinned domains: " +
918 if (HashesIntersect(pkp
.bad_spki_hashes
, hashes
)) {
919 failure_log
->append("Rejecting public key chain for domain " + domain
+
920 ". Validated chain: " + HashesToBase64String(hashes
) +
921 ", matches one or more bad hashes: " +
922 HashesToBase64String(pkp
.bad_spki_hashes
));
926 // If there are no pins, then any valid chain is acceptable.
927 if (pkp
.spki_hashes
.empty())
930 if (HashesIntersect(pkp
.spki_hashes
, hashes
)) {
934 failure_log
->append("Rejecting public key chain for domain " + domain
+
935 ". Validated chain: " + HashesToBase64String(hashes
) +
936 ", expected: " + HashesToBase64String(pkp
.spki_hashes
));
940 bool TransportSecurityState::DomainState::ShouldUpgradeToSSL() const {
941 return sts
.upgrade_mode
== MODE_FORCE_HTTPS
;
944 bool TransportSecurityState::DomainState::ShouldSSLErrorsBeFatal() const {
948 bool TransportSecurityState::DomainState::HasPublicKeyPins() const {
949 return pkp
.spki_hashes
.size() > 0 || pkp
.bad_spki_hashes
.size() > 0;
952 TransportSecurityState::DomainState::PKPState::PKPState() {
955 TransportSecurityState::DomainState::PKPState::~PKPState() {