4 Commits
Author SHA1 Message Date
Leon Anavi 409953c2d9 python3-autobahn: Upgrade 26.10.2 -> 26.11.1
Upgrade to release 26.11.1:

- Security: parse the HTTP headers of the WebSocket opening
  handshake strictly (RFC 9112, RFC 9110). The header block was
  split with str.splitlines(), which also splits on VT, FF, FS, GS,
  RS, NEL and on a bare CR or LF, so a peer could make autobahn see
  header lines that a front proxy treats as part of a header value,
  for example an X-Forwarded-For used with trustXForwardedFor.
  Lines are now separated by CRLF only. ⚠ behaviour change — a
  header block with a bare CR or LF, obs-fold, whitespace before
  the colon, an invalid header name, a header line without a colon
  (was skipped), or a control character in a header value or the
  status line is rejected: the server fails the handshake with HTTP
  400, the client fails the handshake or the proxy CONNECT. A bare
  LF is rejected deliberately, although RFC 9112 allows accepting
  it as a line end. obs-text (0x80-0xFF) in header values is still
  allowed, and header values are trimmed of SP and HTAB only. This
  fixes advisory GHSA-2gqc-mwv3-66rp

- Security: raise the floors of the compress extra (and so all)
  to brotli>=1.2.1 (CPython) and brotlicffi>=1.2.1.0 (PyPy), the
  releases with the fix for CVE-2026-111497, an out-of-bounds write
  in the brotli decoder that permits remote code execution.
  permessage-brotli decodes data sent by the WebSocket peer; it is
  not used unless an application offers or accepts it. The brotli
  1.0.10 and 1.1.1 backports of the fix are not enough, since the
  permessage-brotli receive path needs the decompression limit of
  brotli 1.2. New tests check the declared floors and the installed
  version

- Add tests for the HTTP header parsing of the WebSocket opening
  handshake, on the server, the client and the explicit proxy
  CONNECT, run on Twisted and asyncio

Signed-off-by: Leon Anavi <leon.anavi@konsulko.com>
Signed-off-by: Khem Raj <khem.raj@oss.qualcomm.com>
2026-11-06 00:15:40 -08:00
Leon Anavi ac20bdb6f1 python3-autobahn: Upgrade 26.10.1 -> 26.10.2
Upgrade to release 26.10.2:

- Fix reading the TLS peer certificate
  (TransportDetails.peer_cert) with pyOpenSSL 26.2.0 and later:
  autobahn.twisted.util.extract_peer_certificate() raised
  AttributeError: 'X509' object has no attribute 'get_extension'
  for every certificate with extensions, as pyOpenSSL removed its
  X.509 extension API (and deprecates the rest of its X509 API).
  The certificate is now read with cryptography, in the new
  backend-neutral autobahn.util.peer_certificate_details(), which
  also never raises on certificate content it cannot parse (it is
  peer data, read before authentication): extensions, or a subject
  or issuer, that cannot be read are left empty. The peer_cert dict
  keeps its keys and formats, except: ⚠ extensions[].value was
  OpenSSL's text; a subject or issuer alternative name is still
  given as OpenSSL prints it (DNS:localhost, IP Address:127.0.0.1),
  other extensions now as cryptography prints them; and
  signature_algorithm is ed25519 instead of ED25519 for Ed25519
  certificates

- 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

- 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

- 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

- TransportDetails.is_server is now set on Twisted RawSocket and
  asyncio WebSocket connections (it was None)

Signed-off-by: Leon Anavi <leon.anavi@konsulko.com>
Signed-off-by: Khem Raj <khem.raj@oss.qualcomm.com>
2026-10-23 10:48:01 -07:00
Leon Anavi c7c5a067e3 python3-autobahn: Upgrade 26.7.1 -> 26.10.1
Upgrade to release 26.10.1:

General

- Load the vendored FlatBuffers runtime only when a FlatBuffers
  message is first built or parsed, instead of on every import
  autobahn. The runtime imports numpy whenever numpy is installed,
  so up to 26.7.1 every process importing autobahn also loaded numpy,
  including WebSocket-only users such as Django Channels applications
  served by Daphne. Every autobahn import now needs about 13-17 MB
  less memory on CPython and 18-24 MB less on PyPy, and none loads
  numpy. A new documentation page (docs/memory-footprint.rst, just
  memory-footprint) shows the import memory footprint per release on
  CPython and PyPy.

Wheels

- Publish native Windows ARM64 (win_arm64) wheels with NVX for
  CPython 3.11-3.14, built on GitHub’s windows-11-arm runners (PyPy
  publishes no Windows ARM64 interpreter); thanks to @ndabas.
  cryptography currently publishes no win_arm64 wheel, so the build
  compiles it against an OpenSSL from vcpkg.

- Build cryptography against an OpenSSL from vcpkg on Windows x86_64
  too: cryptography 50.0.2 publishes its Windows PyPy wheels for PyPy
  8 (pp80) only, and the pypy311 wheel build uses PyPy 7.3 (pp73), so
  pip builds it from source there.

