[Python-checkins] cpython (3.4): don't require OpenSSL SNI to pass hostname to ssl functions (#22921)

benjamin.peterson python-checkins at python.org
Mon Nov 24 00:06:59 CET 2014


https://hg.python.org/cpython/rev/f2d4beb90a5b
changeset: 93557:f2d4beb90a5b
branch: 3.4
parent: 93551:3cc8b7227db4
user: Benjamin Peterson <benjamin at python.org>
date: Sun Nov 23 17:04:34 2014 -0600
summary:
 don't require OpenSSL SNI to pass hostname to ssl functions (#22921)
Patch by Donald Stufft.
files:
 Doc/library/ssl.rst | 14 +++++-----
 Lib/asyncio/selector_events.py | 2 +-
 Lib/ftplib.py | 6 +--
 Lib/http/client.py | 3 +-
 Lib/imaplib.py | 6 +--
 Lib/nntplib.py | 3 +-
 Lib/poplib.py | 6 +--
 Lib/smtplib.py | 6 +--
 Lib/ssl.py | 7 +----
 Lib/test/test_asyncio/test_events.py | 8 -----
 Lib/test/test_asyncio/test_selector_events.py | 2 +-
 Lib/test/test_ftplib.py | 4 --
 Lib/test/test_imaplib.py | 4 --
 Lib/test/test_poplib.py | 4 --
 Lib/test/test_ssl.py | 8 +----
 Modules/_ssl.c | 6 ----
 16 files changed, 22 insertions(+), 67 deletions(-)
diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst
--- a/Doc/library/ssl.rst
+++ b/Doc/library/ssl.rst
@@ -664,8 +664,7 @@
 .. 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:: 3.2
 
@@ -1227,11 +1226,12 @@
 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/asyncio/selector_events.py b/Lib/asyncio/selector_events.py
--- a/Lib/asyncio/selector_events.py
+++ b/Lib/asyncio/selector_events.py
@@ -708,7 +708,7 @@
 'server_side': server_side,
 'do_handshake_on_connect': False,
 }
- if server_hostname and not server_side and ssl.HAS_SNI:
+ if server_hostname and not server_side:
 wrap_kwargs['server_hostname'] = server_hostname
 sslsock = sslcontext.wrap_socket(rawsock, **wrap_kwargs)
 
diff --git a/Lib/ftplib.py b/Lib/ftplib.py
--- a/Lib/ftplib.py
+++ b/Lib/ftplib.py
@@ -747,9 +747,8 @@
 resp = self.voidcmd('AUTH TLS')
 else:
 resp = self.voidcmd('AUTH SSL')
- server_hostname = self.host if ssl.HAS_SNI else None
 self.sock = self.context.wrap_socket(self.sock,
- server_hostname=server_hostname)
+ server_hostname=self.host)
 self.file = self.sock.makefile(mode='r', encoding=self.encoding)
 return resp
 
@@ -788,9 +787,8 @@
 def ntransfercmd(self, cmd, rest=None):
 conn, size = FTP.ntransfercmd(self, cmd, rest)
 if self._prot_p:
- server_hostname = self.host if ssl.HAS_SNI else None
 conn = self.context.wrap_socket(conn,
- server_hostname=server_hostname)
+ server_hostname=self.host)
 return conn, size
 
 def abort(self):
diff --git a/Lib/http/client.py b/Lib/http/client.py
--- a/Lib/http/client.py
+++ b/Lib/http/client.py
@@ -1224,10 +1224,9 @@
 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/imaplib.py b/Lib/imaplib.py
--- a/Lib/imaplib.py
+++ b/Lib/imaplib.py
@@ -745,9 +745,8 @@
 ssl_context = ssl._create_stdlib_context()
 typ, dat = self._simple_command(name)
 if typ == 'OK':
- server_hostname = self.host if ssl.HAS_SNI else None
 self.sock = ssl_context.wrap_socket(self.sock,
- server_hostname=server_hostname)
+ server_hostname=self.host)
 self.file = self.sock.makefile('rb')
 self._tls_established = True
 self._get_capabilities()
