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

Generated by: LCOV version 1.10