Skip to content

Commit 66cd65c

Browse files
committed
Python3: Add support for OpenSSL 4.0.0
miss-islington/cpython@f24009f and PR 146403
1 parent 7998e36 commit 66cd65c

File tree

1 file changed

+294
-0
lines changed

1 file changed

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

0 commit comments

Comments
 (0)