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 106346981Scy data->ikev2.IDi = os_memdup(sm->server_id, sm->server_id_len); 107281806Srpaulo if (data->ikev2.IDi == NULL) 108281806Srpaulo goto failed; 109281806Srpaulo data->ikev2.IDi_len = sm->server_id_len; 110214501Srpaulo 111214501Srpaulo data->ikev2.get_shared_secret = eap_ikev2_get_shared_secret; 112214501Srpaulo data->ikev2.cb_ctx = sm; 113214501Srpaulo 114214501Srpaulo return data; 115214501Srpaulo 116214501Srpaulofailed: 117214501Srpaulo ikev2_initiator_deinit(&data->ikev2); 118214501Srpaulo os_free(data); 119214501Srpaulo return NULL; 120214501Srpaulo} 121214501Srpaulo 122214501Srpaulo 123214501Srpaulostatic void eap_ikev2_reset(struct eap_sm *sm, void *priv) 124214501Srpaulo{ 125214501Srpaulo struct eap_ikev2_data *data = priv; 126214501Srpaulo wpabuf_free(data->in_buf); 127214501Srpaulo wpabuf_free(data->out_buf); 128214501Srpaulo ikev2_initiator_deinit(&data->ikev2); 129281806Srpaulo bin_clear_free(data, sizeof(*data)); 130214501Srpaulo} 131214501Srpaulo 132214501Srpaulo 133214501Srpaulostatic struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data, u8 id) 134214501Srpaulo{ 135214501Srpaulo struct wpabuf *req; 136214501Srpaulo u8 flags; 137214501Srpaulo size_t send_len, plen, icv_len = 0; 138214501Srpaulo 139214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Generating Request"); 140214501Srpaulo 141214501Srpaulo flags = 0; 142214501Srpaulo send_len = wpabuf_len(data->out_buf) - data->out_used; 143214501Srpaulo if (1 + send_len > data->fragment_size) { 144214501Srpaulo send_len = data->fragment_size - 1; 145214501Srpaulo flags |= IKEV2_FLAGS_MORE_FRAGMENTS; 146214501Srpaulo if (data->out_used == 0) { 147214501Srpaulo flags |= IKEV2_FLAGS_LENGTH_INCLUDED; 148214501Srpaulo send_len -= 4; 149214501Srpaulo } 150214501Srpaulo } 151214501Srpaulo 152214501Srpaulo plen = 1 + send_len; 153214501Srpaulo if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) 154214501Srpaulo plen += 4; 155214501Srpaulo if (data->keys_ready) { 156214501Srpaulo const struct ikev2_integ_alg *integ; 157214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Add Integrity Checksum " 158214501Srpaulo "Data"); 159214501Srpaulo flags |= IKEV2_FLAGS_ICV_INCLUDED; 160214501Srpaulo integ = ikev2_get_integ(data->ikev2.proposal.integ); 161214501Srpaulo if (integ == NULL) { 162214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG " 163214501Srpaulo "transform / cannot generate ICV"); 164214501Srpaulo return NULL; 165214501Srpaulo } 166214501Srpaulo icv_len = integ->hash_len; 167214501Srpaulo 168214501Srpaulo plen += icv_len; 169214501Srpaulo } 170214501Srpaulo req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, plen, 171214501Srpaulo EAP_CODE_REQUEST, id); 172214501Srpaulo if (req == NULL) 173214501Srpaulo return NULL; 174214501Srpaulo 175214501Srpaulo wpabuf_put_u8(req, flags); /* Flags */ 176214501Srpaulo if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) 177214501Srpaulo wpabuf_put_be32(req, wpabuf_len(data->out_buf)); 178214501Srpaulo 179214501Srpaulo wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used, 180214501Srpaulo send_len); 181214501Srpaulo data->out_used += send_len; 182214501Srpaulo 183214501Srpaulo if (flags & IKEV2_FLAGS_ICV_INCLUDED) { 184214501Srpaulo const u8 *msg = wpabuf_head(req); 185214501Srpaulo size_t len = wpabuf_len(req); 186214501Srpaulo ikev2_integ_hash(data->ikev2.proposal.integ, 187214501Srpaulo data->ikev2.keys.SK_ai, 188214501Srpaulo data->ikev2.keys.SK_integ_len, 189214501Srpaulo msg, len, wpabuf_put(req, icv_len)); 190214501Srpaulo } 191214501Srpaulo 192214501Srpaulo if (data->out_used == wpabuf_len(data->out_buf)) { 193214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes " 194214501Srpaulo "(message sent completely)", 195214501Srpaulo (unsigned long) send_len); 196214501Srpaulo wpabuf_free(data->out_buf); 197214501Srpaulo data->out_buf = NULL; 198214501Srpaulo data->out_used = 0; 199214501Srpaulo } else { 200214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes " 201214501Srpaulo "(%lu more to send)", (unsigned long) send_len, 202214501Srpaulo (unsigned long) wpabuf_len(data->out_buf) - 203214501Srpaulo data->out_used); 204214501Srpaulo eap_ikev2_state(data, WAIT_FRAG_ACK); 205214501Srpaulo } 206214501Srpaulo 207214501Srpaulo return req; 208214501Srpaulo} 209214501Srpaulo 210214501Srpaulo 211214501Srpaulostatic struct wpabuf * eap_ikev2_buildReq(struct eap_sm *sm, void *priv, u8 id) 212214501Srpaulo{ 213214501Srpaulo struct eap_ikev2_data *data = priv; 214214501Srpaulo 215214501Srpaulo switch (data->state) { 216214501Srpaulo case MSG: 217214501Srpaulo if (data->out_buf == NULL) { 218214501Srpaulo data->out_buf = ikev2_initiator_build(&data->ikev2); 219214501Srpaulo if (data->out_buf == NULL) { 220214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to " 221214501Srpaulo "generate IKEv2 message"); 222214501Srpaulo return NULL; 223214501Srpaulo } 224214501Srpaulo data->out_used = 0; 225214501Srpaulo } 226346981Scy /* fall through */ 227214501Srpaulo case WAIT_FRAG_ACK: 228214501Srpaulo return eap_ikev2_build_msg(data, id); 229214501Srpaulo case FRAG_ACK: 230214501Srpaulo return eap_ikev2_build_frag_ack(id, EAP_CODE_REQUEST); 231214501Srpaulo default: 232214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected state %d in " 233214501Srpaulo "buildReq", data->state); 234214501Srpaulo return NULL; 235214501Srpaulo } 236214501Srpaulo} 237214501Srpaulo 238214501Srpaulo 239214501Srpaulostatic Boolean eap_ikev2_check(struct eap_sm *sm, void *priv, 240214501Srpaulo struct wpabuf *respData) 241214501Srpaulo{ 242214501Srpaulo const u8 *pos; 243214501Srpaulo size_t len; 244214501Srpaulo 245214501Srpaulo pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, respData, 246214501Srpaulo &len); 247214501Srpaulo if (pos == NULL) { 248214501Srpaulo wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid frame"); 249214501Srpaulo return TRUE; 250214501Srpaulo } 251214501Srpaulo 252214501Srpaulo return FALSE; 253214501Srpaulo} 254214501Srpaulo 255214501Srpaulo 256214501Srpaulostatic int eap_ikev2_process_icv(struct eap_ikev2_data *data, 257214501Srpaulo const struct wpabuf *respData, 258281806Srpaulo u8 flags, const u8 *pos, const u8 **end, 259281806Srpaulo int frag_ack) 260214501Srpaulo{ 261214501Srpaulo if (flags & IKEV2_FLAGS_ICV_INCLUDED) { 262214501Srpaulo int icv_len = eap_ikev2_validate_icv( 263214501Srpaulo data->ikev2.proposal.integ, &data->ikev2.keys, 0, 264214501Srpaulo respData, pos, *end); 265214501Srpaulo if (icv_len < 0) 266214501Srpaulo return -1; 267214501Srpaulo /* Hide Integrity Checksum Data from further processing */ 268214501Srpaulo *end -= icv_len; 269281806Srpaulo } else if (data->keys_ready && !frag_ack) { 270214501Srpaulo wpa_printf(MSG_INFO, "EAP-IKEV2: The message should have " 271214501Srpaulo "included integrity checksum"); 272214501Srpaulo return -1; 273214501Srpaulo } 274214501Srpaulo 275214501Srpaulo return 0; 276214501Srpaulo} 277214501Srpaulo 278214501Srpaulo 279214501Srpaulostatic int eap_ikev2_process_cont(struct eap_ikev2_data *data, 280214501Srpaulo const u8 *buf, size_t len) 281214501Srpaulo{ 282214501Srpaulo /* Process continuation of a pending message */ 283214501Srpaulo if (len > wpabuf_tailroom(data->in_buf)) { 284214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment overflow"); 285214501Srpaulo eap_ikev2_state(data, FAIL); 286214501Srpaulo return -1; 287214501Srpaulo } 288214501Srpaulo 289214501Srpaulo wpabuf_put_data(data->in_buf, buf, len); 290214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes, waiting for %lu " 291214501Srpaulo "bytes more", (unsigned long) len, 292214501Srpaulo (unsigned long) wpabuf_tailroom(data->in_buf)); 293214501Srpaulo 294214501Srpaulo return 0; 295214501Srpaulo} 296214501Srpaulo 297214501Srpaulo 298214501Srpaulostatic int eap_ikev2_process_fragment(struct eap_ikev2_data *data, 299214501Srpaulo u8 flags, u32 message_length, 300214501Srpaulo const u8 *buf, size_t len) 301214501Srpaulo{ 302214501Srpaulo /* Process a fragment that is not the last one of the message */ 303214501Srpaulo if (data->in_buf == NULL && !(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) { 304214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: No Message Length field in " 305214501Srpaulo "a fragmented packet"); 306214501Srpaulo return -1; 307214501Srpaulo } 308214501Srpaulo 309214501Srpaulo if (data->in_buf == NULL) { 310214501Srpaulo /* First fragment of the message */ 311281806Srpaulo if (message_length > 50000) { 312281806Srpaulo /* Limit maximum memory allocation */ 313281806Srpaulo wpa_printf(MSG_DEBUG, 314281806Srpaulo "EAP-IKEV2: Ignore too long message"); 315281806Srpaulo return -1; 316281806Srpaulo } 317214501Srpaulo data->in_buf = wpabuf_alloc(message_length); 318214501Srpaulo if (data->in_buf == NULL) { 319214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for " 320214501Srpaulo "message"); 321214501Srpaulo return -1; 322214501Srpaulo } 323214501Srpaulo wpabuf_put_data(data->in_buf, buf, len); 324214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes in first " 325214501Srpaulo "fragment, waiting for %lu bytes more", 326214501Srpaulo (unsigned long) len, 327214501Srpaulo (unsigned long) wpabuf_tailroom(data->in_buf)); 328214501Srpaulo } 329214501Srpaulo 330214501Srpaulo return 0; 331214501Srpaulo} 332214501Srpaulo 333214501Srpaulo 334214501Srpaulostatic int eap_ikev2_server_keymat(struct eap_ikev2_data *data) 335214501Srpaulo{ 336214501Srpaulo if (eap_ikev2_derive_keymat( 337214501Srpaulo data->ikev2.proposal.prf, &data->ikev2.keys, 338214501Srpaulo data->ikev2.i_nonce, data->ikev2.i_nonce_len, 339214501Srpaulo data->ikev2.r_nonce, data->ikev2.r_nonce_len, 340214501Srpaulo data->keymat) < 0) { 341214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to derive " 342214501Srpaulo "key material"); 343214501Srpaulo return -1; 344214501Srpaulo } 345214501Srpaulo data->keymat_ok = 1; 346214501Srpaulo return 0; 347214501Srpaulo} 348214501Srpaulo 349214501Srpaulo 350214501Srpaulostatic void eap_ikev2_process(struct eap_sm *sm, void *priv, 351214501Srpaulo struct wpabuf *respData) 352214501Srpaulo{ 353214501Srpaulo struct eap_ikev2_data *data = priv; 354214501Srpaulo const u8 *start, *pos, *end; 355214501Srpaulo size_t len; 356214501Srpaulo u8 flags; 357214501Srpaulo u32 message_length = 0; 358214501Srpaulo struct wpabuf tmpbuf; 359214501Srpaulo 360214501Srpaulo pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, respData, 361214501Srpaulo &len); 362214501Srpaulo if (pos == NULL) 363214501Srpaulo return; /* Should not happen; message already verified */ 364214501Srpaulo 365214501Srpaulo start = pos; 366214501Srpaulo end = start + len; 367214501Srpaulo 368214501Srpaulo if (len == 0) { 369214501Srpaulo /* fragment ack */ 370214501Srpaulo flags = 0; 371214501Srpaulo } else 372214501Srpaulo flags = *pos++; 373214501Srpaulo 374281806Srpaulo if (eap_ikev2_process_icv(data, respData, flags, pos, &end, 375281806Srpaulo data->state == WAIT_FRAG_ACK && len == 0) < 0) 376281806Srpaulo { 377214501Srpaulo eap_ikev2_state(data, FAIL); 378214501Srpaulo return; 379214501Srpaulo } 380214501Srpaulo 381214501Srpaulo if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) { 382214501Srpaulo if (end - pos < 4) { 383214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow"); 384214501Srpaulo eap_ikev2_state(data, FAIL); 385214501Srpaulo return; 386214501Srpaulo } 387214501Srpaulo message_length = WPA_GET_BE32(pos); 388214501Srpaulo pos += 4; 389214501Srpaulo 390214501Srpaulo if (message_length < (u32) (end - pos)) { 391214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message " 392214501Srpaulo "Length (%d; %ld remaining in this msg)", 393214501Srpaulo message_length, (long) (end - pos)); 394214501Srpaulo eap_ikev2_state(data, FAIL); 395214501Srpaulo return; 396214501Srpaulo } 397214501Srpaulo } 398214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x " 399214501Srpaulo "Message Length %u", flags, message_length); 400214501Srpaulo 401214501Srpaulo if (data->state == WAIT_FRAG_ACK) { 402214501Srpaulo if (len != 0) { 403214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload " 404214501Srpaulo "in WAIT_FRAG_ACK state"); 405214501Srpaulo eap_ikev2_state(data, FAIL); 406214501Srpaulo return; 407214501Srpaulo } 408214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged"); 409214501Srpaulo eap_ikev2_state(data, MSG); 410214501Srpaulo return; 411214501Srpaulo } 412214501Srpaulo 413214501Srpaulo if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) { 414214501Srpaulo eap_ikev2_state(data, FAIL); 415214501Srpaulo return; 416214501Srpaulo } 417214501Srpaulo 418214501Srpaulo if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) { 419214501Srpaulo if (eap_ikev2_process_fragment(data, flags, message_length, 420214501Srpaulo pos, end - pos) < 0) 421214501Srpaulo eap_ikev2_state(data, FAIL); 422214501Srpaulo else 423214501Srpaulo eap_ikev2_state(data, FRAG_ACK); 424214501Srpaulo return; 425214501Srpaulo } else if (data->state == FRAG_ACK) { 426214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received"); 427214501Srpaulo data->state = MSG; 428214501Srpaulo } 429214501Srpaulo 430214501Srpaulo if (data->in_buf == NULL) { 431214501Srpaulo /* Wrap unfragmented messages as wpabuf without extra copy */ 432214501Srpaulo wpabuf_set(&tmpbuf, pos, end - pos); 433214501Srpaulo data->in_buf = &tmpbuf; 434214501Srpaulo } 435214501Srpaulo 436214501Srpaulo if (ikev2_initiator_process(&data->ikev2, data->in_buf) < 0) { 437214501Srpaulo if (data->in_buf == &tmpbuf) 438214501Srpaulo data->in_buf = NULL; 439214501Srpaulo eap_ikev2_state(data, FAIL); 440214501Srpaulo return; 441214501Srpaulo } 442214501Srpaulo 443214501Srpaulo switch (data->ikev2.state) { 444214501Srpaulo case SA_AUTH: 445214501Srpaulo /* SA_INIT was sent out, so message have to be 446214501Srpaulo * integrity protected from now on. */ 447214501Srpaulo data->keys_ready = 1; 448214501Srpaulo break; 449214501Srpaulo case IKEV2_DONE: 450214501Srpaulo if (data->state == FAIL) 451214501Srpaulo break; 452214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication completed " 453214501Srpaulo "successfully"); 454214501Srpaulo if (eap_ikev2_server_keymat(data)) 455214501Srpaulo break; 456214501Srpaulo eap_ikev2_state(data, DONE); 457214501Srpaulo break; 458214501Srpaulo default: 459214501Srpaulo break; 460214501Srpaulo } 461214501Srpaulo 462214501Srpaulo if (data->in_buf != &tmpbuf) 463214501Srpaulo wpabuf_free(data->in_buf); 464214501Srpaulo data->in_buf = NULL; 465214501Srpaulo} 466214501Srpaulo 467214501Srpaulo 468214501Srpaulostatic Boolean eap_ikev2_isDone(struct eap_sm *sm, void *priv) 469214501Srpaulo{ 470214501Srpaulo struct eap_ikev2_data *data = priv; 471214501Srpaulo return data->state == DONE || data->state == FAIL; 472214501Srpaulo} 473214501Srpaulo 474214501Srpaulo 475214501Srpaulostatic Boolean eap_ikev2_isSuccess(struct eap_sm *sm, void *priv) 476214501Srpaulo{ 477214501Srpaulo struct eap_ikev2_data *data = priv; 478214501Srpaulo return data->state == DONE && data->ikev2.state == IKEV2_DONE && 479214501Srpaulo data->keymat_ok; 480214501Srpaulo} 481214501Srpaulo 482214501Srpaulo 483214501Srpaulostatic u8 * eap_ikev2_getKey(struct eap_sm *sm, void *priv, size_t *len) 484214501Srpaulo{ 485214501Srpaulo struct eap_ikev2_data *data = priv; 486214501Srpaulo u8 *key; 487214501Srpaulo 488214501Srpaulo if (data->state != DONE || !data->keymat_ok) 489214501Srpaulo return NULL; 490214501Srpaulo 491214501Srpaulo key = os_malloc(EAP_MSK_LEN); 492214501Srpaulo if (key) { 493214501Srpaulo os_memcpy(key, data->keymat, EAP_MSK_LEN); 494214501Srpaulo *len = EAP_MSK_LEN; 495214501Srpaulo } 496214501Srpaulo 497214501Srpaulo return key; 498214501Srpaulo} 499214501Srpaulo 500214501Srpaulo 501214501Srpaulostatic u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 502214501Srpaulo{ 503214501Srpaulo struct eap_ikev2_data *data = priv; 504214501Srpaulo u8 *key; 505214501Srpaulo 506214501Srpaulo if (data->state != DONE || !data->keymat_ok) 507214501Srpaulo return NULL; 508214501Srpaulo 509214501Srpaulo key = os_malloc(EAP_EMSK_LEN); 510214501Srpaulo if (key) { 511214501Srpaulo os_memcpy(key, data->keymat + EAP_MSK_LEN, EAP_EMSK_LEN); 512214501Srpaulo *len = EAP_EMSK_LEN; 513214501Srpaulo } 514214501Srpaulo 515214501Srpaulo return key; 516214501Srpaulo} 517214501Srpaulo 518214501Srpaulo 519281806Srpaulostatic u8 * eap_ikev2_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 520281806Srpaulo{ 521281806Srpaulo struct eap_ikev2_data *data = priv; 522281806Srpaulo u8 *sid; 523281806Srpaulo size_t sid_len; 524281806Srpaulo size_t offset; 525281806Srpaulo 526281806Srpaulo if (data->state != DONE || !data->keymat_ok) 527281806Srpaulo return NULL; 528281806Srpaulo 529281806Srpaulo sid_len = 1 + data->ikev2.i_nonce_len + data->ikev2.r_nonce_len; 530281806Srpaulo sid = os_malloc(sid_len); 531281806Srpaulo if (sid) { 532281806Srpaulo offset = 0; 533281806Srpaulo sid[offset] = EAP_TYPE_IKEV2; 534281806Srpaulo offset++; 535281806Srpaulo os_memcpy(sid + offset, data->ikev2.i_nonce, 536281806Srpaulo data->ikev2.i_nonce_len); 537281806Srpaulo offset += data->ikev2.i_nonce_len; 538281806Srpaulo os_memcpy(sid + offset, data->ikev2.r_nonce, 539281806Srpaulo data->ikev2.r_nonce_len); 540281806Srpaulo *len = sid_len; 541281806Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Derived Session-Id", 542281806Srpaulo sid, sid_len); 543281806Srpaulo } 544281806Srpaulo 545281806Srpaulo return sid; 546281806Srpaulo} 547281806Srpaulo 548281806Srpaulo 549214501Srpauloint eap_server_ikev2_register(void) 550214501Srpaulo{ 551214501Srpaulo struct eap_method *eap; 552214501Srpaulo 553214501Srpaulo eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 554214501Srpaulo EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 555214501Srpaulo "IKEV2"); 556214501Srpaulo if (eap == NULL) 557214501Srpaulo return -1; 558214501Srpaulo 559214501Srpaulo eap->init = eap_ikev2_init; 560214501Srpaulo eap->reset = eap_ikev2_reset; 561214501Srpaulo eap->buildReq = eap_ikev2_buildReq; 562214501Srpaulo eap->check = eap_ikev2_check; 563214501Srpaulo eap->process = eap_ikev2_process; 564214501Srpaulo eap->isDone = eap_ikev2_isDone; 565214501Srpaulo eap->getKey = eap_ikev2_getKey; 566214501Srpaulo eap->isSuccess = eap_ikev2_isSuccess; 567214501Srpaulo eap->get_emsk = eap_ikev2_get_emsk; 568281806Srpaulo eap->getSessionId = eap_ikev2_get_session_id; 569214501Srpaulo 570337817Scy return eap_server_method_register(eap); 571214501Srpaulo} 572