Issue #28022: Deprecate ssl-related arguments in favor of SSLContext.

The deprecation include manual creation of SSLSocket and certfile/keyfile
(or similar) in ftplib, httplib, imaplib, smtplib, poplib and urllib.

ssl.wrap_socket() is not marked as deprecated yet.
This commit is contained in:
Christian Heimes 2016-09-10 23:23:33 +02:00
parent 130bbe5fd3
commit d04863771b
23 changed files with 189 additions and 85 deletions

View file

@ -97,6 +97,13 @@ The module defines the following items:
:attr:`ssl.SSLContext.check_hostname` and *Server Name Indication* (see :attr:`ssl.SSLContext.check_hostname` and *Server Name Indication* (see
:data:`ssl.HAS_SNI`). :data:`ssl.HAS_SNI`).
.. deprecated:: 3.6
*keyfile* and *certfile* are deprecated in favor of *context*.
Please use :meth:`ssl.SSLContext.load_cert_chain` instead, or let
:func:`ssl.create_default_context` select the system's trusted CA
certificates for you.
Here's a sample session using the :class:`FTP_TLS` class:: Here's a sample session using the :class:`FTP_TLS` class::
>>> ftps = FTP_TLS('ftp.pureftpd.org') >>> ftps = FTP_TLS('ftp.pureftpd.org')

View file

@ -69,13 +69,6 @@ The module provides the following classes:
must be a :class:`ssl.SSLContext` instance describing the various SSL must be a :class:`ssl.SSLContext` instance describing the various SSL
options. options.
*key_file* and *cert_file* are deprecated, please use
:meth:`ssl.SSLContext.load_cert_chain` instead, or let
:func:`ssl.create_default_context` select the system's trusted CA
certificates for you. The *check_hostname* parameter is also deprecated; the
:attr:`ssl.SSLContext.check_hostname` attribute of *context* should be used
instead.
Please read :ref:`ssl-security` for more information on best practices. Please read :ref:`ssl-security` for more information on best practices.
.. versionchanged:: 3.2 .. versionchanged:: 3.2
@ -95,6 +88,17 @@ The module provides the following classes:
:func:`ssl._create_unverified_context` can be passed to the *context* :func:`ssl._create_unverified_context` can be passed to the *context*
parameter. parameter.
.. deprecated:: 3.6
*key_file* and *cert_file* are deprecated in favor of *context*.
Please use :meth:`ssl.SSLContext.load_cert_chain` instead, or let
:func:`ssl.create_default_context` select the system's trusted CA
certificates for you.
The *check_hostname* parameter is also deprecated; the
:attr:`ssl.SSLContext.check_hostname` attribute of *context* should
be used instead.
.. class:: HTTPResponse(sock, debuglevel=0, method=None, url=None) .. class:: HTTPResponse(sock, debuglevel=0, method=None, url=None)

View file

@ -103,6 +103,14 @@ There's also a subclass for secure connections:
:attr:`ssl.SSLContext.check_hostname` and *Server Name Indication* (see :attr:`ssl.SSLContext.check_hostname` and *Server Name Indication* (see
:data:`ssl.HAS_SNI`). :data:`ssl.HAS_SNI`).
.. deprecated:: 3.6
*keyfile* and *certfile* are deprecated in favor of *ssl_context*.
Please use :meth:`ssl.SSLContext.load_cert_chain` instead, or let
:func:`ssl.create_default_context` select the system's trusted CA
certificates for you.
The second subclass allows for connections created by a child process: The second subclass allows for connections created by a child process:

View file

@ -62,6 +62,13 @@ The :mod:`poplib` module provides two classes:
:attr:`ssl.SSLContext.check_hostname` and *Server Name Indication* (see :attr:`ssl.SSLContext.check_hostname` and *Server Name Indication* (see
:data:`ssl.HAS_SNI`). :data:`ssl.HAS_SNI`).
.. deprecated:: 3.6
*keyfile* and *certfile* are deprecated in favor of *context*.
Please use :meth:`ssl.SSLContext.load_cert_chain` instead, or let
:func:`ssl.create_default_context` select the system's trusted CA
certificates for you.
One exception is defined as an attribute of the :mod:`poplib` module: One exception is defined as an attribute of the :mod:`poplib` module:

View file

@ -95,6 +95,14 @@ Protocol) and :rfc:`1869` (SMTP Service Extensions).
:attr:`ssl.SSLContext.check_hostname` and *Server Name Indication* (see :attr:`ssl.SSLContext.check_hostname` and *Server Name Indication* (see
:data:`ssl.HAS_SNI`). :data:`ssl.HAS_SNI`).
.. deprecated:: 3.6
*keyfile* and *certfile* are deprecated in favor of *context*.
Please use :meth:`ssl.SSLContext.load_cert_chain` instead, or let
:func:`ssl.create_default_context` select the system's trusted CA
certificates for you.
.. class:: LMTP(host='', port=LMTP_PORT, local_hostname=None, source_address=None) .. class:: LMTP(host='', port=LMTP_PORT, local_hostname=None, source_address=None)
The LMTP protocol, which is very similar to ESMTP, is heavily based on the The LMTP protocol, which is very similar to ESMTP, is heavily based on the

View file

@ -230,7 +230,6 @@ instead.
.. versionchanged:: 3.2 .. versionchanged:: 3.2
New optional argument *ciphers*. New optional argument *ciphers*.
Context creation Context creation
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
@ -925,7 +924,7 @@ SSL Sockets
:ref:`notes on non-blocking sockets <ssl-nonblocking>`. :ref:`notes on non-blocking sockets <ssl-nonblocking>`.
Usually, :class:`SSLSocket` are not created directly, but using the Usually, :class:`SSLSocket` are not created directly, but using the
:func:`wrap_socket` function or the :meth:`SSLContext.wrap_socket` method. the :meth:`SSLContext.wrap_socket` method.
.. versionchanged:: 3.5 .. versionchanged:: 3.5
The :meth:`sendfile` method was added. The :meth:`sendfile` method was added.
@ -935,6 +934,10 @@ SSL Sockets
are received or sent. The socket timeout is now to maximum total duration are received or sent. The socket timeout is now to maximum total duration
of the shutdown. of the shutdown.
.. deprecated:: 3.6
It is deprecated to create a :class:`SSLSocket` instance directly, use
:meth:`SSLContext.wrap_socket` to wrap a socket.
SSL sockets also have the following additional methods and attributes: SSL sockets also have the following additional methods and attributes:
@ -955,6 +958,9 @@ SSL sockets also have the following additional methods and attributes:
The socket timeout is now to maximum total duration to read up to *len* The socket timeout is now to maximum total duration to read up to *len*
bytes. bytes.
.. deprecated:: 3.6
Use :meth:`~SSLSocket.recv` instead of :meth:`~SSLSocket.read`.
.. method:: SSLSocket.write(buf) .. method:: SSLSocket.write(buf)
Write *buf* to the SSL socket and return the number of bytes written. The Write *buf* to the SSL socket and return the number of bytes written. The
@ -970,6 +976,9 @@ SSL sockets also have the following additional methods and attributes:
The socket timeout is no more reset each time bytes are received or sent. The socket timeout is no more reset each time bytes are received or sent.
The socket timeout is now to maximum total duration to write *buf*. The socket timeout is now to maximum total duration to write *buf*.
.. deprecated:: 3.6
Use :meth:`~SSLSocket.send` instead of :meth:`~SSLSocket.write`.
.. note:: .. note::
The :meth:`~SSLSocket.read` and :meth:`~SSLSocket.write` methods are the The :meth:`~SSLSocket.read` and :meth:`~SSLSocket.write` methods are the

View file

@ -111,6 +111,12 @@ The :mod:`urllib.request` module defines the following functions:
.. versionchanged:: 3.4.3 .. versionchanged:: 3.4.3
*context* was added. *context* was added.
.. deprecated:: 3.6
*cafile*, *capath* and *cadefault* are deprecated in favor of *context*.
Please use :meth:`ssl.SSLContext.load_cert_chain` instead, or let
:func:`ssl.create_default_context` select the system's trusted CA
certificates for you.
.. function:: install_opener(opener) .. function:: install_opener(opener)

View file

@ -117,10 +117,10 @@ def finish_request(self, request, client_address):
'test', 'test_asyncio') 'test', 'test_asyncio')
keyfile = os.path.join(here, 'ssl_key.pem') keyfile = os.path.join(here, 'ssl_key.pem')
certfile = os.path.join(here, 'ssl_cert.pem') certfile = os.path.join(here, 'ssl_cert.pem')
ssock = ssl.wrap_socket(request, context = ssl.SSLContext()
keyfile=keyfile, context.load_cert_chain(certfile, keyfile)
certfile=certfile,
server_side=True) ssock = context.wrap_socket(request, server_side=True)
try: try:
self.RequestHandlerClass(ssock, client_address, self) self.RequestHandlerClass(ssock, client_address, self)
ssock.close() ssock.close()

View file

@ -728,6 +728,10 @@ def __init__(self, host='', user='', passwd='', acct='', keyfile=None,
if context is not None and certfile is not None: if context is not None and certfile is not None:
raise ValueError("context and certfile arguments are mutually " raise ValueError("context and certfile arguments are mutually "
"exclusive") "exclusive")
if keyfile is not None or certfile is not None:
import warnings
warnings.warn("keyfile and certfile are deprecated, use a"
"custom context instead", DeprecationWarning, 2)
self.keyfile = keyfile self.keyfile = keyfile
self.certfile = certfile self.certfile = certfile
if context is None: if context is None:

View file

@ -1365,6 +1365,12 @@ def __init__(self, host, port=None, key_file=None, cert_file=None,
check_hostname=None): check_hostname=None):
super(HTTPSConnection, self).__init__(host, port, timeout, super(HTTPSConnection, self).__init__(host, port, timeout,
source_address) source_address)
if (key_file is not None or cert_file is not None or
check_hostname is not None):
import warnings
warnings.warn("key_file, cert_file and check_hostname are "
"deprecated, use a custom context instead.",
DeprecationWarning, 2)
self.key_file = key_file self.key_file = key_file
self.cert_file = cert_file self.cert_file = cert_file
if context is None: if context is None:

View file

