summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/python/python3-pyopenssl/CVE-2026-27448.patch
blob: 87f46b4cb0f4ddda7aae2e84b54146eb491b4a47 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
From d41a814759a9fb49584ca8ab3f7295de49a85aa0 Mon Sep 17 00:00:00 2001
From: Alex Gaynor <alex.gaynor@gmail.com>
Date: Mon, 16 Feb 2026 21:04:37 -0500
Subject: [PATCH] Handle exceptions in set_tlsext_servername_callback callbacks
 (#1478)

When the servername callback raises an exception, call sys.excepthook
with the exception info and return SSL_TLSEXT_ERR_ALERT_FATAL to abort
the handshake. Previously, exceptions would propagate uncaught through
the CFFI callback boundary.

https://claude.ai/code/session_01P7y1XmWkdtC5UcmZwGDvGi

Co-authored-by: Claude <noreply@anthropic.com>

Upstream-Status: Backport [https://github.com/pyca/pyopenssl/commit/d41a814759a9fb49584ca8ab3f7295de49a85aa0]
CVE: CVE-2026-27448
Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
---
 CHANGELOG.rst      |  1 +
 src/OpenSSL/SSL.py |  7 ++++++-
 tests/test_ssl.py  | 50 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 57 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 6e23770..12e60e4 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -18,6 +18,7 @@ Changes:
 
 - Added ``OpenSSL.SSL.Connection.get_selected_srtp_profile`` to determine which SRTP profile was negotiated.
   `#1279 <https://github.com/pyca/pyopenssl/pull/1279>`_.
+- ``Context.set_tlsext_servername_callback`` now handles exceptions raised in the callback by calling ``sys.excepthook`` and returning a fatal TLS alert. Previously, exceptions were silently swallowed and the handshake would proceed as if the callback had succeeded.
 
 23.3.0 (2023-10-25)
 -------------------
diff --git a/src/OpenSSL/SSL.py b/src/OpenSSL/SSL.py
index 4db5240..a6263c4 100644
--- a/src/OpenSSL/SSL.py
+++ b/src/OpenSSL/SSL.py
@@ -1,5 +1,6 @@
 import os
 import socket
+import sys
 import typing
 from errno import errorcode
 from functools import partial, wraps
@@ -1567,7 +1568,11 @@ class Context:
 
         @wraps(callback)
         def wrapper(ssl, alert, arg):
-            callback(Connection._reverse_mapping[ssl])
+            try:
+                callback(Connection._reverse_mapping[ssl])
+            except Exception:
+                sys.excepthook(*sys.exc_info())
+                return _lib.SSL_TLSEXT_ERR_ALERT_FATAL
             return 0
 
         self._tlsext_servername_callback = _ffi.callback(
diff --git a/tests/test_ssl.py b/tests/test_ssl.py
index ca5bf83..55489b9 100644
--- a/tests/test_ssl.py
+++ b/tests/test_ssl.py
@@ -1855,6 +1855,56 @@ class TestServerNameCallback:
 
         assert args == [(server, b"foo1.example.com")]
 
+    def test_servername_callback_exception(
+        self, monkeypatch: pytest.MonkeyPatch
+    ) -> None:
+        """
+        When the callback passed to `Context.set_tlsext_servername_callback`
+        raises an exception, ``sys.excepthook`` is called with the exception
+        and the handshake fails with an ``Error``.
+        """
+        exc = TypeError("server name callback failed")
+
+        def servername(conn: Connection) -> None:
+            raise exc
+
+        excepthook_calls: list[
+            tuple[type[BaseException], BaseException, object]
+        ] = []
+
+        def custom_excepthook(
+            exc_type: type[BaseException],
+            exc_value: BaseException,
+            exc_tb: object,
+        ) -> None:
+            excepthook_calls.append((exc_type, exc_value, exc_tb))
+
+        context = Context(SSLv23_METHOD)
+        context.set_tlsext_servername_callback(servername)
+
+        # Necessary to actually accept the connection
+        context.use_privatekey(load_privatekey(FILETYPE_PEM, server_key_pem))
+        context.use_certificate(
+            load_certificate(FILETYPE_PEM, server_cert_pem)
+        )
+
+        # Do a little connection to trigger the logic
+        server = Connection(context, None)
+        server.set_accept_state()
+
+        client = Connection(Context(SSLv23_METHOD), None)
+        client.set_connect_state()
+        client.set_tlsext_host_name(b"foo1.example.com")
+
+        monkeypatch.setattr(sys, "excepthook", custom_excepthook)
+        with pytest.raises(Error):
+            interact_in_memory(server, client)
+
+        assert len(excepthook_calls) == 1
+        assert excepthook_calls[0][0] is TypeError
+        assert excepthook_calls[0][1] is exc
+        assert excepthook_calls[0][2] is not None
+
 
 class TestApplicationLayerProtoNegotiation:
     """
-- 
2.43.0