[meta-lts-collab][kirkstone][PATCH 7/7] strongswan: Fix CVE-2026-35334

Nitin Wankhade <[email protected]>
Newsgroups org.yoctoproject.lists.yocto-patches
Message-ID <[email protected]>
From: Nitin Wankhade <[email protected]>

Upstream-Status: Backport [https://snapshot.debian.org/archive/debian-security-debug/20260422T125423Z/pool/updates/main/s/strongswan/strongswan_6.0.1-6%2Bdeb13u5.debian.tar.xz]

Signed-off-by: Nitin Wankhade <[email protected]>
---
 ...and-timing-leaks-in-PKCS-1-v1.5-decr.patch | 244 ++++++++++++++++++
 .../strongswan/strongswan_5.9.13.bbappend     |   1 +
 2 files changed, 245 insertions(+)
 create mode 100644 meta-networking/recipes-support/strongswan/files/gmp-Avoid-crash-and-timing-leaks-in-PKCS-1-v1.5-decr.patch

diff --git a/meta-networking/recipes-support/strongswan/files/gmp-Avoid-crash-and-timing-leaks-in-PKCS-1-v1.5-decr.patch b/meta-networking/recipes-support/strongswan/files/gmp-Avoid-crash-and-timing-leaks-in-PKCS-1-v1.5-decr.patch
new file mode 100644
index 0000000..cb6777a
--- /dev/null
+++ b/meta-networking/recipes-support/strongswan/files/gmp-Avoid-crash-and-timing-leaks-in-PKCS-1-v1.5-decr.patch
@@ -0,0 +1,244 @@
+From: Tobias Brunner <[email protected]>
+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
+
+CVE: CVE-2026-35334
+Upstream-Status: Backport [https://snapshot.debian.org/archive/debian-security-debug/20260422T125423Z/pool/updates/main/s/strongswan/strongswan_6.0.1-6%2Bdeb13u5.debian.tar.xz]
+Signed-off-by: Nitin Wankhade <[email protected]>
+===
+diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c
+index 47784b6..08c5eee 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);
+ 
+-	if (stripped.len == 0)
++	/* 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);
++
++	*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 40fe76a..80199a9 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..30a8549
+--- /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_ @} */
diff --git a/meta-networking/recipes-support/strongswan/strongswan_5.9.13.bbappend b/meta-networking/recipes-support/strongswan/strongswan_5.9.13.bbappend
index 8d22b60..a452a92 100644
--- a/meta-networking/recipes-support/strongswan/strongswan_5.9.13.bbappend
+++ b/meta-networking/recipes-support/strongswan/strongswan_5.9.13.bbappend
@@ -5,4 +5,5 @@ SRC_URI += "\
     file://constraints-Case-insensitive-matching-and-reject-exc.patch \
     file://tls-server-Only-accept-non-empty-ECDH-public-keys-wi.patch \
     file://libradius-Reject-undersized-attributes-in-enumerator.patch \
+    file://gmp-Avoid-crash-and-timing-leaks-in-PKCS-1-v1.5-decr.patch \
 "
-- 
2.34.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.