summaryrefslogtreecommitdiffstats
path: root/meta/recipes-connectivity/wpa-supplicant/wpa-supplicant/0005-SAE-Minimize-timing-differences-in-PWE-derivation.patch
diff options
context:
space:
mode:
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.patch244
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 @@
1From 6513db3e96c43c2e36805cf5ead349765d18eaf7 Mon Sep 17 00:00:00 2001
2From: Jouni Malinen <jouni@codeaurora.org>
3Date: Tue, 26 Feb 2019 13:05:09 +0200
4Subject: [PATCH 05/14] SAE: Minimize timing differences in PWE derivation
5
6The QR test result can provide information about the password to an
7attacker, so try to minimize differences in how the
8sae_test_pwd_seed_ecc() result is used. (CVE-2019-9494)
9
10Use heap memory for the dummy password to allow the same password length
11to be used even with long passwords.
12
13Use constant time selection functions to track the real vs. dummy
14variables so that the exact same operations can be performed for both QR
15test results.
16
17Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
18Signed-off-by: Adrian Bunk <bunk@stusta.de>
19Upstream-Status: Backport
20CVE: CVE-2019-9494
21---
22 src/common/sae.c | 106 ++++++++++++++++++++++++++++++-------------------------
23 1 file changed, 57 insertions(+), 49 deletions(-)
24
25diff --git a/src/common/sae.c b/src/common/sae.c
26index 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--
2432.7.4
244