CodeQL: Update the smtplib module to use the ssl stdlib context

This prevents usage of outdated SSL protocol versions and matches the
behavior of the python stdlib smtplib library as of python 3.13
This commit is contained in:
Kovid Goyal 2025-09-15 13:23:25 +05:30
parent 1f69ab8701
commit 0e1dc84203
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C

View File

@ -48,6 +48,7 @@ import email.utils
import hmac
import re
import socket
import ssl
from email.base64mime import body_encode as encode_base64
from functools import partial
from sys import stderr
@ -191,40 +192,6 @@ def quotedata(data):
re.sub(r'(?:\r\n|\n|\r(?!\n))', CRLF, data))
try:
import ssl
except ImportError:
_have_ssl = False
else:
class SSLFakeFile:
'''A fake file like object that really wraps a SSLObject.
It only supports what is needed in smtplib.
'''
def __init__(self, sslobj):
self.sslobj = sslobj
def readline(self, size=-1):
if size < 0:
size = None
str = ''
chr = None
while chr != '\n':
if size is not None and len(str) >= size:
break
chr = self.sslobj.read(1)
if not chr:
break
str += chr
return str
def close(self):
pass
_have_ssl = True
class SMTP:
'''This class manages a connection to an SMTP or ESMTP server.
SMTP Objects:
@ -677,13 +644,10 @@ class SMTP:
raise SMTPException('STARTTLS extension not supported by server.')
resp, reply = self.docmd('STARTTLS')
if resp == 220:
if not _have_ssl:
raise RuntimeError('No SSL support included in this Python')
if context is None:
self.sock = ssl.wrap_socket(self.sock)
else:
self.sock = context.wrap_socket(self.sock, server_hostname=self._host)
self.file = SSLFakeFile(self.sock)
context = ssl._create_stdlib_context()
self.sock = context.wrap_socket(self.sock, server_hostname=self._host)
self.file = None
# RFC 3207:
# The client MUST discard any knowledge obtained from
# the server, such as the list of SMTP service extensions,
@ -812,37 +776,37 @@ class SMTP:
return res
if _have_ssl:
class SMTP_SSL(SMTP):
''' This is a subclass derived from SMTP that connects over an SSL encrypted
socket (to use this class you need a socket module that was compiled with SSL
support). If host is not specified, '' (the local host) is used. If port is
omitted, the standard SMTP-over-SSL port (465) is used. keyfile and certfile
are also optional - they can contain a PEM formatted private key and
certificate chain file for the SSL connection.
'''
class SMTP_SSL(SMTP):
''' This is a subclass derived from SMTP that connects over an SSL encrypted
socket (to use this class you need a socket module that was compiled with SSL
support). If host is not specified, '' (the local host) is used. If port is
omitted, the standard SMTP-over-SSL port (465) is used. keyfile and certfile
are also optional - they can contain a PEM formatted private key and
certificate chain file for the SSL connection.
'''
default_port = SMTP_SSL_PORT
default_port = SMTP_SSL_PORT
def __init__(self, host='', port=0, local_hostname=None,
keyfile=None, certfile=None,
timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
debug_to=partial(print, file=stderr), context=None):
self.keyfile = keyfile
self.certfile = certfile
if context is None:
context = ssl._create_stdlib_context()
self.context = context
SMTP.__init__(self, host, port, local_hostname, timeout,
debug_to=debug_to)
def __init__(self, host='', port=0, local_hostname=None,
keyfile=None, certfile=None,
timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
debug_to=partial(print, file=stderr)):
self.keyfile = keyfile
self.certfile = certfile
SMTP.__init__(self, host, port, local_hostname, timeout,
debug_to=debug_to)
def _get_socket(self, host, port, timeout):
new_socket = super()._get_socket(host, port, timeout)
new_socket = self.context.wrap_socket(new_socket,
server_hostname=self._host)
return new_socket
def _get_socket(self, host, port, timeout):
if self.debuglevel > 0:
self.debug('connect:', (host, port))
new_socket = socket.create_connection((host, port), timeout)
new_socket = ssl.wrap_socket(new_socket, self.keyfile, self.certfile)
self.file = SSLFakeFile(new_socket)
return new_socket
__all__.append('SMTP_SSL')
__all__.append('SMTP_SSL')
#
# LMTP extension