From: Jaipaul Cheernam <jaipaul.cheernam@est.tech>
To: openembedded-core@lists.openembedded.org
Subject: [OE-core][RFC v3 2/6] python3: backport OpenSSL 4.0 support from upstream
Date: Sat, 22 Aug 2026 16:31:51 +0200 [thread overview]
Message-ID: <20260822143155.39273-3-jaipaul.cheernam@est.tech> (raw)
In-Reply-To: <20260822143155.39273-1-jaipaul.cheernam@est.tech>
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 ++++++++++++++++++
...Update-_ssl._SSLSocket-for-OpenSSL-4.patch | 234 ++++++++++++++++
...utdown-test-in-test_ssl.test_got_eof.patch | 41 +++
.../recipes-devtools/python/python3_3.14.7.bb | 3 +
4 files changed, 535 insertions(+)
create mode 100644 meta/recipes-devtools/python/python3/0001-gh-146207-Add-support-for-OpenSSL-4.0.0.patch
create mode 100644 meta/recipes-devtools/python/python3/0002-gh-148292-Update-_ssl._SSLSocket-for-OpenSSL-4.patch
create mode 100644 meta/recipes-devtools/python/python3/0003-gh-148292-Remove-shutdown-test-in-test_ssl.test_got_eof.patch
diff --git a/meta/recipes-devtools/python/python3/0001-gh-146207-Add-support-for-OpenSSL-4.0.0.patch b/meta/recipes-devtools/python/python3/0001-gh-146207-Add-support-for-OpenSSL-4.0.0.patch
new file mode 100644
index 0000000000..bef6044358
--- /dev/null
+++ b/meta/recipes-devtools/python/python3/0001-gh-146207-Add-support-for-OpenSSL-4.0.0.patch
@@ -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
+
diff --git a/meta/recipes-devtools/python/python3/0002-gh-148292-Update-_ssl._SSLSocket-for-OpenSSL-4.patch b/meta/recipes-devtools/python/python3/0002-gh-148292-Update-_ssl._SSLSocket-for-OpenSSL-4.patch
new file mode 100644
index 0000000000..587f141dd4
--- /dev/null
+++ b/meta/recipes-devtools/python/python3/0002-gh-148292-Update-_ssl._SSLSocket-for-OpenSSL-4.patch
@@ -0,0 +1,234 @@
+From 3c2a3014af7d73cc34f2498f60fdf863d9bc7c6c Mon Sep 17 00:00:00 2001
+From: Victor Stinner <vstinner@python.org>
+Date: Mon, 4 May 2026 13:52:57 +0200
+Subject: [PATCH] gh-148292: Update _ssl._SSLSocket for OpenSSL 4 (#149102)
+
+The _SSLSocket object now remembers if it gets an EOF error. In this
+case, read(), sendfile(), write() and do_handshake method calls fail
+with SSLEOFError without calling the underlying OpenSSL function.
+
+Co-authored-by: Gregory P. Smith <greg@krypto.org>
+(cherry picked from commit 7b7fa3f9bf3d7cdf3eb669d02b386e05b39c402a)
+
+Upstream-Status: Backport [https://github.com/python/cpython/commit/3c2a3014af7d]
+
+Note: This is from the unmerged CPython PR #149783 which backports
+OpenSSL 4.0 support to the 3.14 branch. Upstream deferred merging
+until after Python 3.15.1 is released.
+
+Signed-off-by: Jaipaul Cheernam <jaipaul.cheernam@est.tech>
+---
+ Lib/test/test_ssl.py | 82 +++++++++++++++++++
+ ...-04-28-17-47-55.gh-issue-148292.oIq3ml.rst | 7 ++
+ Modules/_ssl.c | 42 ++++++++++
+ 3 files changed, 131 insertions(+)
+ create mode 100644 Misc/NEWS.d/next/Library/2026-04-28-17-47-55.gh-issue-148292.oIq3ml.rst
+
+diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
+index 965dbc36f096499..03d9e3f9e5e96b5 100644
+--- a/Lib/test/test_ssl.py
++++ b/Lib/test/test_ssl.py
+@@ -2711,6 +2711,36 @@ def close(self):
+ def stop(self):
+ self.active = False
+
++class TestEOFServer(threading.Thread):
++ def __init__(self):
++ super().__init__()
++ self.listening = threading.Event()
++ self.address = None
++
++ def run(self):
++ context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
++ context.load_cert_chain(CERTFILE)
++ server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
++ with server_sock:
++ server_sock.settimeout(support.SHORT_TIMEOUT)
++ server_sock.bind((HOST, 0))
++ server_sock.listen(5)
++
++ self.address = server_sock.getsockname()
++ self.listening.set()
++
++ sock, addr = server_sock.accept()
++ sslconn = context.wrap_socket(sock, server_side=True)
++ with sslconn:
++ request = b''
++ while chunk := sslconn.recv(1024):
++ request += chunk
++ if b'\n' in chunk:
++ break
++
++ sslconn.sendall(b'server\n')
++ sslconn.shutdown(socket.SHUT_WR)
++
+ class AsyncoreEchoServer(threading.Thread):
+
+ # this one's based on asyncore.dispatcher
+@@ -4747,6 +4777,58 @@ def background(sock):
+ if cm.exc_value is not None:
+ raise cm.exc_value
+
++ def test_got_eof(self):
++ # gh-148292: Test that _ssl._SSLSocket behaves the same on all OpenSSL
++ # versions on calling methods after EOF (after the first SSLEOFError).
++
++ server = TestEOFServer()
++ server.start()
++ if not server.listening.wait(support.SHORT_TIMEOUT):
++ raise RuntimeError("server took too long")
++ self.addCleanup(server.join)
++
++ context = ssl.create_default_context(cafile=CERTFILE)
++ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
++ sock.settimeout(support.SHORT_TIMEOUT)
++ sock.connect(server.address)
++ sslsock = context.wrap_socket(sock, server_hostname='localhost')
++ with sslsock:
++ sslsock.sendall(b'client\n')
++ # test the _ssl._SSLSocket object, not ssl.SSLSocket
++ sslobj = sslsock._sslobj
++
++ data = sslobj.read(1024)
++ self.assertEqual(data, b'server\n')
++
++ # The second read gets EOF error and sets got_eof_error to 1
++ with self.assertRaises(ssl.SSLEOFError):
++ sslobj.read(1024)
++
++ # Following read(), sendfile(), write() and do_handshake() calls
++ # must raise SSLEOFError
++ with self.assertRaises(ssl.SSLEOFError):
++ # The _SSLSocket remembers the previous EOF error
++ # and raises again SSLEOFError
++ sslobj.read(1024)
++ if hasattr(sslobj, 'sendfile'):
++ with open(__file__, "rb") as fp:
++ with self.assertRaises(ssl.SSLEOFError):
++ sslobj.sendfile(fp.fileno(), 0, 1)
++ with self.assertRaises(ssl.SSLEOFError):
++ sslobj.write(b'client2\n')
++ with self.assertRaises(ssl.SSLEOFError):
++ sslsock.do_handshake()
++
++ self.assertEqual(sslsock.pending(), 0)
++ try:
++ sslsock.shutdown(socket.SHUT_WR)
++ except OSError as exc:
++ self.assertEqual(exc.errno, errno.ENOTCONN)
++ else:
++ # On Windows and on OpenSSL 1.1.1, shutdown() doesn't
++ # raise an error
++ pass
++
+
+ @unittest.skipUnless(has_tls_version('TLSv1_3') and ssl.HAS_PHA,
+ "Test needs TLS 1.3 PHA")
+diff --git a/Misc/NEWS.d/next/Library/2026-04-28-17-47-55.gh-issue-148292.oIq3ml.rst b/Misc/NEWS.d/next/Library/2026-04-28-17-47-55.gh-issue-148292.oIq3ml.rst
+new file mode 100644
+index 000000000000000..e1f308df5a678e6
+--- /dev/null
++++ b/Misc/NEWS.d/next/Library/2026-04-28-17-47-55.gh-issue-148292.oIq3ml.rst
+@@ -0,0 +1,7 @@
++:mod:`ssl`: Update :class:`ssl.SSLSocket` and :class:`ssl.SSLObject` for
++OpenSSL 4. The classes now remember if they get a :exc:`ssl.SSLEOFError`. In this
++case, following :meth:`~ssl.SSLSocket.read`, :meth:`!sendfile`,
++:meth:`~ssl.SSLSocket.write`, and :meth:`~ssl.SSLSocket.do_handshake` calls
++raise :exc:`ssl.SSLEOFError` without calling the underlying OpenSSL function.
++Thanks to that, :class:`ssl.SSLSocket` behaves the same on all OpenSSL versions
++on EOF. Patch by Victor Stinner.
+diff --git a/Modules/_ssl.c b/Modules/_ssl.c
+index 1603d0ffd559559..376df32b7cb4bd6 100644
+--- a/Modules/_ssl.c
++++ b/Modules/_ssl.c
+@@ -352,6 +352,16 @@ typedef struct {
+ * and shutdown methods check for chained exceptions.
+ */
+ PyObject *exc;
++ // gh-148292: If non-zero, read(), sendfile(), write() and do_handshake()
++ // methods raise SSLEOFError without calling the underlying OpenSSL
++ // function. Set to 1 on PY_SSL_ERROR_EOF error.
++ //
++ // On OpenSSL 4, if SSL_read_ex() fails with
++ // SSL_R_UNEXPECTED_EOF_WHILE_READING, the following SSL_read_ex() call
++ // fails with a generic protocol error (ERR_peek_last_error() returns 0).
++ // Use got_eof_error to have the same behavior on OpenSSL 4 and newer and
++ // on OpenSSL 3 and older.
++ int got_eof_error;
+ } PySSLSocket;
+
+ #define PySSLSocket_CAST(op) ((PySSLSocket *)(op))
+@@ -499,6 +509,10 @@ fill_and_set_sslerror(_sslmodulestate *state,
+ PyObject *init_value, *msg, *key;
+ PyUnicodeWriter *writer = NULL;
+
++ if (ssl_errno == PY_SSL_ERROR_EOF && sslsock != NULL) {
++ sslsock->got_eof_error = 1;
++ }
++
+ if (errcode != 0) {
+ int lib, reason;
+
+@@ -654,6 +668,18 @@ PySSL_ChainExceptions(PySSLSocket *sslsock) {
+ return -1;
+ }
+
++
++static void
++set_eof_error(PySSLSocket *sslsock)
++{
++ _sslmodulestate *state = get_state_sock(sslsock);
++ fill_and_set_sslerror(state, sslsock, state->PySSLEOFErrorObject,
++ PY_SSL_ERROR_EOF,
++ "EOF occurred in violation of protocol",
++ __LINE__, 0);
++}
++
++
+ static PyObject *
+ PySSL_SetError(PySSLSocket *sslsock, const char *filename, int lineno)
+ {
+@@ -901,6 +927,7 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock,
+ self->server_hostname = NULL;
+ self->err = err;
+ self->exc = NULL;
++ self->got_eof_error = 0;
+
+ /* Make sure the SSL error state is initialized */
+ ERR_clear_error();
+@@ -1041,6 +1068,11 @@ _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self)
+ BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking);
+ }
+
++ if (self->got_eof_error) {
++ set_eof_error(self);
++ goto error;
++ }
++
+ timeout = GET_SOCKET_TIMEOUT(sock);
+ has_timeout = (timeout > 0);
+ if (has_timeout) {
+@@ -2504,6 +2536,11 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
+ BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking);
+ }
+
++ if (self->got_eof_error) {
++ set_eof_error(self);
++ goto error;
++ }
++
+ timeout = GET_SOCKET_TIMEOUT(sock);
+ has_timeout = (timeout > 0);
+ if (has_timeout) {
+@@ -2644,6 +2681,11 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len,
+ Py_INCREF(sock);
+ }
+
++ if (self->got_eof_error) {
++ set_eof_error(self);
++ goto error;
++ }
++
+ if (!group_right_1) {
+ dest = PyBytes_FromStringAndSize(NULL, len);
+ if (dest == NULL)
diff --git a/meta/recipes-devtools/python/python3/0003-gh-148292-Remove-shutdown-test-in-test_ssl.test_got_eof.patch b/meta/recipes-devtools/python/python3/0003-gh-148292-Remove-shutdown-test-in-test_ssl.test_got_eof.patch
new file mode 100644
index 0000000000..af067f549c
--- /dev/null
+++ b/meta/recipes-devtools/python/python3/0003-gh-148292-Remove-shutdown-test-in-test_ssl.test_got_eof.patch
@@ -0,0 +1,41 @@
+From 81911909bc439d6de8ce6a173b0691b3c58e9e1a Mon Sep 17 00:00:00 2001
+From: Victor Stinner <vstinner@python.org>
+Date: Mon, 4 May 2026 16:20:25 +0200
+Subject: [PATCH] gh-148292: Remove shutdown() test in test_ssl.test_got_eof()
+ (#149366)
+
+The shutdown() behavior depends too much on the operating system and
+it's unrelated to the got_eof_error change.
+
+(cherry picked from commit 1e21cf6fee3830012e458c0fe5dbc6fcd45ace92)
+
+Upstream-Status: Backport [https://github.com/python/cpython/commit/81911909bc43]
+
+Note: This is from the unmerged CPython PR #149783 which backports
+OpenSSL 4.0 support to the 3.14 branch. Upstream deferred merging
+until after Python 3.15.1 is released.
+
+Signed-off-by: Jaipaul Cheernam <jaipaul.cheernam@est.tech>
+---
+ Lib/test/test_ssl.py | 8 --------
+ 1 file changed, 8 deletions(-)
+
+diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
+index 03d9e3f9e5e96b5..6445f122b4272be 100644
+--- a/Lib/test/test_ssl.py
++++ b/Lib/test/test_ssl.py
+@@ -4820,14 +4820,6 @@ def test_got_eof(self):
+ sslsock.do_handshake()
+
+ self.assertEqual(sslsock.pending(), 0)
+- try:
+- sslsock.shutdown(socket.SHUT_WR)
+- except OSError as exc:
+- self.assertEqual(exc.errno, errno.ENOTCONN)
+- else:
+- # On Windows and on OpenSSL 1.1.1, shutdown() doesn't
+- # raise an error
+- pass
+
+
+ @unittest.skipUnless(has_tls_version('TLSv1_3') and ssl.HAS_PHA,
diff --git a/meta/recipes-devtools/python/python3_3.14.7.bb b/meta/recipes-devtools/python/python3_3.14.7.bb
index 568e632278..18373e5b5e 100644
--- a/meta/recipes-devtools/python/python3_3.14.7.bb
+++ b/meta/recipes-devtools/python/python3_3.14.7.bb
@@ -22,6 +22,9 @@ 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 \
+ file://0002-gh-148292-Update-_ssl._SSLSocket-for-OpenSSL-4.patch \
+ file://0003-gh-148292-Remove-shutdown-test-in-test_ssl.test_got_eof.patch \
"
SRC_URI:append:class-native = " \
file://0001-Lib-sysconfig.py-use-prefix-value-from-build-configu.patch \
next prev parent reply other threads:[~2026-08-22 14:32 UTC|newest]
Thread overview: 44+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-14 5:18 [RFC 0/7] openssl: upgrade to 4.0.1 and fix dependent recipes Jaipaul Cheernam
2026-08-14 5:18 ` [PATCH 1/7] openssl: upgrade 3.5.7 -> 4.0.1 Jaipaul Cheernam
2026-08-15 16:20 ` [OE-core] " Mathieu Dubois-Briand
2026-08-14 5:18 ` [PATCH 2/7] python3: backport OpenSSL 4.0 support from upstream Jaipaul Cheernam
2026-08-14 5:18 ` [PATCH 3/7] socat: fix build with OpenSSL 4.0 Jaipaul Cheernam
2026-08-14 5:18 ` [PATCH 4/7] rust: Upgrade 1.96.1 -> 1.97.1 Jaipaul Cheernam
2026-08-15 16:11 ` [OE-core] " Mathieu Dubois-Briand
2026-08-14 5:18 ` [PATCH 5/7] serf: fix build with OpenSSL 4.0 Jaipaul Cheernam
2026-08-14 5:18 ` [PATCH 6/7] u-boot-tools: " Jaipaul Cheernam
2026-08-14 11:12 ` [OE-core] " Alexander Kanavin
2026-08-21 10:44 ` Quentin Schulz
2026-08-15 16:14 ` Mathieu Dubois-Briand
2026-08-14 5:18 ` [PATCH 7/7] kea: " Jaipaul Cheernam
2026-08-14 11:14 ` [OE-core] " Alexander Kanavin
2026-08-20 18:10 ` [RFC v2 0/6] openssl: upgrade to 4.0.1 and fix dependent recipes Jaipaul Cheernam
2026-08-20 18:10 ` [RFC v2 1/6] openssl: upgrade 3.5.7 -> 4.0.1 Jaipaul Cheernam
2026-08-21 17:52 ` [OE-core] " Khem Raj
2026-08-20 18:10 ` [RFC v2 2/6] python3: backport OpenSSL 4.0 support from upstream Jaipaul Cheernam
2026-08-20 18:10 ` [RFC v2 3/6] socat: fix build with OpenSSL 4.0 Jaipaul Cheernam
2026-08-20 18:10 ` [RFC v2 4/6] serf: " Jaipaul Cheernam
2026-08-20 18:10 ` [RFC v2 5/6] u-boot: " Jaipaul Cheernam
2026-08-21 10:52 ` [OE-core] " Quentin Schulz
2026-08-22 14:02 ` Jaipaul Cheernam
2026-08-24 10:59 ` Quentin Schulz
2026-08-20 18:10 ` [RFC v2 6/6] kea: " Jaipaul Cheernam
2026-08-21 21:17 ` [OE-core] [RFC v2 0/6] openssl: upgrade to 4.0.1 and fix dependent recipes Richard Purdie
2026-08-22 14:31 ` [OE-core][RFC v3 0/6] openssl: upgrade 3.5.7 -> 4.0.1 Jaipaul Cheernam
2026-08-22 14:31 ` [OE-core][RFC v3 1/6] " Jaipaul Cheernam
2026-08-22 14:31 ` Jaipaul Cheernam [this message]
2026-08-22 14:31 ` [OE-core][RFC v3 3/6] socat: fix build with OpenSSL 4.0 Jaipaul Cheernam
2026-08-22 14:31 ` [OE-core][RFC v3 4/6] serf: " Jaipaul Cheernam
2026-08-22 14:31 ` [OE-core][RFC v3 5/6] u-boot: " Jaipaul Cheernam
2026-08-22 14:31 ` [OE-core][RFC v3 6/6] kea: " Jaipaul Cheernam
2026-08-22 17:51 ` [RFC v4 0/6] openssl: upgrade 3.5.7 -> 4.0.1 Jaipaul Cheernam
2026-08-22 17:51 ` [RFC v4 1/6] " Jaipaul Cheernam
2026-08-23 6:56 ` [OE-core] " Khem Raj
2026-08-23 6:57 ` Khem Raj
2026-08-22 17:51 ` [RFC v4 2/6] python3: backport OpenSSL 4.0 support from upstream Jaipaul Cheernam
2026-08-22 17:51 ` [RFC v4 3/6] socat: fix build with OpenSSL 4.0 Jaipaul Cheernam
2026-08-22 17:51 ` [RFC v4 4/6] serf: " Jaipaul Cheernam
2026-08-22 17:51 ` [RFC v4 5/6] u-boot: " Jaipaul Cheernam
2026-08-22 17:52 ` [RFC v4 6/6] kea: " Jaipaul Cheernam
2026-08-23 7:02 ` [OE-core] [RFC v4 0/6] openssl: upgrade 3.5.7 -> 4.0.1 Richard Purdie
2026-08-24 14:16 ` Ahmad Fatoum
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260822143155.39273-3-jaipaul.cheernam@est.tech \
--to=jaipaul.cheernam@est.tech \
--cc=openembedded-core@lists.openembedded.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.