1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/message_loop.h"
6#include "base/threading/thread.h"
7#include "chrome/browser/browser_process.h"
8#include "chrome/browser/io_thread.h"
9#include "chrome/browser/net/ssl_config_service_manager.h"
10#include "chrome/browser/prefs/pref_member.h"
11#include "chrome/browser/prefs/pref_service.h"
12#include "chrome/common/pref_names.h"
13#include "content/common/notification_details.h"
14#include "content/common/notification_source.h"
15#include "content/common/notification_type.h"
16#include "net/base/ssl_config_service.h"
17
18////////////////////////////////////////////////////////////////////////////////
19//  SSLConfigServicePref
20
21// An SSLConfigService which stores a cached version of the current SSLConfig
22// prefs, which are updated by SSLConfigServiceManagerPref when the prefs
23// change.
24class SSLConfigServicePref : public net::SSLConfigService {
25 public:
26  SSLConfigServicePref() {}
27  virtual ~SSLConfigServicePref() {}
28
29  // Store SSL config settings in |config|. Must only be called from IO thread.
30  virtual void GetSSLConfig(net::SSLConfig* config);
31
32 private:
33  // Allow the pref watcher to update our internal state.
34  friend class SSLConfigServiceManagerPref;
35
36  // This method is posted to the IO thread from the browser thread to carry the
37  // new config information.
38  void SetNewSSLConfig(const net::SSLConfig& new_config);
39
40  // Cached value of prefs, should only be accessed from IO thread.
41  net::SSLConfig cached_config_;
42
43  DISALLOW_COPY_AND_ASSIGN(SSLConfigServicePref);
44};
45
46void SSLConfigServicePref::GetSSLConfig(net::SSLConfig* config) {
47  *config = cached_config_;
48}
49
50void SSLConfigServicePref::SetNewSSLConfig(
51    const net::SSLConfig& new_config) {
52  net::SSLConfig orig_config = cached_config_;
53  cached_config_ = new_config;
54  ProcessConfigUpdate(orig_config, new_config);
55}
56
57////////////////////////////////////////////////////////////////////////////////
58//  SSLConfigServiceManagerPref
59
60// The manager for holding and updating an SSLConfigServicePref instance.
61class SSLConfigServiceManagerPref
62    : public SSLConfigServiceManager,
63      public NotificationObserver {
64 public:
65  SSLConfigServiceManagerPref(PrefService* user_prefs,
66                              PrefService* local_state);
67  virtual ~SSLConfigServiceManagerPref() {}
68
69  virtual net::SSLConfigService* Get();
70
71 private:
72  // Register user_prefs and local_state SSL preferences.
73  static void RegisterPrefs(PrefService* prefs);
74
75  // Copy pref values to local_state from user_prefs if local_state doesn't have
76  // the pref value and user_prefs has the pref value. Remove them from
77  // user_prefs.
78  static void MigrateUserPrefs(PrefService* local_state,
79                               PrefService* user_prefs);
80
81  // Callback for preference changes.  This will post the changes to the IO
82  // thread with SetNewSSLConfig.
83  virtual void Observe(NotificationType type,
84                       const NotificationSource& source,
85                       const NotificationDetails& details);
86
87  // Store SSL config settings in |config|, directly from the preferences. Must
88  // only be called from UI thread.
89  void GetSSLConfigFromPrefs(net::SSLConfig* config);
90
91  // The prefs (should only be accessed from UI thread)
92  BooleanPrefMember rev_checking_enabled_;
93  BooleanPrefMember ssl3_enabled_;
94  BooleanPrefMember tls1_enabled_;
95
96  scoped_refptr<SSLConfigServicePref> ssl_config_service_;
97
98  DISALLOW_COPY_AND_ASSIGN(SSLConfigServiceManagerPref);
99};
100
101SSLConfigServiceManagerPref::SSLConfigServiceManagerPref(
102    PrefService* user_prefs, PrefService* local_state)
103    : ssl_config_service_(new SSLConfigServicePref()) {
104  DCHECK(user_prefs);
105  DCHECK(local_state);
106
107  RegisterPrefs(user_prefs);
108  RegisterPrefs(local_state);
109
110  // TODO(rtenneti): remove migration code after 6 months.
111  MigrateUserPrefs(local_state, user_prefs);
112
113  rev_checking_enabled_.Init(prefs::kCertRevocationCheckingEnabled,
114                             local_state, this);
115  ssl3_enabled_.Init(prefs::kSSL3Enabled, local_state, this);
116  tls1_enabled_.Init(prefs::kTLS1Enabled, local_state, this);
117
118  // Initialize from UI thread.  This is okay as there shouldn't be anything on
119  // the IO thread trying to access it yet.
120  GetSSLConfigFromPrefs(&ssl_config_service_->cached_config_);
121}
122
123// static
124void SSLConfigServiceManagerPref::RegisterPrefs(PrefService* prefs) {
125  net::SSLConfig default_config;
126  if (!prefs->FindPreference(prefs::kCertRevocationCheckingEnabled)) {
127    prefs->RegisterBooleanPref(prefs::kCertRevocationCheckingEnabled,
128                               default_config.rev_checking_enabled);
129  }
130  if (!prefs->FindPreference(prefs::kSSL3Enabled)) {
131    prefs->RegisterBooleanPref(prefs::kSSL3Enabled,
132                               default_config.ssl3_enabled);
133  }
134  if (!prefs->FindPreference(prefs::kTLS1Enabled)) {
135    prefs->RegisterBooleanPref(prefs::kTLS1Enabled,
136                               default_config.tls1_enabled);
137  }
138}
139
140// static
141void SSLConfigServiceManagerPref::MigrateUserPrefs(PrefService* local_state,
142                                                   PrefService* user_prefs) {
143  if (user_prefs->HasPrefPath(prefs::kCertRevocationCheckingEnabled)) {
144    if (!local_state->HasPrefPath(prefs::kCertRevocationCheckingEnabled)) {
145      // Migrate the kCertRevocationCheckingEnabled preference.
146      local_state->SetBoolean(prefs::kCertRevocationCheckingEnabled,
147          user_prefs->GetBoolean(prefs::kCertRevocationCheckingEnabled));
148    }
149    user_prefs->ClearPref(prefs::kCertRevocationCheckingEnabled);
150  }
151  if (user_prefs->HasPrefPath(prefs::kSSL3Enabled)) {
152    if (!local_state->HasPrefPath(prefs::kSSL3Enabled)) {
153      // Migrate the kSSL3Enabled preference.
154      local_state->SetBoolean(prefs::kSSL3Enabled,
155          user_prefs->GetBoolean(prefs::kSSL3Enabled));
156    }
157    user_prefs->ClearPref(prefs::kSSL3Enabled);
158  }
159  if (user_prefs->HasPrefPath(prefs::kTLS1Enabled)) {
160    if (!local_state->HasPrefPath(prefs::kTLS1Enabled)) {
161      // Migrate the kTLS1Enabled preference.
162      local_state->SetBoolean(prefs::kTLS1Enabled,
163          user_prefs->GetBoolean(prefs::kTLS1Enabled));
164    }
165    user_prefs->ClearPref(prefs::kTLS1Enabled);
166  }
167}
168
169net::SSLConfigService* SSLConfigServiceManagerPref::Get() {
170  return ssl_config_service_;
171}
172
173void SSLConfigServiceManagerPref::Observe(NotificationType type,
174                                          const NotificationSource& source,
175                                          const NotificationDetails& details) {
176  base::Thread* io_thread = g_browser_process->io_thread();
177  if (io_thread) {
178    net::SSLConfig new_config;
179    GetSSLConfigFromPrefs(&new_config);
180
181    // Post a task to |io_loop| with the new configuration, so it can
182    // update |cached_config_|.
183    io_thread->message_loop()->PostTask(
184        FROM_HERE,
185        NewRunnableMethod(
186            ssl_config_service_.get(),
187            &SSLConfigServicePref::SetNewSSLConfig,
188            new_config));
189  }
190}
191
192void SSLConfigServiceManagerPref::GetSSLConfigFromPrefs(
193    net::SSLConfig* config) {
194  config->rev_checking_enabled = rev_checking_enabled_.GetValue();
195  config->ssl3_enabled = ssl3_enabled_.GetValue();
196  config->tls1_enabled = tls1_enabled_.GetValue();
197  SSLConfigServicePref::SetSSLConfigFlags(config);
198}
199
200////////////////////////////////////////////////////////////////////////////////
201//  SSLConfigServiceManager
202
203// static
204SSLConfigServiceManager* SSLConfigServiceManager::CreateDefaultManager(
205    PrefService* user_prefs,
206    PrefService* local_state) {
207  return new SSLConfigServiceManagerPref(user_prefs, local_state);
208}
209