blob: 46a26c575b8241ef91645f040c273ce1db62ac36 [file] [log] [blame]
// 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 "components/ssl_config/ssl_config_service_manager.h"
#include <stdint.h>
#include <algorithm>
#include <string>
#include <vector>
#include "base/bind.h"
#include "base/feature_list.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_util.h"
#include "base/values.h"
#include "components/content_settings/core/browser/content_settings_utils.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_member.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/ssl_config/ssl_config_prefs.h"
#include "components/ssl_config/ssl_config_switches.h"
#include "net/ssl/ssl_cipher_suite_names.h"
#include "net/ssl/ssl_config_service.h"
namespace base {
class SingleThreadTaskRunner;
}
namespace {
// Converts a ListValue of StringValues into a vector of strings. Any Values
// which cannot be converted will be skipped.
std::vector<std::string> ListValueToStringVector(const base::ListValue* value) {
std::vector<std::string> results;
results.reserve(value->GetSize());
std::string s;
for (base::ListValue::const_iterator it = value->begin(); it != value->end();
++it) {
if (!(*it)->GetAsString(&s))
continue;
results.push_back(s);
}
return results;
}
// Parses a vector of cipher suite strings, returning a sorted vector
// containing the underlying SSL/TLS cipher suites. Unrecognized/invalid
// cipher suites will be ignored.
std::vector<uint16_t> ParseCipherSuites(
const std::vector<std::string>& cipher_strings) {
std::vector<uint16_t> cipher_suites;
cipher_suites.reserve(cipher_strings.size());
for (std::vector<std::string>::const_iterator it = cipher_strings.begin();
it != cipher_strings.end(); ++it) {
uint16_t cipher_suite = 0;
if (!net::ParseSSLCipherString(*it, &cipher_suite)) {
LOG(ERROR) << "Ignoring unrecognized or unparsable cipher suite: " << *it;
continue;
}
cipher_suites.push_back(cipher_suite);
}
std::sort(cipher_suites.begin(), cipher_suites.end());
return cipher_suites;
}
// Returns the SSL protocol version (as a uint16_t) represented by a string.
// Returns 0 if the string is invalid.
uint16_t SSLProtocolVersionFromString(const std::string& version_str) {
uint16_t version = 0; // Invalid.
if (version_str == switches::kSSLVersionTLSv1) {
version = net::SSL_PROTOCOL_VERSION_TLS1;
} else if (version_str == switches::kSSLVersionTLSv11) {
version = net::SSL_PROTOCOL_VERSION_TLS1_1;
} else if (version_str == switches::kSSLVersionTLSv12) {
version = net::SSL_PROTOCOL_VERSION_TLS1_2;
} else if (version_str == switches::kSSLVersionTLSv13) {
version = net::SSL_PROTOCOL_VERSION_TLS1_3;
}
return version;
}
} // namespace
////////////////////////////////////////////////////////////////////////////////
// SSLConfigServicePref
// An SSLConfigService which stores a cached version of the current SSLConfig
// prefs, which are updated by SSLConfigServiceManagerPref when the prefs
// change.
class SSLConfigServicePref : public net::SSLConfigService {
public:
explicit SSLConfigServicePref(
const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
// Store SSL config settings in |config|. Must only be called from IO thread.
void GetSSLConfig(net::SSLConfig* config) override;
private:
// Allow the pref watcher to update our internal state.
friend class SSLConfigServiceManagerPref;
~SSLConfigServicePref() override {}
// This method is posted to the IO thread from the browser thread to carry the
// new config information.
void SetNewSSLConfig(const net::SSLConfig& new_config);
// Cached value of prefs, should only be accessed from IO thread.
net::SSLConfig cached_config_;
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
DISALLOW_COPY_AND_ASSIGN(SSLConfigServicePref);
};
SSLConfigServicePref::SSLConfigServicePref(
const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
: io_task_runner_(io_task_runner) {}
void SSLConfigServicePref::GetSSLConfig(net::SSLConfig* config) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
*config = cached_config_;
}
void SSLConfigServicePref::SetNewSSLConfig(const net::SSLConfig& new_config) {
net::SSLConfig orig_config = cached_config_;
cached_config_ = new_config;
ProcessConfigUpdate(orig_config, new_config);
}
////////////////////////////////////////////////////////////////////////////////
// SSLConfigServiceManagerPref
// The manager for holding and updating an SSLConfigServicePref instance.
class SSLConfigServiceManagerPref : public ssl_config::SSLConfigServiceManager {
public:
SSLConfigServiceManagerPref(
PrefService* local_state,
const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
~SSLConfigServiceManagerPref() override {}
// Register local_state SSL preferences.
static void RegisterPrefs(PrefRegistrySimple* registry);
net::SSLConfigService* Get() override;
private:
// Callback for preference changes. This will post the changes to the IO
// thread with SetNewSSLConfig.
void OnPreferenceChanged(PrefService* prefs, const std::string& pref_name);
// Store SSL config settings in |config|, directly from the preferences. Must
// only be called from UI thread.
void GetSSLConfigFromPrefs(net::SSLConfig* config);
// Processes changes to the disabled cipher suites preference, updating the
// cached list of parsed SSL/TLS cipher suites that are disabled.
void OnDisabledCipherSuitesChange(PrefService* local_state);
PrefChangeRegistrar local_state_change_registrar_;
// The local_state prefs (should only be accessed from UI thread)
BooleanPrefMember rev_checking_enabled_;
BooleanPrefMember rev_checking_required_local_anchors_;
BooleanPrefMember sha1_local_anchors_enabled_;
StringPrefMember ssl_version_min_;
StringPrefMember ssl_version_max_;
BooleanPrefMember dhe_enabled_;
// The cached list of disabled SSL cipher suites.
std::vector<uint16_t> disabled_cipher_suites_;
scoped_refptr<SSLConfigServicePref> ssl_config_service_;
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
DISALLOW_COPY_AND_ASSIGN(SSLConfigServiceManagerPref);
};
SSLConfigServiceManagerPref::SSLConfigServiceManagerPref(
PrefService* local_state,
const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
: ssl_config_service_(new SSLConfigServicePref(io_task_runner)),
io_task_runner_(io_task_runner) {
DCHECK(local_state);
PrefChangeRegistrar::NamedChangeCallback local_state_callback =
base::Bind(&SSLConfigServiceManagerPref::OnPreferenceChanged,
base::Unretained(this), local_state);
rev_checking_enabled_.Init(ssl_config::prefs::kCertRevocationCheckingEnabled,
local_state, local_state_callback);
rev_checking_required_local_anchors_.Init(
ssl_config::prefs::kCertRevocationCheckingRequiredLocalAnchors,
local_state, local_state_callback);
sha1_local_anchors_enabled_.Init(
ssl_config::prefs::kCertEnableSha1LocalAnchors, local_state,
local_state_callback);
ssl_version_min_.Init(ssl_config::prefs::kSSLVersionMin, local_state,
local_state_callback);
ssl_version_max_.Init(ssl_config::prefs::kSSLVersionMax, local_state,
local_state_callback);
dhe_enabled_.Init(ssl_config::prefs::kDHEEnabled, local_state,
local_state_callback);
local_state_change_registrar_.Init(local_state);
local_state_change_registrar_.Add(ssl_config::prefs::kCipherSuiteBlacklist,
local_state_callback);
OnDisabledCipherSuitesChange(local_state);
// Initialize from UI thread. This is okay as there shouldn't be anything on
// the IO thread trying to access it yet.
GetSSLConfigFromPrefs(&ssl_config_service_->cached_config_);
}
// static
void SSLConfigServiceManagerPref::RegisterPrefs(PrefRegistrySimple* registry) {
net::SSLConfig default_config;
registry->RegisterBooleanPref(
ssl_config::prefs::kCertRevocationCheckingEnabled,
default_config.rev_checking_enabled);
registry->RegisterBooleanPref(
ssl_config::prefs::kCertRevocationCheckingRequiredLocalAnchors,
default_config.rev_checking_required_local_anchors);
registry->RegisterBooleanPref(ssl_config::prefs::kCertEnableSha1LocalAnchors,
default_config.sha1_local_anchors_enabled);
registry->RegisterStringPref(ssl_config::prefs::kSSLVersionMin,
std::string());
registry->RegisterStringPref(ssl_config::prefs::kSSLVersionMax,
std::string());
registry->RegisterListPref(ssl_config::prefs::kCipherSuiteBlacklist);
registry->RegisterBooleanPref(ssl_config::prefs::kDHEEnabled,
default_config.dhe_enabled);
}
net::SSLConfigService* SSLConfigServiceManagerPref::Get() {
return ssl_config_service_.get();
}
void SSLConfigServiceManagerPref::OnPreferenceChanged(
PrefService* prefs,
const std::string& pref_name_in) {
DCHECK(prefs);
if (pref_name_in == ssl_config::prefs::kCipherSuiteBlacklist)
OnDisabledCipherSuitesChange(prefs);
net::SSLConfig new_config;
GetSSLConfigFromPrefs(&new_config);
// Post a task to |io_loop| with the new configuration, so it can
// update |cached_config_|.
io_task_runner_->PostTask(FROM_HERE,
base::Bind(&SSLConfigServicePref::SetNewSSLConfig,
ssl_config_service_, new_config));
}
void SSLConfigServiceManagerPref::GetSSLConfigFromPrefs(
net::SSLConfig* config) {
// rev_checking_enabled was formerly a user-settable preference, but now
// it is managed-only.
if (rev_checking_enabled_.IsManaged())
config->rev_checking_enabled = rev_checking_enabled_.GetValue();
else
config->rev_checking_enabled = false;
config->rev_checking_required_local_anchors =
rev_checking_required_local_anchors_.GetValue();
config->sha1_local_anchors_enabled = sha1_local_anchors_enabled_.GetValue();
std::string version_min_str = ssl_version_min_.GetValue();
std::string version_max_str = ssl_version_max_.GetValue();
config->version_min = net::kDefaultSSLVersionMin;
config->version_max = net::kDefaultSSLVersionMax;
uint16_t version_min = SSLProtocolVersionFromString(version_min_str);
uint16_t version_max = SSLProtocolVersionFromString(version_max_str);
if (version_min) {
config->version_min = version_min;
}
if (version_max) {
config->version_max = version_max;
}
config->disabled_cipher_suites = disabled_cipher_suites_;
config->dhe_enabled = dhe_enabled_.GetValue();
}
void SSLConfigServiceManagerPref::OnDisabledCipherSuitesChange(
PrefService* local_state) {
const base::ListValue* value =
local_state->GetList(ssl_config::prefs::kCipherSuiteBlacklist);
disabled_cipher_suites_ = ParseCipherSuites(ListValueToStringVector(value));
}
////////////////////////////////////////////////////////////////////////////////
// SSLConfigServiceManager
namespace ssl_config {
// static
SSLConfigServiceManager* SSLConfigServiceManager::CreateDefaultManager(
PrefService* local_state,
const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) {
return new SSLConfigServiceManagerPref(local_state, io_task_runner);
}
// static
void SSLConfigServiceManager::RegisterPrefs(PrefRegistrySimple* registry) {
SSLConfigServiceManagerPref::RegisterPrefs(registry);
}
} // namespace ssl_config