1189251Ssam/* 2189251Ssam * EAP peer method: EAP-PSK (RFC 4764) 3189251Ssam * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> 4189251Ssam * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7189251Ssam * 8189251Ssam * Note: EAP-PSK is an EAP authentication method and as such, completely 9189251Ssam * different from WPA-PSK. This file is not needed for WPA-PSK functionality. 10189251Ssam */ 11189251Ssam 12189251Ssam#include "includes.h" 13189251Ssam 14189251Ssam#include "common.h" 15214734Srpaulo#include "crypto/aes_wrap.h" 16252726Srpaulo#include "crypto/random.h" 17189251Ssam#include "eap_common/eap_psk_common.h" 18214734Srpaulo#include "eap_i.h" 19189251Ssam 20189251Ssam 21189251Ssamstruct eap_psk_data { 22189251Ssam enum { PSK_INIT, PSK_MAC_SENT, PSK_DONE } state; 23189251Ssam u8 rand_p[EAP_PSK_RAND_LEN]; 24189251Ssam u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN]; 25189251Ssam u8 *id_s, *id_p; 26189251Ssam size_t id_s_len, id_p_len; 27189251Ssam u8 msk[EAP_MSK_LEN]; 28189251Ssam u8 emsk[EAP_EMSK_LEN]; 29189251Ssam}; 30189251Ssam 31189251Ssam 32189251Ssamstatic void * eap_psk_init(struct eap_sm *sm) 33189251Ssam{ 34189251Ssam struct eap_psk_data *data; 35189251Ssam const u8 *identity, *password; 36189251Ssam size_t identity_len, password_len; 37189251Ssam 38189251Ssam password = eap_get_config_password(sm, &password_len); 39189251Ssam if (!password || password_len != 16) { 40189251Ssam wpa_printf(MSG_INFO, "EAP-PSK: 16-octet pre-shared key not " 41189251Ssam "configured"); 42189251Ssam return NULL; 43189251Ssam } 44189251Ssam 45189251Ssam data = os_zalloc(sizeof(*data)); 46189251Ssam if (data == NULL) 47189251Ssam return NULL; 48189251Ssam if (eap_psk_key_setup(password, data->ak, data->kdk)) { 49189251Ssam os_free(data); 50189251Ssam return NULL; 51189251Ssam } 52189251Ssam wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, EAP_PSK_AK_LEN); 53189251Ssam wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, EAP_PSK_KDK_LEN); 54189251Ssam data->state = PSK_INIT; 55189251Ssam 56189251Ssam identity = eap_get_config_identity(sm, &identity_len); 57189251Ssam if (identity) { 58189251Ssam data->id_p = os_malloc(identity_len); 59189251Ssam if (data->id_p) 60189251Ssam os_memcpy(data->id_p, identity, identity_len); 61189251Ssam data->id_p_len = identity_len; 62189251Ssam } 63189251Ssam if (data->id_p == NULL) { 64189251Ssam wpa_printf(MSG_INFO, "EAP-PSK: could not get own identity"); 65189251Ssam os_free(data); 66189251Ssam return NULL; 67189251Ssam } 68189251Ssam 69189251Ssam return data; 70189251Ssam} 71189251Ssam 72189251Ssam 73189251Ssamstatic void eap_psk_deinit(struct eap_sm *sm, void *priv) 74189251Ssam{ 75189251Ssam struct eap_psk_data *data = priv; 76189251Ssam os_free(data->id_s); 77189251Ssam os_free(data->id_p); 78189251Ssam os_free(data); 79189251Ssam} 80189251Ssam 81189251Ssam 82189251Ssamstatic struct wpabuf * eap_psk_process_1(struct eap_psk_data *data, 83189251Ssam struct eap_method_ret *ret, 84189251Ssam const struct wpabuf *reqData) 85189251Ssam{ 86189251Ssam const struct eap_psk_hdr_1 *hdr1; 87189251Ssam struct eap_psk_hdr_2 *hdr2; 88189251Ssam struct wpabuf *resp; 89189251Ssam u8 *buf, *pos; 90189251Ssam size_t buflen, len; 91189251Ssam const u8 *cpos; 92189251Ssam 93189251Ssam wpa_printf(MSG_DEBUG, "EAP-PSK: in INIT state"); 94189251Ssam 95189251Ssam cpos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len); 96189251Ssam hdr1 = (const struct eap_psk_hdr_1 *) cpos; 97189251Ssam if (cpos == NULL || len < sizeof(*hdr1)) { 98189251Ssam wpa_printf(MSG_INFO, "EAP-PSK: Invalid first message " 99189251Ssam "length (%lu; expected %lu or more)", 100189251Ssam (unsigned long) len, 101189251Ssam (unsigned long) sizeof(*hdr1)); 102189251Ssam ret->ignore = TRUE; 103189251Ssam return NULL; 104189251Ssam } 105189251Ssam wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr1->flags); 106189251Ssam if (EAP_PSK_FLAGS_GET_T(hdr1->flags) != 0) { 107189251Ssam wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 0)", 108189251Ssam EAP_PSK_FLAGS_GET_T(hdr1->flags)); 109189251Ssam ret->methodState = METHOD_DONE; 110189251Ssam ret->decision = DECISION_FAIL; 111189251Ssam return NULL; 112189251Ssam } 113189251Ssam wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr1->rand_s, 114189251Ssam EAP_PSK_RAND_LEN); 115189251Ssam os_free(data->id_s); 116189251Ssam data->id_s_len = len - sizeof(*hdr1); 117189251Ssam data->id_s = os_malloc(data->id_s_len); 118189251Ssam if (data->id_s == NULL) { 119189251Ssam wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory for " 120189251Ssam "ID_S (len=%lu)", (unsigned long) data->id_s_len); 121189251Ssam ret->ignore = TRUE; 122189251Ssam return NULL; 123189251Ssam } 124189251Ssam os_memcpy(data->id_s, (u8 *) (hdr1 + 1), data->id_s_len); 125189251Ssam wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_S", 126189251Ssam data->id_s, data->id_s_len); 127189251Ssam 128252726Srpaulo if (random_get_bytes(data->rand_p, EAP_PSK_RAND_LEN)) { 129189251Ssam wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data"); 130189251Ssam ret->ignore = TRUE; 131189251Ssam return NULL; 132189251Ssam } 133189251Ssam 134189251Ssam resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, 135189251Ssam sizeof(*hdr2) + data->id_p_len, EAP_CODE_RESPONSE, 136189251Ssam eap_get_id(reqData)); 137189251Ssam if (resp == NULL) 138189251Ssam return NULL; 139189251Ssam hdr2 = wpabuf_put(resp, sizeof(*hdr2)); 140189251Ssam hdr2->flags = EAP_PSK_FLAGS_SET_T(1); /* T=1 */ 141189251Ssam os_memcpy(hdr2->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN); 142189251Ssam os_memcpy(hdr2->rand_p, data->rand_p, EAP_PSK_RAND_LEN); 143189251Ssam wpabuf_put_data(resp, data->id_p, data->id_p_len); 144189251Ssam /* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */ 145189251Ssam buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN; 146189251Ssam buf = os_malloc(buflen); 147189251Ssam if (buf == NULL) { 148189251Ssam wpabuf_free(resp); 149189251Ssam return NULL; 150189251Ssam } 151189251Ssam os_memcpy(buf, data->id_p, data->id_p_len); 152189251Ssam pos = buf + data->id_p_len; 153189251Ssam os_memcpy(pos, data->id_s, data->id_s_len); 154189251Ssam pos += data->id_s_len; 155189251Ssam os_memcpy(pos, hdr1->rand_s, EAP_PSK_RAND_LEN); 156189251Ssam pos += EAP_PSK_RAND_LEN; 157189251Ssam os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN); 158189251Ssam if (omac1_aes_128(data->ak, buf, buflen, hdr2->mac_p)) { 159189251Ssam os_free(buf); 160189251Ssam wpabuf_free(resp); 161189251Ssam return NULL; 162189251Ssam } 163189251Ssam os_free(buf); 164189251Ssam wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_P", hdr2->rand_p, 165189251Ssam EAP_PSK_RAND_LEN); 166189251Ssam wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", hdr2->mac_p, EAP_PSK_MAC_LEN); 167189251Ssam wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_P", 168189251Ssam data->id_p, data->id_p_len); 169189251Ssam 170189251Ssam data->state = PSK_MAC_SENT; 171189251Ssam 172189251Ssam return resp; 173189251Ssam} 174189251Ssam 175189251Ssam 176189251Ssamstatic struct wpabuf * eap_psk_process_3(struct eap_psk_data *data, 177189251Ssam struct eap_method_ret *ret, 178189251Ssam const struct wpabuf *reqData) 179189251Ssam{ 180189251Ssam const struct eap_psk_hdr_3 *hdr3; 181189251Ssam struct eap_psk_hdr_4 *hdr4; 182189251Ssam struct wpabuf *resp; 183189251Ssam u8 *buf, *rpchannel, nonce[16], *decrypted; 184189251Ssam const u8 *pchannel, *tag, *msg; 185189251Ssam u8 mac[EAP_PSK_MAC_LEN]; 186189251Ssam size_t buflen, left, data_len, len, plen; 187189251Ssam int failed = 0; 188189251Ssam const u8 *pos; 189189251Ssam 190189251Ssam wpa_printf(MSG_DEBUG, "EAP-PSK: in MAC_SENT state"); 191189251Ssam 192189251Ssam pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, 193189251Ssam reqData, &len); 194189251Ssam hdr3 = (const struct eap_psk_hdr_3 *) pos; 195189251Ssam if (pos == NULL || len < sizeof(*hdr3)) { 196189251Ssam wpa_printf(MSG_INFO, "EAP-PSK: Invalid third message " 197189251Ssam "length (%lu; expected %lu or more)", 198189251Ssam (unsigned long) len, 199189251Ssam (unsigned long) sizeof(*hdr3)); 200189251Ssam ret->ignore = TRUE; 201189251Ssam return NULL; 202189251Ssam } 203189251Ssam left = len - sizeof(*hdr3); 204189251Ssam pchannel = (const u8 *) (hdr3 + 1); 205189251Ssam wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr3->flags); 206189251Ssam if (EAP_PSK_FLAGS_GET_T(hdr3->flags) != 2) { 207189251Ssam wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 2)", 208189251Ssam EAP_PSK_FLAGS_GET_T(hdr3->flags)); 209189251Ssam ret->methodState = METHOD_DONE; 210189251Ssam ret->decision = DECISION_FAIL; 211189251Ssam return NULL; 212189251Ssam } 213189251Ssam wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr3->rand_s, 214189251Ssam EAP_PSK_RAND_LEN); 215189251Ssam wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_S", hdr3->mac_s, EAP_PSK_MAC_LEN); 216189251Ssam wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL", pchannel, left); 217189251Ssam 218189251Ssam if (left < 4 + 16 + 1) { 219189251Ssam wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in " 220189251Ssam "third message (len=%lu, expected 21)", 221189251Ssam (unsigned long) left); 222189251Ssam ret->ignore = TRUE; 223189251Ssam return NULL; 224189251Ssam } 225189251Ssam 226189251Ssam /* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */ 227189251Ssam buflen = data->id_s_len + EAP_PSK_RAND_LEN; 228189251Ssam buf = os_malloc(buflen); 229189251Ssam if (buf == NULL) 230189251Ssam return NULL; 231189251Ssam os_memcpy(buf, data->id_s, data->id_s_len); 232189251Ssam os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN); 233189251Ssam if (omac1_aes_128(data->ak, buf, buflen, mac)) { 234189251Ssam os_free(buf); 235189251Ssam return NULL; 236189251Ssam } 237189251Ssam os_free(buf); 238189251Ssam if (os_memcmp(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) { 239189251Ssam wpa_printf(MSG_WARNING, "EAP-PSK: Invalid MAC_S in third " 240189251Ssam "message"); 241189251Ssam ret->methodState = METHOD_DONE; 242189251Ssam ret->decision = DECISION_FAIL; 243189251Ssam return NULL; 244189251Ssam } 245189251Ssam wpa_printf(MSG_DEBUG, "EAP-PSK: MAC_S verified successfully"); 246189251Ssam 247189251Ssam if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, 248189251Ssam data->msk, data->emsk)) { 249189251Ssam ret->methodState = METHOD_DONE; 250189251Ssam ret->decision = DECISION_FAIL; 251189251Ssam return NULL; 252189251Ssam } 253189251Ssam wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN); 254189251Ssam wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_MSK_LEN); 255189251Ssam wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: EMSK", data->emsk, EAP_EMSK_LEN); 256189251Ssam 257189251Ssam os_memset(nonce, 0, 12); 258189251Ssam os_memcpy(nonce + 12, pchannel, 4); 259189251Ssam pchannel += 4; 260189251Ssam left -= 4; 261189251Ssam 262189251Ssam tag = pchannel; 263189251Ssam pchannel += 16; 264189251Ssam left -= 16; 265189251Ssam 266189251Ssam msg = pchannel; 267189251Ssam 268189251Ssam wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - nonce", 269189251Ssam nonce, sizeof(nonce)); 270189251Ssam wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - hdr", 271189251Ssam wpabuf_head(reqData), 5); 272189251Ssam wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - cipher msg", msg, left); 273189251Ssam 274189251Ssam decrypted = os_malloc(left); 275189251Ssam if (decrypted == NULL) { 276189251Ssam ret->methodState = METHOD_DONE; 277189251Ssam ret->decision = DECISION_FAIL; 278189251Ssam return NULL; 279189251Ssam } 280189251Ssam os_memcpy(decrypted, msg, left); 281189251Ssam 282189251Ssam if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce), 283189251Ssam wpabuf_head(reqData), 284189251Ssam sizeof(struct eap_hdr) + 1 + 285189251Ssam sizeof(*hdr3) - EAP_PSK_MAC_LEN, decrypted, 286189251Ssam left, tag)) { 287189251Ssam wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed"); 288189251Ssam os_free(decrypted); 289189251Ssam return NULL; 290189251Ssam } 291189251Ssam wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message", 292189251Ssam decrypted, left); 293189251Ssam 294189251Ssam /* Verify R flag */ 295189251Ssam switch (decrypted[0] >> 6) { 296189251Ssam case EAP_PSK_R_FLAG_CONT: 297189251Ssam wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported"); 298189251Ssam failed = 1; 299189251Ssam break; 300189251Ssam case EAP_PSK_R_FLAG_DONE_SUCCESS: 301189251Ssam wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS"); 302189251Ssam break; 303189251Ssam case EAP_PSK_R_FLAG_DONE_FAILURE: 304189251Ssam wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_FAILURE"); 305189251Ssam wpa_printf(MSG_INFO, "EAP-PSK: Authentication server rejected " 306189251Ssam "authentication"); 307189251Ssam failed = 1; 308189251Ssam break; 309189251Ssam } 310189251Ssam 311189251Ssam data_len = 1; 312189251Ssam if ((decrypted[0] & EAP_PSK_E_FLAG) && left > 1) 313189251Ssam data_len++; 314189251Ssam plen = sizeof(*hdr4) + 4 + 16 + data_len; 315189251Ssam resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, plen, 316189251Ssam EAP_CODE_RESPONSE, eap_get_id(reqData)); 317189251Ssam if (resp == NULL) { 318189251Ssam os_free(decrypted); 319189251Ssam return NULL; 320189251Ssam } 321189251Ssam hdr4 = wpabuf_put(resp, sizeof(*hdr4)); 322189251Ssam hdr4->flags = EAP_PSK_FLAGS_SET_T(3); /* T=3 */ 323189251Ssam os_memcpy(hdr4->rand_s, hdr3->rand_s, EAP_PSK_RAND_LEN); 324189251Ssam rpchannel = wpabuf_put(resp, 4 + 16 + data_len); 325189251Ssam 326189251Ssam /* nonce++ */ 327189251Ssam inc_byte_array(nonce, sizeof(nonce)); 328189251Ssam os_memcpy(rpchannel, nonce + 12, 4); 329189251Ssam 330189251Ssam if (decrypted[0] & EAP_PSK_E_FLAG) { 331189251Ssam wpa_printf(MSG_DEBUG, "EAP-PSK: Unsupported E (Ext) flag"); 332189251Ssam failed = 1; 333189251Ssam rpchannel[4 + 16] = (EAP_PSK_R_FLAG_DONE_FAILURE << 6) | 334189251Ssam EAP_PSK_E_FLAG; 335189251Ssam if (left > 1) { 336189251Ssam /* Add empty EXT_Payload with same EXT_Type */ 337189251Ssam rpchannel[4 + 16 + 1] = decrypted[1]; 338189251Ssam } 339189251Ssam } else if (failed) 340189251Ssam rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_FAILURE << 6; 341189251Ssam else 342189251Ssam rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6; 343189251Ssam 344189251Ssam wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (plaintext)", 345189251Ssam rpchannel + 4 + 16, data_len); 346189251Ssam if (aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce), 347189251Ssam wpabuf_head(resp), 348189251Ssam sizeof(struct eap_hdr) + 1 + sizeof(*hdr4), 349189251Ssam rpchannel + 4 + 16, data_len, rpchannel + 4)) { 350189251Ssam os_free(decrypted); 351189251Ssam wpabuf_free(resp); 352189251Ssam return NULL; 353189251Ssam } 354189251Ssam wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (PCHANNEL)", 355189251Ssam rpchannel, 4 + 16 + data_len); 356189251Ssam 357189251Ssam wpa_printf(MSG_DEBUG, "EAP-PSK: Completed %ssuccessfully", 358189251Ssam failed ? "un" : ""); 359189251Ssam data->state = PSK_DONE; 360189251Ssam ret->methodState = METHOD_DONE; 361189251Ssam ret->decision = failed ? DECISION_FAIL : DECISION_UNCOND_SUCC; 362189251Ssam 363189251Ssam os_free(decrypted); 364189251Ssam 365189251Ssam return resp; 366189251Ssam} 367189251Ssam 368189251Ssam 369189251Ssamstatic struct wpabuf * eap_psk_process(struct eap_sm *sm, void *priv, 370189251Ssam struct eap_method_ret *ret, 371189251Ssam const struct wpabuf *reqData) 372189251Ssam{ 373189251Ssam struct eap_psk_data *data = priv; 374189251Ssam const u8 *pos; 375189251Ssam struct wpabuf *resp = NULL; 376189251Ssam size_t len; 377189251Ssam 378189251Ssam pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len); 379189251Ssam if (pos == NULL) { 380189251Ssam ret->ignore = TRUE; 381189251Ssam return NULL; 382189251Ssam } 383189251Ssam 384189251Ssam ret->ignore = FALSE; 385189251Ssam ret->methodState = METHOD_MAY_CONT; 386189251Ssam ret->decision = DECISION_FAIL; 387189251Ssam ret->allowNotifications = TRUE; 388189251Ssam 389189251Ssam switch (data->state) { 390189251Ssam case PSK_INIT: 391189251Ssam resp = eap_psk_process_1(data, ret, reqData); 392189251Ssam break; 393189251Ssam case PSK_MAC_SENT: 394189251Ssam resp = eap_psk_process_3(data, ret, reqData); 395189251Ssam break; 396189251Ssam case PSK_DONE: 397189251Ssam wpa_printf(MSG_DEBUG, "EAP-PSK: in DONE state - ignore " 398189251Ssam "unexpected message"); 399189251Ssam ret->ignore = TRUE; 400189251Ssam return NULL; 401189251Ssam } 402189251Ssam 403189251Ssam if (ret->methodState == METHOD_DONE) { 404189251Ssam ret->allowNotifications = FALSE; 405189251Ssam } 406189251Ssam 407189251Ssam return resp; 408189251Ssam} 409189251Ssam 410189251Ssam 411189251Ssamstatic Boolean eap_psk_isKeyAvailable(struct eap_sm *sm, void *priv) 412189251Ssam{ 413189251Ssam struct eap_psk_data *data = priv; 414189251Ssam return data->state == PSK_DONE; 415189251Ssam} 416189251Ssam 417189251Ssam 418189251Ssamstatic u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len) 419189251Ssam{ 420189251Ssam struct eap_psk_data *data = priv; 421189251Ssam u8 *key; 422189251Ssam 423189251Ssam if (data->state != PSK_DONE) 424189251Ssam return NULL; 425189251Ssam 426189251Ssam key = os_malloc(EAP_MSK_LEN); 427189251Ssam if (key == NULL) 428189251Ssam return NULL; 429189251Ssam 430189251Ssam *len = EAP_MSK_LEN; 431189251Ssam os_memcpy(key, data->msk, EAP_MSK_LEN); 432189251Ssam 433189251Ssam return key; 434189251Ssam} 435189251Ssam 436189251Ssam 437189251Ssamstatic u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 438189251Ssam{ 439189251Ssam struct eap_psk_data *data = priv; 440189251Ssam u8 *key; 441189251Ssam 442189251Ssam if (data->state != PSK_DONE) 443189251Ssam return NULL; 444189251Ssam 445189251Ssam key = os_malloc(EAP_EMSK_LEN); 446189251Ssam if (key == NULL) 447189251Ssam return NULL; 448189251Ssam 449189251Ssam *len = EAP_EMSK_LEN; 450189251Ssam os_memcpy(key, data->emsk, EAP_EMSK_LEN); 451189251Ssam 452189251Ssam return key; 453189251Ssam} 454189251Ssam 455189251Ssam 456189251Ssamint eap_peer_psk_register(void) 457189251Ssam{ 458189251Ssam struct eap_method *eap; 459189251Ssam int ret; 460189251Ssam 461189251Ssam eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 462189251Ssam EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK"); 463189251Ssam if (eap == NULL) 464189251Ssam return -1; 465189251Ssam 466189251Ssam eap->init = eap_psk_init; 467189251Ssam eap->deinit = eap_psk_deinit; 468189251Ssam eap->process = eap_psk_process; 469189251Ssam eap->isKeyAvailable = eap_psk_isKeyAvailable; 470189251Ssam eap->getKey = eap_psk_getKey; 471189251Ssam eap->get_emsk = eap_psk_get_emsk; 472189251Ssam 473189251Ssam ret = eap_peer_method_register(eap); 474189251Ssam if (ret) 475189251Ssam eap_peer_method_free(eap); 476189251Ssam return ret; 477189251Ssam} 478