| 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
|
|
|