1*5b9c547cSRui Paulo /* 2*5b9c547cSRui Paulo * Simultaneous authentication of equals 3*5b9c547cSRui Paulo * Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi> 4*5b9c547cSRui Paulo * 5*5b9c547cSRui Paulo * This software may be distributed under the terms of the BSD license. 6*5b9c547cSRui Paulo * See README for more details. 7*5b9c547cSRui Paulo */ 8*5b9c547cSRui Paulo 9*5b9c547cSRui Paulo #include "includes.h" 10*5b9c547cSRui Paulo 11*5b9c547cSRui Paulo #include "common.h" 12*5b9c547cSRui Paulo #include "crypto/crypto.h" 13*5b9c547cSRui Paulo #include "crypto/sha256.h" 14*5b9c547cSRui Paulo #include "crypto/random.h" 15*5b9c547cSRui Paulo #include "crypto/dh_groups.h" 16*5b9c547cSRui Paulo #include "ieee802_11_defs.h" 17*5b9c547cSRui Paulo #include "sae.h" 18*5b9c547cSRui Paulo 19*5b9c547cSRui Paulo 20*5b9c547cSRui Paulo int sae_set_group(struct sae_data *sae, int group) 21*5b9c547cSRui Paulo { 22*5b9c547cSRui Paulo struct sae_temporary_data *tmp; 23*5b9c547cSRui Paulo 24*5b9c547cSRui Paulo sae_clear_data(sae); 25*5b9c547cSRui Paulo tmp = sae->tmp = os_zalloc(sizeof(*tmp)); 26*5b9c547cSRui Paulo if (tmp == NULL) 27*5b9c547cSRui Paulo return -1; 28*5b9c547cSRui Paulo 29*5b9c547cSRui Paulo /* First, check if this is an ECC group */ 30*5b9c547cSRui Paulo tmp->ec = crypto_ec_init(group); 31*5b9c547cSRui Paulo if (tmp->ec) { 32*5b9c547cSRui Paulo sae->group = group; 33*5b9c547cSRui Paulo tmp->prime_len = crypto_ec_prime_len(tmp->ec); 34*5b9c547cSRui Paulo tmp->prime = crypto_ec_get_prime(tmp->ec); 35*5b9c547cSRui Paulo tmp->order = crypto_ec_get_order(tmp->ec); 36*5b9c547cSRui Paulo return 0; 37*5b9c547cSRui Paulo } 38*5b9c547cSRui Paulo 39*5b9c547cSRui Paulo /* Not an ECC group, check FFC */ 40*5b9c547cSRui Paulo tmp->dh = dh_groups_get(group); 41*5b9c547cSRui Paulo if (tmp->dh) { 42*5b9c547cSRui Paulo sae->group = group; 43*5b9c547cSRui Paulo tmp->prime_len = tmp->dh->prime_len; 44*5b9c547cSRui Paulo if (tmp->prime_len > SAE_MAX_PRIME_LEN) { 45*5b9c547cSRui Paulo sae_clear_data(sae); 46*5b9c547cSRui Paulo return -1; 47*5b9c547cSRui Paulo } 48*5b9c547cSRui Paulo 49*5b9c547cSRui Paulo tmp->prime_buf = crypto_bignum_init_set(tmp->dh->prime, 50*5b9c547cSRui Paulo tmp->prime_len); 51*5b9c547cSRui Paulo if (tmp->prime_buf == NULL) { 52*5b9c547cSRui Paulo sae_clear_data(sae); 53*5b9c547cSRui Paulo return -1; 54*5b9c547cSRui Paulo } 55*5b9c547cSRui Paulo tmp->prime = tmp->prime_buf; 56*5b9c547cSRui Paulo 57*5b9c547cSRui Paulo tmp->order_buf = crypto_bignum_init_set(tmp->dh->order, 58*5b9c547cSRui Paulo tmp->dh->order_len); 59*5b9c547cSRui Paulo if (tmp->order_buf == NULL) { 60*5b9c547cSRui Paulo sae_clear_data(sae); 61*5b9c547cSRui Paulo return -1; 62*5b9c547cSRui Paulo } 63*5b9c547cSRui Paulo tmp->order = tmp->order_buf; 64*5b9c547cSRui Paulo 65*5b9c547cSRui Paulo return 0; 66*5b9c547cSRui Paulo } 67*5b9c547cSRui Paulo 68*5b9c547cSRui Paulo /* Unsupported group */ 69*5b9c547cSRui Paulo return -1; 70*5b9c547cSRui Paulo } 71*5b9c547cSRui Paulo 72*5b9c547cSRui Paulo 73*5b9c547cSRui Paulo void sae_clear_temp_data(struct sae_data *sae) 74*5b9c547cSRui Paulo { 75*5b9c547cSRui Paulo struct sae_temporary_data *tmp; 76*5b9c547cSRui Paulo if (sae == NULL || sae->tmp == NULL) 77*5b9c547cSRui Paulo return; 78*5b9c547cSRui Paulo tmp = sae->tmp; 79*5b9c547cSRui Paulo crypto_ec_deinit(tmp->ec); 80*5b9c547cSRui Paulo crypto_bignum_deinit(tmp->prime_buf, 0); 81*5b9c547cSRui Paulo crypto_bignum_deinit(tmp->order_buf, 0); 82*5b9c547cSRui Paulo crypto_bignum_deinit(tmp->sae_rand, 1); 83*5b9c547cSRui Paulo crypto_bignum_deinit(tmp->pwe_ffc, 1); 84*5b9c547cSRui Paulo crypto_bignum_deinit(tmp->own_commit_scalar, 0); 85*5b9c547cSRui Paulo crypto_bignum_deinit(tmp->own_commit_element_ffc, 0); 86*5b9c547cSRui Paulo crypto_bignum_deinit(tmp->peer_commit_element_ffc, 0); 87*5b9c547cSRui Paulo crypto_ec_point_deinit(tmp->pwe_ecc, 1); 88*5b9c547cSRui Paulo crypto_ec_point_deinit(tmp->own_commit_element_ecc, 0); 89*5b9c547cSRui Paulo crypto_ec_point_deinit(tmp->peer_commit_element_ecc, 0); 90*5b9c547cSRui Paulo wpabuf_free(tmp->anti_clogging_token); 91*5b9c547cSRui Paulo bin_clear_free(tmp, sizeof(*tmp)); 92*5b9c547cSRui Paulo sae->tmp = NULL; 93*5b9c547cSRui Paulo } 94*5b9c547cSRui Paulo 95*5b9c547cSRui Paulo 96*5b9c547cSRui Paulo void sae_clear_data(struct sae_data *sae) 97*5b9c547cSRui Paulo { 98*5b9c547cSRui Paulo if (sae == NULL) 99*5b9c547cSRui Paulo return; 100*5b9c547cSRui Paulo sae_clear_temp_data(sae); 101*5b9c547cSRui Paulo crypto_bignum_deinit(sae->peer_commit_scalar, 0); 102*5b9c547cSRui Paulo os_memset(sae, 0, sizeof(*sae)); 103*5b9c547cSRui Paulo } 104*5b9c547cSRui Paulo 105*5b9c547cSRui Paulo 106*5b9c547cSRui Paulo static void buf_shift_right(u8 *buf, size_t len, size_t bits) 107*5b9c547cSRui Paulo { 108*5b9c547cSRui Paulo size_t i; 109*5b9c547cSRui Paulo for (i = len - 1; i > 0; i--) 110*5b9c547cSRui Paulo buf[i] = (buf[i - 1] << (8 - bits)) | (buf[i] >> bits); 111*5b9c547cSRui Paulo buf[0] >>= bits; 112*5b9c547cSRui Paulo } 113*5b9c547cSRui Paulo 114*5b9c547cSRui Paulo 115*5b9c547cSRui Paulo static struct crypto_bignum * sae_get_rand(struct sae_data *sae) 116*5b9c547cSRui Paulo { 117*5b9c547cSRui Paulo u8 val[SAE_MAX_PRIME_LEN]; 118*5b9c547cSRui Paulo int iter = 0; 119*5b9c547cSRui Paulo struct crypto_bignum *bn = NULL; 120*5b9c547cSRui Paulo int order_len_bits = crypto_bignum_bits(sae->tmp->order); 121*5b9c547cSRui Paulo size_t order_len = (order_len_bits + 7) / 8; 122*5b9c547cSRui Paulo 123*5b9c547cSRui Paulo if (order_len > sizeof(val)) 124*5b9c547cSRui Paulo return NULL; 125*5b9c547cSRui Paulo 126*5b9c547cSRui Paulo for (;;) { 127*5b9c547cSRui Paulo if (iter++ > 100) 128*5b9c547cSRui Paulo return NULL; 129*5b9c547cSRui Paulo if (random_get_bytes(val, order_len) < 0) 130*5b9c547cSRui Paulo return NULL; 131*5b9c547cSRui Paulo if (order_len_bits % 8) 132*5b9c547cSRui Paulo buf_shift_right(val, order_len, 8 - order_len_bits % 8); 133*5b9c547cSRui Paulo bn = crypto_bignum_init_set(val, order_len); 134*5b9c547cSRui Paulo if (bn == NULL) 135*5b9c547cSRui Paulo return NULL; 136*5b9c547cSRui Paulo if (crypto_bignum_is_zero(bn) || 137*5b9c547cSRui Paulo crypto_bignum_is_one(bn) || 138*5b9c547cSRui Paulo crypto_bignum_cmp(bn, sae->tmp->order) >= 0) { 139*5b9c547cSRui Paulo crypto_bignum_deinit(bn, 0); 140*5b9c547cSRui Paulo continue; 141*5b9c547cSRui Paulo } 142*5b9c547cSRui Paulo break; 143*5b9c547cSRui Paulo } 144*5b9c547cSRui Paulo 145*5b9c547cSRui Paulo os_memset(val, 0, order_len); 146*5b9c547cSRui Paulo return bn; 147*5b9c547cSRui Paulo } 148*5b9c547cSRui Paulo 149*5b9c547cSRui Paulo 150*5b9c547cSRui Paulo static struct crypto_bignum * sae_get_rand_and_mask(struct sae_data *sae) 151*5b9c547cSRui Paulo { 152*5b9c547cSRui Paulo crypto_bignum_deinit(sae->tmp->sae_rand, 1); 153*5b9c547cSRui Paulo sae->tmp->sae_rand = sae_get_rand(sae); 154*5b9c547cSRui Paulo if (sae->tmp->sae_rand == NULL) 155*5b9c547cSRui Paulo return NULL; 156*5b9c547cSRui Paulo return sae_get_rand(sae); 157*5b9c547cSRui Paulo } 158*5b9c547cSRui Paulo 159*5b9c547cSRui Paulo 160*5b9c547cSRui Paulo static void sae_pwd_seed_key(const u8 *addr1, const u8 *addr2, u8 *key) 161*5b9c547cSRui Paulo { 162*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: PWE derivation - addr1=" MACSTR 163*5b9c547cSRui Paulo " addr2=" MACSTR, MAC2STR(addr1), MAC2STR(addr2)); 164*5b9c547cSRui Paulo if (os_memcmp(addr1, addr2, ETH_ALEN) > 0) { 165*5b9c547cSRui Paulo os_memcpy(key, addr1, ETH_ALEN); 166*5b9c547cSRui Paulo os_memcpy(key + ETH_ALEN, addr2, ETH_ALEN); 167*5b9c547cSRui Paulo } else { 168*5b9c547cSRui Paulo os_memcpy(key, addr2, ETH_ALEN); 169*5b9c547cSRui Paulo os_memcpy(key + ETH_ALEN, addr1, ETH_ALEN); 170*5b9c547cSRui Paulo } 171*5b9c547cSRui Paulo } 172*5b9c547cSRui Paulo 173*5b9c547cSRui Paulo 174*5b9c547cSRui Paulo static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed, 175*5b9c547cSRui Paulo struct crypto_ec_point *pwe) 176*5b9c547cSRui Paulo { 177*5b9c547cSRui Paulo u8 pwd_value[SAE_MAX_ECC_PRIME_LEN], prime[SAE_MAX_ECC_PRIME_LEN]; 178*5b9c547cSRui Paulo struct crypto_bignum *x; 179*5b9c547cSRui Paulo int y_bit; 180*5b9c547cSRui Paulo size_t bits; 181*5b9c547cSRui Paulo 182*5b9c547cSRui Paulo if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime), 183*5b9c547cSRui Paulo sae->tmp->prime_len) < 0) 184*5b9c547cSRui Paulo return -1; 185*5b9c547cSRui Paulo 186*5b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN); 187*5b9c547cSRui Paulo 188*5b9c547cSRui Paulo /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */ 189*5b9c547cSRui Paulo bits = crypto_ec_prime_len_bits(sae->tmp->ec); 190*5b9c547cSRui Paulo sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking", 191*5b9c547cSRui Paulo prime, sae->tmp->prime_len, pwd_value, bits); 192*5b9c547cSRui Paulo if (bits % 8) 193*5b9c547cSRui Paulo buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8); 194*5b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", 195*5b9c547cSRui Paulo pwd_value, sae->tmp->prime_len); 196*5b9c547cSRui Paulo 197*5b9c547cSRui Paulo if (os_memcmp(pwd_value, prime, sae->tmp->prime_len) >= 0) 198*5b9c547cSRui Paulo return 0; 199*5b9c547cSRui Paulo 200*5b9c547cSRui Paulo y_bit = pwd_seed[SHA256_MAC_LEN - 1] & 0x01; 201*5b9c547cSRui Paulo 202*5b9c547cSRui Paulo x = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len); 203*5b9c547cSRui Paulo if (x == NULL) 204*5b9c547cSRui Paulo return -1; 205*5b9c547cSRui Paulo if (crypto_ec_point_solve_y_coord(sae->tmp->ec, pwe, x, y_bit) < 0) { 206*5b9c547cSRui Paulo crypto_bignum_deinit(x, 0); 207*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: No solution found"); 208*5b9c547cSRui Paulo return 0; 209*5b9c547cSRui Paulo } 210*5b9c547cSRui Paulo crypto_bignum_deinit(x, 0); 211*5b9c547cSRui Paulo 212*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: PWE found"); 213*5b9c547cSRui Paulo 214*5b9c547cSRui Paulo return 1; 215*5b9c547cSRui Paulo } 216*5b9c547cSRui Paulo 217*5b9c547cSRui Paulo 218*5b9c547cSRui Paulo static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed, 219*5b9c547cSRui Paulo struct crypto_bignum *pwe) 220*5b9c547cSRui Paulo { 221*5b9c547cSRui Paulo u8 pwd_value[SAE_MAX_PRIME_LEN]; 222*5b9c547cSRui Paulo size_t bits = sae->tmp->prime_len * 8; 223*5b9c547cSRui Paulo u8 exp[1]; 224*5b9c547cSRui Paulo struct crypto_bignum *a, *b; 225*5b9c547cSRui Paulo int res; 226*5b9c547cSRui Paulo 227*5b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN); 228*5b9c547cSRui Paulo 229*5b9c547cSRui Paulo /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */ 230*5b9c547cSRui Paulo sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking", 231*5b9c547cSRui Paulo sae->tmp->dh->prime, sae->tmp->prime_len, pwd_value, 232*5b9c547cSRui Paulo bits); 233*5b9c547cSRui Paulo if (bits % 8) 234*5b9c547cSRui Paulo buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8); 235*5b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", pwd_value, 236*5b9c547cSRui Paulo sae->tmp->prime_len); 237*5b9c547cSRui Paulo 238*5b9c547cSRui Paulo if (os_memcmp(pwd_value, sae->tmp->dh->prime, sae->tmp->prime_len) >= 0) 239*5b9c547cSRui Paulo { 240*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: pwd-value >= p"); 241*5b9c547cSRui Paulo return 0; 242*5b9c547cSRui Paulo } 243*5b9c547cSRui Paulo 244*5b9c547cSRui Paulo /* PWE = pwd-value^((p-1)/r) modulo p */ 245*5b9c547cSRui Paulo 246*5b9c547cSRui Paulo a = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len); 247*5b9c547cSRui Paulo 248*5b9c547cSRui Paulo if (sae->tmp->dh->safe_prime) { 249*5b9c547cSRui Paulo /* 250*5b9c547cSRui Paulo * r = (p-1)/2 for the group used here, so this becomes: 251*5b9c547cSRui Paulo * PWE = pwd-value^2 modulo p 252*5b9c547cSRui Paulo */ 253*5b9c547cSRui Paulo exp[0] = 2; 254*5b9c547cSRui Paulo b = crypto_bignum_init_set(exp, sizeof(exp)); 255*5b9c547cSRui Paulo } else { 256*5b9c547cSRui Paulo /* Calculate exponent: (p-1)/r */ 257*5b9c547cSRui Paulo exp[0] = 1; 258*5b9c547cSRui Paulo b = crypto_bignum_init_set(exp, sizeof(exp)); 259*5b9c547cSRui Paulo if (b == NULL || 260*5b9c547cSRui Paulo crypto_bignum_sub(sae->tmp->prime, b, b) < 0 || 261*5b9c547cSRui Paulo crypto_bignum_div(b, sae->tmp->order, b) < 0) { 262*5b9c547cSRui Paulo crypto_bignum_deinit(b, 0); 263*5b9c547cSRui Paulo b = NULL; 264*5b9c547cSRui Paulo } 265*5b9c547cSRui Paulo } 266*5b9c547cSRui Paulo 267*5b9c547cSRui Paulo if (a == NULL || b == NULL) 268*5b9c547cSRui Paulo res = -1; 269*5b9c547cSRui Paulo else 270*5b9c547cSRui Paulo res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe); 271*5b9c547cSRui Paulo 272*5b9c547cSRui Paulo crypto_bignum_deinit(a, 0); 273*5b9c547cSRui Paulo crypto_bignum_deinit(b, 0); 274*5b9c547cSRui Paulo 275*5b9c547cSRui Paulo if (res < 0) { 276*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Failed to calculate PWE"); 277*5b9c547cSRui Paulo return -1; 278*5b9c547cSRui Paulo } 279*5b9c547cSRui Paulo 280*5b9c547cSRui Paulo /* if (PWE > 1) --> found */ 281*5b9c547cSRui Paulo if (crypto_bignum_is_zero(pwe) || crypto_bignum_is_one(pwe)) { 282*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: PWE <= 1"); 283*5b9c547cSRui Paulo return 0; 284*5b9c547cSRui Paulo } 285*5b9c547cSRui Paulo 286*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: PWE found"); 287*5b9c547cSRui Paulo return 1; 288*5b9c547cSRui Paulo } 289*5b9c547cSRui Paulo 290*5b9c547cSRui Paulo 291*5b9c547cSRui Paulo static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1, 292*5b9c547cSRui Paulo const u8 *addr2, const u8 *password, 293*5b9c547cSRui Paulo size_t password_len) 294*5b9c547cSRui Paulo { 295*5b9c547cSRui Paulo u8 counter, k = 4; 296*5b9c547cSRui Paulo u8 addrs[2 * ETH_ALEN]; 297*5b9c547cSRui Paulo const u8 *addr[2]; 298*5b9c547cSRui Paulo size_t len[2]; 299*5b9c547cSRui Paulo int found = 0; 300*5b9c547cSRui Paulo struct crypto_ec_point *pwe_tmp; 301*5b9c547cSRui Paulo 302*5b9c547cSRui Paulo if (sae->tmp->pwe_ecc == NULL) { 303*5b9c547cSRui Paulo sae->tmp->pwe_ecc = crypto_ec_point_init(sae->tmp->ec); 304*5b9c547cSRui Paulo if (sae->tmp->pwe_ecc == NULL) 305*5b9c547cSRui Paulo return -1; 306*5b9c547cSRui Paulo } 307*5b9c547cSRui Paulo pwe_tmp = crypto_ec_point_init(sae->tmp->ec); 308*5b9c547cSRui Paulo if (pwe_tmp == NULL) 309*5b9c547cSRui Paulo return -1; 310*5b9c547cSRui Paulo 311*5b9c547cSRui Paulo wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password", 312*5b9c547cSRui Paulo password, password_len); 313*5b9c547cSRui Paulo 314*5b9c547cSRui Paulo /* 315*5b9c547cSRui Paulo * H(salt, ikm) = HMAC-SHA256(salt, ikm) 316*5b9c547cSRui Paulo * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC), 317*5b9c547cSRui Paulo * password || counter) 318*5b9c547cSRui Paulo */ 319*5b9c547cSRui Paulo sae_pwd_seed_key(addr1, addr2, addrs); 320*5b9c547cSRui Paulo 321*5b9c547cSRui Paulo addr[0] = password; 322*5b9c547cSRui Paulo len[0] = password_len; 323*5b9c547cSRui Paulo addr[1] = &counter; 324*5b9c547cSRui Paulo len[1] = sizeof(counter); 325*5b9c547cSRui Paulo 326*5b9c547cSRui Paulo /* 327*5b9c547cSRui Paulo * Continue for at least k iterations to protect against side-channel 328*5b9c547cSRui Paulo * attacks that attempt to determine the number of iterations required 329*5b9c547cSRui Paulo * in the loop. 330*5b9c547cSRui Paulo */ 331*5b9c547cSRui Paulo for (counter = 1; counter < k || !found; counter++) { 332*5b9c547cSRui Paulo u8 pwd_seed[SHA256_MAC_LEN]; 333*5b9c547cSRui Paulo int res; 334*5b9c547cSRui Paulo 335*5b9c547cSRui Paulo if (counter > 200) { 336*5b9c547cSRui Paulo /* This should not happen in practice */ 337*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Failed to derive PWE"); 338*5b9c547cSRui Paulo break; 339*5b9c547cSRui Paulo } 340*5b9c547cSRui Paulo 341*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter); 342*5b9c547cSRui Paulo if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len, 343*5b9c547cSRui Paulo pwd_seed) < 0) 344*5b9c547cSRui Paulo break; 345*5b9c547cSRui Paulo res = sae_test_pwd_seed_ecc(sae, pwd_seed, 346*5b9c547cSRui Paulo found ? pwe_tmp : 347*5b9c547cSRui Paulo sae->tmp->pwe_ecc); 348*5b9c547cSRui Paulo if (res < 0) 349*5b9c547cSRui Paulo break; 350*5b9c547cSRui Paulo if (res == 0) 351*5b9c547cSRui Paulo continue; 352*5b9c547cSRui Paulo if (found) { 353*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Ignore this PWE (one was " 354*5b9c547cSRui Paulo "already selected)"); 355*5b9c547cSRui Paulo } else { 356*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Use this PWE"); 357*5b9c547cSRui Paulo found = 1; 358*5b9c547cSRui Paulo } 359*5b9c547cSRui Paulo } 360*5b9c547cSRui Paulo 361*5b9c547cSRui Paulo crypto_ec_point_deinit(pwe_tmp, 1); 362*5b9c547cSRui Paulo 363*5b9c547cSRui Paulo return found ? 0 : -1; 364*5b9c547cSRui Paulo } 365*5b9c547cSRui Paulo 366*5b9c547cSRui Paulo 367*5b9c547cSRui Paulo static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1, 368*5b9c547cSRui Paulo const u8 *addr2, const u8 *password, 369*5b9c547cSRui Paulo size_t password_len) 370*5b9c547cSRui Paulo { 371*5b9c547cSRui Paulo u8 counter; 372*5b9c547cSRui Paulo u8 addrs[2 * ETH_ALEN]; 373*5b9c547cSRui Paulo const u8 *addr[2]; 374*5b9c547cSRui Paulo size_t len[2]; 375*5b9c547cSRui Paulo int found = 0; 376*5b9c547cSRui Paulo 377*5b9c547cSRui Paulo if (sae->tmp->pwe_ffc == NULL) { 378*5b9c547cSRui Paulo sae->tmp->pwe_ffc = crypto_bignum_init(); 379*5b9c547cSRui Paulo if (sae->tmp->pwe_ffc == NULL) 380*5b9c547cSRui Paulo return -1; 381*5b9c547cSRui Paulo } 382*5b9c547cSRui Paulo 383*5b9c547cSRui Paulo wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password", 384*5b9c547cSRui Paulo password, password_len); 385*5b9c547cSRui Paulo 386*5b9c547cSRui Paulo /* 387*5b9c547cSRui Paulo * H(salt, ikm) = HMAC-SHA256(salt, ikm) 388*5b9c547cSRui Paulo * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC), 389*5b9c547cSRui Paulo * password || counter) 390*5b9c547cSRui Paulo */ 391*5b9c547cSRui Paulo sae_pwd_seed_key(addr1, addr2, addrs); 392*5b9c547cSRui Paulo 393*5b9c547cSRui Paulo addr[0] = password; 394*5b9c547cSRui Paulo len[0] = password_len; 395*5b9c547cSRui Paulo addr[1] = &counter; 396*5b9c547cSRui Paulo len[1] = sizeof(counter); 397*5b9c547cSRui Paulo 398*5b9c547cSRui Paulo for (counter = 1; !found; counter++) { 399*5b9c547cSRui Paulo u8 pwd_seed[SHA256_MAC_LEN]; 400*5b9c547cSRui Paulo int res; 401*5b9c547cSRui Paulo 402*5b9c547cSRui Paulo if (counter > 200) { 403*5b9c547cSRui Paulo /* This should not happen in practice */ 404*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Failed to derive PWE"); 405*5b9c547cSRui Paulo break; 406*5b9c547cSRui Paulo } 407*5b9c547cSRui Paulo 408*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter); 409*5b9c547cSRui Paulo if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len, 410*5b9c547cSRui Paulo pwd_seed) < 0) 411*5b9c547cSRui Paulo break; 412*5b9c547cSRui Paulo res = sae_test_pwd_seed_ffc(sae, pwd_seed, sae->tmp->pwe_ffc); 413*5b9c547cSRui Paulo if (res < 0) 414*5b9c547cSRui Paulo break; 415*5b9c547cSRui Paulo if (res > 0) { 416*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Use this PWE"); 417*5b9c547cSRui Paulo found = 1; 418*5b9c547cSRui Paulo } 419*5b9c547cSRui Paulo } 420*5b9c547cSRui Paulo 421*5b9c547cSRui Paulo return found ? 0 : -1; 422*5b9c547cSRui Paulo } 423*5b9c547cSRui Paulo 424*5b9c547cSRui Paulo 425*5b9c547cSRui Paulo static int sae_derive_commit_element_ecc(struct sae_data *sae, 426*5b9c547cSRui Paulo struct crypto_bignum *mask) 427*5b9c547cSRui Paulo { 428*5b9c547cSRui Paulo /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */ 429*5b9c547cSRui Paulo if (!sae->tmp->own_commit_element_ecc) { 430*5b9c547cSRui Paulo sae->tmp->own_commit_element_ecc = 431*5b9c547cSRui Paulo crypto_ec_point_init(sae->tmp->ec); 432*5b9c547cSRui Paulo if (!sae->tmp->own_commit_element_ecc) 433*5b9c547cSRui Paulo return -1; 434*5b9c547cSRui Paulo } 435*5b9c547cSRui Paulo 436*5b9c547cSRui Paulo if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc, mask, 437*5b9c547cSRui Paulo sae->tmp->own_commit_element_ecc) < 0 || 438*5b9c547cSRui Paulo crypto_ec_point_invert(sae->tmp->ec, 439*5b9c547cSRui Paulo sae->tmp->own_commit_element_ecc) < 0) { 440*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element"); 441*5b9c547cSRui Paulo return -1; 442*5b9c547cSRui Paulo } 443*5b9c547cSRui Paulo 444*5b9c547cSRui Paulo return 0; 445*5b9c547cSRui Paulo } 446*5b9c547cSRui Paulo 447*5b9c547cSRui Paulo 448*5b9c547cSRui Paulo static int sae_derive_commit_element_ffc(struct sae_data *sae, 449*5b9c547cSRui Paulo struct crypto_bignum *mask) 450*5b9c547cSRui Paulo { 451*5b9c547cSRui Paulo /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */ 452*5b9c547cSRui Paulo if (!sae->tmp->own_commit_element_ffc) { 453*5b9c547cSRui Paulo sae->tmp->own_commit_element_ffc = crypto_bignum_init(); 454*5b9c547cSRui Paulo if (!sae->tmp->own_commit_element_ffc) 455*5b9c547cSRui Paulo return -1; 456*5b9c547cSRui Paulo } 457*5b9c547cSRui Paulo 458*5b9c547cSRui Paulo if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, mask, sae->tmp->prime, 459*5b9c547cSRui Paulo sae->tmp->own_commit_element_ffc) < 0 || 460*5b9c547cSRui Paulo crypto_bignum_inverse(sae->tmp->own_commit_element_ffc, 461*5b9c547cSRui Paulo sae->tmp->prime, 462*5b9c547cSRui Paulo sae->tmp->own_commit_element_ffc) < 0) { 463*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element"); 464*5b9c547cSRui Paulo return -1; 465*5b9c547cSRui Paulo } 466*5b9c547cSRui Paulo 467*5b9c547cSRui Paulo return 0; 468*5b9c547cSRui Paulo } 469*5b9c547cSRui Paulo 470*5b9c547cSRui Paulo 471*5b9c547cSRui Paulo static int sae_derive_commit(struct sae_data *sae) 472*5b9c547cSRui Paulo { 473*5b9c547cSRui Paulo struct crypto_bignum *mask; 474*5b9c547cSRui Paulo int ret = -1; 475*5b9c547cSRui Paulo 476*5b9c547cSRui Paulo mask = sae_get_rand_and_mask(sae); 477*5b9c547cSRui Paulo if (mask == NULL) { 478*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Could not get rand/mask"); 479*5b9c547cSRui Paulo return -1; 480*5b9c547cSRui Paulo } 481*5b9c547cSRui Paulo 482*5b9c547cSRui Paulo /* commit-scalar = (rand + mask) modulo r */ 483*5b9c547cSRui Paulo if (!sae->tmp->own_commit_scalar) { 484*5b9c547cSRui Paulo sae->tmp->own_commit_scalar = crypto_bignum_init(); 485*5b9c547cSRui Paulo if (!sae->tmp->own_commit_scalar) 486*5b9c547cSRui Paulo goto fail; 487*5b9c547cSRui Paulo } 488*5b9c547cSRui Paulo crypto_bignum_add(sae->tmp->sae_rand, mask, 489*5b9c547cSRui Paulo sae->tmp->own_commit_scalar); 490*5b9c547cSRui Paulo crypto_bignum_mod(sae->tmp->own_commit_scalar, sae->tmp->order, 491*5b9c547cSRui Paulo sae->tmp->own_commit_scalar); 492*5b9c547cSRui Paulo 493*5b9c547cSRui Paulo if (sae->tmp->ec && sae_derive_commit_element_ecc(sae, mask) < 0) 494*5b9c547cSRui Paulo goto fail; 495*5b9c547cSRui Paulo if (sae->tmp->dh && sae_derive_commit_element_ffc(sae, mask) < 0) 496*5b9c547cSRui Paulo goto fail; 497*5b9c547cSRui Paulo 498*5b9c547cSRui Paulo ret = 0; 499*5b9c547cSRui Paulo fail: 500*5b9c547cSRui Paulo crypto_bignum_deinit(mask, 1); 501*5b9c547cSRui Paulo return ret; 502*5b9c547cSRui Paulo } 503*5b9c547cSRui Paulo 504*5b9c547cSRui Paulo 505*5b9c547cSRui Paulo int sae_prepare_commit(const u8 *addr1, const u8 *addr2, 506*5b9c547cSRui Paulo const u8 *password, size_t password_len, 507*5b9c547cSRui Paulo struct sae_data *sae) 508*5b9c547cSRui Paulo { 509*5b9c547cSRui Paulo if (sae->tmp == NULL) 510*5b9c547cSRui Paulo return -1; 511*5b9c547cSRui Paulo if (sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password, 512*5b9c547cSRui Paulo password_len) < 0) 513*5b9c547cSRui Paulo return -1; 514*5b9c547cSRui Paulo if (sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password, 515*5b9c547cSRui Paulo password_len) < 0) 516*5b9c547cSRui Paulo return -1; 517*5b9c547cSRui Paulo if (sae_derive_commit(sae) < 0) 518*5b9c547cSRui Paulo return -1; 519*5b9c547cSRui Paulo return 0; 520*5b9c547cSRui Paulo } 521*5b9c547cSRui Paulo 522*5b9c547cSRui Paulo 523*5b9c547cSRui Paulo static int sae_derive_k_ecc(struct sae_data *sae, u8 *k) 524*5b9c547cSRui Paulo { 525*5b9c547cSRui Paulo struct crypto_ec_point *K; 526*5b9c547cSRui Paulo int ret = -1; 527*5b9c547cSRui Paulo 528*5b9c547cSRui Paulo K = crypto_ec_point_init(sae->tmp->ec); 529*5b9c547cSRui Paulo if (K == NULL) 530*5b9c547cSRui Paulo goto fail; 531*5b9c547cSRui Paulo 532*5b9c547cSRui Paulo /* 533*5b9c547cSRui Paulo * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE), 534*5b9c547cSRui Paulo * PEER-COMMIT-ELEMENT))) 535*5b9c547cSRui Paulo * If K is identity element (point-at-infinity), reject 536*5b9c547cSRui Paulo * k = F(K) (= x coordinate) 537*5b9c547cSRui Paulo */ 538*5b9c547cSRui Paulo 539*5b9c547cSRui Paulo if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc, 540*5b9c547cSRui Paulo sae->peer_commit_scalar, K) < 0 || 541*5b9c547cSRui Paulo crypto_ec_point_add(sae->tmp->ec, K, 542*5b9c547cSRui Paulo sae->tmp->peer_commit_element_ecc, K) < 0 || 543*5b9c547cSRui Paulo crypto_ec_point_mul(sae->tmp->ec, K, sae->tmp->sae_rand, K) < 0 || 544*5b9c547cSRui Paulo crypto_ec_point_is_at_infinity(sae->tmp->ec, K) || 545*5b9c547cSRui Paulo crypto_ec_point_to_bin(sae->tmp->ec, K, k, NULL) < 0) { 546*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Failed to calculate K and k"); 547*5b9c547cSRui Paulo goto fail; 548*5b9c547cSRui Paulo } 549*5b9c547cSRui Paulo 550*5b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "SAE: k", k, sae->tmp->prime_len); 551*5b9c547cSRui Paulo 552*5b9c547cSRui Paulo ret = 0; 553*5b9c547cSRui Paulo fail: 554*5b9c547cSRui Paulo crypto_ec_point_deinit(K, 1); 555*5b9c547cSRui Paulo return ret; 556*5b9c547cSRui Paulo } 557*5b9c547cSRui Paulo 558*5b9c547cSRui Paulo 559*5b9c547cSRui Paulo static int sae_derive_k_ffc(struct sae_data *sae, u8 *k) 560*5b9c547cSRui Paulo { 561*5b9c547cSRui Paulo struct crypto_bignum *K; 562*5b9c547cSRui Paulo int ret = -1; 563*5b9c547cSRui Paulo 564*5b9c547cSRui Paulo K = crypto_bignum_init(); 565*5b9c547cSRui Paulo if (K == NULL) 566*5b9c547cSRui Paulo goto fail; 567*5b9c547cSRui Paulo 568*5b9c547cSRui Paulo /* 569*5b9c547cSRui Paulo * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE), 570*5b9c547cSRui Paulo * PEER-COMMIT-ELEMENT))) 571*5b9c547cSRui Paulo * If K is identity element (one), reject. 572*5b9c547cSRui Paulo * k = F(K) (= x coordinate) 573*5b9c547cSRui Paulo */ 574*5b9c547cSRui Paulo 575*5b9c547cSRui Paulo if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, sae->peer_commit_scalar, 576*5b9c547cSRui Paulo sae->tmp->prime, K) < 0 || 577*5b9c547cSRui Paulo crypto_bignum_mulmod(K, sae->tmp->peer_commit_element_ffc, 578*5b9c547cSRui Paulo sae->tmp->prime, K) < 0 || 579*5b9c547cSRui Paulo crypto_bignum_exptmod(K, sae->tmp->sae_rand, sae->tmp->prime, K) < 0 580*5b9c547cSRui Paulo || 581*5b9c547cSRui Paulo crypto_bignum_is_one(K) || 582*5b9c547cSRui Paulo crypto_bignum_to_bin(K, k, SAE_MAX_PRIME_LEN, sae->tmp->prime_len) < 583*5b9c547cSRui Paulo 0) { 584*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Failed to calculate K and k"); 585*5b9c547cSRui Paulo goto fail; 586*5b9c547cSRui Paulo } 587*5b9c547cSRui Paulo 588*5b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "SAE: k", k, sae->tmp->prime_len); 589*5b9c547cSRui Paulo 590*5b9c547cSRui Paulo ret = 0; 591*5b9c547cSRui Paulo fail: 592*5b9c547cSRui Paulo crypto_bignum_deinit(K, 1); 593*5b9c547cSRui Paulo return ret; 594*5b9c547cSRui Paulo } 595*5b9c547cSRui Paulo 596*5b9c547cSRui Paulo 597*5b9c547cSRui Paulo static int sae_derive_keys(struct sae_data *sae, const u8 *k) 598*5b9c547cSRui Paulo { 599*5b9c547cSRui Paulo u8 null_key[SAE_KEYSEED_KEY_LEN], val[SAE_MAX_PRIME_LEN]; 600*5b9c547cSRui Paulo u8 keyseed[SHA256_MAC_LEN]; 601*5b9c547cSRui Paulo u8 keys[SAE_KCK_LEN + SAE_PMK_LEN]; 602*5b9c547cSRui Paulo struct crypto_bignum *tmp; 603*5b9c547cSRui Paulo int ret = -1; 604*5b9c547cSRui Paulo 605*5b9c547cSRui Paulo tmp = crypto_bignum_init(); 606*5b9c547cSRui Paulo if (tmp == NULL) 607*5b9c547cSRui Paulo goto fail; 608*5b9c547cSRui Paulo 609*5b9c547cSRui Paulo /* keyseed = H(<0>32, k) 610*5b9c547cSRui Paulo * KCK || PMK = KDF-512(keyseed, "SAE KCK and PMK", 611*5b9c547cSRui Paulo * (commit-scalar + peer-commit-scalar) modulo r) 612*5b9c547cSRui Paulo * PMKID = L((commit-scalar + peer-commit-scalar) modulo r, 0, 128) 613*5b9c547cSRui Paulo */ 614*5b9c547cSRui Paulo 615*5b9c547cSRui Paulo os_memset(null_key, 0, sizeof(null_key)); 616*5b9c547cSRui Paulo hmac_sha256(null_key, sizeof(null_key), k, sae->tmp->prime_len, 617*5b9c547cSRui Paulo keyseed); 618*5b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "SAE: keyseed", keyseed, sizeof(keyseed)); 619*5b9c547cSRui Paulo 620*5b9c547cSRui Paulo crypto_bignum_add(sae->tmp->own_commit_scalar, sae->peer_commit_scalar, 621*5b9c547cSRui Paulo tmp); 622*5b9c547cSRui Paulo crypto_bignum_mod(tmp, sae->tmp->order, tmp); 623*5b9c547cSRui Paulo crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->prime_len); 624*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN); 625*5b9c547cSRui Paulo sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK", 626*5b9c547cSRui Paulo val, sae->tmp->prime_len, keys, sizeof(keys)); 627*5b9c547cSRui Paulo os_memset(keyseed, 0, sizeof(keyseed)); 628*5b9c547cSRui Paulo os_memcpy(sae->tmp->kck, keys, SAE_KCK_LEN); 629*5b9c547cSRui Paulo os_memcpy(sae->pmk, keys + SAE_KCK_LEN, SAE_PMK_LEN); 630*5b9c547cSRui Paulo os_memset(keys, 0, sizeof(keys)); 631*5b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "SAE: KCK", sae->tmp->kck, SAE_KCK_LEN); 632*5b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "SAE: PMK", sae->pmk, SAE_PMK_LEN); 633*5b9c547cSRui Paulo 634*5b9c547cSRui Paulo ret = 0; 635*5b9c547cSRui Paulo fail: 636*5b9c547cSRui Paulo crypto_bignum_deinit(tmp, 0); 637*5b9c547cSRui Paulo return ret; 638*5b9c547cSRui Paulo } 639*5b9c547cSRui Paulo 640*5b9c547cSRui Paulo 641*5b9c547cSRui Paulo int sae_process_commit(struct sae_data *sae) 642*5b9c547cSRui Paulo { 643*5b9c547cSRui Paulo u8 k[SAE_MAX_PRIME_LEN]; 644*5b9c547cSRui Paulo if (sae->tmp == NULL || 645*5b9c547cSRui Paulo (sae->tmp->ec && sae_derive_k_ecc(sae, k) < 0) || 646*5b9c547cSRui Paulo (sae->tmp->dh && sae_derive_k_ffc(sae, k) < 0) || 647*5b9c547cSRui Paulo sae_derive_keys(sae, k) < 0) 648*5b9c547cSRui Paulo return -1; 649*5b9c547cSRui Paulo return 0; 650*5b9c547cSRui Paulo } 651*5b9c547cSRui Paulo 652*5b9c547cSRui Paulo 653*5b9c547cSRui Paulo void sae_write_commit(struct sae_data *sae, struct wpabuf *buf, 654*5b9c547cSRui Paulo const struct wpabuf *token) 655*5b9c547cSRui Paulo { 656*5b9c547cSRui Paulo u8 *pos; 657*5b9c547cSRui Paulo 658*5b9c547cSRui Paulo if (sae->tmp == NULL) 659*5b9c547cSRui Paulo return; 660*5b9c547cSRui Paulo 661*5b9c547cSRui Paulo wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */ 662*5b9c547cSRui Paulo if (token) { 663*5b9c547cSRui Paulo wpabuf_put_buf(buf, token); 664*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "SAE: Anti-clogging token", 665*5b9c547cSRui Paulo wpabuf_head(token), wpabuf_len(token)); 666*5b9c547cSRui Paulo } 667*5b9c547cSRui Paulo pos = wpabuf_put(buf, sae->tmp->prime_len); 668*5b9c547cSRui Paulo crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos, 669*5b9c547cSRui Paulo sae->tmp->prime_len, sae->tmp->prime_len); 670*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "SAE: own commit-scalar", 671*5b9c547cSRui Paulo pos, sae->tmp->prime_len); 672*5b9c547cSRui Paulo if (sae->tmp->ec) { 673*5b9c547cSRui Paulo pos = wpabuf_put(buf, 2 * sae->tmp->prime_len); 674*5b9c547cSRui Paulo crypto_ec_point_to_bin(sae->tmp->ec, 675*5b9c547cSRui Paulo sae->tmp->own_commit_element_ecc, 676*5b9c547cSRui Paulo pos, pos + sae->tmp->prime_len); 677*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(x)", 678*5b9c547cSRui Paulo pos, sae->tmp->prime_len); 679*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(y)", 680*5b9c547cSRui Paulo pos + sae->tmp->prime_len, sae->tmp->prime_len); 681*5b9c547cSRui Paulo } else { 682*5b9c547cSRui Paulo pos = wpabuf_put(buf, sae->tmp->prime_len); 683*5b9c547cSRui Paulo crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos, 684*5b9c547cSRui Paulo sae->tmp->prime_len, sae->tmp->prime_len); 685*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "SAE: own commit-element", 686*5b9c547cSRui Paulo pos, sae->tmp->prime_len); 687*5b9c547cSRui Paulo } 688*5b9c547cSRui Paulo } 689*5b9c547cSRui Paulo 690*5b9c547cSRui Paulo 691*5b9c547cSRui Paulo u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group) 692*5b9c547cSRui Paulo { 693*5b9c547cSRui Paulo if (allowed_groups) { 694*5b9c547cSRui Paulo int i; 695*5b9c547cSRui Paulo for (i = 0; allowed_groups[i] > 0; i++) { 696*5b9c547cSRui Paulo if (allowed_groups[i] == group) 697*5b9c547cSRui Paulo break; 698*5b9c547cSRui Paulo } 699*5b9c547cSRui Paulo if (allowed_groups[i] != group) { 700*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Proposed group %u not " 701*5b9c547cSRui Paulo "enabled in the current configuration", 702*5b9c547cSRui Paulo group); 703*5b9c547cSRui Paulo return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; 704*5b9c547cSRui Paulo } 705*5b9c547cSRui Paulo } 706*5b9c547cSRui Paulo 707*5b9c547cSRui Paulo if (sae->state == SAE_COMMITTED && group != sae->group) { 708*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Do not allow group to be changed"); 709*5b9c547cSRui Paulo return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; 710*5b9c547cSRui Paulo } 711*5b9c547cSRui Paulo 712*5b9c547cSRui Paulo if (group != sae->group && sae_set_group(sae, group) < 0) { 713*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u", 714*5b9c547cSRui Paulo group); 715*5b9c547cSRui Paulo return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; 716*5b9c547cSRui Paulo } 717*5b9c547cSRui Paulo 718*5b9c547cSRui Paulo if (sae->tmp == NULL) { 719*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Group information not yet initialized"); 720*5b9c547cSRui Paulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 721*5b9c547cSRui Paulo } 722*5b9c547cSRui Paulo 723*5b9c547cSRui Paulo if (sae->tmp->dh && !allowed_groups) { 724*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Do not allow FFC group %u without " 725*5b9c547cSRui Paulo "explicit configuration enabling it", group); 726*5b9c547cSRui Paulo return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; 727*5b9c547cSRui Paulo } 728*5b9c547cSRui Paulo 729*5b9c547cSRui Paulo return WLAN_STATUS_SUCCESS; 730*5b9c547cSRui Paulo } 731*5b9c547cSRui Paulo 732*5b9c547cSRui Paulo 733*5b9c547cSRui Paulo static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos, 734*5b9c547cSRui Paulo const u8 *end, const u8 **token, 735*5b9c547cSRui Paulo size_t *token_len) 736*5b9c547cSRui Paulo { 737*5b9c547cSRui Paulo if (*pos + (sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len < end) { 738*5b9c547cSRui Paulo size_t tlen = end - (*pos + (sae->tmp->ec ? 3 : 2) * 739*5b9c547cSRui Paulo sae->tmp->prime_len); 740*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen); 741*5b9c547cSRui Paulo if (token) 742*5b9c547cSRui Paulo *token = *pos; 743*5b9c547cSRui Paulo if (token_len) 744*5b9c547cSRui Paulo *token_len = tlen; 745*5b9c547cSRui Paulo *pos += tlen; 746*5b9c547cSRui Paulo } else { 747*5b9c547cSRui Paulo if (token) 748*5b9c547cSRui Paulo *token = NULL; 749*5b9c547cSRui Paulo if (token_len) 750*5b9c547cSRui Paulo *token_len = 0; 751*5b9c547cSRui Paulo } 752*5b9c547cSRui Paulo } 753*5b9c547cSRui Paulo 754*5b9c547cSRui Paulo 755*5b9c547cSRui Paulo static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos, 756*5b9c547cSRui Paulo const u8 *end) 757*5b9c547cSRui Paulo { 758*5b9c547cSRui Paulo struct crypto_bignum *peer_scalar; 759*5b9c547cSRui Paulo 760*5b9c547cSRui Paulo if (*pos + sae->tmp->prime_len > end) { 761*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Not enough data for scalar"); 762*5b9c547cSRui Paulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 763*5b9c547cSRui Paulo } 764*5b9c547cSRui Paulo 765*5b9c547cSRui Paulo peer_scalar = crypto_bignum_init_set(*pos, sae->tmp->prime_len); 766*5b9c547cSRui Paulo if (peer_scalar == NULL) 767*5b9c547cSRui Paulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 768*5b9c547cSRui Paulo 769*5b9c547cSRui Paulo /* 770*5b9c547cSRui Paulo * IEEE Std 802.11-2012, 11.3.8.6.1: If there is a protocol instance for 771*5b9c547cSRui Paulo * the peer and it is in Authenticated state, the new Commit Message 772*5b9c547cSRui Paulo * shall be dropped if the peer-scalar is identical to the one used in 773*5b9c547cSRui Paulo * the existing protocol instance. 774*5b9c547cSRui Paulo */ 775*5b9c547cSRui Paulo if (sae->state == SAE_ACCEPTED && sae->peer_commit_scalar && 776*5b9c547cSRui Paulo crypto_bignum_cmp(sae->peer_commit_scalar, peer_scalar) == 0) { 777*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Do not accept re-use of previous " 778*5b9c547cSRui Paulo "peer-commit-scalar"); 779*5b9c547cSRui Paulo crypto_bignum_deinit(peer_scalar, 0); 780*5b9c547cSRui Paulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 781*5b9c547cSRui Paulo } 782*5b9c547cSRui Paulo 783*5b9c547cSRui Paulo /* 0 < scalar < r */ 784*5b9c547cSRui Paulo if (crypto_bignum_is_zero(peer_scalar) || 785*5b9c547cSRui Paulo crypto_bignum_cmp(peer_scalar, sae->tmp->order) >= 0) { 786*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Invalid peer scalar"); 787*5b9c547cSRui Paulo crypto_bignum_deinit(peer_scalar, 0); 788*5b9c547cSRui Paulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 789*5b9c547cSRui Paulo } 790*5b9c547cSRui Paulo 791*5b9c547cSRui Paulo 792*5b9c547cSRui Paulo crypto_bignum_deinit(sae->peer_commit_scalar, 0); 793*5b9c547cSRui Paulo sae->peer_commit_scalar = peer_scalar; 794*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-scalar", 795*5b9c547cSRui Paulo *pos, sae->tmp->prime_len); 796*5b9c547cSRui Paulo *pos += sae->tmp->prime_len; 797*5b9c547cSRui Paulo 798*5b9c547cSRui Paulo return WLAN_STATUS_SUCCESS; 799*5b9c547cSRui Paulo } 800*5b9c547cSRui Paulo 801*5b9c547cSRui Paulo 802*5b9c547cSRui Paulo static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos, 803*5b9c547cSRui Paulo const u8 *end) 804*5b9c547cSRui Paulo { 805*5b9c547cSRui Paulo u8 prime[SAE_MAX_ECC_PRIME_LEN]; 806*5b9c547cSRui Paulo 807*5b9c547cSRui Paulo if (pos + 2 * sae->tmp->prime_len > end) { 808*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Not enough data for " 809*5b9c547cSRui Paulo "commit-element"); 810*5b9c547cSRui Paulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 811*5b9c547cSRui Paulo } 812*5b9c547cSRui Paulo 813*5b9c547cSRui Paulo if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime), 814*5b9c547cSRui Paulo sae->tmp->prime_len) < 0) 815*5b9c547cSRui Paulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 816*5b9c547cSRui Paulo 817*5b9c547cSRui Paulo /* element x and y coordinates < p */ 818*5b9c547cSRui Paulo if (os_memcmp(pos, prime, sae->tmp->prime_len) >= 0 || 819*5b9c547cSRui Paulo os_memcmp(pos + sae->tmp->prime_len, prime, 820*5b9c547cSRui Paulo sae->tmp->prime_len) >= 0) { 821*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Invalid coordinates in peer " 822*5b9c547cSRui Paulo "element"); 823*5b9c547cSRui Paulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 824*5b9c547cSRui Paulo } 825*5b9c547cSRui Paulo 826*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(x)", 827*5b9c547cSRui Paulo pos, sae->tmp->prime_len); 828*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(y)", 829*5b9c547cSRui Paulo pos + sae->tmp->prime_len, sae->tmp->prime_len); 830*5b9c547cSRui Paulo 831*5b9c547cSRui Paulo crypto_ec_point_deinit(sae->tmp->peer_commit_element_ecc, 0); 832*5b9c547cSRui Paulo sae->tmp->peer_commit_element_ecc = 833*5b9c547cSRui Paulo crypto_ec_point_from_bin(sae->tmp->ec, pos); 834*5b9c547cSRui Paulo if (sae->tmp->peer_commit_element_ecc == NULL) 835*5b9c547cSRui Paulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 836*5b9c547cSRui Paulo 837*5b9c547cSRui Paulo if (!crypto_ec_point_is_on_curve(sae->tmp->ec, 838*5b9c547cSRui Paulo sae->tmp->peer_commit_element_ecc)) { 839*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Peer element is not on curve"); 840*5b9c547cSRui Paulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 841*5b9c547cSRui Paulo } 842*5b9c547cSRui Paulo 843*5b9c547cSRui Paulo return WLAN_STATUS_SUCCESS; 844*5b9c547cSRui Paulo } 845*5b9c547cSRui Paulo 846*5b9c547cSRui Paulo 847*5b9c547cSRui Paulo static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos, 848*5b9c547cSRui Paulo const u8 *end) 849*5b9c547cSRui Paulo { 850*5b9c547cSRui Paulo struct crypto_bignum *res; 851*5b9c547cSRui Paulo 852*5b9c547cSRui Paulo if (pos + sae->tmp->prime_len > end) { 853*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Not enough data for " 854*5b9c547cSRui Paulo "commit-element"); 855*5b9c547cSRui Paulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 856*5b9c547cSRui Paulo } 857*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element", pos, 858*5b9c547cSRui Paulo sae->tmp->prime_len); 859*5b9c547cSRui Paulo 860*5b9c547cSRui Paulo crypto_bignum_deinit(sae->tmp->peer_commit_element_ffc, 0); 861*5b9c547cSRui Paulo sae->tmp->peer_commit_element_ffc = 862*5b9c547cSRui Paulo crypto_bignum_init_set(pos, sae->tmp->prime_len); 863*5b9c547cSRui Paulo if (sae->tmp->peer_commit_element_ffc == NULL) 864*5b9c547cSRui Paulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 865*5b9c547cSRui Paulo if (crypto_bignum_is_zero(sae->tmp->peer_commit_element_ffc) || 866*5b9c547cSRui Paulo crypto_bignum_is_one(sae->tmp->peer_commit_element_ffc) || 867*5b9c547cSRui Paulo crypto_bignum_cmp(sae->tmp->peer_commit_element_ffc, 868*5b9c547cSRui Paulo sae->tmp->prime) >= 0) { 869*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Invalid peer element"); 870*5b9c547cSRui Paulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 871*5b9c547cSRui Paulo } 872*5b9c547cSRui Paulo 873*5b9c547cSRui Paulo /* scalar-op(r, ELEMENT) = 1 modulo p */ 874*5b9c547cSRui Paulo res = crypto_bignum_init(); 875*5b9c547cSRui Paulo if (res == NULL || 876*5b9c547cSRui Paulo crypto_bignum_exptmod(sae->tmp->peer_commit_element_ffc, 877*5b9c547cSRui Paulo sae->tmp->order, sae->tmp->prime, res) < 0 || 878*5b9c547cSRui Paulo !crypto_bignum_is_one(res)) { 879*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Invalid peer element (scalar-op)"); 880*5b9c547cSRui Paulo crypto_bignum_deinit(res, 0); 881*5b9c547cSRui Paulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 882*5b9c547cSRui Paulo } 883*5b9c547cSRui Paulo crypto_bignum_deinit(res, 0); 884*5b9c547cSRui Paulo 885*5b9c547cSRui Paulo return WLAN_STATUS_SUCCESS; 886*5b9c547cSRui Paulo } 887*5b9c547cSRui Paulo 888*5b9c547cSRui Paulo 889*5b9c547cSRui Paulo static u16 sae_parse_commit_element(struct sae_data *sae, const u8 *pos, 890*5b9c547cSRui Paulo const u8 *end) 891*5b9c547cSRui Paulo { 892*5b9c547cSRui Paulo if (sae->tmp->dh) 893*5b9c547cSRui Paulo return sae_parse_commit_element_ffc(sae, pos, end); 894*5b9c547cSRui Paulo return sae_parse_commit_element_ecc(sae, pos, end); 895*5b9c547cSRui Paulo } 896*5b9c547cSRui Paulo 897*5b9c547cSRui Paulo 898*5b9c547cSRui Paulo u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len, 899*5b9c547cSRui Paulo const u8 **token, size_t *token_len, int *allowed_groups) 900*5b9c547cSRui Paulo { 901*5b9c547cSRui Paulo const u8 *pos = data, *end = data + len; 902*5b9c547cSRui Paulo u16 res; 903*5b9c547cSRui Paulo 904*5b9c547cSRui Paulo /* Check Finite Cyclic Group */ 905*5b9c547cSRui Paulo if (pos + 2 > end) 906*5b9c547cSRui Paulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 907*5b9c547cSRui Paulo res = sae_group_allowed(sae, allowed_groups, WPA_GET_LE16(pos)); 908*5b9c547cSRui Paulo if (res != WLAN_STATUS_SUCCESS) 909*5b9c547cSRui Paulo return res; 910*5b9c547cSRui Paulo pos += 2; 911*5b9c547cSRui Paulo 912*5b9c547cSRui Paulo /* Optional Anti-Clogging Token */ 913*5b9c547cSRui Paulo sae_parse_commit_token(sae, &pos, end, token, token_len); 914*5b9c547cSRui Paulo 915*5b9c547cSRui Paulo /* commit-scalar */ 916*5b9c547cSRui Paulo res = sae_parse_commit_scalar(sae, &pos, end); 917*5b9c547cSRui Paulo if (res != WLAN_STATUS_SUCCESS) 918*5b9c547cSRui Paulo return res; 919*5b9c547cSRui Paulo 920*5b9c547cSRui Paulo /* commit-element */ 921*5b9c547cSRui Paulo return sae_parse_commit_element(sae, pos, end); 922*5b9c547cSRui Paulo } 923*5b9c547cSRui Paulo 924*5b9c547cSRui Paulo 925*5b9c547cSRui Paulo static void sae_cn_confirm(struct sae_data *sae, const u8 *sc, 926*5b9c547cSRui Paulo const struct crypto_bignum *scalar1, 927*5b9c547cSRui Paulo const u8 *element1, size_t element1_len, 928*5b9c547cSRui Paulo const struct crypto_bignum *scalar2, 929*5b9c547cSRui Paulo const u8 *element2, size_t element2_len, 930*5b9c547cSRui Paulo u8 *confirm) 931*5b9c547cSRui Paulo { 932*5b9c547cSRui Paulo const u8 *addr[5]; 933*5b9c547cSRui Paulo size_t len[5]; 934*5b9c547cSRui Paulo u8 scalar_b1[SAE_MAX_PRIME_LEN], scalar_b2[SAE_MAX_PRIME_LEN]; 935*5b9c547cSRui Paulo 936*5b9c547cSRui Paulo /* Confirm 937*5b9c547cSRui Paulo * CN(key, X, Y, Z, ...) = 938*5b9c547cSRui Paulo * HMAC-SHA256(key, D2OS(X) || D2OS(Y) || D2OS(Z) | ...) 939*5b9c547cSRui Paulo * confirm = CN(KCK, send-confirm, commit-scalar, COMMIT-ELEMENT, 940*5b9c547cSRui Paulo * peer-commit-scalar, PEER-COMMIT-ELEMENT) 941*5b9c547cSRui Paulo * verifier = CN(KCK, peer-send-confirm, peer-commit-scalar, 942*5b9c547cSRui Paulo * PEER-COMMIT-ELEMENT, commit-scalar, COMMIT-ELEMENT) 943*5b9c547cSRui Paulo */ 944*5b9c547cSRui Paulo addr[0] = sc; 945*5b9c547cSRui Paulo len[0] = 2; 946*5b9c547cSRui Paulo crypto_bignum_to_bin(scalar1, scalar_b1, sizeof(scalar_b1), 947*5b9c547cSRui Paulo sae->tmp->prime_len); 948*5b9c547cSRui Paulo addr[1] = scalar_b1; 949*5b9c547cSRui Paulo len[1] = sae->tmp->prime_len; 950*5b9c547cSRui Paulo addr[2] = element1; 951*5b9c547cSRui Paulo len[2] = element1_len; 952*5b9c547cSRui Paulo crypto_bignum_to_bin(scalar2, scalar_b2, sizeof(scalar_b2), 953*5b9c547cSRui Paulo sae->tmp->prime_len); 954*5b9c547cSRui Paulo addr[3] = scalar_b2; 955*5b9c547cSRui Paulo len[3] = sae->tmp->prime_len; 956*5b9c547cSRui Paulo addr[4] = element2; 957*5b9c547cSRui Paulo len[4] = element2_len; 958*5b9c547cSRui Paulo hmac_sha256_vector(sae->tmp->kck, sizeof(sae->tmp->kck), 5, addr, len, 959*5b9c547cSRui Paulo confirm); 960*5b9c547cSRui Paulo } 961*5b9c547cSRui Paulo 962*5b9c547cSRui Paulo 963*5b9c547cSRui Paulo static void sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc, 964*5b9c547cSRui Paulo const struct crypto_bignum *scalar1, 965*5b9c547cSRui Paulo const struct crypto_ec_point *element1, 966*5b9c547cSRui Paulo const struct crypto_bignum *scalar2, 967*5b9c547cSRui Paulo const struct crypto_ec_point *element2, 968*5b9c547cSRui Paulo u8 *confirm) 969*5b9c547cSRui Paulo { 970*5b9c547cSRui Paulo u8 element_b1[2 * SAE_MAX_ECC_PRIME_LEN]; 971*5b9c547cSRui Paulo u8 element_b2[2 * SAE_MAX_ECC_PRIME_LEN]; 972*5b9c547cSRui Paulo 973*5b9c547cSRui Paulo crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1, 974*5b9c547cSRui Paulo element_b1 + sae->tmp->prime_len); 975*5b9c547cSRui Paulo crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2, 976*5b9c547cSRui Paulo element_b2 + sae->tmp->prime_len); 977*5b9c547cSRui Paulo 978*5b9c547cSRui Paulo sae_cn_confirm(sae, sc, scalar1, element_b1, 2 * sae->tmp->prime_len, 979*5b9c547cSRui Paulo scalar2, element_b2, 2 * sae->tmp->prime_len, confirm); 980*5b9c547cSRui Paulo } 981*5b9c547cSRui Paulo 982*5b9c547cSRui Paulo 983*5b9c547cSRui Paulo static void sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc, 984*5b9c547cSRui Paulo const struct crypto_bignum *scalar1, 985*5b9c547cSRui Paulo const struct crypto_bignum *element1, 986*5b9c547cSRui Paulo const struct crypto_bignum *scalar2, 987*5b9c547cSRui Paulo const struct crypto_bignum *element2, 988*5b9c547cSRui Paulo u8 *confirm) 989*5b9c547cSRui Paulo { 990*5b9c547cSRui Paulo u8 element_b1[SAE_MAX_PRIME_LEN]; 991*5b9c547cSRui Paulo u8 element_b2[SAE_MAX_PRIME_LEN]; 992*5b9c547cSRui Paulo 993*5b9c547cSRui Paulo crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1), 994*5b9c547cSRui Paulo sae->tmp->prime_len); 995*5b9c547cSRui Paulo crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2), 996*5b9c547cSRui Paulo sae->tmp->prime_len); 997*5b9c547cSRui Paulo 998*5b9c547cSRui Paulo sae_cn_confirm(sae, sc, scalar1, element_b1, sae->tmp->prime_len, 999*5b9c547cSRui Paulo scalar2, element_b2, sae->tmp->prime_len, confirm); 1000*5b9c547cSRui Paulo } 1001*5b9c547cSRui Paulo 1002*5b9c547cSRui Paulo 1003*5b9c547cSRui Paulo void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf) 1004*5b9c547cSRui Paulo { 1005*5b9c547cSRui Paulo const u8 *sc; 1006*5b9c547cSRui Paulo 1007*5b9c547cSRui Paulo if (sae->tmp == NULL) 1008*5b9c547cSRui Paulo return; 1009*5b9c547cSRui Paulo 1010*5b9c547cSRui Paulo /* Send-Confirm */ 1011*5b9c547cSRui Paulo sc = wpabuf_put(buf, 0); 1012*5b9c547cSRui Paulo wpabuf_put_le16(buf, sae->send_confirm); 1013*5b9c547cSRui Paulo sae->send_confirm++; 1014*5b9c547cSRui Paulo 1015*5b9c547cSRui Paulo if (sae->tmp->ec) 1016*5b9c547cSRui Paulo sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar, 1017*5b9c547cSRui Paulo sae->tmp->own_commit_element_ecc, 1018*5b9c547cSRui Paulo sae->peer_commit_scalar, 1019*5b9c547cSRui Paulo sae->tmp->peer_commit_element_ecc, 1020*5b9c547cSRui Paulo wpabuf_put(buf, SHA256_MAC_LEN)); 1021*5b9c547cSRui Paulo else 1022*5b9c547cSRui Paulo sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar, 1023*5b9c547cSRui Paulo sae->tmp->own_commit_element_ffc, 1024*5b9c547cSRui Paulo sae->peer_commit_scalar, 1025*5b9c547cSRui Paulo sae->tmp->peer_commit_element_ffc, 1026*5b9c547cSRui Paulo wpabuf_put(buf, SHA256_MAC_LEN)); 1027*5b9c547cSRui Paulo } 1028*5b9c547cSRui Paulo 1029*5b9c547cSRui Paulo 1030*5b9c547cSRui Paulo int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len) 1031*5b9c547cSRui Paulo { 1032*5b9c547cSRui Paulo u8 verifier[SHA256_MAC_LEN]; 1033*5b9c547cSRui Paulo 1034*5b9c547cSRui Paulo if (len < 2 + SHA256_MAC_LEN) { 1035*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Too short confirm message"); 1036*5b9c547cSRui Paulo return -1; 1037*5b9c547cSRui Paulo } 1038*5b9c547cSRui Paulo 1039*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data)); 1040*5b9c547cSRui Paulo 1041*5b9c547cSRui Paulo if (sae->tmp == NULL) { 1042*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Temporary data not yet available"); 1043*5b9c547cSRui Paulo return -1; 1044*5b9c547cSRui Paulo } 1045*5b9c547cSRui Paulo 1046*5b9c547cSRui Paulo if (sae->tmp->ec) 1047*5b9c547cSRui Paulo sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar, 1048*5b9c547cSRui Paulo sae->tmp->peer_commit_element_ecc, 1049*5b9c547cSRui Paulo sae->tmp->own_commit_scalar, 1050*5b9c547cSRui Paulo sae->tmp->own_commit_element_ecc, 1051*5b9c547cSRui Paulo verifier); 1052*5b9c547cSRui Paulo else 1053*5b9c547cSRui Paulo sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar, 1054*5b9c547cSRui Paulo sae->tmp->peer_commit_element_ffc, 1055*5b9c547cSRui Paulo sae->tmp->own_commit_scalar, 1056*5b9c547cSRui Paulo sae->tmp->own_commit_element_ffc, 1057*5b9c547cSRui Paulo verifier); 1058*5b9c547cSRui Paulo 1059*5b9c547cSRui Paulo if (os_memcmp_const(verifier, data + 2, SHA256_MAC_LEN) != 0) { 1060*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch"); 1061*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "SAE: Received confirm", 1062*5b9c547cSRui Paulo data + 2, SHA256_MAC_LEN); 1063*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "SAE: Calculated verifier", 1064*5b9c547cSRui Paulo verifier, SHA256_MAC_LEN); 1065*5b9c547cSRui Paulo return -1; 1066*5b9c547cSRui Paulo } 1067*5b9c547cSRui Paulo 1068*5b9c547cSRui Paulo return 0; 1069*5b9c547cSRui Paulo } 1070