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]; 24*5b9c547cSRui 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); 79*5b9c547cSRui 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); 116*5b9c547cSRui 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); 11939beb93cSSam Leffler data->id_s = os_malloc(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 os_memcpy(data->id_s, (u8 *) (hdr1 + 1), data->id_s_len); 12739beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_S", 12839beb93cSSam Leffler data->id_s, data->id_s_len); 12939beb93cSSam Leffler 130f05cddf9SRui Paulo if (random_get_bytes(data->rand_p, EAP_PSK_RAND_LEN)) { 13139beb93cSSam Leffler wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data"); 13239beb93cSSam Leffler ret->ignore = TRUE; 13339beb93cSSam Leffler return NULL; 13439beb93cSSam Leffler } 13539beb93cSSam Leffler 13639beb93cSSam Leffler resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, 13739beb93cSSam Leffler sizeof(*hdr2) + data->id_p_len, EAP_CODE_RESPONSE, 13839beb93cSSam Leffler eap_get_id(reqData)); 13939beb93cSSam Leffler if (resp == NULL) 14039beb93cSSam Leffler return NULL; 14139beb93cSSam Leffler hdr2 = wpabuf_put(resp, sizeof(*hdr2)); 14239beb93cSSam Leffler hdr2->flags = EAP_PSK_FLAGS_SET_T(1); /* T=1 */ 14339beb93cSSam Leffler os_memcpy(hdr2->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN); 14439beb93cSSam Leffler os_memcpy(hdr2->rand_p, data->rand_p, EAP_PSK_RAND_LEN); 14539beb93cSSam Leffler wpabuf_put_data(resp, data->id_p, data->id_p_len); 14639beb93cSSam Leffler /* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */ 14739beb93cSSam Leffler buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN; 14839beb93cSSam Leffler buf = os_malloc(buflen); 14939beb93cSSam Leffler if (buf == NULL) { 15039beb93cSSam Leffler wpabuf_free(resp); 15139beb93cSSam Leffler return NULL; 15239beb93cSSam Leffler } 15339beb93cSSam Leffler os_memcpy(buf, data->id_p, data->id_p_len); 15439beb93cSSam Leffler pos = buf + data->id_p_len; 15539beb93cSSam Leffler os_memcpy(pos, data->id_s, data->id_s_len); 15639beb93cSSam Leffler pos += data->id_s_len; 15739beb93cSSam Leffler os_memcpy(pos, hdr1->rand_s, EAP_PSK_RAND_LEN); 15839beb93cSSam Leffler pos += EAP_PSK_RAND_LEN; 15939beb93cSSam Leffler os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN); 16039beb93cSSam Leffler if (omac1_aes_128(data->ak, buf, buflen, hdr2->mac_p)) { 16139beb93cSSam Leffler os_free(buf); 16239beb93cSSam Leffler wpabuf_free(resp); 16339beb93cSSam Leffler return NULL; 16439beb93cSSam Leffler } 16539beb93cSSam Leffler os_free(buf); 16639beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_P", hdr2->rand_p, 16739beb93cSSam Leffler EAP_PSK_RAND_LEN); 16839beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", hdr2->mac_p, EAP_PSK_MAC_LEN); 16939beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_P", 17039beb93cSSam Leffler data->id_p, data->id_p_len); 17139beb93cSSam Leffler 17239beb93cSSam Leffler data->state = PSK_MAC_SENT; 17339beb93cSSam Leffler 17439beb93cSSam Leffler return resp; 17539beb93cSSam Leffler } 17639beb93cSSam Leffler 17739beb93cSSam Leffler 17839beb93cSSam Leffler static struct wpabuf * eap_psk_process_3(struct eap_psk_data *data, 17939beb93cSSam Leffler struct eap_method_ret *ret, 18039beb93cSSam Leffler const struct wpabuf *reqData) 18139beb93cSSam Leffler { 18239beb93cSSam Leffler const struct eap_psk_hdr_3 *hdr3; 18339beb93cSSam Leffler struct eap_psk_hdr_4 *hdr4; 18439beb93cSSam Leffler struct wpabuf *resp; 18539beb93cSSam Leffler u8 *buf, *rpchannel, nonce[16], *decrypted; 18639beb93cSSam Leffler const u8 *pchannel, *tag, *msg; 18739beb93cSSam Leffler u8 mac[EAP_PSK_MAC_LEN]; 18839beb93cSSam Leffler size_t buflen, left, data_len, len, plen; 18939beb93cSSam Leffler int failed = 0; 19039beb93cSSam Leffler const u8 *pos; 19139beb93cSSam Leffler 19239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PSK: in MAC_SENT state"); 19339beb93cSSam Leffler 19439beb93cSSam Leffler pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, 19539beb93cSSam Leffler reqData, &len); 19639beb93cSSam Leffler hdr3 = (const struct eap_psk_hdr_3 *) pos; 19739beb93cSSam Leffler if (pos == NULL || len < sizeof(*hdr3)) { 19839beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-PSK: Invalid third message " 19939beb93cSSam Leffler "length (%lu; expected %lu or more)", 20039beb93cSSam Leffler (unsigned long) len, 20139beb93cSSam Leffler (unsigned long) sizeof(*hdr3)); 20239beb93cSSam Leffler ret->ignore = TRUE; 20339beb93cSSam Leffler return NULL; 20439beb93cSSam Leffler } 20539beb93cSSam Leffler left = len - sizeof(*hdr3); 20639beb93cSSam Leffler pchannel = (const u8 *) (hdr3 + 1); 20739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr3->flags); 20839beb93cSSam Leffler if (EAP_PSK_FLAGS_GET_T(hdr3->flags) != 2) { 20939beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 2)", 21039beb93cSSam Leffler EAP_PSK_FLAGS_GET_T(hdr3->flags)); 21139beb93cSSam Leffler ret->methodState = METHOD_DONE; 21239beb93cSSam Leffler ret->decision = DECISION_FAIL; 21339beb93cSSam Leffler return NULL; 21439beb93cSSam Leffler } 21539beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr3->rand_s, 21639beb93cSSam Leffler EAP_PSK_RAND_LEN); 21739beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_S", hdr3->mac_s, EAP_PSK_MAC_LEN); 21839beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL", pchannel, left); 21939beb93cSSam Leffler 22039beb93cSSam Leffler if (left < 4 + 16 + 1) { 22139beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in " 22239beb93cSSam Leffler "third message (len=%lu, expected 21)", 22339beb93cSSam Leffler (unsigned long) left); 22439beb93cSSam Leffler ret->ignore = TRUE; 22539beb93cSSam Leffler return NULL; 22639beb93cSSam Leffler } 22739beb93cSSam Leffler 22839beb93cSSam Leffler /* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */ 22939beb93cSSam Leffler buflen = data->id_s_len + EAP_PSK_RAND_LEN; 23039beb93cSSam Leffler buf = os_malloc(buflen); 23139beb93cSSam Leffler if (buf == NULL) 23239beb93cSSam Leffler return NULL; 23339beb93cSSam Leffler os_memcpy(buf, data->id_s, data->id_s_len); 23439beb93cSSam Leffler os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN); 23539beb93cSSam Leffler if (omac1_aes_128(data->ak, buf, buflen, mac)) { 23639beb93cSSam Leffler os_free(buf); 23739beb93cSSam Leffler return NULL; 23839beb93cSSam Leffler } 23939beb93cSSam Leffler os_free(buf); 240*5b9c547cSRui Paulo if (os_memcmp_const(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) { 24139beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-PSK: Invalid MAC_S in third " 24239beb93cSSam Leffler "message"); 24339beb93cSSam Leffler ret->methodState = METHOD_DONE; 24439beb93cSSam Leffler ret->decision = DECISION_FAIL; 24539beb93cSSam Leffler return NULL; 24639beb93cSSam Leffler } 24739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PSK: MAC_S verified successfully"); 24839beb93cSSam Leffler 24939beb93cSSam Leffler if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, 25039beb93cSSam Leffler data->msk, data->emsk)) { 25139beb93cSSam Leffler ret->methodState = METHOD_DONE; 25239beb93cSSam Leffler ret->decision = DECISION_FAIL; 25339beb93cSSam Leffler return NULL; 25439beb93cSSam Leffler } 25539beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN); 25639beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_MSK_LEN); 25739beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: EMSK", data->emsk, EAP_EMSK_LEN); 25839beb93cSSam Leffler 25939beb93cSSam Leffler os_memset(nonce, 0, 12); 26039beb93cSSam Leffler os_memcpy(nonce + 12, pchannel, 4); 26139beb93cSSam Leffler pchannel += 4; 26239beb93cSSam Leffler left -= 4; 26339beb93cSSam Leffler 26439beb93cSSam Leffler tag = pchannel; 26539beb93cSSam Leffler pchannel += 16; 26639beb93cSSam Leffler left -= 16; 26739beb93cSSam Leffler 26839beb93cSSam Leffler msg = pchannel; 26939beb93cSSam Leffler 27039beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - nonce", 27139beb93cSSam Leffler nonce, sizeof(nonce)); 27239beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - hdr", 27339beb93cSSam Leffler wpabuf_head(reqData), 5); 27439beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - cipher msg", msg, left); 27539beb93cSSam Leffler 27639beb93cSSam Leffler decrypted = os_malloc(left); 27739beb93cSSam Leffler if (decrypted == NULL) { 27839beb93cSSam Leffler ret->methodState = METHOD_DONE; 27939beb93cSSam Leffler ret->decision = DECISION_FAIL; 28039beb93cSSam Leffler return NULL; 28139beb93cSSam Leffler } 28239beb93cSSam Leffler os_memcpy(decrypted, msg, left); 28339beb93cSSam Leffler 28439beb93cSSam Leffler if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce), 28539beb93cSSam Leffler wpabuf_head(reqData), 28639beb93cSSam Leffler sizeof(struct eap_hdr) + 1 + 28739beb93cSSam Leffler sizeof(*hdr3) - EAP_PSK_MAC_LEN, decrypted, 28839beb93cSSam Leffler left, tag)) { 28939beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed"); 29039beb93cSSam Leffler os_free(decrypted); 29139beb93cSSam Leffler return NULL; 29239beb93cSSam Leffler } 29339beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message", 29439beb93cSSam Leffler decrypted, left); 29539beb93cSSam Leffler 29639beb93cSSam Leffler /* Verify R flag */ 29739beb93cSSam Leffler switch (decrypted[0] >> 6) { 29839beb93cSSam Leffler case EAP_PSK_R_FLAG_CONT: 29939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported"); 30039beb93cSSam Leffler failed = 1; 30139beb93cSSam Leffler break; 30239beb93cSSam Leffler case EAP_PSK_R_FLAG_DONE_SUCCESS: 30339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS"); 30439beb93cSSam Leffler break; 30539beb93cSSam Leffler case EAP_PSK_R_FLAG_DONE_FAILURE: 30639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_FAILURE"); 30739beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-PSK: Authentication server rejected " 30839beb93cSSam Leffler "authentication"); 30939beb93cSSam Leffler failed = 1; 31039beb93cSSam Leffler break; 31139beb93cSSam Leffler } 31239beb93cSSam Leffler 31339beb93cSSam Leffler data_len = 1; 31439beb93cSSam Leffler if ((decrypted[0] & EAP_PSK_E_FLAG) && left > 1) 31539beb93cSSam Leffler data_len++; 31639beb93cSSam Leffler plen = sizeof(*hdr4) + 4 + 16 + data_len; 31739beb93cSSam Leffler resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, plen, 31839beb93cSSam Leffler EAP_CODE_RESPONSE, eap_get_id(reqData)); 31939beb93cSSam Leffler if (resp == NULL) { 32039beb93cSSam Leffler os_free(decrypted); 32139beb93cSSam Leffler return NULL; 32239beb93cSSam Leffler } 32339beb93cSSam Leffler hdr4 = wpabuf_put(resp, sizeof(*hdr4)); 32439beb93cSSam Leffler hdr4->flags = EAP_PSK_FLAGS_SET_T(3); /* T=3 */ 32539beb93cSSam Leffler os_memcpy(hdr4->rand_s, hdr3->rand_s, EAP_PSK_RAND_LEN); 32639beb93cSSam Leffler rpchannel = wpabuf_put(resp, 4 + 16 + data_len); 32739beb93cSSam Leffler 32839beb93cSSam Leffler /* nonce++ */ 32939beb93cSSam Leffler inc_byte_array(nonce, sizeof(nonce)); 33039beb93cSSam Leffler os_memcpy(rpchannel, nonce + 12, 4); 33139beb93cSSam Leffler 33239beb93cSSam Leffler if (decrypted[0] & EAP_PSK_E_FLAG) { 33339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PSK: Unsupported E (Ext) flag"); 33439beb93cSSam Leffler failed = 1; 33539beb93cSSam Leffler rpchannel[4 + 16] = (EAP_PSK_R_FLAG_DONE_FAILURE << 6) | 33639beb93cSSam Leffler EAP_PSK_E_FLAG; 33739beb93cSSam Leffler if (left > 1) { 33839beb93cSSam Leffler /* Add empty EXT_Payload with same EXT_Type */ 33939beb93cSSam Leffler rpchannel[4 + 16 + 1] = decrypted[1]; 34039beb93cSSam Leffler } 34139beb93cSSam Leffler } else if (failed) 34239beb93cSSam Leffler rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_FAILURE << 6; 34339beb93cSSam Leffler else 34439beb93cSSam Leffler rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6; 34539beb93cSSam Leffler 34639beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (plaintext)", 34739beb93cSSam Leffler rpchannel + 4 + 16, data_len); 34839beb93cSSam Leffler if (aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce), 34939beb93cSSam Leffler wpabuf_head(resp), 35039beb93cSSam Leffler sizeof(struct eap_hdr) + 1 + sizeof(*hdr4), 35139beb93cSSam Leffler rpchannel + 4 + 16, data_len, rpchannel + 4)) { 35239beb93cSSam Leffler os_free(decrypted); 35339beb93cSSam Leffler wpabuf_free(resp); 35439beb93cSSam Leffler return NULL; 35539beb93cSSam Leffler } 35639beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (PCHANNEL)", 35739beb93cSSam Leffler rpchannel, 4 + 16 + data_len); 35839beb93cSSam Leffler 35939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PSK: Completed %ssuccessfully", 36039beb93cSSam Leffler failed ? "un" : ""); 36139beb93cSSam Leffler data->state = PSK_DONE; 36239beb93cSSam Leffler ret->methodState = METHOD_DONE; 36339beb93cSSam Leffler ret->decision = failed ? DECISION_FAIL : DECISION_UNCOND_SUCC; 36439beb93cSSam Leffler 36539beb93cSSam Leffler os_free(decrypted); 36639beb93cSSam Leffler 36739beb93cSSam Leffler return resp; 36839beb93cSSam Leffler } 36939beb93cSSam Leffler 37039beb93cSSam Leffler 37139beb93cSSam Leffler static struct wpabuf * eap_psk_process(struct eap_sm *sm, void *priv, 37239beb93cSSam Leffler struct eap_method_ret *ret, 37339beb93cSSam Leffler const struct wpabuf *reqData) 37439beb93cSSam Leffler { 37539beb93cSSam Leffler struct eap_psk_data *data = priv; 37639beb93cSSam Leffler const u8 *pos; 37739beb93cSSam Leffler struct wpabuf *resp = NULL; 37839beb93cSSam Leffler size_t len; 37939beb93cSSam Leffler 38039beb93cSSam Leffler pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len); 38139beb93cSSam Leffler if (pos == NULL) { 38239beb93cSSam Leffler ret->ignore = TRUE; 38339beb93cSSam Leffler return NULL; 38439beb93cSSam Leffler } 38539beb93cSSam Leffler 38639beb93cSSam Leffler ret->ignore = FALSE; 38739beb93cSSam Leffler ret->methodState = METHOD_MAY_CONT; 38839beb93cSSam Leffler ret->decision = DECISION_FAIL; 38939beb93cSSam Leffler ret->allowNotifications = TRUE; 39039beb93cSSam Leffler 39139beb93cSSam Leffler switch (data->state) { 39239beb93cSSam Leffler case PSK_INIT: 39339beb93cSSam Leffler resp = eap_psk_process_1(data, ret, reqData); 39439beb93cSSam Leffler break; 39539beb93cSSam Leffler case PSK_MAC_SENT: 39639beb93cSSam Leffler resp = eap_psk_process_3(data, ret, reqData); 39739beb93cSSam Leffler break; 39839beb93cSSam Leffler case PSK_DONE: 39939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PSK: in DONE state - ignore " 40039beb93cSSam Leffler "unexpected message"); 40139beb93cSSam Leffler ret->ignore = TRUE; 40239beb93cSSam Leffler return NULL; 40339beb93cSSam Leffler } 40439beb93cSSam Leffler 40539beb93cSSam Leffler if (ret->methodState == METHOD_DONE) { 40639beb93cSSam Leffler ret->allowNotifications = FALSE; 40739beb93cSSam Leffler } 40839beb93cSSam Leffler 40939beb93cSSam Leffler return resp; 41039beb93cSSam Leffler } 41139beb93cSSam Leffler 41239beb93cSSam Leffler 41339beb93cSSam Leffler static Boolean eap_psk_isKeyAvailable(struct eap_sm *sm, void *priv) 41439beb93cSSam Leffler { 41539beb93cSSam Leffler struct eap_psk_data *data = priv; 41639beb93cSSam Leffler return data->state == PSK_DONE; 41739beb93cSSam Leffler } 41839beb93cSSam Leffler 41939beb93cSSam Leffler 42039beb93cSSam Leffler static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len) 42139beb93cSSam Leffler { 42239beb93cSSam Leffler struct eap_psk_data *data = priv; 42339beb93cSSam Leffler u8 *key; 42439beb93cSSam Leffler 42539beb93cSSam Leffler if (data->state != PSK_DONE) 42639beb93cSSam Leffler return NULL; 42739beb93cSSam Leffler 42839beb93cSSam Leffler key = os_malloc(EAP_MSK_LEN); 42939beb93cSSam Leffler if (key == NULL) 43039beb93cSSam Leffler return NULL; 43139beb93cSSam Leffler 43239beb93cSSam Leffler *len = EAP_MSK_LEN; 43339beb93cSSam Leffler os_memcpy(key, data->msk, EAP_MSK_LEN); 43439beb93cSSam Leffler 43539beb93cSSam Leffler return key; 43639beb93cSSam Leffler } 43739beb93cSSam Leffler 43839beb93cSSam Leffler 439*5b9c547cSRui Paulo static u8 * eap_psk_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 440*5b9c547cSRui Paulo { 441*5b9c547cSRui Paulo struct eap_psk_data *data = priv; 442*5b9c547cSRui Paulo u8 *id; 443*5b9c547cSRui Paulo 444*5b9c547cSRui Paulo if (data->state != PSK_DONE) 445*5b9c547cSRui Paulo return NULL; 446*5b9c547cSRui Paulo 447*5b9c547cSRui Paulo *len = 1 + 2 * EAP_PSK_RAND_LEN; 448*5b9c547cSRui Paulo id = os_malloc(*len); 449*5b9c547cSRui Paulo if (id == NULL) 450*5b9c547cSRui Paulo return NULL; 451*5b9c547cSRui Paulo 452*5b9c547cSRui Paulo id[0] = EAP_TYPE_PSK; 453*5b9c547cSRui Paulo os_memcpy(id + 1, data->rand_p, EAP_PSK_RAND_LEN); 454*5b9c547cSRui Paulo os_memcpy(id + 1 + EAP_PSK_RAND_LEN, data->rand_s, EAP_PSK_RAND_LEN); 455*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-PSK: Derived Session-Id", id, *len); 456*5b9c547cSRui Paulo 457*5b9c547cSRui Paulo return id; 458*5b9c547cSRui Paulo } 459*5b9c547cSRui Paulo 460*5b9c547cSRui Paulo 46139beb93cSSam Leffler static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 46239beb93cSSam Leffler { 46339beb93cSSam Leffler struct eap_psk_data *data = priv; 46439beb93cSSam Leffler u8 *key; 46539beb93cSSam Leffler 46639beb93cSSam Leffler if (data->state != PSK_DONE) 46739beb93cSSam Leffler return NULL; 46839beb93cSSam Leffler 46939beb93cSSam Leffler key = os_malloc(EAP_EMSK_LEN); 47039beb93cSSam Leffler if (key == NULL) 47139beb93cSSam Leffler return NULL; 47239beb93cSSam Leffler 47339beb93cSSam Leffler *len = EAP_EMSK_LEN; 47439beb93cSSam Leffler os_memcpy(key, data->emsk, EAP_EMSK_LEN); 47539beb93cSSam Leffler 47639beb93cSSam Leffler return key; 47739beb93cSSam Leffler } 47839beb93cSSam Leffler 47939beb93cSSam Leffler 48039beb93cSSam Leffler int eap_peer_psk_register(void) 48139beb93cSSam Leffler { 48239beb93cSSam Leffler struct eap_method *eap; 48339beb93cSSam Leffler int ret; 48439beb93cSSam Leffler 48539beb93cSSam Leffler eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 48639beb93cSSam Leffler EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK"); 48739beb93cSSam Leffler if (eap == NULL) 48839beb93cSSam Leffler return -1; 48939beb93cSSam Leffler 49039beb93cSSam Leffler eap->init = eap_psk_init; 49139beb93cSSam Leffler eap->deinit = eap_psk_deinit; 49239beb93cSSam Leffler eap->process = eap_psk_process; 49339beb93cSSam Leffler eap->isKeyAvailable = eap_psk_isKeyAvailable; 49439beb93cSSam Leffler eap->getKey = eap_psk_getKey; 495*5b9c547cSRui Paulo eap->getSessionId = eap_psk_get_session_id; 49639beb93cSSam Leffler eap->get_emsk = eap_psk_get_emsk; 49739beb93cSSam Leffler 49839beb93cSSam Leffler ret = eap_peer_method_register(eap); 49939beb93cSSam Leffler if (ret) 50039beb93cSSam Leffler eap_peer_method_free(eap); 50139beb93cSSam Leffler return ret; 50239beb93cSSam Leffler } 503