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 1443382998 Lines: 603 681 88.5 %
Date: 2015-09-27 Functions: 35 35 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Simultaneous authentication of equals
       3             :  * Copyright (c) 2012-2015, 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         188 : int sae_set_group(struct sae_data *sae, int group)
      21             : {
      22             :         struct sae_temporary_data *tmp;
      23             : 
      24         188 :         sae_clear_data(sae);
      25         188 :         tmp = sae->tmp = os_zalloc(sizeof(*tmp));
      26         188 :         if (tmp == NULL)
      27           1 :                 return -1;
      28             : 
      29             :         /* First, check if this is an ECC group */
      30         187 :         tmp->ec = crypto_ec_init(group);
      31         187 :         if (tmp->ec) {
      32         141 :                 sae->group = group;
      33         141 :                 tmp->prime_len = crypto_ec_prime_len(tmp->ec);
      34         141 :                 tmp->prime = crypto_ec_get_prime(tmp->ec);
      35         141 :                 tmp->order = crypto_ec_get_order(tmp->ec);
      36         141 :                 return 0;
      37             :         }
      38             : 
      39             :         /* Not an ECC group, check FFC */
      40          46 :         tmp->dh = dh_groups_get(group);
      41          46 :         if (tmp->dh) {
      42          45 :                 sae->group = group;
      43          45 :                 tmp->prime_len = tmp->dh->prime_len;
      44          45 :                 if (tmp->prime_len > SAE_MAX_PRIME_LEN) {
      45           0 :                         sae_clear_data(sae);
      46           0 :                         return -1;
      47             :                 }
      48             : 
      49          45 :                 tmp->prime_buf = crypto_bignum_init_set(tmp->dh->prime,
      50          45 :                                                         tmp->prime_len);
      51          45 :                 if (tmp->prime_buf == NULL) {
      52           0 :                         sae_clear_data(sae);
      53           0 :                         return -1;
      54             :                 }
      55          45 :                 tmp->prime = tmp->prime_buf;
      56             : 
      57          45 :                 tmp->order_buf = crypto_bignum_init_set(tmp->dh->order,
      58          45 :                                                         tmp->dh->order_len);
      59          45 :                 if (tmp->order_buf == NULL) {
      60           0 :                         sae_clear_data(sae);
      61           0 :                         return -1;
      62             :                 }
      63          45 :                 tmp->order = tmp->order_buf;
      64             : 
      65          45 :                 return 0;
      66             :         }
      67             : 
      68             :         /* Unsupported group */
      69           1 :         return -1;
      70             : }
      71             : 
      72             : 
      73        7978 : void sae_clear_temp_data(struct sae_data *sae)
      74             : {
      75             :         struct sae_temporary_data *tmp;
      76        7978 :         if (sae == NULL || sae->tmp == NULL)
      77       15769 :                 return;
      78         187 :         tmp = sae->tmp;
      79         187 :         crypto_ec_deinit(tmp->ec);
      80         187 :         crypto_bignum_deinit(tmp->prime_buf, 0);
      81         187 :         crypto_bignum_deinit(tmp->order_buf, 0);
      82         187 :         crypto_bignum_deinit(tmp->sae_rand, 1);
      83         187 :         crypto_bignum_deinit(tmp->pwe_ffc, 1);
      84         187 :         crypto_bignum_deinit(tmp->own_commit_scalar, 0);
      85         187 :         crypto_bignum_deinit(tmp->own_commit_element_ffc, 0);
      86         187 :         crypto_bignum_deinit(tmp->peer_commit_element_ffc, 0);
      87         187 :         crypto_ec_point_deinit(tmp->pwe_ecc, 1);
      88         187 :         crypto_ec_point_deinit(tmp->own_commit_element_ecc, 0);
      89         187 :         crypto_ec_point_deinit(tmp->peer_commit_element_ecc, 0);
      90         187 :         wpabuf_free(tmp->anti_clogging_token);
      91         187 :         bin_clear_free(tmp, sizeof(*tmp));
      92         187 :         sae->tmp = NULL;
      93             : }
      94             : 
      95             : 
      96       10849 : void sae_clear_data(struct sae_data *sae)
      97             : {
      98       10849 :         if (sae == NULL)
      99       13780 :                 return;
     100        7918 :         sae_clear_temp_data(sae);
     101        7918 :         crypto_bignum_deinit(sae->peer_commit_scalar, 0);
     102        7918 :         os_memset(sae, 0, sizeof(*sae));
     103             : }
     104             : 
     105             : 
     106         205 : static void buf_shift_right(u8 *buf, size_t len, size_t bits)
     107             : {
     108             :         size_t i;
     109       19474 :         for (i = len - 1; i > 0; i--)
     110       19269 :                 buf[i] = (buf[i - 1] << (8 - bits)) | (buf[i] >> bits);
     111         205 :         buf[0] >>= bits;
     112         205 : }
     113             : 
     114             : 
     115         373 : static struct crypto_bignum * sae_get_rand(struct sae_data *sae)
     116             : {
     117             :         u8 val[SAE_MAX_PRIME_LEN];
     118         373 :         int iter = 0;
     119         373 :         struct crypto_bignum *bn = NULL;
     120         373 :         int order_len_bits = crypto_bignum_bits(sae->tmp->order);
     121         373 :         size_t order_len = (order_len_bits + 7) / 8;
     122             : 
     123         373 :         if (order_len > sizeof(val))
     124           0 :                 return NULL;
     125             : 
     126             :         for (;;) {
     127         390 :                 if (iter++ > 100 || random_get_bytes(val, order_len) < 0)
     128           1 :                         return NULL;
     129         389 :                 if (order_len_bits % 8)
     130          40 :                         buf_shift_right(val, order_len, 8 - order_len_bits % 8);
     131         389 :                 bn = crypto_bignum_init_set(val, order_len);
     132         389 :                 if (bn == NULL)
     133           0 :                         return NULL;
     134         778 :                 if (crypto_bignum_is_zero(bn) ||
     135         778 :                     crypto_bignum_is_one(bn) ||
     136         389 :                     crypto_bignum_cmp(bn, sae->tmp->order) >= 0) {
     137          17 :                         crypto_bignum_deinit(bn, 0);
     138          17 :                         continue;
     139             :                 }
     140         372 :                 break;
     141          17 :         }
     142             : 
     143         372 :         os_memset(val, 0, order_len);
     144         372 :         return bn;
     145             : }
     146             : 
     147             : 
     148         187 : static struct crypto_bignum * sae_get_rand_and_mask(struct sae_data *sae)
     149             : {
     150         187 :         crypto_bignum_deinit(sae->tmp->sae_rand, 1);
     151         187 :         sae->tmp->sae_rand = sae_get_rand(sae);
     152         187 :         if (sae->tmp->sae_rand == NULL)
     153           1 :                 return NULL;
     154         186 :         return sae_get_rand(sae);
     155             : }
     156             : 
     157             : 
     158         188 : static void sae_pwd_seed_key(const u8 *addr1, const u8 *addr2, u8 *key)
     159             : {
     160        2256 :         wpa_printf(MSG_DEBUG, "SAE: PWE derivation - addr1=" MACSTR
     161        2256 :                    " addr2=" MACSTR, MAC2STR(addr1), MAC2STR(addr2));
     162         188 :         if (os_memcmp(addr1, addr2, ETH_ALEN) > 0) {
     163          78 :                 os_memcpy(key, addr1, ETH_ALEN);
     164          78 :                 os_memcpy(key + ETH_ALEN, addr2, ETH_ALEN);
     165             :         } else {
     166         110 :                 os_memcpy(key, addr2, ETH_ALEN);
     167         110 :                 os_memcpy(key + ETH_ALEN, addr1, ETH_ALEN);
     168             :         }
     169         188 : }
     170             : 
     171             : 
     172             : static struct crypto_bignum *
     173        5713 : get_rand_1_to_p_1(const u8 *prime, size_t prime_len, size_t prime_bits,
     174             :                   int *r_odd)
     175             : {
     176             :         for (;;) {
     177             :                 struct crypto_bignum *r;
     178             :                 u8 tmp[SAE_MAX_ECC_PRIME_LEN];
     179             : 
     180        5713 :                 if (random_get_bytes(tmp, prime_len) < 0)
     181           2 :                         break;
     182        5712 :                 if (prime_bits % 8)
     183          80 :                         buf_shift_right(tmp, prime_len, 8 - prime_bits % 8);
     184        5712 :                 if (os_memcmp(tmp, prime, prime_len) >= 0)
     185         202 :                         continue;
     186        5611 :                 r = crypto_bignum_init_set(tmp, prime_len);
     187        5611 :                 if (!r)
     188           0 :                         break;
     189        5611 :                 if (crypto_bignum_is_zero(r)) {
     190           0 :                         crypto_bignum_deinit(r, 0);
     191           0 :                         continue;
     192             :                 }
     193             : 
     194        5611 :                 *r_odd = tmp[prime_len - 1] & 0x01;
     195        5611 :                 return r;
     196         101 :         }
     197             : 
     198           1 :         return NULL;
     199             : }
     200             : 
     201             : 
     202        5612 : static int is_quadratic_residue_blind(struct sae_data *sae,
     203             :                                       const u8 *prime, size_t bits,
     204             :                                       const struct crypto_bignum *qr,
     205             :                                       const struct crypto_bignum *qnr,
     206             :                                       const struct crypto_bignum *y_sqr)
     207             : {
     208             :         struct crypto_bignum *r, *num;
     209        5612 :         int r_odd, check, res = -1;
     210             : 
     211             :         /*
     212             :          * Use the blinding technique to mask y_sqr while determining
     213             :          * whether it is a quadratic residue modulo p to avoid leaking
     214             :          * timing information while determining the Legendre symbol.
     215             :          *
     216             :          * v = y_sqr
     217             :          * r = a random number between 1 and p-1, inclusive
     218             :          * num = (v * r * r) modulo p
     219             :          */
     220        5612 :         r = get_rand_1_to_p_1(prime, sae->tmp->prime_len, bits, &r_odd);
     221        5612 :         if (!r)
     222           1 :                 return -1;
     223             : 
     224        5611 :         num = crypto_bignum_init();
     225       11222 :         if (!num ||
     226       11222 :             crypto_bignum_mulmod(y_sqr, r, sae->tmp->prime, num) < 0 ||
     227        5611 :             crypto_bignum_mulmod(num, r, sae->tmp->prime, num) < 0)
     228             :                 goto fail;
     229             : 
     230        5611 :         if (r_odd) {
     231             :                 /*
     232             :                  * num = (num * qr) module p
     233             :                  * LGR(num, p) = 1 ==> quadratic residue
     234             :                  */
     235        2763 :                 if (crypto_bignum_mulmod(num, qr, sae->tmp->prime, num) < 0)
     236           0 :                         goto fail;
     237        2763 :                 check = 1;
     238             :         } else {
     239             :                 /*
     240             :                  * num = (num * qnr) module p
     241             :                  * LGR(num, p) = -1 ==> quadratic residue
     242             :                  */
     243        2848 :                 if (crypto_bignum_mulmod(num, qnr, sae->tmp->prime, num) < 0)
     244           0 :                         goto fail;
     245        2848 :                 check = -1;
     246             :         }
     247             : 
     248        5611 :         res = crypto_bignum_legendre(num, sae->tmp->prime);
     249        5611 :         if (res == -2) {
     250           0 :                 res = -1;
     251           0 :                 goto fail;
     252             :         }
     253        5611 :         res = res == check;
     254             : fail:
     255        5611 :         crypto_bignum_deinit(num, 1);
     256        5611 :         crypto_bignum_deinit(r, 1);
     257        5611 :         return res;
     258             : }
     259             : 
     260             : 
     261        5721 : static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
     262             :                                  const u8 *prime,
     263             :                                  const struct crypto_bignum *qr,
     264             :                                  const struct crypto_bignum *qnr,
     265             :                                  struct crypto_bignum **ret_x_cand)
     266             : {
     267             :         u8 pwd_value[SAE_MAX_ECC_PRIME_LEN];
     268             :         struct crypto_bignum *y_sqr, *x_cand;
     269             :         int res;
     270             :         size_t bits;
     271             : 
     272        5721 :         *ret_x_cand = NULL;
     273             : 
     274        5721 :         wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
     275             : 
     276             :         /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
     277        5721 :         bits = crypto_ec_prime_len_bits(sae->tmp->ec);
     278        5721 :         sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
     279        5721 :                         prime, sae->tmp->prime_len, pwd_value, bits);
     280        5721 :         if (bits % 8)
     281          80 :                 buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8);
     282        5721 :         wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
     283        5721 :                         pwd_value, sae->tmp->prime_len);
     284             : 
     285        5721 :         if (os_memcmp(pwd_value, prime, sae->tmp->prime_len) >= 0)
     286         109 :                 return 0;
     287             : 
     288        5612 :         x_cand = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
     289        5612 :         if (!x_cand)
     290           0 :                 return -1;
     291        5612 :         y_sqr = crypto_ec_point_compute_y_sqr(sae->tmp->ec, x_cand);
     292        5612 :         if (!y_sqr) {
     293           0 :                 crypto_bignum_deinit(x_cand, 1);
     294           0 :                 return -1;
     295             :         }
     296             : 
     297        5612 :         res = is_quadratic_residue_blind(sae, prime, bits, qr, qnr, y_sqr);
     298        5612 :         crypto_bignum_deinit(y_sqr, 1);
     299        5612 :         if (res <= 0) {
     300        2803 :                 crypto_bignum_deinit(x_cand, 1);
     301        2803 :                 return res;
     302             :         }
     303             : 
     304        2809 :         *ret_x_cand = x_cand;
     305        2809 :         return 1;
     306             : }
     307             : 
     308             : 
     309          48 : static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
     310             :                                  struct crypto_bignum *pwe)
     311             : {
     312             :         u8 pwd_value[SAE_MAX_PRIME_LEN];
     313          48 :         size_t bits = sae->tmp->prime_len * 8;
     314             :         u8 exp[1];
     315             :         struct crypto_bignum *a, *b;
     316             :         int res;
     317             : 
     318          48 :         wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
     319             : 
     320             :         /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
     321          96 :         sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
     322          96 :                         sae->tmp->dh->prime, sae->tmp->prime_len, pwd_value,
     323             :                         bits);
     324          48 :         if (bits % 8)
     325           0 :                 buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8);
     326          48 :         wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", pwd_value,
     327          48 :                         sae->tmp->prime_len);
     328             : 
     329          48 :         if (os_memcmp(pwd_value, sae->tmp->dh->prime, sae->tmp->prime_len) >= 0)
     330             :         {
     331           4 :                 wpa_printf(MSG_DEBUG, "SAE: pwd-value >= p");
     332           4 :                 return 0;
     333             :         }
     334             : 
     335             :         /* PWE = pwd-value^((p-1)/r) modulo p */
     336             : 
     337          44 :         a = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
     338             : 
     339          44 :         if (sae->tmp->dh->safe_prime) {
     340             :                 /*
     341             :                  * r = (p-1)/2 for the group used here, so this becomes:
     342             :                  * PWE = pwd-value^2 modulo p
     343             :                  */
     344          18 :                 exp[0] = 2;
     345          18 :                 b = crypto_bignum_init_set(exp, sizeof(exp));
     346             :         } else {
     347             :                 /* Calculate exponent: (p-1)/r */
     348          26 :                 exp[0] = 1;
     349          26 :                 b = crypto_bignum_init_set(exp, sizeof(exp));
     350          52 :                 if (b == NULL ||
     351          52 :                     crypto_bignum_sub(sae->tmp->prime, b, b) < 0 ||
     352          26 :                     crypto_bignum_div(b, sae->tmp->order, b) < 0) {
     353           0 :                         crypto_bignum_deinit(b, 0);
     354           0 :                         b = NULL;
     355             :                 }
     356             :         }
     357             : 
     358          44 :         if (a == NULL || b == NULL)
     359           0 :                 res = -1;
     360             :         else
     361          44 :                 res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe);
     362             : 
     363          44 :         crypto_bignum_deinit(a, 0);
     364          44 :         crypto_bignum_deinit(b, 0);
     365             : 
     366          44 :         if (res < 0) {
     367           0 :                 wpa_printf(MSG_DEBUG, "SAE: Failed to calculate PWE");
     368           0 :                 return -1;
     369             :         }
     370             : 
     371             :         /* if (PWE > 1) --> found */
     372          44 :         if (crypto_bignum_is_zero(pwe) || crypto_bignum_is_one(pwe)) {
     373           0 :                 wpa_printf(MSG_DEBUG, "SAE: PWE <= 1");
     374           0 :                 return 0;
     375             :         }
     376             : 
     377          44 :         wpa_printf(MSG_DEBUG, "SAE: PWE found");
     378          44 :         return 1;
     379             : }
     380             : 
     381             : 
     382         145 : static int get_random_qr_qnr(const u8 *prime, size_t prime_len,
     383             :                              const struct crypto_bignum *prime_bn,
     384             :                              size_t prime_bits, struct crypto_bignum **qr,
     385             :                              struct crypto_bignum **qnr)
     386             : {
     387         145 :         *qr = NULL;
     388         145 :         *qnr = NULL;
     389             : 
     390         742 :         while (!(*qr) || !(*qnr)) {
     391             :                 u8 tmp[SAE_MAX_ECC_PRIME_LEN];
     392             :                 struct crypto_bignum *q;
     393             :                 int res;
     394             : 
     395         453 :                 if (random_get_bytes(tmp, prime_len) < 0)
     396           2 :                         break;
     397         452 :                 if (prime_bits % 8)
     398           5 :                         buf_shift_right(tmp, prime_len, 8 - prime_bits % 8);
     399         452 :                 if (os_memcmp(tmp, prime, prime_len) >= 0)
     400          16 :                         continue;
     401         436 :                 q = crypto_bignum_init_set(tmp, prime_len);
     402         436 :                 if (!q)
     403           0 :                         break;
     404         436 :                 res = crypto_bignum_legendre(q, prime_bn);
     405             : 
     406         436 :                 if (res == 1 && !(*qr))
     407         144 :                         *qr = q;
     408         292 :                 else if (res == -1 && !(*qnr))
     409         144 :                         *qnr = q;
     410             :                 else
     411         148 :                         crypto_bignum_deinit(q, 0);
     412             :         }
     413             : 
     414         145 :         return (*qr && *qnr) ? 0 : -1;
     415             : }
     416             : 
     417             : 
     418         146 : static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
     419             :                               const u8 *addr2, const u8 *password,
     420             :                               size_t password_len)
     421             : {
     422         146 :         u8 counter, k = 40;
     423             :         u8 addrs[2 * ETH_ALEN];
     424             :         const u8 *addr[2];
     425             :         size_t len[2];
     426             :         u8 dummy_password[32];
     427             :         size_t dummy_password_len;
     428         146 :         int pwd_seed_odd = 0;
     429             :         u8 prime[SAE_MAX_ECC_PRIME_LEN];
     430             :         size_t prime_len;
     431         146 :         struct crypto_bignum *x = NULL, *qr, *qnr;
     432             :         size_t bits;
     433             :         int res;
     434             : 
     435         146 :         dummy_password_len = password_len;
     436         146 :         if (dummy_password_len > sizeof(dummy_password))
     437           2 :                 dummy_password_len = sizeof(dummy_password);
     438         146 :         if (random_get_bytes(dummy_password, dummy_password_len) < 0)
     439           1 :                 return -1;
     440             : 
     441         145 :         prime_len = sae->tmp->prime_len;
     442         145 :         if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
     443             :                                  prime_len) < 0)
     444           0 :                 return -1;
     445         145 :         bits = crypto_ec_prime_len_bits(sae->tmp->ec);
     446             : 
     447             :         /*
     448             :          * Create a random quadratic residue (qr) and quadratic non-residue
     449             :          * (qnr) modulo p for blinding purposes during the loop.
     450             :          */
     451         145 :         if (get_random_qr_qnr(prime, prime_len, sae->tmp->prime, bits,
     452             :                               &qr, &qnr) < 0)
     453           1 :                 return -1;
     454             : 
     455         144 :         wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
     456             :                               password, password_len);
     457             : 
     458             :         /*
     459             :          * H(salt, ikm) = HMAC-SHA256(salt, ikm)
     460             :          * base = password
     461             :          * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
     462             :          *              base || counter)
     463             :          */
     464         144 :         sae_pwd_seed_key(addr1, addr2, addrs);
     465             : 
     466         144 :         addr[0] = password;
     467         144 :         len[0] = password_len;
     468         144 :         addr[1] = &counter;
     469         144 :         len[1] = sizeof(counter);
     470             : 
     471             :         /*
     472             :          * Continue for at least k iterations to protect against side-channel
     473             :          * attacks that attempt to determine the number of iterations required
     474             :          * in the loop.
     475             :          */
     476       11728 :         for (counter = 1; counter <= k || !x; counter++) {
     477             :                 u8 pwd_seed[SHA256_MAC_LEN];
     478             :                 struct crypto_bignum *x_cand;
     479             : 
     480        5721 :                 if (counter > 200) {
     481             :                         /* This should not happen in practice */
     482           0 :                         wpa_printf(MSG_DEBUG, "SAE: Failed to derive PWE");
     483           0 :                         break;
     484             :                 }
     485             : 
     486        5721 :                 wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
     487        5721 :                 if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len,
     488             :                                        pwd_seed) < 0)
     489           0 :                         break;
     490             : 
     491        5721 :                 res = sae_test_pwd_seed_ecc(sae, pwd_seed,
     492             :                                             prime, qr, qnr, &x_cand);
     493        5721 :                 if (res < 0)
     494           1 :                         goto fail;
     495        5720 :                 if (res > 0 && !x) {
     496         143 :                         wpa_printf(MSG_DEBUG,
     497             :                                    "SAE: Selected pwd-seed with counter %u",
     498             :                                    counter);
     499         143 :                         x = x_cand;
     500         143 :                         pwd_seed_odd = pwd_seed[SHA256_MAC_LEN - 1] & 0x01;
     501         143 :                         os_memset(pwd_seed, 0, sizeof(pwd_seed));
     502             : 
     503             :                         /*
     504             :                          * Use a dummy password for the following rounds, if
     505             :                          * any.
     506             :                          */
     507         143 :                         addr[0] = dummy_password;
     508         143 :                         len[0] = dummy_password_len;
     509        5577 :                 } else if (res > 0) {
     510        2666 :                         crypto_bignum_deinit(x_cand, 1);
     511             :                 }
     512             :         }
     513             : 
     514         143 :         if (!x) {
     515           0 :                 wpa_printf(MSG_DEBUG, "SAE: Could not generate PWE");
     516           0 :                 res = -1;
     517           0 :                 goto fail;
     518             :         }
     519             : 
     520         143 :         if (!sae->tmp->pwe_ecc)
     521         135 :                 sae->tmp->pwe_ecc = crypto_ec_point_init(sae->tmp->ec);
     522         143 :         if (!sae->tmp->pwe_ecc)
     523           0 :                 res = -1;
     524             :         else
     525         143 :                 res = crypto_ec_point_solve_y_coord(sae->tmp->ec,
     526         143 :                                                     sae->tmp->pwe_ecc, x,
     527             :                                                     pwd_seed_odd);
     528         143 :         crypto_bignum_deinit(x, 1);
     529         143 :         if (res < 0) {
     530             :                 /*
     531             :                  * This should not happen since we already checked that there
     532             :                  * is a result.
     533             :                  */
     534           0 :                 wpa_printf(MSG_DEBUG, "SAE: Could not solve y");
     535             :         }
     536             : 
     537             : fail:
     538         144 :         crypto_bignum_deinit(qr, 0);
     539         144 :         crypto_bignum_deinit(qnr, 0);
     540             : 
     541         144 :         return res;
     542             : }
     543             : 
     544             : 
     545          44 : static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
     546             :                               const u8 *addr2, const u8 *password,
     547             :                               size_t password_len)
     548             : {
     549             :         u8 counter;
     550             :         u8 addrs[2 * ETH_ALEN];
     551             :         const u8 *addr[2];
     552             :         size_t len[2];
     553          44 :         int found = 0;
     554             : 
     555          44 :         if (sae->tmp->pwe_ffc == NULL) {
     556          44 :                 sae->tmp->pwe_ffc = crypto_bignum_init();
     557          44 :                 if (sae->tmp->pwe_ffc == NULL)
     558           0 :                         return -1;
     559             :         }
     560             : 
     561          44 :         wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
     562             :                               password, password_len);
     563             : 
     564             :         /*
     565             :          * H(salt, ikm) = HMAC-SHA256(salt, ikm)
     566             :          * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
     567             :          *              password || counter)
     568             :          */
     569          44 :         sae_pwd_seed_key(addr1, addr2, addrs);
     570             : 
     571          44 :         addr[0] = password;
     572          44 :         len[0] = password_len;
     573          44 :         addr[1] = &counter;
     574          44 :         len[1] = sizeof(counter);
     575             : 
     576         184 :         for (counter = 1; !found; counter++) {
     577             :                 u8 pwd_seed[SHA256_MAC_LEN];
     578             :                 int res;
     579             : 
     580          48 :                 if (counter > 200) {
     581             :                         /* This should not happen in practice */
     582           0 :                         wpa_printf(MSG_DEBUG, "SAE: Failed to derive PWE");
     583           0 :                         break;
     584             :                 }
     585             : 
     586          48 :                 wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
     587          48 :                 if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len,
     588             :                                        pwd_seed) < 0)
     589           0 :                         break;
     590          48 :                 res = sae_test_pwd_seed_ffc(sae, pwd_seed, sae->tmp->pwe_ffc);
     591          48 :                 if (res < 0)
     592           0 :                         break;
     593          48 :                 if (res > 0) {
     594          44 :                         wpa_printf(MSG_DEBUG, "SAE: Use this PWE");
     595          44 :                         found = 1;
     596             :                 }
     597             :         }
     598             : 
     599          44 :         return found ? 0 : -1;
     600             : }
     601             : 
     602             : 
     603         142 : static int sae_derive_commit_element_ecc(struct sae_data *sae,
     604             :                                          struct crypto_bignum *mask)
     605             : {
     606             :         /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */
     607         142 :         if (!sae->tmp->own_commit_element_ecc) {
     608         268 :                 sae->tmp->own_commit_element_ecc =
     609         134 :                         crypto_ec_point_init(sae->tmp->ec);
     610         134 :                 if (!sae->tmp->own_commit_element_ecc)
     611           0 :                         return -1;
     612             :         }
     613             : 
     614         142 :         if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc, mask,
     615         284 :                                 sae->tmp->own_commit_element_ecc) < 0 ||
     616         142 :             crypto_ec_point_invert(sae->tmp->ec,
     617         142 :                                    sae->tmp->own_commit_element_ecc) < 0) {
     618           0 :                 wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element");
     619           0 :                 return -1;
     620             :         }
     621             : 
     622         142 :         return 0;
     623             : }
     624             : 
     625             : 
     626          44 : static int sae_derive_commit_element_ffc(struct sae_data *sae,
     627             :                                          struct crypto_bignum *mask)
     628             : {
     629             :         /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */
     630          44 :         if (!sae->tmp->own_commit_element_ffc) {
     631          44 :                 sae->tmp->own_commit_element_ffc = crypto_bignum_init();
     632          44 :                 if (!sae->tmp->own_commit_element_ffc)
     633           0 :                         return -1;
     634             :         }
     635             : 
     636          44 :         if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, mask, sae->tmp->prime,
     637          88 :                                   sae->tmp->own_commit_element_ffc) < 0 ||
     638          88 :             crypto_bignum_inverse(sae->tmp->own_commit_element_ffc,
     639          44 :                                   sae->tmp->prime,
     640          44 :                                   sae->tmp->own_commit_element_ffc) < 0) {
     641           0 :                 wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element");
     642           0 :                 return -1;
     643             :         }
     644             : 
     645          44 :         return 0;
     646             : }
     647             : 
     648             : 
     649         187 : static int sae_derive_commit(struct sae_data *sae)
     650             : {
     651             :         struct crypto_bignum *mask;
     652         187 :         int ret = -1;
     653         187 :         unsigned int counter = 0;
     654             : 
     655             :         do {
     656         187 :                 counter++;
     657         187 :                 if (counter > 100) {
     658             :                         /*
     659             :                          * This cannot really happen in practice if the random
     660             :                          * number generator is working. Anyway, to avoid even a
     661             :                          * theoretical infinite loop, break out after 100
     662             :                          * attemps.
     663             :                          */
     664           0 :                         return -1;
     665             :                 }
     666             : 
     667         187 :                 mask = sae_get_rand_and_mask(sae);
     668         187 :                 if (mask == NULL) {
     669           1 :                         wpa_printf(MSG_DEBUG, "SAE: Could not get rand/mask");
     670           1 :                         return -1;
     671             :                 }
     672             : 
     673             :                 /* commit-scalar = (rand + mask) modulo r */
     674         186 :                 if (!sae->tmp->own_commit_scalar) {
     675         178 :                         sae->tmp->own_commit_scalar = crypto_bignum_init();
     676         178 :                         if (!sae->tmp->own_commit_scalar)
     677           0 :                                 goto fail;
     678             :                 }
     679         186 :                 crypto_bignum_add(sae->tmp->sae_rand, mask,
     680         186 :                                   sae->tmp->own_commit_scalar);
     681         186 :                 crypto_bignum_mod(sae->tmp->own_commit_scalar, sae->tmp->order,
     682         186 :                                   sae->tmp->own_commit_scalar);
     683         372 :         } while (crypto_bignum_is_zero(sae->tmp->own_commit_scalar) ||
     684         186 :                  crypto_bignum_is_one(sae->tmp->own_commit_scalar));
     685             : 
     686         372 :         if ((sae->tmp->ec && sae_derive_commit_element_ecc(sae, mask) < 0) ||
     687         230 :             (sae->tmp->dh && sae_derive_commit_element_ffc(sae, mask) < 0))
     688             :                 goto fail;
     689             : 
     690         186 :         ret = 0;
     691             : fail:
     692         186 :         crypto_bignum_deinit(mask, 1);
     693         186 :         return ret;
     694             : }
     695             : 
     696             : 
     697         190 : int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
     698             :                        const u8 *password, size_t password_len,
     699             :                        struct sae_data *sae)
     700             : {
     701         380 :         if (sae->tmp == NULL ||
     702         336 :             (sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password,
     703         187 :                                                 password_len) < 0) ||
     704         231 :             (sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password,
     705         187 :                                                 password_len) < 0) ||
     706         187 :             sae_derive_commit(sae) < 0)
     707           4 :                 return -1;
     708         186 :         return 0;
     709             : }
     710             : 
     711             : 
     712         118 : static int sae_derive_k_ecc(struct sae_data *sae, u8 *k)
     713             : {
     714             :         struct crypto_ec_point *K;
     715         118 :         int ret = -1;
     716             : 
     717         118 :         K = crypto_ec_point_init(sae->tmp->ec);
     718         118 :         if (K == NULL)
     719           0 :                 goto fail;
     720             : 
     721             :         /*
     722             :          * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE),
     723             :          *                                        PEER-COMMIT-ELEMENT)))
     724             :          * If K is identity element (point-at-infinity), reject
     725             :          * k = F(K) (= x coordinate)
     726             :          */
     727             : 
     728         118 :         if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc,
     729         236 :                                 sae->peer_commit_scalar, K) < 0 ||
     730         118 :             crypto_ec_point_add(sae->tmp->ec, K,
     731         236 :                                 sae->tmp->peer_commit_element_ecc, K) < 0 ||
     732         236 :             crypto_ec_point_mul(sae->tmp->ec, K, sae->tmp->sae_rand, K) < 0 ||
     733         236 :             crypto_ec_point_is_at_infinity(sae->tmp->ec, K) ||
     734         118 :             crypto_ec_point_to_bin(sae->tmp->ec, K, k, NULL) < 0) {
     735           0 :                 wpa_printf(MSG_DEBUG, "SAE: Failed to calculate K and k");
     736           0 :                 goto fail;
     737             :         }
     738             : 
     739         118 :         wpa_hexdump_key(MSG_DEBUG, "SAE: k", k, sae->tmp->prime_len);
     740             : 
     741         118 :         ret = 0;
     742             : fail:
     743         118 :         crypto_ec_point_deinit(K, 1);
     744         118 :         return ret;
     745             : }
     746             : 
     747             : 
     748          37 : static int sae_derive_k_ffc(struct sae_data *sae, u8 *k)
     749             : {
     750             :         struct crypto_bignum *K;
     751          37 :         int ret = -1;
     752             : 
     753          37 :         K = crypto_bignum_init();
     754          37 :         if (K == NULL)
     755           0 :                 goto fail;
     756             : 
     757             :         /*
     758             :          * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE),
     759             :          *                                        PEER-COMMIT-ELEMENT)))
     760             :          * If K is identity element (one), reject.
     761             :          * k = F(K) (= x coordinate)
     762             :          */
     763             : 
     764          37 :         if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, sae->peer_commit_scalar,
     765          74 :                                   sae->tmp->prime, K) < 0 ||
     766          37 :             crypto_bignum_mulmod(K, sae->tmp->peer_commit_element_ffc,
     767          74 :                                  sae->tmp->prime, K) < 0 ||
     768          37 :             crypto_bignum_exptmod(K, sae->tmp->sae_rand, sae->tmp->prime, K) < 0
     769          37 :             ||
     770          74 :             crypto_bignum_is_one(K) ||
     771          37 :             crypto_bignum_to_bin(K, k, SAE_MAX_PRIME_LEN, sae->tmp->prime_len) <
     772             :             0) {
     773           0 :                 wpa_printf(MSG_DEBUG, "SAE: Failed to calculate K and k");
     774           0 :                 goto fail;
     775             :         }
     776             : 
     777          37 :         wpa_hexdump_key(MSG_DEBUG, "SAE: k", k, sae->tmp->prime_len);
     778             : 
     779          37 :         ret = 0;
     780             : fail:
     781          37 :         crypto_bignum_deinit(K, 1);
     782          37 :         return ret;
     783             : }
     784             : 
     785             : 
     786         155 : static int sae_derive_keys(struct sae_data *sae, const u8 *k)
     787             : {
     788             :         u8 null_key[SAE_KEYSEED_KEY_LEN], val[SAE_MAX_PRIME_LEN];
     789             :         u8 keyseed[SHA256_MAC_LEN];
     790             :         u8 keys[SAE_KCK_LEN + SAE_PMK_LEN];
     791             :         struct crypto_bignum *tmp;
     792         155 :         int ret = -1;
     793             : 
     794         155 :         tmp = crypto_bignum_init();
     795         155 :         if (tmp == NULL)
     796           0 :                 goto fail;
     797             : 
     798             :         /* keyseed = H(<0>32, k)
     799             :          * KCK || PMK = KDF-512(keyseed, "SAE KCK and PMK",
     800             :          *                      (commit-scalar + peer-commit-scalar) modulo r)
     801             :          * PMKID = L((commit-scalar + peer-commit-scalar) modulo r, 0, 128)
     802             :          */
     803             : 
     804         155 :         os_memset(null_key, 0, sizeof(null_key));
     805         155 :         hmac_sha256(null_key, sizeof(null_key), k, sae->tmp->prime_len,
     806             :                     keyseed);
     807         155 :         wpa_hexdump_key(MSG_DEBUG, "SAE: keyseed", keyseed, sizeof(keyseed));
     808             : 
     809         155 :         crypto_bignum_add(sae->tmp->own_commit_scalar, sae->peer_commit_scalar,
     810             :                           tmp);
     811         155 :         crypto_bignum_mod(tmp, sae->tmp->order, tmp);
     812         155 :         crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->prime_len);
     813         155 :         wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
     814         155 :         sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
     815         155 :                    val, sae->tmp->prime_len, keys, sizeof(keys));
     816         155 :         os_memset(keyseed, 0, sizeof(keyseed));
     817         155 :         os_memcpy(sae->tmp->kck, keys, SAE_KCK_LEN);
     818         155 :         os_memcpy(sae->pmk, keys + SAE_KCK_LEN, SAE_PMK_LEN);
     819         155 :         os_memset(keys, 0, sizeof(keys));
     820         155 :         wpa_hexdump_key(MSG_DEBUG, "SAE: KCK", sae->tmp->kck, SAE_KCK_LEN);
     821         155 :         wpa_hexdump_key(MSG_DEBUG, "SAE: PMK", sae->pmk, SAE_PMK_LEN);
     822             : 
     823         155 :         ret = 0;
     824             : fail:
     825         155 :         crypto_bignum_deinit(tmp, 0);
     826         155 :         return ret;
     827             : }
     828             : 
     829             : 
     830         155 : int sae_process_commit(struct sae_data *sae)
     831             : {
     832             :         u8 k[SAE_MAX_PRIME_LEN];
     833         310 :         if (sae->tmp == NULL ||
     834         428 :             (sae->tmp->ec && sae_derive_k_ecc(sae, k) < 0) ||
     835         347 :             (sae->tmp->dh && sae_derive_k_ffc(sae, k) < 0) ||
     836         155 :             sae_derive_keys(sae, k) < 0)
     837           0 :                 return -1;
     838         155 :         return 0;
     839             : }
     840             : 
     841             : 
     842         190 : void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
     843             :                       const struct wpabuf *token)
     844             : {
     845             :         u8 *pos;
     846             : 
     847         190 :         if (sae->tmp == NULL)
     848         190 :                 return;
     849             : 
     850         190 :         wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */
     851         190 :         if (token) {
     852           5 :                 wpabuf_put_buf(buf, token);
     853           5 :                 wpa_hexdump(MSG_DEBUG, "SAE: Anti-clogging token",
     854             :                             wpabuf_head(token), wpabuf_len(token));
     855             :         }
     856         190 :         pos = wpabuf_put(buf, sae->tmp->prime_len);
     857         380 :         crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos,
     858         380 :                              sae->tmp->prime_len, sae->tmp->prime_len);
     859         190 :         wpa_hexdump(MSG_DEBUG, "SAE: own commit-scalar",
     860         190 :                     pos, sae->tmp->prime_len);
     861         190 :         if (sae->tmp->ec) {
     862         146 :                 pos = wpabuf_put(buf, 2 * sae->tmp->prime_len);
     863         292 :                 crypto_ec_point_to_bin(sae->tmp->ec,
     864         146 :                                        sae->tmp->own_commit_element_ecc,
     865         146 :                                        pos, pos + sae->tmp->prime_len);
     866         146 :                 wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(x)",
     867         146 :                             pos, sae->tmp->prime_len);
     868         292 :                 wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(y)",
     869         292 :                             pos + sae->tmp->prime_len, sae->tmp->prime_len);
     870             :         } else {
     871          44 :                 pos = wpabuf_put(buf, sae->tmp->prime_len);
     872          88 :                 crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos,
     873          88 :                                      sae->tmp->prime_len, sae->tmp->prime_len);
     874          44 :                 wpa_hexdump(MSG_DEBUG, "SAE: own commit-element",
     875          44 :                             pos, sae->tmp->prime_len);
     876             :         }
     877             : }
     878             : 
     879             : 
     880         193 : u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group)
     881             : {
     882         193 :         if (allowed_groups) {
     883             :                 int i;
     884         291 :                 for (i = 0; allowed_groups[i] > 0; i++) {
     885         278 :                         if (allowed_groups[i] == group)
     886         120 :                                 break;
     887             :                 }
     888         133 :                 if (allowed_groups[i] != group) {
     889          13 :                         wpa_printf(MSG_DEBUG, "SAE: Proposed group %u not "
     890             :                                    "enabled in the current configuration",
     891             :                                    group);
     892          13 :                         return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
     893             :                 }
     894             :         }
     895             : 
     896         180 :         if (sae->state == SAE_COMMITTED && group != sae->group) {
     897           0 :                 wpa_printf(MSG_DEBUG, "SAE: Do not allow group to be changed");
     898           0 :                 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
     899             :         }
     900             : 
     901         180 :         if (group != sae->group && sae_set_group(sae, group) < 0) {
     902           0 :                 wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u",
     903             :                            group);
     904           0 :                 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
     905             :         }
     906             : 
     907         180 :         if (sae->tmp == NULL) {
     908           0 :                 wpa_printf(MSG_DEBUG, "SAE: Group information not yet initialized");
     909           0 :                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
     910             :         }
     911             : 
     912         180 :         if (sae->tmp->dh && !allowed_groups) {
     913           2 :                 wpa_printf(MSG_DEBUG, "SAE: Do not allow FFC group %u without "
     914             :                            "explicit configuration enabling it", group);
     915           2 :                 return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
     916             :         }
     917             : 
     918         178 :         return WLAN_STATUS_SUCCESS;
     919             : }
     920             : 
     921             : 
     922         173 : static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
     923             :                                    const u8 *end, const u8 **token,
     924             :                                    size_t *token_len)
     925             : {
     926         173 :         if (*pos + (sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len < end) {
     927          10 :                 size_t tlen = end - (*pos + (sae->tmp->ec ? 3 : 2) *
     928           5 :                                      sae->tmp->prime_len);
     929           5 :                 wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen);
     930           5 :                 if (token)
     931           5 :                         *token = *pos;
     932           5 :                 if (token_len)
     933           5 :                         *token_len = tlen;
     934           5 :                 *pos += tlen;
     935             :         } else {
     936         168 :                 if (token)
     937          92 :                         *token = NULL;
     938         168 :                 if (token_len)
     939          92 :                         *token_len = 0;
     940             :         }
     941         173 : }
     942             : 
     943             : 
     944         173 : static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
     945             :                                    const u8 *end)
     946             : {
     947             :         struct crypto_bignum *peer_scalar;
     948             : 
     949         173 :         if (*pos + sae->tmp->prime_len > end) {
     950           0 :                 wpa_printf(MSG_DEBUG, "SAE: Not enough data for scalar");
     951           0 :                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
     952             :         }
     953             : 
     954         173 :         peer_scalar = crypto_bignum_init_set(*pos, sae->tmp->prime_len);
     955         173 :         if (peer_scalar == NULL)
     956           0 :                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
     957             : 
     958             :         /*
     959             :          * IEEE Std 802.11-2012, 11.3.8.6.1: If there is a protocol instance for
     960             :          * the peer and it is in Authenticated state, the new Commit Message
     961             :          * shall be dropped if the peer-scalar is identical to the one used in
     962             :          * the existing protocol instance.
     963             :          */
     964         173 :         if (sae->state == SAE_ACCEPTED && sae->peer_commit_scalar &&
     965           0 :             crypto_bignum_cmp(sae->peer_commit_scalar, peer_scalar) == 0) {
     966           0 :                 wpa_printf(MSG_DEBUG, "SAE: Do not accept re-use of previous "
     967             :                            "peer-commit-scalar");
     968           0 :                 crypto_bignum_deinit(peer_scalar, 0);
     969           0 :                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
     970             :         }
     971             : 
     972             :         /* 1 < scalar < r */
     973         345 :         if (crypto_bignum_is_zero(peer_scalar) ||
     974         343 :             crypto_bignum_is_one(peer_scalar) ||
     975         171 :             crypto_bignum_cmp(peer_scalar, sae->tmp->order) >= 0) {
     976           3 :                 wpa_printf(MSG_DEBUG, "SAE: Invalid peer scalar");
     977           3 :                 crypto_bignum_deinit(peer_scalar, 0);
     978           3 :                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
     979             :         }
     980             : 
     981             : 
     982         170 :         crypto_bignum_deinit(sae->peer_commit_scalar, 0);
     983         170 :         sae->peer_commit_scalar = peer_scalar;
     984         170 :         wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-scalar",
     985         170 :                     *pos, sae->tmp->prime_len);
     986         170 :         *pos += sae->tmp->prime_len;
     987             : 
     988         170 :         return WLAN_STATUS_SUCCESS;
     989             : }
     990             : 
     991             : 
     992         128 : static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos,
     993             :                                         const u8 *end)
     994             : {
     995             :         u8 prime[SAE_MAX_ECC_PRIME_LEN];
     996             : 
     997         128 :         if (pos + 2 * sae->tmp->prime_len > end) {
     998           1 :                 wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
     999             :                            "commit-element");
    1000           1 :                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
    1001             :         }
    1002             : 
    1003         127 :         if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
    1004         127 :                                  sae->tmp->prime_len) < 0)
    1005           0 :                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
    1006             : 
    1007             :         /* element x and y coordinates < p */
    1008         253 :         if (os_memcmp(pos, prime, sae->tmp->prime_len) >= 0 ||
    1009         126 :             os_memcmp(pos + sae->tmp->prime_len, prime,
    1010             :                       sae->tmp->prime_len) >= 0) {
    1011           2 :                 wpa_printf(MSG_DEBUG, "SAE: Invalid coordinates in peer "
    1012             :                            "element");
    1013           2 :                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
    1014             :         }
    1015             : 
    1016         125 :         wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(x)",
    1017         125 :                     pos, sae->tmp->prime_len);
    1018         250 :         wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(y)",
    1019         250 :                     pos + sae->tmp->prime_len, sae->tmp->prime_len);
    1020             : 
    1021         125 :         crypto_ec_point_deinit(sae->tmp->peer_commit_element_ecc, 0);
    1022         250 :         sae->tmp->peer_commit_element_ecc =
    1023         125 :                 crypto_ec_point_from_bin(sae->tmp->ec, pos);
    1024         125 :         if (sae->tmp->peer_commit_element_ecc == NULL)
    1025           0 :                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
    1026             : 
    1027         125 :         if (!crypto_ec_point_is_on_curve(sae->tmp->ec,
    1028         125 :                                          sae->tmp->peer_commit_element_ecc)) {
    1029           1 :                 wpa_printf(MSG_DEBUG, "SAE: Peer element is not on curve");
    1030           1 :                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
    1031             :         }
    1032             : 
    1033         124 :         return WLAN_STATUS_SUCCESS;
    1034             : }
    1035             : 
    1036             : 
    1037          42 : static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos,
    1038             :                                         const u8 *end)
    1039             : {
    1040             :         struct crypto_bignum *res, *one;
    1041          42 :         const u8 one_bin[1] = { 0x01 };
    1042             : 
    1043          42 :         if (pos + sae->tmp->prime_len > end) {
    1044           1 :                 wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
    1045             :                            "commit-element");
    1046           1 :                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
    1047             :         }
    1048          41 :         wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element", pos,
    1049          41 :                     sae->tmp->prime_len);
    1050             : 
    1051          41 :         crypto_bignum_deinit(sae->tmp->peer_commit_element_ffc, 0);
    1052          82 :         sae->tmp->peer_commit_element_ffc =
    1053          41 :                 crypto_bignum_init_set(pos, sae->tmp->prime_len);
    1054          41 :         if (sae->tmp->peer_commit_element_ffc == NULL)
    1055           0 :                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
    1056             :         /* 1 < element < p - 1 */
    1057          41 :         res = crypto_bignum_init();
    1058          41 :         one = crypto_bignum_init_set(one_bin, sizeof(one_bin));
    1059          82 :         if (!res || !one ||
    1060          82 :             crypto_bignum_sub(sae->tmp->prime, one, res) ||
    1061          81 :             crypto_bignum_is_zero(sae->tmp->peer_commit_element_ffc) ||
    1062          79 :             crypto_bignum_is_one(sae->tmp->peer_commit_element_ffc) ||
    1063          39 :             crypto_bignum_cmp(sae->tmp->peer_commit_element_ffc, res) >= 0) {
    1064           3 :                 crypto_bignum_deinit(res, 0);
    1065           3 :                 crypto_bignum_deinit(one, 0);
    1066           3 :                 wpa_printf(MSG_DEBUG, "SAE: Invalid peer element");
    1067           3 :                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
    1068             :         }
    1069          38 :         crypto_bignum_deinit(one, 0);
    1070             : 
    1071             :         /* scalar-op(r, ELEMENT) = 1 modulo p */
    1072          76 :         if (crypto_bignum_exptmod(sae->tmp->peer_commit_element_ffc,
    1073         114 :                                   sae->tmp->order, sae->tmp->prime, res) < 0 ||
    1074          38 :             !crypto_bignum_is_one(res)) {
    1075           0 :                 wpa_printf(MSG_DEBUG, "SAE: Invalid peer element (scalar-op)");
    1076           0 :                 crypto_bignum_deinit(res, 0);
    1077           0 :                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
    1078             :         }
    1079          38 :         crypto_bignum_deinit(res, 0);
    1080             : 
    1081          38 :         return WLAN_STATUS_SUCCESS;
    1082             : }
    1083             : 
    1084             : 
    1085         170 : static u16 sae_parse_commit_element(struct sae_data *sae, const u8 *pos,
    1086             :                                     const u8 *end)
    1087             : {
    1088         170 :         if (sae->tmp->dh)
    1089          42 :                 return sae_parse_commit_element_ffc(sae, pos, end);
    1090         128 :         return sae_parse_commit_element_ecc(sae, pos, end);
    1091             : }
    1092             : 
    1093             : 
    1094         188 : u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
    1095             :                      const u8 **token, size_t *token_len, int *allowed_groups)
    1096             : {
    1097         188 :         const u8 *pos = data, *end = data + len;
    1098             :         u16 res;
    1099             : 
    1100             :         /* Check Finite Cyclic Group */
    1101         188 :         if (pos + 2 > end)
    1102           1 :                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
    1103         187 :         res = sae_group_allowed(sae, allowed_groups, WPA_GET_LE16(pos));
    1104         187 :         if (res != WLAN_STATUS_SUCCESS)
    1105          14 :                 return res;
    1106         173 :         pos += 2;
    1107             : 
    1108             :         /* Optional Anti-Clogging Token */
    1109         173 :         sae_parse_commit_token(sae, &pos, end, token, token_len);
    1110             : 
    1111             :         /* commit-scalar */
    1112         173 :         res = sae_parse_commit_scalar(sae, &pos, end);
    1113         173 :         if (res != WLAN_STATUS_SUCCESS)
    1114           3 :                 return res;
    1115             : 
    1116             :         /* commit-element */
    1117         170 :         res = sae_parse_commit_element(sae, pos, end);
    1118         170 :         if (res != WLAN_STATUS_SUCCESS)
    1119           8 :                 return res;
    1120             : 
    1121             :         /*
    1122             :          * Check whether peer-commit-scalar and PEER-COMMIT-ELEMENT are same as
    1123             :          * the values we sent which would be evidence of a reflection attack.
    1124             :          */
    1125         258 :         if (!sae->tmp->own_commit_scalar ||
    1126          96 :             crypto_bignum_cmp(sae->tmp->own_commit_scalar,
    1127          98 :                               sae->peer_commit_scalar) != 0 ||
    1128           3 :             (sae->tmp->dh &&
    1129           2 :              (!sae->tmp->own_commit_element_ffc ||
    1130           1 :               crypto_bignum_cmp(sae->tmp->own_commit_element_ffc,
    1131           3 :                                 sae->tmp->peer_commit_element_ffc) != 0)) ||
    1132           3 :             (sae->tmp->ec &&
    1133           2 :              (!sae->tmp->own_commit_element_ecc ||
    1134           1 :               crypto_ec_point_cmp(sae->tmp->ec,
    1135           1 :                                   sae->tmp->own_commit_element_ecc,
    1136           1 :                                   sae->tmp->peer_commit_element_ecc) != 0)))
    1137         160 :                 return WLAN_STATUS_SUCCESS; /* scalars/elements are different */
    1138             : 
    1139             :         /*
    1140             :          * This is a reflection attack - return special value to trigger caller
    1141             :          * to silently discard the frame instead of replying with a specific
    1142             :          * status code.
    1143             :          */
    1144           2 :         return SAE_SILENTLY_DISCARD;
    1145             : }
    1146             : 
    1147             : 
    1148         481 : static void sae_cn_confirm(struct sae_data *sae, const u8 *sc,
    1149             :                            const struct crypto_bignum *scalar1,
    1150             :                            const u8 *element1, size_t element1_len,
    1151             :                            const struct crypto_bignum *scalar2,
    1152             :                            const u8 *element2, size_t element2_len,
    1153             :                            u8 *confirm)
    1154             : {
    1155             :         const u8 *addr[5];
    1156             :         size_t len[5];
    1157             :         u8 scalar_b1[SAE_MAX_PRIME_LEN], scalar_b2[SAE_MAX_PRIME_LEN];
    1158             : 
    1159             :         /* Confirm
    1160             :          * CN(key, X, Y, Z, ...) =
    1161             :          *    HMAC-SHA256(key, D2OS(X) || D2OS(Y) || D2OS(Z) | ...)
    1162             :          * confirm = CN(KCK, send-confirm, commit-scalar, COMMIT-ELEMENT,
    1163             :          *              peer-commit-scalar, PEER-COMMIT-ELEMENT)
    1164             :          * verifier = CN(KCK, peer-send-confirm, peer-commit-scalar,
    1165             :          *               PEER-COMMIT-ELEMENT, commit-scalar, COMMIT-ELEMENT)
    1166             :          */
    1167         481 :         addr[0] = sc;
    1168         481 :         len[0] = 2;
    1169         481 :         crypto_bignum_to_bin(scalar1, scalar_b1, sizeof(scalar_b1),
    1170         481 :                              sae->tmp->prime_len);
    1171         481 :         addr[1] = scalar_b1;
    1172         481 :         len[1] = sae->tmp->prime_len;
    1173         481 :         addr[2] = element1;
    1174         481 :         len[2] = element1_len;
    1175         481 :         crypto_bignum_to_bin(scalar2, scalar_b2, sizeof(scalar_b2),
    1176         481 :                              sae->tmp->prime_len);
    1177         481 :         addr[3] = scalar_b2;
    1178         481 :         len[3] = sae->tmp->prime_len;
    1179         481 :         addr[4] = element2;
    1180         481 :         len[4] = element2_len;
    1181         481 :         hmac_sha256_vector(sae->tmp->kck, sizeof(sae->tmp->kck), 5, addr, len,
    1182             :                            confirm);
    1183         481 : }
    1184             : 
    1185             : 
    1186         407 : static void sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc,
    1187             :                                const struct crypto_bignum *scalar1,
    1188             :                                const struct crypto_ec_point *element1,
    1189             :                                const struct crypto_bignum *scalar2,
    1190             :                                const struct crypto_ec_point *element2,
    1191             :                                u8 *confirm)
    1192             : {
    1193             :         u8 element_b1[2 * SAE_MAX_ECC_PRIME_LEN];
    1194             :         u8 element_b2[2 * SAE_MAX_ECC_PRIME_LEN];
    1195             : 
    1196         407 :         crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1,
    1197         407 :                                element_b1 + sae->tmp->prime_len);
    1198         407 :         crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2,
    1199         407 :                                element_b2 + sae->tmp->prime_len);
    1200             : 
    1201         407 :         sae_cn_confirm(sae, sc, scalar1, element_b1, 2 * sae->tmp->prime_len,
    1202         407 :                        scalar2, element_b2, 2 * sae->tmp->prime_len, confirm);
    1203         407 : }
    1204             : 
    1205             : 
    1206          74 : static void sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc,
    1207             :                                const struct crypto_bignum *scalar1,
    1208             :                                const struct crypto_bignum *element1,
    1209             :                                const struct crypto_bignum *scalar2,
    1210             :                                const struct crypto_bignum *element2,
    1211             :                                u8 *confirm)
    1212             : {
    1213             :         u8 element_b1[SAE_MAX_PRIME_LEN];
    1214             :         u8 element_b2[SAE_MAX_PRIME_LEN];
    1215             : 
    1216          74 :         crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1),
    1217          74 :                              sae->tmp->prime_len);
    1218          74 :         crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2),
    1219          74 :                              sae->tmp->prime_len);
    1220             : 
    1221          74 :         sae_cn_confirm(sae, sc, scalar1, element_b1, sae->tmp->prime_len,
    1222          74 :                        scalar2, element_b2, sae->tmp->prime_len, confirm);
    1223          74 : }
    1224             : 
    1225             : 
    1226         245 : void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
    1227             : {
    1228             :         const u8 *sc;
    1229             : 
    1230         245 :         if (sae->tmp == NULL)
    1231         245 :                 return;
    1232             : 
    1233             :         /* Send-Confirm */
    1234         245 :         sc = wpabuf_put(buf, 0);
    1235         245 :         wpabuf_put_le16(buf, sae->send_confirm);
    1236         245 :         sae->send_confirm++;
    1237             : 
    1238         245 :         if (sae->tmp->ec)
    1239         208 :                 sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar,
    1240         208 :                                    sae->tmp->own_commit_element_ecc,
    1241         208 :                                    sae->peer_commit_scalar,
    1242         208 :                                    sae->tmp->peer_commit_element_ecc,
    1243         208 :                                    wpabuf_put(buf, SHA256_MAC_LEN));
    1244             :         else
    1245          37 :                 sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar,
    1246          37 :                                    sae->tmp->own_commit_element_ffc,
    1247          37 :                                    sae->peer_commit_scalar,
    1248          37 :                                    sae->tmp->peer_commit_element_ffc,
    1249          37 :                                    wpabuf_put(buf, SHA256_MAC_LEN));
    1250             : }
    1251             : 
    1252             : 
    1253         237 : int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len)
    1254             : {
    1255             :         u8 verifier[SHA256_MAC_LEN];
    1256             : 
    1257         237 :         if (len < 2 + SHA256_MAC_LEN) {
    1258           1 :                 wpa_printf(MSG_DEBUG, "SAE: Too short confirm message");
    1259           1 :                 return -1;
    1260             :         }
    1261             : 
    1262         236 :         wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data));
    1263             : 
    1264         236 :         if (sae->tmp == NULL) {
    1265           0 :                 wpa_printf(MSG_DEBUG, "SAE: Temporary data not yet available");
    1266           0 :                 return -1;
    1267             :         }
    1268             : 
    1269         236 :         if (sae->tmp->ec)
    1270         199 :                 sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar,
    1271         199 :                                    sae->tmp->peer_commit_element_ecc,
    1272         199 :                                    sae->tmp->own_commit_scalar,
    1273         199 :                                    sae->tmp->own_commit_element_ecc,
    1274             :                                    verifier);
    1275             :         else
    1276          37 :                 sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar,
    1277          37 :                                    sae->tmp->peer_commit_element_ffc,
    1278          37 :                                    sae->tmp->own_commit_scalar,
    1279          37 :                                    sae->tmp->own_commit_element_ffc,
    1280             :                                    verifier);
    1281             : 
    1282         236 :         if (os_memcmp_const(verifier, data + 2, SHA256_MAC_LEN) != 0) {
    1283         108 :                 wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch");
    1284         108 :                 wpa_hexdump(MSG_DEBUG, "SAE: Received confirm",
    1285             :                             data + 2, SHA256_MAC_LEN);
    1286         108 :                 wpa_hexdump(MSG_DEBUG, "SAE: Calculated verifier",
    1287             :                             verifier, SHA256_MAC_LEN);
    1288         108 :                 return -1;
    1289             :         }
    1290             : 
    1291         128 :         return 0;
    1292             : }

Generated by: LCOV version 1.10