From 9359f01469bf61587bfe50210d162e290285000f Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 20 Mar 2026 14:37:54 +0100 Subject: [PATCH 1/8] gh-146207: Add support for OpenSSL 4.0.0 alpha1 OpenSSL 4.0.0 alpha1 no longer defines the symbols: * SSLv3_method * TLSv1_method * TLSv1_1_method * TLSv1_2_method --- Lib/test/test_ssl.py | 46 ++++++++++--------- ...-03-20-16-52-37.gh-issue-146207.1n374d.rst | 1 + Modules/_ssl.c | 13 ++++++ 3 files changed, 39 insertions(+), 21 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-03-20-16-52-37.gh-issue-146207.1n374d.rst diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index dc795c6bd8a41f..e682320511cf22 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -395,7 +395,7 @@ def test_constants(self): ssl.OP_NO_COMPRESSION self.assertEqual(ssl.HAS_SNI, True) self.assertEqual(ssl.HAS_ECDH, True) - self.assertEqual(ssl.HAS_TLSv1_2, True) + ssl.HAS_TLSv1_2 self.assertEqual(ssl.HAS_TLSv1_3, True) ssl.OP_NO_SSLv2 ssl.OP_NO_SSLv3 @@ -656,12 +656,14 @@ def test_openssl111_deprecations(self): ssl.OP_NO_TLSv1_2, ssl.OP_NO_TLSv1_3 ] - protocols = [ - ssl.PROTOCOL_TLSv1, - ssl.PROTOCOL_TLSv1_1, - ssl.PROTOCOL_TLSv1_2, - ssl.PROTOCOL_TLS - ] + protocols = [] + if hasattr(ssl, 'PROTOCOL_TLSv1'): + protocols.append(ssl.PROTOCOL_TLSv1) + if hasattr(ssl, 'PROTOCOL_TLSv1_1'): + protocols.append(ssl.PROTOCOL_TLSv1_1) + if hasattr(ssl, 'PROTOCOL_TLSv1_2'): + protocols.append(ssl.PROTOCOL_TLSv1_2) + protocols.append(ssl.PROTOCOL_TLS) versions = [ ssl.TLSVersion.SSLv3, ssl.TLSVersion.TLSv1, @@ -1205,6 +1207,7 @@ def test_min_max_version(self): ssl.TLSVersion.TLSv1, ssl.TLSVersion.TLSv1_1, ssl.TLSVersion.TLSv1_2, + ssl.TLSVersion.TLSv1_3, ssl.TLSVersion.SSLv3, } ) @@ -1218,7 +1221,7 @@ def test_min_max_version(self): with self.assertRaises(ValueError): ctx.minimum_version = 42 - if has_tls_protocol(ssl.PROTOCOL_TLSv1_1): + if has_tls_protocol('PROTOCOL_TLSv1_1'): ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_1) self.assertIn( @@ -1675,23 +1678,24 @@ def test__create_stdlib_context(self): self.assertFalse(ctx.check_hostname) self._assert_context_options(ctx) - if has_tls_protocol(ssl.PROTOCOL_TLSv1): + if has_tls_protocol('PROTOCOL_TLSv1'): with warnings_helper.check_warnings(): ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1) self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1) self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) self._assert_context_options(ctx) - with warnings_helper.check_warnings(): - ctx = ssl._create_stdlib_context( - ssl.PROTOCOL_TLSv1_2, - cert_reqs=ssl.CERT_REQUIRED, - check_hostname=True - ) - self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1_2) - self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED) - self.assertTrue(ctx.check_hostname) - self._assert_context_options(ctx) + if has_tls_protocol('PROTOCOL_TLSv1_2'): + with warnings_helper.check_warnings(): + ctx = ssl._create_stdlib_context( + ssl.PROTOCOL_TLSv1_2, + cert_reqs=ssl.CERT_REQUIRED, + check_hostname=True + ) + self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1_2) + self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED) + self.assertTrue(ctx.check_hostname) + self._assert_context_options(ctx) ctx = ssl._create_stdlib_context(purpose=ssl.Purpose.CLIENT_AUTH) self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_SERVER) @@ -3654,10 +3658,10 @@ def test_protocol_tlsv1_2(self): client_options=ssl.OP_NO_TLSv1_2) try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1_2, 'TLSv1.2') - if has_tls_protocol(ssl.PROTOCOL_TLSv1): + if has_tls_protocol('PROTOCOL_TLSv1'): try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1, False) try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1_2, False) - if has_tls_protocol(ssl.PROTOCOL_TLSv1_1): + if has_tls_protocol('PROTOCOL_TLSv1_1'): try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_1, False) try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_2, False) diff --git a/Misc/NEWS.d/next/Library/2026-03-20-16-52-37.gh-issue-146207.1n374d.rst b/Misc/NEWS.d/next/Library/2026-03-20-16-52-37.gh-issue-146207.1n374d.rst new file mode 100644 index 00000000000000..e31d29f4f19381 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-03-20-16-52-37.gh-issue-146207.1n374d.rst @@ -0,0 +1 @@ +Add support for OpenSSL 4.0.0 alpha1. Patch by Victor Stinner. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 2eb31229a9bf3c..829b0598d5d136 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -164,6 +164,13 @@ static void _PySSLFixErrno(void) { #error Unsupported OpenSSL version #endif +#if (OPENSSL_VERSION_NUMBER >= 0x40000000L) +# define OPENSSL_NO_SSL3 +# define OPENSSL_NO_TLS1 +# define OPENSSL_NO_TLS1_1 +# define OPENSSL_NO_TLS1_2 +#endif + /* OpenSSL API 1.1.0+ does not include version methods */ #ifndef OPENSSL_NO_SSL3_METHOD extern const SSL_METHOD *SSLv3_method(void); @@ -6967,9 +6974,15 @@ sslmodule_init_constants(PyObject *m) ADD_INT_CONST("PROTOCOL_TLS", PY_SSL_VERSION_TLS); ADD_INT_CONST("PROTOCOL_TLS_CLIENT", PY_SSL_VERSION_TLS_CLIENT); ADD_INT_CONST("PROTOCOL_TLS_SERVER", PY_SSL_VERSION_TLS_SERVER); +#ifndef OPENSSL_NO_TLS1 ADD_INT_CONST("PROTOCOL_TLSv1", PY_SSL_VERSION_TLS1); +#endif +#ifndef OPENSSL_NO_TLS1_1 ADD_INT_CONST("PROTOCOL_TLSv1_1", PY_SSL_VERSION_TLS1_1); +#endif +#ifndef OPENSSL_NO_TLS1_2 ADD_INT_CONST("PROTOCOL_TLSv1_2", PY_SSL_VERSION_TLS1_2); +#endif #define ADD_OPTION(NAME, VALUE) if (sslmodule_add_option(m, NAME, (VALUE)) < 0) return -1 From 5f9bc317bf3f9908b4b478a948315caa3b2dcd80 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 20 Mar 2026 17:19:34 +0100 Subject: [PATCH 2/8] Test openssl-4.0.0-alpha1 in GitHub Action --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2fa2ab768dc48b..40feaef01ce1f3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -275,6 +275,7 @@ jobs: - { name: openssl, version: 3.4.4 } - { name: openssl, version: 3.5.5 } - { name: openssl, version: 3.6.1 } + - { name: openssl, version: 4.0.0-alpha1 } ## AWS-LC - { name: aws-lc, version: 1.68.0 } env: From 8e607c4856279f19857817d121b20e92a59c0fb0 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 20 Mar 2026 17:35:54 +0100 Subject: [PATCH 3/8] Update test_openssl_version() --- Lib/test/test_ssl.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index e682320511cf22..c00a9af658474e 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -586,11 +586,11 @@ def test_openssl_version(self): # Some sanity checks follow # >= 1.1.1 self.assertGreaterEqual(n, 0x10101000) - # < 4.0 - self.assertLess(n, 0x40000000) + # < 5.0 + self.assertLess(n, 0x50000000) major, minor, fix, patch, status = t self.assertGreaterEqual(major, 1) - self.assertLess(major, 4) + self.assertLess(major, 5) self.assertGreaterEqual(minor, 0) self.assertLess(minor, 256) self.assertGreaterEqual(fix, 0) From a5152be63f6b2181a3619d369c14b1fe9c24339f Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 20 Mar 2026 17:44:39 +0100 Subject: [PATCH 4/8] Update multissltests.py for OpenSSL 4 --- Tools/ssl/multissltests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tools/ssl/multissltests.py b/Tools/ssl/multissltests.py index 3b4507c6771b69..c6f0be0ebd9927 100755 --- a/Tools/ssl/multissltests.py +++ b/Tools/ssl/multissltests.py @@ -427,11 +427,11 @@ class BuildOpenSSL(AbstractBuilder): depend_target = 'depend' def _post_install(self): - if self.version.startswith("3."): + if self.version.startswith(("3.", "4.")): self._post_install_3xx() def _build_src(self, config_args=()): - if self.version.startswith("3."): + if self.version.startswith(("3.", "4.")): config_args += ("enable-fips",) super()._build_src(config_args) From 4ee447a19341bcff180cadeca310ad66139b7faf Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 20 Mar 2026 17:52:01 +0100 Subject: [PATCH 5/8] Add const qualifier to fix compiler warnings --- Modules/_ssl.c | 10 +++++----- Modules/_ssl/cert.c | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 829b0598d5d136..7d43f1ac9863af 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -1158,7 +1158,7 @@ _asn1obj2py(_sslmodulestate *state, const ASN1_OBJECT *name, int no_name) static PyObject * _create_tuple_for_attribute(_sslmodulestate *state, - ASN1_OBJECT *name, ASN1_STRING *value) + const ASN1_OBJECT *name, const ASN1_STRING *value) { Py_ssize_t buflen; PyObject *pyattr; @@ -1187,16 +1187,16 @@ _create_tuple_for_attribute(_sslmodulestate *state, } static PyObject * -_create_tuple_for_X509_NAME (_sslmodulestate *state, X509_NAME *xname) +_create_tuple_for_X509_NAME (_sslmodulestate *state, const X509_NAME *xname) { PyObject *dn = NULL; /* tuple which represents the "distinguished name" */ PyObject *rdn = NULL; /* tuple to hold a "relative distinguished name" */ PyObject *rdnt; PyObject *attr = NULL; /* tuple to hold an attribute */ int entry_count = X509_NAME_entry_count(xname); - X509_NAME_ENTRY *entry; - ASN1_OBJECT *name; - ASN1_STRING *value; + const X509_NAME_ENTRY *entry; + const ASN1_OBJECT *name; + const ASN1_STRING *value; int index_counter; int rdn_level = -1; int retcode; diff --git a/Modules/_ssl/cert.c b/Modules/_ssl/cert.c index f2e7be896687c8..061b0fb31716a4 100644 --- a/Modules/_ssl/cert.c +++ b/Modules/_ssl/cert.c @@ -128,7 +128,8 @@ _ssl_Certificate_get_info_impl(PySSLCertificate *self) } static PyObject* -_x509name_print(_sslmodulestate *state, X509_NAME *name, int indent, unsigned long flags) +_x509name_print(_sslmodulestate *state, const X509_NAME *name, + int indent, unsigned long flags) { PyObject *res; BIO *biobuf; From 71e9c1af6a1bcc9e21e5f7bca73d61b1c437e5b0 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 21 Mar 2026 10:50:03 +0100 Subject: [PATCH 6/8] Revert "Test openssl-4.0.0-alpha1 in GitHub Action" This reverts commit 5f9bc317bf3f9908b4b478a948315caa3b2dcd80. --- .github/workflows/build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 40feaef01ce1f3..2fa2ab768dc48b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -275,7 +275,6 @@ jobs: - { name: openssl, version: 3.4.4 } - { name: openssl, version: 3.5.5 } - { name: openssl, version: 3.6.1 } - - { name: openssl, version: 4.0.0-alpha1 } ## AWS-LC - { name: aws-lc, version: 1.68.0 } env: From 4b55d227e5feb7dd82e040e41fd2cbd315ea5d96 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 21 Mar 2026 11:58:27 +0100 Subject: [PATCH 7/8] Apply suggestion from @picnixz MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Modules/_ssl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 7d43f1ac9863af..f8fb7d681518d8 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -1187,7 +1187,7 @@ _create_tuple_for_attribute(_sslmodulestate *state, } static PyObject * -_create_tuple_for_X509_NAME (_sslmodulestate *state, const X509_NAME *xname) +_create_tuple_for_X509_NAME(_sslmodulestate *state, const X509_NAME *xname) { PyObject *dn = NULL; /* tuple which represents the "distinguished name" */ PyObject *rdn = NULL; /* tuple to hold a "relative distinguished name" */ From 1b64620d7818ea7b6e25ca2ef10787ea2f654142 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 21 Mar 2026 12:00:43 +0100 Subject: [PATCH 8/8] Define also OPENSSL_NO_SSL3_METHOD macro --- Modules/_ssl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Modules/_ssl.c b/Modules/_ssl.c index f8fb7d681518d8..09c2f4c714d16d 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -169,6 +169,10 @@ static void _PySSLFixErrno(void) { # define OPENSSL_NO_TLS1 # define OPENSSL_NO_TLS1_1 # define OPENSSL_NO_TLS1_2 +# define OPENSSL_NO_SSL3_METHOD +# define OPENSSL_NO_TLS1_METHOD +# define OPENSSL_NO_TLS1_1_METHOD +# define OPENSSL_NO_TLS1_2_METHOD #endif /* OpenSSL API 1.1.0+ does not include version methods */