From 48aae57996c89a5601534320fdd078da978fb7bb Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Mon, 2 Dec 2013 20:01:29 +0100 Subject: [PATCH] Issue #19782: imaplib now supports SSLContext.check_hostname and server name indication for TLS/SSL connections. --- Doc/library/imaplib.rst | 8 ++++++++ Lib/imaplib.py | 8 ++++++-- Lib/test/test_imaplib.py | 28 ++++++++++++++++++++++++++-- Misc/NEWS | 3 +++ 4 files changed, 43 insertions(+), 4 deletions(-) diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst index 01236fbb8ea..be2f599b0c4 100644 --- a/Doc/library/imaplib.rst +++ b/Doc/library/imaplib.rst @@ -80,6 +80,10 @@ There's also a subclass for secure connections: .. versionchanged:: 3.3 *ssl_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`). The second subclass allows for connections created by a child process: @@ -437,6 +441,10 @@ An :class:`IMAP4` instance has the following methods: .. versionadded:: 3.2 + .. versionchanged:: 3.4 + The method now supports hostname check with + :attr:`SSLContext.check_hostname` and *Server Name Indicator* (see + :data:`~ssl.HAS_SNI`). .. method:: IMAP4.status(mailbox, names) diff --git a/Lib/imaplib.py b/Lib/imaplib.py index dabf161b87a..ade2f9c2aa0 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -745,7 +745,9 @@ class IMAP4: ssl_context = ssl._create_stdlib_context() typ, dat = self._simple_command(name) if typ == 'OK': - self.sock = ssl_context.wrap_socket(self.sock) + server_hostname = self.host if ssl.HAS_SNI else None + self.sock = ssl_context.wrap_socket(self.sock, + server_hostname=server_hostname) self.file = self.sock.makefile('rb') self._tls_established = True self._get_capabilities() @@ -1216,7 +1218,9 @@ if HAVE_SSL: def _create_socket(self): sock = IMAP4._create_socket(self) - return self.ssl_context.wrap_socket(sock) + server_hostname = self.host if ssl.HAS_SNI else None + return self.ssl_context.wrap_socket(sock, + server_hostname=server_hostname) def open(self, host='', port=IMAP4_SSL_PORT): """Setup connection to remote server on "host:port". diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index 81bfd1fbc2d..bafd62b63d2 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -20,6 +20,7 @@ except ImportError: ssl = None CERTFILE = None +CAFILE = None class TestImaplib(unittest.TestCase): @@ -348,6 +349,25 @@ class ThreadedNetworkedTestsSSL(BaseThreadedNetworkedTests): server_class = SecureTCPServer imap_class = IMAP4_SSL + @reap_threads + def test_ssl_verified(self): + ssl_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + ssl_context.verify_mode = ssl.CERT_REQUIRED + ssl_context.check_hostname = True + ssl_context.load_verify_locations(CAFILE) + + with self.assertRaisesRegex(ssl.CertificateError, + "hostname '127.0.0.1' doesn't match 'localhost'"): + with self.reaped_server(SimpleIMAPHandler) as server: + client = self.imap_class(*server.server_address, + ssl_context=ssl_context) + client.shutdown() + + with self.reaped_server(SimpleIMAPHandler) as server: + client = self.imap_class("localhost", server.server_address[1], + ssl_context=ssl_context) + client.shutdown() + class RemoteIMAPTest(unittest.TestCase): host = 'cyrus.andrew.cmu.edu' @@ -460,11 +480,15 @@ def load_tests(*args): if support.is_resource_enabled('network'): if ssl: - global CERTFILE + global CERTFILE, CAFILE CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir, - "keycert.pem") + "keycert3.pem") if not os.path.exists(CERTFILE): raise support.TestFailed("Can't read certificate files!") + CAFILE = os.path.join(os.path.dirname(__file__) or os.curdir, + "pycacert.pem") + if not os.path.exists(CAFILE): + raise support.TestFailed("Can't read CA file!") tests.extend([ ThreadedNetworkedTests, ThreadedNetworkedTestsSSL, RemoteIMAPTest, RemoteIMAP_SSLTest, RemoteIMAP_STARTTLSTest, diff --git a/Misc/NEWS b/Misc/NEWS index 9b71e13d8bf..3785840afca 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,9 @@ Core and Builtins Library ------- +- Issue #19782: imaplib now supports SSLContext.check_hostname and server name + indication for TLS/SSL connections. + - Issue #19834: Support unpickling of exceptions pickled by Python 2. - Issue #19781: ftplib now supports SSLContext.check_hostname and server name