diff options
-rw-r--r-- | net/http/http_network_transaction.cc | 21 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_nss.cc | 43 | ||||
-rw-r--r-- | net/url_request/url_request_unittest.cc | 28 |
3 files changed, 54 insertions, 38 deletions
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index 0e278eb..0a2c8c4 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -1306,6 +1306,7 @@ int HttpNetworkTransaction::HandleSSLHandshakeError(int error) { uint16 version_max = server_ssl_config_.version_max; switch (error) { + case ERR_CONNECTION_CLOSED: case ERR_SSL_PROTOCOL_ERROR: case ERR_SSL_VERSION_OR_CIPHER_MISMATCH: if (version_max >= SSL_PROTOCOL_VERSION_TLS1 && @@ -1329,6 +1330,26 @@ int HttpNetworkTransaction::HandleSSLHandshakeError(int error) { should_fallback = true; } break; + case ERR_CONNECTION_RESET: + if (version_max >= SSL_PROTOCOL_VERSION_TLS1_1 && + version_max > server_ssl_config_.version_min) { + // Some network devices that inspect application-layer packets seem to + // inject TCP reset packets to break the connections when they see TLS + // 1.1 in ClientHello or ServerHello. See http://crbug.com/130293. + // + // Only allow ERR_CONNECTION_RESET to trigger a fallback from TLS 1.1 or + // 1.2. We don't lose much in this fallback because the explicit IV for + // CBC mode in TLS 1.1 is approximated by record splitting in TLS + // 1.0. The fallback will be more painful for TLS 1.2 when we have GCM + // support. + // + // ERR_CONNECTION_RESET is a common network error, so we don't want it + // to trigger a version fallback in general, especially the TLS 1.0 -> + // SSL 3.0 fallback, which would drop TLS extensions. + version_max--; + should_fallback = true; + } + break; case ERR_SSL_BAD_RECORD_MAC_ALERT: if (version_max >= SSL_PROTOCOL_VERSION_TLS1_1 && version_max > server_ssl_config_.version_min) { diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc index deece93..6eca964 100644 --- a/net/socket/ssl_client_socket_nss.cc +++ b/net/socket/ssl_client_socket_nss.cc @@ -474,18 +474,6 @@ int MapNSSClientError(PRErrorCode err) { } } -// Map NSS error code from the first SSL handshake to network error code. -int MapNSSClientHandshakeError(PRErrorCode err) { - switch (err) { - // If the server closed on us, it is a protocol error. - // Some TLS-intolerant servers do this when we request TLS. - case PR_END_OF_FILE_ERROR: - return ERR_SSL_PROTOCOL_ERROR; - default: - return MapNSSClientError(err); - } -} - } // namespace // SSLClientSocketNSS::Core provides a thread-safe, ref-counted core that is @@ -720,7 +708,7 @@ class SSLClientSocketNSS::Core : public base::RefCountedThreadSafe<Core> { // Handles an NSS error generated while handshaking or performing IO. // Returns a network error code mapped from the original NSS error. - int HandleNSSError(PRErrorCode error, bool handshake_error); + int HandleNSSError(PRErrorCode error); int DoHandshakeLoop(int last_io_result); int DoReadLoop(int result); @@ -1683,12 +1671,10 @@ void SSLClientSocketNSS::Core::HandshakeSucceeded() { nss_handshake_state_)); } -int SSLClientSocketNSS::Core::HandleNSSError(PRErrorCode nss_error, - bool handshake_error) { +int SSLClientSocketNSS::Core::HandleNSSError(PRErrorCode nss_error) { DCHECK(OnNSSTaskRunner()); - int net_error = handshake_error ? MapNSSClientHandshakeError(nss_error) : - MapNSSClientError(nss_error); + int net_error = MapNSSClientError(nss_error); #if defined(OS_WIN) // On Windows, a handle to the HCRYPTPROV is cached in the X509Certificate @@ -1846,24 +1832,7 @@ int SSLClientSocketNSS::Core::DoHandshake() { } } else { PRErrorCode prerr = PR_GetError(); - net_error = HandleNSSError(prerr, true); - - // Some network devices that inspect application-layer packets seem to - // inject TCP reset packets to break the connections when they see - // TLS 1.1 in ClientHello or ServerHello. See http://crbug.com/130293. - // - // Only allow ERR_CONNECTION_RESET to trigger a fallback from TLS 1.1 or - // 1.2. We don't lose much in this fallback because the explicit IV for CBC - // mode in TLS 1.1 is approximated by record splitting in TLS 1.0. The - // fallback will be more painful for TLS 1.2 when we have GCM support. - // - // ERR_CONNECTION_RESET is a common network error, so we don't want it - // to trigger a version fallback in general, especially the TLS 1.0 -> - // SSL 3.0 fallback, which would drop TLS extensions. - if (prerr == PR_CONNECT_RESET_ERROR && - ssl_config_.version_max >= SSL_PROTOCOL_VERSION_TLS1_1) { - net_error = ERR_SSL_PROTOCOL_ERROR; - } + net_error = HandleNSSError(prerr); // If not done, stay in this state if (net_error == ERR_IO_PENDING) { @@ -1990,7 +1959,7 @@ int SSLClientSocketNSS::Core::DoPayloadRead() { // If *next_result == 0, then that indicates EOF, and no special error // handling is needed. pending_read_nss_error_ = PR_GetError(); - *next_result = HandleNSSError(pending_read_nss_error_, false); + *next_result = HandleNSSError(pending_read_nss_error_); if (rv > 0 && *next_result == ERR_IO_PENDING) { // If at least some data was read from PR_Read(), do not treat // insufficient data as an error to return in the next call to @@ -2052,7 +2021,7 @@ int SSLClientSocketNSS::Core::DoPayloadWrite() { if (prerr == PR_WOULD_BLOCK_ERROR) return ERR_IO_PENDING; - rv = HandleNSSError(prerr, false); + rv = HandleNSSError(prerr); PostOrRunCallback( FROM_HERE, base::Bind(&AddLogEventWithCallback, weak_net_log_, diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index c770041..d139888 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc @@ -7046,7 +7046,8 @@ TEST_F(HTTPSFallbackTest, TLSv1FallbackReset) { } #endif // !OS_ANDROID -// Tests that we don't fallback with servers that implement TLS_FALLBACK_SCSV. +// Tests that we don't fallback on handshake failure with servers that implement +// TLS_FALLBACK_SCSV. Also ensure that the original error code is reported. #if defined(USE_OPENSSL) TEST_F(HTTPSFallbackTest, DISABLED_FallbackSCSV) { #else @@ -7071,6 +7072,31 @@ TEST_F(HTTPSFallbackTest, FallbackSCSV) { ExpectFailure(ERR_SSL_VERSION_OR_CIPHER_MISMATCH); } +// Tests that we don't fallback on connection closed with servers that implement +// TLS_FALLBACK_SCSV. Also ensure that the original error code is reported. +#if defined(USE_OPENSSL) +TEST_F(HTTPSFallbackTest, DISABLED_FallbackSCSVClosed) { +#else +TEST_F(HTTPSFallbackTest, FallbackSCSVClosed) { +#endif + SpawnedTestServer::SSLOptions ssl_options( + SpawnedTestServer::SSLOptions::CERT_OK); + // Configure HTTPS server to be intolerant of TLS >= 1.0 in order to trigger + // a version fallback. + ssl_options.tls_intolerant = + SpawnedTestServer::SSLOptions::TLS_INTOLERANT_ALL; + ssl_options.tls_intolerance_type = + SpawnedTestServer::SSLOptions::TLS_INTOLERANCE_CLOSE; + // Have the server process TLS_FALLBACK_SCSV so that version fallback + // connections are rejected. + ssl_options.fallback_scsv_enabled = true; + + ASSERT_NO_FATAL_FAILURE(DoFallbackTest(ssl_options)); + + // The original error should be replayed on rejected fallback. + ExpectFailure(ERR_CONNECTION_CLOSED); +} + // Tests that the SSLv3 fallback triggers on alert. TEST_F(HTTPSFallbackTest, SSLv3Fallback) { SpawnedTestServer::SSLOptions ssl_options( |