LCOV - code coverage report
Current view: top level - src/common - sae.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1401264779 Lines: 466 570 81.8 %
Date: 2014-05-28 Functions: 32 32 100.0 %

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

Generated by: LCOV version 1.10