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