1214501Srpaulo/* 2214501Srpaulo * EAP-IKEv2 server (RFC 5106) 3214501Srpaulo * Copyright (c) 2007, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7214501Srpaulo */ 8214501Srpaulo 9214501Srpaulo#include "includes.h" 10214501Srpaulo 11214501Srpaulo#include "common.h" 12214501Srpaulo#include "eap_i.h" 13214501Srpaulo#include "eap_common/eap_ikev2_common.h" 14214501Srpaulo#include "ikev2.h" 15214501Srpaulo 16214501Srpaulo 17214501Srpaulostruct eap_ikev2_data { 18214501Srpaulo struct ikev2_initiator_data ikev2; 19214501Srpaulo enum { MSG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state; 20214501Srpaulo struct wpabuf *in_buf; 21214501Srpaulo struct wpabuf *out_buf; 22214501Srpaulo size_t out_used; 23214501Srpaulo size_t fragment_size; 24214501Srpaulo int keys_ready; 25214501Srpaulo u8 keymat[EAP_MSK_LEN + EAP_EMSK_LEN]; 26214501Srpaulo int keymat_ok; 27214501Srpaulo}; 28214501Srpaulo 29214501Srpaulo 30214501Srpaulostatic const u8 * eap_ikev2_get_shared_secret(void *ctx, const u8 *IDr, 31214501Srpaulo size_t IDr_len, 32214501Srpaulo size_t *secret_len) 33214501Srpaulo{ 34214501Srpaulo struct eap_sm *sm = ctx; 35214501Srpaulo 36214501Srpaulo if (IDr == NULL) { 37214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: No IDr received - default " 38214501Srpaulo "to user identity from EAP-Identity"); 39214501Srpaulo IDr = sm->identity; 40214501Srpaulo IDr_len = sm->identity_len; 41214501Srpaulo } 42214501Srpaulo 43214501Srpaulo if (eap_user_get(sm, IDr, IDr_len, 0) < 0 || sm->user == NULL || 44214501Srpaulo sm->user->password == NULL) { 45214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: No user entry found"); 46214501Srpaulo return NULL; 47214501Srpaulo } 48214501Srpaulo 49214501Srpaulo *secret_len = sm->user->password_len; 50214501Srpaulo return sm->user->password; 51214501Srpaulo} 52214501Srpaulo 53214501Srpaulo 54214501Srpaulostatic const char * eap_ikev2_state_txt(int state) 55214501Srpaulo{ 56214501Srpaulo switch (state) { 57214501Srpaulo case MSG: 58214501Srpaulo return "MSG"; 59214501Srpaulo case FRAG_ACK: 60214501Srpaulo return "FRAG_ACK"; 61214501Srpaulo case WAIT_FRAG_ACK: 62214501Srpaulo return "WAIT_FRAG_ACK"; 63214501Srpaulo case DONE: 64214501Srpaulo return "DONE"; 65214501Srpaulo case FAIL: 66214501Srpaulo return "FAIL"; 67214501Srpaulo default: 68214501Srpaulo return "?"; 69214501Srpaulo } 70214501Srpaulo} 71214501Srpaulo 72214501Srpaulo 73214501Srpaulostatic void eap_ikev2_state(struct eap_ikev2_data *data, int state) 74214501Srpaulo{ 75214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: %s -> %s", 76214501Srpaulo eap_ikev2_state_txt(data->state), 77214501Srpaulo eap_ikev2_state_txt(state)); 78214501Srpaulo data->state = state; 79214501Srpaulo} 80214501Srpaulo 81214501Srpaulo 82214501Srpaulostatic void * eap_ikev2_init(struct eap_sm *sm) 83214501Srpaulo{ 84214501Srpaulo struct eap_ikev2_data *data; 85214501Srpaulo 86214501Srpaulo data = os_zalloc(sizeof(*data)); 87214501Srpaulo if (data == NULL) 88214501Srpaulo return NULL; 89214501Srpaulo data->state = MSG; 90252726Srpaulo data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size : 91252726Srpaulo IKEV2_FRAGMENT_SIZE; 92214501Srpaulo data->ikev2.state = SA_INIT; 93214501Srpaulo data->ikev2.peer_auth = PEER_AUTH_SECRET; 94214501Srpaulo data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2"); 95214501Srpaulo if (data->ikev2.key_pad == NULL) 96214501Srpaulo goto failed; 97214501Srpaulo data->ikev2.key_pad_len = 21; 98214501Srpaulo 99214501Srpaulo /* TODO: make proposals configurable */ 100214501Srpaulo data->ikev2.proposal.proposal_num = 1; 101214501Srpaulo data->ikev2.proposal.integ = AUTH_HMAC_SHA1_96; 102214501Srpaulo data->ikev2.proposal.prf = PRF_HMAC_SHA1; 103214501Srpaulo data->ikev2.proposal.encr = ENCR_AES_CBC; 104214501Srpaulo data->ikev2.proposal.dh = DH_GROUP2_1024BIT_MODP; 105214501Srpaulo 106214501Srpaulo data->ikev2.IDi = (u8 *) os_strdup("hostapd"); 107214501Srpaulo data->ikev2.IDi_len = 7; 108214501Srpaulo 109214501Srpaulo data->ikev2.get_shared_secret = eap_ikev2_get_shared_secret; 110214501Srpaulo data->ikev2.cb_ctx = sm; 111214501Srpaulo 112214501Srpaulo return data; 113214501Srpaulo 114214501Srpaulofailed: 115214501Srpaulo ikev2_initiator_deinit(&data->ikev2); 116214501Srpaulo os_free(data); 117214501Srpaulo return NULL; 118214501Srpaulo} 119214501Srpaulo 120214501Srpaulo 121214501Srpaulostatic void eap_ikev2_reset(struct eap_sm *sm, void *priv) 122214501Srpaulo{ 123214501Srpaulo struct eap_ikev2_data *data = priv; 124214501Srpaulo wpabuf_free(data->in_buf); 125214501Srpaulo wpabuf_free(data->out_buf); 126214501Srpaulo ikev2_initiator_deinit(&data->ikev2); 127214501Srpaulo os_free(data); 128214501Srpaulo} 129214501Srpaulo 130214501Srpaulo 131214501Srpaulostatic struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data, u8 id) 132214501Srpaulo{ 133214501Srpaulo struct wpabuf *req; 134214501Srpaulo u8 flags; 135214501Srpaulo size_t send_len, plen, icv_len = 0; 136214501Srpaulo 137214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Generating Request"); 138214501Srpaulo 139214501Srpaulo flags = 0; 140214501Srpaulo send_len = wpabuf_len(data->out_buf) - data->out_used; 141214501Srpaulo if (1 + send_len > data->fragment_size) { 142214501Srpaulo send_len = data->fragment_size - 1; 143214501Srpaulo flags |= IKEV2_FLAGS_MORE_FRAGMENTS; 144214501Srpaulo if (data->out_used == 0) { 145214501Srpaulo flags |= IKEV2_FLAGS_LENGTH_INCLUDED; 146214501Srpaulo send_len -= 4; 147214501Srpaulo } 148214501Srpaulo } 149214501Srpaulo 150214501Srpaulo plen = 1 + send_len; 151214501Srpaulo if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) 152214501Srpaulo plen += 4; 153214501Srpaulo if (data->keys_ready) { 154214501Srpaulo const struct ikev2_integ_alg *integ; 155214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Add Integrity Checksum " 156214501Srpaulo "Data"); 157214501Srpaulo flags |= IKEV2_FLAGS_ICV_INCLUDED; 158214501Srpaulo integ = ikev2_get_integ(data->ikev2.proposal.integ); 159214501Srpaulo if (integ == NULL) { 160214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG " 161214501Srpaulo "transform / cannot generate ICV"); 162214501Srpaulo return NULL; 163214501Srpaulo } 164214501Srpaulo icv_len = integ->hash_len; 165214501Srpaulo 166214501Srpaulo plen += icv_len; 167214501Srpaulo } 168214501Srpaulo req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, plen, 169214501Srpaulo EAP_CODE_REQUEST, id); 170214501Srpaulo if (req == NULL) 171214501Srpaulo return NULL; 172214501Srpaulo 173214501Srpaulo wpabuf_put_u8(req, flags); /* Flags */ 174214501Srpaulo if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) 175214501Srpaulo wpabuf_put_be32(req, wpabuf_len(data->out_buf)); 176214501Srpaulo 177214501Srpaulo wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used, 178214501Srpaulo send_len); 179214501Srpaulo data->out_used += send_len; 180214501Srpaulo 181214501Srpaulo if (flags & IKEV2_FLAGS_ICV_INCLUDED) { 182214501Srpaulo const u8 *msg = wpabuf_head(req); 183214501Srpaulo size_t len = wpabuf_len(req); 184214501Srpaulo ikev2_integ_hash(data->ikev2.proposal.integ, 185214501Srpaulo data->ikev2.keys.SK_ai, 186214501Srpaulo data->ikev2.keys.SK_integ_len, 187214501Srpaulo msg, len, wpabuf_put(req, icv_len)); 188214501Srpaulo } 189214501Srpaulo 190214501Srpaulo if (data->out_used == wpabuf_len(data->out_buf)) { 191214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes " 192214501Srpaulo "(message sent completely)", 193214501Srpaulo (unsigned long) send_len); 194214501Srpaulo wpabuf_free(data->out_buf); 195214501Srpaulo data->out_buf = NULL; 196214501Srpaulo data->out_used = 0; 197214501Srpaulo } else { 198214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes " 199214501Srpaulo "(%lu more to send)", (unsigned long) send_len, 200214501Srpaulo (unsigned long) wpabuf_len(data->out_buf) - 201214501Srpaulo data->out_used); 202214501Srpaulo eap_ikev2_state(data, WAIT_FRAG_ACK); 203214501Srpaulo } 204214501Srpaulo 205214501Srpaulo return req; 206214501Srpaulo} 207214501Srpaulo 208214501Srpaulo 209214501Srpaulostatic struct wpabuf * eap_ikev2_buildReq(struct eap_sm *sm, void *priv, u8 id) 210214501Srpaulo{ 211214501Srpaulo struct eap_ikev2_data *data = priv; 212214501Srpaulo 213214501Srpaulo switch (data->state) { 214214501Srpaulo case MSG: 215214501Srpaulo if (data->out_buf == NULL) { 216214501Srpaulo data->out_buf = ikev2_initiator_build(&data->ikev2); 217214501Srpaulo if (data->out_buf == NULL) { 218214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to " 219214501Srpaulo "generate IKEv2 message"); 220214501Srpaulo return NULL; 221214501Srpaulo } 222214501Srpaulo data->out_used = 0; 223214501Srpaulo } 224214501Srpaulo /* pass through */ 225214501Srpaulo case WAIT_FRAG_ACK: 226214501Srpaulo return eap_ikev2_build_msg(data, id); 227214501Srpaulo case FRAG_ACK: 228214501Srpaulo return eap_ikev2_build_frag_ack(id, EAP_CODE_REQUEST); 229214501Srpaulo default: 230214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected state %d in " 231214501Srpaulo "buildReq", data->state); 232214501Srpaulo return NULL; 233214501Srpaulo } 234214501Srpaulo} 235214501Srpaulo 236214501Srpaulo 237214501Srpaulostatic Boolean eap_ikev2_check(struct eap_sm *sm, void *priv, 238214501Srpaulo struct wpabuf *respData) 239214501Srpaulo{ 240214501Srpaulo const u8 *pos; 241214501Srpaulo size_t len; 242214501Srpaulo 243214501Srpaulo pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, respData, 244214501Srpaulo &len); 245214501Srpaulo if (pos == NULL) { 246214501Srpaulo wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid frame"); 247214501Srpaulo return TRUE; 248214501Srpaulo } 249214501Srpaulo 250214501Srpaulo return FALSE; 251214501Srpaulo} 252214501Srpaulo 253214501Srpaulo 254214501Srpaulostatic int eap_ikev2_process_icv(struct eap_ikev2_data *data, 255214501Srpaulo const struct wpabuf *respData, 256214501Srpaulo u8 flags, const u8 *pos, const u8 **end) 257214501Srpaulo{ 258214501Srpaulo if (flags & IKEV2_FLAGS_ICV_INCLUDED) { 259214501Srpaulo int icv_len = eap_ikev2_validate_icv( 260214501Srpaulo data->ikev2.proposal.integ, &data->ikev2.keys, 0, 261214501Srpaulo respData, pos, *end); 262214501Srpaulo if (icv_len < 0) 263214501Srpaulo return -1; 264214501Srpaulo /* Hide Integrity Checksum Data from further processing */ 265214501Srpaulo *end -= icv_len; 266214501Srpaulo } else if (data->keys_ready) { 267214501Srpaulo wpa_printf(MSG_INFO, "EAP-IKEV2: The message should have " 268214501Srpaulo "included integrity checksum"); 269214501Srpaulo return -1; 270214501Srpaulo } 271214501Srpaulo 272214501Srpaulo return 0; 273214501Srpaulo} 274214501Srpaulo 275214501Srpaulo 276214501Srpaulostatic int eap_ikev2_process_cont(struct eap_ikev2_data *data, 277214501Srpaulo const u8 *buf, size_t len) 278214501Srpaulo{ 279214501Srpaulo /* Process continuation of a pending message */ 280214501Srpaulo if (len > wpabuf_tailroom(data->in_buf)) { 281214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment overflow"); 282214501Srpaulo eap_ikev2_state(data, FAIL); 283214501Srpaulo return -1; 284214501Srpaulo } 285214501Srpaulo 286214501Srpaulo wpabuf_put_data(data->in_buf, buf, len); 287214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes, waiting for %lu " 288214501Srpaulo "bytes more", (unsigned long) len, 289214501Srpaulo (unsigned long) wpabuf_tailroom(data->in_buf)); 290214501Srpaulo 291214501Srpaulo return 0; 292214501Srpaulo} 293214501Srpaulo 294214501Srpaulo 295214501Srpaulostatic int eap_ikev2_process_fragment(struct eap_ikev2_data *data, 296214501Srpaulo u8 flags, u32 message_length, 297214501Srpaulo const u8 *buf, size_t len) 298214501Srpaulo{ 299214501Srpaulo /* Process a fragment that is not the last one of the message */ 300214501Srpaulo if (data->in_buf == NULL && !(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) { 301214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: No Message Length field in " 302214501Srpaulo "a fragmented packet"); 303214501Srpaulo return -1; 304214501Srpaulo } 305214501Srpaulo 306214501Srpaulo if (data->in_buf == NULL) { 307214501Srpaulo /* First fragment of the message */ 308214501Srpaulo data->in_buf = wpabuf_alloc(message_length); 309214501Srpaulo if (data->in_buf == NULL) { 310214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for " 311214501Srpaulo "message"); 312214501Srpaulo return -1; 313214501Srpaulo } 314214501Srpaulo wpabuf_put_data(data->in_buf, buf, len); 315214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes in first " 316214501Srpaulo "fragment, waiting for %lu bytes more", 317214501Srpaulo (unsigned long) len, 318214501Srpaulo (unsigned long) wpabuf_tailroom(data->in_buf)); 319214501Srpaulo } 320214501Srpaulo 321214501Srpaulo return 0; 322214501Srpaulo} 323214501Srpaulo 324214501Srpaulo 325214501Srpaulostatic int eap_ikev2_server_keymat(struct eap_ikev2_data *data) 326214501Srpaulo{ 327214501Srpaulo if (eap_ikev2_derive_keymat( 328214501Srpaulo data->ikev2.proposal.prf, &data->ikev2.keys, 329214501Srpaulo data->ikev2.i_nonce, data->ikev2.i_nonce_len, 330214501Srpaulo data->ikev2.r_nonce, data->ikev2.r_nonce_len, 331214501Srpaulo data->keymat) < 0) { 332214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to derive " 333214501Srpaulo "key material"); 334214501Srpaulo return -1; 335214501Srpaulo } 336214501Srpaulo data->keymat_ok = 1; 337214501Srpaulo return 0; 338214501Srpaulo} 339214501Srpaulo 340214501Srpaulo 341214501Srpaulostatic void eap_ikev2_process(struct eap_sm *sm, void *priv, 342214501Srpaulo struct wpabuf *respData) 343214501Srpaulo{ 344214501Srpaulo struct eap_ikev2_data *data = priv; 345214501Srpaulo const u8 *start, *pos, *end; 346214501Srpaulo size_t len; 347214501Srpaulo u8 flags; 348214501Srpaulo u32 message_length = 0; 349214501Srpaulo struct wpabuf tmpbuf; 350214501Srpaulo 351214501Srpaulo pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, respData, 352214501Srpaulo &len); 353214501Srpaulo if (pos == NULL) 354214501Srpaulo return; /* Should not happen; message already verified */ 355214501Srpaulo 356214501Srpaulo start = pos; 357214501Srpaulo end = start + len; 358214501Srpaulo 359214501Srpaulo if (len == 0) { 360214501Srpaulo /* fragment ack */ 361214501Srpaulo flags = 0; 362214501Srpaulo } else 363214501Srpaulo flags = *pos++; 364214501Srpaulo 365214501Srpaulo if (eap_ikev2_process_icv(data, respData, flags, pos, &end) < 0) { 366214501Srpaulo eap_ikev2_state(data, FAIL); 367214501Srpaulo return; 368214501Srpaulo } 369214501Srpaulo 370214501Srpaulo if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) { 371214501Srpaulo if (end - pos < 4) { 372214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow"); 373214501Srpaulo eap_ikev2_state(data, FAIL); 374214501Srpaulo return; 375214501Srpaulo } 376214501Srpaulo message_length = WPA_GET_BE32(pos); 377214501Srpaulo pos += 4; 378214501Srpaulo 379214501Srpaulo if (message_length < (u32) (end - pos)) { 380214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message " 381214501Srpaulo "Length (%d; %ld remaining in this msg)", 382214501Srpaulo message_length, (long) (end - pos)); 383214501Srpaulo eap_ikev2_state(data, FAIL); 384214501Srpaulo return; 385214501Srpaulo } 386214501Srpaulo } 387214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x " 388214501Srpaulo "Message Length %u", flags, message_length); 389214501Srpaulo 390214501Srpaulo if (data->state == WAIT_FRAG_ACK) { 391214501Srpaulo if (len != 0) { 392214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload " 393214501Srpaulo "in WAIT_FRAG_ACK state"); 394214501Srpaulo eap_ikev2_state(data, FAIL); 395214501Srpaulo return; 396214501Srpaulo } 397214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged"); 398214501Srpaulo eap_ikev2_state(data, MSG); 399214501Srpaulo return; 400214501Srpaulo } 401214501Srpaulo 402214501Srpaulo if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) { 403214501Srpaulo eap_ikev2_state(data, FAIL); 404214501Srpaulo return; 405214501Srpaulo } 406214501Srpaulo 407214501Srpaulo if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) { 408214501Srpaulo if (eap_ikev2_process_fragment(data, flags, message_length, 409214501Srpaulo pos, end - pos) < 0) 410214501Srpaulo eap_ikev2_state(data, FAIL); 411214501Srpaulo else 412214501Srpaulo eap_ikev2_state(data, FRAG_ACK); 413214501Srpaulo return; 414214501Srpaulo } else if (data->state == FRAG_ACK) { 415214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received"); 416214501Srpaulo data->state = MSG; 417214501Srpaulo } 418214501Srpaulo 419214501Srpaulo if (data->in_buf == NULL) { 420214501Srpaulo /* Wrap unfragmented messages as wpabuf without extra copy */ 421214501Srpaulo wpabuf_set(&tmpbuf, pos, end - pos); 422214501Srpaulo data->in_buf = &tmpbuf; 423214501Srpaulo } 424214501Srpaulo 425214501Srpaulo if (ikev2_initiator_process(&data->ikev2, data->in_buf) < 0) { 426214501Srpaulo if (data->in_buf == &tmpbuf) 427214501Srpaulo data->in_buf = NULL; 428214501Srpaulo eap_ikev2_state(data, FAIL); 429214501Srpaulo return; 430214501Srpaulo } 431214501Srpaulo 432214501Srpaulo switch (data->ikev2.state) { 433214501Srpaulo case SA_AUTH: 434214501Srpaulo /* SA_INIT was sent out, so message have to be 435214501Srpaulo * integrity protected from now on. */ 436214501Srpaulo data->keys_ready = 1; 437214501Srpaulo break; 438214501Srpaulo case IKEV2_DONE: 439214501Srpaulo if (data->state == FAIL) 440214501Srpaulo break; 441214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication completed " 442214501Srpaulo "successfully"); 443214501Srpaulo if (eap_ikev2_server_keymat(data)) 444214501Srpaulo break; 445214501Srpaulo eap_ikev2_state(data, DONE); 446214501Srpaulo break; 447214501Srpaulo default: 448214501Srpaulo break; 449214501Srpaulo } 450214501Srpaulo 451214501Srpaulo if (data->in_buf != &tmpbuf) 452214501Srpaulo wpabuf_free(data->in_buf); 453214501Srpaulo data->in_buf = NULL; 454214501Srpaulo} 455214501Srpaulo 456214501Srpaulo 457214501Srpaulostatic Boolean eap_ikev2_isDone(struct eap_sm *sm, void *priv) 458214501Srpaulo{ 459214501Srpaulo struct eap_ikev2_data *data = priv; 460214501Srpaulo return data->state == DONE || data->state == FAIL; 461214501Srpaulo} 462214501Srpaulo 463214501Srpaulo 464214501Srpaulostatic Boolean eap_ikev2_isSuccess(struct eap_sm *sm, void *priv) 465214501Srpaulo{ 466214501Srpaulo struct eap_ikev2_data *data = priv; 467214501Srpaulo return data->state == DONE && data->ikev2.state == IKEV2_DONE && 468214501Srpaulo data->keymat_ok; 469214501Srpaulo} 470214501Srpaulo 471214501Srpaulo 472214501Srpaulostatic u8 * eap_ikev2_getKey(struct eap_sm *sm, void *priv, size_t *len) 473214501Srpaulo{ 474214501Srpaulo struct eap_ikev2_data *data = priv; 475214501Srpaulo u8 *key; 476214501Srpaulo 477214501Srpaulo if (data->state != DONE || !data->keymat_ok) 478214501Srpaulo return NULL; 479214501Srpaulo 480214501Srpaulo key = os_malloc(EAP_MSK_LEN); 481214501Srpaulo if (key) { 482214501Srpaulo os_memcpy(key, data->keymat, EAP_MSK_LEN); 483214501Srpaulo *len = EAP_MSK_LEN; 484214501Srpaulo } 485214501Srpaulo 486214501Srpaulo return key; 487214501Srpaulo} 488214501Srpaulo 489214501Srpaulo 490214501Srpaulostatic u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 491214501Srpaulo{ 492214501Srpaulo struct eap_ikev2_data *data = priv; 493214501Srpaulo u8 *key; 494214501Srpaulo 495214501Srpaulo if (data->state != DONE || !data->keymat_ok) 496214501Srpaulo return NULL; 497214501Srpaulo 498214501Srpaulo key = os_malloc(EAP_EMSK_LEN); 499214501Srpaulo if (key) { 500214501Srpaulo os_memcpy(key, data->keymat + EAP_MSK_LEN, EAP_EMSK_LEN); 501214501Srpaulo *len = EAP_EMSK_LEN; 502214501Srpaulo } 503214501Srpaulo 504214501Srpaulo return key; 505214501Srpaulo} 506214501Srpaulo 507214501Srpaulo 508214501Srpauloint eap_server_ikev2_register(void) 509214501Srpaulo{ 510214501Srpaulo struct eap_method *eap; 511214501Srpaulo int ret; 512214501Srpaulo 513214501Srpaulo eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 514214501Srpaulo EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 515214501Srpaulo "IKEV2"); 516214501Srpaulo if (eap == NULL) 517214501Srpaulo return -1; 518214501Srpaulo 519214501Srpaulo eap->init = eap_ikev2_init; 520214501Srpaulo eap->reset = eap_ikev2_reset; 521214501Srpaulo eap->buildReq = eap_ikev2_buildReq; 522214501Srpaulo eap->check = eap_ikev2_check; 523214501Srpaulo eap->process = eap_ikev2_process; 524214501Srpaulo eap->isDone = eap_ikev2_isDone; 525214501Srpaulo eap->getKey = eap_ikev2_getKey; 526214501Srpaulo eap->isSuccess = eap_ikev2_isSuccess; 527214501Srpaulo eap->get_emsk = eap_ikev2_get_emsk; 528214501Srpaulo 529214501Srpaulo ret = eap_server_method_register(eap); 530214501Srpaulo if (ret) 531214501Srpaulo eap_server_method_free(eap); 532214501Srpaulo return ret; 533214501Srpaulo} 534