setup: require that Python has TLS 1.1 or TLS 1.2
authorManuel Jacob <me@manueljacob.de>
Sat, 30 May 2020 23:42:19 +0200
changeset 44893 95c832849955
parent 44892 dd7c4a208a4e
child 44894 39c598f1c774
setup: require that Python has TLS 1.1 or TLS 1.2 This ensures that Mercurial never downgrades the minimum TLS version from TLS 1.1+ to TLS 1.0+ and enables us to remove that compatibility code. It is reasonable to expect that distributions having Python 2.7.9+ or having backported modern features to the ssl module (which we require) have a OpenSSL version supporting TLS 1.1 or TLS 1.2, as this is the main reason why distributions would want to backport these features. TLS 1.1 and TLS 1.2 are often either both enabled or both not enabled. However, both can be disabled independently, at least on current Python / OpenSSL versions. For the record, I contacted the CPython developers to remark that unconditionally defining ssl.PROTOCOL_TLSv1_1 / ssl.PROTOCOL_TLSv1_2 is problematic: https://github.com/python/cpython/commit/6e8cda91d92da72800d891b2fc2073ecbc134d98#r39569316
relnotes/next
setup.py
--- a/relnotes/next	Sun May 31 12:07:17 2020 +0200
+++ b/relnotes/next	Sat May 30 23:42:19 2020 +0200
@@ -7,7 +7,9 @@
 == Backwards Compatibility Changes ==
 
 * Mercurial now requires at least Python 2.7.9 or a Python version that
-  backported modern SSL/TLS features (as defined in PEP 466).
+  backported modern SSL/TLS features (as defined in PEP 466), and that Python
+  was compiled against a OpenSSL version supporting TLS 1.1 or TLS 1.2
+  (likely this requires the OpenSSL version to be at least 1.0.1).
 
 
 == Internal API Changes ==
--- a/setup.py	Sun May 31 12:07:17 2020 +0200
+++ b/setup.py	Sat May 30 23:42:19 2020 +0200
@@ -98,6 +98,28 @@
     printf(error, file=sys.stderr)
     sys.exit(1)
 
+# ssl.HAS_TLSv1* are preferred to check support but they were added in Python
+# 3.7. Prior to CPython commit 6e8cda91d92da72800d891b2fc2073ecbc134d98
+# (backported to the 3.7 branch), ssl.PROTOCOL_TLSv1_1 / ssl.PROTOCOL_TLSv1_2
+# were defined only if compiled against a OpenSSL version with TLS 1.1 / 1.2
+# support. At the mentioned commit, they were unconditionally defined.
+_notset = object()
+has_tlsv1_1 = getattr(ssl, 'HAS_TLSv1_1', _notset)
+if has_tlsv1_1 is _notset:
+    has_tlsv1_1 = getattr(ssl, 'PROTOCOL_TLSv1_1', _notset) is not _notset
+has_tlsv1_2 = getattr(ssl, 'HAS_TLSv1_2', _notset)
+if has_tlsv1_2 is _notset:
+    has_tlsv1_2 = getattr(ssl, 'PROTOCOL_TLSv1_2', _notset) is not _notset
+if not (has_tlsv1_1 or has_tlsv1_2):
+    error = """
+The `ssl` module does not advertise support for TLS 1.1 or TLS 1.2.
+Please make sure that your Python installation was compiled against an OpenSSL
+version enabling these features (likely this requires the OpenSSL version to
+be at least 1.0.1).
+"""
+    printf(error, file=sys.stderr)
+    sys.exit(1)
+
 if sys.version_info[0] >= 3:
     DYLIB_SUFFIX = sysconfig.get_config_vars()['EXT_SUFFIX']
 else: