Skip to content

Commit 2875c60

Browse files
authored
bpo-43880: Show DeprecationWarnings for deprecated ssl module features (GH-25455)
* ssl.OP_NO_SSLv2 * ssl.OP_NO_SSLv3 * ssl.OP_NO_TLSv1 * ssl.OP_NO_TLSv1_1 * ssl.OP_NO_TLSv1_2 * ssl.OP_NO_TLSv1_3 * ssl.PROTOCOL_SSLv2 * ssl.PROTOCOL_SSLv3 * ssl.PROTOCOL_SSLv23 (alias for PROTOCOL_TLS) * ssl.PROTOCOL_TLS * ssl.PROTOCOL_TLSv1 * ssl.PROTOCOL_TLSv1_1 * ssl.PROTOCOL_TLSv1_2 * ssl.TLSVersion.SSLv3 * ssl.TLSVersion.TLSv1 * ssl.TLSVersion.TLSv1_1 * ssl.wrap_socket() * ssl.RAND_pseudo_bytes() * ssl.RAND_egd() (already removed since it's not supported by OpenSSL 1.1.1) * ssl.SSLContext() without a protocol argument * ssl.match_hostname() * hashlib.pbkdf2_hmac() (pure Python implementation, fast OpenSSL function will stay) Signed-off-by: Christian Heimes <christian@python.org>
1 parent 89d1550 commit 2875c60

14 files changed

+305
-201
lines changed

Doc/library/hashlib.rst

+6
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,12 @@ include a `salt <https://en.wikipedia.org/wiki/Salt_%28cryptography%29>`_.
266266
Python implementation uses an inline version of :mod:`hmac`. It is about
267267
three times slower and doesn't release the GIL.
268268

269+
.. deprecated:: 3.10
270+
271+
Slow Python implementation of *pbkdf2_hmac* is deprecated. In the
272+
future the function will only be available when Python is compiled
273+
with OpenSSL.
274+
269275
.. function:: scrypt(password, *, salt, n, r, p, maxmem=0, dklen=64)
270276

271277
The function provides scrypt password-based key derivation function as

Doc/library/ssl.rst

+44-17
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ probably additional platforms, as long as OpenSSL is installed on that platform.
2525

2626
Some behavior may be platform dependent, since calls are made to the
2727
operating system socket APIs. The installed version of OpenSSL may also
28-
cause variations in behavior. For example, TLSv1.1 and TLSv1.2 come with
29-
openssl version 1.0.1.
28+
cause variations in behavior. For example, TLSv1.3 with OpenSSL version
29+
1.1.1.
3030

3131
.. warning::
3232
Don't use this module without reading the :ref:`ssl-security`. Doing so
@@ -63,6 +63,8 @@ by SSL sockets created through the :meth:`SSLContext.wrap_socket` method.
6363
:pep:`644` has been implemented. The ssl module requires OpenSSL 1.1.1
6464
or newer.
6565

66+
Use of deprecated constants and functions result in deprecation warnings.
67+
6668

6769
Functions, Constants, and Exceptions
6870
------------------------------------
@@ -136,8 +138,9 @@ purposes.
136138
:const:`None`, this function can choose to trust the system's default
137139
CA certificates instead.
138140

139-
The settings are: :data:`PROTOCOL_TLS`, :data:`OP_NO_SSLv2`, and
140-
:data:`OP_NO_SSLv3` with high encryption cipher suites without RC4 and
141+
The settings are: :data:`PROTOCOL_TLS_CLIENT` or
142+
:data:`PROTOCOL_TLS_SERVER`, :data:`OP_NO_SSLv2`, and :data:`OP_NO_SSLv3`
143+
with high encryption cipher suites without RC4 and
141144
without unauthenticated cipher suites. Passing :data:`~Purpose.SERVER_AUTH`
142145
as *purpose* sets :data:`~SSLContext.verify_mode` to :data:`CERT_REQUIRED`
143146
and either loads CA certificates (when at least one of *cafile*, *capath* or
@@ -185,6 +188,12 @@ purposes.
185188

186189
Support for key logging to :envvar:`SSLKEYLOGFILE` was added.
187190

191+
.. versionchanged:: 3.10
192+
193+
The context now uses :data:`PROTOCOL_TLS_CLIENT` or
194+
:data:`PROTOCOL_TLS_SERVER` protocol instead of generic
195+
:data:`PROTOCOL_TLS`.
196+
188197

189198
Exceptions
190199
^^^^^^^^^^
@@ -417,7 +426,7 @@ Certificate handling
417426
previously. Return an integer (no fractions of a second in the
418427
input format)
419428

420-
.. function:: get_server_certificate(addr, ssl_version=PROTOCOL_TLS, ca_certs=None)
429+
.. function:: get_server_certificate(addr, ssl_version=PROTOCOL_TLS_CLIENT, ca_certs=None)
421430

422431
Given the address ``addr`` of an SSL-protected server, as a (*hostname*,
423432
*port-number*) pair, fetches the server's certificate, and returns it as a
@@ -654,6 +663,8 @@ Constants
654663

655664
.. versionadded:: 3.6
656665

666+
.. deprecated:: 3.10
667+
657668
.. data:: PROTOCOL_TLS_CLIENT
658669

659670
Auto-negotiate the highest protocol version like :data:`PROTOCOL_TLS`,
@@ -707,16 +718,18 @@ Constants
707718
.. deprecated:: 3.6
708719

709720
OpenSSL has deprecated all version specific protocols. Use the default
710-
protocol :data:`PROTOCOL_TLS` with flags like :data:`OP_NO_SSLv3` instead.
721+
protocol :data:`PROTOCOL_TLS_SERVER` or :data:`PROTOCOL_TLS_CLIENT`
722+
with :attr:`SSLContext.minimum_version` and
723+
:attr:`SSLContext.maximum_version` instead.
724+
711725

712726
.. data:: PROTOCOL_TLSv1
713727

714728
Selects TLS version 1.0 as the channel encryption protocol.
715729

716730
.. deprecated:: 3.6
717731

718-
OpenSSL has deprecated all version specific protocols. Use the default
719-
protocol :data:`PROTOCOL_TLS` with flags like :data:`OP_NO_SSLv3` instead.
732+
OpenSSL has deprecated all version specific protocols.
720733

721734
.. data:: PROTOCOL_TLSv1_1
722735

@@ -727,8 +740,7 @@ Constants
727740

728741
.. deprecated:: 3.6
729742

730-
OpenSSL has deprecated all version specific protocols. Use the default
731-
protocol :data:`PROTOCOL_TLS` with flags like :data:`OP_NO_SSLv3` instead.
743+
OpenSSL has deprecated all version specific protocols.
732744

733745
.. data:: PROTOCOL_TLSv1_2
734746

@@ -739,8 +751,7 @@ Constants
739751

740752
.. deprecated:: 3.6
741753

742-
OpenSSL has deprecated all version specific protocols. Use the default
743-
protocol :data:`PROTOCOL_TLS` with flags like :data:`OP_NO_SSLv3` instead.
754+
OpenSSL has deprecated all version specific protocols.
744755

745756
.. data:: OP_ALL
746757

@@ -762,7 +773,6 @@ Constants
762773

763774
SSLv2 is deprecated
764775

765-
766776
.. data:: OP_NO_SSLv3
767777

768778
Prevents an SSLv3 connection. This option is only applicable in
@@ -1068,6 +1078,11 @@ Constants
10681078

10691079
SSL 3.0 to TLS 1.3.
10701080

1081+
.. deprecated:: 3.10
1082+
1083+
All :class:`TLSVersion` members except :attr:`TLSVersion.TLSv1_2` and
1084+
:attr:`TLSVersion.TLSv1_3` are deprecated.
1085+
10711086

10721087
SSL Sockets
10731088
-----------
@@ -1423,7 +1438,7 @@ such as SSL configuration options, certificate(s) and private key(s).
14231438
It also manages a cache of SSL sessions for server-side sockets, in order
14241439
to speed up repeated connections from the same clients.
14251440

1426-
.. class:: SSLContext(protocol=PROTOCOL_TLS)
1441+
.. class:: SSLContext(protocol=None)
14271442

14281443
Create a new SSL context. You may pass *protocol* which must be one
14291444
of the ``PROTOCOL_*`` constants defined in this module. The parameter
@@ -1472,6 +1487,12 @@ to speed up repeated connections from the same clients.
14721487
ciphers, no ``NULL`` ciphers and no ``MD5`` ciphers (except for
14731488
:data:`PROTOCOL_SSLv2`).
14741489

1490+
.. deprecated:: 3.10
1491+
1492+
:class:`SSLContext` without protocol argument is deprecated. The
1493+
context class will either require :data:`PROTOCOL_TLS_CLIENT` or
1494+
:data:`PROTOCOL_TLS_SERVER` protocol in the future.
1495+
14751496

14761497
:class:`SSLContext` objects have the following methods and attributes:
14771498

@@ -1934,7 +1955,7 @@ to speed up repeated connections from the same clients.
19341955
.. attribute:: SSLContext.num_tickets
19351956

19361957
Control the number of TLS 1.3 session tickets of a
1937-
:attr:`TLS_PROTOCOL_SERVER` context. The setting has no impact on TLS
1958+
:attr:`PROTOCOL_TLS_SERVER` context. The setting has no impact on TLS
19381959
1.0 to 1.2 connections.
19391960

19401961
.. versionadded:: 3.8
@@ -1951,6 +1972,12 @@ to speed up repeated connections from the same clients.
19511972
>>> ssl.create_default_context().options # doctest: +SKIP
19521973
<Options.OP_ALL|OP_NO_SSLv3|OP_NO_SSLv2|OP_NO_COMPRESSION: 2197947391>
19531974

1975+
.. deprecated:: 3.7
1976+
1977+
All ``OP_NO_SSL*`` and ``OP_NO_TLS*`` options have been deprecated since
1978+
Python 3.7. Use :attr:`SSLContext.minimum_version` and
1979+
:attr:`SSLContext.maximum_version` instead.
1980+
19541981
.. attribute:: SSLContext.post_handshake_auth
19551982

19561983
Enable TLS 1.3 post-handshake client authentication. Post-handshake auth
@@ -2623,8 +2650,8 @@ disabled by default.
26232650
::
26242651

26252652
>>> client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2626-
>>> client_context.options |= ssl.OP_NO_TLSv1
2627-
>>> client_context.options |= ssl.OP_NO_TLSv1_1
2653+
>>> client_context.minimum_version = ssl.TLSVersion.TLSv1_3
2654+
>>> client_context.maximum_version = ssl.TLSVersion.TLSv1_3
26282655

26292656

26302657
The SSL context created above will only allow TLSv1.2 and later (if

Lib/hashlib.py

+6
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ def __hash_new(name, data=b'', **kwargs):
181181
# OpenSSL's PKCS5_PBKDF2_HMAC requires OpenSSL 1.0+ with HMAC and SHA
182182
from _hashlib import pbkdf2_hmac
183183
except ImportError:
184+
from warnings import warn as _warn
184185
_trans_5C = bytes((x ^ 0x5C) for x in range(256))
185186
_trans_36 = bytes((x ^ 0x36) for x in range(256))
186187

@@ -191,6 +192,11 @@ def pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None):
191192
as OpenSSL's PKCS5_PBKDF2_HMAC for short passwords and much faster
192193
for long passwords.
193194
"""
195+
_warn(
196+
"Python implementation of pbkdf2_hmac() is deprecated.",
197+
category=DeprecationWarning,
198+
stacklevel=2
199+
)
194200
if not isinstance(hash_name, str):
195201
raise TypeError(hash_name)
196202

Lib/ssl.py

+44-9
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,11 @@ def match_hostname(cert, hostname):
381381
CertificateError is raised on failure. On success, the function
382382
returns nothing.
383383
"""
384+
warnings.warn(
385+
"ssl module: match_hostname() is deprecated",
386+
category=DeprecationWarning,
387+
stacklevel=2
388+
)
384389
if not cert:
385390
raise ValueError("empty or no certificate, match_hostname needs a "
386391
"SSL socket or SSL context with either "
@@ -479,7 +484,15 @@ class SSLContext(_SSLContext):
479484
sslsocket_class = None # SSLSocket is assigned later.
480485
sslobject_class = None # SSLObject is assigned later.
481486

482-
def __new__(cls, protocol=PROTOCOL_TLS, *args, **kwargs):
487+
def __new__(cls, protocol=None, *args, **kwargs):
488+
if protocol is None:
489+
warnings.warn(
490+
"ssl module: "
491+
"SSLContext() without protocol argument is deprecated.",
492+
category=DeprecationWarning,
493+
stacklevel=2
494+
)
495+
protocol = PROTOCOL_TLS
483496
self = _SSLContext.__new__(cls, protocol)
484497
return self
485498

@@ -518,6 +531,7 @@ def wrap_bio(self, incoming, outgoing, server_side=False,
518531
)
519532

520533
def set_npn_protocols(self, npn_protocols):
534+
warnings.warn("NPN is deprecated, use ALPN instead", stacklevel=2)
521535
protos = bytearray()
522536
for protocol in npn_protocols:
523537
b = bytes(protocol, 'ascii')
@@ -734,12 +748,15 @@ def create_default_context(purpose=Purpose.SERVER_AUTH, *, cafile=None,
734748
# SSLContext sets OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_COMPRESSION,
735749
# OP_CIPHER_SERVER_PREFERENCE, OP_SINGLE_DH_USE and OP_SINGLE_ECDH_USE
736750
# by default.
737-
context = SSLContext(PROTOCOL_TLS)
738-
739751
if purpose == Purpose.SERVER_AUTH:
740752
# verify certs and host name in client mode
753+
context = SSLContext(PROTOCOL_TLS_CLIENT)
741754
context.verify_mode = CERT_REQUIRED
742755
context.check_hostname = True
756+
elif purpose == Purpose.CLIENT_AUTH:
757+
context = SSLContext(PROTOCOL_TLS_SERVER)
758+
else:
759+
raise ValueError(purpose)
743760

744761
if cafile or capath or cadata:
745762
context.load_verify_locations(cafile, capath, cadata)
@@ -755,7 +772,7 @@ def create_default_context(purpose=Purpose.SERVER_AUTH, *, cafile=None,
755772
context.keylog_filename = keylogfile
756773
return context
757774

758-
def _create_unverified_context(protocol=PROTOCOL_TLS, *, cert_reqs=CERT_NONE,
775+
def _create_unverified_context(protocol=None, *, cert_reqs=CERT_NONE,
759776
check_hostname=False, purpose=Purpose.SERVER_AUTH,
760777
certfile=None, keyfile=None,
761778
cafile=None, capath=None, cadata=None):
@@ -772,10 +789,18 @@ def _create_unverified_context(protocol=PROTOCOL_TLS, *, cert_reqs=CERT_NONE,
772789
# SSLContext sets OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_COMPRESSION,
773790
# OP_CIPHER_SERVER_PREFERENCE, OP_SINGLE_DH_USE and OP_SINGLE_ECDH_USE
774791
# by default.
775-
context = SSLContext(protocol)
792+
if purpose == Purpose.SERVER_AUTH:
793+
# verify certs and host name in client mode
794+
if protocol is None:
795+
protocol = PROTOCOL_TLS_CLIENT
796+
elif purpose == Purpose.CLIENT_AUTH:
797+
if protocol is None:
798+
protocol = PROTOCOL_TLS_SERVER
799+
else:
800+
raise ValueError(purpose)
776801

777-
if not check_hostname:
778-
context.check_hostname = False
802+
context = SSLContext(protocol)
803+
context.check_hostname = check_hostname
779804
if cert_reqs is not None:
780805
context.verify_mode = cert_reqs
781806
if check_hostname:
@@ -909,6 +934,9 @@ def selected_npn_protocol(self):
909934
"""Return the currently selected NPN protocol as a string, or ``None``
910935
if a next protocol was not negotiated or if NPN is not supported by one
911936
of the peers."""
937+
warnings.warn(
938+
"ssl module: NPN is deprecated, use ALPN instead", stacklevel=2
939+
)
912940

913941
def selected_alpn_protocol(self):
914942
"""Return the currently selected ALPN protocol as a string, or ``None``
@@ -1123,6 +1151,9 @@ def getpeercert(self, binary_form=False):
11231151
@_sslcopydoc
11241152
def selected_npn_protocol(self):
11251153
self._checkClosed()
1154+
warnings.warn(
1155+
"ssl module: NPN is deprecated, use ALPN instead", stacklevel=2
1156+
)
11261157
return None
11271158

11281159
@_sslcopydoc
@@ -1382,7 +1413,11 @@ def wrap_socket(sock, keyfile=None, certfile=None,
13821413
do_handshake_on_connect=True,
13831414
suppress_ragged_eofs=True,
13841415
ciphers=None):
1385-
1416+
warnings.warn(
1417+
"ssl module: wrap_socket is deprecated, use SSLContext.wrap_socket()",
1418+
category=DeprecationWarning,
1419+
stacklevel=2
1420+
)
13861421
if server_side and not certfile:
13871422
raise ValueError("certfile must be specified for server-side "
13881423
"operations")
@@ -1460,7 +1495,7 @@ def PEM_cert_to_DER_cert(pem_cert_string):
14601495
d = pem_cert_string.strip()[len(PEM_HEADER):-len(PEM_FOOTER)]
14611496
return base64.decodebytes(d.encode('ASCII', 'strict'))
14621497

1463-
def get_server_certificate(addr, ssl_version=PROTOCOL_TLS, ca_certs=None):
1498+
def get_server_certificate(addr, ssl_version=PROTOCOL_TLS_CLIENT, ca_certs=None):
14641499
"""Retrieve the certificate from the server at the specified address,
14651500
and return it as a PEM-encoded string.
14661501
If 'ca_certs' is specified, validate the server cert against it.

Lib/test/pythoninfo.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ def format_attr(attr, value):
504504
copy_attributes(info_add, ssl, 'ssl.%s', attributes, formatter=format_attr)
505505

506506
for name, ctx in (
507-
('SSLContext', ssl.SSLContext()),
507+
('SSLContext', ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)),
508508
('default_https_context', ssl._create_default_https_context()),
509509
('stdlib_context', ssl._create_stdlib_context()),
510510
):

Lib/test/test_asyncio/utils.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def dummy_ssl_context():
9191
if ssl is None:
9292
return None
9393
else:
94-
return ssl.SSLContext(ssl.PROTOCOL_TLS)
94+
return simple_client_sslcontext(disable_verify=True)
9595

9696

9797
def run_briefly(loop):
@@ -158,7 +158,7 @@ def finish_request(self, request, client_address):
158158
# contains the ssl key and certificate files) differs
159159
# between the stdlib and stand-alone asyncio.
160160
# Prefer our own if we can find it.
161-
context = ssl.SSLContext()
161+
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
162162
context.load_cert_chain(ONLYCERT, ONLYKEY)
163163

164164
ssock = context.wrap_socket(request, server_side=True)

Lib/test/test_ftplib.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ class SSLConnection(asyncore.dispatcher):
324324
_ssl_closing = False
325325

326326
def secure_connection(self):
327-
context = ssl.SSLContext()
327+
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
328328
context.load_cert_chain(CERTFILE)
329329
socket = context.wrap_socket(self.socket,
330330
suppress_ragged_eofs=False,

Lib/test/test_hashlib.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from test.support import _4G, bigmemtest
2222
from test.support.import_helper import import_fresh_module
2323
from test.support import threading_helper
24+
from test.support import warnings_helper
2425
from http.client import HTTPException
2526

2627
# Were we compiled --with-pydebug or with #define Py_DEBUG?
@@ -1021,7 +1022,10 @@ def _test_pbkdf2_hmac(self, pbkdf2, supported):
10211022

10221023
@unittest.skipIf(builtin_hashlib is None, "test requires builtin_hashlib")
10231024
def test_pbkdf2_hmac_py(self):
1024-
self._test_pbkdf2_hmac(builtin_hashlib.pbkdf2_hmac, builtin_hashes)
1025+
with warnings_helper.check_warnings():
1026+
self._test_pbkdf2_hmac(
1027+
builtin_hashlib.pbkdf2_hmac, builtin_hashes
1028+
)
10251029

10261030
@unittest.skipUnless(hasattr(openssl_hashlib, 'pbkdf2_hmac'),
10271031
' test requires OpenSSL > 1.0')

0 commit comments

Comments
 (0)