diff options
author | wtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-26 16:22:17 +0000 |
---|---|---|
committer | wtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-26 16:22:17 +0000 |
commit | 80c75f6850ba88b4a2305663c63069fec9d7580a (patch) | |
tree | e9aef636347e0f10a7ff7356cb759976c665f073 | |
parent | 0969d1b4edbc89ee74421a20b2fb4f78b7e43448 (diff) | |
download | chromium_src-80c75f6850ba88b4a2305663c63069fec9d7580a.zip chromium_src-80c75f6850ba88b4a2305663c63069fec9d7580a.tar.gz chromium_src-80c75f6850ba88b4a2305663c63069fec9d7580a.tar.bz2 |
Use TLS 1.1.
Enable SSL 3.0 ~ TLS 1.1 by default. If the SSLClientSocket class does
not support TLS 1.1, enable SSL 3.0 ~ TLS 1.0 by default.
TLS intolerant servers are handled by falling back to the next lower
protocol version at a time, rather than falling back to SSL 3.0 directly.
In the SSLConfig structure, replace the ssl3_enabled and tls1_enabled
members by version_min and version_max to allow multiple, contiguous
protocol versions to be enabled, and rename the ssl3_fallback member to
version_fallback.
The preferences prefs::kSSL3Enabled and prefs::kTLS1Enabled are not
yet removed. Generalize prefs::kTLS1Enabled to mean enabling or
disabling all TLS versions.
R=agl@chromium.org,rsleevi@chromium.org
BUG=126340
TEST=net_unittests --gtest_filter=HTTPSRequestTest.TLSv1Fallback
Review URL: https://chromiumcodereview.appspot.com/10377022
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@139204 0039d316-1c4b-4281-b951-d872f2087c98
22 files changed, 378 insertions, 115 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 7bbfc28..426fd9c 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -8327,7 +8327,7 @@ The following plug-in is unresponsive: <ph name="PLUGIN_NAME">$1 The connection is compressed with <ph name="COMPRESSION">$1<ex>DEFLATE</ex></ph>. </message> <message name="IDS_PAGE_INFO_SECURITY_TAB_FALLBACK_MESSAGE" desc="This message is displayed when the first secure connection to a site failed and Chrome retried with an older protocol."> - The connection had to be retried using SSL 3.0. This typically means that the server is using very old software and may have other security issues. + The connection had to be retried using an older version of the TLS or SSL protocol. This typically means that the server is using very old software and may have other security issues. </message> <message name="IDS_PAGE_INFO_SECURITY_TAB_RENEGOTIATION_MESSAGE" desc="This message is displayed when the server hasn't been updated to fix a recent security issues. TLS here is an acronym and need not be translated. 'renegotiation' is a technical term describing a process of agreeing on a new set of security parameters and secrets. 'extension' here should be taken to mean 'amendment' rather than elongation."> The server does not support the TLS renegotiation extension. diff --git a/chrome/browser/net/ssl_config_service_manager_pref.cc b/chrome/browser/net/ssl_config_service_manager_pref.cc index 1bf7cdb..f591429 100644 --- a/chrome/browser/net/ssl_config_service_manager_pref.cc +++ b/chrome/browser/net/ssl_config_service_manager_pref.cc @@ -178,10 +178,12 @@ void SSLConfigServiceManagerPref::RegisterPrefs(PrefService* prefs) { net::SSLConfig default_config; prefs->RegisterBooleanPref(prefs::kCertRevocationCheckingEnabled, default_config.rev_checking_enabled); - prefs->RegisterBooleanPref(prefs::kSSL3Enabled, - default_config.ssl3_enabled); - prefs->RegisterBooleanPref(prefs::kTLS1Enabled, - default_config.tls1_enabled); + bool ssl3_enabled = + default_config.version_min == net::SSL_PROTOCOL_VERSION_SSL3; + bool tls1_enabled = + default_config.version_max >= net::SSL_PROTOCOL_VERSION_TLS1; + prefs->RegisterBooleanPref(prefs::kSSL3Enabled, ssl3_enabled); + prefs->RegisterBooleanPref(prefs::kTLS1Enabled, tls1_enabled); prefs->RegisterBooleanPref(prefs::kEnableOriginBoundCerts, default_config.domain_bound_certs_enabled); prefs->RegisterBooleanPref(prefs::kDisableSSLRecordSplitting, @@ -228,8 +230,18 @@ void SSLConfigServiceManagerPref::Observe( 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(); + // TODO(wtc): replace ssl3_enabled_ and tls1_enabled_ with preferences + // that specify the minimum and maximum protocol versions. For now, + // generalize tls1_enabled_ to mean enabling or disabling all TLS + // versions. + bool ssl3_enabled = ssl3_enabled_.GetValue(); + bool tls1_enabled = tls1_enabled_.GetValue(); + config->version_min = net::SSLConfigService::default_version_min(); + config->version_max = net::SSLConfigService::default_version_max(); + if (!ssl3_enabled && config->version_min == net::SSL_PROTOCOL_VERSION_SSL3) + config->version_min = net::SSL_PROTOCOL_VERSION_TLS1; + if (!tls1_enabled) + config->version_max = net::SSL_PROTOCOL_VERSION_SSL3; config->disabled_cipher_suites = disabled_cipher_suites_; config->domain_bound_certs_enabled = domain_bound_certs_enabled_.GetValue(); // disabling False Start also happens to disable record splitting. diff --git a/chrome/browser/net/ssl_config_service_manager_pref_unittest.cc b/chrome/browser/net/ssl_config_service_manager_pref_unittest.cc index 3d8704b..7b4413c 100644 --- a/chrome/browser/net/ssl_config_service_manager_pref_unittest.cc +++ b/chrome/browser/net/ssl_config_service_manager_pref_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -140,10 +140,11 @@ TEST_F(SSLConfigServiceManagerPrefTest, IgnoreLegacySSLSettings) { SSLConfig ssl_config; config_service->GetSSLConfig(&ssl_config); - // The default value in the absence of command-line options is that both - // protocols are enabled. - EXPECT_TRUE(ssl_config.ssl3_enabled); - EXPECT_TRUE(ssl_config.tls1_enabled); + // The default value in the absence of command-line options is that + // SSL 3.0 ~ default_version_max() are enabled. + EXPECT_EQ(net::SSL_PROTOCOL_VERSION_SSL3, ssl_config.version_min); + EXPECT_EQ(net::SSLConfigService::default_version_max(), + ssl_config.version_max); // The existing user settings should be removed from the pref_service. EXPECT_FALSE(pref_service->HasPrefPath(prefs::kSSL3Enabled)); @@ -196,8 +197,8 @@ TEST_F(SSLConfigServiceManagerPrefTest, CommandLineOverridesUserPrefs) { config_service->GetSSLConfig(&ssl_config); // Command-line flags to disable should override the user preferences to // enable. - EXPECT_FALSE(ssl_config.ssl3_enabled); - EXPECT_FALSE(ssl_config.tls1_enabled); + EXPECT_EQ(net::SSL_PROTOCOL_VERSION_TLS1, ssl_config.version_min); + EXPECT_EQ(net::SSL_PROTOCOL_VERSION_SSL3, ssl_config.version_max); // Explicitly double-check the settings are not in the user preference // store. diff --git a/chrome/browser/page_info_model.cc b/chrome/browser/page_info_model.cc index 39e521e..b1a2d07 100644 --- a/chrome/browser/page_info_model.cc +++ b/chrome/browser/page_info_model.cc @@ -228,7 +228,7 @@ PageInfoModel::PageInfoModel(Profile* profile, ASCIIToUTF16(ssl_version_str)); bool did_fallback = (ssl.connection_status & - net::SSL_CONNECTION_SSL3_FALLBACK) != 0; + net::SSL_CONNECTION_VERSION_FALLBACK) != 0; bool no_renegotiation = (ssl.connection_status & net::SSL_CONNECTION_NO_RENEGOTIATION_EXTENSION) != 0; @@ -255,7 +255,7 @@ PageInfoModel::PageInfoModel(Profile* profile, } if (did_fallback) { - // For now, only SSLv3 fallback will trigger a warning icon. + // For now, only SSL/TLS version fallback will trigger a warning icon. if (icon_id < ICON_STATE_WARNING_MINOR) icon_id = ICON_STATE_WARNING_MINOR; description += ASCIIToUTF16("\n\n"); diff --git a/chrome/browser/website_settings.cc b/chrome/browser/website_settings.cc index 38ad2ad..ceb8551 100644 --- a/chrome/browser/website_settings.cc +++ b/chrome/browser/website_settings.cc @@ -357,7 +357,7 @@ void WebsiteSettings::Init(Profile* profile, ASCIIToUTF16(ssl_version_str)); bool did_fallback = (ssl.connection_status & - net::SSL_CONNECTION_SSL3_FALLBACK) != 0; + net::SSL_CONNECTION_VERSION_FALLBACK) != 0; bool no_renegotiation = (ssl.connection_status & net::SSL_CONNECTION_NO_RENEGOTIATION_EXTENSION) != 0; diff --git a/net/base/ssl_config_service.cc b/net/base/ssl_config_service.cc index 602bb21..3a79540 100644 --- a/net/base/ssl_config_service.cc +++ b/net/base/ssl_config_service.cc @@ -10,22 +10,39 @@ #include "net/base/crl_set.h" #include "net/base/ssl_config_service_defaults.h" +#if defined(USE_OPENSSL) +#include <openssl/ssl.h> +#endif + namespace net { +static uint16 g_default_version_min = SSL_PROTOCOL_VERSION_SSL3; + +static uint16 g_default_version_max = +#if defined(USE_OPENSSL) +#if defined(SSL_OP_NO_TLSv1_1) + SSL_PROTOCOL_VERSION_TLS1_1; +#else + SSL_PROTOCOL_VERSION_TLS1; +#endif +#else + SSL_PROTOCOL_VERSION_TLS1_1; +#endif + SSLConfig::CertAndStatus::CertAndStatus() : cert_status(0) {} SSLConfig::CertAndStatus::~CertAndStatus() {} SSLConfig::SSLConfig() : rev_checking_enabled(false), - ssl3_enabled(true), - tls1_enabled(true), + version_min(g_default_version_min), + version_max(g_default_version_max), cached_info_enabled(false), domain_bound_certs_enabled(false), false_start_enabled(true), send_client_cert(false), verify_ev_cert(false), - ssl3_fallback(false), + version_fallback(false), cert_io_enabled(true) { } @@ -102,6 +119,21 @@ bool SSLConfigService::cached_info_enabled() { } // static +uint16 SSLConfigService::default_version_min() { + return g_default_version_min; +} + +// static +void SSLConfigService::SetDefaultVersionMax(uint16 version_max) { + g_default_version_max = version_max; +} + +// static +uint16 SSLConfigService::default_version_max() { + return g_default_version_max; +} + +// static void SSLConfigService::EnableDomainBoundCertsTrial() { g_domain_bound_certs_trial = true; } @@ -128,8 +160,8 @@ void SSLConfigService::ProcessConfigUpdate(const SSLConfig& orig_config, const SSLConfig& new_config) { bool config_changed = (orig_config.rev_checking_enabled != new_config.rev_checking_enabled) || - (orig_config.ssl3_enabled != new_config.ssl3_enabled) || - (orig_config.tls1_enabled != new_config.tls1_enabled) || + (orig_config.version_min != new_config.version_min) || + (orig_config.version_max != new_config.version_max) || (orig_config.disabled_cipher_suites != new_config.disabled_cipher_suites) || (orig_config.domain_bound_certs_enabled != @@ -148,7 +180,7 @@ bool SSLConfigService::IsSNIAvailable(SSLConfigService* service) { SSLConfig ssl_config; service->GetSSLConfig(&ssl_config); - return ssl_config.tls1_enabled; + return ssl_config.version_max >= SSL_PROTOCOL_VERSION_TLS1; } } // namespace net diff --git a/net/base/ssl_config_service.h b/net/base/ssl_config_service.h index f977370..37f66d2 100644 --- a/net/base/ssl_config_service.h +++ b/net/base/ssl_config_service.h @@ -19,10 +19,24 @@ namespace net { +// Various TLS/SSL ProtocolVersion values encoded as uint16 +// struct { +// uint8 major; +// uint8 minor; +// } ProtocolVersion; +// The most significant byte is |major|, and the least significant byte +// is |minor|. +enum { + SSL_PROTOCOL_VERSION_SSL3 = 0x0300, + SSL_PROTOCOL_VERSION_TLS1 = 0x0301, + SSL_PROTOCOL_VERSION_TLS1_1 = 0x0302, + SSL_PROTOCOL_VERSION_TLS1_2 = 0x0303, +}; + // A collection of SSL-related configuration settings. struct NET_EXPORT SSLConfig { // Default to revocation checking. - // Default to SSL 3.0 on and TLS 1.0 on. + // Default to SSL 3.0 ~ default_version_max() on. SSLConfig(); ~SSLConfig(); @@ -43,9 +57,13 @@ struct NET_EXPORT SSLConfig { // cached revocation information will be considered. bool rev_checking_enabled; - // SSL 2.0 is not supported. - bool ssl3_enabled; // True if SSL 3.0 is enabled. - bool tls1_enabled; // True if TLS 1.0 is enabled. + // The minimum and maximum protocol versions that are enabled. + // SSL 3.0 is 0x0300, TLS 1.0 is 0x0301, TLS 1.1 is 0x0302, and so on. + // (Use the SSL_PROTOCOL_VERSION_xxx enumerators defined above.) + // SSL 2.0 is not supported. If version_max < version_min, it means no + // protocol versions are enabled. + uint16 version_min; + uint16 version_max; // Presorted list of cipher suites which should be explicitly prevented from // being used in addition to those disabled by the net built-in policy. @@ -96,8 +114,9 @@ struct NET_EXPORT SSLConfig { bool verify_ev_cert; // True if we should verify the certificate for EV. - bool ssl3_fallback; // True if we are falling back to SSL 3.0 (one still - // needs to clear tls1_enabled). + bool version_fallback; // True if we are falling back to an older protocol + // version (one still needs to decrement + // version_max). // If cert_io_enabled is false, then certificate verification will not // result in additional HTTP requests. (For example: to fetch missing @@ -154,6 +173,13 @@ class NET_EXPORT SSLConfigService static void EnableCachedInfo(); static bool cached_info_enabled(); + // Gets the default minimum protocol version. + static uint16 default_version_min(); + + // Sets and gets the default maximum protocol version. + static void SetDefaultVersionMax(uint16 version_max); + static uint16 default_version_max(); + // Force domain bound cert support to be enabled. static void EnableDomainBoundCertsTrial(); diff --git a/net/base/ssl_config_service_unittest.cc b/net/base/ssl_config_service_unittest.cc index 2ac2a9b..7c28b61 100644 --- a/net/base/ssl_config_service_unittest.cc +++ b/net/base/ssl_config_service_unittest.cc @@ -50,8 +50,8 @@ class MockSSLConfigServiceObserver : public SSLConfigService::Observer { TEST(SSLConfigServiceTest, NoChangesWontNotifyObservers) { SSLConfig initial_config; initial_config.rev_checking_enabled = true; - initial_config.ssl3_enabled = true; - initial_config.tls1_enabled = true; + initial_config.version_min = SSL_PROTOCOL_VERSION_SSL3; + initial_config.version_max = SSL_PROTOCOL_VERSION_TLS1_1; scoped_refptr<MockSSLConfigService> mock_service( new MockSSLConfigService(initial_config)); @@ -67,8 +67,8 @@ TEST(SSLConfigServiceTest, NoChangesWontNotifyObservers) { TEST(SSLConfigServiceTest, ConfigUpdatesNotifyObservers) { SSLConfig initial_config; initial_config.rev_checking_enabled = true; - initial_config.ssl3_enabled = true; - initial_config.tls1_enabled = true; + initial_config.version_min = SSL_PROTOCOL_VERSION_SSL3; + initial_config.version_max = SSL_PROTOCOL_VERSION_TLS1_1; scoped_refptr<MockSSLConfigService> mock_service( new MockSSLConfigService(initial_config)); @@ -80,11 +80,11 @@ TEST(SSLConfigServiceTest, ConfigUpdatesNotifyObservers) { EXPECT_CALL(observer, OnSSLConfigChanged()).Times(1); mock_service->SetSSLConfig(initial_config); - initial_config.ssl3_enabled = false; + initial_config.version_min = SSL_PROTOCOL_VERSION_TLS1; EXPECT_CALL(observer, OnSSLConfigChanged()).Times(1); mock_service->SetSSLConfig(initial_config); - initial_config.tls1_enabled = false; + initial_config.version_max = SSL_PROTOCOL_VERSION_SSL3; EXPECT_CALL(observer, OnSSLConfigChanged()).Times(1); mock_service->SetSSLConfig(initial_config); diff --git a/net/base/ssl_connection_status_flags.h b/net/base/ssl_connection_status_flags.h index 9596f00..bf349ce 100644 --- a/net/base/ssl_connection_status_flags.h +++ b/net/base/ssl_connection_status_flags.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -18,8 +18,8 @@ enum { SSL_CONNECTION_COMPRESSION_SHIFT = 16, SSL_CONNECTION_COMPRESSION_MASK = 3, - // We fell back to SSLv3 for this connection. - SSL_CONNECTION_SSL3_FALLBACK = 1 << 18, + // We fell back to an older protocol version for this connection. + SSL_CONNECTION_VERSION_FALLBACK = 1 << 18, // The server doesn't support the renegotiation_info extension. If this bit // is not set then either the extension isn't supported, or we don't have any diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index 7b52766..8f94732 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -1162,16 +1162,39 @@ int HttpNetworkTransaction::HandleSSLHandshakeError(int error) { switch (error) { case ERR_SSL_PROTOCOL_ERROR: case ERR_SSL_VERSION_OR_CIPHER_MISMATCH: + if (server_ssl_config_.version_max >= SSL_PROTOCOL_VERSION_TLS1 && + server_ssl_config_.version_max > server_ssl_config_.version_min) { + // This could be a TLS-intolerant server or a server that chose a + // cipher suite defined only for higher protocol versions (such as + // an SSL 3.0 server that chose a TLS-only cipher suite). Fall + // back to the next lower version and retry. + // NOTE: if the SSLClientSocket class doesn't support TLS 1.1, + // specifying TLS 1.1 in version_max will result in a TLS 1.0 + // handshake, so falling back from TLS 1.1 to TLS 1.0 will simply + // repeat the TLS 1.0 handshake. To avoid this problem, the default + // version_max should match the maximum protocol version supported + // by the SSLClientSocket class. + LOG(WARNING) << "Falling back one version because host is " + "TLS intolerant: " << GetHostAndPort(request_->url) + << " error: " << error; + server_ssl_config_.version_max--; + server_ssl_config_.version_fallback = true; + ResetConnectionAndRequestForResend(); + error = OK; + } + break; case ERR_SSL_DECOMPRESSION_FAILURE_ALERT: case ERR_SSL_BAD_RECORD_MAC_ALERT: - if (server_ssl_config_.tls1_enabled) { - // This could be a TLS-intolerant server, an SSL 3.0 server that - // chose a TLS-only cipher suite or a server with buggy DEFLATE - // support. Turn off TLS 1.0, DEFLATE support and retry. - LOG(WARNING) << "Falling back to SSLv3 because host is TLS intolerant: " - << GetHostAndPort(request_->url); - server_ssl_config_.tls1_enabled = false; - server_ssl_config_.ssl3_fallback = true; + if (server_ssl_config_.version_max >= SSL_PROTOCOL_VERSION_TLS1 && + server_ssl_config_.version_min == SSL_PROTOCOL_VERSION_SSL3) { + // This could be a server with buggy DEFLATE support. Turn off TLS, + // DEFLATE support and retry. + // TODO(wtc): turn off DEFLATE support only. Do not tie it to TLS. + LOG(WARNING) << "Falling back to SSLv3 because host has buggy TLS " + "compression support: " + << GetHostAndPort(request_->url) << " error: " << error; + server_ssl_config_.version_max = SSL_PROTOCOL_VERSION_SSL3; + server_ssl_config_.version_fallback = true; ResetConnectionAndRequestForResend(); error = OK; } @@ -1188,10 +1211,9 @@ int HttpNetworkTransaction::HandleIOError(int error) { // SSL errors may happen at any time during the stream and indicate issues // with the underlying connection. Because the peer may request // renegotiation at any time, check and handle any possible SSL handshake - // related errors. In addition to renegotiation, TLS False/Snap Start may - // cause SSL handshake errors to be delayed until the first or second Write - // (Snap Start) or the first Read (False & Snap Start) on the underlying - // connection. + // related errors. In addition to renegotiation, TLS False Start may cause + // SSL handshake errors (specifically servers with buggy DEFLATE support) + // to be delayed until the first Read on the underlying connection. error = HandleSSLHandshakeError(error); switch (error) { diff --git a/net/http/http_network_transaction_spdy2_unittest.cc b/net/http/http_network_transaction_spdy2_unittest.cc index 27470e0..fdb18b0 100644 --- a/net/http/http_network_transaction_spdy2_unittest.cc +++ b/net/http/http_network_transaction_spdy2_unittest.cc @@ -9101,8 +9101,8 @@ TEST_F(HttpNetworkTransactionSpdy2Test, // [ssl_]data3 contains the data for the third SSL handshake. When a // connection to a server fails during an SSL handshake, - // HttpNetworkTransaction will attempt to fallback to SSLv3 if the initial - // connection was attempted with TLSv1. This is transparent to the caller + // HttpNetworkTransaction will attempt to fallback to TLSv1 if the previous + // connection was attempted with TLSv1.1. This is transparent to the caller // of the HttpNetworkTransaction. Because this test failure is due to // requiring a client certificate, this fallback handshake should also // fail. @@ -9112,6 +9112,19 @@ TEST_F(HttpNetworkTransactionSpdy2Test, net::StaticSocketDataProvider data3(NULL, 0, NULL, 0); session_deps.socket_factory.AddSocketDataProvider(&data3); + // [ssl_]data4 contains the data for the fourth SSL handshake. When a + // connection to a server fails during an SSL handshake, + // HttpNetworkTransaction will attempt to fallback to SSLv3 if the previous + // connection was attempted with TLSv1. This is transparent to the caller + // of the HttpNetworkTransaction. Because this test failure is due to + // requiring a client certificate, this fallback handshake should also + // fail. + SSLSocketDataProvider ssl_data4(ASYNC, net::ERR_SSL_PROTOCOL_ERROR); + ssl_data4.cert_request_info = cert_request.get(); + session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data4); + net::StaticSocketDataProvider data4(NULL, 0, NULL, 0); + session_deps.socket_factory.AddSocketDataProvider(&data4); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); @@ -9140,8 +9153,8 @@ TEST_F(HttpNetworkTransactionSpdy2Test, ASSERT_EQ(NULL, client_cert.get()); // Restart the handshake. This will consume ssl_data2, which fails, and - // then consume ssl_data3, which should also fail. The result code is - // checked against what ssl_data3 should return. + // then consume ssl_data3 and ssl_data4, both of which should also fail. + // The result code is checked against what ssl_data4 should return. rv = callback.WaitForResult(); ASSERT_EQ(net::ERR_SSL_PROTOCOL_ERROR, rv); @@ -9208,8 +9221,8 @@ TEST_F(HttpNetworkTransactionSpdy2Test, session_deps.socket_factory.AddSocketDataProvider(&data2); // As described in ClientAuthCertCache_Direct_NoFalseStart, [ssl_]data3 is - // the data for the SSL handshake once the TLSv1 connection falls back to - // SSLv3. It has the same behaviour as [ssl_]data2. + // the data for the SSL handshake once the TLSv1.1 connection falls back to + // TLSv1. It has the same behaviour as [ssl_]data2. SSLSocketDataProvider ssl_data3(ASYNC, net::OK); ssl_data3.cert_request_info = cert_request.get(); session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data3); @@ -9217,6 +9230,15 @@ TEST_F(HttpNetworkTransactionSpdy2Test, data2_reads, arraysize(data2_reads), NULL, 0); session_deps.socket_factory.AddSocketDataProvider(&data3); + // [ssl_]data4 is the data for the SSL handshake once the TLSv1 connection + // falls back to SSLv3. It has the same behaviour as [ssl_]data2. + SSLSocketDataProvider ssl_data4(ASYNC, net::OK); + ssl_data4.cert_request_info = cert_request.get(); + session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data4); + net::StaticSocketDataProvider data4( + data2_reads, arraysize(data2_reads), NULL, 0); + session_deps.socket_factory.AddSocketDataProvider(&data4); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); @@ -9246,8 +9268,8 @@ TEST_F(HttpNetworkTransactionSpdy2Test, // Restart the handshake. This will consume ssl_data2, which fails, and - // then consume ssl_data3, which should also fail. The result code is - // checked against what ssl_data3 should return. + // then consume ssl_data3 and ssl_data4, both of which should also fail. + // The result code is checked against what ssl_data4 should return. rv = callback.WaitForResult(); ASSERT_EQ(net::ERR_SSL_PROTOCOL_ERROR, rv); @@ -9290,11 +9312,14 @@ TEST_F(HttpNetworkTransactionSpdy2Test, ClientAuthCertCache_Proxy_Fail) { net::StaticSocketDataProvider data2(NULL, 0, NULL, 0); session_deps.socket_factory.AddSocketDataProvider(&data2); + // TODO(wtc): find out why this unit test doesn't need [ssl_]data3. +#if 0 SSLSocketDataProvider ssl_data3(ASYNC, net::ERR_SSL_PROTOCOL_ERROR); ssl_data3.cert_request_info = cert_request.get(); session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data3); net::StaticSocketDataProvider data3(NULL, 0, NULL, 0); session_deps.socket_factory.AddSocketDataProvider(&data3); +#endif net::HttpRequestInfo requests[2]; requests[0].url = GURL("https://www.example.com/"); diff --git a/net/http/http_network_transaction_spdy3_unittest.cc b/net/http/http_network_transaction_spdy3_unittest.cc index 6f7468d..81051b2 100644 --- a/net/http/http_network_transaction_spdy3_unittest.cc +++ b/net/http/http_network_transaction_spdy3_unittest.cc @@ -9100,8 +9100,8 @@ TEST_F(HttpNetworkTransactionSpdy3Test, // [ssl_]data3 contains the data for the third SSL handshake. When a // connection to a server fails during an SSL handshake, - // HttpNetworkTransaction will attempt to fallback to SSLv3 if the initial - // connection was attempted with TLSv1. This is transparent to the caller + // HttpNetworkTransaction will attempt to fallback to TLSv1 if the previous + // connection was attempted with TLSv1.1. This is transparent to the caller // of the HttpNetworkTransaction. Because this test failure is due to // requiring a client certificate, this fallback handshake should also // fail. @@ -9111,6 +9111,19 @@ TEST_F(HttpNetworkTransactionSpdy3Test, net::StaticSocketDataProvider data3(NULL, 0, NULL, 0); session_deps.socket_factory.AddSocketDataProvider(&data3); + // [ssl_]data4 contains the data for the fourth SSL handshake. When a + // connection to a server fails during an SSL handshake, + // HttpNetworkTransaction will attempt to fallback to SSLv3 if the previous + // connection was attempted with TLSv1. This is transparent to the caller + // of the HttpNetworkTransaction. Because this test failure is due to + // requiring a client certificate, this fallback handshake should also + // fail. + SSLSocketDataProvider ssl_data4(ASYNC, net::ERR_SSL_PROTOCOL_ERROR); + ssl_data4.cert_request_info = cert_request.get(); + session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data4); + net::StaticSocketDataProvider data4(NULL, 0, NULL, 0); + session_deps.socket_factory.AddSocketDataProvider(&data4); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); @@ -9139,8 +9152,8 @@ TEST_F(HttpNetworkTransactionSpdy3Test, ASSERT_EQ(NULL, client_cert.get()); // Restart the handshake. This will consume ssl_data2, which fails, and - // then consume ssl_data3, which should also fail. The result code is - // checked against what ssl_data3 should return. + // then consume ssl_data3 and ssl_data4, both of which should also fail. + // The result code is checked against what ssl_data4 should return. rv = callback.WaitForResult(); ASSERT_EQ(net::ERR_SSL_PROTOCOL_ERROR, rv); @@ -9206,8 +9219,8 @@ TEST_F(HttpNetworkTransactionSpdy3Test, ClientAuthCertCache_Direct_FalseStart) { session_deps.socket_factory.AddSocketDataProvider(&data2); // As described in ClientAuthCertCache_Direct_NoFalseStart, [ssl_]data3 is - // the data for the SSL handshake once the TLSv1 connection falls back to - // SSLv3. It has the same behaviour as [ssl_]data2. + // the data for the SSL handshake once the TLSv1.1 connection falls back to + // TLSv1. It has the same behaviour as [ssl_]data2. SSLSocketDataProvider ssl_data3(ASYNC, net::OK); ssl_data3.cert_request_info = cert_request.get(); session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data3); @@ -9215,6 +9228,15 @@ TEST_F(HttpNetworkTransactionSpdy3Test, ClientAuthCertCache_Direct_FalseStart) { data2_reads, arraysize(data2_reads), NULL, 0); session_deps.socket_factory.AddSocketDataProvider(&data3); + // [ssl_]data4 is the data for the SSL handshake once the TLSv1 connection + // falls back to SSLv3. It has the same behaviour as [ssl_]data2. + SSLSocketDataProvider ssl_data4(ASYNC, net::OK); + ssl_data4.cert_request_info = cert_request.get(); + session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data4); + net::StaticSocketDataProvider data4( + data2_reads, arraysize(data2_reads), NULL, 0); + session_deps.socket_factory.AddSocketDataProvider(&data4); + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); @@ -9244,8 +9266,8 @@ TEST_F(HttpNetworkTransactionSpdy3Test, ClientAuthCertCache_Direct_FalseStart) { // Restart the handshake. This will consume ssl_data2, which fails, and - // then consume ssl_data3, which should also fail. The result code is - // checked against what ssl_data3 should return. + // then consume ssl_data3 and ssl_data4, both of which should also fail. + // The result code is checked against what ssl_data4 should return. rv = callback.WaitForResult(); ASSERT_EQ(net::ERR_SSL_PROTOCOL_ERROR, rv); @@ -9288,11 +9310,14 @@ TEST_F(HttpNetworkTransactionSpdy3Test, ClientAuthCertCache_Proxy_Fail) { net::StaticSocketDataProvider data2(NULL, 0, NULL, 0); session_deps.socket_factory.AddSocketDataProvider(&data2); + // TODO(wtc): find out why this unit test doesn't need [ssl_]data3. +#if 0 SSLSocketDataProvider ssl_data3(ASYNC, net::ERR_SSL_PROTOCOL_ERROR); ssl_data3.cert_request_info = cert_request.get(); session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data3); net::StaticSocketDataProvider data3(NULL, 0, NULL, 0); session_deps.socket_factory.AddSocketDataProvider(&data3); +#endif net::HttpRequestInfo requests[2]; requests[0].url = GURL("https://www.example.com/"); diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc index 7a2aa87..15cba9d 100644 --- a/net/http/http_stream_factory_impl_job.cc +++ b/net/http/http_stream_factory_impl_job.cc @@ -1071,8 +1071,30 @@ void HttpStreamFactoryImpl::Job::InitSSLConfig( ssl_config->false_start_enabled = false; } - UMA_HISTOGRAM_ENUMERATION("Net.ConnectionUsedSSLv3Fallback", - static_cast<int>(ssl_config->ssl3_fallback), 2); + enum { + FALLBACK_NONE = 0, // SSL version fallback did not occur. + FALLBACK_SSL3 = 1, // Fell back to SSL 3.0. + FALLBACK_TLS1 = 2, // Fell back to TLS 1.0. + FALLBACK_TLS1_1 = 3, // Fell back to TLS 1.1. + FALLBACK_MAX + }; + + int fallback = FALLBACK_NONE; + if (ssl_config->version_fallback) { + switch (ssl_config->version_max) { + case SSL_PROTOCOL_VERSION_SSL3: + fallback = FALLBACK_SSL3; + break; + case SSL_PROTOCOL_VERSION_TLS1: + fallback = FALLBACK_TLS1; + break; + case SSL_PROTOCOL_VERSION_TLS1_1: + fallback = FALLBACK_TLS1_1; + break; + } + } + UMA_HISTOGRAM_ENUMERATION("Net.ConnectionUsedSSLVersionFallback", + fallback, FALLBACK_MAX); if (request_info_.load_flags & LOAD_VERIFY_EV_CERT) ssl_config->verify_ev_cert = true; diff --git a/net/socket/client_socket_factory.cc b/net/socket/client_socket_factory.cc index 60daef4..42f6d4f 100644 --- a/net/socket/client_socket_factory.cc +++ b/net/socket/client_socket_factory.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -134,6 +134,14 @@ ClientSocketFactory* ClientSocketFactory::GetDefaultFactory() { // static void ClientSocketFactory::UseSystemSSL() { g_use_system_ssl = true; + +#if defined(OS_WIN) + // Reflect the capability of SSLClientSocketWin. + SSLConfigService::SetDefaultVersionMax(SSL_PROTOCOL_VERSION_TLS1); +#elif defined(OS_MACOSX) + // Reflect the capability of SSLClientSocketMac. + SSLConfigService::SetDefaultVersionMax(SSL_PROTOCOL_VERSION_TLS1); +#endif } } // namespace net diff --git a/net/socket/client_socket_pool_manager.cc b/net/socket/client_socket_pool_manager.cc index 20b02f4..70f1edb 100644 --- a/net/socket/client_socket_pool_manager.cc +++ b/net/socket/client_socket_pool_manager.cc @@ -112,11 +112,35 @@ int InitSocketPoolHelper(const GURL& request_url, std::string connection_group = origin_host_port.ToString(); DCHECK(!connection_group.empty()); if (using_ssl) { - std::string prefix; - if (ssl_config_for_origin.tls1_enabled) { - prefix = "ssl/"; - } else { - prefix = "sslv3/"; + // All connections in a group should use the same SSLConfig settings. + // Encode version_max in the connection group's name, unless it's the + // default version_max. (We want the common case to use the shortest + // encoding). A version_max of TLS 1.1 is encoded as "ssl(max:3.2)/" + // rather than "tlsv1.1/" because the actual protocol version, which + // is selected by the server, may not be TLS 1.1. Do not encode + // version_min in the connection group's name because version_min + // should be the same for all connections, whereas version_max may + // change for version fallbacks. + std::string prefix = "ssl/"; + if (ssl_config_for_origin.version_max != + SSLConfigService::default_version_max()) { + switch (ssl_config_for_origin.version_max) { + case SSL_PROTOCOL_VERSION_TLS1_2: + prefix = "ssl(max:3.3)/"; + break; + case SSL_PROTOCOL_VERSION_TLS1_1: + prefix = "ssl(max:3.2)/"; + break; + case SSL_PROTOCOL_VERSION_TLS1: + prefix = "ssl(max:3.1)/"; + break; + case SSL_PROTOCOL_VERSION_SSL3: + prefix = "sslv3/"; + break; + default: + CHECK(false); + break; + } } connection_group = prefix + connection_group; } diff --git a/net/socket/ssl_client_socket_mac.cc b/net/socket/ssl_client_socket_mac.cc index f84f3fb..862ef52 100644 --- a/net/socket/ssl_client_socket_mac.cc +++ b/net/socket/ssl_client_socket_mac.cc @@ -738,8 +738,8 @@ void SSLClientSocketMac::GetSSLInfo(SSLInfo* ssl_info) { SSL_CONNECTION_CIPHERSUITE_SHIFT; } - if (ssl_config_.ssl3_fallback) - ssl_info->connection_status |= SSL_CONNECTION_SSL3_FALLBACK; + if (ssl_config_.version_fallback) + ssl_info->connection_status |= SSL_CONNECTION_VERSION_FALLBACK; } void SSLClientSocketMac::GetSSLCertRequestInfo( @@ -812,15 +812,23 @@ int SSLClientSocketMac::InitializeSSLContext() { if (status) return NetErrorFromOSStatus(status); + // If ssl_config_.version_max > SSL_PROTOCOL_VERSION_TLS1, it means the + // SSLConfigService::SetDefaultVersionMax(SSL_PROTOCOL_VERSION_TLS1) call + // in ClientSocketFactory::UseSystemSSL() is not effective. + DCHECK_LE(ssl_config_.version_max, SSL_PROTOCOL_VERSION_TLS1); + + bool ssl3_enabled = (ssl_config_.version_min == SSL_PROTOCOL_VERSION_SSL3); status = SSLSetProtocolVersionEnabled(ssl_context_, kSSLProtocol3, - ssl_config_.ssl3_enabled); + ssl3_enabled); if (status) return NetErrorFromOSStatus(status); + bool tls1_enabled = (ssl_config_.version_min <= SSL_PROTOCOL_VERSION_TLS1 && + ssl_config_.version_max >= SSL_PROTOCOL_VERSION_TLS1); status = SSLSetProtocolVersionEnabled(ssl_context_, kTLSProtocol1, - ssl_config_.tls1_enabled); + tls1_enabled); if (status) return NetErrorFromOSStatus(status); diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc index ed99bbf..d45b429 100644 --- a/net/socket/ssl_client_socket_nss.cc +++ b/net/socket/ssl_client_socket_nss.cc @@ -864,16 +864,13 @@ int SSLClientSocketNSS::InitializeSSLOptions() { return ERR_UNEXPECTED; } - rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL3, ssl_config_.ssl3_enabled); + SSLVersionRange version_range; + version_range.min = ssl_config_.version_min; + version_range.max = ssl_config_.version_max; + rv = SSL_VersionRangeSet(nss_fd_, &version_range); if (rv != SECSuccess) { - LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_ENABLE_SSL3"); - return ERR_UNEXPECTED; - } - - rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_TLS, ssl_config_.tls1_enabled); - if (rv != SECSuccess) { - LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_ENABLE_TLS"); - return ERR_UNEXPECTED; + LogFailedNSSFunction(net_log_, "SSL_VersionRangeSet", ""); + return ERR_NO_SSL_VERSIONS_ENABLED; } for (std::vector<uint16>::const_iterator it = @@ -900,7 +897,8 @@ int SSLClientSocketNSS::InitializeSSLOptions() { // is advertised. Thus, if TLS is disabled (probably because we are doing // SSLv3 fallback), we disable DEFLATE also. // See http://crbug.com/31628 - rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_DEFLATE, ssl_config_.tls1_enabled); + rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_DEFLATE, + ssl_config_.version_max >= SSL_PROTOCOL_VERSION_TLS1); if (rv != SECSuccess) LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_ENABLE_DEFLATE"); #endif @@ -1135,8 +1133,8 @@ void SSLClientSocketNSS::UpdateConnectionStatus() { } #endif - if (ssl_config_.ssl3_fallback) - ssl_connection_status_ |= SSL_CONNECTION_SSL3_FALLBACK; + if (ssl_config_.version_fallback) + ssl_connection_status_ |= SSL_CONNECTION_VERSION_FALLBACK; } void SSLClientSocketNSS::DoReadCallback(int rv) { @@ -1759,7 +1757,9 @@ int SSLClientSocketNSS::DoVerifyCertComplete(int result) { IsCertStatusMinorError(cert_status))) && server_cert_verify_result_->is_issued_by_known_root && transport_security_state_) { - bool sni_available = ssl_config_.tls1_enabled || ssl_config_.ssl3_fallback; + bool sni_available = + ssl_config_.version_max >= SSL_PROTOCOL_VERSION_TLS1 || + ssl_config_.version_fallback; const std::string& host = host_and_port_.host(); TransportSecurityState::DomainState domain_state; diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc index 55f9fbf..ba52ec0 100644 --- a/net/socket/ssl_client_socket_openssl.cc +++ b/net/socket/ssl_client_socket_openssl.cc @@ -467,13 +467,29 @@ bool SSLClientSocketOpenSSL::Init() { // set everything we care about to an absolute value. SslSetClearMask options; options.ConfigureFlag(SSL_OP_NO_SSLv2, true); - options.ConfigureFlag(SSL_OP_NO_SSLv3, !ssl_config_.ssl3_enabled); - options.ConfigureFlag(SSL_OP_NO_TLSv1, !ssl_config_.tls1_enabled); + bool ssl3_enabled = (ssl_config_.version_min == SSL_PROTOCOL_VERSION_SSL3); + options.ConfigureFlag(SSL_OP_NO_SSLv3, !ssl3_enabled); + bool tls1_enabled = (ssl_config_.version_min <= SSL_PROTOCOL_VERSION_TLS1 && + ssl_config_.version_max >= SSL_PROTOCOL_VERSION_TLS1); + options.ConfigureFlag(SSL_OP_NO_TLSv1, !tls1_enabled); +#if defined(SSL_OP_NO_TLSv1_1) + bool tls1_1_enabled = + (ssl_config_.version_min <= SSL_PROTOCOL_VERSION_TLS1_1 && + ssl_config_.version_max >= SSL_PROTOCOL_VERSION_TLS1_1); + options.ConfigureFlag(SSL_OP_NO_TLSv1_1, !tls1_1_enabled); +#endif +#if defined(SSL_OP_NO_TLSv1_2) + bool tls1_2_enabled = + (ssl_config_.version_min <= SSL_PROTOCOL_VERSION_TLS1_2 && + ssl_config_.version_max >= SSL_PROTOCOL_VERSION_TLS1_2); + options.ConfigureFlag(SSL_OP_NO_TLSv1_2, !tls1_2_enabled); +#endif #if defined(SSL_OP_NO_COMPRESSION) // If TLS was disabled also disable compression, to provide maximum site // compatibility in the case of protocol fallback. See http://crbug.com/31628 - options.ConfigureFlag(SSL_OP_NO_COMPRESSION, !ssl_config_.tls1_enabled); + options.ConfigureFlag(SSL_OP_NO_COMPRESSION, + ssl_config_.version_max < SSL_PROTOCOL_VERSION_TLS1); #endif // TODO(joth): Set this conditionally, see http://crbug.com/55410 @@ -601,8 +617,8 @@ void SSLClientSocketOpenSSL::GetSSLInfo(SSLInfo* ssl_info) { UMA_HISTOGRAM_ENUMERATION("Net.RenegotiationExtensionSupported", implicit_cast<int>(peer_supports_renego_ext), 2); - if (ssl_config_.ssl3_fallback) - ssl_info->connection_status |= SSL_CONNECTION_SSL3_FALLBACK; + if (ssl_config_.version_fallback) + ssl_info->connection_status |= SSL_CONNECTION_VERSION_FALLBACK; DVLOG(3) << "Encoded connection status: cipher suite = " << SSLConnectionStatusToCipherSuite(ssl_info->connection_status) diff --git a/net/socket/ssl_client_socket_win.cc b/net/socket/ssl_client_socket_win.cc index 1442ad6..8728532 100644 --- a/net/socket/ssl_client_socket_win.cc +++ b/net/socket/ssl_client_socket_win.cc @@ -116,6 +116,7 @@ static int MapSecurityError(SECURITY_STATUS err) { // A bitmask consisting of these bit flags encodes which versions of the SSL // protocol (SSL 3.0 and TLS 1.0) are enabled. +// TODO(wtc): support TLS 1.1 and TLS 1.2 on Windows Vista and later. enum { SSL3 = 1 << 0, TLS1 = 1 << 1, @@ -423,6 +424,8 @@ void SSLClientSocketWin::GetSSLInfo(SSLInfo* ssl_info) { // dwExchStrength and dwHashStrength. dwExchStrength needs to be // normalized. ssl_info->security_bits = connection_info.dwCipherStrength; + // TODO(wtc): connection_info.dwProtocol is the negotiated version. + // Save it in ssl_info->connection_status. } // SecPkgContext_CipherInfo comes from CNG and is available on Vista or // later only. On XP, the next QueryContextAttributes call fails with @@ -442,8 +445,8 @@ void SSLClientSocketWin::GetSSLInfo(SSLInfo* ssl_info) { // any field related to the compression method. } - if (ssl_config_.ssl3_fallback) - ssl_info->connection_status |= SSL_CONNECTION_SSL3_FALLBACK; + if (ssl_config_.version_fallback) + ssl_info->connection_status |= SSL_CONNECTION_VERSION_FALLBACK; } void SSLClientSocketWin::GetSSLCertRequestInfo( @@ -585,11 +588,17 @@ int SSLClientSocketWin::Connect(const CompletionCallback& callback) { } int SSLClientSocketWin::InitializeSSLContext() { + // If ssl_config_.version_max > SSL_PROTOCOL_VERSION_TLS1, it means the + // SSLConfigService::SetDefaultVersionMax(SSL_PROTOCOL_VERSION_TLS1) call + // in ClientSocketFactory::UseSystemSSL() is not effective. + DCHECK_LE(ssl_config_.version_max, SSL_PROTOCOL_VERSION_TLS1); int ssl_version_mask = 0; - if (ssl_config_.ssl3_enabled) + if (ssl_config_.version_min == SSL_PROTOCOL_VERSION_SSL3) ssl_version_mask |= SSL3; - if (ssl_config_.tls1_enabled) + if (ssl_config_.version_min <= SSL_PROTOCOL_VERSION_TLS1 && + ssl_config_.version_max >= SSL_PROTOCOL_VERSION_TLS1) { ssl_version_mask |= TLS1; + } // If we pass 0 to GetCredHandle, we will let Schannel select the protocols, // rather than enabling no protocols. So we have to fail here. if (ssl_version_mask == 0) diff --git a/net/socket/ssl_server_socket_nss.cc b/net/socket/ssl_server_socket_nss.cc index 9ba0aaa..76d5559 100644 --- a/net/socket/ssl_server_socket_nss.cc +++ b/net/socket/ssl_server_socket_nss.cc @@ -68,8 +68,8 @@ SSLServerSocketNSS::SSLServerSocketNSS( next_handshake_state_(STATE_NONE), completed_handshake_(false) { ssl_config_.false_start_enabled = false; - ssl_config_.ssl3_enabled = true; - ssl_config_.tls1_enabled = true; + ssl_config_.version_min = SSL_PROTOCOL_VERSION_SSL3; + ssl_config_.version_max = SSL_PROTOCOL_VERSION_TLS1_1; // TODO(hclam): Need a better way to clone a key. std::vector<uint8> key_bytes; @@ -284,16 +284,13 @@ int SSLServerSocketNSS::InitializeSSLOptions() { return ERR_UNEXPECTED; } - rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL3, PR_TRUE); + SSLVersionRange version_range; + version_range.min = ssl_config_.version_min; + version_range.max = ssl_config_.version_max; + rv = SSL_VersionRangeSet(nss_fd_, &version_range); if (rv != SECSuccess) { - LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_ENABLE_SSL3"); - return ERR_UNEXPECTED; - } - - rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_TLS, ssl_config_.tls1_enabled); - if (rv != SECSuccess) { - LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_ENABLE_TLS"); - return ERR_UNEXPECTED; + LogFailedNSSFunction(net_log_, "SSL_VersionRangeSet", ""); + return ERR_NO_SSL_VERSIONS_ENABLED; } for (std::vector<uint16>::const_iterator it = diff --git a/net/socket/ssl_server_socket_unittest.cc b/net/socket/ssl_server_socket_unittest.cc index 53af569..806a598 100644 --- a/net/socket/ssl_server_socket_unittest.cc +++ b/net/socket/ssl_server_socket_unittest.cc @@ -326,8 +326,8 @@ class SSLServerSocketTest : public PlatformTest { ssl_config.cached_info_enabled = false; ssl_config.false_start_enabled = false; ssl_config.domain_bound_certs_enabled = false; - ssl_config.ssl3_enabled = true; - ssl_config.tls1_enabled = true; + ssl_config.version_min = SSL_PROTOCOL_VERSION_SSL3; + ssl_config.version_max = SSL_PROTOCOL_VERSION_TLS1_1; // Certificate provided by the host doesn't need authority. net::SSLConfig::CertAndStatus cert_and_status; diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index aae4b4e..e6b7658 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc @@ -1751,9 +1751,45 @@ TEST_F(HTTPSRequestTest, SSLv3Fallback) { EXPECT_EQ(1, d.response_started_count()); EXPECT_NE(0, d.bytes_received()); - EXPECT_EQ(SSL_CONNECTION_VERSION_SSL3, + EXPECT_EQ(static_cast<int>(SSL_CONNECTION_VERSION_SSL3), SSLConnectionStatusToVersion(r.ssl_info().connection_status)); - EXPECT_TRUE(r.ssl_info().connection_status & SSL_CONNECTION_SSL3_FALLBACK); + EXPECT_TRUE(r.ssl_info().connection_status & SSL_CONNECTION_VERSION_FALLBACK); +} + +// Tests TLSv1.1 -> TLSv1 fallback. Verifies that we don't fall back more +// than necessary. +TEST_F(HTTPSRequestTest, TLSv1Fallback) { + uint16 default_version_max = SSLConfigService::default_version_max(); + // The OpenSSL library in use may not support TLS 1.1. +#if !defined(USE_OPENSSL) + EXPECT_GT(default_version_max, SSL_PROTOCOL_VERSION_TLS1); +#endif + if (default_version_max <= SSL_PROTOCOL_VERSION_TLS1) + return; + + TestServer::HTTPSOptions https_options( + TestServer::HTTPSOptions::CERT_OK); + https_options.tls_intolerant = + TestServer::HTTPSOptions::TLS_INTOLERANT_TLS1_1; + TestServer test_server(https_options, + FilePath(FILE_PATH_LITERAL("net/data/ssl"))); + ASSERT_TRUE(test_server.Start()); + + TestDelegate d; + TestURLRequestContext context(true); + context.Init(); + d.set_allow_certificate_errors(true); + URLRequest r(test_server.GetURL(""), &d); + r.set_context(&context); + r.Start(); + + MessageLoop::current()->Run(); + + EXPECT_EQ(1, d.response_started_count()); + EXPECT_NE(0, d.bytes_received()); + EXPECT_EQ(static_cast<int>(SSL_CONNECTION_VERSION_TLS1), + SSLConnectionStatusToVersion(r.ssl_info().connection_status)); + EXPECT_TRUE(r.ssl_info().connection_status & SSL_CONNECTION_VERSION_FALLBACK); } // This tests that a load of www.google.com with a certificate error sets |