@@ -1223,9 +1222,8 @@
 
 def _create_socket(self):
 sock = IMAP4._create_socket(self)
- server_hostname = self.host if ssl.HAS_SNI else None
 return self.ssl_context.wrap_socket(sock,
- server_hostname=server_hostname)
+ server_hostname=self.host)
 
 def open(self, host='', port=IMAP4_SSL_PORT):
 """Setup connection to remote server on "host:port".
diff --git a/Lib/nntplib.py b/Lib/nntplib.py
--- a/Lib/nntplib.py
+++ b/Lib/nntplib.py
@@ -289,8 +289,7 @@
 # Generate a default SSL context if none was passed.
 if context is None:
 context = ssl._create_stdlib_context()
- server_hostname = hostname if ssl.HAS_SNI else None
- return context.wrap_socket(sock, server_hostname=server_hostname)
+ return context.wrap_socket(sock, server_hostname=hostname)
 
 
 # The classes themselves
diff --git a/Lib/poplib.py b/Lib/poplib.py
--- a/Lib/poplib.py
+++ b/Lib/poplib.py
@@ -387,9 +387,8 @@
 if context is None:
 context = ssl._create_stdlib_context()
 resp = self._shortcmd('STLS')
- server_hostname = self.host if ssl.HAS_SNI else None
 self.sock = context.wrap_socket(self.sock,
- server_hostname=server_hostname)
+ server_hostname=self.host)
 self.file = self.sock.makefile('rb')
 self._tls_established = True
 return resp
@@ -430,9 +429,8 @@
 
 def _create_socket(self, timeout):
 sock = POP3._create_socket(self, timeout)
- server_hostname = self.host if ssl.HAS_SNI else None
 sock = self.context.wrap_socket(sock,
- server_hostname=server_hostname)
+ server_hostname=self.host)
 return sock
 
 def stls(self, keyfile=None, certfile=None, context=None):
diff --git a/Lib/smtplib.py b/Lib/smtplib.py
--- a/Lib/smtplib.py
+++ b/Lib/smtplib.py
@@ -684,9 +684,8 @@
 if context is None:
 context = ssl._create_stdlib_context(certfile=certfile,
 keyfile=keyfile)
- server_hostname = self._host if ssl.HAS_SNI else None
 self.sock = context.wrap_socket(self.sock,
- server_hostname=server_hostname)
+ server_hostname=self._host)
 self.file = None
 # RFC 3207:
 # The client MUST discard any knowledge obtained from
@@ -915,9 +914,8 @@
 print('connect:', (host, port), file=stderr)
 new_socket = socket.create_connection((host, port), timeout,
 self.source_address)
- server_hostname = self._host if ssl.HAS_SNI else None
 new_socket = self.context.wrap_socket(new_socket,
- server_hostname=server_hostname)
+ server_hostname=self._host)
 return new_socket
 
 __all__.append("SMTP_SSL")
diff --git a/Lib/ssl.py b/Lib/ssl.py
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -538,12 +538,7 @@
 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_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py
--- a/Lib/test/test_asyncio/test_events.py
+++ b/Lib/test/test_asyncio/test_events.py
@@ -12,9 +12,6 @@
 import ssl
 except ImportError:
 ssl = None
- HAS_SNI = False
-else:
- from ssl import HAS_SNI
 import subprocess
 import sys
 import threading
@@ -857,7 +854,6 @@
 server.close()
 
 @unittest.skipIf(ssl is None, 'No ssl module')
- @unittest.skipUnless(HAS_SNI, 'No SNI support in ssl module')
 def test_create_server_ssl_verify_failed(self):
 proto = MyProto(loop=self.loop)
 server, host, port = self._make_ssl_server(
@@ -882,7 +878,6 @@
 server.close()
 
 @unittest.skipIf(ssl is None, 'No ssl module')
- @unittest.skipUnless(HAS_SNI, 'No SNI support in ssl module')
 @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'No UNIX Sockets')
 def test_create_unix_server_ssl_verify_failed(self):
 proto = MyProto(loop=self.loop)
@@ -909,7 +904,6 @@
 server.close()
 
 @unittest.skipIf(ssl is None, 'No ssl module')
- @unittest.skipUnless(HAS_SNI, 'No SNI support in ssl module')
 def test_create_server_ssl_match_failed(self):
 proto = MyProto(loop=self.loop)
 server, host, port = self._make_ssl_server(
@@ -937,7 +931,6 @@
 server.close()
 
 @unittest.skipIf(ssl is None, 'No ssl module')
- @unittest.skipUnless(HAS_SNI, 'No SNI support in ssl module')
 @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'No UNIX Sockets')
 def test_create_unix_server_ssl_verified(self):
 proto = MyProto(loop=self.loop)
@@ -963,7 +956,6 @@
 server.close()
 
 @unittest.skipIf(ssl is None, 'No ssl module')
- @unittest.skipUnless(HAS_SNI, 'No SNI support in ssl module')
 def test_create_server_ssl_verified(self):
 proto = MyProto(loop=self.loop)
 server, host, port = self._make_ssl_server(
diff --git a/Lib/test/test_asyncio/test_selector_events.py b/Lib/test/test_asyncio/test_selector_events.py
--- a/Lib/test/test_asyncio/test_selector_events.py
+++ b/Lib/test/test_asyncio/test_selector_events.py
@@ -1408,7 +1408,7 @@
 self.assertEqual(tr._conn_lost, 1)
 self.assertEqual(1, self.loop.remove_reader_count[1])
 
- @unittest.skipIf(ssl is None or not ssl.HAS_SNI, 'No SNI support')
+ @unittest.skipIf(ssl is None, 'No SSL support')
 def test_server_hostname(self):
 _SelectorSslTransport(
 self.loop, self.sock, self.protocol, self.sslcontext,
diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py
--- a/Lib/test/test_ftplib.py
+++ b/Lib/test/test_ftplib.py
@@ -15,9 +15,6 @@
 import ssl
 except ImportError:
 ssl = None
- HAS_SNI = False
-else:
- from ssl import HAS_SNI
 
 from unittest import TestCase, skipUnless
 from test import support
@@ -927,7 +924,6 @@
 self.client.ccc()
 self.assertRaises(ValueError, self.client.sock.unwrap)
 
- @skipUnless(HAS_SNI, 'No SNI support in ssl module')
 def test_check_hostname(self):
 self.client.quit()
 ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py
--- a/Lib/test/test_imaplib.py
+++ b/Lib/test/test_imaplib.py
@@ -18,9 +18,6 @@
 import ssl
 except ImportError:
 ssl = None
- HAS_SNI = False
-else:
- from ssl import HAS_SNI
 
 CERTFILE = None
 CAFILE = None
@@ -352,7 +349,6 @@
 imap_class = IMAP4_SSL
 
 @reap_threads
- @unittest.skipUnless(HAS_SNI, 'No SNI support in ssl module')
 def test_ssl_verified(self):
 ssl_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
 ssl_context.verify_mode = ssl.CERT_REQUIRED
diff --git a/Lib/test/test_poplib.py b/Lib/test/test_poplib.py
--- a/Lib/test/test_poplib.py
+++ b/Lib/test/test_poplib.py
@@ -21,13 +21,10 @@
 SUPPORTS_SSL = False
 if hasattr(poplib, 'POP3_SSL'):
 import ssl
- from ssl import HAS_SNI
 
 SUPPORTS_SSL = True
 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir, "keycert3.pem")
 CAFILE = os.path.join(os.path.dirname(__file__) or os.curdir, "pycacert.pem")
-else:
- HAS_SNI = False
 
 requires_ssl = skipUnless(SUPPORTS_SSL, 'SSL not supported')
 
@@ -334,7 +331,6 @@
 self.assertEqual(resp, expected)
 
 @requires_ssl
- @skipUnless(HAS_SNI, 'No SNI support in ssl module')
 def test_stls_context(self):
 expected = b'+OK Begin TLS negotiation'
 ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -1281,11 +1281,8 @@
 # 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))
@@ -2038,7 +2035,6 @@
 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
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -2806,12 +2806,6 @@
 &sock, &server_side,
 "idna", &hostname))
 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,
-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /