// Copyright (c) 2011 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 "base/message_loop.h" #include "base/threading/thread.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/io_thread.h" #include "chrome/browser/net/ssl_config_service_manager.h" #include "chrome/browser/prefs/pref_member.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/common/pref_names.h" #include "content/common/notification_details.h" #include "content/common/notification_source.h" #include "content/common/notification_type.h" #include "net/base/ssl_config_service.h" //////////////////////////////////////////////////////////////////////////////// // 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: SSLConfigServicePref() {} virtual ~SSLConfigServicePref() {} // Store SSL config settings in |config|. Must only be called from IO thread. virtual void GetSSLConfig(net::SSLConfig* config); private: // Allow the pref watcher to update our internal state. friend class SSLConfigServiceManagerPref; // 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_; DISALLOW_COPY_AND_ASSIGN(SSLConfigServicePref); }; void SSLConfigServicePref::GetSSLConfig(net::SSLConfig* config) { *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 SSLConfigServiceManager, public NotificationObserver { public: SSLConfigServiceManagerPref(PrefService* user_prefs, PrefService* local_state); virtual ~SSLConfigServiceManagerPref() {} virtual net::SSLConfigService* Get(); private: // Register user_prefs and local_state SSL preferences. static void RegisterPrefs(PrefService* prefs); // Copy pref values to local_state from user_prefs if local_state doesn't have // the pref value and user_prefs has the pref value. Remove them from // user_prefs. static void MigrateUserPrefs(PrefService* local_state, PrefService* user_prefs); // Callback for preference changes. This will post the changes to the IO // thread with SetNewSSLConfig. virtual void Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details); // Store SSL config settings in |config|, directly from the preferences. Must // only be called from UI thread. void GetSSLConfigFromPrefs(net::SSLConfig* config); // The prefs (should only be accessed from UI thread) BooleanPrefMember rev_checking_enabled_; BooleanPrefMember ssl3_enabled_; BooleanPrefMember tls1_enabled_; scoped_refptr<SSLConfigServicePref> ssl_config_service_; DISALLOW_COPY_AND_ASSIGN(SSLConfigServiceManagerPref); }; SSLConfigServiceManagerPref::SSLConfigServiceManagerPref( PrefService* user_prefs, PrefService* local_state) : ssl_config_service_(new SSLConfigServicePref()) { DCHECK(user_prefs); DCHECK(local_state); RegisterPrefs(user_prefs); RegisterPrefs(local_state); // TODO(rtenneti): remove migration code after 6 months. MigrateUserPrefs(local_state, user_prefs); rev_checking_enabled_.Init(prefs::kCertRevocationCheckingEnabled, local_state, this); ssl3_enabled_.Init(prefs::kSSL3Enabled, local_state, this); tls1_enabled_.Init(prefs::kTLS1Enabled, local_state, this); // 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(PrefService* prefs) { net::SSLConfig default_config; if (!prefs->FindPreference(prefs::kCertRevocationCheckingEnabled)) { prefs->RegisterBooleanPref(prefs::kCertRevocationCheckingEnabled, default_config.rev_checking_enabled); } if (!prefs->FindPreference(prefs::kSSL3Enabled)) { prefs->RegisterBooleanPref(prefs::kSSL3Enabled, default_config.ssl3_enabled); } if (!prefs->FindPreference(prefs::kTLS1Enabled)) { prefs->RegisterBooleanPref(prefs::kTLS1Enabled, default_config.tls1_enabled); } } // static void SSLConfigServiceManagerPref::MigrateUserPrefs(PrefService* local_state, PrefService* user_prefs) { if (user_prefs->HasPrefPath(prefs::kCertRevocationCheckingEnabled)) { if (!local_state->HasPrefPath(prefs::kCertRevocationCheckingEnabled)) { // Migrate the kCertRevocationCheckingEnabled preference. local_state->SetBoolean(prefs::kCertRevocationCheckingEnabled, user_prefs->GetBoolean(prefs::kCertRevocationCheckingEnabled)); } user_prefs->ClearPref(prefs::kCertRevocationCheckingEnabled); } if (user_prefs->HasPrefPath(prefs::kSSL3Enabled)) { if (!local_state->HasPrefPath(prefs::kSSL3Enabled)) { // Migrate the kSSL3Enabled preference. local_state->SetBoolean(prefs::kSSL3Enabled, user_prefs->GetBoolean(prefs::kSSL3Enabled)); } user_prefs->ClearPref(prefs::kSSL3Enabled); } if (user_prefs->HasPrefPath(prefs::kTLS1Enabled)) { if (!local_state->HasPrefPath(prefs::kTLS1Enabled)) { // Migrate the kTLS1Enabled preference. local_state->SetBoolean(prefs::kTLS1Enabled, user_prefs->GetBoolean(prefs::kTLS1Enabled)); } user_prefs->ClearPref(prefs::kTLS1Enabled); } } net::SSLConfigService* SSLConfigServiceManagerPref::Get() { return ssl_config_service_; } void SSLConfigServiceManagerPref::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { base::Thread* io_thread = g_browser_process->io_thread(); if (io_thread) { net::SSLConfig new_config; GetSSLConfigFromPrefs(&new_config); // Post a task to |io_loop| with the new configuration, so it can // update |cached_config_|. io_thread->message_loop()->PostTask( FROM_HERE, NewRunnableMethod( ssl_config_service_.get(), &SSLConfigServicePref::SetNewSSLConfig, new_config)); } } void SSLConfigServiceManagerPref::GetSSLConfigFromPrefs( net::SSLConfig* config) { config->rev_checking_enabled = rev_checking_enabled_.GetValue(); config->ssl3_enabled = ssl3_enabled_.GetValue(); config->tls1_enabled = tls1_enabled_.GetValue(); SSLConfigServicePref::SetSSLConfigFlags(config); } //////////////////////////////////////////////////////////////////////////////// // SSLConfigServiceManager // static SSLConfigServiceManager* SSLConfigServiceManager::CreateDefaultManager( PrefService* user_prefs, PrefService* local_state) { return new SSLConfigServiceManagerPref(user_prefs, local_state); }