Kaydet (Commit) a5768f72 authored tarafından Christian Heimes's avatar Christian Heimes

Issue #19785: smtplib now supports SSLContext.check_hostname and server name

indication for TLS/SSL connections.
üst 216d463b
...@@ -90,6 +90,10 @@ Protocol) and :rfc:`1869` (SMTP Service Extensions). ...@@ -90,6 +90,10 @@ Protocol) and :rfc:`1869` (SMTP Service Extensions).
.. versionchanged:: 3.3 .. versionchanged:: 3.3
source_address argument was added. 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) .. class:: LMTP(host='', port=LMTP_PORT, local_hostname=None, source_address=None)
...@@ -316,6 +320,11 @@ An :class:`SMTP` instance has the following methods: ...@@ -316,6 +320,11 @@ An :class:`SMTP` instance has the following methods:
.. versionchanged:: 3.3 .. versionchanged:: 3.3
*context* was added. *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=[]) .. method:: SMTP.sendmail(from_addr, to_addrs, msg, mail_options=[], rcpt_options=[])
......
...@@ -232,6 +232,7 @@ class SMTP: ...@@ -232,6 +232,7 @@ class SMTP:
will be used. will be used.
""" """
self._host = host
self.timeout = timeout self.timeout = timeout
self.esmtp_features = {} self.esmtp_features = {}
self.source_address = source_address self.source_address = source_address
...@@ -667,7 +668,9 @@ class SMTP: ...@@ -667,7 +668,9 @@ class SMTP:
if context is None: if context is None:
context = ssl._create_stdlib_context(certfile=certfile, context = ssl._create_stdlib_context(certfile=certfile,
keyfile=keyfile) 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 self.file = None
# RFC 3207: # RFC 3207:
# The client MUST discard any knowledge obtained from # The client MUST discard any knowledge obtained from
...@@ -892,7 +895,9 @@ if _have_ssl: ...@@ -892,7 +895,9 @@ if _have_ssl:
print('connect:', (host, port), file=stderr) print('connect:', (host, port), file=stderr)
new_socket = socket.create_connection((host, port), timeout, new_socket = socket.create_connection((host, port), timeout,
self.source_address) 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 return new_socket
__all__.append("SMTP_SSL") __all__.append("SMTP_SSL")
......
...@@ -3,23 +3,35 @@ ...@@ -3,23 +3,35 @@
import unittest import unittest
from test import support from test import support
import smtplib import smtplib
import socket
ssl = support.import_module("ssl") ssl = support.import_module("ssl")
support.requires("network") 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): class SmtpTest(unittest.TestCase):
testServer = 'smtp.gmail.com' testServer = 'smtp.gmail.com'
remotePort = 25 remotePort = 25
context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
def test_connect_starttls(self): def test_connect_starttls(self):
support.get_attribute(smtplib, 'SMTP_SSL') support.get_attribute(smtplib, 'SMTP_SSL')
context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
with support.transient_internet(self.testServer): with support.transient_internet(self.testServer):
server = smtplib.SMTP(self.testServer, self.remotePort) server = smtplib.SMTP(self.testServer, self.remotePort)
try: try:
server.starttls(context=self.context) server.starttls(context=context)
except smtplib.SMTPException as e: except smtplib.SMTPException as e:
if e.args[0] == 'STARTTLS extension not supported by server.': if e.args[0] == 'STARTTLS extension not supported by server.':
unittest.skip(e.args[0]) unittest.skip(e.args[0])
...@@ -32,7 +44,7 @@ class SmtpTest(unittest.TestCase): ...@@ -32,7 +44,7 @@ class SmtpTest(unittest.TestCase):
class SmtpSSLTest(unittest.TestCase): class SmtpSSLTest(unittest.TestCase):
testServer = 'smtp.gmail.com' testServer = 'smtp.gmail.com'
remotePort = 465 remotePort = 465
context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) can_verify = check_ssl_verifiy(testServer, remotePort)
def test_connect(self): def test_connect(self):
support.get_attribute(smtplib, 'SMTP_SSL') support.get_attribute(smtplib, 'SMTP_SSL')
...@@ -49,9 +61,19 @@ class SmtpSSLTest(unittest.TestCase): ...@@ -49,9 +61,19 @@ class SmtpSSLTest(unittest.TestCase):
server.quit() server.quit()
def test_connect_using_sslcontext(self): 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') support.get_attribute(smtplib, 'SMTP_SSL')
context = ssl.create_default_context()
with support.transient_internet(self.testServer): 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.ehlo()
server.quit() server.quit()
......
...@@ -18,6 +18,9 @@ Core and Builtins ...@@ -18,6 +18,9 @@ Core and Builtins
Library 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 - Issue #19784: poplib now supports SSLContext.check_hostname and server name
indication for TLS/SSL connections. indication for TLS/SSL connections.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment