Index: net/base/transport_security_state.cc |
diff --git a/net/base/transport_security_state.cc b/net/base/transport_security_state.cc |
deleted file mode 100644 |
index 50b4dac25309ca27d51965e4e8754e3c254e29e0..0000000000000000000000000000000000000000 |
--- a/net/base/transport_security_state.cc |
+++ /dev/null |
@@ -1,854 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "net/base/transport_security_state.h" |
- |
-#if defined(USE_OPENSSL) |
-#include <openssl/ecdsa.h> |
-#include <openssl/ssl.h> |
-#else // !defined(USE_OPENSSL) |
-#include <cryptohi.h> |
-#include <hasht.h> |
-#include <keyhi.h> |
-#include <pk11pub.h> |
-#include <nspr.h> |
-#endif |
- |
-#include <algorithm> |
- |
-#include "base/base64.h" |
-#include "base/build_time.h" |
-#include "base/logging.h" |
-#include "base/memory/scoped_ptr.h" |
-#include "base/metrics/histogram.h" |
-#include "base/sha1.h" |
-#include "base/string_number_conversions.h" |
-#include "base/string_util.h" |
-#include "base/time.h" |
-#include "base/utf_string_conversions.h" |
-#include "base/values.h" |
-#include "crypto/sha2.h" |
-#include "googleurl/src/gurl.h" |
-#include "net/base/dns_util.h" |
-#include "net/base/ssl_info.h" |
-#include "net/base/x509_cert_types.h" |
-#include "net/base/x509_certificate.h" |
-#include "net/http/http_security_headers.h" |
- |
-#if defined(USE_OPENSSL) |
-#include "crypto/openssl_util.h" |
-#endif |
- |
-namespace net { |
- |
-namespace { |
- |
-std::string HashesToBase64String(const HashValueVector& hashes) { |
- std::string str; |
- for (size_t i = 0; i != hashes.size(); ++i) { |
- if (i != 0) |
- str += ","; |
- str += hashes[i].ToString(); |
- } |
- return str; |
-} |
- |
-std::string HashHost(const std::string& canonicalized_host) { |
- char hashed[crypto::kSHA256Length]; |
- crypto::SHA256HashString(canonicalized_host, hashed, sizeof(hashed)); |
- return std::string(hashed, sizeof(hashed)); |
-} |
- |
-// Returns true if the intersection of |a| and |b| is not empty. If either |
-// |a| or |b| is empty, returns false. |
-bool HashesIntersect(const HashValueVector& a, |
- const HashValueVector& b) { |
- for (HashValueVector::const_iterator i = a.begin(); i != a.end(); ++i) { |
- HashValueVector::const_iterator j = |
- std::find_if(b.begin(), b.end(), HashValuesEqual(*i)); |
- if (j != b.end()) |
- return true; |
- } |
- return false; |
-} |
- |
-bool AddHash(const char* sha1_hash, |
- HashValueVector* out) { |
- HashValue hash(HASH_VALUE_SHA1); |
- memcpy(hash.data(), sha1_hash, hash.size()); |
- out->push_back(hash); |
- return true; |
-} |
- |
-} // namespace |
- |
-TransportSecurityState::TransportSecurityState() |
- : delegate_(NULL) { |
-} |
- |
-TransportSecurityState::Iterator::Iterator(const TransportSecurityState& state) |
- : iterator_(state.enabled_hosts_.begin()), |
- end_(state.enabled_hosts_.end()) { |
-} |
- |
-TransportSecurityState::Iterator::~Iterator() {} |
- |
-void TransportSecurityState::SetDelegate( |
- TransportSecurityState::Delegate* delegate) { |
- delegate_ = delegate; |
-} |
- |
-void TransportSecurityState::EnableHost(const std::string& host, |
- const DomainState& state) { |
- DCHECK(CalledOnValidThread()); |
- |
- const std::string canonicalized_host = CanonicalizeHost(host); |
- if (canonicalized_host.empty()) |
- return; |
- |
- DomainState existing_state; |
- |
- // Use the original creation date if we already have this host. (But note |
- // that statically-defined states have no |created| date. Therefore, we do |
- // not bother to search the SNI-only static states.) |
- DomainState state_copy(state); |
- if (GetDomainState(host, false /* sni_enabled */, &existing_state) && |
- !existing_state.created.is_null()) { |
- state_copy.created = existing_state.created; |
- } |
- |
- // No need to store this value since it is redundant. (|canonicalized_host| |
- // is the map key.) |
- state_copy.domain.clear(); |
- |
- enabled_hosts_[HashHost(canonicalized_host)] = state_copy; |
- DirtyNotify(); |
-} |
- |
-bool TransportSecurityState::DeleteDynamicDataForHost(const std::string& host) { |
- DCHECK(CalledOnValidThread()); |
- |
- const std::string canonicalized_host = CanonicalizeHost(host); |
- if (canonicalized_host.empty()) |
- return false; |
- |
- DomainStateMap::iterator i = enabled_hosts_.find( |
- HashHost(canonicalized_host)); |
- if (i != enabled_hosts_.end()) { |
- enabled_hosts_.erase(i); |
- DirtyNotify(); |
- return true; |
- } |
- return false; |
-} |
- |
-bool TransportSecurityState::GetDomainState(const std::string& host, |
- bool sni_enabled, |
- DomainState* result) { |
- DCHECK(CalledOnValidThread()); |
- |
- DomainState state; |
- const std::string canonicalized_host = CanonicalizeHost(host); |
- if (canonicalized_host.empty()) |
- return false; |
- |
- bool has_preload = GetStaticDomainState(canonicalized_host, sni_enabled, |
- &state); |
- std::string canonicalized_preload = CanonicalizeHost(state.domain); |
- |
- base::Time current_time(base::Time::Now()); |
- |
- for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { |
- std::string host_sub_chunk(&canonicalized_host[i], |
- canonicalized_host.size() - i); |
- // Exact match of a preload always wins. |
- if (has_preload && host_sub_chunk == canonicalized_preload) { |
- *result = state; |
- return true; |
- } |
- |
- DomainStateMap::iterator j = |
- enabled_hosts_.find(HashHost(host_sub_chunk)); |
- if (j == enabled_hosts_.end()) |
- continue; |
- |
- if (current_time > j->second.upgrade_expiry && |
- current_time > j->second.dynamic_spki_hashes_expiry) { |
- enabled_hosts_.erase(j); |
- DirtyNotify(); |
- continue; |
- } |
- |
- state = j->second; |
- state.domain = DNSDomainToString(host_sub_chunk); |
- |
- // Succeed if we matched the domain exactly or if subdomain matches are |
- // allowed. |
- if (i == 0 || j->second.include_subdomains) { |
- *result = state; |
- return true; |
- } |
- |
- return false; |
- } |
- |
- return false; |
-} |
- |
-void TransportSecurityState::ClearDynamicData() { |
- enabled_hosts_.clear(); |
-} |
- |
-void TransportSecurityState::DeleteAllDynamicDataSince(const base::Time& time) { |
- DCHECK(CalledOnValidThread()); |
- |
- bool dirtied = false; |
- |
- DomainStateMap::iterator i = enabled_hosts_.begin(); |
- while (i != enabled_hosts_.end()) { |
- if (i->second.created >= time) { |
- dirtied = true; |
- enabled_hosts_.erase(i++); |
- } else { |
- i++; |
- } |
- } |
- |
- if (dirtied) |
- DirtyNotify(); |
-} |
- |
-TransportSecurityState::~TransportSecurityState() {} |
- |
-void TransportSecurityState::DirtyNotify() { |
- DCHECK(CalledOnValidThread()); |
- |
- if (delegate_) |
- delegate_->StateIsDirty(this); |
-} |
- |
-// static |
-std::string TransportSecurityState::CanonicalizeHost(const std::string& host) { |
- // We cannot perform the operations as detailed in the spec here as |host| |
- // has already undergone IDN processing before it reached us. Thus, we check |
- // that there are no invalid characters in the host and lowercase the result. |
- |
- std::string new_host; |
- if (!DNSDomainFromDot(host, &new_host)) { |
- // DNSDomainFromDot can fail if any label is > 63 bytes or if the whole |
- // name is >255 bytes. However, search terms can have those properties. |
- return std::string(); |
- } |
- |
- for (size_t i = 0; new_host[i]; i += new_host[i] + 1) { |
- const unsigned label_length = static_cast<unsigned>(new_host[i]); |
- if (!label_length) |
- break; |
- |
- for (size_t j = 0; j < label_length; ++j) { |
- // RFC 3490, 4.1, step 3 |
- if (!IsSTD3ASCIIValidCharacter(new_host[i + 1 + j])) |
- return std::string(); |
- |
- new_host[i + 1 + j] = tolower(new_host[i + 1 + j]); |
- } |
- |
- // step 3(b) |
- if (new_host[i + 1] == '-' || |
- new_host[i + label_length] == '-') { |
- return std::string(); |
- } |
- } |
- |
- return new_host; |
-} |
- |
-// |ReportUMAOnPinFailure| uses these to report which domain was associated |
-// with the public key pinning failure. |
-// |
-// DO NOT CHANGE THE ORDERING OF THESE NAMES OR REMOVE ANY OF THEM. Add new |
-// domains at the END of the listing (but before DOMAIN_NUM_EVENTS). |
-enum SecondLevelDomainName { |
- DOMAIN_NOT_PINNED, |
- |
- DOMAIN_GOOGLE_COM, |
- DOMAIN_ANDROID_COM, |
- DOMAIN_GOOGLE_ANALYTICS_COM, |
- DOMAIN_GOOGLEPLEX_COM, |
- DOMAIN_YTIMG_COM, |
- DOMAIN_GOOGLEUSERCONTENT_COM, |
- DOMAIN_YOUTUBE_COM, |
- DOMAIN_GOOGLEAPIS_COM, |
- DOMAIN_GOOGLEADSERVICES_COM, |
- DOMAIN_GOOGLECODE_COM, |
- DOMAIN_APPSPOT_COM, |
- DOMAIN_GOOGLESYNDICATION_COM, |
- DOMAIN_DOUBLECLICK_NET, |
- DOMAIN_GSTATIC_COM, |
- DOMAIN_GMAIL_COM, |
- DOMAIN_GOOGLEMAIL_COM, |
- DOMAIN_GOOGLEGROUPS_COM, |
- |
- DOMAIN_TORPROJECT_ORG, |
- |
- DOMAIN_TWITTER_COM, |
- DOMAIN_TWIMG_COM, |
- |
- DOMAIN_AKAMAIHD_NET, |
- |
- DOMAIN_TOR2WEB_ORG, |
- |
- DOMAIN_YOUTU_BE, |
- DOMAIN_GOOGLECOMMERCE_COM, |
- DOMAIN_URCHIN_COM, |
- DOMAIN_GOO_GL, |
- DOMAIN_G_CO, |
- DOMAIN_GOOGLE_AC, |
- DOMAIN_GOOGLE_AD, |
- DOMAIN_GOOGLE_AE, |
- DOMAIN_GOOGLE_AF, |
- DOMAIN_GOOGLE_AG, |
- DOMAIN_GOOGLE_AM, |
- DOMAIN_GOOGLE_AS, |
- DOMAIN_GOOGLE_AT, |
- DOMAIN_GOOGLE_AZ, |
- DOMAIN_GOOGLE_BA, |
- DOMAIN_GOOGLE_BE, |
- DOMAIN_GOOGLE_BF, |
- DOMAIN_GOOGLE_BG, |
- DOMAIN_GOOGLE_BI, |
- DOMAIN_GOOGLE_BJ, |
- DOMAIN_GOOGLE_BS, |
- DOMAIN_GOOGLE_BY, |
- DOMAIN_GOOGLE_CA, |
- DOMAIN_GOOGLE_CAT, |
- DOMAIN_GOOGLE_CC, |
- DOMAIN_GOOGLE_CD, |
- DOMAIN_GOOGLE_CF, |
- DOMAIN_GOOGLE_CG, |
- DOMAIN_GOOGLE_CH, |
- DOMAIN_GOOGLE_CI, |
- DOMAIN_GOOGLE_CL, |
- DOMAIN_GOOGLE_CM, |
- DOMAIN_GOOGLE_CN, |
- DOMAIN_CO_AO, |
- DOMAIN_CO_BW, |
- DOMAIN_CO_CK, |
- DOMAIN_CO_CR, |
- DOMAIN_CO_HU, |
- DOMAIN_CO_ID, |
- DOMAIN_CO_IL, |
- DOMAIN_CO_IM, |
- DOMAIN_CO_IN, |
- DOMAIN_CO_JE, |
- DOMAIN_CO_JP, |
- DOMAIN_CO_KE, |
- DOMAIN_CO_KR, |
- DOMAIN_CO_LS, |
- DOMAIN_CO_MA, |
- DOMAIN_CO_MZ, |
- DOMAIN_CO_NZ, |
- DOMAIN_CO_TH, |
- DOMAIN_CO_TZ, |
- DOMAIN_CO_UG, |
- DOMAIN_CO_UK, |
- DOMAIN_CO_UZ, |
- DOMAIN_CO_VE, |
- DOMAIN_CO_VI, |
- DOMAIN_CO_ZA, |
- DOMAIN_CO_ZM, |
- DOMAIN_CO_ZW, |
- DOMAIN_COM_AF, |
- DOMAIN_COM_AG, |
- DOMAIN_COM_AI, |
- DOMAIN_COM_AR, |
- DOMAIN_COM_AU, |
- DOMAIN_COM_BD, |
- DOMAIN_COM_BH, |
- DOMAIN_COM_BN, |
- DOMAIN_COM_BO, |
- DOMAIN_COM_BR, |
- DOMAIN_COM_BY, |
- DOMAIN_COM_BZ, |
- DOMAIN_COM_CN, |
- DOMAIN_COM_CO, |
- DOMAIN_COM_CU, |
- DOMAIN_COM_CY, |
- DOMAIN_COM_DO, |
- DOMAIN_COM_EC, |
- DOMAIN_COM_EG, |
- DOMAIN_COM_ET, |
- DOMAIN_COM_FJ, |
- DOMAIN_COM_GE, |
- DOMAIN_COM_GH, |
- DOMAIN_COM_GI, |
- DOMAIN_COM_GR, |
- DOMAIN_COM_GT, |
- DOMAIN_COM_HK, |
- DOMAIN_COM_IQ, |
- DOMAIN_COM_JM, |
- DOMAIN_COM_JO, |
- DOMAIN_COM_KH, |
- DOMAIN_COM_KW, |
- DOMAIN_COM_LB, |
- DOMAIN_COM_LY, |
- DOMAIN_COM_MT, |
- DOMAIN_COM_MX, |
- DOMAIN_COM_MY, |
- DOMAIN_COM_NA, |
- DOMAIN_COM_NF, |
- DOMAIN_COM_NG, |
- DOMAIN_COM_NI, |
- DOMAIN_COM_NP, |
- DOMAIN_COM_NR, |
- DOMAIN_COM_OM, |
- DOMAIN_COM_PA, |
- DOMAIN_COM_PE, |
- DOMAIN_COM_PH, |
- DOMAIN_COM_PK, |
- DOMAIN_COM_PL, |
- DOMAIN_COM_PR, |
- DOMAIN_COM_PY, |
- DOMAIN_COM_QA, |
- DOMAIN_COM_RU, |
- DOMAIN_COM_SA, |
- DOMAIN_COM_SB, |
- DOMAIN_COM_SG, |
- DOMAIN_COM_SL, |
- DOMAIN_COM_SV, |
- DOMAIN_COM_TJ, |
- DOMAIN_COM_TN, |
- DOMAIN_COM_TR, |
- DOMAIN_COM_TW, |
- DOMAIN_COM_UA, |
- DOMAIN_COM_UY, |
- DOMAIN_COM_VC, |
- DOMAIN_COM_VE, |
- DOMAIN_COM_VN, |
- DOMAIN_GOOGLE_CV, |
- DOMAIN_GOOGLE_CZ, |
- DOMAIN_GOOGLE_DE, |
- DOMAIN_GOOGLE_DJ, |
- DOMAIN_GOOGLE_DK, |
- DOMAIN_GOOGLE_DM, |
- DOMAIN_GOOGLE_DZ, |
- DOMAIN_GOOGLE_EE, |
- DOMAIN_GOOGLE_ES, |
- DOMAIN_GOOGLE_FI, |
- DOMAIN_GOOGLE_FM, |
- DOMAIN_GOOGLE_FR, |
- DOMAIN_GOOGLE_GA, |
- DOMAIN_GOOGLE_GE, |
- DOMAIN_GOOGLE_GG, |
- DOMAIN_GOOGLE_GL, |
- DOMAIN_GOOGLE_GM, |
- DOMAIN_GOOGLE_GP, |
- DOMAIN_GOOGLE_GR, |
- DOMAIN_GOOGLE_GY, |
- DOMAIN_GOOGLE_HK, |
- DOMAIN_GOOGLE_HN, |
- DOMAIN_GOOGLE_HR, |
- DOMAIN_GOOGLE_HT, |
- DOMAIN_GOOGLE_HU, |
- DOMAIN_GOOGLE_IE, |
- DOMAIN_GOOGLE_IM, |
- DOMAIN_GOOGLE_INFO, |
- DOMAIN_GOOGLE_IQ, |
- DOMAIN_GOOGLE_IS, |
- DOMAIN_GOOGLE_IT, |
- DOMAIN_IT_AO, |
- DOMAIN_GOOGLE_JE, |
- DOMAIN_GOOGLE_JO, |
- DOMAIN_GOOGLE_JOBS, |
- DOMAIN_GOOGLE_JP, |
- DOMAIN_GOOGLE_KG, |
- DOMAIN_GOOGLE_KI, |
- DOMAIN_GOOGLE_KZ, |
- DOMAIN_GOOGLE_LA, |
- DOMAIN_GOOGLE_LI, |
- DOMAIN_GOOGLE_LK, |
- DOMAIN_GOOGLE_LT, |
- DOMAIN_GOOGLE_LU, |
- DOMAIN_GOOGLE_LV, |
- DOMAIN_GOOGLE_MD, |
- DOMAIN_GOOGLE_ME, |
- DOMAIN_GOOGLE_MG, |
- DOMAIN_GOOGLE_MK, |
- DOMAIN_GOOGLE_ML, |
- DOMAIN_GOOGLE_MN, |
- DOMAIN_GOOGLE_MS, |
- DOMAIN_GOOGLE_MU, |
- DOMAIN_GOOGLE_MV, |
- DOMAIN_GOOGLE_MW, |
- DOMAIN_GOOGLE_NE, |
- DOMAIN_NE_JP, |
- DOMAIN_GOOGLE_NET, |
- DOMAIN_GOOGLE_NL, |
- DOMAIN_GOOGLE_NO, |
- DOMAIN_GOOGLE_NR, |
- DOMAIN_GOOGLE_NU, |
- DOMAIN_OFF_AI, |
- DOMAIN_GOOGLE_PK, |
- DOMAIN_GOOGLE_PL, |
- DOMAIN_GOOGLE_PN, |
- DOMAIN_GOOGLE_PS, |
- DOMAIN_GOOGLE_PT, |
- DOMAIN_GOOGLE_RO, |
- DOMAIN_GOOGLE_RS, |
- DOMAIN_GOOGLE_RU, |
- DOMAIN_GOOGLE_RW, |
- DOMAIN_GOOGLE_SC, |
- DOMAIN_GOOGLE_SE, |
- DOMAIN_GOOGLE_SH, |
- DOMAIN_GOOGLE_SI, |
- DOMAIN_GOOGLE_SK, |
- DOMAIN_GOOGLE_SM, |
- DOMAIN_GOOGLE_SN, |
- DOMAIN_GOOGLE_SO, |
- DOMAIN_GOOGLE_ST, |
- DOMAIN_GOOGLE_TD, |
- DOMAIN_GOOGLE_TG, |
- DOMAIN_GOOGLE_TK, |
- DOMAIN_GOOGLE_TL, |
- DOMAIN_GOOGLE_TM, |
- DOMAIN_GOOGLE_TN, |
- DOMAIN_GOOGLE_TO, |
- DOMAIN_GOOGLE_TP, |
- DOMAIN_GOOGLE_TT, |
- DOMAIN_GOOGLE_US, |
- DOMAIN_GOOGLE_UZ, |
- DOMAIN_GOOGLE_VG, |
- DOMAIN_GOOGLE_VU, |
- DOMAIN_GOOGLE_WS, |
- |
- DOMAIN_CHROMIUM_ORG, |
- |
- DOMAIN_CRYPTO_CAT, |
- |
- // Boundary value for UMA_HISTOGRAM_ENUMERATION: |
- DOMAIN_NUM_EVENTS |
-}; |
- |
-// PublicKeyPins contains a number of SubjectPublicKeyInfo hashes for a site. |
-// The validated certificate chain for the site must not include any of |
-// |excluded_hashes| and must include one or more of |required_hashes|. |
-struct PublicKeyPins { |
- const char* const* required_hashes; |
- const char* const* excluded_hashes; |
-}; |
- |
-struct HSTSPreload { |
- uint8 length; |
- bool include_subdomains; |
- char dns_name[34]; |
- bool https_required; |
- PublicKeyPins pins; |
- SecondLevelDomainName second_level_domain_name; |
-}; |
- |
-static bool HasPreload(const struct HSTSPreload* entries, size_t num_entries, |
- const std::string& canonicalized_host, size_t i, |
- TransportSecurityState::DomainState* out, bool* ret) { |
- for (size_t j = 0; j < num_entries; j++) { |
- if (entries[j].length == canonicalized_host.size() - i && |
- memcmp(entries[j].dns_name, &canonicalized_host[i], |
- entries[j].length) == 0) { |
- if (!entries[j].include_subdomains && i != 0) { |
- *ret = false; |
- } else { |
- out->include_subdomains = entries[j].include_subdomains; |
- *ret = true; |
- if (!entries[j].https_required) |
- out->upgrade_mode = TransportSecurityState::DomainState::MODE_DEFAULT; |
- if (entries[j].pins.required_hashes) { |
- const char* const* sha1_hash = entries[j].pins.required_hashes; |
- while (*sha1_hash) { |
- AddHash(*sha1_hash, &out->static_spki_hashes); |
- sha1_hash++; |
- } |
- } |
- if (entries[j].pins.excluded_hashes) { |
- const char* const* sha1_hash = entries[j].pins.excluded_hashes; |
- while (*sha1_hash) { |
- AddHash(*sha1_hash, &out->bad_static_spki_hashes); |
- sha1_hash++; |
- } |
- } |
- } |
- return true; |
- } |
- } |
- return false; |
-} |
- |
-#include "net/base/transport_security_state_static.h" |
- |
-// Returns the HSTSPreload entry for the |canonicalized_host| in |entries|, |
-// or NULL if there is none. Prefers exact hostname matches to those that |
-// match only because HSTSPreload.include_subdomains is true. |
-// |
-// |canonicalized_host| should be the hostname as canonicalized by |
-// CanonicalizeHost. |
-static const struct HSTSPreload* GetHSTSPreload( |
- const std::string& canonicalized_host, |
- const struct HSTSPreload* entries, |
- size_t num_entries) { |
- for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { |
- for (size_t j = 0; j < num_entries; j++) { |
- const struct HSTSPreload* entry = entries + j; |
- |
- if (i != 0 && !entry->include_subdomains) |
- continue; |
- |
- if (entry->length == canonicalized_host.size() - i && |
- memcmp(entry->dns_name, &canonicalized_host[i], entry->length) == 0) { |
- return entry; |
- } |
- } |
- } |
- |
- return NULL; |
-} |
- |
-bool TransportSecurityState::AddHSTSHeader(const std::string& host, |
- const std::string& value) { |
- base::Time now = base::Time::Now(); |
- TransportSecurityState::DomainState domain_state; |
- if (ParseHSTSHeader(now, value, &domain_state.upgrade_expiry, |
- &domain_state.include_subdomains)) { |
- // Handle max-age == 0 |
- if (now == domain_state.upgrade_expiry) |
- domain_state.upgrade_mode = DomainState::MODE_DEFAULT; |
- else |
- domain_state.upgrade_mode = DomainState::MODE_FORCE_HTTPS; |
- domain_state.created = now; |
- EnableHost(host, domain_state); |
- return true; |
- } |
- return false; |
-} |
- |
-bool TransportSecurityState::AddHPKPHeader(const std::string& host, |
- const std::string& value, |
- const SSLInfo& ssl_info) { |
- base::Time now = base::Time::Now(); |
- TransportSecurityState::DomainState domain_state; |
- if (ParseHPKPHeader(now, value, ssl_info.public_key_hashes, |
- &domain_state.dynamic_spki_hashes_expiry, |
- &domain_state.dynamic_spki_hashes)) { |
- domain_state.upgrade_mode = DomainState::MODE_DEFAULT; |
- domain_state.created = now; |
- EnableHost(host, domain_state); |
- return true; |
- } |
- return false; |
-} |
- |
-bool TransportSecurityState::AddHSTS(const std::string& host, |
- const base::Time& expiry, |
- bool include_subdomains) { |
- // Copy-and-modify the existing DomainState for this host (if any). |
- TransportSecurityState::DomainState domain_state; |
- const std::string canonicalized_host = CanonicalizeHost(host); |
- const std::string hashed_host = HashHost(canonicalized_host); |
- DomainStateMap::const_iterator i = enabled_hosts_.find( |
- hashed_host); |
- if (i != enabled_hosts_.end()) |
- domain_state = i->second; |
- |
- domain_state.created = base::Time::Now(); |
- domain_state.include_subdomains = include_subdomains; |
- domain_state.upgrade_expiry = expiry; |
- domain_state.upgrade_mode = DomainState::MODE_FORCE_HTTPS; |
- EnableHost(host, domain_state); |
- return true; |
-} |
- |
-bool TransportSecurityState::AddHPKP(const std::string& host, |
- const base::Time& expiry, |
- bool include_subdomains, |
- const HashValueVector& hashes) { |
- // Copy-and-modify the existing DomainState for this host (if any). |
- TransportSecurityState::DomainState domain_state; |
- const std::string canonicalized_host = CanonicalizeHost(host); |
- const std::string hashed_host = HashHost(canonicalized_host); |
- DomainStateMap::const_iterator i = enabled_hosts_.find( |
- hashed_host); |
- if (i != enabled_hosts_.end()) |
- domain_state = i->second; |
- |
- domain_state.created = base::Time::Now(); |
- domain_state.include_subdomains = include_subdomains; |
- domain_state.dynamic_spki_hashes_expiry = expiry; |
- domain_state.dynamic_spki_hashes = hashes; |
- EnableHost(host, domain_state); |
- return true; |
-} |
- |
-// static |
-bool TransportSecurityState::IsGooglePinnedProperty(const std::string& host, |
- bool sni_enabled) { |
- std::string canonicalized_host = CanonicalizeHost(host); |
- const struct HSTSPreload* entry = |
- GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS); |
- |
- if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts) |
- return true; |
- |
- if (sni_enabled) { |
- entry = GetHSTSPreload(canonicalized_host, kPreloadedSNISTS, |
- kNumPreloadedSNISTS); |
- if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts) |
- return true; |
- } |
- |
- return false; |
-} |
- |
-// static |
-void TransportSecurityState::ReportUMAOnPinFailure(const std::string& host) { |
- std::string canonicalized_host = CanonicalizeHost(host); |
- |
- const struct HSTSPreload* entry = |
- GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS); |
- |
- if (!entry) { |
- entry = GetHSTSPreload(canonicalized_host, kPreloadedSNISTS, |
- kNumPreloadedSNISTS); |
- } |
- |
- if (!entry) { |
- // We don't care to report pin failures for dynamic pins. |
- return; |
- } |
- |
- DCHECK(entry); |
- DCHECK(entry->pins.required_hashes); |
- DCHECK(entry->second_level_domain_name != DOMAIN_NOT_PINNED); |
- |
- UMA_HISTOGRAM_ENUMERATION("Net.PublicKeyPinFailureDomain", |
- entry->second_level_domain_name, DOMAIN_NUM_EVENTS); |
-} |
- |
-// static |
-bool TransportSecurityState::IsBuildTimely() { |
- const base::Time build_time = base::GetBuildTime(); |
- // We consider built-in information to be timely for 10 weeks. |
- return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */; |
-} |
- |
-bool TransportSecurityState::GetStaticDomainState( |
- const std::string& canonicalized_host, |
- bool sni_enabled, |
- DomainState* out) { |
- DCHECK(CalledOnValidThread()); |
- |
- out->upgrade_mode = DomainState::MODE_FORCE_HTTPS; |
- out->include_subdomains = false; |
- |
- const bool is_build_timely = IsBuildTimely(); |
- |
- for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { |
- std::string host_sub_chunk(&canonicalized_host[i], |
- canonicalized_host.size() - i); |
- out->domain = DNSDomainToString(host_sub_chunk); |
- std::string hashed_host(HashHost(host_sub_chunk)); |
- if (forced_hosts_.find(hashed_host) != forced_hosts_.end()) { |
- *out = forced_hosts_[hashed_host]; |
- out->domain = DNSDomainToString(host_sub_chunk); |
- return true; |
- } |
- bool ret; |
- if (is_build_timely && |
- HasPreload(kPreloadedSTS, kNumPreloadedSTS, canonicalized_host, i, out, |
- &ret)) { |
- return ret; |
- } |
- if (sni_enabled && |
- is_build_timely && |
- HasPreload(kPreloadedSNISTS, kNumPreloadedSNISTS, canonicalized_host, i, |
- out, &ret)) { |
- return ret; |
- } |
- } |
- |
- return false; |
-} |
- |
-void TransportSecurityState::AddOrUpdateEnabledHosts( |
- const std::string& hashed_host, const DomainState& state) { |
- enabled_hosts_[hashed_host] = state; |
-} |
- |
-void TransportSecurityState::AddOrUpdateForcedHosts( |
- const std::string& hashed_host, const DomainState& state) { |
- forced_hosts_[hashed_host] = state; |
-} |
- |
-TransportSecurityState::DomainState::DomainState() |
- : upgrade_mode(MODE_FORCE_HTTPS), |
- created(base::Time::Now()), |
- include_subdomains(false) { |
-} |
- |
-TransportSecurityState::DomainState::~DomainState() { |
-} |
- |
-bool TransportSecurityState::DomainState::CheckPublicKeyPins( |
- const HashValueVector& hashes) const { |
- // Validate that hashes is not empty. By the time this code is called (in |
- // production), that should never happen, but it's good to be defensive. |
- // And, hashes *can* be empty in some test scenarios. |
- if (hashes.empty()) { |
- LOG(ERROR) << "Rejecting empty public key chain for public-key-pinned " |
- "domain " << domain; |
- return false; |
- } |
- |
- if (HashesIntersect(bad_static_spki_hashes, hashes)) { |
- LOG(ERROR) << "Rejecting public key chain for domain " << domain |
- << ". Validated chain: " << HashesToBase64String(hashes) |
- << ", matches one or more bad hashes: " |
- << HashesToBase64String(bad_static_spki_hashes); |
- return false; |
- } |
- |
- // If there are no pins, then any valid chain is acceptable. |
- if (dynamic_spki_hashes.empty() && static_spki_hashes.empty()) |
- return true; |
- |
- if (HashesIntersect(dynamic_spki_hashes, hashes) || |
- HashesIntersect(static_spki_hashes, hashes)) { |
- return true; |
- } |
- |
- LOG(ERROR) << "Rejecting public key chain for domain " << domain |
- << ". Validated chain: " << HashesToBase64String(hashes) |
- << ", expected: " << HashesToBase64String(dynamic_spki_hashes) |
- << " or: " << HashesToBase64String(static_spki_hashes); |
- return false; |
-} |
- |
-bool TransportSecurityState::DomainState::ShouldUpgradeToSSL() const { |
- return upgrade_mode == MODE_FORCE_HTTPS; |
-} |
- |
-bool TransportSecurityState::DomainState::ShouldSSLErrorsBeFatal() const { |
- return true; |
-} |
- |
-bool TransportSecurityState::DomainState::Equals( |
- const DomainState& other) const { |
- // TODO(palmer): Implement this |
- (void) other; |
- return true; |
-} |
- |
-bool TransportSecurityState::DomainState::HasPublicKeyPins() const { |
- return static_spki_hashes.size() > 0 || |
- bad_static_spki_hashes.size() > 0 || |
- dynamic_spki_hashes.size() > 0; |
-} |
- |
-} // namespace |