| // 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 kDHECiphersFeature{ |
| "DHECiphers", 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); |
| |
| // Restore DHE-based ciphers if enabled via features. |
| // TODO(davidben): Remove this when the removal has succeeded. |
| // https://crbug.com/619194. |
| if (base::FeatureList::IsEnabled(kDHECiphersFeature)) { |
| local_state->SetDefaultPrefValue(ssl_config::prefs::kDHEEnabled, |
| new base::FundamentalValue(true)); |
| } |
| |
| 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 |