WebSocket

- Make all four per-message compression extensions
  (permessage-deflate, -bzip2, -brotli, -snappy) enforce the
  decompression budget the same way: decompression stops near the
  remaining maxMessagePayloadSize budget instead of decompressing a
  whole frame first, and “over budget” as well as “budget already
  used up” raise PayloadExceededError. brotli now bounds its output
  with Decompressor.process(output_buffer_limit=...), snappy is
  decompressed one framing chunk at a time, and deflate no longer
  lets one octet through once the budget is used up.

- Add autobahn.exception.PayloadCorruptError: every compression
  extension now raises it for input it cannot decompress (corrupt,
  truncated, or not the extension’s format), instead of the library’s
  own exception (zlib.error, OSError, brotli.error, …), and snappy no
  longer accepts such input silently. The protocol fails the
  connection with close code 1007 (invalid frame payload data), the
  same for every extension and on both Twisted and asyncio.

- Fix permessage-brotli failing on the second message of a connection
  when context takeover was negotiated (the default): the compressor
  and decompressor were reused after their brotli stream had
  finished. Each message is now a new brotli stream, which is the
  wire format brotli used for the first message already, and for no
  context takeover.

- Fix an asyncio WebSocket connection being left open, but no longer
  serviced, when an exception escaped the processing of received
  data: the connection is now dropped, as on Twisted.

- Add a documentation page on WebSocket compression
  (docs/websocket/compression.rst): for each of the four extensions,
  which Python package and which compression library (and bundled
  version) it uses on CPython and on PyPy, plus context takeover,
  decompression limits and the handling of invalid data. The old,
  unpublished page under docs/work/ did not cover permessage-brotli

Signed-off-by: Leon Anavi <leon.anavi@konsulko.com>
Signed-off-by: Khem Raj <khem.raj@oss.qualcomm.com>
2026-10-19 15:08:22 -07:00
Leon Anavi a49b5106a1 python3-autobahn: Upgrade 26.6.1 -> 26.7.1
Upgrade to release 26.7.1:

- Fix WebSocket maxMessagePayloadSize being enforced against the
  compressed on-the-wire frame length instead of the uncompressed
  reassembled message size when permessage-compress
  (deflate/bzip2/snappy/brotli) is negotiated. A small compressed
  frame could inflate far beyond the configured limit and be
  delivered to the application (a decompression-bomb style
  denial-of-service; security advisory GHSA-hxp9-w8x3-p566, same
  class as CVE-2016-10544). The limit is now re-checked at the
  inflation site against the running uncompressed message size,
  and the connection is failed with close code 1009 (message too
  big) before delivery - for both the whole-message and streaming
  receive APIs and every compression backend. Behaviour change:
  a compressed message that inflates past maxMessagePayloadSize
  is now rejected where it previously passed; uncompressed traffic
  and the per-frame maxFramePayloadSize wire guard are unaffected
- Fix the permessage-deflate max_message_size receive cap silently
  truncating an over-limit message and raising a zlib error instead
  of cleanly rejecting it: the bounded decompress(..., max_length)
  left the remaining input in unconsumed_tail undrained, so the
  message was corrupted rather than reported. Decompression is now
  bounded cumulatively across frames and raises
  PayloadExceededError as soon as the uncompressed size would
  exceed the cap
- Make bounded decompression backend-agnostic:
  decompress_message_data() gains an optional max_output_len
  argument (documented on the PerMessageCompress base class) and
  every permessage-compress backend now honours it. deflate and
  bzip2 stop inflating once the limit is reached (native
  incremental cap); snappy and brotli, whose libraries expose no
  output-length argument, inflate the frame (already bounded on
  the wire by maxFramePayloadSize) and then reject - a weaker but
  still clean per-frame guarantee. The WebSocket receive path
  passes the remaining maxMessagePayloadSize budget so a
  compressed frame no longer expands unbounded into memory before
  the size check; the previous post-inflation check remains as a
  backstop. Previously only deflate had any decompressed-output
  cap, so a snappy/bzip2/brotli frame could inflate fully into
  memory first
- Make the asyncio RawSocket receive size limit configurable, at
  parity with the Twisted backend. The asyncio
  WampRawSocketFactory now exposes
  setProtocolOptions(maxMessagePayloadSize=...) /
  resetProtocolOptions() (bounds [512, 2**24], default 16 MB), and
  the configured value drives both the advertised handshake length
  exponent and the enforced receive cap (rounded up to the next
  power of two), matching the Twisted factory. Previously the
  asyncio receive limit was hardwired to 16 MB (a dead
  max_size=None branch), so an asyncio WAMP peer could not tighten
  its RawSocket receive limit for DoS hardening and Crossbar's
  RawSocket max_message_size had no effect on the asyncio path

Signed-off-by: Leon Anavi <leon.anavi@konsulko.com>
Signed-off-by: Khem Raj <khem.raj@oss.qualcomm.com>
2026-07-20 23:08:10 -07:00