From 4d14fa1870841a36b2effab760bbaa52ac072d2a Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Sun, 23 Nov 2014 20:13:31 -0600 Subject: allow hostname to be passed to SSLContext even if OpenSSL doesn't support SNI (closes #22921) Patch from Donald Stufft. --- Doc/library/ssl.rst | 14 +++++++------- Lib/httplib.py | 3 +-- Lib/ssl.py | 7 +------ Lib/test/test_ssl.py | 8 ++------ Modules/_ssl.c | 6 ------ 5 files changed, 11 insertions(+), 27 deletions(-) diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index c52b073ff7..0674cdfc56 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -645,8 +645,7 @@ Constants .. data:: HAS_SNI Whether the OpenSSL library has built-in support for the *Server Name - Indication* extension (as defined in :rfc:`4366`). When true, you can - use the *server_hostname* argument to :meth:`SSLContext.wrap_socket`. + Indication* extension (as defined in :rfc:`4366`). .. versionadded:: 2.7.9 @@ -1136,11 +1135,12 @@ to speed up repeated connections from the same clients. On client connections, the optional parameter *server_hostname* specifies the hostname of the service which we are connecting to. This allows a single server to host multiple SSL-based services with distinct certificates, - quite similarly to HTTP virtual hosts. Specifying *server_hostname* - will raise a :exc:`ValueError` if the OpenSSL library doesn't have support - for it (that is, if :data:`HAS_SNI` is :const:`False`). Specifying - *server_hostname* will also raise a :exc:`ValueError` if *server_side* - is true. + quite similarly to HTTP virtual hosts. Specifying *server_hostname* will + raise a :exc:`ValueError` if *server_side* is true. + + .. versionchanged:: 3.5 + Always allow a server_hostname to be passed, even if OpenSSL does not + have SNI. .. method:: SSLContext.session_stats() diff --git a/Lib/httplib.py b/Lib/httplib.py index db5fa373a7..6d2e38d83c 100644 --- a/Lib/httplib.py +++ b/Lib/httplib.py @@ -1214,10 +1214,9 @@ else: server_hostname = self._tunnel_host else: server_hostname = self.host - sni_hostname = server_hostname if ssl.HAS_SNI else None self.sock = self._context.wrap_socket(self.sock, - server_hostname=sni_hostname) + server_hostname=server_hostname) if not self._context.check_hostname and self._check_hostname: try: ssl.match_hostname(self.sock.getpeercert(), server_hostname) diff --git a/Lib/ssl.py b/Lib/ssl.py index 4b682848e7..c9f25c0bf0 100644 --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -527,12 +527,7 @@ class SSLSocket(socket): raise ValueError("server_hostname can only be specified " "in client mode") if self._context.check_hostname and not server_hostname: - if HAS_SNI: - raise ValueError("check_hostname requires server_hostname") - else: - raise ValueError("check_hostname requires server_hostname, " - "but it's not supported by your OpenSSL " - "library") + raise ValueError("check_hostname requires server_hostname") self.server_side = server_side self.server_hostname = server_hostname self.do_handshake_on_connect = do_handshake_on_connect diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 39aa17c09f..b023fbc8a8 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -1323,11 +1323,8 @@ class NetworkedTests(unittest.TestCase): # Same with a server hostname s = ctx.wrap_socket(socket.socket(socket.AF_INET), server_hostname="svn.python.org") - if ssl.HAS_SNI: - s.connect(("svn.python.org", 443)) - s.close() - else: - self.assertRaises(ValueError, s.connect, ("svn.python.org", 443)) + s.connect(("svn.python.org", 443)) + s.close() # This should fail because we have no verification certs ctx.verify_mode = ssl.CERT_REQUIRED s = ctx.wrap_socket(socket.socket(socket.AF_INET)) @@ -2089,7 +2086,6 @@ else: cert = s.getpeercert() self.assertTrue(cert, "Can't get peer certificate.") - @needs_sni def test_check_hostname(self): if support.verbose: sys.stdout.write("\n") diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 1638ebe3b6..8ee8c3d149 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -2824,12 +2824,6 @@ context_wrap_socket(PySSLContext *self, PyObject *args, PyObject *kwds) &sock, &server_side, "idna", &hostname, &ssl_sock)) return NULL; -#if !HAVE_SNI - PyMem_Free(hostname); - PyErr_SetString(PyExc_ValueError, "server_hostname is not supported " - "by your OpenSSL library"); - return NULL; -#endif } res = (PyObject *) newPySSLSocket(self, sock, server_side, -- cgit v1.2.1