diff mbox series

[OE-core,scarthgap,V2,4/6] strongswan: Fix CVE-2026-35331

Message ID 20260609092407.893299-4-nitin.wankhade333@gmail.com
State New
Headers show
Series [OE-core,scarthgap,V2,1/6] strongswan: Fix CVE-2026-35328 | expand

Commit Message

Nitin Wankhade June 9, 2026, 9:24 a.m. UTC
Upstream-Status: Backport [https://github.com/strongswan/strongswan/commit/64130ede5cd8f61edd35a1b488c874fa328a42b0]
                          [https://github.com/strongswan/strongswan/commit/c66143db48bab9eb82cc86190687938b809611eb]

Signed-off-by: Nitin Wankhade <nitin.wankhade333@gmail.com>
---
 ...-insensitive-matching-and-reject-exc.patch | 176 ++++++++++++++++++
 .../strongswan/strongswan_5.9.14.bb           |   1 +
 2 files changed, 177 insertions(+)
 create mode 100644 meta-networking/recipes-support/strongswan/strongswan/constraints-Case-insensitive-matching-and-reject-exc.patch
diff mbox series

Patch

diff --git a/meta-networking/recipes-support/strongswan/strongswan/constraints-Case-insensitive-matching-and-reject-exc.patch b/meta-networking/recipes-support/strongswan/strongswan/constraints-Case-insensitive-matching-and-reject-exc.patch
new file mode 100644
index 0000000000..86e530d7e0
--- /dev/null
+++ b/meta-networking/recipes-support/strongswan/strongswan/constraints-Case-insensitive-matching-and-reject-exc.patch
@@ -0,0 +1,176 @@ 
+From: Tobias Brunner <tobias@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
+
+CVE: CVE-2026-35331
+Upstream-Status: Backport [https://github.com/strongswan/strongswan/commit/64130ede5cd8f61edd35a1b488c874fa328a42b0]
+                          [https://github.com/strongswan/strongswan/commit/c66143db48bab9eb82cc86190687938b809611eb]
+Signed-off-by: Nitin Wankhade <nitin.wankhade333@gmail.com>
+===
+diff --git a/src/libstrongswan/plugins/constraints/constraints_validator.c b/src/libstrongswan/plugins/constraints/constraints_validator.c
+index 27bdb89..daa7bfa 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@strongswan.org", "tester@strongswan.org", TRUE },
++	{ "tester@strongswan.org", "tester@strongSwan.org", TRUE },
++	{ "tester@strongswan.org", "TESTER@strongswan.org", TRUE },
+ 	{ "tester@strongswan.org", "atester@strongswan.org", FALSE },
+ 	{ "email:strongswan.org", "tester@strongswan.org", TRUE },
++	{ "email:strongswan.org", "tester@strongSwan.org", TRUE },
+ 	{ "email:strongswan.org", "tester@test.strongswan.org", FALSE },
+ 	{ "email:.strongswan.org", "tester@test.strongswan.org", TRUE },
+ 	{ "email:.strongswan.org", "tester@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@strongswan.org", "tester@strongswan.org", FALSE },
++	{ "tester@strongswan.org", "TESTER@strongswan.org", FALSE },
+ 	{ "tester@strongswan.org", "atester@strongswan.org", TRUE },
+ 	{ "email:strongswan.org", "tester@strongswan.org", FALSE },
++	{ "email:strongswan.org", "tester@strongSwan.org", FALSE },
+ 	{ "email:strongswan.org", "tester@test.strongswan.org", TRUE },
+ 	{ "email:.strongswan.org", "tester@test.strongswan.org", FALSE },
+ 	{ "email:.strongswan.org", "tester@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 },
diff --git a/meta-networking/recipes-support/strongswan/strongswan_5.9.14.bb b/meta-networking/recipes-support/strongswan/strongswan_5.9.14.bb
index 85fd95d6b8..41a4de845f 100644
--- a/meta-networking/recipes-support/strongswan/strongswan_5.9.14.bb
+++ b/meta-networking/recipes-support/strongswan/strongswan_5.9.14.bb
@@ -15,6 +15,7 @@  SRC_URI = "https://download.strongswan.org/strongswan-${PV}.tar.bz2 \
            file://tls-server-Prevent-infinite-loop-if-supported-versio.patch \
            file://pkcs5-pkcs7-Avoid-NULL-pointer-dereference-when-veri.patch \
            file://libsimaka-Reject-zero-length-EAP-SIM-AKA-attributes.patch \
+           file://constraints-Case-insensitive-matching-and-reject-exc.patch \
            "
 
 SRC_URI[sha256sum] = "728027ddda4cb34c67c4cec97d3ddb8c274edfbabdaeecf7e74693b54fc33678"