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 "utils/const_time.h"
13 #include "crypto/crypto.h"
14 #include "crypto/sha256.h"
15 #include "crypto/random.h"
16 #include "crypto/dh_groups.h"
17 #include "ieee802_11_defs.h"
18 #include "dragonfly.h"
22 int sae_set_group(struct sae_data
*sae
, int group
)
24 struct sae_temporary_data
*tmp
;
26 #ifdef CONFIG_TESTING_OPTIONS
27 /* Allow all groups for testing purposes in non-production builds. */
28 #else /* CONFIG_TESTING_OPTIONS */
29 if (!dragonfly_suitable_group(group
, 0)) {
30 wpa_printf(MSG_DEBUG
, "SAE: Reject unsuitable group %d", group
);
33 #endif /* CONFIG_TESTING_OPTIONS */
36 tmp
= sae
->tmp
= os_zalloc(sizeof(*tmp
));
40 /* First, check if this is an ECC group */
41 tmp
->ec
= crypto_ec_init(group
);
43 wpa_printf(MSG_DEBUG
, "SAE: Selecting supported ECC group %d",
46 tmp
->prime_len
= crypto_ec_prime_len(tmp
->ec
);
47 tmp
->prime
= crypto_ec_get_prime(tmp
->ec
);
48 tmp
->order
= crypto_ec_get_order(tmp
->ec
);
52 /* Not an ECC group, check FFC */
53 tmp
->dh
= dh_groups_get(group
);
55 wpa_printf(MSG_DEBUG
, "SAE: Selecting supported FFC group %d",
58 tmp
->prime_len
= tmp
->dh
->prime_len
;
59 if (tmp
->prime_len
> SAE_MAX_PRIME_LEN
) {
64 tmp
->prime_buf
= crypto_bignum_init_set(tmp
->dh
->prime
,
66 if (tmp
->prime_buf
== NULL
) {
70 tmp
->prime
= tmp
->prime_buf
;
72 tmp
->order_buf
= crypto_bignum_init_set(tmp
->dh
->order
,
74 if (tmp
->order_buf
== NULL
) {
78 tmp
->order
= tmp
->order_buf
;
83 /* Unsupported group */
85 "SAE: Group %d not supported by the crypto library", group
);
90 void sae_clear_temp_data(struct sae_data
*sae
)
92 struct sae_temporary_data
*tmp
;
93 if (sae
== NULL
|| sae
->tmp
== NULL
)
96 crypto_ec_deinit(tmp
->ec
);
97 crypto_bignum_deinit(tmp
->prime_buf
, 0);
98 crypto_bignum_deinit(tmp
->order_buf
, 0);
99 crypto_bignum_deinit(tmp
->sae_rand
, 1);
100 crypto_bignum_deinit(tmp
->pwe_ffc
, 1);
101 crypto_bignum_deinit(tmp
->own_commit_scalar
, 0);
102 crypto_bignum_deinit(tmp
->own_commit_element_ffc
, 0);
103 crypto_bignum_deinit(tmp
->peer_commit_element_ffc
, 0);
104 crypto_ec_point_deinit(tmp
->pwe_ecc
, 1);
105 crypto_ec_point_deinit(tmp
->own_commit_element_ecc
, 0);
106 crypto_ec_point_deinit(tmp
->peer_commit_element_ecc
, 0);
107 wpabuf_free(tmp
->anti_clogging_token
);
109 bin_clear_free(tmp
, sizeof(*tmp
));
114 void sae_clear_data(struct sae_data
*sae
)
118 sae_clear_temp_data(sae
);
119 crypto_bignum_deinit(sae
->peer_commit_scalar
, 0);
120 os_memset(sae
, 0, sizeof(*sae
));
124 static void sae_pwd_seed_key(const u8
*addr1
, const u8
*addr2
, u8
*key
)
126 wpa_printf(MSG_DEBUG
, "SAE: PWE derivation - addr1=" MACSTR
127 " addr2=" MACSTR
, MAC2STR(addr1
), MAC2STR(addr2
));
128 if (os_memcmp(addr1
, addr2
, ETH_ALEN
) > 0) {
129 os_memcpy(key
, addr1
, ETH_ALEN
);
130 os_memcpy(key
+ ETH_ALEN
, addr2
, ETH_ALEN
);
132 os_memcpy(key
, addr2
, ETH_ALEN
);
133 os_memcpy(key
+ ETH_ALEN
, addr1
, ETH_ALEN
);
138 static int sae_test_pwd_seed_ecc(struct sae_data
*sae
, const u8
*pwd_seed
,
139 const u8
*prime
, const u8
*qr
, const u8
*qnr
,
142 struct crypto_bignum
*y_sqr
, *x_cand
;
146 unsigned int in_range
;
148 wpa_hexdump_key(MSG_DEBUG
, "SAE: pwd-seed", pwd_seed
, SHA256_MAC_LEN
);
150 /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
151 bits
= crypto_ec_prime_len_bits(sae
->tmp
->ec
);
152 if (sha256_prf_bits(pwd_seed
, SHA256_MAC_LEN
, "SAE Hunting and Pecking",
153 prime
, sae
->tmp
->prime_len
, pwd_value
, bits
) < 0)
156 buf_shift_right(pwd_value
, sae
->tmp
->prime_len
, 8 - bits
% 8);
157 wpa_hexdump_key(MSG_DEBUG
, "SAE: pwd-value",
158 pwd_value
, sae
->tmp
->prime_len
);
160 cmp_prime
= const_time_memcmp(pwd_value
, prime
, sae
->tmp
->prime_len
);
161 /* Create a const_time mask for selection based on prf result
162 * being smaller than prime. */
163 in_range
= const_time_fill_msb((unsigned int) cmp_prime
);
164 /* The algorithm description would skip the next steps if
165 * cmp_prime >= 0 (reutnr 0 here), but go through them regardless to
166 * minimize externally observable differences in behavior. */
168 x_cand
= crypto_bignum_init_set(pwd_value
, sae
->tmp
->prime_len
);
171 y_sqr
= crypto_ec_point_compute_y_sqr(sae
->tmp
->ec
, x_cand
);
172 crypto_bignum_deinit(x_cand
, 1);
176 res
= dragonfly_is_quadratic_residue_blind(sae
->tmp
->ec
, qr
, qnr
,
178 crypto_bignum_deinit(y_sqr
, 1);
181 return const_time_select_int(in_range
, res
, 0);
185 /* Returns -1 on fatal failure, 0 if PWE cannot be derived from the provided
186 * pwd-seed, or 1 if a valid PWE was derived from pwd-seed. */
187 static int sae_test_pwd_seed_ffc(struct sae_data
*sae
, const u8
*pwd_seed
,
188 struct crypto_bignum
*pwe
)
190 u8 pwd_value
[SAE_MAX_PRIME_LEN
];
191 size_t bits
= sae
->tmp
->prime_len
* 8;
193 struct crypto_bignum
*a
, *b
= NULL
;
197 wpa_hexdump_key(MSG_DEBUG
, "SAE: pwd-seed", pwd_seed
, SHA256_MAC_LEN
);
199 /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
200 if (sha256_prf_bits(pwd_seed
, SHA256_MAC_LEN
, "SAE Hunting and Pecking",
201 sae
->tmp
->dh
->prime
, sae
->tmp
->prime_len
, pwd_value
,
204 wpa_hexdump_key(MSG_DEBUG
, "SAE: pwd-value", pwd_value
,
205 sae
->tmp
->prime_len
);
207 /* Check whether pwd-value < p */
208 res
= const_time_memcmp(pwd_value
, sae
->tmp
->dh
->prime
,
209 sae
->tmp
->prime_len
);
210 /* pwd-value >= p is invalid, so res is < 0 for the valid cases and
211 * the negative sign can be used to fill the mask for constant time
213 pwd_value_valid
= const_time_fill_msb(res
);
215 /* If pwd-value >= p, force pwd-value to be < p and perform the
216 * calculations anyway to hide timing difference. The derived PWE will
217 * be ignored in that case. */
218 pwd_value
[0] = const_time_select_u8(pwd_value_valid
, pwd_value
[0], 0);
220 /* PWE = pwd-value^((p-1)/r) modulo p */
223 a
= crypto_bignum_init_set(pwd_value
, sae
->tmp
->prime_len
);
227 /* This is an optimization based on the used group that does not depend
228 * on the password in any way, so it is fine to use separate branches
229 * for this step without constant time operations. */
230 if (sae
->tmp
->dh
->safe_prime
) {
232 * r = (p-1)/2 for the group used here, so this becomes:
233 * PWE = pwd-value^2 modulo p
236 b
= crypto_bignum_init_set(exp
, sizeof(exp
));
238 /* Calculate exponent: (p-1)/r */
240 b
= crypto_bignum_init_set(exp
, sizeof(exp
));
242 crypto_bignum_sub(sae
->tmp
->prime
, b
, b
) < 0 ||
243 crypto_bignum_div(b
, sae
->tmp
->order
, b
) < 0)
250 res
= crypto_bignum_exptmod(a
, b
, sae
->tmp
->prime
, pwe
);
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.
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);
268 crypto_bignum_deinit(a
, 1);
269 crypto_bignum_deinit(b
, 1);
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
, const char *identifier
)
279 u8 addrs
[2 * ETH_ALEN
];
283 u8
*dummy_password
, *tmp_password
;
284 int pwd_seed_odd
= 0;
285 u8 prime
[SAE_MAX_ECC_PRIME_LEN
];
287 struct crypto_bignum
*x
= NULL
, *qr
= NULL
, *qnr
= NULL
;
288 u8 x_bin
[SAE_MAX_ECC_PRIME_LEN
];
289 u8 x_cand_bin
[SAE_MAX_ECC_PRIME_LEN
];
290 u8 qr_bin
[SAE_MAX_ECC_PRIME_LEN
];
291 u8 qnr_bin
[SAE_MAX_ECC_PRIME_LEN
];
293 u8 found
= 0; /* 0 (false) or 0xff (true) to be used as const_time_*
296 os_memset(x_bin
, 0, sizeof(x_bin
));
298 dummy_password
= os_malloc(password_len
);
299 tmp_password
= os_malloc(password_len
);
300 if (!dummy_password
|| !tmp_password
||
301 random_get_bytes(dummy_password
, password_len
) < 0)
304 prime_len
= sae
->tmp
->prime_len
;
305 if (crypto_bignum_to_bin(sae
->tmp
->prime
, prime
, sizeof(prime
),
310 * Create a random quadratic residue (qr) and quadratic non-residue
311 * (qnr) modulo p for blinding purposes during the loop.
313 if (dragonfly_get_random_qr_qnr(sae
->tmp
->prime
, &qr
, &qnr
) < 0 ||
314 crypto_bignum_to_bin(qr
, qr_bin
, sizeof(qr_bin
), prime_len
) < 0 ||
315 crypto_bignum_to_bin(qnr
, qnr_bin
, sizeof(qnr_bin
), prime_len
) < 0)
318 wpa_hexdump_ascii_key(MSG_DEBUG
, "SAE: password",
319 password
, password_len
);
321 wpa_printf(MSG_DEBUG
, "SAE: password identifier: %s",
325 * H(salt, ikm) = HMAC-SHA256(salt, ikm)
326 * base = password [|| identifier]
327 * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
330 sae_pwd_seed_key(addr1
, addr2
, addrs
);
332 addr
[0] = tmp_password
;
333 len
[0] = password_len
;
336 addr
[num_elem
] = (const u8
*) identifier
;
337 len
[num_elem
] = os_strlen(identifier
);
340 addr
[num_elem
] = &counter
;
341 len
[num_elem
] = sizeof(counter
);
345 * Continue for at least k iterations to protect against side-channel
346 * attacks that attempt to determine the number of iterations required
349 k
= dragonfly_min_pwe_loop_iter(sae
->group
);
351 for (counter
= 1; counter
<= k
|| !found
; counter
++) {
352 u8 pwd_seed
[SHA256_MAC_LEN
];
355 /* This should not happen in practice */
356 wpa_printf(MSG_DEBUG
, "SAE: Failed to derive PWE");
360 wpa_printf(MSG_DEBUG
, "SAE: counter = %03u", counter
);
361 const_time_select_bin(found
, dummy_password
, password
,
362 password_len
, tmp_password
);
363 if (hmac_sha256_vector(addrs
, sizeof(addrs
), num_elem
,
364 addr
, len
, pwd_seed
) < 0)
367 res
= sae_test_pwd_seed_ecc(sae
, pwd_seed
,
368 prime
, qr_bin
, qnr_bin
, x_cand_bin
);
369 const_time_select_bin(found
, x_bin
, x_cand_bin
, prime_len
,
371 pwd_seed_odd
= const_time_select_u8(
373 pwd_seed
[SHA256_MAC_LEN
- 1] & 0x01);
374 os_memset(pwd_seed
, 0, sizeof(pwd_seed
));
377 /* Need to minimize differences in handling res == 0 and 1 here
378 * to avoid differences in timing and instruction cache access,
379 * so use const_time_select_*() to make local copies of the
380 * values based on whether this loop iteration was the one that
381 * found the pwd-seed/x. */
383 /* found is 0 or 0xff here and res is 0 or 1. Bitwise OR of them
384 * (with res converted to 0/0xff) handles this in constant time.
387 wpa_printf(MSG_DEBUG
, "SAE: pwd-seed result %d found=0x%02x",
392 wpa_printf(MSG_DEBUG
, "SAE: Could not generate PWE");
397 x
= crypto_bignum_init_set(x_bin
, prime_len
);
403 if (!sae
->tmp
->pwe_ecc
)
404 sae
->tmp
->pwe_ecc
= crypto_ec_point_init(sae
->tmp
->ec
);
405 if (!sae
->tmp
->pwe_ecc
)
408 res
= crypto_ec_point_solve_y_coord(sae
->tmp
->ec
,
409 sae
->tmp
->pwe_ecc
, x
,
413 * This should not happen since we already checked that there
416 wpa_printf(MSG_DEBUG
, "SAE: Could not solve y");
420 crypto_bignum_deinit(qr
, 0);
421 crypto_bignum_deinit(qnr
, 0);
422 os_free(dummy_password
);
423 bin_clear_free(tmp_password
, password_len
);
424 crypto_bignum_deinit(x
, 1);
425 os_memset(x_bin
, 0, sizeof(x_bin
));
426 os_memset(x_cand_bin
, 0, sizeof(x_cand_bin
));
432 static int sae_derive_pwe_ffc(struct sae_data
*sae
, const u8
*addr1
,
433 const u8
*addr2
, const u8
*password
,
434 size_t password_len
, const char *identifier
)
436 u8 counter
, k
, sel_counter
= 0;
437 u8 addrs
[2 * ETH_ALEN
];
441 u8 found
= 0; /* 0 (false) or 0xff (true) to be used as const_time_*
444 struct crypto_bignum
*pwe
;
445 size_t prime_len
= sae
->tmp
->prime_len
* 8;
448 crypto_bignum_deinit(sae
->tmp
->pwe_ffc
, 1);
449 sae
->tmp
->pwe_ffc
= NULL
;
451 /* Allocate a buffer to maintain selected and candidate PWE for constant
453 pwe_buf
= os_zalloc(prime_len
* 2);
454 pwe
= crypto_bignum_init();
455 if (!pwe_buf
|| !pwe
)
458 wpa_hexdump_ascii_key(MSG_DEBUG
, "SAE: password",
459 password
, password_len
);
462 * H(salt, ikm) = HMAC-SHA256(salt, ikm)
463 * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
464 * password [|| identifier] || counter)
466 sae_pwd_seed_key(addr1
, addr2
, addrs
);
469 len
[0] = password_len
;
472 addr
[num_elem
] = (const u8
*) identifier
;
473 len
[num_elem
] = os_strlen(identifier
);
476 addr
[num_elem
] = &counter
;
477 len
[num_elem
] = sizeof(counter
);
480 k
= dragonfly_min_pwe_loop_iter(sae
->group
);
482 for (counter
= 1; counter
<= k
|| !found
; counter
++) {
483 u8 pwd_seed
[SHA256_MAC_LEN
];
487 /* This should not happen in practice */
488 wpa_printf(MSG_DEBUG
, "SAE: Failed to derive PWE");
492 wpa_printf(MSG_DEBUG
, "SAE: counter = %02u", counter
);
493 if (hmac_sha256_vector(addrs
, sizeof(addrs
), num_elem
,
494 addr
, len
, pwd_seed
) < 0)
496 res
= sae_test_pwd_seed_ffc(sae
, pwd_seed
, pwe
);
497 /* res is -1 for fatal failure, 0 if a valid PWE was not found,
498 * or 1 if a valid PWE was found. */
501 /* Store the candidate PWE into the second half of pwe_buf and
502 * the selected PWE in the beginning of pwe_buf using constant
504 if (crypto_bignum_to_bin(pwe
, pwe_buf
+ prime_len
, prime_len
,
507 const_time_select_bin(found
, pwe_buf
, pwe_buf
+ prime_len
,
509 sel_counter
= const_time_select_u8(found
, sel_counter
, counter
);
510 mask
= const_time_eq_u8(res
, 1);
511 found
= const_time_select_u8(found
, found
, mask
);
517 wpa_printf(MSG_DEBUG
, "SAE: Use PWE from counter = %02u", sel_counter
);
518 sae
->tmp
->pwe_ffc
= crypto_bignum_init_set(pwe_buf
, prime_len
);
520 crypto_bignum_deinit(pwe
, 1);
521 bin_clear_free(pwe_buf
, prime_len
* 2);
522 return sae
->tmp
->pwe_ffc
? 0 : -1;
526 static int sae_derive_commit_element_ecc(struct sae_data
*sae
,
527 struct crypto_bignum
*mask
)
529 /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */
530 if (!sae
->tmp
->own_commit_element_ecc
) {
531 sae
->tmp
->own_commit_element_ecc
=
532 crypto_ec_point_init(sae
->tmp
->ec
);
533 if (!sae
->tmp
->own_commit_element_ecc
)
537 if (crypto_ec_point_mul(sae
->tmp
->ec
, sae
->tmp
->pwe_ecc
, mask
,
538 sae
->tmp
->own_commit_element_ecc
) < 0 ||
539 crypto_ec_point_invert(sae
->tmp
->ec
,
540 sae
->tmp
->own_commit_element_ecc
) < 0) {
541 wpa_printf(MSG_DEBUG
, "SAE: Could not compute commit-element");
549 static int sae_derive_commit_element_ffc(struct sae_data
*sae
,
550 struct crypto_bignum
*mask
)
552 /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */
553 if (!sae
->tmp
->own_commit_element_ffc
) {
554 sae
->tmp
->own_commit_element_ffc
= crypto_bignum_init();
555 if (!sae
->tmp
->own_commit_element_ffc
)
559 if (crypto_bignum_exptmod(sae
->tmp
->pwe_ffc
, mask
, sae
->tmp
->prime
,
560 sae
->tmp
->own_commit_element_ffc
) < 0 ||
561 crypto_bignum_inverse(sae
->tmp
->own_commit_element_ffc
,
563 sae
->tmp
->own_commit_element_ffc
) < 0) {
564 wpa_printf(MSG_DEBUG
, "SAE: Could not compute commit-element");
572 static int sae_derive_commit(struct sae_data
*sae
)
574 struct crypto_bignum
*mask
;
577 mask
= crypto_bignum_init();
578 if (!sae
->tmp
->sae_rand
)
579 sae
->tmp
->sae_rand
= crypto_bignum_init();
580 if (!sae
->tmp
->own_commit_scalar
)
581 sae
->tmp
->own_commit_scalar
= crypto_bignum_init();
582 ret
= !mask
|| !sae
->tmp
->sae_rand
|| !sae
->tmp
->own_commit_scalar
||
583 dragonfly_generate_scalar(sae
->tmp
->order
, sae
->tmp
->sae_rand
,
585 sae
->tmp
->own_commit_scalar
) < 0 ||
587 sae_derive_commit_element_ecc(sae
, mask
) < 0) ||
589 sae_derive_commit_element_ffc(sae
, mask
) < 0);
590 crypto_bignum_deinit(mask
, 1);
595 int sae_prepare_commit(const u8
*addr1
, const u8
*addr2
,
596 const u8
*password
, size_t password_len
,
597 const char *identifier
, struct sae_data
*sae
)
599 if (sae
->tmp
== NULL
||
600 (sae
->tmp
->ec
&& sae_derive_pwe_ecc(sae
, addr1
, addr2
, password
,
603 (sae
->tmp
->dh
&& sae_derive_pwe_ffc(sae
, addr1
, addr2
, password
,
606 sae_derive_commit(sae
) < 0)
612 static int sae_derive_k_ecc(struct sae_data
*sae
, u8
*k
)
614 struct crypto_ec_point
*K
;
617 K
= crypto_ec_point_init(sae
->tmp
->ec
);
622 * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE),
623 * PEER-COMMIT-ELEMENT)))
624 * If K is identity element (point-at-infinity), reject
625 * k = F(K) (= x coordinate)
628 if (crypto_ec_point_mul(sae
->tmp
->ec
, sae
->tmp
->pwe_ecc
,
629 sae
->peer_commit_scalar
, K
) < 0 ||
630 crypto_ec_point_add(sae
->tmp
->ec
, K
,
631 sae
->tmp
->peer_commit_element_ecc
, K
) < 0 ||
632 crypto_ec_point_mul(sae
->tmp
->ec
, K
, sae
->tmp
->sae_rand
, K
) < 0 ||
633 crypto_ec_point_is_at_infinity(sae
->tmp
->ec
, K
) ||
634 crypto_ec_point_to_bin(sae
->tmp
->ec
, K
, k
, NULL
) < 0) {
635 wpa_printf(MSG_DEBUG
, "SAE: Failed to calculate K and k");
639 wpa_hexdump_key(MSG_DEBUG
, "SAE: k", k
, sae
->tmp
->prime_len
);
643 crypto_ec_point_deinit(K
, 1);
648 static int sae_derive_k_ffc(struct sae_data
*sae
, u8
*k
)
650 struct crypto_bignum
*K
;
653 K
= crypto_bignum_init();
658 * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE),
659 * PEER-COMMIT-ELEMENT)))
660 * If K is identity element (one), reject.
661 * k = F(K) (= x coordinate)
664 if (crypto_bignum_exptmod(sae
->tmp
->pwe_ffc
, sae
->peer_commit_scalar
,
665 sae
->tmp
->prime
, K
) < 0 ||
666 crypto_bignum_mulmod(K
, sae
->tmp
->peer_commit_element_ffc
,
667 sae
->tmp
->prime
, K
) < 0 ||
668 crypto_bignum_exptmod(K
, sae
->tmp
->sae_rand
, sae
->tmp
->prime
, K
) < 0
670 crypto_bignum_is_one(K
) ||
671 crypto_bignum_to_bin(K
, k
, SAE_MAX_PRIME_LEN
, sae
->tmp
->prime_len
) <
673 wpa_printf(MSG_DEBUG
, "SAE: Failed to calculate K and k");
677 wpa_hexdump_key(MSG_DEBUG
, "SAE: k", k
, sae
->tmp
->prime_len
);
681 crypto_bignum_deinit(K
, 1);
686 static int sae_derive_keys(struct sae_data
*sae
, const u8
*k
)
688 u8 null_key
[SAE_KEYSEED_KEY_LEN
], val
[SAE_MAX_PRIME_LEN
];
689 u8 keyseed
[SHA256_MAC_LEN
];
690 u8 keys
[SAE_KCK_LEN
+ SAE_PMK_LEN
];
691 struct crypto_bignum
*tmp
;
694 tmp
= crypto_bignum_init();
698 /* keyseed = H(<0>32, k)
699 * KCK || PMK = KDF-512(keyseed, "SAE KCK and PMK",
700 * (commit-scalar + peer-commit-scalar) modulo r)
701 * PMKID = L((commit-scalar + peer-commit-scalar) modulo r, 0, 128)
704 os_memset(null_key
, 0, sizeof(null_key
));
705 hmac_sha256(null_key
, sizeof(null_key
), k
, sae
->tmp
->prime_len
,
707 wpa_hexdump_key(MSG_DEBUG
, "SAE: keyseed", keyseed
, sizeof(keyseed
));
709 crypto_bignum_add(sae
->tmp
->own_commit_scalar
, sae
->peer_commit_scalar
,
711 crypto_bignum_mod(tmp
, sae
->tmp
->order
, tmp
);
712 crypto_bignum_to_bin(tmp
, val
, sizeof(val
), sae
->tmp
->prime_len
);
713 wpa_hexdump(MSG_DEBUG
, "SAE: PMKID", val
, SAE_PMKID_LEN
);
714 if (sha256_prf(keyseed
, sizeof(keyseed
), "SAE KCK and PMK",
715 val
, sae
->tmp
->prime_len
, keys
, sizeof(keys
)) < 0)
717 os_memset(keyseed
, 0, sizeof(keyseed
));
718 os_memcpy(sae
->tmp
->kck
, keys
, SAE_KCK_LEN
);
719 os_memcpy(sae
->pmk
, keys
+ SAE_KCK_LEN
, SAE_PMK_LEN
);
720 os_memcpy(sae
->pmkid
, val
, SAE_PMKID_LEN
);
721 os_memset(keys
, 0, sizeof(keys
));
722 wpa_hexdump_key(MSG_DEBUG
, "SAE: KCK", sae
->tmp
->kck
, SAE_KCK_LEN
);
723 wpa_hexdump_key(MSG_DEBUG
, "SAE: PMK", sae
->pmk
, SAE_PMK_LEN
);
727 crypto_bignum_deinit(tmp
, 0);
732 int sae_process_commit(struct sae_data
*sae
)
734 u8 k
[SAE_MAX_PRIME_LEN
];
735 if (sae
->tmp
== NULL
||
736 (sae
->tmp
->ec
&& sae_derive_k_ecc(sae
, k
) < 0) ||
737 (sae
->tmp
->dh
&& sae_derive_k_ffc(sae
, k
) < 0) ||
738 sae_derive_keys(sae
, k
) < 0)
744 void sae_write_commit(struct sae_data
*sae
, struct wpabuf
*buf
,
745 const struct wpabuf
*token
, const char *identifier
)
749 if (sae
->tmp
== NULL
)
752 wpabuf_put_le16(buf
, sae
->group
); /* Finite Cyclic Group */
754 wpabuf_put_buf(buf
, token
);
755 wpa_hexdump(MSG_DEBUG
, "SAE: Anti-clogging token",
756 wpabuf_head(token
), wpabuf_len(token
));
758 pos
= wpabuf_put(buf
, sae
->tmp
->prime_len
);
759 crypto_bignum_to_bin(sae
->tmp
->own_commit_scalar
, pos
,
760 sae
->tmp
->prime_len
, sae
->tmp
->prime_len
);
761 wpa_hexdump(MSG_DEBUG
, "SAE: own commit-scalar",
762 pos
, sae
->tmp
->prime_len
);
764 pos
= wpabuf_put(buf
, 2 * sae
->tmp
->prime_len
);
765 crypto_ec_point_to_bin(sae
->tmp
->ec
,
766 sae
->tmp
->own_commit_element_ecc
,
767 pos
, pos
+ sae
->tmp
->prime_len
);
768 wpa_hexdump(MSG_DEBUG
, "SAE: own commit-element(x)",
769 pos
, sae
->tmp
->prime_len
);
770 wpa_hexdump(MSG_DEBUG
, "SAE: own commit-element(y)",
771 pos
+ sae
->tmp
->prime_len
, sae
->tmp
->prime_len
);
773 pos
= wpabuf_put(buf
, sae
->tmp
->prime_len
);
774 crypto_bignum_to_bin(sae
->tmp
->own_commit_element_ffc
, pos
,
775 sae
->tmp
->prime_len
, sae
->tmp
->prime_len
);
776 wpa_hexdump(MSG_DEBUG
, "SAE: own commit-element",
777 pos
, sae
->tmp
->prime_len
);
781 /* Password Identifier element */
782 wpabuf_put_u8(buf
, WLAN_EID_EXTENSION
);
783 wpabuf_put_u8(buf
, 1 + os_strlen(identifier
));
784 wpabuf_put_u8(buf
, WLAN_EID_EXT_PASSWORD_IDENTIFIER
);
785 wpabuf_put_str(buf
, identifier
);
786 wpa_printf(MSG_DEBUG
, "SAE: own Password Identifier: %s",
792 u16
sae_group_allowed(struct sae_data
*sae
, int *allowed_groups
, u16 group
)
794 if (allowed_groups
) {
796 for (i
= 0; allowed_groups
[i
] > 0; i
++) {
797 if (allowed_groups
[i
] == group
)
800 if (allowed_groups
[i
] != group
) {
801 wpa_printf(MSG_DEBUG
, "SAE: Proposed group %u not "
802 "enabled in the current configuration",
804 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED
;
808 if (sae
->state
== SAE_COMMITTED
&& group
!= sae
->group
) {
809 wpa_printf(MSG_DEBUG
, "SAE: Do not allow group to be changed");
810 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED
;
813 if (group
!= sae
->group
&& sae_set_group(sae
, group
) < 0) {
814 wpa_printf(MSG_DEBUG
, "SAE: Unsupported Finite Cyclic Group %u",
816 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED
;
819 if (sae
->tmp
== NULL
) {
820 wpa_printf(MSG_DEBUG
, "SAE: Group information not yet initialized");
821 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
824 if (sae
->tmp
->dh
&& !allowed_groups
) {
825 wpa_printf(MSG_DEBUG
, "SAE: Do not allow FFC group %u without "
826 "explicit configuration enabling it", group
);
827 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED
;
830 return WLAN_STATUS_SUCCESS
;
834 static int sae_is_password_id_elem(const u8
*pos
, const u8
*end
)
836 return end
- pos
>= 3 &&
837 pos
[0] == WLAN_EID_EXTENSION
&&
839 end
- pos
- 2 >= pos
[1] &&
840 pos
[2] == WLAN_EID_EXT_PASSWORD_IDENTIFIER
;
844 static void sae_parse_commit_token(struct sae_data
*sae
, const u8
**pos
,
845 const u8
*end
, const u8
**token
,
848 size_t scalar_elem_len
, tlen
;
856 scalar_elem_len
= (sae
->tmp
->ec
? 3 : 2) * sae
->tmp
->prime_len
;
857 if (scalar_elem_len
>= (size_t) (end
- *pos
))
858 return; /* No extra data beyond peer scalar and element */
860 /* It is a bit difficult to parse this now that there is an
861 * optional variable length Anti-Clogging Token field and
862 * optional variable length Password Identifier element in the
863 * frame. We are sending out fixed length Anti-Clogging Token
864 * fields, so use that length as a requirement for the received
865 * token and check for the presence of possible Password
866 * Identifier element based on the element header information.
868 tlen
= end
- (*pos
+ scalar_elem_len
);
870 if (tlen
< SHA256_MAC_LEN
) {
871 wpa_printf(MSG_DEBUG
,
872 "SAE: Too short optional data (%u octets) to include our Anti-Clogging Token",
873 (unsigned int) tlen
);
877 elem
= *pos
+ scalar_elem_len
;
878 if (sae_is_password_id_elem(elem
, end
)) {
879 /* Password Identifier element takes out all available
880 * extra octets, so there can be no Anti-Clogging token in
885 elem
+= SHA256_MAC_LEN
;
886 if (sae_is_password_id_elem(elem
, end
)) {
887 /* Password Identifier element is included in the end, so
888 * remove its length from the Anti-Clogging token field. */
892 wpa_hexdump(MSG_DEBUG
, "SAE: Anti-Clogging Token", *pos
, tlen
);
901 static u16
sae_parse_commit_scalar(struct sae_data
*sae
, const u8
**pos
,
904 struct crypto_bignum
*peer_scalar
;
906 if (sae
->tmp
->prime_len
> end
- *pos
) {
907 wpa_printf(MSG_DEBUG
, "SAE: Not enough data for scalar");
908 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
911 peer_scalar
= crypto_bignum_init_set(*pos
, sae
->tmp
->prime_len
);
912 if (peer_scalar
== NULL
)
913 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
916 * IEEE Std 802.11-2012, 11.3.8.6.1: If there is a protocol instance for
917 * the peer and it is in Authenticated state, the new Commit Message
918 * shall be dropped if the peer-scalar is identical to the one used in
919 * the existing protocol instance.
921 if (sae
->state
== SAE_ACCEPTED
&& sae
->peer_commit_scalar
&&
922 crypto_bignum_cmp(sae
->peer_commit_scalar
, peer_scalar
) == 0) {
923 wpa_printf(MSG_DEBUG
, "SAE: Do not accept re-use of previous "
924 "peer-commit-scalar");
925 crypto_bignum_deinit(peer_scalar
, 0);
926 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
930 if (crypto_bignum_is_zero(peer_scalar
) ||
931 crypto_bignum_is_one(peer_scalar
) ||
932 crypto_bignum_cmp(peer_scalar
, sae
->tmp
->order
) >= 0) {
933 wpa_printf(MSG_DEBUG
, "SAE: Invalid peer scalar");
934 crypto_bignum_deinit(peer_scalar
, 0);
935 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
939 crypto_bignum_deinit(sae
->peer_commit_scalar
, 0);
940 sae
->peer_commit_scalar
= peer_scalar
;
941 wpa_hexdump(MSG_DEBUG
, "SAE: Peer commit-scalar",
942 *pos
, sae
->tmp
->prime_len
);
943 *pos
+= sae
->tmp
->prime_len
;
945 return WLAN_STATUS_SUCCESS
;
949 static u16
sae_parse_commit_element_ecc(struct sae_data
*sae
, const u8
**pos
,
952 u8 prime
[SAE_MAX_ECC_PRIME_LEN
];
954 if (2 * sae
->tmp
->prime_len
> end
- *pos
) {
955 wpa_printf(MSG_DEBUG
, "SAE: Not enough data for "
957 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
960 if (crypto_bignum_to_bin(sae
->tmp
->prime
, prime
, sizeof(prime
),
961 sae
->tmp
->prime_len
) < 0)
962 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
964 /* element x and y coordinates < p */
965 if (os_memcmp(*pos
, prime
, sae
->tmp
->prime_len
) >= 0 ||
966 os_memcmp(*pos
+ sae
->tmp
->prime_len
, prime
,
967 sae
->tmp
->prime_len
) >= 0) {
968 wpa_printf(MSG_DEBUG
, "SAE: Invalid coordinates in peer "
970 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
973 wpa_hexdump(MSG_DEBUG
, "SAE: Peer commit-element(x)",
974 *pos
, sae
->tmp
->prime_len
);
975 wpa_hexdump(MSG_DEBUG
, "SAE: Peer commit-element(y)",
976 *pos
+ sae
->tmp
->prime_len
, sae
->tmp
->prime_len
);
978 crypto_ec_point_deinit(sae
->tmp
->peer_commit_element_ecc
, 0);
979 sae
->tmp
->peer_commit_element_ecc
=
980 crypto_ec_point_from_bin(sae
->tmp
->ec
, *pos
);
981 if (sae
->tmp
->peer_commit_element_ecc
== NULL
)
982 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
984 if (!crypto_ec_point_is_on_curve(sae
->tmp
->ec
,
985 sae
->tmp
->peer_commit_element_ecc
)) {
986 wpa_printf(MSG_DEBUG
, "SAE: Peer element is not on curve");
987 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
990 *pos
+= 2 * sae
->tmp
->prime_len
;
992 return WLAN_STATUS_SUCCESS
;
996 static u16
sae_parse_commit_element_ffc(struct sae_data
*sae
, const u8
**pos
,
999 struct crypto_bignum
*res
, *one
;
1000 const u8 one_bin
[1] = { 0x01 };
1002 if (sae
->tmp
->prime_len
> end
- *pos
) {
1003 wpa_printf(MSG_DEBUG
, "SAE: Not enough data for "
1005 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1007 wpa_hexdump(MSG_DEBUG
, "SAE: Peer commit-element", *pos
,
1008 sae
->tmp
->prime_len
);
1010 crypto_bignum_deinit(sae
->tmp
->peer_commit_element_ffc
, 0);
1011 sae
->tmp
->peer_commit_element_ffc
=
1012 crypto_bignum_init_set(*pos
, sae
->tmp
->prime_len
);
1013 if (sae
->tmp
->peer_commit_element_ffc
== NULL
)
1014 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1015 /* 1 < element < p - 1 */
1016 res
= crypto_bignum_init();
1017 one
= crypto_bignum_init_set(one_bin
, sizeof(one_bin
));
1019 crypto_bignum_sub(sae
->tmp
->prime
, one
, res
) ||
1020 crypto_bignum_is_zero(sae
->tmp
->peer_commit_element_ffc
) ||
1021 crypto_bignum_is_one(sae
->tmp
->peer_commit_element_ffc
) ||
1022 crypto_bignum_cmp(sae
->tmp
->peer_commit_element_ffc
, res
) >= 0) {
1023 crypto_bignum_deinit(res
, 0);
1024 crypto_bignum_deinit(one
, 0);
1025 wpa_printf(MSG_DEBUG
, "SAE: Invalid peer element");
1026 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1028 crypto_bignum_deinit(one
, 0);
1030 /* scalar-op(r, ELEMENT) = 1 modulo p */
1031 if (crypto_bignum_exptmod(sae
->tmp
->peer_commit_element_ffc
,
1032 sae
->tmp
->order
, sae
->tmp
->prime
, res
) < 0 ||
1033 !crypto_bignum_is_one(res
)) {
1034 wpa_printf(MSG_DEBUG
, "SAE: Invalid peer element (scalar-op)");
1035 crypto_bignum_deinit(res
, 0);
1036 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1038 crypto_bignum_deinit(res
, 0);
1040 *pos
+= sae
->tmp
->prime_len
;
1042 return WLAN_STATUS_SUCCESS
;
1046 static u16
sae_parse_commit_element(struct sae_data
*sae
, const u8
**pos
,
1050 return sae_parse_commit_element_ffc(sae
, pos
, end
);
1051 return sae_parse_commit_element_ecc(sae
, pos
, end
);
1055 static int sae_parse_password_identifier(struct sae_data
*sae
,
1056 const u8
*pos
, const u8
*end
)
1058 wpa_hexdump(MSG_DEBUG
, "SAE: Possible elements at the end of the frame",
1060 if (!sae_is_password_id_elem(pos
, end
)) {
1061 if (sae
->tmp
->pw_id
) {
1062 wpa_printf(MSG_DEBUG
,
1063 "SAE: No Password Identifier included, but expected one (%s)",
1065 return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER
;
1067 os_free(sae
->tmp
->pw_id
);
1068 sae
->tmp
->pw_id
= NULL
;
1069 return WLAN_STATUS_SUCCESS
; /* No Password Identifier */
1072 if (sae
->tmp
->pw_id
&&
1073 (pos
[1] - 1 != (int) os_strlen(sae
->tmp
->pw_id
) ||
1074 os_memcmp(sae
->tmp
->pw_id
, pos
+ 3, pos
[1] - 1) != 0)) {
1075 wpa_printf(MSG_DEBUG
,
1076 "SAE: The included Password Identifier does not match the expected one (%s)",
1078 return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER
;
1081 os_free(sae
->tmp
->pw_id
);
1082 sae
->tmp
->pw_id
= os_malloc(pos
[1]);
1083 if (!sae
->tmp
->pw_id
)
1084 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1085 os_memcpy(sae
->tmp
->pw_id
, pos
+ 3, pos
[1] - 1);
1086 sae
->tmp
->pw_id
[pos
[1] - 1] = '\0';
1087 wpa_hexdump_ascii(MSG_DEBUG
, "SAE: Received Password Identifier",
1088 sae
->tmp
->pw_id
, pos
[1] - 1);
1089 return WLAN_STATUS_SUCCESS
;
1093 u16
sae_parse_commit(struct sae_data
*sae
, const u8
*data
, size_t len
,
1094 const u8
**token
, size_t *token_len
, int *allowed_groups
)
1096 const u8
*pos
= data
, *end
= data
+ len
;
1099 /* Check Finite Cyclic Group */
1101 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1102 res
= sae_group_allowed(sae
, allowed_groups
, WPA_GET_LE16(pos
));
1103 if (res
!= WLAN_STATUS_SUCCESS
)
1107 /* Optional Anti-Clogging Token */
1108 sae_parse_commit_token(sae
, &pos
, end
, token
, token_len
);
1111 res
= sae_parse_commit_scalar(sae
, &pos
, end
);
1112 if (res
!= WLAN_STATUS_SUCCESS
)
1115 /* commit-element */
1116 res
= sae_parse_commit_element(sae
, &pos
, end
);
1117 if (res
!= WLAN_STATUS_SUCCESS
)
1120 /* Optional Password Identifier element */
1121 res
= sae_parse_password_identifier(sae
, pos
, end
);
1122 if (res
!= WLAN_STATUS_SUCCESS
)
1126 * Check whether peer-commit-scalar and PEER-COMMIT-ELEMENT are same as
1127 * the values we sent which would be evidence of a reflection attack.
1129 if (!sae
->tmp
->own_commit_scalar
||
1130 crypto_bignum_cmp(sae
->tmp
->own_commit_scalar
,
1131 sae
->peer_commit_scalar
) != 0 ||
1133 (!sae
->tmp
->own_commit_element_ffc
||
1134 crypto_bignum_cmp(sae
->tmp
->own_commit_element_ffc
,
1135 sae
->tmp
->peer_commit_element_ffc
) != 0)) ||
1137 (!sae
->tmp
->own_commit_element_ecc
||
1138 crypto_ec_point_cmp(sae
->tmp
->ec
,
1139 sae
->tmp
->own_commit_element_ecc
,
1140 sae
->tmp
->peer_commit_element_ecc
) != 0)))
1141 return WLAN_STATUS_SUCCESS
; /* scalars/elements are different */
1144 * This is a reflection attack - return special value to trigger caller
1145 * to silently discard the frame instead of replying with a specific
1148 return SAE_SILENTLY_DISCARD
;
1152 static void sae_cn_confirm(struct sae_data
*sae
, const u8
*sc
,
1153 const struct crypto_bignum
*scalar1
,
1154 const u8
*element1
, size_t element1_len
,
1155 const struct crypto_bignum
*scalar2
,
1156 const u8
*element2
, size_t element2_len
,
1161 u8 scalar_b1
[SAE_MAX_PRIME_LEN
], scalar_b2
[SAE_MAX_PRIME_LEN
];
1164 * CN(key, X, Y, Z, ...) =
1165 * HMAC-SHA256(key, D2OS(X) || D2OS(Y) || D2OS(Z) | ...)
1166 * confirm = CN(KCK, send-confirm, commit-scalar, COMMIT-ELEMENT,
1167 * peer-commit-scalar, PEER-COMMIT-ELEMENT)
1168 * verifier = CN(KCK, peer-send-confirm, peer-commit-scalar,
1169 * PEER-COMMIT-ELEMENT, commit-scalar, COMMIT-ELEMENT)
1173 crypto_bignum_to_bin(scalar1
, scalar_b1
, sizeof(scalar_b1
),
1174 sae
->tmp
->prime_len
);
1175 addr
[1] = scalar_b1
;
1176 len
[1] = sae
->tmp
->prime_len
;
1178 len
[2] = element1_len
;
1179 crypto_bignum_to_bin(scalar2
, scalar_b2
, sizeof(scalar_b2
),
1180 sae
->tmp
->prime_len
);
1181 addr
[3] = scalar_b2
;
1182 len
[3] = sae
->tmp
->prime_len
;
1184 len
[4] = element2_len
;
1185 hmac_sha256_vector(sae
->tmp
->kck
, sizeof(sae
->tmp
->kck
), 5, addr
, len
,
1190 static void sae_cn_confirm_ecc(struct sae_data
*sae
, const u8
*sc
,
1191 const struct crypto_bignum
*scalar1
,
1192 const struct crypto_ec_point
*element1
,
1193 const struct crypto_bignum
*scalar2
,
1194 const struct crypto_ec_point
*element2
,
1197 u8 element_b1
[2 * SAE_MAX_ECC_PRIME_LEN
];
1198 u8 element_b2
[2 * SAE_MAX_ECC_PRIME_LEN
];
1200 crypto_ec_point_to_bin(sae
->tmp
->ec
, element1
, element_b1
,
1201 element_b1
+ sae
->tmp
->prime_len
);
1202 crypto_ec_point_to_bin(sae
->tmp
->ec
, element2
, element_b2
,
1203 element_b2
+ sae
->tmp
->prime_len
);
1205 sae_cn_confirm(sae
, sc
, scalar1
, element_b1
, 2 * sae
->tmp
->prime_len
,
1206 scalar2
, element_b2
, 2 * sae
->tmp
->prime_len
, confirm
);
1210 static void sae_cn_confirm_ffc(struct sae_data
*sae
, const u8
*sc
,
1211 const struct crypto_bignum
*scalar1
,
1212 const struct crypto_bignum
*element1
,
1213 const struct crypto_bignum
*scalar2
,
1214 const struct crypto_bignum
*element2
,
1217 u8 element_b1
[SAE_MAX_PRIME_LEN
];
1218 u8 element_b2
[SAE_MAX_PRIME_LEN
];
1220 crypto_bignum_to_bin(element1
, element_b1
, sizeof(element_b1
),
1221 sae
->tmp
->prime_len
);
1222 crypto_bignum_to_bin(element2
, element_b2
, sizeof(element_b2
),
1223 sae
->tmp
->prime_len
);
1225 sae_cn_confirm(sae
, sc
, scalar1
, element_b1
, sae
->tmp
->prime_len
,
1226 scalar2
, element_b2
, sae
->tmp
->prime_len
, confirm
);
1230 void sae_write_confirm(struct sae_data
*sae
, struct wpabuf
*buf
)
1234 if (sae
->tmp
== NULL
)
1238 sc
= wpabuf_put(buf
, 0);
1239 wpabuf_put_le16(buf
, sae
->send_confirm
);
1240 if (sae
->send_confirm
< 0xffff)
1241 sae
->send_confirm
++;
1244 sae_cn_confirm_ecc(sae
, sc
, sae
->tmp
->own_commit_scalar
,
1245 sae
->tmp
->own_commit_element_ecc
,
1246 sae
->peer_commit_scalar
,
1247 sae
->tmp
->peer_commit_element_ecc
,
1248 wpabuf_put(buf
, SHA256_MAC_LEN
));
1250 sae_cn_confirm_ffc(sae
, sc
, sae
->tmp
->own_commit_scalar
,
1251 sae
->tmp
->own_commit_element_ffc
,
1252 sae
->peer_commit_scalar
,
1253 sae
->tmp
->peer_commit_element_ffc
,
1254 wpabuf_put(buf
, SHA256_MAC_LEN
));
1258 int sae_check_confirm(struct sae_data
*sae
, const u8
*data
, size_t len
)
1260 u8 verifier
[SHA256_MAC_LEN
];
1262 if (len
< 2 + SHA256_MAC_LEN
) {
1263 wpa_printf(MSG_DEBUG
, "SAE: Too short confirm message");
1267 wpa_printf(MSG_DEBUG
, "SAE: peer-send-confirm %u", WPA_GET_LE16(data
));
1269 if (!sae
->tmp
|| !sae
->peer_commit_scalar
||
1270 !sae
->tmp
->own_commit_scalar
) {
1271 wpa_printf(MSG_DEBUG
, "SAE: Temporary data not yet available");
1276 if (!sae
->tmp
->peer_commit_element_ecc
||
1277 !sae
->tmp
->own_commit_element_ecc
)
1279 sae_cn_confirm_ecc(sae
, data
, sae
->peer_commit_scalar
,
1280 sae
->tmp
->peer_commit_element_ecc
,
1281 sae
->tmp
->own_commit_scalar
,
1282 sae
->tmp
->own_commit_element_ecc
,
1285 if (!sae
->tmp
->peer_commit_element_ffc
||
1286 !sae
->tmp
->own_commit_element_ffc
)
1288 sae_cn_confirm_ffc(sae
, data
, sae
->peer_commit_scalar
,
1289 sae
->tmp
->peer_commit_element_ffc
,
1290 sae
->tmp
->own_commit_scalar
,
1291 sae
->tmp
->own_commit_element_ffc
,
1295 if (os_memcmp_const(verifier
, data
+ 2, SHA256_MAC_LEN
) != 0) {
1296 wpa_printf(MSG_DEBUG
, "SAE: Confirm mismatch");
1297 wpa_hexdump(MSG_DEBUG
, "SAE: Received confirm",
1298 data
+ 2, SHA256_MAC_LEN
);
1299 wpa_hexdump(MSG_DEBUG
, "SAE: Calculated verifier",
1300 verifier
, SHA256_MAC_LEN
);
1308 const char * sae_state_txt(enum sae_state state
)