diff options
author | Adrian Bunk <bunk@stusta.de> | 2019-06-19 21:04:22 +0300 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2019-06-30 22:34:23 +0100 |
commit | ee0e9eaafed96587b6f1c6b995cd7d5927170c21 (patch) | |
tree | c3e3b3602923c23aa0614a44b3b4049e6f340dea /meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0004-EAP-pwd-Use-constant-time-and-memory-access-for-find.patch | |
parent | 76c220e5fe43aef1014e6eec7f0136c2b34be308 (diff) | |
download | poky-ee0e9eaafed96587b6f1c6b995cd7d5927170c21.tar.gz |
wpa-supplicant: Fix CVE-2019-9494 CVE-2019-9495 CVE-2019-9496 CVE-2019-9497 CVE-2019-9498 CVE-2019-9499 CVE-2019-11555
(From OE-Core rev: ae8e0440fc1177bf44e46804e1f5927cb86f8324)
Signed-off-by: Adrian Bunk <bunk@stusta.de>
Signed-off-by: Armin Kuster <akuster808@gmail.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
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.patch | 327 |
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 @@ | |||
1 | From aaf65feac67c3993935634eefe5bc76b9fce03aa Mon Sep 17 00:00:00 2001 | ||
2 | From: Jouni Malinen <jouni@codeaurora.org> | ||
3 | Date: Tue, 26 Feb 2019 11:59:45 +0200 | ||
4 | Subject: [PATCH 04/14] EAP-pwd: Use constant time and memory access for | ||
5 | finding the PWE | ||
6 | |||
7 | This algorithm could leak information to external observers in form of | ||
8 | timing differences or memory access patterns (cache use). While the | ||
9 | previous implementation had protection against the most visible timing | ||
10 | differences (looping 40 rounds and masking the legendre operation), it | ||
11 | did not protect against memory access patterns between the two possible | ||
12 | code paths in the masking operations. That might be sufficient to allow | ||
13 | an unprivileged process running on the same device to be able to | ||
14 | determine which path is being executed through a cache attack and based | ||
15 | on that, determine information about the used password. | ||
16 | |||
17 | Convert the PWE finding loop to use constant time functions and | ||
18 | identical memory access path without different branches for the QR/QNR | ||
19 | cases to minimize possible side-channel information similarly to the | ||
20 | changes done for SAE authentication. (CVE-2019-9495) | ||
21 | |||
22 | Signed-off-by: Jouni Malinen <jouni@codeaurora.org> | ||
23 | Signed-off-by: Adrian Bunk <bunk@stusta.de> | ||
24 | Upstream-Status: Backport | ||
25 | CVE: CVE-2019-9495 | ||
26 | --- | ||
27 | src/eap_common/eap_pwd_common.c | 187 +++++++++++++++++++++------------------- | ||
28 | 1 file changed, 99 insertions(+), 88 deletions(-) | ||
29 | |||
30 | diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c | ||
31 | index 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 | -- | ||
326 | 2.7.4 | ||
327 | |||