| Index: net/http/transport_security_persister.cc
|
| diff --git a/net/http/transport_security_persister.cc b/net/http/transport_security_persister.cc
|
| deleted file mode 100644
|
| index 82a4b51401ca2fda99e5ea069802f4f9975cd443..0000000000000000000000000000000000000000
|
| --- a/net/http/transport_security_persister.cc
|
| +++ /dev/null
|
| @@ -1,328 +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/http/transport_security_persister.h"
|
| -
|
| -#include "base/base64.h"
|
| -#include "base/bind.h"
|
| -#include "base/files/file_path.h"
|
| -#include "base/files/file_util.h"
|
| -#include "base/json/json_reader.h"
|
| -#include "base/json/json_writer.h"
|
| -#include "base/message_loop/message_loop.h"
|
| -#include "base/message_loop/message_loop_proxy.h"
|
| -#include "base/sequenced_task_runner.h"
|
| -#include "base/task_runner_util.h"
|
| -#include "base/values.h"
|
| -#include "crypto/sha2.h"
|
| -#include "net/cert/x509_certificate.h"
|
| -#include "net/http/transport_security_state.h"
|
| -
|
| -using net::HashValue;
|
| -using net::HashValueTag;
|
| -using net::HashValueVector;
|
| -using net::TransportSecurityState;
|
| -
|
| -namespace {
|
| -
|
| -base::ListValue* SPKIHashesToListValue(const HashValueVector& hashes) {
|
| - base::ListValue* pins = new base::ListValue;
|
| - for (size_t i = 0; i != hashes.size(); i++)
|
| - pins->Append(new base::StringValue(hashes[i].ToString()));
|
| - return pins;
|
| -}
|
| -
|
| -void SPKIHashesFromListValue(const base::ListValue& pins,
|
| - HashValueVector* hashes) {
|
| - size_t num_pins = pins.GetSize();
|
| - for (size_t i = 0; i < num_pins; ++i) {
|
| - std::string type_and_base64;
|
| - HashValue fingerprint;
|
| - if (pins.GetString(i, &type_and_base64) &&
|
| - fingerprint.FromString(type_and_base64)) {
|
| - hashes->push_back(fingerprint);
|
| - }
|
| - }
|
| -}
|
| -
|
| -// This function converts the binary hashes to a base64 string which we can
|
| -// include in a JSON file.
|
| -std::string HashedDomainToExternalString(const std::string& hashed) {
|
| - std::string out;
|
| - base::Base64Encode(hashed, &out);
|
| - return out;
|
| -}
|
| -
|
| -// This inverts |HashedDomainToExternalString|, above. It turns an external
|
| -// string (from a JSON file) into an internal (binary) string.
|
| -std::string ExternalStringToHashedDomain(const std::string& external) {
|
| - std::string out;
|
| - if (!base::Base64Decode(external, &out) ||
|
| - out.size() != crypto::kSHA256Length) {
|
| - return std::string();
|
| - }
|
| -
|
| - return out;
|
| -}
|
| -
|
| -const char kIncludeSubdomains[] = "include_subdomains";
|
| -const char kStsIncludeSubdomains[] = "sts_include_subdomains";
|
| -const char kPkpIncludeSubdomains[] = "pkp_include_subdomains";
|
| -const char kMode[] = "mode";
|
| -const char kExpiry[] = "expiry";
|
| -const char kDynamicSPKIHashesExpiry[] = "dynamic_spki_hashes_expiry";
|
| -const char kDynamicSPKIHashes[] = "dynamic_spki_hashes";
|
| -const char kForceHTTPS[] = "force-https";
|
| -const char kStrict[] = "strict";
|
| -const char kDefault[] = "default";
|
| -const char kPinningOnly[] = "pinning-only";
|
| -const char kCreated[] = "created";
|
| -const char kStsObserved[] = "sts_observed";
|
| -const char kPkpObserved[] = "pkp_observed";
|
| -
|
| -std::string LoadState(const base::FilePath& path) {
|
| - std::string result;
|
| - if (!base::ReadFileToString(path, &result)) {
|
| - return "";
|
| - }
|
| - return result;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -
|
| -namespace net {
|
| -
|
| -TransportSecurityPersister::TransportSecurityPersister(
|
| - TransportSecurityState* state,
|
| - const base::FilePath& profile_path,
|
| - const scoped_refptr<base::SequencedTaskRunner>& background_runner,
|
| - bool readonly)
|
| - : transport_security_state_(state),
|
| - writer_(profile_path.AppendASCII("TransportSecurity"), background_runner),
|
| - foreground_runner_(base::MessageLoop::current()->message_loop_proxy()),
|
| - background_runner_(background_runner),
|
| - readonly_(readonly),
|
| - weak_ptr_factory_(this) {
|
| - transport_security_state_->SetDelegate(this);
|
| -
|
| - base::PostTaskAndReplyWithResult(
|
| - background_runner_.get(),
|
| - FROM_HERE,
|
| - base::Bind(&::LoadState, writer_.path()),
|
| - base::Bind(&TransportSecurityPersister::CompleteLoad,
|
| - weak_ptr_factory_.GetWeakPtr()));
|
| -}
|
| -
|
| -TransportSecurityPersister::~TransportSecurityPersister() {
|
| - DCHECK(foreground_runner_->RunsTasksOnCurrentThread());
|
| -
|
| - if (writer_.HasPendingWrite())
|
| - writer_.DoScheduledWrite();
|
| -
|
| - transport_security_state_->SetDelegate(NULL);
|
| -}
|
| -
|
| -void TransportSecurityPersister::StateIsDirty(
|
| - TransportSecurityState* state) {
|
| - DCHECK(foreground_runner_->RunsTasksOnCurrentThread());
|
| - DCHECK_EQ(transport_security_state_, state);
|
| -
|
| - if (!readonly_)
|
| - writer_.ScheduleWrite(this);
|
| -}
|
| -
|
| -bool TransportSecurityPersister::SerializeData(std::string* output) {
|
| - DCHECK(foreground_runner_->RunsTasksOnCurrentThread());
|
| -
|
| - base::DictionaryValue toplevel;
|
| - base::Time now = base::Time::Now();
|
| - TransportSecurityState::Iterator state(*transport_security_state_);
|
| - for (; state.HasNext(); state.Advance()) {
|
| - const std::string& hostname = state.hostname();
|
| - const TransportSecurityState::DomainState& domain_state =
|
| - state.domain_state();
|
| -
|
| - base::DictionaryValue* serialized = new base::DictionaryValue;
|
| - serialized->SetBoolean(kStsIncludeSubdomains,
|
| - domain_state.sts.include_subdomains);
|
| - serialized->SetBoolean(kPkpIncludeSubdomains,
|
| - domain_state.pkp.include_subdomains);
|
| - serialized->SetDouble(kStsObserved,
|
| - domain_state.sts.last_observed.ToDoubleT());
|
| - serialized->SetDouble(kPkpObserved,
|
| - domain_state.pkp.last_observed.ToDoubleT());
|
| - serialized->SetDouble(kExpiry, domain_state.sts.expiry.ToDoubleT());
|
| - serialized->SetDouble(kDynamicSPKIHashesExpiry,
|
| - domain_state.pkp.expiry.ToDoubleT());
|
| -
|
| - switch (domain_state.sts.upgrade_mode) {
|
| - case TransportSecurityState::DomainState::MODE_FORCE_HTTPS:
|
| - serialized->SetString(kMode, kForceHTTPS);
|
| - break;
|
| - case TransportSecurityState::DomainState::MODE_DEFAULT:
|
| - serialized->SetString(kMode, kDefault);
|
| - break;
|
| - default:
|
| - NOTREACHED() << "DomainState with unknown mode";
|
| - delete serialized;
|
| - continue;
|
| - }
|
| -
|
| - if (now < domain_state.pkp.expiry) {
|
| - serialized->Set(kDynamicSPKIHashes,
|
| - SPKIHashesToListValue(domain_state.pkp.spki_hashes));
|
| - }
|
| -
|
| - toplevel.Set(HashedDomainToExternalString(hostname), serialized);
|
| - }
|
| -
|
| - base::JSONWriter::WriteWithOptions(&toplevel,
|
| - base::JSONWriter::OPTIONS_PRETTY_PRINT,
|
| - output);
|
| - return true;
|
| -}
|
| -
|
| -bool TransportSecurityPersister::LoadEntries(const std::string& serialized,
|
| - bool* dirty) {
|
| - DCHECK(foreground_runner_->RunsTasksOnCurrentThread());
|
| -
|
| - transport_security_state_->ClearDynamicData();
|
| - return Deserialize(serialized, dirty, transport_security_state_);
|
| -}
|
| -
|
| -// static
|
| -bool TransportSecurityPersister::Deserialize(const std::string& serialized,
|
| - bool* dirty,
|
| - TransportSecurityState* state) {
|
| - scoped_ptr<base::Value> value(base::JSONReader::Read(serialized));
|
| - base::DictionaryValue* dict_value = NULL;
|
| - if (!value.get() || !value->GetAsDictionary(&dict_value))
|
| - return false;
|
| -
|
| - const base::Time current_time(base::Time::Now());
|
| - bool dirtied = false;
|
| -
|
| - for (base::DictionaryValue::Iterator i(*dict_value);
|
| - !i.IsAtEnd(); i.Advance()) {
|
| - const base::DictionaryValue* parsed = NULL;
|
| - if (!i.value().GetAsDictionary(&parsed)) {
|
| - LOG(WARNING) << "Could not parse entry " << i.key() << "; skipping entry";
|
| - continue;
|
| - }
|
| -
|
| - TransportSecurityState::DomainState domain_state;
|
| -
|
| - // kIncludeSubdomains is a legacy synonym for kStsIncludeSubdomains and
|
| - // kPkpIncludeSubdomains. Parse at least one of these properties,
|
| - // preferably the new ones.
|
| - bool include_subdomains = false;
|
| - bool parsed_include_subdomains = parsed->GetBoolean(kIncludeSubdomains,
|
| - &include_subdomains);
|
| - domain_state.sts.include_subdomains = include_subdomains;
|
| - domain_state.pkp.include_subdomains = include_subdomains;
|
| - if (parsed->GetBoolean(kStsIncludeSubdomains, &include_subdomains)) {
|
| - domain_state.sts.include_subdomains = include_subdomains;
|
| - parsed_include_subdomains = true;
|
| - }
|
| - if (parsed->GetBoolean(kPkpIncludeSubdomains, &include_subdomains)) {
|
| - domain_state.pkp.include_subdomains = include_subdomains;
|
| - parsed_include_subdomains = true;
|
| - }
|
| -
|
| - std::string mode_string;
|
| - double expiry = 0;
|
| - if (!parsed_include_subdomains ||
|
| - !parsed->GetString(kMode, &mode_string) ||
|
| - !parsed->GetDouble(kExpiry, &expiry)) {
|
| - LOG(WARNING) << "Could not parse some elements of entry " << i.key()
|
| - << "; skipping entry";
|
| - continue;
|
| - }
|
| -
|
| - // Don't fail if this key is not present.
|
| - double dynamic_spki_hashes_expiry = 0;
|
| - parsed->GetDouble(kDynamicSPKIHashesExpiry,
|
| - &dynamic_spki_hashes_expiry);
|
| -
|
| - const base::ListValue* pins_list = NULL;
|
| - if (parsed->GetList(kDynamicSPKIHashes, &pins_list)) {
|
| - SPKIHashesFromListValue(*pins_list, &domain_state.pkp.spki_hashes);
|
| - }
|
| -
|
| - if (mode_string == kForceHTTPS || mode_string == kStrict) {
|
| - domain_state.sts.upgrade_mode =
|
| - TransportSecurityState::DomainState::MODE_FORCE_HTTPS;
|
| - } else if (mode_string == kDefault || mode_string == kPinningOnly) {
|
| - domain_state.sts.upgrade_mode =
|
| - TransportSecurityState::DomainState::MODE_DEFAULT;
|
| - } else {
|
| - LOG(WARNING) << "Unknown TransportSecurityState mode string "
|
| - << mode_string << " found for entry " << i.key()
|
| - << "; skipping entry";
|
| - continue;
|
| - }
|
| -
|
| - domain_state.sts.expiry = base::Time::FromDoubleT(expiry);
|
| - domain_state.pkp.expiry =
|
| - base::Time::FromDoubleT(dynamic_spki_hashes_expiry);
|
| -
|
| - double sts_observed;
|
| - double pkp_observed;
|
| - if (parsed->GetDouble(kStsObserved, &sts_observed)) {
|
| - domain_state.sts.last_observed = base::Time::FromDoubleT(sts_observed);
|
| - } else if (parsed->GetDouble(kCreated, &sts_observed)) {
|
| - // kCreated is a legacy synonym for both kStsObserved and kPkpObserved.
|
| - domain_state.sts.last_observed = base::Time::FromDoubleT(sts_observed);
|
| - } else {
|
| - // We're migrating an old entry with no observation date. Make sure we
|
| - // write the new date back in a reasonable time frame.
|
| - dirtied = true;
|
| - domain_state.sts.last_observed = base::Time::Now();
|
| - }
|
| - if (parsed->GetDouble(kPkpObserved, &pkp_observed)) {
|
| - domain_state.pkp.last_observed = base::Time::FromDoubleT(pkp_observed);
|
| - } else if (parsed->GetDouble(kCreated, &pkp_observed)) {
|
| - domain_state.pkp.last_observed = base::Time::FromDoubleT(pkp_observed);
|
| - } else {
|
| - dirtied = true;
|
| - domain_state.pkp.last_observed = base::Time::Now();
|
| - }
|
| -
|
| - if (domain_state.sts.expiry <= current_time &&
|
| - domain_state.pkp.expiry <= current_time) {
|
| - // Make sure we dirty the state if we drop an entry.
|
| - dirtied = true;
|
| - continue;
|
| - }
|
| -
|
| - std::string hashed = ExternalStringToHashedDomain(i.key());
|
| - if (hashed.empty()) {
|
| - dirtied = true;
|
| - continue;
|
| - }
|
| -
|
| - state->AddOrUpdateEnabledHosts(hashed, domain_state);
|
| - }
|
| -
|
| - *dirty = dirtied;
|
| - return true;
|
| -}
|
| -
|
| -void TransportSecurityPersister::CompleteLoad(const std::string& state) {
|
| - DCHECK(foreground_runner_->RunsTasksOnCurrentThread());
|
| -
|
| - if (state.empty())
|
| - return;
|
| -
|
| - bool dirty = false;
|
| - if (!LoadEntries(state, &dirty)) {
|
| - LOG(ERROR) << "Failed to deserialize state: " << state;
|
| - return;
|
| - }
|
| - if (dirty)
|
| - StateIsDirty(transport_security_state_);
|
| -}
|
| -
|
| -} // namespace net
|
|
|