]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Disable SSLv2 in simple_httpclient.
authorBen Darnell <ben@bendarnell.com>
Mon, 9 Jan 2012 19:59:24 +0000 (11:59 -0800)
committerBen Darnell <ben@bendarnell.com>
Mon, 9 Jan 2012 19:59:24 +0000 (11:59 -0800)
Contrary to the python documentation, SSLv2 is enabled by default
unless openssl version 1.0 or newer is used; older versions appear
to still be in use (e.g. in Ubuntu 10.04 LTS and Mac OS X Lion)

tornado/simple_httpclient.py
tornado/test/httpserver_test.py

index ce2762f1d36f526be16dee0ee30cb9cb3443cee5..1f90bef93b4d3565fb048ae49c55b470ddc3767f 100644 (file)
@@ -17,6 +17,7 @@ import logging
 import os.path
 import re
 import socket
+import sys
 import time
 import urlparse
 import zlib
@@ -185,6 +186,26 @@ class _HTTPConnection(object):
                     ssl_options["keyfile"] = request.client_key
                 if request.client_cert is not None:
                     ssl_options["certfile"] = request.client_cert
+
+                # SSL interoperability is tricky.  We want to disable
+                # SSLv2 for security reasons; it wasn't disabled by default
+                # until openssl 1.0.  The best way to do this is to use
+                # the SSL_OP_NO_SSLv2, but that wasn't exposed to python
+                # until 3.2.  Python 2.7 adds the ciphers argument, which
+                # can also be used to disable SSLv2.  As a last resort
+                # on python 2.6, we set ssl_version to SSLv3.  This is
+                # more narrow than we'd like since it also breaks
+                # compatibility with servers configured for TLSv1 only,
+                # but nearly all servers support SSLv3:
+                # http://blog.ivanristic.com/2011/09/ssl-survey-protocol-support.html
+                if sys.version_info >= (2,7):
+                    ssl_options["ciphers"] = "DEFAULT:!SSLv2"
+                else:
+                    # This is really only necessary for pre-1.0 versions
+                    # of openssl, but python 2.6 doesn't expose version
+                    # information.
+                    ssl_options["ssl_version"] = ssl.PROTOCOL_SSLv3
+
                 self.stream = SSLIOStream(socket.socket(af, socktype, proto),
                                           io_loop=self.io_loop,
                                           ssl_options=ssl_options,
index 1f0fb23c2b6c7fa7150f4930fda0cfc3e2c17b02..a55ca92fc87597afd37632bbc63820f8a70812f6 100644 (file)
@@ -104,11 +104,22 @@ class SSLv3Test(BaseSSLTest, SSLTestMixin):
 class TLSv1Test(BaseSSLTest, SSLTestMixin):
     def get_ssl_version(self): return ssl.PROTOCOL_TLSv1
 
+class SSLv2Test(BaseSSLTest):
+    def get_ssl_version(self): return ssl.PROTOCOL_SSLv2
+
+    def test_sslv2_fail(self):
+        # This is really more of a client test, but run it here since
+        # we've got all the other ssl version tests here.
+        # Clients should have SSLv2 disabled by default.
+        response = self.fetch('/')
+        self.assertEqual(response.code, 599)
+
 if ssl is None:
     del BaseSSLTest
     del SSLv23Test
     del SSLv3Test
     del TLSv1Test
+    del SSLv2Test
 elif getattr(ssl, 'OPENSSL_VERSION_INFO', (0,0)) < (1,0):
     # In pre-1.0 versions of openssl, SSLv23 clients always send SSLv2
     # ClientHello messages, which are rejected by SSLv3 and TLSv1