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

Generated by: LCOV version 1.10