diff options
| author | Hitendra Prajapati <hprajapati@mvista.com> | 2026-05-14 18:45:41 +0530 |
|---|---|---|
| committer | Anuj Mittal <anuj.mittal@oss.qualcomm.com> | 2026-05-21 08:57:48 +0530 |
| commit | a587f53a0eff978246f7aec466fb42588c339056 (patch) | |
| tree | 051ee6a8f39f6b50084944f06ed2bc4954bd6911 | |
| parent | 9f70f8d461abae94342da0e41ed978022e0eefe2 (diff) | |
| download | meta-openembedded-a587f53a0eff978246f7aec466fb42588c339056.tar.gz | |
strongswan: fix for CVE-2026-35334
Pick patch according to [1]
[1] https://download.strongswan.org/security/CVE-2026-35334
[2] https://www.strongswan.org/blog/2026/04/22/strongswan-vulnerability-(cve-2026-35334).html
[3] https://security-tracker.debian.org/tracker/CVE-2026-35334
Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
| -rw-r--r-- | meta-networking/recipes-support/strongswan/strongswan/CVE-2026-35334.patch | 255 | ||||
| -rw-r--r-- | meta-networking/recipes-support/strongswan/strongswan_5.9.14.bb | 1 |
2 files changed, 256 insertions, 0 deletions
diff --git a/meta-networking/recipes-support/strongswan/strongswan/CVE-2026-35334.patch b/meta-networking/recipes-support/strongswan/strongswan/CVE-2026-35334.patch new file mode 100644 index 0000000000..5ed9f1bf61 --- /dev/null +++ b/meta-networking/recipes-support/strongswan/strongswan/CVE-2026-35334.patch | |||
| @@ -0,0 +1,255 @@ | |||
| 1 | From c23cf29373bb25a24b952ea4c5bf7ea326b78714 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Tobias Brunner <tobias@strongswan.org> | ||
| 3 | Date: Tue, 24 Mar 2026 18:00:23 +0100 | ||
| 4 | Subject: [PATCH] gmp: Avoid crash and timing leaks in PKCS#1 v1.5 decryption | ||
| 5 | padding validation | ||
| 6 | MIME-Version: 1.0 | ||
| 7 | Content-Type: text/plain; charset=UTF-8 | ||
| 8 | Content-Transfer-Encoding: 8bit | ||
| 9 | |||
| 10 | This fixes a potential crash due to a null-pointer dereference if rsadp() | ||
| 11 | returns NULL (e.g. with an all-zero ciphertext). | ||
| 12 | |||
| 13 | And it also implements the PKCS#1 v1.5 decryption padding check in | ||
| 14 | constant time. | ||
| 15 | |||
| 16 | The timing leak caused by the previous implementation was measured at | ||
| 17 | ~17.5 μs at 3 GHz, which could allow a Bleichenbacher-like attack in | ||
| 18 | LAN environments. However, because of how RSA encryption is used in | ||
| 19 | strongSwan, this is not that much of an issue in practice. The mechanism | ||
| 20 | is only used for two use cases. One is SCEP/EST via PKCS#7 enveloped | ||
| 21 | data. Fortunately, this can not be triggered in significant numbers by | ||
| 22 | an attacker. The other use case is TLS as used by EAP methods (EAP-TLS, | ||
| 23 | EAP-PEAP/TTLS) during the authentication. While the cipher suites that | ||
| 24 | use RSA encryption are still enabled by default, the TLS messages are | ||
| 25 | wrapped in EAP and encrypted by IKE, making any kind of attack difficult. | ||
| 26 | |||
| 27 | Note that the gmp plugin isn't enabled anymore by default. And even | ||
| 28 | before that, most setups had the openssl plugin enabled, which has | ||
| 29 | priority over the gmp plugin. So it's unlikely the plugin was used in | ||
| 30 | practice. | ||
| 31 | |||
| 32 | Also note that this patch doesn't modify libstrongswan's Makefile.am | ||
| 33 | to avoid potentially requiring autotools when patching a tarball. | ||
| 34 | |||
| 35 | Fixes: d615ffdcf3cd ("implement gmp_rsa_private_key.decrypt()") | ||
| 36 | Fixes: CVE-2026-35334 | ||
| 37 | |||
| 38 | |||
| 39 | CVE: CVE-2026-35334 | ||
| 40 | Upstream-Status: Backport [https://download.strongswan.org/security/CVE-2026-35334/strongswan-5.3.1-6.0.5_gmp_rsa_decrypt_pad.patch] | ||
| 41 | Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> | ||
| 42 | --- | ||
| 43 | .../plugins/gmp/gmp_rsa_private_key.c | 54 ++++++--- | ||
| 44 | src/libstrongswan/utils/utils.h | 1 + | ||
| 45 | src/libstrongswan/utils/utils/constant_time.h | 103 ++++++++++++++++++ | ||
| 46 | 3 files changed, 140 insertions(+), 18 deletions(-) | ||
| 47 | create mode 100644 src/libstrongswan/utils/utils/constant_time.h | ||
| 48 | |||
| 49 | diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c | ||
| 50 | index 47784b6..7312fa9 100644 | ||
| 51 | --- a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c | ||
| 52 | +++ b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c | ||
| 53 | @@ -495,8 +495,8 @@ METHOD(private_key_t, decrypt, bool, | ||
| 54 | private_gmp_rsa_private_key_t *this, encryption_scheme_t scheme, | ||
| 55 | void *params, chunk_t crypto, chunk_t *plain) | ||
| 56 | { | ||
| 57 | - chunk_t em, stripped; | ||
| 58 | - bool success = FALSE; | ||
| 59 | + chunk_t em; | ||
| 60 | + u_int valid, i, j, found_sep = 0, sep_index = 0, m_index; | ||
| 61 | |||
| 62 | if (scheme != ENCRYPT_RSA_PKCS1) | ||
| 63 | { | ||
| 64 | @@ -505,33 +505,51 @@ METHOD(private_key_t, decrypt, bool, | ||
| 65 | return FALSE; | ||
| 66 | } | ||
| 67 | /* rsa decryption using PKCS#1 RSADP */ | ||
| 68 | - stripped = em = rsadp(this, crypto); | ||
| 69 | + em = rsadp(this, crypto); | ||
| 70 | + if (em.len != this->k) | ||
| 71 | + { | ||
| 72 | + return FALSE; | ||
| 73 | + } | ||
| 74 | |||
| 75 | - /* PKCS#1 v1.5 8.1 encryption-block formatting (EB = 00 || 02 || PS || 00 || D) */ | ||
| 76 | + /* PKCS#1 v1.5, RFC 8017, section 7.2.2 message structure: | ||
| 77 | + * EM = 00 || 02 || PS || 00 || M */ | ||
| 78 | |||
| 79 | /* check for hex pattern 00 02 in decrypted message */ | ||
| 80 | - if ((*stripped.ptr++ != 0x00) || (*(stripped.ptr++) != 0x02)) | ||
| 81 | + valid = constant_time_eq(em.ptr[0], 0x00); | ||
| 82 | + valid &= constant_time_eq(em.ptr[1], 0x02); | ||
| 83 | + | ||
| 84 | + /* the plaintext data starts after first 0x00 byte */ | ||
| 85 | + for (i = 2; i < em.len; i++) | ||
| 86 | { | ||
| 87 | - DBG1(DBG_LIB, "incorrect padding - probably wrong rsa key"); | ||
| 88 | - goto end; | ||
| 89 | + u_int zero = constant_time_eq(em.ptr[i], 0x00); | ||
| 90 | + | ||
| 91 | + sep_index = constant_time_select(i, sep_index, ~found_sep & zero); | ||
| 92 | + found_sep |= zero; | ||
| 93 | } | ||
| 94 | - stripped.len -= 2; | ||
| 95 | |||
| 96 | - /* the plaintext data starts after first 0x00 byte */ | ||
| 97 | - while (stripped.len-- > 0 && *stripped.ptr++ != 0x00) | ||
| 98 | + /* make sure PS is at least eight bytes long (plus the initial bytes) */ | ||
| 99 | + valid &= constant_time_ge(sep_index, 10); | ||
| 100 | + | ||
| 101 | + /* instead of copying the message directly, we try not to reveal the message | ||
| 102 | + * length i.e. where the 0x00 byte was. and since clearing a chunk is | ||
| 103 | + * relatively efficient, i.e. doesn't leak much, we always allocate and copy | ||
| 104 | + * a value and then clear it if the structure was invalid */ | ||
| 105 | + m_index = constant_time_select(sep_index + 1, 11, valid); | ||
| 106 | |||
| 107 | - if (stripped.len == 0) | ||
| 108 | + *plain = chunk_alloc(this->k); | ||
| 109 | + for (i = 0, j = 0; i < em.len; i++) | ||
| 110 | { | ||
| 111 | - DBG1(DBG_LIB, "no plaintext data"); | ||
| 112 | - goto end; | ||
| 113 | + plain->ptr[j] = em.ptr[i]; | ||
| 114 | + j += constant_time_ge(i, m_index); | ||
| 115 | } | ||
| 116 | + plain->len = j; | ||
| 117 | |||
| 118 | - *plain = chunk_clone(stripped); | ||
| 119 | - success = TRUE; | ||
| 120 | - | ||
| 121 | -end: | ||
| 122 | + if (!valid) | ||
| 123 | + { | ||
| 124 | + chunk_clear(plain); | ||
| 125 | + } | ||
| 126 | chunk_clear(&em); | ||
| 127 | - return success; | ||
| 128 | + return valid; | ||
| 129 | } | ||
| 130 | |||
| 131 | METHOD(private_key_t, get_keysize, int, | ||
| 132 | diff --git a/src/libstrongswan/utils/utils.h b/src/libstrongswan/utils/utils.h | ||
| 133 | index 42d0114..ab0be72 100644 | ||
| 134 | --- a/src/libstrongswan/utils/utils.h | ||
| 135 | +++ b/src/libstrongswan/utils/utils.h | ||
| 136 | @@ -53,6 +53,7 @@ | ||
| 137 | #include "utils/atomics.h" | ||
| 138 | #include "utils/align.h" | ||
| 139 | #include "utils/byteorder.h" | ||
| 140 | +#include "utils/constant_time.h" | ||
| 141 | #include "utils/string.h" | ||
| 142 | #include "utils/memory.h" | ||
| 143 | #include "utils/strerror.h" | ||
| 144 | diff --git a/src/libstrongswan/utils/utils/constant_time.h b/src/libstrongswan/utils/utils/constant_time.h | ||
| 145 | new file mode 100644 | ||
| 146 | index 0000000..0c2c6a2 | ||
| 147 | --- /dev/null | ||
| 148 | +++ b/src/libstrongswan/utils/utils/constant_time.h | ||
| 149 | @@ -0,0 +1,103 @@ | ||
| 150 | +/* | ||
| 151 | + * Copyright (C) 2026 Tobias Brunner | ||
| 152 | + * | ||
| 153 | + * Copyright (C) secunet Security Networks AG | ||
| 154 | + * | ||
| 155 | + * This program is free software; you can redistribute it and/or modify it | ||
| 156 | + * under the terms of the GNU General Public License as published by the | ||
| 157 | + * Free Software Foundation; either version 2 of the License, or (at your | ||
| 158 | + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | ||
| 159 | + * | ||
| 160 | + * This program is distributed in the hope that it will be useful, but | ||
| 161 | + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| 162 | + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 163 | + * for more details. | ||
| 164 | + */ | ||
| 165 | + | ||
| 166 | +/** | ||
| 167 | + * @defgroup constant_time_i constant_time | ||
| 168 | + * @{ @ingroup constant_time_i | ||
| 169 | + */ | ||
| 170 | + | ||
| 171 | +#ifndef CONSTANT_TIME_H_ | ||
| 172 | +#define CONSTANT_TIME_H_ | ||
| 173 | + | ||
| 174 | +#include <stdint.h> | ||
| 175 | + | ||
| 176 | +/** | ||
| 177 | + * Check if the given values are not equal in constant time. | ||
| 178 | + * | ||
| 179 | + * @param x first value to check | ||
| 180 | + * @param y second value to check | ||
| 181 | + * @return 1 if values are not equal, 0 otherwise | ||
| 182 | + */ | ||
| 183 | +static inline u_int constant_time_neq(uint32_t x, uint32_t y) | ||
| 184 | +{ | ||
| 185 | + return ((x-y) | (y-x)) >> 31; | ||
| 186 | +} | ||
| 187 | + | ||
| 188 | +/** | ||
| 189 | + * Check if the given values are equal in constant time. | ||
| 190 | + * | ||
| 191 | + * @param x first value to check | ||
| 192 | + * @param y second value to check | ||
| 193 | + * @return 1 if values are equal, 0 otherwise | ||
| 194 | + */ | ||
| 195 | +static inline u_int constant_time_eq(uint32_t x, uint32_t y) | ||
| 196 | +{ | ||
| 197 | + return 1 ^ constant_time_neq(x, y); | ||
| 198 | +} | ||
| 199 | + | ||
| 200 | +/** | ||
| 201 | + * Compare the two values and return 1 if the first argument is lower than | ||
| 202 | + * the second in constant time. | ||
| 203 | + * | ||
| 204 | + * @param x first value to check | ||
| 205 | + * @param y second value to check | ||
| 206 | + * @return 1 if first value is lower than second | ||
| 207 | + */ | ||
| 208 | +static inline u_int constant_time_lt(uint32_t x, uint32_t y) | ||
| 209 | +{ | ||
| 210 | + return (x ^ ((x^y) | ((x-y) ^ y))) >> 31; | ||
| 211 | +} | ||
| 212 | + | ||
| 213 | +/** | ||
| 214 | + * Compare the two values and return 1 if the first argument greater or equal to | ||
| 215 | + * the second in constant time. | ||
| 216 | + * | ||
| 217 | + * @param x first value to check | ||
| 218 | + * @param y second value to check | ||
| 219 | + * @return 1 if first value is greater or equal to the second | ||
| 220 | + */ | ||
| 221 | +static inline u_int constant_time_ge(uint32_t x, uint32_t y) | ||
| 222 | +{ | ||
| 223 | + return 1 ^ constant_time_lt(x, y); | ||
| 224 | +} | ||
| 225 | + | ||
| 226 | +/** | ||
| 227 | + * Return a 32-bit all bit-set mask if the given value is not 0. | ||
| 228 | + * | ||
| 229 | + * @param x value to check | ||
| 230 | + * @return 0xffffffff if value is != 0, 0 otherwise | ||
| 231 | + */ | ||
| 232 | +static inline uint32_t constant_time_mask(uint32_t x) | ||
| 233 | +{ | ||
| 234 | + return -(uint32_t)constant_time_neq(x, 0); | ||
| 235 | +} | ||
| 236 | + | ||
| 237 | +/** | ||
| 238 | + * Select one of two values depending on whether the condition is != 0 or not. | ||
| 239 | + * Basically equivalent to 'c ? x : y'. | ||
| 240 | + * | ||
| 241 | + * @param x first value to select | ||
| 242 | + * @param y second value to select | ||
| 243 | + * @param c condition | ||
| 244 | + * @return x if c is != 0, y otherwise | ||
| 245 | + */ | ||
| 246 | +static inline uint32_t constant_time_select(uint32_t x, uint32_t y, uint32_t c) | ||
| 247 | +{ | ||
| 248 | + uint32_t m = constant_time_mask(c); | ||
| 249 | + return (x & m) | (y & ~m); | ||
| 250 | +} | ||
| 251 | + | ||
| 252 | +#endif /** CONSTANT_TIME_H_ @} */ | ||
| 253 | -- | ||
| 254 | 2.50.1 | ||
| 255 | |||
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 820a1ad9e8..7cc67e4d92 100644 --- a/meta-networking/recipes-support/strongswan/strongswan_5.9.14.bb +++ b/meta-networking/recipes-support/strongswan/strongswan_5.9.14.bb | |||
| @@ -11,6 +11,7 @@ DEPENDS:append = "${@bb.utils.contains('DISTRO_FEATURES', 'tpm2', ' tpm2-tss', | |||
| 11 | SRC_URI = "https://download.strongswan.org/strongswan-${PV}.tar.bz2 \ | 11 | SRC_URI = "https://download.strongswan.org/strongswan-${PV}.tar.bz2 \ |
| 12 | file://CVE-2025-62291.patch \ | 12 | file://CVE-2025-62291.patch \ |
| 13 | file://CVE-2026-25075.patch \ | 13 | file://CVE-2026-25075.patch \ |
| 14 | file://CVE-2026-35334.patch \ | ||
| 14 | " | 15 | " |
| 15 | 16 | ||
| 16 | SRC_URI[sha256sum] = "728027ddda4cb34c67c4cec97d3ddb8c274edfbabdaeecf7e74693b54fc33678" | 17 | SRC_URI[sha256sum] = "728027ddda4cb34c67c4cec97d3ddb8c274edfbabdaeecf7e74693b54fc33678" |
