LCOV - code coverage report
Current view: top level - src/eap_common - eap_eke_common.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1393793999 Lines: 322 398 80.9 %
Date: 2014-03-02 Functions: 26 26 100.0 %
Branches: 109 189 57.7 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * EAP server/peer: EAP-EKE shared routines
       3                 :            :  * Copyright (c) 2011-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/aes.h"
      13                 :            : #include "crypto/aes_wrap.h"
      14                 :            : #include "crypto/crypto.h"
      15                 :            : #include "crypto/dh_groups.h"
      16                 :            : #include "crypto/random.h"
      17                 :            : #include "crypto/sha1.h"
      18                 :            : #include "crypto/sha256.h"
      19                 :            : #include "eap_common/eap_defs.h"
      20                 :            : #include "eap_eke_common.h"
      21                 :            : 
      22                 :            : 
      23                 :         32 : static int eap_eke_dh_len(u8 group)
      24                 :            : {
      25   [ -  -  +  +  :         32 :         switch (group) {
                   +  - ]
      26                 :            :         case EAP_EKE_DHGROUP_EKE_2:
      27                 :          0 :                 return 128;
      28                 :            :         case EAP_EKE_DHGROUP_EKE_5:
      29                 :          0 :                 return 192;
      30                 :            :         case EAP_EKE_DHGROUP_EKE_14:
      31                 :          8 :                 return 256;
      32                 :            :         case EAP_EKE_DHGROUP_EKE_15:
      33                 :          4 :                 return 384;
      34                 :            :         case EAP_EKE_DHGROUP_EKE_16:
      35                 :         20 :                 return 512;
      36                 :            :         }
      37                 :            : 
      38                 :         32 :         return -1;
      39                 :            : }
      40                 :            : 
      41                 :            : 
      42                 :         16 : static int eap_eke_dhcomp_len(u8 dhgroup, u8 encr)
      43                 :            : {
      44                 :            :         int dhlen;
      45                 :            : 
      46                 :         16 :         dhlen = eap_eke_dh_len(dhgroup);
      47         [ -  + ]:         16 :         if (dhlen < 0)
      48                 :          0 :                 return -1;
      49         [ -  + ]:         16 :         if (encr != EAP_EKE_ENCR_AES128_CBC)
      50                 :          0 :                 return -1;
      51                 :         16 :         return AES_BLOCK_SIZE + dhlen;
      52                 :            : }
      53                 :            : 
      54                 :            : 
      55                 :         32 : static const struct dh_group * eap_eke_dh_group(u8 group)
      56                 :            : {
      57   [ -  -  +  +  :         32 :         switch (group) {
                   +  - ]
      58                 :            :         case EAP_EKE_DHGROUP_EKE_2:
      59                 :          0 :                 return dh_groups_get(2);
      60                 :            :         case EAP_EKE_DHGROUP_EKE_5:
      61                 :          0 :                 return dh_groups_get(5);
      62                 :            :         case EAP_EKE_DHGROUP_EKE_14:
      63                 :          8 :                 return dh_groups_get(14);
      64                 :            :         case EAP_EKE_DHGROUP_EKE_15:
      65                 :          4 :                 return dh_groups_get(15);
      66                 :            :         case EAP_EKE_DHGROUP_EKE_16:
      67                 :         20 :                 return dh_groups_get(16);
      68                 :            :         }
      69                 :            : 
      70                 :         32 :         return NULL;
      71                 :            : }
      72                 :            : 
      73                 :            : 
      74                 :         16 : static int eap_eke_dh_generator(u8 group)
      75                 :            : {
      76   [ -  -  +  +  :         16 :         switch (group) {
                   +  - ]
      77                 :            :         case EAP_EKE_DHGROUP_EKE_2:
      78                 :          0 :                 return 5;
      79                 :            :         case EAP_EKE_DHGROUP_EKE_5:
      80                 :          0 :                 return 31;
      81                 :            :         case EAP_EKE_DHGROUP_EKE_14:
      82                 :          4 :                 return 11;
      83                 :            :         case EAP_EKE_DHGROUP_EKE_15:
      84                 :          2 :                 return 5;
      85                 :            :         case EAP_EKE_DHGROUP_EKE_16:
      86                 :         10 :                 return 5;
      87                 :            :         }
      88                 :            : 
      89                 :         16 :         return -1;
      90                 :            : }
      91                 :            : 
      92                 :            : 
      93                 :         16 : static int eap_eke_pnonce_len(u8 mac)
      94                 :            : {
      95                 :            :         int mac_len;
      96                 :            : 
      97         [ +  + ]:         16 :         if (mac == EAP_EKE_MAC_HMAC_SHA1)
      98                 :          2 :                 mac_len = SHA1_MAC_LEN;
      99         [ +  - ]:         14 :         else if (mac == EAP_EKE_MAC_HMAC_SHA2_256)
     100                 :         14 :                 mac_len = SHA256_MAC_LEN;
     101                 :            :         else
     102                 :          0 :                 return -1;
     103                 :            : 
     104                 :         16 :         return AES_BLOCK_SIZE + 16 + mac_len;
     105                 :            : }
     106                 :            : 
     107                 :            : 
     108                 :         16 : static int eap_eke_pnonce_ps_len(u8 mac)
     109                 :            : {
     110                 :            :         int mac_len;
     111                 :            : 
     112         [ +  + ]:         16 :         if (mac == EAP_EKE_MAC_HMAC_SHA1)
     113                 :          2 :                 mac_len = SHA1_MAC_LEN;
     114         [ +  - ]:         14 :         else if (mac == EAP_EKE_MAC_HMAC_SHA2_256)
     115                 :         14 :                 mac_len = SHA256_MAC_LEN;
     116                 :            :         else
     117                 :          0 :                 return -1;
     118                 :            : 
     119                 :         16 :         return AES_BLOCK_SIZE + 2 * 16 + mac_len;
     120                 :            : }
     121                 :            : 
     122                 :            : 
     123                 :         32 : static int eap_eke_prf_len(u8 prf)
     124                 :            : {
     125         [ +  + ]:         32 :         if (prf == EAP_EKE_PRF_HMAC_SHA1)
     126                 :          4 :                 return 20;
     127         [ +  - ]:         28 :         if (prf == EAP_EKE_PRF_HMAC_SHA2_256)
     128                 :         28 :                 return 32;
     129                 :         32 :         return -1;
     130                 :            : }
     131                 :            : 
     132                 :            : 
     133                 :         16 : static int eap_eke_nonce_len(u8 prf)
     134                 :            : {
     135                 :            :         int prf_len;
     136                 :            : 
     137                 :         16 :         prf_len = eap_eke_prf_len(prf);
     138         [ -  + ]:         16 :         if (prf_len < 0)
     139                 :          0 :                 return -1;
     140                 :            : 
     141         [ -  + ]:         16 :         if (prf_len > 2 * 16)
     142                 :          0 :                 return (prf_len + 1) / 2;
     143                 :            : 
     144                 :         16 :         return 16;
     145                 :            : }
     146                 :            : 
     147                 :            : 
     148                 :         16 : static int eap_eke_auth_len(u8 prf)
     149                 :            : {
     150      [ +  +  - ]:         16 :         switch (prf) {
     151                 :            :         case EAP_EKE_PRF_HMAC_SHA1:
     152                 :          2 :                 return SHA1_MAC_LEN;
     153                 :            :         case EAP_EKE_PRF_HMAC_SHA2_256:
     154                 :         14 :                 return SHA256_MAC_LEN;
     155                 :            :         }
     156                 :            : 
     157                 :         16 :         return -1;
     158                 :            : }
     159                 :            : 
     160                 :            : 
     161                 :         16 : int eap_eke_dh_init(u8 group, u8 *ret_priv, u8 *ret_pub)
     162                 :            : {
     163                 :            :         int generator;
     164                 :            :         u8 gen;
     165                 :            :         const struct dh_group *dh;
     166                 :            :         size_t pub_len, i;
     167                 :            : 
     168                 :         16 :         generator = eap_eke_dh_generator(group);
     169 [ -  + ][ +  - ]:         16 :         if (generator < 0 || generator > 255)
     170                 :          0 :                 return -1;
     171                 :         16 :         gen = generator;
     172                 :            : 
     173                 :         16 :         dh = eap_eke_dh_group(group);
     174         [ -  + ]:         16 :         if (dh == NULL)
     175                 :          0 :                 return -1;
     176                 :            : 
     177                 :            :         /* x = random number 2 .. p-1 */
     178         [ -  + ]:         16 :         if (random_get_bytes(ret_priv, dh->prime_len))
     179                 :          0 :                 return -1;
     180         [ -  + ]:         16 :         if (os_memcmp(ret_priv, dh->prime, dh->prime_len) > 0) {
     181                 :            :                 /* Make sure private value is smaller than prime */
     182                 :          0 :                 ret_priv[0] = 0;
     183                 :            :         }
     184         [ +  - ]:         16 :         for (i = 0; i < dh->prime_len - 1; i++) {
     185         [ +  - ]:         16 :                 if (ret_priv[i])
     186                 :         16 :                         break;
     187                 :            :         }
     188 [ -  + ][ #  # ]:         16 :         if (i == dh->prime_len - 1 && (ret_priv[i] == 0 || ret_priv[i] == 1))
                 [ #  # ]
     189                 :          0 :                 return -1;
     190                 :         16 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: DH private value",
     191                 :            :                         ret_priv, dh->prime_len);
     192                 :            : 
     193                 :            :         /* y = g ^ x (mod p) */
     194                 :         16 :         pub_len = dh->prime_len;
     195         [ -  + ]:         16 :         if (crypto_mod_exp(&gen, 1, ret_priv, dh->prime_len,
     196                 :            :                            dh->prime, dh->prime_len, ret_pub, &pub_len) < 0)
     197                 :          0 :                 return -1;
     198         [ -  + ]:         16 :         if (pub_len < dh->prime_len) {
     199                 :          0 :                 size_t pad = dh->prime_len - pub_len;
     200                 :          0 :                 os_memmove(ret_pub + pad, ret_pub, pub_len);
     201                 :          0 :                 os_memset(ret_pub, 0, pad);
     202                 :            :         }
     203                 :            : 
     204                 :         16 :         wpa_hexdump(MSG_DEBUG, "EAP-EKE: DH public value",
     205                 :            :                     ret_pub, dh->prime_len);
     206                 :            : 
     207                 :         16 :         return 0;
     208                 :            : }
     209                 :            : 
     210                 :            : 
     211                 :         60 : static int eap_eke_prf(u8 prf, const u8 *key, size_t key_len, const u8 *data,
     212                 :            :                        size_t data_len, const u8 *data2, size_t data2_len,
     213                 :            :                        u8 *res)
     214                 :            : {
     215                 :            :         const u8 *addr[2];
     216                 :            :         size_t len[2];
     217                 :         60 :         size_t num_elem = 1;
     218                 :            : 
     219                 :         60 :         addr[0] = data;
     220                 :         60 :         len[0] = data_len;
     221         [ +  + ]:         60 :         if (data2) {
     222                 :         28 :                 num_elem++;
     223                 :         28 :                 addr[1] = data2;
     224                 :         28 :                 len[1] = data2_len;
     225                 :            :         }
     226                 :            : 
     227         [ +  + ]:         60 :         if (prf == EAP_EKE_PRF_HMAC_SHA1)
     228                 :          8 :                 return hmac_sha1_vector(key, key_len, num_elem, addr, len, res);
     229         [ +  - ]:         52 :         if (prf == EAP_EKE_PRF_HMAC_SHA2_256)
     230                 :         52 :                 return hmac_sha256_vector(key, key_len, num_elem, addr, len,
     231                 :            :                                           res);
     232                 :         60 :         return -1;
     233                 :            : }
     234                 :            : 
     235                 :            : 
     236                 :          8 : static int eap_eke_prf_hmac_sha1(const u8 *key, size_t key_len, const u8 *data,
     237                 :            :                                  size_t data_len, u8 *res, size_t len)
     238                 :            : {
     239                 :            :         u8 hash[SHA1_MAC_LEN];
     240                 :            :         u8 idx;
     241                 :            :         const u8 *addr[3];
     242                 :            :         size_t vlen[3];
     243                 :            :         int ret;
     244                 :            : 
     245                 :          8 :         idx = 0;
     246                 :          8 :         addr[0] = hash;
     247                 :          8 :         vlen[0] = SHA1_MAC_LEN;
     248                 :          8 :         addr[1] = data;
     249                 :          8 :         vlen[1] = data_len;
     250                 :          8 :         addr[2] = &idx;
     251                 :          8 :         vlen[2] = 1;
     252                 :            : 
     253         [ +  + ]:         30 :         while (len > 0) {
     254                 :         22 :                 idx++;
     255         [ +  + ]:         22 :                 if (idx == 1)
     256                 :          8 :                         ret = hmac_sha1_vector(key, key_len, 2, &addr[1],
     257                 :            :                                                &vlen[1], hash);
     258                 :            :                 else
     259                 :         14 :                         ret = hmac_sha1_vector(key, key_len, 3, addr, vlen,
     260                 :            :                                                hash);
     261         [ -  + ]:         22 :                 if (ret < 0)
     262                 :          0 :                         return -1;
     263         [ +  + ]:         22 :                 if (len > SHA1_MAC_LEN) {
     264                 :         14 :                         os_memcpy(res, hash, SHA1_MAC_LEN);
     265                 :         14 :                         res += SHA1_MAC_LEN;
     266                 :         14 :                         len -= SHA1_MAC_LEN;
     267                 :            :                 } else {
     268                 :          8 :                         os_memcpy(res, hash, len);
     269                 :          8 :                         len = 0;
     270                 :            :                 }
     271                 :            :         }
     272                 :            : 
     273                 :          8 :         return 0;
     274                 :            : }
     275                 :            : 
     276                 :            : 
     277                 :         52 : static int eap_eke_prf_hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
     278                 :            :                                    size_t data_len, u8 *res, size_t len)
     279                 :            : {
     280                 :            :         u8 hash[SHA256_MAC_LEN];
     281                 :            :         u8 idx;
     282                 :            :         const u8 *addr[3];
     283                 :            :         size_t vlen[3];
     284                 :            :         int ret;
     285                 :            : 
     286                 :         52 :         idx = 0;
     287                 :         52 :         addr[0] = hash;
     288                 :         52 :         vlen[0] = SHA256_MAC_LEN;
     289                 :         52 :         addr[1] = data;
     290                 :         52 :         vlen[1] = data_len;
     291                 :         52 :         addr[2] = &idx;
     292                 :         52 :         vlen[2] = 1;
     293                 :            : 
     294         [ +  + ]:        154 :         while (len > 0) {
     295                 :        102 :                 idx++;
     296         [ +  + ]:        102 :                 if (idx == 1)
     297                 :         52 :                         ret = hmac_sha256_vector(key, key_len, 2, &addr[1],
     298                 :            :                                                  &vlen[1], hash);
     299                 :            :                 else
     300                 :         50 :                         ret = hmac_sha256_vector(key, key_len, 3, addr, vlen,
     301                 :            :                                                  hash);
     302         [ -  + ]:        102 :                 if (ret < 0)
     303                 :          0 :                         return -1;
     304         [ +  + ]:        102 :                 if (len > SHA256_MAC_LEN) {
     305                 :         50 :                         os_memcpy(res, hash, SHA256_MAC_LEN);
     306                 :         50 :                         res += SHA256_MAC_LEN;
     307                 :         50 :                         len -= SHA256_MAC_LEN;
     308                 :            :                 } else {
     309                 :         52 :                         os_memcpy(res, hash, len);
     310                 :         52 :                         len = 0;
     311                 :            :                 }
     312                 :            :         }
     313                 :            : 
     314                 :         52 :         return 0;
     315                 :            : }
     316                 :            : 
     317                 :            : 
     318                 :         60 : static int eap_eke_prfplus(u8 prf, const u8 *key, size_t key_len,
     319                 :            :                            const u8 *data, size_t data_len, u8 *res, size_t len)
     320                 :            : {
     321         [ +  + ]:         60 :         if (prf == EAP_EKE_PRF_HMAC_SHA1)
     322                 :          8 :                 return eap_eke_prf_hmac_sha1(key, key_len, data, data_len, res,
     323                 :            :                                              len);
     324         [ +  - ]:         52 :         if (prf == EAP_EKE_PRF_HMAC_SHA2_256)
     325                 :         52 :                 return eap_eke_prf_hmac_sha256(key, key_len, data, data_len,
     326                 :            :                                                res, len);
     327                 :         60 :         return -1;
     328                 :            : }
     329                 :            : 
     330                 :            : 
     331                 :         16 : int eap_eke_derive_key(struct eap_eke_session *sess,
     332                 :            :                        const u8 *password, size_t password_len,
     333                 :            :                        const u8 *id_s, size_t id_s_len, const u8 *id_p,
     334                 :            :                        size_t id_p_len, u8 *key)
     335                 :            : {
     336                 :            :         u8 zeros[EAP_EKE_MAX_HASH_LEN];
     337                 :            :         u8 temp[EAP_EKE_MAX_HASH_LEN];
     338                 :         16 :         size_t key_len = 16; /* Only AES-128-CBC is used here */
     339                 :            :         u8 *id;
     340                 :            : 
     341                 :            :         /* temp = prf(0+, password) */
     342                 :         16 :         os_memset(zeros, 0, sess->prf_len);
     343         [ -  + ]:         16 :         if (eap_eke_prf(sess->prf, zeros, sess->prf_len,
     344                 :            :                         password, password_len, NULL, 0, temp) < 0)
     345                 :          0 :                 return -1;
     346                 :         16 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: temp = prf(0+, password)",
     347                 :         16 :                         temp, sess->prf_len);
     348                 :            : 
     349                 :            :         /* key = prf+(temp, ID_S | ID_P) */
     350                 :         16 :         id = os_malloc(id_s_len + id_p_len);
     351         [ -  + ]:         16 :         if (id == NULL)
     352                 :          0 :                 return -1;
     353                 :         16 :         os_memcpy(id, id_s, id_s_len);
     354                 :         16 :         os_memcpy(id + id_s_len, id_p, id_p_len);
     355                 :         16 :         wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: ID_S | ID_P",
     356                 :            :                           id, id_s_len + id_p_len);
     357         [ -  + ]:         16 :         if (eap_eke_prfplus(sess->prf, temp, sess->prf_len,
     358                 :            :                             id, id_s_len + id_p_len, key, key_len) < 0) {
     359                 :          0 :                 os_free(id);
     360                 :          0 :                 return -1;
     361                 :            :         }
     362                 :         16 :         os_free(id);
     363                 :         16 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: key = prf+(temp, ID_S | ID_P)",
     364                 :            :                         key, key_len);
     365                 :            : 
     366                 :         16 :         return 0;
     367                 :            : }
     368                 :            : 
     369                 :            : 
     370                 :         16 : int eap_eke_dhcomp(struct eap_eke_session *sess, const u8 *key, const u8 *dhpub,
     371                 :            :                    u8 *ret_dhcomp)
     372                 :            : {
     373                 :            :         u8 pub[EAP_EKE_MAX_DH_LEN];
     374                 :            :         int dh_len;
     375                 :            :         u8 iv[AES_BLOCK_SIZE];
     376                 :            : 
     377                 :         16 :         dh_len = eap_eke_dh_len(sess->dhgroup);
     378         [ -  + ]:         16 :         if (dh_len < 0)
     379                 :          0 :                 return -1;
     380                 :            : 
     381                 :            :         /*
     382                 :            :          * DHComponent = Encr(key, y)
     383                 :            :          *
     384                 :            :          * All defined DH groups use primes that have length devisible by 16, so
     385                 :            :          * no need to do extra padding for y (= pub).
     386                 :            :          */
     387         [ -  + ]:         16 :         if (sess->encr != EAP_EKE_ENCR_AES128_CBC)
     388                 :          0 :                 return -1;
     389         [ -  + ]:         16 :         if (random_get_bytes(iv, AES_BLOCK_SIZE))
     390                 :          0 :                 return -1;
     391                 :         16 :         wpa_hexdump(MSG_DEBUG, "EAP-EKE: IV for Encr(key, y)",
     392                 :            :                     iv, AES_BLOCK_SIZE);
     393                 :         16 :         os_memcpy(pub, dhpub, dh_len);
     394         [ -  + ]:         16 :         if (aes_128_cbc_encrypt(key, iv, pub, dh_len) < 0)
     395                 :          0 :                 return -1;
     396                 :         16 :         os_memcpy(ret_dhcomp, iv, AES_BLOCK_SIZE);
     397                 :         16 :         os_memcpy(ret_dhcomp + AES_BLOCK_SIZE, pub, dh_len);
     398                 :         16 :         wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent = Encr(key, y)",
     399                 :         16 :                     ret_dhcomp, AES_BLOCK_SIZE + dh_len);
     400                 :            : 
     401                 :         16 :         return 0;
     402                 :            : }
     403                 :            : 
     404                 :            : 
     405                 :         16 : int eap_eke_shared_secret(struct eap_eke_session *sess, const u8 *key,
     406                 :            :                           const u8 *dhpriv, const u8 *peer_dhcomp)
     407                 :            : {
     408                 :            :         u8 zeros[EAP_EKE_MAX_HASH_LEN];
     409                 :            :         u8 peer_pub[EAP_EKE_MAX_DH_LEN];
     410                 :            :         u8 modexp[EAP_EKE_MAX_DH_LEN];
     411                 :            :         size_t len;
     412                 :            :         const struct dh_group *dh;
     413                 :            : 
     414         [ -  + ]:         16 :         if (sess->encr != EAP_EKE_ENCR_AES128_CBC)
     415                 :          0 :                 return -1;
     416                 :            : 
     417                 :         16 :         dh = eap_eke_dh_group(sess->dhgroup);
     418         [ -  + ]:         16 :         if (dh == NULL)
     419                 :          0 :                 return -1;
     420                 :            : 
     421                 :            :         /* Decrypt peer DHComponent */
     422                 :         16 :         os_memcpy(peer_pub, peer_dhcomp + AES_BLOCK_SIZE, dh->prime_len);
     423         [ -  + ]:         16 :         if (aes_128_cbc_decrypt(key, peer_dhcomp, peer_pub, dh->prime_len) < 0) {
     424                 :          0 :                 wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt DHComponent");
     425                 :          0 :                 return -1;
     426                 :            :         }
     427                 :         16 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Decrypted peer DH pubkey",
     428                 :            :                         peer_pub, dh->prime_len);
     429                 :            : 
     430                 :            :         /* SharedSecret = prf(0+, g ^ (x_s * x_p) (mod p)) */
     431                 :         16 :         len = dh->prime_len;
     432         [ -  + ]:         16 :         if (crypto_mod_exp(peer_pub, dh->prime_len, dhpriv, dh->prime_len,
     433                 :            :                            dh->prime, dh->prime_len, modexp, &len) < 0)
     434                 :          0 :                 return -1;
     435         [ -  + ]:         16 :         if (len < dh->prime_len) {
     436                 :          0 :                 size_t pad = dh->prime_len - len;
     437                 :          0 :                 os_memmove(modexp + pad, modexp, len);
     438                 :          0 :                 os_memset(modexp, 0, pad);
     439                 :            :         }
     440                 :            : 
     441                 :         16 :         os_memset(zeros, 0, sess->auth_len);
     442         [ -  + ]:         16 :         if (eap_eke_prf(sess->prf, zeros, sess->auth_len, modexp, dh->prime_len,
     443                 :         16 :                         NULL, 0, sess->shared_secret) < 0)
     444                 :          0 :                 return -1;
     445                 :         16 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: SharedSecret",
     446                 :         32 :                         sess->shared_secret, sess->auth_len);
     447                 :            : 
     448                 :         16 :         return 0;
     449                 :            : }
     450                 :            : 
     451                 :            : 
     452                 :         16 : int eap_eke_derive_ke_ki(struct eap_eke_session *sess,
     453                 :            :                          const u8 *id_s, size_t id_s_len,
     454                 :            :                          const u8 *id_p, size_t id_p_len)
     455                 :            : {
     456                 :            :         u8 buf[EAP_EKE_MAX_KE_LEN + EAP_EKE_MAX_KI_LEN];
     457                 :            :         size_t ke_len, ki_len;
     458                 :            :         u8 *data;
     459                 :            :         size_t data_len;
     460                 :         16 :         const char *label = "EAP-EKE Keys";
     461                 :            :         size_t label_len;
     462                 :            : 
     463                 :            :         /*
     464                 :            :          * Ke | Ki = prf+(SharedSecret, "EAP-EKE Keys" | ID_S | ID_P)
     465                 :            :          * Ke = encryption key
     466                 :            :          * Ki = integrity protection key
     467                 :            :          * Length of each key depends on the selected algorithms.
     468                 :            :          */
     469                 :            : 
     470         [ +  - ]:         16 :         if (sess->encr == EAP_EKE_ENCR_AES128_CBC)
     471                 :         16 :                 ke_len = 16;
     472                 :            :         else
     473                 :          0 :                 return -1;
     474                 :            : 
     475         [ +  + ]:         16 :         if (sess->mac == EAP_EKE_PRF_HMAC_SHA1)
     476                 :          2 :                 ki_len = 20;
     477         [ +  - ]:         14 :         else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256)
     478                 :         14 :                 ki_len = 32;
     479                 :            :         else
     480                 :          0 :                 return -1;
     481                 :            : 
     482                 :         16 :         label_len = os_strlen(label);
     483                 :         16 :         data_len = label_len + id_s_len + id_p_len;
     484                 :         16 :         data = os_malloc(data_len);
     485         [ -  + ]:         16 :         if (data == NULL)
     486                 :          0 :                 return -1;
     487                 :         16 :         os_memcpy(data, label, label_len);
     488                 :         16 :         os_memcpy(data + label_len, id_s, id_s_len);
     489                 :         16 :         os_memcpy(data + label_len + id_s_len, id_p, id_p_len);
     490         [ -  + ]:         16 :         if (eap_eke_prfplus(sess->prf, sess->shared_secret, sess->prf_len,
     491                 :            :                             data, data_len, buf, ke_len + ki_len) < 0) {
     492                 :          0 :                 os_free(data);
     493                 :          0 :                 return -1;
     494                 :            :         }
     495                 :            : 
     496                 :         16 :         os_memcpy(sess->ke, buf, ke_len);
     497                 :         16 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ke", sess->ke, ke_len);
     498                 :         16 :         os_memcpy(sess->ki, buf + ke_len, ki_len);
     499                 :         16 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ki", sess->ki, ki_len);
     500                 :            : 
     501                 :         16 :         os_free(data);
     502                 :         16 :         return 0;
     503                 :            : }
     504                 :            : 
     505                 :            : 
     506                 :         14 : int eap_eke_derive_ka(struct eap_eke_session *sess,
     507                 :            :                       const u8 *id_s, size_t id_s_len,
     508                 :            :                       const u8 *id_p, size_t id_p_len,
     509                 :            :                       const u8 *nonce_p, const u8 *nonce_s)
     510                 :            : {
     511                 :            :         u8 *data, *pos;
     512                 :            :         size_t data_len;
     513                 :         14 :         const char *label = "EAP-EKE Ka";
     514                 :            :         size_t label_len;
     515                 :            : 
     516                 :            :         /*
     517                 :            :          * Ka = prf+(SharedSecret, "EAP-EKE Ka" | ID_S | ID_P | Nonce_P |
     518                 :            :          *           Nonce_S)
     519                 :            :          * Ka = authentication key
     520                 :            :          * Length of the key depends on the selected algorithms.
     521                 :            :          */
     522                 :            : 
     523                 :         14 :         label_len = os_strlen(label);
     524                 :         14 :         data_len = label_len + id_s_len + id_p_len + 2 * sess->nonce_len;
     525                 :         14 :         data = os_malloc(data_len);
     526         [ -  + ]:         14 :         if (data == NULL)
     527                 :          0 :                 return -1;
     528                 :         14 :         pos = data;
     529                 :         14 :         os_memcpy(pos, label, label_len);
     530                 :         14 :         pos += label_len;
     531                 :         14 :         os_memcpy(pos, id_s, id_s_len);
     532                 :         14 :         pos += id_s_len;
     533                 :         14 :         os_memcpy(pos, id_p, id_p_len);
     534                 :         14 :         pos += id_p_len;
     535                 :         14 :         os_memcpy(pos, nonce_p, sess->nonce_len);
     536                 :         14 :         pos += sess->nonce_len;
     537                 :         14 :         os_memcpy(pos, nonce_s, sess->nonce_len);
     538         [ -  + ]:         14 :         if (eap_eke_prfplus(sess->prf, sess->shared_secret, sess->prf_len,
     539                 :         28 :                             data, data_len, sess->ka, sess->prf_len) < 0) {
     540                 :          0 :                 os_free(data);
     541                 :          0 :                 return -1;
     542                 :            :         }
     543                 :         14 :         os_free(data);
     544                 :            : 
     545                 :         14 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ka", sess->ka, sess->prf_len);
     546                 :            : 
     547                 :         14 :         return 0;
     548                 :            : }
     549                 :            : 
     550                 :            : 
     551                 :         14 : int eap_eke_derive_msk(struct eap_eke_session *sess,
     552                 :            :                        const u8 *id_s, size_t id_s_len,
     553                 :            :                        const u8 *id_p, size_t id_p_len,
     554                 :            :                        const u8 *nonce_p, const u8 *nonce_s,
     555                 :            :                        u8 *msk, u8 *emsk)
     556                 :            : {
     557                 :            :         u8 *data, *pos;
     558                 :            :         size_t data_len;
     559                 :         14 :         const char *label = "EAP-EKE Exported Keys";
     560                 :            :         size_t label_len;
     561                 :            :         u8 buf[EAP_MSK_LEN + EAP_EMSK_LEN];
     562                 :            : 
     563                 :            :         /*
     564                 :            :          * MSK | EMSK = prf+(SharedSecret, "EAP-EKE Exported Keys" | ID_S |
     565                 :            :          *                   ID_P | Nonce_P | Nonce_S)
     566                 :            :          */
     567                 :            : 
     568                 :         14 :         label_len = os_strlen(label);
     569                 :         14 :         data_len = label_len + id_s_len + id_p_len + 2 * sess->nonce_len;
     570                 :         14 :         data = os_malloc(data_len);
     571         [ -  + ]:         14 :         if (data == NULL)
     572                 :          0 :                 return -1;
     573                 :         14 :         pos = data;
     574                 :         14 :         os_memcpy(pos, label, label_len);
     575                 :         14 :         pos += label_len;
     576                 :         14 :         os_memcpy(pos, id_s, id_s_len);
     577                 :         14 :         pos += id_s_len;
     578                 :         14 :         os_memcpy(pos, id_p, id_p_len);
     579                 :         14 :         pos += id_p_len;
     580                 :         14 :         os_memcpy(pos, nonce_p, sess->nonce_len);
     581                 :         14 :         pos += sess->nonce_len;
     582                 :         14 :         os_memcpy(pos, nonce_s, sess->nonce_len);
     583         [ -  + ]:         14 :         if (eap_eke_prfplus(sess->prf, sess->shared_secret, sess->prf_len,
     584                 :            :                             data, data_len, buf, EAP_MSK_LEN + EAP_EMSK_LEN) <
     585                 :            :             0) {
     586                 :          0 :                 os_free(data);
     587                 :          0 :                 return -1;
     588                 :            :         }
     589                 :         14 :         os_free(data);
     590                 :            : 
     591                 :         14 :         os_memcpy(msk, buf, EAP_MSK_LEN);
     592                 :         14 :         os_memcpy(emsk, buf + EAP_MSK_LEN, EAP_EMSK_LEN);
     593                 :         14 :         os_memset(buf, 0, sizeof(buf));
     594                 :            : 
     595                 :         14 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: MSK", msk, EAP_MSK_LEN);
     596                 :         14 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: EMSK", msk, EAP_EMSK_LEN);
     597                 :            : 
     598                 :         14 :         return 0;
     599                 :            : }
     600                 :            : 
     601                 :            : 
     602                 :         44 : static int eap_eke_mac(u8 mac, const u8 *key, const u8 *data, size_t data_len,
     603                 :            :                        u8 *res)
     604                 :            : {
     605         [ +  + ]:         44 :         if (mac == EAP_EKE_MAC_HMAC_SHA1)
     606                 :          6 :                 return hmac_sha1(key, SHA1_MAC_LEN, data, data_len, res);
     607         [ +  - ]:         38 :         if (mac == EAP_EKE_MAC_HMAC_SHA2_256)
     608                 :         38 :                 return hmac_sha256(key, SHA256_MAC_LEN, data, data_len, res);
     609                 :         44 :         return -1;
     610                 :            : }
     611                 :            : 
     612                 :            : 
     613                 :         22 : int eap_eke_prot(struct eap_eke_session *sess,
     614                 :            :                  const u8 *data, size_t data_len,
     615                 :            :                  u8 *prot, size_t *prot_len)
     616                 :            : {
     617                 :            :         size_t block_size, icv_len, pad;
     618                 :            :         u8 *pos, *iv, *e;
     619                 :            : 
     620         [ +  - ]:         22 :         if (sess->encr == EAP_EKE_ENCR_AES128_CBC)
     621                 :         22 :                 block_size = AES_BLOCK_SIZE;
     622                 :            :         else
     623                 :          0 :                 return -1;
     624                 :            : 
     625         [ +  + ]:         22 :         if (sess->mac == EAP_EKE_PRF_HMAC_SHA1)
     626                 :          3 :                 icv_len = SHA1_MAC_LEN;
     627         [ +  - ]:         19 :         else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256)
     628                 :         19 :                 icv_len = SHA256_MAC_LEN;
     629                 :            :         else
     630                 :          0 :                 return -1;
     631                 :            : 
     632                 :         22 :         pad = data_len % block_size;
     633         [ -  + ]:         22 :         if (pad)
     634                 :          0 :                 pad = block_size - pad;
     635                 :            : 
     636         [ -  + ]:         22 :         if (*prot_len < block_size + data_len + pad + icv_len) {
     637                 :          0 :                 wpa_printf(MSG_INFO, "EAP-EKE: Not enough room for Prot() data");
     638                 :            :         }
     639                 :         22 :         pos = prot;
     640                 :            : 
     641         [ -  + ]:         22 :         if (random_get_bytes(pos, block_size))
     642                 :          0 :                 return -1;
     643                 :         22 :         iv = pos;
     644                 :         22 :         wpa_hexdump(MSG_DEBUG, "EAP-EKE: IV for Prot()", iv, block_size);
     645                 :         22 :         pos += block_size;
     646                 :            : 
     647                 :         22 :         e = pos;
     648                 :         22 :         os_memcpy(pos, data, data_len);
     649                 :         22 :         pos += data_len;
     650         [ -  + ]:         22 :         if (pad) {
     651         [ #  # ]:          0 :                 if (random_get_bytes(pos, pad))
     652                 :          0 :                         return -1;
     653                 :          0 :                 pos += pad;
     654                 :            :         }
     655                 :            : 
     656         [ -  + ]:         22 :         if (aes_128_cbc_encrypt(sess->ke, iv, e, data_len + pad) < 0)
     657                 :          0 :                 return -1;
     658                 :            : 
     659         [ -  + ]:         22 :         if (eap_eke_mac(sess->mac, sess->ki, e, data_len + pad, pos) < 0)
     660                 :          0 :                 return -1;
     661                 :         22 :         pos += icv_len;
     662                 :            : 
     663                 :         22 :         *prot_len = pos - prot;
     664                 :         22 :         return 0;
     665                 :            : }
     666                 :            : 
     667                 :            : 
     668                 :         22 : int eap_eke_decrypt_prot(struct eap_eke_session *sess,
     669                 :            :                          const u8 *prot, size_t prot_len,
     670                 :            :                          u8 *data, size_t *data_len)
     671                 :            : {
     672                 :            :         size_t block_size, icv_len;
     673                 :            :         u8 icv[EAP_EKE_MAX_HASH_LEN];
     674                 :            : 
     675         [ +  - ]:         22 :         if (sess->encr == EAP_EKE_ENCR_AES128_CBC)
     676                 :         22 :                 block_size = AES_BLOCK_SIZE;
     677                 :            :         else
     678                 :          0 :                 return -1;
     679                 :            : 
     680         [ +  + ]:         22 :         if (sess->mac == EAP_EKE_PRF_HMAC_SHA1)
     681                 :          3 :                 icv_len = SHA1_MAC_LEN;
     682         [ +  - ]:         19 :         else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256)
     683                 :         19 :                 icv_len = SHA256_MAC_LEN;
     684                 :            :         else
     685                 :          0 :                 return -1;
     686                 :            : 
     687         [ -  + ]:         22 :         if (prot_len < 2 * block_size + icv_len)
     688                 :          0 :                 return -1;
     689         [ -  + ]:         22 :         if ((prot_len - icv_len) % block_size)
     690                 :          0 :                 return -1;
     691                 :            : 
     692         [ -  + ]:         22 :         if (eap_eke_mac(sess->mac, sess->ki, prot + block_size,
     693                 :         22 :                         prot_len - block_size - icv_len, icv) < 0)
     694                 :          0 :                 return -1;
     695         [ +  + ]:         22 :         if (os_memcmp(icv, prot + prot_len - icv_len, icv_len) != 0) {
     696                 :          1 :                 wpa_printf(MSG_INFO, "EAP-EKE: ICV mismatch in Prot() data");
     697                 :          1 :                 return -1;
     698                 :            :         }
     699                 :            : 
     700         [ -  + ]:         21 :         if (*data_len < prot_len - block_size - icv_len) {
     701                 :          0 :                 wpa_printf(MSG_INFO, "EAP-EKE: Not enough room for decrypted Prot() data");
     702                 :          0 :                 return -1;
     703                 :            :         }
     704                 :            : 
     705                 :         21 :         *data_len = prot_len - block_size - icv_len;
     706                 :         21 :         os_memcpy(data, prot + block_size, *data_len);
     707         [ -  + ]:         21 :         if (aes_128_cbc_decrypt(sess->ke, prot, data, *data_len) < 0) {
     708                 :          0 :                 wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt Prot() data");
     709                 :          0 :                 return -1;
     710                 :            :         }
     711                 :         21 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Decrypted Prot() data",
     712                 :            :                         data, *data_len);
     713                 :            : 
     714                 :         22 :         return 0;
     715                 :            : }
     716                 :            : 
     717                 :            : 
     718                 :         28 : int eap_eke_auth(struct eap_eke_session *sess, const char *label,
     719                 :            :                  const struct wpabuf *msgs, u8 *auth)
     720                 :            : {
     721                 :         28 :         wpa_printf(MSG_DEBUG, "EAP-EKE: Auth(%s)", label);
     722                 :         28 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ka for Auth",
     723                 :         56 :                         sess->ka, sess->auth_len);
     724                 :         28 :         wpa_hexdump_buf(MSG_MSGDUMP, "EAP-EKE: Messages for Auth", msgs);
     725                 :         56 :         return eap_eke_prf(sess->prf, sess->ka, sess->auth_len,
     726                 :            :                            (const u8 *) label, os_strlen(label),
     727                 :         28 :                            wpabuf_head(msgs), wpabuf_len(msgs), auth);
     728                 :            : }
     729                 :            : 
     730                 :            : 
     731                 :         16 : int eap_eke_session_init(struct eap_eke_session *sess, u8 dhgroup, u8 encr,
     732                 :            :                          u8 prf, u8 mac)
     733                 :            : {
     734                 :         16 :         sess->dhgroup = dhgroup;
     735                 :         16 :         sess->encr = encr;
     736                 :         16 :         sess->prf = prf;
     737                 :         16 :         sess->mac = mac;
     738                 :            : 
     739                 :         16 :         sess->prf_len = eap_eke_prf_len(prf);
     740         [ -  + ]:         16 :         if (sess->prf_len < 0)
     741                 :          0 :                 return -1;
     742                 :         16 :         sess->nonce_len = eap_eke_nonce_len(prf);
     743         [ -  + ]:         16 :         if (sess->nonce_len < 0)
     744                 :          0 :                 return -1;
     745                 :         16 :         sess->auth_len = eap_eke_auth_len(prf);
     746         [ -  + ]:         16 :         if (sess->auth_len < 0)
     747                 :          0 :                 return -1;
     748                 :         16 :         sess->dhcomp_len = eap_eke_dhcomp_len(sess->dhgroup, sess->encr);
     749         [ -  + ]:         16 :         if (sess->dhcomp_len < 0)
     750                 :          0 :                 return -1;
     751                 :         16 :         sess->pnonce_len = eap_eke_pnonce_len(sess->mac);
     752         [ -  + ]:         16 :         if (sess->pnonce_len < 0)
     753                 :          0 :                 return -1;
     754                 :         16 :         sess->pnonce_ps_len = eap_eke_pnonce_ps_len(sess->mac);
     755         [ -  + ]:         16 :         if (sess->pnonce_ps_len < 0)
     756                 :          0 :                 return -1;
     757                 :            : 
     758                 :         16 :         return 0;
     759                 :            : }
     760                 :            : 
     761                 :            : 
     762                 :         34 : void eap_eke_session_clean(struct eap_eke_session *sess)
     763                 :            : {
     764                 :         34 :         os_memset(sess->shared_secret, 0, EAP_EKE_MAX_HASH_LEN);
     765                 :         34 :         os_memset(sess->ke, 0, EAP_EKE_MAX_KE_LEN);
     766                 :         34 :         os_memset(sess->ki, 0, EAP_EKE_MAX_KI_LEN);
     767                 :         34 :         os_memset(sess->ka, 0, EAP_EKE_MAX_KA_LEN);
     768                 :         34 : }

Generated by: LCOV version 1.9