Issue #19782: imaplib now supports SSLContext.check_hostname and server name

indication for TLS/SSL connections.
This commit is contained in:
Christian Heimes 2013-12-02 20:01:29 +01:00
parent 0c924b83ee
commit 48aae57996
4 changed files with 43 additions and 4 deletions

View File

@ -80,6 +80,10 @@ There's also a subclass for secure connections:
.. versionchanged:: 3.3 .. versionchanged:: 3.3
*ssl_context* parameter added. *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: 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 .. 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) .. method:: IMAP4.status(mailbox, names)

View File

@ -745,7 +745,9 @@ class IMAP4:
ssl_context = ssl._create_stdlib_context() ssl_context = ssl._create_stdlib_context()
typ, dat = self._simple_command(name) typ, dat = self._simple_command(name)
if typ == 'OK': 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.file = self.sock.makefile('rb')
self._tls_established = True self._tls_established = True
self._get_capabilities() self._get_capabilities()
@ -1216,7 +1218,9 @@ if HAVE_SSL:
def _create_socket(self): def _create_socket(self):
sock = IMAP4._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): def open(self, host='', port=IMAP4_SSL_PORT):
"""Setup connection to remote server on "host:port". """Setup connection to remote server on "host:port".

View File

@ -20,6 +20,7 @@ except ImportError:
ssl = None ssl = None
CERTFILE = None CERTFILE = None
CAFILE = None
class TestImaplib(unittest.TestCase): class TestImaplib(unittest.TestCase):
@ -348,6 +349,25 @@ class ThreadedNetworkedTestsSSL(BaseThreadedNetworkedTests):
server_class = SecureTCPServer server_class = SecureTCPServer
imap_class = IMAP4_SSL 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): class RemoteIMAPTest(unittest.TestCase):
host = 'cyrus.andrew.cmu.edu' host = 'cyrus.andrew.cmu.edu'
@ -460,11 +480,15 @@ def load_tests(*args):
if support.is_resource_enabled('network'): if support.is_resource_enabled('network'):
if ssl: if ssl:
global CERTFILE global CERTFILE, CAFILE
CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir, CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
"keycert.pem") "keycert3.pem")
if not os.path.exists(CERTFILE): if not os.path.exists(CERTFILE):
raise support.TestFailed("Can't read certificate files!") 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([ tests.extend([
ThreadedNetworkedTests, ThreadedNetworkedTestsSSL, ThreadedNetworkedTests, ThreadedNetworkedTestsSSL,
RemoteIMAPTest, RemoteIMAP_SSLTest, RemoteIMAP_STARTTLSTest, RemoteIMAPTest, RemoteIMAP_SSLTest, RemoteIMAP_STARTTLSTest,

View File

@ -18,6 +18,9 @@ Core and Builtins
Library 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 #19834: Support unpickling of exceptions pickled by Python 2.
- Issue #19781: ftplib now supports SSLContext.check_hostname and server name - Issue #19781: ftplib now supports SSLContext.check_hostname and server name