diff options
-rw-r--r-- | Doc/library/smtplib.rst | 9 | ||||
-rw-r--r-- | Lib/smtplib.py | 9 | ||||
-rw-r--r-- | Lib/test/test_smtpnet.py | 30 | ||||
-rw-r--r-- | Misc/NEWS | 3 |
4 files changed, 45 insertions, 6 deletions
diff --git a/Doc/library/smtplib.rst b/Doc/library/smtplib.rst index a7d1538..eba8ae9 100644 --- a/Doc/library/smtplib.rst +++ b/Doc/library/smtplib.rst @@ -90,6 +90,10 @@ Protocol) and :rfc:`1869` (SMTP Service Extensions). .. versionchanged:: 3.3 source_address argument was added. + .. versionchanged:: 3.4 + The class now supports hostname check with + :attr:`SSLContext.check_hostname` and *Server Name Indicator* (see + :data:`~ssl.HAS_SNI`). .. class:: LMTP(host='', port=LMTP_PORT, local_hostname=None, source_address=None) @@ -316,6 +320,11 @@ An :class:`SMTP` instance has the following methods: .. versionchanged:: 3.3 *context* was added. + .. versionchanged:: 3.4 + The method now supports hostname check with + :attr:`SSLContext.check_hostname` and *Server Name Indicator* (see + :data:`~ssl.HAS_SNI`). + .. method:: SMTP.sendmail(from_addr, to_addrs, msg, mail_options=[], rcpt_options=[]) diff --git a/Lib/smtplib.py b/Lib/smtplib.py index 6fc65f6..796b866 100644 --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -232,6 +232,7 @@ class SMTP: will be used. """ + self._host = host self.timeout = timeout self.esmtp_features = {} self.source_address = source_address @@ -667,7 +668,9 @@ class SMTP: if context is None: context = ssl._create_stdlib_context(certfile=certfile, keyfile=keyfile) - 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 = None # RFC 3207: # The client MUST discard any knowledge obtained from @@ -892,7 +895,9 @@ if _have_ssl: print('connect:', (host, port), file=stderr) new_socket = socket.create_connection((host, port), timeout, self.source_address) - new_socket = self.context.wrap_socket(new_socket) + server_hostname = self._host if ssl.HAS_SNI else None + new_socket = self.context.wrap_socket(new_socket, + server_hostname=server_hostname) return new_socket __all__.append("SMTP_SSL") diff --git a/Lib/test/test_smtpnet.py b/Lib/test/test_smtpnet.py index 86224ef..56952ad 100644 --- a/Lib/test/test_smtpnet.py +++ b/Lib/test/test_smtpnet.py @@ -3,23 +3,35 @@ import unittest from test import support import smtplib +import socket ssl = support.import_module("ssl") support.requires("network") +def check_ssl_verifiy(host, port): + context = ssl.create_default_context() + with socket.create_connection((host, port)) as sock: + try: + sock = context.wrap_socket(sock, server_hostname=host) + except Exception: + return False + else: + sock.close() + return True + class SmtpTest(unittest.TestCase): testServer = 'smtp.gmail.com' remotePort = 25 - context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) def test_connect_starttls(self): support.get_attribute(smtplib, 'SMTP_SSL') + context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) with support.transient_internet(self.testServer): server = smtplib.SMTP(self.testServer, self.remotePort) try: - server.starttls(context=self.context) + server.starttls(context=context) except smtplib.SMTPException as e: if e.args[0] == 'STARTTLS extension not supported by server.': unittest.skip(e.args[0]) @@ -32,7 +44,7 @@ class SmtpTest(unittest.TestCase): class SmtpSSLTest(unittest.TestCase): testServer = 'smtp.gmail.com' remotePort = 465 - context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + can_verify = check_ssl_verifiy(testServer, remotePort) def test_connect(self): support.get_attribute(smtplib, 'SMTP_SSL') @@ -49,9 +61,19 @@ class SmtpSSLTest(unittest.TestCase): server.quit() def test_connect_using_sslcontext(self): + context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + support.get_attribute(smtplib, 'SMTP_SSL') + with support.transient_internet(self.testServer): + server = smtplib.SMTP_SSL(self.testServer, self.remotePort, context=context) + server.ehlo() + server.quit() + + @unittest.skipUnless(can_verify, "SSL certificate can't be verified") + def test_connect_using_sslcontext_verified(self): support.get_attribute(smtplib, 'SMTP_SSL') + context = ssl.create_default_context() with support.transient_internet(self.testServer): - server = smtplib.SMTP_SSL(self.testServer, self.remotePort, context=self.context) + server = smtplib.SMTP_SSL(self.testServer, self.remotePort, context=context) server.ehlo() server.quit() @@ -18,6 +18,9 @@ Core and Builtins Library ------- +- Issue #19785: smtplib now supports SSLContext.check_hostname and server name + indication for TLS/SSL connections. + - Issue #19784: poplib now supports SSLContext.check_hostname and server name indication for TLS/SSL connections. |