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

Generated by: LCOV version 1.10