From 98339d1e7df3a8d754b1931b28c1df17ca4f7149 Mon Sep 17 00:00:00 2001 From: Debian Python Team Date: Tue, 7 Jun 2022 19:53:46 +0100 Subject: [PATCH] _sslutil__avoid_deprecation_warnings_from_python_3_10_s_ssl_module # HG changeset patch # User Julien Cristau # Date 1649506532 -7200 # Sat Apr 09 14:15:32 2022 +0200 # Node ID 410916fc5935c7855c2cf4876d8311d34aabc29a # Parent 96cc0ab5e1e68e4e163e8933842f908dcf42897a sslutil: avoid deprecation warnings from python 3.10's ssl module Use ssl.PROTOCOL_TLS_{CLIENT,SERVER} and SSLContext.{min,max}imum_version when supported (3.7+). And, catch deprecation warnings when the user asks for deprecated TLS versions (1.0 and 1.1). Differential Revision: https://phab.mercurial-scm.org/D12488 Gbp-Pq: Topic py310 Gbp-Pq: Name 3_sslutil__avoid_deprecation_warnings_from_python_3_10_s_ssl_module.patch --- mercurial/sslutil.py | 129 +++++++++++++++++++++++++++++++------------ 1 file changed, 93 insertions(+), 36 deletions(-) diff --git a/mercurial/sslutil.py b/mercurial/sslutil.py index 2b1e0d7..38b670e 100644 --- a/mercurial/sslutil.py +++ b/mercurial/sslutil.py @@ -13,6 +13,7 @@ import hashlib import os import re import ssl +import warnings from .i18n import _ from .pycompat import getattr @@ -309,14 +310,38 @@ def wrapsocket(sock, keyfile, certfile, ui, serverhostname=None): # bundle with a specific CA cert removed. If the system/default CA bundle # is loaded and contains that removed CA, you've just undone the user's # choice. - # - # Despite its name, PROTOCOL_SSLv23 selects the highest protocol that both - # ends support, including TLS protocols. commonssloptions() restricts the - # set of allowed protocols. - sslcontext = ssl.SSLContext(ssl.PROTOCOL_SSLv23) - sslcontext.options |= commonssloptions(settings[b'minimumprotocol']) + + if util.safehasattr(ssl, 'PROTOCOL_TLS_CLIENT'): + # python 3.7+ + sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + minimumprotocol = settings[b'minimumprotocol'] + if minimumprotocol == b'tls1.0': + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', 'ssl.TLSVersion.TLSv1 is deprecated', DeprecationWarning) + sslcontext.minimum_version = ssl.TLSVersion.TLSv1 + elif minimumprotocol == b'tls1.1': + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', 'ssl.TLSVersion.TLSv1_1 is deprecated', DeprecationWarning) + sslcontext.minimum_version = ssl.TLSVersion.TLSv1_1 + elif minimumprotocol == b'tls1.2': + sslcontext.minimum_version = ssl.TLSVersion.TLSv1_2 + else: + raise error.Abort(_(b'this should not happen')) + # Prevent CRIME. + # There is no guarantee this attribute is defined on the module. + sslcontext.options |= getattr(ssl, 'OP_NO_COMPRESSION', 0) + else: + # Despite its name, PROTOCOL_SSLv23 selects the highest protocol that both + # ends support, including TLS protocols. commonssloptions() restricts the + # set of allowed protocols. + sslcontext = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + sslcontext.options |= commonssloptions(settings[b'minimumprotocol']) + + # We check the hostname ourselves in _verifycert + sslcontext.check_hostname = False sslcontext.verify_mode = settings[b'verifymode'] + if settings[b'ciphers']: try: sslcontext.set_ciphers(pycompat.sysstr(settings[b'ciphers'])) @@ -510,37 +535,69 @@ def wrapserversocket( _(b'referenced certificate file (%s) does not exist') % f ) - # Despite its name, PROTOCOL_SSLv23 selects the highest protocol that both - # ends support, including TLS protocols. commonssloptions() restricts the - # set of allowed protocols. - protocol = ssl.PROTOCOL_SSLv23 - options = commonssloptions(b'tls1.0') - - # This config option is intended for use in tests only. It is a giant - # footgun to kill security. Don't define it. - exactprotocol = ui.config(b'devel', b'serverexactprotocol') - if exactprotocol == b'tls1.0': - if b'tls1.0' not in supportedprotocols: - raise error.Abort(_(b'TLS 1.0 not supported by this Python')) - protocol = ssl.PROTOCOL_TLSv1 - elif exactprotocol == b'tls1.1': - if b'tls1.1' not in supportedprotocols: - raise error.Abort(_(b'TLS 1.1 not supported by this Python')) - protocol = ssl.PROTOCOL_TLSv1_1 - elif exactprotocol == b'tls1.2': - if b'tls1.2' not in supportedprotocols: - raise error.Abort(_(b'TLS 1.2 not supported by this Python')) - protocol = ssl.PROTOCOL_TLSv1_2 - elif exactprotocol: - raise error.Abort( - _(b'invalid value for serverexactprotocol: %s') % exactprotocol - ) + if util.safehasattr(ssl, 'PROTOCOL_TLS_SERVER'): + # python 3.7+ + sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + sslcontext.options |= getattr(ssl, 'OP_NO_COMPRESSION', 0) + + # This config option is intended for use in tests only. It is a giant + # footgun to kill security. Don't define it. + exactprotocol = ui.config(b'devel', b'serverexactprotocol') + if exactprotocol == b'tls1.0': + if b'tls1.0' not in supportedprotocols: + raise error.Abort(_(b'TLS 1.0 not supported by this Python')) + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', 'ssl.TLSVersion.TLSv1 is deprecated', DeprecationWarning) + sslcontext.minimum_version = ssl.TLSVersion.TLSv1 + sslcontext.maximum_version = ssl.TLSVersion.TLSv1 + elif exactprotocol == b'tls1.1': + if b'tls1.1' not in supportedprotocols: + raise error.Abort(_(b'TLS 1.1 not supported by this Python')) + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', 'ssl.TLSVersion.TLSv1_1 is deprecated', DeprecationWarning) + sslcontext.minimum_version = ssl.TLSVersion.TLSv1_1 + sslcontext.maximum_version = ssl.TLSVersion.TLSv1_1 + elif exactprotocol == b'tls1.2': + if b'tls1.2' not in supportedprotocols: + raise error.Abort(_(b'TLS 1.2 not supported by this Python')) + sslcontext.minimum_version = ssl.TLSVersion.TLSv1_2 + sslcontext.maximum_version = ssl.TLSVersion.TLSv1_2 + elif exactprotocol: + raise error.Abort( + _(b'invalid value for serverexactprotocol: %s') % exactprotocol + ) + else: + # Despite its name, PROTOCOL_SSLv23 selects the highest protocol that both + # ends support, including TLS protocols. commonssloptions() restricts the + # set of allowed protocols. + protocol = ssl.PROTOCOL_SSLv23 + options = commonssloptions(b'tls1.0') + + # This config option is intended for use in tests only. It is a giant + # footgun to kill security. Don't define it. + exactprotocol = ui.config(b'devel', b'serverexactprotocol') + if exactprotocol == b'tls1.0': + if b'tls1.0' not in supportedprotocols: + raise error.Abort(_(b'TLS 1.0 not supported by this Python')) + protocol = ssl.PROTOCOL_TLSv1 + elif exactprotocol == b'tls1.1': + if b'tls1.1' not in supportedprotocols: + raise error.Abort(_(b'TLS 1.1 not supported by this Python')) + protocol = ssl.PROTOCOL_TLSv1_1 + elif exactprotocol == b'tls1.2': + if b'tls1.2' not in supportedprotocols: + raise error.Abort(_(b'TLS 1.2 not supported by this Python')) + protocol = ssl.PROTOCOL_TLSv1_2 + elif exactprotocol: + raise error.Abort( + _(b'invalid value for serverexactprotocol: %s') % exactprotocol + ) - # We /could/ use create_default_context() here since it doesn't load - # CAs when configured for client auth. However, it is hard-coded to - # use ssl.PROTOCOL_SSLv23 which may not be appropriate here. - sslcontext = ssl.SSLContext(protocol) - sslcontext.options |= options + # We /could/ use create_default_context() here since it doesn't load + # CAs when configured for client auth. However, it is hard-coded to + # use ssl.PROTOCOL_SSLv23 which may not be appropriate here. + sslcontext = ssl.SSLContext(protocol) + sslcontext.options |= options # Improve forward secrecy. sslcontext.options |= getattr(ssl, 'OP_SINGLE_DH_USE', 0) -- 2.30.2