summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/net/ssl_config_service_manager_pref.cc79
-rw-r--r--chrome/browser/net/ssl_config_service_manager_pref_unittest.cc112
-rw-r--r--chrome/browser/prefs/browser_prefs.cc1
-rw-r--r--chrome/browser/prefs/command_line_pref_store.cc17
-rw-r--r--chrome/browser/prefs/command_line_pref_store.h3
-rw-r--r--chrome/browser/prefs/command_line_pref_store_unittest.cc55
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/common/chrome_switches.cc3
-rw-r--r--chrome/common/chrome_switches.h1
-rw-r--r--chrome/common/pref_names.cc1
-rw-r--r--chrome/common/pref_names.h1
11 files changed, 272 insertions, 2 deletions
diff --git a/chrome/browser/net/ssl_config_service_manager_pref.cc b/chrome/browser/net/ssl_config_service_manager_pref.cc
index 5c3ff9b..1c18d62 100644
--- a/chrome/browser/net/ssl_config_service_manager_pref.cc
+++ b/chrome/browser/net/ssl_config_service_manager_pref.cc
@@ -1,16 +1,65 @@
// 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 "chrome/browser/net/ssl_config_service_manager.h"
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/pref_names.h"
#include "content/browser/browser_thread.h"
+#include "content/common/notification_details.h"
+#include "content/common/notification_source.h"
+#include "net/base/ssl_cipher_suite_names.h"
#include "net/base/ssl_config_service.h"
+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 ListValue* value) {
+ std::vector<std::string> results;
+ results.reserve(value->GetSize());
+ std::string s;
+ for (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> ParseCipherSuites(
+ const std::vector<std::string>& cipher_strings) {
+ std::vector<uint16> 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 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;
+}
+
+} // namespace
+
////////////////////////////////////////////////////////////////////////////////
// SSLConfigServicePref
@@ -77,11 +126,20 @@ class SSLConfigServiceManagerPref
// 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* prefs);
+
+ PrefChangeRegistrar pref_change_registrar_;
+
// The prefs (should only be accessed from UI thread)
BooleanPrefMember rev_checking_enabled_;
BooleanPrefMember ssl3_enabled_;
BooleanPrefMember tls1_enabled_;
+ // The cached list of disabled SSL cipher suites.
+ std::vector<uint16> disabled_cipher_suites_;
+
scoped_refptr<SSLConfigServicePref> ssl_config_service_;
DISALLOW_COPY_AND_ASSIGN(SSLConfigServiceManagerPref);
@@ -96,7 +154,10 @@ SSLConfigServiceManagerPref::SSLConfigServiceManagerPref(
local_state, this);
ssl3_enabled_.Init(prefs::kSSL3Enabled, local_state, this);
tls1_enabled_.Init(prefs::kTLS1Enabled, local_state, this);
+ pref_change_registrar_.Init(local_state);
+ pref_change_registrar_.Add(prefs::kCipherSuiteBlacklist, this);
+ 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_);
@@ -111,6 +172,7 @@ void SSLConfigServiceManagerPref::RegisterPrefs(PrefService* prefs) {
default_config.ssl3_enabled);
prefs->RegisterBooleanPref(prefs::kTLS1Enabled,
default_config.tls1_enabled);
+ prefs->RegisterListPref(prefs::kCipherSuiteBlacklist);
}
net::SSLConfigService* SSLConfigServiceManagerPref::Get() {
@@ -122,6 +184,12 @@ void SSLConfigServiceManagerPref::Observe(int type,
const NotificationDetails& details) {
if (type == chrome::NOTIFICATION_PREF_CHANGED) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ std::string* pref_name_in = Details<std::string>(details).ptr();
+ PrefService* prefs = Source<PrefService>(source).ptr();
+ DCHECK(pref_name_in && prefs);
+ if (*pref_name_in == prefs::kCipherSuiteBlacklist)
+ OnDisabledCipherSuitesChange(prefs);
+
net::SSLConfig new_config;
GetSSLConfigFromPrefs(&new_config);
@@ -142,9 +210,16 @@ void SSLConfigServiceManagerPref::GetSSLConfigFromPrefs(
config->rev_checking_enabled = rev_checking_enabled_.GetValue();
config->ssl3_enabled = ssl3_enabled_.GetValue();
config->tls1_enabled = tls1_enabled_.GetValue();
+ config->disabled_cipher_suites = disabled_cipher_suites_;
SSLConfigServicePref::SetSSLConfigFlags(config);
}
+void SSLConfigServiceManagerPref::OnDisabledCipherSuitesChange(
+ PrefService* prefs) {
+ const ListValue* value = prefs->GetList(prefs::kCipherSuiteBlacklist);
+ disabled_cipher_suites_ = ParseCipherSuites(ListValueToStringVector(value));
+}
+
////////////////////////////////////////////////////////////////////////////////
// SSLConfigServiceManager
diff --git a/chrome/browser/net/ssl_config_service_manager_pref_unittest.cc b/chrome/browser/net/ssl_config_service_manager_pref_unittest.cc
new file mode 100644
index 0000000..603947f
--- /dev/null
+++ b/chrome/browser/net/ssl_config_service_manager_pref_unittest.cc
@@ -0,0 +1,112 @@
+// 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 "chrome/browser/net/pref_proxy_config_service.h"
+
+#include "base/message_loop.h"
+#include "base/values.h"
+#include "chrome/browser/net/ssl_config_service_manager.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/testing_pref_service.h"
+#include "content/browser/browser_thread.h"
+#include "net/base/ssl_config_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::ListValue;
+using base::Value;
+using net::SSLConfig;
+using net::SSLConfigService;
+
+class SSLConfigServiceManagerPrefTest : public testing::Test {
+ public:
+ SSLConfigServiceManagerPrefTest() {}
+
+ virtual void SetUp() {
+ message_loop_.reset(new MessageLoop());
+ ui_thread_.reset(
+ new BrowserThread(BrowserThread::UI, message_loop_.get()));
+ io_thread_.reset(
+ new BrowserThread(BrowserThread::IO, message_loop_.get()));
+ pref_service_.reset(new TestingPrefService());
+ SSLConfigServiceManager::RegisterPrefs(pref_service_.get());
+ }
+
+ virtual void TearDown() {
+ pref_service_.reset();
+ io_thread_.reset();
+ ui_thread_.reset();
+ message_loop_.reset();
+ }
+
+ protected:
+ scoped_ptr<MessageLoop> message_loop_;
+ scoped_ptr<BrowserThread> ui_thread_;
+ scoped_ptr<BrowserThread> io_thread_;
+ scoped_ptr<TestingPrefService> pref_service_;
+};
+
+// Test that cipher suites can be disabled. "Good" refers to the fact that
+// every value is expected to be successfully parsed into a cipher suite.
+TEST_F(SSLConfigServiceManagerPrefTest, GoodDisabledCipherSuites) {
+ scoped_ptr<SSLConfigServiceManager> config_manager(
+ SSLConfigServiceManager::CreateDefaultManager(pref_service_.get()));
+ ASSERT_TRUE(config_manager.get());
+ scoped_refptr<SSLConfigService> config_service(config_manager->Get());
+ ASSERT_TRUE(config_service.get());
+
+ SSLConfig old_config;
+ config_service->GetSSLConfig(&old_config);
+ EXPECT_TRUE(old_config.disabled_cipher_suites.empty());
+
+ ListValue* list_value = new ListValue();
+ list_value->Append(Value::CreateStringValue("0x0004"));
+ list_value->Append(Value::CreateStringValue("0x0005"));
+ pref_service_->SetUserPref(prefs::kCipherSuiteBlacklist, list_value);
+
+ // Pump the message loop to notify the SSLConfigServiceManagerPref that the
+ // preferences changed.
+ message_loop_->RunAllPending();
+
+ SSLConfig config;
+ config_service->GetSSLConfig(&config);
+
+ EXPECT_NE(old_config.disabled_cipher_suites, config.disabled_cipher_suites);
+ ASSERT_EQ(2u, config.disabled_cipher_suites.size());
+ EXPECT_EQ(0x0004, config.disabled_cipher_suites[0]);
+ EXPECT_EQ(0x0005, config.disabled_cipher_suites[1]);
+}
+
+// Test that cipher suites can be disabled. "Bad" refers to the fact that
+// there are one or more non-cipher suite strings in the preference. They
+// should be ignored.
+TEST_F(SSLConfigServiceManagerPrefTest, BadDisabledCipherSuites) {
+ scoped_ptr<SSLConfigServiceManager> config_manager(
+ SSLConfigServiceManager::CreateDefaultManager(pref_service_.get()));
+ ASSERT_TRUE(config_manager.get());
+ scoped_refptr<SSLConfigService> config_service(config_manager->Get());
+ ASSERT_TRUE(config_service.get());
+
+ SSLConfig old_config;
+ config_service->GetSSLConfig(&old_config);
+ EXPECT_TRUE(old_config.disabled_cipher_suites.empty());
+
+ ListValue* list_value = new ListValue();
+ list_value->Append(Value::CreateStringValue("0x0004"));
+ list_value->Append(Value::CreateStringValue("TLS_NOT_WITH_A_CIPHER_SUITE"));
+ list_value->Append(Value::CreateStringValue("0x0005"));
+ list_value->Append(Value::CreateStringValue("0xBEEFY"));
+ pref_service_->SetUserPref(prefs::kCipherSuiteBlacklist, list_value);
+
+ // Pump the message loop to notify the SSLConfigServiceManagerPref that the
+ // preferences changed.
+ message_loop_->RunAllPending();
+
+ SSLConfig config;
+ config_service->GetSSLConfig(&config);
+
+ EXPECT_NE(old_config.disabled_cipher_suites, config.disabled_cipher_suites);
+ ASSERT_EQ(2u, config.disabled_cipher_suites.size());
+ EXPECT_EQ(0x0004, config.disabled_cipher_suites[0]);
+ EXPECT_EQ(0x0005, config.disabled_cipher_suites[1]);
+}
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index c163edd..4275cc6 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -28,6 +28,7 @@
#include "chrome/browser/metrics/metrics_log.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/browser/net/net_pref_observer.h"
+#include "chrome/browser/net/ssl_config_service_manager.h"
#include "chrome/browser/net/predictor_api.h"
#include "chrome/browser/net/pref_proxy_config_service.h"
#include "chrome/browser/net/ssl_config_service_manager.h"
diff --git a/chrome/browser/prefs/command_line_pref_store.cc b/chrome/browser/prefs/command_line_pref_store.cc
index a475c45..021be74 100644
--- a/chrome/browser/prefs/command_line_pref_store.cc
+++ b/chrome/browser/prefs/command_line_pref_store.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/prefs/command_line_pref_store.h"
#include "base/logging.h"
+#include "base/string_split.h"
#include "base/values.h"
#include "chrome/browser/prefs/proxy_config_dictionary.h"
#include "chrome/common/chrome_switches.h"
@@ -48,6 +49,7 @@ CommandLinePrefStore::CommandLinePrefStore(const CommandLine* command_line)
ApplySimpleSwitches();
ApplyProxyMode();
ValidateProxySwitches();
+ ApplySSLSwitches();
}
CommandLinePrefStore::~CommandLinePrefStore() {}
@@ -106,3 +108,18 @@ void CommandLinePrefStore::ApplyProxyMode() {
bypass_list));
}
}
+
+void CommandLinePrefStore::ApplySSLSwitches() {
+ if (command_line_->HasSwitch(switches::kCipherSuiteBlacklist)) {
+ std::string cipher_suites =
+ command_line_->GetSwitchValueASCII(switches::kCipherSuiteBlacklist);
+ std::vector<std::string> cipher_strings;
+ base::SplitString(cipher_suites, ',', &cipher_strings);
+ base::ListValue* list_value = new base::ListValue();
+ for (std::vector<std::string>::const_iterator it = cipher_strings.begin();
+ it != cipher_strings.end(); ++it) {
+ list_value->Append(base::Value::CreateStringValue(*it));
+ }
+ SetValue(prefs::kCipherSuiteBlacklist, list_value);
+ }
+}
diff --git a/chrome/browser/prefs/command_line_pref_store.h b/chrome/browser/prefs/command_line_pref_store.h
index 7bc3cc8..5555b18 100644
--- a/chrome/browser/prefs/command_line_pref_store.h
+++ b/chrome/browser/prefs/command_line_pref_store.h
@@ -46,6 +46,9 @@ class CommandLinePrefStore : public ValueMapPrefStore {
// Determines the proxy mode preference from the given proxy switches.
void ApplyProxyMode();
+ // Apply the SSL/TLS preferences from the given switches.
+ void ApplySSLSwitches();
+
// Weak reference.
const CommandLine* command_line_;
diff --git a/chrome/browser/prefs/command_line_pref_store_unittest.cc b/chrome/browser/prefs/command_line_pref_store_unittest.cc
index aa4eeb6..ecb81d2 100644
--- a/chrome/browser/prefs/command_line_pref_store_unittest.cc
+++ b/chrome/browser/prefs/command_line_pref_store_unittest.cc
@@ -34,6 +34,23 @@ class TestCommandLinePrefStore : public CommandLinePrefStore {
ASSERT_TRUE(dict.GetMode(&actual_mode));
EXPECT_EQ(expected_mode, actual_mode);
}
+
+ void VerifySSLCipherSuites(const char* const* ciphers,
+ size_t cipher_count) {
+ const Value* value = NULL;
+ ASSERT_EQ(PrefStore::READ_OK,
+ GetValue(prefs::kCipherSuiteBlacklist, &value));
+ ASSERT_EQ(Value::TYPE_LIST, value->GetType());
+ const ListValue* list_value = static_cast<const ListValue*>(value);
+ ASSERT_EQ(cipher_count, list_value->GetSize());
+
+ std::string cipher_string;
+ for (ListValue::const_iterator it = list_value->begin();
+ it != list_value->end(); ++it, ++ciphers) {
+ ASSERT_TRUE((*it)->GetAsString(&cipher_string));
+ EXPECT_EQ(*ciphers, cipher_string);
+ }
+ }
};
const char unknown_bool[] = "unknown_switch";
@@ -159,3 +176,41 @@ TEST(CommandLinePrefStoreTest, ManualProxyModeInference) {
new TestCommandLinePrefStore(&cl3);
store3->VerifyProxyMode(ProxyPrefs::MODE_DIRECT);
}
+
+TEST(CommandLinePrefStoreTest, DisableSSLCipherSuites) {
+ CommandLine cl1(CommandLine::NO_PROGRAM);
+ cl1.AppendSwitchASCII(switches::kCipherSuiteBlacklist,
+ "0x0004,0x0005");
+ scoped_refptr<TestCommandLinePrefStore> store1 =
+ new TestCommandLinePrefStore(&cl1);
+ const char* const expected_ciphers1[] = {
+ "0x0004",
+ "0x0005",
+ };
+ store1->VerifySSLCipherSuites(expected_ciphers1,
+ arraysize(expected_ciphers1));
+
+ CommandLine cl2(CommandLine::NO_PROGRAM);
+ cl2.AppendSwitchASCII(switches::kCipherSuiteBlacklist,
+ "0x0004, WHITESPACE_IGNORED TEST , 0x0005");
+ scoped_refptr<TestCommandLinePrefStore> store2 =
+ new TestCommandLinePrefStore(&cl2);
+ const char* const expected_ciphers2[] = {
+ "0x0004",
+ "WHITESPACE_IGNORED TEST",
+ "0x0005",
+ };
+ store2->VerifySSLCipherSuites(expected_ciphers2,
+ arraysize(expected_ciphers2));
+
+ CommandLine cl3(CommandLine::NO_PROGRAM);
+ cl3.AppendSwitchASCII(switches::kCipherSuiteBlacklist,
+ "0x0004;MOAR;0x0005");
+ scoped_refptr<TestCommandLinePrefStore> store3 =
+ new TestCommandLinePrefStore(&cl3);
+ const char* const expected_ciphers3[] = {
+ "0x0004;MOAR;0x0005"
+ };
+ store3->VerifySSLCipherSuites(expected_ciphers3,
+ arraysize(expected_ciphers3));
+}
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index a33673b..06814af 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1501,6 +1501,7 @@
'browser/net/pref_proxy_config_service_unittest.cc',
'browser/net/quoted_printable_unittest.cc',
'browser/net/sqlite_persistent_cookie_store_unittest.cc',
+ 'browser/net/ssl_config_service_manager_pref_unittest.cc',
'browser/net/url_fixer_upper_unittest.cc',
'browser/net/url_info_unittest.cc',
'browser/notifications/desktop_notification_service_unittest.cc',
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 5eab5e3..1011697 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -112,6 +112,9 @@ const char kCheckForUpdateIntervalSec[] = "check-for-update-interval";
// this version cannot be loaded, Chrome will exit.
const char kChromeVersion[] = "chrome-version";
+// Comma-separated list of SSL cipher suites to disable.
+const char kCipherSuiteBlacklist[] = "cipher-suite-blacklist";
+
// Used with kCloudPrintFile. Tells Chrome to delete the file when
// finished displaying the print dialog.
const char kCloudPrintDeleteFile[] = "cloud-print-delete-file";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 0088b0b..3fe3cfd 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -48,6 +48,7 @@ extern const char kBrowserAssertTest[];
extern const char kBrowserCrashTest[];
extern const char kCheckForUpdateIntervalSec[];
extern const char kChromeVersion[];
+extern const char kCipherSuiteBlacklist[];
extern const char kCloudPrintDeleteFile[];
extern const char kCloudPrintFile[];
extern const char kCloudPrintJobTitle[];
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index eeb55ba..f11b4d8 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -749,6 +749,7 @@ const char kProfileInfoCache[] = "profile.info_cache";
const char kCertRevocationCheckingEnabled[] = "ssl.rev_checking.enabled";
const char kSSL3Enabled[] = "ssl.ssl3.enabled";
const char kTLS1Enabled[] = "ssl.tls1.enabled";
+const char kCipherSuiteBlacklist[] = "ssl.cipher_suites.blacklist";
// The metrics client GUID and session ID.
const char kMetricsClientID[] = "user_experience_metrics.client_id";
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 08e1318..f45de8a 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -255,6 +255,7 @@ extern const char kPasswordsUseLocalProfileId[];
extern const char kCertRevocationCheckingEnabled[];
extern const char kSSL3Enabled[];
extern const char kTLS1Enabled[];
+extern const char kCipherSuiteBlacklist[];
extern const char kMetricsClientID[];
extern const char kMetricsSessionID[];