1 /*
2 * Simultaneous authentication of equals
3 * Copyright (c) 2012-2016, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9 #ifdef CONFIG_WPA3_SAE
10
11 #include "utils/includes.h"
12 #include "utils/common.h"
13 #include "utils/const_time.h"
14 #include "crypto/crypto.h"
15 #include "crypto/sha256.h"
16 #include "crypto/random.h"
17 #include "crypto/dh_groups.h"
18 #include "ieee802_11_defs.h"
19 #include "sae.h"
20 #include "dragonfly.h"
21 #include "esp_wifi_crypto_types.h"
22 #include "common/defs.h"
23
sae_set_group(struct sae_data * sae,int group)24 int sae_set_group(struct sae_data *sae, int group)
25 {
26 struct sae_temporary_data *tmp;
27
28 sae_clear_data(sae);
29 tmp = sae->tmp = os_zalloc(sizeof(*tmp));
30 if (tmp == NULL)
31 return ESP_FAIL;
32
33 /* First, check if this is an ECC group */
34 tmp->ec = crypto_ec_init(group);
35 if (tmp->ec) {
36 wpa_printf(MSG_DEBUG, "SAE: Selecting supported ECC group %d",
37 group);
38 sae->group = group;
39 tmp->prime_len = crypto_ec_prime_len(tmp->ec);
40 tmp->prime = crypto_ec_get_prime(tmp->ec);
41 tmp->order_len = crypto_ec_order_len(tmp->ec);
42 tmp->order = crypto_ec_get_order(tmp->ec);
43 return ESP_OK;
44 }
45
46 /* Not an ECC group, check FFC */
47 tmp->dh = dh_groups_get(group);
48 if (tmp->dh) {
49 wpa_printf(MSG_DEBUG, "SAE: Selecting supported FFC group %d",
50 group);
51 sae->group = group;
52 tmp->prime_len = tmp->dh->prime_len;
53 if (tmp->prime_len > SAE_MAX_PRIME_LEN) {
54 sae_clear_data(sae);
55 return ESP_FAIL;
56 }
57
58 tmp->prime_buf = crypto_bignum_init_set(tmp->dh->prime,
59 tmp->prime_len);
60 if (tmp->prime_buf == NULL) {
61 sae_clear_data(sae);
62 return ESP_FAIL;
63 }
64 tmp->prime = tmp->prime_buf;
65
66 tmp->order_len = tmp->dh->order_len;
67 tmp->order_buf = crypto_bignum_init_set(tmp->dh->order,
68 tmp->dh->order_len);
69 if (tmp->order_buf == NULL) {
70 sae_clear_data(sae);
71 return ESP_FAIL;
72 }
73 tmp->order = tmp->order_buf;
74
75 return ESP_OK;
76 }
77
78 /* Unsupported group */
79 wpa_printf(MSG_DEBUG,
80 "SAE: Group %d not supported by the crypto library", group);
81 return ESP_FAIL;
82 }
83
84
sae_clear_temp_data(struct sae_data * sae)85 void sae_clear_temp_data(struct sae_data *sae)
86 {
87 struct sae_temporary_data *tmp;
88 if (sae == NULL || sae->tmp == NULL)
89 return;
90 tmp = sae->tmp;
91 crypto_ec_deinit(tmp->ec);
92 crypto_bignum_deinit(tmp->prime_buf, 0);
93 crypto_bignum_deinit(tmp->order_buf, 0);
94 crypto_bignum_deinit(tmp->sae_rand, 1);
95 crypto_bignum_deinit(tmp->pwe_ffc, 1);
96 crypto_bignum_deinit(tmp->own_commit_scalar, 0);
97 crypto_bignum_deinit(tmp->own_commit_element_ffc, 0);
98 crypto_bignum_deinit(tmp->peer_commit_element_ffc, 0);
99 crypto_ec_point_deinit(tmp->pwe_ecc, 1);
100 crypto_ec_point_deinit(tmp->own_commit_element_ecc, 0);
101 crypto_ec_point_deinit(tmp->peer_commit_element_ecc, 0);
102 wpabuf_free(tmp->anti_clogging_token);
103 wpabuf_free(tmp->own_rejected_groups);
104 wpabuf_free(tmp->peer_rejected_groups);
105 os_free(tmp->pw_id);
106 bin_clear_free(tmp, sizeof(*tmp));
107 sae->tmp = NULL;
108 }
109
sae_clear_data(struct sae_data * sae)110 void sae_clear_data(struct sae_data *sae)
111 {
112 if (sae == NULL)
113 return;
114 sae_clear_temp_data(sae);
115 crypto_bignum_deinit(sae->peer_commit_scalar, 0);
116 crypto_bignum_deinit(sae->peer_commit_scalar_accepted, 0);
117 os_memset(sae, 0, sizeof(*sae));
118 }
119
120
sae_pwd_seed_key(const u8 * addr1,const u8 * addr2,u8 * key)121 static void sae_pwd_seed_key(const u8 *addr1, const u8 *addr2, u8 *key)
122 {
123 wpa_printf(MSG_DEBUG, "SAE: PWE derivation - addr1=" MACSTR
124 " addr2=" MACSTR, MAC2STR(addr1), MAC2STR(addr2));
125 if (os_memcmp(addr1, addr2, ETH_ALEN) > 0) {
126 os_memcpy(key, addr1, ETH_ALEN);
127 os_memcpy(key + ETH_ALEN, addr2, ETH_ALEN);
128 } else {
129 os_memcpy(key, addr2, ETH_ALEN);
130 os_memcpy(key + ETH_ALEN, addr1, ETH_ALEN);
131 }
132 }
133
sae_test_pwd_seed_ecc(struct sae_data * sae,const u8 * pwd_seed,const u8 * prime,const u8 * qr,const u8 * qnr,u8 * pwd_value)134 static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
135 const u8 *prime, const u8 *qr, const u8 *qnr,
136 u8 *pwd_value)
137 {
138 struct crypto_bignum *y_sqr, *x_cand;
139 int res;
140 size_t bits;
141 int cmp_prime;
142 unsigned int in_range;
143
144 wpa_hexdump_key(MSG_MSGDUMP, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
145
146 /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
147 bits = crypto_ec_prime_len_bits(sae->tmp->ec);
148 if (sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
149 prime, sae->tmp->prime_len, pwd_value, bits) < 0)
150 return ESP_FAIL;
151 if (bits % 8)
152 buf_shift_right(pwd_value, sae->tmp->prime_len, 8 - bits % 8);
153 wpa_hexdump_key(MSG_MSGDUMP, "SAE: pwd-value",
154 pwd_value, sae->tmp->prime_len);
155
156 cmp_prime = const_time_memcmp(pwd_value, prime, sae->tmp->prime_len);
157 /* Create a const_time mask for selection based on prf result
158 * being smaller than prime. */
159 in_range = const_time_fill_msb((unsigned int) cmp_prime);
160 /* The algorithm description would skip the next steps if
161 * cmp_prime >= 0 (return 0 here), but go through them regardless to
162 * minimize externally observable differences in behavior. */
163
164 x_cand = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
165 if (!x_cand)
166 return ESP_FAIL;
167 y_sqr = crypto_ec_point_compute_y_sqr(sae->tmp->ec, x_cand);
168 crypto_bignum_deinit(x_cand, 1);
169 if (!y_sqr)
170 return ESP_FAIL;
171
172 res = dragonfly_is_quadratic_residue_blind(sae->tmp->ec, qr, qnr,
173 y_sqr);
174 crypto_bignum_deinit(y_sqr, 1);
175
176 if (res < 0) {
177 return res;
178 }
179 return const_time_select_int(in_range, res, 0);
180 }
181
182
183 /* Returns -1 on fatal failure, 0 if PWE cannot be derived from the provided
184 * pwd-seed, or 1 if a valid PWE was derived from pwd-seed. */
sae_test_pwd_seed_ffc(struct sae_data * sae,const u8 * pwd_seed,struct crypto_bignum * pwe)185 static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
186 struct crypto_bignum *pwe)
187 {
188 u8 pwd_value[SAE_MAX_PRIME_LEN];
189 size_t bits = sae->tmp->prime_len * 8;
190 u8 exp[1];
191 struct crypto_bignum *a, *b = NULL;
192 int res, is_val;
193 u8 pwd_value_valid;
194
195 wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
196
197 /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
198 if (sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
199 sae->tmp->dh->prime, sae->tmp->prime_len, pwd_value,
200 bits) < 0)
201 return ESP_FAIL;
202 wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", pwd_value,
203 sae->tmp->prime_len);
204
205 /* Check whether pwd-value < p */
206 res = const_time_memcmp(pwd_value, sae->tmp->dh->prime,
207 sae->tmp->prime_len);
208 /* pwd-value >= p is invalid, so res is < 0 for the valid cases and
209 * the negative sign can be used to fill the mask for constant time
210 * selection */
211 pwd_value_valid = const_time_fill_msb(res);
212
213 /* If pwd-value >= p, force pwd-value to be < p and perform the
214 * calculations anyway to hide timing difference. The derived PWE will
215 * be ignored in that case. */
216 pwd_value[0] = const_time_select_u8(pwd_value_valid, pwd_value[0], 0);
217
218 /* PWE = pwd-value^((p-1)/r) modulo p */
219
220 res = -1;
221 a = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
222
223 if (!a)
224 goto fail;
225
226 /* This is an optimization based on the used group that does not depend
227 * on the password in any way, so it is fine to use separate branches
228 * for this step without constant time operations. */
229 if (sae->tmp->dh->safe_prime) {
230 /*
231 * r = (p-1)/2 for the group used here, so this becomes:
232 * PWE = pwd-value^2 modulo p
233 */
234 exp[0] = 2;
235 b = crypto_bignum_init_set(exp, sizeof(exp));
236 } else {
237 /* Calculate exponent: (p-1)/r */
238 exp[0] = 1;
239 b = crypto_bignum_init_set(exp, sizeof(exp));
240 if (b == NULL ||
241 crypto_bignum_sub(sae->tmp->prime, b, b) < 0 ||
242 crypto_bignum_div(b, sae->tmp->order, b) < 0)
243 goto fail;
244 }
245
246
247 if (!b)
248 goto fail;
249
250 res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe);
251 if (res < 0)
252 goto fail;
253
254 /* There were no fatal errors in calculations, so determine the return
255 * value using constant time operations. We get here for number of
256 * invalid cases which are cleared here after having performed all the
257 * computation. PWE is valid if pwd-value was less than prime and
258 * PWE > 1. Start with pwd-value check first and then use constant time
259 * operations to clear res to 0 if PWE is 0 or 1.
260 */
261 res = const_time_select_u8(pwd_value_valid, 1, 0);
262 is_val = crypto_bignum_is_zero(pwe);
263 res = const_time_select_u8(const_time_is_zero(is_val), res, 0);
264 is_val = crypto_bignum_is_one(pwe);
265 res = const_time_select_u8(const_time_is_zero(is_val), res, 0);
266
267 fail:
268 crypto_bignum_deinit(a, 1);
269 crypto_bignum_deinit(b, 1);
270 return res;
271 }
272
273
sae_derive_pwe_ecc(struct sae_data * sae,const u8 * addr1,const u8 * addr2,const u8 * password,size_t password_len)274 static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
275 const u8 *addr2, const u8 *password,
276 size_t password_len)
277 {
278 u8 counter, k;
279 u8 addrs[2 * ETH_ALEN];
280 const u8 *addr[2];
281 size_t len[2];
282 u8 *stub_password, *tmp_password;
283 int pwd_seed_odd = 0;
284 u8 prime[SAE_MAX_ECC_PRIME_LEN];
285 size_t prime_len;
286 struct crypto_bignum *x = NULL, *y = NULL, *qr = NULL, *qnr = NULL;
287 u8 x_bin[SAE_MAX_ECC_PRIME_LEN];
288 u8 x_cand_bin[SAE_MAX_ECC_PRIME_LEN];
289 u8 qr_bin[SAE_MAX_ECC_PRIME_LEN];
290 u8 qnr_bin[SAE_MAX_ECC_PRIME_LEN];
291 u8 x_y[2 * SAE_MAX_ECC_PRIME_LEN];
292 int res = -1;
293 u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
294 * mask */
295 unsigned int is_eq;
296
297 os_memset(x_bin, 0, sizeof(x_bin));
298
299 stub_password = os_malloc(password_len);
300 tmp_password = os_malloc(password_len);
301 if (!stub_password || !tmp_password ||
302 random_get_bytes(stub_password, password_len) < 0)
303 goto fail;
304
305 prime_len = sae->tmp->prime_len;
306 if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
307 prime_len) < 0)
308 goto fail;
309
310 /*
311 * Create a random quadratic residue (qr) and quadratic non-residue
312 * (qnr) modulo p for blinding purposes during the loop.
313 */
314 if (dragonfly_get_random_qr_qnr(sae->tmp->prime, &qr, &qnr) < 0 ||
315 crypto_bignum_to_bin(qr, qr_bin, sizeof(qr_bin), prime_len) < 0 ||
316 crypto_bignum_to_bin(qnr, qnr_bin, sizeof(qnr_bin), prime_len) < 0)
317 goto fail;
318
319 wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
320 password, password_len);
321
322 /*
323 * H(salt, ikm) = HMAC-SHA256(salt, ikm)
324 * base = password
325 * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
326 * base || counter)
327 */
328 sae_pwd_seed_key(addr1, addr2, addrs);
329
330 addr[0] = tmp_password;
331 len[0] = password_len;
332 addr[1] = &counter;
333 len[1] = sizeof(counter);
334
335 k = dragonfly_min_pwe_loop_iter(sae->group);
336
337 /*
338 * Continue for at least k iterations to protect against side-channel
339 * attacks that attempt to determine the number of iterations required
340 * in the loop.
341 */
342 for (counter = 1; counter <= k || !found; counter++) {
343 u8 pwd_seed[SHA256_MAC_LEN];
344
345 if (counter > 200) {
346 /* This should not happen in practice */
347 wpa_printf(MSG_DEBUG, "SAE: Failed to derive PWE");
348 break;
349 }
350
351 wpa_printf(MSG_MSGDUMP, "SAE: counter = %03u", counter);
352 const_time_select_bin(found, stub_password, password,
353 password_len, tmp_password);
354 if (hmac_sha256_vector(addrs, sizeof(addrs), 2,
355 addr, len, pwd_seed) < 0)
356 break;
357
358 res = sae_test_pwd_seed_ecc(sae, pwd_seed,
359 prime, qr_bin, qnr_bin, x_cand_bin);
360 const_time_select_bin(found, x_bin, x_cand_bin, prime_len,
361 x_bin);
362 pwd_seed_odd = const_time_select_u8(
363 found, pwd_seed_odd,
364 pwd_seed[SHA256_MAC_LEN - 1] & 0x01);
365 os_memset(pwd_seed, 0, sizeof(pwd_seed));
366 if (res < 0)
367 goto fail;
368 /* Need to minimize differences in handling res == 0 and 1 here
369 * to avoid differences in timing and instruction cache access,
370 * so use const_time_select_*() to make local copies of the
371 * values based on whether this loop iteration was the one that
372 * found the pwd-seed/x. */
373
374 /* found is 0 or 0xff here and res is 0 or 1. Bitwise OR of them
375 * (with res converted to 0/0xff) handles this in constant time.
376 */
377 found |= res * 0xff;
378 wpa_printf(MSG_MSGDUMP, "SAE: pwd-seed result %d found=0x%02x",
379 res, found);
380 }
381
382 if (!found) {
383 wpa_printf(MSG_DEBUG, "SAE: Could not generate PWE");
384 res = -1;
385 goto fail;
386 }
387
388 x = crypto_bignum_init_set(x_bin, prime_len);
389 if (!x) {
390 res = -1;
391 goto fail;
392 }
393
394 /* y = sqrt(x^3 + ax + b) mod p
395 * if LSB(save) == LSB(y): PWE = (x, y)
396 * else: PWE = (x, p - y)
397 *
398 * Calculate y and the two possible values for PWE and after that,
399 * use constant time selection to copy the correct alternative.
400 */
401 y = crypto_ec_point_compute_y_sqr(sae->tmp->ec, x);
402 if (!y ||
403 dragonfly_sqrt(sae->tmp->ec, y, y) < 0 ||
404 crypto_bignum_to_bin(y, x_y, SAE_MAX_ECC_PRIME_LEN,
405 prime_len) < 0 ||
406 crypto_bignum_sub(sae->tmp->prime, y, y) < 0 ||
407 crypto_bignum_to_bin(y, x_y + SAE_MAX_ECC_PRIME_LEN,
408 SAE_MAX_ECC_PRIME_LEN, prime_len) < 0) {
409 wpa_printf(MSG_DEBUG, "SAE: Could not solve y");
410 goto fail;
411 }
412
413 is_eq = const_time_eq(pwd_seed_odd, x_y[prime_len - 1] & 0x01);
414 const_time_select_bin(is_eq, x_y, x_y + SAE_MAX_ECC_PRIME_LEN,
415 prime_len, x_y + prime_len);
416 os_memcpy(x_y, x_bin, prime_len);
417 wpa_hexdump_key(MSG_DEBUG, "SAE: PWE", x_y, 2 * prime_len);
418 crypto_ec_point_deinit(sae->tmp->pwe_ecc, 1);
419 sae->tmp->pwe_ecc = crypto_ec_point_from_bin(sae->tmp->ec, x_y);
420 if (!sae->tmp->pwe_ecc) {
421 wpa_printf(MSG_DEBUG, "SAE: Could not generate PWE");
422 res = -1;
423 }
424
425 fail:
426 forced_memzero(x_y, sizeof(x_y));
427 crypto_bignum_deinit(qr, 0);
428 crypto_bignum_deinit(qnr, 0);
429 crypto_bignum_deinit(y, 1);
430 os_free(stub_password);
431 bin_clear_free(tmp_password, password_len);
432 crypto_bignum_deinit(x, 1);
433 os_memset(x_bin, 0, sizeof(x_bin));
434 os_memset(x_cand_bin, 0, sizeof(x_cand_bin));
435 return res;
436 }
437
438
sae_derive_pwe_ffc(struct sae_data * sae,const u8 * addr1,const u8 * addr2,const u8 * password,size_t password_len)439 static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
440 const u8 *addr2, const u8 *password,
441 size_t password_len)
442 {
443 u8 counter, k, sel_counter = 0;
444 u8 addrs[2 * ETH_ALEN];
445 const u8 *addr[2];
446 size_t len[2];
447 u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
448 * mask */
449 u8 mask;
450 struct crypto_bignum *pwe;
451 size_t prime_len = sae->tmp->prime_len * 8;
452 u8 *pwe_buf;
453 crypto_bignum_deinit(sae->tmp->pwe_ffc, 1);
454 sae->tmp->pwe_ffc = NULL;
455
456 /* Allocate a buffer to maintain selected and candidate PWE for constant
457 * time selection. */
458 pwe_buf = os_zalloc(prime_len * 2);
459 pwe = crypto_bignum_init();
460 if (!pwe_buf || !pwe)
461 goto fail;
462
463 wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
464 password, password_len);
465
466 /*
467 * H(salt, ikm) = HMAC-SHA256(salt, ikm)
468 * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
469 * password || counter)
470 */
471 sae_pwd_seed_key(addr1, addr2, addrs);
472
473 addr[0] = password;
474 len[0] = password_len;
475 addr[1] = &counter;
476 len[1] = sizeof(counter);
477
478 k = dragonfly_min_pwe_loop_iter(sae->group);
479
480 for (counter = 1; counter <= k || !found; counter++) {
481 u8 pwd_seed[SHA256_MAC_LEN];
482 int res;
483
484 if (counter > 200) {
485 /* This should not happen in practice */
486 wpa_printf(MSG_DEBUG, "SAE: Failed to derive PWE");
487 break;
488 }
489
490 wpa_printf(MSG_DEBUG, "SAE: counter = %02u", counter);
491 if (hmac_sha256_vector(addrs, sizeof(addrs), 2,
492 addr, len, pwd_seed) < 0)
493 break;
494 res = sae_test_pwd_seed_ffc(sae, pwd_seed, pwe);
495 /* res is -1 for fatal failure, 0 if a valid PWE was not found,
496 * or 1 if a valid PWE was found. */
497 if (res < 0)
498 break;
499 /* Store the candidate PWE into the second half of pwe_buf and
500 * the selected PWE in the beginning of pwe_buf using constant
501 * time selection. */
502 if (crypto_bignum_to_bin(pwe, pwe_buf + prime_len, prime_len,
503 prime_len) < 0)
504 break;
505 const_time_select_bin(found, pwe_buf, pwe_buf + prime_len,
506 prime_len, pwe_buf);
507 sel_counter = const_time_select_u8(found, sel_counter, counter);
508 mask = const_time_eq_u8(res, 1);
509 found = const_time_select_u8(found, found, mask);
510 }
511
512 if (!found)
513 goto fail;
514
515 wpa_printf(MSG_DEBUG, "SAE: Use PWE from counter = %02u", sel_counter);
516 sae->tmp->pwe_ffc = crypto_bignum_init_set(pwe_buf, prime_len);
517 fail:
518 crypto_bignum_deinit(pwe, 1);
519 bin_clear_free(pwe_buf, prime_len * 2);
520 return sae->tmp->pwe_ffc ? 0 : -1;
521 }
522
523
hkdf_extract(size_t hash_len,const u8 * salt,size_t salt_len,size_t num_elem,const u8 * addr[],const size_t len[],u8 * prk)524 static int hkdf_extract(size_t hash_len, const u8 *salt, size_t salt_len,
525 size_t num_elem, const u8 *addr[], const size_t len[],
526 u8 *prk)
527 {
528 if (hash_len == 32)
529 return hmac_sha256_vector(salt, salt_len, num_elem, addr, len,
530 prk);
531 return -1;
532 }
533
534
hkdf_expand(size_t hash_len,const u8 * prk,size_t prk_len,const char * info,u8 * okm,size_t okm_len)535 static int hkdf_expand(size_t hash_len, const u8 *prk, size_t prk_len,
536 const char *info, u8 *okm, size_t okm_len)
537 {
538 size_t info_len = os_strlen(info);
539
540 if (hash_len == 32)
541 return hmac_sha256_kdf(prk, prk_len, NULL,
542 (const u8 *) info, info_len,
543 okm, okm_len);
544 return -1;
545 }
546
547
sswu_curve_param(int group,int * z)548 static int sswu_curve_param(int group, int *z)
549 {
550 switch (group) {
551 case 19:
552 *z = -10;
553 return 0;
554 }
555
556 return -1;
557 }
558
559
debug_print_bignum(const char * title,const struct crypto_bignum * a,size_t prime_len)560 static void debug_print_bignum(const char *title, const struct crypto_bignum *a,
561 size_t prime_len)
562 {
563 u8 *bin;
564
565 bin = os_malloc(prime_len);
566 if (bin && crypto_bignum_to_bin(a, bin, prime_len, prime_len) >= 0)
567 wpa_hexdump_key(MSG_DEBUG, title, bin, prime_len);
568 else
569 wpa_printf(MSG_DEBUG, "Could not print bignum (%s)", title);
570 bin_clear_free(bin, prime_len);
571 }
572
sswu(struct crypto_ec * ec,int group,const struct crypto_bignum * u)573 static struct crypto_ec_point * sswu(struct crypto_ec *ec, int group,
574 const struct crypto_bignum *u)
575 {
576 int z_int;
577 const struct crypto_bignum *b, *prime;
578 struct crypto_bignum *a, *u2, *t1, *t2, *z, *t, *zero, *one, *two, *three,
579 *x1a, *x1b, *y = NULL;
580 struct crypto_bignum *x1 = NULL, *x2, *gx1, *gx2, *v = NULL;
581 struct crypto_bignum *tmp = NULL;
582 unsigned int m_is_zero, is_qr, is_eq;
583 size_t prime_len;
584 u8 bin[SAE_MAX_ECC_PRIME_LEN];
585 u8 bin1[SAE_MAX_ECC_PRIME_LEN];
586 u8 bin2[SAE_MAX_ECC_PRIME_LEN];
587 u8 x_y[2 * SAE_MAX_ECC_PRIME_LEN];
588 struct crypto_ec_point *p = NULL;
589
590 if (sswu_curve_param(group, &z_int) < 0)
591 return NULL;
592
593 prime = crypto_ec_get_prime(ec);
594 prime_len = crypto_ec_prime_len(ec);
595 /* Value of 'a' defined for curve secp256r1 in 'y^2 = x^3 + ax + b' */
596 uint8_t buf[32] = {0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc};
597 a = crypto_bignum_init_set(buf, 32);
598 b = crypto_ec_get_b(ec);
599
600 u2 = crypto_bignum_init();
601 t1 = crypto_bignum_init();
602 t2 = crypto_bignum_init();
603 z = crypto_bignum_init_uint(abs(z_int));
604 t = crypto_bignum_init();
605 zero = crypto_bignum_init_uint(0);
606 one = crypto_bignum_init_uint(1);
607 two = crypto_bignum_init_uint(2);
608 three = crypto_bignum_init_uint(3);
609 x1a = crypto_bignum_init();
610 x1b = crypto_bignum_init();
611 x2 = crypto_bignum_init();
612 gx1 = crypto_bignum_init();
613 gx2 = crypto_bignum_init();
614 tmp = crypto_bignum_init();
615 if (!u2 || !t1 || !t2 || !z || !t || !zero || !one || !two || !three ||
616 !x1a || !x1b || !x2 || !gx1 || !gx2 || !tmp)
617 goto fail;
618
619 if (z_int < 0 && crypto_bignum_sub(prime, z, z) < 0)
620 goto fail;
621
622 /* m = z^2 * u^4 + z * u^2 */
623 /* --> tmp = z * u^2, m = tmp^2 + tmp */
624
625 /* u2 = u^2
626 * t1 = z * u2
627 * t2 = t1^2
628 * m = t1 = t1 + t2 */
629 if (crypto_bignum_sqrmod(u, prime, u2) < 0 ||
630 crypto_bignum_mulmod(z, u2, prime, t1) < 0 ||
631 crypto_bignum_sqrmod(t1, prime, t2) < 0 ||
632 crypto_bignum_addmod(t1, t2, prime, t1) < 0)
633 goto fail;
634 debug_print_bignum("SSWU: m", t1, prime_len);
635
636 /* l = CEQ(m, 0)
637 * t = CSEL(l, 0, inverse(m); where inverse(x) is calculated as
638 * x^(p-2) modulo p which will handle m == 0 case correctly */
639 /* TODO: Make sure crypto_bignum_is_zero() is constant time */
640 m_is_zero = const_time_eq(crypto_bignum_is_zero(t1), 1);
641 /* t = m^(p-2) modulo p */
642 if (crypto_bignum_sub(prime, two, t2) < 0 ||
643 crypto_bignum_exptmod(t1, t2, prime, t) < 0)
644 goto fail;
645 debug_print_bignum("SSWU: t", t, prime_len);
646
647 /* b / (z * a) */
648 if (crypto_bignum_mulmod(z, a, prime, t1) < 0 ||
649 crypto_bignum_inverse(t1, prime, t1) < 0 ||
650 crypto_bignum_mulmod(b, t1, prime, x1a) < 0)
651 goto fail;
652 debug_print_bignum("SSWU: x1a = b / (z * a)", x1a, prime_len);
653
654 /* (-b/a) * (1 + t) */
655 if (crypto_bignum_sub(prime, b, t1) < 0 ||
656 crypto_bignum_inverse(a, prime, t2) < 0 ||
657 crypto_bignum_mulmod(t1, t2, prime, t1) < 0 ||
658 crypto_bignum_addmod(one, t, prime, t2) < 0 ||
659 crypto_bignum_mulmod(t1, t2, prime, x1b) < 0)
660 goto fail;
661 debug_print_bignum("SSWU: x1b = (-b/a) * (1 + t)", x1b, prime_len);
662
663 /* x1 = CSEL(CEQ(m, 0), x1a, x1b) */
664 if (crypto_bignum_to_bin(x1a, bin1, sizeof(bin1), prime_len) < 0 ||
665 crypto_bignum_to_bin(x1b, bin2, sizeof(bin2), prime_len) < 0)
666 goto fail;
667 const_time_select_bin(m_is_zero, bin1, bin2, prime_len, bin);
668 x1 = crypto_bignum_init_set(bin, prime_len);
669 if (!x1)
670 goto fail;
671 debug_print_bignum("SSWU: x1 = CSEL(l, x1a, x1b)", x1, prime_len);
672
673 /* gx1 = x1^3 + a * x1 + b */
674 if (crypto_bignum_exptmod(x1, three, prime, t1) < 0 ||
675 crypto_bignum_mulmod(a, x1, prime, t2) < 0 ||
676 crypto_bignum_addmod(t1, t2, prime, t1) < 0 ||
677 crypto_bignum_addmod(t1, b, prime, gx1) < 0)
678 goto fail;
679 debug_print_bignum("SSWU: gx1 = x1^3 + a * x1 + b", gx1, prime_len);
680
681 /* x2 = z * u^2 * x1 */
682 if (crypto_bignum_mulmod(z, u2, prime, t1) < 0 ||
683 crypto_bignum_mulmod(t1, x1, prime, x2) < 0)
684 goto fail;
685 debug_print_bignum("SSWU: x2 = z * u^2 * x1", x2, prime_len);
686
687 /* gx2 = x2^3 + a * x2 + b */
688 if (crypto_bignum_exptmod(x2, three, prime, t1) < 0 ||
689 crypto_bignum_mulmod(a, x2, prime, t2) < 0 ||
690 crypto_bignum_addmod(t1, t2, prime, t1) < 0 ||
691 crypto_bignum_addmod(t1, b, prime, gx2) < 0)
692 goto fail;
693 debug_print_bignum("SSWU: gx2 = x2^3 + a * x2 + b", gx2, prime_len);
694
695 /* l = gx1 is a quadratic residue modulo p
696 * --> gx1^((p-1)/2) modulo p is zero or one */
697 if (crypto_bignum_sub(prime, one, t1) < 0 ||
698 crypto_bignum_rshift(t1, 1, t1) < 0 ||
699 crypto_bignum_exptmod(gx1, t1, prime, tmp) < 0)
700 goto fail;
701 debug_print_bignum("SSWU: gx1^((p-1)/2) modulo p", t1, prime_len);
702 is_qr = const_time_eq(crypto_bignum_is_zero(tmp) |
703 crypto_bignum_is_one(tmp), 1);
704
705 /* v = CSEL(l, gx1, gx2) */
706 if (crypto_bignum_to_bin(gx1, bin1, sizeof(bin1), prime_len) < 0 ||
707 crypto_bignum_to_bin(gx2, bin2, sizeof(bin2), prime_len) < 0)
708 goto fail;
709 const_time_select_bin(is_qr, bin1, bin2, prime_len, bin);
710 v = crypto_bignum_init_set(bin, prime_len);
711 if (!v)
712 goto fail;
713 debug_print_bignum("SSWU: v = CSEL(l, gx1, gx2)", v, prime_len);
714
715 /* x = CSEL(l, x1, x2) */
716 if (crypto_bignum_to_bin(x1, bin1, sizeof(bin1), prime_len) < 0 ||
717 crypto_bignum_to_bin(x2, bin2, sizeof(bin2), prime_len) < 0)
718 goto fail;
719 const_time_select_bin(is_qr, bin1, bin2, prime_len, x_y);
720 wpa_hexdump_key(MSG_DEBUG, "SSWU: x = CSEL(l, x1, x2)", x_y, prime_len);
721
722 /* y = sqrt(v) */
723 y = crypto_bignum_init();
724 if (!y || dragonfly_sqrt(ec, v, y) < 0)
725 goto fail;
726 debug_print_bignum("SSWU: y = sqrt(v)", y, prime_len);
727
728 /* l = CEQ(LSB(u), LSB(y)) */
729 if (crypto_bignum_to_bin(u, bin1, sizeof(bin1), prime_len) < 0 ||
730 crypto_bignum_to_bin(y, bin2, sizeof(bin2), prime_len) < 0)
731 goto fail;
732 is_eq = const_time_eq(bin1[prime_len - 1] & 0x01,
733 bin2[prime_len - 1] & 0x01);
734
735 /* P = CSEL(l, (x,y), (x, p-y)) */
736 if (crypto_bignum_sub(prime, y, t1) < 0)
737 goto fail;
738 debug_print_bignum("SSWU: p - y", t1, prime_len);
739 if (crypto_bignum_to_bin(y, bin1, sizeof(bin1), prime_len) < 0 ||
740 crypto_bignum_to_bin(t1, bin2, sizeof(bin2), prime_len) < 0)
741 goto fail;
742 const_time_select_bin(is_eq, bin1, bin2, prime_len, &x_y[prime_len]);
743
744 /* output P */
745 wpa_hexdump_key(MSG_DEBUG, "SSWU: P.x", x_y, prime_len);
746 wpa_hexdump_key(MSG_DEBUG, "SSWU: P.y", &x_y[prime_len], prime_len);
747 p = crypto_ec_point_from_bin(ec, x_y);
748
749 fail:
750 crypto_bignum_deinit(a, 0);
751 crypto_bignum_deinit(tmp, 0);
752 crypto_bignum_deinit(u2, 1);
753 crypto_bignum_deinit(t1, 1);
754 crypto_bignum_deinit(t2, 1);
755 crypto_bignum_deinit(z, 0);
756 crypto_bignum_deinit(t, 1);
757 crypto_bignum_deinit(x1a, 1);
758 crypto_bignum_deinit(x1b, 1);
759 crypto_bignum_deinit(x1, 1);
760 crypto_bignum_deinit(x2, 1);
761 crypto_bignum_deinit(gx1, 1);
762 crypto_bignum_deinit(gx2, 1);
763 crypto_bignum_deinit(y, 1);
764 crypto_bignum_deinit(v, 1);
765 crypto_bignum_deinit(zero, 0);
766 crypto_bignum_deinit(one, 0);
767 crypto_bignum_deinit(two, 0);
768 crypto_bignum_deinit(three, 0);
769 forced_memzero(bin, sizeof(bin));
770 forced_memzero(bin1, sizeof(bin1));
771 forced_memzero(bin2, sizeof(bin2));
772 forced_memzero(x_y, sizeof(x_y));
773 return p;
774 }
775
776
sae_pwd_seed(size_t hash_len,const u8 * ssid,size_t ssid_len,const u8 * password,size_t password_len,const char * identifier,u8 * pwd_seed)777 static int sae_pwd_seed(size_t hash_len, const u8 *ssid, size_t ssid_len,
778 const u8 *password, size_t password_len,
779 const char *identifier, u8 *pwd_seed)
780 {
781 const u8 *addr[2];
782 size_t len[2];
783 size_t num_elem;
784
785 /* pwd-seed = HKDF-Extract(ssid, password [ || identifier ]) */
786 addr[0] = password;
787 len[0] = password_len;
788 num_elem = 1;
789 wpa_hexdump_ascii(MSG_DEBUG, "SAE: SSID", ssid, ssid_len);
790 wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
791 password, password_len);
792 if (identifier) {
793 wpa_printf(MSG_DEBUG, "SAE: password identifier: %s",
794 identifier);
795 addr[num_elem] = (const u8 *) identifier;
796 len[num_elem] = os_strlen(identifier);
797 num_elem++;
798 }
799 if (hkdf_extract(hash_len, ssid, ssid_len, num_elem, addr, len,
800 pwd_seed) < 0)
801 return -1;
802 wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, hash_len);
803 return 0;
804 }
805
806
sae_ecc_prime_len_2_hash_len(size_t prime_len)807 size_t sae_ecc_prime_len_2_hash_len(size_t prime_len)
808 {
809 if (prime_len <= 256 / 8)
810 return 32;
811 if (prime_len <= 384 / 8)
812 return 48;
813 return 64;
814 }
815
816
817 static struct crypto_ec_point *
sae_derive_pt_ecc(struct crypto_ec * ec,int group,const u8 * ssid,size_t ssid_len,const u8 * password,size_t password_len,const char * identifier)818 sae_derive_pt_ecc(struct crypto_ec *ec, int group,
819 const u8 *ssid, size_t ssid_len,
820 const u8 *password, size_t password_len,
821 const char *identifier)
822 {
823 u8 pwd_seed[64];
824 u8 pwd_value[SAE_MAX_ECC_PRIME_LEN * 2];
825 size_t pwd_value_len, hash_len, prime_len;
826 const struct crypto_bignum *prime;
827 struct crypto_bignum *bn = NULL;
828 struct crypto_ec_point *p1 = NULL, *p2 = NULL, *pt = NULL;
829
830 prime = crypto_ec_get_prime(ec);
831 prime_len = crypto_ec_prime_len(ec);
832 if (prime_len > SAE_MAX_ECC_PRIME_LEN)
833 goto fail;
834 hash_len = sae_ecc_prime_len_2_hash_len(prime_len);
835
836 /* len = olen(p) + ceil(olen(p)/2) */
837 pwd_value_len = prime_len + (prime_len + 1) / 2;
838
839 if (sae_pwd_seed(hash_len, ssid, ssid_len, password, password_len,
840 identifier, pwd_seed) < 0)
841 goto fail;
842
843 /* pwd-value = HKDF-Expand(pwd-seed, "SAE Hash to Element u1 P1", len)
844 */
845 if (hkdf_expand(hash_len, pwd_seed, hash_len,
846 "SAE Hash to Element u1 P1", pwd_value, pwd_value_len) <
847 0)
848 goto fail;
849 wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value (u1 P1)",
850 pwd_value, pwd_value_len);
851
852 /* u1 = pwd-value modulo p */
853 bn = crypto_bignum_init_set(pwd_value, pwd_value_len);
854 if (!bn || crypto_bignum_mod(bn, prime, bn) < 0 ||
855 crypto_bignum_to_bin(bn, pwd_value, sizeof(pwd_value),
856 prime_len) < 0)
857 goto fail;
858 wpa_hexdump_key(MSG_DEBUG, "SAE: u1", pwd_value, prime_len);
859
860 /* P1 = SSWU(u1) */
861 p1 = sswu(ec, group, bn);
862 if (!p1)
863 goto fail;
864
865 /* pwd-value = HKDF-Expand(pwd-seed, "SAE Hash to Element u2 P2", len)
866 */
867 if (hkdf_expand(hash_len, pwd_seed, hash_len,
868 "SAE Hash to Element u2 P2", pwd_value,
869 pwd_value_len) < 0)
870 goto fail;
871 wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value (u2 P2)",
872 pwd_value, pwd_value_len);
873
874 /* u2 = pwd-value modulo p */
875 crypto_bignum_deinit(bn, 1);
876 bn = crypto_bignum_init_set(pwd_value, pwd_value_len);
877 if (!bn || crypto_bignum_mod(bn, prime, bn) < 0 ||
878 crypto_bignum_to_bin(bn, pwd_value, sizeof(pwd_value),
879 prime_len) < 0)
880 goto fail;
881 wpa_hexdump_key(MSG_DEBUG, "SAE: u2", pwd_value, prime_len);
882
883 /* P2 = SSWU(u2) */
884 p2 = sswu(ec, group, bn);
885 if (!p2)
886 goto fail;
887
888 /* PT = elem-op(P1, P2) */
889 pt = crypto_ec_point_init(ec);
890 if (!pt)
891 goto fail;
892 if (crypto_ec_point_add(ec, p1, p2, pt) < 0) {
893 crypto_ec_point_deinit(pt, 1);
894 pt = NULL;
895 }
896
897 fail:
898 forced_memzero(pwd_seed, sizeof(pwd_seed));
899 forced_memzero(pwd_value, sizeof(pwd_value));
900 crypto_bignum_deinit(bn, 1);
901 crypto_ec_point_deinit(p1, 1);
902 crypto_ec_point_deinit(p2, 1);
903 return pt;
904 }
905
906
sae_ffc_prime_len_2_hash_len(size_t prime_len)907 size_t sae_ffc_prime_len_2_hash_len(size_t prime_len)
908 {
909 if (prime_len <= 2048 / 8)
910 return 32;
911 if (prime_len <= 3072 / 8)
912 return 48;
913 return 64;
914 }
915
916
917 static struct crypto_bignum *
sae_derive_pt_ffc(const struct dh_group * dh,int group,const u8 * ssid,size_t ssid_len,const u8 * password,size_t password_len,const char * identifier)918 sae_derive_pt_ffc(const struct dh_group *dh, int group,
919 const u8 *ssid, size_t ssid_len,
920 const u8 *password, size_t password_len,
921 const char *identifier)
922 {
923 size_t hash_len, prime_len, pwd_value_len;
924 struct crypto_bignum *prime, *order;
925 struct crypto_bignum *one = NULL, *two = NULL, *bn = NULL, *tmp = NULL,
926 *pt = NULL;
927 u8 pwd_seed[64];
928 u8 pwd_value[SAE_MAX_PRIME_LEN + SAE_MAX_PRIME_LEN / 2];
929
930 prime = crypto_bignum_init_set(dh->prime, dh->prime_len);
931 order = crypto_bignum_init_set(dh->order, dh->order_len);
932 if (!prime || !order)
933 goto fail;
934 prime_len = dh->prime_len;
935 if (prime_len > SAE_MAX_PRIME_LEN)
936 goto fail;
937 hash_len = sae_ffc_prime_len_2_hash_len(prime_len);
938
939 /* len = olen(p) + ceil(olen(p)/2) */
940 pwd_value_len = prime_len + (prime_len + 1) / 2;
941 if (pwd_value_len > sizeof(pwd_value))
942 goto fail;
943
944 if (sae_pwd_seed(hash_len, ssid, ssid_len, password, password_len,
945 identifier, pwd_seed) < 0)
946 goto fail;
947
948 /* pwd-value = HKDF-Expand(pwd-seed, "SAE Hash to Element", len) */
949 if (hkdf_expand(hash_len, pwd_seed, hash_len,
950 "SAE Hash to Element", pwd_value, pwd_value_len) < 0)
951 goto fail;
952 wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
953 pwd_value, pwd_value_len);
954
955 /* pwd-value = (pwd-value modulo (p-2)) + 2 */
956 bn = crypto_bignum_init_set(pwd_value, pwd_value_len);
957 one = crypto_bignum_init_uint(1);
958 two = crypto_bignum_init_uint(2);
959 tmp = crypto_bignum_init();
960 if (!bn || !one || !two || !tmp ||
961 crypto_bignum_sub(prime, two, tmp) < 0 ||
962 crypto_bignum_mod(bn, tmp, bn) < 0 ||
963 crypto_bignum_add(bn, two, bn) < 0 ||
964 crypto_bignum_to_bin(bn, pwd_value, sizeof(pwd_value),
965 prime_len) < 0)
966 goto fail;
967 wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value(reduced)",
968 pwd_value, prime_len);
969
970 /* PT = pwd-value^((p-1)/q) modulo p */
971 pt = crypto_bignum_init();
972 if (!pt ||
973 crypto_bignum_sub(prime, one, tmp) < 0 ||
974 crypto_bignum_div(tmp, order, tmp) < 0 ||
975 crypto_bignum_exptmod(bn, tmp, prime, pt) < 0) {
976 crypto_bignum_deinit(pt, 1);
977 pt = NULL;
978 goto fail;
979 }
980 debug_print_bignum("SAE: PT", pt, prime_len);
981
982 fail:
983 forced_memzero(pwd_seed, sizeof(pwd_seed));
984 forced_memzero(pwd_value, sizeof(pwd_value));
985 crypto_bignum_deinit(bn, 1);
986 crypto_bignum_deinit(tmp, 1);
987 crypto_bignum_deinit(one, 0);
988 crypto_bignum_deinit(two, 0);
989 crypto_bignum_deinit(prime, 0);
990 crypto_bignum_deinit(order, 0);
991 return pt;
992 }
993
994
995 static struct sae_pt *
sae_derive_pt_group(int group,const u8 * ssid,size_t ssid_len,const u8 * password,size_t password_len,const char * identifier)996 sae_derive_pt_group(int group, const u8 *ssid, size_t ssid_len,
997 const u8 *password, size_t password_len,
998 const char *identifier)
999 {
1000 struct sae_pt *pt;
1001
1002 wpa_printf(MSG_DEBUG, "SAE: Derive PT - group %d", group);
1003
1004 if (ssid_len > 32)
1005 return NULL;
1006
1007 pt = os_zalloc(sizeof(*pt));
1008 if (!pt)
1009 return NULL;
1010 #ifdef CONFIG_SAE_PK
1011 os_memcpy(pt->ssid, ssid, ssid_len);
1012 pt->ssid_len = ssid_len;
1013 #endif /* CONFIG_SAE_PK */
1014
1015 pt->group = group;
1016 pt->ec = crypto_ec_init(group);
1017 if (pt->ec) {
1018 pt->ecc_pt = sae_derive_pt_ecc(pt->ec, group, ssid, ssid_len,
1019 password, password_len,
1020 identifier);
1021 if (!pt->ecc_pt) {
1022 wpa_printf(MSG_DEBUG, "SAE: Failed to derive PT");
1023 goto fail;
1024 }
1025
1026 return pt;
1027 }
1028
1029 pt->dh = dh_groups_get(group);
1030 if (!pt->dh) {
1031 wpa_printf(MSG_DEBUG, "SAE: Unsupported group %d", group);
1032 goto fail;
1033 }
1034
1035 pt->ffc_pt = sae_derive_pt_ffc(pt->dh, group, ssid, ssid_len,
1036 password, password_len, identifier);
1037 if (!pt->ffc_pt) {
1038 wpa_printf(MSG_DEBUG, "SAE: Failed to derive PT");
1039 goto fail;
1040 }
1041
1042 return pt;
1043 fail:
1044 sae_deinit_pt(pt);
1045 return NULL;
1046 }
1047
1048
sae_derive_pt(int * groups,const u8 * ssid,size_t ssid_len,const u8 * password,size_t password_len,const char * identifier)1049 struct sae_pt * sae_derive_pt(int *groups, const u8 *ssid, size_t ssid_len,
1050 const u8 *password, size_t password_len,
1051 const char *identifier)
1052 {
1053 struct sae_pt *pt = NULL, *last = NULL, *tmp;
1054 int default_groups[] = { 19, 0 };
1055 int i;
1056
1057 if (!groups)
1058 groups = default_groups;
1059 for (i = 0; groups[i] > 0; i++) {
1060 tmp = sae_derive_pt_group(groups[i], ssid, ssid_len, password,
1061 password_len, identifier);
1062 if (!tmp)
1063 continue;
1064
1065 if (last)
1066 last->next = tmp;
1067 else
1068 pt = tmp;
1069 last = tmp;
1070 }
1071
1072 return pt;
1073 }
1074
1075
sae_max_min_addr(const u8 * addr[],size_t len[],const u8 * addr1,const u8 * addr2)1076 static void sae_max_min_addr(const u8 *addr[], size_t len[],
1077 const u8 *addr1, const u8 *addr2)
1078 {
1079 len[0] = ETH_ALEN;
1080 len[1] = ETH_ALEN;
1081 if (os_memcmp(addr1, addr2, ETH_ALEN) > 0) {
1082 addr[0] = addr1;
1083 addr[1] = addr2;
1084 } else {
1085 addr[0] = addr2;
1086 addr[1] = addr1;
1087 }
1088 }
1089
1090
1091 struct crypto_ec_point *
sae_derive_pwe_from_pt_ecc(const struct sae_pt * pt,const u8 * addr1,const u8 * addr2)1092 sae_derive_pwe_from_pt_ecc(const struct sae_pt *pt,
1093 const u8 *addr1, const u8 *addr2)
1094 {
1095 u8 bin[SAE_MAX_ECC_PRIME_LEN * 2];
1096 size_t prime_len;
1097 const u8 *addr[2];
1098 size_t len[2];
1099 u8 salt[64], hash[64];
1100 size_t hash_len;
1101 const struct crypto_bignum *order;
1102 struct crypto_bignum *tmp = NULL, *val = NULL, *one = NULL;
1103 struct crypto_ec_point *pwe = NULL;
1104
1105 wpa_printf(MSG_DEBUG, "SAE: Derive PWE from PT");
1106 prime_len = crypto_ec_prime_len(pt->ec);
1107 if (crypto_ec_point_to_bin(pt->ec, pt->ecc_pt,
1108 bin, bin + prime_len) < 0)
1109 return NULL;
1110 wpa_hexdump_key(MSG_DEBUG, "SAE: PT.x", bin, prime_len);
1111 wpa_hexdump_key(MSG_DEBUG, "SAE: PT.y", bin + prime_len, prime_len);
1112
1113 sae_max_min_addr(addr, len, addr1, addr2);
1114
1115 /* val = H(0^n,
1116 * MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC)) */
1117 wpa_printf(MSG_DEBUG, "SAE: val = H(0^n, MAX(addrs) || MIN(addrs))");
1118 hash_len = sae_ecc_prime_len_2_hash_len(prime_len);
1119 os_memset(salt, 0, hash_len);
1120 if (hkdf_extract(hash_len, salt, hash_len, 2, addr, len, hash) < 0)
1121 goto fail;
1122 wpa_hexdump(MSG_DEBUG, "SAE: val", hash, hash_len);
1123
1124 /* val = val modulo (q - 1) + 1 */
1125 order = crypto_ec_get_order(pt->ec);
1126 tmp = crypto_bignum_init();
1127 val = crypto_bignum_init_set(hash, hash_len);
1128 one = crypto_bignum_init_uint(1);
1129 if (!tmp || !val || !one ||
1130 crypto_bignum_sub(order, one, tmp) < 0 ||
1131 crypto_bignum_mod(val, tmp, val) < 0 ||
1132 crypto_bignum_add(val, one, val) < 0)
1133 goto fail;
1134 debug_print_bignum("SAE: val(reduced to 1..q-1)", val, prime_len);
1135
1136 /* PWE = scalar-op(val, PT) */
1137 pwe = crypto_ec_point_init(pt->ec);
1138 if (!pwe ||
1139 crypto_ec_point_mul(pt->ec, pt->ecc_pt, val, pwe) < 0 ||
1140 crypto_ec_point_to_bin(pt->ec, pwe, bin, bin + prime_len) < 0) {
1141 crypto_ec_point_deinit(pwe, 1);
1142 pwe = NULL;
1143 goto fail;
1144 }
1145 wpa_hexdump_key(MSG_DEBUG, "SAE: PWE.x", bin, prime_len);
1146 wpa_hexdump_key(MSG_DEBUG, "SAE: PWE.y", bin + prime_len, prime_len);
1147
1148 fail:
1149 crypto_bignum_deinit(tmp, 1);
1150 crypto_bignum_deinit(val, 1);
1151 crypto_bignum_deinit(one, 0);
1152 return pwe;
1153 }
1154
1155
1156 struct crypto_bignum *
sae_derive_pwe_from_pt_ffc(const struct sae_pt * pt,const u8 * addr1,const u8 * addr2)1157 sae_derive_pwe_from_pt_ffc(const struct sae_pt *pt,
1158 const u8 *addr1, const u8 *addr2)
1159 {
1160 size_t prime_len;
1161 const u8 *addr[2];
1162 size_t len[2];
1163 u8 salt[64], hash[64];
1164 size_t hash_len;
1165 struct crypto_bignum *tmp = NULL, *val = NULL, *one = NULL;
1166 struct crypto_bignum *pwe = NULL, *order = NULL, *prime = NULL;
1167
1168 wpa_printf(MSG_DEBUG, "SAE: Derive PWE from PT");
1169 prime = crypto_bignum_init_set(pt->dh->prime, pt->dh->prime_len);
1170 order = crypto_bignum_init_set(pt->dh->order, pt->dh->order_len);
1171 if (!prime || !order)
1172 goto fail;
1173 prime_len = pt->dh->prime_len;
1174
1175 sae_max_min_addr(addr, len, addr1, addr2);
1176
1177 /* val = H(0^n,
1178 * MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC)) */
1179 wpa_printf(MSG_DEBUG, "SAE: val = H(0^n, MAX(addrs) || MIN(addrs))");
1180 hash_len = sae_ffc_prime_len_2_hash_len(prime_len);
1181 os_memset(salt, 0, hash_len);
1182 if (hkdf_extract(hash_len, salt, hash_len, 2, addr, len, hash) < 0)
1183 goto fail;
1184 wpa_hexdump(MSG_DEBUG, "SAE: val", hash, hash_len);
1185
1186 /* val = val modulo (q - 1) + 1 */
1187 tmp = crypto_bignum_init();
1188 val = crypto_bignum_init_set(hash, hash_len);
1189 one = crypto_bignum_init_uint(1);
1190 if (!tmp || !val || !one ||
1191 crypto_bignum_sub(order, one, tmp) < 0 ||
1192 crypto_bignum_mod(val, tmp, val) < 0 ||
1193 crypto_bignum_add(val, one, val) < 0)
1194 goto fail;
1195 debug_print_bignum("SAE: val(reduced to 1..q-1)", val, prime_len);
1196
1197 /* PWE = scalar-op(val, PT) */
1198 pwe = crypto_bignum_init();
1199 if (!pwe || crypto_bignum_exptmod(pt->ffc_pt, val, prime, pwe) < 0) {
1200 crypto_bignum_deinit(pwe, 1);
1201 pwe = NULL;
1202 goto fail;
1203 }
1204 debug_print_bignum("SAE: PWE", pwe, prime_len);
1205
1206 fail:
1207 crypto_bignum_deinit(tmp, 1);
1208 crypto_bignum_deinit(val, 1);
1209 crypto_bignum_deinit(one, 0);
1210 crypto_bignum_deinit(prime, 0);
1211 crypto_bignum_deinit(order, 0);
1212 return pwe;
1213 }
1214
1215
sae_deinit_pt(struct sae_pt * pt)1216 void sae_deinit_pt(struct sae_pt *pt)
1217 {
1218 struct sae_pt *prev;
1219
1220 while (pt) {
1221 crypto_ec_point_deinit(pt->ecc_pt, 1);
1222 crypto_bignum_deinit(pt->ffc_pt, 1);
1223 crypto_ec_deinit(pt->ec);
1224 prev = pt;
1225 pt = pt->next;
1226 os_free(prev);
1227 }
1228 }
1229
1230
sae_derive_commit_element_ecc(struct sae_data * sae,struct crypto_bignum * mask)1231 static int sae_derive_commit_element_ecc(struct sae_data *sae,
1232 struct crypto_bignum *mask)
1233 {
1234 /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */
1235 if (!sae->tmp->own_commit_element_ecc) {
1236 sae->tmp->own_commit_element_ecc =
1237 crypto_ec_point_init(sae->tmp->ec);
1238 if (!sae->tmp->own_commit_element_ecc)
1239 return ESP_FAIL;
1240 }
1241
1242 if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc, mask,
1243 sae->tmp->own_commit_element_ecc) < 0 ||
1244 crypto_ec_point_invert(sae->tmp->ec,
1245 sae->tmp->own_commit_element_ecc) < 0) {
1246 wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element");
1247 return ESP_FAIL;
1248 }
1249
1250 return ESP_OK;
1251 }
1252
1253
sae_derive_commit_element_ffc(struct sae_data * sae,struct crypto_bignum * mask)1254 static int sae_derive_commit_element_ffc(struct sae_data *sae,
1255 struct crypto_bignum *mask)
1256 {
1257 /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */
1258 if (!sae->tmp->own_commit_element_ffc) {
1259 sae->tmp->own_commit_element_ffc = crypto_bignum_init();
1260 if (!sae->tmp->own_commit_element_ffc)
1261 return ESP_FAIL;
1262 }
1263
1264 if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, mask, sae->tmp->prime,
1265 sae->tmp->own_commit_element_ffc) < 0 ||
1266 crypto_bignum_inverse(sae->tmp->own_commit_element_ffc,
1267 sae->tmp->prime,
1268 sae->tmp->own_commit_element_ffc) < 0) {
1269 wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element");
1270 return ESP_FAIL;
1271 }
1272
1273 return ESP_OK;
1274 }
1275
1276
sae_derive_commit(struct sae_data * sae)1277 static int sae_derive_commit(struct sae_data *sae)
1278 {
1279 struct crypto_bignum *mask = NULL;
1280 int ret;
1281
1282 mask = crypto_bignum_init();
1283 if (!sae->tmp->sae_rand)
1284 sae->tmp->sae_rand = crypto_bignum_init();
1285 if (!sae->tmp->own_commit_scalar)
1286 sae->tmp->own_commit_scalar = crypto_bignum_init();
1287 ret = !mask || !sae->tmp->sae_rand || !sae->tmp->own_commit_scalar ||
1288 dragonfly_generate_scalar(sae->tmp->order, sae->tmp->sae_rand,
1289 mask,
1290 sae->tmp->own_commit_scalar) < 0 ||
1291 (sae->tmp->ec &&
1292 sae_derive_commit_element_ecc(sae, mask) < 0) ||
1293 (sae->tmp->dh &&
1294 sae_derive_commit_element_ffc(sae, mask) < 0);
1295 crypto_bignum_deinit(mask, 1);
1296 return ret ? -1 : 0;
1297 }
1298
1299
sae_prepare_commit(const u8 * addr1,const u8 * addr2,const u8 * password,size_t password_len,struct sae_data * sae)1300 int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
1301 const u8 *password, size_t password_len,
1302 struct sae_data *sae)
1303 {
1304 if (sae->tmp == NULL ||
1305 (sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password,
1306 password_len) < 0) ||
1307 (sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password,
1308 password_len) < 0))
1309 return ESP_FAIL;
1310
1311 sae->h2e = 0;
1312 sae->pk = 0;
1313 return sae_derive_commit(sae);
1314 }
1315
1316
sae_prepare_commit_pt(struct sae_data * sae,const struct sae_pt * pt,const u8 * addr1,const u8 * addr2,int * rejected_groups,const struct sae_pk * pk)1317 int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
1318 const u8 *addr1, const u8 *addr2,
1319 int *rejected_groups, const struct sae_pk *pk)
1320 {
1321 if (!sae->tmp)
1322 return -1;
1323
1324 while (pt) {
1325 if (pt->group == sae->group)
1326 break;
1327 pt = pt->next;
1328 }
1329 if (!pt) {
1330 wpa_printf(MSG_INFO, "SAE: Could not find PT for group %u",
1331 sae->group);
1332 return -1;
1333 }
1334 #ifdef CONFIG_SAE_PK
1335 os_memcpy(sae->tmp->ssid, pt->ssid, pt->ssid_len);
1336 sae->tmp->ssid_len = pt->ssid_len;
1337 sae->tmp->ap_pk = pk;
1338 #endif /* CONFIG_SAE_PK */
1339
1340 sae->tmp->own_addr_higher = os_memcmp(addr1, addr2, ETH_ALEN) > 0;
1341 wpabuf_free(sae->tmp->own_rejected_groups);
1342 sae->tmp->own_rejected_groups = NULL;
1343 if (rejected_groups) {
1344 int count, i;
1345 struct wpabuf *groups;
1346
1347 count = int_array_len(rejected_groups);
1348 groups = wpabuf_alloc(count * 2);
1349 if (!groups)
1350 return -1;
1351 for (i = 0; i < count; i++)
1352 wpabuf_put_le16(groups, rejected_groups[i]);
1353 sae->tmp->own_rejected_groups = groups;
1354 }
1355
1356 if (pt->ec) {
1357 crypto_ec_point_deinit(sae->tmp->pwe_ecc, 1);
1358 sae->tmp->pwe_ecc = sae_derive_pwe_from_pt_ecc(pt, addr1,
1359 addr2);
1360 if (!sae->tmp->pwe_ecc)
1361 return -1;
1362 }
1363
1364 if (pt->dh) {
1365 crypto_bignum_deinit(sae->tmp->pwe_ffc, 1);
1366 sae->tmp->pwe_ffc = sae_derive_pwe_from_pt_ffc(pt, addr1,
1367 addr2);
1368 if (!sae->tmp->pwe_ffc)
1369 return -1;
1370 }
1371
1372 sae->h2e = 1;
1373 return sae_derive_commit(sae);
1374 }
1375
1376
sae_derive_k_ecc(struct sae_data * sae,u8 * k)1377 static int sae_derive_k_ecc(struct sae_data *sae, u8 *k)
1378 {
1379 struct crypto_ec_point *K;
1380 int ret = -1;
1381
1382 K = crypto_ec_point_init(sae->tmp->ec);
1383 if (K == NULL)
1384 goto fail;
1385
1386 /*
1387 * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE),
1388 * PEER-COMMIT-ELEMENT)))
1389 * If K is identity element (point-at-infinity), reject
1390 * k = F(K) (= x coordinate)
1391 */
1392
1393 if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc,
1394 sae->peer_commit_scalar, K) < 0 ||
1395 crypto_ec_point_add(sae->tmp->ec, K,
1396 sae->tmp->peer_commit_element_ecc, K) < 0 ||
1397 crypto_ec_point_mul(sae->tmp->ec, K, sae->tmp->sae_rand, K) < 0 ||
1398 crypto_ec_point_is_at_infinity(sae->tmp->ec, K) ||
1399 crypto_ec_point_to_bin(sae->tmp->ec, K, k, NULL) < 0) {
1400 wpa_printf(MSG_DEBUG, "SAE: Failed to calculate K and k");
1401 goto fail;
1402 }
1403
1404 wpa_hexdump_key(MSG_DEBUG, "SAE: k", k, sae->tmp->prime_len);
1405
1406 ret = 0;
1407 fail:
1408 crypto_ec_point_deinit(K, 1);
1409 return ret;
1410 }
1411
1412
sae_derive_k_ffc(struct sae_data * sae,u8 * k)1413 static int sae_derive_k_ffc(struct sae_data *sae, u8 *k)
1414 {
1415 struct crypto_bignum *K;
1416 int ret = -1;
1417
1418 K = crypto_bignum_init();
1419 if (K == NULL)
1420 goto fail;
1421
1422 /*
1423 * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE),
1424 * PEER-COMMIT-ELEMENT)))
1425 * If K is identity element (one), reject.
1426 * k = F(K) (= x coordinate)
1427 */
1428
1429 if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, sae->peer_commit_scalar,
1430 sae->tmp->prime, K) < 0 ||
1431 crypto_bignum_mulmod(K, sae->tmp->peer_commit_element_ffc,
1432 sae->tmp->prime, K) < 0 ||
1433 crypto_bignum_exptmod(K, sae->tmp->sae_rand, sae->tmp->prime, K) < 0
1434 ||
1435 crypto_bignum_is_one(K) ||
1436 crypto_bignum_to_bin(K, k, SAE_MAX_PRIME_LEN, sae->tmp->prime_len) <
1437 0) {
1438 wpa_printf(MSG_DEBUG, "SAE: Failed to calculate K and k");
1439 goto fail;
1440 }
1441
1442 wpa_hexdump_key(MSG_DEBUG, "SAE: k", k, sae->tmp->prime_len);
1443
1444 ret = 0;
1445 fail:
1446 crypto_bignum_deinit(K, 1);
1447 return ret;
1448 }
1449
1450
sae_kdf_hash(size_t hash_len,const u8 * k,const char * label,const u8 * context,size_t context_len,u8 * out,size_t out_len)1451 static int sae_kdf_hash(size_t hash_len, const u8 *k, const char *label,
1452 const u8 *context, size_t context_len,
1453 u8 *out, size_t out_len)
1454 {
1455 if (hash_len == 32)
1456 return sha256_prf(k, hash_len, label,
1457 context, context_len, out, out_len);
1458 return -1;
1459 }
1460
1461
sae_derive_keys(struct sae_data * sae,const u8 * k)1462 static int sae_derive_keys(struct sae_data *sae, const u8 *k)
1463 {
1464 u8 zero[SAE_MAX_HASH_LEN], val[SAE_MAX_PRIME_LEN];
1465 const u8 *salt;
1466 struct wpabuf *rejected_groups = NULL;
1467 u8 keyseed[SAE_MAX_HASH_LEN];
1468 u8 keys[2 * SAE_MAX_HASH_LEN + SAE_PMK_LEN];
1469 struct crypto_bignum *tmp;
1470 int ret = -1;
1471 size_t hash_len, salt_len, prime_len = sae->tmp->prime_len;
1472 const u8 *addr[1];
1473 size_t len[1];
1474
1475 tmp = crypto_bignum_init();
1476 if (tmp == NULL)
1477 goto fail;
1478
1479 /* keyseed = H(salt, k)
1480 * KCK || PMK = KDF-Hash-Length(keyseed, "SAE KCK and PMK",
1481 * (commit-scalar + peer-commit-scalar) modulo r)
1482 * PMKID = L((commit-scalar + peer-commit-scalar) modulo r, 0, 128)
1483 *
1484 * When SAE_PK is used,
1485 * KCK || PMK || KEK = KDF-Hash-Length(keyseed, "SAE-PK keys", context)
1486 */
1487 if (!sae->h2e)
1488 hash_len = SHA256_MAC_LEN;
1489 else if (sae->tmp->dh)
1490 hash_len = sae_ffc_prime_len_2_hash_len(prime_len);
1491 else
1492 hash_len = sae_ecc_prime_len_2_hash_len(prime_len);
1493
1494 if (sae->h2e && (sae->tmp->own_rejected_groups ||
1495 sae->tmp->peer_rejected_groups)) {
1496 struct wpabuf *own, *peer;
1497
1498 own = sae->tmp->own_rejected_groups;
1499 peer = sae->tmp->peer_rejected_groups;
1500 salt_len = 0;
1501 if (own)
1502 salt_len += wpabuf_len(own);
1503 if (peer)
1504 salt_len += wpabuf_len(peer);
1505 rejected_groups = wpabuf_alloc(salt_len);
1506 if (!rejected_groups)
1507 goto fail;
1508 if (sae->tmp->own_addr_higher) {
1509 if (own)
1510 wpabuf_put_buf(rejected_groups, own);
1511 if (peer)
1512 wpabuf_put_buf(rejected_groups, peer);
1513 } else {
1514 if (peer)
1515 wpabuf_put_buf(rejected_groups, peer);
1516 if (own)
1517 wpabuf_put_buf(rejected_groups, own);
1518 }
1519 salt = wpabuf_head(rejected_groups);
1520 salt_len = wpabuf_len(rejected_groups);
1521 } else {
1522 os_memset(zero, 0, hash_len);
1523 salt = zero;
1524 salt_len = hash_len;
1525 }
1526 wpa_hexdump(MSG_DEBUG, "SAE: salt for keyseed derivation",
1527 salt, salt_len);
1528 addr[0] = k;
1529 len[0] = prime_len;
1530 if (hkdf_extract(hash_len, salt, salt_len, 1, addr, len, keyseed) < 0)
1531 goto fail;
1532 wpa_hexdump_key(MSG_DEBUG, "SAE: keyseed", keyseed, hash_len);
1533
1534 if (crypto_bignum_add(sae->tmp->own_commit_scalar,
1535 sae->peer_commit_scalar, tmp) < 0 ||
1536 crypto_bignum_mod(tmp, sae->tmp->order, tmp) < 0)
1537 goto fail;
1538 /* IEEE Std 802.11-2016 is not exactly clear on the encoding of the bit
1539 * string that is needed for KCK, PMK, and PMKID derivation, but it
1540 * seems to make most sense to encode the
1541 * (commit-scalar + peer-commit-scalar) mod r part as a bit string by
1542 * zero padding it from left to the length of the order (in full
1543 * octets). */
1544 if (crypto_bignum_to_bin(tmp, val, sizeof(val),
1545 sae->tmp->order_len) < 0) {
1546 goto fail;
1547 }
1548 wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
1549
1550 #ifdef CONFIG_SAE_PK
1551 if (sae->pk) {
1552 if (sae_kdf_hash(hash_len, keyseed, "SAE-PK keys",
1553 val, sae->tmp->order_len,
1554 keys, 2 * hash_len + SAE_PMK_LEN) < 0)
1555 goto fail;
1556 } else {
1557 if (sae_kdf_hash(hash_len, keyseed, "SAE KCK and PMK",
1558 val, sae->tmp->order_len,
1559 keys, hash_len + SAE_PMK_LEN) < 0)
1560 goto fail;
1561 }
1562 #else /* CONFIG_SAE_PK */
1563 if (sae_kdf_hash(hash_len, keyseed, "SAE KCK and PMK",
1564 val, sae->tmp->order_len,
1565 keys, hash_len + SAE_PMK_LEN) < 0)
1566 goto fail;
1567 #endif /* !CONFIG_SAE_PK */
1568
1569 forced_memzero(keyseed, sizeof(keyseed));
1570 os_memcpy(sae->tmp->kck, keys, hash_len);
1571 sae->tmp->kck_len = hash_len;
1572 os_memcpy(sae->pmk, keys + hash_len, SAE_PMK_LEN);
1573 sae->pmk_len = SAE_PMK_LEN;
1574 os_memcpy(sae->pmkid, val, SAE_PMKID_LEN);
1575
1576 #ifdef CONFIG_SAE_PK
1577 if (sae->pk) {
1578 os_memcpy(sae->tmp->kek, keys + hash_len + SAE_PMK_LEN, hash_len);
1579 sae->tmp->kek_len = hash_len;
1580 wpa_hexdump_key(MSG_DEBUG, "SAE: KEK for SAE-PK",
1581 sae->tmp->kek, sae->tmp->kek_len);
1582 }
1583 #endif /* CONFIG_SAE_PK */
1584 forced_memzero(keys, sizeof(keys));
1585 wpa_hexdump_key(MSG_DEBUG, "SAE: KCK",
1586 sae->tmp->kck, sae->tmp->kck_len);
1587 wpa_hexdump_key(MSG_DEBUG, "SAE: PMK", sae->pmk, SAE_PMK_LEN);
1588
1589 ret = 0;
1590 fail:
1591 wpabuf_free(rejected_groups);
1592 crypto_bignum_deinit(tmp, 0);
1593 return ret;
1594 }
1595
1596
sae_process_commit(struct sae_data * sae)1597 int sae_process_commit(struct sae_data *sae)
1598 {
1599 u8 k[SAE_MAX_PRIME_LEN] = {0};
1600 if (sae->tmp == NULL ||
1601 (sae->tmp->ec && sae_derive_k_ecc(sae, k) < 0) ||
1602 (sae->tmp->dh && sae_derive_k_ffc(sae, k) < 0) ||
1603 sae_derive_keys(sae, k) < 0)
1604 return ESP_FAIL;
1605 return ESP_OK;
1606 }
1607
1608
sae_write_commit(struct sae_data * sae,struct wpabuf * buf,const struct wpabuf * token,const char * identifier)1609 int sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
1610 const struct wpabuf *token, const char *identifier)
1611 {
1612 u8 *pos;
1613
1614 if (sae->tmp == NULL)
1615 return ESP_FAIL;
1616
1617 wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */
1618 if (!sae->h2e && token) {
1619 wpabuf_put_buf(buf, token);
1620 wpa_hexdump(MSG_DEBUG, "SAE: Anti-clogging token",
1621 wpabuf_head(token), wpabuf_len(token));
1622 }
1623 pos = wpabuf_put(buf, sae->tmp->prime_len);
1624 if (crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos,
1625 sae->tmp->prime_len, sae->tmp->prime_len) < 0) {
1626 wpa_printf(MSG_ERROR, "SAE: failed bignum operation on own commit scalar");
1627 return ESP_FAIL;
1628 }
1629 wpa_hexdump(MSG_DEBUG, "SAE: own commit-scalar",
1630 pos, sae->tmp->prime_len);
1631 if (sae->tmp->ec) {
1632 pos = wpabuf_put(buf, 2 * sae->tmp->prime_len);
1633 if (crypto_ec_point_to_bin(sae->tmp->ec,
1634 sae->tmp->own_commit_element_ecc,
1635 pos, pos + sae->tmp->prime_len) < 0) {
1636 wpa_printf(MSG_ERROR, "SAE: failed bignum op while deriving ec point");
1637 return ESP_FAIL;
1638 }
1639 wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(x)",
1640 pos, sae->tmp->prime_len);
1641 wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(y)",
1642 pos + sae->tmp->prime_len, sae->tmp->prime_len);
1643 } else {
1644 pos = wpabuf_put(buf, sae->tmp->prime_len);
1645 if (crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos,
1646 sae->tmp->prime_len, sae->tmp->prime_len) < 0) {
1647 wpa_printf(MSG_ERROR, "SAE: failed bignum operation on commit elem ffc");
1648 return ESP_FAIL;
1649 }
1650 wpa_hexdump(MSG_DEBUG, "SAE: own commit-element",
1651 pos, sae->tmp->prime_len);
1652 }
1653
1654 if (identifier) {
1655 /* Password Identifier element */
1656 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
1657 wpabuf_put_u8(buf, 1 + os_strlen(identifier));
1658 wpabuf_put_u8(buf, WLAN_EID_EXT_PASSWORD_IDENTIFIER);
1659 wpabuf_put_str(buf, identifier);
1660 wpa_printf(MSG_DEBUG, "SAE: own Password Identifier: %s",
1661 identifier);
1662 }
1663 if (sae->h2e && sae->tmp->own_rejected_groups) {
1664 wpa_hexdump_buf(MSG_DEBUG, "SAE: own Rejected Groups",
1665 sae->tmp->own_rejected_groups);
1666 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
1667 wpabuf_put_u8(buf,
1668 1 + wpabuf_len(sae->tmp->own_rejected_groups));
1669 wpabuf_put_u8(buf, WLAN_EID_EXT_REJECTED_GROUPS);
1670 wpabuf_put_buf(buf, sae->tmp->own_rejected_groups);
1671 }
1672
1673 if (sae->h2e && token) {
1674 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
1675 wpabuf_put_u8(buf, 1 + wpabuf_len(token));
1676 wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
1677 wpabuf_put_buf(buf, token);
1678 wpa_hexdump_buf(MSG_DEBUG,
1679 "SAE: Anti-clogging token (in container)",
1680 token);
1681 }
1682 return ESP_OK;
1683 }
1684
1685
sae_group_allowed(struct sae_data * sae,int * allowed_groups,u16 group)1686 u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group)
1687 {
1688 if (allowed_groups) {
1689 int i;
1690 for (i = 0; allowed_groups[i] > 0; i++) {
1691 if (allowed_groups[i] == group)
1692 break;
1693 }
1694 if (allowed_groups[i] != group) {
1695 wpa_printf(MSG_DEBUG, "SAE: Proposed group %u not "
1696 "enabled in the current configuration",
1697 group);
1698 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
1699 }
1700 }
1701
1702 if (sae->state == SAE_COMMITTED && group != sae->group) {
1703 wpa_printf(MSG_DEBUG, "SAE: Do not allow group to be changed");
1704 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
1705 }
1706
1707 if (group != sae->group && sae_set_group(sae, group) < 0) {
1708 wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u",
1709 group);
1710 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
1711 }
1712
1713 if (sae->tmp == NULL) {
1714 wpa_printf(MSG_DEBUG, "SAE: Group information not yet initialized");
1715 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1716 }
1717
1718 if (sae->tmp->dh && !allowed_groups) {
1719 wpa_printf(MSG_DEBUG, "SAE: Do not allow FFC group %u without "
1720 "explicit configuration enabling it", group);
1721 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
1722 }
1723
1724 return WLAN_STATUS_SUCCESS;
1725 }
1726
1727
sae_is_password_id_elem(const u8 * pos,const u8 * end)1728 static int sae_is_password_id_elem(const u8 *pos, const u8 *end)
1729 {
1730 return end - pos >= 3 &&
1731 pos[0] == WLAN_EID_EXTENSION &&
1732 pos[1] >= 1 &&
1733 end - pos - 2 >= pos[1] &&
1734 pos[2] == WLAN_EID_EXT_PASSWORD_IDENTIFIER;
1735 }
1736
1737
sae_is_rejected_groups_elem(const u8 * pos,const u8 * end)1738 static int sae_is_rejected_groups_elem(const u8 *pos, const u8 *end)
1739 {
1740 return end - pos >= 3 &&
1741 pos[0] == WLAN_EID_EXTENSION &&
1742 pos[1] >= 2 &&
1743 end - pos - 2 >= pos[1] &&
1744 pos[2] == WLAN_EID_EXT_REJECTED_GROUPS;
1745 }
1746
1747
sae_is_token_container_elem(const u8 * pos,const u8 * end)1748 static int sae_is_token_container_elem(const u8 *pos, const u8 *end)
1749 {
1750 return end - pos >= 3 &&
1751 pos[0] == WLAN_EID_EXTENSION &&
1752 pos[1] >= 1 &&
1753 end - pos - 2 >= pos[1] &&
1754 pos[2] == WLAN_EID_EXT_ANTI_CLOGGING_TOKEN;
1755 }
1756
1757
sae_parse_commit_token(struct sae_data * sae,const u8 ** pos,const u8 * end,const u8 ** token,size_t * token_len,int h2e)1758 static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
1759 const u8 *end, const u8 **token,
1760 size_t *token_len, int h2e)
1761 {
1762 size_t scalar_elem_len, tlen;
1763
1764 if (token)
1765 *token = NULL;
1766 if (token_len)
1767 *token_len = 0;
1768
1769 if (h2e)
1770 return; /* No Anti-Clogging Token field outside container IE */
1771
1772 scalar_elem_len = (sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len;
1773 if (scalar_elem_len >= (size_t) (end - *pos))
1774 return; /* No extra data beyond peer scalar and element */
1775
1776 tlen = end - (*pos + scalar_elem_len);
1777
1778 if (tlen < SHA256_MAC_LEN) {
1779 wpa_printf(MSG_DEBUG,
1780 "SAE: Too short optional data (%u octets) to include our Anti-Clogging Token",
1781 (unsigned int) tlen);
1782 return;
1783 }
1784
1785 wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen);
1786 if (token)
1787 *token = *pos;
1788 if (token_len)
1789 *token_len = tlen;
1790 *pos += tlen;
1791 }
1792
1793
sae_parse_token_container(struct sae_data * sae,const u8 * pos,const u8 * end,const u8 ** token,size_t * token_len)1794 static void sae_parse_token_container(struct sae_data *sae,
1795 const u8 *pos, const u8 *end,
1796 const u8 **token, size_t *token_len)
1797 {
1798 wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
1799 pos, end - pos);
1800 if (!sae_is_token_container_elem(pos, end))
1801 return;
1802 *token = pos + 3;
1803 *token_len = pos[1] - 1;
1804 wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token (in container)",
1805 *token, *token_len);
1806 }
1807
1808
sae_parse_commit_scalar(struct sae_data * sae,const u8 ** pos,const u8 * end)1809 static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
1810 const u8 *end)
1811 {
1812 struct crypto_bignum *peer_scalar;
1813
1814 if (sae->tmp->prime_len > end - *pos) {
1815 wpa_printf(MSG_DEBUG, "SAE: Not enough data for scalar");
1816 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1817 }
1818
1819 peer_scalar = crypto_bignum_init_set(*pos, sae->tmp->prime_len);
1820 if (peer_scalar == NULL)
1821 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1822
1823 /*
1824 * IEEE Std 802.11-2012, 11.3.8.6.1: If there is a protocol instance for
1825 * the peer and it is in Authenticated state, the new Commit Message
1826 * shall be dropped if the peer-scalar is identical to the one used in
1827 * the existing protocol instance.
1828 */
1829 if (sae->state == SAE_ACCEPTED && sae->peer_commit_scalar_accepted &&
1830 crypto_bignum_cmp(sae->peer_commit_scalar_accepted,
1831 peer_scalar) == 0) {
1832 wpa_printf(MSG_DEBUG, "SAE: Do not accept re-use of previous "
1833 "peer-commit-scalar");
1834 crypto_bignum_deinit(peer_scalar, 0);
1835 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1836 }
1837
1838 /* 1 < scalar < r */
1839 if (crypto_bignum_is_zero(peer_scalar) ||
1840 crypto_bignum_is_one(peer_scalar) ||
1841 crypto_bignum_cmp(peer_scalar, sae->tmp->order) >= 0) {
1842 wpa_printf(MSG_DEBUG, "SAE: Invalid peer scalar");
1843 crypto_bignum_deinit(peer_scalar, 0);
1844 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1845 }
1846
1847 crypto_bignum_deinit(sae->peer_commit_scalar, 0);
1848 sae->peer_commit_scalar = peer_scalar;
1849 wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-scalar",
1850 *pos, sae->tmp->prime_len);
1851 *pos += sae->tmp->prime_len;
1852
1853 return WLAN_STATUS_SUCCESS;
1854 }
1855
1856
sae_parse_commit_element_ecc(struct sae_data * sae,const u8 ** pos,const u8 * end)1857 static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 **pos,
1858 const u8 *end)
1859 {
1860 u8 prime[SAE_MAX_ECC_PRIME_LEN];
1861
1862 if (2 * sae->tmp->prime_len > end - *pos) {
1863 wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
1864 "commit-element");
1865 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1866 }
1867
1868 if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
1869 sae->tmp->prime_len) < 0)
1870 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1871
1872 /* element x and y coordinates < p */
1873 if (os_memcmp(*pos, prime, sae->tmp->prime_len) >= 0 ||
1874 os_memcmp(*pos + sae->tmp->prime_len, prime,
1875 sae->tmp->prime_len) >= 0) {
1876 wpa_printf(MSG_DEBUG, "SAE: Invalid coordinates in peer "
1877 "element");
1878 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1879 }
1880
1881 wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(x)",
1882 *pos, sae->tmp->prime_len);
1883 wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(y)",
1884 *pos + sae->tmp->prime_len, sae->tmp->prime_len);
1885
1886 crypto_ec_point_deinit(sae->tmp->peer_commit_element_ecc, 0);
1887 sae->tmp->peer_commit_element_ecc =
1888 crypto_ec_point_from_bin(sae->tmp->ec, *pos);
1889 if (!sae->tmp->peer_commit_element_ecc) {
1890 wpa_printf(MSG_DEBUG, "SAE: Peer element is not a valid point");
1891 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1892 }
1893
1894 if (!crypto_ec_point_is_on_curve(sae->tmp->ec,
1895 sae->tmp->peer_commit_element_ecc)) {
1896 wpa_printf(MSG_DEBUG, "SAE: Peer element is not on curve");
1897 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1898 }
1899
1900 *pos += 2 * sae->tmp->prime_len;
1901
1902 return WLAN_STATUS_SUCCESS;
1903 }
1904
1905
sae_parse_commit_element_ffc(struct sae_data * sae,const u8 ** pos,const u8 * end)1906 static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 **pos,
1907 const u8 *end)
1908 {
1909 struct crypto_bignum *res, *one;
1910 const u8 one_bin[1] = { 0x01 };
1911
1912 if (sae->tmp->prime_len > end - *pos) {
1913 wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
1914 "commit-element");
1915 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1916 }
1917 wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element", *pos,
1918 sae->tmp->prime_len);
1919
1920 crypto_bignum_deinit(sae->tmp->peer_commit_element_ffc, 0);
1921 sae->tmp->peer_commit_element_ffc =
1922 crypto_bignum_init_set(*pos, sae->tmp->prime_len);
1923 if (sae->tmp->peer_commit_element_ffc == NULL)
1924 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1925 /* 1 < element < p - 1 */
1926 res = crypto_bignum_init();
1927 one = crypto_bignum_init_set(one_bin, sizeof(one_bin));
1928 if (!res || !one ||
1929 crypto_bignum_sub(sae->tmp->prime, one, res) ||
1930 crypto_bignum_is_zero(sae->tmp->peer_commit_element_ffc) ||
1931 crypto_bignum_is_one(sae->tmp->peer_commit_element_ffc) ||
1932 crypto_bignum_cmp(sae->tmp->peer_commit_element_ffc, res) >= 0) {
1933 crypto_bignum_deinit(res, 0);
1934 crypto_bignum_deinit(one, 0);
1935 wpa_printf(MSG_DEBUG, "SAE: Invalid peer element");
1936 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1937 }
1938 crypto_bignum_deinit(one, 0);
1939
1940 /* scalar-op(r, ELEMENT) = 1 modulo p */
1941 if (crypto_bignum_exptmod(sae->tmp->peer_commit_element_ffc,
1942 sae->tmp->order, sae->tmp->prime, res) < 0 ||
1943 !crypto_bignum_is_one(res)) {
1944 wpa_printf(MSG_DEBUG, "SAE: Invalid peer element (scalar-op)");
1945 crypto_bignum_deinit(res, 0);
1946 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1947 }
1948 crypto_bignum_deinit(res, 0);
1949
1950 *pos += sae->tmp->prime_len;
1951
1952 return WLAN_STATUS_SUCCESS;
1953 }
1954
1955
sae_parse_commit_element(struct sae_data * sae,const u8 ** pos,const u8 * end)1956 static u16 sae_parse_commit_element(struct sae_data *sae, const u8 **pos,
1957 const u8 *end)
1958 {
1959 if (sae->tmp->dh)
1960 return sae_parse_commit_element_ffc(sae, pos, end);
1961 return sae_parse_commit_element_ecc(sae, pos, end);
1962 }
1963
1964
sae_parse_password_identifier(struct sae_data * sae,const u8 ** pos,const u8 * end)1965 static int sae_parse_password_identifier(struct sae_data *sae,
1966 const u8 **pos, const u8 *end)
1967 {
1968 const u8 *epos;
1969 u8 len;
1970
1971 wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
1972 *pos, end - *pos);
1973 if (!sae_is_password_id_elem(*pos, end)) {
1974 if (sae->tmp->pw_id) {
1975 wpa_printf(MSG_DEBUG,
1976 "SAE: No Password Identifier included, but expected one (%s)",
1977 sae->tmp->pw_id);
1978 return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
1979 }
1980 os_free(sae->tmp->pw_id);
1981 sae->tmp->pw_id = NULL;
1982 return WLAN_STATUS_SUCCESS; /* No Password Identifier */
1983 }
1984
1985 epos = *pos;
1986 epos++; /* skip IE type */
1987 len = *epos++; /* IE length */
1988 if (len > end - epos || len < 1)
1989 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1990 epos++; /* skip ext ID */
1991 len--;
1992
1993 if (sae->tmp->pw_id &&
1994 (len != os_strlen(sae->tmp->pw_id) ||
1995 os_memcmp(sae->tmp->pw_id, epos, len) != 0)) {
1996 wpa_printf(MSG_DEBUG,
1997 "SAE: The included Password Identifier does not match the expected one (%s)",
1998 sae->tmp->pw_id);
1999 return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
2000 }
2001
2002 os_free(sae->tmp->pw_id);
2003 sae->tmp->pw_id = os_malloc(len + 1);
2004 if (!sae->tmp->pw_id)
2005 return WLAN_STATUS_UNSPECIFIED_FAILURE;
2006 os_memcpy(sae->tmp->pw_id, epos, len);
2007 sae->tmp->pw_id[len] = '\0';
2008 *pos = epos + len;
2009 return WLAN_STATUS_SUCCESS;
2010 }
2011
2012
sae_parse_rejected_groups(struct sae_data * sae,const u8 ** pos,const u8 * end)2013 static int sae_parse_rejected_groups(struct sae_data *sae,
2014 const u8 **pos, const u8 *end)
2015 {
2016 const u8 *epos;
2017 u8 len;
2018
2019 wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
2020 *pos, end - *pos);
2021 if (!sae_is_rejected_groups_elem(*pos, end)) {
2022 wpabuf_free(sae->tmp->peer_rejected_groups);
2023 sae->tmp->peer_rejected_groups = NULL;
2024 return WLAN_STATUS_SUCCESS;
2025 }
2026
2027 epos = *pos;
2028 epos++; /* skip IE type */
2029 len = *epos++; /* IE length */
2030 if (len > end - epos || len < 1)
2031 return WLAN_STATUS_UNSPECIFIED_FAILURE;
2032 epos++; /* skip ext ID */
2033 len--;
2034
2035 if (len & 1) {
2036 wpa_printf(MSG_DEBUG,
2037 "SAE: Invalid length of the Rejected Groups element payload: %u",
2038 len);
2039 return WLAN_STATUS_UNSPECIFIED_FAILURE;
2040 }
2041 wpabuf_free(sae->tmp->peer_rejected_groups);
2042 sae->tmp->peer_rejected_groups = wpabuf_alloc(len);
2043 if (!sae->tmp->peer_rejected_groups)
2044 return WLAN_STATUS_UNSPECIFIED_FAILURE;
2045 wpabuf_put_data(sae->tmp->peer_rejected_groups, epos, len);
2046 wpa_hexdump_buf(MSG_DEBUG, "SAE: Received Rejected Groups list",
2047 sae->tmp->peer_rejected_groups);
2048 *pos = epos + len;
2049 return WLAN_STATUS_SUCCESS;
2050 }
2051
2052
sae_parse_commit(struct sae_data * sae,const u8 * data,size_t len,const u8 ** token,size_t * token_len,int * allowed_groups,int h2e)2053 u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
2054 const u8 **token, size_t *token_len, int *allowed_groups,
2055 int h2e)
2056 {
2057 const u8 *pos = data, *end = data + len;
2058 u16 res;
2059
2060 /* Check Finite Cyclic Group */
2061 if (end - pos < 2)
2062 return WLAN_STATUS_UNSPECIFIED_FAILURE;
2063 res = sae_group_allowed(sae, allowed_groups, WPA_GET_LE16(pos));
2064 if (res != WLAN_STATUS_SUCCESS)
2065 return res;
2066 pos += 2;
2067
2068 /* Optional Anti-Clogging Token */
2069 sae_parse_commit_token(sae, &pos, end, token, token_len, h2e);
2070
2071 /* commit-scalar */
2072 res = sae_parse_commit_scalar(sae, &pos, end);
2073 if (res != WLAN_STATUS_SUCCESS)
2074 return res;
2075
2076 /* commit-element */
2077 res = sae_parse_commit_element(sae, &pos, end);
2078 if (res != WLAN_STATUS_SUCCESS)
2079 return res;
2080
2081 /* Optional Password Identifier element */
2082 res = sae_parse_password_identifier(sae, &pos, end);
2083 if (res != WLAN_STATUS_SUCCESS)
2084 return res;
2085
2086 /* Conditional Rejected Groups element */
2087 if (h2e) {
2088 res = sae_parse_rejected_groups(sae, &pos, end);
2089 if (res != WLAN_STATUS_SUCCESS)
2090 return res;
2091 } else {
2092 wpabuf_free(sae->tmp->peer_rejected_groups);
2093 sae->tmp->peer_rejected_groups = NULL;
2094 }
2095
2096 /* Optional Anti-Clogging Token Container element */
2097 if (h2e)
2098 sae_parse_token_container(sae, pos, end, token, token_len);
2099
2100 /*
2101 * Check whether peer-commit-scalar and PEER-COMMIT-ELEMENT are same as
2102 * the values we sent which would be evidence of a reflection attack.
2103 */
2104 if (!sae->tmp->own_commit_scalar ||
2105 crypto_bignum_cmp(sae->tmp->own_commit_scalar,
2106 sae->peer_commit_scalar) != 0 ||
2107 (sae->tmp->dh &&
2108 (!sae->tmp->own_commit_element_ffc ||
2109 crypto_bignum_cmp(sae->tmp->own_commit_element_ffc,
2110 sae->tmp->peer_commit_element_ffc) != 0)) ||
2111 (sae->tmp->ec &&
2112 (!sae->tmp->own_commit_element_ecc ||
2113 crypto_ec_point_cmp(sae->tmp->ec,
2114 sae->tmp->own_commit_element_ecc,
2115 sae->tmp->peer_commit_element_ecc) != 0)))
2116 return WLAN_STATUS_SUCCESS; /* scalars/elements are different */
2117
2118 /*
2119 * This is a reflection attack - return special value to trigger caller
2120 * to silently discard the frame instead of replying with a specific
2121 * status code.
2122 */
2123 return SAE_SILENTLY_DISCARD;
2124 }
2125
2126
sae_cn_confirm(struct sae_data * sae,const u8 * sc,const struct crypto_bignum * scalar1,const u8 * element1,size_t element1_len,const struct crypto_bignum * scalar2,const u8 * element2,size_t element2_len,u8 * confirm)2127 static int sae_cn_confirm(struct sae_data *sae, const u8 *sc,
2128 const struct crypto_bignum *scalar1,
2129 const u8 *element1, size_t element1_len,
2130 const struct crypto_bignum *scalar2,
2131 const u8 *element2, size_t element2_len,
2132 u8 *confirm)
2133 {
2134 const u8 *addr[5];
2135 size_t len[5];
2136 u8 scalar_b1[SAE_MAX_PRIME_LEN], scalar_b2[SAE_MAX_PRIME_LEN];
2137
2138 /* Confirm
2139 * CN(key, X, Y, Z, ...) =
2140 * HMAC-SHA256(key, D2OS(X) || D2OS(Y) || D2OS(Z) | ...)
2141 * confirm = CN(KCK, send-confirm, commit-scalar, COMMIT-ELEMENT,
2142 * peer-commit-scalar, PEER-COMMIT-ELEMENT)
2143 * verifier = CN(KCK, peer-send-confirm, peer-commit-scalar,
2144 * PEER-COMMIT-ELEMENT, commit-scalar, COMMIT-ELEMENT)
2145 */
2146 if (crypto_bignum_to_bin(scalar1, scalar_b1, sizeof(scalar_b1),
2147 sae->tmp->prime_len) < 0 ||
2148 crypto_bignum_to_bin(scalar2, scalar_b2, sizeof(scalar_b2),
2149 sae->tmp->prime_len) < 0)
2150 return ESP_FAIL;
2151 addr[0] = sc;
2152 len[0] = 2;
2153 addr[1] = scalar_b1;
2154 len[1] = sae->tmp->prime_len;
2155 addr[2] = element1;
2156 len[2] = element1_len;
2157 addr[3] = scalar_b2;
2158 len[3] = sae->tmp->prime_len;
2159 addr[4] = element2;
2160 len[4] = element2_len;
2161 return hkdf_extract(SAE_KCK_LEN, sae->tmp->kck, sae->tmp->kck_len,
2162 5, addr, len, confirm);
2163 }
2164
2165
sae_cn_confirm_ecc(struct sae_data * sae,const u8 * sc,const struct crypto_bignum * scalar1,const struct crypto_ec_point * element1,const struct crypto_bignum * scalar2,const struct crypto_ec_point * element2,u8 * confirm)2166 static int sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc,
2167 const struct crypto_bignum *scalar1,
2168 const struct crypto_ec_point *element1,
2169 const struct crypto_bignum *scalar2,
2170 const struct crypto_ec_point *element2,
2171 u8 *confirm)
2172 {
2173 u8 element_b1[2 * SAE_MAX_ECC_PRIME_LEN];
2174 u8 element_b2[2 * SAE_MAX_ECC_PRIME_LEN];
2175
2176 if (crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1,
2177 element_b1 + sae->tmp->prime_len) < 0) {
2178 wpa_printf(MSG_ERROR, "SAE: failed bignum op while deriving ec point");
2179 return ESP_FAIL;
2180 }
2181 if (crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2,
2182 element_b2 + sae->tmp->prime_len) < 0) {
2183 wpa_printf(MSG_ERROR, "SAE: failed bignum op while deriving ec point");
2184 return ESP_FAIL;
2185 }
2186
2187 sae_cn_confirm(sae, sc, scalar1, element_b1, 2 * sae->tmp->prime_len,
2188 scalar2, element_b2, 2 * sae->tmp->prime_len, confirm);
2189 return ESP_OK;
2190 }
2191
2192
sae_cn_confirm_ffc(struct sae_data * sae,const u8 * sc,const struct crypto_bignum * scalar1,const struct crypto_bignum * element1,const struct crypto_bignum * scalar2,const struct crypto_bignum * element2,u8 * confirm)2193 static int sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc,
2194 const struct crypto_bignum *scalar1,
2195 const struct crypto_bignum *element1,
2196 const struct crypto_bignum *scalar2,
2197 const struct crypto_bignum *element2,
2198 u8 *confirm)
2199 {
2200 u8 element_b1[SAE_MAX_PRIME_LEN];
2201 u8 element_b2[SAE_MAX_PRIME_LEN];
2202
2203 if (crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1),
2204 sae->tmp->prime_len) < 0) {
2205 wpa_printf(MSG_ERROR, "SAE: failed bignum op while generating SAE confirm - e1");
2206 return ESP_FAIL;
2207 }
2208 if (crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2),
2209 sae->tmp->prime_len) < 0) {
2210 wpa_printf(MSG_ERROR, "SAE: failed bignum op while generating SAE confirm - e2");
2211 return ESP_FAIL;
2212 }
2213
2214 if (sae_cn_confirm(sae, sc, scalar1, element_b1, sae->tmp->prime_len,
2215 scalar2, element_b2, sae->tmp->prime_len, confirm) < 0)
2216 return -1;
2217 return ESP_OK;
2218 }
2219
2220
sae_write_confirm(struct sae_data * sae,struct wpabuf * buf)2221 int sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
2222 {
2223 const u8 *sc;
2224 size_t hash_len;
2225
2226 if (sae->tmp == NULL)
2227 return ESP_FAIL;
2228
2229 hash_len = sae->tmp->kck_len;
2230 /* Send-Confirm */
2231 sc = wpabuf_put(buf, 0);
2232 wpabuf_put_le16(buf, sae->send_confirm);
2233 if (sae->send_confirm < 0xffff)
2234 sae->send_confirm++;
2235
2236 if (sae->tmp->ec) {
2237 if (sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar,
2238 sae->tmp->own_commit_element_ecc,
2239 sae->peer_commit_scalar,
2240 sae->tmp->peer_commit_element_ecc,
2241 wpabuf_put(buf, hash_len))) {
2242 wpa_printf(MSG_ERROR, "SAE: failed generate SAE confirm (ecc)");
2243 return ESP_FAIL;
2244 }
2245 } else {
2246 if (sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar,
2247 sae->tmp->own_commit_element_ffc,
2248 sae->peer_commit_scalar,
2249 sae->tmp->peer_commit_element_ffc,
2250 wpabuf_put(buf, hash_len))) {
2251 wpa_printf(MSG_ERROR, "SAE: failed generate SAE confirm (ffc)");
2252 return ESP_FAIL;
2253 }
2254 }
2255 return ESP_OK;
2256 }
2257
2258
sae_check_confirm(struct sae_data * sae,const u8 * data,size_t len)2259 int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len)
2260 {
2261 u8 verifier[SAE_MAX_HASH_LEN];
2262 size_t hash_len;
2263
2264 if (!sae->tmp) {
2265 return ESP_FAIL;
2266 }
2267 hash_len = sae->tmp->kck_len;
2268 if (len < 2 + hash_len) {
2269 wpa_printf(MSG_DEBUG, "SAE: Too short confirm message");
2270 return ESP_FAIL;
2271 }
2272
2273 wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data));
2274
2275 if (sae->tmp == NULL || !sae->peer_commit_scalar ||
2276 !sae->tmp->own_commit_scalar) {
2277 wpa_printf(MSG_DEBUG, "SAE: Temporary data not yet available");
2278 return ESP_FAIL;
2279 }
2280
2281 if (sae->tmp->ec) {
2282 if (!sae->tmp->peer_commit_element_ecc ||
2283 !sae->tmp->own_commit_element_ecc)
2284 return ESP_FAIL;
2285 if (sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar,
2286 sae->tmp->peer_commit_element_ecc,
2287 sae->tmp->own_commit_scalar,
2288 sae->tmp->own_commit_element_ecc,
2289 verifier)) {
2290 wpa_printf(MSG_ERROR, "SAE: failed to check SAE confirm (ecc)");
2291 return ESP_FAIL;
2292 }
2293 } else {
2294 if (!sae->tmp->peer_commit_element_ffc ||
2295 !sae->tmp->own_commit_element_ffc)
2296 return ESP_FAIL;
2297 if (sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar,
2298 sae->tmp->peer_commit_element_ffc,
2299 sae->tmp->own_commit_scalar,
2300 sae->tmp->own_commit_element_ffc,
2301 verifier)) {
2302 wpa_printf(MSG_ERROR, "SAE: failed check SAE confirm (ffc)");
2303 return ESP_FAIL;
2304 }
2305 }
2306
2307 if (os_memcmp_const(verifier, data + 2, hash_len) != 0) {
2308 wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch");
2309 wpa_hexdump(MSG_DEBUG, "SAE: Received confirm",
2310 data + 2, hash_len);
2311 wpa_hexdump(MSG_DEBUG, "SAE: Calculated verifier",
2312 verifier, hash_len);
2313 return ESP_FAIL;
2314 }
2315
2316 #ifdef CONFIG_SAE_PK
2317 if (sae_check_confirm_pk(sae, data + 2 + hash_len,
2318 len - 2 - hash_len) != ESP_OK)
2319 return ESP_FAIL;
2320 #endif /* CONFIG_SAE_PK */
2321
2322 return ESP_OK;
2323 }
2324
sae_state_txt(enum sae_state state)2325 const char * sae_state_txt(enum sae_state state)
2326 {
2327 switch (state) {
2328 case SAE_NOTHING:
2329 return "Nothing";
2330 case SAE_COMMITTED:
2331 return "Committed";
2332 case SAE_CONFIRMED:
2333 return "Confirmed";
2334 case SAE_ACCEPTED:
2335 return "Accepted";
2336 }
2337 return "?";
2338 }
2339
2340 #endif /* CONFIG_WPA3_SAE */
2341