18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * EAP-IKEv2 server (RFC 5106) 38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2007, Jouni Malinen <j@w1.fi> 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details. 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h" 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h" 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_i.h" 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_common/eap_ikev2_common.h" 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ikev2.h" 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct eap_ikev2_data { 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ikev2_initiator_data ikev2; 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt enum { MSG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state; 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *in_buf; 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *out_buf; 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t out_used; 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t fragment_size; 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int keys_ready; 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 keymat[EAP_MSK_LEN + EAP_EMSK_LEN]; 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int keymat_ok; 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const u8 * eap_ikev2_get_shared_secret(void *ctx, const u8 *IDr, 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t IDr_len, 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t *secret_len) 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_sm *sm = ctx; 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (IDr == NULL) { 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: No IDr received - default " 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "to user identity from EAP-Identity"); 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt IDr = sm->identity; 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt IDr_len = sm->identity_len; 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (eap_user_get(sm, IDr, IDr_len, 0) < 0 || sm->user == NULL || 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sm->user->password == NULL) { 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: No user entry found"); 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *secret_len = sm->user->password_len; 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return sm->user->password; 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char * eap_ikev2_state_txt(int state) 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (state) { 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case MSG: 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "MSG"; 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case FRAG_ACK: 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "FRAG_ACK"; 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case WAIT_FRAG_ACK: 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "WAIT_FRAG_ACK"; 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case DONE: 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "DONE"; 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case FAIL: 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "FAIL"; 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "?"; 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eap_ikev2_state(struct eap_ikev2_data *data, int state) 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: %s -> %s", 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_ikev2_state_txt(data->state), 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_ikev2_state_txt(state)); 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = state; 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void * eap_ikev2_init(struct eap_sm *sm) 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_ikev2_data *data; 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data = os_zalloc(sizeof(*data)); 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data == NULL) 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = MSG; 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size : 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt IKEV2_FRAGMENT_SIZE; 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->ikev2.state = SA_INIT; 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->ikev2.peer_auth = PEER_AUTH_SECRET; 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2"); 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->ikev2.key_pad == NULL) 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto failed; 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->ikev2.key_pad_len = 21; 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: make proposals configurable */ 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->ikev2.proposal.proposal_num = 1; 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->ikev2.proposal.integ = AUTH_HMAC_SHA1_96; 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->ikev2.proposal.prf = PRF_HMAC_SHA1; 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->ikev2.proposal.encr = ENCR_AES_CBC; 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->ikev2.proposal.dh = DH_GROUP2_1024BIT_MODP; 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt data->ikev2.IDi = os_malloc(sm->server_id_len); 10734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt if (data->ikev2.IDi == NULL) 10834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt goto failed; 10934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt os_memcpy(data->ikev2.IDi, sm->server_id, sm->server_id_len); 11034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt data->ikev2.IDi_len = sm->server_id_len; 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->ikev2.get_shared_secret = eap_ikev2_get_shared_secret; 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->ikev2.cb_ctx = sm; 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return data; 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfailed: 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ikev2_initiator_deinit(&data->ikev2); 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data); 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eap_ikev2_reset(struct eap_sm *sm, void *priv) 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_ikev2_data *data = priv; 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(data->in_buf); 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(data->out_buf); 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ikev2_initiator_deinit(&data->ikev2); 130c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt bin_clear_free(data, sizeof(*data)); 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data, u8 id) 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *req; 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 flags; 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t send_len, plen, icv_len = 0; 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: Generating Request"); 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt flags = 0; 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt send_len = wpabuf_len(data->out_buf) - data->out_used; 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (1 + send_len > data->fragment_size) { 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt send_len = data->fragment_size - 1; 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt flags |= IKEV2_FLAGS_MORE_FRAGMENTS; 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->out_used == 0) { 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt flags |= IKEV2_FLAGS_LENGTH_INCLUDED; 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt send_len -= 4; 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plen = 1 + send_len; 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plen += 4; 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->keys_ready) { 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct ikev2_integ_alg *integ; 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: Add Integrity Checksum " 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Data"); 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt flags |= IKEV2_FLAGS_ICV_INCLUDED; 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt integ = ikev2_get_integ(data->ikev2.proposal.integ); 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (integ == NULL) { 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG " 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "transform / cannot generate ICV"); 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt icv_len = integ->hash_len; 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plen += icv_len; 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, plen, 1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt EAP_CODE_REQUEST, id); 1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (req == NULL) 1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_u8(req, flags); /* Flags */ 1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_be32(req, wpabuf_len(data->out_buf)); 1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used, 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt send_len); 1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->out_used += send_len; 1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (flags & IKEV2_FLAGS_ICV_INCLUDED) { 1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *msg = wpabuf_head(req); 1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len = wpabuf_len(req); 1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ikev2_integ_hash(data->ikev2.proposal.integ, 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->ikev2.keys.SK_ai, 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->ikev2.keys.SK_integ_len, 1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg, len, wpabuf_put(req, icv_len)); 1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->out_used == wpabuf_len(data->out_buf)) { 1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes " 1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(message sent completely)", 1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) send_len); 1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(data->out_buf); 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->out_buf = NULL; 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->out_used = 0; 2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes " 2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(%lu more to send)", (unsigned long) send_len, 2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) wpabuf_len(data->out_buf) - 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->out_used); 2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_ikev2_state(data, WAIT_FRAG_ACK); 2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return req; 2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eap_ikev2_buildReq(struct eap_sm *sm, void *priv, u8 id) 2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_ikev2_data *data = priv; 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (data->state) { 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case MSG: 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->out_buf == NULL) { 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->out_buf = ikev2_initiator_build(&data->ikev2); 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->out_buf == NULL) { 2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to " 2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "generate IKEv2 message"); 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->out_used = 0; 2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* pass through */ 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case WAIT_FRAG_ACK: 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return eap_ikev2_build_msg(data, id); 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case FRAG_ACK: 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return eap_ikev2_build_frag_ack(id, EAP_CODE_REQUEST); 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected state %d in " 2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "buildReq", data->state); 2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic Boolean eap_ikev2_check(struct eap_sm *sm, void *priv, 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *respData) 2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos; 2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len; 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, respData, 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &len); 2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos == NULL) { 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid frame"); 2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return TRUE; 2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return FALSE; 2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int eap_ikev2_process_icv(struct eap_ikev2_data *data, 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct wpabuf *respData, 2595a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt u8 flags, const u8 *pos, const u8 **end, 2605a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt int frag_ack) 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (flags & IKEV2_FLAGS_ICV_INCLUDED) { 2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int icv_len = eap_ikev2_validate_icv( 2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->ikev2.proposal.integ, &data->ikev2.keys, 0, 2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt respData, pos, *end); 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (icv_len < 0) 2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Hide Integrity Checksum Data from further processing */ 2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *end -= icv_len; 2705a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt } else if (data->keys_ready && !frag_ack) { 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "EAP-IKEV2: The message should have " 2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "included integrity checksum"); 2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int eap_ikev2_process_cont(struct eap_ikev2_data *data, 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *buf, size_t len) 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Process continuation of a pending message */ 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len > wpabuf_tailroom(data->in_buf)) { 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment overflow"); 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_ikev2_state(data, FAIL); 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(data->in_buf, buf, len); 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes, waiting for %lu " 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "bytes more", (unsigned long) len, 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) wpabuf_tailroom(data->in_buf)); 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int eap_ikev2_process_fragment(struct eap_ikev2_data *data, 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 flags, u32 message_length, 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *buf, size_t len) 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Process a fragment that is not the last one of the message */ 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->in_buf == NULL && !(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) { 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: No Message Length field in " 3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "a fragmented packet"); 3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->in_buf == NULL) { 3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* First fragment of the message */ 312fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (message_length > 50000) { 313fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt /* Limit maximum memory allocation */ 314fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_DEBUG, 315fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt "EAP-IKEV2: Ignore too long message"); 316fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return -1; 317fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->in_buf = wpabuf_alloc(message_length); 3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->in_buf == NULL) { 3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for " 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "message"); 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(data->in_buf, buf, len); 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes in first " 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "fragment, waiting for %lu bytes more", 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) len, 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) wpabuf_tailroom(data->in_buf)); 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int eap_ikev2_server_keymat(struct eap_ikev2_data *data) 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (eap_ikev2_derive_keymat( 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->ikev2.proposal.prf, &data->ikev2.keys, 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->ikev2.i_nonce, data->ikev2.i_nonce_len, 3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->ikev2.r_nonce, data->ikev2.r_nonce_len, 3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->keymat) < 0) { 3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to derive " 3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "key material"); 3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->keymat_ok = 1; 3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eap_ikev2_process(struct eap_sm *sm, void *priv, 3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *respData) 3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_ikev2_data *data = priv; 3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *start, *pos, *end; 3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len; 3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 flags; 3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u32 message_length = 0; 3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf tmpbuf; 3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, respData, 3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &len); 3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos == NULL) 3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; /* Should not happen; message already verified */ 3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt start = pos; 3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = start + len; 3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len == 0) { 3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* fragment ack */ 3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt flags = 0; 3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else 3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt flags = *pos++; 3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3755a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt if (eap_ikev2_process_icv(data, respData, flags, pos, &end, 3765a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt data->state == WAIT_FRAG_ACK && len == 0) < 0) 3775a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt { 3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_ikev2_state(data, FAIL); 3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) { 3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (end - pos < 4) { 3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow"); 3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_ikev2_state(data, FAIL); 3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt message_length = WPA_GET_BE32(pos); 3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 4; 3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (message_length < (u32) (end - pos)) { 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message " 3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Length (%d; %ld remaining in this msg)", 3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt message_length, (long) (end - pos)); 3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_ikev2_state(data, FAIL); 3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x " 4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Message Length %u", flags, message_length); 4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->state == WAIT_FRAG_ACK) { 4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len != 0) { 4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload " 4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "in WAIT_FRAG_ACK state"); 4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_ikev2_state(data, FAIL); 4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged"); 4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_ikev2_state(data, MSG); 4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) { 4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_ikev2_state(data, FAIL); 4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) { 4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (eap_ikev2_process_fragment(data, flags, message_length, 4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos, end - pos) < 0) 4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_ikev2_state(data, FAIL); 4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_ikev2_state(data, FRAG_ACK); 4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if (data->state == FRAG_ACK) { 4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received"); 4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = MSG; 4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->in_buf == NULL) { 4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Wrap unfragmented messages as wpabuf without extra copy */ 4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_set(&tmpbuf, pos, end - pos); 4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->in_buf = &tmpbuf; 4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_initiator_process(&data->ikev2, data->in_buf) < 0) { 4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->in_buf == &tmpbuf) 4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->in_buf = NULL; 4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_ikev2_state(data, FAIL); 4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (data->ikev2.state) { 4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case SA_AUTH: 4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* SA_INIT was sent out, so message have to be 4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * integrity protected from now on. */ 4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->keys_ready = 1; 4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case IKEV2_DONE: 4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->state == FAIL) 4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication completed " 4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "successfully"); 4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (eap_ikev2_server_keymat(data)) 4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_ikev2_state(data, DONE); 4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->in_buf != &tmpbuf) 4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(data->in_buf); 4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->in_buf = NULL; 4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic Boolean eap_ikev2_isDone(struct eap_sm *sm, void *priv) 4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_ikev2_data *data = priv; 4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return data->state == DONE || data->state == FAIL; 4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic Boolean eap_ikev2_isSuccess(struct eap_sm *sm, void *priv) 4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_ikev2_data *data = priv; 4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return data->state == DONE && data->ikev2.state == IKEV2_DONE && 4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->keymat_ok; 4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic u8 * eap_ikev2_getKey(struct eap_sm *sm, void *priv, size_t *len) 4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_ikev2_data *data = priv; 4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *key; 4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->state != DONE || !data->keymat_ok) 4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt key = os_malloc(EAP_MSK_LEN); 4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (key) { 4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(key, data->keymat, EAP_MSK_LEN); 4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *len = EAP_MSK_LEN; 4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return key; 4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_ikev2_data *data = priv; 5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *key; 5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->state != DONE || !data->keymat_ok) 5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt key = os_malloc(EAP_EMSK_LEN); 5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (key) { 5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(key, data->keymat + EAP_MSK_LEN, EAP_EMSK_LEN); 5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *len = EAP_EMSK_LEN; 5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return key; 5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 520fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic u8 * eap_ikev2_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 521fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{ 522fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt struct eap_ikev2_data *data = priv; 523fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt u8 *sid; 524fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt size_t sid_len; 525fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt size_t offset; 526fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 527fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (data->state != DONE || !data->keymat_ok) 528fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return NULL; 529fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 530fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt sid_len = 1 + data->ikev2.i_nonce_len + data->ikev2.r_nonce_len; 531fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt sid = os_malloc(sid_len); 532fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (sid) { 533fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt offset = 0; 534fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt sid[offset] = EAP_TYPE_IKEV2; 535fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt offset++; 536fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_memcpy(sid + offset, data->ikev2.i_nonce, 537fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt data->ikev2.i_nonce_len); 538fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt offset += data->ikev2.i_nonce_len; 539fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt os_memcpy(sid + offset, data->ikev2.r_nonce, 540fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt data->ikev2.r_nonce_len); 541fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt *len = sid_len; 542fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Derived Session-Id", 543fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt sid, sid_len); 544fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt } 545fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 546fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt return sid; 547fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt} 548fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 549fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt 5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eap_server_ikev2_register(void) 5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_method *eap; 5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "IKEV2"); 5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (eap == NULL) 5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->init = eap_ikev2_init; 5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->reset = eap_ikev2_reset; 5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->buildReq = eap_ikev2_buildReq; 5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->check = eap_ikev2_check; 5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->process = eap_ikev2_process; 5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->isDone = eap_ikev2_isDone; 5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->getKey = eap_ikev2_getKey; 5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->isSuccess = eap_ikev2_isSuccess; 5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->get_emsk = eap_ikev2_get_emsk; 569fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt eap->getSessionId = eap_ikev2_get_session_id; 5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5711d6bf427f4769edb60865a3999d01eeb8f8fcb19Dmitry Shmidt return eap_server_method_register(eap); 5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 573