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