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