blob: 41b8981cdd3db45e672a67ced80d1f56fed4d945 [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 "chrome/browser/ssl/ssl_config_service_manager.h"
#include <stdint.h>
#include <algorithm>
#include <string>
#include <vector>
#include "base/bind.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/metrics/field_trial_params.h"
#include "base/strings/string_util.h"
#include "base/values.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.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 "mojo/public/cpp/bindings/interface_ptr_set.h"
#include "net/cert/cert_verifier.h"
#include "net/ssl/ssl_cipher_suite_names.h"
#include "net/ssl/ssl_config_service.h"
#include "url/url_canon.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;
}
// Writes the SSL protocol version represented by a string to |version|. Returns
// false if the string is not recognized.
bool SSLProtocolVersionFromString(const std::string& version_str,
network::mojom::SSLVersion* version) {
if (version_str == switches::kSSLVersionTLSv1) {
*version = network::mojom::SSLVersion::kTLS1;
return true;
}
if (version_str == switches::kSSLVersionTLSv11) {
*version = network::mojom::SSLVersion::kTLS11;
return true;
}
if (version_str == switches::kSSLVersionTLSv12) {
*version = network::mojom::SSLVersion::kTLS12;
return true;
}
if (version_str == switches::kSSLVersionTLSv13) {
*version = network::mojom::SSLVersion::kTLS13;
return true;
}
return false;
}
// Given a vector of hostname patterns |patterns|, returns a vector containing
// the canonical form. Any entries which cannot be parsed are skipped.
std::vector<std::string> CanonicalizeHostnamePatterns(
const std::vector<std::string>& patterns) {
std::vector<std::string> out;
out.reserve(patterns.size());
for (base::StringPiece pattern : patterns) {
std::string canon_pattern;
url::Component canon_component;
url::StdStringCanonOutput canon_output(&canon_pattern);
if (!url::CanonicalizeHost(pattern.data(),
url::Component(0, pattern.size()), &canon_output,
&canon_component)) {
continue;
}
canon_output.Complete();
out.push_back(canon_pattern);
}
return out;
}
const char kTLS13VariantExperimentName[] = "TLS13Variant";
////////////////////////////////////////////////////////////////////////////////
// SSLConfigServiceManagerPref
// The manager for holding and updating one or more
// network::mojom::SSLConfigClients.
class SSLConfigServiceManagerPref : public SSLConfigServiceManager {
public:
explicit SSLConfigServiceManagerPref(PrefService* local_state);
~SSLConfigServiceManagerPref() override {}
// Register local_state SSL preferences.
static void RegisterPrefs(PrefRegistrySimple* registry);
void AddToNetworkContextParams(
network::mojom::NetworkContextParams* network_context_params) override;
void FlushForTesting() 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);
// Returns the current SSLConfig settings from preferences. Assumes
// |disabled_cipher_suites_| is up-to-date, but reads all other settings from
// live prefs.
network::mojom::SSLConfigPtr GetSSLConfigFromPrefs() const;
// 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.
BooleanPrefMember rev_checking_enabled_;
BooleanPrefMember rev_checking_required_local_anchors_;
BooleanPrefMember sha1_local_anchors_enabled_;
BooleanPrefMember symantec_legacy_infrastructure_enabled_;
StringPrefMember ssl_version_min_;
StringPrefMember ssl_version_max_;
StringPrefMember tls13_variant_;
StringListPrefMember h2_client_cert_coalescing_host_patterns_;
// The cached list of disabled SSL cipher suites.
std::vector<uint16_t> disabled_cipher_suites_;
mojo::InterfacePtrSet<network::mojom::SSLConfigClient> ssl_config_client_set_;
DISALLOW_COPY_AND_ASSIGN(SSLConfigServiceManagerPref);
};
SSLConfigServiceManagerPref::SSLConfigServiceManagerPref(
PrefService* local_state) {
DCHECK(local_state);
const std::string tls13_variant =
base::GetFieldTrialParamValue(kTLS13VariantExperimentName, "variant");
const char* tls13_value = nullptr;
const char* version_value = nullptr;
if (tls13_variant == "disabled") {
tls13_value = switches::kTLS13VariantDisabled;
} else if (tls13_variant == "draft23") {
tls13_value = switches::kTLS13VariantDraft23;
version_value = switches::kSSLVersionTLSv13;
} else if (tls13_variant == "draft28") {
tls13_value = switches::kTLS13VariantDraft28;
version_value = switches::kSSLVersionTLSv13;
} else if (tls13_variant == "final") {
tls13_value = switches::kTLS13VariantFinal;
version_value = switches::kSSLVersionTLSv13;
}
if (tls13_value) {
local_state->SetDefaultPrefValue(prefs::kTLS13Variant,
base::Value(tls13_value));
}
if (version_value) {
local_state->SetDefaultPrefValue(prefs::kSSLVersionMax,
base::Value(version_value));
}
PrefChangeRegistrar::NamedChangeCallback local_state_callback =
base::BindRepeating(&SSLConfigServiceManagerPref::OnPreferenceChanged,
base::Unretained(this), local_state);
rev_checking_enabled_.Init(prefs::kCertRevocationCheckingEnabled, local_state,
local_state_callback);
rev_checking_required_local_anchors_.Init(
prefs::kCertRevocationCheckingRequiredLocalAnchors, local_state,
local_state_callback);
sha1_local_anchors_enabled_.Init(prefs::kCertEnableSha1LocalAnchors,
local_state, local_state_callback);
symantec_legacy_infrastructure_enabled_.Init(
prefs::kCertEnableSymantecLegacyInfrastructure, local_state,
local_state_callback);
ssl_version_min_.Init(prefs::kSSLVersionMin, local_state,
local_state_callback);
ssl_version_max_.Init(prefs::kSSLVersionMax, local_state,
local_state_callback);
tls13_variant_.Init(prefs::kTLS13Variant, local_state, local_state_callback);
h2_client_cert_coalescing_host_patterns_.Init(
prefs::kH2ClientCertCoalescingHosts, local_state, local_state_callback);
local_state_change_registrar_.Init(local_state);
local_state_change_registrar_.Add(prefs::kCipherSuiteBlacklist,
local_state_callback);
// Populate |disabled_cipher_suites_| with the initial pref value.
OnDisabledCipherSuitesChange(local_state);
}
// static
void SSLConfigServiceManagerPref::RegisterPrefs(PrefRegistrySimple* registry) {
net::SSLConfig default_config;
net::CertVerifier::Config default_verifier_config;
registry->RegisterBooleanPref(prefs::kCertRevocationCheckingEnabled,
default_verifier_config.enable_rev_checking);
registry->RegisterBooleanPref(
prefs::kCertRevocationCheckingRequiredLocalAnchors,
default_verifier_config.require_rev_checking_local_anchors);
registry->RegisterBooleanPref(
prefs::kCertEnableSha1LocalAnchors,
default_verifier_config.enable_sha1_local_anchors);
registry->RegisterBooleanPref(
prefs::kCertEnableSymantecLegacyInfrastructure,
default_verifier_config.disable_symantec_enforcement);
registry->RegisterStringPref(prefs::kSSLVersionMin, std::string());
registry->RegisterStringPref(prefs::kSSLVersionMax, std::string());
registry->RegisterStringPref(prefs::kTLS13Variant, std::string());
registry->RegisterListPref(prefs::kCipherSuiteBlacklist);
registry->RegisterListPref(prefs::kH2ClientCertCoalescingHosts);
}
void SSLConfigServiceManagerPref::AddToNetworkContextParams(
network::mojom::NetworkContextParams* network_context_params) {
network_context_params->initial_ssl_config = GetSSLConfigFromPrefs();
network::mojom::SSLConfigClientPtr ssl_config_client;
network_context_params->ssl_config_client_request =
mojo::MakeRequest(&ssl_config_client);
ssl_config_client_set_.AddPtr(std::move(ssl_config_client));
}
void SSLConfigServiceManagerPref::FlushForTesting() {
ssl_config_client_set_.FlushForTesting();
}
void SSLConfigServiceManagerPref::OnPreferenceChanged(
PrefService* prefs,
const std::string& pref_name_in) {
DCHECK(prefs);
if (pref_name_in == prefs::kCipherSuiteBlacklist)
OnDisabledCipherSuitesChange(prefs);
network::mojom::SSLConfigPtr new_config = GetSSLConfigFromPrefs();
network::mojom::SSLConfig* raw_config = new_config.get();
ssl_config_client_set_.ForAllPtrs(
[raw_config](network::mojom::SSLConfigClient* client) {
// Mojo calls consume all InterfacePtrs passed to them, so have to
// clone the config for each call.
client->OnSSLConfigUpdated(raw_config->Clone());
});
}
network::mojom::SSLConfigPtr
SSLConfigServiceManagerPref::GetSSLConfigFromPrefs() const {
network::mojom::SSLConfigPtr config = network::mojom::SSLConfig::New();
// 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();
config->symantec_enforcement_disabled =
symantec_legacy_infrastructure_enabled_.GetValue();
std::string version_min_str = ssl_version_min_.GetValue();
std::string version_max_str = ssl_version_max_.GetValue();
std::string tls13_variant_str = tls13_variant_.GetValue();
network::mojom::SSLVersion version_min;
if (SSLProtocolVersionFromString(version_min_str, &version_min))
config->version_min = version_min;
network::mojom::SSLVersion version_max;
if (SSLProtocolVersionFromString(version_max_str, &version_max) &&
version_max >= network::mojom::SSLVersion::kTLS12) {
config->version_max = version_max;
}
if (tls13_variant_str == switches::kTLS13VariantDisabled) {
if (config->version_max > network::mojom::SSLVersion::kTLS12)
config->version_max = network::mojom::SSLVersion::kTLS12;
} else if (tls13_variant_str == switches::kTLS13VariantDraft23) {
config->tls13_variant = network::mojom::TLS13Variant::kDraft23;
} else if (tls13_variant_str == switches::kTLS13VariantDraft28) {
config->tls13_variant = network::mojom::TLS13Variant::kDraft28;
} else if (tls13_variant_str == switches::kTLS13VariantFinal) {
config->tls13_variant = network::mojom::TLS13Variant::kFinal;
}
config->disabled_cipher_suites = disabled_cipher_suites_;
config->client_cert_pooling_policy = CanonicalizeHostnamePatterns(
h2_client_cert_coalescing_host_patterns_.GetValue());
return config;
}
void SSLConfigServiceManagerPref::OnDisabledCipherSuitesChange(
PrefService* local_state) {
const base::ListValue* value =
local_state->GetList(prefs::kCipherSuiteBlacklist);
disabled_cipher_suites_ = ParseCipherSuites(ListValueToStringVector(value));
}
} // namespace
////////////////////////////////////////////////////////////////////////////////
// SSLConfigServiceManager
// static
SSLConfigServiceManager* SSLConfigServiceManager::CreateDefaultManager(
PrefService* local_state) {
return new SSLConfigServiceManagerPref(local_state);
}
// static
void SSLConfigServiceManager::RegisterPrefs(PrefRegistrySimple* registry) {
SSLConfigServiceManagerPref::RegisterPrefs(registry);
}