|  | // 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; | 
|  | } | 
|  |  | 
|  | const base::Feature kTLS13Feature{ | 
|  | "NegotiateTLS13", base::FEATURE_DISABLED_BY_DEFAULT, | 
|  | }; | 
|  |  | 
|  | }  // 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); | 
|  |  | 
|  | if (base::FeatureList::IsEnabled(kTLS13Feature)) { | 
|  | local_state->SetDefaultPrefValue( | 
|  | ssl_config::prefs::kSSLVersionMax, | 
|  | new base::StringValue(switches::kSSLVersionTLSv13)); | 
|  | } | 
|  |  | 
|  | 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, | 
|  | false); | 
|  | 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 |