Version in base suite: 0.37.0-6 Base version: qpid-proton_0.37.0-6 Target version: qpid-proton_0.37.0-6+deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/q/qpid-proton/qpid-proton_0.37.0-6.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/q/qpid-proton/qpid-proton_0.37.0-6+deb13u1.dsc changelog | 29 + control | 1 patches/CVE-2026-105031_Make-pn_ssl_domain_set_trusted_ca_db-replace-the-.patch | 225 ++++++++++ patches/CVE-2026-105042_Limit-the-AMQP-decoder-nesting-depth.patch | 150 ++++++ patches/CVE-2026-114230_Validate-the-SASL-state-before-handling-a-frame.patch | 59 ++ patches/CVE-2026-115942_Bound-wildcard-pattern-match-in-match_dns_pattern.patch | 34 + patches/series | 4 7 files changed, 502 insertions(+) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp8b9m0lml/qpid-proton_0.37.0-6.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp8b9m0lml/qpid-proton_0.37.0-6+deb13u1.dsc: no acceptable signature found diff -Nru qpid-proton-0.37.0/debian/changelog qpid-proton-0.37.0/debian/changelog --- qpid-proton-0.37.0/debian/changelog 2025-02-26 13:19:48.000000000 +0000 +++ qpid-proton-0.37.0/debian/changelog 2026-11-10 15:08:41.000000000 +0000 @@ -1,3 +1,32 @@ +qpid-proton (0.37.0-6+deb13u1) trixie; urgency=medium + + * CVE-2026-105031: the OpenSSL TLS implementation added to rather + than replaced the default system trust anchors, potentially + trusting unexpected peer certificates. Applied upstream patch + "PROTON-2976: Make pn_ssl_domain_set_trusted_ca_db replace the + default CAs": + - CVE-2026-105031_Make-pn_ssl_domain_set_trusted_ca_db-replace-the-.patch + * CVE-2026-105042: a deeply nested message body decoded by + pn_message_body() could overflow the stack and crash the + application. Applied a minimal fix bounding the decoder nesting + depth (upstream reworked the decoder in 0.41.1): + - CVE-2026-105042_Limit-the-AMQP-decoder-nesting-depth.patch + * CVE-2026-114230: SASL frame dispatch also dispatched AMQP frames + claiming to be SASL frames, allowing authentication bypass. + Applied upstream patch "PROTON-2970: Validate the SASL state + before handling a frame": + - CVE-2026-114230_Validate-the-SASL-state-before-handling-a-fra....patch + * CVE-2026-115942: a misconfigured wildcard TLS certificate causes a + stack read overflow. Applied a minimal fix rejecting wildcard + patterns that cannot match without reading out of bounds (upstream + enforces RFC 9525 through a full rework in 0.41.1): + - CVE-2026-115942_Bound-wildcard-pattern-match-in-match_dns_pattern.patch + (Closes: #1152779) + * debian/control: Add python3-setuptools to Build-Depends, for the + distutils shim needed by the CMake Python detection with Python 3.13. + + -- Thomas Goirand Tue, 10 Nov 2026 16:08:41 +0100 + qpid-proton (0.37.0-6) unstable; urgency=medium * Rebuild to remove python 3.12 support. diff -Nru qpid-proton-0.37.0/debian/control qpid-proton-0.37.0/debian/control --- qpid-proton-0.37.0/debian/control 2025-02-26 13:19:48.000000000 +0000 +++ qpid-proton-0.37.0/debian/control 2026-11-10 15:08:41.000000000 +0000 @@ -14,6 +14,7 @@ pkgconf, python3-all, python3-all-dev, + python3-setuptools, python3-sphinx, swig, uuid-dev, diff -Nru qpid-proton-0.37.0/debian/patches/CVE-2026-105031_Make-pn_ssl_domain_set_trusted_ca_db-replace-the-.patch qpid-proton-0.37.0/debian/patches/CVE-2026-105031_Make-pn_ssl_domain_set_trusted_ca_db-replace-the-.patch --- qpid-proton-0.37.0/debian/patches/CVE-2026-105031_Make-pn_ssl_domain_set_trusted_ca_db-replace-the-.patch 1970-01-01 00:00:00.000000000 +0000 +++ qpid-proton-0.37.0/debian/patches/CVE-2026-105031_Make-pn_ssl_domain_set_trusted_ca_db-replace-the-.patch 2026-11-10 15:08:41.000000000 +0000 @@ -0,0 +1,225 @@ +Description: Make pn_ssl_domain_set_trusted_ca_db replace the default CAs + When using the OpenSSL TLS implementation, both the + pn_ssl_domain_set_trusted_ca_db() & pn_tls_config_set_trusted_certs() + APIs added to rather than replaced the default system trust anchors, + leading to potentially trusting unexpected peer certificates: the + context now gets a fresh certificate store instead of loading into + the one holding the system defaults. + . + Fixes CVE-2026-105031. +Author: Andrew Stitcher +Date: Mon, 28 Sep 2026 21:20:01 -0400 +Origin: upstream, https://github.com/apache/qpid-proton/commit/d793f97e4a2d0f960eda32724a2e867236468337 +Last-Update: 2026-11-10 + +Index: qpid-proton/c/include/proton/ssl.h +=================================================================== +--- qpid-proton.orig/c/include/proton/ssl.h ++++ qpid-proton/c/include/proton/ssl.h +@@ -174,6 +174,11 @@ PN_EXTERN int pn_ssl_domain_set_credent + * will depend on how the OS is set up. When using the Windows SChannel implementation the default + * will be the users default trusted certificate store. + * ++ * @note The database given here replaces that default rather than adding to it, so after ++ * this call the certificates named here are the only trust anchors the domain will accept. ++ * Repeating the call replaces the database again; to trust more than one CA, name a ++ * directory or a file holding all of them. ++ * + * @param[in] domain the ssl domain that will use the database. + * @param[in] certificate_db database of trusted CAs, used to authenticate the peer. + * @return 0 on success +Index: qpid-proton/c/include/proton/tls.h +=================================================================== +--- qpid-proton.orig/c/include/proton/tls.h ++++ qpid-proton/c/include/proton/tls.h +@@ -170,6 +170,11 @@ PN_TLS_EXTERN int pn_tls_config_set_cre + * will depend on how the OS is set up. When using the Windows SChannel implementation the default + * will be the users default trusted certificate store. + * ++ * @note The database given here replaces that default rather than adding to it, so after ++ * this call the certificates named here are the only trust anchors the domain will accept. ++ * Repeating the call replaces the database again; to trust more than one CA, name a ++ * directory or a file holding all of them. ++ * + * @param[in] domain the tls domain that will use the database. + * @param[in] certificate_db database of trusted CAs, used to authenticate the peer. + * @return 0 on success +Index: qpid-proton/c/src/ssl/openssl.c +=================================================================== +--- qpid-proton.orig/c/src/ssl/openssl.c ++++ qpid-proton/c/src/ssl/openssl.c +@@ -716,11 +716,28 @@ int pn_ssl_domain_set_trusted_ca_db(pn_s + file = certificate_db; + } + +- if (SSL_CTX_load_verify_locations( domain->ctx, file, dir ) != 1) { +- ssl_log_error("SSL_CTX_load_verify_locations( %s ) failed", certificate_db); ++ /* Replace the context's store rather than loading into it: the store already holds the ++ system default certificates, installed when the domain was created, and the documented ++ contract is that naming a database overrides that default rather than adding to it. ++ Loading into the existing store would leave every system CA a trust anchor, so a peer ++ holding any publicly issued certificate would verify against a domain configured to ++ trust one private CA. SSL_CTX_set_cert_store() takes ownership and frees the old ++ store. */ ++ X509_STORE *store = X509_STORE_new(); ++ if (!store) { ++ ssl_log_error("Unable to allocate certificate store"); + return -1; + } ++ // Support intermediate/subordinate CAs as trust anchors, as the replaced store did. ++ X509_STORE_set_flags(store, X509_V_FLAG_PARTIAL_CHAIN); + ++ if (X509_STORE_load_locations( store, file, dir ) != 1) { ++ ssl_log_error("X509_STORE_load_locations( %s ) failed", certificate_db); ++ X509_STORE_free(store); ++ return -1; ++ } ++ ++ SSL_CTX_set_cert_store( domain->ctx, store ); + return 0; + } + +Index: qpid-proton/c/src/tls/openssl.c +=================================================================== +--- qpid-proton.orig/c/src/tls/openssl.c ++++ qpid-proton/c/src/tls/openssl.c +@@ -971,11 +971,28 @@ int pn_tls_config_set_trusted_certs(pn_t + file = certificate_db; + } + +- if (SSL_CTX_load_verify_locations( domain->ctx, file, dir ) != 1) { +- ssl_log_error("SSL_CTX_load_verify_locations( %s ) failed", certificate_db); ++ /* Replace the context's store rather than loading into it: the store already holds the ++ system default certificates, installed when the domain was created, and the documented ++ contract is that naming a database overrides that default rather than adding to it. ++ Loading into the existing store would leave every system CA a trust anchor, so a peer ++ holding any publicly issued certificate would verify against a domain configured to ++ trust one private CA. SSL_CTX_set_cert_store() takes ownership and frees the old ++ store. */ ++ X509_STORE *store = X509_STORE_new(); ++ if (!store) { ++ ssl_log_error("Unable to allocate certificate store"); + return -1; + } ++ // Support intermediate/subordinate CAs as trust anchors, as the replaced store did. ++ X509_STORE_set_flags(store, X509_V_FLAG_PARTIAL_CHAIN); + ++ if (X509_STORE_load_locations( store, file, dir ) != 1) { ++ ssl_log_error("X509_STORE_load_locations( %s ) failed", certificate_db); ++ X509_STORE_free(store); ++ return -1; ++ } ++ ++ SSL_CTX_set_cert_store( domain->ctx, store ); + return 0; + } + +Index: qpid-proton/python/tests/proton_tests/ssl.py +=================================================================== +--- qpid-proton.orig/python/tests/proton_tests/ssl.py ++++ qpid-proton/python/tests/proton_tests/ssl.py +@@ -231,6 +231,104 @@ class SslTest(common.Test): + server.connection.close() + self._pump(client, server) + ++ def _system_ca_domains(self, system_ca): ++ """ Build a fresh client/server domain pair with the system default trust store ++ pointed at system_ca. ++ ++ OpenSSL reads SSL_CERT_FILE when the domain installs the system defaults, so the ++ variable has to be in place before the domains are constructed - hence the fresh ++ pair rather than the ones setUp() made. SChannel takes its default from the ++ Windows certificate store and ignores the variable. ++ """ ++ old = os.environ.get("SSL_CERT_FILE") ++ os.environ["SSL_CERT_FILE"] = system_ca ++ try: ++ return (SSLDomain(SSLDomain.MODE_SERVER), SSLDomain(SSLDomain.MODE_CLIENT)) ++ finally: ++ if old is None: ++ del os.environ["SSL_CERT_FILE"] ++ else: ++ os.environ["SSL_CERT_FILE"] = old ++ ++ def test_trusted_ca_db_replaces_system_default(self): ++ """ A configured CA database overrides the system default rather than adding to it. ++ ++ Without this the system store stays in the trust set, so a certificate issued by ++ any CA the machine happens to trust verifies against a domain configured to trust ++ one private CA. bad-server is self-signed, so treating it as a system root makes ++ it exactly such a certificate. ++ """ ++ if os.name == "nt": ++ raise Skipped("Windows SChannel does not use SSL_CERT_FILE.") ++ server_domain, client_domain = self._system_ca_domains( ++ self._testpath("bad-server-certificate.pem")) ++ ++ server_domain.set_credentials(self._testpath("bad-server-certificate.pem"), ++ self._testpath("bad-server-private-key.pem"), ++ "server-password") ++ client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) ++ client_domain.set_peer_authentication(SSLDomain.VERIFY_PEER) ++ ++ server = SslTest.SslTestConnection(server_domain, mode=Transport.SERVER) ++ client = SslTest.SslTestConnection(client_domain) ++ ++ client.connection.open() ++ server.connection.open() ++ self._pump(client, server) ++ ++ assert client.transport.closed ++ assert server.transport.closed ++ assert client.connection.state & Endpoint.REMOTE_UNINIT ++ assert server.connection.state & Endpoint.REMOTE_UNINIT ++ ++ def test_system_default_ca_db_used_when_unconfigured(self): ++ """ With no CA database configured the system default is still the trust set. ++ """ ++ if os.name == "nt": ++ raise Skipped("Windows SChannel does not use SSL_CERT_FILE.") ++ server_domain, client_domain = self._system_ca_domains( ++ self._testpath("bad-server-certificate.pem")) ++ ++ server_domain.set_credentials(self._testpath("bad-server-certificate.pem"), ++ self._testpath("bad-server-private-key.pem"), ++ "server-password") ++ client_domain.set_peer_authentication(SSLDomain.VERIFY_PEER) ++ ++ server = SslTest.SslTestConnection(server_domain, mode=Transport.SERVER) ++ client = SslTest.SslTestConnection(client_domain) ++ ++ client.connection.open() ++ server.connection.open() ++ self._pump(client, server) ++ assert client.ssl.protocol_name() is not None ++ client.connection.close() ++ server.connection.close() ++ self._pump(client, server) ++ ++ def test_intermediate_ca(self): ++ """ Ensure an intermediate/subordinate certificate can be used as a CA for validation. ++ """ ++ if os.name == "nt": ++ raise Skipped("Test of OpenSSL X509_V_FLAG_PARTIAL_CHAIN flag.") ++ self.server_domain.set_credentials(self._testpath("server-certificate-ca2.pem"), ++ self._testpath("server-private-key-ca2.pem"), ++ "server-password") ++ ++ self.client_domain.set_trusted_ca_db(self._testpath("subca-certificate.pem")) ++ self.client_domain.set_peer_authentication(SSLDomain.VERIFY_PEER) ++ ++ server = SslTest.SslTestConnection(self.server_domain, mode=Transport.SERVER) ++ client = SslTest.SslTestConnection(self.client_domain) ++ ++ client.connection.open() ++ server.connection.open() ++ self._pump(client, server) ++ assert client.ssl.get_cert_subject() is not None ++ assert client.transport.condition is None ++ client.connection.close() ++ server.connection.close() ++ self._pump(client, server) ++ + def test_certificate_fingerprint_and_subfields(self): + if os.name == "nt": + raise Skipped("Windows support for certificate fingerprint and subfield not implemented yet") diff -Nru qpid-proton-0.37.0/debian/patches/CVE-2026-105042_Limit-the-AMQP-decoder-nesting-depth.patch qpid-proton-0.37.0/debian/patches/CVE-2026-105042_Limit-the-AMQP-decoder-nesting-depth.patch --- qpid-proton-0.37.0/debian/patches/CVE-2026-105042_Limit-the-AMQP-decoder-nesting-depth.patch 1970-01-01 00:00:00.000000000 +0000 +++ qpid-proton-0.37.0/debian/patches/CVE-2026-105042_Limit-the-AMQP-decoder-nesting-depth.patch 2026-11-10 15:08:41.000000000 +0000 @@ -0,0 +1,150 @@ +Description: Limit the AMQP decoder nesting depth + A message body that is deeply nested and decoded by pn_message_body() + could overflow the stack and cause a crash: every container or + described level of the AMQP encoding consumes a C stack frame, so a + crafted message nested a few thousands of times, encoded with a few + bytes per level, is enough. The decoder now refuses to descend past + PN_DECODER_MAX_DEPTH (1000) levels and reports PN_ARG_ERR instead. + . + Fixes CVE-2026-105042. + . + Upstream reworked the decoder to be iterative rather than recursive + in 0.41.1 (PROTON-2967), which is not practical to backport to the + 0.37.x branch; this is the minimal equivalent fix. +Author: Thomas Goirand +Date: Mon, 10 Nov 2026 17:00:00 +0100 +Forwarded: no +Assisted-By: Infomaniak Euria-Code +Last-Update: 2026-11-10 + +Index: qpid-proton/c/src/core/decoder.c +=================================================================== +--- qpid-proton.orig/c/src/core/decoder.c ++++ qpid-proton/c/src/core/decoder.c +@@ -39,6 +39,7 @@ void pn_decoder_initialize(pn_decoder_t + decoder->size = 0; + decoder->position = NULL; + decoder->error = NULL; ++ decoder->depth = 0; + } + + void pn_decoder_finalize(pn_decoder_t *decoder) +@@ -179,10 +180,14 @@ static inline pn_type_t pn_code2type(uin + + static int pni_decoder_decode_type(pn_decoder_t *decoder, pn_data_t *data, uint8_t *code); + static int pni_decoder_single_described(pn_decoder_t *decoder, pn_data_t *data); ++static int pni_decoder_decode_value(pn_decoder_t *decoder, pn_data_t *data, uint8_t code); + static int pni_decoder_single(pn_decoder_t *decoder, pn_data_t *data); ++static int pni_decoder_decode_value_inner(pn_decoder_t *decoder, pn_data_t *data, uint8_t code); ++static int pni_decoder_single_described_inner(pn_decoder_t *decoder, pn_data_t *data); ++static int pni_decoder_single_inner(pn_decoder_t *decoder, pn_data_t *data); + void pni_data_set_array_type(pn_data_t *data, pn_type_t type); + +-static int pni_decoder_decode_value(pn_decoder_t *decoder, pn_data_t *data, uint8_t code) ++static int pni_decoder_decode_value_inner(pn_decoder_t *decoder, pn_data_t *data, uint8_t code) + { + int err; + conv_t conv; +@@ -485,7 +490,7 @@ static inline bool pni_allowed_descripto + code != PNE_MAP8 && code != PNE_MAP32; + } + +-int pni_decoder_single_described(pn_decoder_t *decoder, pn_data_t *data) ++static int pni_decoder_single_described_inner(pn_decoder_t *decoder, pn_data_t *data) + { + if (!pn_decoder_remaining(decoder)) { + return PN_UNDERFLOW; +@@ -506,7 +511,7 @@ int pni_decoder_single_described(pn_deco + return 0; + } + +-int pni_decoder_single(pn_decoder_t *decoder, pn_data_t *data) ++static int pni_decoder_single_inner(pn_decoder_t *decoder, pn_data_t *data) + { + uint8_t code; + int err = pni_decoder_decode_type(decoder, data, &code); +@@ -524,12 +529,61 @@ ssize_t pn_decoder_decode(pn_decoder_t * + decoder->input = src; + decoder->size = size; + decoder->position = src; ++ decoder->depth = 0; + + int err = pni_decoder_single(decoder, dst); + +- if (err == PN_UNDERFLOW) ++ if (err == PN_UNDERFLOW) + return pn_error_format(pn_data_error(dst), PN_UNDERFLOW, "not enough data to decode"); + if (err) return err; + + return decoder->position - decoder->input; + } ++ ++/* Recursion guards: an AMQP value nests containers and described values, ++ * and every level of nesting consumes a C stack frame. A crafted message ++ * can nest thousands of levels from a few bytes each, overflowing the ++ * stack (CVE-2026-105042). Every recursive entry goes through one of ++ * these wrappers, which refuse to descend past PN_DECODER_MAX_DEPTH. ++ * Upstream reworked the decoder to be iterative in 0.41.1 (PROTON-2967); ++ * this is the minimal fix for the 0.37.x branch. ++ */ ++ ++static int pni_decoder_decode_value(pn_decoder_t *decoder, pn_data_t *data, uint8_t code) ++{ ++ if (decoder->depth >= PN_DECODER_MAX_DEPTH) { ++ return pn_error_format(pn_data_error(data), PN_ARG_ERR, ++ "AMQP value nesting too deep (limit: %d)", ++ PN_DECODER_MAX_DEPTH); ++ } ++ decoder->depth++; ++ int err = pni_decoder_decode_value_inner(decoder, data, code); ++ decoder->depth--; ++ return err; ++} ++ ++static int pni_decoder_single_described(pn_decoder_t *decoder, pn_data_t *data) ++{ ++ if (decoder->depth >= PN_DECODER_MAX_DEPTH) { ++ return pn_error_format(pn_data_error(data), PN_ARG_ERR, ++ "AMQP value nesting too deep (limit: %d)", ++ PN_DECODER_MAX_DEPTH); ++ } ++ decoder->depth++; ++ int err = pni_decoder_single_described_inner(decoder, data); ++ decoder->depth--; ++ return err; ++} ++ ++int pni_decoder_single(pn_decoder_t *decoder, pn_data_t *data) ++{ ++ if (decoder->depth >= PN_DECODER_MAX_DEPTH) { ++ return pn_error_format(pn_data_error(data), PN_ARG_ERR, ++ "AMQP value nesting too deep (limit: %d)", ++ PN_DECODER_MAX_DEPTH); ++ } ++ decoder->depth++; ++ int err = pni_decoder_single_inner(decoder, data); ++ decoder->depth--; ++ return err; ++} +Index: qpid-proton/c/src/core/decoder.h +=================================================================== +--- qpid-proton.orig/c/src/core/decoder.h ++++ qpid-proton/c/src/core/decoder.h +@@ -22,11 +22,17 @@ + * + */ + ++/* Maximum AMQP nesting depth accepted by the decoder: every container or ++ described level recurses, so a deep enough message would overflow the ++ C stack (CVE-2026-105042). */ ++#define PN_DECODER_MAX_DEPTH 1000 ++ + typedef struct pn_decoder_t { + const char *input; + size_t size; + const char *position; + pn_error_t *error; ++ int depth; + } pn_decoder_t; + + void pn_decoder_initialize(pn_decoder_t *decoder); diff -Nru qpid-proton-0.37.0/debian/patches/CVE-2026-114230_Validate-the-SASL-state-before-handling-a-frame.patch qpid-proton-0.37.0/debian/patches/CVE-2026-114230_Validate-the-SASL-state-before-handling-a-frame.patch --- qpid-proton-0.37.0/debian/patches/CVE-2026-114230_Validate-the-SASL-state-before-handling-a-frame.patch 1970-01-01 00:00:00.000000000 +0000 +++ qpid-proton-0.37.0/debian/patches/CVE-2026-114230_Validate-the-SASL-state-before-handling-a-frame.patch 2026-11-10 15:08:41.000000000 +0000 @@ -0,0 +1,59 @@ +Description: Validate the SASL state before handling a frame + When dispatching SASL frames to authenticate the peer, Proton would + also dispatch AMQP frames if they claimed to be SASL frames. This + allows authentication bypass: the frames are now rejected unless the + SASL layer is in the state expecting them. + . + Fixes CVE-2026-114230. +Author: Andrew Stitcher +Date: Mon, 24 Aug 2026 21:43:15 -0400 +Origin: upstream, https://github.com/apache/qpid-proton/commit/0ec4d39707285d12608e6597671747c541ba245d +Last-Update: 2026-11-10 + +diff --git a/c/src/sasl/sasl.c b/c/src/sasl/sasl.c +index 1fc16a9d..5467781f 100644 +--- a/c/src/sasl/sasl.c ++++ b/c/src/sasl/sasl.c +@@ -898,6 +898,10 @@ int pn_do_init(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, + + // We should only receive this if we are a sasl server + if (sasl->client) return PN_ERR; ++ // Check the protocol state using desired_state not last_state: a pipelining peer can ++ // legitimately send its next frame before we've actually written out our own, so ++ // last_state can still be lagging behind the frame we've already committed to sending. ++ if (sasl->desired_state != SASL_POSTED_MECHANISMS) return PN_ERR; + + pn_bytes_t mech; + pn_bytes_t recv; +@@ -930,6 +934,7 @@ int pn_do_mechanisms(pn_transport_t *transport, uint8_t frame_type, uint16_t cha + + // We should only receive this if we are a sasl client + if (!sasl->client) return PN_ERR; ++ if (sasl->desired_state != SASL_NONE) return PN_ERR; + + pn_string_t *mechs = pn_string(""); + +@@ -998,6 +1003,7 @@ int pn_do_challenge(pn_transport_t *transport, uint8_t frame_type, uint16_t chan + + // We should only receive this if we are a sasl client + if (!sasl->client) return PN_ERR; ++ if (sasl->desired_state != SASL_POSTED_INIT && sasl->desired_state != SASL_POSTED_RESPONSE) return PN_ERR; + + pn_bytes_t recv; + +@@ -1019,6 +1025,7 @@ int pn_do_response(pn_transport_t *transport, uint8_t frame_type, uint16_t chann + + // We should only receive this if we are a sasl server + if (sasl->client) return PN_ERR; ++ if (sasl->desired_state != SASL_POSTED_CHALLENGE) return PN_ERR; + + pn_bytes_t recv; + +@@ -1040,6 +1047,7 @@ int pn_do_outcome(pn_transport_t *transport, uint8_t frame_type, uint16_t channe + + // We should only receive this if we are a sasl client + if (!sasl->client) return PN_ERR; ++ if (sasl->desired_state != SASL_POSTED_INIT && sasl->desired_state != SASL_POSTED_RESPONSE) return PN_ERR; + + uint8_t outcome; + pn_bytes_t recv; diff -Nru qpid-proton-0.37.0/debian/patches/CVE-2026-115942_Bound-wildcard-pattern-match-in-match_dns_pattern.patch qpid-proton-0.37.0/debian/patches/CVE-2026-115942_Bound-wildcard-pattern-match-in-match_dns_pattern.patch --- qpid-proton-0.37.0/debian/patches/CVE-2026-115942_Bound-wildcard-pattern-match-in-match_dns_pattern.patch 1970-01-01 00:00:00.000000000 +0000 +++ qpid-proton-0.37.0/debian/patches/CVE-2026-115942_Bound-wildcard-pattern-match-in-match_dns_pattern.patch 2026-11-10 15:08:41.000000000 +0000 @@ -0,0 +1,34 @@ +Description: Bound the wildcard pattern match against the subject label + A misconfigured wildcard TLS certificate causes a stack read overflow: + when the fixed prefix and suffix of a wildcard DNS pattern are longer + than the label of the host name being verified, the suffix comparison + reads before the start of the subject label buffer. Such a pattern can + never match, so it is now rejected before any out of bounds read. + . + Fixes CVE-2026-115942. + . + Upstream 0.41.1 reworked the whole host name verification on top of + X509_VERIFY_PARAM, enforcing RFC 9525 (PROTON-2974), which is not + practical to backport to the 0.37.x branch; this is the minimal + equivalent fix for the stack read overflow. +Author: Thomas Goirand +Date: Mon, 10 Nov 2026 17:00:00 +0100 +Forwarded: no +Assisted-By: Infomaniak Euria-Code +Last-Update: 2026-11-10 + +Index: qpid-proton/c/src/ssl/openssl.c +=================================================================== +--- qpid-proton.orig/c/src/ssl/openssl.c ++++ qpid-proton/c/src/ssl/openssl.c +@@ -260,6 +260,10 @@ static bool match_dns_pattern( const cha + char *suffix = star + 1; + int suffix_len = strlen(suffix); + if (prefix_len && pn_strncasecmp( prefix, slabel, prefix_len )) return false; ++ /* A wildcard pattern whose fixed parts cannot fit in the subject ++ label can never match, and trying to would read outside of the ++ subject label buffer (CVE-2026-115942). */ ++ if (prefix_len + suffix_len > (int) strlen(slabel)) return false; + if (suffix_len && pn_strncasecmp( suffix, + slabel + (strlen(slabel) - suffix_len), + suffix_len )) return false; diff -Nru qpid-proton-0.37.0/debian/patches/series qpid-proton-0.37.0/debian/patches/series --- qpid-proton-0.37.0/debian/patches/series 2025-02-26 13:19:48.000000000 +0000 +++ qpid-proton-0.37.0/debian/patches/series 2026-11-10 15:08:41.000000000 +0000 @@ -1,3 +1,7 @@ remove-cgi continue-building-with-deprecated-declarations.patch 0002-Drop-old-FindPython.cmake.patch +CVE-2026-105031_Make-pn_ssl_domain_set_trusted_ca_db-replace-the-.patch +CVE-2026-105042_Limit-the-AMQP-decoder-nesting-depth.patch +CVE-2026-114230_Validate-the-SASL-state-before-handling-a-frame.patch +CVE-2026-115942_Bound-wildcard-pattern-match-in-match_dns_pattern.patch