[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