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"
21 static int sae_suitable_group(int group
)
23 #ifdef CONFIG_TESTING_OPTIONS
24 /* Allow all groups for testing purposes in non-production builds. */
26 #else /* CONFIG_TESTING_OPTIONS */
27 /* Enforce REVmd rules on which SAE groups are suitable for production
28 * purposes: FFC groups whose prime is >= 3072 bits and ECC groups
29 * defined over a prime field whose prime is >= 256 bits. Furthermore,
30 * ECC groups defined over a characteristic 2 finite field and ECC
31 * groups with a co-factor greater than 1 are not suitable. */
32 return group
== 19 || group
== 20 || group
== 21 ||
33 group
== 28 || group
== 29 || group
== 30 ||
34 group
== 15 || group
== 16 || group
== 17 || group
== 18;
35 #endif /* CONFIG_TESTING_OPTIONS */
39 int sae_set_group(struct sae_data
*sae
, int group
)
41 struct sae_temporary_data
*tmp
;
43 if (!sae_suitable_group(group
)) {
44 wpa_printf(MSG_DEBUG
, "SAE: Reject unsuitable group %d", group
);
49 tmp
= sae
->tmp
= os_zalloc(sizeof(*tmp
));
53 /* First, check if this is an ECC group */
54 tmp
->ec
= crypto_ec_init(group
);
56 wpa_printf(MSG_DEBUG
, "SAE: Selecting supported ECC group %d",
59 tmp
->prime_len
= crypto_ec_prime_len(tmp
->ec
);
60 tmp
->prime
= crypto_ec_get_prime(tmp
->ec
);
61 tmp
->order
= crypto_ec_get_order(tmp
->ec
);
65 /* Not an ECC group, check FFC */
66 tmp
->dh
= dh_groups_get(group
);
68 wpa_printf(MSG_DEBUG
, "SAE: Selecting supported FFC group %d",
71 tmp
->prime_len
= tmp
->dh
->prime_len
;
72 if (tmp
->prime_len
> SAE_MAX_PRIME_LEN
) {
77 tmp
->prime_buf
= crypto_bignum_init_set(tmp
->dh
->prime
,
79 if (tmp
->prime_buf
== NULL
) {
83 tmp
->prime
= tmp
->prime_buf
;
85 tmp
->order_buf
= crypto_bignum_init_set(tmp
->dh
->order
,
87 if (tmp
->order_buf
== NULL
) {
91 tmp
->order
= tmp
->order_buf
;
96 /* Unsupported group */
98 "SAE: Group %d not supported by the crypto library", group
);
103 void sae_clear_temp_data(struct sae_data
*sae
)
105 struct sae_temporary_data
*tmp
;
106 if (sae
== NULL
|| sae
->tmp
== NULL
)
109 crypto_ec_deinit(tmp
->ec
);
110 crypto_bignum_deinit(tmp
->prime_buf
, 0);
111 crypto_bignum_deinit(tmp
->order_buf
, 0);
112 crypto_bignum_deinit(tmp
->sae_rand
, 1);
113 crypto_bignum_deinit(tmp
->pwe_ffc
, 1);
114 crypto_bignum_deinit(tmp
->own_commit_scalar
, 0);
115 crypto_bignum_deinit(tmp
->own_commit_element_ffc
, 0);
116 crypto_bignum_deinit(tmp
->peer_commit_element_ffc
, 0);
117 crypto_ec_point_deinit(tmp
->pwe_ecc
, 1);
118 crypto_ec_point_deinit(tmp
->own_commit_element_ecc
, 0);
119 crypto_ec_point_deinit(tmp
->peer_commit_element_ecc
, 0);
120 wpabuf_free(tmp
->anti_clogging_token
);
122 bin_clear_free(tmp
, sizeof(*tmp
));
127 void sae_clear_data(struct sae_data
*sae
)
131 sae_clear_temp_data(sae
);
132 crypto_bignum_deinit(sae
->peer_commit_scalar
, 0);
133 os_memset(sae
, 0, sizeof(*sae
));
137 static struct crypto_bignum
* sae_get_rand(struct sae_data
*sae
)
139 u8 val
[SAE_MAX_PRIME_LEN
];
141 struct crypto_bignum
*bn
= NULL
;
142 int order_len_bits
= crypto_bignum_bits(sae
->tmp
->order
);
143 size_t order_len
= (order_len_bits
+ 7) / 8;
145 if (order_len
> sizeof(val
))
149 if (iter
++ > 100 || random_get_bytes(val
, order_len
) < 0)
151 if (order_len_bits
% 8)
152 buf_shift_right(val
, order_len
, 8 - order_len_bits
% 8);
153 bn
= crypto_bignum_init_set(val
, order_len
);
156 if (crypto_bignum_is_zero(bn
) ||
157 crypto_bignum_is_one(bn
) ||
158 crypto_bignum_cmp(bn
, sae
->tmp
->order
) >= 0) {
159 crypto_bignum_deinit(bn
, 0);
165 os_memset(val
, 0, order_len
);
170 static struct crypto_bignum
* sae_get_rand_and_mask(struct sae_data
*sae
)
172 crypto_bignum_deinit(sae
->tmp
->sae_rand
, 1);
173 sae
->tmp
->sae_rand
= sae_get_rand(sae
);
174 if (sae
->tmp
->sae_rand
== NULL
)
176 return sae_get_rand(sae
);
180 static void sae_pwd_seed_key(const u8
*addr1
, const u8
*addr2
, u8
*key
)
182 wpa_printf(MSG_DEBUG
, "SAE: PWE derivation - addr1=" MACSTR
183 " addr2=" MACSTR
, MAC2STR(addr1
), MAC2STR(addr2
));
184 if (os_memcmp(addr1
, addr2
, ETH_ALEN
) > 0) {
185 os_memcpy(key
, addr1
, ETH_ALEN
);
186 os_memcpy(key
+ ETH_ALEN
, addr2
, ETH_ALEN
);
188 os_memcpy(key
, addr2
, ETH_ALEN
);
189 os_memcpy(key
+ ETH_ALEN
, addr1
, ETH_ALEN
);
194 static struct crypto_bignum
*
195 get_rand_1_to_p_1(const u8
*prime
, size_t prime_len
, size_t prime_bits
,
199 struct crypto_bignum
*r
;
200 u8 tmp
[SAE_MAX_ECC_PRIME_LEN
];
202 if (random_get_bytes(tmp
, prime_len
) < 0)
205 buf_shift_right(tmp
, prime_len
, 8 - prime_bits
% 8);
206 if (os_memcmp(tmp
, prime
, prime_len
) >= 0)
208 r
= crypto_bignum_init_set(tmp
, prime_len
);
211 if (crypto_bignum_is_zero(r
)) {
212 crypto_bignum_deinit(r
, 0);
216 *r_odd
= tmp
[prime_len
- 1] & 0x01;
224 static int is_quadratic_residue_blind(struct sae_data
*sae
,
225 const u8
*prime
, size_t bits
,
226 const u8
*qr
, const u8
*qnr
,
227 const struct crypto_bignum
*y_sqr
)
229 struct crypto_bignum
*r
, *num
, *qr_or_qnr
= NULL
;
230 int r_odd
, check
, res
= -1;
231 u8 qr_or_qnr_bin
[SAE_MAX_ECC_PRIME_LEN
];
232 size_t prime_len
= sae
->tmp
->prime_len
;
236 * Use the blinding technique to mask y_sqr while determining
237 * whether it is a quadratic residue modulo p to avoid leaking
238 * timing information while determining the Legendre symbol.
241 * r = a random number between 1 and p-1, inclusive
242 * num = (v * r * r) modulo p
244 r
= get_rand_1_to_p_1(prime
, prime_len
, bits
, &r_odd
);
248 num
= crypto_bignum_init();
250 crypto_bignum_mulmod(y_sqr
, r
, sae
->tmp
->prime
, num
) < 0 ||
251 crypto_bignum_mulmod(num
, r
, sae
->tmp
->prime
, num
) < 0)
255 * Need to minimize differences in handling different cases, so try to
256 * avoid branches and timing differences.
259 * num = (num * qr) module p
260 * LGR(num, p) = 1 ==> quadratic residue
262 * num = (num * qnr) module p
263 * LGR(num, p) = -1 ==> quadratic residue
265 mask
= const_time_is_zero(r_odd
);
266 const_time_select_bin(mask
, qnr
, qr
, prime_len
, qr_or_qnr_bin
);
267 qr_or_qnr
= crypto_bignum_init_set(qr_or_qnr_bin
, prime_len
);
269 crypto_bignum_mulmod(num
, qr_or_qnr
, sae
->tmp
->prime
, num
) < 0)
271 /* r_odd is 0 or 1; branchless version of check = r_odd ? 1 : -1, */
272 check
= const_time_select_int(mask
, -1, 1);
274 res
= crypto_bignum_legendre(num
, sae
->tmp
->prime
);
279 /* branchless version of res = res == check
280 * (res is -1, 0, or 1; check is -1 or 1) */
281 mask
= const_time_eq(res
, check
);
282 res
= const_time_select_int(mask
, 1, 0);
284 crypto_bignum_deinit(num
, 1);
285 crypto_bignum_deinit(r
, 1);
286 crypto_bignum_deinit(qr_or_qnr
, 1);
291 static int sae_test_pwd_seed_ecc(struct sae_data
*sae
, const u8
*pwd_seed
,
292 const u8
*prime
, const u8
*qr
, const u8
*qnr
,
295 struct crypto_bignum
*y_sqr
, *x_cand
;
299 wpa_hexdump_key(MSG_DEBUG
, "SAE: pwd-seed", pwd_seed
, SHA256_MAC_LEN
);
301 /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
302 bits
= crypto_ec_prime_len_bits(sae
->tmp
->ec
);
303 if (sha256_prf_bits(pwd_seed
, SHA256_MAC_LEN
, "SAE Hunting and Pecking",
304 prime
, sae
->tmp
->prime_len
, pwd_value
, bits
) < 0)
307 buf_shift_right(pwd_value
, sae
->tmp
->prime_len
, 8 - bits
% 8);
308 wpa_hexdump_key(MSG_DEBUG
, "SAE: pwd-value",
309 pwd_value
, sae
->tmp
->prime_len
);
311 if (const_time_memcmp(pwd_value
, prime
, sae
->tmp
->prime_len
) >= 0)
314 x_cand
= crypto_bignum_init_set(pwd_value
, sae
->tmp
->prime_len
);
317 y_sqr
= crypto_ec_point_compute_y_sqr(sae
->tmp
->ec
, x_cand
);
318 crypto_bignum_deinit(x_cand
, 1);
322 res
= is_quadratic_residue_blind(sae
, prime
, bits
, qr
, qnr
, y_sqr
);
323 crypto_bignum_deinit(y_sqr
, 1);
328 /* Returns -1 on fatal failure, 0 if PWE cannot be derived from the provided
329 * pwd-seed, or 1 if a valid PWE was derived from pwd-seed. */
330 static int sae_test_pwd_seed_ffc(struct sae_data
*sae
, const u8
*pwd_seed
,
331 struct crypto_bignum
*pwe
)
333 u8 pwd_value
[SAE_MAX_PRIME_LEN
];
334 size_t bits
= sae
->tmp
->prime_len
* 8;
336 struct crypto_bignum
*a
, *b
= NULL
;
340 wpa_hexdump_key(MSG_DEBUG
, "SAE: pwd-seed", pwd_seed
, SHA256_MAC_LEN
);
342 /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
343 if (sha256_prf_bits(pwd_seed
, SHA256_MAC_LEN
, "SAE Hunting and Pecking",
344 sae
->tmp
->dh
->prime
, sae
->tmp
->prime_len
, pwd_value
,
347 wpa_hexdump_key(MSG_DEBUG
, "SAE: pwd-value", pwd_value
,
348 sae
->tmp
->prime_len
);
350 /* Check whether pwd-value < p */
351 res
= const_time_memcmp(pwd_value
, sae
->tmp
->dh
->prime
,
352 sae
->tmp
->prime_len
);
353 /* pwd-value >= p is invalid, so res is < 0 for the valid cases and
354 * the negative sign can be used to fill the mask for constant time
356 pwd_value_valid
= const_time_fill_msb(res
);
358 /* If pwd-value >= p, force pwd-value to be < p and perform the
359 * calculations anyway to hide timing difference. The derived PWE will
360 * be ignored in that case. */
361 pwd_value
[0] = const_time_select_u8(pwd_value_valid
, pwd_value
[0], 0);
363 /* PWE = pwd-value^((p-1)/r) modulo p */
366 a
= crypto_bignum_init_set(pwd_value
, sae
->tmp
->prime_len
);
370 /* This is an optimization based on the used group that does not depend
371 * on the password in any way, so it is fine to use separate branches
372 * for this step without constant time operations. */
373 if (sae
->tmp
->dh
->safe_prime
) {
375 * r = (p-1)/2 for the group used here, so this becomes:
376 * PWE = pwd-value^2 modulo p
379 b
= crypto_bignum_init_set(exp
, sizeof(exp
));
381 /* Calculate exponent: (p-1)/r */
383 b
= crypto_bignum_init_set(exp
, sizeof(exp
));
385 crypto_bignum_sub(sae
->tmp
->prime
, b
, b
) < 0 ||
386 crypto_bignum_div(b
, sae
->tmp
->order
, b
) < 0)
393 res
= crypto_bignum_exptmod(a
, b
, sae
->tmp
->prime
, pwe
);
397 /* There were no fatal errors in calculations, so determine the return
398 * value using constant time operations. We get here for number of
399 * invalid cases which are cleared here after having performed all the
400 * computation. PWE is valid if pwd-value was less than prime and
401 * PWE > 1. Start with pwd-value check first and then use constant time
402 * operations to clear res to 0 if PWE is 0 or 1.
404 res
= const_time_select_u8(pwd_value_valid
, 1, 0);
405 is_val
= crypto_bignum_is_zero(pwe
);
406 res
= const_time_select_u8(const_time_is_zero(is_val
), res
, 0);
407 is_val
= crypto_bignum_is_one(pwe
);
408 res
= const_time_select_u8(const_time_is_zero(is_val
), res
, 0);
411 crypto_bignum_deinit(a
, 1);
412 crypto_bignum_deinit(b
, 1);
417 static int get_random_qr_qnr(const u8
*prime
, size_t prime_len
,
418 const struct crypto_bignum
*prime_bn
,
419 size_t prime_bits
, struct crypto_bignum
**qr
,
420 struct crypto_bignum
**qnr
)
425 while (!(*qr
) || !(*qnr
)) {
426 u8 tmp
[SAE_MAX_ECC_PRIME_LEN
];
427 struct crypto_bignum
*q
;
430 if (random_get_bytes(tmp
, prime_len
) < 0)
433 buf_shift_right(tmp
, prime_len
, 8 - prime_bits
% 8);
434 if (os_memcmp(tmp
, prime
, prime_len
) >= 0)
436 q
= crypto_bignum_init_set(tmp
, prime_len
);
439 res
= crypto_bignum_legendre(q
, prime_bn
);
441 if (res
== 1 && !(*qr
))
443 else if (res
== -1 && !(*qnr
))
446 crypto_bignum_deinit(q
, 0);
449 return (*qr
&& *qnr
) ? 0 : -1;
453 static int sae_derive_pwe_ecc(struct sae_data
*sae
, const u8
*addr1
,
454 const u8
*addr2
, const u8
*password
,
455 size_t password_len
, const char *identifier
)
458 u8 addrs
[2 * ETH_ALEN
];
462 u8
*dummy_password
, *tmp_password
;
463 int pwd_seed_odd
= 0;
464 u8 prime
[SAE_MAX_ECC_PRIME_LEN
];
466 struct crypto_bignum
*x
= NULL
, *qr
= NULL
, *qnr
= NULL
;
467 u8 x_bin
[SAE_MAX_ECC_PRIME_LEN
];
468 u8 x_cand_bin
[SAE_MAX_ECC_PRIME_LEN
];
469 u8 qr_bin
[SAE_MAX_ECC_PRIME_LEN
];
470 u8 qnr_bin
[SAE_MAX_ECC_PRIME_LEN
];
473 u8 found
= 0; /* 0 (false) or 0xff (true) to be used as const_time_*
476 os_memset(x_bin
, 0, sizeof(x_bin
));
478 dummy_password
= os_malloc(password_len
);
479 tmp_password
= os_malloc(password_len
);
480 if (!dummy_password
|| !tmp_password
||
481 random_get_bytes(dummy_password
, password_len
) < 0)
484 prime_len
= sae
->tmp
->prime_len
;
485 if (crypto_bignum_to_bin(sae
->tmp
->prime
, prime
, sizeof(prime
),
488 bits
= crypto_ec_prime_len_bits(sae
->tmp
->ec
);
491 * Create a random quadratic residue (qr) and quadratic non-residue
492 * (qnr) modulo p for blinding purposes during the loop.
494 if (get_random_qr_qnr(prime
, prime_len
, sae
->tmp
->prime
, bits
,
496 crypto_bignum_to_bin(qr
, qr_bin
, sizeof(qr_bin
), prime_len
) < 0 ||
497 crypto_bignum_to_bin(qnr
, qnr_bin
, sizeof(qnr_bin
), prime_len
) < 0)
500 wpa_hexdump_ascii_key(MSG_DEBUG
, "SAE: password",
501 password
, password_len
);
503 wpa_printf(MSG_DEBUG
, "SAE: password identifier: %s",
507 * H(salt, ikm) = HMAC-SHA256(salt, ikm)
508 * base = password [|| identifier]
509 * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
512 sae_pwd_seed_key(addr1
, addr2
, addrs
);
514 addr
[0] = tmp_password
;
515 len
[0] = password_len
;
518 addr
[num_elem
] = (const u8
*) identifier
;
519 len
[num_elem
] = os_strlen(identifier
);
522 addr
[num_elem
] = &counter
;
523 len
[num_elem
] = sizeof(counter
);
527 * Continue for at least k iterations to protect against side-channel
528 * attacks that attempt to determine the number of iterations required
531 for (counter
= 1; counter
<= k
|| !found
; counter
++) {
532 u8 pwd_seed
[SHA256_MAC_LEN
];
535 /* This should not happen in practice */
536 wpa_printf(MSG_DEBUG
, "SAE: Failed to derive PWE");
540 wpa_printf(MSG_DEBUG
, "SAE: counter = %03u", counter
);
541 const_time_select_bin(found
, dummy_password
, password
,
542 password_len
, tmp_password
);
543 if (hmac_sha256_vector(addrs
, sizeof(addrs
), num_elem
,
544 addr
, len
, pwd_seed
) < 0)
547 res
= sae_test_pwd_seed_ecc(sae
, pwd_seed
,
548 prime
, qr_bin
, qnr_bin
, x_cand_bin
);
549 const_time_select_bin(found
, x_bin
, x_cand_bin
, prime_len
,
551 pwd_seed_odd
= const_time_select_u8(
553 pwd_seed
[SHA256_MAC_LEN
- 1] & 0x01);
554 os_memset(pwd_seed
, 0, sizeof(pwd_seed
));
557 /* Need to minimize differences in handling res == 0 and 1 here
558 * to avoid differences in timing and instruction cache access,
559 * so use const_time_select_*() to make local copies of the
560 * values based on whether this loop iteration was the one that
561 * found the pwd-seed/x. */
563 /* found is 0 or 0xff here and res is 0 or 1. Bitwise OR of them
564 * (with res converted to 0/0xff) handles this in constant time.
567 wpa_printf(MSG_DEBUG
, "SAE: pwd-seed result %d found=0x%02x",
572 wpa_printf(MSG_DEBUG
, "SAE: Could not generate PWE");
577 x
= crypto_bignum_init_set(x_bin
, prime_len
);
583 if (!sae
->tmp
->pwe_ecc
)
584 sae
->tmp
->pwe_ecc
= crypto_ec_point_init(sae
->tmp
->ec
);
585 if (!sae
->tmp
->pwe_ecc
)
588 res
= crypto_ec_point_solve_y_coord(sae
->tmp
->ec
,
589 sae
->tmp
->pwe_ecc
, x
,
593 * This should not happen since we already checked that there
596 wpa_printf(MSG_DEBUG
, "SAE: Could not solve y");
600 crypto_bignum_deinit(qr
, 0);
601 crypto_bignum_deinit(qnr
, 0);
602 os_free(dummy_password
);
603 bin_clear_free(tmp_password
, password_len
);
604 crypto_bignum_deinit(x
, 1);
605 os_memset(x_bin
, 0, sizeof(x_bin
));
606 os_memset(x_cand_bin
, 0, sizeof(x_cand_bin
));
612 static int sae_modp_group_require_masking(int group
)
614 /* Groups for which pwd-value is likely to be >= p frequently */
615 return group
== 22 || group
== 23 || group
== 24;
619 static int sae_derive_pwe_ffc(struct sae_data
*sae
, const u8
*addr1
,
620 const u8
*addr2
, const u8
*password
,
621 size_t password_len
, const char *identifier
)
623 u8 counter
, k
, sel_counter
= 0;
624 u8 addrs
[2 * ETH_ALEN
];
628 u8 found
= 0; /* 0 (false) or 0xff (true) to be used as const_time_*
631 struct crypto_bignum
*pwe
;
632 size_t prime_len
= sae
->tmp
->prime_len
* 8;
635 crypto_bignum_deinit(sae
->tmp
->pwe_ffc
, 1);
636 sae
->tmp
->pwe_ffc
= NULL
;
638 /* Allocate a buffer to maintain selected and candidate PWE for constant
640 pwe_buf
= os_zalloc(prime_len
* 2);
641 pwe
= crypto_bignum_init();
642 if (!pwe_buf
|| !pwe
)
645 wpa_hexdump_ascii_key(MSG_DEBUG
, "SAE: password",
646 password
, password_len
);
649 * H(salt, ikm) = HMAC-SHA256(salt, ikm)
650 * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
651 * password [|| identifier] || counter)
653 sae_pwd_seed_key(addr1
, addr2
, addrs
);
656 len
[0] = password_len
;
659 addr
[num_elem
] = (const u8
*) identifier
;
660 len
[num_elem
] = os_strlen(identifier
);
663 addr
[num_elem
] = &counter
;
664 len
[num_elem
] = sizeof(counter
);
667 k
= sae_modp_group_require_masking(sae
->group
) ? 40 : 1;
669 for (counter
= 1; counter
<= k
|| !found
; counter
++) {
670 u8 pwd_seed
[SHA256_MAC_LEN
];
674 /* This should not happen in practice */
675 wpa_printf(MSG_DEBUG
, "SAE: Failed to derive PWE");
679 wpa_printf(MSG_DEBUG
, "SAE: counter = %02u", counter
);
680 if (hmac_sha256_vector(addrs
, sizeof(addrs
), num_elem
,
681 addr
, len
, pwd_seed
) < 0)
683 res
= sae_test_pwd_seed_ffc(sae
, pwd_seed
, pwe
);
684 /* res is -1 for fatal failure, 0 if a valid PWE was not found,
685 * or 1 if a valid PWE was found. */
688 /* Store the candidate PWE into the second half of pwe_buf and
689 * the selected PWE in the beginning of pwe_buf using constant
691 if (crypto_bignum_to_bin(pwe
, pwe_buf
+ prime_len
, prime_len
,
694 const_time_select_bin(found
, pwe_buf
, pwe_buf
+ prime_len
,
696 sel_counter
= const_time_select_u8(found
, sel_counter
, counter
);
697 mask
= const_time_eq_u8(res
, 1);
698 found
= const_time_select_u8(found
, found
, mask
);
704 wpa_printf(MSG_DEBUG
, "SAE: Use PWE from counter = %02u", sel_counter
);
705 sae
->tmp
->pwe_ffc
= crypto_bignum_init_set(pwe_buf
, prime_len
);
707 crypto_bignum_deinit(pwe
, 1);
708 bin_clear_free(pwe_buf
, prime_len
* 2);
709 return sae
->tmp
->pwe_ffc
? 0 : -1;
713 static int sae_derive_commit_element_ecc(struct sae_data
*sae
,
714 struct crypto_bignum
*mask
)
716 /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */
717 if (!sae
->tmp
->own_commit_element_ecc
) {
718 sae
->tmp
->own_commit_element_ecc
=
719 crypto_ec_point_init(sae
->tmp
->ec
);
720 if (!sae
->tmp
->own_commit_element_ecc
)
724 if (crypto_ec_point_mul(sae
->tmp
->ec
, sae
->tmp
->pwe_ecc
, mask
,
725 sae
->tmp
->own_commit_element_ecc
) < 0 ||
726 crypto_ec_point_invert(sae
->tmp
->ec
,
727 sae
->tmp
->own_commit_element_ecc
) < 0) {
728 wpa_printf(MSG_DEBUG
, "SAE: Could not compute commit-element");
736 static int sae_derive_commit_element_ffc(struct sae_data
*sae
,
737 struct crypto_bignum
*mask
)
739 /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */
740 if (!sae
->tmp
->own_commit_element_ffc
) {
741 sae
->tmp
->own_commit_element_ffc
= crypto_bignum_init();
742 if (!sae
->tmp
->own_commit_element_ffc
)
746 if (crypto_bignum_exptmod(sae
->tmp
->pwe_ffc
, mask
, sae
->tmp
->prime
,
747 sae
->tmp
->own_commit_element_ffc
) < 0 ||
748 crypto_bignum_inverse(sae
->tmp
->own_commit_element_ffc
,
750 sae
->tmp
->own_commit_element_ffc
) < 0) {
751 wpa_printf(MSG_DEBUG
, "SAE: Could not compute commit-element");
759 static int sae_derive_commit(struct sae_data
*sae
)
761 struct crypto_bignum
*mask
;
763 unsigned int counter
= 0;
769 * This cannot really happen in practice if the random
770 * number generator is working. Anyway, to avoid even a
771 * theoretical infinite loop, break out after 100
777 mask
= sae_get_rand_and_mask(sae
);
779 wpa_printf(MSG_DEBUG
, "SAE: Could not get rand/mask");
783 /* commit-scalar = (rand + mask) modulo r */
784 if (!sae
->tmp
->own_commit_scalar
) {
785 sae
->tmp
->own_commit_scalar
= crypto_bignum_init();
786 if (!sae
->tmp
->own_commit_scalar
)
789 crypto_bignum_add(sae
->tmp
->sae_rand
, mask
,
790 sae
->tmp
->own_commit_scalar
);
791 crypto_bignum_mod(sae
->tmp
->own_commit_scalar
, sae
->tmp
->order
,
792 sae
->tmp
->own_commit_scalar
);
793 } while (crypto_bignum_is_zero(sae
->tmp
->own_commit_scalar
) ||
794 crypto_bignum_is_one(sae
->tmp
->own_commit_scalar
));
796 if ((sae
->tmp
->ec
&& sae_derive_commit_element_ecc(sae
, mask
) < 0) ||
797 (sae
->tmp
->dh
&& sae_derive_commit_element_ffc(sae
, mask
) < 0))
802 crypto_bignum_deinit(mask
, 1);
807 int sae_prepare_commit(const u8
*addr1
, const u8
*addr2
,
808 const u8
*password
, size_t password_len
,
809 const char *identifier
, struct sae_data
*sae
)
811 if (sae
->tmp
== NULL
||
812 (sae
->tmp
->ec
&& sae_derive_pwe_ecc(sae
, addr1
, addr2
, password
,
815 (sae
->tmp
->dh
&& sae_derive_pwe_ffc(sae
, addr1
, addr2
, password
,
818 sae_derive_commit(sae
) < 0)
824 static int sae_derive_k_ecc(struct sae_data
*sae
, u8
*k
)
826 struct crypto_ec_point
*K
;
829 K
= crypto_ec_point_init(sae
->tmp
->ec
);
834 * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE),
835 * PEER-COMMIT-ELEMENT)))
836 * If K is identity element (point-at-infinity), reject
837 * k = F(K) (= x coordinate)
840 if (crypto_ec_point_mul(sae
->tmp
->ec
, sae
->tmp
->pwe_ecc
,
841 sae
->peer_commit_scalar
, K
) < 0 ||
842 crypto_ec_point_add(sae
->tmp
->ec
, K
,
843 sae
->tmp
->peer_commit_element_ecc
, K
) < 0 ||
844 crypto_ec_point_mul(sae
->tmp
->ec
, K
, sae
->tmp
->sae_rand
, K
) < 0 ||
845 crypto_ec_point_is_at_infinity(sae
->tmp
->ec
, K
) ||
846 crypto_ec_point_to_bin(sae
->tmp
->ec
, K
, k
, NULL
) < 0) {
847 wpa_printf(MSG_DEBUG
, "SAE: Failed to calculate K and k");
851 wpa_hexdump_key(MSG_DEBUG
, "SAE: k", k
, sae
->tmp
->prime_len
);
855 crypto_ec_point_deinit(K
, 1);
860 static int sae_derive_k_ffc(struct sae_data
*sae
, u8
*k
)
862 struct crypto_bignum
*K
;
865 K
= crypto_bignum_init();
870 * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE),
871 * PEER-COMMIT-ELEMENT)))
872 * If K is identity element (one), reject.
873 * k = F(K) (= x coordinate)
876 if (crypto_bignum_exptmod(sae
->tmp
->pwe_ffc
, sae
->peer_commit_scalar
,
877 sae
->tmp
->prime
, K
) < 0 ||
878 crypto_bignum_mulmod(K
, sae
->tmp
->peer_commit_element_ffc
,
879 sae
->tmp
->prime
, K
) < 0 ||
880 crypto_bignum_exptmod(K
, sae
->tmp
->sae_rand
, sae
->tmp
->prime
, K
) < 0
882 crypto_bignum_is_one(K
) ||
883 crypto_bignum_to_bin(K
, k
, SAE_MAX_PRIME_LEN
, sae
->tmp
->prime_len
) <
885 wpa_printf(MSG_DEBUG
, "SAE: Failed to calculate K and k");
889 wpa_hexdump_key(MSG_DEBUG
, "SAE: k", k
, sae
->tmp
->prime_len
);
893 crypto_bignum_deinit(K
, 1);
898 static int sae_derive_keys(struct sae_data
*sae
, const u8
*k
)
900 u8 null_key
[SAE_KEYSEED_KEY_LEN
], val
[SAE_MAX_PRIME_LEN
];
901 u8 keyseed
[SHA256_MAC_LEN
];
902 u8 keys
[SAE_KCK_LEN
+ SAE_PMK_LEN
];
903 struct crypto_bignum
*tmp
;
906 tmp
= crypto_bignum_init();
910 /* keyseed = H(<0>32, k)
911 * KCK || PMK = KDF-512(keyseed, "SAE KCK and PMK",
912 * (commit-scalar + peer-commit-scalar) modulo r)
913 * PMKID = L((commit-scalar + peer-commit-scalar) modulo r, 0, 128)
916 os_memset(null_key
, 0, sizeof(null_key
));
917 hmac_sha256(null_key
, sizeof(null_key
), k
, sae
->tmp
->prime_len
,
919 wpa_hexdump_key(MSG_DEBUG
, "SAE: keyseed", keyseed
, sizeof(keyseed
));
921 crypto_bignum_add(sae
->tmp
->own_commit_scalar
, sae
->peer_commit_scalar
,
923 crypto_bignum_mod(tmp
, sae
->tmp
->order
, tmp
);
924 crypto_bignum_to_bin(tmp
, val
, sizeof(val
), sae
->tmp
->prime_len
);
925 wpa_hexdump(MSG_DEBUG
, "SAE: PMKID", val
, SAE_PMKID_LEN
);
926 if (sha256_prf(keyseed
, sizeof(keyseed
), "SAE KCK and PMK",
927 val
, sae
->tmp
->prime_len
, keys
, sizeof(keys
)) < 0)
929 os_memset(keyseed
, 0, sizeof(keyseed
));
930 os_memcpy(sae
->tmp
->kck
, keys
, SAE_KCK_LEN
);
931 os_memcpy(sae
->pmk
, keys
+ SAE_KCK_LEN
, SAE_PMK_LEN
);
932 os_memcpy(sae
->pmkid
, val
, SAE_PMKID_LEN
);
933 os_memset(keys
, 0, sizeof(keys
));
934 wpa_hexdump_key(MSG_DEBUG
, "SAE: KCK", sae
->tmp
->kck
, SAE_KCK_LEN
);
935 wpa_hexdump_key(MSG_DEBUG
, "SAE: PMK", sae
->pmk
, SAE_PMK_LEN
);
939 crypto_bignum_deinit(tmp
, 0);
944 int sae_process_commit(struct sae_data
*sae
)
946 u8 k
[SAE_MAX_PRIME_LEN
];
947 if (sae
->tmp
== NULL
||
948 (sae
->tmp
->ec
&& sae_derive_k_ecc(sae
, k
) < 0) ||
949 (sae
->tmp
->dh
&& sae_derive_k_ffc(sae
, k
) < 0) ||
950 sae_derive_keys(sae
, k
) < 0)
956 void sae_write_commit(struct sae_data
*sae
, struct wpabuf
*buf
,
957 const struct wpabuf
*token
, const char *identifier
)
961 if (sae
->tmp
== NULL
)
964 wpabuf_put_le16(buf
, sae
->group
); /* Finite Cyclic Group */
966 wpabuf_put_buf(buf
, token
);
967 wpa_hexdump(MSG_DEBUG
, "SAE: Anti-clogging token",
968 wpabuf_head(token
), wpabuf_len(token
));
970 pos
= wpabuf_put(buf
, sae
->tmp
->prime_len
);
971 crypto_bignum_to_bin(sae
->tmp
->own_commit_scalar
, pos
,
972 sae
->tmp
->prime_len
, sae
->tmp
->prime_len
);
973 wpa_hexdump(MSG_DEBUG
, "SAE: own commit-scalar",
974 pos
, sae
->tmp
->prime_len
);
976 pos
= wpabuf_put(buf
, 2 * sae
->tmp
->prime_len
);
977 crypto_ec_point_to_bin(sae
->tmp
->ec
,
978 sae
->tmp
->own_commit_element_ecc
,
979 pos
, pos
+ sae
->tmp
->prime_len
);
980 wpa_hexdump(MSG_DEBUG
, "SAE: own commit-element(x)",
981 pos
, sae
->tmp
->prime_len
);
982 wpa_hexdump(MSG_DEBUG
, "SAE: own commit-element(y)",
983 pos
+ sae
->tmp
->prime_len
, sae
->tmp
->prime_len
);
985 pos
= wpabuf_put(buf
, sae
->tmp
->prime_len
);
986 crypto_bignum_to_bin(sae
->tmp
->own_commit_element_ffc
, pos
,
987 sae
->tmp
->prime_len
, sae
->tmp
->prime_len
);
988 wpa_hexdump(MSG_DEBUG
, "SAE: own commit-element",
989 pos
, sae
->tmp
->prime_len
);
993 /* Password Identifier element */
994 wpabuf_put_u8(buf
, WLAN_EID_EXTENSION
);
995 wpabuf_put_u8(buf
, 1 + os_strlen(identifier
));
996 wpabuf_put_u8(buf
, WLAN_EID_EXT_PASSWORD_IDENTIFIER
);
997 wpabuf_put_str(buf
, identifier
);
998 wpa_printf(MSG_DEBUG
, "SAE: own Password Identifier: %s",
1004 u16
sae_group_allowed(struct sae_data
*sae
, int *allowed_groups
, u16 group
)
1006 if (allowed_groups
) {
1008 for (i
= 0; allowed_groups
[i
] > 0; i
++) {
1009 if (allowed_groups
[i
] == group
)
1012 if (allowed_groups
[i
] != group
) {
1013 wpa_printf(MSG_DEBUG
, "SAE: Proposed group %u not "
1014 "enabled in the current configuration",
1016 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED
;
1020 if (sae
->state
== SAE_COMMITTED
&& group
!= sae
->group
) {
1021 wpa_printf(MSG_DEBUG
, "SAE: Do not allow group to be changed");
1022 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED
;
1025 if (group
!= sae
->group
&& sae_set_group(sae
, group
) < 0) {
1026 wpa_printf(MSG_DEBUG
, "SAE: Unsupported Finite Cyclic Group %u",
1028 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED
;
1031 if (sae
->tmp
== NULL
) {
1032 wpa_printf(MSG_DEBUG
, "SAE: Group information not yet initialized");
1033 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1036 if (sae
->tmp
->dh
&& !allowed_groups
) {
1037 wpa_printf(MSG_DEBUG
, "SAE: Do not allow FFC group %u without "
1038 "explicit configuration enabling it", group
);
1039 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED
;
1042 return WLAN_STATUS_SUCCESS
;
1046 static int sae_is_password_id_elem(const u8
*pos
, const u8
*end
)
1048 return end
- pos
>= 3 &&
1049 pos
[0] == WLAN_EID_EXTENSION
&&
1051 end
- pos
- 2 >= pos
[1] &&
1052 pos
[2] == WLAN_EID_EXT_PASSWORD_IDENTIFIER
;
1056 static void sae_parse_commit_token(struct sae_data
*sae
, const u8
**pos
,
1057 const u8
*end
, const u8
**token
,
1060 size_t scalar_elem_len
, tlen
;
1068 scalar_elem_len
= (sae
->tmp
->ec
? 3 : 2) * sae
->tmp
->prime_len
;
1069 if (scalar_elem_len
>= (size_t) (end
- *pos
))
1070 return; /* No extra data beyond peer scalar and element */
1072 /* It is a bit difficult to parse this now that there is an
1073 * optional variable length Anti-Clogging Token field and
1074 * optional variable length Password Identifier element in the
1075 * frame. We are sending out fixed length Anti-Clogging Token
1076 * fields, so use that length as a requirement for the received
1077 * token and check for the presence of possible Password
1078 * Identifier element based on the element header information.
1080 tlen
= end
- (*pos
+ scalar_elem_len
);
1082 if (tlen
< SHA256_MAC_LEN
) {
1083 wpa_printf(MSG_DEBUG
,
1084 "SAE: Too short optional data (%u octets) to include our Anti-Clogging Token",
1085 (unsigned int) tlen
);
1089 elem
= *pos
+ scalar_elem_len
;
1090 if (sae_is_password_id_elem(elem
, end
)) {
1091 /* Password Identifier element takes out all available
1092 * extra octets, so there can be no Anti-Clogging token in
1097 elem
+= SHA256_MAC_LEN
;
1098 if (sae_is_password_id_elem(elem
, end
)) {
1099 /* Password Identifier element is included in the end, so
1100 * remove its length from the Anti-Clogging token field. */
1101 tlen
-= 2 + elem
[1];
1104 wpa_hexdump(MSG_DEBUG
, "SAE: Anti-Clogging Token", *pos
, tlen
);
1113 static u16
sae_parse_commit_scalar(struct sae_data
*sae
, const u8
**pos
,
1116 struct crypto_bignum
*peer_scalar
;
1118 if (sae
->tmp
->prime_len
> end
- *pos
) {
1119 wpa_printf(MSG_DEBUG
, "SAE: Not enough data for scalar");
1120 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1123 peer_scalar
= crypto_bignum_init_set(*pos
, sae
->tmp
->prime_len
);
1124 if (peer_scalar
== NULL
)
1125 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1128 * IEEE Std 802.11-2012, 11.3.8.6.1: If there is a protocol instance for
1129 * the peer and it is in Authenticated state, the new Commit Message
1130 * shall be dropped if the peer-scalar is identical to the one used in
1131 * the existing protocol instance.
1133 if (sae
->state
== SAE_ACCEPTED
&& sae
->peer_commit_scalar
&&
1134 crypto_bignum_cmp(sae
->peer_commit_scalar
, peer_scalar
) == 0) {
1135 wpa_printf(MSG_DEBUG
, "SAE: Do not accept re-use of previous "
1136 "peer-commit-scalar");
1137 crypto_bignum_deinit(peer_scalar
, 0);
1138 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1141 /* 1 < scalar < r */
1142 if (crypto_bignum_is_zero(peer_scalar
) ||
1143 crypto_bignum_is_one(peer_scalar
) ||
1144 crypto_bignum_cmp(peer_scalar
, sae
->tmp
->order
) >= 0) {
1145 wpa_printf(MSG_DEBUG
, "SAE: Invalid peer scalar");
1146 crypto_bignum_deinit(peer_scalar
, 0);
1147 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1151 crypto_bignum_deinit(sae
->peer_commit_scalar
, 0);
1152 sae
->peer_commit_scalar
= peer_scalar
;
1153 wpa_hexdump(MSG_DEBUG
, "SAE: Peer commit-scalar",
1154 *pos
, sae
->tmp
->prime_len
);
1155 *pos
+= sae
->tmp
->prime_len
;
1157 return WLAN_STATUS_SUCCESS
;
1161 static u16
sae_parse_commit_element_ecc(struct sae_data
*sae
, const u8
**pos
,
1164 u8 prime
[SAE_MAX_ECC_PRIME_LEN
];
1166 if (2 * sae
->tmp
->prime_len
> end
- *pos
) {
1167 wpa_printf(MSG_DEBUG
, "SAE: Not enough data for "
1169 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1172 if (crypto_bignum_to_bin(sae
->tmp
->prime
, prime
, sizeof(prime
),
1173 sae
->tmp
->prime_len
) < 0)
1174 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1176 /* element x and y coordinates < p */
1177 if (os_memcmp(*pos
, prime
, sae
->tmp
->prime_len
) >= 0 ||
1178 os_memcmp(*pos
+ sae
->tmp
->prime_len
, prime
,
1179 sae
->tmp
->prime_len
) >= 0) {
1180 wpa_printf(MSG_DEBUG
, "SAE: Invalid coordinates in peer "
1182 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1185 wpa_hexdump(MSG_DEBUG
, "SAE: Peer commit-element(x)",
1186 *pos
, sae
->tmp
->prime_len
);
1187 wpa_hexdump(MSG_DEBUG
, "SAE: Peer commit-element(y)",
1188 *pos
+ sae
->tmp
->prime_len
, sae
->tmp
->prime_len
);
1190 crypto_ec_point_deinit(sae
->tmp
->peer_commit_element_ecc
, 0);
1191 sae
->tmp
->peer_commit_element_ecc
=
1192 crypto_ec_point_from_bin(sae
->tmp
->ec
, *pos
);
1193 if (sae
->tmp
->peer_commit_element_ecc
== NULL
)
1194 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1196 if (!crypto_ec_point_is_on_curve(sae
->tmp
->ec
,
1197 sae
->tmp
->peer_commit_element_ecc
)) {
1198 wpa_printf(MSG_DEBUG
, "SAE: Peer element is not on curve");
1199 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1202 *pos
+= 2 * sae
->tmp
->prime_len
;
1204 return WLAN_STATUS_SUCCESS
;
1208 static u16
sae_parse_commit_element_ffc(struct sae_data
*sae
, const u8
**pos
,
1211 struct crypto_bignum
*res
, *one
;
1212 const u8 one_bin
[1] = { 0x01 };
1214 if (sae
->tmp
->prime_len
> end
- *pos
) {
1215 wpa_printf(MSG_DEBUG
, "SAE: Not enough data for "
1217 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1219 wpa_hexdump(MSG_DEBUG
, "SAE: Peer commit-element", *pos
,
1220 sae
->tmp
->prime_len
);
1222 crypto_bignum_deinit(sae
->tmp
->peer_commit_element_ffc
, 0);
1223 sae
->tmp
->peer_commit_element_ffc
=
1224 crypto_bignum_init_set(*pos
, sae
->tmp
->prime_len
);
1225 if (sae
->tmp
->peer_commit_element_ffc
== NULL
)
1226 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1227 /* 1 < element < p - 1 */
1228 res
= crypto_bignum_init();
1229 one
= crypto_bignum_init_set(one_bin
, sizeof(one_bin
));
1231 crypto_bignum_sub(sae
->tmp
->prime
, one
, res
) ||
1232 crypto_bignum_is_zero(sae
->tmp
->peer_commit_element_ffc
) ||
1233 crypto_bignum_is_one(sae
->tmp
->peer_commit_element_ffc
) ||
1234 crypto_bignum_cmp(sae
->tmp
->peer_commit_element_ffc
, res
) >= 0) {
1235 crypto_bignum_deinit(res
, 0);
1236 crypto_bignum_deinit(one
, 0);
1237 wpa_printf(MSG_DEBUG
, "SAE: Invalid peer element");
1238 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1240 crypto_bignum_deinit(one
, 0);
1242 /* scalar-op(r, ELEMENT) = 1 modulo p */
1243 if (crypto_bignum_exptmod(sae
->tmp
->peer_commit_element_ffc
,
1244 sae
->tmp
->order
, sae
->tmp
->prime
, res
) < 0 ||
1245 !crypto_bignum_is_one(res
)) {
1246 wpa_printf(MSG_DEBUG
, "SAE: Invalid peer element (scalar-op)");
1247 crypto_bignum_deinit(res
, 0);
1248 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1250 crypto_bignum_deinit(res
, 0);
1252 *pos
+= sae
->tmp
->prime_len
;
1254 return WLAN_STATUS_SUCCESS
;
1258 static u16
sae_parse_commit_element(struct sae_data
*sae
, const u8
**pos
,
1262 return sae_parse_commit_element_ffc(sae
, pos
, end
);
1263 return sae_parse_commit_element_ecc(sae
, pos
, end
);
1267 static int sae_parse_password_identifier(struct sae_data
*sae
,
1268 const u8
*pos
, const u8
*end
)
1270 wpa_hexdump(MSG_DEBUG
, "SAE: Possible elements at the end of the frame",
1272 if (!sae_is_password_id_elem(pos
, end
)) {
1273 if (sae
->tmp
->pw_id
) {
1274 wpa_printf(MSG_DEBUG
,
1275 "SAE: No Password Identifier included, but expected one (%s)",
1277 return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER
;
1279 os_free(sae
->tmp
->pw_id
);
1280 sae
->tmp
->pw_id
= NULL
;
1281 return WLAN_STATUS_SUCCESS
; /* No Password Identifier */
1284 if (sae
->tmp
->pw_id
&&
1285 (pos
[1] - 1 != (int) os_strlen(sae
->tmp
->pw_id
) ||
1286 os_memcmp(sae
->tmp
->pw_id
, pos
+ 3, pos
[1] - 1) != 0)) {
1287 wpa_printf(MSG_DEBUG
,
1288 "SAE: The included Password Identifier does not match the expected one (%s)",
1290 return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER
;
1293 os_free(sae
->tmp
->pw_id
);
1294 sae
->tmp
->pw_id
= os_malloc(pos
[1]);
1295 if (!sae
->tmp
->pw_id
)
1296 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1297 os_memcpy(sae
->tmp
->pw_id
, pos
+ 3, pos
[1] - 1);
1298 sae
->tmp
->pw_id
[pos
[1] - 1] = '\0';
1299 wpa_hexdump_ascii(MSG_DEBUG
, "SAE: Received Password Identifier",
1300 sae
->tmp
->pw_id
, pos
[1] - 1);
1301 return WLAN_STATUS_SUCCESS
;
1305 u16
sae_parse_commit(struct sae_data
*sae
, const u8
*data
, size_t len
,
1306 const u8
**token
, size_t *token_len
, int *allowed_groups
)
1308 const u8
*pos
= data
, *end
= data
+ len
;
1311 /* Check Finite Cyclic Group */
1313 return WLAN_STATUS_UNSPECIFIED_FAILURE
;
1314 res
= sae_group_allowed(sae
, allowed_groups
, WPA_GET_LE16(pos
));
1315 if (res
!= WLAN_STATUS_SUCCESS
)
1319 /* Optional Anti-Clogging Token */
1320 sae_parse_commit_token(sae
, &pos
, end
, token
, token_len
);
1323 res
= sae_parse_commit_scalar(sae
, &pos
, end
);
1324 if (res
!= WLAN_STATUS_SUCCESS
)
1327 /* commit-element */
1328 res
= sae_parse_commit_element(sae
, &pos
, end
);
1329 if (res
!= WLAN_STATUS_SUCCESS
)
1332 /* Optional Password Identifier element */
1333 res
= sae_parse_password_identifier(sae
, pos
, end
);
1334 if (res
!= WLAN_STATUS_SUCCESS
)
1338 * Check whether peer-commit-scalar and PEER-COMMIT-ELEMENT are same as
1339 * the values we sent which would be evidence of a reflection attack.
1341 if (!sae
->tmp
->own_commit_scalar
||
1342 crypto_bignum_cmp(sae
->tmp
->own_commit_scalar
,
1343 sae
->peer_commit_scalar
) != 0 ||
1345 (!sae
->tmp
->own_commit_element_ffc
||
1346 crypto_bignum_cmp(sae
->tmp
->own_commit_element_ffc
,
1347 sae
->tmp
->peer_commit_element_ffc
) != 0)) ||
1349 (!sae
->tmp
->own_commit_element_ecc
||
1350 crypto_ec_point_cmp(sae
->tmp
->ec
,
1351 sae
->tmp
->own_commit_element_ecc
,
1352 sae
->tmp
->peer_commit_element_ecc
) != 0)))
1353 return WLAN_STATUS_SUCCESS
; /* scalars/elements are different */
1356 * This is a reflection attack - return special value to trigger caller
1357 * to silently discard the frame instead of replying with a specific
1360 return SAE_SILENTLY_DISCARD
;
1364 static void sae_cn_confirm(struct sae_data
*sae
, const u8
*sc
,
1365 const struct crypto_bignum
*scalar1
,
1366 const u8
*element1
, size_t element1_len
,
1367 const struct crypto_bignum
*scalar2
,
1368 const u8
*element2
, size_t element2_len
,
1373 u8 scalar_b1
[SAE_MAX_PRIME_LEN
], scalar_b2
[SAE_MAX_PRIME_LEN
];
1376 * CN(key, X, Y, Z, ...) =
1377 * HMAC-SHA256(key, D2OS(X) || D2OS(Y) || D2OS(Z) | ...)
1378 * confirm = CN(KCK, send-confirm, commit-scalar, COMMIT-ELEMENT,
1379 * peer-commit-scalar, PEER-COMMIT-ELEMENT)
1380 * verifier = CN(KCK, peer-send-confirm, peer-commit-scalar,
1381 * PEER-COMMIT-ELEMENT, commit-scalar, COMMIT-ELEMENT)
1385 crypto_bignum_to_bin(scalar1
, scalar_b1
, sizeof(scalar_b1
),
1386 sae
->tmp
->prime_len
);
1387 addr
[1] = scalar_b1
;
1388 len
[1] = sae
->tmp
->prime_len
;
1390 len
[2] = element1_len
;
1391 crypto_bignum_to_bin(scalar2
, scalar_b2
, sizeof(scalar_b2
),
1392 sae
->tmp
->prime_len
);
1393 addr
[3] = scalar_b2
;
1394 len
[3] = sae
->tmp
->prime_len
;
1396 len
[4] = element2_len
;
1397 hmac_sha256_vector(sae
->tmp
->kck
, sizeof(sae
->tmp
->kck
), 5, addr
, len
,
1402 static void sae_cn_confirm_ecc(struct sae_data
*sae
, const u8
*sc
,
1403 const struct crypto_bignum
*scalar1
,
1404 const struct crypto_ec_point
*element1
,
1405 const struct crypto_bignum
*scalar2
,
1406 const struct crypto_ec_point
*element2
,
1409 u8 element_b1
[2 * SAE_MAX_ECC_PRIME_LEN
];
1410 u8 element_b2
[2 * SAE_MAX_ECC_PRIME_LEN
];
1412 crypto_ec_point_to_bin(sae
->tmp
->ec
, element1
, element_b1
,
1413 element_b1
+ sae
->tmp
->prime_len
);
1414 crypto_ec_point_to_bin(sae
->tmp
->ec
, element2
, element_b2
,
1415 element_b2
+ sae
->tmp
->prime_len
);
1417 sae_cn_confirm(sae
, sc
, scalar1
, element_b1
, 2 * sae
->tmp
->prime_len
,
1418 scalar2
, element_b2
, 2 * sae
->tmp
->prime_len
, confirm
);
1422 static void sae_cn_confirm_ffc(struct sae_data
*sae
, const u8
*sc
,
1423 const struct crypto_bignum
*scalar1
,
1424 const struct crypto_bignum
*element1
,
1425 const struct crypto_bignum
*scalar2
,
1426 const struct crypto_bignum
*element2
,
1429 u8 element_b1
[SAE_MAX_PRIME_LEN
];
1430 u8 element_b2
[SAE_MAX_PRIME_LEN
];
1432 crypto_bignum_to_bin(element1
, element_b1
, sizeof(element_b1
),
1433 sae
->tmp
->prime_len
);
1434 crypto_bignum_to_bin(element2
, element_b2
, sizeof(element_b2
),
1435 sae
->tmp
->prime_len
);
1437 sae_cn_confirm(sae
, sc
, scalar1
, element_b1
, sae
->tmp
->prime_len
,
1438 scalar2
, element_b2
, sae
->tmp
->prime_len
, confirm
);
1442 void sae_write_confirm(struct sae_data
*sae
, struct wpabuf
*buf
)
1446 if (sae
->tmp
== NULL
)
1450 sc
= wpabuf_put(buf
, 0);
1451 wpabuf_put_le16(buf
, sae
->send_confirm
);
1452 if (sae
->send_confirm
< 0xffff)
1453 sae
->send_confirm
++;
1456 sae_cn_confirm_ecc(sae
, sc
, sae
->tmp
->own_commit_scalar
,
1457 sae
->tmp
->own_commit_element_ecc
,
1458 sae
->peer_commit_scalar
,
1459 sae
->tmp
->peer_commit_element_ecc
,
1460 wpabuf_put(buf
, SHA256_MAC_LEN
));
1462 sae_cn_confirm_ffc(sae
, sc
, sae
->tmp
->own_commit_scalar
,
1463 sae
->tmp
->own_commit_element_ffc
,
1464 sae
->peer_commit_scalar
,
1465 sae
->tmp
->peer_commit_element_ffc
,
1466 wpabuf_put(buf
, SHA256_MAC_LEN
));
1470 int sae_check_confirm(struct sae_data
*sae
, const u8
*data
, size_t len
)
1472 u8 verifier
[SHA256_MAC_LEN
];
1474 if (len
< 2 + SHA256_MAC_LEN
) {
1475 wpa_printf(MSG_DEBUG
, "SAE: Too short confirm message");
1479 wpa_printf(MSG_DEBUG
, "SAE: peer-send-confirm %u", WPA_GET_LE16(data
));
1481 if (!sae
->tmp
|| !sae
->peer_commit_scalar
||
1482 !sae
->tmp
->own_commit_scalar
) {
1483 wpa_printf(MSG_DEBUG
, "SAE: Temporary data not yet available");
1488 if (!sae
->tmp
->peer_commit_element_ecc
||
1489 !sae
->tmp
->own_commit_element_ecc
)
1491 sae_cn_confirm_ecc(sae
, data
, sae
->peer_commit_scalar
,
1492 sae
->tmp
->peer_commit_element_ecc
,
1493 sae
->tmp
->own_commit_scalar
,
1494 sae
->tmp
->own_commit_element_ecc
,
1497 if (!sae
->tmp
->peer_commit_element_ffc
||
1498 !sae
->tmp
->own_commit_element_ffc
)
1500 sae_cn_confirm_ffc(sae
, data
, sae
->peer_commit_scalar
,
1501 sae
->tmp
->peer_commit_element_ffc
,
1502 sae
->tmp
->own_commit_scalar
,
1503 sae
->tmp
->own_commit_element_ffc
,
1507 if (os_memcmp_const(verifier
, data
+ 2, SHA256_MAC_LEN
) != 0) {
1508 wpa_printf(MSG_DEBUG
, "SAE: Confirm mismatch");
1509 wpa_hexdump(MSG_DEBUG
, "SAE: Received confirm",
1510 data
+ 2, SHA256_MAC_LEN
);
1511 wpa_hexdump(MSG_DEBUG
, "SAE: Calculated verifier",
1512 verifier
, SHA256_MAC_LEN
);
1520 const char * sae_state_txt(enum sae_state state
)