@ -1267,7 +1267,10 @@ def __init__(self, host='', port=IMAP4_SSL_PORT, keyfile=None,
if ssl_context is not None and certfile is not None: if ssl_context is not None and certfile is not None:
raise ValueError("ssl_context and certfile arguments are mutually " raise ValueError("ssl_context and certfile arguments are mutually "
"exclusive") "exclusive")
if keyfile is not None or certfile is not None:
import warnings
warnings.warn("keyfile and certfile are deprecated, use a"
"custom ssl_context instead", DeprecationWarning, 2)
self.keyfile = keyfile self.keyfile = keyfile
self.certfile = certfile self.certfile = certfile
if ssl_context is None: if ssl_context is None:

View file

@ -431,6 +431,10 @@ def __init__(self, host, port=POP3_SSL_PORT, keyfile=None, certfile=None,
if context is not None and certfile is not None: if context is not None and certfile is not None:
raise ValueError("context and certfile arguments are mutually " raise ValueError("context and certfile arguments are mutually "
"exclusive") "exclusive")
if keyfile is not None or certfile is not None:
import warnings
warnings.warn("keyfile and certfile are deprecated, use a"
"custom context instead", DeprecationWarning, 2)
self.keyfile = keyfile self.keyfile = keyfile
self.certfile = certfile self.certfile = certfile
if context is None: if context is None:

View file

@ -759,6 +759,10 @@ def starttls(self, keyfile=None, certfile=None, context=None):
if context is not None and certfile is not None: if context is not None and certfile is not None:
raise ValueError("context and certfile arguments are mutually " raise ValueError("context and certfile arguments are mutually "
"exclusive") "exclusive")
if keyfile is not None or certfile is not None:
import warnings
warnings.warn("keyfile and certfile are deprecated, use a"
"custom context instead", DeprecationWarning, 2)
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)
@ -1011,6 +1015,10 @@ def __init__(self, host='', port=0, local_hostname=None,
if context is not None and certfile is not None: if context is not None and certfile is not None:
raise ValueError("context and certfile arguments are mutually " raise ValueError("context and certfile arguments are mutually "
"exclusive") "exclusive")
if keyfile is not None or certfile is not None:
import warnings
warnings.warn("keyfile and certfile are deprecated, use a"
"custom context instead", DeprecationWarning, 2)
self.keyfile = keyfile self.keyfile = keyfile
self.certfile = certfile self.certfile = certfile
if context is None: if context is None:

View file

@ -1091,7 +1091,6 @@ def wrap_socket(sock, keyfile=None, certfile=None,
do_handshake_on_connect=True, do_handshake_on_connect=True,
suppress_ragged_eofs=True, suppress_ragged_eofs=True,
ciphers=None): ciphers=None):
return SSLSocket(sock=sock, keyfile=keyfile, certfile=certfile, return SSLSocket(sock=sock, keyfile=keyfile, certfile=certfile,
server_side=server_side, cert_reqs=cert_reqs, server_side=server_side, cert_reqs=cert_reqs,
ssl_version=ssl_version, ca_certs=ca_certs, ssl_version=ssl_version, ca_certs=ca_certs,

View file

@ -311,10 +311,12 @@ class SSLConnection(asyncore.dispatcher):
_ssl_closing = False _ssl_closing = False
def secure_connection(self): def secure_connection(self):
socket = ssl.wrap_socket(self.socket, suppress_ragged_eofs=False, context = ssl.SSLContext()
certfile=CERTFILE, server_side=True, context.load_cert_chain(CERTFILE)
do_handshake_on_connect=False, socket = context.wrap_socket(self.socket,
ssl_version=ssl.PROTOCOL_SSLv23) suppress_ragged_eofs=False,
server_side=True,
do_handshake_on_connect=False)
self.del_channel() self.del_channel()
self.set_socket(socket) self.set_socket(socket)
self._ssl_accepting = True self._ssl_accepting = True

View file

@ -77,9 +77,9 @@ class SecureTCPServer(socketserver.TCPServer):
def get_request(self): def get_request(self):
newsocket, fromaddr = self.socket.accept() newsocket, fromaddr = self.socket.accept()
connstream = ssl.wrap_socket(newsocket, context = ssl.SSLContext()
server_side=True, context.load_cert_chain(CERTFILE)
certfile=CERTFILE) connstream = context.wrap_socket(newsocket, server_side=True)
return connstream, fromaddr return connstream, fromaddr
IMAP4_SSL = imaplib.IMAP4_SSL IMAP4_SSL = imaplib.IMAP4_SSL

View file

@ -1542,8 +1542,10 @@ def run_server(self, sock):
elif cmd == b'STARTTLS\r\n': elif cmd == b'STARTTLS\r\n':
reader.close() reader.close()
client.sendall(b'382 Begin TLS negotiation now\r\n') client.sendall(b'382 Begin TLS negotiation now\r\n')
client = ssl.wrap_socket( context = ssl.SSLContext()
client, server_side=True, certfile=certfile) context.load_cert_chain(certfile)
client = context.wrap_socket(
client, server_side=True)
cleanup.enter_context(client) cleanup.enter_context(client)
reader = cleanup.enter_context(client.makefile('rb')) reader = cleanup.enter_context(client.makefile('rb'))
elif cmd == b'QUIT\r\n': elif cmd == b'QUIT\r\n':

View file

@ -152,10 +152,12 @@ def cmd_utf8(self, arg):
def cmd_stls(self, arg): def cmd_stls(self, arg):
if self.tls_active is False: if self.tls_active is False:
self.push('+OK Begin TLS negotiation') self.push('+OK Begin TLS negotiation')
tls_sock = ssl.wrap_socket(self.socket, certfile=CERTFILE, context = ssl.SSLContext()
server_side=True, context.load_cert_chain(CERTFILE)
do_handshake_on_connect=False, tls_sock = context.wrap_socket(self.socket,
suppress_ragged_eofs=False) server_side=True,
do_handshake_on_connect=False,
suppress_ragged_eofs=False)
self.del_channel() self.del_channel()
self.set_socket(tls_sock) self.set_socket(tls_sock)
self.tls_active = True self.tls_active = True

View file

@ -143,6 +143,21 @@ def f(*args, **kwargs):
needs_sni = unittest.skipUnless(ssl.HAS_SNI, "SNI support needed for this test") needs_sni = unittest.skipUnless(ssl.HAS_SNI, "SNI support needed for this test")
def test_wrap_socket(sock, ssl_version=ssl.PROTOCOL_TLS, *,
cert_reqs=ssl.CERT_NONE, ca_certs=None,
ciphers=None, certfile=None, keyfile=None,
**kwargs):
context = ssl.SSLContext(ssl_version)
if cert_reqs is not None:
context.verify_mode = cert_reqs
if ca_certs is not None:
context.load_verify_locations(ca_certs)
if certfile is not None or keyfile is not None:
context.load_cert_chain(certfile, keyfile)
if ciphers is not None:
context.set_ciphers(ciphers)
return context.wrap_socket(sock, **kwargs)
class BasicSocketTests(unittest.TestCase): class BasicSocketTests(unittest.TestCase):
def test_constants(self): def test_constants(self):
@ -363,7 +378,7 @@ def test_refcycle(self):
# Issue #7943: an SSL object doesn't create reference cycles with # Issue #7943: an SSL object doesn't create reference cycles with
# itself. # itself.
s = socket.socket(socket.AF_INET) s = socket.socket(socket.AF_INET)
ss = ssl.wrap_socket(s) ss = test_wrap_socket(s)
wr = weakref.ref(ss) wr = weakref.ref(ss)
with support.check_warnings(("", ResourceWarning)): with support.check_warnings(("", ResourceWarning)):
del ss del ss
@ -373,7 +388,7 @@ def test_wrapped_unconnected(self):
# Methods on an unconnected SSLSocket propagate the original # Methods on an unconnected SSLSocket propagate the original
# OSError raise by the underlying socket object. # OSError raise by the underlying socket object.
s = socket.socket(socket.AF_INET) s = socket.socket(socket.AF_INET)
with ssl.wrap_socket(s) as ss: with test_wrap_socket(s) as ss:
self.assertRaises(OSError, ss.recv, 1) self.assertRaises(OSError, ss.recv, 1)
self.assertRaises(OSError, ss.recv_into, bytearray(b'x')) self.assertRaises(OSError, ss.recv_into, bytearray(b'x'))
self.assertRaises(OSError, ss.recvfrom, 1) self.assertRaises(OSError, ss.recvfrom, 1)
@ -387,10 +402,10 @@ def test_timeout(self):
for timeout in (None, 0.0, 5.0): for timeout in (None, 0.0, 5.0):
s = socket.socket(socket.AF_INET) s = socket.socket(socket.AF_INET)
s.settimeout(timeout) s.settimeout(timeout)
with ssl.wrap_socket(s) as ss: with test_wrap_socket(s) as ss:
self.assertEqual(timeout, ss.gettimeout()) self.assertEqual(timeout, ss.gettimeout())
def test_errors(self): def test_errors_sslwrap(self):
sock = socket.socket() sock = socket.socket()
self.assertRaisesRegex(ValueError, self.assertRaisesRegex(ValueError,
"certfile must be specified", "certfile must be specified",
@ -400,10 +415,10 @@ def test_errors(self):
ssl.wrap_socket, sock, server_side=True) ssl.wrap_socket, sock, server_side=True)
self.assertRaisesRegex(ValueError, self.assertRaisesRegex(ValueError,
"certfile must be specified for server-side operations", "certfile must be specified for server-side operations",
ssl.wrap_socket, sock, server_side=True, certfile="") ssl.wrap_socket, sock, server_side=True, certfile="")
with ssl.wrap_socket(sock, server_side=True, certfile=CERTFILE) as s: with ssl.wrap_socket(sock, server_side=True, certfile=CERTFILE) as s:
self.assertRaisesRegex(ValueError, "can't connect in server-side mode", self.assertRaisesRegex(ValueError, "can't connect in server-side mode",
s.connect, (HOST, 8080)) s.connect, (HOST, 8080))
with self.assertRaises(OSError) as cm: with self.assertRaises(OSError) as cm:
with socket.socket() as sock: with socket.socket() as sock:
ssl.wrap_socket(sock, certfile=NONEXISTINGCERT) ssl.wrap_socket(sock, certfile=NONEXISTINGCERT)
@ -426,7 +441,7 @@ def bad_cert_test(self, certfile):
sock = socket.socket() sock = socket.socket()
self.addCleanup(sock.close) self.addCleanup(sock.close)
with self.assertRaises(ssl.SSLError): with self.assertRaises(ssl.SSLError):
ssl.wrap_socket(sock, test_wrap_socket(sock,
certfile=certfile, certfile=certfile,
ssl_version=ssl.PROTOCOL_TLSv1) ssl_version=ssl.PROTOCOL_TLSv1)
@ -613,7 +628,7 @@ def test_unknown_channel_binding(self):
s.listen() s.listen()
c = socket.socket(socket.AF_INET) c = socket.socket(socket.AF_INET)
c.connect(s.getsockname()) c.connect(s.getsockname())
with ssl.wrap_socket(c, do_handshake_on_connect=False) as ss: with test_wrap_socket(c, do_handshake_on_connect=False) as ss:
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
ss.get_channel_binding("unknown-type") ss.get_channel_binding("unknown-type")
s.close() s.close()
@ -623,15 +638,15 @@ def test_unknown_channel_binding(self):
def test_tls_unique_channel_binding(self): def test_tls_unique_channel_binding(self):
# unconnected should return None for known type # unconnected should return None for known type
s = socket.socket(socket.AF_INET) s = socket.socket(socket.AF_INET)
with ssl.wrap_socket(s) as ss: with test_wrap_socket(s) as ss:
self.assertIsNone(ss.get_channel_binding("tls-unique")) self.assertIsNone(ss.get_channel_binding("tls-unique"))
# the same for server-side # the same for server-side
s = socket.socket(socket.AF_INET) s = socket.socket(socket.AF_INET)
with ssl.wrap_socket(s, server_side=True, certfile=CERTFILE) as ss: with test_wrap_socket(s, server_side=True, certfile=CERTFILE) as ss:
self.assertIsNone(ss.get_channel_binding("tls-unique")) self.assertIsNone(ss.get_channel_binding("tls-unique"))
def test_dealloc_warn(self): def test_dealloc_warn(self):
ss = ssl.wrap_socket(socket.socket(socket.AF_INET)) ss = test_wrap_socket(socket.socket(socket.AF_INET))
r = repr(ss) r = repr(ss)
with self.assertWarns(ResourceWarning) as cm: with self.assertWarns(ResourceWarning) as cm:
ss = None ss = None
@ -750,7 +765,7 @@ def test_unsupported_dtls(self):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.addCleanup(s.close) self.addCleanup(s.close)
with self.assertRaises(NotImplementedError) as cx: with self.assertRaises(NotImplementedError) as cx:
ssl.wrap_socket(s, cert_reqs=ssl.CERT_NONE) test_wrap_socket(s, cert_reqs=ssl.CERT_NONE)
self.assertEqual(str(cx.exception), "only stream sockets are supported") self.assertEqual(str(cx.exception), "only stream sockets are supported")
ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
with self.assertRaises(NotImplementedError) as cx: with self.assertRaises(NotImplementedError) as cx:
@ -826,7 +841,7 @@ def test_connect_ex_error(self):
server = socket.socket(socket.AF_INET) server = socket.socket(socket.AF_INET)
self.addCleanup(server.close) self.addCleanup(server.close)
port = support.bind_port(server) # Reserve port but don't listen port = support.bind_port(server) # Reserve port but don't listen
s = ssl.wrap_socket(socket.socket(socket.AF_INET), s = test_wrap_socket(socket.socket(socket.AF_INET),
cert_reqs=ssl.CERT_REQUIRED) cert_reqs=ssl.CERT_REQUIRED)
self.addCleanup(s.close) self.addCleanup(s.close)
rc = s.connect_ex((HOST, port)) rc = s.connect_ex((HOST, port))
@ -1444,13 +1459,13 @@ def setUp(self):
self.addCleanup(server.__exit__, None, None, None) self.addCleanup(server.__exit__, None, None, None)
def test_connect(self): def test_connect(self):
with ssl.wrap_socket(socket.socket(socket.AF_INET), with test_wrap_socket(socket.socket(socket.AF_INET),
cert_reqs=ssl.CERT_NONE) as s: cert_reqs=ssl.CERT_NONE) as s:
s.connect(self.server_addr) s.connect(self.server_addr)
self.assertEqual({}, s.getpeercert()) self.assertEqual({}, s.getpeercert())
# this should succeed because we specify the root cert # this should succeed because we specify the root cert
with ssl.wrap_socket(socket.socket(socket.AF_INET), with test_wrap_socket(socket.socket(socket.AF_INET),
cert_reqs=ssl.CERT_REQUIRED, cert_reqs=ssl.CERT_REQUIRED,
ca_certs=SIGNING_CA) as s: ca_certs=SIGNING_CA) as s:
s.connect(self.server_addr) s.connect(self.server_addr)
@ -1460,7 +1475,7 @@ def test_connect_fail(self):
# This should fail because we have no verification certs. Connection # This should fail because we have no verification certs. Connection
# failure crashes ThreadedEchoServer, so run this in an independent # failure crashes ThreadedEchoServer, so run this in an independent
# test method. # test method.
s = ssl.wrap_socket(socket.socket(socket.AF_INET), s = test_wrap_socket(socket.socket(socket.AF_INET),
cert_reqs=ssl.CERT_REQUIRED) cert_reqs=ssl.CERT_REQUIRED)
self.addCleanup(s.close) self.addCleanup(s.close)
self.assertRaisesRegex(ssl.SSLError, "certificate verify failed", self.assertRaisesRegex(ssl.SSLError, "certificate verify failed",
@ -1468,7 +1483,7 @@ def test_connect_fail(self):
def test_connect_ex(self): def test_connect_ex(self):
# Issue #11326: check connect_ex() implementation # Issue #11326: check connect_ex() implementation
s = ssl.wrap_socket(socket.socket(socket.AF_INET), s = test_wrap_socket(socket.socket(socket.AF_INET),
cert_reqs=ssl.CERT_REQUIRED, cert_reqs=ssl.CERT_REQUIRED,
ca_certs=SIGNING_CA) ca_certs=SIGNING_CA)
self.addCleanup(s.close) self.addCleanup(s.close)
@ -1478,7 +1493,7 @@ def test_connect_ex(self):
def test_non_blocking_connect_ex(self): def test_non_blocking_connect_ex(self):
# Issue #11326: non-blocking connect_ex() should allow handshake # Issue #11326: non-blocking connect_ex() should allow handshake
# to proceed after the socket gets ready. # to proceed after the socket gets ready.
s = ssl.wrap_socket(socket.socket(socket.AF_INET), s = test_wrap_socket(socket.socket(socket.AF_INET),
cert_reqs=ssl.CERT_REQUIRED, cert_reqs=ssl.CERT_REQUIRED,
ca_certs=SIGNING_CA, ca_certs=SIGNING_CA,
do_handshake_on_connect=False) do_handshake_on_connect=False)
@ -1578,7 +1593,7 @@ def test_makefile_close(self):
# Issue #5238: creating a file-like object with makefile() shouldn't # Issue #5238: creating a file-like object with makefile() shouldn't
# delay closing the underlying "real socket" (here tested with its # delay closing the underlying "real socket" (here tested with its
# file descriptor, hence skipping the test under Windows). # file descriptor, hence skipping the test under Windows).
ss = ssl.wrap_socket(socket.socket(socket.AF_INET)) ss = test_wrap_socket(socket.socket(socket.AF_INET))
ss.connect(self.server_addr) ss.connect(self.server_addr)
fd = ss.fileno() fd = ss.fileno()
f = ss.makefile() f = ss.makefile()
@ -1596,7 +1611,7 @@ def test_non_blocking_handshake(self):
s = socket.socket(socket.AF_INET) s = socket.socket(socket.AF_INET)
s.connect(self.server_addr) s.connect(self.server_addr)
s.setblocking(False) s.setblocking(False)
s = ssl.wrap_socket(s, s = test_wrap_socket(s,
cert_reqs=ssl.CERT_NONE, cert_reqs=ssl.CERT_NONE,
do_handshake_on_connect=False) do_handshake_on_connect=False)
self.addCleanup(s.close) self.addCleanup(s.close)
@ -1622,16 +1637,16 @@ def test_get_server_certificate_fail(self):
_test_get_server_certificate_fail(self, *self.server_addr) _test_get_server_certificate_fail(self, *self.server_addr)
def test_ciphers(self): def test_ciphers(self):
with ssl.wrap_socket(socket.socket(socket.AF_INET), with test_wrap_socket(socket.socket(socket.AF_INET),
cert_reqs=ssl.CERT_NONE, ciphers="ALL") as s: cert_reqs=ssl.CERT_NONE, ciphers="ALL") as s:
s.connect(self.server_addr) s.connect(self.server_addr)
with ssl.wrap_socket(socket.socket(socket.AF_INET), with test_wrap_socket(socket.socket(socket.AF_INET),
cert_reqs=ssl.CERT_NONE, ciphers="DEFAULT") as s: cert_reqs=ssl.CERT_NONE, ciphers="DEFAULT") as s:
s.connect(self.server_addr) s.connect(self.server_addr)
# Error checking can happen at instantiation or when connecting # Error checking can happen at instantiation or when connecting
with self.assertRaisesRegex(ssl.SSLError, "No cipher can be selected"): with self.assertRaisesRegex(ssl.SSLError, "No cipher can be selected"):
with socket.socket(socket.AF_INET) as sock: with socket.socket(socket.AF_INET) as sock:
s = ssl.wrap_socket(sock, s = test_wrap_socket(sock,
cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx") cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx")
s.connect(self.server_addr) s.connect(self.server_addr)
@ -1749,7 +1764,7 @@ def test_timeout_connect_ex(self):
# Issue #12065: on a timeout, connect_ex() should return the original # Issue #12065: on a timeout, connect_ex() should return the original
# errno (mimicking the behaviour of non-SSL sockets). # errno (mimicking the behaviour of non-SSL sockets).
with support.transient_internet(REMOTE_HOST): with support.transient_internet(REMOTE_HOST):
s = ssl.wrap_socket(socket.socket(socket.AF_INET), s = test_wrap_socket(socket.socket(socket.AF_INET),
cert_reqs=ssl.CERT_REQUIRED, cert_reqs=ssl.CERT_REQUIRED,
do_handshake_on_connect=False) do_handshake_on_connect=False)
self.addCleanup(s.close) self.addCleanup(s.close)
@ -2040,7 +2055,7 @@ class EchoServer (asyncore.dispatcher):
class ConnectionHandler (asyncore.dispatcher_with_send): class ConnectionHandler (asyncore.dispatcher_with_send):
def __init__(self, conn, certfile): def __init__(self, conn, certfile):
self.socket = ssl.wrap_socket(conn, server_side=True, self.socket = test_wrap_socket(conn, server_side=True,
certfile=certfile, certfile=certfile,
do_handshake_on_connect=False) do_handshake_on_connect=False)
asyncore.dispatcher_with_send.__init__(self, self.socket) asyncore.dispatcher_with_send.__init__(self, self.socket)
@ -2401,7 +2416,7 @@ def test_wrong_cert(self):
connectionchatty=False) connectionchatty=False)
with server, \ with server, \
socket.socket() as sock, \ socket.socket() as sock, \
ssl.wrap_socket(sock, test_wrap_socket(sock,
certfile=certfile, certfile=certfile,
ssl_version=ssl.PROTOCOL_TLSv1) as s: ssl_version=ssl.PROTOCOL_TLSv1) as s:
try: try:
@ -2448,7 +2463,7 @@ def connector():
c.connect((HOST, port)) c.connect((HOST, port))
listener_gone.wait() listener_gone.wait()
try: try:
ssl_sock = ssl.wrap_socket(c) ssl_sock = test_wrap_socket(c)
except OSError: except OSError:
pass pass
else: else:
@ -2638,7 +2653,7 @@ def test_starttls(self):
sys.stdout.write( sys.stdout.write(
" client: read %r from server, starting TLS...\n" " client: read %r from server, starting TLS...\n"
% msg) % msg)
conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1) conn = test_wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
wrapped = True wrapped = True
elif indata == b"ENDTLS" and msg.startswith(b"ok"): elif indata == b"ENDTLS" and msg.startswith(b"ok"):
# ENDTLS ok, switch back to clear text # ENDTLS ok, switch back to clear text
@ -2699,7 +2714,7 @@ def test_asyncore_server(self):
indata = b"FOO\n" indata = b"FOO\n"
server = AsyncoreEchoServer(CERTFILE) server = AsyncoreEchoServer(CERTFILE)
with server: with server:
s = ssl.wrap_socket(socket.socket()) s = test_wrap_socket(socket.socket())
s.connect(('127.0.0.1', server.port)) s.connect(('127.0.0.1', server.port))
if support.verbose: if support.verbose:
sys.stdout.write( sys.stdout.write(
@ -2732,7 +2747,7 @@ def test_recv_send(self):
chatty=True, chatty=True,
connectionchatty=False) connectionchatty=False)
with server: with server:
s = ssl.wrap_socket(socket.socket(), s = test_wrap_socket(socket.socket(),
server_side=False, server_side=False,
certfile=CERTFILE, certfile=CERTFILE,
ca_certs=CERTFILE, ca_certs=CERTFILE,
@ -2856,7 +2871,7 @@ def test_recv_zero(self):
self.addCleanup(server.__exit__, None, None) self.addCleanup(server.__exit__, None, None)
s = socket.create_connection((HOST, server.port)) s = socket.create_connection((HOST, server.port))
self.addCleanup(s.close) self.addCleanup(s.close)
s = ssl.wrap_socket(s, suppress_ragged_eofs=False) s = test_wrap_socket(s, suppress_ragged_eofs=False)
self.addCleanup(s.close) self.addCleanup(s.close)
# recv/read(0) should return no data # recv/read(0) should return no data
@ -2878,7 +2893,7 @@ def test_nonblocking_send(self):
chatty=True, chatty=True,
connectionchatty=False) connectionchatty=False)
with server: with server:
s = ssl.wrap_socket(socket.socket(), s = test_wrap_socket(socket.socket(),
server_side=False, server_side=False,
certfile=CERTFILE, certfile=CERTFILE,
ca_certs=CERTFILE, ca_certs=CERTFILE,
@ -2932,12 +2947,12 @@ def serve():
c.connect((host, port)) c.connect((host, port))
# Will attempt handshake and time out # Will attempt handshake and time out
self.assertRaisesRegex(socket.timeout, "timed out", self.assertRaisesRegex(socket.timeout, "timed out",
ssl.wrap_socket, c) test_wrap_socket, c)
finally: finally:
c.close() c.close()
try: try:
c = socket.socket(socket.AF_INET) c = socket.socket(socket.AF_INET)
c = ssl.wrap_socket(c) c = test_wrap_socket(c)
c.settimeout(0.2) c.settimeout(0.2)
# Will attempt handshake and time out # Will attempt handshake and time out
self.assertRaisesRegex(socket.timeout, "timed out", self.assertRaisesRegex(socket.timeout, "timed out",
@ -3062,7 +3077,7 @@ def test_tls_unique_channel_binding(self):
chatty=True, chatty=True,
connectionchatty=False) connectionchatty=False)
with server: with server:
s = ssl.wrap_socket(socket.socket(), s = test_wrap_socket(socket.socket(),
server_side=False, server_side=False,
certfile=CERTFILE, certfile=CERTFILE,
ca_certs=CERTFILE, ca_certs=CERTFILE,
@ -3087,7 +3102,7 @@ def test_tls_unique_channel_binding(self):
s.close() s.close()
# now, again # now, again
s = ssl.wrap_socket(socket.socket(), s = test_wrap_socket(socket.socket(),
server_side=False, server_side=False,
certfile=CERTFILE, certfile=CERTFILE,
ca_certs=CERTFILE, ca_certs=CERTFILE,

View file

@ -469,10 +469,11 @@ def test_URLopener_deprecation(self):
@unittest.skipUnless(ssl, "ssl module required") @unittest.skipUnless(ssl, "ssl module required")
def test_cafile_and_context(self): def test_cafile_and_context(self):
context = ssl.create_default_context() context = ssl.create_default_context()
with self.assertRaises(ValueError): with support.check_warnings(('', DeprecationWarning)):
urllib.request.urlopen( with self.assertRaises(ValueError):
"https://localhost", cafile="/nonexistent/path", context=context urllib.request.urlopen(
) "https://localhost", cafile="/nonexistent/path", context=context
)
class urlopen_DataTests(unittest.TestCase): class urlopen_DataTests(unittest.TestCase):
"""Test urlopen() opening a data URL.""" """Test urlopen() opening a data URL."""

View file

@ -548,26 +548,28 @@ def test_https(self):
def test_https_with_cafile(self): def test_https_with_cafile(self):
handler = self.start_https_server(certfile=CERT_localhost) handler = self.start_https_server(certfile=CERT_localhost)
# Good cert with support.check_warnings(('', DeprecationWarning)):
data = self.urlopen("https://localhost:%s/bizarre" % handler.port, # Good cert
cafile=CERT_localhost) data = self.urlopen("https://localhost:%s/bizarre" % handler.port,
self.assertEqual(data, b"we care a bit") cafile=CERT_localhost)
# Bad cert self.assertEqual(data, b"we care a bit")
with self.assertRaises(urllib.error.URLError) as cm: # Bad cert
self.urlopen("https://localhost:%s/bizarre" % handler.port, with self.assertRaises(urllib.error.URLError) as cm:
cafile=CERT_fakehostname) self.urlopen("https://localhost:%s/bizarre" % handler.port,
# Good cert, but mismatching hostname cafile=CERT_fakehostname)
handler = self.start_https_server(certfile=CERT_fakehostname) # Good cert, but mismatching hostname
with self.assertRaises(ssl.CertificateError) as cm: handler = self.start_https_server(certfile=CERT_fakehostname)
self.urlopen("https://localhost:%s/bizarre" % handler.port, with self.assertRaises(ssl.CertificateError) as cm:
cafile=CERT_fakehostname) self.urlopen("https://localhost:%s/bizarre" % handler.port,
cafile=CERT_fakehostname)
def test_https_with_cadefault(self): def test_https_with_cadefault(self):
handler = self.start_https_server(certfile=CERT_localhost) handler = self.start_https_server(certfile=CERT_localhost)
# Self-signed cert should fail verification with system certificate store # Self-signed cert should fail verification with system certificate store
with self.assertRaises(urllib.error.URLError) as cm: with support.check_warnings(('', DeprecationWarning)):
self.urlopen("https://localhost:%s/bizarre" % handler.port, with self.assertRaises(urllib.error.URLError) as cm:
cadefault=True) self.urlopen("https://localhost:%s/bizarre" % handler.port,
cadefault=True)
def test_https_sni(self): def test_https_sni(self):
if ssl is None: if ssl is None:

View file

@ -198,6 +198,9 @@ def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
''' '''
global _opener global _opener
if cafile or capath or cadefault: if cafile or capath or cadefault:
import warnings
warnings.warn("cafile, cpath and cadefault are deprecated, use a "
"custom context instead.", DeprecationWarning, 2)
if context is not None: if context is not None:
raise ValueError( raise ValueError(
"You can't pass both context and any of cafile, capath, and " "You can't pass both context and any of cafile, capath, and "

View file

@ -138,7 +138,11 @@ Core and Builtins
Library Library
------- -------
- Issue 28043: SSLContext has improved default settings: OP_NO_SSLv2, - Issue #28022: Deprecate ssl-related arguments in favor of SSLContext. The
deprecation include manual creation of SSLSocket and certfile/keyfile
(or similar) in ftplib, httplib, imaplib, smtplib, poplib and urllib.
- Issue #28043: SSLContext has improved default settings: OP_NO_SSLv2,
OP_NO_SSLv3, OP_NO_COMPRESSION, OP_CIPHER_SERVER_PREFERENCE, OP_NO_SSLv3, OP_NO_COMPRESSION, OP_CIPHER_SERVER_PREFERENCE,
OP_SINGLE_DH_USE, OP_SINGLE_ECDH_USE and HIGH ciphers without MD5. OP_SINGLE_DH_USE, OP_SINGLE_ECDH_USE and HIGH ciphers without MD5.