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 1401264779 Lines: 314 398 78.9 %
Date: 2014-05-28 Functions: 26 26 100.0 %

          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          36 : static int eap_eke_dh_len(u8 group)
      24             : {
      25          36 :         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          24 :                 return 512;
      36             :         }
      37             : 
      38           0 :         return -1;
      39             : }
      40             : 
      41             : 
      42          18 : static int eap_eke_dhcomp_len(u8 dhgroup, u8 encr)
      43             : {
      44             :         int dhlen;
      45             : 
      46          18 :         dhlen = eap_eke_dh_len(dhgroup);
      47          18 :         if (dhlen < 0)
      48           0 :                 return -1;
      49          18 :         if (encr != EAP_EKE_ENCR_AES128_CBC)
      50           0 :                 return -1;
      51          18 :         return AES_BLOCK_SIZE + dhlen;
      52             : }
      53             : 
      54             : 
      55          36 : static const struct dh_group * eap_eke_dh_group(u8 group)
      56             : {
      57          36 :         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          24 :                 return dh_groups_get(16);
      68             :         }
      69             : 
      70           0 :         return NULL;
      71             : }
      72             : 
      73             : 
      74          18 : static int eap_eke_dh_generator(u8 group)
      75             : {
      76          18 :         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          12 :                 return 5;
      87             :         }
      88             : 
      89           0 :         return -1;
      90             : }
      91             : 
      92             : 
      93          18 : static int eap_eke_pnonce_len(u8 mac)
      94             : {
      95             :         int mac_len;
      96             : 
      97          18 :         if (mac == EAP_EKE_MAC_HMAC_SHA1)
      98           2 :                 mac_len = SHA1_MAC_LEN;
      99          16 :         else if (mac == EAP_EKE_MAC_HMAC_SHA2_256)
     100          16 :                 mac_len = SHA256_MAC_LEN;
     101             :         else
     102           0 :                 return -1;
     103             : 
     104          18 :         return AES_BLOCK_SIZE + 16 + mac_len;
     105             : }
     106             : 
     107             : 
     108          18 : static int eap_eke_pnonce_ps_len(u8 mac)
     109             : {
     110             :         int mac_len;
     111             : 
     112          18 :         if (mac == EAP_EKE_MAC_HMAC_SHA1)
     113           2 :                 mac_len = SHA1_MAC_LEN;
     114          16 :         else if (mac == EAP_EKE_MAC_HMAC_SHA2_256)
     115          16 :                 mac_len = SHA256_MAC_LEN;
     116             :         else
     117           0 :                 return -1;
     118             : 
     119          18 :         return AES_BLOCK_SIZE + 2 * 16 + mac_len;
     120             : }
     121             : 
     122             : 
     123          36 : static int eap_eke_prf_len(u8 prf)
     124             : {
     125          36 :         if (prf == EAP_EKE_PRF_HMAC_SHA1)
     126           4 :                 return 20;
     127          32 :         if (prf == EAP_EKE_PRF_HMAC_SHA2_256)
     128          32 :                 return 32;
     129           0 :         return -1;
     130             : }
     131             : 
     132             : 
     133          18 : static int eap_eke_nonce_len(u8 prf)
     134             : {
     135             :         int prf_len;
     136             : 
     137          18 :         prf_len = eap_eke_prf_len(prf);
     138          18 :         if (prf_len < 0)
     139           0 :                 return -1;
     140             : 
     141          18 :         if (prf_len > 2 * 16)
     142           0 :                 return (prf_len + 1) / 2;
     143             : 
     144          18 :         return 16;
     145             : }
     146             : 
     147             : 
     148          18 : static int eap_eke_auth_len(u8 prf)
     149             : {
     150          18 :         switch (prf) {
     151             :         case EAP_EKE_PRF_HMAC_SHA1:
     152           2 :                 return SHA1_MAC_LEN;
     153             :         case EAP_EKE_PRF_HMAC_SHA2_256:
     154          16 :                 return SHA256_MAC_LEN;
     155             :         }
     156             : 
     157           0 :         return -1;
     158             : }
     159             : 
     160             : 
     161          18 : 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          18 :         generator = eap_eke_dh_generator(group);
     169          18 :         if (generator < 0 || generator > 255)
     170           0 :                 return -1;
     171          18 :         gen = generator;
     172             : 
     173          18 :         dh = eap_eke_dh_group(group);
     174          18 :         if (dh == NULL)
     175           0 :                 return -1;
     176             : 
     177             :         /* x = random number 2 .. p-1 */
     178          18 :         if (random_get_bytes(ret_priv, dh->prime_len))
     179           0 :                 return -1;
     180          18 :         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          18 :         for (i = 0; i < dh->prime_len - 1; i++) {
     185          18 :                 if (ret_priv[i])
     186          18 :                         break;
     187             :         }
     188          18 :         if (i == dh->prime_len - 1 && (ret_priv[i] == 0 || ret_priv[i] == 1))
     189           0 :                 return -1;
     190          18 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: DH private value",
     191             :                         ret_priv, dh->prime_len);
     192             : 
     193             :         /* y = g ^ x (mod p) */
     194          18 :         pub_len = dh->prime_len;
     195          18 :         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          18 :         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          18 :         wpa_hexdump(MSG_DEBUG, "EAP-EKE: DH public value",
     205             :                     ret_pub, dh->prime_len);
     206             : 
     207          18 :         return 0;
     208             : }
     209             : 
     210             : 
     211          68 : 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          68 :         size_t num_elem = 1;
     218             : 
     219          68 :         addr[0] = data;
     220          68 :         len[0] = data_len;
     221          68 :         if (data2) {
     222          32 :                 num_elem++;
     223          32 :                 addr[1] = data2;
     224          32 :                 len[1] = data2_len;
     225             :         }
     226             : 
     227          68 :         if (prf == EAP_EKE_PRF_HMAC_SHA1)
     228           8 :                 return hmac_sha1_vector(key, key_len, num_elem, addr, len, res);
     229          60 :         if (prf == EAP_EKE_PRF_HMAC_SHA2_256)
     230          60 :                 return hmac_sha256_vector(key, key_len, num_elem, addr, len,
     231             :                                           res);
     232           0 :         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          38 :         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          60 : 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          60 :         idx = 0;
     287          60 :         addr[0] = hash;
     288          60 :         vlen[0] = SHA256_MAC_LEN;
     289          60 :         addr[1] = data;
     290          60 :         vlen[1] = data_len;
     291          60 :         addr[2] = &idx;
     292          60 :         vlen[2] = 1;
     293             : 
     294         238 :         while (len > 0) {
     295         118 :                 idx++;
     296         118 :                 if (idx == 1)
     297          60 :                         ret = hmac_sha256_vector(key, key_len, 2, &addr[1],
     298             :                                                  &vlen[1], hash);
     299             :                 else
     300          58 :                         ret = hmac_sha256_vector(key, key_len, 3, addr, vlen,
     301             :                                                  hash);
     302         118 :                 if (ret < 0)
     303           0 :                         return -1;
     304         118 :                 if (len > SHA256_MAC_LEN) {
     305          58 :                         os_memcpy(res, hash, SHA256_MAC_LEN);
     306          58 :                         res += SHA256_MAC_LEN;
     307          58 :                         len -= SHA256_MAC_LEN;
     308             :                 } else {
     309          60 :                         os_memcpy(res, hash, len);
     310          60 :                         len = 0;
     311             :                 }
     312             :         }
     313             : 
     314          60 :         return 0;
     315             : }
     316             : 
     317             : 
     318          68 : 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          68 :         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          60 :         if (prf == EAP_EKE_PRF_HMAC_SHA2_256)
     325          60 :                 return eap_eke_prf_hmac_sha256(key, key_len, data, data_len,
     326             :                                                res, len);
     327           0 :         return -1;
     328             : }
     329             : 
     330             : 
     331          18 : 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          18 :         size_t key_len = 16; /* Only AES-128-CBC is used here */
     339             :         u8 *id;
     340             : 
     341             :         /* temp = prf(0+, password) */
     342          18 :         os_memset(zeros, 0, sess->prf_len);
     343          18 :         if (eap_eke_prf(sess->prf, zeros, sess->prf_len,
     344             :                         password, password_len, NULL, 0, temp) < 0)
     345           0 :                 return -1;
     346          18 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: temp = prf(0+, password)",
     347          18 :                         temp, sess->prf_len);
     348             : 
     349             :         /* key = prf+(temp, ID_S | ID_P) */
     350          18 :         id = os_malloc(id_s_len + id_p_len);
     351          18 :         if (id == NULL)
     352           0 :                 return -1;
     353          18 :         os_memcpy(id, id_s, id_s_len);
     354          18 :         os_memcpy(id + id_s_len, id_p, id_p_len);
     355          18 :         wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: ID_S | ID_P",
     356             :                           id, id_s_len + id_p_len);
     357          18 :         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          18 :         os_free(id);
     363          18 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: key = prf+(temp, ID_S | ID_P)",
     364             :                         key, key_len);
     365             : 
     366          18 :         return 0;
     367             : }
     368             : 
     369             : 
     370          18 : 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          18 :         dh_len = eap_eke_dh_len(sess->dhgroup);
     378          18 :         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          18 :         if (sess->encr != EAP_EKE_ENCR_AES128_CBC)
     388           0 :                 return -1;
     389          18 :         if (random_get_bytes(iv, AES_BLOCK_SIZE))
     390           0 :                 return -1;
     391          18 :         wpa_hexdump(MSG_DEBUG, "EAP-EKE: IV for Encr(key, y)",
     392             :                     iv, AES_BLOCK_SIZE);
     393          18 :         os_memcpy(pub, dhpub, dh_len);
     394          18 :         if (aes_128_cbc_encrypt(key, iv, pub, dh_len) < 0)
     395           0 :                 return -1;
     396          18 :         os_memcpy(ret_dhcomp, iv, AES_BLOCK_SIZE);
     397          18 :         os_memcpy(ret_dhcomp + AES_BLOCK_SIZE, pub, dh_len);
     398          18 :         wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent = Encr(key, y)",
     399          18 :                     ret_dhcomp, AES_BLOCK_SIZE + dh_len);
     400             : 
     401          18 :         return 0;
     402             : }
     403             : 
     404             : 
     405          18 : 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          18 :         if (sess->encr != EAP_EKE_ENCR_AES128_CBC)
     415           0 :                 return -1;
     416             : 
     417          18 :         dh = eap_eke_dh_group(sess->dhgroup);
     418          18 :         if (dh == NULL)
     419           0 :                 return -1;
     420             : 
     421             :         /* Decrypt peer DHComponent */
     422          18 :         os_memcpy(peer_pub, peer_dhcomp + AES_BLOCK_SIZE, dh->prime_len);
     423          18 :         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          18 :         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          18 :         len = dh->prime_len;
     432          18 :         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          18 :         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          18 :         os_memset(zeros, 0, sess->auth_len);
     442          18 :         if (eap_eke_prf(sess->prf, zeros, sess->auth_len, modexp, dh->prime_len,
     443          18 :                         NULL, 0, sess->shared_secret) < 0)
     444           0 :                 return -1;
     445          36 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: SharedSecret",
     446          36 :                         sess->shared_secret, sess->auth_len);
     447             : 
     448          18 :         return 0;
     449             : }
     450             : 
     451             : 
     452          18 : 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          18 :         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          18 :         if (sess->encr == EAP_EKE_ENCR_AES128_CBC)
     471          18 :                 ke_len = 16;
     472             :         else
     473           0 :                 return -1;
     474             : 
     475          18 :         if (sess->mac == EAP_EKE_PRF_HMAC_SHA1)
     476           2 :                 ki_len = 20;
     477          16 :         else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256)
     478          16 :                 ki_len = 32;
     479             :         else
     480           0 :                 return -1;
     481             : 
     482          18 :         label_len = os_strlen(label);
     483          18 :         data_len = label_len + id_s_len + id_p_len;
     484          18 :         data = os_malloc(data_len);
     485          18 :         if (data == NULL)
     486           0 :                 return -1;
     487          18 :         os_memcpy(data, label, label_len);
     488          18 :         os_memcpy(data + label_len, id_s, id_s_len);
     489          18 :         os_memcpy(data + label_len + id_s_len, id_p, id_p_len);
     490          18 :         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          18 :         os_memcpy(sess->ke, buf, ke_len);
     497          18 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ke", sess->ke, ke_len);
     498          18 :         os_memcpy(sess->ki, buf + ke_len, ki_len);
     499          18 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ki", sess->ki, ki_len);
     500             : 
     501          18 :         os_free(data);
     502          18 :         return 0;
     503             : }
     504             : 
     505             : 
     506          16 : 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          16 :         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          16 :         label_len = os_strlen(label);
     524          16 :         data_len = label_len + id_s_len + id_p_len + 2 * sess->nonce_len;
     525          16 :         data = os_malloc(data_len);
     526          16 :         if (data == NULL)
     527           0 :                 return -1;
     528          16 :         pos = data;
     529          16 :         os_memcpy(pos, label, label_len);
     530          16 :         pos += label_len;
     531          16 :         os_memcpy(pos, id_s, id_s_len);
     532          16 :         pos += id_s_len;
     533          16 :         os_memcpy(pos, id_p, id_p_len);
     534          16 :         pos += id_p_len;
     535          16 :         os_memcpy(pos, nonce_p, sess->nonce_len);
     536          16 :         pos += sess->nonce_len;
     537          16 :         os_memcpy(pos, nonce_s, sess->nonce_len);
     538          32 :         if (eap_eke_prfplus(sess->prf, sess->shared_secret, sess->prf_len,
     539          32 :                             data, data_len, sess->ka, sess->prf_len) < 0) {
     540           0 :                 os_free(data);
     541           0 :                 return -1;
     542             :         }
     543          16 :         os_free(data);
     544             : 
     545          16 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ka", sess->ka, sess->prf_len);
     546             : 
     547          16 :         return 0;
     548             : }
     549             : 
     550             : 
     551          16 : 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          16 :         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          16 :         label_len = os_strlen(label);
     569          16 :         data_len = label_len + id_s_len + id_p_len + 2 * sess->nonce_len;
     570          16 :         data = os_malloc(data_len);
     571          16 :         if (data == NULL)
     572           0 :                 return -1;
     573          16 :         pos = data;
     574          16 :         os_memcpy(pos, label, label_len);
     575          16 :         pos += label_len;
     576          16 :         os_memcpy(pos, id_s, id_s_len);
     577          16 :         pos += id_s_len;
     578          16 :         os_memcpy(pos, id_p, id_p_len);
     579          16 :         pos += id_p_len;
     580          16 :         os_memcpy(pos, nonce_p, sess->nonce_len);
     581          16 :         pos += sess->nonce_len;
     582          16 :         os_memcpy(pos, nonce_s, sess->nonce_len);
     583          16 :         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          16 :         os_free(data);
     590             : 
     591          16 :         os_memcpy(msk, buf, EAP_MSK_LEN);
     592          16 :         os_memcpy(emsk, buf + EAP_MSK_LEN, EAP_EMSK_LEN);
     593          16 :         os_memset(buf, 0, sizeof(buf));
     594             : 
     595          16 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: MSK", msk, EAP_MSK_LEN);
     596          16 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: EMSK", msk, EAP_EMSK_LEN);
     597             : 
     598          16 :         return 0;
     599             : }
     600             : 
     601             : 
     602          50 : static int eap_eke_mac(u8 mac, const u8 *key, const u8 *data, size_t data_len,
     603             :                        u8 *res)
     604             : {
     605          50 :         if (mac == EAP_EKE_MAC_HMAC_SHA1)
     606           6 :                 return hmac_sha1(key, SHA1_MAC_LEN, data, data_len, res);
     607          44 :         if (mac == EAP_EKE_MAC_HMAC_SHA2_256)
     608          44 :                 return hmac_sha256(key, SHA256_MAC_LEN, data, data_len, res);
     609           0 :         return -1;
     610             : }
     611             : 
     612             : 
     613          25 : 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          25 :         if (sess->encr == EAP_EKE_ENCR_AES128_CBC)
     621          25 :                 block_size = AES_BLOCK_SIZE;
     622             :         else
     623           0 :                 return -1;
     624             : 
     625          25 :         if (sess->mac == EAP_EKE_PRF_HMAC_SHA1)
     626           3 :                 icv_len = SHA1_MAC_LEN;
     627          22 :         else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256)
     628          22 :                 icv_len = SHA256_MAC_LEN;
     629             :         else
     630           0 :                 return -1;
     631             : 
     632          25 :         pad = data_len % block_size;
     633          25 :         if (pad)
     634           0 :                 pad = block_size - pad;
     635             : 
     636          25 :         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          25 :         pos = prot;
     640             : 
     641          25 :         if (random_get_bytes(pos, block_size))
     642           0 :                 return -1;
     643          25 :         iv = pos;
     644          25 :         wpa_hexdump(MSG_DEBUG, "EAP-EKE: IV for Prot()", iv, block_size);
     645          25 :         pos += block_size;
     646             : 
     647          25 :         e = pos;
     648          25 :         os_memcpy(pos, data, data_len);
     649          25 :         pos += data_len;
     650          25 :         if (pad) {
     651           0 :                 if (random_get_bytes(pos, pad))
     652           0 :                         return -1;
     653           0 :                 pos += pad;
     654             :         }
     655             : 
     656          25 :         if (aes_128_cbc_encrypt(sess->ke, iv, e, data_len + pad) < 0)
     657           0 :                 return -1;
     658             : 
     659          25 :         if (eap_eke_mac(sess->mac, sess->ki, e, data_len + pad, pos) < 0)
     660           0 :                 return -1;
     661          25 :         pos += icv_len;
     662             : 
     663          25 :         *prot_len = pos - prot;
     664          25 :         return 0;
     665             : }
     666             : 
     667             : 
     668          25 : 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          25 :         if (sess->encr == EAP_EKE_ENCR_AES128_CBC)
     676          25 :                 block_size = AES_BLOCK_SIZE;
     677             :         else
     678           0 :                 return -1;
     679             : 
     680          25 :         if (sess->mac == EAP_EKE_PRF_HMAC_SHA1)
     681           3 :                 icv_len = SHA1_MAC_LEN;
     682          22 :         else if (sess->mac == EAP_EKE_PRF_HMAC_SHA2_256)
     683          22 :                 icv_len = SHA256_MAC_LEN;
     684             :         else
     685           0 :                 return -1;
     686             : 
     687          25 :         if (prot_len < 2 * block_size + icv_len)
     688           0 :                 return -1;
     689          25 :         if ((prot_len - icv_len) % block_size)
     690           0 :                 return -1;
     691             : 
     692          25 :         if (eap_eke_mac(sess->mac, sess->ki, prot + block_size,
     693          25 :                         prot_len - block_size - icv_len, icv) < 0)
     694           0 :                 return -1;
     695          25 :         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          24 :         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          24 :         *data_len = prot_len - block_size - icv_len;
     706          24 :         os_memcpy(data, prot + block_size, *data_len);
     707          24 :         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          24 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Decrypted Prot() data",
     712             :                         data, *data_len);
     713             : 
     714          24 :         return 0;
     715             : }
     716             : 
     717             : 
     718          32 : int eap_eke_auth(struct eap_eke_session *sess, const char *label,
     719             :                  const struct wpabuf *msgs, u8 *auth)
     720             : {
     721          32 :         wpa_printf(MSG_DEBUG, "EAP-EKE: Auth(%s)", label);
     722          64 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Ka for Auth",
     723          64 :                         sess->ka, sess->auth_len);
     724          32 :         wpa_hexdump_buf(MSG_MSGDUMP, "EAP-EKE: Messages for Auth", msgs);
     725          64 :         return eap_eke_prf(sess->prf, sess->ka, sess->auth_len,
     726             :                            (const u8 *) label, os_strlen(label),
     727          32 :                            wpabuf_head(msgs), wpabuf_len(msgs), auth);
     728             : }
     729             : 
     730             : 
     731          18 : int eap_eke_session_init(struct eap_eke_session *sess, u8 dhgroup, u8 encr,
     732             :                          u8 prf, u8 mac)
     733             : {
     734          18 :         sess->dhgroup = dhgroup;
     735          18 :         sess->encr = encr;
     736          18 :         sess->prf = prf;
     737          18 :         sess->mac = mac;
     738             : 
     739          18 :         sess->prf_len = eap_eke_prf_len(prf);
     740          18 :         if (sess->prf_len < 0)
     741           0 :                 return -1;
     742          18 :         sess->nonce_len = eap_eke_nonce_len(prf);
     743          18 :         if (sess->nonce_len < 0)
     744           0 :                 return -1;
     745          18 :         sess->auth_len = eap_eke_auth_len(prf);
     746          18 :         if (sess->auth_len < 0)
     747           0 :                 return -1;
     748          18 :         sess->dhcomp_len = eap_eke_dhcomp_len(sess->dhgroup, sess->encr);
     749          18 :         if (sess->dhcomp_len < 0)
     750           0 :                 return -1;
     751          18 :         sess->pnonce_len = eap_eke_pnonce_len(sess->mac);
     752          18 :         if (sess->pnonce_len < 0)
     753           0 :                 return -1;
     754          18 :         sess->pnonce_ps_len = eap_eke_pnonce_ps_len(sess->mac);
     755          18 :         if (sess->pnonce_ps_len < 0)
     756           0 :                 return -1;
     757             : 
     758          18 :         return 0;
     759             : }
     760             : 
     761             : 
     762          38 : void eap_eke_session_clean(struct eap_eke_session *sess)
     763             : {
     764          38 :         os_memset(sess->shared_secret, 0, EAP_EKE_MAX_HASH_LEN);
     765          38 :         os_memset(sess->ke, 0, EAP_EKE_MAX_KE_LEN);
     766          38 :         os_memset(sess->ki, 0, EAP_EKE_MAX_KI_LEN);
     767          38 :         os_memset(sess->ka, 0, EAP_EKE_MAX_KA_LEN);
     768          38 : }

Generated by: LCOV version 1.10