Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-pyOpenSSL for
openSUSE:Factory checked in at 2026-03-19 17:26:45
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pyOpenSSL (Old)
and /work/SRC/openSUSE:Factory/.python-pyOpenSSL.new.8177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pyOpenSSL"
Thu Mar 19 17:26:45 2026 rev:63 rq:1340914 version:26.0.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pyOpenSSL/python-pyOpenSSL.changes
2025-10-24 17:23:16.451006082 +0200
+++
/work/SRC/openSUSE:Factory/.python-pyOpenSSL.new.8177/python-pyOpenSSL.changes
2026-03-19 17:26:47.067528325 +0100
@@ -1,0 +2,22 @@
+Wed Mar 18 13:48:45 UTC 2026 - Daniel Garcia <[email protected]>
+
+- update to 26.0.0 (bsc#1259808, CVE-2026-27459, bsc#1259804, CVE-2026-27448):
+ ## Backward-incompatible changes:
+ * Dropped support for Python 3.7.
+ * The minimum cryptography version is now 46.0.0.
+
+ ## Changes:
+ - Added support for using aws-lc instead of OpenSSL.
+ - Properly raise an error if a DTLS cookie callback returned a
+ cookie longer than DTLS1_COOKIE_LENGTH bytes. Previously this
+ would result in a buffer-overflow. Credit to dark_haxor for
+ reporting the issue. CVE-2026-27459
+ - Added OpenSSL.SSL.Connection.get_group_name to determine which
+ group name was negotiated.
+ - 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.
+ Credit to Leury Castillo for reporting this issue. CVE-2026-27448
+
+-------------------------------------------------------------------
Old:
----
pyopenssl-25.3.0.tar.gz
New:
----
pyopenssl-26.0.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-pyOpenSSL.spec ++++++
--- /var/tmp/diff_new_pack.ZP5BdL/_old 2026-03-19 17:26:47.799558689 +0100
+++ /var/tmp/diff_new_pack.ZP5BdL/_new 2026-03-19 17:26:47.799558689 +0100
@@ -1,7 +1,7 @@
#
# spec file for package python-pyOpenSSL
#
-# Copyright (c) 2025 SUSE LLC and contributors
+# Copyright (c) 2026 SUSE LLC and contributors
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -26,7 +26,7 @@
%endif
%{?sle15_python_module_pythons}
Name: python-pyOpenSSL%{psuffix}
-Version: 25.3.0
+Version: 26.0.0
Release: 0
Summary: Python wrapper module around the OpenSSL library
License: Apache-2.0
++++++ pyopenssl-25.3.0.tar.gz -> pyopenssl-26.0.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyopenssl-25.3.0/CHANGELOG.rst
new/pyopenssl-26.0.0/CHANGELOG.rst
--- old/pyopenssl-25.3.0/CHANGELOG.rst 2025-09-17 02:31:40.000000000 +0200
+++ new/pyopenssl-26.0.0/CHANGELOG.rst 2026-03-15 15:28:02.000000000 +0100
@@ -4,18 +4,26 @@
Versions are year-based with a strict backward-compatibility policy.
The third digit is only for regressions.
-25.4.0 (UNRELEASED)
+26.0.0 (2026-03-15)
-------------------
Backward-incompatible changes:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+- Dropped support for Python 3.7.
+- The minimum ``cryptography`` version is now 46.0.0.
+
Deprecations:
^^^^^^^^^^^^^
Changes:
^^^^^^^^
+- Added support for using aws-lc instead of OpenSSL.
+- Properly raise an error if a DTLS cookie callback returned a cookie longer
than ``DTLS1_COOKIE_LENGTH`` bytes. Previously this would result in a
buffer-overflow. Credit to **dark_haxor** for reporting the issue.
**CVE-2026-27459**
+- Added ``OpenSSL.SSL.Connection.get_group_name`` to determine which group
name was negotiated.
+- ``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. Credit to **Leury Castillo** for reporting
this issue. **CVE-2026-27448**
+
25.3.0 (2025-09-16)
-------------------
@@ -100,7 +108,7 @@
- Deprecated ``add_extensions`` and ``get_extensions`` on
``OpenSSL.crypto.X509Req`` and ``OpenSSL.crypto.X509``. These should have been
deprecated at the same time ``X509Extension`` was. Users should use
pyca/cryptography's X.509 APIs instead.
- Deprecated ``OpenSSL.crypto.get_elliptic_curves`` and
``OpenSSL.crypto.get_elliptic_curve``, as well as passing the reult of them to
``OpenSSL.SSL.Context.set_tmp_ecdh``, users should instead pass curves from
``cryptography``.
- Deprecated passing ``X509`` objects to
``OpenSSL.SSL.Context.use_certificate``,
``OpenSSL.SSL.Connection.use_certificate``,
``OpenSSL.SSL.Context.add_extra_chain_cert``, and
``OpenSSL.SSL.Context.add_client_ca``, users should instead pass
``cryptography.x509.Certificate`` instances. This is in preparation for
deprecating pyOpenSSL's ``X509`` entirely.
-- Deprecated passing ``PKey`` objects to
``OpenSSL.SSL.Context.use_privatekey`` and
``OpenSSL.SSL.Connection.use_privatekey``, users should instead pass
``cryptography`` priate key instances. This is in preparation for deprecating
pyOpenSSL's ``PKey`` entirely.
+- Deprecated passing ``PKey`` objects to
``OpenSSL.SSL.Context.use_privatekey`` and
``OpenSSL.SSL.Connection.use_privatekey``, users should instead pass
``cryptography`` private key instances. This is in preparation for deprecating
pyOpenSSL's ``PKey`` entirely.
Changes:
^^^^^^^^
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyopenssl-25.3.0/PKG-INFO
new/pyopenssl-26.0.0/PKG-INFO
--- old/pyopenssl-25.3.0/PKG-INFO 2025-09-17 02:31:46.799708800 +0200
+++ new/pyopenssl-26.0.0/PKG-INFO 2026-03-15 15:28:07.175517300 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: pyOpenSSL
-Version: 25.3.0
+Version: 26.0.0
Summary: Python wrapper module around the OpenSSL library
Home-page: https://pyopenssl.org/
Author: The pyOpenSSL developers
@@ -14,7 +14,6 @@
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX
Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
@@ -26,9 +25,9 @@
Classifier: Topic :: Security :: Cryptography
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Networking
-Requires-Python: >=3.7
+Requires-Python: >=3.8
License-File: LICENSE
-Requires-Dist: cryptography<47,>=45.0.7
+Requires-Dist: cryptography<47,>=46.0.0
Requires-Dist: typing-extensions>=4.9; python_version < "3.13" and
python_version >= "3.8"
Provides-Extra: test
Requires-Dist: pytest-rerunfailures; extra == "test"
@@ -97,18 +96,26 @@
Release Information
===================
-25.4.0 (UNRELEASED)
+26.0.0 (2026-03-15)
-------------------
Backward-incompatible changes:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+- Dropped support for Python 3.7.
+- The minimum ``cryptography`` version is now 46.0.0.
+
Deprecations:
^^^^^^^^^^^^^
Changes:
^^^^^^^^
+- Added support for using aws-lc instead of OpenSSL.
+- Properly raise an error if a DTLS cookie callback returned a cookie longer
than ``DTLS1_COOKIE_LENGTH`` bytes. Previously this would result in a
buffer-overflow. Credit to **dark_haxor** for reporting the issue.
**CVE-2026-27459**
+- Added ``OpenSSL.SSL.Connection.get_group_name`` to determine which group
name was negotiated.
+- ``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. Credit to **Leury Castillo** for reporting
this issue. **CVE-2026-27448**
+
25.3.0 (2025-09-16)
-------------------
@@ -193,7 +200,7 @@
- Deprecated ``add_extensions`` and ``get_extensions`` on
``OpenSSL.crypto.X509Req`` and ``OpenSSL.crypto.X509``. These should have been
deprecated at the same time ``X509Extension`` was. Users should use
pyca/cryptography's X.509 APIs instead.
- Deprecated ``OpenSSL.crypto.get_elliptic_curves`` and
``OpenSSL.crypto.get_elliptic_curve``, as well as passing the reult of them to
``OpenSSL.SSL.Context.set_tmp_ecdh``, users should instead pass curves from
``cryptography``.
- Deprecated passing ``X509`` objects to
``OpenSSL.SSL.Context.use_certificate``,
``OpenSSL.SSL.Connection.use_certificate``,
``OpenSSL.SSL.Context.add_extra_chain_cert``, and
``OpenSSL.SSL.Context.add_client_ca``, users should instead pass
``cryptography.x509.Certificate`` instances. This is in preparation for
deprecating pyOpenSSL's ``X509`` entirely.
-- Deprecated passing ``PKey`` objects to
``OpenSSL.SSL.Context.use_privatekey`` and
``OpenSSL.SSL.Connection.use_privatekey``, users should instead pass
``cryptography`` priate key instances. This is in preparation for deprecating
pyOpenSSL's ``PKey`` entirely.
+- Deprecated passing ``PKey`` objects to
``OpenSSL.SSL.Context.use_privatekey`` and
``OpenSSL.SSL.Connection.use_privatekey``, users should instead pass
``cryptography`` private key instances. This is in preparation for deprecating
pyOpenSSL's ``PKey`` entirely.
Changes:
^^^^^^^^
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyopenssl-25.3.0/doc/introduction.rst
new/pyopenssl-26.0.0/doc/introduction.rst
--- old/pyopenssl-25.3.0/doc/introduction.rst 2025-09-17 02:31:40.000000000
+0200
+++ new/pyopenssl-26.0.0/doc/introduction.rst 2026-03-15 15:28:02.000000000
+0100
@@ -14,7 +14,7 @@
Later it was maintained by `Jean-Paul Calderone`_ who among other things
managed to make pyOpenSSL a pure Python project which the current maintainers
are *very* grateful for.
Over the time the standard library's ``ssl`` module improved, never reaching
the completeness of pyOpenSSL's API coverage.
-pyOpenSSL remains the only choice for full-featured TLS code in Python
versions 3.7+ and PyPy_.
+pyOpenSSL remains the only choice for full-featured TLS code in Python
versions 3.8+ and PyPy_.
Development
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyopenssl-25.3.0/noxfile.py
new/pyopenssl-26.0.0/noxfile.py
--- old/pyopenssl-25.3.0/noxfile.py 2025-09-17 02:31:40.000000000 +0200
+++ new/pyopenssl-26.0.0/noxfile.py 2026-03-15 15:28:02.000000000 +0100
@@ -3,7 +3,7 @@
nox.options.reuse_existing_virtualenvs = True
nox.options.default_venv_backend = "uv|virtualenv"
-MINIMUM_CRYPTOGRAPHY_VERSION = "45.0.7"
+MINIMUM_CRYPTOGRAPHY_VERSION = "46.0.0"
@nox.session
@@ -28,12 +28,6 @@
if "random-order" in session.name:
random_order = True
- session.env.update(
- {
- "PIP_NO_BINARY": "" if use_wheel else "cryptography",
- }
- )
-
deps = ["coverage>=4.2"]
if cryptography_version == "minimum":
@@ -42,8 +36,13 @@
if random_order:
deps.append("pytest-randomly")
+ extra_install_args = []
+ if not use_wheel:
+ extra_install_args.append("--no-binary")
+ extra_install_args.append("cryptography")
+
session.install(*deps)
- session.install("-e", ".[test]")
+ session.install("-e", ".[test]", *extra_install_args)
if cryptography_version == "main":
session.install("git+https://github.com/pyca/cryptography.git")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyopenssl-25.3.0/setup.py
new/pyopenssl-26.0.0/setup.py
--- old/pyopenssl-25.3.0/setup.py 2025-09-17 02:31:40.000000000 +0200
+++ new/pyopenssl-26.0.0/setup.py 2026-03-15 15:28:02.000000000 +0100
@@ -77,7 +77,6 @@
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX",
"Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
@@ -90,11 +89,11 @@
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: System :: Networking",
],
- python_requires=">=3.7",
+ python_requires=">=3.8",
packages=find_packages(where="src"),
package_dir={"": "src"},
install_requires=[
- "cryptography>=45.0.7,<47",
+ "cryptography>=46.0.0,<47",
(
"typing-extensions>=4.9; "
"python_version < '3.13' and python_version >= '3.8'"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyopenssl-25.3.0/src/OpenSSL/SSL.py
new/pyopenssl-26.0.0/src/OpenSSL/SSL.py
--- old/pyopenssl-25.3.0/src/OpenSSL/SSL.py 2025-09-17 02:31:40.000000000
+0200
+++ new/pyopenssl-26.0.0/src/OpenSSL/SSL.py 2026-03-15 15:28:02.000000000
+0100
@@ -2,6 +2,7 @@
import os
import socket
+import sys
import typing
import warnings
from collections.abc import Sequence
@@ -64,7 +65,6 @@
"OPENSSL_VERSION_NUMBER",
"OP_ALL",
"OP_CIPHER_SERVER_PREFERENCE",
- "OP_COOKIE_EXCHANGE",
"OP_DONT_INSERT_EMPTY_FRAGMENTS",
"OP_EPHEMERAL_RSA",
"OP_MICROSOFT_BIG_SSLV3_BUFFER",
@@ -221,7 +221,11 @@
OP_NO_COMPRESSION: int = _lib.SSL_OP_NO_COMPRESSION
OP_NO_QUERY_MTU: int = _lib.SSL_OP_NO_QUERY_MTU
-OP_COOKIE_EXCHANGE: int = _lib.SSL_OP_COOKIE_EXCHANGE
+try:
+ OP_COOKIE_EXCHANGE: int | None = _lib.SSL_OP_COOKIE_EXCHANGE
+ __all__.append("OP_COOKIE_EXCHANGE")
+except AttributeError:
+ OP_COOKIE_EXCHANGE = None
OP_NO_TICKET: int = _lib.SSL_OP_NO_TICKET
try:
@@ -716,11 +720,18 @@
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
@@ -815,6 +826,16 @@
getattr(_lib, "Cryptography_HAS_KEYLOG", 0), "Key logging not available"
)
+_requires_ssl_get0_group_name = _make_requires(
+ getattr(_lib, "Cryptography_HAS_SSL_GET0_GROUP_NAME", 0),
+ "Getting group name is not supported by the linked OpenSSL version",
+)
+
+_requires_ssl_cookie = _make_requires(
+ getattr(_lib, "Cryptography_HAS_SSL_COOKIE", 0),
+ "DTLS cookie support is not available",
+)
+
class Session:
"""
@@ -1041,7 +1062,7 @@
binary wheels that cryptography (pyOpenSSL's primary dependency) ships:
* macOS will only load certificates using this method if the user has
- the ``[email protected]`` `Homebrew <https://brew.sh>`_ formula installed
+ the ``openssl@3`` `Homebrew <https://brew.sh>`_ formula installed
in the default location.
* Windows will not work.
* manylinux cryptography wheels will work on most common Linux
@@ -1747,7 +1768,11 @@
@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(
@@ -1905,6 +1930,7 @@
self._set_ocsp_callback(helper, data)
@_require_not_used
+ @_requires_ssl_cookie
def set_cookie_generate_callback(
self, callback: _CookieGenerateCallback
) -> None:
@@ -1915,6 +1941,7 @@
)
@_require_not_used
+ @_requires_ssl_cookie
def set_cookie_verify_callback(
self, callback: _CookieVerifyCallback
) -> None:
@@ -3202,6 +3229,26 @@
return _ffi.string(profile.name)
+ @_requires_ssl_get0_group_name
+ def get_group_name(self) -> str | None:
+ """
+ Get the name of the negotiated group for the key exchange.
+
+ :return: A string giving the group name or :data:`None`.
+ """
+ # Do not remove this guard.
+ # SSL_get0_group_name crashes with a segfault if called without
+ # an established connection (should return NULL but doesn't).
+ session = _lib.SSL_get_session(self._ssl)
+ if session == _ffi.NULL:
+ return None
+
+ group_name = _lib.SSL_get0_group_name(self._ssl)
+ if group_name == _ffi.NULL:
+ return None
+
+ return _ffi.string(group_name).decode("utf-8")
+
def request_ocsp(self) -> None:
"""
Called to request that the server sends stapled OCSP data, if
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyopenssl-25.3.0/src/OpenSSL/crypto.py
new/pyopenssl-26.0.0/src/OpenSSL/crypto.py
--- old/pyopenssl-25.3.0/src/OpenSSL/crypto.py 2025-09-17 02:31:40.000000000
+0200
+++ new/pyopenssl-26.0.0/src/OpenSSL/crypto.py 2026-03-15 15:28:02.000000000
+0100
@@ -885,9 +885,11 @@
_lib.GENERAL_NAME_print(bio, name)
parts.append(_bio_to_string(bio).decode("utf-8"))
else:
- value = _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[
- :
- ].decode("utf-8")
+ asn1_string = _ffi.cast("ASN1_STRING*", name.d.ia5)
+ value = _ffi.buffer(
+ _lib.ASN1_STRING_get0_data(asn1_string),
+ _lib.ASN1_STRING_length(asn1_string),
+ )[:].decode("utf-8")
parts.append(label + ":" + value)
return ", ".join(parts)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyopenssl-25.3.0/src/OpenSSL/version.py
new/pyopenssl-26.0.0/src/OpenSSL/version.py
--- old/pyopenssl-25.3.0/src/OpenSSL/version.py 2025-09-17 02:31:40.000000000
+0200
+++ new/pyopenssl-26.0.0/src/OpenSSL/version.py 2026-03-15 15:28:02.000000000
+0100
@@ -17,7 +17,7 @@
"__version__",
]
-__version__ = "25.3.0"
+__version__ = "26.0.0"
__title__ = "pyOpenSSL"
__uri__ = "https://pyopenssl.org/"
@@ -25,4 +25,4 @@
__author__ = "The pyOpenSSL developers"
__email__ = "[email protected]"
__license__ = "Apache License, Version 2.0"
-__copyright__ = f"Copyright 2001-2025 {__author__}"
+__copyright__ = f"Copyright 2001-2026 {__author__}"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyopenssl-25.3.0/src/pyOpenSSL.egg-info/PKG-INFO
new/pyopenssl-26.0.0/src/pyOpenSSL.egg-info/PKG-INFO
--- old/pyopenssl-25.3.0/src/pyOpenSSL.egg-info/PKG-INFO 2025-09-17
02:31:46.000000000 +0200
+++ new/pyopenssl-26.0.0/src/pyOpenSSL.egg-info/PKG-INFO 2026-03-15
15:28:07.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: pyOpenSSL
-Version: 25.3.0
+Version: 26.0.0
Summary: Python wrapper module around the OpenSSL library
Home-page: https://pyopenssl.org/
Author: The pyOpenSSL developers
@@ -14,7 +14,6 @@
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX
Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
@@ -26,9 +25,9 @@
Classifier: Topic :: Security :: Cryptography
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Networking
-Requires-Python: >=3.7
+Requires-Python: >=3.8
License-File: LICENSE
-Requires-Dist: cryptography<47,>=45.0.7
+Requires-Dist: cryptography<47,>=46.0.0
Requires-Dist: typing-extensions>=4.9; python_version < "3.13" and
python_version >= "3.8"
Provides-Extra: test
Requires-Dist: pytest-rerunfailures; extra == "test"
@@ -97,18 +96,26 @@
Release Information
===================
-25.4.0 (UNRELEASED)
+26.0.0 (2026-03-15)
-------------------
Backward-incompatible changes:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+- Dropped support for Python 3.7.
+- The minimum ``cryptography`` version is now 46.0.0.
+
Deprecations:
^^^^^^^^^^^^^
Changes:
^^^^^^^^
+- Added support for using aws-lc instead of OpenSSL.
+- Properly raise an error if a DTLS cookie callback returned a cookie longer
than ``DTLS1_COOKIE_LENGTH`` bytes. Previously this would result in a
buffer-overflow. Credit to **dark_haxor** for reporting the issue.
**CVE-2026-27459**
+- Added ``OpenSSL.SSL.Connection.get_group_name`` to determine which group
name was negotiated.
+- ``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. Credit to **Leury Castillo** for reporting
this issue. **CVE-2026-27448**
+
25.3.0 (2025-09-16)
-------------------
@@ -193,7 +200,7 @@
- Deprecated ``add_extensions`` and ``get_extensions`` on
``OpenSSL.crypto.X509Req`` and ``OpenSSL.crypto.X509``. These should have been
deprecated at the same time ``X509Extension`` was. Users should use
pyca/cryptography's X.509 APIs instead.
- Deprecated ``OpenSSL.crypto.get_elliptic_curves`` and
``OpenSSL.crypto.get_elliptic_curve``, as well as passing the reult of them to
``OpenSSL.SSL.Context.set_tmp_ecdh``, users should instead pass curves from
``cryptography``.
- Deprecated passing ``X509`` objects to
``OpenSSL.SSL.Context.use_certificate``,
``OpenSSL.SSL.Connection.use_certificate``,
``OpenSSL.SSL.Context.add_extra_chain_cert``, and
``OpenSSL.SSL.Context.add_client_ca``, users should instead pass
``cryptography.x509.Certificate`` instances. This is in preparation for
deprecating pyOpenSSL's ``X509`` entirely.
-- Deprecated passing ``PKey`` objects to
``OpenSSL.SSL.Context.use_privatekey`` and
``OpenSSL.SSL.Connection.use_privatekey``, users should instead pass
``cryptography`` priate key instances. This is in preparation for deprecating
pyOpenSSL's ``PKey`` entirely.
+- Deprecated passing ``PKey`` objects to
``OpenSSL.SSL.Context.use_privatekey`` and
``OpenSSL.SSL.Connection.use_privatekey``, users should instead pass
``cryptography`` private key instances. This is in preparation for deprecating
pyOpenSSL's ``PKey`` entirely.
Changes:
^^^^^^^^
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyopenssl-25.3.0/src/pyOpenSSL.egg-info/requires.txt
new/pyopenssl-26.0.0/src/pyOpenSSL.egg-info/requires.txt
--- old/pyopenssl-25.3.0/src/pyOpenSSL.egg-info/requires.txt 2025-09-17
02:31:46.000000000 +0200
+++ new/pyopenssl-26.0.0/src/pyOpenSSL.egg-info/requires.txt 2026-03-15
15:28:07.000000000 +0100
@@ -1,4 +1,4 @@
-cryptography<47,>=45.0.7
+cryptography<47,>=46.0.0
[:python_version < "3.13" and python_version >= "3.8"]
typing-extensions>=4.9
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyopenssl-25.3.0/tests/conftest.py
new/pyopenssl-26.0.0/tests/conftest.py
--- old/pyopenssl-25.3.0/tests/conftest.py 2025-09-17 02:31:40.000000000
+0200
+++ new/pyopenssl-26.0.0/tests/conftest.py 2026-03-15 15:28:02.000000000
+0100
@@ -6,6 +6,10 @@
import pytest
+from OpenSSL.SSL import OPENSSL_VERSION, SSLeay_version
+
+is_awslc = b"AWS-LC" in SSLeay_version(OPENSSL_VERSION)
+
def pytest_report_header(config: pytest.Config) -> str:
import cryptography
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyopenssl-25.3.0/tests/test_crypto.py
new/pyopenssl-26.0.0/tests/test_crypto.py
--- old/pyopenssl-25.3.0/tests/test_crypto.py 2025-09-17 02:31:40.000000000
+0200
+++ new/pyopenssl-26.0.0/tests/test_crypto.py 2026-03-15 15:28:02.000000000
+0100
@@ -58,6 +58,7 @@
load_publickey,
)
+from . import conftest
from .util import (
NON_ASCII,
)
@@ -71,7 +72,7 @@
return datetime.now(timezone.utc).replace(tzinfo=None)
-GOOD_CIPHER = "blowfish"
+GOOD_CIPHER = "aes-256-cbc"
BAD_CIPHER = "zippers"
GOOD_DIGEST = "SHA256"
@@ -555,60 +556,6 @@
-----END PUBLIC KEY-----
"""
-crlData = b"""\
------BEGIN X509 CRL-----
-MIIBWzCBxTANBgkqhkiG9w0BAQQFADBYMQswCQYDVQQGEwJVUzELMAkGA1UECBMC
-SUwxEDAOBgNVBAcTB0NoaWNhZ28xEDAOBgNVBAoTB1Rlc3RpbmcxGDAWBgNVBAMT
-D1Rlc3RpbmcgUm9vdCBDQRcNMDkwNzI2MDQzNDU2WhcNMTIwOTI3MDI0MTUyWjA8
-MBUCAgOrGA8yMDA5MDcyNTIzMzQ1NlowIwICAQAYDzIwMDkwNzI1MjMzNDU2WjAM
-MAoGA1UdFQQDCgEEMA0GCSqGSIb3DQEBBAUAA4GBAEBt7xTs2htdD3d4ErrcGAw1
-4dKcVnIWTutoI7xxen26Wwvh8VCsT7i/UeP+rBl9rC/kfjWjzQk3/zleaarGTpBT
-0yp4HXRFFoRhhSE/hP+eteaPXRgrsNRLHe9ZDd69wmh7J1wMDb0m81RG7kqcbsid
-vrzEeLDRiiPl92dyyWmu
------END X509 CRL-----
-"""
-
-# The signature on this CRL is invalid.
-crlDataUnsupportedExtension = b"""\
------BEGIN X509 CRL-----
-MIIGRzCCBS8CAQEwDQYJKoZIhvcNAQELBQAwJzELMAkGA1UEBhMCVVMxGDAWBgNV
-BAMMD2NyeXB0b2dyYXBoeS5pbxgPMjAxNTAxMDEwMDAwMDBaGA8yMDE2MDEwMTAw
-MDAwMFowggTOMBQCAQAYDzIwMTUwMTAxMDAwMDAwWjByAgEBGA8yMDE1MDEwMTAw
-MDAwMFowXDAYBgNVHRgEERgPMjAxNTAxMDEwMDAwMDBaMDQGA1UdHQQtMCukKTAn
-MQswCQYDVQQGEwJVUzEYMBYGA1UEAwwPY3J5cHRvZ3JhcGh5LmlvMAoGA1UdFQQD
-CgEAMHICAQIYDzIwMTUwMTAxMDAwMDAwWjBcMBgGA1UdGAQRGA8yMDE1MDEwMTAw
-MDAwMFowNAYDVR0dBC0wK6QpMCcxCzAJBgNVBAYTAlVTMRgwFgYDVQQDDA9jcnlw
-dG9ncmFwaHkuaW8wCgYDVR0VBAMKAQEwcgIBAxgPMjAxNTAxMDEwMDAwMDBaMFww
-GAYDVR0YBBEYDzIwMTUwMTAxMDAwMDAwWjA0BgNVHR0ELTArpCkwJzELMAkGA1UE
-BhMCVVMxGDAWBgNVBAMMD2NyeXB0b2dyYXBoeS5pbzAKBgNVHRUEAwoBAjByAgEE
-GA8yMDE1MDEwMTAwMDAwMFowXDAYBgNVHRgEERgPMjAxNTAxMDEwMDAwMDBaMDQG
-A1UdHQQtMCukKTAnMQswCQYDVQQGEwJVUzEYMBYGA1UEAwwPY3J5cHRvZ3JhcGh5
-LmlvMAoGA1UdFQQDCgEDMHICAQUYDzIwMTUwMTAxMDAwMDAwWjBcMBgGA1UdGAQR
-GA8yMDE1MDEwMTAwMDAwMFowNAYDVR0dBC0wK6QpMCcxCzAJBgNVBAYTAlVTMRgw
-FgYDVQQDDA9jcnlwdG9ncmFwaHkuaW8wCgYDVR0VBAMKAQQwcgIBBhgPMjAxNTAx
-MDEwMDAwMDBaMFwwGAYDVR0YBBEYDzIwMTUwMTAxMDAwMDAwWjA0BgNVHR0ELTAr
-pCkwJzELMAkGA1UEBhMCVVMxGDAWBgNVBAMMD2NyeXB0b2dyYXBoeS5pbzAKBgNV
-HRUEAwoBBTByAgEHGA8yMDE1MDEwMTAwMDAwMFowXDAYBgNVHRgEERgPMjAxNTAx
-MDEwMDAwMDBaMDQGA1UdHQQtMCukKTAnMQswCQYDVQQGEwJVUzEYMBYGA1UEAwwP
-Y3J5cHRvZ3JhcGh5LmlvMAoGA1UdFQQDCgEGMHICAQgYDzIwMTUwMTAxMDAwMDAw
-WjBcMBgGA1UdGAQRGA8yMDE1MDEwMTAwMDAwMFowNAYDVR0dBC0wK6QpMCcxCzAJ
-BgNVBAYTAlVTMRgwFgYDVQQDDA9jcnlwdG9ncmFwaHkuaW8wCgYDVR0VBAMKAQgw
-cgIBCRgPMjAxNTAxMDEwMDAwMDBaMFwwGAYDVR0YBBEYDzIwMTUwMTAxMDAwMDAw
-WjA0BgNVHR0ELTArpCkwJzELMAkGA1UEBhMCVVMxGDAWBgNVBAMMD2NyeXB0b2dy
-YXBoeS5pbzAKBgNVHRUEAwoBCTByAgEKGA8yMDE1MDEwMTAwMDAwMFowXDAYBgNV
-HRgEERgPMjAxNTAxMDEwMDAwMDBaMDQGA1UdHQQtMCukKTAnMQswCQYDVQQGEwJV
-UzEYMBYGA1UEAwwPY3J5cHRvZ3JhcGh5LmlvMAoGA1UdFQQDCgEKMC4CAQsYDzIw
-MTUwMTAxMDAwMDAwWjAYMAoGA1UdFQQDCgEBMAoGAyoDBAQDCgEAMA0GCSqGSIb3
-DQEBCwUAA4IBAQBTaloHlPaCZzYee8LxkWej5meiqxQVNWFoVdjesroa+f1FRrH+
-drRU60Nq97KCKf7f9GNN/J3ZIlQmYhmuDqh12f+XLpotoj1ZRfBz2hjFCkJlv+2c
-oWWGNHgA70ndFoVtcmX088SYpX8E3ARATivS4q2h9WlwV6rO93mhg3HGIe3JpcK4
-7BcW6Poi/ut/zsDOkVbI00SqaujRpdmdCTht82MH3ztjyDkI9KYaD/YEweKSrWOz
-SdEILd164bfBeLuplVI+xpmTEMVNpXBlSXl7+xIw9Vk7p7Q1Pa3k/SvhOldYCm6y
-C1xAg/AAq6w78yzYt18j5Mj0s6eeHi1YpHKw
------END X509 CRL-----
-"""
-
-
# A broken RSA private key which can be used to test the error path through
# PKey.check.
inconsistentPrivateKeyPEM = b"""-----BEGIN RSA PRIVATE KEY-----
@@ -1077,8 +1024,22 @@
[
(dsa_private_key_pem, dsa.DSAPrivateKey),
(ec_private_key_pem, ec.EllipticCurvePrivateKey),
- (ed25519_private_key_pem, ed25519.Ed25519PrivateKey),
- (ed448_private_key_pem, ed448.Ed448PrivateKey),
+ pytest.param(
+ ed25519_private_key_pem,
+ ed25519.Ed25519PrivateKey,
+ marks=pytest.mark.skipif(
+ conftest.is_awslc,
+ reason="aws-lc doesn't support Ed25519 serialization",
+ ),
+ ),
+ pytest.param(
+ ed448_private_key_pem,
+ ed448.Ed448PrivateKey,
+ marks=pytest.mark.skipif(
+ conftest.is_awslc,
+ reason="aws-lc doesn't support Ed448",
+ ),
+ ),
(rsa_private_key_pem, rsa.RSAPrivateKey),
],
)
@@ -1131,8 +1092,22 @@
[
(dsa_public_key_pem, dsa.DSAPublicKey),
(ec_public_key_pem, ec.EllipticCurvePublicKey),
- (ed25519_public_key_pem, ed25519.Ed25519PublicKey),
- (ed448_public_key_pem, ed448.Ed448PublicKey),
+ pytest.param(
+ ed25519_public_key_pem,
+ ed25519.Ed25519PublicKey,
+ marks=pytest.mark.skipif(
+ conftest.is_awslc,
+ reason="aws-lc doesn't support Ed25519 serialization",
+ ),
+ ),
+ pytest.param(
+ ed448_public_key_pem,
+ ed448.Ed448PublicKey,
+ marks=pytest.mark.skipif(
+ conftest.is_awslc,
+ reason="aws-lc doesn't support Ed448",
+ ),
+ ),
(rsa_public_key_pem, rsa.RSAPublicKey),
],
)
@@ -1876,6 +1851,8 @@
key = PKey()
key.generate_key(TYPE_RSA, 2048)
cert.set_pubkey(key)
+ cert.gmtime_adj_notBefore(0)
+ cert.gmtime_adj_notAfter(24 * 60 * 60)
cert.sign(key, GOOD_DIGEST)
def test_construction(self) -> None:
@@ -1944,20 +1921,21 @@
set(certificate, when)
assert get(certificate) == when
- # A plus two hours and thirty minutes offset
- when = b"20040203040506+0530"
- set(certificate, when)
- assert get(certificate) == when
-
- # A minus one hour fifteen minutes offset
- when = b"20040203040506-0115"
- set(certificate, when)
- assert (
- get(
- certificate,
+ if not conftest.is_awslc:
+ # A plus two hours and thirty minutes offset
+ when = b"20040203040506+0530"
+ set(certificate, when)
+ assert get(certificate) == when
+
+ # A minus one hour fifteen minutes offset
+ when = b"20040203040506-0115"
+ set(certificate, when)
+ assert (
+ get(
+ certificate,
+ )
+ == when
)
- == when
- )
# An invalid string results in a ValueError
with pytest.raises(ValueError):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyopenssl-25.3.0/tests/test_ssl.py
new/pyopenssl-26.0.0/tests/test_ssl.py
--- old/pyopenssl-25.3.0/tests/test_ssl.py 2025-09-17 02:31:40.000000000
+0200
+++ new/pyopenssl-26.0.0/tests/test_ssl.py 2026-03-15 15:28:02.000000000
+0100
@@ -37,6 +37,7 @@
SOL_SOCKET,
gaierror,
socket,
+ socketpair,
)
from sys import getfilesystemencoding, platform
from weakref import ref
@@ -66,7 +67,6 @@
)
from OpenSSL.SSL import (
DTLS_METHOD,
- MODE_RELEASE_BUFFERS,
NO_OVERLAPPING_PROTOCOLS,
OP_COOKIE_EXCHANGE,
OP_NO_COMPRESSION,
@@ -131,6 +131,7 @@
_NoOverlappingProtocols,
)
+from . import conftest
from .test_crypto import (
client_cert_pem,
client_key_pem,
@@ -642,6 +643,12 @@
"",
"no cipher match",
),
+ # aws-lc
+ (
+ "SSL routines",
+ "OPENSSL_internal",
+ "NO_CIPHER_MATCH",
+ ),
]
def test_load_client_ca(self, context: Context, ca_file: bytes) -> None:
@@ -670,7 +677,8 @@
"""
Passing the path as unicode raises a warning but works.
"""
- pytest.deprecated_call(context.load_client_ca, ca_file.decode("ascii"))
+ with pytest.deprecated_call():
+ context.load_client_ca(ca_file.decode("ascii")) # type:
ignore[arg-type]
def test_set_session_id(self, context: Context) -> None:
"""
@@ -698,6 +706,12 @@
"",
"ssl session id context too long",
),
+ # aws-lc
+ (
+ "SSL routines",
+ "OPENSSL_internal",
+ "SSL_SESSION_ID_CONTEXT_TOO_LONG",
+ ),
]
def test_set_session_id_unicode(self, context: Context) -> None:
@@ -705,7 +719,8 @@
`Context.set_session_id` raises a warning if a unicode string is
passed.
"""
- pytest.deprecated_call(context.set_session_id, "abc")
+ with pytest.deprecated_call():
+ context.set_session_id("abc") # type: ignore[arg-type]
def test_method(self) -> None:
"""
@@ -919,7 +934,8 @@
newly set mode.
"""
context = Context(SSLv23_METHOD)
- assert MODE_RELEASE_BUFFERS & context.set_mode(MODE_RELEASE_BUFFERS)
+ mode = _lib.SSL_MODE_ENABLE_PARTIAL_WRITE
+ assert mode & context.set_mode(mode)
def test_set_timeout_wrong_args(self) -> None:
"""
@@ -966,7 +982,7 @@
"""
key = PKey()
key.generate_key(TYPE_RSA, 1024)
- pem = dump_privatekey(FILETYPE_PEM, key, "blowfish", passphrase)
+ pem = dump_privatekey(FILETYPE_PEM, key, "aes-256-cbc", passphrase)
with open(tmpfile, "w") as fObj:
fObj.write(pem.decode("ascii"))
return tmpfile
@@ -1160,7 +1176,7 @@
client_context = Context(TLS_METHOD)
client_context.set_max_proto_version(low_version)
- with pytest.raises(Error, match="unsupported protocol"):
+ with pytest.raises(Error, match=r"(?i)unsupported.protocol"):
self._handshake_test(server_context, client_context)
client_context = Context(TLS_METHOD)
@@ -1629,7 +1645,9 @@
if mode == SSL.VERIFY_PEER:
with pytest.raises(Exception) as exc:
self._handshake_test(serverContext, clientContext)
- assert "certificate verify failed" in str(exc.value)
+ assert "certificate verify failed" in str(
+ exc.value
+ ) or "CERTIFICATE_VERIFY_FAILED" in str(exc.value)
else:
self._handshake_test(serverContext, clientContext)
@@ -1858,9 +1876,27 @@
with pytest.deprecated_call():
context.set_tmp_ecdh(curve)
+ awslc_unsupported_curves = {
+ "BRAINPOOLP256R1",
+ "BRAINPOOLP384R1",
+ "BRAINPOOLP512R1",
+ "SECP192R1",
+ "SECT163K1",
+ "SECT163R2",
+ "SECT233K1",
+ "SECT233R1",
+ "SECT283K1",
+ "SECT283R1",
+ "SECT409K1",
+ "SECT409R1",
+ "SECT571K1",
+ "SECT571R1",
+ }
for name in dir(ec.EllipticCurveOID):
if name.startswith("_"):
continue
+ if conftest.is_awslc and name in awslc_unsupported_curves:
+ continue
oid = getattr(ec.EllipticCurveOID, name)
cryptography_curve = ec.get_curve_for_oid(oid)
context.set_tmp_ecdh(cryptography_curve())
@@ -2031,6 +2067,56 @@
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:
"""
@@ -2696,10 +2782,12 @@
assert tls_server.get_state_string() in [
b"before/accept initialization",
b"before SSL initialization",
+ b"TLS server start_accept",
]
assert tls_client.get_state_string() in [
b"before/connect initialization",
b"before SSL initialization",
+ b"TLS client start_connect",
]
def test_app_data(self) -> None:
@@ -3070,7 +3158,14 @@
`OpenSSL.SSL.WantWriteError` if writing to the connection's BIO
fail indicating a should-write state.
"""
- client_socket, _ = socket_pair()
+ # Use Unix domain sockets rather than TCP loopback. On macOS,
+ # TCP loopback aggressively auto-tunes buffer sizes and drains
+ # the send buffer into the peer's receive buffer nearly
+ # instantly, so the send buffer won't stay full long enough
+ # for do_handshake() to observe it.
+ client_socket, peer = socketpair()
+ client_socket.setblocking(False)
+ peer.setblocking(False)
# Fill up the client's send buffer so Connection won't be able to write
# anything. Start by sending larger chunks (Windows Socket I/O is slow)
# and continue by writing a single byte at a time so we can be sure we
@@ -3169,9 +3264,10 @@
return False # Retry succeeded
except SSL.Error as e:
reason = get_ssl_error_reason(e)
- assert reason == "bad write retry", (
- f"Retry failed with unexpected SSL error: {e!r}({reason})."
- )
+ assert reason in (
+ "bad write retry",
+ "BAD_WRITE_RETRY",
+ ), f"Retry failed with unexpected SSL error: {e!r}({reason})."
return True # Bad write retry
def _shutdown_connections(
@@ -3437,6 +3533,54 @@
assert server_protocol_version == client_protocol_version
+ @pytest.mark.skipif(
+ not getattr(_lib, "Cryptography_HAS_SSL_GET0_GROUP_NAME", None),
+ reason="SSL_get0_group_name unavailable",
+ )
+ def test_get_group_name_before_connect(self) -> None:
+ """
+ `Connection.get_group_name()` returns `None` if no connection
+ has been established.
+ """
+ ctx = Context(TLS_METHOD)
+ conn = Connection(ctx, None)
+ assert conn.get_group_name() is None
+
+ @pytest.mark.skipif(
+ not getattr(_lib, "Cryptography_HAS_SSL_GET0_GROUP_NAME", None),
+ reason="SSL_get0_group_name unavailable",
+ )
+ def test_group_name_null_case(
+ self, monkeypatch: pytest.MonkeyPatch
+ ) -> None:
+ """
+ `Connection.get_group_name()` returns `None` when SSL_get0_group_name
+ returns NULL.
+ """
+ monkeypatch.setattr(_lib, "SSL_get0_group_name", lambda ssl: _ffi.NULL)
+
+ server, client = loopback()
+ assert server.get_group_name() is None
+ assert client.get_group_name() is None
+
+ @pytest.mark.skipif(
+ not getattr(_lib, "Cryptography_HAS_SSL_GET0_GROUP_NAME", None),
+ reason="SSL_get0_group_name unavailable",
+ )
+ def test_get_group_name(self) -> None:
+ """
+ `Connection.get_group_name()` returns a string giving the
+ name of the connection's negotiated key exchange group.
+ """
+ server, client = loopback()
+ server_group_name = server.get_group_name()
+ client_group_name = client.get_group_name()
+
+ assert isinstance(server_group_name, str)
+ assert isinstance(client_group_name, str)
+
+ assert server_group_name == client_group_name
+
def test_wantReadError(self) -> None:
"""
`Connection.bio_read` raises `OpenSSL.SSL.WantReadError` if there are
@@ -3837,6 +3981,10 @@
connection = Connection(Context(SSLv23_METHOD), None)
assert connection.total_renegotiations() == 0
+ @pytest.mark.skipif(
+ conftest.is_awslc,
+ reason="aws-lc doesn't support renegotiation",
+ )
def test_renegotiate(self) -> None:
"""
Go through a complete renegotiation cycle.
@@ -3930,6 +4078,10 @@
"OP_NO_COMPRESSION unavailable - OpenSSL version may be too old"
),
)
+ @pytest.mark.skipif(
+ conftest.is_awslc,
+ reason="aws-lc defines OP_NO_COMPRESSION as 0",
+ )
def test_op_no_compression(self) -> None:
"""
The value of `OpenSSL.SSL.OP_NO_COMPRESSION` is 0x20000, the
@@ -4992,12 +5144,62 @@
c.set_ciphertext_mtu(500)
assert 0 < c.get_cleartext_mtu() < 500
+ @pytest.mark.skipif(
+ OP_COOKIE_EXCHANGE is None,
+ reason="DTLS cookie exchange not supported",
+ )
def test_it_works_at_all(self) -> None:
self._test_handshake_and_data(srtp_profile=None)
+ @pytest.mark.skipif(
+ OP_COOKIE_EXCHANGE is None,
+ reason="DTLS cookie exchange not supported",
+ )
def test_it_works_with_srtp(self) -> None:
self._test_handshake_and_data(srtp_profile=b"SRTP_AES128_CM_SHA1_80")
+ @pytest.mark.skipif(
+ OP_COOKIE_EXCHANGE is None,
+ reason="DTLS cookie exchange not supported",
+ )
+ 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)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyopenssl-25.3.0/tests/test_util.py
new/pyopenssl-26.0.0/tests/test_util.py
--- old/pyopenssl-25.3.0/tests/test_util.py 2025-09-17 02:31:40.000000000
+0200
+++ new/pyopenssl-26.0.0/tests/test_util.py 2026-03-15 15:28:02.000000000
+0100
@@ -16,4 +16,4 @@
lib.ERR_put_error(lib.ERR_LIB_EVP, 0, 1112, b"", 10)
with pytest.raises(ValueError) as exc:
exception_from_error_queue(ValueError)
- assert exc.value.args[0][0][2] == ""
+ assert exc.value.args[0][0][2] in ("", "unknown error")