diff --git a/Doc/library/poplib.rst b/Doc/library/poplib.rst index e248d6b834a..deb49fc787f 100644 --- a/Doc/library/poplib.rst +++ b/Doc/library/poplib.rst @@ -53,6 +53,10 @@ The :mod:`poplib` module provides two classes: .. versionchanged:: 3.2 *context* parameter added. + .. versionchanged:: 3.4 + The class now supports hostname check with + :attr:`SSLContext.check_hostname` and *Server Name Indicator* (see + :data:`~ssl.HAS_SNI`). One exception is defined as an attribute of the :mod:`poplib` module: @@ -198,6 +202,11 @@ An :class:`POP3` instance has the following methods: .. versionadded:: 3.4 + .. versionchanged:: 3.4 + The method now supports hostname check with + :attr:`SSLContext.check_hostname` and *Server Name Indicator* (see + :data:`~ssl.HAS_SNI`). + Instances of :class:`POP3_SSL` have no additional methods. The interface of this subclass is identical to its parent. diff --git a/Lib/poplib.py b/Lib/poplib.py index 00ffbcb166b..23a3517e983 100644 --- a/Lib/poplib.py +++ b/Lib/poplib.py @@ -387,7 +387,9 @@ class POP3: if context is None: context = ssl._create_stdlib_context() resp = self._shortcmd('STLS') - self.sock = context.wrap_socket(self.sock) + server_hostname = self.host if ssl.HAS_SNI else None + self.sock = context.wrap_socket(self.sock, + server_hostname=server_hostname) self.file = self.sock.makefile('rb') self._tls_established = True return resp @@ -428,7 +430,9 @@ if HAVE_SSL: def _create_socket(self, timeout): sock = POP3._create_socket(self, timeout) - sock = self.context.wrap_socket(sock) + server_hostname = self.host if ssl.HAS_SNI else None + sock = self.context.wrap_socket(sock, + server_hostname=server_hostname) return sock def stls(self, keyfile=None, certfile=None, context=None): diff --git a/Lib/test/test_poplib.py b/Lib/test/test_poplib.py index 70fe4265c5b..31f8a3c85c5 100644 --- a/Lib/test/test_poplib.py +++ b/Lib/test/test_poplib.py @@ -23,7 +23,8 @@ if hasattr(poplib, 'POP3_SSL'): import ssl SUPPORTS_SSL = True - CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir, "keycert.pem") + 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") requires_ssl = skipUnless(SUPPORTS_SSL, 'SSL not supported') # the dummy data returned by server when LIST and RETR commands are issued @@ -332,6 +333,12 @@ class TestPOP3Class(TestCase): def test_stls_context(self): expected = b'+OK Begin TLS negotiation' ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) + ctx.load_verify_locations(CAFILE) + ctx.verify_mode = ssl.CERT_REQUIRED + ctx.check_hostname = True + with self.assertRaises(ssl.CertificateError): + resp = self.client.stls(context=ctx) + self.client = poplib.POP3("localhost", self.server.port, timeout=3) resp = self.client.stls(context=ctx) self.assertEqual(resp, expected) diff --git a/Misc/NEWS b/Misc/NEWS index 3785840afca..9f0dbb93550 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,9 @@ Core and Builtins Library ------- +- Issue #19784: poplib now supports SSLContext.check_hostname and server name + indication for TLS/SSL connections. + - Issue #19782: imaplib now supports SSLContext.check_hostname and server name indication for TLS/SSL connections.