summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/http/http_network_transaction.cc6
-rw-r--r--net/http/http_stream_factory.h3
-rw-r--r--net/http/http_stream_factory_impl.cc9
-rw-r--r--net/http/http_stream_factory_impl.h4
-rw-r--r--net/http/http_stream_factory_impl_job.cc7
-rw-r--r--net/test/base_test_server.cc8
-rw-r--r--net/test/base_test_server.h4
-rwxr-xr-xnet/tools/testserver/testserver.py14
-rw-r--r--net/url_request/url_request_unittest.cc23
-rw-r--r--third_party/tlslite/README.chromium1
-rw-r--r--third_party/tlslite/patches/tls_intolerant.patch60
-rw-r--r--third_party/tlslite/tlslite/TLSConnection.py16
12 files changed, 120 insertions, 35 deletions
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index 43df7ce..7b52766 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -1168,8 +1168,10 @@ int HttpNetworkTransaction::HandleSSLHandshakeError(int error) {
// 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.
- session_->http_stream_factory()->AddTLSIntolerantServer(
- HostPortPair::FromURL(request_->url));
+ 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;
ResetConnectionAndRequestForResend();
error = OK;
}
diff --git a/net/http/http_stream_factory.h b/net/http/http_stream_factory.h
index 58efdf3..df9cecf 100644
--- a/net/http/http_stream_factory.h
+++ b/net/http/http_stream_factory.h
@@ -180,9 +180,6 @@ class NET_EXPORT HttpStreamFactory {
const SSLConfig& server_ssl_config,
const SSLConfig& proxy_ssl_config) = 0;
- virtual void AddTLSIntolerantServer(const HostPortPair& server) = 0;
- virtual bool IsTLSIntolerantServer(const HostPortPair& server) const = 0;
-
// If pipelining is supported, creates a Value summary of the currently active
// pipelines. Caller assumes ownership of the returned value. Otherwise,
// returns an empty Value.
diff --git a/net/http/http_stream_factory_impl.cc b/net/http/http_stream_factory_impl.cc
index c142224..75e7365 100644
--- a/net/http/http_stream_factory_impl.cc
+++ b/net/http/http_stream_factory_impl.cc
@@ -119,15 +119,6 @@ void HttpStreamFactoryImpl::PreconnectStreams(
job->Preconnect(num_streams);
}
-void HttpStreamFactoryImpl::AddTLSIntolerantServer(const HostPortPair& server) {
- tls_intolerant_servers_.insert(server);
-}
-
-bool HttpStreamFactoryImpl::IsTLSIntolerantServer(
- const HostPortPair& server) const {
- return ContainsKey(tls_intolerant_servers_, server);
-}
-
base::Value* HttpStreamFactoryImpl::PipelineInfoToValue() const {
return http_pipelined_host_pool_.PipelineInfoToValue();
}
diff --git a/net/http/http_stream_factory_impl.h b/net/http/http_stream_factory_impl.h
index 238b435..2542298 100644
--- a/net/http/http_stream_factory_impl.h
+++ b/net/http/http_stream_factory_impl.h
@@ -42,8 +42,6 @@ class NET_EXPORT_PRIVATE HttpStreamFactoryImpl :
const HttpRequestInfo& info,
const SSLConfig& server_ssl_config,
const SSLConfig& proxy_ssl_config) OVERRIDE;
- virtual void AddTLSIntolerantServer(const HostPortPair& server) OVERRIDE;
- virtual bool IsTLSIntolerantServer(const HostPortPair& server) const OVERRIDE;
virtual base::Value* PipelineInfoToValue() const OVERRIDE;
// HttpPipelinedHostPool::Delegate interface
@@ -99,8 +97,6 @@ class NET_EXPORT_PRIVATE HttpStreamFactoryImpl :
HttpNetworkSession* const session_;
- std::set<HostPortPair> tls_intolerant_servers_;
-
// All Requests are handed out to clients. By the time HttpStreamFactoryImpl
// is destroyed, all Requests should be deleted (which should remove them from
// |request_map_|. The Requests will delete the corresponding job.
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc
index 408c75e..bc4af30 100644
--- a/net/http/http_stream_factory_impl_job.cc
+++ b/net/http/http_stream_factory_impl_job.cc
@@ -1051,13 +1051,6 @@ bool HttpStreamFactoryImpl::Job::IsHttpsProxyAndHttpUrl() {
void HttpStreamFactoryImpl::Job::InitSSLConfig(
const HostPortPair& origin_server,
SSLConfig* ssl_config) const {
- if (stream_factory_->IsTLSIntolerantServer(origin_server)) {
- LOG(WARNING) << "Falling back to SSLv3 because host is TLS intolerant: "
- << origin_server.ToString();
- ssl_config->ssl3_fallback = true;
- ssl_config->tls1_enabled = false;
- }
-
if (proxy_info_.is_https() && ssl_config->send_client_cert) {
// When connecting through an HTTPS proxy, disable TLS False Start so
// that client authentication errors can be distinguished between those
diff --git a/net/test/base_test_server.cc b/net/test/base_test_server.cc
index eefd953..533cb9d 100644
--- a/net/test/base_test_server.cc
+++ b/net/test/base_test_server.cc
@@ -58,14 +58,16 @@ BaseTestServer::HTTPSOptions::HTTPSOptions()
ocsp_status(OCSP_OK),
request_client_certificate(false),
bulk_ciphers(HTTPSOptions::BULK_CIPHER_ANY),
- record_resume(false) {}
+ record_resume(false),
+ tls_intolerant(false) {}
BaseTestServer::HTTPSOptions::HTTPSOptions(
BaseTestServer::HTTPSOptions::ServerCertificate cert)
: server_certificate(cert),
request_client_certificate(false),
bulk_ciphers(HTTPSOptions::BULK_CIPHER_ANY),
- record_resume(false) {}
+ record_resume(false),
+ tls_intolerant(false) {}
BaseTestServer::HTTPSOptions::~HTTPSOptions() {}
@@ -375,6 +377,8 @@ bool BaseTestServer::GenerateArguments(base::DictionaryValue* arguments) const {
arguments->Set("ssl-bulk-cipher", bulk_cipher_values.release());
if (https_options_.record_resume)
arguments->Set("https-record-resume", base::Value::CreateNullValue());
+ if (https_options_.tls_intolerant)
+ arguments->Set("tls-intolerant", base::Value::CreateNullValue());
}
return true;
}
diff --git a/net/test/base_test_server.h b/net/test/base_test_server.h
index fd04e55..f7d5654 100644
--- a/net/test/base_test_server.h
+++ b/net/test/base_test_server.h
@@ -126,6 +126,10 @@ class BaseTestServer {
// causes it to log session cache actions and echo the log on
// /ssl-session-cache.
bool record_resume;
+
+ // If true, the server will abort any TLS handshake in order to test
+ // SSLv3 fallback.
+ bool tls_intolerant;
};
// Pass as the 'host' parameter during construction to server on 127.0.0.1
diff --git a/net/tools/testserver/testserver.py b/net/tools/testserver/testserver.py
index 6461997..9fc92ee 100755
--- a/net/tools/testserver/testserver.py
+++ b/net/tools/testserver/testserver.py
@@ -133,11 +133,13 @@ class HTTPSServer(tlslite.api.TLSSocketServerMixIn,
def __init__(self, server_address, request_hander_class, pem_cert_and_key,
ssl_client_auth, ssl_client_cas, ssl_bulk_ciphers,
- record_resume_info):
+ record_resume_info, tls_intolerant):
self.cert_chain = tlslite.api.X509CertChain().parseChain(pem_cert_and_key)
self.private_key = tlslite.api.parsePEMKey(pem_cert_and_key, private=True)
self.ssl_client_auth = ssl_client_auth
self.ssl_client_cas = []
+ self.tls_intolerant = tls_intolerant
+
for ca_file in ssl_client_cas:
s = open(ca_file).read()
x509 = tlslite.api.X509()
@@ -163,7 +165,8 @@ class HTTPSServer(tlslite.api.TLSSocketServerMixIn,
sessionCache=self.session_cache,
reqCert=self.ssl_client_auth,
settings=self.ssl_handshake_settings,
- reqCAs=self.ssl_client_cas)
+ reqCAs=self.ssl_client_cas,
+ tlsIntolerant=self.tls_intolerant)
tlsConnection.ignoreAbruptClose = True
return True
except tlslite.api.TLSAbruptCloseError:
@@ -2045,7 +2048,8 @@ def main(options, args):
return
server = HTTPSServer((host, port), TestPageHandler, pem_cert_and_key,
options.ssl_client_auth, options.ssl_client_ca,
- options.ssl_bulk_cipher, options.record_resume)
+ options.ssl_bulk_cipher, options.record_resume,
+ options.tls_intolerant)
print 'HTTPS server started on %s:%d...' % (host, server.server_port)
else:
server = HTTPServer((host, port), TestPageHandler)
@@ -2172,6 +2176,10 @@ if __name__ == '__main__':
help='The type of OCSP response generated for the '
'automatically generated certificate. One of '
'[ok,revoked,invalid]')
+ option_parser.add_option('', '--tls-intolerant', dest='tls_intolerant',
+ const=True, default=False, action='store_const',
+ help='If true, TLS connections will be aborted '
+ ' in order to test SSLv3 fallback.')
option_parser.add_option('', '--https-record-resume', dest='record_resume',
const=True, default=False, action='store_const',
help='Record resumption cache events rather than'
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index d825711..7126fa3 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -1726,6 +1726,29 @@ TEST_F(HTTPSCRLSetTest, ExpiredCRLSet) {
EXPECT_FALSE(cert_status & CERT_STATUS_REV_CHECKING_ENABLED);
}
+TEST_F(HTTPSRequestTest, SSLv3Fallback) {
+ TestServer::HTTPSOptions https_options(
+ TestServer::HTTPSOptions::CERT_OK);
+ https_options.tls_intolerant = true;
+ TestServer test_server(https_options,
+ FilePath(FILE_PATH_LITERAL("net/data/ssl")));
+ ASSERT_TRUE(test_server.Start());
+
+ TestDelegate d;
+ scoped_refptr<TestURLRequestContext> context(new TestURLRequestContext(true));
+ context->Init();
+ d.set_allow_certificate_errors(true);
+ URLRequest r(test_server.GetURL(""), &d);
+ r.set_context(context.get());
+ r.Start();
+
+ MessageLoop::current()->Run();
+
+ EXPECT_EQ(1, d.response_started_count());
+ EXPECT_NE(0, d.bytes_received());
+ EXPECT_TRUE(r.ssl_info().connection_status & SSL_CONNECTION_SSL3_FALLBACK);
+}
+
// This tests that a load of www.google.com with a certificate error sets
// the |certificate_errors_are_fatal| flag correctly. This flag will cause
// the interstitial to be fatal.
diff --git a/third_party/tlslite/README.chromium b/third_party/tlslite/README.chromium
index ea99656..916fd36 100644
--- a/third_party/tlslite/README.chromium
+++ b/third_party/tlslite/README.chromium
@@ -30,3 +30,4 @@ Local Modifications:
- patches/parse_chain.patch: tlslite/X509CertChain.py and tlslite/X509.py were
updated to add a parseChain method, that can parse multiple certificates from
a PEM string.
+- patches/tls_intolerant.patch: allow TLSLite to simulate a TLS-intolerant server.
diff --git a/third_party/tlslite/patches/tls_intolerant.patch b/third_party/tlslite/patches/tls_intolerant.patch
new file mode 100644
index 0000000..506b4d3c
--- /dev/null
+++ b/third_party/tlslite/patches/tls_intolerant.patch
@@ -0,0 +1,60 @@
+diff --git a/third_party/tlslite/tlslite/TLSConnection.py b/third_party/tlslite/tlslite/TLSConnection.py
+index 7e38a23..02c7478 100644
+--- a/third_party/tlslite/tlslite/TLSConnection.py
++++ b/third_party/tlslite/tlslite/TLSConnection.py
+@@ -932,7 +932,7 @@ class TLSConnection(TLSRecordLayer):
+ def handshakeServer(self, sharedKeyDB=None, verifierDB=None,
+ certChain=None, privateKey=None, reqCert=False,
+ sessionCache=None, settings=None, checker=None,
+- reqCAs=None):
++ reqCAs=None, tlsIntolerant=False):
+ """Perform a handshake in the role of server.
+
+ This function performs an SSL or TLS handshake. Depending on
+@@ -1012,14 +1012,14 @@ class TLSConnection(TLSRecordLayer):
+ """
+ for result in self.handshakeServerAsync(sharedKeyDB, verifierDB,
+ certChain, privateKey, reqCert, sessionCache, settings,
+- checker, reqCAs):
++ checker, reqCAs, tlsIntolerant):
+ pass
+
+
+ def handshakeServerAsync(self, sharedKeyDB=None, verifierDB=None,
+ certChain=None, privateKey=None, reqCert=False,
+ sessionCache=None, settings=None, checker=None,
+- reqCAs=None):
++ reqCAs=None, tlsIntolerant=False):
+ """Start a server handshake operation on the TLS connection.
+
+ This function returns a generator which behaves similarly to
+@@ -1036,14 +1036,15 @@ class TLSConnection(TLSRecordLayer):
+ verifierDB=verifierDB, certChain=certChain,
+ privateKey=privateKey, reqCert=reqCert,
+ sessionCache=sessionCache, settings=settings,
+- reqCAs=reqCAs)
++ reqCAs=reqCAs,
++ tlsIntolerant=tlsIntolerant)
+ for result in self._handshakeWrapperAsync(handshaker, checker):
+ yield result
+
+
+ def _handshakeServerAsyncHelper(self, sharedKeyDB, verifierDB,
+ certChain, privateKey, reqCert, sessionCache,
+- settings, reqCAs):
++ settings, reqCAs, tlsIntolerant):
+
+ self._handshakeStart(client=False)
+
+@@ -1111,6 +1112,11 @@ class TLSConnection(TLSRecordLayer):
+ "Too old version: %s" % str(clientHello.client_version)):
+ yield result
+
++ if tlsIntolerant and clientHello.client_version > (3, 0):
++ for result in self._sendError(\
++ AlertDescription.handshake_failure):
++ yield result
++
+ #If client's version is too high, propose my highest version
+ elif clientHello.client_version > settings.maxVersion:
+ self.version = settings.maxVersion
diff --git a/third_party/tlslite/tlslite/TLSConnection.py b/third_party/tlslite/tlslite/TLSConnection.py
index 7e38a23..02c7478 100644
--- a/third_party/tlslite/tlslite/TLSConnection.py
+++ b/third_party/tlslite/tlslite/TLSConnection.py
@@ -932,7 +932,7 @@ class TLSConnection(TLSRecordLayer):
def handshakeServer(self, sharedKeyDB=None, verifierDB=None,
certChain=None, privateKey=None, reqCert=False,
sessionCache=None, settings=None, checker=None,
- reqCAs=None):
+ reqCAs=None, tlsIntolerant=False):
"""Perform a handshake in the role of server.
This function performs an SSL or TLS handshake. Depending on
@@ -1012,14 +1012,14 @@ class TLSConnection(TLSRecordLayer):
"""
for result in self.handshakeServerAsync(sharedKeyDB, verifierDB,
certChain, privateKey, reqCert, sessionCache, settings,
- checker, reqCAs):
+ checker, reqCAs, tlsIntolerant):
pass
def handshakeServerAsync(self, sharedKeyDB=None, verifierDB=None,
certChain=None, privateKey=None, reqCert=False,
sessionCache=None, settings=None, checker=None,
- reqCAs=None):
+ reqCAs=None, tlsIntolerant=False):
"""Start a server handshake operation on the TLS connection.
This function returns a generator which behaves similarly to
@@ -1036,14 +1036,15 @@ class TLSConnection(TLSRecordLayer):
verifierDB=verifierDB, certChain=certChain,
privateKey=privateKey, reqCert=reqCert,
sessionCache=sessionCache, settings=settings,
- reqCAs=reqCAs)
+ reqCAs=reqCAs,
+ tlsIntolerant=tlsIntolerant)
for result in self._handshakeWrapperAsync(handshaker, checker):
yield result
def _handshakeServerAsyncHelper(self, sharedKeyDB, verifierDB,
certChain, privateKey, reqCert, sessionCache,
- settings, reqCAs):
+ settings, reqCAs, tlsIntolerant):
self._handshakeStart(client=False)
@@ -1111,6 +1112,11 @@ class TLSConnection(TLSRecordLayer):
"Too old version: %s" % str(clientHello.client_version)):
yield result
+ if tlsIntolerant and clientHello.client_version > (3, 0):
+ for result in self._sendError(\
+ AlertDescription.handshake_failure):
+ yield result
+
#If client's version is too high, propose my highest version
elif clientHello.client_version > settings.maxVersion:
self.version = settings.maxVersion