// 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 #include #include #include #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 ListValueToStringVector(const base::ListValue* value) { std::vector 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 ParseCipherSuites( const std::vector& cipher_strings) { std::vector cipher_suites; cipher_suites.reserve(cipher_strings.size()); for (std::vector::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; } return version; } const base::Feature kSSLVersionFallbackTLSv11 { "SSLVersionFallbackTLSv1.1", 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& 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 io_task_runner_; DISALLOW_COPY_AND_ASSIGN(SSLConfigServicePref); }; SSLConfigServicePref::SSLConfigServicePref( const scoped_refptr& 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& 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_; StringPrefMember ssl_version_min_; StringPrefMember ssl_version_max_; StringPrefMember ssl_version_fallback_min_; BooleanPrefMember rc4_enabled_; // The cached list of disabled SSL cipher suites. std::vector disabled_cipher_suites_; scoped_refptr ssl_config_service_; scoped_refptr io_task_runner_; DISALLOW_COPY_AND_ASSIGN(SSLConfigServiceManagerPref); }; SSLConfigServiceManagerPref::SSLConfigServiceManagerPref( PrefService* local_state, const scoped_refptr& io_task_runner) : ssl_config_service_(new SSLConfigServicePref(io_task_runner)), io_task_runner_(io_task_runner) { DCHECK(local_state); // Restore the TLS 1.1 fallback leg if enabled via features. // TODO(davidben): Remove this when the fallback removal has succeeded. // https://crbug.com/536200. if (base::FeatureList::IsEnabled(kSSLVersionFallbackTLSv11)) { local_state->SetDefaultPrefValue( ssl_config::prefs::kSSLVersionFallbackMin, new base::StringValue(switches::kSSLVersionTLSv11)); } 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); 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); ssl_version_fallback_min_.Init(ssl_config::prefs::kSSLVersionFallbackMin, local_state, local_state_callback); rc4_enabled_.Init(ssl_config::prefs::kRC4Enabled, 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->RegisterStringPref(ssl_config::prefs::kSSLVersionMin, std::string()); registry->RegisterStringPref(ssl_config::prefs::kSSLVersionMax, std::string()); registry->RegisterStringPref(ssl_config::prefs::kSSLVersionFallbackMin, std::string()); registry->RegisterListPref(ssl_config::prefs::kCipherSuiteBlacklist); registry->RegisterBooleanPref(ssl_config::prefs::kRC4Enabled, default_config.rc4_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_.get(), 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(); std::string version_min_str = ssl_version_min_.GetValue(); std::string version_max_str = ssl_version_max_.GetValue(); std::string version_fallback_min_str = ssl_version_fallback_min_.GetValue(); config->version_min = net::kDefaultSSLVersionMin; config->version_max = net::kDefaultSSLVersionMax; config->version_fallback_min = net::kDefaultSSLVersionFallbackMin; uint16_t version_min = SSLProtocolVersionFromString(version_min_str); uint16_t version_max = SSLProtocolVersionFromString(version_max_str); uint16_t version_fallback_min = SSLProtocolVersionFromString(version_fallback_min_str); if (version_min) { config->version_min = version_min; } if (version_max) { uint16_t supported_version_max = config->version_max; config->version_max = std::min(supported_version_max, version_max); } // Values below TLS 1.1 are invalid. if (version_fallback_min && version_fallback_min >= net::SSL_PROTOCOL_VERSION_TLS1_1) { config->version_fallback_min = version_fallback_min; } config->disabled_cipher_suites = disabled_cipher_suites_; config->rc4_enabled = rc4_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& io_task_runner) { return new SSLConfigServiceManagerPref(local_state, io_task_runner); } // static void SSLConfigServiceManager::RegisterPrefs(PrefRegistrySimple* registry) { SSLConfigServiceManagerPref::RegisterPrefs(registry); } } // namespace ssl_config