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 1393793999 Lines: 467 570 81.9 %
Date: 2014-03-02 Functions: 32 32 100.0 %
Branches: 184 296 62.2 %

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

Generated by: LCOV version 1.9