139beb93cSSam Leffler /* 239beb93cSSam Leffler * EAP-IKEv2 peer (RFC 5106) 339beb93cSSam Leffler * Copyright (c) 2007, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 5*f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6*f05cddf9SRui Paulo * See README for more details. 739beb93cSSam Leffler */ 839beb93cSSam Leffler 939beb93cSSam Leffler #include "includes.h" 1039beb93cSSam Leffler 1139beb93cSSam Leffler #include "common.h" 1239beb93cSSam Leffler #include "eap_i.h" 1339beb93cSSam Leffler #include "eap_common/eap_ikev2_common.h" 1439beb93cSSam Leffler #include "ikev2.h" 1539beb93cSSam Leffler 1639beb93cSSam Leffler 1739beb93cSSam Leffler struct eap_ikev2_data { 1839beb93cSSam Leffler struct ikev2_responder_data ikev2; 1939beb93cSSam Leffler enum { WAIT_START, PROC_MSG, WAIT_FRAG_ACK, DONE, FAIL } state; 2039beb93cSSam Leffler struct wpabuf *in_buf; 2139beb93cSSam Leffler struct wpabuf *out_buf; 2239beb93cSSam Leffler size_t out_used; 2339beb93cSSam Leffler size_t fragment_size; 2439beb93cSSam Leffler int keys_ready; 2539beb93cSSam Leffler u8 keymat[EAP_MSK_LEN + EAP_EMSK_LEN]; 2639beb93cSSam Leffler int keymat_ok; 2739beb93cSSam Leffler }; 2839beb93cSSam Leffler 2939beb93cSSam Leffler 3039beb93cSSam Leffler static const char * eap_ikev2_state_txt(int state) 3139beb93cSSam Leffler { 3239beb93cSSam Leffler switch (state) { 3339beb93cSSam Leffler case WAIT_START: 3439beb93cSSam Leffler return "WAIT_START"; 3539beb93cSSam Leffler case PROC_MSG: 3639beb93cSSam Leffler return "PROC_MSG"; 3739beb93cSSam Leffler case WAIT_FRAG_ACK: 3839beb93cSSam Leffler return "WAIT_FRAG_ACK"; 3939beb93cSSam Leffler case DONE: 4039beb93cSSam Leffler return "DONE"; 4139beb93cSSam Leffler case FAIL: 4239beb93cSSam Leffler return "FAIL"; 4339beb93cSSam Leffler default: 4439beb93cSSam Leffler return "?"; 4539beb93cSSam Leffler } 4639beb93cSSam Leffler } 4739beb93cSSam Leffler 4839beb93cSSam Leffler 4939beb93cSSam Leffler static void eap_ikev2_state(struct eap_ikev2_data *data, int state) 5039beb93cSSam Leffler { 5139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-IKEV2: %s -> %s", 5239beb93cSSam Leffler eap_ikev2_state_txt(data->state), 5339beb93cSSam Leffler eap_ikev2_state_txt(state)); 5439beb93cSSam Leffler data->state = state; 5539beb93cSSam Leffler } 5639beb93cSSam Leffler 5739beb93cSSam Leffler 5839beb93cSSam Leffler static void * eap_ikev2_init(struct eap_sm *sm) 5939beb93cSSam Leffler { 6039beb93cSSam Leffler struct eap_ikev2_data *data; 6139beb93cSSam Leffler const u8 *identity, *password; 6239beb93cSSam Leffler size_t identity_len, password_len; 6339beb93cSSam Leffler 6439beb93cSSam Leffler identity = eap_get_config_identity(sm, &identity_len); 6539beb93cSSam Leffler if (identity == NULL) { 6639beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-IKEV2: No identity available"); 6739beb93cSSam Leffler return NULL; 6839beb93cSSam Leffler } 6939beb93cSSam Leffler 7039beb93cSSam Leffler data = os_zalloc(sizeof(*data)); 7139beb93cSSam Leffler if (data == NULL) 7239beb93cSSam Leffler return NULL; 7339beb93cSSam Leffler data->state = WAIT_START; 7439beb93cSSam Leffler data->fragment_size = IKEV2_FRAGMENT_SIZE; 7539beb93cSSam Leffler data->ikev2.state = SA_INIT; 7639beb93cSSam Leffler data->ikev2.peer_auth = PEER_AUTH_SECRET; 7739beb93cSSam Leffler data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2"); 7839beb93cSSam Leffler if (data->ikev2.key_pad == NULL) 7939beb93cSSam Leffler goto failed; 8039beb93cSSam Leffler data->ikev2.key_pad_len = 21; 8139beb93cSSam Leffler data->ikev2.IDr = os_malloc(identity_len); 8239beb93cSSam Leffler if (data->ikev2.IDr == NULL) 8339beb93cSSam Leffler goto failed; 8439beb93cSSam Leffler os_memcpy(data->ikev2.IDr, identity, identity_len); 8539beb93cSSam Leffler data->ikev2.IDr_len = identity_len; 8639beb93cSSam Leffler 8739beb93cSSam Leffler password = eap_get_config_password(sm, &password_len); 8839beb93cSSam Leffler if (password) { 8939beb93cSSam Leffler data->ikev2.shared_secret = os_malloc(password_len); 9039beb93cSSam Leffler if (data->ikev2.shared_secret == NULL) 9139beb93cSSam Leffler goto failed; 9239beb93cSSam Leffler os_memcpy(data->ikev2.shared_secret, password, password_len); 9339beb93cSSam Leffler data->ikev2.shared_secret_len = password_len; 9439beb93cSSam Leffler } 9539beb93cSSam Leffler 9639beb93cSSam Leffler return data; 9739beb93cSSam Leffler 9839beb93cSSam Leffler failed: 9939beb93cSSam Leffler ikev2_responder_deinit(&data->ikev2); 10039beb93cSSam Leffler os_free(data); 10139beb93cSSam Leffler return NULL; 10239beb93cSSam Leffler } 10339beb93cSSam Leffler 10439beb93cSSam Leffler 10539beb93cSSam Leffler static void eap_ikev2_deinit(struct eap_sm *sm, void *priv) 10639beb93cSSam Leffler { 10739beb93cSSam Leffler struct eap_ikev2_data *data = priv; 10839beb93cSSam Leffler wpabuf_free(data->in_buf); 10939beb93cSSam Leffler wpabuf_free(data->out_buf); 11039beb93cSSam Leffler ikev2_responder_deinit(&data->ikev2); 11139beb93cSSam Leffler os_free(data); 11239beb93cSSam Leffler } 11339beb93cSSam Leffler 11439beb93cSSam Leffler 11539beb93cSSam Leffler static int eap_ikev2_peer_keymat(struct eap_ikev2_data *data) 11639beb93cSSam Leffler { 11739beb93cSSam Leffler if (eap_ikev2_derive_keymat( 11839beb93cSSam Leffler data->ikev2.proposal.prf, &data->ikev2.keys, 11939beb93cSSam Leffler data->ikev2.i_nonce, data->ikev2.i_nonce_len, 12039beb93cSSam Leffler data->ikev2.r_nonce, data->ikev2.r_nonce_len, 12139beb93cSSam Leffler data->keymat) < 0) { 12239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to " 12339beb93cSSam Leffler "derive key material"); 12439beb93cSSam Leffler return -1; 12539beb93cSSam Leffler } 12639beb93cSSam Leffler data->keymat_ok = 1; 12739beb93cSSam Leffler return 0; 12839beb93cSSam Leffler } 12939beb93cSSam Leffler 13039beb93cSSam Leffler 13139beb93cSSam Leffler static struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data, 13239beb93cSSam Leffler struct eap_method_ret *ret, u8 id) 13339beb93cSSam Leffler { 13439beb93cSSam Leffler struct wpabuf *resp; 13539beb93cSSam Leffler u8 flags; 13639beb93cSSam Leffler size_t send_len, plen, icv_len = 0; 13739beb93cSSam Leffler 13839beb93cSSam Leffler ret->ignore = FALSE; 13939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-IKEV2: Generating Response"); 14039beb93cSSam Leffler ret->allowNotifications = TRUE; 14139beb93cSSam Leffler 14239beb93cSSam Leffler flags = 0; 14339beb93cSSam Leffler send_len = wpabuf_len(data->out_buf) - data->out_used; 14439beb93cSSam Leffler if (1 + send_len > data->fragment_size) { 14539beb93cSSam Leffler send_len = data->fragment_size - 1; 14639beb93cSSam Leffler flags |= IKEV2_FLAGS_MORE_FRAGMENTS; 14739beb93cSSam Leffler if (data->out_used == 0) { 14839beb93cSSam Leffler flags |= IKEV2_FLAGS_LENGTH_INCLUDED; 14939beb93cSSam Leffler send_len -= 4; 15039beb93cSSam Leffler } 15139beb93cSSam Leffler } 15239beb93cSSam Leffler #ifdef CCNS_PL 15339beb93cSSam Leffler /* Some issues figuring out the length of the message if Message Length 15439beb93cSSam Leffler * field not included?! */ 15539beb93cSSam Leffler if (!(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) 15639beb93cSSam Leffler flags |= IKEV2_FLAGS_LENGTH_INCLUDED; 15739beb93cSSam Leffler #endif /* CCNS_PL */ 15839beb93cSSam Leffler 15939beb93cSSam Leffler plen = 1 + send_len; 16039beb93cSSam Leffler if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) 16139beb93cSSam Leffler plen += 4; 16239beb93cSSam Leffler if (data->keys_ready) { 16339beb93cSSam Leffler const struct ikev2_integ_alg *integ; 16439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-IKEV2: Add Integrity Checksum " 16539beb93cSSam Leffler "Data"); 16639beb93cSSam Leffler flags |= IKEV2_FLAGS_ICV_INCLUDED; 16739beb93cSSam Leffler integ = ikev2_get_integ(data->ikev2.proposal.integ); 16839beb93cSSam Leffler if (integ == NULL) { 16939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG " 17039beb93cSSam Leffler "transform / cannot generate ICV"); 17139beb93cSSam Leffler return NULL; 17239beb93cSSam Leffler } 17339beb93cSSam Leffler icv_len = integ->hash_len; 17439beb93cSSam Leffler 17539beb93cSSam Leffler plen += icv_len; 17639beb93cSSam Leffler } 17739beb93cSSam Leffler resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, plen, 17839beb93cSSam Leffler EAP_CODE_RESPONSE, id); 17939beb93cSSam Leffler if (resp == NULL) 18039beb93cSSam Leffler return NULL; 18139beb93cSSam Leffler 18239beb93cSSam Leffler wpabuf_put_u8(resp, flags); /* Flags */ 18339beb93cSSam Leffler if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) 18439beb93cSSam Leffler wpabuf_put_be32(resp, wpabuf_len(data->out_buf)); 18539beb93cSSam Leffler 18639beb93cSSam Leffler wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used, 18739beb93cSSam Leffler send_len); 18839beb93cSSam Leffler data->out_used += send_len; 18939beb93cSSam Leffler 19039beb93cSSam Leffler if (flags & IKEV2_FLAGS_ICV_INCLUDED) { 19139beb93cSSam Leffler const u8 *msg = wpabuf_head(resp); 19239beb93cSSam Leffler size_t len = wpabuf_len(resp); 19339beb93cSSam Leffler ikev2_integ_hash(data->ikev2.proposal.integ, 19439beb93cSSam Leffler data->ikev2.keys.SK_ar, 19539beb93cSSam Leffler data->ikev2.keys.SK_integ_len, 19639beb93cSSam Leffler msg, len, wpabuf_put(resp, icv_len)); 19739beb93cSSam Leffler } 19839beb93cSSam Leffler 19939beb93cSSam Leffler ret->methodState = METHOD_MAY_CONT; 20039beb93cSSam Leffler ret->decision = DECISION_FAIL; 20139beb93cSSam Leffler 20239beb93cSSam Leffler if (data->out_used == wpabuf_len(data->out_buf)) { 20339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes " 20439beb93cSSam Leffler "(message sent completely)", 20539beb93cSSam Leffler (unsigned long) send_len); 20639beb93cSSam Leffler wpabuf_free(data->out_buf); 20739beb93cSSam Leffler data->out_buf = NULL; 20839beb93cSSam Leffler data->out_used = 0; 20939beb93cSSam Leffler switch (data->ikev2.state) { 21039beb93cSSam Leffler case SA_AUTH: 21139beb93cSSam Leffler /* SA_INIT was sent out, so message have to be 21239beb93cSSam Leffler * integrity protected from now on. */ 21339beb93cSSam Leffler data->keys_ready = 1; 21439beb93cSSam Leffler break; 21539beb93cSSam Leffler case IKEV2_DONE: 21639beb93cSSam Leffler ret->methodState = METHOD_DONE; 21739beb93cSSam Leffler if (data->state == FAIL) 21839beb93cSSam Leffler break; 21939beb93cSSam Leffler ret->decision = DECISION_COND_SUCC; 22039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication " 22139beb93cSSam Leffler "completed successfully"); 22239beb93cSSam Leffler if (eap_ikev2_peer_keymat(data)) 22339beb93cSSam Leffler break; 22439beb93cSSam Leffler eap_ikev2_state(data, DONE); 22539beb93cSSam Leffler break; 22639beb93cSSam Leffler case IKEV2_FAILED: 22739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication " 22839beb93cSSam Leffler "failed"); 22939beb93cSSam Leffler ret->methodState = METHOD_DONE; 23039beb93cSSam Leffler ret->decision = DECISION_FAIL; 23139beb93cSSam Leffler break; 23239beb93cSSam Leffler default: 23339beb93cSSam Leffler break; 23439beb93cSSam Leffler } 23539beb93cSSam Leffler } else { 23639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes " 23739beb93cSSam Leffler "(%lu more to send)", (unsigned long) send_len, 23839beb93cSSam Leffler (unsigned long) wpabuf_len(data->out_buf) - 23939beb93cSSam Leffler data->out_used); 24039beb93cSSam Leffler eap_ikev2_state(data, WAIT_FRAG_ACK); 24139beb93cSSam Leffler } 24239beb93cSSam Leffler 24339beb93cSSam Leffler return resp; 24439beb93cSSam Leffler } 24539beb93cSSam Leffler 24639beb93cSSam Leffler 24739beb93cSSam Leffler static int eap_ikev2_process_icv(struct eap_ikev2_data *data, 24839beb93cSSam Leffler const struct wpabuf *reqData, 24939beb93cSSam Leffler u8 flags, const u8 *pos, const u8 **end) 25039beb93cSSam Leffler { 25139beb93cSSam Leffler if (flags & IKEV2_FLAGS_ICV_INCLUDED) { 25239beb93cSSam Leffler int icv_len = eap_ikev2_validate_icv( 25339beb93cSSam Leffler data->ikev2.proposal.integ, &data->ikev2.keys, 1, 25439beb93cSSam Leffler reqData, pos, *end); 25539beb93cSSam Leffler if (icv_len < 0) 25639beb93cSSam Leffler return -1; 25739beb93cSSam Leffler /* Hide Integrity Checksum Data from further processing */ 25839beb93cSSam Leffler *end -= icv_len; 25939beb93cSSam Leffler } else if (data->keys_ready) { 26039beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-IKEV2: The message should have " 26139beb93cSSam Leffler "included integrity checksum"); 26239beb93cSSam Leffler return -1; 26339beb93cSSam Leffler } 26439beb93cSSam Leffler 26539beb93cSSam Leffler return 0; 26639beb93cSSam Leffler } 26739beb93cSSam Leffler 26839beb93cSSam Leffler 26939beb93cSSam Leffler static int eap_ikev2_process_cont(struct eap_ikev2_data *data, 27039beb93cSSam Leffler const u8 *buf, size_t len) 27139beb93cSSam Leffler { 27239beb93cSSam Leffler /* Process continuation of a pending message */ 27339beb93cSSam Leffler if (len > wpabuf_tailroom(data->in_buf)) { 27439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment overflow"); 27539beb93cSSam Leffler eap_ikev2_state(data, FAIL); 27639beb93cSSam Leffler return -1; 27739beb93cSSam Leffler } 27839beb93cSSam Leffler 27939beb93cSSam Leffler wpabuf_put_data(data->in_buf, buf, len); 28039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes, waiting " 28139beb93cSSam Leffler "for %lu bytes more", (unsigned long) len, 28239beb93cSSam Leffler (unsigned long) wpabuf_tailroom(data->in_buf)); 28339beb93cSSam Leffler 28439beb93cSSam Leffler return 0; 28539beb93cSSam Leffler } 28639beb93cSSam Leffler 28739beb93cSSam Leffler 28839beb93cSSam Leffler static struct wpabuf * eap_ikev2_process_fragment(struct eap_ikev2_data *data, 28939beb93cSSam Leffler struct eap_method_ret *ret, 29039beb93cSSam Leffler u8 id, u8 flags, 29139beb93cSSam Leffler u32 message_length, 29239beb93cSSam Leffler const u8 *buf, size_t len) 29339beb93cSSam Leffler { 29439beb93cSSam Leffler /* Process a fragment that is not the last one of the message */ 29539beb93cSSam Leffler if (data->in_buf == NULL && !(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) { 29639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-IKEV2: No Message Length field in " 29739beb93cSSam Leffler "a fragmented packet"); 29839beb93cSSam Leffler ret->ignore = TRUE; 29939beb93cSSam Leffler return NULL; 30039beb93cSSam Leffler } 30139beb93cSSam Leffler 30239beb93cSSam Leffler if (data->in_buf == NULL) { 30339beb93cSSam Leffler /* First fragment of the message */ 30439beb93cSSam Leffler data->in_buf = wpabuf_alloc(message_length); 30539beb93cSSam Leffler if (data->in_buf == NULL) { 30639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for " 30739beb93cSSam Leffler "message"); 30839beb93cSSam Leffler ret->ignore = TRUE; 30939beb93cSSam Leffler return NULL; 31039beb93cSSam Leffler } 31139beb93cSSam Leffler wpabuf_put_data(data->in_buf, buf, len); 31239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes in first " 31339beb93cSSam Leffler "fragment, waiting for %lu bytes more", 31439beb93cSSam Leffler (unsigned long) len, 31539beb93cSSam Leffler (unsigned long) wpabuf_tailroom(data->in_buf)); 31639beb93cSSam Leffler } 31739beb93cSSam Leffler 31839beb93cSSam Leffler return eap_ikev2_build_frag_ack(id, EAP_CODE_RESPONSE); 31939beb93cSSam Leffler } 32039beb93cSSam Leffler 32139beb93cSSam Leffler 32239beb93cSSam Leffler static struct wpabuf * eap_ikev2_process(struct eap_sm *sm, void *priv, 32339beb93cSSam Leffler struct eap_method_ret *ret, 32439beb93cSSam Leffler const struct wpabuf *reqData) 32539beb93cSSam Leffler { 32639beb93cSSam Leffler struct eap_ikev2_data *data = priv; 32739beb93cSSam Leffler const u8 *start, *pos, *end; 32839beb93cSSam Leffler size_t len; 32939beb93cSSam Leffler u8 flags, id; 33039beb93cSSam Leffler u32 message_length = 0; 33139beb93cSSam Leffler struct wpabuf tmpbuf; 33239beb93cSSam Leffler 33339beb93cSSam Leffler pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, reqData, &len); 33439beb93cSSam Leffler if (pos == NULL) { 33539beb93cSSam Leffler ret->ignore = TRUE; 33639beb93cSSam Leffler return NULL; 33739beb93cSSam Leffler } 33839beb93cSSam Leffler 33939beb93cSSam Leffler id = eap_get_id(reqData); 34039beb93cSSam Leffler 34139beb93cSSam Leffler start = pos; 34239beb93cSSam Leffler end = start + len; 34339beb93cSSam Leffler 34439beb93cSSam Leffler if (len == 0) 34539beb93cSSam Leffler flags = 0; /* fragment ack */ 34639beb93cSSam Leffler else 34739beb93cSSam Leffler flags = *pos++; 34839beb93cSSam Leffler 34939beb93cSSam Leffler if (eap_ikev2_process_icv(data, reqData, flags, pos, &end) < 0) { 35039beb93cSSam Leffler ret->ignore = TRUE; 35139beb93cSSam Leffler return NULL; 35239beb93cSSam Leffler } 35339beb93cSSam Leffler 35439beb93cSSam Leffler if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) { 35539beb93cSSam Leffler if (end - pos < 4) { 35639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow"); 35739beb93cSSam Leffler ret->ignore = TRUE; 35839beb93cSSam Leffler return NULL; 35939beb93cSSam Leffler } 36039beb93cSSam Leffler message_length = WPA_GET_BE32(pos); 36139beb93cSSam Leffler pos += 4; 36239beb93cSSam Leffler 36339beb93cSSam Leffler if (message_length < (u32) (end - pos)) { 36439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message " 36539beb93cSSam Leffler "Length (%d; %ld remaining in this msg)", 36639beb93cSSam Leffler message_length, (long) (end - pos)); 36739beb93cSSam Leffler ret->ignore = TRUE; 36839beb93cSSam Leffler return NULL; 36939beb93cSSam Leffler } 37039beb93cSSam Leffler } 37139beb93cSSam Leffler 37239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x " 37339beb93cSSam Leffler "Message Length %u", flags, message_length); 37439beb93cSSam Leffler 37539beb93cSSam Leffler if (data->state == WAIT_FRAG_ACK) { 37639beb93cSSam Leffler #ifdef CCNS_PL 37739beb93cSSam Leffler if (len > 1) /* Empty Flags field included in ACK */ 37839beb93cSSam Leffler #else /* CCNS_PL */ 37939beb93cSSam Leffler if (len != 0) 38039beb93cSSam Leffler #endif /* CCNS_PL */ 38139beb93cSSam Leffler { 38239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload " 38339beb93cSSam Leffler "in WAIT_FRAG_ACK state"); 38439beb93cSSam Leffler ret->ignore = TRUE; 38539beb93cSSam Leffler return NULL; 38639beb93cSSam Leffler } 38739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged"); 38839beb93cSSam Leffler eap_ikev2_state(data, PROC_MSG); 38939beb93cSSam Leffler return eap_ikev2_build_msg(data, ret, id); 39039beb93cSSam Leffler } 39139beb93cSSam Leffler 39239beb93cSSam Leffler if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) { 39339beb93cSSam Leffler ret->ignore = TRUE; 39439beb93cSSam Leffler return NULL; 39539beb93cSSam Leffler } 39639beb93cSSam Leffler 39739beb93cSSam Leffler if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) { 39839beb93cSSam Leffler return eap_ikev2_process_fragment(data, ret, id, flags, 39939beb93cSSam Leffler message_length, pos, 40039beb93cSSam Leffler end - pos); 40139beb93cSSam Leffler } 40239beb93cSSam Leffler 40339beb93cSSam Leffler if (data->in_buf == NULL) { 40439beb93cSSam Leffler /* Wrap unfragmented messages as wpabuf without extra copy */ 40539beb93cSSam Leffler wpabuf_set(&tmpbuf, pos, end - pos); 40639beb93cSSam Leffler data->in_buf = &tmpbuf; 40739beb93cSSam Leffler } 40839beb93cSSam Leffler 40939beb93cSSam Leffler if (ikev2_responder_process(&data->ikev2, data->in_buf) < 0) { 41039beb93cSSam Leffler if (data->in_buf == &tmpbuf) 41139beb93cSSam Leffler data->in_buf = NULL; 41239beb93cSSam Leffler eap_ikev2_state(data, FAIL); 41339beb93cSSam Leffler return NULL; 41439beb93cSSam Leffler } 41539beb93cSSam Leffler 41639beb93cSSam Leffler if (data->in_buf != &tmpbuf) 41739beb93cSSam Leffler wpabuf_free(data->in_buf); 41839beb93cSSam Leffler data->in_buf = NULL; 41939beb93cSSam Leffler 42039beb93cSSam Leffler if (data->out_buf == NULL) { 42139beb93cSSam Leffler data->out_buf = ikev2_responder_build(&data->ikev2); 42239beb93cSSam Leffler if (data->out_buf == NULL) { 42339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to generate " 42439beb93cSSam Leffler "IKEv2 message"); 42539beb93cSSam Leffler return NULL; 42639beb93cSSam Leffler } 42739beb93cSSam Leffler data->out_used = 0; 42839beb93cSSam Leffler } 42939beb93cSSam Leffler 43039beb93cSSam Leffler eap_ikev2_state(data, PROC_MSG); 43139beb93cSSam Leffler return eap_ikev2_build_msg(data, ret, id); 43239beb93cSSam Leffler } 43339beb93cSSam Leffler 43439beb93cSSam Leffler 43539beb93cSSam Leffler static Boolean eap_ikev2_isKeyAvailable(struct eap_sm *sm, void *priv) 43639beb93cSSam Leffler { 43739beb93cSSam Leffler struct eap_ikev2_data *data = priv; 43839beb93cSSam Leffler return data->state == DONE && data->keymat_ok; 43939beb93cSSam Leffler } 44039beb93cSSam Leffler 44139beb93cSSam Leffler 44239beb93cSSam Leffler static u8 * eap_ikev2_getKey(struct eap_sm *sm, void *priv, size_t *len) 44339beb93cSSam Leffler { 44439beb93cSSam Leffler struct eap_ikev2_data *data = priv; 44539beb93cSSam Leffler u8 *key; 44639beb93cSSam Leffler 44739beb93cSSam Leffler if (data->state != DONE || !data->keymat_ok) 44839beb93cSSam Leffler return NULL; 44939beb93cSSam Leffler 45039beb93cSSam Leffler key = os_malloc(EAP_MSK_LEN); 45139beb93cSSam Leffler if (key) { 45239beb93cSSam Leffler os_memcpy(key, data->keymat, EAP_MSK_LEN); 45339beb93cSSam Leffler *len = EAP_MSK_LEN; 45439beb93cSSam Leffler } 45539beb93cSSam Leffler 45639beb93cSSam Leffler return key; 45739beb93cSSam Leffler } 45839beb93cSSam Leffler 45939beb93cSSam Leffler 46039beb93cSSam Leffler static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 46139beb93cSSam Leffler { 46239beb93cSSam Leffler struct eap_ikev2_data *data = priv; 46339beb93cSSam Leffler u8 *key; 46439beb93cSSam Leffler 46539beb93cSSam Leffler if (data->state != DONE || !data->keymat_ok) 46639beb93cSSam Leffler return NULL; 46739beb93cSSam Leffler 46839beb93cSSam Leffler key = os_malloc(EAP_EMSK_LEN); 46939beb93cSSam Leffler if (key) { 47039beb93cSSam Leffler os_memcpy(key, data->keymat + EAP_MSK_LEN, EAP_EMSK_LEN); 47139beb93cSSam Leffler *len = EAP_EMSK_LEN; 47239beb93cSSam Leffler } 47339beb93cSSam Leffler 47439beb93cSSam Leffler return key; 47539beb93cSSam Leffler } 47639beb93cSSam Leffler 47739beb93cSSam Leffler 47839beb93cSSam Leffler int eap_peer_ikev2_register(void) 47939beb93cSSam Leffler { 48039beb93cSSam Leffler struct eap_method *eap; 48139beb93cSSam Leffler int ret; 48239beb93cSSam Leffler 48339beb93cSSam Leffler eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 48439beb93cSSam Leffler EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 48539beb93cSSam Leffler "IKEV2"); 48639beb93cSSam Leffler if (eap == NULL) 48739beb93cSSam Leffler return -1; 48839beb93cSSam Leffler 48939beb93cSSam Leffler eap->init = eap_ikev2_init; 49039beb93cSSam Leffler eap->deinit = eap_ikev2_deinit; 49139beb93cSSam Leffler eap->process = eap_ikev2_process; 49239beb93cSSam Leffler eap->isKeyAvailable = eap_ikev2_isKeyAvailable; 49339beb93cSSam Leffler eap->getKey = eap_ikev2_getKey; 49439beb93cSSam Leffler eap->get_emsk = eap_ikev2_get_emsk; 49539beb93cSSam Leffler 49639beb93cSSam Leffler ret = eap_peer_method_register(eap); 49739beb93cSSam Leffler if (ret) 49839beb93cSSam Leffler eap_peer_method_free(eap); 49939beb93cSSam Leffler return ret; 50039beb93cSSam Leffler } 501