139beb93cSSam Leffler /* 239beb93cSSam Leffler * EAP peer method: EAP-PSK (RFC 4764) 339beb93cSSam Leffler * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 539beb93cSSam Leffler * This program is free software; you can redistribute it and/or modify 639beb93cSSam Leffler * it under the terms of the GNU General Public License version 2 as 739beb93cSSam Leffler * published by the Free Software Foundation. 839beb93cSSam Leffler * 939beb93cSSam Leffler * Alternatively, this software may be distributed under the terms of BSD 1039beb93cSSam Leffler * license. 1139beb93cSSam Leffler * 1239beb93cSSam Leffler * See README and COPYING for more details. 1339beb93cSSam Leffler * 1439beb93cSSam Leffler * Note: EAP-PSK is an EAP authentication method and as such, completely 1539beb93cSSam Leffler * different from WPA-PSK. This file is not needed for WPA-PSK functionality. 1639beb93cSSam Leffler */ 1739beb93cSSam Leffler 1839beb93cSSam Leffler #include "includes.h" 1939beb93cSSam Leffler 2039beb93cSSam Leffler #include "common.h" 2139beb93cSSam Leffler #include "eap_peer/eap_i.h" 2239beb93cSSam Leffler #include "aes_wrap.h" 2339beb93cSSam Leffler #include "eap_common/eap_psk_common.h" 2439beb93cSSam Leffler 2539beb93cSSam Leffler 2639beb93cSSam Leffler struct eap_psk_data { 2739beb93cSSam Leffler enum { PSK_INIT, PSK_MAC_SENT, PSK_DONE } state; 2839beb93cSSam Leffler u8 rand_p[EAP_PSK_RAND_LEN]; 2939beb93cSSam Leffler u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN]; 3039beb93cSSam Leffler u8 *id_s, *id_p; 3139beb93cSSam Leffler size_t id_s_len, id_p_len; 3239beb93cSSam Leffler u8 msk[EAP_MSK_LEN]; 3339beb93cSSam Leffler u8 emsk[EAP_EMSK_LEN]; 3439beb93cSSam Leffler }; 3539beb93cSSam Leffler 3639beb93cSSam Leffler 3739beb93cSSam Leffler static void * eap_psk_init(struct eap_sm *sm) 3839beb93cSSam Leffler { 3939beb93cSSam Leffler struct eap_psk_data *data; 4039beb93cSSam Leffler const u8 *identity, *password; 4139beb93cSSam Leffler size_t identity_len, password_len; 4239beb93cSSam Leffler 4339beb93cSSam Leffler password = eap_get_config_password(sm, &password_len); 4439beb93cSSam Leffler if (!password || password_len != 16) { 4539beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-PSK: 16-octet pre-shared key not " 4639beb93cSSam Leffler "configured"); 4739beb93cSSam Leffler return NULL; 4839beb93cSSam Leffler } 4939beb93cSSam Leffler 5039beb93cSSam Leffler data = os_zalloc(sizeof(*data)); 5139beb93cSSam Leffler if (data == NULL) 5239beb93cSSam Leffler return NULL; 5339beb93cSSam Leffler if (eap_psk_key_setup(password, data->ak, data->kdk)) { 5439beb93cSSam Leffler os_free(data); 5539beb93cSSam Leffler return NULL; 5639beb93cSSam Leffler } 5739beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, EAP_PSK_AK_LEN); 5839beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, EAP_PSK_KDK_LEN); 5939beb93cSSam Leffler data->state = PSK_INIT; 6039beb93cSSam Leffler 6139beb93cSSam Leffler identity = eap_get_config_identity(sm, &identity_len); 6239beb93cSSam Leffler if (identity) { 6339beb93cSSam Leffler data->id_p = os_malloc(identity_len); 6439beb93cSSam Leffler if (data->id_p) 6539beb93cSSam Leffler os_memcpy(data->id_p, identity, identity_len); 6639beb93cSSam Leffler data->id_p_len = identity_len; 6739beb93cSSam Leffler } 6839beb93cSSam Leffler if (data->id_p == NULL) { 6939beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-PSK: could not get own identity"); 7039beb93cSSam Leffler os_free(data); 7139beb93cSSam Leffler return NULL; 7239beb93cSSam Leffler } 7339beb93cSSam Leffler 7439beb93cSSam Leffler return data; 7539beb93cSSam Leffler } 7639beb93cSSam Leffler 7739beb93cSSam Leffler 7839beb93cSSam Leffler static void eap_psk_deinit(struct eap_sm *sm, void *priv) 7939beb93cSSam Leffler { 8039beb93cSSam Leffler struct eap_psk_data *data = priv; 8139beb93cSSam Leffler os_free(data->id_s); 8239beb93cSSam Leffler os_free(data->id_p); 8339beb93cSSam Leffler os_free(data); 8439beb93cSSam Leffler } 8539beb93cSSam Leffler 8639beb93cSSam Leffler 8739beb93cSSam Leffler static struct wpabuf * eap_psk_process_1(struct eap_psk_data *data, 8839beb93cSSam Leffler struct eap_method_ret *ret, 8939beb93cSSam Leffler const struct wpabuf *reqData) 9039beb93cSSam Leffler { 9139beb93cSSam Leffler const struct eap_psk_hdr_1 *hdr1; 9239beb93cSSam Leffler struct eap_psk_hdr_2 *hdr2; 9339beb93cSSam Leffler struct wpabuf *resp; 9439beb93cSSam Leffler u8 *buf, *pos; 9539beb93cSSam Leffler size_t buflen, len; 9639beb93cSSam Leffler const u8 *cpos; 9739beb93cSSam Leffler 9839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PSK: in INIT state"); 9939beb93cSSam Leffler 10039beb93cSSam Leffler cpos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len); 10139beb93cSSam Leffler hdr1 = (const struct eap_psk_hdr_1 *) cpos; 10239beb93cSSam Leffler if (cpos == NULL || len < sizeof(*hdr1)) { 10339beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-PSK: Invalid first message " 10439beb93cSSam Leffler "length (%lu; expected %lu or more)", 10539beb93cSSam Leffler (unsigned long) len, 10639beb93cSSam Leffler (unsigned long) sizeof(*hdr1)); 10739beb93cSSam Leffler ret->ignore = TRUE; 10839beb93cSSam Leffler return NULL; 10939beb93cSSam Leffler } 11039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr1->flags); 11139beb93cSSam Leffler if (EAP_PSK_FLAGS_GET_T(hdr1->flags) != 0) { 11239beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 0)", 11339beb93cSSam Leffler EAP_PSK_FLAGS_GET_T(hdr1->flags)); 11439beb93cSSam Leffler ret->methodState = METHOD_DONE; 11539beb93cSSam Leffler ret->decision = DECISION_FAIL; 11639beb93cSSam Leffler return NULL; 11739beb93cSSam Leffler } 11839beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr1->rand_s, 11939beb93cSSam Leffler EAP_PSK_RAND_LEN); 12039beb93cSSam Leffler os_free(data->id_s); 12139beb93cSSam Leffler data->id_s_len = len - sizeof(*hdr1); 12239beb93cSSam Leffler data->id_s = os_malloc(data->id_s_len); 12339beb93cSSam Leffler if (data->id_s == NULL) { 12439beb93cSSam Leffler wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory for " 12539beb93cSSam Leffler "ID_S (len=%lu)", (unsigned long) data->id_s_len); 12639beb93cSSam Leffler ret->ignore = TRUE; 12739beb93cSSam Leffler return NULL; 12839beb93cSSam Leffler } 12939beb93cSSam Leffler os_memcpy(data->id_s, (u8 *) (hdr1 + 1), data->id_s_len); 13039beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_S", 13139beb93cSSam Leffler data->id_s, data->id_s_len); 13239beb93cSSam Leffler 13339beb93cSSam Leffler if (os_get_random(data->rand_p, EAP_PSK_RAND_LEN)) { 13439beb93cSSam Leffler wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data"); 13539beb93cSSam Leffler ret->ignore = TRUE; 13639beb93cSSam Leffler return NULL; 13739beb93cSSam Leffler } 13839beb93cSSam Leffler 13939beb93cSSam Leffler resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, 14039beb93cSSam Leffler sizeof(*hdr2) + data->id_p_len, EAP_CODE_RESPONSE, 14139beb93cSSam Leffler eap_get_id(reqData)); 14239beb93cSSam Leffler if (resp == NULL) 14339beb93cSSam Leffler return NULL; 14439beb93cSSam Leffler hdr2 = wpabuf_put(resp, sizeof(*hdr2)); 14539beb93cSSam Leffler hdr2->flags = EAP_PSK_FLAGS_SET_T(1); /* T=1 */ 14639beb93cSSam Leffler os_memcpy(hdr2->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN); 14739beb93cSSam Leffler os_memcpy(hdr2->rand_p, data->rand_p, EAP_PSK_RAND_LEN); 14839beb93cSSam Leffler wpabuf_put_data(resp, data->id_p, data->id_p_len); 14939beb93cSSam Leffler /* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */ 15039beb93cSSam Leffler buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN; 15139beb93cSSam Leffler buf = os_malloc(buflen); 15239beb93cSSam Leffler if (buf == NULL) { 15339beb93cSSam Leffler wpabuf_free(resp); 15439beb93cSSam Leffler return NULL; 15539beb93cSSam Leffler } 15639beb93cSSam Leffler os_memcpy(buf, data->id_p, data->id_p_len); 15739beb93cSSam Leffler pos = buf + data->id_p_len; 15839beb93cSSam Leffler os_memcpy(pos, data->id_s, data->id_s_len); 15939beb93cSSam Leffler pos += data->id_s_len; 16039beb93cSSam Leffler os_memcpy(pos, hdr1->rand_s, EAP_PSK_RAND_LEN); 16139beb93cSSam Leffler pos += EAP_PSK_RAND_LEN; 16239beb93cSSam Leffler os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN); 16339beb93cSSam Leffler if (omac1_aes_128(data->ak, buf, buflen, hdr2->mac_p)) { 16439beb93cSSam Leffler os_free(buf); 16539beb93cSSam Leffler wpabuf_free(resp); 16639beb93cSSam Leffler return NULL; 16739beb93cSSam Leffler } 16839beb93cSSam Leffler os_free(buf); 16939beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_P", hdr2->rand_p, 17039beb93cSSam Leffler EAP_PSK_RAND_LEN); 17139beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", hdr2->mac_p, EAP_PSK_MAC_LEN); 17239beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_P", 17339beb93cSSam Leffler data->id_p, data->id_p_len); 17439beb93cSSam Leffler 17539beb93cSSam Leffler data->state = PSK_MAC_SENT; 17639beb93cSSam Leffler 17739beb93cSSam Leffler return resp; 17839beb93cSSam Leffler } 17939beb93cSSam Leffler 18039beb93cSSam Leffler 18139beb93cSSam Leffler static struct wpabuf * eap_psk_process_3(struct eap_psk_data *data, 18239beb93cSSam Leffler struct eap_method_ret *ret, 18339beb93cSSam Leffler const struct wpabuf *reqData) 18439beb93cSSam Leffler { 18539beb93cSSam Leffler const struct eap_psk_hdr_3 *hdr3; 18639beb93cSSam Leffler struct eap_psk_hdr_4 *hdr4; 18739beb93cSSam Leffler struct wpabuf *resp; 18839beb93cSSam Leffler u8 *buf, *rpchannel, nonce[16], *decrypted; 18939beb93cSSam Leffler const u8 *pchannel, *tag, *msg; 19039beb93cSSam Leffler u8 mac[EAP_PSK_MAC_LEN]; 19139beb93cSSam Leffler size_t buflen, left, data_len, len, plen; 19239beb93cSSam Leffler int failed = 0; 19339beb93cSSam Leffler const u8 *pos; 19439beb93cSSam Leffler 19539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PSK: in MAC_SENT state"); 19639beb93cSSam Leffler 19739beb93cSSam Leffler pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, 19839beb93cSSam Leffler reqData, &len); 19939beb93cSSam Leffler hdr3 = (const struct eap_psk_hdr_3 *) pos; 20039beb93cSSam Leffler if (pos == NULL || len < sizeof(*hdr3)) { 20139beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-PSK: Invalid third message " 20239beb93cSSam Leffler "length (%lu; expected %lu or more)", 20339beb93cSSam Leffler (unsigned long) len, 20439beb93cSSam Leffler (unsigned long) sizeof(*hdr3)); 20539beb93cSSam Leffler ret->ignore = TRUE; 20639beb93cSSam Leffler return NULL; 20739beb93cSSam Leffler } 20839beb93cSSam Leffler left = len - sizeof(*hdr3); 20939beb93cSSam Leffler pchannel = (const u8 *) (hdr3 + 1); 21039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr3->flags); 21139beb93cSSam Leffler if (EAP_PSK_FLAGS_GET_T(hdr3->flags) != 2) { 21239beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 2)", 21339beb93cSSam Leffler EAP_PSK_FLAGS_GET_T(hdr3->flags)); 21439beb93cSSam Leffler ret->methodState = METHOD_DONE; 21539beb93cSSam Leffler ret->decision = DECISION_FAIL; 21639beb93cSSam Leffler return NULL; 21739beb93cSSam Leffler } 21839beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr3->rand_s, 21939beb93cSSam Leffler EAP_PSK_RAND_LEN); 22039beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_S", hdr3->mac_s, EAP_PSK_MAC_LEN); 22139beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL", pchannel, left); 22239beb93cSSam Leffler 22339beb93cSSam Leffler if (left < 4 + 16 + 1) { 22439beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in " 22539beb93cSSam Leffler "third message (len=%lu, expected 21)", 22639beb93cSSam Leffler (unsigned long) left); 22739beb93cSSam Leffler ret->ignore = TRUE; 22839beb93cSSam Leffler return NULL; 22939beb93cSSam Leffler } 23039beb93cSSam Leffler 23139beb93cSSam Leffler /* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */ 23239beb93cSSam Leffler buflen = data->id_s_len + EAP_PSK_RAND_LEN; 23339beb93cSSam Leffler buf = os_malloc(buflen); 23439beb93cSSam Leffler if (buf == NULL) 23539beb93cSSam Leffler return NULL; 23639beb93cSSam Leffler os_memcpy(buf, data->id_s, data->id_s_len); 23739beb93cSSam Leffler os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN); 23839beb93cSSam Leffler if (omac1_aes_128(data->ak, buf, buflen, mac)) { 23939beb93cSSam Leffler os_free(buf); 24039beb93cSSam Leffler return NULL; 24139beb93cSSam Leffler } 24239beb93cSSam Leffler os_free(buf); 24339beb93cSSam Leffler if (os_memcmp(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) { 24439beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-PSK: Invalid MAC_S in third " 24539beb93cSSam Leffler "message"); 24639beb93cSSam Leffler ret->methodState = METHOD_DONE; 24739beb93cSSam Leffler ret->decision = DECISION_FAIL; 24839beb93cSSam Leffler return NULL; 24939beb93cSSam Leffler } 25039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PSK: MAC_S verified successfully"); 25139beb93cSSam Leffler 25239beb93cSSam Leffler if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, 25339beb93cSSam Leffler data->msk, data->emsk)) { 25439beb93cSSam Leffler ret->methodState = METHOD_DONE; 25539beb93cSSam Leffler ret->decision = DECISION_FAIL; 25639beb93cSSam Leffler return NULL; 25739beb93cSSam Leffler } 25839beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN); 25939beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_MSK_LEN); 26039beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: EMSK", data->emsk, EAP_EMSK_LEN); 26139beb93cSSam Leffler 26239beb93cSSam Leffler os_memset(nonce, 0, 12); 26339beb93cSSam Leffler os_memcpy(nonce + 12, pchannel, 4); 26439beb93cSSam Leffler pchannel += 4; 26539beb93cSSam Leffler left -= 4; 26639beb93cSSam Leffler 26739beb93cSSam Leffler tag = pchannel; 26839beb93cSSam Leffler pchannel += 16; 26939beb93cSSam Leffler left -= 16; 27039beb93cSSam Leffler 27139beb93cSSam Leffler msg = pchannel; 27239beb93cSSam Leffler 27339beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - nonce", 27439beb93cSSam Leffler nonce, sizeof(nonce)); 27539beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - hdr", 27639beb93cSSam Leffler wpabuf_head(reqData), 5); 27739beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - cipher msg", msg, left); 27839beb93cSSam Leffler 27939beb93cSSam Leffler decrypted = os_malloc(left); 28039beb93cSSam Leffler if (decrypted == NULL) { 28139beb93cSSam Leffler ret->methodState = METHOD_DONE; 28239beb93cSSam Leffler ret->decision = DECISION_FAIL; 28339beb93cSSam Leffler return NULL; 28439beb93cSSam Leffler } 28539beb93cSSam Leffler os_memcpy(decrypted, msg, left); 28639beb93cSSam Leffler 28739beb93cSSam Leffler if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce), 28839beb93cSSam Leffler wpabuf_head(reqData), 28939beb93cSSam Leffler sizeof(struct eap_hdr) + 1 + 29039beb93cSSam Leffler sizeof(*hdr3) - EAP_PSK_MAC_LEN, decrypted, 29139beb93cSSam Leffler left, tag)) { 29239beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed"); 29339beb93cSSam Leffler os_free(decrypted); 29439beb93cSSam Leffler return NULL; 29539beb93cSSam Leffler } 29639beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message", 29739beb93cSSam Leffler decrypted, left); 29839beb93cSSam Leffler 29939beb93cSSam Leffler /* Verify R flag */ 30039beb93cSSam Leffler switch (decrypted[0] >> 6) { 30139beb93cSSam Leffler case EAP_PSK_R_FLAG_CONT: 30239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported"); 30339beb93cSSam Leffler failed = 1; 30439beb93cSSam Leffler break; 30539beb93cSSam Leffler case EAP_PSK_R_FLAG_DONE_SUCCESS: 30639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS"); 30739beb93cSSam Leffler break; 30839beb93cSSam Leffler case EAP_PSK_R_FLAG_DONE_FAILURE: 30939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_FAILURE"); 31039beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-PSK: Authentication server rejected " 31139beb93cSSam Leffler "authentication"); 31239beb93cSSam Leffler failed = 1; 31339beb93cSSam Leffler break; 31439beb93cSSam Leffler } 31539beb93cSSam Leffler 31639beb93cSSam Leffler data_len = 1; 31739beb93cSSam Leffler if ((decrypted[0] & EAP_PSK_E_FLAG) && left > 1) 31839beb93cSSam Leffler data_len++; 31939beb93cSSam Leffler plen = sizeof(*hdr4) + 4 + 16 + data_len; 32039beb93cSSam Leffler resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, plen, 32139beb93cSSam Leffler EAP_CODE_RESPONSE, eap_get_id(reqData)); 32239beb93cSSam Leffler if (resp == NULL) { 32339beb93cSSam Leffler os_free(decrypted); 32439beb93cSSam Leffler return NULL; 32539beb93cSSam Leffler } 32639beb93cSSam Leffler hdr4 = wpabuf_put(resp, sizeof(*hdr4)); 32739beb93cSSam Leffler hdr4->flags = EAP_PSK_FLAGS_SET_T(3); /* T=3 */ 32839beb93cSSam Leffler os_memcpy(hdr4->rand_s, hdr3->rand_s, EAP_PSK_RAND_LEN); 32939beb93cSSam Leffler rpchannel = wpabuf_put(resp, 4 + 16 + data_len); 33039beb93cSSam Leffler 33139beb93cSSam Leffler /* nonce++ */ 33239beb93cSSam Leffler inc_byte_array(nonce, sizeof(nonce)); 33339beb93cSSam Leffler os_memcpy(rpchannel, nonce + 12, 4); 33439beb93cSSam Leffler 33539beb93cSSam Leffler if (decrypted[0] & EAP_PSK_E_FLAG) { 33639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PSK: Unsupported E (Ext) flag"); 33739beb93cSSam Leffler failed = 1; 33839beb93cSSam Leffler rpchannel[4 + 16] = (EAP_PSK_R_FLAG_DONE_FAILURE << 6) | 33939beb93cSSam Leffler EAP_PSK_E_FLAG; 34039beb93cSSam Leffler if (left > 1) { 34139beb93cSSam Leffler /* Add empty EXT_Payload with same EXT_Type */ 34239beb93cSSam Leffler rpchannel[4 + 16 + 1] = decrypted[1]; 34339beb93cSSam Leffler } 34439beb93cSSam Leffler } else if (failed) 34539beb93cSSam Leffler rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_FAILURE << 6; 34639beb93cSSam Leffler else 34739beb93cSSam Leffler rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6; 34839beb93cSSam Leffler 34939beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (plaintext)", 35039beb93cSSam Leffler rpchannel + 4 + 16, data_len); 35139beb93cSSam Leffler if (aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce), 35239beb93cSSam Leffler wpabuf_head(resp), 35339beb93cSSam Leffler sizeof(struct eap_hdr) + 1 + sizeof(*hdr4), 35439beb93cSSam Leffler rpchannel + 4 + 16, data_len, rpchannel + 4)) { 35539beb93cSSam Leffler os_free(decrypted); 35639beb93cSSam Leffler wpabuf_free(resp); 35739beb93cSSam Leffler return NULL; 35839beb93cSSam Leffler } 35939beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (PCHANNEL)", 36039beb93cSSam Leffler rpchannel, 4 + 16 + data_len); 36139beb93cSSam Leffler 36239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PSK: Completed %ssuccessfully", 36339beb93cSSam Leffler failed ? "un" : ""); 36439beb93cSSam Leffler data->state = PSK_DONE; 36539beb93cSSam Leffler ret->methodState = METHOD_DONE; 36639beb93cSSam Leffler ret->decision = failed ? DECISION_FAIL : DECISION_UNCOND_SUCC; 36739beb93cSSam Leffler 36839beb93cSSam Leffler os_free(decrypted); 36939beb93cSSam Leffler 37039beb93cSSam Leffler return resp; 37139beb93cSSam Leffler } 37239beb93cSSam Leffler 37339beb93cSSam Leffler 37439beb93cSSam Leffler static struct wpabuf * eap_psk_process(struct eap_sm *sm, void *priv, 37539beb93cSSam Leffler struct eap_method_ret *ret, 37639beb93cSSam Leffler const struct wpabuf *reqData) 37739beb93cSSam Leffler { 37839beb93cSSam Leffler struct eap_psk_data *data = priv; 37939beb93cSSam Leffler const u8 *pos; 38039beb93cSSam Leffler struct wpabuf *resp = NULL; 38139beb93cSSam Leffler size_t len; 38239beb93cSSam Leffler 38339beb93cSSam Leffler pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len); 38439beb93cSSam Leffler if (pos == NULL) { 38539beb93cSSam Leffler ret->ignore = TRUE; 38639beb93cSSam Leffler return NULL; 38739beb93cSSam Leffler } 38839beb93cSSam Leffler 38939beb93cSSam Leffler ret->ignore = FALSE; 39039beb93cSSam Leffler ret->methodState = METHOD_MAY_CONT; 39139beb93cSSam Leffler ret->decision = DECISION_FAIL; 39239beb93cSSam Leffler ret->allowNotifications = TRUE; 39339beb93cSSam Leffler 39439beb93cSSam Leffler switch (data->state) { 39539beb93cSSam Leffler case PSK_INIT: 39639beb93cSSam Leffler resp = eap_psk_process_1(data, ret, reqData); 39739beb93cSSam Leffler break; 39839beb93cSSam Leffler case PSK_MAC_SENT: 39939beb93cSSam Leffler resp = eap_psk_process_3(data, ret, reqData); 40039beb93cSSam Leffler break; 40139beb93cSSam Leffler case PSK_DONE: 40239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PSK: in DONE state - ignore " 40339beb93cSSam Leffler "unexpected message"); 40439beb93cSSam Leffler ret->ignore = TRUE; 40539beb93cSSam Leffler return NULL; 40639beb93cSSam Leffler } 40739beb93cSSam Leffler 40839beb93cSSam Leffler if (ret->methodState == METHOD_DONE) { 40939beb93cSSam Leffler ret->allowNotifications = FALSE; 41039beb93cSSam Leffler } 41139beb93cSSam Leffler 41239beb93cSSam Leffler return resp; 41339beb93cSSam Leffler } 41439beb93cSSam Leffler 41539beb93cSSam Leffler 41639beb93cSSam Leffler static Boolean eap_psk_isKeyAvailable(struct eap_sm *sm, void *priv) 41739beb93cSSam Leffler { 41839beb93cSSam Leffler struct eap_psk_data *data = priv; 41939beb93cSSam Leffler return data->state == PSK_DONE; 42039beb93cSSam Leffler } 42139beb93cSSam Leffler 42239beb93cSSam Leffler 42339beb93cSSam Leffler static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len) 42439beb93cSSam Leffler { 42539beb93cSSam Leffler struct eap_psk_data *data = priv; 42639beb93cSSam Leffler u8 *key; 42739beb93cSSam Leffler 42839beb93cSSam Leffler if (data->state != PSK_DONE) 42939beb93cSSam Leffler return NULL; 43039beb93cSSam Leffler 43139beb93cSSam Leffler key = os_malloc(EAP_MSK_LEN); 43239beb93cSSam Leffler if (key == NULL) 43339beb93cSSam Leffler return NULL; 43439beb93cSSam Leffler 43539beb93cSSam Leffler *len = EAP_MSK_LEN; 43639beb93cSSam Leffler os_memcpy(key, data->msk, EAP_MSK_LEN); 43739beb93cSSam Leffler 43839beb93cSSam Leffler return key; 43939beb93cSSam Leffler } 44039beb93cSSam Leffler 44139beb93cSSam Leffler 44239beb93cSSam Leffler static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 44339beb93cSSam Leffler { 44439beb93cSSam Leffler struct eap_psk_data *data = priv; 44539beb93cSSam Leffler u8 *key; 44639beb93cSSam Leffler 44739beb93cSSam Leffler if (data->state != PSK_DONE) 44839beb93cSSam Leffler return NULL; 44939beb93cSSam Leffler 45039beb93cSSam Leffler key = os_malloc(EAP_EMSK_LEN); 45139beb93cSSam Leffler if (key == NULL) 45239beb93cSSam Leffler return NULL; 45339beb93cSSam Leffler 45439beb93cSSam Leffler *len = EAP_EMSK_LEN; 45539beb93cSSam Leffler os_memcpy(key, data->emsk, EAP_EMSK_LEN); 45639beb93cSSam Leffler 45739beb93cSSam Leffler return key; 45839beb93cSSam Leffler } 45939beb93cSSam Leffler 46039beb93cSSam Leffler 46139beb93cSSam Leffler int eap_peer_psk_register(void) 46239beb93cSSam Leffler { 46339beb93cSSam Leffler struct eap_method *eap; 46439beb93cSSam Leffler int ret; 46539beb93cSSam Leffler 46639beb93cSSam Leffler eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 46739beb93cSSam Leffler EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK"); 46839beb93cSSam Leffler if (eap == NULL) 46939beb93cSSam Leffler return -1; 47039beb93cSSam Leffler 47139beb93cSSam Leffler eap->init = eap_psk_init; 47239beb93cSSam Leffler eap->deinit = eap_psk_deinit; 47339beb93cSSam Leffler eap->process = eap_psk_process; 47439beb93cSSam Leffler eap->isKeyAvailable = eap_psk_isKeyAvailable; 47539beb93cSSam Leffler eap->getKey = eap_psk_getKey; 47639beb93cSSam Leffler eap->get_emsk = eap_psk_get_emsk; 47739beb93cSSam Leffler 47839beb93cSSam Leffler ret = eap_peer_method_register(eap); 47939beb93cSSam Leffler if (ret) 48039beb93cSSam Leffler eap_peer_method_free(eap); 48139beb93cSSam Leffler return ret; 48239beb93cSSam Leffler } 483