Skip to content

Commit 6e0f8b1

Browse files
committed
Python3: Add support for OpenSSL 4.0.0
miss-islington/cpython@f24009f and PR 146403
1 parent 102b6f5 commit 6e0f8b1

File tree

1 file changed

+255
-0
lines changed

1 file changed

+255
-0
lines changed
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
From b9eb9f73e0f77acdc89bd85773a13f95bcc2d81b Mon Sep 17 00:00:00 2001
2+
From: Victor Stinner <vstinner@python.org>
3+
Date: Wed, 25 Mar 2026 07:44:47 +0100
4+
Subject: [PATCH] gh-146207: Add support for OpenSSL 4.0.0 alpha1 (GH-146217)
5+
MIME-Version: 1.0
6+
Content-Type: text/plain; charset=UTF-8
7+
Content-Transfer-Encoding: 8bit
8+
9+
OpenSSL 4.0.0 alpha1 removed these functions:
10+
11+
* SSLv3_method()
12+
* TLSv1_method()
13+
* TLSv1_1_method()
14+
* TLSv1_2_method()
15+
16+
Other changes:
17+
18+
* Update test_openssl_version().
19+
* Update multissltests.py for OpenSSL 4.
20+
* Add const qualifier to fix compiler warnings.
21+
(cherry picked from commit 3364e7e62fa24d0e19133fb0f90b1c24ef1110c5)
22+
23+
Co-authored-by: Victor Stinner <vstinner@python.org>
24+
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
25+
---
26+
Lib/test/test_ssl.py | 52 ++++++++++++++++++++------------------
27+
Modules/_ssl.c | 27 ++++++++++++++++----
28+
Modules/_ssl/cert.c | 3 ++-
29+
Tools/ssl/multissltests.py | 7 ++++-
30+
4 files changed, 58 insertions(+), 31 deletions(-)
31+
32+
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
33+
index 423d0292b4ebf8..0eced257a55333 100644
34+
--- a/Lib/test/test_ssl.py
35+
+++ b/Lib/test/test_ssl.py
36+
@@ -380,7 +380,7 @@ def test_constants(self):
37+
ssl.OP_NO_COMPRESSION
38+
self.assertEqual(ssl.HAS_SNI, True)
39+
self.assertEqual(ssl.HAS_ECDH, True)
40+
- self.assertEqual(ssl.HAS_TLSv1_2, True)
41+
+ self.assertIsInstance(ssl.HAS_TLSv1_2, bool)
42+
self.assertEqual(ssl.HAS_TLSv1_3, True)
43+
ssl.OP_NO_SSLv2
44+
ssl.OP_NO_SSLv3
45+
@@ -571,11 +571,11 @@ def test_openssl_version(self):
46+
# Some sanity checks follow
47+
# >= 1.1.1
48+
self.assertGreaterEqual(n, 0x10101000)
49+
- # < 4.0
50+
- self.assertLess(n, 0x40000000)
51+
+ # < 5.0
52+
+ self.assertLess(n, 0x50000000)
53+
major, minor, fix, patch, status = t
54+
self.assertGreaterEqual(major, 1)
55+
- self.assertLess(major, 4)
56+
+ self.assertLess(major, 5)
57+
self.assertGreaterEqual(minor, 0)
58+
self.assertLess(minor, 256)
59+
self.assertGreaterEqual(fix, 0)
60+
@@ -641,12 +641,14 @@ def test_openssl111_deprecations(self):
61+
ssl.OP_NO_TLSv1_2,
62+
ssl.OP_NO_TLSv1_3
63+
]
64+
- protocols = [
65+
- ssl.PROTOCOL_TLSv1,
66+
- ssl.PROTOCOL_TLSv1_1,
67+
- ssl.PROTOCOL_TLSv1_2,
68+
- ssl.PROTOCOL_TLS
69+
- ]
70+
+ protocols = []
71+
+ if hasattr(ssl, 'PROTOCOL_TLSv1'):
72+
+ protocols.append(ssl.PROTOCOL_TLSv1)
73+
+ if hasattr(ssl, 'PROTOCOL_TLSv1_1'):
74+
+ protocols.append(ssl.PROTOCOL_TLSv1_1)
75+
+ if hasattr(ssl, 'PROTOCOL_TLSv1_2'):
76+
+ protocols.append(ssl.PROTOCOL_TLSv1_2)
77+
+ protocols.append(ssl.PROTOCOL_TLS)
78+
versions = [
79+
ssl.TLSVersion.SSLv3,
80+
ssl.TLSVersion.TLSv1,
81+
@@ -1140,6 +1142,7 @@ def test_min_max_version(self):
82+
ssl.TLSVersion.TLSv1,
83+
ssl.TLSVersion.TLSv1_1,
84+
ssl.TLSVersion.TLSv1_2,
85+
+ ssl.TLSVersion.TLSv1_3,
86+
ssl.TLSVersion.SSLv3,
87+
}
88+
)
89+
@@ -1153,7 +1156,7 @@ def test_min_max_version(self):
90+
with self.assertRaises(ValueError):
91+
ctx.minimum_version = 42
92+
93+
- if has_tls_protocol(ssl.PROTOCOL_TLSv1_1):
94+
+ if has_tls_protocol('PROTOCOL_TLSv1_1'):
95+
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_1)
96+
97+
self.assertIn(
98+
@@ -1605,23 +1608,24 @@ def test__create_stdlib_context(self):
99+
self.assertFalse(ctx.check_hostname)
100+
self._assert_context_options(ctx)
101+
102+
- if has_tls_protocol(ssl.PROTOCOL_TLSv1):
103+
+ if has_tls_protocol('PROTOCOL_TLSv1'):
104+
with warnings_helper.check_warnings():
105+
ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1)
106+
self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1)
107+
self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
108+
self._assert_context_options(ctx)
109+
110+
- with warnings_helper.check_warnings():
111+
- ctx = ssl._create_stdlib_context(
112+
- ssl.PROTOCOL_TLSv1_2,
113+
- cert_reqs=ssl.CERT_REQUIRED,
114+
- check_hostname=True
115+
- )
116+
- self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1_2)
117+
- self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
118+
- self.assertTrue(ctx.check_hostname)
119+
- self._assert_context_options(ctx)
120+
+ if has_tls_protocol('PROTOCOL_TLSv1_2'):
121+
+ with warnings_helper.check_warnings():
122+
+ ctx = ssl._create_stdlib_context(
123+
+ ssl.PROTOCOL_TLSv1_2,
124+
+ cert_reqs=ssl.CERT_REQUIRED,
125+
+ check_hostname=True
126+
+ )
127+
+ self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1_2)
128+
+ self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
129+
+ self.assertTrue(ctx.check_hostname)
130+
+ self._assert_context_options(ctx)
131+
132+
ctx = ssl._create_stdlib_context(purpose=ssl.Purpose.CLIENT_AUTH)
133+
self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS_SERVER)
134+
@@ -3517,10 +3521,10 @@ def test_protocol_tlsv1_2(self):
135+
client_options=ssl.OP_NO_TLSv1_2)
136+
137+
try_protocol_combo(ssl.PROTOCOL_TLS, ssl.PROTOCOL_TLSv1_2, 'TLSv1.2')
138+
- if has_tls_protocol(ssl.PROTOCOL_TLSv1):
139+
+ if has_tls_protocol('PROTOCOL_TLSv1'):
140+
try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1, False)
141+
try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1_2, False)
142+
- if has_tls_protocol(ssl.PROTOCOL_TLSv1_1):
143+
+ if has_tls_protocol('PROTOCOL_TLSv1_1'):
144+
try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_1, False)
145+
try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_2, False)
146+
147+
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
148+
index a24b6b30b2f648..60a3d3f6a8fc90 100644
149+
--- a/Modules/_ssl.c
150+
+++ b/Modules/_ssl.c
151+
@@ -134,6 +134,17 @@ static void _PySSLFixErrno(void) {
152+
#error Unsupported OpenSSL version
153+
#endif
154+
155+
+#if (OPENSSL_VERSION_NUMBER >= 0x40000000L)
156+
+# define OPENSSL_NO_SSL3
157+
+# define OPENSSL_NO_TLS1
158+
+# define OPENSSL_NO_TLS1_1
159+
+# define OPENSSL_NO_TLS1_2
160+
+# define OPENSSL_NO_SSL3_METHOD
161+
+# define OPENSSL_NO_TLS1_METHOD
162+
+# define OPENSSL_NO_TLS1_1_METHOD
163+
+# define OPENSSL_NO_TLS1_2_METHOD
164+
+#endif
165+
+
166+
/* OpenSSL API 1.1.0+ does not include version methods */
167+
#ifndef OPENSSL_NO_SSL3_METHOD
168+
extern const SSL_METHOD *SSLv3_method(void);
169+
@@ -1133,7 +1144,7 @@ _asn1obj2py(_sslmodulestate *state, const ASN1_OBJECT *name, int no_name)
170+
171+
static PyObject *
172+
_create_tuple_for_attribute(_sslmodulestate *state,
173+
- ASN1_OBJECT *name, ASN1_STRING *value)
174+
+ const ASN1_OBJECT *name, const ASN1_STRING *value)
175+
{
176+
Py_ssize_t buflen;
177+
PyObject *pyattr;
178+
@@ -1162,16 +1173,16 @@ _create_tuple_for_attribute(_sslmodulestate *state,
179+
}
180+
181+
static PyObject *
182+
-_create_tuple_for_X509_NAME (_sslmodulestate *state, X509_NAME *xname)
183+
+_create_tuple_for_X509_NAME(_sslmodulestate *state, const X509_NAME *xname)
184+
{
185+
PyObject *dn = NULL; /* tuple which represents the "distinguished name" */
186+
PyObject *rdn = NULL; /* tuple to hold a "relative distinguished name" */
187+
PyObject *rdnt;
188+
PyObject *attr = NULL; /* tuple to hold an attribute */
189+
int entry_count = X509_NAME_entry_count(xname);
190+
- X509_NAME_ENTRY *entry;
191+
- ASN1_OBJECT *name;
192+
- ASN1_STRING *value;
193+
+ const X509_NAME_ENTRY *entry;
194+
+ const ASN1_OBJECT *name;
195+
+ const ASN1_STRING *value;
196+
int index_counter;
197+
int rdn_level = -1;
198+
int retcode;
199+
@@ -6510,9 +6521,15 @@ sslmodule_init_constants(PyObject *m)
200+
ADD_INT_CONST("PROTOCOL_TLS", PY_SSL_VERSION_TLS);
201+
ADD_INT_CONST("PROTOCOL_TLS_CLIENT", PY_SSL_VERSION_TLS_CLIENT);
202+
ADD_INT_CONST("PROTOCOL_TLS_SERVER", PY_SSL_VERSION_TLS_SERVER);
203+
+#ifndef OPENSSL_NO_TLS1
204+
ADD_INT_CONST("PROTOCOL_TLSv1", PY_SSL_VERSION_TLS1);
205+
+#endif
206+
+#ifndef OPENSSL_NO_TLS1_1
207+
ADD_INT_CONST("PROTOCOL_TLSv1_1", PY_SSL_VERSION_TLS1_1);
208+
+#endif
209+
+#ifndef OPENSSL_NO_TLS1_2
210+
ADD_INT_CONST("PROTOCOL_TLSv1_2", PY_SSL_VERSION_TLS1_2);
211+
+#endif
212+
213+
#define ADD_OPTION(NAME, VALUE) if (sslmodule_add_option(m, NAME, (VALUE)) < 0) return -1
214+
215+
diff --git a/Modules/_ssl/cert.c b/Modules/_ssl/cert.c
216+
index f2e7be896687c8..061b0fb31716a4 100644
217+
--- a/Modules/_ssl/cert.c
218+
+++ b/Modules/_ssl/cert.c
219+
@@ -128,7 +128,8 @@ _ssl_Certificate_get_info_impl(PySSLCertificate *self)
220+
}
221+
222+
static PyObject*
223+
-_x509name_print(_sslmodulestate *state, X509_NAME *name, int indent, unsigned long flags)
224+
+_x509name_print(_sslmodulestate *state, const X509_NAME *name,
225+
+ int indent, unsigned long flags)
226+
{
227+
PyObject *res;
228+
BIO *biobuf;
229+
diff --git a/Tools/ssl/multissltests.py b/Tools/ssl/multissltests.py
230+
index 86baf8a3a74bd4..9019b2bcf38768 100755
231+
--- a/Tools/ssl/multissltests.py
232+
+++ b/Tools/ssl/multissltests.py
233+
@@ -414,9 +414,11 @@ class BuildOpenSSL(AbstractBuilder):
234+
def _post_install(self):
235+
if self.version.startswith("3."):
236+
self._post_install_3xx()
237+
+ elif self.version.startswith("4."):
238+
+ self._post_install_4xx()
239+
240+
def _build_src(self, config_args=()):
241+
- if self.version.startswith("3."):
242+
+ if self.version.startswith(("3.", "4.")):
243+
config_args += ("enable-fips",)
244+
super()._build_src(config_args)
245+
246+
@@ -432,6 +434,9 @@ def _post_install_3xx(self):
247+
lib64 = self.lib_dir + "64"
248+
os.symlink(lib64, self.lib_dir)
249+
250+
+ def _post_install_4xx(self):
251+
+ self._post_install_3xx()
252+
+
253+
@property
254+
def short_version(self):
255+
"""Short version for OpenSSL download URL"""

0 commit comments

Comments
 (0)