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/0005-SAE-Minimize-timing-differences-in-PWE-derivation.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/0005-SAE-Minimize-timing-differences-in-PWE-derivation.patch')
-rw-r--r-- | meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0005-SAE-Minimize-timing-differences-in-PWE-derivation.patch | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0005-SAE-Minimize-timing-differences-in-PWE-derivation.patch b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0005-SAE-Minimize-timing-differences-in-PWE-derivation.patch new file mode 100644 index 0000000000..6a567c5fb6 --- /dev/null +++ b/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0005-SAE-Minimize-timing-differences-in-PWE-derivation.patch | |||
@@ -0,0 +1,244 @@ | |||
1 | From 6513db3e96c43c2e36805cf5ead349765d18eaf7 Mon Sep 17 00:00:00 2001 | ||
2 | From: Jouni Malinen <jouni@codeaurora.org> | ||
3 | Date: Tue, 26 Feb 2019 13:05:09 +0200 | ||
4 | Subject: [PATCH 05/14] SAE: Minimize timing differences in PWE derivation | ||
5 | |||
6 | The QR test result can provide information about the password to an | ||
7 | attacker, so try to minimize differences in how the | ||
8 | sae_test_pwd_seed_ecc() result is used. (CVE-2019-9494) | ||
9 | |||
10 | Use heap memory for the dummy password to allow the same password length | ||
11 | to be used even with long passwords. | ||
12 | |||
13 | Use constant time selection functions to track the real vs. dummy | ||
14 | variables so that the exact same operations can be performed for both QR | ||
15 | test results. | ||
16 | |||
17 | Signed-off-by: Jouni Malinen <jouni@codeaurora.org> | ||
18 | Signed-off-by: Adrian Bunk <bunk@stusta.de> | ||
19 | Upstream-Status: Backport | ||
20 | CVE: CVE-2019-9494 | ||
21 | --- | ||
22 | src/common/sae.c | 106 ++++++++++++++++++++++++++++++------------------------- | ||
23 | 1 file changed, 57 insertions(+), 49 deletions(-) | ||
24 | |||
25 | diff --git a/src/common/sae.c b/src/common/sae.c | ||
26 | index 8129a7c..d55323b 100644 | ||
27 | --- a/src/common/sae.c | ||
28 | +++ b/src/common/sae.c | ||
29 | @@ -9,6 +9,7 @@ | ||
30 | #include "includes.h" | ||
31 | |||
32 | #include "common.h" | ||
33 | +#include "utils/const_time.h" | ||
34 | #include "crypto/crypto.h" | ||
35 | #include "crypto/sha256.h" | ||
36 | #include "crypto/random.h" | ||
37 | @@ -292,15 +293,12 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed, | ||
38 | const u8 *prime, | ||
39 | const struct crypto_bignum *qr, | ||
40 | const struct crypto_bignum *qnr, | ||
41 | - struct crypto_bignum **ret_x_cand) | ||
42 | + u8 *pwd_value) | ||
43 | { | ||
44 | - u8 pwd_value[SAE_MAX_ECC_PRIME_LEN]; | ||
45 | struct crypto_bignum *y_sqr, *x_cand; | ||
46 | int res; | ||
47 | size_t bits; | ||
48 | |||
49 | - *ret_x_cand = NULL; | ||
50 | - | ||
51 | wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN); | ||
52 | |||
53 | /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */ | ||
54 | @@ -309,7 +307,7 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed, | ||
55 | prime, sae->tmp->prime_len, pwd_value, bits) < 0) | ||
56 | return -1; | ||
57 | if (bits % 8) | ||
58 | - buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8); | ||
59 | + buf_shift_right(pwd_value, sae->tmp->prime_len, 8 - bits % 8); | ||
60 | wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", | ||
61 | pwd_value, sae->tmp->prime_len); | ||
62 | |||
63 | @@ -320,20 +318,13 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed, | ||
64 | if (!x_cand) | ||
65 | return -1; | ||
66 | y_sqr = crypto_ec_point_compute_y_sqr(sae->tmp->ec, x_cand); | ||
67 | - if (!y_sqr) { | ||
68 | - crypto_bignum_deinit(x_cand, 1); | ||
69 | + crypto_bignum_deinit(x_cand, 1); | ||
70 | + if (!y_sqr) | ||
71 | return -1; | ||
72 | - } | ||
73 | |||
74 | res = is_quadratic_residue_blind(sae, prime, bits, qr, qnr, y_sqr); | ||
75 | crypto_bignum_deinit(y_sqr, 1); | ||
76 | - if (res <= 0) { | ||
77 | - crypto_bignum_deinit(x_cand, 1); | ||
78 | - return res; | ||
79 | - } | ||
80 | - | ||
81 | - *ret_x_cand = x_cand; | ||
82 | - return 1; | ||
83 | + return res; | ||
84 | } | ||
85 | |||
86 | |||
87 | @@ -454,25 +445,30 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, | ||
88 | const u8 *addr[3]; | ||
89 | size_t len[3]; | ||
90 | size_t num_elem; | ||
91 | - u8 dummy_password[32]; | ||
92 | - size_t dummy_password_len; | ||
93 | + u8 *dummy_password, *tmp_password; | ||
94 | int pwd_seed_odd = 0; | ||
95 | u8 prime[SAE_MAX_ECC_PRIME_LEN]; | ||
96 | size_t prime_len; | ||
97 | - struct crypto_bignum *x = NULL, *qr, *qnr; | ||
98 | + struct crypto_bignum *x = NULL, *qr = NULL, *qnr = NULL; | ||
99 | + u8 x_bin[SAE_MAX_ECC_PRIME_LEN]; | ||
100 | + u8 x_cand_bin[SAE_MAX_ECC_PRIME_LEN]; | ||
101 | size_t bits; | ||
102 | - int res; | ||
103 | + int res = -1; | ||
104 | + u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_* | ||
105 | + * mask */ | ||
106 | |||
107 | - dummy_password_len = password_len; | ||
108 | - if (dummy_password_len > sizeof(dummy_password)) | ||
109 | - dummy_password_len = sizeof(dummy_password); | ||
110 | - if (random_get_bytes(dummy_password, dummy_password_len) < 0) | ||
111 | - return -1; | ||
112 | + os_memset(x_bin, 0, sizeof(x_bin)); | ||
113 | + | ||
114 | + dummy_password = os_malloc(password_len); | ||
115 | + tmp_password = os_malloc(password_len); | ||
116 | + if (!dummy_password || !tmp_password || | ||
117 | + random_get_bytes(dummy_password, password_len) < 0) | ||
118 | + goto fail; | ||
119 | |||
120 | prime_len = sae->tmp->prime_len; | ||
121 | if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime), | ||
122 | prime_len) < 0) | ||
123 | - return -1; | ||
124 | + goto fail; | ||
125 | bits = crypto_ec_prime_len_bits(sae->tmp->ec); | ||
126 | |||
127 | /* | ||
128 | @@ -481,7 +477,7 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, | ||
129 | */ | ||
130 | if (get_random_qr_qnr(prime, prime_len, sae->tmp->prime, bits, | ||
131 | &qr, &qnr) < 0) | ||
132 | - return -1; | ||
133 | + goto fail; | ||
134 | |||
135 | wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password", | ||
136 | password, password_len); | ||
137 | @@ -497,7 +493,7 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, | ||
138 | */ | ||
139 | sae_pwd_seed_key(addr1, addr2, addrs); | ||
140 | |||
141 | - addr[0] = password; | ||
142 | + addr[0] = tmp_password; | ||
143 | len[0] = password_len; | ||
144 | num_elem = 1; | ||
145 | if (identifier) { | ||
146 | @@ -514,9 +510,8 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, | ||
147 | * attacks that attempt to determine the number of iterations required | ||
148 | * in the loop. | ||
149 | */ | ||
150 | - for (counter = 1; counter <= k || !x; counter++) { | ||
151 | + for (counter = 1; counter <= k || !found; counter++) { | ||
152 | u8 pwd_seed[SHA256_MAC_LEN]; | ||
153 | - struct crypto_bignum *x_cand; | ||
154 | |||
155 | if (counter > 200) { | ||
156 | /* This should not happen in practice */ | ||
157 | @@ -524,36 +519,45 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, | ||
158 | break; | ||
159 | } | ||
160 | |||
161 | - wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter); | ||
162 | + wpa_printf(MSG_DEBUG, "SAE: counter = %03u", counter); | ||
163 | + const_time_select_bin(found, dummy_password, password, | ||
164 | + password_len, tmp_password); | ||
165 | if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem, | ||
166 | addr, len, pwd_seed) < 0) | ||
167 | break; | ||
168 | |||
169 | res = sae_test_pwd_seed_ecc(sae, pwd_seed, | ||
170 | - prime, qr, qnr, &x_cand); | ||
171 | + prime, qr, qnr, x_cand_bin); | ||
172 | + const_time_select_bin(found, x_bin, x_cand_bin, prime_len, | ||
173 | + x_bin); | ||
174 | + pwd_seed_odd = const_time_select_u8( | ||
175 | + found, pwd_seed_odd, | ||
176 | + pwd_seed[SHA256_MAC_LEN - 1] & 0x01); | ||
177 | + os_memset(pwd_seed, 0, sizeof(pwd_seed)); | ||
178 | if (res < 0) | ||
179 | goto fail; | ||
180 | - if (res > 0 && !x) { | ||
181 | - wpa_printf(MSG_DEBUG, | ||
182 | - "SAE: Selected pwd-seed with counter %u", | ||
183 | - counter); | ||
184 | - x = x_cand; | ||
185 | - pwd_seed_odd = pwd_seed[SHA256_MAC_LEN - 1] & 0x01; | ||
186 | - os_memset(pwd_seed, 0, sizeof(pwd_seed)); | ||
187 | + /* Need to minimize differences in handling res == 0 and 1 here | ||
188 | + * to avoid differences in timing and instruction cache access, | ||
189 | + * so use const_time_select_*() to make local copies of the | ||
190 | + * values based on whether this loop iteration was the one that | ||
191 | + * found the pwd-seed/x. */ | ||
192 | + | ||
193 | + /* found is 0 or 0xff here and res is 0 or 1. Bitwise OR of them | ||
194 | + * (with res converted to 0/0xff) handles this in constant time. | ||
195 | + */ | ||
196 | + found |= res * 0xff; | ||
197 | + wpa_printf(MSG_DEBUG, "SAE: pwd-seed result %d found=0x%02x", | ||
198 | + res, found); | ||
199 | + } | ||
200 | |||
201 | - /* | ||
202 | - * Use a dummy password for the following rounds, if | ||
203 | - * any. | ||
204 | - */ | ||
205 | - addr[0] = dummy_password; | ||
206 | - len[0] = dummy_password_len; | ||
207 | - } else if (res > 0) { | ||
208 | - crypto_bignum_deinit(x_cand, 1); | ||
209 | - } | ||
210 | + if (!found) { | ||
211 | + wpa_printf(MSG_DEBUG, "SAE: Could not generate PWE"); | ||
212 | + res = -1; | ||
213 | + goto fail; | ||
214 | } | ||
215 | |||
216 | + x = crypto_bignum_init_set(x_bin, prime_len); | ||
217 | if (!x) { | ||
218 | - wpa_printf(MSG_DEBUG, "SAE: Could not generate PWE"); | ||
219 | res = -1; | ||
220 | goto fail; | ||
221 | } | ||
222 | @@ -566,7 +570,6 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, | ||
223 | res = crypto_ec_point_solve_y_coord(sae->tmp->ec, | ||
224 | sae->tmp->pwe_ecc, x, | ||
225 | pwd_seed_odd); | ||
226 | - crypto_bignum_deinit(x, 1); | ||
227 | if (res < 0) { | ||
228 | /* | ||
229 | * This should not happen since we already checked that there | ||
230 | @@ -578,6 +581,11 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, | ||
231 | fail: | ||
232 | crypto_bignum_deinit(qr, 0); | ||
233 | crypto_bignum_deinit(qnr, 0); | ||
234 | + os_free(dummy_password); | ||
235 | + bin_clear_free(tmp_password, password_len); | ||
236 | + crypto_bignum_deinit(x, 1); | ||
237 | + os_memset(x_bin, 0, sizeof(x_bin)); | ||
238 | + os_memset(x_cand_bin, 0, sizeof(x_cand_bin)); | ||
239 | |||
240 | return res; | ||
241 | } | ||
242 | -- | ||
243 | 2.7.4 | ||
244 | |||