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