15b9c547cSRui Paulo /* 25b9c547cSRui Paulo * EAP peer method: EAP-EKE (RFC 6124) 35b9c547cSRui Paulo * Copyright (c) 2013, Jouni Malinen <j@w1.fi> 45b9c547cSRui Paulo * 55b9c547cSRui Paulo * This software may be distributed under the terms of the BSD license. 65b9c547cSRui Paulo * See README for more details. 75b9c547cSRui Paulo */ 85b9c547cSRui Paulo 95b9c547cSRui Paulo #include "includes.h" 105b9c547cSRui Paulo 115b9c547cSRui Paulo #include "common.h" 125b9c547cSRui Paulo #include "crypto/random.h" 135b9c547cSRui Paulo #include "eap_peer/eap_i.h" 145b9c547cSRui Paulo #include "eap_common/eap_eke_common.h" 155b9c547cSRui Paulo 165b9c547cSRui Paulo struct eap_eke_data { 175b9c547cSRui Paulo enum { 185b9c547cSRui Paulo IDENTITY, COMMIT, CONFIRM, SUCCESS, FAILURE 195b9c547cSRui Paulo } state; 205b9c547cSRui Paulo u8 msk[EAP_MSK_LEN]; 215b9c547cSRui Paulo u8 emsk[EAP_EMSK_LEN]; 225b9c547cSRui Paulo u8 *peerid; 235b9c547cSRui Paulo size_t peerid_len; 245b9c547cSRui Paulo u8 *serverid; 255b9c547cSRui Paulo size_t serverid_len; 265b9c547cSRui Paulo u8 dh_priv[EAP_EKE_MAX_DH_LEN]; 275b9c547cSRui Paulo struct eap_eke_session sess; 285b9c547cSRui Paulo u8 nonce_p[EAP_EKE_MAX_NONCE_LEN]; 295b9c547cSRui Paulo u8 nonce_s[EAP_EKE_MAX_NONCE_LEN]; 305b9c547cSRui Paulo struct wpabuf *msgs; 315b9c547cSRui Paulo u8 dhgroup; /* forced DH group or 0 to allow all supported */ 325b9c547cSRui Paulo u8 encr; /* forced encryption algorithm or 0 to allow all supported */ 335b9c547cSRui Paulo u8 prf; /* forced PRF or 0 to allow all supported */ 345b9c547cSRui Paulo u8 mac; /* forced MAC or 0 to allow all supported */ 355b9c547cSRui Paulo }; 365b9c547cSRui Paulo 375b9c547cSRui Paulo 385b9c547cSRui Paulo static const char * eap_eke_state_txt(int state) 395b9c547cSRui Paulo { 405b9c547cSRui Paulo switch (state) { 415b9c547cSRui Paulo case IDENTITY: 425b9c547cSRui Paulo return "IDENTITY"; 435b9c547cSRui Paulo case COMMIT: 445b9c547cSRui Paulo return "COMMIT"; 455b9c547cSRui Paulo case CONFIRM: 465b9c547cSRui Paulo return "CONFIRM"; 475b9c547cSRui Paulo case SUCCESS: 485b9c547cSRui Paulo return "SUCCESS"; 495b9c547cSRui Paulo case FAILURE: 505b9c547cSRui Paulo return "FAILURE"; 515b9c547cSRui Paulo default: 525b9c547cSRui Paulo return "?"; 535b9c547cSRui Paulo } 545b9c547cSRui Paulo } 555b9c547cSRui Paulo 565b9c547cSRui Paulo 575b9c547cSRui Paulo static void eap_eke_state(struct eap_eke_data *data, int state) 585b9c547cSRui Paulo { 595b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: %s -> %s", 605b9c547cSRui Paulo eap_eke_state_txt(data->state), eap_eke_state_txt(state)); 615b9c547cSRui Paulo data->state = state; 625b9c547cSRui Paulo } 635b9c547cSRui Paulo 645b9c547cSRui Paulo 655b9c547cSRui Paulo static void eap_eke_deinit(struct eap_sm *sm, void *priv); 665b9c547cSRui Paulo 675b9c547cSRui Paulo 685b9c547cSRui Paulo static void * eap_eke_init(struct eap_sm *sm) 695b9c547cSRui Paulo { 705b9c547cSRui Paulo struct eap_eke_data *data; 715b9c547cSRui Paulo const u8 *identity, *password; 725b9c547cSRui Paulo size_t identity_len, password_len; 735b9c547cSRui Paulo const char *phase1; 745b9c547cSRui Paulo 755b9c547cSRui Paulo password = eap_get_config_password(sm, &password_len); 765b9c547cSRui Paulo if (!password) { 775b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: No password configured"); 785b9c547cSRui Paulo return NULL; 795b9c547cSRui Paulo } 805b9c547cSRui Paulo 815b9c547cSRui Paulo data = os_zalloc(sizeof(*data)); 825b9c547cSRui Paulo if (data == NULL) 835b9c547cSRui Paulo return NULL; 845b9c547cSRui Paulo eap_eke_state(data, IDENTITY); 855b9c547cSRui Paulo 865b9c547cSRui Paulo identity = eap_get_config_identity(sm, &identity_len); 875b9c547cSRui Paulo if (identity) { 885b9c547cSRui Paulo data->peerid = os_malloc(identity_len); 895b9c547cSRui Paulo if (data->peerid == NULL) { 905b9c547cSRui Paulo eap_eke_deinit(sm, data); 915b9c547cSRui Paulo return NULL; 925b9c547cSRui Paulo } 935b9c547cSRui Paulo os_memcpy(data->peerid, identity, identity_len); 945b9c547cSRui Paulo data->peerid_len = identity_len; 955b9c547cSRui Paulo } 965b9c547cSRui Paulo 975b9c547cSRui Paulo phase1 = eap_get_config_phase1(sm); 985b9c547cSRui Paulo if (phase1) { 995b9c547cSRui Paulo const char *pos; 1005b9c547cSRui Paulo 1015b9c547cSRui Paulo pos = os_strstr(phase1, "dhgroup="); 1025b9c547cSRui Paulo if (pos) { 1035b9c547cSRui Paulo data->dhgroup = atoi(pos + 8); 1045b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Forced dhgroup %u", 1055b9c547cSRui Paulo data->dhgroup); 1065b9c547cSRui Paulo } 1075b9c547cSRui Paulo 1085b9c547cSRui Paulo pos = os_strstr(phase1, "encr="); 1095b9c547cSRui Paulo if (pos) { 1105b9c547cSRui Paulo data->encr = atoi(pos + 5); 1115b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Forced encr %u", 1125b9c547cSRui Paulo data->encr); 1135b9c547cSRui Paulo } 1145b9c547cSRui Paulo 1155b9c547cSRui Paulo pos = os_strstr(phase1, "prf="); 1165b9c547cSRui Paulo if (pos) { 1175b9c547cSRui Paulo data->prf = atoi(pos + 4); 1185b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Forced prf %u", 1195b9c547cSRui Paulo data->prf); 1205b9c547cSRui Paulo } 1215b9c547cSRui Paulo 1225b9c547cSRui Paulo pos = os_strstr(phase1, "mac="); 1235b9c547cSRui Paulo if (pos) { 1245b9c547cSRui Paulo data->mac = atoi(pos + 4); 1255b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Forced mac %u", 1265b9c547cSRui Paulo data->mac); 1275b9c547cSRui Paulo } 1285b9c547cSRui Paulo } 1295b9c547cSRui Paulo 1305b9c547cSRui Paulo return data; 1315b9c547cSRui Paulo } 1325b9c547cSRui Paulo 1335b9c547cSRui Paulo 1345b9c547cSRui Paulo static void eap_eke_deinit(struct eap_sm *sm, void *priv) 1355b9c547cSRui Paulo { 1365b9c547cSRui Paulo struct eap_eke_data *data = priv; 1375b9c547cSRui Paulo eap_eke_session_clean(&data->sess); 1385b9c547cSRui Paulo os_free(data->serverid); 1395b9c547cSRui Paulo os_free(data->peerid); 1405b9c547cSRui Paulo wpabuf_free(data->msgs); 1415b9c547cSRui Paulo bin_clear_free(data, sizeof(*data)); 1425b9c547cSRui Paulo } 1435b9c547cSRui Paulo 1445b9c547cSRui Paulo 1455b9c547cSRui Paulo static struct wpabuf * eap_eke_build_msg(struct eap_eke_data *data, int id, 1465b9c547cSRui Paulo size_t length, u8 eke_exch) 1475b9c547cSRui Paulo { 1485b9c547cSRui Paulo struct wpabuf *msg; 1495b9c547cSRui Paulo size_t plen; 1505b9c547cSRui Paulo 1515b9c547cSRui Paulo plen = 1 + length; 1525b9c547cSRui Paulo 1535b9c547cSRui Paulo msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EKE, plen, 1545b9c547cSRui Paulo EAP_CODE_RESPONSE, id); 1555b9c547cSRui Paulo if (msg == NULL) { 1565b9c547cSRui Paulo wpa_printf(MSG_ERROR, "EAP-EKE: Failed to allocate memory"); 1575b9c547cSRui Paulo return NULL; 1585b9c547cSRui Paulo } 1595b9c547cSRui Paulo 1605b9c547cSRui Paulo wpabuf_put_u8(msg, eke_exch); 1615b9c547cSRui Paulo 1625b9c547cSRui Paulo return msg; 1635b9c547cSRui Paulo } 1645b9c547cSRui Paulo 1655b9c547cSRui Paulo 1665b9c547cSRui Paulo static int eap_eke_supp_dhgroup(u8 dhgroup) 1675b9c547cSRui Paulo { 1685b9c547cSRui Paulo return dhgroup == EAP_EKE_DHGROUP_EKE_2 || 1695b9c547cSRui Paulo dhgroup == EAP_EKE_DHGROUP_EKE_5 || 1705b9c547cSRui Paulo dhgroup == EAP_EKE_DHGROUP_EKE_14 || 1715b9c547cSRui Paulo dhgroup == EAP_EKE_DHGROUP_EKE_15 || 1725b9c547cSRui Paulo dhgroup == EAP_EKE_DHGROUP_EKE_16; 1735b9c547cSRui Paulo } 1745b9c547cSRui Paulo 1755b9c547cSRui Paulo 1765b9c547cSRui Paulo static int eap_eke_supp_encr(u8 encr) 1775b9c547cSRui Paulo { 1785b9c547cSRui Paulo return encr == EAP_EKE_ENCR_AES128_CBC; 1795b9c547cSRui Paulo } 1805b9c547cSRui Paulo 1815b9c547cSRui Paulo 1825b9c547cSRui Paulo static int eap_eke_supp_prf(u8 prf) 1835b9c547cSRui Paulo { 1845b9c547cSRui Paulo return prf == EAP_EKE_PRF_HMAC_SHA1 || 1855b9c547cSRui Paulo prf == EAP_EKE_PRF_HMAC_SHA2_256; 1865b9c547cSRui Paulo } 1875b9c547cSRui Paulo 1885b9c547cSRui Paulo 1895b9c547cSRui Paulo static int eap_eke_supp_mac(u8 mac) 1905b9c547cSRui Paulo { 1915b9c547cSRui Paulo return mac == EAP_EKE_MAC_HMAC_SHA1 || 1925b9c547cSRui Paulo mac == EAP_EKE_MAC_HMAC_SHA2_256; 1935b9c547cSRui Paulo } 1945b9c547cSRui Paulo 1955b9c547cSRui Paulo 1965b9c547cSRui Paulo static struct wpabuf * eap_eke_build_fail(struct eap_eke_data *data, 1975b9c547cSRui Paulo struct eap_method_ret *ret, 198*325151a3SRui Paulo u8 id, u32 failure_code) 1995b9c547cSRui Paulo { 2005b9c547cSRui Paulo struct wpabuf *resp; 2015b9c547cSRui Paulo 2025b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Failure/Response - code=0x%x", 2035b9c547cSRui Paulo failure_code); 2045b9c547cSRui Paulo 205*325151a3SRui Paulo resp = eap_eke_build_msg(data, id, 4, EAP_EKE_FAILURE); 2065b9c547cSRui Paulo if (resp) 2075b9c547cSRui Paulo wpabuf_put_be32(resp, failure_code); 2085b9c547cSRui Paulo 2095b9c547cSRui Paulo os_memset(data->dh_priv, 0, sizeof(data->dh_priv)); 2105b9c547cSRui Paulo eap_eke_session_clean(&data->sess); 2115b9c547cSRui Paulo 2125b9c547cSRui Paulo eap_eke_state(data, FAILURE); 2135b9c547cSRui Paulo ret->methodState = METHOD_DONE; 2145b9c547cSRui Paulo ret->decision = DECISION_FAIL; 2155b9c547cSRui Paulo ret->allowNotifications = FALSE; 2165b9c547cSRui Paulo 2175b9c547cSRui Paulo return resp; 2185b9c547cSRui Paulo } 2195b9c547cSRui Paulo 2205b9c547cSRui Paulo 2215b9c547cSRui Paulo static struct wpabuf * eap_eke_process_id(struct eap_eke_data *data, 2225b9c547cSRui Paulo struct eap_method_ret *ret, 2235b9c547cSRui Paulo const struct wpabuf *reqData, 2245b9c547cSRui Paulo const u8 *payload, 2255b9c547cSRui Paulo size_t payload_len) 2265b9c547cSRui Paulo { 2275b9c547cSRui Paulo struct wpabuf *resp; 2285b9c547cSRui Paulo unsigned num_prop, i; 2295b9c547cSRui Paulo const u8 *pos, *end; 2305b9c547cSRui Paulo const u8 *prop = NULL; 2315b9c547cSRui Paulo u8 idtype; 232*325151a3SRui Paulo u8 id = eap_get_id(reqData); 2335b9c547cSRui Paulo 2345b9c547cSRui Paulo if (data->state != IDENTITY) { 235*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 2365b9c547cSRui Paulo EAP_EKE_FAIL_PROTO_ERROR); 2375b9c547cSRui Paulo } 2385b9c547cSRui Paulo 2395b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-ID/Request"); 2405b9c547cSRui Paulo 2415b9c547cSRui Paulo if (payload_len < 2 + 4) { 2425b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data"); 243*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 2445b9c547cSRui Paulo EAP_EKE_FAIL_PROTO_ERROR); 2455b9c547cSRui Paulo } 2465b9c547cSRui Paulo 2475b9c547cSRui Paulo pos = payload; 2485b9c547cSRui Paulo end = payload + payload_len; 2495b9c547cSRui Paulo 2505b9c547cSRui Paulo num_prop = *pos++; 2515b9c547cSRui Paulo pos++; /* Ignore Reserved field */ 2525b9c547cSRui Paulo 2535b9c547cSRui Paulo if (pos + num_prop * 4 > end) { 2545b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data (num_prop=%u)", 2555b9c547cSRui Paulo num_prop); 256*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 2575b9c547cSRui Paulo EAP_EKE_FAIL_PROTO_ERROR); 2585b9c547cSRui Paulo } 2595b9c547cSRui Paulo 2605b9c547cSRui Paulo for (i = 0; i < num_prop; i++) { 2615b9c547cSRui Paulo const u8 *tmp = pos; 2625b9c547cSRui Paulo 2635b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Proposal #%u: dh=%u encr=%u prf=%u mac=%u", 2645b9c547cSRui Paulo i, pos[0], pos[1], pos[2], pos[3]); 2655b9c547cSRui Paulo pos += 4; 2665b9c547cSRui Paulo 2675b9c547cSRui Paulo if ((data->dhgroup && data->dhgroup != *tmp) || 2685b9c547cSRui Paulo !eap_eke_supp_dhgroup(*tmp)) 2695b9c547cSRui Paulo continue; 2705b9c547cSRui Paulo tmp++; 2715b9c547cSRui Paulo if ((data->encr && data->encr != *tmp) || 2725b9c547cSRui Paulo !eap_eke_supp_encr(*tmp)) 2735b9c547cSRui Paulo continue; 2745b9c547cSRui Paulo tmp++; 2755b9c547cSRui Paulo if ((data->prf && data->prf != *tmp) || 2765b9c547cSRui Paulo !eap_eke_supp_prf(*tmp)) 2775b9c547cSRui Paulo continue; 2785b9c547cSRui Paulo tmp++; 2795b9c547cSRui Paulo if ((data->mac && data->mac != *tmp) || 2805b9c547cSRui Paulo !eap_eke_supp_mac(*tmp)) 2815b9c547cSRui Paulo continue; 2825b9c547cSRui Paulo 2835b9c547cSRui Paulo prop = tmp - 3; 2845b9c547cSRui Paulo if (eap_eke_session_init(&data->sess, prop[0], prop[1], prop[2], 2855b9c547cSRui Paulo prop[3]) < 0) { 2865b9c547cSRui Paulo prop = NULL; 2875b9c547cSRui Paulo continue; 2885b9c547cSRui Paulo } 2895b9c547cSRui Paulo 2905b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Selected proposal"); 2915b9c547cSRui Paulo break; 2925b9c547cSRui Paulo } 2935b9c547cSRui Paulo 2945b9c547cSRui Paulo if (prop == NULL) { 2955b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: No acceptable proposal found"); 296*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 2975b9c547cSRui Paulo EAP_EKE_FAIL_NO_PROPOSAL_CHOSEN); 2985b9c547cSRui Paulo } 2995b9c547cSRui Paulo 3005b9c547cSRui Paulo pos += (num_prop - i - 1) * 4; 3015b9c547cSRui Paulo 3025b9c547cSRui Paulo if (pos == end) { 3035b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data to include IDType/Identity"); 304*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 3055b9c547cSRui Paulo EAP_EKE_FAIL_PROTO_ERROR); 3065b9c547cSRui Paulo } 3075b9c547cSRui Paulo 3085b9c547cSRui Paulo idtype = *pos++; 3095b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Server IDType %u", idtype); 3105b9c547cSRui Paulo wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Server Identity", 3115b9c547cSRui Paulo pos, end - pos); 3125b9c547cSRui Paulo os_free(data->serverid); 3135b9c547cSRui Paulo data->serverid = os_malloc(end - pos); 3145b9c547cSRui Paulo if (data->serverid == NULL) { 315*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 3165b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 3175b9c547cSRui Paulo } 3185b9c547cSRui Paulo os_memcpy(data->serverid, pos, end - pos); 3195b9c547cSRui Paulo data->serverid_len = end - pos; 3205b9c547cSRui Paulo 3215b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-ID/Response"); 3225b9c547cSRui Paulo 323*325151a3SRui Paulo resp = eap_eke_build_msg(data, id, 3245b9c547cSRui Paulo 2 + 4 + 1 + data->peerid_len, 3255b9c547cSRui Paulo EAP_EKE_ID); 3265b9c547cSRui Paulo if (resp == NULL) { 327*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 3285b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 3295b9c547cSRui Paulo } 3305b9c547cSRui Paulo 3315b9c547cSRui Paulo wpabuf_put_u8(resp, 1); /* NumProposals */ 3325b9c547cSRui Paulo wpabuf_put_u8(resp, 0); /* Reserved */ 3335b9c547cSRui Paulo wpabuf_put_data(resp, prop, 4); /* Selected Proposal */ 3345b9c547cSRui Paulo wpabuf_put_u8(resp, EAP_EKE_ID_NAI); 3355b9c547cSRui Paulo if (data->peerid) 3365b9c547cSRui Paulo wpabuf_put_data(resp, data->peerid, data->peerid_len); 3375b9c547cSRui Paulo 3385b9c547cSRui Paulo wpabuf_free(data->msgs); 3395b9c547cSRui Paulo data->msgs = wpabuf_alloc(wpabuf_len(reqData) + wpabuf_len(resp)); 3405b9c547cSRui Paulo if (data->msgs == NULL) { 3415b9c547cSRui Paulo wpabuf_free(resp); 342*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 3435b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 3445b9c547cSRui Paulo } 3455b9c547cSRui Paulo wpabuf_put_buf(data->msgs, reqData); 3465b9c547cSRui Paulo wpabuf_put_buf(data->msgs, resp); 3475b9c547cSRui Paulo 3485b9c547cSRui Paulo eap_eke_state(data, COMMIT); 3495b9c547cSRui Paulo 3505b9c547cSRui Paulo return resp; 3515b9c547cSRui Paulo } 3525b9c547cSRui Paulo 3535b9c547cSRui Paulo 3545b9c547cSRui Paulo static struct wpabuf * eap_eke_process_commit(struct eap_sm *sm, 3555b9c547cSRui Paulo struct eap_eke_data *data, 3565b9c547cSRui Paulo struct eap_method_ret *ret, 3575b9c547cSRui Paulo const struct wpabuf *reqData, 3585b9c547cSRui Paulo const u8 *payload, 3595b9c547cSRui Paulo size_t payload_len) 3605b9c547cSRui Paulo { 3615b9c547cSRui Paulo struct wpabuf *resp; 3625b9c547cSRui Paulo const u8 *pos, *end, *dhcomp; 3635b9c547cSRui Paulo size_t prot_len; 3645b9c547cSRui Paulo u8 *rpos; 3655b9c547cSRui Paulo u8 key[EAP_EKE_MAX_KEY_LEN]; 3665b9c547cSRui Paulo u8 pub[EAP_EKE_MAX_DH_LEN]; 3675b9c547cSRui Paulo const u8 *password; 3685b9c547cSRui Paulo size_t password_len; 369*325151a3SRui Paulo u8 id = eap_get_id(reqData); 3705b9c547cSRui Paulo 3715b9c547cSRui Paulo if (data->state != COMMIT) { 3725b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Commit/Request received in unexpected state (%d)", data->state); 373*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 3745b9c547cSRui Paulo EAP_EKE_FAIL_PROTO_ERROR); 3755b9c547cSRui Paulo } 3765b9c547cSRui Paulo 3775b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Commit/Request"); 3785b9c547cSRui Paulo 3795b9c547cSRui Paulo password = eap_get_config_password(sm, &password_len); 3805b9c547cSRui Paulo if (password == NULL) { 3815b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: No password configured!"); 382*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 3835b9c547cSRui Paulo EAP_EKE_FAIL_PASSWD_NOT_FOUND); 3845b9c547cSRui Paulo } 3855b9c547cSRui Paulo 3865b9c547cSRui Paulo pos = payload; 3875b9c547cSRui Paulo end = payload + payload_len; 3885b9c547cSRui Paulo 3895b9c547cSRui Paulo if (pos + data->sess.dhcomp_len > end) { 3905b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit"); 391*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 3925b9c547cSRui Paulo EAP_EKE_FAIL_PROTO_ERROR); 3935b9c547cSRui Paulo } 3945b9c547cSRui Paulo 3955b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_S", 3965b9c547cSRui Paulo pos, data->sess.dhcomp_len); 3975b9c547cSRui Paulo dhcomp = pos; 3985b9c547cSRui Paulo pos += data->sess.dhcomp_len; 3995b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos); 4005b9c547cSRui Paulo 4015b9c547cSRui Paulo /* 4025b9c547cSRui Paulo * temp = prf(0+, password) 4035b9c547cSRui Paulo * key = prf+(temp, ID_S | ID_P) 4045b9c547cSRui Paulo */ 4055b9c547cSRui Paulo if (eap_eke_derive_key(&data->sess, password, password_len, 4065b9c547cSRui Paulo data->serverid, data->serverid_len, 4075b9c547cSRui Paulo data->peerid, data->peerid_len, key) < 0) { 4085b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key"); 409*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 4105b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 4115b9c547cSRui Paulo } 4125b9c547cSRui Paulo 4135b9c547cSRui Paulo /* 4145b9c547cSRui Paulo * y_p = g ^ x_p (mod p) 4155b9c547cSRui Paulo * x_p = random number 2 .. p-1 4165b9c547cSRui Paulo */ 4175b9c547cSRui Paulo if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) { 4185b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH"); 4195b9c547cSRui Paulo os_memset(key, 0, sizeof(key)); 420*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 4215b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 4225b9c547cSRui Paulo } 4235b9c547cSRui Paulo 4245b9c547cSRui Paulo if (eap_eke_shared_secret(&data->sess, key, data->dh_priv, dhcomp) < 0) 4255b9c547cSRui Paulo { 4265b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret"); 4275b9c547cSRui Paulo os_memset(key, 0, sizeof(key)); 428*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 4295b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 4305b9c547cSRui Paulo } 4315b9c547cSRui Paulo 4325b9c547cSRui Paulo if (eap_eke_derive_ke_ki(&data->sess, 4335b9c547cSRui Paulo data->serverid, data->serverid_len, 4345b9c547cSRui Paulo data->peerid, data->peerid_len) < 0) { 4355b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki"); 4365b9c547cSRui Paulo os_memset(key, 0, sizeof(key)); 437*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 4385b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 4395b9c547cSRui Paulo } 4405b9c547cSRui Paulo 4415b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Commit/Response"); 4425b9c547cSRui Paulo 443*325151a3SRui Paulo resp = eap_eke_build_msg(data, id, 4445b9c547cSRui Paulo data->sess.dhcomp_len + data->sess.pnonce_len, 4455b9c547cSRui Paulo EAP_EKE_COMMIT); 4465b9c547cSRui Paulo if (resp == NULL) { 4475b9c547cSRui Paulo os_memset(key, 0, sizeof(key)); 448*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 4495b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 4505b9c547cSRui Paulo } 4515b9c547cSRui Paulo 4525b9c547cSRui Paulo /* DHComponent_P = Encr(key, y_p) */ 4535b9c547cSRui Paulo rpos = wpabuf_put(resp, data->sess.dhcomp_len); 4545b9c547cSRui Paulo if (eap_eke_dhcomp(&data->sess, key, pub, rpos) < 0) { 4555b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_P"); 4565b9c547cSRui Paulo os_memset(key, 0, sizeof(key)); 457*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 4585b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 4595b9c547cSRui Paulo } 4605b9c547cSRui Paulo os_memset(key, 0, sizeof(key)); 4615b9c547cSRui Paulo 4625b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P", 4635b9c547cSRui Paulo rpos, data->sess.dhcomp_len); 4645b9c547cSRui Paulo 4655b9c547cSRui Paulo if (random_get_bytes(data->nonce_p, data->sess.nonce_len)) { 4665b9c547cSRui Paulo wpabuf_free(resp); 467*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 4685b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 4695b9c547cSRui Paulo } 4705b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P", 4715b9c547cSRui Paulo data->nonce_p, data->sess.nonce_len); 4725b9c547cSRui Paulo prot_len = wpabuf_tailroom(resp); 4735b9c547cSRui Paulo if (eap_eke_prot(&data->sess, data->nonce_p, data->sess.nonce_len, 4745b9c547cSRui Paulo wpabuf_put(resp, 0), &prot_len) < 0) { 4755b9c547cSRui Paulo wpabuf_free(resp); 476*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 4775b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 4785b9c547cSRui Paulo } 4795b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P", 4805b9c547cSRui Paulo wpabuf_put(resp, 0), prot_len); 4815b9c547cSRui Paulo wpabuf_put(resp, prot_len); 4825b9c547cSRui Paulo 4835b9c547cSRui Paulo /* TODO: CBValue */ 4845b9c547cSRui Paulo 4855b9c547cSRui Paulo if (wpabuf_resize(&data->msgs, wpabuf_len(reqData) + wpabuf_len(resp)) 4865b9c547cSRui Paulo < 0) { 4875b9c547cSRui Paulo wpabuf_free(resp); 488*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 4895b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 4905b9c547cSRui Paulo } 4915b9c547cSRui Paulo wpabuf_put_buf(data->msgs, reqData); 4925b9c547cSRui Paulo wpabuf_put_buf(data->msgs, resp); 4935b9c547cSRui Paulo 4945b9c547cSRui Paulo eap_eke_state(data, CONFIRM); 4955b9c547cSRui Paulo 4965b9c547cSRui Paulo return resp; 4975b9c547cSRui Paulo } 4985b9c547cSRui Paulo 4995b9c547cSRui Paulo 5005b9c547cSRui Paulo static struct wpabuf * eap_eke_process_confirm(struct eap_eke_data *data, 5015b9c547cSRui Paulo struct eap_method_ret *ret, 5025b9c547cSRui Paulo const struct wpabuf *reqData, 5035b9c547cSRui Paulo const u8 *payload, 5045b9c547cSRui Paulo size_t payload_len) 5055b9c547cSRui Paulo { 5065b9c547cSRui Paulo struct wpabuf *resp; 5075b9c547cSRui Paulo const u8 *pos, *end; 5085b9c547cSRui Paulo size_t prot_len; 5095b9c547cSRui Paulo u8 nonces[2 * EAP_EKE_MAX_NONCE_LEN]; 5105b9c547cSRui Paulo u8 auth_s[EAP_EKE_MAX_HASH_LEN]; 5115b9c547cSRui Paulo size_t decrypt_len; 5125b9c547cSRui Paulo u8 *auth; 513*325151a3SRui Paulo u8 id = eap_get_id(reqData); 5145b9c547cSRui Paulo 5155b9c547cSRui Paulo if (data->state != CONFIRM) { 5165b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Confirm/Request received in unexpected state (%d)", 5175b9c547cSRui Paulo data->state); 518*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 5195b9c547cSRui Paulo EAP_EKE_FAIL_PROTO_ERROR); 5205b9c547cSRui Paulo } 5215b9c547cSRui Paulo 5225b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Confirm/Request"); 5235b9c547cSRui Paulo 5245b9c547cSRui Paulo pos = payload; 5255b9c547cSRui Paulo end = payload + payload_len; 5265b9c547cSRui Paulo 5275b9c547cSRui Paulo if (pos + data->sess.pnonce_ps_len + data->sess.prf_len > end) { 5285b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Confirm"); 529*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 5305b9c547cSRui Paulo EAP_EKE_FAIL_PROTO_ERROR); 5315b9c547cSRui Paulo } 5325b9c547cSRui Paulo 5335b9c547cSRui Paulo decrypt_len = sizeof(nonces); 5345b9c547cSRui Paulo if (eap_eke_decrypt_prot(&data->sess, pos, data->sess.pnonce_ps_len, 5355b9c547cSRui Paulo nonces, &decrypt_len) < 0) { 5365b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_PS"); 537*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 5385b9c547cSRui Paulo EAP_EKE_FAIL_AUTHENTICATION_FAIL); 5395b9c547cSRui Paulo } 5405b9c547cSRui Paulo if (decrypt_len != (size_t) 2 * data->sess.nonce_len) { 5415b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: PNonce_PS protected data length does not match length of Nonce_P and Nonce_S"); 542*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 5435b9c547cSRui Paulo EAP_EKE_FAIL_AUTHENTICATION_FAIL); 5445b9c547cSRui Paulo } 5455b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_P | Nonce_S", 5465b9c547cSRui Paulo nonces, 2 * data->sess.nonce_len); 5475b9c547cSRui Paulo if (os_memcmp(data->nonce_p, nonces, data->sess.nonce_len) != 0) { 5485b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_P does not match transmitted Nonce_P"); 549*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 5505b9c547cSRui Paulo EAP_EKE_FAIL_AUTHENTICATION_FAIL); 5515b9c547cSRui Paulo } 5525b9c547cSRui Paulo 5535b9c547cSRui Paulo os_memcpy(data->nonce_s, nonces + data->sess.nonce_len, 5545b9c547cSRui Paulo data->sess.nonce_len); 5555b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_S", 5565b9c547cSRui Paulo data->nonce_s, data->sess.nonce_len); 5575b9c547cSRui Paulo 5585b9c547cSRui Paulo if (eap_eke_derive_ka(&data->sess, data->serverid, data->serverid_len, 5595b9c547cSRui Paulo data->peerid, data->peerid_len, 5605b9c547cSRui Paulo data->nonce_p, data->nonce_s) < 0) { 561*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 5625b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 5635b9c547cSRui Paulo } 5645b9c547cSRui Paulo 5655b9c547cSRui Paulo if (eap_eke_auth(&data->sess, "EAP-EKE server", data->msgs, auth_s) < 0) 5665b9c547cSRui Paulo { 567*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 5685b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 5695b9c547cSRui Paulo } 5705b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_S", auth_s, data->sess.prf_len); 5715b9c547cSRui Paulo if (os_memcmp_const(auth_s, pos + data->sess.pnonce_ps_len, 5725b9c547cSRui Paulo data->sess.prf_len) != 0) { 5735b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Auth_S does not match"); 574*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 5755b9c547cSRui Paulo EAP_EKE_FAIL_AUTHENTICATION_FAIL); 5765b9c547cSRui Paulo } 5775b9c547cSRui Paulo 5785b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Confirm/Response"); 5795b9c547cSRui Paulo 580*325151a3SRui Paulo resp = eap_eke_build_msg(data, id, 5815b9c547cSRui Paulo data->sess.pnonce_len + data->sess.prf_len, 5825b9c547cSRui Paulo EAP_EKE_CONFIRM); 5835b9c547cSRui Paulo if (resp == NULL) { 584*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 5855b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 5865b9c547cSRui Paulo } 5875b9c547cSRui Paulo 5885b9c547cSRui Paulo prot_len = wpabuf_tailroom(resp); 5895b9c547cSRui Paulo if (eap_eke_prot(&data->sess, data->nonce_s, data->sess.nonce_len, 5905b9c547cSRui Paulo wpabuf_put(resp, 0), &prot_len) < 0) { 5915b9c547cSRui Paulo wpabuf_free(resp); 592*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 5935b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 5945b9c547cSRui Paulo } 5955b9c547cSRui Paulo wpabuf_put(resp, prot_len); 5965b9c547cSRui Paulo 5975b9c547cSRui Paulo auth = wpabuf_put(resp, data->sess.prf_len); 5985b9c547cSRui Paulo if (eap_eke_auth(&data->sess, "EAP-EKE peer", data->msgs, auth) < 0) { 5995b9c547cSRui Paulo wpabuf_free(resp); 600*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 6015b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 6025b9c547cSRui Paulo } 6035b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth, data->sess.prf_len); 6045b9c547cSRui Paulo 6055b9c547cSRui Paulo if (eap_eke_derive_msk(&data->sess, data->serverid, data->serverid_len, 6065b9c547cSRui Paulo data->peerid, data->peerid_len, 6075b9c547cSRui Paulo data->nonce_s, data->nonce_p, 6085b9c547cSRui Paulo data->msk, data->emsk) < 0) { 6095b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive MSK/EMSK"); 6105b9c547cSRui Paulo wpabuf_free(resp); 611*325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 6125b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 6135b9c547cSRui Paulo } 6145b9c547cSRui Paulo 6155b9c547cSRui Paulo os_memset(data->dh_priv, 0, sizeof(data->dh_priv)); 6165b9c547cSRui Paulo eap_eke_session_clean(&data->sess); 6175b9c547cSRui Paulo 6185b9c547cSRui Paulo eap_eke_state(data, SUCCESS); 6195b9c547cSRui Paulo ret->methodState = METHOD_MAY_CONT; 6205b9c547cSRui Paulo ret->decision = DECISION_COND_SUCC; 6215b9c547cSRui Paulo ret->allowNotifications = FALSE; 6225b9c547cSRui Paulo 6235b9c547cSRui Paulo return resp; 6245b9c547cSRui Paulo } 6255b9c547cSRui Paulo 6265b9c547cSRui Paulo 6275b9c547cSRui Paulo static struct wpabuf * eap_eke_process_failure(struct eap_eke_data *data, 6285b9c547cSRui Paulo struct eap_method_ret *ret, 6295b9c547cSRui Paulo const struct wpabuf *reqData, 6305b9c547cSRui Paulo const u8 *payload, 6315b9c547cSRui Paulo size_t payload_len) 6325b9c547cSRui Paulo { 6335b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Failure/Request"); 6345b9c547cSRui Paulo 6355b9c547cSRui Paulo if (payload_len < 4) { 6365b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Failure"); 6375b9c547cSRui Paulo } else { 6385b9c547cSRui Paulo u32 code; 6395b9c547cSRui Paulo code = WPA_GET_BE32(payload); 6405b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Failure-Code 0x%x", code); 6415b9c547cSRui Paulo } 6425b9c547cSRui Paulo 643*325151a3SRui Paulo return eap_eke_build_fail(data, ret, eap_get_id(reqData), 644*325151a3SRui Paulo EAP_EKE_FAIL_NO_ERROR); 6455b9c547cSRui Paulo } 6465b9c547cSRui Paulo 6475b9c547cSRui Paulo 6485b9c547cSRui Paulo static struct wpabuf * eap_eke_process(struct eap_sm *sm, void *priv, 6495b9c547cSRui Paulo struct eap_method_ret *ret, 6505b9c547cSRui Paulo const struct wpabuf *reqData) 6515b9c547cSRui Paulo { 6525b9c547cSRui Paulo struct eap_eke_data *data = priv; 6535b9c547cSRui Paulo struct wpabuf *resp; 6545b9c547cSRui Paulo const u8 *pos, *end; 6555b9c547cSRui Paulo size_t len; 6565b9c547cSRui Paulo u8 eke_exch; 6575b9c547cSRui Paulo 6585b9c547cSRui Paulo pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, reqData, &len); 6595b9c547cSRui Paulo if (pos == NULL || len < 1) { 6605b9c547cSRui Paulo ret->ignore = TRUE; 6615b9c547cSRui Paulo return NULL; 6625b9c547cSRui Paulo } 6635b9c547cSRui Paulo 6645b9c547cSRui Paulo end = pos + len; 6655b9c547cSRui Paulo eke_exch = *pos++; 6665b9c547cSRui Paulo 6675b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: exch %d", eke_exch); 6685b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received Data", pos, end - pos); 6695b9c547cSRui Paulo 6705b9c547cSRui Paulo ret->ignore = FALSE; 6715b9c547cSRui Paulo ret->methodState = METHOD_MAY_CONT; 6725b9c547cSRui Paulo ret->decision = DECISION_FAIL; 6735b9c547cSRui Paulo ret->allowNotifications = TRUE; 6745b9c547cSRui Paulo 6755b9c547cSRui Paulo switch (eke_exch) { 6765b9c547cSRui Paulo case EAP_EKE_ID: 6775b9c547cSRui Paulo resp = eap_eke_process_id(data, ret, reqData, pos, end - pos); 6785b9c547cSRui Paulo break; 6795b9c547cSRui Paulo case EAP_EKE_COMMIT: 6805b9c547cSRui Paulo resp = eap_eke_process_commit(sm, data, ret, reqData, 6815b9c547cSRui Paulo pos, end - pos); 6825b9c547cSRui Paulo break; 6835b9c547cSRui Paulo case EAP_EKE_CONFIRM: 6845b9c547cSRui Paulo resp = eap_eke_process_confirm(data, ret, reqData, 6855b9c547cSRui Paulo pos, end - pos); 6865b9c547cSRui Paulo break; 6875b9c547cSRui Paulo case EAP_EKE_FAILURE: 6885b9c547cSRui Paulo resp = eap_eke_process_failure(data, ret, reqData, 6895b9c547cSRui Paulo pos, end - pos); 6905b9c547cSRui Paulo break; 6915b9c547cSRui Paulo default: 6925b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Ignoring message with unknown EKE-Exch %d", eke_exch); 6935b9c547cSRui Paulo ret->ignore = TRUE; 6945b9c547cSRui Paulo return NULL; 6955b9c547cSRui Paulo } 6965b9c547cSRui Paulo 6975b9c547cSRui Paulo if (ret->methodState == METHOD_DONE) 6985b9c547cSRui Paulo ret->allowNotifications = FALSE; 6995b9c547cSRui Paulo 7005b9c547cSRui Paulo return resp; 7015b9c547cSRui Paulo } 7025b9c547cSRui Paulo 7035b9c547cSRui Paulo 7045b9c547cSRui Paulo static Boolean eap_eke_isKeyAvailable(struct eap_sm *sm, void *priv) 7055b9c547cSRui Paulo { 7065b9c547cSRui Paulo struct eap_eke_data *data = priv; 7075b9c547cSRui Paulo return data->state == SUCCESS; 7085b9c547cSRui Paulo } 7095b9c547cSRui Paulo 7105b9c547cSRui Paulo 7115b9c547cSRui Paulo static u8 * eap_eke_getKey(struct eap_sm *sm, void *priv, size_t *len) 7125b9c547cSRui Paulo { 7135b9c547cSRui Paulo struct eap_eke_data *data = priv; 7145b9c547cSRui Paulo u8 *key; 7155b9c547cSRui Paulo 7165b9c547cSRui Paulo if (data->state != SUCCESS) 7175b9c547cSRui Paulo return NULL; 7185b9c547cSRui Paulo 7195b9c547cSRui Paulo key = os_malloc(EAP_MSK_LEN); 7205b9c547cSRui Paulo if (key == NULL) 7215b9c547cSRui Paulo return NULL; 7225b9c547cSRui Paulo os_memcpy(key, data->msk, EAP_MSK_LEN); 7235b9c547cSRui Paulo *len = EAP_MSK_LEN; 7245b9c547cSRui Paulo 7255b9c547cSRui Paulo return key; 7265b9c547cSRui Paulo } 7275b9c547cSRui Paulo 7285b9c547cSRui Paulo 7295b9c547cSRui Paulo static u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 7305b9c547cSRui Paulo { 7315b9c547cSRui Paulo struct eap_eke_data *data = priv; 7325b9c547cSRui Paulo u8 *key; 7335b9c547cSRui Paulo 7345b9c547cSRui Paulo if (data->state != SUCCESS) 7355b9c547cSRui Paulo return NULL; 7365b9c547cSRui Paulo 7375b9c547cSRui Paulo key = os_malloc(EAP_EMSK_LEN); 7385b9c547cSRui Paulo if (key == NULL) 7395b9c547cSRui Paulo return NULL; 7405b9c547cSRui Paulo os_memcpy(key, data->emsk, EAP_EMSK_LEN); 7415b9c547cSRui Paulo *len = EAP_EMSK_LEN; 7425b9c547cSRui Paulo 7435b9c547cSRui Paulo return key; 7445b9c547cSRui Paulo } 7455b9c547cSRui Paulo 7465b9c547cSRui Paulo 747*325151a3SRui Paulo static u8 * eap_eke_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 748*325151a3SRui Paulo { 749*325151a3SRui Paulo struct eap_eke_data *data = priv; 750*325151a3SRui Paulo u8 *sid; 751*325151a3SRui Paulo size_t sid_len; 752*325151a3SRui Paulo 753*325151a3SRui Paulo if (data->state != SUCCESS) 754*325151a3SRui Paulo return NULL; 755*325151a3SRui Paulo 756*325151a3SRui Paulo sid_len = 1 + 2 * data->sess.nonce_len; 757*325151a3SRui Paulo sid = os_malloc(sid_len); 758*325151a3SRui Paulo if (sid == NULL) 759*325151a3SRui Paulo return NULL; 760*325151a3SRui Paulo sid[0] = EAP_TYPE_EKE; 761*325151a3SRui Paulo os_memcpy(sid + 1, data->nonce_p, data->sess.nonce_len); 762*325151a3SRui Paulo os_memcpy(sid + 1 + data->sess.nonce_len, data->nonce_s, 763*325151a3SRui Paulo data->sess.nonce_len); 764*325151a3SRui Paulo *len = sid_len; 765*325151a3SRui Paulo 766*325151a3SRui Paulo return sid; 767*325151a3SRui Paulo } 768*325151a3SRui Paulo 769*325151a3SRui Paulo 7705b9c547cSRui Paulo int eap_peer_eke_register(void) 7715b9c547cSRui Paulo { 7725b9c547cSRui Paulo struct eap_method *eap; 7735b9c547cSRui Paulo int ret; 7745b9c547cSRui Paulo 7755b9c547cSRui Paulo eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 7765b9c547cSRui Paulo EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE"); 7775b9c547cSRui Paulo if (eap == NULL) 7785b9c547cSRui Paulo return -1; 7795b9c547cSRui Paulo 7805b9c547cSRui Paulo eap->init = eap_eke_init; 7815b9c547cSRui Paulo eap->deinit = eap_eke_deinit; 7825b9c547cSRui Paulo eap->process = eap_eke_process; 7835b9c547cSRui Paulo eap->isKeyAvailable = eap_eke_isKeyAvailable; 7845b9c547cSRui Paulo eap->getKey = eap_eke_getKey; 7855b9c547cSRui Paulo eap->get_emsk = eap_eke_get_emsk; 786*325151a3SRui Paulo eap->getSessionId = eap_eke_get_session_id; 7875b9c547cSRui Paulo 7885b9c547cSRui Paulo ret = eap_peer_method_register(eap); 7895b9c547cSRui Paulo if (ret) 7905b9c547cSRui Paulo eap_peer_method_free(eap); 7915b9c547cSRui Paulo return ret; 7925b9c547cSRui Paulo } 793