15b9c547cSRui Paulo /* 25b9c547cSRui Paulo * hostapd / EAP-EKE (RFC 6124) server 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_server/eap_i.h" 145b9c547cSRui Paulo #include "eap_common/eap_eke_common.h" 155b9c547cSRui Paulo 165b9c547cSRui Paulo 175b9c547cSRui Paulo struct eap_eke_data { 185b9c547cSRui Paulo enum { 195b9c547cSRui Paulo IDENTITY, COMMIT, CONFIRM, FAILURE_REPORT, SUCCESS, FAILURE 205b9c547cSRui Paulo } state; 215b9c547cSRui Paulo u8 msk[EAP_MSK_LEN]; 225b9c547cSRui Paulo u8 emsk[EAP_EMSK_LEN]; 235b9c547cSRui Paulo u8 *peerid; 245b9c547cSRui Paulo size_t peerid_len; 255b9c547cSRui Paulo u8 peerid_type; 265b9c547cSRui Paulo u8 serverid_type; 275b9c547cSRui Paulo u8 dh_priv[EAP_EKE_MAX_DH_LEN]; 285b9c547cSRui Paulo u8 key[EAP_EKE_MAX_KEY_LEN]; 295b9c547cSRui Paulo struct eap_eke_session sess; 305b9c547cSRui Paulo u8 nonce_p[EAP_EKE_MAX_NONCE_LEN]; 315b9c547cSRui Paulo u8 nonce_s[EAP_EKE_MAX_NONCE_LEN]; 325b9c547cSRui Paulo struct wpabuf *msgs; 335b9c547cSRui Paulo int phase2; 345b9c547cSRui Paulo u32 failure_code; 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 FAILURE_REPORT: 485b9c547cSRui Paulo return "FAILURE_REPORT"; 495b9c547cSRui Paulo case SUCCESS: 505b9c547cSRui Paulo return "SUCCESS"; 515b9c547cSRui Paulo case FAILURE: 525b9c547cSRui Paulo return "FAILURE"; 535b9c547cSRui Paulo default: 545b9c547cSRui Paulo return "?"; 555b9c547cSRui Paulo } 565b9c547cSRui Paulo } 575b9c547cSRui Paulo 585b9c547cSRui Paulo 595b9c547cSRui Paulo static void eap_eke_state(struct eap_eke_data *data, int state) 605b9c547cSRui Paulo { 615b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: %s -> %s", 625b9c547cSRui Paulo eap_eke_state_txt(data->state), 635b9c547cSRui Paulo eap_eke_state_txt(state)); 645b9c547cSRui Paulo data->state = state; 655b9c547cSRui Paulo } 665b9c547cSRui Paulo 675b9c547cSRui Paulo 685b9c547cSRui Paulo static void eap_eke_fail(struct eap_eke_data *data, u32 code) 695b9c547cSRui Paulo { 705b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Failure - code 0x%x", code); 715b9c547cSRui Paulo data->failure_code = code; 725b9c547cSRui Paulo eap_eke_state(data, FAILURE_REPORT); 735b9c547cSRui Paulo } 745b9c547cSRui Paulo 755b9c547cSRui Paulo 765b9c547cSRui Paulo static void * eap_eke_init(struct eap_sm *sm) 775b9c547cSRui Paulo { 785b9c547cSRui Paulo struct eap_eke_data *data; 795b9c547cSRui Paulo size_t i; 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 data->serverid_type = EAP_EKE_ID_OPAQUE; 87c1d255d3SCy Schubert for (i = 0; i < sm->cfg->server_id_len; i++) { 88c1d255d3SCy Schubert if (sm->cfg->server_id[i] == '.' && 895b9c547cSRui Paulo data->serverid_type == EAP_EKE_ID_OPAQUE) 905b9c547cSRui Paulo data->serverid_type = EAP_EKE_ID_FQDN; 91c1d255d3SCy Schubert if (sm->cfg->server_id[i] == '@') 925b9c547cSRui Paulo data->serverid_type = EAP_EKE_ID_NAI; 935b9c547cSRui Paulo } 945b9c547cSRui Paulo 955b9c547cSRui Paulo data->phase2 = sm->init_phase2; 965b9c547cSRui Paulo 975b9c547cSRui Paulo return data; 985b9c547cSRui Paulo } 995b9c547cSRui Paulo 1005b9c547cSRui Paulo 1015b9c547cSRui Paulo static void eap_eke_reset(struct eap_sm *sm, void *priv) 1025b9c547cSRui Paulo { 1035b9c547cSRui Paulo struct eap_eke_data *data = priv; 1045b9c547cSRui Paulo eap_eke_session_clean(&data->sess); 1055b9c547cSRui Paulo os_free(data->peerid); 1065b9c547cSRui Paulo wpabuf_free(data->msgs); 1075b9c547cSRui Paulo bin_clear_free(data, sizeof(*data)); 1085b9c547cSRui Paulo } 1095b9c547cSRui Paulo 1105b9c547cSRui Paulo 1115b9c547cSRui Paulo static struct wpabuf * eap_eke_build_msg(struct eap_eke_data *data, 1125b9c547cSRui Paulo u8 id, size_t length, u8 eke_exch) 1135b9c547cSRui Paulo { 1145b9c547cSRui Paulo struct wpabuf *msg; 1155b9c547cSRui Paulo size_t plen; 1165b9c547cSRui Paulo 1175b9c547cSRui Paulo plen = 1 + length; 1185b9c547cSRui Paulo 1195b9c547cSRui Paulo msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EKE, plen, 1205b9c547cSRui Paulo EAP_CODE_REQUEST, id); 1215b9c547cSRui Paulo if (msg == NULL) { 1225b9c547cSRui Paulo wpa_printf(MSG_ERROR, "EAP-EKE: Failed to allocate memory"); 1235b9c547cSRui Paulo return NULL; 1245b9c547cSRui Paulo } 1255b9c547cSRui Paulo 1265b9c547cSRui Paulo wpabuf_put_u8(msg, eke_exch); 1275b9c547cSRui Paulo 1285b9c547cSRui Paulo return msg; 1295b9c547cSRui Paulo } 1305b9c547cSRui Paulo 1315b9c547cSRui Paulo 1325b9c547cSRui Paulo static int supported_proposal(const u8 *pos) 1335b9c547cSRui Paulo { 1345b9c547cSRui Paulo if (pos[0] == EAP_EKE_DHGROUP_EKE_16 && 1355b9c547cSRui Paulo pos[1] == EAP_EKE_ENCR_AES128_CBC && 1365b9c547cSRui Paulo pos[2] == EAP_EKE_PRF_HMAC_SHA2_256 && 1375b9c547cSRui Paulo pos[3] == EAP_EKE_MAC_HMAC_SHA2_256) 1385b9c547cSRui Paulo return 1; 1395b9c547cSRui Paulo 1405b9c547cSRui Paulo if (pos[0] == EAP_EKE_DHGROUP_EKE_15 && 1415b9c547cSRui Paulo pos[1] == EAP_EKE_ENCR_AES128_CBC && 1425b9c547cSRui Paulo pos[2] == EAP_EKE_PRF_HMAC_SHA2_256 && 1435b9c547cSRui Paulo pos[3] == EAP_EKE_MAC_HMAC_SHA2_256) 1445b9c547cSRui Paulo return 1; 1455b9c547cSRui Paulo 1465b9c547cSRui Paulo if (pos[0] == EAP_EKE_DHGROUP_EKE_14 && 1475b9c547cSRui Paulo pos[1] == EAP_EKE_ENCR_AES128_CBC && 1485b9c547cSRui Paulo pos[2] == EAP_EKE_PRF_HMAC_SHA2_256 && 1495b9c547cSRui Paulo pos[3] == EAP_EKE_MAC_HMAC_SHA2_256) 1505b9c547cSRui Paulo return 1; 1515b9c547cSRui Paulo 1525b9c547cSRui Paulo if (pos[0] == EAP_EKE_DHGROUP_EKE_14 && 1535b9c547cSRui Paulo pos[1] == EAP_EKE_ENCR_AES128_CBC && 1545b9c547cSRui Paulo pos[2] == EAP_EKE_PRF_HMAC_SHA1 && 1555b9c547cSRui Paulo pos[3] == EAP_EKE_MAC_HMAC_SHA1) 1565b9c547cSRui Paulo return 1; 1575b9c547cSRui Paulo 1585b9c547cSRui Paulo return 0; 1595b9c547cSRui Paulo } 1605b9c547cSRui Paulo 1615b9c547cSRui Paulo 1625b9c547cSRui Paulo static struct wpabuf * eap_eke_build_failure(struct eap_eke_data *data, u8 id) 1635b9c547cSRui Paulo { 1645b9c547cSRui Paulo struct wpabuf *msg; 1655b9c547cSRui Paulo 1665b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Failure: Failure-Code=0x%x", 1675b9c547cSRui Paulo data->failure_code); 1685b9c547cSRui Paulo 1695b9c547cSRui Paulo msg = eap_eke_build_msg(data, id, 4, EAP_EKE_FAILURE); 1705b9c547cSRui Paulo if (msg == NULL) { 1715b9c547cSRui Paulo eap_eke_state(data, FAILURE); 1725b9c547cSRui Paulo return NULL; 1735b9c547cSRui Paulo } 1745b9c547cSRui Paulo wpabuf_put_be32(msg, data->failure_code); 1755b9c547cSRui Paulo 1765b9c547cSRui Paulo return msg; 1775b9c547cSRui Paulo } 1785b9c547cSRui Paulo 1795b9c547cSRui Paulo 1805b9c547cSRui Paulo static struct wpabuf * eap_eke_build_identity(struct eap_sm *sm, 1815b9c547cSRui Paulo struct eap_eke_data *data, 1825b9c547cSRui Paulo u8 id) 1835b9c547cSRui Paulo { 1845b9c547cSRui Paulo struct wpabuf *msg; 1855b9c547cSRui Paulo size_t plen; 1865b9c547cSRui Paulo 1875b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Identity"); 1885b9c547cSRui Paulo 189c1d255d3SCy Schubert plen = 2 + 4 * 4 + 1 + sm->cfg->server_id_len; 1905b9c547cSRui Paulo msg = eap_eke_build_msg(data, id, plen, EAP_EKE_ID); 1915b9c547cSRui Paulo if (msg == NULL) 1925b9c547cSRui Paulo return NULL; 1935b9c547cSRui Paulo 1945b9c547cSRui Paulo wpabuf_put_u8(msg, 4); /* NumProposals */ 1955b9c547cSRui Paulo wpabuf_put_u8(msg, 0); /* Reserved */ 1965b9c547cSRui Paulo 1975b9c547cSRui Paulo /* Proposal - DH Group 16 with AES128-CBC and SHA256 */ 1985b9c547cSRui Paulo wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_16); /* Group Description */ 1995b9c547cSRui Paulo wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */ 2005b9c547cSRui Paulo wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */ 2015b9c547cSRui Paulo wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA2_256); /* MAC */ 2025b9c547cSRui Paulo 2035b9c547cSRui Paulo /* Proposal - DH Group 15 with AES128-CBC and SHA256 */ 2045b9c547cSRui Paulo wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_15); /* Group Description */ 2055b9c547cSRui Paulo wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */ 2065b9c547cSRui Paulo wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */ 2075b9c547cSRui Paulo wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA2_256); /* MAC */ 2085b9c547cSRui Paulo 2095b9c547cSRui Paulo /* Proposal - DH Group 14 with AES128-CBC and SHA256 */ 2105b9c547cSRui Paulo wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_14); /* Group Description */ 2115b9c547cSRui Paulo wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */ 2125b9c547cSRui Paulo wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA2_256); /* PRF */ 2135b9c547cSRui Paulo wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA2_256); /* MAC */ 2145b9c547cSRui Paulo 2155b9c547cSRui Paulo /* 2165b9c547cSRui Paulo * Proposal - DH Group 14 with AES128-CBC and SHA1 2175b9c547cSRui Paulo * (mandatory to implement algorithms) 2185b9c547cSRui Paulo */ 2195b9c547cSRui Paulo wpabuf_put_u8(msg, EAP_EKE_DHGROUP_EKE_14); /* Group Description */ 2205b9c547cSRui Paulo wpabuf_put_u8(msg, EAP_EKE_ENCR_AES128_CBC); /* Encryption */ 2215b9c547cSRui Paulo wpabuf_put_u8(msg, EAP_EKE_PRF_HMAC_SHA1); /* PRF */ 2225b9c547cSRui Paulo wpabuf_put_u8(msg, EAP_EKE_MAC_HMAC_SHA1); /* MAC */ 2235b9c547cSRui Paulo 2245b9c547cSRui Paulo /* Server IDType + Identity */ 2255b9c547cSRui Paulo wpabuf_put_u8(msg, data->serverid_type); 226c1d255d3SCy Schubert wpabuf_put_data(msg, sm->cfg->server_id, sm->cfg->server_id_len); 2275b9c547cSRui Paulo 2285b9c547cSRui Paulo wpabuf_free(data->msgs); 2295b9c547cSRui Paulo data->msgs = wpabuf_dup(msg); 2305b9c547cSRui Paulo if (data->msgs == NULL) { 2315b9c547cSRui Paulo wpabuf_free(msg); 2325b9c547cSRui Paulo return NULL; 2335b9c547cSRui Paulo } 2345b9c547cSRui Paulo 2355b9c547cSRui Paulo return msg; 2365b9c547cSRui Paulo } 2375b9c547cSRui Paulo 2385b9c547cSRui Paulo 2395b9c547cSRui Paulo static struct wpabuf * eap_eke_build_commit(struct eap_sm *sm, 2405b9c547cSRui Paulo struct eap_eke_data *data, u8 id) 2415b9c547cSRui Paulo { 2425b9c547cSRui Paulo struct wpabuf *msg; 2435b9c547cSRui Paulo u8 pub[EAP_EKE_MAX_DH_LEN]; 2445b9c547cSRui Paulo 2455b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Commit"); 2465b9c547cSRui Paulo 2475b9c547cSRui Paulo if (sm->user == NULL || sm->user->password == NULL) { 2485b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Password with not configured"); 2495b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND); 2505b9c547cSRui Paulo return eap_eke_build_failure(data, id); 2515b9c547cSRui Paulo } 2525b9c547cSRui Paulo 2535b9c547cSRui Paulo if (eap_eke_derive_key(&data->sess, sm->user->password, 2545b9c547cSRui Paulo sm->user->password_len, 255c1d255d3SCy Schubert sm->cfg->server_id, sm->cfg->server_id_len, 2565b9c547cSRui Paulo data->peerid, data->peerid_len, data->key) < 0) { 2575b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key"); 2585b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 2595b9c547cSRui Paulo return eap_eke_build_failure(data, id); 2605b9c547cSRui Paulo } 2615b9c547cSRui Paulo 2625b9c547cSRui Paulo msg = eap_eke_build_msg(data, id, data->sess.dhcomp_len, 2635b9c547cSRui Paulo EAP_EKE_COMMIT); 2645b9c547cSRui Paulo if (msg == NULL) { 2655b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 2665b9c547cSRui Paulo return eap_eke_build_failure(data, id); 2675b9c547cSRui Paulo } 2685b9c547cSRui Paulo 2695b9c547cSRui Paulo /* 2705b9c547cSRui Paulo * y_s = g ^ x_s (mod p) 2715b9c547cSRui Paulo * x_s = random number 2 .. p-1 2725b9c547cSRui Paulo * temp = prf(0+, password) 2735b9c547cSRui Paulo * key = prf+(temp, ID_S | ID_P) 2745b9c547cSRui Paulo * DHComponent_S = Encr(key, y_s) 2755b9c547cSRui Paulo */ 2765b9c547cSRui Paulo 2775b9c547cSRui Paulo if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) { 2785b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH"); 279*a90b9d01SCy Schubert wpabuf_free(msg); 2805b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 2815b9c547cSRui Paulo return eap_eke_build_failure(data, id); 2825b9c547cSRui Paulo } 2835b9c547cSRui Paulo 2845b9c547cSRui Paulo if (eap_eke_dhcomp(&data->sess, data->key, pub, 2855b9c547cSRui Paulo wpabuf_put(msg, data->sess.dhcomp_len)) 2865b9c547cSRui Paulo < 0) { 2875b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_S"); 2885b9c547cSRui Paulo wpabuf_free(msg); 2895b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 2905b9c547cSRui Paulo return eap_eke_build_failure(data, id); 2915b9c547cSRui Paulo } 2925b9c547cSRui Paulo 2935b9c547cSRui Paulo if (wpabuf_resize(&data->msgs, wpabuf_len(msg)) < 0) { 2945b9c547cSRui Paulo wpabuf_free(msg); 2955b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 2965b9c547cSRui Paulo return eap_eke_build_failure(data, id); 2975b9c547cSRui Paulo } 2985b9c547cSRui Paulo wpabuf_put_buf(data->msgs, msg); 2995b9c547cSRui Paulo 3005b9c547cSRui Paulo return msg; 3015b9c547cSRui Paulo } 3025b9c547cSRui Paulo 3035b9c547cSRui Paulo 3045b9c547cSRui Paulo static struct wpabuf * eap_eke_build_confirm(struct eap_sm *sm, 3055b9c547cSRui Paulo struct eap_eke_data *data, u8 id) 3065b9c547cSRui Paulo { 3075b9c547cSRui Paulo struct wpabuf *msg; 3085b9c547cSRui Paulo size_t plen, prot_len; 3095b9c547cSRui Paulo u8 nonces[2 * EAP_EKE_MAX_NONCE_LEN]; 3105b9c547cSRui Paulo u8 *auth; 3115b9c547cSRui Paulo 3125b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Confirm"); 3135b9c547cSRui Paulo 3145b9c547cSRui Paulo plen = data->sess.pnonce_ps_len + data->sess.prf_len; 3155b9c547cSRui Paulo msg = eap_eke_build_msg(data, id, plen, EAP_EKE_CONFIRM); 3165b9c547cSRui Paulo if (msg == NULL) { 3175b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 3185b9c547cSRui Paulo return eap_eke_build_failure(data, id); 3195b9c547cSRui Paulo } 3205b9c547cSRui Paulo 3215b9c547cSRui Paulo if (random_get_bytes(data->nonce_s, data->sess.nonce_len)) { 3225b9c547cSRui Paulo wpabuf_free(msg); 3235b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 3245b9c547cSRui Paulo return eap_eke_build_failure(data, id); 3255b9c547cSRui Paulo } 3265b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_S", 3275b9c547cSRui Paulo data->nonce_s, data->sess.nonce_len); 3285b9c547cSRui Paulo 3295b9c547cSRui Paulo os_memcpy(nonces, data->nonce_p, data->sess.nonce_len); 3305b9c547cSRui Paulo os_memcpy(nonces + data->sess.nonce_len, data->nonce_s, 3315b9c547cSRui Paulo data->sess.nonce_len); 3325b9c547cSRui Paulo prot_len = wpabuf_tailroom(msg); 3335b9c547cSRui Paulo if (eap_eke_prot(&data->sess, nonces, 2 * data->sess.nonce_len, 3345b9c547cSRui Paulo wpabuf_put(msg, 0), &prot_len) < 0) { 3355b9c547cSRui Paulo wpabuf_free(msg); 3365b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 3375b9c547cSRui Paulo return eap_eke_build_failure(data, id); 3385b9c547cSRui Paulo } 3395b9c547cSRui Paulo wpabuf_put(msg, prot_len); 3405b9c547cSRui Paulo 3415b9c547cSRui Paulo if (eap_eke_derive_ka(&data->sess, 342c1d255d3SCy Schubert sm->cfg->server_id, sm->cfg->server_id_len, 3435b9c547cSRui Paulo data->peerid, data->peerid_len, 3445b9c547cSRui Paulo data->nonce_p, data->nonce_s) < 0) { 3455b9c547cSRui Paulo wpabuf_free(msg); 3465b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 3475b9c547cSRui Paulo return eap_eke_build_failure(data, id); 3485b9c547cSRui Paulo } 3495b9c547cSRui Paulo 3505b9c547cSRui Paulo auth = wpabuf_put(msg, data->sess.prf_len); 3515b9c547cSRui Paulo if (eap_eke_auth(&data->sess, "EAP-EKE server", data->msgs, auth) < 0) { 3525b9c547cSRui Paulo wpabuf_free(msg); 3535b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 3545b9c547cSRui Paulo return eap_eke_build_failure(data, id); 3555b9c547cSRui Paulo } 3565b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_S", auth, data->sess.prf_len); 3575b9c547cSRui Paulo 3585b9c547cSRui Paulo return msg; 3595b9c547cSRui Paulo } 3605b9c547cSRui Paulo 3615b9c547cSRui Paulo 3625b9c547cSRui Paulo static struct wpabuf * eap_eke_buildReq(struct eap_sm *sm, void *priv, u8 id) 3635b9c547cSRui Paulo { 3645b9c547cSRui Paulo struct eap_eke_data *data = priv; 3655b9c547cSRui Paulo 3665b9c547cSRui Paulo switch (data->state) { 3675b9c547cSRui Paulo case IDENTITY: 3685b9c547cSRui Paulo return eap_eke_build_identity(sm, data, id); 3695b9c547cSRui Paulo case COMMIT: 3705b9c547cSRui Paulo return eap_eke_build_commit(sm, data, id); 3715b9c547cSRui Paulo case CONFIRM: 3725b9c547cSRui Paulo return eap_eke_build_confirm(sm, data, id); 3735b9c547cSRui Paulo case FAILURE_REPORT: 3745b9c547cSRui Paulo return eap_eke_build_failure(data, id); 3755b9c547cSRui Paulo default: 3765b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Unknown state %d in buildReq", 3775b9c547cSRui Paulo data->state); 3785b9c547cSRui Paulo break; 3795b9c547cSRui Paulo } 3805b9c547cSRui Paulo return NULL; 3815b9c547cSRui Paulo } 3825b9c547cSRui Paulo 3835b9c547cSRui Paulo 384c1d255d3SCy Schubert static bool eap_eke_check(struct eap_sm *sm, void *priv, 3855b9c547cSRui Paulo struct wpabuf *respData) 3865b9c547cSRui Paulo { 3875b9c547cSRui Paulo struct eap_eke_data *data = priv; 3885b9c547cSRui Paulo size_t len; 3895b9c547cSRui Paulo const u8 *pos; 3905b9c547cSRui Paulo u8 eke_exch; 3915b9c547cSRui Paulo 3925b9c547cSRui Paulo pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, respData, &len); 3935b9c547cSRui Paulo if (pos == NULL || len < 1) { 3945b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Invalid frame"); 395c1d255d3SCy Schubert return true; 3965b9c547cSRui Paulo } 3975b9c547cSRui Paulo 3985b9c547cSRui Paulo eke_exch = *pos; 3995b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Received frame: EKE-Exch=%d", eke_exch); 4005b9c547cSRui Paulo 4015b9c547cSRui Paulo if (data->state == IDENTITY && eke_exch == EAP_EKE_ID) 402c1d255d3SCy Schubert return false; 4035b9c547cSRui Paulo 4045b9c547cSRui Paulo if (data->state == COMMIT && eke_exch == EAP_EKE_COMMIT) 405c1d255d3SCy Schubert return false; 4065b9c547cSRui Paulo 4075b9c547cSRui Paulo if (data->state == CONFIRM && eke_exch == EAP_EKE_CONFIRM) 408c1d255d3SCy Schubert return false; 4095b9c547cSRui Paulo 4105b9c547cSRui Paulo if (eke_exch == EAP_EKE_FAILURE) 411c1d255d3SCy Schubert return false; 4125b9c547cSRui Paulo 4135b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Unexpected EKE-Exch=%d in state=%d", 4145b9c547cSRui Paulo eke_exch, data->state); 4155b9c547cSRui Paulo 416c1d255d3SCy Schubert return true; 4175b9c547cSRui Paulo } 4185b9c547cSRui Paulo 4195b9c547cSRui Paulo 4205b9c547cSRui Paulo static void eap_eke_process_identity(struct eap_sm *sm, 4215b9c547cSRui Paulo struct eap_eke_data *data, 4225b9c547cSRui Paulo const struct wpabuf *respData, 4235b9c547cSRui Paulo const u8 *payload, size_t payloadlen) 4245b9c547cSRui Paulo { 4255b9c547cSRui Paulo const u8 *pos, *end; 4265b9c547cSRui Paulo int i; 4275b9c547cSRui Paulo 4285b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Identity"); 4295b9c547cSRui Paulo 4305b9c547cSRui Paulo if (data->state != IDENTITY) { 4315b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR); 4325b9c547cSRui Paulo return; 4335b9c547cSRui Paulo } 4345b9c547cSRui Paulo 4355b9c547cSRui Paulo pos = payload; 4365b9c547cSRui Paulo end = payload + payloadlen; 4375b9c547cSRui Paulo 4385b9c547cSRui Paulo if (pos + 2 + 4 + 1 > end) { 4395b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Too short EAP-EKE-ID payload"); 4405b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR); 4415b9c547cSRui Paulo return; 4425b9c547cSRui Paulo } 4435b9c547cSRui Paulo 4445b9c547cSRui Paulo if (*pos != 1) { 4455b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Unexpected NumProposals %d (expected 1)", 4465b9c547cSRui Paulo *pos); 4475b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR); 4485b9c547cSRui Paulo return; 4495b9c547cSRui Paulo } 4505b9c547cSRui Paulo 4515b9c547cSRui Paulo pos += 2; 4525b9c547cSRui Paulo 4535b9c547cSRui Paulo if (!supported_proposal(pos)) { 4545b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Unexpected Proposal (%u:%u:%u:%u)", 4555b9c547cSRui Paulo pos[0], pos[1], pos[2], pos[3]); 4565b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR); 4575b9c547cSRui Paulo return; 4585b9c547cSRui Paulo } 4595b9c547cSRui Paulo 4605b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Selected Proposal (%u:%u:%u:%u)", 4615b9c547cSRui Paulo pos[0], pos[1], pos[2], pos[3]); 4625b9c547cSRui Paulo if (eap_eke_session_init(&data->sess, pos[0], pos[1], pos[2], pos[3]) < 4635b9c547cSRui Paulo 0) { 4645b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 4655b9c547cSRui Paulo return; 4665b9c547cSRui Paulo } 4675b9c547cSRui Paulo pos += 4; 4685b9c547cSRui Paulo 4695b9c547cSRui Paulo data->peerid_type = *pos++; 4705b9c547cSRui Paulo os_free(data->peerid); 47185732ac8SCy Schubert data->peerid = os_memdup(pos, end - pos); 4725b9c547cSRui Paulo if (data->peerid == NULL) { 4735b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Failed to allocate memory for peerid"); 4745b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 4755b9c547cSRui Paulo return; 4765b9c547cSRui Paulo } 4775b9c547cSRui Paulo data->peerid_len = end - pos; 4785b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Peer IDType %u", data->peerid_type); 4795b9c547cSRui Paulo wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Peer Identity", 4805b9c547cSRui Paulo data->peerid, data->peerid_len); 4815b9c547cSRui Paulo 4825b9c547cSRui Paulo if (eap_user_get(sm, data->peerid, data->peerid_len, data->phase2)) { 4835b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Peer Identity not found from user database"); 4845b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND); 4855b9c547cSRui Paulo return; 4865b9c547cSRui Paulo } 4875b9c547cSRui Paulo 4885b9c547cSRui Paulo for (i = 0; i < EAP_MAX_METHODS; i++) { 4895b9c547cSRui Paulo if (sm->user->methods[i].vendor == EAP_VENDOR_IETF && 4905b9c547cSRui Paulo sm->user->methods[i].method == EAP_TYPE_EKE) 4915b9c547cSRui Paulo break; 4925b9c547cSRui Paulo } 4935b9c547cSRui Paulo if (i == EAP_MAX_METHODS) { 4945b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Matching user entry does not allow EAP-EKE"); 4955b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND); 4965b9c547cSRui Paulo return; 4975b9c547cSRui Paulo } 4985b9c547cSRui Paulo 4995b9c547cSRui Paulo if (sm->user->password == NULL || sm->user->password_len == 0) { 5005b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: No password configured for peer"); 5015b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND); 5025b9c547cSRui Paulo return; 5035b9c547cSRui Paulo } 5045b9c547cSRui Paulo 5055b9c547cSRui Paulo if (wpabuf_resize(&data->msgs, wpabuf_len(respData)) < 0) { 5065b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 5075b9c547cSRui Paulo return; 5085b9c547cSRui Paulo } 5095b9c547cSRui Paulo wpabuf_put_buf(data->msgs, respData); 5105b9c547cSRui Paulo 5115b9c547cSRui Paulo eap_eke_state(data, COMMIT); 5125b9c547cSRui Paulo } 5135b9c547cSRui Paulo 5145b9c547cSRui Paulo 5155b9c547cSRui Paulo static void eap_eke_process_commit(struct eap_sm *sm, 5165b9c547cSRui Paulo struct eap_eke_data *data, 5175b9c547cSRui Paulo const struct wpabuf *respData, 5185b9c547cSRui Paulo const u8 *payload, size_t payloadlen) 5195b9c547cSRui Paulo { 5205b9c547cSRui Paulo const u8 *pos, *end, *dhcomp, *pnonce; 5215b9c547cSRui Paulo size_t decrypt_len; 5225b9c547cSRui Paulo 5235b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Commit"); 5245b9c547cSRui Paulo 5255b9c547cSRui Paulo if (data->state != COMMIT) { 5265b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR); 5275b9c547cSRui Paulo return; 5285b9c547cSRui Paulo } 5295b9c547cSRui Paulo 5305b9c547cSRui Paulo pos = payload; 5315b9c547cSRui Paulo end = payload + payloadlen; 5325b9c547cSRui Paulo 5335b9c547cSRui Paulo if (pos + data->sess.dhcomp_len + data->sess.pnonce_len > end) { 5345b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit"); 5355b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR); 5365b9c547cSRui Paulo return; 5375b9c547cSRui Paulo } 5385b9c547cSRui Paulo 5395b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P", 5405b9c547cSRui Paulo pos, data->sess.dhcomp_len); 5415b9c547cSRui Paulo dhcomp = pos; 5425b9c547cSRui Paulo pos += data->sess.dhcomp_len; 5435b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P", pos, data->sess.pnonce_len); 5445b9c547cSRui Paulo pnonce = pos; 5455b9c547cSRui Paulo pos += data->sess.pnonce_len; 5465b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos); 5475b9c547cSRui Paulo 5485b9c547cSRui Paulo if (eap_eke_shared_secret(&data->sess, data->key, data->dh_priv, dhcomp) 5495b9c547cSRui Paulo < 0) { 5505b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret"); 5515b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 5525b9c547cSRui Paulo return; 5535b9c547cSRui Paulo } 5545b9c547cSRui Paulo 5555b9c547cSRui Paulo if (eap_eke_derive_ke_ki(&data->sess, 556c1d255d3SCy Schubert sm->cfg->server_id, sm->cfg->server_id_len, 5575b9c547cSRui Paulo data->peerid, data->peerid_len) < 0) { 5585b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki"); 5595b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 5605b9c547cSRui Paulo return; 5615b9c547cSRui Paulo } 5625b9c547cSRui Paulo 5635b9c547cSRui Paulo decrypt_len = sizeof(data->nonce_p); 5645b9c547cSRui Paulo if (eap_eke_decrypt_prot(&data->sess, pnonce, data->sess.pnonce_len, 5655b9c547cSRui Paulo data->nonce_p, &decrypt_len) < 0) { 5665b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_P"); 5675b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL); 5685b9c547cSRui Paulo return; 5695b9c547cSRui Paulo } 5705b9c547cSRui Paulo if (decrypt_len < (size_t) data->sess.nonce_len) { 5715b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: PNonce_P protected data too short to include Nonce_P"); 5725b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL); 5735b9c547cSRui Paulo return; 5745b9c547cSRui Paulo } 5755b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P", 5765b9c547cSRui Paulo data->nonce_p, data->sess.nonce_len); 5775b9c547cSRui Paulo 5785b9c547cSRui Paulo if (wpabuf_resize(&data->msgs, wpabuf_len(respData)) < 0) { 5795b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 5805b9c547cSRui Paulo return; 5815b9c547cSRui Paulo } 5825b9c547cSRui Paulo wpabuf_put_buf(data->msgs, respData); 5835b9c547cSRui Paulo 5845b9c547cSRui Paulo eap_eke_state(data, CONFIRM); 5855b9c547cSRui Paulo } 5865b9c547cSRui Paulo 5875b9c547cSRui Paulo 5885b9c547cSRui Paulo static void eap_eke_process_confirm(struct eap_sm *sm, 5895b9c547cSRui Paulo struct eap_eke_data *data, 5905b9c547cSRui Paulo const struct wpabuf *respData, 5915b9c547cSRui Paulo const u8 *payload, size_t payloadlen) 5925b9c547cSRui Paulo { 5935b9c547cSRui Paulo size_t decrypt_len; 5945b9c547cSRui Paulo u8 nonce[EAP_EKE_MAX_NONCE_LEN]; 5955b9c547cSRui Paulo u8 auth_p[EAP_EKE_MAX_HASH_LEN]; 5965b9c547cSRui Paulo 5975b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Confirm"); 5985b9c547cSRui Paulo 5995b9c547cSRui Paulo if (data->state != CONFIRM) { 6005b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR); 6015b9c547cSRui Paulo return; 6025b9c547cSRui Paulo } 6035b9c547cSRui Paulo 6045b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Confirm"); 6055b9c547cSRui Paulo 6065b9c547cSRui Paulo if (payloadlen < (size_t) data->sess.pnonce_len + data->sess.prf_len) { 6075b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Confirm"); 6085b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR); 6095b9c547cSRui Paulo return; 6105b9c547cSRui Paulo } 6115b9c547cSRui Paulo 6125b9c547cSRui Paulo decrypt_len = sizeof(nonce); 6135b9c547cSRui Paulo if (eap_eke_decrypt_prot(&data->sess, payload, data->sess.pnonce_len, 6145b9c547cSRui Paulo nonce, &decrypt_len) < 0) { 6155b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_S"); 6165b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL); 6175b9c547cSRui Paulo return; 6185b9c547cSRui Paulo } 6195b9c547cSRui Paulo if (decrypt_len < (size_t) data->sess.nonce_len) { 6205b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: PNonce_S protected data too short to include Nonce_S"); 6215b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL); 6225b9c547cSRui Paulo return; 6235b9c547cSRui Paulo } 6245b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_S", 6255b9c547cSRui Paulo nonce, data->sess.nonce_len); 6265b9c547cSRui Paulo if (os_memcmp(nonce, data->nonce_s, data->sess.nonce_len) != 0) { 6275b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_S does not match previously sent Nonce_S"); 6285b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL); 6295b9c547cSRui Paulo return; 6305b9c547cSRui Paulo } 6315b9c547cSRui Paulo 6325b9c547cSRui Paulo if (eap_eke_auth(&data->sess, "EAP-EKE peer", data->msgs, auth_p) < 0) { 6335b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Could not derive Auth_P"); 6345b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 6355b9c547cSRui Paulo return; 6365b9c547cSRui Paulo } 6375b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth_p, data->sess.prf_len); 6385b9c547cSRui Paulo if (os_memcmp_const(auth_p, payload + data->sess.pnonce_len, 6395b9c547cSRui Paulo data->sess.prf_len) != 0) { 6405b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Auth_P does not match"); 6415b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL); 6425b9c547cSRui Paulo return; 6435b9c547cSRui Paulo } 6445b9c547cSRui Paulo 645c1d255d3SCy Schubert if (eap_eke_derive_msk(&data->sess, sm->cfg->server_id, 646c1d255d3SCy Schubert sm->cfg->server_id_len, 6475b9c547cSRui Paulo data->peerid, data->peerid_len, 6485b9c547cSRui Paulo data->nonce_s, data->nonce_p, 6495b9c547cSRui Paulo data->msk, data->emsk) < 0) { 6505b9c547cSRui Paulo wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive MSK/EMSK"); 6515b9c547cSRui Paulo eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); 6525b9c547cSRui Paulo return; 6535b9c547cSRui Paulo } 6545b9c547cSRui Paulo 6555b9c547cSRui Paulo os_memset(data->dh_priv, 0, sizeof(data->dh_priv)); 6565b9c547cSRui Paulo os_memset(data->key, 0, sizeof(data->key)); 6575b9c547cSRui Paulo eap_eke_session_clean(&data->sess); 6585b9c547cSRui Paulo 6595b9c547cSRui Paulo eap_eke_state(data, SUCCESS); 6605b9c547cSRui Paulo } 6615b9c547cSRui Paulo 6625b9c547cSRui Paulo 6635b9c547cSRui Paulo static void eap_eke_process_failure(struct eap_sm *sm, 6645b9c547cSRui Paulo struct eap_eke_data *data, 6655b9c547cSRui Paulo const struct wpabuf *respData, 6665b9c547cSRui Paulo const u8 *payload, size_t payloadlen) 6675b9c547cSRui Paulo { 6685b9c547cSRui Paulo u32 code; 6695b9c547cSRui Paulo 6705b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Failure"); 6715b9c547cSRui Paulo 6725b9c547cSRui Paulo if (payloadlen < 4) { 6735b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Failure"); 6745b9c547cSRui Paulo eap_eke_state(data, FAILURE); 6755b9c547cSRui Paulo return; 6765b9c547cSRui Paulo } 6775b9c547cSRui Paulo 6785b9c547cSRui Paulo code = WPA_GET_BE32(payload); 6795b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "EAP-EKE: Peer reported failure code 0x%x", code); 6805b9c547cSRui Paulo 6815b9c547cSRui Paulo eap_eke_state(data, FAILURE); 6825b9c547cSRui Paulo } 6835b9c547cSRui Paulo 6845b9c547cSRui Paulo 6855b9c547cSRui Paulo static void eap_eke_process(struct eap_sm *sm, void *priv, 6865b9c547cSRui Paulo struct wpabuf *respData) 6875b9c547cSRui Paulo { 6885b9c547cSRui Paulo struct eap_eke_data *data = priv; 6895b9c547cSRui Paulo u8 eke_exch; 6905b9c547cSRui Paulo size_t len; 6915b9c547cSRui Paulo const u8 *pos, *end; 6925b9c547cSRui Paulo 6935b9c547cSRui Paulo pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_EKE, respData, &len); 6945b9c547cSRui Paulo if (pos == NULL || len < 1) 6955b9c547cSRui Paulo return; 6965b9c547cSRui Paulo 6975b9c547cSRui Paulo eke_exch = *pos; 6985b9c547cSRui Paulo end = pos + len; 6995b9c547cSRui Paulo pos++; 7005b9c547cSRui Paulo 7015b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-EKE: Received payload", pos, end - pos); 7025b9c547cSRui Paulo 7035b9c547cSRui Paulo switch (eke_exch) { 7045b9c547cSRui Paulo case EAP_EKE_ID: 7055b9c547cSRui Paulo eap_eke_process_identity(sm, data, respData, pos, end - pos); 7065b9c547cSRui Paulo break; 7075b9c547cSRui Paulo case EAP_EKE_COMMIT: 7085b9c547cSRui Paulo eap_eke_process_commit(sm, data, respData, pos, end - pos); 7095b9c547cSRui Paulo break; 7105b9c547cSRui Paulo case EAP_EKE_CONFIRM: 7115b9c547cSRui Paulo eap_eke_process_confirm(sm, data, respData, pos, end - pos); 7125b9c547cSRui Paulo break; 7135b9c547cSRui Paulo case EAP_EKE_FAILURE: 7145b9c547cSRui Paulo eap_eke_process_failure(sm, data, respData, pos, end - pos); 7155b9c547cSRui Paulo break; 7165b9c547cSRui Paulo } 7175b9c547cSRui Paulo } 7185b9c547cSRui Paulo 7195b9c547cSRui Paulo 720c1d255d3SCy Schubert static bool eap_eke_isDone(struct eap_sm *sm, void *priv) 7215b9c547cSRui Paulo { 7225b9c547cSRui Paulo struct eap_eke_data *data = priv; 7235b9c547cSRui Paulo return data->state == SUCCESS || data->state == FAILURE; 7245b9c547cSRui Paulo } 7255b9c547cSRui Paulo 7265b9c547cSRui Paulo 7275b9c547cSRui Paulo static u8 * eap_eke_getKey(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 73585732ac8SCy Schubert key = os_memdup(data->msk, EAP_MSK_LEN); 7365b9c547cSRui Paulo if (key == NULL) 7375b9c547cSRui Paulo return NULL; 7385b9c547cSRui Paulo *len = EAP_MSK_LEN; 7395b9c547cSRui Paulo 7405b9c547cSRui Paulo return key; 7415b9c547cSRui Paulo } 7425b9c547cSRui Paulo 7435b9c547cSRui Paulo 7445b9c547cSRui Paulo static u8 * eap_eke_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 7455b9c547cSRui Paulo { 7465b9c547cSRui Paulo struct eap_eke_data *data = priv; 7475b9c547cSRui Paulo u8 *key; 7485b9c547cSRui Paulo 7495b9c547cSRui Paulo if (data->state != SUCCESS) 7505b9c547cSRui Paulo return NULL; 7515b9c547cSRui Paulo 75285732ac8SCy Schubert key = os_memdup(data->emsk, EAP_EMSK_LEN); 7535b9c547cSRui Paulo if (key == NULL) 7545b9c547cSRui Paulo return NULL; 7555b9c547cSRui Paulo *len = EAP_EMSK_LEN; 7565b9c547cSRui Paulo 7575b9c547cSRui Paulo return key; 7585b9c547cSRui Paulo } 7595b9c547cSRui Paulo 7605b9c547cSRui Paulo 761c1d255d3SCy Schubert static bool eap_eke_isSuccess(struct eap_sm *sm, void *priv) 7625b9c547cSRui Paulo { 7635b9c547cSRui Paulo struct eap_eke_data *data = priv; 7645b9c547cSRui Paulo return data->state == SUCCESS; 7655b9c547cSRui Paulo } 7665b9c547cSRui Paulo 7675b9c547cSRui Paulo 768325151a3SRui Paulo static u8 * eap_eke_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 769325151a3SRui Paulo { 770325151a3SRui Paulo struct eap_eke_data *data = priv; 771325151a3SRui Paulo u8 *sid; 772325151a3SRui Paulo size_t sid_len; 773325151a3SRui Paulo 774325151a3SRui Paulo if (data->state != SUCCESS) 775325151a3SRui Paulo return NULL; 776325151a3SRui Paulo 777325151a3SRui Paulo sid_len = 1 + 2 * data->sess.nonce_len; 778325151a3SRui Paulo sid = os_malloc(sid_len); 779325151a3SRui Paulo if (sid == NULL) 780325151a3SRui Paulo return NULL; 781325151a3SRui Paulo sid[0] = EAP_TYPE_EKE; 782325151a3SRui Paulo os_memcpy(sid + 1, data->nonce_p, data->sess.nonce_len); 783325151a3SRui Paulo os_memcpy(sid + 1 + data->sess.nonce_len, data->nonce_s, 784325151a3SRui Paulo data->sess.nonce_len); 785325151a3SRui Paulo *len = sid_len; 786325151a3SRui Paulo 787325151a3SRui Paulo return sid; 788325151a3SRui Paulo } 789325151a3SRui Paulo 790325151a3SRui Paulo 7915b9c547cSRui Paulo int eap_server_eke_register(void) 7925b9c547cSRui Paulo { 7935b9c547cSRui Paulo struct eap_method *eap; 7945b9c547cSRui Paulo 7955b9c547cSRui Paulo eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 7965b9c547cSRui Paulo EAP_VENDOR_IETF, EAP_TYPE_EKE, "EKE"); 7975b9c547cSRui Paulo if (eap == NULL) 7985b9c547cSRui Paulo return -1; 7995b9c547cSRui Paulo 8005b9c547cSRui Paulo eap->init = eap_eke_init; 8015b9c547cSRui Paulo eap->reset = eap_eke_reset; 8025b9c547cSRui Paulo eap->buildReq = eap_eke_buildReq; 8035b9c547cSRui Paulo eap->check = eap_eke_check; 8045b9c547cSRui Paulo eap->process = eap_eke_process; 8055b9c547cSRui Paulo eap->isDone = eap_eke_isDone; 8065b9c547cSRui Paulo eap->getKey = eap_eke_getKey; 8075b9c547cSRui Paulo eap->isSuccess = eap_eke_isSuccess; 8085b9c547cSRui Paulo eap->get_emsk = eap_eke_get_emsk; 809325151a3SRui Paulo eap->getSessionId = eap_eke_get_session_id; 8105b9c547cSRui Paulo 811780fb4a2SCy Schubert return eap_server_method_register(eap); 8125b9c547cSRui Paulo } 813