2 * Simultaneous authentication of equals
3 * Copyright (c) 2012-2016, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
12 #include "crypto/crypto.h"
13 #include "crypto/sha256.h"
14 #include "crypto/random.h"
15 #include "crypto/dh_groups.h"
16 #include "ieee802_11_defs.h"
20 int sae_set_group(struct sae_data *sae, int group)
22 struct sae_temporary_data *tmp;
25 tmp = sae->tmp = os_zalloc(sizeof(*tmp));
29 /* First, check if this is an ECC group */
30 tmp->ec = crypto_ec_init(group);
32 wpa_printf(MSG_DEBUG, "SAE: Selecting supported ECC group %d",
35 tmp->prime_len = crypto_ec_prime_len(tmp->ec);
36 tmp->prime = crypto_ec_get_prime(tmp->ec);
37 tmp->order = crypto_ec_get_order(tmp->ec);
41 /* Not an ECC group, check FFC */
42 tmp->dh = dh_groups_get(group);
44 wpa_printf(MSG_DEBUG, "SAE: Selecting supported FFC group %d",
47 tmp->prime_len = tmp->dh->prime_len;
48 if (tmp->prime_len > SAE_MAX_PRIME_LEN) {
53 tmp->prime_buf = crypto_bignum_init_set(tmp->dh->prime,
55 if (tmp->prime_buf == NULL) {
59 tmp->prime = tmp->prime_buf;
61 tmp->order_buf = crypto_bignum_init_set(tmp->dh->order,
63 if (tmp->order_buf == NULL) {
67 tmp->order = tmp->order_buf;
72 /* Unsupported group */
74 "SAE: Group %d not supported by the crypto library", group);
79 void sae_clear_temp_data(struct sae_data *sae)
81 struct sae_temporary_data *tmp;
82 if (sae == NULL || sae->tmp == NULL)
85 crypto_ec_deinit(tmp->ec);
86 crypto_bignum_deinit(tmp->prime_buf, 0);
87 crypto_bignum_deinit(tmp->order_buf, 0);
88 crypto_bignum_deinit(tmp->sae_rand, 1);
89 crypto_bignum_deinit(tmp->pwe_ffc, 1);
90 crypto_bignum_deinit(tmp->own_commit_scalar, 0);
91 crypto_bignum_deinit(tmp->own_commit_element_ffc, 0);
92 crypto_bignum_deinit(tmp->peer_commit_element_ffc, 0);
93 crypto_ec_point_deinit(tmp->pwe_ecc, 1);
94 crypto_ec_point_deinit(tmp->own_commit_element_ecc, 0);
95 crypto_ec_point_deinit(tmp->peer_commit_element_ecc, 0);
96 wpabuf_free(tmp->anti_clogging_token);
98 bin_clear_free(tmp, sizeof(*tmp));
103 void sae_clear_data(struct sae_data *sae)
107 sae_clear_temp_data(sae);
108 crypto_bignum_deinit(sae->peer_commit_scalar, 0);
109 os_memset(sae, 0, sizeof(*sae));
113 static void buf_shift_right(u8 *buf, size_t len, size_t bits)
116 for (i = len - 1; i > 0; i--)
117 buf[i] = (buf[i - 1] << (8 - bits)) | (buf[i] >> bits);
122 static struct crypto_bignum * sae_get_rand(struct sae_data *sae)
124 u8 val[SAE_MAX_PRIME_LEN];
126 struct crypto_bignum *bn = NULL;
127 int order_len_bits = crypto_bignum_bits(sae->tmp->order);
128 size_t order_len = (order_len_bits + 7) / 8;
130 if (order_len > sizeof(val))
134 if (iter++ > 100 || random_get_bytes(val, order_len) < 0)
136 if (order_len_bits % 8)
137 buf_shift_right(val, order_len, 8 - order_len_bits % 8);
138 bn = crypto_bignum_init_set(val, order_len);
141 if (crypto_bignum_is_zero(bn) ||
142 crypto_bignum_is_one(bn) ||
143 crypto_bignum_cmp(bn, sae->tmp->order) >= 0) {
144 crypto_bignum_deinit(bn, 0);
150 os_memset(val, 0, order_len);
155 static struct crypto_bignum * sae_get_rand_and_mask(struct sae_data *sae)
157 crypto_bignum_deinit(sae->tmp->sae_rand, 1);
158 sae->tmp->sae_rand = sae_get_rand(sae);
159 if (sae->tmp->sae_rand == NULL)
161 return sae_get_rand(sae);
165 static void sae_pwd_seed_key(const u8 *addr1, const u8 *addr2, u8 *key)
167 wpa_printf(MSG_DEBUG, "SAE: PWE derivation - addr1=" MACSTR
168 " addr2=" MACSTR, MAC2STR(addr1), MAC2STR(addr2));
169 if (os_memcmp(addr1, addr2, ETH_ALEN) > 0) {
170 os_memcpy(key, addr1, ETH_ALEN);
171 os_memcpy(key + ETH_ALEN, addr2, ETH_ALEN);
173 os_memcpy(key, addr2, ETH_ALEN);
174 os_memcpy(key + ETH_ALEN, addr1, ETH_ALEN);
179 static struct crypto_bignum *
180 get_rand_1_to_p_1(const u8 *prime, size_t prime_len, size_t prime_bits,
184 struct crypto_bignum *r;
185 u8 tmp[SAE_MAX_ECC_PRIME_LEN];
187 if (random_get_bytes(tmp, prime_len) < 0)
190 buf_shift_right(tmp, prime_len, 8 - prime_bits % 8);
191 if (os_memcmp(tmp, prime, prime_len) >= 0)
193 r = crypto_bignum_init_set(tmp, prime_len);
196 if (crypto_bignum_is_zero(r)) {
197 crypto_bignum_deinit(r, 0);
201 *r_odd = tmp[prime_len - 1] & 0x01;
209 static int is_quadratic_residue_blind(struct sae_data *sae,
210 const u8 *prime, size_t bits,
211 const struct crypto_bignum *qr,
212 const struct crypto_bignum *qnr,
213 const struct crypto_bignum *y_sqr)
215 struct crypto_bignum *r, *num;
216 int r_odd, check, res = -1;
219 * Use the blinding technique to mask y_sqr while determining
220 * whether it is a quadratic residue modulo p to avoid leaking
221 * timing information while determining the Legendre symbol.
224 * r = a random number between 1 and p-1, inclusive
225 * num = (v * r * r) modulo p
227 r = get_rand_1_to_p_1(prime, sae->tmp->prime_len, bits, &r_odd);
231 num = crypto_bignum_init();
233 crypto_bignum_mulmod(y_sqr, r, sae->tmp->prime, num) < 0 ||
234 crypto_bignum_mulmod(num, r, sae->tmp->prime, num) < 0)
239 * num = (num * qr) module p
240 * LGR(num, p) = 1 ==> quadratic residue
242 if (crypto_bignum_mulmod(num, qr, sae->tmp->prime, num) < 0)
247 * num = (num * qnr) module p
248 * LGR(num, p) = -1 ==> quadratic residue
250 if (crypto_bignum_mulmod(num, qnr, sae->tmp->prime, num) < 0)
255 res = crypto_bignum_legendre(num, sae->tmp->prime);
262 crypto_bignum_deinit(num, 1);
263 crypto_bignum_deinit(r, 1);
268 static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
270 const struct crypto_bignum *qr,
271 const struct crypto_bignum *qnr,
272 struct crypto_bignum **ret_x_cand)
274 u8 pwd_value[SAE_MAX_ECC_PRIME_LEN];
275 struct crypto_bignum *y_sqr, *x_cand;
281 wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
283 /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
284 bits = crypto_ec_prime_len_bits(sae->tmp->ec);
285 if (sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
286 prime, sae->tmp->prime_len, pwd_value, bits) < 0)
289 buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8);
290 wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
291 pwd_value, sae->tmp->prime_len);
293 if (os_memcmp(pwd_value, prime, sae->tmp->prime_len) >= 0)
296 x_cand = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
299 y_sqr = crypto_ec_point_compute_y_sqr(sae->tmp->ec, x_cand);
301 crypto_bignum_deinit(x_cand, 1);
305 res = is_quadratic_residue_blind(sae, prime, bits, qr, qnr, y_sqr);
306 crypto_bignum_deinit(y_sqr, 1);
308 crypto_bignum_deinit(x_cand, 1);
312 *ret_x_cand = x_cand;
317 static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
318 struct crypto_bignum *pwe)
320 u8 pwd_value[SAE_MAX_PRIME_LEN];
321 size_t bits = sae->tmp->prime_len * 8;
323 struct crypto_bignum *a, *b;
326 wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
328 /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
329 if (sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
330 sae->tmp->dh->prime, sae->tmp->prime_len, pwd_value,
333 wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", pwd_value,
334 sae->tmp->prime_len);
336 if (os_memcmp(pwd_value, sae->tmp->dh->prime, sae->tmp->prime_len) >= 0)
338 wpa_printf(MSG_DEBUG, "SAE: pwd-value >= p");
342 /* PWE = pwd-value^((p-1)/r) modulo p */
344 a = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
346 if (sae->tmp->dh->safe_prime) {
348 * r = (p-1)/2 for the group used here, so this becomes:
349 * PWE = pwd-value^2 modulo p
352 b = crypto_bignum_init_set(exp, sizeof(exp));
354 /* Calculate exponent: (p-1)/r */
356 b = crypto_bignum_init_set(exp, sizeof(exp));
358 crypto_bignum_sub(sae->tmp->prime, b, b) < 0 ||
359 crypto_bignum_div(b, sae->tmp->order, b) < 0) {
360 crypto_bignum_deinit(b, 0);
365 if (a == NULL || b == NULL)
368 res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe);
370 crypto_bignum_deinit(a, 0);
371 crypto_bignum_deinit(b, 0);
374 wpa_printf(MSG_DEBUG, "SAE: Failed to calculate PWE");
378 /* if (PWE > 1) --> found */
379 if (crypto_bignum_is_zero(pwe) || crypto_bignum_is_one(pwe)) {
380 wpa_printf(MSG_DEBUG, "SAE: PWE <= 1");
384 wpa_printf(MSG_DEBUG, "SAE: PWE found");
389 static int get_random_qr_qnr(const u8 *prime, size_t prime_len,
390 const struct crypto_bignum *prime_bn,
391 size_t prime_bits, struct crypto_bignum **qr,
392 struct crypto_bignum **qnr)
397 while (!(*qr) || !(*qnr)) {
398 u8 tmp[SAE_MAX_ECC_PRIME_LEN];
399 struct crypto_bignum *q;
402 if (random_get_bytes(tmp, prime_len) < 0)
405 buf_shift_right(tmp, prime_len, 8 - prime_bits % 8);
406 if (os_memcmp(tmp, prime, prime_len) >= 0)
408 q = crypto_bignum_init_set(tmp, prime_len);
411 res = crypto_bignum_legendre(q, prime_bn);
413 if (res == 1 && !(*qr))
415 else if (res == -1 && !(*qnr))
418 crypto_bignum_deinit(q, 0);
421 return (*qr && *qnr) ? 0 : -1;
425 static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
426 const u8 *addr2, const u8 *password,
427 size_t password_len, const char *identifier)
430 u8 addrs[2 * ETH_ALEN];
434 u8 dummy_password[32];
435 size_t dummy_password_len;
436 int pwd_seed_odd = 0;
437 u8 prime[SAE_MAX_ECC_PRIME_LEN];
439 struct crypto_bignum *x = NULL, *qr, *qnr;
443 dummy_password_len = password_len;
444 if (dummy_password_len > sizeof(dummy_password))
445 dummy_password_len = sizeof(dummy_password);
446 if (random_get_bytes(dummy_password, dummy_password_len) < 0)
449 prime_len = sae->tmp->prime_len;
450 if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
453 bits = crypto_ec_prime_len_bits(sae->tmp->ec);
456 * Create a random quadratic residue (qr) and quadratic non-residue
457 * (qnr) modulo p for blinding purposes during the loop.
459 if (get_random_qr_qnr(prime, prime_len, sae->tmp->prime, bits,
463 wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
464 password, password_len);
466 wpa_printf(MSG_DEBUG, "SAE: password identifier: %s",
470 * H(salt, ikm) = HMAC-SHA256(salt, ikm)
471 * base = password [|| identifier]
472 * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
475 sae_pwd_seed_key(addr1, addr2, addrs);
478 len[0] = password_len;
481 addr[num_elem] = (const u8 *) identifier;
482 len[num_elem] = os_strlen(identifier);
485 addr[num_elem] = &counter;
486 len[num_elem] = sizeof(counter);
490 * Continue for at least k iterations to protect against side-channel
491 * attacks that attempt to determine the number of iterations required
494 for (counter = 1; counter <= k || !x; counter++) {
495 u8 pwd_seed[SHA256_MAC_LEN];
496 struct crypto_bignum *x_cand;
499 /* This should not happen in practice */
500 wpa_printf(MSG_DEBUG, "SAE: Failed to derive PWE");
504 wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
505 if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem,
506 addr, len, pwd_seed) < 0)
509 res = sae_test_pwd_seed_ecc(sae, pwd_seed,
510 prime, qr, qnr, &x_cand);
514 wpa_printf(MSG_DEBUG,
515 "SAE: Selected pwd-seed with counter %u",
518 pwd_seed_odd = pwd_seed[SHA256_MAC_LEN - 1] & 0x01;
519 os_memset(pwd_seed, 0, sizeof(pwd_seed));
522 * Use a dummy password for the following rounds, if
525 addr[0] = dummy_password;
526 len[0] = dummy_password_len;
527 } else if (res > 0) {
528 crypto_bignum_deinit(x_cand, 1);
533 wpa_printf(MSG_DEBUG, "SAE: Could not generate PWE");
538 if (!sae->tmp->pwe_ecc)
539 sae->tmp->pwe_ecc = crypto_ec_point_init(sae->tmp->ec);
540 if (!sae->tmp->pwe_ecc)
543 res = crypto_ec_point_solve_y_coord(sae->tmp->ec,
544 sae->tmp->pwe_ecc, x,
546 crypto_bignum_deinit(x, 1);
549 * This should not happen since we already checked that there
552 wpa_printf(MSG_DEBUG, "SAE: Could not solve y");
556 crypto_bignum_deinit(qr, 0);
557 crypto_bignum_deinit(qnr, 0);
563 static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
564 const u8 *addr2, const u8 *password,
565 size_t password_len, const char *identifier)
568 u8 addrs[2 * ETH_ALEN];
574 if (sae->tmp->pwe_ffc == NULL) {
575 sae->tmp->pwe_ffc = crypto_bignum_init();
576 if (sae->tmp->pwe_ffc == NULL)
580 wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
581 password, password_len);
584 * H(salt, ikm) = HMAC-SHA256(salt, ikm)
585 * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
586 * password [|| identifier] || counter)
588 sae_pwd_seed_key(addr1, addr2, addrs);
591 len[0] = password_len;
594 addr[num_elem] = (const u8 *) identifier;
595 len[num_elem] = os_strlen(identifier);
598 addr[num_elem] = &counter;
599 len[num_elem] = sizeof(counter);
602 for (counter = 1; !found; counter++) {
603 u8 pwd_seed[SHA256_MAC_LEN];
607 /* This should not happen in practice */
608 wpa_printf(MSG_DEBUG, "SAE: Failed to derive PWE");
612 wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
613 if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem,
614 addr, len, pwd_seed) < 0)
616 res = sae_test_pwd_seed_ffc(sae, pwd_seed, sae->tmp->pwe_ffc);
620 wpa_printf(MSG_DEBUG, "SAE: Use this PWE");
625 return found ? 0 : -1;
629 static int sae_derive_commit_element_ecc(struct sae_data *sae,
630 struct crypto_bignum *mask)
632 /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */
633 if (!sae->tmp->own_commit_element_ecc) {
634 sae->tmp->own_commit_element_ecc =
635 crypto_ec_point_init(sae->tmp->ec);
636 if (!sae->tmp->own_commit_element_ecc)
640 if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc, mask,
641 sae->tmp->own_commit_element_ecc) < 0 ||
642 crypto_ec_point_invert(sae->tmp->ec,
643 sae->tmp->own_commit_element_ecc) < 0) {
644 wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element");
652 static int sae_derive_commit_element_ffc(struct sae_data *sae,
653 struct crypto_bignum *mask)
655 /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */
656 if (!sae->tmp->own_commit_element_ffc) {
657 sae->tmp->own_commit_element_ffc = crypto_bignum_init();
658 if (!sae->tmp->own_commit_element_ffc)
662 if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, mask, sae->tmp->prime,
663 sae->tmp->own_commit_element_ffc) < 0 ||
664 crypto_bignum_inverse(sae->tmp->own_commit_element_ffc,
666 sae->tmp->own_commit_element_ffc) < 0) {
667 wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element");
675 static int sae_derive_commit(struct sae_data *sae)
677 struct crypto_bignum *mask;
679 unsigned int counter = 0;
685 * This cannot really happen in practice if the random
686 * number generator is working. Anyway, to avoid even a
687 * theoretical infinite loop, break out after 100
693 mask = sae_get_rand_and_mask(sae);
695 wpa_printf(MSG_DEBUG, "SAE: Could not get rand/mask");
699 /* commit-scalar = (rand + mask) modulo r */
700 if (!sae->tmp->own_commit_scalar) {
701 sae->tmp->own_commit_scalar = crypto_bignum_init();
702 if (!sae->tmp->own_commit_scalar)
705 crypto_bignum_add(sae->tmp->sae_rand, mask,
706 sae->tmp->own_commit_scalar);
707 crypto_bignum_mod(sae->tmp->own_commit_scalar, sae->tmp->order,
708 sae->tmp->own_commit_scalar);
709 } while (crypto_bignum_is_zero(sae->tmp->own_commit_scalar) ||
710 crypto_bignum_is_one(sae->tmp->own_commit_scalar));
712 if ((sae->tmp->ec && sae_derive_commit_element_ecc(sae, mask) < 0) ||
713 (sae->tmp->dh && sae_derive_commit_element_ffc(sae, mask) < 0))
718 crypto_bignum_deinit(mask, 1);
723 int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
724 const u8 *password, size_t password_len,
725 const char *identifier, struct sae_data *sae)
727 if (sae->tmp == NULL ||
728 (sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password,
731 (sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password,
734 sae_derive_commit(sae) < 0)
740 static int sae_derive_k_ecc(struct sae_data *sae, u8 *k)
742 struct crypto_ec_point *K;
745 K = crypto_ec_point_init(sae->tmp->ec);
750 * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE),
751 * PEER-COMMIT-ELEMENT)))
752 * If K is identity element (point-at-infinity), reject
753 * k = F(K) (= x coordinate)
756 if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc,
757 sae->peer_commit_scalar, K) < 0 ||
758 crypto_ec_point_add(sae->tmp->ec, K,
759 sae->tmp->peer_commit_element_ecc, K) < 0 ||
760 crypto_ec_point_mul(sae->tmp->ec, K, sae->tmp->sae_rand, K) < 0 ||
761 crypto_ec_point_is_at_infinity(sae->tmp->ec, K) ||
762 crypto_ec_point_to_bin(sae->tmp->ec, K, k, NULL) < 0) {
763 wpa_printf(MSG_DEBUG, "SAE: Failed to calculate K and k");
767 wpa_hexdump_key(MSG_DEBUG, "SAE: k", k, sae->tmp->prime_len);
771 crypto_ec_point_deinit(K, 1);
776 static int sae_derive_k_ffc(struct sae_data *sae, u8 *k)
778 struct crypto_bignum *K;
781 K = crypto_bignum_init();
786 * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE),
787 * PEER-COMMIT-ELEMENT)))
788 * If K is identity element (one), reject.
789 * k = F(K) (= x coordinate)
792 if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, sae->peer_commit_scalar,
793 sae->tmp->prime, K) < 0 ||
794 crypto_bignum_mulmod(K, sae->tmp->peer_commit_element_ffc,
795 sae->tmp->prime, K) < 0 ||
796 crypto_bignum_exptmod(K, sae->tmp->sae_rand, sae->tmp->prime, K) < 0
798 crypto_bignum_is_one(K) ||
799 crypto_bignum_to_bin(K, k, SAE_MAX_PRIME_LEN, sae->tmp->prime_len) <
801 wpa_printf(MSG_DEBUG, "SAE: Failed to calculate K and k");
805 wpa_hexdump_key(MSG_DEBUG, "SAE: k", k, sae->tmp->prime_len);
809 crypto_bignum_deinit(K, 1);
814 static int sae_derive_keys(struct sae_data *sae, const u8 *k)
816 u8 null_key[SAE_KEYSEED_KEY_LEN], val[SAE_MAX_PRIME_LEN];
817 u8 keyseed[SHA256_MAC_LEN];
818 u8 keys[SAE_KCK_LEN + SAE_PMK_LEN];
819 struct crypto_bignum *tmp;
822 tmp = crypto_bignum_init();
826 /* keyseed = H(<0>32, k)
827 * KCK || PMK = KDF-512(keyseed, "SAE KCK and PMK",
828 * (commit-scalar + peer-commit-scalar) modulo r)
829 * PMKID = L((commit-scalar + peer-commit-scalar) modulo r, 0, 128)
832 os_memset(null_key, 0, sizeof(null_key));
833 hmac_sha256(null_key, sizeof(null_key), k, sae->tmp->prime_len,
835 wpa_hexdump_key(MSG_DEBUG, "SAE: keyseed", keyseed, sizeof(keyseed));
837 crypto_bignum_add(sae->tmp->own_commit_scalar, sae->peer_commit_scalar,
839 crypto_bignum_mod(tmp, sae->tmp->order, tmp);
840 crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->prime_len);
841 wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
842 if (sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
843 val, sae->tmp->prime_len, keys, sizeof(keys)) < 0)
845 os_memset(keyseed, 0, sizeof(keyseed));
846 os_memcpy(sae->tmp->kck, keys, SAE_KCK_LEN);
847 os_memcpy(sae->pmk, keys + SAE_KCK_LEN, SAE_PMK_LEN);
848 os_memcpy(sae->pmkid, val, SAE_PMKID_LEN);
849 os_memset(keys, 0, sizeof(keys));
850 wpa_hexdump_key(MSG_DEBUG, "SAE: KCK", sae->tmp->kck, SAE_KCK_LEN);
851 wpa_hexdump_key(MSG_DEBUG, "SAE: PMK", sae->pmk, SAE_PMK_LEN);
855 crypto_bignum_deinit(tmp, 0);
860 int sae_process_commit(struct sae_data *sae)
862 u8 k[SAE_MAX_PRIME_LEN];
863 if (sae->tmp == NULL ||
864 (sae->tmp->ec && sae_derive_k_ecc(sae, k) < 0) ||
865 (sae->tmp->dh && sae_derive_k_ffc(sae, k) < 0) ||
866 sae_derive_keys(sae, k) < 0)
872 void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
873 const struct wpabuf *token, const char *identifier)
877 if (sae->tmp == NULL)
880 wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */
882 wpabuf_put_buf(buf, token);
883 wpa_hexdump(MSG_DEBUG, "SAE: Anti-clogging token",
884 wpabuf_head(token), wpabuf_len(token));
886 pos = wpabuf_put(buf, sae->tmp->prime_len);
887 crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos,
888 sae->tmp->prime_len, sae->tmp->prime_len);
889 wpa_hexdump(MSG_DEBUG, "SAE: own commit-scalar",
890 pos, sae->tmp->prime_len);
892 pos = wpabuf_put(buf, 2 * sae->tmp->prime_len);
893 crypto_ec_point_to_bin(sae->tmp->ec,
894 sae->tmp->own_commit_element_ecc,
895 pos, pos + sae->tmp->prime_len);
896 wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(x)",
897 pos, sae->tmp->prime_len);
898 wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(y)",
899 pos + sae->tmp->prime_len, sae->tmp->prime_len);
901 pos = wpabuf_put(buf, sae->tmp->prime_len);
902 crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos,
903 sae->tmp->prime_len, sae->tmp->prime_len);
904 wpa_hexdump(MSG_DEBUG, "SAE: own commit-element",
905 pos, sae->tmp->prime_len);
909 /* Password Identifier element */
910 wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
911 wpabuf_put_u8(buf, 1 + os_strlen(identifier));
912 wpabuf_put_u8(buf, WLAN_EID_EXT_PASSWORD_IDENTIFIER);
913 wpabuf_put_str(buf, identifier);
914 wpa_printf(MSG_DEBUG, "SAE: own Password Identifier: %s",
920 u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group)
922 if (allowed_groups) {
924 for (i = 0; allowed_groups[i] > 0; i++) {
925 if (allowed_groups[i] == group)
928 if (allowed_groups[i] != group) {
929 wpa_printf(MSG_DEBUG, "SAE: Proposed group %u not "
930 "enabled in the current configuration",
932 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
936 if (sae->state == SAE_COMMITTED && group != sae->group) {
937 wpa_printf(MSG_DEBUG, "SAE: Do not allow group to be changed");
938 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
941 if (group != sae->group && sae_set_group(sae, group) < 0) {
942 wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u",
944 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
947 if (sae->tmp == NULL) {
948 wpa_printf(MSG_DEBUG, "SAE: Group information not yet initialized");
949 return WLAN_STATUS_UNSPECIFIED_FAILURE;
952 if (sae->tmp->dh && !allowed_groups) {
953 wpa_printf(MSG_DEBUG, "SAE: Do not allow FFC group %u without "
954 "explicit configuration enabling it", group);
955 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
958 return WLAN_STATUS_SUCCESS;
962 static int sae_is_password_id_elem(const u8 *pos, const u8 *end)
964 return end - pos >= 3 &&
965 pos[0] == WLAN_EID_EXTENSION &&
967 end - pos - 2 >= pos[1] &&
968 pos[2] == WLAN_EID_EXT_PASSWORD_IDENTIFIER;
972 static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
973 const u8 *end, const u8 **token,
976 size_t scalar_elem_len, tlen;
984 scalar_elem_len = (sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len;
985 if (scalar_elem_len >= (size_t) (end - *pos))
986 return; /* No extra data beyond peer scalar and element */
988 /* It is a bit difficult to parse this now that there is an
989 * optional variable length Anti-Clogging Token field and
990 * optional variable length Password Identifier element in the
991 * frame. We are sending out fixed length Anti-Clogging Token
992 * fields, so use that length as a requirement for the received
993 * token and check for the presence of possible Password
994 * Identifier element based on the element header information.
996 tlen = end - (*pos + scalar_elem_len);
998 if (tlen < SHA256_MAC_LEN) {
999 wpa_printf(MSG_DEBUG,
1000 "SAE: Too short optional data (%u octets) to include our Anti-Clogging Token",
1001 (unsigned int) tlen);
1005 elem = *pos + scalar_elem_len;
1006 if (sae_is_password_id_elem(elem, end)) {
1007 /* Password Identifier element takes out all available
1008 * extra octets, so there can be no Anti-Clogging token in
1013 elem += SHA256_MAC_LEN;
1014 if (sae_is_password_id_elem(elem, end)) {
1015 /* Password Identifier element is included in the end, so
1016 * remove its length from the Anti-Clogging token field. */
1017 tlen -= 2 + elem[1];
1020 wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen);
1029 static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
1032 struct crypto_bignum *peer_scalar;
1034 if (sae->tmp->prime_len > end - *pos) {
1035 wpa_printf(MSG_DEBUG, "SAE: Not enough data for scalar");
1036 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1039 peer_scalar = crypto_bignum_init_set(*pos, sae->tmp->prime_len);
1040 if (peer_scalar == NULL)
1041 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1044 * IEEE Std 802.11-2012, 11.3.8.6.1: If there is a protocol instance for
1045 * the peer and it is in Authenticated state, the new Commit Message
1046 * shall be dropped if the peer-scalar is identical to the one used in
1047 * the existing protocol instance.
1049 if (sae->state == SAE_ACCEPTED && sae->peer_commit_scalar &&
1050 crypto_bignum_cmp(sae->peer_commit_scalar, peer_scalar) == 0) {
1051 wpa_printf(MSG_DEBUG, "SAE: Do not accept re-use of previous "
1052 "peer-commit-scalar");
1053 crypto_bignum_deinit(peer_scalar, 0);
1054 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1057 /* 1 < scalar < r */
1058 if (crypto_bignum_is_zero(peer_scalar) ||
1059 crypto_bignum_is_one(peer_scalar) ||
1060 crypto_bignum_cmp(peer_scalar, sae->tmp->order) >= 0) {
1061 wpa_printf(MSG_DEBUG, "SAE: Invalid peer scalar");
1062 crypto_bignum_deinit(peer_scalar, 0);
1063 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1067 crypto_bignum_deinit(sae->peer_commit_scalar, 0);
1068 sae->peer_commit_scalar = peer_scalar;
1069 wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-scalar",
1070 *pos, sae->tmp->prime_len);
1071 *pos += sae->tmp->prime_len;
1073 return WLAN_STATUS_SUCCESS;
1077 static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 **pos,
1080 u8 prime[SAE_MAX_ECC_PRIME_LEN];
1082 if (2 * sae->tmp->prime_len > end - *pos) {
1083 wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
1085 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1088 if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
1089 sae->tmp->prime_len) < 0)
1090 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1092 /* element x and y coordinates < p */
1093 if (os_memcmp(*pos, prime, sae->tmp->prime_len) >= 0 ||
1094 os_memcmp(*pos + sae->tmp->prime_len, prime,
1095 sae->tmp->prime_len) >= 0) {
1096 wpa_printf(MSG_DEBUG, "SAE: Invalid coordinates in peer "
1098 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1101 wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(x)",
1102 *pos, sae->tmp->prime_len);
1103 wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(y)",
1104 *pos + sae->tmp->prime_len, sae->tmp->prime_len);
1106 crypto_ec_point_deinit(sae->tmp->peer_commit_element_ecc, 0);
1107 sae->tmp->peer_commit_element_ecc =
1108 crypto_ec_point_from_bin(sae->tmp->ec, *pos);
1109 if (sae->tmp->peer_commit_element_ecc == NULL)
1110 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1112 if (!crypto_ec_point_is_on_curve(sae->tmp->ec,
1113 sae->tmp->peer_commit_element_ecc)) {
1114 wpa_printf(MSG_DEBUG, "SAE: Peer element is not on curve");
1115 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1118 *pos += 2 * sae->tmp->prime_len;
1120 return WLAN_STATUS_SUCCESS;
1124 static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 **pos,
1127 struct crypto_bignum *res, *one;
1128 const u8 one_bin[1] = { 0x01 };
1130 if (sae->tmp->prime_len > end - *pos) {
1131 wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
1133 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1135 wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element", *pos,
1136 sae->tmp->prime_len);
1138 crypto_bignum_deinit(sae->tmp->peer_commit_element_ffc, 0);
1139 sae->tmp->peer_commit_element_ffc =
1140 crypto_bignum_init_set(*pos, sae->tmp->prime_len);
1141 if (sae->tmp->peer_commit_element_ffc == NULL)
1142 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1143 /* 1 < element < p - 1 */
1144 res = crypto_bignum_init();
1145 one = crypto_bignum_init_set(one_bin, sizeof(one_bin));
1147 crypto_bignum_sub(sae->tmp->prime, one, res) ||
1148 crypto_bignum_is_zero(sae->tmp->peer_commit_element_ffc) ||
1149 crypto_bignum_is_one(sae->tmp->peer_commit_element_ffc) ||
1150 crypto_bignum_cmp(sae->tmp->peer_commit_element_ffc, res) >= 0) {
1151 crypto_bignum_deinit(res, 0);
1152 crypto_bignum_deinit(one, 0);
1153 wpa_printf(MSG_DEBUG, "SAE: Invalid peer element");
1154 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1156 crypto_bignum_deinit(one, 0);
1158 /* scalar-op(r, ELEMENT) = 1 modulo p */
1159 if (crypto_bignum_exptmod(sae->tmp->peer_commit_element_ffc,
1160 sae->tmp->order, sae->tmp->prime, res) < 0 ||
1161 !crypto_bignum_is_one(res)) {
1162 wpa_printf(MSG_DEBUG, "SAE: Invalid peer element (scalar-op)");
1163 crypto_bignum_deinit(res, 0);
1164 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1166 crypto_bignum_deinit(res, 0);
1168 *pos += sae->tmp->prime_len;
1170 return WLAN_STATUS_SUCCESS;
1174 static u16 sae_parse_commit_element(struct sae_data *sae, const u8 **pos,
1178 return sae_parse_commit_element_ffc(sae, pos, end);
1179 return sae_parse_commit_element_ecc(sae, pos, end);
1183 static int sae_parse_password_identifier(struct sae_data *sae,
1184 const u8 *pos, const u8 *end)
1186 wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
1188 if (!sae_is_password_id_elem(pos, end)) {
1189 if (sae->tmp->pw_id) {
1190 wpa_printf(MSG_DEBUG,
1191 "SAE: No Password Identifier included, but expected one (%s)",
1193 return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
1195 os_free(sae->tmp->pw_id);
1196 sae->tmp->pw_id = NULL;
1197 return WLAN_STATUS_SUCCESS; /* No Password Identifier */
1200 if (sae->tmp->pw_id &&
1201 (pos[1] - 1 != (int) os_strlen(sae->tmp->pw_id) ||
1202 os_memcmp(sae->tmp->pw_id, pos + 3, pos[1] - 1) != 0)) {
1203 wpa_printf(MSG_DEBUG,
1204 "SAE: The included Password Identifier does not match the expected one (%s)",
1206 return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
1209 os_free(sae->tmp->pw_id);
1210 sae->tmp->pw_id = os_malloc(pos[1]);
1211 if (!sae->tmp->pw_id)
1212 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1213 os_memcpy(sae->tmp->pw_id, pos + 3, pos[1] - 1);
1214 sae->tmp->pw_id[pos[1] - 1] = '\0';
1215 wpa_hexdump_ascii(MSG_DEBUG, "SAE: Received Password Identifier",
1216 sae->tmp->pw_id, pos[1] - 1);
1217 return WLAN_STATUS_SUCCESS;
1221 u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
1222 const u8 **token, size_t *token_len, int *allowed_groups)
1224 const u8 *pos = data, *end = data + len;
1227 /* Check Finite Cyclic Group */
1229 return WLAN_STATUS_UNSPECIFIED_FAILURE;
1230 res = sae_group_allowed(sae, allowed_groups, WPA_GET_LE16(pos));
1231 if (res != WLAN_STATUS_SUCCESS)
1235 /* Optional Anti-Clogging Token */
1236 sae_parse_commit_token(sae, &pos, end, token, token_len);
1239 res = sae_parse_commit_scalar(sae, &pos, end);
1240 if (res != WLAN_STATUS_SUCCESS)
1243 /* commit-element */
1244 res = sae_parse_commit_element(sae, &pos, end);
1245 if (res != WLAN_STATUS_SUCCESS)
1248 /* Optional Password Identifier element */
1249 res = sae_parse_password_identifier(sae, pos, end);
1250 if (res != WLAN_STATUS_SUCCESS)
1254 * Check whether peer-commit-scalar and PEER-COMMIT-ELEMENT are same as
1255 * the values we sent which would be evidence of a reflection attack.
1257 if (!sae->tmp->own_commit_scalar ||
1258 crypto_bignum_cmp(sae->tmp->own_commit_scalar,
1259 sae->peer_commit_scalar) != 0 ||
1261 (!sae->tmp->own_commit_element_ffc ||
1262 crypto_bignum_cmp(sae->tmp->own_commit_element_ffc,
1263 sae->tmp->peer_commit_element_ffc) != 0)) ||
1265 (!sae->tmp->own_commit_element_ecc ||
1266 crypto_ec_point_cmp(sae->tmp->ec,
1267 sae->tmp->own_commit_element_ecc,
1268 sae->tmp->peer_commit_element_ecc) != 0)))
1269 return WLAN_STATUS_SUCCESS; /* scalars/elements are different */
1272 * This is a reflection attack - return special value to trigger caller
1273 * to silently discard the frame instead of replying with a specific
1276 return SAE_SILENTLY_DISCARD;
1280 static void sae_cn_confirm(struct sae_data *sae, const u8 *sc,
1281 const struct crypto_bignum *scalar1,
1282 const u8 *element1, size_t element1_len,
1283 const struct crypto_bignum *scalar2,
1284 const u8 *element2, size_t element2_len,
1289 u8 scalar_b1[SAE_MAX_PRIME_LEN], scalar_b2[SAE_MAX_PRIME_LEN];
1292 * CN(key, X, Y, Z, ...) =
1293 * HMAC-SHA256(key, D2OS(X) || D2OS(Y) || D2OS(Z) | ...)
1294 * confirm = CN(KCK, send-confirm, commit-scalar, COMMIT-ELEMENT,
1295 * peer-commit-scalar, PEER-COMMIT-ELEMENT)
1296 * verifier = CN(KCK, peer-send-confirm, peer-commit-scalar,
1297 * PEER-COMMIT-ELEMENT, commit-scalar, COMMIT-ELEMENT)
1301 crypto_bignum_to_bin(scalar1, scalar_b1, sizeof(scalar_b1),
1302 sae->tmp->prime_len);
1303 addr[1] = scalar_b1;
1304 len[1] = sae->tmp->prime_len;
1306 len[2] = element1_len;
1307 crypto_bignum_to_bin(scalar2, scalar_b2, sizeof(scalar_b2),
1308 sae->tmp->prime_len);
1309 addr[3] = scalar_b2;
1310 len[3] = sae->tmp->prime_len;
1312 len[4] = element2_len;
1313 hmac_sha256_vector(sae->tmp->kck, sizeof(sae->tmp->kck), 5, addr, len,
1318 static void sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc,
1319 const struct crypto_bignum *scalar1,
1320 const struct crypto_ec_point *element1,
1321 const struct crypto_bignum *scalar2,
1322 const struct crypto_ec_point *element2,
1325 u8 element_b1[2 * SAE_MAX_ECC_PRIME_LEN];
1326 u8 element_b2[2 * SAE_MAX_ECC_PRIME_LEN];
1328 crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1,
1329 element_b1 + sae->tmp->prime_len);
1330 crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2,
1331 element_b2 + sae->tmp->prime_len);
1333 sae_cn_confirm(sae, sc, scalar1, element_b1, 2 * sae->tmp->prime_len,
1334 scalar2, element_b2, 2 * sae->tmp->prime_len, confirm);
1338 static void sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc,
1339 const struct crypto_bignum *scalar1,
1340 const struct crypto_bignum *element1,
1341 const struct crypto_bignum *scalar2,
1342 const struct crypto_bignum *element2,
1345 u8 element_b1[SAE_MAX_PRIME_LEN];
1346 u8 element_b2[SAE_MAX_PRIME_LEN];
1348 crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1),
1349 sae->tmp->prime_len);
1350 crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2),
1351 sae->tmp->prime_len);
1353 sae_cn_confirm(sae, sc, scalar1, element_b1, sae->tmp->prime_len,
1354 scalar2, element_b2, sae->tmp->prime_len, confirm);
1358 void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
1362 if (sae->tmp == NULL)
1366 sc = wpabuf_put(buf, 0);
1367 wpabuf_put_le16(buf, sae->send_confirm);
1368 if (sae->send_confirm < 0xffff)
1369 sae->send_confirm++;
1372 sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar,
1373 sae->tmp->own_commit_element_ecc,
1374 sae->peer_commit_scalar,
1375 sae->tmp->peer_commit_element_ecc,
1376 wpabuf_put(buf, SHA256_MAC_LEN));
1378 sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar,
1379 sae->tmp->own_commit_element_ffc,
1380 sae->peer_commit_scalar,
1381 sae->tmp->peer_commit_element_ffc,
1382 wpabuf_put(buf, SHA256_MAC_LEN));
1386 int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len)
1388 u8 verifier[SHA256_MAC_LEN];
1390 if (len < 2 + SHA256_MAC_LEN) {
1391 wpa_printf(MSG_DEBUG, "SAE: Too short confirm message");
1395 wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data));
1397 if (sae->tmp == NULL) {
1398 wpa_printf(MSG_DEBUG, "SAE: Temporary data not yet available");
1403 sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar,
1404 sae->tmp->peer_commit_element_ecc,
1405 sae->tmp->own_commit_scalar,
1406 sae->tmp->own_commit_element_ecc,
1409 sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar,
1410 sae->tmp->peer_commit_element_ffc,
1411 sae->tmp->own_commit_scalar,
1412 sae->tmp->own_commit_element_ffc,
1415 if (os_memcmp_const(verifier, data + 2, SHA256_MAC_LEN) != 0) {
1416 wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch");
1417 wpa_hexdump(MSG_DEBUG, "SAE: Received confirm",
1418 data + 2, SHA256_MAC_LEN);
1419 wpa_hexdump(MSG_DEBUG, "SAE: Calculated verifier",
1420 verifier, SHA256_MAC_LEN);
1428 const char * sae_state_txt(enum sae_state state)