diff options
author | hawk@chromium.org <hawk@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-09 22:07:32 +0000 |
---|---|---|
committer | hawk@chromium.org <hawk@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-09 22:07:32 +0000 |
commit | f37c98ff15a2c2de0b86646be4ff7c5e2f59b703 (patch) | |
tree | 07f3dab046d81479ad73a521216ded00b32fb051 /net | |
parent | f7238c977a13f719f2d540a2927a51f6c1e70e74 (diff) | |
download | chromium_src-f37c98ff15a2c2de0b86646be4ff7c5e2f59b703.zip chromium_src-f37c98ff15a2c2de0b86646be4ff7c5e2f59b703.tar.gz chromium_src-f37c98ff15a2c2de0b86646be4ff7c5e2f59b703.tar.bz2 |
Add an SSLConfigService implementation for Mac OS X
BUG=19293
TEST=https://test-ssev.verisign.com/ has three links: one should work OK, the other should warn that the certificate is expired, the other that the certificate is revoked.
Review URL: http://codereview.chromium.org/193009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@25798 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/base/ssl_config_service.cc | 4 | ||||
-rw-r--r-- | net/base/ssl_config_service_mac.cc | 147 | ||||
-rw-r--r-- | net/base/ssl_config_service_mac.h | 55 | ||||
-rw-r--r-- | net/base/ssl_config_service_mac_unittest.cc | 115 | ||||
-rw-r--r-- | net/net.gyp | 3 |
5 files changed, 324 insertions, 0 deletions
diff --git a/net/base/ssl_config_service.cc b/net/base/ssl_config_service.cc index 8fae14e..67d1349 100644 --- a/net/base/ssl_config_service.cc +++ b/net/base/ssl_config_service.cc @@ -6,6 +6,8 @@ #if defined(OS_WIN) #include "net/base/ssl_config_service_win.h" +#elif defined(OS_MACOSX) +#include "net/base/ssl_config_service_mac.h" #else #include "net/base/ssl_config_service_defaults.h" #endif @@ -16,6 +18,8 @@ namespace net { SSLConfigService* SSLConfigService::CreateSystemSSLConfigService() { #if defined(OS_WIN) return new SSLConfigServiceWin; +#elif defined(OS_MACOSX) + return new SSLConfigServiceMac; #else return new SSLConfigServiceDefaults; #endif diff --git a/net/base/ssl_config_service_mac.cc b/net/base/ssl_config_service_mac.cc new file mode 100644 index 0000000..e4cbf1b --- /dev/null +++ b/net/base/ssl_config_service_mac.cc @@ -0,0 +1,147 @@ +// Copyright (c) 2009 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 "net/base/ssl_config_service_mac.h" + +#include <CoreFoundation/CoreFoundation.h> + +#include "base/scoped_cftyperef.h" + +using base::TimeDelta; +using base::TimeTicks; + +namespace net { + +namespace { + +static const int kConfigUpdateInterval = 10; // seconds + +static const bool kSSL2EnabledDefaultValue = false; +static const bool kSSL3EnabledDefaultValue = true; +static const bool kTLS1EnabledDefaultValue = true; + +static CFStringRef kRevocationPreferencesIdentifier = + CFSTR("com.apple.security.revocation"); +static CFStringRef kOCSPStyleKey = CFSTR("OCSPStyle"); +static CFStringRef kCRLStyleKey = CFSTR("CRLStyle"); +static CFStringRef kNoneRevocationValue = CFSTR("None"); +static CFStringRef kBestAttemptRevocationValue = CFSTR("BestAttempt"); +static CFStringRef kSSL2EnabledKey = CFSTR("org.chromium.ssl.ssl2"); +static CFStringRef kSSL3EnabledKey = CFSTR("org.chromium.ssl.ssl3"); +static CFStringRef kTLS1EnabledKey = CFSTR("org.chromium.ssl.tls1"); + +bool RevocationStyleIsEnabled(CFStringRef key) { + CFPropertyListRef plist_ref = CFPreferencesCopyValue(kOCSPStyleKey, + kRevocationPreferencesIdentifier, kCFPreferencesCurrentUser, + kCFPreferencesAnyHost); + if (plist_ref) { + scoped_cftyperef<CFPropertyListRef> scoped_plist_ref(plist_ref); + if (CFGetTypeID(plist_ref) == CFStringGetTypeID()) { + CFStringRef style = reinterpret_cast<CFStringRef>(plist_ref); + if (CFStringCompare(kNoneRevocationValue, style, + kCFCompareCaseInsensitive)) + return true; + } + } + return false; +} + +inline bool SSLVersionIsEnabled(CFStringRef key, bool default_value) { + Boolean exists_and_valid; + Boolean rv = CFPreferencesGetAppBooleanValue(key, + kCFPreferencesCurrentApplication, + &exists_and_valid); + if (!exists_and_valid) + return default_value; + return rv; +} + +} // namespace + +SSLConfigServiceMac::SSLConfigServiceMac() : ever_updated_(false) { + // We defer retrieving the settings until the first call to GetSSLConfig, to + // avoid an expensive call on the UI thread, which could affect startup time. +} + +SSLConfigServiceMac::SSLConfigServiceMac(TimeTicks now) : ever_updated_(false) { + UpdateConfig(now); +} + +void SSLConfigServiceMac::GetSSLConfigAt(SSLConfig* config, TimeTicks now) { + if (!ever_updated_ || + now - config_time_ > TimeDelta::FromSeconds(kConfigUpdateInterval)) + UpdateConfig(now); + *config = config_info_; +} + +// static +bool SSLConfigServiceMac::GetSSLConfigNow(SSLConfig* config) { + // Our own revocation checking flag is a binary value, but Mac OS X uses + // several shades of revocation checking: + // - None (i.e., disabled, the default) + // - BestAttempt + // - RequireIfPresent + // - RequireForall + // Mac OS X also breaks down revocation check for both CRLs and OCSP. We + // set our revocation flag if the system-wide settings for either OCSP + // or CRLs is anything other than None. + config->rev_checking_enabled = (RevocationStyleIsEnabled(kOCSPStyleKey) || + RevocationStyleIsEnabled(kCRLStyleKey)); + + config->ssl2_enabled = SSLVersionIsEnabled(kSSL2EnabledKey, + kSSL2EnabledDefaultValue); + config->ssl3_enabled = SSLVersionIsEnabled(kSSL3EnabledKey, + kSSL3EnabledDefaultValue); + config->tls1_enabled = SSLVersionIsEnabled(kTLS1EnabledKey, + kTLS1EnabledDefaultValue); + + return true; +} + +// static +void SSLConfigServiceMac::SetSSL2Enabled(bool enabled) { + CFPreferencesSetAppValue(kSSL2EnabledKey, + enabled ? kCFBooleanTrue : kCFBooleanFalse, + kCFPreferencesCurrentApplication); + CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication); +} + +// static +void SSLConfigServiceMac::SetSSL3Enabled(bool enabled) { + CFPreferencesSetAppValue(kSSL3EnabledKey, + enabled ? kCFBooleanTrue : kCFBooleanFalse, + kCFPreferencesCurrentApplication); + CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication); +} + +// static +void SSLConfigServiceMac::SetTLS1Enabled(bool enabled) { + CFPreferencesSetAppValue(kTLS1EnabledKey, + enabled ? kCFBooleanTrue : kCFBooleanFalse, + kCFPreferencesCurrentApplication); + CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication); +} + +// static +void SSLConfigServiceMac::SetRevCheckingEnabled(bool enabled) { + // This method is provided for use by the unit tests. These settings + // are normally changed via the Keychain Access application's preferences + // dialog. + CFPreferencesSetValue(kOCSPStyleKey, + enabled ? kBestAttemptRevocationValue : kNoneRevocationValue, + kRevocationPreferencesIdentifier, kCFPreferencesCurrentUser, + kCFPreferencesAnyHost); + CFPreferencesSetValue(kCRLStyleKey, + enabled ? kBestAttemptRevocationValue : kNoneRevocationValue, + kRevocationPreferencesIdentifier, kCFPreferencesCurrentUser, + kCFPreferencesAnyHost); +} + +void SSLConfigServiceMac::UpdateConfig(TimeTicks now) { + GetSSLConfigNow(&config_info_); + config_time_ = now; + ever_updated_ = true; +} + +} // namespace net diff --git a/net/base/ssl_config_service_mac.h b/net/base/ssl_config_service_mac.h new file mode 100644 index 0000000..4741034 --- /dev/null +++ b/net/base/ssl_config_service_mac.h @@ -0,0 +1,55 @@ +// Copyright (c) 2009 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. + +#ifndef NET_BASE_SSL_CONFIG_SERVICE_MAC_H_ +#define NET_BASE_SSL_CONFIG_SERVICE_MAC_H_ + +#include "base/time.h" +#include "net/base/ssl_config_service.h" + +namespace net { + +// This class is responsible for getting and setting the SSL configuration on +// Mac OS X. +class SSLConfigServiceMac : public SSLConfigService { + public: + SSLConfigServiceMac(); + explicit SSLConfigServiceMac(base::TimeTicks now); // Used for testing. + virtual ~SSLConfigServiceMac() {} + + // Get the current SSL configuration settings. Can be called on any + // thread. + static bool GetSSLConfigNow(SSLConfig* config); + + // Setters. Can be called on any thread. + static void SetRevCheckingEnabled(bool enabled); + static void SetSSL2Enabled(bool enabled); + static void SetSSL3Enabled(bool enabled); + static void SetTLS1Enabled(bool enabled); + + // Get the (cached) SSL configuration settings that are fresh within 10 + // seconds. This is cheaper than GetSSLConfigNow and is suitable when + // we don't need the absolutely current configuration settings. This + // method is not thread-safe, so it must be called on the same thread. + void GetSSLConfig(SSLConfig* config) { + GetSSLConfigAt(config, base::TimeTicks::Now()); + } + + // Used for testing. + void GetSSLConfigAt(SSLConfig* config, base::TimeTicks now); + + private: + void UpdateConfig(base::TimeTicks now); + + // We store the system SSL config and the time that we fetched it. + SSLConfig config_info_; + base::TimeTicks config_time_; + bool ever_updated_; + + DISALLOW_EVIL_CONSTRUCTORS(SSLConfigServiceMac); +}; + +} // namespace net + +#endif // NET_BASE_SSL_CONFIG_SERVICE_MAC_H_ diff --git a/net/base/ssl_config_service_mac_unittest.cc b/net/base/ssl_config_service_mac_unittest.cc new file mode 100644 index 0000000..d16129b --- /dev/null +++ b/net/base/ssl_config_service_mac_unittest.cc @@ -0,0 +1,115 @@ +// Copyright (c) 2009 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 "net/base/ssl_config_service_mac.h" +#include "testing/gtest/include/gtest/gtest.h" + +using base::TimeDelta; +using base::TimeTicks; + +namespace { + +class SSLConfigServiceMacTest : public testing::Test { +}; + +} // namespace + +TEST(SSLConfigServiceMacTest, GetNowTest) { + // Verify that the constructor sets the correct default values. + net::SSLConfig config; + EXPECT_EQ(true, config.rev_checking_enabled); + EXPECT_EQ(false, config.ssl2_enabled); + EXPECT_EQ(true, config.ssl3_enabled); + EXPECT_EQ(true, config.tls1_enabled); + + bool rv = net::SSLConfigServiceMac::GetSSLConfigNow(&config); + EXPECT_TRUE(rv); +} + +TEST(SSLConfigServiceMacTest, SetTest) { + // Save the current settings so we can restore them after the tests. + net::SSLConfig config_save; + bool rv = net::SSLConfigServiceMac::GetSSLConfigNow(&config_save); + EXPECT_TRUE(rv); + + net::SSLConfig config; + + // Test SetRevCheckingEnabled. + net::SSLConfigServiceMac::SetRevCheckingEnabled(true); + rv = net::SSLConfigServiceMac::GetSSLConfigNow(&config); + EXPECT_TRUE(rv); + EXPECT_TRUE(config.rev_checking_enabled); + + net::SSLConfigServiceMac::SetRevCheckingEnabled(false); + rv = net::SSLConfigServiceMac::GetSSLConfigNow(&config); + EXPECT_TRUE(rv); + EXPECT_FALSE(config.rev_checking_enabled); + + net::SSLConfigServiceMac::SetRevCheckingEnabled( + config_save.rev_checking_enabled); + + // Test SetSSL2Enabled. + net::SSLConfigServiceMac::SetSSL2Enabled(true); + rv = net::SSLConfigServiceMac::GetSSLConfigNow(&config); + EXPECT_TRUE(rv); + EXPECT_TRUE(config.ssl2_enabled); + + net::SSLConfigServiceMac::SetSSL2Enabled(false); + rv = net::SSLConfigServiceMac::GetSSLConfigNow(&config); + EXPECT_TRUE(rv); + EXPECT_FALSE(config.ssl2_enabled); + + net::SSLConfigServiceMac::SetSSL2Enabled(config_save.ssl2_enabled); + + // Test SetSSL3Enabled. + net::SSLConfigServiceMac::SetSSL3Enabled(true); + rv = net::SSLConfigServiceMac::GetSSLConfigNow(&config); + EXPECT_TRUE(rv); + EXPECT_TRUE(config.ssl3_enabled); + + net::SSLConfigServiceMac::SetSSL3Enabled(false); + rv = net::SSLConfigServiceMac::GetSSLConfigNow(&config); + EXPECT_TRUE(rv); + EXPECT_FALSE(config.ssl3_enabled); + + net::SSLConfigServiceMac::SetSSL3Enabled(config_save.ssl3_enabled); + + // Test SetTLS1Enabled. + net::SSLConfigServiceMac::SetTLS1Enabled(true); + rv = net::SSLConfigServiceMac::GetSSLConfigNow(&config); + EXPECT_TRUE(rv); + EXPECT_TRUE(config.tls1_enabled); + + net::SSLConfigServiceMac::SetTLS1Enabled(false); + rv = net::SSLConfigServiceMac::GetSSLConfigNow(&config); + EXPECT_TRUE(rv); + EXPECT_FALSE(config.tls1_enabled); + + net::SSLConfigServiceMac::SetTLS1Enabled(config_save.tls1_enabled); +} + +TEST(SSLConfigServiceMacTest, GetTest) { + TimeTicks now = TimeTicks::Now(); + TimeTicks now_1 = now + TimeDelta::FromSeconds(1); + TimeTicks now_11 = now + TimeDelta::FromSeconds(11); + + net::SSLConfig config, config_1, config_11; + scoped_refptr<net::SSLConfigServiceMac> config_service( + new net::SSLConfigServiceMac(now)); + config_service->GetSSLConfigAt(&config, now); + + // Flip rev_checking_enabled. + net::SSLConfigServiceMac::SetRevCheckingEnabled( + !config.rev_checking_enabled); + + config_service->GetSSLConfigAt(&config_1, now_1); + EXPECT_EQ(config.rev_checking_enabled, config_1.rev_checking_enabled); + + config_service->GetSSLConfigAt(&config_11, now_11); + EXPECT_EQ(!config.rev_checking_enabled, config_11.rev_checking_enabled); + + // Restore the original value. + net::SSLConfigServiceMac::SetRevCheckingEnabled( + config.rev_checking_enabled); +} diff --git a/net/net.gyp b/net/net.gyp index 00d5039..34281d1 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -124,6 +124,8 @@ 'base/ssl_config_service.cc', 'base/ssl_config_service.h', 'base/ssl_config_service_defaults.h', + 'base/ssl_config_service_mac.cc', + 'base/ssl_config_service_mac.h', 'base/ssl_config_service_win.cc', 'base/ssl_config_service_win.h', 'base/ssl_info.h', @@ -472,6 +474,7 @@ 'base/run_all_unittests.cc', 'base/sdch_filter_unittest.cc', 'base/ssl_client_auth_cache_unittest.cc', + 'base/ssl_config_service_mac_unittest.cc', 'base/ssl_config_service_win_unittest.cc', 'base/strict_transport_security_state_unittest.cc', 'base/telnet_server_unittest.cc', |