eap_server_ikev2.c revision 302408
11558Srgrimes/* 298542Smckusick * EAP-IKEv2 server (RFC 5106) 398542Smckusick * Copyright (c) 2007, Jouni Malinen <j@w1.fi> 498542Smckusick * 598542Smckusick * This software may be distributed under the terms of the BSD license. 698542Smckusick * See README for more details. 798542Smckusick */ 898542Smckusick 9110884Smckusick#include "includes.h" 1098542Smckusick 11136721Srwatson#include "common.h" 12136721Srwatson#include "eap_i.h" 13136721Srwatson#include "eap_common/eap_ikev2_common.h" 14136721Srwatson#include "ikev2.h" 15136721Srwatson 16136721Srwatson 17136721Srwatsonstruct eap_ikev2_data { 18136721Srwatson struct ikev2_initiator_data ikev2; 19136721Srwatson enum { MSG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state; 20136721Srwatson struct wpabuf *in_buf; 21136721Srwatson struct wpabuf *out_buf; 22136721Srwatson size_t out_used; 23136721Srwatson size_t fragment_size; 24136721Srwatson int keys_ready; 25136721Srwatson u8 keymat[EAP_MSK_LEN + EAP_EMSK_LEN]; 26136721Srwatson int keymat_ok; 27136721Srwatson}; 28136721Srwatson 29136721Srwatson 30136721Srwatsonstatic const u8 * eap_ikev2_get_shared_secret(void *ctx, const u8 *IDr, 31136721Srwatson size_t IDr_len, 321558Srgrimes size_t *secret_len) 331558Srgrimes{ 341558Srgrimes struct eap_sm *sm = ctx; 351558Srgrimes 361558Srgrimes if (IDr == NULL) { 371558Srgrimes wpa_printf(MSG_DEBUG, "EAP-IKEV2: No IDr received - default " 381558Srgrimes "to user identity from EAP-Identity"); 391558Srgrimes IDr = sm->identity; 401558Srgrimes IDr_len = sm->identity_len; 411558Srgrimes } 421558Srgrimes 431558Srgrimes if (eap_user_get(sm, IDr, IDr_len, 0) < 0 || sm->user == NULL || 441558Srgrimes sm->user->password == NULL) { 451558Srgrimes wpa_printf(MSG_DEBUG, "EAP-IKEV2: No user entry found"); 461558Srgrimes return NULL; 471558Srgrimes } 481558Srgrimes 491558Srgrimes *secret_len = sm->user->password_len; 501558Srgrimes return sm->user->password; 511558Srgrimes} 521558Srgrimes 531558Srgrimes 541558Srgrimesstatic const char * eap_ikev2_state_txt(int state) 551558Srgrimes{ 561558Srgrimes switch (state) { 571558Srgrimes case MSG: 581558Srgrimes return "MSG"; 5923675Speter case FRAG_ACK: 6055724Speter return "FRAG_ACK"; 611558Srgrimes case WAIT_FRAG_ACK: 621558Srgrimes return "WAIT_FRAG_ACK"; 63207143Spjd case DONE: 64207143Spjd return "DONE"; 65207143Spjd case FAIL: 6623675Speter return "FAIL"; 6723675Speter default: 6823675Speter return "?"; 6923675Speter } 70246812Smckusick} 71246812Smckusick 721558Srgrimes 731558Srgrimesstatic void eap_ikev2_state(struct eap_ikev2_data *data, int state) 74246812Smckusick{ 75246812Smckusick wpa_printf(MSG_DEBUG, "EAP-IKEV2: %s -> %s", 76246812Smckusick eap_ikev2_state_txt(data->state), 77250056Sdes eap_ikev2_state_txt(state)); 781558Srgrimes data->state = state; 7998542Smckusick} 8098542Smckusick 8198542Smckusick 8298542Smckusickstatic void * eap_ikev2_init(struct eap_sm *sm) 8398542Smckusick{ 8498542Smckusick struct eap_ikev2_data *data; 8598542Smckusick 8698542Smckusick data = os_zalloc(sizeof(*data)); 87134589Sscottl if (data == NULL) 88134589Sscottl return NULL; 89134589Sscottl data->state = MSG; 90134589Sscottl data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size : 91134589Sscottl IKEV2_FRAGMENT_SIZE; 92134589Sscottl data->ikev2.state = SA_INIT; 93134589Sscottl data->ikev2.peer_auth = PEER_AUTH_SECRET; 9441474Sjulian data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2"); 95102231Strhodes if (data->ikev2.key_pad == NULL) 9641474Sjulian goto failed; 9741474Sjulian data->ikev2.key_pad_len = 21; 9841474Sjulian 9941474Sjulian /* TODO: make proposals configurable */ 10041474Sjulian data->ikev2.proposal.proposal_num = 1; 10141474Sjulian data->ikev2.proposal.integ = AUTH_HMAC_SHA1_96; 10241474Sjulian data->ikev2.proposal.prf = PRF_HMAC_SHA1; 10341474Sjulian data->ikev2.proposal.encr = ENCR_AES_CBC; 10441474Sjulian data->ikev2.proposal.dh = DH_GROUP2_1024BIT_MODP; 10541474Sjulian 10641474Sjulian data->ikev2.IDi = os_malloc(sm->server_id_len); 10741474Sjulian if (data->ikev2.IDi == NULL) 10841474Sjulian goto failed; 109136281Struckman os_memcpy(data->ikev2.IDi, sm->server_id, sm->server_id_len); 110136281Struckman data->ikev2.IDi_len = sm->server_id_len; 111136281Struckman 112136281Struckman data->ikev2.get_shared_secret = eap_ikev2_get_shared_secret; 113136281Struckman data->ikev2.cb_ctx = sm; 114136281Struckman 115136281Struckman return data; 116136281Struckman 117136281Struckmanfailed: 118136281Struckman ikev2_initiator_deinit(&data->ikev2); 119136281Struckman os_free(data); 120136281Struckman return NULL; 121136281Struckman} 122136281Struckman 123136281Struckman 12441474Sjulianstatic void eap_ikev2_reset(struct eap_sm *sm, void *priv) 12541474Sjulian{ 12641474Sjulian struct eap_ikev2_data *data = priv; 12741474Sjulian wpabuf_free(data->in_buf); 12841474Sjulian wpabuf_free(data->out_buf); 12941474Sjulian ikev2_initiator_deinit(&data->ikev2); 13041474Sjulian bin_clear_free(data, sizeof(*data)); 13141474Sjulian} 1321558Srgrimes 1331558Srgrimes 1341558Srgrimesstatic struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data, u8 id) 1351558Srgrimes{ 1361558Srgrimes struct wpabuf *req; 137246812Smckusick u8 flags; 13898542Smckusick size_t send_len, plen, icv_len = 0; 13923675Speter 14023675Speter wpa_printf(MSG_DEBUG, "EAP-IKEV2: Generating Request"); 14123675Speter 142247212Smckusick flags = 0; 1431558Srgrimes send_len = wpabuf_len(data->out_buf) - data->out_used; 14423675Speter if (1 + send_len > data->fragment_size) { 14598542Smckusick send_len = data->fragment_size - 1; 14698542Smckusick flags |= IKEV2_FLAGS_MORE_FRAGMENTS; 14723675Speter if (data->out_used == 0) { 14823675Speter flags |= IKEV2_FLAGS_LENGTH_INCLUDED; 14998542Smckusick send_len -= 4; 15098542Smckusick } 1511558Srgrimes } 15223675Speter 1531558Srgrimes plen = 1 + send_len; 154134589Sscottl if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) 15598542Smckusick plen += 4; 15698542Smckusick if (data->keys_ready) { 15798542Smckusick const struct ikev2_integ_alg *integ; 1581558Srgrimes wpa_printf(MSG_DEBUG, "EAP-IKEV2: Add Integrity Checksum " 159134589Sscottl "Data"); 160134589Sscottl flags |= IKEV2_FLAGS_ICV_INCLUDED; 161134589Sscottl integ = ikev2_get_integ(data->ikev2.proposal.integ); 162134589Sscottl if (integ == NULL) { 163134589Sscottl wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG " 164134589Sscottl "transform / cannot generate ICV"); 165134589Sscottl return NULL; 166246812Smckusick } 167246812Smckusick icv_len = integ->hash_len; 168246812Smckusick 169246812Smckusick plen += icv_len; 170247212Smckusick } 171247212Smckusick req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, plen, 172247212Smckusick EAP_CODE_REQUEST, id); 173247212Smckusick if (req == NULL) 174247212Smckusick return NULL; 175247212Smckusick 176247212Smckusick wpabuf_put_u8(req, flags); /* Flags */ 177247212Smckusick if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) 178247212Smckusick wpabuf_put_be32(req, wpabuf_len(data->out_buf)); 179247212Smckusick 180247212Smckusick wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used, 181247212Smckusick send_len); 182247212Smckusick data->out_used += send_len; 183247212Smckusick 184247212Smckusick if (flags & IKEV2_FLAGS_ICV_INCLUDED) { 185247212Smckusick const u8 *msg = wpabuf_head(req); 186247212Smckusick size_t len = wpabuf_len(req); 187247212Smckusick ikev2_integ_hash(data->ikev2.proposal.integ, 188247212Smckusick data->ikev2.keys.SK_ai, 189247212Smckusick data->ikev2.keys.SK_integ_len, 190247212Smckusick msg, len, wpabuf_put(req, icv_len)); 191247212Smckusick } 192247212Smckusick 193247212Smckusick if (data->out_used == wpabuf_len(data->out_buf)) { 194247212Smckusick wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes " 195260178Sscottl "(message sent completely)", 196260178Sscottl (unsigned long) send_len); 197260178Sscottl wpabuf_free(data->out_buf); 198260178Sscottl data->out_buf = NULL; 199260178Sscottl data->out_used = 0; 2001558Srgrimes } else { 201260178Sscottl wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes " 202260178Sscottl "(%lu more to send)", (unsigned long) send_len, 203260178Sscottl (unsigned long) wpabuf_len(data->out_buf) - 2041558Srgrimes data->out_used); 20586514Siedowse eap_ikev2_state(data, WAIT_FRAG_ACK); 20674556Smckusick } 20774556Smckusick 20874556Smckusick return req; 20986514Siedowse} 21086514Siedowse 211247212Smckusick 2121558Srgrimesstatic struct wpabuf * eap_ikev2_buildReq(struct eap_sm *sm, void *priv, u8 id) 21398542Smckusick{ 21486514Siedowse struct eap_ikev2_data *data = priv; 215247212Smckusick 21686514Siedowse switch (data->state) { 2171558Srgrimes case MSG: 21874556Smckusick if (data->out_buf == NULL) { 2191558Srgrimes data->out_buf = ikev2_initiator_build(&data->ikev2); 2201558Srgrimes if (data->out_buf == NULL) { 2211558Srgrimes wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to " 222260178Sscottl "generate IKEv2 message"); 2231558Srgrimes return NULL; 2241558Srgrimes } 2251558Srgrimes data->out_used = 0; 226100935Sphk } 227100935Sphk /* pass through */ 2281558Srgrimes case WAIT_FRAG_ACK: 2291558Srgrimes return eap_ikev2_build_msg(data, id); 23098542Smckusick case FRAG_ACK: 23198542Smckusick return eap_ikev2_build_frag_ack(id, EAP_CODE_REQUEST); 2321558Srgrimes default: 23398542Smckusick wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected state %d in " 23498542Smckusick "buildReq", data->state); 2351558Srgrimes return NULL; 2361558Srgrimes } 2371558Srgrimes} 2381558Srgrimes 2391558Srgrimes 2401558Srgrimesstatic Boolean eap_ikev2_check(struct eap_sm *sm, void *priv, 24162668Smckusick struct wpabuf *respData) 24262668Smckusick{ 24362668Smckusick const u8 *pos; 2441558Srgrimes size_t len; 2451558Srgrimes 2461558Srgrimes pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, respData, 2478871Srgrimes &len); 2481558Srgrimes if (pos == NULL) { 2491558Srgrimes wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid frame"); 2508871Srgrimes return TRUE; 2511558Srgrimes } 2521558Srgrimes 2531558Srgrimes return FALSE; 2548871Srgrimes} 2551558Srgrimes 256229778Suqs 2571558Srgrimesstatic int eap_ikev2_process_icv(struct eap_ikev2_data *data, 2581558Srgrimes const struct wpabuf *respData, 2591558Srgrimes u8 flags, const u8 *pos, const u8 **end, 2601558Srgrimes int frag_ack) 2611558Srgrimes{ 2621558Srgrimes if (flags & IKEV2_FLAGS_ICV_INCLUDED) { 2631558Srgrimes int icv_len = eap_ikev2_validate_icv( 2641558Srgrimes data->ikev2.proposal.integ, &data->ikev2.keys, 0, 2651558Srgrimes respData, pos, *end); 2661558Srgrimes if (icv_len < 0) 2671558Srgrimes return -1; 26898542Smckusick /* Hide Integrity Checksum Data from further processing */ 2691558Srgrimes *end -= icv_len; 2701558Srgrimes } else if (data->keys_ready && !frag_ack) { 2711558Srgrimes wpa_printf(MSG_INFO, "EAP-IKEV2: The message should have " 2721558Srgrimes "included integrity checksum"); 2731558Srgrimes return -1; 2741558Srgrimes } 2751558Srgrimes 2761558Srgrimes return 0; 2771558Srgrimes} 2781558Srgrimes 2791558Srgrimes 2801558Srgrimesstatic int eap_ikev2_process_cont(struct eap_ikev2_data *data, 2811558Srgrimes const u8 *buf, size_t len) 2821558Srgrimes{ 28398542Smckusick /* Process continuation of a pending message */ 2841558Srgrimes if (len > wpabuf_tailroom(data->in_buf)) { 285260178Sscottl wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment overflow"); 286260178Sscottl eap_ikev2_state(data, FAIL); 2871558Srgrimes return -1; 28874556Smckusick } 289260178Sscottl 290260178Sscottl wpabuf_put_data(data->in_buf, buf, len); 291260178Sscottl wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes, waiting for %lu " 292260178Sscottl "bytes more", (unsigned long) len, 293260178Sscottl (unsigned long) wpabuf_tailroom(data->in_buf)); 294260178Sscottl 295260178Sscottl return 0; 296260178Sscottl} 297260178Sscottl 298260178Sscottl 299260178Sscottlstatic int eap_ikev2_process_fragment(struct eap_ikev2_data *data, 300260178Sscottl u8 flags, u32 message_length, 301260178Sscottl const u8 *buf, size_t len) 302260178Sscottl{ 303260178Sscottl /* Process a fragment that is not the last one of the message */ 304260178Sscottl if (data->in_buf == NULL && !(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) { 305260178Sscottl wpa_printf(MSG_DEBUG, "EAP-IKEV2: No Message Length field in " 306260178Sscottl "a fragmented packet"); 307260178Sscottl return -1; 308260178Sscottl } 309260178Sscottl 310260178Sscottl if (data->in_buf == NULL) { 311260178Sscottl /* First fragment of the message */ 312260178Sscottl if (message_length > 50000) { 313260178Sscottl /* Limit maximum memory allocation */ 314260178Sscottl wpa_printf(MSG_DEBUG, 315260178Sscottl "EAP-IKEV2: Ignore too long message"); 316260178Sscottl return -1; 317260178Sscottl } 318260178Sscottl data->in_buf = wpabuf_alloc(message_length); 319260178Sscottl if (data->in_buf == NULL) { 320260178Sscottl wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for " 321260178Sscottl "message"); 322260178Sscottl return -1; 323260178Sscottl } 324260178Sscottl wpabuf_put_data(data->in_buf, buf, len); 325260178Sscottl wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes in first " 326260178Sscottl "fragment, waiting for %lu bytes more", 327260178Sscottl (unsigned long) len, 328260178Sscottl (unsigned long) wpabuf_tailroom(data->in_buf)); 3291558Srgrimes } 330260178Sscottl 331260178Sscottl return 0; 332260178Sscottl} 3331558Srgrimes 334260178Sscottl 335260178Sscottlstatic int eap_ikev2_server_keymat(struct eap_ikev2_data *data) 336260178Sscottl{ 3371558Srgrimes if (eap_ikev2_derive_keymat( 338260178Sscottl data->ikev2.proposal.prf, &data->ikev2.keys, 339260178Sscottl data->ikev2.i_nonce, data->ikev2.i_nonce_len, 3401558Srgrimes data->ikev2.r_nonce, data->ikev2.r_nonce_len, 341260178Sscottl data->keymat) < 0) { 342260178Sscottl wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to derive " 34370050Siedowse "key material"); 34498542Smckusick return -1; 34598542Smckusick } 34698542Smckusick data->keymat_ok = 1; 34798542Smckusick return 0; 34898542Smckusick} 34998542Smckusick 350260178Sscottl 351260178Sscottlstatic void eap_ikev2_process(struct eap_sm *sm, void *priv, 3521558Srgrimes struct wpabuf *respData) 3531558Srgrimes{ 3541558Srgrimes struct eap_ikev2_data *data = priv; 3551558Srgrimes const u8 *start, *pos, *end; 3561558Srgrimes size_t len; 3571558Srgrimes u8 flags; 3581558Srgrimes u32 message_length = 0; 3591558Srgrimes struct wpabuf tmpbuf; 3601558Srgrimes 3611558Srgrimes pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, respData, 3621558Srgrimes &len); 36323675Speter if (pos == NULL) 364260178Sscottl return; /* Should not happen; message already verified */ 3657585Sbde 366248658Smckusick start = pos; 367248658Smckusick end = start + len; 368248658Smckusick 369248658Smckusick if (len == 0) { 370248658Smckusick /* fragment ack */ 371248658Smckusick flags = 0; 372263629Smckusick } else 373248658Smckusick flags = *pos++; 374248658Smckusick 375248658Smckusick if (eap_ikev2_process_icv(data, respData, flags, pos, &end, 376248658Smckusick data->state == WAIT_FRAG_ACK && len == 0) < 0) 377248658Smckusick { 378248658Smckusick eap_ikev2_state(data, FAIL); 379248658Smckusick return; 380248658Smckusick } 381248658Smckusick 382248658Smckusick if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) { 383248658Smckusick if (end - pos < 4) { 384248658Smckusick wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow"); 385248658Smckusick eap_ikev2_state(data, FAIL); 386248658Smckusick return; 387263629Smckusick } 388248658Smckusick message_length = WPA_GET_BE32(pos); 389248658Smckusick pos += 4; 390248658Smckusick 391248658Smckusick if (message_length < (u32) (end - pos)) { 392248658Smckusick wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message " 393248658Smckusick "Length (%d; %ld remaining in this msg)", 394248658Smckusick message_length, (long) (end - pos)); 395248658Smckusick eap_ikev2_state(data, FAIL); 396248658Smckusick return; 39723675Speter } 3987585Sbde } 39941474Sjulian wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x " 40092839Simp "Message Length %u", flags, message_length); 40198542Smckusick 40292839Simp if (data->state == WAIT_FRAG_ACK) { 40392839Simp if (len != 0) { 404100935Sphk wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload " 40592839Simp "in WAIT_FRAG_ACK state"); 406163845Spjd eap_ikev2_state(data, FAIL); 40792839Simp return; 408240406Sobrien } 409221233Sdes wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged"); 410250056Sdes eap_ikev2_state(data, MSG); 41198542Smckusick return; 41292839Simp } 41392839Simp 414100935Sphk if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) { 415248658Smckusick eap_ikev2_state(data, FAIL); 41698542Smckusick return; 41792839Simp } 41898542Smckusick 419100935Sphk if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) { 42092839Simp if (eap_ikev2_process_fragment(data, flags, message_length, 421100935Sphk pos, end - pos) < 0) 42292839Simp eap_ikev2_state(data, FAIL); 423100935Sphk else 424103398Sphk eap_ikev2_state(data, FRAG_ACK); 425100935Sphk return; 426247212Smckusick } else if (data->state == FRAG_ACK) { 42792839Simp wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received"); 42892839Simp data->state = MSG; 42992839Simp } 43098542Smckusick 43192839Simp if (data->in_buf == NULL) { 43292839Simp /* Wrap unfragmented messages as wpabuf without extra copy */ 433260178Sscottl wpabuf_set(&tmpbuf, pos, end - pos); 43498542Smckusick data->in_buf = &tmpbuf; 43598542Smckusick } 436248658Smckusick 437247212Smckusick if (ikev2_initiator_process(&data->ikev2, data->in_buf) < 0) { 43892839Simp if (data->in_buf == &tmpbuf) 439188110Smckusick data->in_buf = NULL; 44092839Simp eap_ikev2_state(data, FAIL); 44198542Smckusick return; 44292839Simp } 443126345Sscottl 44492839Simp switch (data->ikev2.state) { 44592839Simp case SA_AUTH: 44692839Simp /* SA_INIT was sent out, so message have to be 447247212Smckusick * integrity protected from now on. */ 44892839Simp data->keys_ready = 1; 449100935Sphk break; 45092839Simp case IKEV2_DONE: 45192839Simp if (data->state == FAIL) 45292839Simp break; 45392839Simp wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication completed " 45492839Simp "successfully"); 45592839Simp if (eap_ikev2_server_keymat(data)) 45692839Simp break; 45792839Simp eap_ikev2_state(data, DONE); 45892839Simp break; 45992839Simp default: 46092839Simp break; 46192839Simp } 46292839Simp 46392839Simp if (data->in_buf != &tmpbuf) 464100935Sphk wpabuf_free(data->in_buf); 465100935Sphk data->in_buf = NULL; 46692839Simp} 46792839Simp 46892839Simp 469163845Spjdstatic Boolean eap_ikev2_isDone(struct eap_sm *sm, void *priv) 470207141Sjeff{ 471224059Smckusick struct eap_ikev2_data *data = priv; 472260178Sscottl return data->state == DONE || data->state == FAIL; 473207143Spjd} 474207143Spjd 475 476static Boolean eap_ikev2_isSuccess(struct eap_sm *sm, void *priv) 477{ 478 struct eap_ikev2_data *data = priv; 479 return data->state == DONE && data->ikev2.state == IKEV2_DONE && 480 data->keymat_ok; 481} 482 483 484static u8 * eap_ikev2_getKey(struct eap_sm *sm, void *priv, size_t *len) 485{ 486 struct eap_ikev2_data *data = priv; 487 u8 *key; 488 489 if (data->state != DONE || !data->keymat_ok) 490 return NULL; 491 492 key = os_malloc(EAP_MSK_LEN); 493 if (key) { 494 os_memcpy(key, data->keymat, EAP_MSK_LEN); 495 *len = EAP_MSK_LEN; 496 } 497 498 return key; 499} 500 501 502static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 503{ 504 struct eap_ikev2_data *data = priv; 505 u8 *key; 506 507 if (data->state != DONE || !data->keymat_ok) 508 return NULL; 509 510 key = os_malloc(EAP_EMSK_LEN); 511 if (key) { 512 os_memcpy(key, data->keymat + EAP_MSK_LEN, EAP_EMSK_LEN); 513 *len = EAP_EMSK_LEN; 514 } 515 516 return key; 517} 518 519 520static u8 * eap_ikev2_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 521{ 522 struct eap_ikev2_data *data = priv; 523 u8 *sid; 524 size_t sid_len; 525 size_t offset; 526 527 if (data->state != DONE || !data->keymat_ok) 528 return NULL; 529 530 sid_len = 1 + data->ikev2.i_nonce_len + data->ikev2.r_nonce_len; 531 sid = os_malloc(sid_len); 532 if (sid) { 533 offset = 0; 534 sid[offset] = EAP_TYPE_IKEV2; 535 offset++; 536 os_memcpy(sid + offset, data->ikev2.i_nonce, 537 data->ikev2.i_nonce_len); 538 offset += data->ikev2.i_nonce_len; 539 os_memcpy(sid + offset, data->ikev2.r_nonce, 540 data->ikev2.r_nonce_len); 541 *len = sid_len; 542 wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Derived Session-Id", 543 sid, sid_len); 544 } 545 546 return sid; 547} 548 549 550int eap_server_ikev2_register(void) 551{ 552 struct eap_method *eap; 553 int ret; 554 555 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 556 EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 557 "IKEV2"); 558 if (eap == NULL) 559 return -1; 560 561 eap->init = eap_ikev2_init; 562 eap->reset = eap_ikev2_reset; 563 eap->buildReq = eap_ikev2_buildReq; 564 eap->check = eap_ikev2_check; 565 eap->process = eap_ikev2_process; 566 eap->isDone = eap_ikev2_isDone; 567 eap->getKey = eap_ikev2_getKey; 568 eap->isSuccess = eap_ikev2_isSuccess; 569 eap->get_emsk = eap_ikev2_get_emsk; 570 eap->getSessionId = eap_ikev2_get_session_id; 571 572 ret = eap_server_method_register(eap); 573 if (ret) 574 eap_server_method_free(eap); 575 return ret; 576} 577