summaryrefslogtreecommitdiffstats
path: root/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0004-EAP-pwd-Use-constant-time-and-memory-access-for-find.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0004-EAP-pwd-Use-constant-time-and-memory-access-for-find.patch')
-rw-r--r--meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0004-EAP-pwd-Use-constant-time-and-memory-access-for-find.patch327
1 files changed, 327 insertions, 0 deletions
diff --git a/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0004-EAP-pwd-Use-constant-time-and-memory-access-for-find.patch b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0004-EAP-pwd-Use-constant-time-and-memory-access-for-find.patch
new file mode 100644
index 0000000000..471380c443
--- /dev/null
+++ b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0004-EAP-pwd-Use-constant-time-and-memory-access-for-find.patch
@@ -0,0 +1,327 @@
1From aaf65feac67c3993935634eefe5bc76b9fce03aa Mon Sep 17 00:00:00 2001
2From: Jouni Malinen <jouni@codeaurora.org>
3Date: Tue, 26 Feb 2019 11:59:45 +0200
4Subject: [PATCH 04/14] EAP-pwd: Use constant time and memory access for
5 finding the PWE
6
7This algorithm could leak information to external observers in form of
8timing differences or memory access patterns (cache use). While the
9previous implementation had protection against the most visible timing
10differences (looping 40 rounds and masking the legendre operation), it
11did not protect against memory access patterns between the two possible
12code paths in the masking operations. That might be sufficient to allow
13an unprivileged process running on the same device to be able to
14determine which path is being executed through a cache attack and based
15on that, determine information about the used password.
16
17Convert the PWE finding loop to use constant time functions and
18identical memory access path without different branches for the QR/QNR
19cases to minimize possible side-channel information similarly to the
20changes done for SAE authentication. (CVE-2019-9495)
21
22Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
23Signed-off-by: Adrian Bunk <bunk@stusta.de>
24Upstream-Status: Backport
25CVE: CVE-2019-9495
26---
27 src/eap_common/eap_pwd_common.c | 187 +++++++++++++++++++++-------------------
28 1 file changed, 99 insertions(+), 88 deletions(-)
29
30diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
31index 02fe01e..e49aaf8 100644
32--- a/src/eap_common/eap_pwd_common.c
33+++ b/src/eap_common/eap_pwd_common.c
34@@ -8,11 +8,15 @@
35
36 #include "includes.h"
37 #include "common.h"
38+#include "utils/const_time.h"
39 #include "crypto/sha256.h"
40 #include "crypto/crypto.h"
41 #include "eap_defs.h"
42 #include "eap_pwd_common.h"
43
44+#define MAX_ECC_PRIME_LEN 66
45+
46+
47 /* The random function H(x) = HMAC-SHA256(0^32, x) */
48 struct crypto_hash * eap_pwd_h_init(void)
49 {
50@@ -102,6 +106,15 @@ EAP_PWD_group * get_eap_pwd_group(u16 num)
51 }
52
53
54+static void buf_shift_right(u8 *buf, size_t len, size_t bits)
55+{
56+ size_t i;
57+ for (i = len - 1; i > 0; i--)
58+ buf[i] = (buf[i - 1] << (8 - bits)) | (buf[i] >> bits);
59+ buf[0] >>= bits;
60+}
61+
62+
63 /*
64 * compute a "random" secret point on an elliptic curve based
65 * on the password and identities.
66@@ -113,17 +126,27 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
67 const u8 *token)
68 {
69 struct crypto_bignum *qr = NULL, *qnr = NULL, *one = NULL;
70+ struct crypto_bignum *qr_or_qnr = NULL;
71+ u8 qr_bin[MAX_ECC_PRIME_LEN];
72+ u8 qnr_bin[MAX_ECC_PRIME_LEN];
73+ u8 qr_or_qnr_bin[MAX_ECC_PRIME_LEN];
74+ u8 x_bin[MAX_ECC_PRIME_LEN];
75 struct crypto_bignum *tmp1 = NULL, *tmp2 = NULL, *pm1 = NULL;
76 struct crypto_hash *hash;
77 unsigned char pwe_digest[SHA256_MAC_LEN], *prfbuf = NULL, ctr;
78- int is_odd, ret = 0, check, found = 0;
79- size_t primebytelen, primebitlen;
80- struct crypto_bignum *x_candidate = NULL, *rnd = NULL, *cofactor = NULL;
81+ int ret = 0, check, res;
82+ u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
83+ * mask */
84+ size_t primebytelen = 0, primebitlen;
85+ struct crypto_bignum *x_candidate = NULL, *cofactor = NULL;
86 const struct crypto_bignum *prime;
87+ u8 mask, found_ctr = 0, is_odd = 0;
88
89 if (grp->pwe)
90 return -1;
91
92+ os_memset(x_bin, 0, sizeof(x_bin));
93+
94 prime = crypto_ec_get_prime(grp->group);
95 cofactor = crypto_bignum_init();
96 grp->pwe = crypto_ec_point_init(grp->group);
97@@ -152,8 +175,6 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
98
99 /* get a random quadratic residue and nonresidue */
100 while (!qr || !qnr) {
101- int res;
102-
103 if (crypto_bignum_rand(tmp1, prime) < 0)
104 goto fail;
105 res = crypto_bignum_legendre(tmp1, prime);
106@@ -167,6 +188,11 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
107 if (!tmp1)
108 goto fail;
109 }
110+ if (crypto_bignum_to_bin(qr, qr_bin, sizeof(qr_bin),
111+ primebytelen) < 0 ||
112+ crypto_bignum_to_bin(qnr, qnr_bin, sizeof(qnr_bin),
113+ primebytelen) < 0)
114+ goto fail;
115
116 os_memset(prfbuf, 0, primebytelen);
117 ctr = 0;
118@@ -194,17 +220,16 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
119 eap_pwd_h_update(hash, &ctr, sizeof(ctr));
120 eap_pwd_h_final(hash, pwe_digest);
121
122- crypto_bignum_deinit(rnd, 1);
123- rnd = crypto_bignum_init_set(pwe_digest, SHA256_MAC_LEN);
124- if (!rnd) {
125- wpa_printf(MSG_INFO, "EAP-pwd: unable to create rnd");
126- goto fail;
127- }
128+ is_odd = const_time_select_u8(
129+ found, is_odd, pwe_digest[SHA256_MAC_LEN - 1] & 0x01);
130 if (eap_pwd_kdf(pwe_digest, SHA256_MAC_LEN,
131 (u8 *) "EAP-pwd Hunting And Pecking",
132 os_strlen("EAP-pwd Hunting And Pecking"),
133 prfbuf, primebitlen) < 0)
134 goto fail;
135+ if (primebitlen % 8)
136+ buf_shift_right(prfbuf, primebytelen,
137+ 8 - primebitlen % 8);
138
139 crypto_bignum_deinit(x_candidate, 1);
140 x_candidate = crypto_bignum_init_set(prfbuf, primebytelen);
141@@ -214,24 +239,13 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
142 goto fail;
143 }
144
145- /*
146- * eap_pwd_kdf() returns a string of bits 0..primebitlen but
147- * BN_bin2bn will treat that string of bits as a big endian
148- * number. If the primebitlen is not an even multiple of 8
149- * then excessive bits-- those _after_ primebitlen-- so now
150- * we have to shift right the amount we masked off.
151- */
152- if ((primebitlen % 8) &&
153- crypto_bignum_rshift(x_candidate,
154- (8 - (primebitlen % 8)),
155- x_candidate) < 0)
156- goto fail;
157-
158 if (crypto_bignum_cmp(x_candidate, prime) >= 0)
159 continue;
160
161- wpa_hexdump(MSG_DEBUG, "EAP-pwd: x_candidate",
162- prfbuf, primebytelen);
163+ wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: x_candidate",
164+ prfbuf, primebytelen);
165+ const_time_select_bin(found, x_bin, prfbuf, primebytelen,
166+ x_bin);
167
168 /*
169 * compute y^2 using the equation of the curve
170@@ -261,13 +275,15 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
171 * Flip a coin, multiply by the random quadratic residue or the
172 * random quadratic nonresidue and record heads or tails.
173 */
174- if (crypto_bignum_is_odd(tmp1)) {
175- crypto_bignum_mulmod(tmp2, qr, prime, tmp2);
176- check = 1;
177- } else {
178- crypto_bignum_mulmod(tmp2, qnr, prime, tmp2);
179- check = -1;
180- }
181+ mask = const_time_eq_u8(crypto_bignum_is_odd(tmp1), 1);
182+ check = const_time_select_s8(mask, 1, -1);
183+ const_time_select_bin(mask, qr_bin, qnr_bin, primebytelen,
184+ qr_or_qnr_bin);
185+ crypto_bignum_deinit(qr_or_qnr, 1);
186+ qr_or_qnr = crypto_bignum_init_set(qr_or_qnr_bin, primebytelen);
187+ if (!qr_or_qnr ||
188+ crypto_bignum_mulmod(tmp2, qr_or_qnr, prime, tmp2) < 0)
189+ goto fail;
190
191 /*
192 * Now it's safe to do legendre, if check is 1 then it's
193@@ -275,59 +291,12 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
194 * change result), if check is -1 then it's the opposite test
195 * (multiplying a qr by qnr would make a qnr).
196 */
197- if (crypto_bignum_legendre(tmp2, prime) == check) {
198- if (found == 1)
199- continue;
200-
201- /* need to unambiguously identify the solution */
202- is_odd = crypto_bignum_is_odd(rnd);
203-
204- /*
205- * We know x_candidate is a quadratic residue so set
206- * it here.
207- */
208- if (crypto_ec_point_solve_y_coord(grp->group, grp->pwe,
209- x_candidate,
210- is_odd) != 0) {
211- wpa_printf(MSG_INFO,
212- "EAP-pwd: Could not solve for y");
213- continue;
214- }
215-
216- /*
217- * If there's a solution to the equation then the point
218- * must be on the curve so why check again explicitly?
219- * OpenSSL code says this is required by X9.62. We're
220- * not X9.62 but it can't hurt just to be sure.
221- */
222- if (!crypto_ec_point_is_on_curve(grp->group,
223- grp->pwe)) {
224- wpa_printf(MSG_INFO,
225- "EAP-pwd: point is not on curve");
226- continue;
227- }
228-
229- if (!crypto_bignum_is_one(cofactor)) {
230- /* make sure the point is not in a small
231- * sub-group */
232- if (crypto_ec_point_mul(grp->group, grp->pwe,
233- cofactor,
234- grp->pwe) != 0) {
235- wpa_printf(MSG_INFO,
236- "EAP-pwd: cannot multiply generator by order");
237- continue;
238- }
239- if (crypto_ec_point_is_at_infinity(grp->group,
240- grp->pwe)) {
241- wpa_printf(MSG_INFO,
242- "EAP-pwd: point is at infinity");
243- continue;
244- }
245- }
246- wpa_printf(MSG_DEBUG,
247- "EAP-pwd: found a PWE in %d tries", ctr);
248- found = 1;
249- }
250+ res = crypto_bignum_legendre(tmp2, prime);
251+ if (res == -2)
252+ goto fail;
253+ mask = const_time_eq(res, check);
254+ found_ctr = const_time_select_u8(found, found_ctr, ctr);
255+ found |= mask;
256 }
257 if (found == 0) {
258 wpa_printf(MSG_INFO,
259@@ -335,6 +304,44 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
260 num);
261 goto fail;
262 }
263+
264+ /*
265+ * We know x_candidate is a quadratic residue so set it here.
266+ */
267+ crypto_bignum_deinit(x_candidate, 1);
268+ x_candidate = crypto_bignum_init_set(x_bin, primebytelen);
269+ if (!x_candidate ||
270+ crypto_ec_point_solve_y_coord(grp->group, grp->pwe, x_candidate,
271+ is_odd) != 0) {
272+ wpa_printf(MSG_INFO, "EAP-pwd: Could not solve for y");
273+ goto fail;
274+ }
275+
276+ /*
277+ * If there's a solution to the equation then the point must be on the
278+ * curve so why check again explicitly? OpenSSL code says this is
279+ * required by X9.62. We're not X9.62 but it can't hurt just to be sure.
280+ */
281+ if (!crypto_ec_point_is_on_curve(grp->group, grp->pwe)) {
282+ wpa_printf(MSG_INFO, "EAP-pwd: point is not on curve");
283+ goto fail;
284+ }
285+
286+ if (!crypto_bignum_is_one(cofactor)) {
287+ /* make sure the point is not in a small sub-group */
288+ if (crypto_ec_point_mul(grp->group, grp->pwe, cofactor,
289+ grp->pwe) != 0) {
290+ wpa_printf(MSG_INFO,
291+ "EAP-pwd: cannot multiply generator by order");
292+ goto fail;
293+ }
294+ if (crypto_ec_point_is_at_infinity(grp->group, grp->pwe)) {
295+ wpa_printf(MSG_INFO, "EAP-pwd: point is at infinity");
296+ goto fail;
297+ }
298+ }
299+ wpa_printf(MSG_DEBUG, "EAP-pwd: found a PWE in %02d tries", found_ctr);
300+
301 if (0) {
302 fail:
303 crypto_ec_point_deinit(grp->pwe, 1);
304@@ -344,14 +351,18 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
305 /* cleanliness and order.... */
306 crypto_bignum_deinit(cofactor, 1);
307 crypto_bignum_deinit(x_candidate, 1);
308- crypto_bignum_deinit(rnd, 1);
309 crypto_bignum_deinit(pm1, 0);
310 crypto_bignum_deinit(tmp1, 1);
311 crypto_bignum_deinit(tmp2, 1);
312 crypto_bignum_deinit(qr, 1);
313 crypto_bignum_deinit(qnr, 1);
314+ crypto_bignum_deinit(qr_or_qnr, 1);
315 crypto_bignum_deinit(one, 0);
316- os_free(prfbuf);
317+ bin_clear_free(prfbuf, primebytelen);
318+ os_memset(qr_bin, 0, sizeof(qr_bin));
319+ os_memset(qnr_bin, 0, sizeof(qnr_bin));
320+ os_memset(qr_or_qnr_bin, 0, sizeof(qr_or_qnr_bin));
321+ os_memset(pwe_digest, 0, sizeof(pwe_digest));
322
323 return ret;
324 }
325--
3262.7.4
327