SAE: Use const_time selection for PWE in FFC
This is an initial step towards making the FFC case use strictly constant time operations similarly to the ECC case. sae_test_pwd_seed_ffc() does not yet have constant time behavior, though. This is related to CVE-2019-9494. Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
This commit is contained in:
parent
90839597cc
commit
f8f20717f8
1 changed files with 35 additions and 18 deletions
|
@ -612,17 +612,28 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
|
|||
const u8 *addr2, const u8 *password,
|
||||
size_t password_len, const char *identifier)
|
||||
{
|
||||
u8 counter, k;
|
||||
u8 counter, k, sel_counter = 0;
|
||||
u8 addrs[2 * ETH_ALEN];
|
||||
const u8 *addr[3];
|
||||
size_t len[3];
|
||||
size_t num_elem;
|
||||
int found = 0;
|
||||
struct crypto_bignum *pwe = NULL;
|
||||
u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
|
||||
* mask */
|
||||
u8 mask;
|
||||
struct crypto_bignum *pwe;
|
||||
size_t prime_len = sae->tmp->prime_len * 8;
|
||||
u8 *pwe_buf;
|
||||
|
||||
crypto_bignum_deinit(sae->tmp->pwe_ffc, 1);
|
||||
sae->tmp->pwe_ffc = NULL;
|
||||
|
||||
/* Allocate a buffer to maintain selected and candidate PWE for constant
|
||||
* time selection. */
|
||||
pwe_buf = os_zalloc(prime_len * 2);
|
||||
pwe = crypto_bignum_init();
|
||||
if (!pwe_buf || !pwe)
|
||||
goto fail;
|
||||
|
||||
wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
|
||||
password, password_len);
|
||||
|
||||
|
@ -661,27 +672,33 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
|
|||
if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem,
|
||||
addr, len, pwd_seed) < 0)
|
||||
break;
|
||||
if (!pwe) {
|
||||
pwe = crypto_bignum_init();
|
||||
if (!pwe)
|
||||
break;
|
||||
}
|
||||
res = sae_test_pwd_seed_ffc(sae, pwd_seed, pwe);
|
||||
/* res is -1 for fatal failure, 0 if a valid PWE was not found,
|
||||
* or 1 if a valid PWE was found. */
|
||||
if (res < 0)
|
||||
break;
|
||||
if (res > 0) {
|
||||
found = 1;
|
||||
if (!sae->tmp->pwe_ffc) {
|
||||
wpa_printf(MSG_DEBUG, "SAE: Use this PWE");
|
||||
sae->tmp->pwe_ffc = pwe;
|
||||
pwe = NULL;
|
||||
}
|
||||
}
|
||||
/* Store the candidate PWE into the second half of pwe_buf and
|
||||
* the selected PWE in the beginning of pwe_buf using constant
|
||||
* time selection. */
|
||||
if (crypto_bignum_to_bin(pwe, pwe_buf + prime_len, prime_len,
|
||||
prime_len) < 0)
|
||||
break;
|
||||
const_time_select_bin(found, pwe_buf, pwe_buf + prime_len,
|
||||
prime_len, pwe_buf);
|
||||
sel_counter = const_time_select_u8(found, sel_counter, counter);
|
||||
mask = const_time_eq_u8(res, 1);
|
||||
found = const_time_select_u8(found, found, mask);
|
||||
}
|
||||
|
||||
crypto_bignum_deinit(pwe, 1);
|
||||
if (!found)
|
||||
goto fail;
|
||||
|
||||
return found ? 0 : -1;
|
||||
wpa_printf(MSG_DEBUG, "SAE: Use PWE from counter = %02u", sel_counter);
|
||||
sae->tmp->pwe_ffc = crypto_bignum_init_set(pwe_buf, prime_len);
|
||||
fail:
|
||||
crypto_bignum_deinit(pwe, 1);
|
||||
bin_clear_free(pwe_buf, prime_len * 2);
|
||||
return sae->tmp->pwe_ffc ? 0 : -1;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue