LCOV - code coverage report
Current view: top level - src/eap_peer - eap_eke.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1475438200 Lines: 384 401 95.8 %
Date: 2016-10-02 Functions: 20 20 100.0 %

          Line data    Source code
       1             : /*
       2             :  * EAP peer method: EAP-EKE (RFC 6124)
       3             :  * Copyright (c) 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/random.h"
      13             : #include "eap_peer/eap_i.h"
      14             : #include "eap_common/eap_eke_common.h"
      15             : 
      16             : struct eap_eke_data {
      17             :         enum {
      18             :                 IDENTITY, COMMIT, CONFIRM, SUCCESS, FAILURE
      19             :         } state;
      20             :         u8 msk[EAP_MSK_LEN];
      21             :         u8 emsk[EAP_EMSK_LEN];
      22             :         u8 *peerid;
      23             :         size_t peerid_len;
      24             :         u8 *serverid;
      25             :         size_t serverid_len;
      26             :         u8 dh_priv[EAP_EKE_MAX_DH_LEN];
      27             :         struct eap_eke_session sess;
      28             :         u8 nonce_p[EAP_EKE_MAX_NONCE_LEN];
      29             :         u8 nonce_s[EAP_EKE_MAX_NONCE_LEN];
      30             :         struct wpabuf *msgs;
      31             :         u8 dhgroup; /* forced DH group or 0 to allow all supported */
      32             :         u8 encr; /* forced encryption algorithm or 0 to allow all supported */
      33             :         u8 prf; /* forced PRF or 0 to allow all supported */
      34             :         u8 mac; /* forced MAC or 0 to allow all supported */
      35             : };
      36             : 
      37             : 
      38        3200 : static const char * eap_eke_state_txt(int state)
      39             : {
      40        3200 :         switch (state) {
      41             :         case IDENTITY:
      42        1254 :                 return "IDENTITY";
      43             :         case COMMIT:
      44         805 :                 return "COMMIT";
      45             :         case CONFIRM:
      46         715 :                 return "CONFIRM";
      47             :         case SUCCESS:
      48         334 :                 return "SUCCESS";
      49             :         case FAILURE:
      50          92 :                 return "FAILURE";
      51             :         default:
      52           0 :                 return "?";
      53             :         }
      54             : }
      55             : 
      56             : 
      57        1600 : static void eap_eke_state(struct eap_eke_data *data, int state)
      58             : {
      59        3200 :         wpa_printf(MSG_DEBUG, "EAP-EKE: %s -> %s",
      60        1600 :                    eap_eke_state_txt(data->state), eap_eke_state_txt(state));
      61        1600 :         data->state = state;
      62        1600 : }
      63             : 
      64             : 
      65             : static void eap_eke_deinit(struct eap_sm *sm, void *priv);
      66             : 
      67             : 
      68         420 : static void * eap_eke_init(struct eap_sm *sm)
      69             : {
      70             :         struct eap_eke_data *data;
      71             :         const u8 *identity, *password;
      72             :         size_t identity_len, password_len;
      73             :         const char *phase1;
      74             : 
      75         420 :         password = eap_get_config_password(sm, &password_len);
      76         420 :         if (!password) {
      77           0 :                 wpa_printf(MSG_INFO, "EAP-EKE: No password configured");
      78           0 :                 return NULL;
      79             :         }
      80             : 
      81         420 :         data = os_zalloc(sizeof(*data));
      82         420 :         if (data == NULL)
      83           1 :                 return NULL;
      84         419 :         eap_eke_state(data, IDENTITY);
      85             : 
      86         419 :         identity = eap_get_config_identity(sm, &identity_len);
      87         419 :         if (identity) {
      88         419 :                 data->peerid = os_malloc(identity_len);
      89         419 :                 if (data->peerid == NULL) {
      90           1 :                         eap_eke_deinit(sm, data);
      91           1 :                         return NULL;
      92             :                 }
      93         418 :                 os_memcpy(data->peerid, identity, identity_len);
      94         418 :                 data->peerid_len = identity_len;
      95             :         }
      96             : 
      97         418 :         phase1 = eap_get_config_phase1(sm);
      98         418 :         if (phase1) {
      99             :                 const char *pos;
     100             : 
     101         307 :                 pos = os_strstr(phase1, "dhgroup=");
     102         307 :                 if (pos) {
     103         307 :                         data->dhgroup = atoi(pos + 8);
     104         307 :                         wpa_printf(MSG_DEBUG, "EAP-EKE: Forced dhgroup %u",
     105         307 :                                    data->dhgroup);
     106             :                 }
     107             : 
     108         307 :                 pos = os_strstr(phase1, "encr=");
     109         307 :                 if (pos) {
     110         307 :                         data->encr = atoi(pos + 5);
     111         307 :                         wpa_printf(MSG_DEBUG, "EAP-EKE: Forced encr %u",
     112         307 :                                    data->encr);
     113             :                 }
     114             : 
     115         307 :                 pos = os_strstr(phase1, "prf=");
     116         307 :                 if (pos) {
     117         307 :                         data->prf = atoi(pos + 4);
     118         307 :                         wpa_printf(MSG_DEBUG, "EAP-EKE: Forced prf %u",
     119         307 :                                    data->prf);
     120             :                 }
     121             : 
     122         307 :                 pos = os_strstr(phase1, "mac=");
     123         307 :                 if (pos) {
     124         307 :                         data->mac = atoi(pos + 4);
     125         307 :                         wpa_printf(MSG_DEBUG, "EAP-EKE: Forced mac %u",
     126         307 :                                    data->mac);
     127             :                 }
     128             :         }
     129             : 
     130         418 :         return data;
     131             : }
     132             : 
     133             : 
     134         419 : static void eap_eke_deinit(struct eap_sm *sm, void *priv)
     135             : {
     136         419 :         struct eap_eke_data *data = priv;
     137         419 :         eap_eke_session_clean(&data->sess);
     138         419 :         os_free(data->serverid);
     139         419 :         os_free(data->peerid);
     140         419 :         wpabuf_free(data->msgs);
     141         419 :         bin_clear_free(data, sizeof(*data));
     142         419 : }
     143             : 
     144             : 
     145        1199 : static struct wpabuf * eap_eke_build_msg(struct eap_eke_data *data, int id,
     146             :                                          size_t length, u8 eke_exch)
     147             : {
     148             :         struct wpabuf *msg;
     149             :         size_t plen;
     150             : 
     151        1199 :         plen = 1 + length;
     152             : 
     153        1199 :         msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EKE, plen,
     154             :                             EAP_CODE_RESPONSE, id);
     155        1199 :         if (msg == NULL) {
     156           5 :                 wpa_printf(MSG_ERROR, "EAP-EKE: Failed to allocate memory");
     157           5 :                 return NULL;
     158             :         }
     159             : 
     160        1194 :         wpabuf_put_u8(msg, eke_exch);
     161             : 
     162        1194 :         return msg;
     163             : }
     164             : 
     165             : 
     166         719 : static int eap_eke_supp_dhgroup(u8 dhgroup)
     167             : {
     168        1436 :         return dhgroup == EAP_EKE_DHGROUP_EKE_2 ||
     169         717 :                 dhgroup == EAP_EKE_DHGROUP_EKE_5 ||
     170         102 :                 dhgroup == EAP_EKE_DHGROUP_EKE_14 ||
     171         820 :                 dhgroup == EAP_EKE_DHGROUP_EKE_15 ||
     172             :                 dhgroup == EAP_EKE_DHGROUP_EKE_16;
     173             : }
     174             : 
     175             : 
     176         717 : static int eap_eke_supp_encr(u8 encr)
     177             : {
     178         717 :         return encr == EAP_EKE_ENCR_AES128_CBC;
     179             : }
     180             : 
     181             : 
     182         413 : static int eap_eke_supp_prf(u8 prf)
     183             : {
     184         413 :         return prf == EAP_EKE_PRF_HMAC_SHA1 ||
     185             :                 prf == EAP_EKE_PRF_HMAC_SHA2_256;
     186             : }
     187             : 
     188             : 
     189         411 : static int eap_eke_supp_mac(u8 mac)
     190             : {
     191         411 :         return mac == EAP_EKE_MAC_HMAC_SHA1 ||
     192             :                 mac == EAP_EKE_MAC_HMAC_SHA2_256;
     193             : }
     194             : 
     195             : 
     196          92 : static struct wpabuf * eap_eke_build_fail(struct eap_eke_data *data,
     197             :                                           struct eap_method_ret *ret,
     198             :                                           u8 id, u32 failure_code)
     199             : {
     200             :         struct wpabuf *resp;
     201             : 
     202          92 :         wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Failure/Response - code=0x%x",
     203             :                    failure_code);
     204             : 
     205          92 :         resp = eap_eke_build_msg(data, id, 4, EAP_EKE_FAILURE);
     206          92 :         if (resp)
     207          92 :                 wpabuf_put_be32(resp, failure_code);
     208             : 
     209          92 :         os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
     210          92 :         eap_eke_session_clean(&data->sess);
     211             : 
     212          92 :         eap_eke_state(data, FAILURE);
     213          92 :         ret->methodState = METHOD_DONE;
     214          92 :         ret->decision = DECISION_FAIL;
     215          92 :         ret->allowNotifications = FALSE;
     216             : 
     217          92 :         return resp;
     218             : }
     219             : 
     220             : 
     221         415 : static struct wpabuf * eap_eke_process_id(struct eap_eke_data *data,
     222             :                                           struct eap_method_ret *ret,
     223             :                                           const struct wpabuf *reqData,
     224             :                                           const u8 *payload,
     225             :                                           size_t payload_len)
     226             : {
     227             :         struct wpabuf *resp;
     228             :         unsigned num_prop, i;
     229             :         const u8 *pos, *end;
     230         415 :         const u8 *prop = NULL;
     231             :         u8 idtype;
     232         415 :         u8 id = eap_get_id(reqData);
     233             : 
     234         415 :         if (data->state != IDENTITY) {
     235           1 :                 return eap_eke_build_fail(data, ret, id,
     236             :                                           EAP_EKE_FAIL_PROTO_ERROR);
     237             :         }
     238             : 
     239         414 :         wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-ID/Request");
     240             : 
     241         414 :         if (payload_len < 2 + 4) {
     242           2 :                 wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data");
     243           2 :                 return eap_eke_build_fail(data, ret, id,
     244             :                                           EAP_EKE_FAIL_PROTO_ERROR);
     245             :         }
     246             : 
     247         412 :         pos = payload;
     248         412 :         end = payload + payload_len;
     249             : 
     250         412 :         num_prop = *pos++;
     251         412 :         pos++; /* Ignore Reserved field */
     252             : 
     253         412 :         if (pos + num_prop * 4 > end) {
     254           1 :                 wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data (num_prop=%u)",
     255             :                            num_prop);
     256           1 :                 return eap_eke_build_fail(data, ret, id,
     257             :                                           EAP_EKE_FAIL_PROTO_ERROR);
     258             :         }
     259             : 
     260        1332 :         for (i = 0; i < num_prop; i++) {
     261        1330 :                 const u8 *tmp = pos;
     262             : 
     263        5320 :                 wpa_printf(MSG_DEBUG, "EAP-EKE: Proposal #%u: dh=%u encr=%u prf=%u mac=%u",
     264        5320 :                            i, pos[0], pos[1], pos[2], pos[3]);
     265        1330 :                 pos += 4;
     266             : 
     267        2049 :                 if ((data->dhgroup && data->dhgroup != *tmp) ||
     268         719 :                     !eap_eke_supp_dhgroup(*tmp))
     269         613 :                         continue;
     270         717 :                 tmp++;
     271        1434 :                 if ((data->encr && data->encr != *tmp) ||
     272         717 :                     !eap_eke_supp_encr(*tmp))
     273           2 :                         continue;
     274         715 :                 tmp++;
     275        1128 :                 if ((data->prf && data->prf != *tmp) ||
     276         413 :                     !eap_eke_supp_prf(*tmp))
     277         304 :                         continue;
     278         411 :                 tmp++;
     279         822 :                 if ((data->mac && data->mac != *tmp) ||
     280         411 :                     !eap_eke_supp_mac(*tmp))
     281           2 :                         continue;
     282             : 
     283         409 :                 prop = tmp - 3;
     284         409 :                 if (eap_eke_session_init(&data->sess, prop[0], prop[1], prop[2],
     285         409 :                                          prop[3]) < 0) {
     286           0 :                         prop = NULL;
     287           0 :                         continue;
     288             :                 }
     289             : 
     290         409 :                 wpa_printf(MSG_DEBUG, "EAP-EKE: Selected proposal");
     291         409 :                 break;
     292             :         }
     293             : 
     294         411 :         if (prop == NULL) {
     295           2 :                 wpa_printf(MSG_DEBUG, "EAP-EKE: No acceptable proposal found");
     296           2 :                 return eap_eke_build_fail(data, ret, id,
     297             :                                           EAP_EKE_FAIL_NO_PROPOSAL_CHOSEN);
     298             :         }
     299             : 
     300         409 :         pos += (num_prop - i - 1) * 4;
     301             : 
     302         409 :         if (pos == end) {
     303           1 :                 wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data to include IDType/Identity");
     304           1 :                 return eap_eke_build_fail(data, ret, id,
     305             :                                           EAP_EKE_FAIL_PROTO_ERROR);
     306             :         }
     307             : 
     308         408 :         idtype = *pos++;
     309         408 :         wpa_printf(MSG_DEBUG, "EAP-EKE: Server IDType %u", idtype);
     310         408 :         wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Server Identity",
     311         408 :                           pos, end - pos);
     312         408 :         os_free(data->serverid);
     313         408 :         data->serverid = os_malloc(end - pos);
     314         408 :         if (data->serverid == NULL) {
     315           1 :                 return eap_eke_build_fail(data, ret, id,
     316             :                                           EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
     317             :         }
     318         407 :         os_memcpy(data->serverid, pos, end - pos);
     319         407 :         data->serverid_len = end - pos;
     320             : 
     321         407 :         wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-ID/Response");
     322             : 
     323         407 :         resp = eap_eke_build_msg(data, id,
     324         407 :                                  2 + 4 + 1 + data->peerid_len,
     325             :                                  EAP_EKE_ID);
     326         407 :         if (resp == NULL) {
     327           3 :                 return eap_eke_build_fail(data, ret, id,
     328             :                                           EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
     329             :         }
     330             : 
     331         404 :         wpabuf_put_u8(resp, 1); /* NumProposals */
     332         404 :         wpabuf_put_u8(resp, 0); /* Reserved */
     333         404 :         wpabuf_put_data(resp, prop, 4); /* Selected Proposal */
     334         404 :         wpabuf_put_u8(resp, EAP_EKE_ID_NAI);
     335         404 :         if (data->peerid)
     336         404 :                 wpabuf_put_data(resp, data->peerid, data->peerid_len);
     337             : 
     338         404 :         wpabuf_free(data->msgs);
     339         404 :         data->msgs = wpabuf_alloc(wpabuf_len(reqData) + wpabuf_len(resp));
     340         404 :         if (data->msgs == NULL) {
     341           1 :                 wpabuf_free(resp);
     342           1 :                 return eap_eke_build_fail(data, ret, id,
     343             :                                           EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
     344             :         }
     345         403 :         wpabuf_put_buf(data->msgs, reqData);
     346         403 :         wpabuf_put_buf(data->msgs, resp);
     347             : 
     348         403 :         eap_eke_state(data, COMMIT);
     349             : 
     350         403 :         return resp;
     351             : }
     352             : 
     353             : 
     354         384 : static struct wpabuf * eap_eke_process_commit(struct eap_sm *sm,
     355             :                                               struct eap_eke_data *data,
     356             :                                               struct eap_method_ret *ret,
     357             :                                               const struct wpabuf *reqData,
     358             :                                               const u8 *payload,
     359             :                                               size_t payload_len)
     360             : {
     361             :         struct wpabuf *resp;
     362             :         const u8 *pos, *end, *dhcomp;
     363             :         size_t prot_len;
     364             :         u8 *rpos;
     365             :         u8 key[EAP_EKE_MAX_KEY_LEN];
     366             :         u8 pub[EAP_EKE_MAX_DH_LEN];
     367             :         const u8 *password;
     368             :         size_t password_len;
     369         384 :         u8 id = eap_get_id(reqData);
     370             : 
     371         384 :         if (data->state != COMMIT) {
     372           1 :                 wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Commit/Request received in unexpected state (%d)", data->state);
     373           1 :                 return eap_eke_build_fail(data, ret, id,
     374             :                                           EAP_EKE_FAIL_PROTO_ERROR);
     375             :         }
     376             : 
     377         383 :         wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Commit/Request");
     378             : 
     379         383 :         password = eap_get_config_password(sm, &password_len);
     380         383 :         if (password == NULL) {
     381           0 :                 wpa_printf(MSG_INFO, "EAP-EKE: No password configured!");
     382           0 :                 return eap_eke_build_fail(data, ret, id,
     383             :                                           EAP_EKE_FAIL_PASSWD_NOT_FOUND);
     384             :         }
     385             : 
     386         383 :         pos = payload;
     387         383 :         end = payload + payload_len;
     388             : 
     389         383 :         if (pos + data->sess.dhcomp_len > end) {
     390           1 :                 wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit");
     391           1 :                 return eap_eke_build_fail(data, ret, id,
     392             :                                           EAP_EKE_FAIL_PROTO_ERROR);
     393             :         }
     394             : 
     395         382 :         wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_S",
     396         382 :                     pos, data->sess.dhcomp_len);
     397         382 :         dhcomp = pos;
     398         382 :         pos += data->sess.dhcomp_len;
     399         382 :         wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos);
     400             : 
     401             :         /*
     402             :          * temp = prf(0+, password)
     403             :          * key = prf+(temp, ID_S | ID_P)
     404             :          */
     405        1146 :         if (eap_eke_derive_key(&data->sess, password, password_len,
     406         382 :                                data->serverid, data->serverid_len,
     407         382 :                                data->peerid, data->peerid_len, key) < 0) {
     408           4 :                 wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key");
     409           4 :                 return eap_eke_build_fail(data, ret, id,
     410             :                                           EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
     411             :         }
     412             : 
     413             :         /*
     414             :          * y_p = g ^ x_p (mod p)
     415             :          * x_p = random number 2 .. p-1
     416             :          */
     417         378 :         if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) {
     418           3 :                 wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH");
     419           3 :                 os_memset(key, 0, sizeof(key));
     420           3 :                 return eap_eke_build_fail(data, ret, id,
     421             :                                           EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
     422             :         }
     423             : 
     424         375 :         if (eap_eke_shared_secret(&data->sess, key, data->dh_priv, dhcomp) < 0)
     425             :         {
     426           3 :                 wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret");
     427           3 :                 os_memset(key, 0, sizeof(key));
     428           3 :                 return eap_eke_build_fail(data, ret, id,
     429             :                                           EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
     430             :         }
     431             : 
     432        1116 :         if (eap_eke_derive_ke_ki(&data->sess,
     433         372 :                                  data->serverid, data->serverid_len,
     434         372 :                                  data->peerid, data->peerid_len) < 0) {
     435           3 :                 wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki");
     436           3 :                 os_memset(key, 0, sizeof(key));
     437           3 :                 return eap_eke_build_fail(data, ret, id,
     438             :                                           EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
     439             :         }
     440             : 
     441         369 :         wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Commit/Response");
     442             : 
     443         369 :         resp = eap_eke_build_msg(data, id,
     444         369 :                                  data->sess.dhcomp_len + data->sess.pnonce_len,
     445             :                                  EAP_EKE_COMMIT);
     446         369 :         if (resp == NULL) {
     447           1 :                 os_memset(key, 0, sizeof(key));
     448           1 :                 return eap_eke_build_fail(data, ret, id,
     449             :                                           EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
     450             :         }
     451             : 
     452             :         /* DHComponent_P = Encr(key, y_p) */
     453         368 :         rpos = wpabuf_put(resp, data->sess.dhcomp_len);
     454         368 :         if (eap_eke_dhcomp(&data->sess, key, pub, rpos) < 0) {
     455           3 :                 wpabuf_free(resp);
     456           3 :                 wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_P");
     457           3 :                 os_memset(key, 0, sizeof(key));
     458           3 :                 return eap_eke_build_fail(data, ret, id,
     459             :                                           EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
     460             :         }
     461         365 :         os_memset(key, 0, sizeof(key));
     462             : 
     463         365 :         wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P",
     464         365 :                     rpos, data->sess.dhcomp_len);
     465             : 
     466         365 :         if (random_get_bytes(data->nonce_p, data->sess.nonce_len)) {
     467           1 :                 wpabuf_free(resp);
     468           1 :                 return eap_eke_build_fail(data, ret, id,
     469             :                                           EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
     470             :         }
     471         728 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P",
     472         728 :                         data->nonce_p, data->sess.nonce_len);
     473         364 :         prot_len = wpabuf_tailroom(resp);
     474         364 :         if (eap_eke_prot(&data->sess, data->nonce_p, data->sess.nonce_len,
     475         364 :                          wpabuf_put(resp, 0), &prot_len) < 0) {
     476           2 :                 wpabuf_free(resp);
     477           2 :                 return eap_eke_build_fail(data, ret, id,
     478             :                                           EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
     479             :         }
     480         724 :         wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P",
     481         362 :                     wpabuf_put(resp, 0), prot_len);
     482         362 :         wpabuf_put(resp, prot_len);
     483             : 
     484             :         /* TODO: CBValue */
     485             : 
     486         362 :         if (wpabuf_resize(&data->msgs, wpabuf_len(reqData) + wpabuf_len(resp))
     487             :             < 0) {
     488           1 :                 wpabuf_free(resp);
     489           1 :                 return eap_eke_build_fail(data, ret, id,
     490             :                                           EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
     491             :         }
     492         361 :         wpabuf_put_buf(data->msgs, reqData);
     493         361 :         wpabuf_put_buf(data->msgs, resp);
     494             : 
     495         361 :         eap_eke_state(data, CONFIRM);
     496             : 
     497         361 :         return resp;
     498             : }
     499             : 
     500             : 
     501         340 : static struct wpabuf * eap_eke_process_confirm(struct eap_eke_data *data,
     502             :                                                struct eap_method_ret *ret,
     503             :                                                const struct wpabuf *reqData,
     504             :                                                const u8 *payload,
     505             :                                                size_t payload_len)
     506             : {
     507             :         struct wpabuf *resp;
     508             :         const u8 *pos, *end;
     509             :         size_t prot_len;
     510             :         u8 nonces[2 * EAP_EKE_MAX_NONCE_LEN];
     511             :         u8 auth_s[EAP_EKE_MAX_HASH_LEN];
     512             :         size_t decrypt_len;
     513             :         u8 *auth;
     514         340 :         u8 id = eap_get_id(reqData);
     515             : 
     516         340 :         if (data->state != CONFIRM) {
     517           1 :                 wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Confirm/Request received in unexpected state (%d)",
     518           1 :                            data->state);
     519           1 :                 return eap_eke_build_fail(data, ret, id,
     520             :                                           EAP_EKE_FAIL_PROTO_ERROR);
     521             :         }
     522             : 
     523         339 :         wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Confirm/Request");
     524             : 
     525         339 :         pos = payload;
     526         339 :         end = payload + payload_len;
     527             : 
     528         339 :         if (pos + data->sess.pnonce_ps_len + data->sess.prf_len > end) {
     529           1 :                 wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Confirm");
     530           1 :                 return eap_eke_build_fail(data, ret, id,
     531             :                                           EAP_EKE_FAIL_PROTO_ERROR);
     532             :         }
     533             : 
     534         338 :         decrypt_len = sizeof(nonces);
     535         338 :         if (eap_eke_decrypt_prot(&data->sess, pos, data->sess.pnonce_ps_len,
     536             :                                  nonces, &decrypt_len) < 0) {
     537           3 :                 wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_PS");
     538           3 :                 return eap_eke_build_fail(data, ret, id,
     539             :                                           EAP_EKE_FAIL_AUTHENTICATION_FAIL);
     540             :         }
     541         335 :         if (decrypt_len != (size_t) 2 * data->sess.nonce_len) {
     542           0 :                 wpa_printf(MSG_INFO, "EAP-EKE: PNonce_PS protected data length does not match length of Nonce_P and Nonce_S");
     543           0 :                 return eap_eke_build_fail(data, ret, id,
     544             :                                           EAP_EKE_FAIL_AUTHENTICATION_FAIL);
     545             :         }
     546         335 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_P | Nonce_S",
     547         335 :                         nonces, 2 * data->sess.nonce_len);
     548         335 :         if (os_memcmp(data->nonce_p, nonces, data->sess.nonce_len) != 0) {
     549           0 :                 wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_P does not match transmitted Nonce_P");
     550           0 :                 return eap_eke_build_fail(data, ret, id,
     551             :                                           EAP_EKE_FAIL_AUTHENTICATION_FAIL);
     552             :         }
     553             : 
     554         335 :         os_memcpy(data->nonce_s, nonces + data->sess.nonce_len,
     555             :                   data->sess.nonce_len);
     556         670 :         wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_S",
     557         670 :                         data->nonce_s, data->sess.nonce_len);
     558             : 
     559         670 :         if (eap_eke_derive_ka(&data->sess, data->serverid, data->serverid_len,
     560         335 :                               data->peerid, data->peerid_len,
     561         335 :                               data->nonce_p, data->nonce_s) < 0) {
     562           3 :                 return eap_eke_build_fail(data, ret, id,
     563             :                                           EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
     564             :         }
     565             : 
     566         332 :         if (eap_eke_auth(&data->sess, "EAP-EKE server", data->msgs, auth_s) < 0)
     567             :         {
     568           1 :                 return eap_eke_build_fail(data, ret, id,
     569             :                                           EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
     570             :         }
     571         331 :         wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_S", auth_s, data->sess.prf_len);
     572         331 :         if (os_memcmp_const(auth_s, pos + data->sess.pnonce_ps_len,
     573         331 :                             data->sess.prf_len) != 0) {
     574           0 :                 wpa_printf(MSG_INFO, "EAP-EKE: Auth_S does not match");
     575           0 :                 return eap_eke_build_fail(data, ret, id,
     576             :                                           EAP_EKE_FAIL_AUTHENTICATION_FAIL);
     577             :         }
     578             : 
     579         331 :         wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Confirm/Response");
     580             : 
     581         331 :         resp = eap_eke_build_msg(data, id,
     582         331 :                                  data->sess.pnonce_len + data->sess.prf_len,
     583             :                                  EAP_EKE_CONFIRM);
     584         331 :         if (resp == NULL) {
     585           1 :                 return eap_eke_build_fail(data, ret, id,
     586             :                                           EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
     587             :         }
     588             : 
     589         330 :         prot_len = wpabuf_tailroom(resp);
     590         330 :         if (eap_eke_prot(&data->sess, data->nonce_s, data->sess.nonce_len,
     591         330 :                          wpabuf_put(resp, 0), &prot_len) < 0) {
     592           1 :                 wpabuf_free(resp);
     593           1 :                 return eap_eke_build_fail(data, ret, id,
     594             :                                           EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
     595             :         }
     596         329 :         wpabuf_put(resp, prot_len);
     597             : 
     598         329 :         auth = wpabuf_put(resp, data->sess.prf_len);
     599         329 :         if (eap_eke_auth(&data->sess, "EAP-EKE peer", data->msgs, auth) < 0) {
     600           1 :                 wpabuf_free(resp);
     601           1 :                 return eap_eke_build_fail(data, ret, id,
     602             :                                           EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
     603             :         }
     604         328 :         wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth, data->sess.prf_len);
     605             : 
     606         656 :         if (eap_eke_derive_msk(&data->sess, data->serverid, data->serverid_len,
     607         328 :                                data->peerid, data->peerid_len,
     608         328 :                                data->nonce_s, data->nonce_p,
     609         328 :                                data->msk, data->emsk) < 0) {
     610           3 :                 wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive MSK/EMSK");
     611           3 :                 wpabuf_free(resp);
     612           3 :                 return eap_eke_build_fail(data, ret, id,
     613             :                                           EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
     614             :         }
     615             : 
     616         325 :         os_memset(data->dh_priv, 0, sizeof(data->dh_priv));
     617         325 :         eap_eke_session_clean(&data->sess);
     618             : 
     619         325 :         eap_eke_state(data, SUCCESS);
     620         325 :         ret->methodState = METHOD_MAY_CONT;
     621         325 :         ret->decision = DECISION_COND_SUCC;
     622         325 :         ret->allowNotifications = FALSE;
     623             : 
     624         325 :         return resp;
     625             : }
     626             : 
     627             : 
     628          42 : static struct wpabuf * eap_eke_process_failure(struct eap_eke_data *data,
     629             :                                                struct eap_method_ret *ret,
     630             :                                                const struct wpabuf *reqData,
     631             :                                                const u8 *payload,
     632             :                                                size_t payload_len)
     633             : {
     634          42 :         wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Failure/Request");
     635             : 
     636          42 :         if (payload_len < 4) {
     637           1 :                 wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Failure");
     638             :         } else {
     639             :                 u32 code;
     640          41 :                 code = WPA_GET_BE32(payload);
     641          41 :                 wpa_printf(MSG_INFO, "EAP-EKE: Failure-Code 0x%x", code);
     642             :         }
     643             : 
     644          42 :         return eap_eke_build_fail(data, ret, eap_get_id(reqData),
     645             :                                   EAP_EKE_FAIL_NO_ERROR);
     646             : }
     647             : 
     648             : 
     649        1183 : static struct wpabuf * eap_eke_process(struct eap_sm *sm, void *priv,
     650             :                                        struct eap_method_ret *ret,
     651             :                                        const struct wpabuf *reqData)
     652             : {
     653        1183 :         struct eap_eke_data *data = priv;
     654             :         struct wpabuf *resp;
     655             :         const u8 *pos, *end;
     656             :         size_t len;
     657             :         u8 eke_exch;
     658             : 
     659        1183 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, reqData, &len);
     660        1183 :         if (pos == NULL || len < 1) {
     661           1 :                 ret->ignore = TRUE;
     662           1 :                 return NULL;
     663             :         }
     664             : 
     665        1182 :         end = pos + len;
     666        1182 :         eke_exch = *pos++;
     667             : 
     668        1182 :         wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: exch %d", eke_exch);
     669        1182 :         wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received Data", pos, end - pos);
     670             : 
     671        1182 :         ret->ignore = FALSE;
     672        1182 :         ret->methodState = METHOD_MAY_CONT;
     673        1182 :         ret->decision = DECISION_FAIL;
     674        1182 :         ret->allowNotifications = TRUE;
     675             : 
     676        1182 :         switch (eke_exch) {
     677             :         case EAP_EKE_ID:
     678         415 :                 resp = eap_eke_process_id(data, ret, reqData, pos, end - pos);
     679         415 :                 break;
     680             :         case EAP_EKE_COMMIT:
     681         384 :                 resp = eap_eke_process_commit(sm, data, ret, reqData,
     682         384 :                                               pos, end - pos);
     683         384 :                 break;
     684             :         case EAP_EKE_CONFIRM:
     685         340 :                 resp = eap_eke_process_confirm(data, ret, reqData,
     686         340 :                                                pos, end - pos);
     687         340 :                 break;
     688             :         case EAP_EKE_FAILURE:
     689          42 :                 resp = eap_eke_process_failure(data, ret, reqData,
     690          42 :                                                pos, end - pos);
     691          42 :                 break;
     692             :         default:
     693           1 :                 wpa_printf(MSG_DEBUG, "EAP-EKE: Ignoring message with unknown EKE-Exch %d", eke_exch);
     694           1 :                 ret->ignore = TRUE;
     695           1 :                 return NULL;
     696             :         }
     697             : 
     698        1181 :         if (ret->methodState == METHOD_DONE)
     699          92 :                 ret->allowNotifications = FALSE;
     700             : 
     701        1181 :         return resp;
     702             : }
     703             : 
     704             : 
     705        1181 : static Boolean eap_eke_isKeyAvailable(struct eap_sm *sm, void *priv)
     706             : {
     707        1181 :         struct eap_eke_data *data = priv;
     708        1181 :         return data->state == SUCCESS;
     709             : }
     710             : 
     711             : 
     712         325 : static u8 * eap_eke_getKey(struct eap_sm *sm, void *priv, size_t *len)
     713             : {
     714         325 :         struct eap_eke_data *data = priv;
     715             :         u8 *key;
     716             : 
     717         325 :         if (data->state != SUCCESS)
     718           0 :                 return NULL;
     719             : 
     720         325 :         key = os_malloc(EAP_MSK_LEN);
     721         325 :         if (key == NULL)
     722           1 :                 return NULL;
     723         324 :         os_memcpy(key, data->msk, EAP_MSK_LEN);
     724         324 :         *len = EAP_MSK_LEN;
     725             : 
     726         324 :         return key;
     727             : }
     728             : 
     729             : 
     730           3 : static u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
     731             : {
     732           3 :         struct eap_eke_data *data = priv;
     733             :         u8 *key;
     734             : 
     735           3 :         if (data->state != SUCCESS)
     736           0 :                 return NULL;
     737             : 
     738           3 :         key = os_malloc(EAP_EMSK_LEN);
     739           3 :         if (key == NULL)
     740           1 :                 return NULL;
     741           2 :         os_memcpy(key, data->emsk, EAP_EMSK_LEN);
     742           2 :         *len = EAP_EMSK_LEN;
     743             : 
     744           2 :         return key;
     745             : }
     746             : 
     747             : 
     748         325 : static u8 * eap_eke_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
     749             : {
     750         325 :         struct eap_eke_data *data = priv;
     751             :         u8 *sid;
     752             :         size_t sid_len;
     753             : 
     754         325 :         if (data->state != SUCCESS)
     755           0 :                 return NULL;
     756             : 
     757         325 :         sid_len = 1 + 2 * data->sess.nonce_len;
     758         325 :         sid = os_malloc(sid_len);
     759         325 :         if (sid == NULL)
     760           1 :                 return NULL;
     761         324 :         sid[0] = EAP_TYPE_EKE;
     762         324 :         os_memcpy(sid + 1, data->nonce_p, data->sess.nonce_len);
     763         324 :         os_memcpy(sid + 1 + data->sess.nonce_len, data->nonce_s,
     764             :                   data->sess.nonce_len);
     765         324 :         *len = sid_len;
     766             : 
     767         324 :         return sid;
     768             : }
     769             : 
     770             : 
     771          49 : int eap_peer_eke_register(void)
     772             : {
     773             :         struct eap_method *eap;
     774             : 
     775          49 :         eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
     776             :                                     EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE");
     777          49 :         if (eap == NULL)
     778           0 :                 return -1;
     779             : 
     780          49 :         eap->init = eap_eke_init;
     781          49 :         eap->deinit = eap_eke_deinit;
     782          49 :         eap->process = eap_eke_process;
     783          49 :         eap->isKeyAvailable = eap_eke_isKeyAvailable;
     784          49 :         eap->getKey = eap_eke_getKey;
     785          49 :         eap->get_emsk = eap_eke_get_emsk;
     786          49 :         eap->getSessionId = eap_eke_get_session_id;
     787             : 
     788          49 :         return eap_peer_method_register(eap);
     789             : }

Generated by: LCOV version 1.10