[Pkg-swan-devel] [Git][debian/strongswan][debian/trixie] 9 commits: d/patches: add fix for integer underflow in libsimaka when handling...
Yves-Alexis Perez (@corsac)
gitlab at salsa.debian.org
Sun Apr 26 10:11:09 BST 2026
Yves-Alexis Perez pushed to branch debian/trixie at Debian / strongswan
Commits:
bdced378 by Yves-Alexis Perez at 2026-04-09T09:28:06+02:00
d/patches: add fix for integer underflow in libsimaka when handling EAP-SIM/AKA attributes (CVE-2026-35330)
- - - - -
fbacb95d by Yves-Alexis Perez at 2026-04-09T09:28:21+02:00
d/patches: add fix for integer underflow in libradius when handling RADIUS attributes (CVE-2026-35333)
- - - - -
a5889600 by Yves-Alexis Perez at 2026-04-09T09:28:37+02:00
d/patches: add fix for NULL-pointer dereference in libtls when handling ECDH public values (CVE-2026-35332)
- - - - -
33e02ade by Yves-Alexis Perez at 2026-04-09T09:28:53+02:00
d/patches: add fix for infinite loop in libtls when handling supported versions TLS extension (CVE-2026-35328)
- - - - -
3c394532 by Yves-Alexis Perez at 2026-04-09T09:29:05+02:00
d/patches: add fix for NULL-pointer dereference in libstrongswan (pkcs5) and the pkcs7 plugin when processing padding in PKCS#7 (CVE-2026-35329)
- - - - -
06f81dde by Yves-Alexis Perez at 2026-04-09T09:29:20+02:00
d/patches: add fix for acceptation of authentication certificates violating name constraints (CVE-2026-35331)
- - - - -
fba2dc0c by Yves-Alexis Perez at 2026-04-09T09:29:48+02:00
d/patches: add fix for possible NULL-pointer dereference in gmp plugin for RSA decryption (CVE-2026-35334)
- - - - -
1f9f1cd0 by Yves-Alexis Perez at 2026-04-09T09:36:22+02:00
finalize changelog
- - - - -
a53ad826 by Yves-Alexis Perez at 2026-04-09T09:36:44+02:00
upload strongSwan 6.0.1-6+deb13u5 to trixie-security
- - - - -
9 changed files:
- debian/changelog
- + debian/patches/0010-libsimaka-Reject-zero-length-EAP-SIM-AKA-attributes.patch
- + debian/patches/0011-libradius-Reject-undersized-attributes-in-enumerator.patch
- + debian/patches/0012-tls-server-Only-accept-non-empty-ECDH-public-keys-wi.patch
- + debian/patches/0013-tls-server-Prevent-infinite-loop-if-supported-versio.patch
- + debian/patches/0014-pkcs5-pkcs7-Avoid-NULL-pointer-dereference-when-veri.patch
- + debian/patches/0015-constraints-Case-insensitive-matching-and-reject-exc.patch
- + debian/patches/0016-gmp-Avoid-crash-and-timing-leaks-in-PKCS-1-v1.5-decr.patch
- debian/patches/series
Changes:
=====================================
debian/changelog
=====================================
@@ -1,3 +1,22 @@
+strongswan (6.0.1-6+deb13u5) trixie-security; urgency=medium
+
+ * d/patches: add fix for integer underflow in libsimaka when handling
+ EAP-SIM/AKA attributes (CVE-2026-35330)
+ * d/patches: add fix for integer underflow in libradius when handling RADIUS
+ attributes (CVE-2026-35333)
+ * d/patches: add fix for NULL-pointer dereference in libtls when handling
+ ECDH public values (CVE-2026-35332)
+ * d/patches: add fix for infinite loop in libtls when handling supported
+ versions TLS extension (CVE-2026-35328)
+ * d/patches: add fix for NULL-pointer dereference in libstrongswan (pkcs5)
+ and the pkcs7 plugin when processing padding in PKCS#7 (CVE-2026-35329)
+ * d/patches: add fix for acceptation of authentication certificates
+ violating name constraints (CVE-2026-35331)
+ * d/patches: add fix for possible NULL-pointer dereference in gmp plugin for
+ RSA decryption (CVE-2026-35334)
+
+ -- Yves-Alexis Perez <corsac at debian.org> Thu, 09 Apr 2026 09:36:31 +0200
+
strongswan (6.0.1-6+deb13u4) trixie-security; urgency=medium
* d/patch: fix integer overflow in EAP-TTLS plugin (CVE-2026-25075)
=====================================
debian/patches/0010-libsimaka-Reject-zero-length-EAP-SIM-AKA-attributes.patch
=====================================
@@ -0,0 +1,53 @@
+From: =?utf-8?q?Lukas_Johannes_M=C3=B6ller?= <research at johannes-moeller.dev>
+Date: Wed, 11 Mar 2026 16:07:10 +0000
+Subject: libsimaka: Reject zero-length EAP-SIM/AKA attributes
+MIME-Version: 1.0
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: 8bit
+
+parse_attributes() accepts hdr->length == 0 in the AT_ENCR_DATA,
+AT_RAND, AT_PADDING, default branches. The code then subtracts the
+fixed attribute header size from the encoded length, which underflows
+and exposes a wrapped payload length to later code. In particular,
+for the cases where add_attribute() is called, this causes a heap-based
+buffer overflow (a buffer of 12 bytes is allocated to which the wrapped
+length is written). For AT_PADDING, the underflow is irrelevant as
+add_attribute() is not called. Instead, this results in an infinite loop.
+
+Reject zero-length attributes before subtracting the attribute header.
+
+Signed-off-by: Lukas Johannes Möller <research at johannes-moeller.dev>
+
+Fixes: f8330d03953b ("Added a libsimaka library with shared message handling code for EAP-SIM/AKA")
+Fixes: CVE-2026-35330
+---
+ src/libsimaka/simaka_message.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/src/libsimaka/simaka_message.c b/src/libsimaka/simaka_message.c
+index 6706568..4862048 100644
+--- a/src/libsimaka/simaka_message.c
++++ b/src/libsimaka/simaka_message.c
+@@ -416,7 +416,7 @@ static bool parse_attributes(private_simaka_message_t *this, chunk_t in)
+ case AT_ENCR_DATA:
+ case AT_RAND:
+ {
+- if (hdr->length * 4 > in.len || in.len < 4)
++ if (hdr->length == 0 || hdr->length * 4 > in.len || in.len < 4)
+ {
+ return invalid_length(hdr->type);
+ }
+@@ -439,7 +439,7 @@ static bool parse_attributes(private_simaka_message_t *this, chunk_t in)
+ case AT_PADDING:
+ default:
+ {
+- if (hdr->length * 4 > in.len || in.len < 4)
++ if (hdr->length == 0 || hdr->length * 4 > in.len || in.len < 4)
+ {
+ return invalid_length(hdr->type);
+ }
+@@ -932,4 +932,3 @@ simaka_message_t *simaka_message_create(bool request, uint8_t identifier,
+ return simaka_message_create_data(chunk_create((char*)&hdr, sizeof(hdr)),
+ crypto);
+ }
+-
=====================================
debian/patches/0011-libradius-Reject-undersized-attributes-in-enumerator.patch
=====================================
@@ -0,0 +1,40 @@
+From: =?utf-8?q?Lukas_Johannes_M=C3=B6ller?= <research at johannes-moeller.dev>
+Date: Thu, 12 Mar 2026 10:24:45 +0000
+Subject: libradius: Reject undersized attributes in enumerator
+MIME-Version: 1.0
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: 8bit
+
+attribute_enumerate() accepts RADIUS attributes whose length byte is
+smaller than sizeof(rattr_t) (2). For length == 0, the iterator never
+advances and traps callers — including verify() — in a non-advancing
+loop. For length == 1, misaligned packed-struct reads occur.
+
+Add a separate check for this->next->length < sizeof(rattr_t) after
+the existing truncation guard. This mirrors radius_message_parse(),
+which already distinguishes invalid length from truncation.
+
+Signed-off-by: Lukas Johannes Möller <research at johannes-moeller.dev>
+
+Fixes: 4a6b84a93461 ("reintegrated eap-radius branch into trunk")
+Fixes: CVE-2026-35333
+---
+ src/libradius/radius_message.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/src/libradius/radius_message.c b/src/libradius/radius_message.c
+index 8e2db0c..5679e47 100644
+--- a/src/libradius/radius_message.c
++++ b/src/libradius/radius_message.c
+@@ -261,6 +261,11 @@ METHOD(enumerator_t, attribute_enumerate, bool,
+ DBG1(DBG_IKE, "RADIUS message truncated");
+ return FALSE;
+ }
++ if (this->next->length < sizeof(rattr_t))
++ {
++ DBG1(DBG_IKE, "RADIUS attribute has invalid length");
++ return FALSE;
++ }
+ *type = this->next->type;
+ data->ptr = this->next->value;
+ data->len = this->next->length - sizeof(rattr_t);
=====================================
debian/patches/0012-tls-server-Only-accept-non-empty-ECDH-public-keys-wi.patch
=====================================
@@ -0,0 +1,49 @@
+From: Tobias Brunner <tobias at strongswan.org>
+Date: Fri, 20 Mar 2026 17:38:07 +0100
+Subject: tls-server: Only accept non-empty ECDH public keys with TLS < 1.3
+
+This prevents a crash due to a null-pointer dereference when processing
+an empty ECDH public key.
+
+The previous length check only applied in the `!ec` case, so in the `ec`
+case, the access to `pub.ptr[0]` was unguarded. If a crafted TLS
+record ends with an empty ClientKeyExchange, then `read_data8` sets
+`pub` to `chunk_empty`, causing a null-pointer dereference.
+
+Note that if some data follows the empty ClientKeyExchange, this just
+causes a 1-byte out-of-bounds read that has no further effect as the
+TLS session is aborted immediately. Either because the read value
+doesn't equal TLS_ANSI_UNCOMPRESSED or because the empty public key
+is rejected by `set_public_key()`.
+
+The referenced commit that introduced the pointer access, added the
+check for `pub.len` specifically to the `!ec` case, while the pointer
+access was initially unconditional (probably because the code was just
+copied from `tls_peer.c` which processes ECDH public keys in a separate
+function, so there was no `ec` flag). The latter was fixed a couple of
+days later with 7b3c01845f63 ("Read the compression type byte for EC
+groups, only"). However, that commit didn't change the length check.
+Anyway, it's possible that the original intention was to add the check
+to the `ec` case on the previous line, or that there was some confusion
+with the parenthesis and something like the current code was intended to
+begin with.
+
+Fixes: e6cce7ff0d1b ("Prepend point format to ECDH public key")
+Fixes: CVE-2026-35332
+---
+ src/libtls/tls_server.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/libtls/tls_server.c b/src/libtls/tls_server.c
+index 3ad9fd2..1fd3955 100644
+--- a/src/libtls/tls_server.c
++++ b/src/libtls/tls_server.c
+@@ -860,7 +860,7 @@ static status_t process_key_exchange_dhe(private_tls_server_t *this,
+ group = this->dh->get_method(this->dh);
+ ec = key_exchange_is_ecdh(group);
+ if ((ec && !reader->read_data8(reader, &pub)) ||
+- (!ec && (!reader->read_data16(reader, &pub) || pub.len == 0)))
++ (!ec && !reader->read_data16(reader, &pub)) || pub.len == 0)
+ {
+ DBG1(DBG_TLS, "received invalid Client Key Exchange");
+ this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
=====================================
debian/patches/0013-tls-server-Prevent-infinite-loop-if-supported-versio.patch
=====================================
@@ -0,0 +1,41 @@
+From: Tobias Brunner <tobias at strongswan.org>
+Date: Wed, 25 Mar 2026 10:17:46 +0100
+Subject: tls-server: Prevent infinite loop if supported versions are too
+ short
+
+If the extension doesn't contain a multiple of two bytes, the previous
+code would get stuck in an infinite loop as `remaining()` continued to
+return TRUE while `read_uint16()` failed to parse a value. Initiating
+several connections with such an extension allows a DoS attack as no
+threads would eventually be available to handle packets/events.
+
+Fixes: 7fbe2e27ecf6 ("tls-server: TLS 1.3 support for TLS server implementation")
+Fixes: CVE-2026-35328
+---
+ src/libtls/tls_server.c | 11 ++++-------
+ 1 file changed, 4 insertions(+), 7 deletions(-)
+
+diff --git a/src/libtls/tls_server.c b/src/libtls/tls_server.c
+index 1fd3955..bffc01c 100644
+--- a/src/libtls/tls_server.c
++++ b/src/libtls/tls_server.c
+@@ -471,15 +471,12 @@ static status_t process_client_hello(private_tls_server_t *this,
+ bio_reader_t *client_versions;
+
+ client_versions = bio_reader_create(versions);
+- while (client_versions->remaining(client_versions))
++ while (client_versions->read_uint16(client_versions, &version))
+ {
+- if (client_versions->read_uint16(client_versions, &version))
++ if (this->tls->set_version(this->tls, version, version))
+ {
+- if (this->tls->set_version(this->tls, version, version))
+- {
+- this->client_version = version;
+- break;
+- }
++ this->client_version = version;
++ break;
+ }
+ }
+ client_versions->destroy(client_versions);
=====================================
debian/patches/0014-pkcs5-pkcs7-Avoid-NULL-pointer-dereference-when-veri.patch
=====================================
@@ -0,0 +1,56 @@
+From: Tobias Brunner <tobias at strongswan.org>
+Date: Wed, 25 Mar 2026 10:28:45 +0100
+Subject: pkcs5/pkcs7: Avoid NULL pointer dereference when verifying padding
+
+Can be triggered via empty PKCS#7 encrypted- or enveloped-data content
+in IKEv1 CERT payload.
+
+Fixes: 4076e3ee9121 ("Extract PKCS#5 handling from pkcs8 plugin to separate helper class")
+Fixes: d7aa09104f08 ("Implement PKCS#7 enveloped-data parsing and decryption")
+Fixes: CVE-2026-35329
+---
+ src/libstrongswan/crypto/pkcs5.c | 5 +++++
+ src/libstrongswan/plugins/pkcs7/pkcs7_enveloped_data.c | 14 +++++++++++---
+ 2 files changed, 16 insertions(+), 3 deletions(-)
+
+diff --git a/src/libstrongswan/crypto/pkcs5.c b/src/libstrongswan/crypto/pkcs5.c
+index e48a9ad..4851d3f 100644
+--- a/src/libstrongswan/crypto/pkcs5.c
++++ b/src/libstrongswan/crypto/pkcs5.c
+@@ -113,6 +113,11 @@ static bool verify_padding(crypter_t *crypter, chunk_t *blob)
+ {
+ uint8_t padding, count;
+
++ if (!blob->len)
++ {
++ return FALSE;
++ }
++
+ padding = count = blob->ptr[blob->len - 1];
+
+ if (padding > crypter->get_block_size(crypter))
+diff --git a/src/libstrongswan/plugins/pkcs7/pkcs7_enveloped_data.c b/src/libstrongswan/plugins/pkcs7/pkcs7_enveloped_data.c
+index 8b26bad..795d979 100644
+--- a/src/libstrongswan/plugins/pkcs7/pkcs7_enveloped_data.c
++++ b/src/libstrongswan/plugins/pkcs7/pkcs7_enveloped_data.c
+@@ -182,9 +182,17 @@ static bool decrypt(private_key_t *private, chunk_t key, chunk_t iv, int oid,
+ */
+ static bool remove_padding(private_pkcs7_enveloped_data_t *this)
+ {
+- u_char *pos = this->content.ptr + this->content.len - 1;
+- u_char pattern = *pos;
+- size_t padding = pattern;
++ u_char *pos, pattern;
++ size_t padding;
++
++ if (!this->content.len)
++ {
++ return FALSE;
++ }
++
++ pos = this->content.ptr + this->content.len - 1;
++ pattern = *pos;
++ padding = pattern;
+
+ if (padding > this->content.len)
+ {
=====================================
debian/patches/0015-constraints-Case-insensitive-matching-and-reject-exc.patch
=====================================
@@ -0,0 +1,175 @@
+From: Tobias Brunner <tobias at strongswan.org>
+Date: Mon, 23 Mar 2026 17:45:11 +0100
+Subject: constraints: Case-insensitive matching and reject excluded DN name
+ constraints
+
+The case is generally ignored when matching identities. So this is
+an issue with excluded name constraints where a malicious intermediate
+CA could evade the constraints by issuing certificates with names that
+just modify the case (e.g. strongSwan.org instead strongswan.org).
+
+Note that it's likely that permitted name constraints are preferred over
+excluded name constraints as it might be difficult to come up with a
+conclusive list of names to exclude.
+
+With directoryName (DN) name constraints the issue is a bit more comples.
+Some RDNs have to be matched in a case-insensitive manner, which we e.g.
+do in `identification.c::rdn_equals`. By not doing it for name
+constraints, a malicious intermediate CA could evade an excluded name
+constraint just by modifying the case in such an RDN.
+
+While we could use the mentioned function in `dn_matches`, this doesn't
+properly fix the problem because the function is basically too strict.
+Especially in regards to RDNs of type UTF8String, which are only compared
+binary. To match these properly, we'd have to implement the string
+preparation described in RFC 5280, section 7.1 and the referenced RFCs.
+Until that's the case, we reject excluded name constraints of type
+directoryName as we are unable to enforce them.
+
+Fixes: a2b340764fac ("Implemented NameConstraint matching in constraints plugin")
+Fixes: CVE-2026-35331
+---
+ .../plugins/constraints/constraints_validator.c | 28 ++++++++++++++++++----
+ src/libstrongswan/tests/suites/test_certnames.c | 21 +++++++++++-----
+ 2 files changed, 39 insertions(+), 10 deletions(-)
+
+diff --git a/src/libstrongswan/plugins/constraints/constraints_validator.c b/src/libstrongswan/plugins/constraints/constraints_validator.c
+index 51c1057..1f55d11 100644
+--- a/src/libstrongswan/plugins/constraints/constraints_validator.c
++++ b/src/libstrongswan/plugins/constraints/constraints_validator.c
+@@ -55,6 +55,18 @@ static bool check_pathlen(x509_t *issuer, int pathlen)
+ return TRUE;
+ }
+
++/**
++ * Check if the constraint and ID strings match case-insensitively
++ */
++static bool string_matches(chunk_t constraint, chunk_t id)
++{
++ /* make sure the two strings have actually the same length */
++ return constraint.len == id.len &&
++ memchr(constraint.ptr, 0, constraint.len) == NULL &&
++ memchr(id.ptr, 0, id.len) == NULL &&
++ strncasecmp(constraint.ptr, id.ptr, constraint.len) == 0;
++}
++
+ /**
+ * Check if a FQDN constraint matches
+ */
+@@ -70,7 +82,7 @@ static bool fqdn_matches(identification_t *constraint, identification_t *id)
+ return FALSE;
+ }
+ diff = chunk_create(i.ptr, i.len - c.len);
+- if (!chunk_equals(c, chunk_skip(i, diff.len)))
++ if (!string_matches(c, chunk_skip(i, diff.len)))
+ {
+ return FALSE;
+ }
+@@ -101,10 +113,10 @@ static bool email_matches(identification_t *constraint, identification_t *id)
+ }
+ if (memchr(c.ptr, '@', c.len))
+ { /* constraint is a full email address */
+- return chunk_equals(c, i);
++ return string_matches(c, i);
+ }
+ diff = chunk_create(i.ptr, i.len - c.len);
+- if (!chunk_equals(c, chunk_skip(i, diff.len)))
++ if (!string_matches(c, chunk_skip(i, diff.len)))
+ {
+ return FALSE;
+ }
+@@ -389,9 +401,17 @@ static bool collect_constraints(x509_t *x509, bool permitted, hashtable_t **out)
+ type = constraint->get_type(constraint);
+ switch (type)
+ {
++ case ID_DER_ASN1_DN:
++ if (!permitted)
++ {
++ DBG1(DBG_CFG, "excluded %N NameConstraint not supported",
++ id_type_names, type);
++ success = FALSE;
++ break;
++ }
++ /* fall-through */
+ case ID_FQDN:
+ case ID_RFC822_ADDR:
+- case ID_DER_ASN1_DN:
+ case ID_IPV4_ADDR_SUBNET:
+ case ID_IPV6_ADDR_SUBNET:
+ break;
+diff --git a/src/libstrongswan/tests/suites/test_certnames.c b/src/libstrongswan/tests/suites/test_certnames.c
+index 2549fb6..14570ee 100644
+--- a/src/libstrongswan/tests/suites/test_certnames.c
++++ b/src/libstrongswan/tests/suites/test_certnames.c
+@@ -207,8 +207,10 @@ static struct {
+ bool good;
+ } permitted_san[] = {
+ { ".strongswan.org", "test.strongswan.org", TRUE },
++ { ".strongswan.org", "test.strongSwan.org", TRUE },
+ { "strongswan.org", "test.strongswan.org", TRUE },
+ { "a.b.c.strongswan.org", "d.a.b.c.strongswan.org", TRUE },
++ { "a.b.c.strongswan.org", "d.A.b.C.strongswan.org", TRUE },
+ { "a.b.c.strongswan.org", "a.b.c.d.strongswan.org", FALSE },
+ { "strongswan.org", "strongswan.org.com", FALSE },
+ { ".strongswan.org", "strongswan.org", FALSE },
+@@ -216,8 +218,11 @@ static struct {
+ { "strongswan.org", "swan.org", FALSE },
+ { "strongswan.org", "swan.org", FALSE },
+ { "tester at strongswan.org", "tester at strongswan.org", TRUE },
++ { "tester at strongswan.org", "tester at strongSwan.org", TRUE },
++ { "tester at strongswan.org", "TESTER at strongswan.org", TRUE },
+ { "tester at strongswan.org", "atester at strongswan.org", FALSE },
+ { "email:strongswan.org", "tester at strongswan.org", TRUE },
++ { "email:strongswan.org", "tester at strongSwan.org", TRUE },
+ { "email:strongswan.org", "tester at test.strongswan.org", FALSE },
+ { "email:.strongswan.org", "tester at test.strongswan.org", TRUE },
+ { "email:.strongswan.org", "tester at strongswan.org", FALSE },
+@@ -248,11 +253,11 @@ static struct {
+ char *subject;
+ bool good;
+ } excluded_dn[] = {
+- { "C=CH, O=another", "C=CH, O=strongSwan, CN=tester", TRUE },
+- { "C=CH, O=another", "C=CH, O=anot", TRUE },
+- { "C=CH, O=another", "C=CH, O=anot, CN=tester", TRUE },
++ { "C=CH, O=another", "C=CH, O=strongSwan, CN=tester", FALSE },
++ { "C=CH, O=another", "C=CH, O=anot", FALSE },
++ { "C=CH, O=another", "C=CH, O=anot, CN=tester", FALSE },
+ { "C=CH, O=another", "C=CH, O=another, CN=tester", FALSE },
+- { "C=CH, O=another", "C=CH, CN=tester, O=another", TRUE },
++ { "C=CH, O=another", "C=CH, CN=tester, O=another", FALSE },
+ };
+
+ START_TEST(test_excluded_dn)
+@@ -281,7 +286,9 @@ static struct {
+ } excluded_san[] = {
+ { ".strongswan.org", "test.strongswan.org", FALSE },
+ { "strongswan.org", "test.strongswan.org", FALSE },
++ { "strongswan.org", "test.strongSwan.org", FALSE },
+ { "a.b.c.strongswan.org", "d.a.b.c.strongswan.org", FALSE },
++ { "a.b.c.strongswan.org", "d.a.b.C.strongswan.org", FALSE },
+ { "a.b.c.strongswan.org", "a.b.c.d.strongswan.org", TRUE },
+ { "strongswan.org", "strongswan.org.com", TRUE },
+ { ".strongswan.org", "strongswan.org", TRUE },
+@@ -289,8 +296,10 @@ static struct {
+ { "strongswan.org", "swan.org", TRUE },
+ { "strongswan.org", "swan.org", TRUE },
+ { "tester at strongswan.org", "tester at strongswan.org", FALSE },
++ { "tester at strongswan.org", "TESTER at strongswan.org", FALSE },
+ { "tester at strongswan.org", "atester at strongswan.org", TRUE },
+ { "email:strongswan.org", "tester at strongswan.org", FALSE },
++ { "email:strongswan.org", "tester at strongSwan.org", FALSE },
+ { "email:strongswan.org", "tester at test.strongswan.org", TRUE },
+ { "email:.strongswan.org", "tester at test.strongswan.org", FALSE },
+ { "email:.strongswan.org", "tester at strongswan.org", TRUE },
+@@ -418,9 +427,9 @@ static struct {
+ char *subject;
+ bool good;
+ } excluded_dn_levels[] = {
+- { "C=CH, O=strongSwan", "C=CH", "C=DE", TRUE },
++ { "C=CH, O=strongSwan", "C=CH", "C=DE", FALSE },
+ { "C=CH, O=strongSwan", "C=CH", "C=CH", FALSE },
+- { "C=CH, O=strongSwan", "C=DE", "C=CH", TRUE },
++ { "C=CH, O=strongSwan", "C=DE", "C=CH", FALSE },
+ { "C=CH, O=strongSwan", "C=DE", "C=DE", FALSE },
+ { "C=CH, O=strongSwan", "C=DE", "C=CH, O=strongSwan", FALSE },
+ { NULL, "C=CH", "C=CH, O=strongSwan", FALSE },
=====================================
debian/patches/0016-gmp-Avoid-crash-and-timing-leaks-in-PKCS-1-v1.5-decr.patch
=====================================
@@ -0,0 +1,246 @@
+From: Tobias Brunner <tobias at strongswan.org>
+Date: Tue, 24 Mar 2026 18:00:23 +0100
+Subject: gmp: Avoid crash and timing leaks in PKCS#1 v1.5 decryption padding
+ validation
+MIME-Version: 1.0
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: 8bit
+
+This fixes a potential crash due to a null-pointer dereference if rsadp()
+returns NULL (e.g. with an all-zero ciphertext).
+
+And it also implements the PKCS#1 v1.5 decryption padding check in
+constant time.
+
+The timing leak caused by the previous implementation was measured at
+~17.5 μs at 3 GHz, which could allow a Bleichenbacher-like attack in
+LAN environments. However, because of how RSA encryption is used in
+strongSwan, this is not that much of an issue in practice. The mechanism
+is only used for two use cases. One is SCEP/EST via PKCS#7 enveloped
+data. Fortunately, this can not be triggered in significant numbers by
+an attacker. The other use case is TLS as used by EAP methods (EAP-TLS,
+EAP-PEAP/TTLS) during the authentication. While the cipher suites that
+use RSA encryption are still enabled by default, the TLS messages are
+wrapped in EAP and encrypted by IKE, making any kind of attack difficult.
+
+Note that the gmp plugin isn't enabled anymore by default. And even
+before that, most setups had the openssl plugin enabled, which has
+priority over the gmp plugin. So it's unlikely the plugin was used in
+practice.
+
+Also note that this patch doesn't modify libstrongswan's Makefile.am
+to avoid potentially requiring autotools when patching a tarball.
+
+Fixes: d615ffdcf3cd ("implement gmp_rsa_private_key.decrypt()")
+Fixes: CVE-2026-35334
+---
+ .../plugins/gmp/gmp_rsa_private_key.c | 54 +++++++----
+ src/libstrongswan/utils/utils.h | 1 +
+ src/libstrongswan/utils/utils/constant_time.h | 103 +++++++++++++++++++++
+ 3 files changed, 140 insertions(+), 18 deletions(-)
+ create mode 100644 src/libstrongswan/utils/utils/constant_time.h
+
+diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c
+index 63e8f54..64f730f 100644
+--- a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c
++++ b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c
+@@ -495,8 +495,8 @@ METHOD(private_key_t, decrypt, bool,
+ private_gmp_rsa_private_key_t *this, encryption_scheme_t scheme,
+ void *params, chunk_t crypto, chunk_t *plain)
+ {
+- chunk_t em, stripped;
+- bool success = FALSE;
++ chunk_t em;
++ u_int valid, i, j, found_sep = 0, sep_index = 0, m_index;
+
+ if (scheme != ENCRYPT_RSA_PKCS1)
+ {
+@@ -505,33 +505,51 @@ METHOD(private_key_t, decrypt, bool,
+ return FALSE;
+ }
+ /* rsa decryption using PKCS#1 RSADP */
+- stripped = em = rsadp(this, crypto);
++ em = rsadp(this, crypto);
++ if (em.len != this->k)
++ {
++ return FALSE;
++ }
+
+- /* PKCS#1 v1.5 8.1 encryption-block formatting (EB = 00 || 02 || PS || 00 || D) */
++ /* PKCS#1 v1.5, RFC 8017, section 7.2.2 message structure:
++ * EM = 00 || 02 || PS || 00 || M */
+
+ /* check for hex pattern 00 02 in decrypted message */
+- if ((*stripped.ptr++ != 0x00) || (*(stripped.ptr++) != 0x02))
++ valid = constant_time_eq(em.ptr[0], 0x00);
++ valid &= constant_time_eq(em.ptr[1], 0x02);
++
++ /* the plaintext data starts after first 0x00 byte */
++ for (i = 2; i < em.len; i++)
+ {
+- DBG1(DBG_LIB, "incorrect padding - probably wrong rsa key");
+- goto end;
++ u_int zero = constant_time_eq(em.ptr[i], 0x00);
++
++ sep_index = constant_time_select(i, sep_index, ~found_sep & zero);
++ found_sep |= zero;
+ }
+- stripped.len -= 2;
+
+- /* the plaintext data starts after first 0x00 byte */
+- while (stripped.len-- > 0 && *stripped.ptr++ != 0x00)
++ /* make sure PS is at least eight bytes long (plus the initial bytes) */
++ valid &= constant_time_ge(sep_index, 10);
++
++ /* instead of copying the message directly, we try not to reveal the message
++ * length i.e. where the 0x00 byte was. and since clearing a chunk is
++ * relatively efficient, i.e. doesn't leak much, we always allocate and copy
++ * a value and then clear it if the structure was invalid */
++ m_index = constant_time_select(sep_index + 1, 11, valid);
+
+- if (stripped.len == 0)
++ *plain = chunk_alloc(this->k);
++ for (i = 0, j = 0; i < em.len; i++)
+ {
+- DBG1(DBG_LIB, "no plaintext data");
+- goto end;
++ plain->ptr[j] = em.ptr[i];
++ j += constant_time_ge(i, m_index);
+ }
++ plain->len = j;
+
+- *plain = chunk_clone(stripped);
+- success = TRUE;
+-
+-end:
++ if (!valid)
++ {
++ chunk_clear(plain);
++ }
+ chunk_clear(&em);
+- return success;
++ return valid;
+ }
+
+ METHOD(private_key_t, get_keysize, int,
+diff --git a/src/libstrongswan/utils/utils.h b/src/libstrongswan/utils/utils.h
+index 42d0114..ab0be72 100644
+--- a/src/libstrongswan/utils/utils.h
++++ b/src/libstrongswan/utils/utils.h
+@@ -53,6 +53,7 @@
+ #include "utils/atomics.h"
+ #include "utils/align.h"
+ #include "utils/byteorder.h"
++#include "utils/constant_time.h"
+ #include "utils/string.h"
+ #include "utils/memory.h"
+ #include "utils/strerror.h"
+diff --git a/src/libstrongswan/utils/utils/constant_time.h b/src/libstrongswan/utils/utils/constant_time.h
+new file mode 100644
+index 0000000..0c2c6a2
+--- /dev/null
++++ b/src/libstrongswan/utils/utils/constant_time.h
+@@ -0,0 +1,103 @@
++/*
++ * Copyright (C) 2026 Tobias Brunner
++ *
++ * Copyright (C) secunet Security Networks AG
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * for more details.
++ */
++
++/**
++ * @defgroup constant_time_i constant_time
++ * @{ @ingroup constant_time_i
++ */
++
++#ifndef CONSTANT_TIME_H_
++#define CONSTANT_TIME_H_
++
++#include <stdint.h>
++
++/**
++ * Check if the given values are not equal in constant time.
++ *
++ * @param x first value to check
++ * @param y second value to check
++ * @return 1 if values are not equal, 0 otherwise
++ */
++static inline u_int constant_time_neq(uint32_t x, uint32_t y)
++{
++ return ((x-y) | (y-x)) >> 31;
++}
++
++/**
++ * Check if the given values are equal in constant time.
++ *
++ * @param x first value to check
++ * @param y second value to check
++ * @return 1 if values are equal, 0 otherwise
++ */
++static inline u_int constant_time_eq(uint32_t x, uint32_t y)
++{
++ return 1 ^ constant_time_neq(x, y);
++}
++
++/**
++ * Compare the two values and return 1 if the first argument is lower than
++ * the second in constant time.
++ *
++ * @param x first value to check
++ * @param y second value to check
++ * @return 1 if first value is lower than second
++ */
++static inline u_int constant_time_lt(uint32_t x, uint32_t y)
++{
++ return (x ^ ((x^y) | ((x-y) ^ y))) >> 31;
++}
++
++/**
++ * Compare the two values and return 1 if the first argument greater or equal to
++ * the second in constant time.
++ *
++ * @param x first value to check
++ * @param y second value to check
++ * @return 1 if first value is greater or equal to the second
++ */
++static inline u_int constant_time_ge(uint32_t x, uint32_t y)
++{
++ return 1 ^ constant_time_lt(x, y);
++}
++
++/**
++ * Return a 32-bit all bit-set mask if the given value is not 0.
++ *
++ * @param x value to check
++ * @return 0xffffffff if value is != 0, 0 otherwise
++ */
++static inline uint32_t constant_time_mask(uint32_t x)
++{
++ return -(uint32_t)constant_time_neq(x, 0);
++}
++
++/**
++ * Select one of two values depending on whether the condition is != 0 or not.
++ * Basically equivalent to 'c ? x : y'.
++ *
++ * @param x first value to select
++ * @param y second value to select
++ * @param c condition
++ * @return x if c is != 0, y otherwise
++ */
++static inline uint32_t constant_time_select(uint32_t x, uint32_t y, uint32_t c)
++{
++ uint32_t m = constant_time_mask(c);
++ return (x & m) | (y & ~m);
++}
++
++#endif /** CONSTANT_TIME_H_ @} */
=====================================
debian/patches/series
=====================================
@@ -7,3 +7,10 @@ dont-load-kernel-libipsec-plugin-by-default.patch
0007-eap-mschapv2-Fix-length-check-for-Failure-Request-pa.patch
0008-nm-Create-safe-copies-of-files-for-user-specific-con.patch
0009-eap-ttls-Prevent-crash-if-AVP-length-header-field-is.patch
+0010-libsimaka-Reject-zero-length-EAP-SIM-AKA-attributes.patch
+0011-libradius-Reject-undersized-attributes-in-enumerator.patch
+0012-tls-server-Only-accept-non-empty-ECDH-public-keys-wi.patch
+0013-tls-server-Prevent-infinite-loop-if-supported-versio.patch
+0014-pkcs5-pkcs7-Avoid-NULL-pointer-dereference-when-veri.patch
+0015-constraints-Case-insensitive-matching-and-reject-exc.patch
+0016-gmp-Avoid-crash-and-timing-leaks-in-PKCS-1-v1.5-decr.patch
View it on GitLab: https://salsa.debian.org/debian/strongswan/-/compare/8739a3a3fe4a9c75ff46a3240459cf26669d9fa5...a53ad826fa9adc7e4f8b01527d9d538bd632480a
--
View it on GitLab: https://salsa.debian.org/debian/strongswan/-/compare/8739a3a3fe4a9c75ff46a3240459cf26669d9fa5...a53ad826fa9adc7e4f8b01527d9d538bd632480a
You're receiving this email because of your account on salsa.debian.org. Manage all notifications: https://salsa.debian.org/-/profile/notifications | Help: https://salsa.debian.org/help
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-swan-devel/attachments/20260426/841e8b81/attachment-0001.htm>
More information about the Pkg-swan-devel
mailing list