Version in base suite: 25.0.0-1 Base version: pyopenssl_25.0.0-1 Target version: pyopenssl_25.0.0-1+deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/p/pyopenssl/pyopenssl_25.0.0-1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/p/pyopenssl/pyopenssl_25.0.0-1+deb13u1.dsc changelog | 9 patches/0001-Handle-exceptions-in-set_tlsext_servername_callback-.patch | 107 ++++++++++ patches/0002-Fix-buffer-overflow-in-DTLS-cookie-generation-callba.patch | 91 ++++++++ patches/series | 2 4 files changed, 209 insertions(+) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp32r7q7l5/pyopenssl_25.0.0-1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp32r7q7l5/pyopenssl_25.0.0-1+deb13u1.dsc: no acceptable signature found diff -Nru pyopenssl-25.0.0/debian/changelog pyopenssl-25.0.0/debian/changelog --- pyopenssl-25.0.0/debian/changelog 2025-01-17 18:22:27.000000000 +0000 +++ pyopenssl-25.0.0/debian/changelog 2026-06-22 16:13:17.000000000 +0000 @@ -1,3 +1,12 @@ +pyopenssl (25.0.0-1+deb13u1) trixie; urgency=medium + + * Non-maintainer upload. + * CVE-2026-27448: Unhandled exceptions in set_tlsext_servername_callback + callbacks did not cancel connections + * CVE-2026-27459: Buffer overflow in DTLS cookie callback + + -- Adrian Bunk Mon, 22 Jun 2026 19:13:17 +0300 + pyopenssl (25.0.0-1) unstable; urgency=medium * New upstream version. diff -Nru pyopenssl-25.0.0/debian/patches/0001-Handle-exceptions-in-set_tlsext_servername_callback-.patch pyopenssl-25.0.0/debian/patches/0001-Handle-exceptions-in-set_tlsext_servername_callback-.patch --- pyopenssl-25.0.0/debian/patches/0001-Handle-exceptions-in-set_tlsext_servername_callback-.patch 1970-01-01 00:00:00.000000000 +0000 +++ pyopenssl-25.0.0/debian/patches/0001-Handle-exceptions-in-set_tlsext_servername_callback-.patch 2026-06-22 16:11:08.000000000 +0000 @@ -0,0 +1,107 @@ +From df3c6da11667645e7ca886a7f4fe7f2d9d8d80d7 Mon Sep 17 00:00:00 2001 +From: Alex Gaynor +Date: Mon, 16 Feb 2026 21:04:37 -0500 +Subject: 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 +--- + src/OpenSSL/SSL.py | 7 ++++++- + tests/test_ssl.py | 50 ++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 56 insertions(+), 1 deletion(-) + +diff --git a/src/OpenSSL/SSL.py b/src/OpenSSL/SSL.py +index bc9c188..1dbd1c8 100644 +--- a/src/OpenSSL/SSL.py ++++ b/src/OpenSSL/SSL.py +@@ -2,6 +2,7 @@ from __future__ import annotations + + import os + import socket ++import sys + import typing + import warnings + from collections.abc import Sequence +@@ -1686,7 +1687,11 @@ class Context: + + @wraps(callback) + def wrapper(ssl, alert, arg): # type: ignore[no-untyped-def] +- 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 21d30cf..0f0dad1 100644 +--- a/tests/test_ssl.py ++++ b/tests/test_ssl.py +@@ -1936,6 +1936,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.47.3 + diff -Nru pyopenssl-25.0.0/debian/patches/0002-Fix-buffer-overflow-in-DTLS-cookie-generation-callba.patch pyopenssl-25.0.0/debian/patches/0002-Fix-buffer-overflow-in-DTLS-cookie-generation-callba.patch --- pyopenssl-25.0.0/debian/patches/0002-Fix-buffer-overflow-in-DTLS-cookie-generation-callba.patch 1970-01-01 00:00:00.000000000 +0000 +++ pyopenssl-25.0.0/debian/patches/0002-Fix-buffer-overflow-in-DTLS-cookie-generation-callba.patch 2026-06-22 16:11:08.000000000 +0000 @@ -0,0 +1,91 @@ +From 434d56816d36adb05c87a6fea0b1ee3da1cea8bf Mon Sep 17 00:00:00 2001 +From: Alex Gaynor +Date: Wed, 18 Feb 2026 07:46:15 -0500 +Subject: Fix buffer overflow in DTLS cookie generation callback (#1479) + +The cookie generate callback copied user-returned bytes into a +fixed-size native buffer without enforcing a maximum length. A +callback returning more than DTLS1_COOKIE_LENGTH bytes would overflow +the OpenSSL-provided buffer, corrupting adjacent memory. + +Co-authored-by: Claude Opus 4.6 +--- + src/OpenSSL/SSL.py | 7 +++++++ + tests/test_ssl.py | 38 ++++++++++++++++++++++++++++++++++++++ + 2 files changed, 45 insertions(+) + +diff --git a/src/OpenSSL/SSL.py b/src/OpenSSL/SSL.py +index 1dbd1c8..bccf920 100644 +--- a/src/OpenSSL/SSL.py ++++ b/src/OpenSSL/SSL.py +@@ -716,11 +716,18 @@ class _CookieGenerateCallbackHelper(_CallbackExceptionHelper): + def __init__(self, callback: _CookieGenerateCallback) -> None: + _CallbackExceptionHelper.__init__(self) + ++ max_cookie_len = getattr(_lib, "DTLS1_COOKIE_LENGTH", 255) ++ + @wraps(callback) + def wrapper(ssl, out, outlen): # type: ignore[no-untyped-def] + try: + conn = Connection._reverse_mapping[ssl] + cookie = callback(conn) ++ if len(cookie) > max_cookie_len: ++ raise ValueError( ++ f"Cookie too long (got {len(cookie)} bytes, " ++ f"max {max_cookie_len})" ++ ) + out[0 : len(cookie)] = cookie + outlen[0] = len(cookie) + return 1 +diff --git a/tests/test_ssl.py b/tests/test_ssl.py +index 0f0dad1..41b37be 100644 +--- a/tests/test_ssl.py ++++ b/tests/test_ssl.py +@@ -4727,6 +4727,44 @@ class TestDTLS: + def test_it_works_with_srtp(self) -> None: + self._test_handshake_and_data(srtp_profile=b"SRTP_AES128_CM_SHA1_80") + ++ def test_cookie_generate_too_long(self) -> None: ++ s_ctx = Context(DTLS_METHOD) ++ ++ def generate_cookie(ssl: Connection) -> bytes: ++ return b"\x00" * 256 ++ ++ def verify_cookie(ssl: Connection, cookie: bytes) -> bool: ++ return True ++ ++ s_ctx.set_cookie_generate_callback(generate_cookie) ++ s_ctx.set_cookie_verify_callback(verify_cookie) ++ s_ctx.use_privatekey(load_privatekey(FILETYPE_PEM, server_key_pem)) ++ s_ctx.use_certificate(load_certificate(FILETYPE_PEM, server_cert_pem)) ++ s_ctx.set_options(OP_NO_QUERY_MTU) ++ s = Connection(s_ctx) ++ s.set_accept_state() ++ ++ c_ctx = Context(DTLS_METHOD) ++ c_ctx.set_options(OP_NO_QUERY_MTU) ++ c = Connection(c_ctx) ++ c.set_connect_state() ++ ++ c.set_ciphertext_mtu(1500) ++ s.set_ciphertext_mtu(1500) ++ ++ # Client sends ClientHello ++ try: ++ c.do_handshake() ++ except SSL.WantReadError: ++ pass ++ chunk = c.bio_read(self.LARGE_BUFFER) ++ s.bio_write(chunk) ++ ++ # Server tries DTLSv1_listen, which triggers cookie generation. ++ # The oversized cookie should raise ValueError. ++ with pytest.raises(ValueError, match="Cookie too long"): ++ s.DTLSv1_listen() ++ + def test_timeout(self, monkeypatch: pytest.MonkeyPatch) -> None: + c_ctx = Context(DTLS_METHOD) + c = Connection(c_ctx) +-- +2.47.3 + diff -Nru pyopenssl-25.0.0/debian/patches/series pyopenssl-25.0.0/debian/patches/series --- pyopenssl-25.0.0/debian/patches/series 2025-01-17 18:22:27.000000000 +0000 +++ pyopenssl-25.0.0/debian/patches/series 2026-06-22 16:13:16.000000000 +0000 @@ -1,2 +1,4 @@ 0001-disable-test_set_default_verify_paths-since-it-tries.patch 0003-Fix-running-tests-on-32-bit-time_t-platforms.patch +0001-Handle-exceptions-in-set_tlsext_servername_callback-.patch +0002-Fix-buffer-overflow-in-DTLS-cookie-generation-callba.patch