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 @@ class SSLWSGIServerMixin:
'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 @@ else:
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 @@ else:
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 @@ if HAVE_SSL:
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 @@ if HAVE_SSL:
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 @@ class SMTP:
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 @@ if _have_ssl:
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 @@ if ssl is not None:
_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 @@ if ssl:
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 @@ class LocalServerTests(unittest.TestCase):
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 @@ class DummyPOP3Handler(asynchat.async_chat):
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 skip_if_broken_ubuntu_ssl(func):
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 @@ class BasicSocketTests(unittest.TestCase):
# 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 @@ class BasicSocketTests(unittest.TestCase):
# 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 @@ class BasicSocketTests(unittest.TestCase):
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 @@ class BasicSocketTests(unittest.TestCase):
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 @@ class BasicSocketTests(unittest.TestCase):
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 @@ class BasicSocketTests(unittest.TestCase):
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 @@ class BasicSocketTests(unittest.TestCase):
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 @@ class BasicSocketTests(unittest.TestCase):
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 @@ class BasicSocketTests(unittest.TestCase):
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 @@ class SimpleBackgroundTests(unittest.TestCase):
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 @@ class SimpleBackgroundTests(unittest.TestCase):
# 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 @@ class SimpleBackgroundTests(unittest.TestCase):
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 @@ class SimpleBackgroundTests(unittest.TestCase):
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 @@ class SimpleBackgroundTests(unittest.TestCase):
# 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 @@ class SimpleBackgroundTests(unittest.TestCase):
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 @@ class SimpleBackgroundTests(unittest.TestCase):
_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 @@ class NetworkedTests(unittest.TestCase):
# 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 @@ if _have_threads:
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 @@ if _have_threads:
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 @@ if _have_threads:
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 @@ if _have_threads:
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 @@ if _have_threads:
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 @@ if _have_threads:
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 @@ if _have_threads:
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 @@ if _have_threads:
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 @@ if _have_threads:
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 @@ if _have_threads:
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 @@ if _have_threads:
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 @@ Connection: close
@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 @@ class TestUrlopen(unittest.TestCase):
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.