Commit f37c98ff authored by hawk@chromium.org's avatar hawk@chromium.org

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
parent f7238c97
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#if defined(OS_WIN) #if defined(OS_WIN)
#include "net/base/ssl_config_service_win.h" #include "net/base/ssl_config_service_win.h"
#elif defined(OS_MACOSX)
#include "net/base/ssl_config_service_mac.h"
#else #else
#include "net/base/ssl_config_service_defaults.h" #include "net/base/ssl_config_service_defaults.h"
#endif #endif
...@@ -16,6 +18,8 @@ namespace net { ...@@ -16,6 +18,8 @@ namespace net {
SSLConfigService* SSLConfigService::CreateSystemSSLConfigService() { SSLConfigService* SSLConfigService::CreateSystemSSLConfigService() {
#if defined(OS_WIN) #if defined(OS_WIN)
return new SSLConfigServiceWin; return new SSLConfigServiceWin;
#elif defined(OS_MACOSX)
return new SSLConfigServiceMac;
#else #else
return new SSLConfigServiceDefaults; return new SSLConfigServiceDefaults;
#endif #endif
......
// 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
// 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_
// 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);
}
...@@ -124,6 +124,8 @@ ...@@ -124,6 +124,8 @@
'base/ssl_config_service.cc', 'base/ssl_config_service.cc',
'base/ssl_config_service.h', 'base/ssl_config_service.h',
'base/ssl_config_service_defaults.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.cc',
'base/ssl_config_service_win.h', 'base/ssl_config_service_win.h',
'base/ssl_info.h', 'base/ssl_info.h',
...@@ -472,6 +474,7 @@ ...@@ -472,6 +474,7 @@
'base/run_all_unittests.cc', 'base/run_all_unittests.cc',
'base/sdch_filter_unittest.cc', 'base/sdch_filter_unittest.cc',
'base/ssl_client_auth_cache_unittest.cc', 'base/ssl_client_auth_cache_unittest.cc',
'base/ssl_config_service_mac_unittest.cc',
'base/ssl_config_service_win_unittest.cc', 'base/ssl_config_service_win_unittest.cc',
'base/strict_transport_security_state_unittest.cc', 'base/strict_transport_security_state_unittest.cc',
'base/telnet_server_unittest.cc', 'base/telnet_server_unittest.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment