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()
88 DCHECK(CalledOnValidThread());
91 TransportSecurityState::Iterator::Iterator(const TransportSecurityState& state)
92 : iterator_(state.enabled_hosts_.begin()),
93 end_(state.enabled_hosts_.end()) {
96 TransportSecurityState::Iterator::~Iterator() {}
98 bool TransportSecurityState::ShouldSSLErrorsBeFatal(const std::string& host,
101 if (GetStaticDomainState(host, sni_enabled, &state))
103 return GetDynamicDomainState(host, &state);
106 bool TransportSecurityState::ShouldUpgradeToSSL(const std::string& host,
108 DomainState dynamic_state;
109 if (GetDynamicDomainState(host, &dynamic_state))
110 return dynamic_state.ShouldUpgradeToSSL();
112 DomainState static_state;
113 if (GetStaticDomainState(host, sni_enabled, &static_state) &&
114 static_state.ShouldUpgradeToSSL()) {
121 bool TransportSecurityState::CheckPublicKeyPins(const std::string& host,
123 const HashValueVector& hashes,
124 std::string* failure_log) {
125 DomainState dynamic_state;
126 if (GetDynamicDomainState(host, &dynamic_state))
127 return dynamic_state.CheckPublicKeyPins(hashes, failure_log);
129 DomainState static_state;
130 if (GetStaticDomainState(host, sni_enabled, &static_state) &&
131 static_state.CheckPublicKeyPins(hashes, failure_log)) {
138 bool TransportSecurityState::HasPublicKeyPins(const std::string& host,
140 DomainState dynamic_state;
141 if (GetDynamicDomainState(host, &dynamic_state))
142 return dynamic_state.HasPublicKeyPins();
144 DomainState static_state;
145 if (GetStaticDomainState(host, sni_enabled, &static_state)) {
146 if (static_state.HasPublicKeyPins())
153 void TransportSecurityState::SetDelegate(
154 TransportSecurityState::Delegate* delegate) {
155 DCHECK(CalledOnValidThread());
156 delegate_ = delegate;
159 void TransportSecurityState::EnableHost(const std::string& host,
160 const DomainState& state) {
161 DCHECK(CalledOnValidThread());
163 const std::string canonicalized_host = CanonicalizeHost(host);
164 if (canonicalized_host.empty())
167 DomainState state_copy(state);
168 // No need to store this value since it is redundant. (|canonicalized_host|
170 state_copy.domain.clear();
172 enabled_hosts_[HashHost(canonicalized_host)] = state_copy;
176 bool TransportSecurityState::DeleteDynamicDataForHost(const std::string& host) {
177 DCHECK(CalledOnValidThread());
179 const std::string canonicalized_host = CanonicalizeHost(host);
180 if (canonicalized_host.empty())
183 DomainStateMap::iterator i = enabled_hosts_.find(
184 HashHost(canonicalized_host));
185 if (i != enabled_hosts_.end()) {
186 enabled_hosts_.erase(i);
193 void TransportSecurityState::ClearDynamicData() {
194 DCHECK(CalledOnValidThread());
195 enabled_hosts_.clear();
198 void TransportSecurityState::DeleteAllDynamicDataSince(const base::Time& time) {
199 DCHECK(CalledOnValidThread());
201 bool dirtied = false;
202 DomainStateMap::iterator i = enabled_hosts_.begin();
203 while (i != enabled_hosts_.end()) {
204 if (i->second.sts.last_observed >= time &&
205 i->second.pkp.last_observed >= time) {
207 enabled_hosts_.erase(i++);
211 if (i->second.sts.last_observed >= time) {
213 i->second.sts.upgrade_mode = DomainState::MODE_DEFAULT;
214 } else if (i->second.pkp.last_observed >= time) {
216 i->second.pkp.spki_hashes.clear();
217 i->second.pkp.expiry = base::Time();
226 TransportSecurityState::~TransportSecurityState() {
227 DCHECK(CalledOnValidThread());
230 void TransportSecurityState::DirtyNotify() {
231 DCHECK(CalledOnValidThread());
234 delegate_->StateIsDirty(this);
238 std::string TransportSecurityState::CanonicalizeHost(const std::string& host) {
239 // We cannot perform the operations as detailed in the spec here as |host|
240 // has already undergone IDN processing before it reached us. Thus, we check
241 // that there are no invalid characters in the host and lowercase the result.
243 std::string new_host;
244 if (!DNSDomainFromDot(host, &new_host)) {
245 // DNSDomainFromDot can fail if any label is > 63 bytes or if the whole
246 // name is >255 bytes. However, search terms can have those properties.
247 return std::string();
250 for (size_t i = 0; new_host[i]; i += new_host[i] + 1) {
251 const unsigned label_length = static_cast<unsigned>(new_host[i]);
255 for (size_t j = 0; j < label_length; ++j) {
256 new_host[i + 1 + j] = tolower(new_host[i + 1 + j]);
263 // |ReportUMAOnPinFailure| uses these to report which domain was associated
264 // with the public key pinning failure.
266 // DO NOT CHANGE THE ORDERING OF THESE NAMES OR REMOVE ANY OF THEM. Add new
267 // domains at the END of the listing (but before DOMAIN_NUM_EVENTS).
268 enum SecondLevelDomainName {
273 DOMAIN_GOOGLE_ANALYTICS_COM,
274 DOMAIN_GOOGLEPLEX_COM,
276 DOMAIN_GOOGLEUSERCONTENT_COM,
278 DOMAIN_GOOGLEAPIS_COM,
279 DOMAIN_GOOGLEADSERVICES_COM,
280 DOMAIN_GOOGLECODE_COM,
282 DOMAIN_GOOGLESYNDICATION_COM,
283 DOMAIN_DOUBLECLICK_NET,
286 DOMAIN_GOOGLEMAIL_COM,
287 DOMAIN_GOOGLEGROUPS_COM,
289 DOMAIN_TORPROJECT_ORG,
299 DOMAIN_GOOGLECOMMERCE_COM,
526 DOMAIN_GOOGLETAGMANAGER_COM,
527 DOMAIN_GOOGLETAGSERVICES_COM,
529 // Boundary value for UMA_HISTOGRAM_ENUMERATION:
533 // PublicKeyPins contains a number of SubjectPublicKeyInfo hashes for a site.
534 // The validated certificate chain for the site must not include any of
535 // |excluded_hashes| and must include one or more of |required_hashes|.
536 struct PublicKeyPins {
537 const char* const* required_hashes;
538 const char* const* excluded_hashes;
543 bool include_subdomains;
547 SecondLevelDomainName second_level_domain_name;
550 static bool HasPreload(const struct HSTSPreload* entries, size_t num_entries,
551 const std::string& canonicalized_host, size_t i,
552 TransportSecurityState::DomainState* out, bool* ret) {
553 for (size_t j = 0; j < num_entries; j++) {
554 if (entries[j].length == canonicalized_host.size() - i &&
555 memcmp(entries[j].dns_name, &canonicalized_host[i],
556 entries[j].length) == 0) {
557 if (!entries[j].include_subdomains && i != 0) {
560 out->sts.include_subdomains = entries[j].include_subdomains;
561 out->sts.last_observed = base::GetBuildTime();
562 out->pkp.include_subdomains = entries[j].include_subdomains;
563 out->pkp.last_observed = base::GetBuildTime();
565 out->sts.upgrade_mode =
566 TransportSecurityState::DomainState::MODE_FORCE_HTTPS;
567 if (!entries[j].https_required)
568 out->sts.upgrade_mode =
569 TransportSecurityState::DomainState::MODE_DEFAULT;
570 if (entries[j].pins.required_hashes) {
571 const char* const* sha1_hash = entries[j].pins.required_hashes;
573 AddHash(*sha1_hash, &out->pkp.spki_hashes);
577 if (entries[j].pins.excluded_hashes) {
578 const char* const* sha1_hash = entries[j].pins.excluded_hashes;
580 AddHash(*sha1_hash, &out->pkp.bad_spki_hashes);
591 #include "net/http/transport_security_state_static.h"
593 // Returns the HSTSPreload entry for the |canonicalized_host| in |entries|,
594 // or NULL if there is none. Prefers exact hostname matches to those that
595 // match only because HSTSPreload.include_subdomains is true.
597 // |canonicalized_host| should be the hostname as canonicalized by
599 static const struct HSTSPreload* GetHSTSPreload(
600 const std::string& canonicalized_host,
601 const struct HSTSPreload* entries,
602 size_t num_entries) {
603 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) {
604 for (size_t j = 0; j < num_entries; j++) {
605 const struct HSTSPreload* entry = entries + j;
607 if (i != 0 && !entry->include_subdomains)
610 if (entry->length == canonicalized_host.size() - i &&
611 memcmp(entry->dns_name, &canonicalized_host[i], entry->length) == 0) {
620 bool TransportSecurityState::AddHSTSHeader(const std::string& host,
621 const std::string& value) {
622 DCHECK(CalledOnValidThread());
624 base::Time now = base::Time::Now();
625 base::TimeDelta max_age;
626 TransportSecurityState::DomainState domain_state;
627 GetDynamicDomainState(host, &domain_state);
628 if (ParseHSTSHeader(value, &max_age, &domain_state.sts.include_subdomains)) {
629 // Handle max-age == 0
630 if (max_age.InSeconds() == 0)
631 domain_state.sts.upgrade_mode = DomainState::MODE_DEFAULT;
633 domain_state.sts.upgrade_mode = DomainState::MODE_FORCE_HTTPS;
634 domain_state.sts.last_observed = now;
635 domain_state.sts.expiry = now + max_age;
636 EnableHost(host, domain_state);
642 bool TransportSecurityState::AddHPKPHeader(const std::string& host,
643 const std::string& value,
644 const SSLInfo& ssl_info) {
645 DCHECK(CalledOnValidThread());
647 base::Time now = base::Time::Now();
648 base::TimeDelta max_age;
649 TransportSecurityState::DomainState domain_state;
650 GetDynamicDomainState(host, &domain_state);
651 if (ParseHPKPHeader(value,
652 ssl_info.public_key_hashes,
654 &domain_state.pkp.include_subdomains,
655 &domain_state.pkp.spki_hashes)) {
656 // TODO(palmer): http://crbug.com/243865 handle max-age == 0.
657 domain_state.pkp.last_observed = now;
658 domain_state.pkp.expiry = now + max_age;
659 EnableHost(host, domain_state);
665 bool TransportSecurityState::AddHSTS(const std::string& host,
666 const base::Time& expiry,
667 bool include_subdomains) {
668 DCHECK(CalledOnValidThread());
670 // Copy-and-modify the existing DomainState for this host (if any).
671 TransportSecurityState::DomainState domain_state;
672 const std::string canonicalized_host = CanonicalizeHost(host);
673 const std::string hashed_host = HashHost(canonicalized_host);
674 DomainStateMap::const_iterator i = enabled_hosts_.find(
676 if (i != enabled_hosts_.end())
677 domain_state = i->second;
679 domain_state.sts.last_observed = base::Time::Now();
680 domain_state.sts.include_subdomains = include_subdomains;
681 domain_state.sts.expiry = expiry;
682 domain_state.sts.upgrade_mode = DomainState::MODE_FORCE_HTTPS;
683 EnableHost(host, domain_state);
687 bool TransportSecurityState::AddHPKP(const std::string& host,
688 const base::Time& expiry,
689 bool include_subdomains,
690 const HashValueVector& hashes) {
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.pkp.last_observed = base::Time::Now();
703 domain_state.pkp.include_subdomains = include_subdomains;
704 domain_state.pkp.expiry = expiry;
705 domain_state.pkp.spki_hashes = hashes;
706 EnableHost(host, domain_state);
711 bool TransportSecurityState::IsGooglePinnedProperty(const std::string& host,
713 std::string canonicalized_host = CanonicalizeHost(host);
714 const struct HSTSPreload* entry =
715 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS);
717 if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts)
721 entry = GetHSTSPreload(canonicalized_host, kPreloadedSNISTS,
722 kNumPreloadedSNISTS);
723 if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts)
731 void TransportSecurityState::ReportUMAOnPinFailure(const std::string& host) {
732 std::string canonicalized_host = CanonicalizeHost(host);
734 const struct HSTSPreload* entry =
735 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS);
738 entry = GetHSTSPreload(canonicalized_host, kPreloadedSNISTS,
739 kNumPreloadedSNISTS);
743 // We don't care to report pin failures for dynamic pins.
748 DCHECK(entry->pins.required_hashes);
749 DCHECK(entry->second_level_domain_name != DOMAIN_NOT_PINNED);
751 UMA_HISTOGRAM_ENUMERATION("Net.PublicKeyPinFailureDomain",
752 entry->second_level_domain_name, DOMAIN_NUM_EVENTS);
756 bool TransportSecurityState::IsBuildTimely() {
757 const base::Time build_time = base::GetBuildTime();
758 // We consider built-in information to be timely for 10 weeks.
759 return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */;
762 bool TransportSecurityState::GetStaticDomainState(const std::string& host,
764 DomainState* out) const {
765 DCHECK(CalledOnValidThread());
767 const std::string canonicalized_host = CanonicalizeHost(host);
769 out->sts.upgrade_mode = DomainState::MODE_FORCE_HTTPS;
770 out->sts.include_subdomains = false;
771 out->pkp.include_subdomains = false;
773 const bool is_build_timely = IsBuildTimely();
775 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) {
776 std::string host_sub_chunk(&canonicalized_host[i],
777 canonicalized_host.size() - i);
778 out->domain = DNSDomainToString(host_sub_chunk);
780 if (is_build_timely &&
781 HasPreload(kPreloadedSTS, kNumPreloadedSTS, canonicalized_host, i, out,
787 HasPreload(kPreloadedSNISTS, kNumPreloadedSNISTS, canonicalized_host, i,
796 bool TransportSecurityState::GetDynamicDomainState(const std::string& host,
797 DomainState* result) {
798 DCHECK(CalledOnValidThread());
801 const std::string canonicalized_host = CanonicalizeHost(host);
802 if (canonicalized_host.empty())
805 base::Time current_time(base::Time::Now());
807 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) {
808 std::string host_sub_chunk(&canonicalized_host[i],
809 canonicalized_host.size() - i);
810 DomainStateMap::iterator j =
811 enabled_hosts_.find(HashHost(host_sub_chunk));
812 if (j == enabled_hosts_.end())
815 if (current_time > j->second.sts.expiry &&
816 current_time > j->second.pkp.expiry) {
817 enabled_hosts_.erase(j);
823 state.domain = DNSDomainToString(host_sub_chunk);
825 // Succeed if we matched the domain exactly or if subdomain matches are
827 if (i == 0 || j->second.sts.include_subdomains ||
828 j->second.pkp.include_subdomains) {
839 void TransportSecurityState::AddOrUpdateEnabledHosts(
840 const std::string& hashed_host, const DomainState& state) {
841 DCHECK(CalledOnValidThread());
842 enabled_hosts_[hashed_host] = state;
845 TransportSecurityState::DomainState::DomainState() {
846 sts.upgrade_mode = MODE_DEFAULT;
847 sts.include_subdomains = false;
848 pkp.include_subdomains = false;
851 TransportSecurityState::DomainState::~DomainState() {
854 bool TransportSecurityState::DomainState::CheckPublicKeyPins(
855 const HashValueVector& hashes, std::string* failure_log) const {
856 // Validate that hashes is not empty. By the time this code is called (in
857 // production), that should never happen, but it's good to be defensive.
858 // And, hashes *can* be empty in some test scenarios.
859 if (hashes.empty()) {
861 "Rejecting empty public key chain for public-key-pinned domains: " +
866 if (HashesIntersect(pkp.bad_spki_hashes, hashes)) {
867 failure_log->append("Rejecting public key chain for domain " + domain +
868 ". Validated chain: " + HashesToBase64String(hashes) +
869 ", matches one or more bad hashes: " +
870 HashesToBase64String(pkp.bad_spki_hashes));
874 // If there are no pins, then any valid chain is acceptable.
875 if (pkp.spki_hashes.empty())
878 if (HashesIntersect(pkp.spki_hashes, hashes)) {
882 failure_log->append("Rejecting public key chain for domain " + domain +
883 ". Validated chain: " + HashesToBase64String(hashes) +
884 ", expected: " + HashesToBase64String(pkp.spki_hashes));
888 bool TransportSecurityState::DomainState::ShouldUpgradeToSSL() const {
889 return sts.upgrade_mode == MODE_FORCE_HTTPS;
892 bool TransportSecurityState::DomainState::ShouldSSLErrorsBeFatal() const {
896 bool TransportSecurityState::DomainState::HasPublicKeyPins() const {
897 return pkp.spki_hashes.size() > 0 || pkp.bad_spki_hashes.size() > 0;
900 TransportSecurityState::DomainState::PKPState::PKPState() {
903 TransportSecurityState::DomainState::PKPState::~PKPState() {