new file mode 100644
@@ -0,0 +1,257 @@
+From 3364e7e62fa24d0e19133fb0f90b1c24ef1110c5 Mon Sep 17 00:00:00 2001
+From: Victor Stinner <vstinner@python.org>
+Date: Wed, 25 Mar 2026 07:44:47 +0100
+Subject: [PATCH] gh-146207: Add support for OpenSSL 4.0.0 alpha1 (#146217)
+
+OpenSSL 4.0.0 alpha1 removed these functions:
+
+* SSLv3_method()
+* TLSv1_method()
+* TLSv1_1_method()
+* TLSv1_2_method()
+
+Other changes:
+
+* Update test_openssl_version().
+* Update multissltests.py for OpenSSL 4.
+* Add const qualifier to fix compiler warnings.
+
+Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
+Signed-off-by: Victor Stinner <vstinner@python.org>
+
+Upstream-Status: Backport [https://github.com/python/cpython/commit/3364e7e62fa24d0e19133fb0f90b1c24ef1110c5]
+Signed-off-by: Jaipaul Cheernam <jaipaul.cheernam@est.tech>
+---
+ Lib/test/test_ssl.py | 52 ++++++++++++++++++++------------------
+ Modules/_ssl.c | 27 ++++++++++++++++----
+ Modules/_ssl/cert.c | 3 ++-
+ Tools/ssl/multissltests.py | 7 ++++-
+ 4 files changed, 58 insertions(+), 31 deletions(-)
+
+diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
+index dc795c6bd8a..61355927296 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)
++ self.assertIsInstance(ssl.HAS_TLSv1_2, bool)
+ self.assertEqual(ssl.HAS_TLSv1_3, True)
+ ssl.OP_NO_SSLv2
+ ssl.OP_NO_SSLv3
+@@ -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)
+@@ -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/Modules/_ssl.c b/Modules/_ssl.c
+index b45295b4c0c..6f75af86113 100644
+--- a/Modules/_ssl.c
++++ b/Modules/_ssl.c
+@@ -164,6 +164,17 @@ 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
++# 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 */
+ #ifndef OPENSSL_NO_SSL3_METHOD
+ extern const SSL_METHOD *SSLv3_method(void);
+@@ -1151,7 +1162,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;
+@@ -1180,16 +1191,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;
+@@ -6967,9 +6978,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
+
+diff --git a/Modules/_ssl/cert.c b/Modules/_ssl/cert.c
+index f2e7be89668..061b0fb3171 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;
+diff --git a/Tools/ssl/multissltests.py b/Tools/ssl/multissltests.py
+index 3b4507c6771..48207e5330f 100755
+--- a/Tools/ssl/multissltests.py
++++ b/Tools/ssl/multissltests.py
+@@ -429,9 +429,11 @@ def _post_install(self):
+ def _post_install(self):
+ if self.version.startswith("3."):
+ self._post_install_3xx()
++ elif self.version.startswith("4."):
++ self._post_install_4xx()
+
+ 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)
+
+@@ -447,6 +449,9 @@ def _post_install_3xx(self):
+ lib64 = self.lib_dir + "64"
+ os.symlink(lib64, self.lib_dir)
+
++ def _post_install_4xx(self):
++ self._post_install_3xx()
++
+ @property
+ def short_version(self):
+ """Short version for OpenSSL download URL"""
+--
+2.25.1
+
@@ -22,6 +22,7 @@ SRC_URI = "http://www.python.org/ftp/python/${PV}/Python-${PV}.tar.xz \
file://0001-Avoid-shebang-overflow-on-python-config.py.patch \
file://0001-Update-test_sysconfig-for-posix_user-purelib.patch \
file://0001-prefer-valid-entrypoints.patch \
+ file://0001-gh-146207-Add-support-for-OpenSSL-4.0.0.patch \
"
SRC_URI:append:class-native = " \
file://0001-Lib-sysconfig.py-use-prefix-value-from-build-configu.patch \
Backport CPython commit 3364e7e62fa24d0e19133fb0f90b1c24ef1110c5: gh-146207: Add support for OpenSSL 4.0.0 alpha1 (#146217) OpenSSL 4.0.0 alpha1 removed these functions: * SSLv3_method() * TLSv1_method() * TLSv1_1_method() * TLSv1_2_method() Other changes: * Update test_openssl_version(). * Update multissltests.py for OpenSSL 4. * Add const qualifier to fix compiler warnings. Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> Upstream-Status: Backport [https://github.com/python/cpython/commit/3364e7e62fa24d0e19133fb0f90b1c24ef1110c5] Signed-off-by: Jaipaul Cheernam <jaipaul.cheernam@est.tech> --- ...146207-Add-support-for-OpenSSL-4.0.0.patch | 257 ++++++++++++++++++ .../recipes-devtools/python/python3_3.14.7.bb | 1 + 2 files changed, 258 insertions(+) create mode 100644 meta/recipes-devtools/python/python3/0001-gh-146207-Add-support-for-OpenSSL-4.0.0.patch