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) { 88*85732ac8SCy Schubert data->peerid = os_memdup(identity, identity_len); 895b9c547cSRui Paulo if (data->peerid == NULL) { 905b9c547cSRui Paulo eap_eke_deinit(sm, data); 915b9c547cSRui Paulo return NULL; 925b9c547cSRui Paulo } 935b9c547cSRui Paulo data->peerid_len = identity_len; 945b9c547cSRui Paulo } 955b9c547cSRui Paulo 965b9c547cSRui Paulo phase1 = eap_get_config_phase1(sm); 975b9c547cSRui Paulo if (phase1) { 985b9c547cSRui Paulo const char *pos; 995b9c547cSRui Paulo 1005b9c547cSRui Paulo pos = os_strstr(phase1, "dhgroup="); 1015b9c547cSRui Paulo if (pos) { 1025b9c547cSRui Paulo data->dhgroup = atoi(pos + 8); 1035b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Forced dhgroup %u", 1045b9c547cSRui Paulo data->dhgroup); 1055b9c547cSRui Paulo } 1065b9c547cSRui Paulo 1075b9c547cSRui Paulo pos = os_strstr(phase1, "encr="); 1085b9c547cSRui Paulo if (pos) { 1095b9c547cSRui Paulo data->encr = atoi(pos + 5); 1105b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Forced encr %u", 1115b9c547cSRui Paulo data->encr); 1125b9c547cSRui Paulo } 1135b9c547cSRui Paulo 1145b9c547cSRui Paulo pos = os_strstr(phase1, "prf="); 1155b9c547cSRui Paulo if (pos) { 1165b9c547cSRui Paulo data->prf = atoi(pos + 4); 1175b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Forced prf %u", 1185b9c547cSRui Paulo data->prf); 1195b9c547cSRui Paulo } 1205b9c547cSRui Paulo 1215b9c547cSRui Paulo pos = os_strstr(phase1, "mac="); 1225b9c547cSRui Paulo if (pos) { 1235b9c547cSRui Paulo data->mac = atoi(pos + 4); 1245b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Forced mac %u", 1255b9c547cSRui Paulo data->mac); 1265b9c547cSRui Paulo } 1275b9c547cSRui Paulo } 1285b9c547cSRui Paulo 1295b9c547cSRui Paulo return data; 1305b9c547cSRui Paulo } 1315b9c547cSRui Paulo 1325b9c547cSRui Paulo 1335b9c547cSRui Paulo static void eap_eke_deinit(struct eap_sm *sm, void *priv) 1345b9c547cSRui Paulo { 1355b9c547cSRui Paulo struct eap_eke_data *data = priv; 1365b9c547cSRui Paulo eap_eke_session_clean(&data->sess); 1375b9c547cSRui Paulo os_free(data->serverid); 1385b9c547cSRui Paulo os_free(data->peerid); 1395b9c547cSRui Paulo wpabuf_free(data->msgs); 1405b9c547cSRui Paulo bin_clear_free(data, sizeof(*data)); 1415b9c547cSRui Paulo } 1425b9c547cSRui Paulo 1435b9c547cSRui Paulo 1445b9c547cSRui Paulo static struct wpabuf * eap_eke_build_msg(struct eap_eke_data *data, int id, 1455b9c547cSRui Paulo size_t length, u8 eke_exch) 1465b9c547cSRui Paulo { 1475b9c547cSRui Paulo struct wpabuf *msg; 1485b9c547cSRui Paulo size_t plen; 1495b9c547cSRui Paulo 1505b9c547cSRui Paulo plen = 1 + length; 1515b9c547cSRui Paulo 1525b9c547cSRui Paulo msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EKE, plen, 1535b9c547cSRui Paulo EAP_CODE_RESPONSE, id); 1545b9c547cSRui Paulo if (msg == NULL) { 1555b9c547cSRui Paulo wpa_printf(MSG_ERROR, "EAP-EKE: Failed to allocate memory"); 1565b9c547cSRui Paulo return NULL; 1575b9c547cSRui Paulo } 1585b9c547cSRui Paulo 1595b9c547cSRui Paulo wpabuf_put_u8(msg, eke_exch); 1605b9c547cSRui Paulo 1615b9c547cSRui Paulo return msg; 1625b9c547cSRui Paulo } 1635b9c547cSRui Paulo 1645b9c547cSRui Paulo 1655b9c547cSRui Paulo static int eap_eke_supp_dhgroup(u8 dhgroup) 1665b9c547cSRui Paulo { 1675b9c547cSRui Paulo return dhgroup == EAP_EKE_DHGROUP_EKE_2 || 1685b9c547cSRui Paulo dhgroup == EAP_EKE_DHGROUP_EKE_5 || 1695b9c547cSRui Paulo dhgroup == EAP_EKE_DHGROUP_EKE_14 || 1705b9c547cSRui Paulo dhgroup == EAP_EKE_DHGROUP_EKE_15 || 1715b9c547cSRui Paulo dhgroup == EAP_EKE_DHGROUP_EKE_16; 1725b9c547cSRui Paulo } 1735b9c547cSRui Paulo 1745b9c547cSRui Paulo 1755b9c547cSRui Paulo static int eap_eke_supp_encr(u8 encr) 1765b9c547cSRui Paulo { 1775b9c547cSRui Paulo return encr == EAP_EKE_ENCR_AES128_CBC; 1785b9c547cSRui Paulo } 1795b9c547cSRui Paulo 1805b9c547cSRui Paulo 1815b9c547cSRui Paulo static int eap_eke_supp_prf(u8 prf) 1825b9c547cSRui Paulo { 1835b9c547cSRui Paulo return prf == EAP_EKE_PRF_HMAC_SHA1 || 1845b9c547cSRui Paulo prf == EAP_EKE_PRF_HMAC_SHA2_256; 1855b9c547cSRui Paulo } 1865b9c547cSRui Paulo 1875b9c547cSRui Paulo 1885b9c547cSRui Paulo static int eap_eke_supp_mac(u8 mac) 1895b9c547cSRui Paulo { 1905b9c547cSRui Paulo return mac == EAP_EKE_MAC_HMAC_SHA1 || 1915b9c547cSRui Paulo mac == EAP_EKE_MAC_HMAC_SHA2_256; 1925b9c547cSRui Paulo } 1935b9c547cSRui Paulo 1945b9c547cSRui Paulo 1955b9c547cSRui Paulo static struct wpabuf * eap_eke_build_fail(struct eap_eke_data *data, 1965b9c547cSRui Paulo struct eap_method_ret *ret, 197325151a3SRui Paulo u8 id, u32 failure_code) 1985b9c547cSRui Paulo { 1995b9c547cSRui Paulo struct wpabuf *resp; 2005b9c547cSRui Paulo 2015b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Failure/Response - code=0x%x", 2025b9c547cSRui Paulo failure_code); 2035b9c547cSRui Paulo 204325151a3SRui Paulo resp = eap_eke_build_msg(data, id, 4, EAP_EKE_FAILURE); 2055b9c547cSRui Paulo if (resp) 2065b9c547cSRui Paulo wpabuf_put_be32(resp, failure_code); 2075b9c547cSRui Paulo 2085b9c547cSRui Paulo os_memset(data->dh_priv, 0, sizeof(data->dh_priv)); 2095b9c547cSRui Paulo eap_eke_session_clean(&data->sess); 2105b9c547cSRui Paulo 2115b9c547cSRui Paulo eap_eke_state(data, FAILURE); 2125b9c547cSRui Paulo ret->methodState = METHOD_DONE; 2135b9c547cSRui Paulo ret->decision = DECISION_FAIL; 2145b9c547cSRui Paulo ret->allowNotifications = FALSE; 2155b9c547cSRui Paulo 2165b9c547cSRui Paulo return resp; 2175b9c547cSRui Paulo } 2185b9c547cSRui Paulo 2195b9c547cSRui Paulo 2205b9c547cSRui Paulo static struct wpabuf * eap_eke_process_id(struct eap_eke_data *data, 2215b9c547cSRui Paulo struct eap_method_ret *ret, 2225b9c547cSRui Paulo const struct wpabuf *reqData, 2235b9c547cSRui Paulo const u8 *payload, 2245b9c547cSRui Paulo size_t payload_len) 2255b9c547cSRui Paulo { 2265b9c547cSRui Paulo struct wpabuf *resp; 2275b9c547cSRui Paulo unsigned num_prop, i; 2285b9c547cSRui Paulo const u8 *pos, *end; 2295b9c547cSRui Paulo const u8 *prop = NULL; 2305b9c547cSRui Paulo u8 idtype; 231325151a3SRui Paulo u8 id = eap_get_id(reqData); 2325b9c547cSRui Paulo 2335b9c547cSRui Paulo if (data->state != IDENTITY) { 234325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 2355b9c547cSRui Paulo EAP_EKE_FAIL_PROTO_ERROR); 2365b9c547cSRui Paulo } 2375b9c547cSRui Paulo 2385b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-ID/Request"); 2395b9c547cSRui Paulo 2405b9c547cSRui Paulo if (payload_len < 2 + 4) { 2415b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data"); 242325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 2435b9c547cSRui Paulo EAP_EKE_FAIL_PROTO_ERROR); 2445b9c547cSRui Paulo } 2455b9c547cSRui Paulo 2465b9c547cSRui Paulo pos = payload; 2475b9c547cSRui Paulo end = payload + payload_len; 2485b9c547cSRui Paulo 2495b9c547cSRui Paulo num_prop = *pos++; 2505b9c547cSRui Paulo pos++; /* Ignore Reserved field */ 2515b9c547cSRui Paulo 2525b9c547cSRui Paulo if (pos + num_prop * 4 > end) { 2535b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data (num_prop=%u)", 2545b9c547cSRui Paulo num_prop); 255325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 2565b9c547cSRui Paulo EAP_EKE_FAIL_PROTO_ERROR); 2575b9c547cSRui Paulo } 2585b9c547cSRui Paulo 2595b9c547cSRui Paulo for (i = 0; i < num_prop; i++) { 2605b9c547cSRui Paulo const u8 *tmp = pos; 2615b9c547cSRui Paulo 2625b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Proposal #%u: dh=%u encr=%u prf=%u mac=%u", 2635b9c547cSRui Paulo i, pos[0], pos[1], pos[2], pos[3]); 2645b9c547cSRui Paulo pos += 4; 2655b9c547cSRui Paulo 2665b9c547cSRui Paulo if ((data->dhgroup && data->dhgroup != *tmp) || 2675b9c547cSRui Paulo !eap_eke_supp_dhgroup(*tmp)) 2685b9c547cSRui Paulo continue; 2695b9c547cSRui Paulo tmp++; 2705b9c547cSRui Paulo if ((data->encr && data->encr != *tmp) || 2715b9c547cSRui Paulo !eap_eke_supp_encr(*tmp)) 2725b9c547cSRui Paulo continue; 2735b9c547cSRui Paulo tmp++; 2745b9c547cSRui Paulo if ((data->prf && data->prf != *tmp) || 2755b9c547cSRui Paulo !eap_eke_supp_prf(*tmp)) 2765b9c547cSRui Paulo continue; 2775b9c547cSRui Paulo tmp++; 2785b9c547cSRui Paulo if ((data->mac && data->mac != *tmp) || 2795b9c547cSRui Paulo !eap_eke_supp_mac(*tmp)) 2805b9c547cSRui Paulo continue; 2815b9c547cSRui Paulo 2825b9c547cSRui Paulo prop = tmp - 3; 2835b9c547cSRui Paulo if (eap_eke_session_init(&data->sess, prop[0], prop[1], prop[2], 2845b9c547cSRui Paulo prop[3]) < 0) { 2855b9c547cSRui Paulo prop = NULL; 2865b9c547cSRui Paulo continue; 2875b9c547cSRui Paulo } 2885b9c547cSRui Paulo 2895b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Selected proposal"); 2905b9c547cSRui Paulo break; 2915b9c547cSRui Paulo } 2925b9c547cSRui Paulo 2935b9c547cSRui Paulo if (prop == NULL) { 2945b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: No acceptable proposal found"); 295325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 2965b9c547cSRui Paulo EAP_EKE_FAIL_NO_PROPOSAL_CHOSEN); 2975b9c547cSRui Paulo } 2985b9c547cSRui Paulo 2995b9c547cSRui Paulo pos += (num_prop - i - 1) * 4; 3005b9c547cSRui Paulo 3015b9c547cSRui Paulo if (pos == end) { 3025b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Too short ID/Request Data to include IDType/Identity"); 303325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 3045b9c547cSRui Paulo EAP_EKE_FAIL_PROTO_ERROR); 3055b9c547cSRui Paulo } 3065b9c547cSRui Paulo 3075b9c547cSRui Paulo idtype = *pos++; 3085b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Server IDType %u", idtype); 3095b9c547cSRui Paulo wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Server Identity", 3105b9c547cSRui Paulo pos, end - pos); 3115b9c547cSRui Paulo os_free(data->serverid); 312*85732ac8SCy Schubert data->serverid = os_memdup(pos, end - pos); 3135b9c547cSRui Paulo if (data->serverid == NULL) { 314325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 3155b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 3165b9c547cSRui Paulo } 3175b9c547cSRui Paulo data->serverid_len = end - pos; 3185b9c547cSRui Paulo 3195b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-ID/Response"); 3205b9c547cSRui Paulo 321325151a3SRui Paulo resp = eap_eke_build_msg(data, id, 3225b9c547cSRui Paulo 2 + 4 + 1 + data->peerid_len, 3235b9c547cSRui Paulo EAP_EKE_ID); 3245b9c547cSRui Paulo if (resp == NULL) { 325325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 3265b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 3275b9c547cSRui Paulo } 3285b9c547cSRui Paulo 3295b9c547cSRui Paulo wpabuf_put_u8(resp, 1); /* NumProposals */ 3305b9c547cSRui Paulo wpabuf_put_u8(resp, 0); /* Reserved */ 3315b9c547cSRui Paulo wpabuf_put_data(resp, prop, 4); /* Selected Proposal */ 3325b9c547cSRui Paulo wpabuf_put_u8(resp, EAP_EKE_ID_NAI); 3335b9c547cSRui Paulo if (data->peerid) 3345b9c547cSRui Paulo wpabuf_put_data(resp, data->peerid, data->peerid_len); 3355b9c547cSRui Paulo 3365b9c547cSRui Paulo wpabuf_free(data->msgs); 3375b9c547cSRui Paulo data->msgs = wpabuf_alloc(wpabuf_len(reqData) + wpabuf_len(resp)); 3385b9c547cSRui Paulo if (data->msgs == NULL) { 3395b9c547cSRui Paulo wpabuf_free(resp); 340325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 3415b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 3425b9c547cSRui Paulo } 3435b9c547cSRui Paulo wpabuf_put_buf(data->msgs, reqData); 3445b9c547cSRui Paulo wpabuf_put_buf(data->msgs, resp); 3455b9c547cSRui Paulo 3465b9c547cSRui Paulo eap_eke_state(data, COMMIT); 3475b9c547cSRui Paulo 3485b9c547cSRui Paulo return resp; 3495b9c547cSRui Paulo } 3505b9c547cSRui Paulo 3515b9c547cSRui Paulo 3525b9c547cSRui Paulo static struct wpabuf * eap_eke_process_commit(struct eap_sm *sm, 3535b9c547cSRui Paulo struct eap_eke_data *data, 3545b9c547cSRui Paulo struct eap_method_ret *ret, 3555b9c547cSRui Paulo const struct wpabuf *reqData, 3565b9c547cSRui Paulo const u8 *payload, 3575b9c547cSRui Paulo size_t payload_len) 3585b9c547cSRui Paulo { 3595b9c547cSRui Paulo struct wpabuf *resp; 3605b9c547cSRui Paulo const u8 *pos, *end, *dhcomp; 3615b9c547cSRui Paulo size_t prot_len; 3625b9c547cSRui Paulo u8 *rpos; 3635b9c547cSRui Paulo u8 key[EAP_EKE_MAX_KEY_LEN]; 3645b9c547cSRui Paulo u8 pub[EAP_EKE_MAX_DH_LEN]; 3655b9c547cSRui Paulo const u8 *password; 3665b9c547cSRui Paulo size_t password_len; 367325151a3SRui Paulo u8 id = eap_get_id(reqData); 3685b9c547cSRui Paulo 3695b9c547cSRui Paulo if (data->state != COMMIT) { 3705b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Commit/Request received in unexpected state (%d)", data->state); 371325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 3725b9c547cSRui Paulo EAP_EKE_FAIL_PROTO_ERROR); 3735b9c547cSRui Paulo } 3745b9c547cSRui Paulo 3755b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Commit/Request"); 3765b9c547cSRui Paulo 3775b9c547cSRui Paulo password = eap_get_config_password(sm, &password_len); 3785b9c547cSRui Paulo if (password == NULL) { 3795b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: No password configured!"); 380325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 3815b9c547cSRui Paulo EAP_EKE_FAIL_PASSWD_NOT_FOUND); 3825b9c547cSRui Paulo } 3835b9c547cSRui Paulo 3845b9c547cSRui Paulo pos = payload; 3855b9c547cSRui Paulo end = payload + payload_len; 3865b9c547cSRui Paulo 3875b9c547cSRui Paulo if (pos + data->sess.dhcomp_len > end) { 3885b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit"); 389325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 3905b9c547cSRui Paulo EAP_EKE_FAIL_PROTO_ERROR); 3915b9c547cSRui Paulo } 3925b9c547cSRui Paulo 3935b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_S", 3945b9c547cSRui Paulo pos, data->sess.dhcomp_len); 3955b9c547cSRui Paulo dhcomp = pos; 3965b9c547cSRui Paulo pos += data->sess.dhcomp_len; 3975b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos); 3985b9c547cSRui Paulo 3995b9c547cSRui Paulo /* 4005b9c547cSRui Paulo * temp = prf(0+, password) 4015b9c547cSRui Paulo * key = prf+(temp, ID_S | ID_P) 4025b9c547cSRui Paulo */ 4035b9c547cSRui Paulo if (eap_eke_derive_key(&data->sess, password, password_len, 4045b9c547cSRui Paulo data->serverid, data->serverid_len, 4055b9c547cSRui Paulo data->peerid, data->peerid_len, key) < 0) { 4065b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key"); 407325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 4085b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 4095b9c547cSRui Paulo } 4105b9c547cSRui Paulo 4115b9c547cSRui Paulo /* 4125b9c547cSRui Paulo * y_p = g ^ x_p (mod p) 4135b9c547cSRui Paulo * x_p = random number 2 .. p-1 4145b9c547cSRui Paulo */ 4155b9c547cSRui Paulo if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) { 4165b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH"); 4175b9c547cSRui Paulo os_memset(key, 0, sizeof(key)); 418325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 4195b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 4205b9c547cSRui Paulo } 4215b9c547cSRui Paulo 4225b9c547cSRui Paulo if (eap_eke_shared_secret(&data->sess, key, data->dh_priv, dhcomp) < 0) 4235b9c547cSRui Paulo { 4245b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret"); 4255b9c547cSRui Paulo os_memset(key, 0, sizeof(key)); 426325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 4275b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 4285b9c547cSRui Paulo } 4295b9c547cSRui Paulo 4305b9c547cSRui Paulo if (eap_eke_derive_ke_ki(&data->sess, 4315b9c547cSRui Paulo data->serverid, data->serverid_len, 4325b9c547cSRui Paulo data->peerid, data->peerid_len) < 0) { 4335b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki"); 4345b9c547cSRui Paulo os_memset(key, 0, sizeof(key)); 435325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 4365b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 4375b9c547cSRui Paulo } 4385b9c547cSRui Paulo 4395b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Commit/Response"); 4405b9c547cSRui Paulo 441325151a3SRui Paulo resp = eap_eke_build_msg(data, id, 4425b9c547cSRui Paulo data->sess.dhcomp_len + data->sess.pnonce_len, 4435b9c547cSRui Paulo EAP_EKE_COMMIT); 4445b9c547cSRui Paulo if (resp == NULL) { 4455b9c547cSRui Paulo os_memset(key, 0, sizeof(key)); 446325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 4475b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 4485b9c547cSRui Paulo } 4495b9c547cSRui Paulo 4505b9c547cSRui Paulo /* DHComponent_P = Encr(key, y_p) */ 4515b9c547cSRui Paulo rpos = wpabuf_put(resp, data->sess.dhcomp_len); 4525b9c547cSRui Paulo if (eap_eke_dhcomp(&data->sess, key, pub, rpos) < 0) { 453780fb4a2SCy Schubert wpabuf_free(resp); 4545b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_P"); 4555b9c547cSRui Paulo os_memset(key, 0, sizeof(key)); 456325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 4575b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 4585b9c547cSRui Paulo } 4595b9c547cSRui Paulo os_memset(key, 0, sizeof(key)); 4605b9c547cSRui Paulo 4615b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P", 4625b9c547cSRui Paulo rpos, data->sess.dhcomp_len); 4635b9c547cSRui Paulo 4645b9c547cSRui Paulo if (random_get_bytes(data->nonce_p, data->sess.nonce_len)) { 4655b9c547cSRui Paulo wpabuf_free(resp); 466325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 4675b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 4685b9c547cSRui Paulo } 4695b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P", 4705b9c547cSRui Paulo data->nonce_p, data->sess.nonce_len); 4715b9c547cSRui Paulo prot_len = wpabuf_tailroom(resp); 4725b9c547cSRui Paulo if (eap_eke_prot(&data->sess, data->nonce_p, data->sess.nonce_len, 4735b9c547cSRui Paulo wpabuf_put(resp, 0), &prot_len) < 0) { 4745b9c547cSRui Paulo wpabuf_free(resp); 475325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 4765b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 4775b9c547cSRui Paulo } 4785b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P", 4795b9c547cSRui Paulo wpabuf_put(resp, 0), prot_len); 4805b9c547cSRui Paulo wpabuf_put(resp, prot_len); 4815b9c547cSRui Paulo 4825b9c547cSRui Paulo /* TODO: CBValue */ 4835b9c547cSRui Paulo 4845b9c547cSRui Paulo if (wpabuf_resize(&data->msgs, wpabuf_len(reqData) + wpabuf_len(resp)) 4855b9c547cSRui Paulo < 0) { 4865b9c547cSRui Paulo wpabuf_free(resp); 487325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 4885b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 4895b9c547cSRui Paulo } 4905b9c547cSRui Paulo wpabuf_put_buf(data->msgs, reqData); 4915b9c547cSRui Paulo wpabuf_put_buf(data->msgs, resp); 4925b9c547cSRui Paulo 4935b9c547cSRui Paulo eap_eke_state(data, CONFIRM); 4945b9c547cSRui Paulo 4955b9c547cSRui Paulo return resp; 4965b9c547cSRui Paulo } 4975b9c547cSRui Paulo 4985b9c547cSRui Paulo 4995b9c547cSRui Paulo static struct wpabuf * eap_eke_process_confirm(struct eap_eke_data *data, 5005b9c547cSRui Paulo struct eap_method_ret *ret, 5015b9c547cSRui Paulo const struct wpabuf *reqData, 5025b9c547cSRui Paulo const u8 *payload, 5035b9c547cSRui Paulo size_t payload_len) 5045b9c547cSRui Paulo { 5055b9c547cSRui Paulo struct wpabuf *resp; 5065b9c547cSRui Paulo const u8 *pos, *end; 5075b9c547cSRui Paulo size_t prot_len; 5085b9c547cSRui Paulo u8 nonces[2 * EAP_EKE_MAX_NONCE_LEN]; 5095b9c547cSRui Paulo u8 auth_s[EAP_EKE_MAX_HASH_LEN]; 5105b9c547cSRui Paulo size_t decrypt_len; 5115b9c547cSRui Paulo u8 *auth; 512325151a3SRui Paulo u8 id = eap_get_id(reqData); 5135b9c547cSRui Paulo 5145b9c547cSRui Paulo if (data->state != CONFIRM) { 5155b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Confirm/Request received in unexpected state (%d)", 5165b9c547cSRui Paulo data->state); 517325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 5185b9c547cSRui Paulo EAP_EKE_FAIL_PROTO_ERROR); 5195b9c547cSRui Paulo } 5205b9c547cSRui Paulo 5215b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Confirm/Request"); 5225b9c547cSRui Paulo 5235b9c547cSRui Paulo pos = payload; 5245b9c547cSRui Paulo end = payload + payload_len; 5255b9c547cSRui Paulo 5265b9c547cSRui Paulo if (pos + data->sess.pnonce_ps_len + data->sess.prf_len > end) { 5275b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Confirm"); 528325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 5295b9c547cSRui Paulo EAP_EKE_FAIL_PROTO_ERROR); 5305b9c547cSRui Paulo } 5315b9c547cSRui Paulo 5325b9c547cSRui Paulo decrypt_len = sizeof(nonces); 5335b9c547cSRui Paulo if (eap_eke_decrypt_prot(&data->sess, pos, data->sess.pnonce_ps_len, 5345b9c547cSRui Paulo nonces, &decrypt_len) < 0) { 5355b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_PS"); 536325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 5375b9c547cSRui Paulo EAP_EKE_FAIL_AUTHENTICATION_FAIL); 5385b9c547cSRui Paulo } 5395b9c547cSRui Paulo if (decrypt_len != (size_t) 2 * data->sess.nonce_len) { 5405b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: PNonce_PS protected data length does not match length of Nonce_P and Nonce_S"); 541325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 5425b9c547cSRui Paulo EAP_EKE_FAIL_AUTHENTICATION_FAIL); 5435b9c547cSRui Paulo } 5445b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_P | Nonce_S", 5455b9c547cSRui Paulo nonces, 2 * data->sess.nonce_len); 5465b9c547cSRui Paulo if (os_memcmp(data->nonce_p, nonces, data->sess.nonce_len) != 0) { 5475b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_P does not match transmitted Nonce_P"); 548325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 5495b9c547cSRui Paulo EAP_EKE_FAIL_AUTHENTICATION_FAIL); 5505b9c547cSRui Paulo } 5515b9c547cSRui Paulo 5525b9c547cSRui Paulo os_memcpy(data->nonce_s, nonces + data->sess.nonce_len, 5535b9c547cSRui Paulo data->sess.nonce_len); 5545b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_S", 5555b9c547cSRui Paulo data->nonce_s, data->sess.nonce_len); 5565b9c547cSRui Paulo 5575b9c547cSRui Paulo if (eap_eke_derive_ka(&data->sess, data->serverid, data->serverid_len, 5585b9c547cSRui Paulo data->peerid, data->peerid_len, 5595b9c547cSRui Paulo data->nonce_p, data->nonce_s) < 0) { 560325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 5615b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 5625b9c547cSRui Paulo } 5635b9c547cSRui Paulo 5645b9c547cSRui Paulo if (eap_eke_auth(&data->sess, "EAP-EKE server", data->msgs, auth_s) < 0) 5655b9c547cSRui Paulo { 566325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 5675b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 5685b9c547cSRui Paulo } 5695b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_S", auth_s, data->sess.prf_len); 5705b9c547cSRui Paulo if (os_memcmp_const(auth_s, pos + data->sess.pnonce_ps_len, 5715b9c547cSRui Paulo data->sess.prf_len) != 0) { 5725b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Auth_S does not match"); 573325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 5745b9c547cSRui Paulo EAP_EKE_FAIL_AUTHENTICATION_FAIL); 5755b9c547cSRui Paulo } 5765b9c547cSRui Paulo 5775b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Confirm/Response"); 5785b9c547cSRui Paulo 579325151a3SRui Paulo resp = eap_eke_build_msg(data, id, 5805b9c547cSRui Paulo data->sess.pnonce_len + data->sess.prf_len, 5815b9c547cSRui Paulo EAP_EKE_CONFIRM); 5825b9c547cSRui Paulo if (resp == NULL) { 583325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 5845b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 5855b9c547cSRui Paulo } 5865b9c547cSRui Paulo 5875b9c547cSRui Paulo prot_len = wpabuf_tailroom(resp); 5885b9c547cSRui Paulo if (eap_eke_prot(&data->sess, data->nonce_s, data->sess.nonce_len, 5895b9c547cSRui Paulo wpabuf_put(resp, 0), &prot_len) < 0) { 5905b9c547cSRui Paulo wpabuf_free(resp); 591325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 5925b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 5935b9c547cSRui Paulo } 5945b9c547cSRui Paulo wpabuf_put(resp, prot_len); 5955b9c547cSRui Paulo 5965b9c547cSRui Paulo auth = wpabuf_put(resp, data->sess.prf_len); 5975b9c547cSRui Paulo if (eap_eke_auth(&data->sess, "EAP-EKE peer", data->msgs, auth) < 0) { 5985b9c547cSRui Paulo wpabuf_free(resp); 599325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 6005b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 6015b9c547cSRui Paulo } 6025b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth, data->sess.prf_len); 6035b9c547cSRui Paulo 6045b9c547cSRui Paulo if (eap_eke_derive_msk(&data->sess, data->serverid, data->serverid_len, 6055b9c547cSRui Paulo data->peerid, data->peerid_len, 6065b9c547cSRui Paulo data->nonce_s, data->nonce_p, 6075b9c547cSRui Paulo data->msk, data->emsk) < 0) { 6085b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive MSK/EMSK"); 6095b9c547cSRui Paulo wpabuf_free(resp); 610325151a3SRui Paulo return eap_eke_build_fail(data, ret, id, 6115b9c547cSRui Paulo EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 6125b9c547cSRui Paulo } 6135b9c547cSRui Paulo 6145b9c547cSRui Paulo os_memset(data->dh_priv, 0, sizeof(data->dh_priv)); 6155b9c547cSRui Paulo eap_eke_session_clean(&data->sess); 6165b9c547cSRui Paulo 6175b9c547cSRui Paulo eap_eke_state(data, SUCCESS); 6185b9c547cSRui Paulo ret->methodState = METHOD_MAY_CONT; 6195b9c547cSRui Paulo ret->decision = DECISION_COND_SUCC; 6205b9c547cSRui Paulo ret->allowNotifications = FALSE; 6215b9c547cSRui Paulo 6225b9c547cSRui Paulo return resp; 6235b9c547cSRui Paulo } 6245b9c547cSRui Paulo 6255b9c547cSRui Paulo 6265b9c547cSRui Paulo static struct wpabuf * eap_eke_process_failure(struct eap_eke_data *data, 6275b9c547cSRui Paulo struct eap_method_ret *ret, 6285b9c547cSRui Paulo const struct wpabuf *reqData, 6295b9c547cSRui Paulo const u8 *payload, 6305b9c547cSRui Paulo size_t payload_len) 6315b9c547cSRui Paulo { 6325b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Failure/Request"); 6335b9c547cSRui Paulo 6345b9c547cSRui Paulo if (payload_len < 4) { 6355b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Failure"); 6365b9c547cSRui Paulo } else { 6375b9c547cSRui Paulo u32 code; 6385b9c547cSRui Paulo code = WPA_GET_BE32(payload); 6395b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Failure-Code 0x%x", code); 6405b9c547cSRui Paulo } 6415b9c547cSRui Paulo 642325151a3SRui Paulo return eap_eke_build_fail(data, ret, eap_get_id(reqData), 643325151a3SRui Paulo EAP_EKE_FAIL_NO_ERROR); 6445b9c547cSRui Paulo } 6455b9c547cSRui Paulo 6465b9c547cSRui Paulo 6475b9c547cSRui Paulo static struct wpabuf * eap_eke_process(struct eap_sm *sm, void *priv, 6485b9c547cSRui Paulo struct eap_method_ret *ret, 6495b9c547cSRui Paulo const struct wpabuf *reqData) 6505b9c547cSRui Paulo { 6515b9c547cSRui Paulo struct eap_eke_data *data = priv; 6525b9c547cSRui Paulo struct wpabuf *resp; 6535b9c547cSRui Paulo const u8 *pos, *end; 6545b9c547cSRui Paulo size_t len; 6555b9c547cSRui Paulo u8 eke_exch; 6565b9c547cSRui Paulo 6575b9c547cSRui Paulo pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, reqData, &len); 6585b9c547cSRui Paulo if (pos == NULL || len < 1) { 6595b9c547cSRui Paulo ret->ignore = TRUE; 6605b9c547cSRui Paulo return NULL; 6615b9c547cSRui Paulo } 6625b9c547cSRui Paulo 6635b9c547cSRui Paulo end = pos + len; 6645b9c547cSRui Paulo eke_exch = *pos++; 6655b9c547cSRui Paulo 6665b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: exch %d", eke_exch); 6675b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received Data", pos, end - pos); 6685b9c547cSRui Paulo 6695b9c547cSRui Paulo ret->ignore = FALSE; 6705b9c547cSRui Paulo ret->methodState = METHOD_MAY_CONT; 6715b9c547cSRui Paulo ret->decision = DECISION_FAIL; 6725b9c547cSRui Paulo ret->allowNotifications = TRUE; 6735b9c547cSRui Paulo 6745b9c547cSRui Paulo switch (eke_exch) { 6755b9c547cSRui Paulo case EAP_EKE_ID: 6765b9c547cSRui Paulo resp = eap_eke_process_id(data, ret, reqData, pos, end - pos); 6775b9c547cSRui Paulo break; 6785b9c547cSRui Paulo case EAP_EKE_COMMIT: 6795b9c547cSRui Paulo resp = eap_eke_process_commit(sm, data, ret, reqData, 6805b9c547cSRui Paulo pos, end - pos); 6815b9c547cSRui Paulo break; 6825b9c547cSRui Paulo case EAP_EKE_CONFIRM: 6835b9c547cSRui Paulo resp = eap_eke_process_confirm(data, ret, reqData, 6845b9c547cSRui Paulo pos, end - pos); 6855b9c547cSRui Paulo break; 6865b9c547cSRui Paulo case EAP_EKE_FAILURE: 6875b9c547cSRui Paulo resp = eap_eke_process_failure(data, ret, reqData, 6885b9c547cSRui Paulo pos, end - pos); 6895b9c547cSRui Paulo break; 6905b9c547cSRui Paulo default: 6915b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Ignoring message with unknown EKE-Exch %d", eke_exch); 6925b9c547cSRui Paulo ret->ignore = TRUE; 6935b9c547cSRui Paulo return NULL; 6945b9c547cSRui Paulo } 6955b9c547cSRui Paulo 6965b9c547cSRui Paulo if (ret->methodState == METHOD_DONE) 6975b9c547cSRui Paulo ret->allowNotifications = FALSE; 6985b9c547cSRui Paulo 6995b9c547cSRui Paulo return resp; 7005b9c547cSRui Paulo } 7015b9c547cSRui Paulo 7025b9c547cSRui Paulo 7035b9c547cSRui Paulo static Boolean eap_eke_isKeyAvailable(struct eap_sm *sm, void *priv) 7045b9c547cSRui Paulo { 7055b9c547cSRui Paulo struct eap_eke_data *data = priv; 7065b9c547cSRui Paulo return data->state == SUCCESS; 7075b9c547cSRui Paulo } 7085b9c547cSRui Paulo 7095b9c547cSRui Paulo 7105b9c547cSRui Paulo static u8 * eap_eke_getKey(struct eap_sm *sm, void *priv, size_t *len) 7115b9c547cSRui Paulo { 7125b9c547cSRui Paulo struct eap_eke_data *data = priv; 7135b9c547cSRui Paulo u8 *key; 7145b9c547cSRui Paulo 7155b9c547cSRui Paulo if (data->state != SUCCESS) 7165b9c547cSRui Paulo return NULL; 7175b9c547cSRui Paulo 718*85732ac8SCy Schubert key = os_memdup(data->msk, EAP_MSK_LEN); 7195b9c547cSRui Paulo if (key == NULL) 7205b9c547cSRui Paulo return NULL; 7215b9c547cSRui Paulo *len = EAP_MSK_LEN; 7225b9c547cSRui Paulo 7235b9c547cSRui Paulo return key; 7245b9c547cSRui Paulo } 7255b9c547cSRui Paulo 7265b9c547cSRui Paulo 7275b9c547cSRui Paulo static u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 7285b9c547cSRui Paulo { 7295b9c547cSRui Paulo struct eap_eke_data *data = priv; 7305b9c547cSRui Paulo u8 *key; 7315b9c547cSRui Paulo 7325b9c547cSRui Paulo if (data->state != SUCCESS) 7335b9c547cSRui Paulo return NULL; 7345b9c547cSRui Paulo 735*85732ac8SCy Schubert key = os_memdup(data->emsk, EAP_EMSK_LEN); 7365b9c547cSRui Paulo if (key == NULL) 7375b9c547cSRui Paulo return NULL; 7385b9c547cSRui Paulo *len = EAP_EMSK_LEN; 7395b9c547cSRui Paulo 7405b9c547cSRui Paulo return key; 7415b9c547cSRui Paulo } 7425b9c547cSRui Paulo 7435b9c547cSRui Paulo 744325151a3SRui Paulo static u8 * eap_eke_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 745325151a3SRui Paulo { 746325151a3SRui Paulo struct eap_eke_data *data = priv; 747325151a3SRui Paulo u8 *sid; 748325151a3SRui Paulo size_t sid_len; 749325151a3SRui Paulo 750325151a3SRui Paulo if (data->state != SUCCESS) 751325151a3SRui Paulo return NULL; 752325151a3SRui Paulo 753325151a3SRui Paulo sid_len = 1 + 2 * data->sess.nonce_len; 754325151a3SRui Paulo sid = os_malloc(sid_len); 755325151a3SRui Paulo if (sid == NULL) 756325151a3SRui Paulo return NULL; 757325151a3SRui Paulo sid[0] = EAP_TYPE_EKE; 758325151a3SRui Paulo os_memcpy(sid + 1, data->nonce_p, data->sess.nonce_len); 759325151a3SRui Paulo os_memcpy(sid + 1 + data->sess.nonce_len, data->nonce_s, 760325151a3SRui Paulo data->sess.nonce_len); 761325151a3SRui Paulo *len = sid_len; 762325151a3SRui Paulo 763325151a3SRui Paulo return sid; 764325151a3SRui Paulo } 765325151a3SRui Paulo 766325151a3SRui Paulo 7675b9c547cSRui Paulo int eap_peer_eke_register(void) 7685b9c547cSRui Paulo { 7695b9c547cSRui Paulo struct eap_method *eap; 7705b9c547cSRui Paulo 7715b9c547cSRui Paulo eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 7725b9c547cSRui Paulo EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE"); 7735b9c547cSRui Paulo if (eap == NULL) 7745b9c547cSRui Paulo return -1; 7755b9c547cSRui Paulo 7765b9c547cSRui Paulo eap->init = eap_eke_init; 7775b9c547cSRui Paulo eap->deinit = eap_eke_deinit; 7785b9c547cSRui Paulo eap->process = eap_eke_process; 7795b9c547cSRui Paulo eap->isKeyAvailable = eap_eke_isKeyAvailable; 7805b9c547cSRui Paulo eap->getKey = eap_eke_getKey; 7815b9c547cSRui Paulo eap->get_emsk = eap_eke_get_emsk; 782325151a3SRui Paulo eap->getSessionId = eap_eke_get_session_id; 7835b9c547cSRui Paulo 784780fb4a2SCy Schubert return eap_peer_method_register(eap); 7855b9c547cSRui Paulo } 786