已开启
fix(cve): 修复 CVE-2026-35334 在 strongswan 中的漏洞 #107
fix(cve): 修复 CVE-2026-35334 在 strongswan 中的漏洞 #107
已开启
infra_team创建于 6月13日
共 2 个文件变更+256-1
@@ -0,0 +1,250 @@
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+ .../plugins/gmp/gmp_rsa_private_key.c | 54 ++++++---
39+ src/libstrongswan/utils/utils.h | 1 +
40+ src/libstrongswan/utils/utils/constant_time.h | 103 ++++++++++++++++++
41+ 3 files changed, 140 insertions(+), 18 deletions(-)
42+ create mode 100644 src/libstrongswan/utils/utils/constant_time.h
43+ 
44+diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c
45+index 63e8f54cddcb..64f730fdf7c3 100644
46+--- a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c
47++++ b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c
48+@@ -495,8 +495,8 @@ METHOD(private_key_t, decrypt, bool,
49+ private_gmp_rsa_private_key_t *this, encryption_scheme_t scheme,
50+ void *params, chunk_t crypto, chunk_t *plain)
51+ {
52+- chunk_t em, stripped;
53+- bool success = FALSE;
54++ chunk_t em;
55++ u_int valid, i, j, found_sep = 0, sep_index = 0, m_index;
56+
57+ if (scheme != ENCRYPT_RSA_PKCS1)
58+ {
59+@@ -505,33 +505,51 @@ METHOD(private_key_t, decrypt, bool,
60+ return FALSE;
61+ }
62+ /* rsa decryption using PKCS#1 RSADP */
63+- stripped = em = rsadp(this, crypto);
64++ em = rsadp(this, crypto);
65++ if (em.len != this->k)
66++ {
67++ return FALSE;
68++ }
69+
70+- /* PKCS#1 v1.5 8.1 encryption-block formatting (EB = 00 || 02 || PS || 00 || D) */
71++ /* PKCS#1 v1.5, RFC 8017, section 7.2.2 message structure:
72++ * EM = 00 || 02 || PS || 00 || M */
73+
74+ /* check for hex pattern 00 02 in decrypted message */
75+- if ((*stripped.ptr++ != 0x00) || (*(stripped.ptr++) != 0x02))
76++ valid = constant_time_eq(em.ptr[0], 0x00);
77++ valid &= constant_time_eq(em.ptr[1], 0x02);
78++
79++ /* the plaintext data starts after first 0x00 byte */
80++ for (i = 2; i < em.len; i++)
81+ {
82+- DBG1(DBG_LIB, "incorrect padding - probably wrong rsa key");
83+- goto end;
84++ u_int zero = constant_time_eq(em.ptr[i], 0x00);
85++
86++ sep_index = constant_time_select(i, sep_index, ~found_sep & zero);
87++ found_sep |= zero;
88+ }
89+- stripped.len -= 2;
90+
91+- /* the plaintext data starts after first 0x00 byte */
92+- while (stripped.len-- > 0 && *stripped.ptr++ != 0x00)
93++ /* make sure PS is at least eight bytes long (plus the initial bytes) */
94++ valid &= constant_time_ge(sep_index, 10);
95++
96++ /* instead of copying the message directly, we try not to reveal the message
97++ * length i.e. where the 0x00 byte was. and since clearing a chunk is
98++ * relatively efficient, i.e. doesn't leak much, we always allocate and copy
99++ * a value and then clear it if the structure was invalid */
100++ m_index = constant_time_select(sep_index + 1, 11, valid);
101+
102+- if (stripped.len == 0)
103++ *plain = chunk_alloc(this->k);
104++ for (i = 0, j = 0; i < em.len; i++)
105+ {
106+- DBG1(DBG_LIB, "no plaintext data");
107+- goto end;
108++ plain->ptr[j] = em.ptr[i];
109++ j += constant_time_ge(i, m_index);
110+ }
111++ plain->len = j;
112+
113+- *plain = chunk_clone(stripped);
114+- success = TRUE;
115+-
116+-end:
117++ if (!valid)
118++ {
119++ chunk_clear(plain);
120++ }
121+ chunk_clear(&em);
122+- return success;
123++ return valid;
124+ }
125+
126+ METHOD(private_key_t, get_keysize, int,
127+diff --git a/src/libstrongswan/utils/utils.h b/src/libstrongswan/utils/utils.h
128+index 42d01144a2f6..ab0be7206ee9 100644
129+--- a/src/libstrongswan/utils/utils.h
130++++ b/src/libstrongswan/utils/utils.h
131+@@ -53,6 +53,7 @@
132+ #include "utils/atomics.h"
133+ #include "utils/align.h"
134+ #include "utils/byteorder.h"
135++#include "utils/constant_time.h"
136+ #include "utils/string.h"
137+ #include "utils/memory.h"
138+ #include "utils/strerror.h"
139+diff --git a/src/libstrongswan/utils/utils/constant_time.h b/src/libstrongswan/utils/utils/constant_time.h
140+new file mode 100644
141+index 000000000000..0c2c6a2e04ae
142+--- /dev/null
143++++ b/src/libstrongswan/utils/utils/constant_time.h
144+@@ -0,0 +1,103 @@
145++/*
146++ * Copyright (C) 2026 Tobias Brunner
147++ *
148++ * Copyright (C) secunet Security Networks AG
149++ *
150++ * This program is free software; you can redistribute it and/or modify it
151++ * under the terms of the GNU General Public License as published by the
152++ * Free Software Foundation; either version 2 of the License, or (at your
153++ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
154++ *
155++ * This program is distributed in the hope that it will be useful, but
156++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
157++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
158++ * for more details.
159++ */
160++
161++/**
162++ * @defgroup constant_time_i constant_time
163++ * @{ @ingroup constant_time_i
164++ */
165++
166++#ifndef CONSTANT_TIME_H_
167++#define CONSTANT_TIME_H_
168++
169++#include <stdint.h>
170++
171++/**
172++ * Check if the given values are not equal in constant time.
173++ *
174++ * @param x first value to check
175++ * @param y second value to check
176++ * @return 1 if values are not equal, 0 otherwise
177++ */
178++static inline u_int constant_time_neq(uint32_t x, uint32_t y)
179++{
180++ return ((x-y) | (y-x)) >> 31;
181++}
182++
183++/**
184++ * Check if the given values are equal in constant time.
185++ *
186++ * @param x first value to check
187++ * @param y second value to check
188++ * @return 1 if values are equal, 0 otherwise
189++ */
190++static inline u_int constant_time_eq(uint32_t x, uint32_t y)
191++{
192++ return 1 ^ constant_time_neq(x, y);
193++}
194++
195++/**
196++ * Compare the two values and return 1 if the first argument is lower than
197++ * the second in constant time.
198++ *
199++ * @param x first value to check
200++ * @param y second value to check
201++ * @return 1 if first value is lower than second
202++ */
203++static inline u_int constant_time_lt(uint32_t x, uint32_t y)
204++{
205++ return (x ^ ((x^y) | ((x-y) ^ y))) >> 31;
206++}
207++
208++/**
209++ * Compare the two values and return 1 if the first argument greater or equal to
210++ * the second in constant time.
211++ *
212++ * @param x first value to check
213++ * @param y second value to check
214++ * @return 1 if first value is greater or equal to the second
215++ */
216++static inline u_int constant_time_ge(uint32_t x, uint32_t y)
217++{
218++ return 1 ^ constant_time_lt(x, y);
219++}
220++
221++/**
222++ * Return a 32-bit all bit-set mask if the given value is not 0.
223++ *
224++ * @param x value to check
225++ * @return 0xffffffff if value is != 0, 0 otherwise
226++ */
227++static inline uint32_t constant_time_mask(uint32_t x)
228++{
229++ return -(uint32_t)constant_time_neq(x, 0);
230++}
231++
232++/**
233++ * Select one of two values depending on whether the condition is != 0 or not.
234++ * Basically equivalent to 'c ? x : y'.
235++ *
236++ * @param x first value to select
237++ * @param y second value to select
238++ * @param c condition
239++ * @return x if c is != 0, y otherwise
240++ */
241++static inline uint32_t constant_time_select(uint32_t x, uint32_t y, uint32_t c)
242++{
243++ uint32_t m = constant_time_mask(c);
244++ return (x & m) | (y & ~m);
245++}
246++
247++#endif /** CONSTANT_TIME_H_ @} */
248+--
249+2.43.0
250+ 
@@ -1,6 +1,6 @@
1Name: strongswan1Name: strongswan
2Version: 5.9.142Version: 5.9.14
3-Release: 23+Release: 3
4Summary: An OpenSource IPsec-based VPN and TNC solution4Summary: An OpenSource IPsec-based VPN and TNC solution
5License: GPL-2.0-or-later5License: GPL-2.0-or-later
6URL: https://www.strongswan.org/6URL: https://www.strongswan.org/
@@ -11,6 +11,8 @@ Patch1: aes-crypter-support-sw64-arch.patch
11Patch2: strongswan-5.9.14-harden-strongswan.service.patch11Patch2: strongswan-5.9.14-harden-strongswan.service.patch
12# https://download.strongswan.org/security/CVE-2025-62291/strongswan-4.4.0-6.0.2_eap_mschapv2_failure_request_len.patch12# https://download.strongswan.org/security/CVE-2025-62291/strongswan-4.4.0-6.0.2_eap_mschapv2_failure_request_len.patch
13Patch6001: strongswan-4.4.0-6.0.2_eap_mschapv2_failure_request_len.patch13Patch6001: strongswan-4.4.0-6.0.2_eap_mschapv2_failure_request_len.patch
14+# https://download.strongswan.org/security/CVE-2026-35334/strongswan-5.3.1-6.0.5_gmp_rsa_decrypt_pad.patch
15+Patch6002: strongswan-5.3.1-6.0.5_gmp_rsa_decrypt_pad.patch
14 16 
15BuildRequires: gcc chrpath autoconf automake libtool tpm2-abrmd17BuildRequires: gcc chrpath autoconf automake libtool tpm2-abrmd
16BuildRequires: systemd-devel gmp-devel libcurl-devel NetworkManager-libnm-devel openldap-devel18BuildRequires: systemd-devel gmp-devel libcurl-devel NetworkManager-libnm-devel openldap-devel
@@ -195,6 +197,9 @@ echo "%{_libdir}/strongswan" > %{buildroot}/etc/ld.so.conf.d/%{name}-%{_arch}.co
195%{_libexecdir}/strongswan/charon-nm197%{_libexecdir}/strongswan/charon-nm
196 198 
197%changelog199%changelog
200+* Sat Jun 13 2026 infra_team <zhaiwenjie1@huawei.com> - 5.9.14-3
201+- fix CVE-2026-35334: gmp plugin RSA decryption NULL pointer dereference
202+ 
198* Sat Nov 08 2025 Funda Wang <fundawang@yeah.net> - 5.9.14-2203* Sat Nov 08 2025 Funda Wang <fundawang@yeah.net> - 5.9.14-2
199- fix CVE-2025-62291204- fix CVE-2025-62291
200 205