diff --git a/.audit/oberstet_fix_2016.md b/.audit/oberstet_fix_2016.md new file mode 100644 index 000000000..9958f46cb --- /dev/null +++ b/.audit/oberstet_fix_2016.md @@ -0,0 +1,8 @@ +- [ ] I did **not** use any AI-assistance tools to help create this pull request. +- [x] I **did** use AI-assistance tools to *help* create this pull request. +- [x] I have read, understood and followed the project's AI_POLICY.md when creating code, documentation etc. for this pull request. + +Submitted by: @oberstet +Date: 2026-10-20 +Related issue(s): #2016 +Branch: oberstet:fix_2016 diff --git a/docs/changelog.rst b/docs/changelog.rst index 054429207..e347f101b 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -14,7 +14,7 @@ Changelog * Fix the TLS peer certificate never being available on Twisted WebSocket and RawSocket connections: it was read when the TCP connection was made, before the TLS handshake, and so was always ``None``. It is now read when the TLS handshake is complete, together with the TLS channel ID. With this, TLS client certificate authentication (Crossbar.io authmethod ``tls``, and dynamic authenticators reading ``transport.peer_cert``) works again (#2014) * Fix asyncio: fill ``TransportDetails.peer_cert`` (it was always ``None``), and treat a TLS server connection without a client certificate as secure, with a TLS channel ID: ``is_secure`` was derived from the peer certificate, so WAMP-cryptosign with channel binding failed on asyncio servers (#2014) * **⚠ behaviour change** — the TLS channel ID ``tls-unique`` on Twisted now follows RFC 5929 (the first TLS Finished message of the handshake, in a full handshake the client's), as Python's ``ssl`` module, and so autobahn on asyncio, already did. Twisted used the server's Finished message, so WAMP-cryptosign with channel binding failed between Twisted and asyncio peers over WebSocket, and between Twisted RawSocket peers (whose protocols did not set ``is_server``, so the client side used the wrong message). Twisted peers on autobahn 26.10.1 or older and on 26.10.2 no longer agree on the channel ID over WebSocket: upgrade both sides of connections that use channel binding (#2014) -* Work around a PyPy bug: PyPy's ``ssl`` module (up to at least PyPy 7.3.23) returns the server's TLS Finished message from ``get_channel_binding("tls-unique")`` instead of the first (the client's), so autobahn on asyncio on PyPy disagreed with all other peers on the channel ID. The new ``autobahn.util.tls_unique()`` uses PyPy's own ``tls_unique_cb()`` on PyPy, which returns the right message (#2014) +* Work around a PyPy bug: PyPy's ``ssl`` module (up to at least PyPy 7.3.23) returns the server's TLS Finished message from ``get_channel_binding("tls-unique")`` instead of the first (the client's), so autobahn on asyncio on PyPy disagreed with all other peers on the channel ID. The new ``autobahn.util.tls_unique()`` uses PyPy's own ``tls_unique_cb()`` on PyPy, which returns the right message (#2014; reported as `pypy/pypy#5676 `__) * ``TransportDetails.is_server`` is now set on Twisted RawSocket and asyncio WebSocket connections (it was ``None``) (#2014) **Tests & CI/CD** @@ -22,6 +22,7 @@ Changelog * Add tests for WAMP over TLS on Twisted and asyncio, over WebSocket and RawSocket, on TLS 1.2 and 1.3, with certificates created per test: the peer certificate, TLS client certificate authentication, WAMP-cryptosign with channel binding, and ``tls-unique`` against Python's ``ssl`` module (#2014) * Fix ``test_tx_choosereactor`` replacing ``sys.modules`` with a copy, which broke later lazy imports in the same test process (``KeyError: '_strptime'``) (#2014) * CI runs the asyncio unit tests also when the Twisted unit tests fail, so that both backends always report (#2014) +* Release 26.10.2: changelog, release notes and version (#2016) 26.10.1 ------- diff --git a/docs/release-notes.rst b/docs/release-notes.rst index eeb9427d3..c0da45621 100644 --- a/docs/release-notes.rst +++ b/docs/release-notes.rst @@ -8,6 +8,41 @@ Release Notes This page provides a high-level overview of important changes in each release. For detailed technical changes, see the :ref:`changelog `. +26.10.2 +------- + +**Release Type:** Stable release (bug fix) + +Highlights +^^^^^^^^^^ + +* **WAMP over TLS**: the TLS peer certificate (``TransportDetails.peer_cert``) is + read again with pyOpenSSL 26.2.0 and later, and on Twisted WebSocket and + RawSocket connections it is read after the TLS handshake (it was always + ``None``), so TLS client certificate authentication works again. On asyncio, + ``peer_cert`` is filled, and a TLS server connection without a client + certificate is secure and has a channel ID. The certificate is read with + ``cryptography``, in the new ``autobahn.util.peer_certificate_details()``. + +* **⚠ TLS channel binding**: ``tls-unique`` on Twisted now follows RFC 5929, as + Python's ``ssl`` module does, so WAMP-cryptosign with channel binding works + between Twisted and asyncio peers. Twisted peers on 26.10.1 or older and on + 26.10.2 no longer agree on the channel ID over WebSocket: upgrade both sides of + connections that use channel binding. On PyPy, autobahn works around a PyPy + ``ssl`` bug (`pypy/pypy#5676 `__). + +* **⚠ peer_cert format**: ``extensions[].value`` is OpenSSL's text only for + subject and issuer alternative names, other extensions are given as + ``cryptography`` prints them; ``signature_algorithm`` is ``ed25519`` instead of + ``ED25519`` for Ed25519 certificates. + +Release Links +^^^^^^^^^^^^^ + +* `PyPI Package `__ + +**Detailed Changes:** See :ref:`changelog` (26.10.2 section) + 26.10.1 ------- diff --git a/pyproject.toml b/pyproject.toml index 445da3048..fad17ff36 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "autobahn" -version = "26.10.2.dev1" +version = "26.10.2" description = "WebSocket client & server library, WAMP real-time framework" readme = "README.md" requires-python = ">=3.11" diff --git a/src/autobahn/_version.py b/src/autobahn/_version.py index 867fddac7..a62a829b1 100644 --- a/src/autobahn/_version.py +++ b/src/autobahn/_version.py @@ -24,6 +24,6 @@ # ############################################################################### -__version__ = "26.10.2.dev1" +__version__ = "26.10.2" __build__ = "00000000-0000000"