LCOV - code coverage report
Current view: top level - src/common - sae.c (source / functions) Hit Total Coverage
Test: hostapd hwsim test run 1388338050 Lines: 459 562 81.7 %
Date: 2013-12-29 Functions: 32 32 100.0 %
Branches: 173 286 60.5 %

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

Generated by: LCOV version 1.9