Commit 9deb374b authored by Benjamin Peterson's avatar Benjamin Peterson

allow hostname to be passed to SSLContext even if OpenSSL doesn't support SNI (closes #22921)

Patch from Donald Stufft.
parent 919963b0
...@@ -645,8 +645,7 @@ Constants ...@@ -645,8 +645,7 @@ Constants
.. data:: HAS_SNI .. data:: HAS_SNI
Whether the OpenSSL library has built-in support for the *Server Name Whether the OpenSSL library has built-in support for the *Server Name
Indication* extension (as defined in :rfc:`4366`). When true, you can Indication* extension (as defined in :rfc:`4366`).
use the *server_hostname* argument to :meth:`SSLContext.wrap_socket`.
.. versionadded:: 2.7.9 .. versionadded:: 2.7.9
...@@ -1136,11 +1135,12 @@ to speed up repeated connections from the same clients. ...@@ -1136,11 +1135,12 @@ to speed up repeated connections from the same clients.
On client connections, the optional parameter *server_hostname* specifies On client connections, the optional parameter *server_hostname* specifies
the hostname of the service which we are connecting to. This allows a the hostname of the service which we are connecting to. This allows a
single server to host multiple SSL-based services with distinct certificates, single server to host multiple SSL-based services with distinct certificates,
quite similarly to HTTP virtual hosts. Specifying *server_hostname* quite similarly to HTTP virtual hosts. Specifying *server_hostname* will
will raise a :exc:`ValueError` if the OpenSSL library doesn't have support raise a :exc:`ValueError` if *server_side* is true.
for it (that is, if :data:`HAS_SNI` is :const:`False`). Specifying
*server_hostname* will also raise a :exc:`ValueError` if *server_side* .. versionchanged:: 3.5
is true. Always allow a server_hostname to be passed, even if OpenSSL does not
have SNI.
.. method:: SSLContext.session_stats() .. method:: SSLContext.session_stats()
......
...@@ -1214,10 +1214,9 @@ else: ...@@ -1214,10 +1214,9 @@ else:
server_hostname = self._tunnel_host server_hostname = self._tunnel_host
else: else:
server_hostname = self.host server_hostname = self.host
sni_hostname = server_hostname if ssl.HAS_SNI else None
self.sock = self._context.wrap_socket(self.sock, 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: if not self._context.check_hostname and self._check_hostname:
try: try:
ssl.match_hostname(self.sock.getpeercert(), server_hostname) ssl.match_hostname(self.sock.getpeercert(), server_hostname)
......
...@@ -527,12 +527,7 @@ class SSLSocket(socket): ...@@ -527,12 +527,7 @@ class SSLSocket(socket):
raise ValueError("server_hostname can only be specified " raise ValueError("server_hostname can only be specified "
"in client mode") "in client mode")
if self._context.check_hostname and not server_hostname: if self._context.check_hostname and not server_hostname:
if HAS_SNI:
raise ValueError("check_hostname requires server_hostname") raise ValueError("check_hostname requires server_hostname")
else:
raise ValueError("check_hostname requires server_hostname, "
"but it's not supported by your OpenSSL "
"library")
self.server_side = server_side self.server_side = server_side
self.server_hostname = server_hostname self.server_hostname = server_hostname
self.do_handshake_on_connect = do_handshake_on_connect self.do_handshake_on_connect = do_handshake_on_connect
......
...@@ -1323,11 +1323,8 @@ class NetworkedTests(unittest.TestCase): ...@@ -1323,11 +1323,8 @@ class NetworkedTests(unittest.TestCase):
# Same with a server hostname # Same with a server hostname
s = ctx.wrap_socket(socket.socket(socket.AF_INET), s = ctx.wrap_socket(socket.socket(socket.AF_INET),
server_hostname="svn.python.org") server_hostname="svn.python.org")
if ssl.HAS_SNI:
s.connect(("svn.python.org", 443)) s.connect(("svn.python.org", 443))
s.close() s.close()
else:
self.assertRaises(ValueError, s.connect, ("svn.python.org", 443))
# This should fail because we have no verification certs # This should fail because we have no verification certs
ctx.verify_mode = ssl.CERT_REQUIRED ctx.verify_mode = ssl.CERT_REQUIRED
s = ctx.wrap_socket(socket.socket(socket.AF_INET)) s = ctx.wrap_socket(socket.socket(socket.AF_INET))
...@@ -2089,7 +2086,6 @@ else: ...@@ -2089,7 +2086,6 @@ else:
cert = s.getpeercert() cert = s.getpeercert()
self.assertTrue(cert, "Can't get peer certificate.") self.assertTrue(cert, "Can't get peer certificate.")
@needs_sni
def test_check_hostname(self): def test_check_hostname(self):
if support.verbose: if support.verbose:
sys.stdout.write("\n") sys.stdout.write("\n")
......
...@@ -2824,12 +2824,6 @@ context_wrap_socket(PySSLContext *self, PyObject *args, PyObject *kwds) ...@@ -2824,12 +2824,6 @@ context_wrap_socket(PySSLContext *self, PyObject *args, PyObject *kwds)
&sock, &server_side, &sock, &server_side,
"idna", &hostname, &ssl_sock)) "idna", &hostname, &ssl_sock))
return NULL; 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, res = (PyObject *) newPySSLSocket(self, sock, server_side,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment