1189251Ssam/* 2189251Ssam * EAP peer method: EAP-SAKE (RFC 4763) 3346981Scy * Copyright (c) 2006-2019, 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 9189251Ssam#include "includes.h" 10189251Ssam 11189251Ssam#include "common.h" 12252726Srpaulo#include "crypto/random.h" 13189251Ssam#include "eap_peer/eap_i.h" 14189251Ssam#include "eap_common/eap_sake_common.h" 15189251Ssam 16189251Ssamstruct eap_sake_data { 17189251Ssam enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state; 18189251Ssam u8 root_secret_a[EAP_SAKE_ROOT_SECRET_LEN]; 19189251Ssam u8 root_secret_b[EAP_SAKE_ROOT_SECRET_LEN]; 20189251Ssam u8 rand_s[EAP_SAKE_RAND_LEN]; 21189251Ssam u8 rand_p[EAP_SAKE_RAND_LEN]; 22189251Ssam struct { 23189251Ssam u8 auth[EAP_SAKE_TEK_AUTH_LEN]; 24189251Ssam u8 cipher[EAP_SAKE_TEK_CIPHER_LEN]; 25189251Ssam } tek; 26189251Ssam u8 msk[EAP_MSK_LEN]; 27189251Ssam u8 emsk[EAP_EMSK_LEN]; 28189251Ssam u8 session_id; 29189251Ssam int session_id_set; 30189251Ssam u8 *peerid; 31189251Ssam size_t peerid_len; 32189251Ssam u8 *serverid; 33189251Ssam size_t serverid_len; 34189251Ssam}; 35189251Ssam 36189251Ssam 37189251Ssamstatic const char * eap_sake_state_txt(int state) 38189251Ssam{ 39189251Ssam switch (state) { 40189251Ssam case IDENTITY: 41189251Ssam return "IDENTITY"; 42189251Ssam case CHALLENGE: 43189251Ssam return "CHALLENGE"; 44189251Ssam case CONFIRM: 45189251Ssam return "CONFIRM"; 46189251Ssam case SUCCESS: 47189251Ssam return "SUCCESS"; 48189251Ssam case FAILURE: 49189251Ssam return "FAILURE"; 50189251Ssam default: 51189251Ssam return "?"; 52189251Ssam } 53189251Ssam} 54189251Ssam 55189251Ssam 56189251Ssamstatic void eap_sake_state(struct eap_sake_data *data, int state) 57189251Ssam{ 58189251Ssam wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s", 59189251Ssam eap_sake_state_txt(data->state), 60189251Ssam eap_sake_state_txt(state)); 61189251Ssam data->state = state; 62189251Ssam} 63189251Ssam 64189251Ssam 65189251Ssamstatic void eap_sake_deinit(struct eap_sm *sm, void *priv); 66189251Ssam 67189251Ssam 68189251Ssamstatic void * eap_sake_init(struct eap_sm *sm) 69189251Ssam{ 70189251Ssam struct eap_sake_data *data; 71189251Ssam const u8 *identity, *password; 72189251Ssam size_t identity_len, password_len; 73189251Ssam 74189251Ssam password = eap_get_config_password(sm, &password_len); 75189251Ssam if (!password || password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) { 76189251Ssam wpa_printf(MSG_INFO, "EAP-SAKE: No key of correct length " 77189251Ssam "configured"); 78189251Ssam return NULL; 79189251Ssam } 80189251Ssam 81189251Ssam data = os_zalloc(sizeof(*data)); 82189251Ssam if (data == NULL) 83189251Ssam return NULL; 84189251Ssam data->state = IDENTITY; 85189251Ssam 86189251Ssam identity = eap_get_config_identity(sm, &identity_len); 87189251Ssam if (identity) { 88346981Scy data->peerid = os_memdup(identity, identity_len); 89189251Ssam if (data->peerid == NULL) { 90189251Ssam eap_sake_deinit(sm, data); 91189251Ssam return NULL; 92189251Ssam } 93189251Ssam data->peerid_len = identity_len; 94189251Ssam } 95189251Ssam 96189251Ssam os_memcpy(data->root_secret_a, password, EAP_SAKE_ROOT_SECRET_LEN); 97189251Ssam os_memcpy(data->root_secret_b, 98189251Ssam password + EAP_SAKE_ROOT_SECRET_LEN, 99189251Ssam EAP_SAKE_ROOT_SECRET_LEN); 100189251Ssam 101189251Ssam return data; 102189251Ssam} 103189251Ssam 104189251Ssam 105189251Ssamstatic void eap_sake_deinit(struct eap_sm *sm, void *priv) 106189251Ssam{ 107189251Ssam struct eap_sake_data *data = priv; 108189251Ssam os_free(data->serverid); 109189251Ssam os_free(data->peerid); 110281806Srpaulo bin_clear_free(data, sizeof(*data)); 111189251Ssam} 112189251Ssam 113189251Ssam 114189251Ssamstatic struct wpabuf * eap_sake_build_msg(struct eap_sake_data *data, 115189251Ssam int id, size_t length, u8 subtype) 116189251Ssam{ 117189251Ssam struct eap_sake_hdr *sake; 118189251Ssam struct wpabuf *msg; 119189251Ssam size_t plen; 120189251Ssam 121189251Ssam plen = length + sizeof(struct eap_sake_hdr); 122189251Ssam 123189251Ssam msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_SAKE, plen, 124189251Ssam EAP_CODE_RESPONSE, id); 125189251Ssam if (msg == NULL) { 126189251Ssam wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory " 127189251Ssam "request"); 128189251Ssam return NULL; 129189251Ssam } 130189251Ssam 131189251Ssam sake = wpabuf_put(msg, sizeof(*sake)); 132189251Ssam sake->version = EAP_SAKE_VERSION; 133189251Ssam sake->session_id = data->session_id; 134189251Ssam sake->subtype = subtype; 135189251Ssam 136189251Ssam return msg; 137189251Ssam} 138189251Ssam 139189251Ssam 140189251Ssamstatic struct wpabuf * eap_sake_process_identity(struct eap_sm *sm, 141189251Ssam struct eap_sake_data *data, 142189251Ssam struct eap_method_ret *ret, 143289549Srpaulo u8 id, 144189251Ssam const u8 *payload, 145189251Ssam size_t payload_len) 146189251Ssam{ 147189251Ssam struct eap_sake_parse_attr attr; 148189251Ssam struct wpabuf *resp; 149189251Ssam 150189251Ssam if (data->state != IDENTITY) { 151189251Ssam ret->ignore = TRUE; 152189251Ssam return NULL; 153189251Ssam } 154189251Ssam 155189251Ssam wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Identity"); 156189251Ssam 157189251Ssam if (eap_sake_parse_attributes(payload, payload_len, &attr)) 158189251Ssam return NULL; 159189251Ssam 160189251Ssam if (!attr.perm_id_req && !attr.any_id_req) { 161189251Ssam wpa_printf(MSG_INFO, "EAP-SAKE: No AT_PERM_ID_REQ or " 162189251Ssam "AT_ANY_ID_REQ in Request/Identity"); 163189251Ssam return NULL; 164189251Ssam } 165189251Ssam 166189251Ssam wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Identity"); 167189251Ssam 168289549Srpaulo resp = eap_sake_build_msg(data, id, 2 + data->peerid_len, 169189251Ssam EAP_SAKE_SUBTYPE_IDENTITY); 170189251Ssam if (resp == NULL) 171189251Ssam return NULL; 172189251Ssam 173189251Ssam wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID"); 174189251Ssam eap_sake_add_attr(resp, EAP_SAKE_AT_PEERID, 175189251Ssam data->peerid, data->peerid_len); 176189251Ssam 177189251Ssam eap_sake_state(data, CHALLENGE); 178189251Ssam 179189251Ssam return resp; 180189251Ssam} 181189251Ssam 182189251Ssam 183189251Ssamstatic struct wpabuf * eap_sake_process_challenge(struct eap_sm *sm, 184189251Ssam struct eap_sake_data *data, 185189251Ssam struct eap_method_ret *ret, 186289549Srpaulo u8 id, 187189251Ssam const u8 *payload, 188189251Ssam size_t payload_len) 189189251Ssam{ 190189251Ssam struct eap_sake_parse_attr attr; 191189251Ssam struct wpabuf *resp; 192189251Ssam u8 *rpos; 193189251Ssam size_t rlen; 194189251Ssam 195189251Ssam if (data->state != IDENTITY && data->state != CHALLENGE) { 196189251Ssam wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge received " 197189251Ssam "in unexpected state (%d)", data->state); 198189251Ssam ret->ignore = TRUE; 199189251Ssam return NULL; 200189251Ssam } 201189251Ssam if (data->state == IDENTITY) 202189251Ssam eap_sake_state(data, CHALLENGE); 203189251Ssam 204189251Ssam wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Challenge"); 205189251Ssam 206189251Ssam if (eap_sake_parse_attributes(payload, payload_len, &attr)) 207189251Ssam return NULL; 208189251Ssam 209189251Ssam if (!attr.rand_s) { 210189251Ssam wpa_printf(MSG_INFO, "EAP-SAKE: Request/Challenge did not " 211189251Ssam "include AT_RAND_S"); 212189251Ssam return NULL; 213189251Ssam } 214189251Ssam 215189251Ssam os_memcpy(data->rand_s, attr.rand_s, EAP_SAKE_RAND_LEN); 216189251Ssam wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)", 217189251Ssam data->rand_s, EAP_SAKE_RAND_LEN); 218189251Ssam 219252726Srpaulo if (random_get_bytes(data->rand_p, EAP_SAKE_RAND_LEN)) { 220189251Ssam wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data"); 221189251Ssam return NULL; 222189251Ssam } 223189251Ssam wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_P (peer rand)", 224189251Ssam data->rand_p, EAP_SAKE_RAND_LEN); 225189251Ssam 226189251Ssam os_free(data->serverid); 227189251Ssam data->serverid = NULL; 228189251Ssam data->serverid_len = 0; 229189251Ssam if (attr.serverid) { 230189251Ssam wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-SAKE: SERVERID", 231189251Ssam attr.serverid, attr.serverid_len); 232346981Scy data->serverid = os_memdup(attr.serverid, attr.serverid_len); 233189251Ssam if (data->serverid == NULL) 234189251Ssam return NULL; 235189251Ssam data->serverid_len = attr.serverid_len; 236189251Ssam } 237189251Ssam 238346981Scy if (eap_sake_derive_keys(data->root_secret_a, data->root_secret_b, 239346981Scy data->rand_s, data->rand_p, 240346981Scy (u8 *) &data->tek, data->msk, 241346981Scy data->emsk) < 0) { 242346981Scy wpa_printf(MSG_INFO, "EAP-SAKE: Failed to derive keys"); 243346981Scy return NULL; 244346981Scy } 245189251Ssam 246189251Ssam wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Challenge"); 247189251Ssam 248189251Ssam rlen = 2 + EAP_SAKE_RAND_LEN + 2 + EAP_SAKE_MIC_LEN; 249189251Ssam if (data->peerid) 250189251Ssam rlen += 2 + data->peerid_len; 251289549Srpaulo resp = eap_sake_build_msg(data, id, rlen, EAP_SAKE_SUBTYPE_CHALLENGE); 252189251Ssam if (resp == NULL) 253189251Ssam return NULL; 254189251Ssam 255189251Ssam wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_P"); 256189251Ssam eap_sake_add_attr(resp, EAP_SAKE_AT_RAND_P, 257189251Ssam data->rand_p, EAP_SAKE_RAND_LEN); 258189251Ssam 259189251Ssam if (data->peerid) { 260189251Ssam wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID"); 261189251Ssam eap_sake_add_attr(resp, EAP_SAKE_AT_PEERID, 262189251Ssam data->peerid, data->peerid_len); 263189251Ssam } 264189251Ssam 265189251Ssam wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P"); 266189251Ssam wpabuf_put_u8(resp, EAP_SAKE_AT_MIC_P); 267189251Ssam wpabuf_put_u8(resp, 2 + EAP_SAKE_MIC_LEN); 268189251Ssam rpos = wpabuf_put(resp, EAP_SAKE_MIC_LEN); 269189251Ssam if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p, 270189251Ssam data->serverid, data->serverid_len, 271189251Ssam data->peerid, data->peerid_len, 1, 272189251Ssam wpabuf_head(resp), wpabuf_len(resp), rpos, 273189251Ssam rpos)) { 274189251Ssam wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC"); 275189251Ssam wpabuf_free(resp); 276189251Ssam return NULL; 277189251Ssam } 278189251Ssam 279189251Ssam eap_sake_state(data, CONFIRM); 280189251Ssam 281189251Ssam return resp; 282189251Ssam} 283189251Ssam 284189251Ssam 285189251Ssamstatic struct wpabuf * eap_sake_process_confirm(struct eap_sm *sm, 286189251Ssam struct eap_sake_data *data, 287189251Ssam struct eap_method_ret *ret, 288289549Srpaulo u8 id, 289189251Ssam const struct wpabuf *reqData, 290189251Ssam const u8 *payload, 291189251Ssam size_t payload_len) 292189251Ssam{ 293189251Ssam struct eap_sake_parse_attr attr; 294189251Ssam u8 mic_s[EAP_SAKE_MIC_LEN]; 295189251Ssam struct wpabuf *resp; 296189251Ssam u8 *rpos; 297189251Ssam 298189251Ssam if (data->state != CONFIRM) { 299189251Ssam ret->ignore = TRUE; 300189251Ssam return NULL; 301189251Ssam } 302189251Ssam 303189251Ssam wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Confirm"); 304189251Ssam 305189251Ssam if (eap_sake_parse_attributes(payload, payload_len, &attr)) 306189251Ssam return NULL; 307189251Ssam 308189251Ssam if (!attr.mic_s) { 309189251Ssam wpa_printf(MSG_INFO, "EAP-SAKE: Request/Confirm did not " 310189251Ssam "include AT_MIC_S"); 311189251Ssam return NULL; 312189251Ssam } 313189251Ssam 314337817Scy if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p, 315337817Scy data->serverid, data->serverid_len, 316337817Scy data->peerid, data->peerid_len, 0, 317337817Scy wpabuf_head(reqData), wpabuf_len(reqData), 318337817Scy attr.mic_s, mic_s)) { 319337817Scy wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC"); 320337817Scy eap_sake_state(data, FAILURE); 321337817Scy ret->methodState = METHOD_DONE; 322337817Scy ret->decision = DECISION_FAIL; 323337817Scy ret->allowNotifications = FALSE; 324337817Scy wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Auth-Reject"); 325337817Scy return eap_sake_build_msg(data, id, 0, 326337817Scy EAP_SAKE_SUBTYPE_AUTH_REJECT); 327337817Scy } 328281806Srpaulo if (os_memcmp_const(attr.mic_s, mic_s, EAP_SAKE_MIC_LEN) != 0) { 329189251Ssam wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_S"); 330189251Ssam eap_sake_state(data, FAILURE); 331189251Ssam ret->methodState = METHOD_DONE; 332189251Ssam ret->decision = DECISION_FAIL; 333189251Ssam ret->allowNotifications = FALSE; 334189251Ssam wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending " 335189251Ssam "Response/Auth-Reject"); 336289549Srpaulo return eap_sake_build_msg(data, id, 0, 337189251Ssam EAP_SAKE_SUBTYPE_AUTH_REJECT); 338189251Ssam } 339189251Ssam 340189251Ssam wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Confirm"); 341189251Ssam 342289549Srpaulo resp = eap_sake_build_msg(data, id, 2 + EAP_SAKE_MIC_LEN, 343189251Ssam EAP_SAKE_SUBTYPE_CONFIRM); 344189251Ssam if (resp == NULL) 345189251Ssam return NULL; 346189251Ssam 347189251Ssam wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P"); 348189251Ssam wpabuf_put_u8(resp, EAP_SAKE_AT_MIC_P); 349189251Ssam wpabuf_put_u8(resp, 2 + EAP_SAKE_MIC_LEN); 350189251Ssam rpos = wpabuf_put(resp, EAP_SAKE_MIC_LEN); 351189251Ssam if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p, 352189251Ssam data->serverid, data->serverid_len, 353189251Ssam data->peerid, data->peerid_len, 1, 354189251Ssam wpabuf_head(resp), wpabuf_len(resp), rpos, 355189251Ssam rpos)) { 356189251Ssam wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC"); 357189251Ssam wpabuf_free(resp); 358189251Ssam return NULL; 359189251Ssam } 360189251Ssam 361189251Ssam eap_sake_state(data, SUCCESS); 362189251Ssam ret->methodState = METHOD_DONE; 363189251Ssam ret->decision = DECISION_UNCOND_SUCC; 364189251Ssam ret->allowNotifications = FALSE; 365189251Ssam 366189251Ssam return resp; 367189251Ssam} 368189251Ssam 369189251Ssam 370189251Ssamstatic struct wpabuf * eap_sake_process(struct eap_sm *sm, void *priv, 371189251Ssam struct eap_method_ret *ret, 372189251Ssam const struct wpabuf *reqData) 373189251Ssam{ 374189251Ssam struct eap_sake_data *data = priv; 375189251Ssam const struct eap_sake_hdr *req; 376189251Ssam struct wpabuf *resp; 377189251Ssam const u8 *pos, *end; 378189251Ssam size_t len; 379289549Srpaulo u8 subtype, session_id, id; 380189251Ssam 381189251Ssam pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, reqData, &len); 382189251Ssam if (pos == NULL || len < sizeof(struct eap_sake_hdr)) { 383189251Ssam ret->ignore = TRUE; 384189251Ssam return NULL; 385189251Ssam } 386189251Ssam 387189251Ssam req = (const struct eap_sake_hdr *) pos; 388189251Ssam end = pos + len; 389289549Srpaulo id = eap_get_id(reqData); 390189251Ssam subtype = req->subtype; 391189251Ssam session_id = req->session_id; 392189251Ssam pos = (const u8 *) (req + 1); 393189251Ssam 394189251Ssam wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype %d " 395189251Ssam "session_id %d", subtype, session_id); 396189251Ssam wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes", 397189251Ssam pos, end - pos); 398189251Ssam 399189251Ssam if (data->session_id_set && data->session_id != session_id) { 400189251Ssam wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)", 401189251Ssam session_id, data->session_id); 402189251Ssam ret->ignore = TRUE; 403189251Ssam return NULL; 404189251Ssam } 405189251Ssam data->session_id = session_id; 406189251Ssam data->session_id_set = 1; 407189251Ssam 408189251Ssam ret->ignore = FALSE; 409189251Ssam ret->methodState = METHOD_MAY_CONT; 410189251Ssam ret->decision = DECISION_FAIL; 411189251Ssam ret->allowNotifications = TRUE; 412189251Ssam 413189251Ssam switch (subtype) { 414189251Ssam case EAP_SAKE_SUBTYPE_IDENTITY: 415289549Srpaulo resp = eap_sake_process_identity(sm, data, ret, id, 416189251Ssam pos, end - pos); 417189251Ssam break; 418189251Ssam case EAP_SAKE_SUBTYPE_CHALLENGE: 419289549Srpaulo resp = eap_sake_process_challenge(sm, data, ret, id, 420189251Ssam pos, end - pos); 421189251Ssam break; 422189251Ssam case EAP_SAKE_SUBTYPE_CONFIRM: 423289549Srpaulo resp = eap_sake_process_confirm(sm, data, ret, id, reqData, 424189251Ssam pos, end - pos); 425189251Ssam break; 426189251Ssam default: 427189251Ssam wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring message with " 428189251Ssam "unknown subtype %d", subtype); 429189251Ssam ret->ignore = TRUE; 430189251Ssam return NULL; 431189251Ssam } 432189251Ssam 433189251Ssam if (ret->methodState == METHOD_DONE) 434189251Ssam ret->allowNotifications = FALSE; 435189251Ssam 436189251Ssam return resp; 437189251Ssam} 438189251Ssam 439189251Ssam 440189251Ssamstatic Boolean eap_sake_isKeyAvailable(struct eap_sm *sm, void *priv) 441189251Ssam{ 442189251Ssam struct eap_sake_data *data = priv; 443189251Ssam return data->state == SUCCESS; 444189251Ssam} 445189251Ssam 446189251Ssam 447189251Ssamstatic u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len) 448189251Ssam{ 449189251Ssam struct eap_sake_data *data = priv; 450189251Ssam u8 *key; 451189251Ssam 452189251Ssam if (data->state != SUCCESS) 453189251Ssam return NULL; 454189251Ssam 455346981Scy key = os_memdup(data->msk, EAP_MSK_LEN); 456189251Ssam if (key == NULL) 457189251Ssam return NULL; 458189251Ssam *len = EAP_MSK_LEN; 459189251Ssam 460189251Ssam return key; 461189251Ssam} 462189251Ssam 463189251Ssam 464281806Srpaulostatic u8 * eap_sake_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 465281806Srpaulo{ 466281806Srpaulo struct eap_sake_data *data = priv; 467281806Srpaulo u8 *id; 468281806Srpaulo 469281806Srpaulo if (data->state != SUCCESS) 470281806Srpaulo return NULL; 471281806Srpaulo 472281806Srpaulo *len = 1 + 2 * EAP_SAKE_RAND_LEN; 473281806Srpaulo id = os_malloc(*len); 474281806Srpaulo if (id == NULL) 475281806Srpaulo return NULL; 476281806Srpaulo 477281806Srpaulo id[0] = EAP_TYPE_SAKE; 478281806Srpaulo os_memcpy(id + 1, data->rand_s, EAP_SAKE_RAND_LEN); 479281806Srpaulo os_memcpy(id + 1 + EAP_SAKE_RAND_LEN, data->rand_s, EAP_SAKE_RAND_LEN); 480281806Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Derived Session-Id", id, *len); 481281806Srpaulo 482281806Srpaulo return id; 483281806Srpaulo} 484281806Srpaulo 485281806Srpaulo 486189251Ssamstatic u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 487189251Ssam{ 488189251Ssam struct eap_sake_data *data = priv; 489189251Ssam u8 *key; 490189251Ssam 491189251Ssam if (data->state != SUCCESS) 492189251Ssam return NULL; 493189251Ssam 494346981Scy key = os_memdup(data->emsk, EAP_EMSK_LEN); 495189251Ssam if (key == NULL) 496189251Ssam return NULL; 497189251Ssam *len = EAP_EMSK_LEN; 498189251Ssam 499189251Ssam return key; 500189251Ssam} 501189251Ssam 502189251Ssam 503189251Ssamint eap_peer_sake_register(void) 504189251Ssam{ 505189251Ssam struct eap_method *eap; 506189251Ssam 507189251Ssam eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 508189251Ssam EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE"); 509189251Ssam if (eap == NULL) 510189251Ssam return -1; 511189251Ssam 512189251Ssam eap->init = eap_sake_init; 513189251Ssam eap->deinit = eap_sake_deinit; 514189251Ssam eap->process = eap_sake_process; 515189251Ssam eap->isKeyAvailable = eap_sake_isKeyAvailable; 516189251Ssam eap->getKey = eap_sake_getKey; 517281806Srpaulo eap->getSessionId = eap_sake_get_session_id; 518189251Ssam eap->get_emsk = eap_sake_get_emsk; 519189251Ssam 520337817Scy return eap_peer_method_register(eap); 521189251Ssam} 522