$search
00001 /* 00002 * EAP-IKEv2 peer (RFC 5106) 00003 * Copyright (c) 2007, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 */ 00014 00015 #include "includes.h" 00016 00017 #include "common.h" 00018 #include "eap_i.h" 00019 #include "eap_common/eap_ikev2_common.h" 00020 #include "ikev2.h" 00021 00022 00023 struct eap_ikev2_data { 00024 struct ikev2_responder_data ikev2; 00025 enum { WAIT_START, PROC_MSG, WAIT_FRAG_ACK, DONE, FAIL } state; 00026 struct wpabuf *in_buf; 00027 struct wpabuf *out_buf; 00028 size_t out_used; 00029 size_t fragment_size; 00030 int keys_ready; 00031 u8 keymat[EAP_MSK_LEN + EAP_EMSK_LEN]; 00032 int keymat_ok; 00033 }; 00034 00035 00036 static const char * eap_ikev2_state_txt(int state) 00037 { 00038 switch (state) { 00039 case WAIT_START: 00040 return "WAIT_START"; 00041 case PROC_MSG: 00042 return "PROC_MSG"; 00043 case WAIT_FRAG_ACK: 00044 return "WAIT_FRAG_ACK"; 00045 case DONE: 00046 return "DONE"; 00047 case FAIL: 00048 return "FAIL"; 00049 default: 00050 return "?"; 00051 } 00052 } 00053 00054 00055 static void eap_ikev2_state(struct eap_ikev2_data *data, int state) 00056 { 00057 wpa_printf(MSG_DEBUG, "EAP-IKEV2: %s -> %s", 00058 eap_ikev2_state_txt(data->state), 00059 eap_ikev2_state_txt(state)); 00060 data->state = state; 00061 } 00062 00063 00064 static void * eap_ikev2_init(struct eap_sm *sm) 00065 { 00066 struct eap_ikev2_data *data; 00067 const u8 *identity, *password; 00068 size_t identity_len, password_len; 00069 00070 identity = eap_get_config_identity(sm, &identity_len); 00071 if (identity == NULL) { 00072 wpa_printf(MSG_INFO, "EAP-IKEV2: No identity available"); 00073 return NULL; 00074 } 00075 00076 data = os_zalloc(sizeof(*data)); 00077 if (data == NULL) 00078 return NULL; 00079 data->state = WAIT_START; 00080 data->fragment_size = IKEV2_FRAGMENT_SIZE; 00081 data->ikev2.state = SA_INIT; 00082 data->ikev2.peer_auth = PEER_AUTH_SECRET; 00083 data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2"); 00084 if (data->ikev2.key_pad == NULL) 00085 goto failed; 00086 data->ikev2.key_pad_len = 21; 00087 data->ikev2.IDr = os_malloc(identity_len); 00088 if (data->ikev2.IDr == NULL) 00089 goto failed; 00090 os_memcpy(data->ikev2.IDr, identity, identity_len); 00091 data->ikev2.IDr_len = identity_len; 00092 00093 password = eap_get_config_password(sm, &password_len); 00094 if (password) { 00095 data->ikev2.shared_secret = os_malloc(password_len); 00096 if (data->ikev2.shared_secret == NULL) 00097 goto failed; 00098 os_memcpy(data->ikev2.shared_secret, password, password_len); 00099 data->ikev2.shared_secret_len = password_len; 00100 } 00101 00102 return data; 00103 00104 failed: 00105 ikev2_responder_deinit(&data->ikev2); 00106 os_free(data); 00107 return NULL; 00108 } 00109 00110 00111 static void eap_ikev2_deinit(struct eap_sm *sm, void *priv) 00112 { 00113 struct eap_ikev2_data *data = priv; 00114 wpabuf_free(data->in_buf); 00115 wpabuf_free(data->out_buf); 00116 ikev2_responder_deinit(&data->ikev2); 00117 os_free(data); 00118 } 00119 00120 00121 static int eap_ikev2_peer_keymat(struct eap_ikev2_data *data) 00122 { 00123 if (eap_ikev2_derive_keymat( 00124 data->ikev2.proposal.prf, &data->ikev2.keys, 00125 data->ikev2.i_nonce, data->ikev2.i_nonce_len, 00126 data->ikev2.r_nonce, data->ikev2.r_nonce_len, 00127 data->keymat) < 0) { 00128 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to " 00129 "derive key material"); 00130 return -1; 00131 } 00132 data->keymat_ok = 1; 00133 return 0; 00134 } 00135 00136 00137 static struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data, 00138 struct eap_method_ret *ret, u8 id) 00139 { 00140 struct wpabuf *resp; 00141 u8 flags; 00142 size_t send_len, plen, icv_len = 0; 00143 00144 ret->ignore = FALSE; 00145 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Generating Response"); 00146 ret->allowNotifications = TRUE; 00147 00148 flags = 0; 00149 send_len = wpabuf_len(data->out_buf) - data->out_used; 00150 if (1 + send_len > data->fragment_size) { 00151 send_len = data->fragment_size - 1; 00152 flags |= IKEV2_FLAGS_MORE_FRAGMENTS; 00153 if (data->out_used == 0) { 00154 flags |= IKEV2_FLAGS_LENGTH_INCLUDED; 00155 send_len -= 4; 00156 } 00157 } 00158 #ifdef CCNS_PL 00159 /* Some issues figuring out the length of the message if Message Length 00160 * field not included?! */ 00161 if (!(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) 00162 flags |= IKEV2_FLAGS_LENGTH_INCLUDED; 00163 #endif /* CCNS_PL */ 00164 00165 plen = 1 + send_len; 00166 if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) 00167 plen += 4; 00168 if (data->keys_ready) { 00169 const struct ikev2_integ_alg *integ; 00170 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Add Integrity Checksum " 00171 "Data"); 00172 flags |= IKEV2_FLAGS_ICV_INCLUDED; 00173 integ = ikev2_get_integ(data->ikev2.proposal.integ); 00174 if (integ == NULL) { 00175 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG " 00176 "transform / cannot generate ICV"); 00177 return NULL; 00178 } 00179 icv_len = integ->hash_len; 00180 00181 plen += icv_len; 00182 } 00183 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, plen, 00184 EAP_CODE_RESPONSE, id); 00185 if (resp == NULL) 00186 return NULL; 00187 00188 wpabuf_put_u8(resp, flags); /* Flags */ 00189 if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) 00190 wpabuf_put_be32(resp, wpabuf_len(data->out_buf)); 00191 00192 wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used, 00193 send_len); 00194 data->out_used += send_len; 00195 00196 if (flags & IKEV2_FLAGS_ICV_INCLUDED) { 00197 const u8 *msg = wpabuf_head(resp); 00198 size_t len = wpabuf_len(resp); 00199 ikev2_integ_hash(data->ikev2.proposal.integ, 00200 data->ikev2.keys.SK_ar, 00201 data->ikev2.keys.SK_integ_len, 00202 msg, len, wpabuf_put(resp, icv_len)); 00203 } 00204 00205 ret->methodState = METHOD_MAY_CONT; 00206 ret->decision = DECISION_FAIL; 00207 00208 if (data->out_used == wpabuf_len(data->out_buf)) { 00209 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes " 00210 "(message sent completely)", 00211 (unsigned long) send_len); 00212 wpabuf_free(data->out_buf); 00213 data->out_buf = NULL; 00214 data->out_used = 0; 00215 switch (data->ikev2.state) { 00216 case SA_AUTH: 00217 /* SA_INIT was sent out, so message have to be 00218 * integrity protected from now on. */ 00219 data->keys_ready = 1; 00220 break; 00221 case IKEV2_DONE: 00222 ret->methodState = METHOD_DONE; 00223 if (data->state == FAIL) 00224 break; 00225 ret->decision = DECISION_COND_SUCC; 00226 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication " 00227 "completed successfully"); 00228 if (eap_ikev2_peer_keymat(data)) 00229 break; 00230 eap_ikev2_state(data, DONE); 00231 break; 00232 case IKEV2_FAILED: 00233 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication " 00234 "failed"); 00235 ret->methodState = METHOD_DONE; 00236 ret->decision = DECISION_FAIL; 00237 break; 00238 default: 00239 break; 00240 } 00241 } else { 00242 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes " 00243 "(%lu more to send)", (unsigned long) send_len, 00244 (unsigned long) wpabuf_len(data->out_buf) - 00245 data->out_used); 00246 eap_ikev2_state(data, WAIT_FRAG_ACK); 00247 } 00248 00249 return resp; 00250 } 00251 00252 00253 static int eap_ikev2_process_icv(struct eap_ikev2_data *data, 00254 const struct wpabuf *reqData, 00255 u8 flags, const u8 *pos, const u8 **end) 00256 { 00257 if (flags & IKEV2_FLAGS_ICV_INCLUDED) { 00258 int icv_len = eap_ikev2_validate_icv( 00259 data->ikev2.proposal.integ, &data->ikev2.keys, 1, 00260 reqData, pos, *end); 00261 if (icv_len < 0) 00262 return -1; 00263 /* Hide Integrity Checksum Data from further processing */ 00264 *end -= icv_len; 00265 } else if (data->keys_ready) { 00266 wpa_printf(MSG_INFO, "EAP-IKEV2: The message should have " 00267 "included integrity checksum"); 00268 return -1; 00269 } 00270 00271 return 0; 00272 } 00273 00274 00275 static int eap_ikev2_process_cont(struct eap_ikev2_data *data, 00276 const u8 *buf, size_t len) 00277 { 00278 /* Process continuation of a pending message */ 00279 if (len > wpabuf_tailroom(data->in_buf)) { 00280 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment overflow"); 00281 eap_ikev2_state(data, FAIL); 00282 return -1; 00283 } 00284 00285 wpabuf_put_data(data->in_buf, buf, len); 00286 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes, waiting " 00287 "for %lu bytes more", (unsigned long) len, 00288 (unsigned long) wpabuf_tailroom(data->in_buf)); 00289 00290 return 0; 00291 } 00292 00293 00294 static struct wpabuf * eap_ikev2_process_fragment(struct eap_ikev2_data *data, 00295 struct eap_method_ret *ret, 00296 u8 id, u8 flags, 00297 u32 message_length, 00298 const u8 *buf, size_t len) 00299 { 00300 /* Process a fragment that is not the last one of the message */ 00301 if (data->in_buf == NULL && !(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) { 00302 wpa_printf(MSG_DEBUG, "EAP-IKEV2: No Message Length field in " 00303 "a fragmented packet"); 00304 ret->ignore = TRUE; 00305 return NULL; 00306 } 00307 00308 if (data->in_buf == NULL) { 00309 /* First fragment of the message */ 00310 data->in_buf = wpabuf_alloc(message_length); 00311 if (data->in_buf == NULL) { 00312 wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for " 00313 "message"); 00314 ret->ignore = TRUE; 00315 return NULL; 00316 } 00317 wpabuf_put_data(data->in_buf, buf, len); 00318 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes in first " 00319 "fragment, waiting for %lu bytes more", 00320 (unsigned long) len, 00321 (unsigned long) wpabuf_tailroom(data->in_buf)); 00322 } 00323 00324 return eap_ikev2_build_frag_ack(id, EAP_CODE_RESPONSE); 00325 } 00326 00327 00328 static struct wpabuf * eap_ikev2_process(struct eap_sm *sm, void *priv, 00329 struct eap_method_ret *ret, 00330 const struct wpabuf *reqData) 00331 { 00332 struct eap_ikev2_data *data = priv; 00333 const u8 *start, *pos, *end; 00334 size_t len; 00335 u8 flags, id; 00336 u32 message_length = 0; 00337 struct wpabuf tmpbuf; 00338 00339 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, reqData, &len); 00340 if (pos == NULL) { 00341 ret->ignore = TRUE; 00342 return NULL; 00343 } 00344 00345 id = eap_get_id(reqData); 00346 00347 start = pos; 00348 end = start + len; 00349 00350 if (len == 0) 00351 flags = 0; /* fragment ack */ 00352 else 00353 flags = *pos++; 00354 00355 if (eap_ikev2_process_icv(data, reqData, flags, pos, &end) < 0) { 00356 ret->ignore = TRUE; 00357 return NULL; 00358 } 00359 00360 if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) { 00361 if (end - pos < 4) { 00362 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow"); 00363 ret->ignore = TRUE; 00364 return NULL; 00365 } 00366 message_length = WPA_GET_BE32(pos); 00367 pos += 4; 00368 00369 if (message_length < (u32) (end - pos)) { 00370 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message " 00371 "Length (%d; %ld remaining in this msg)", 00372 message_length, (long) (end - pos)); 00373 ret->ignore = TRUE; 00374 return NULL; 00375 } 00376 } 00377 00378 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x " 00379 "Message Length %u", flags, message_length); 00380 00381 if (data->state == WAIT_FRAG_ACK) { 00382 #ifdef CCNS_PL 00383 if (len > 1) /* Empty Flags field included in ACK */ 00384 #else /* CCNS_PL */ 00385 if (len != 0) 00386 #endif /* CCNS_PL */ 00387 { 00388 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload " 00389 "in WAIT_FRAG_ACK state"); 00390 ret->ignore = TRUE; 00391 return NULL; 00392 } 00393 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged"); 00394 eap_ikev2_state(data, PROC_MSG); 00395 return eap_ikev2_build_msg(data, ret, id); 00396 } 00397 00398 if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) { 00399 ret->ignore = TRUE; 00400 return NULL; 00401 } 00402 00403 if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) { 00404 return eap_ikev2_process_fragment(data, ret, id, flags, 00405 message_length, pos, 00406 end - pos); 00407 } 00408 00409 if (data->in_buf == NULL) { 00410 /* Wrap unfragmented messages as wpabuf without extra copy */ 00411 wpabuf_set(&tmpbuf, pos, end - pos); 00412 data->in_buf = &tmpbuf; 00413 } 00414 00415 if (ikev2_responder_process(&data->ikev2, data->in_buf) < 0) { 00416 if (data->in_buf == &tmpbuf) 00417 data->in_buf = NULL; 00418 eap_ikev2_state(data, FAIL); 00419 return NULL; 00420 } 00421 00422 if (data->in_buf != &tmpbuf) 00423 wpabuf_free(data->in_buf); 00424 data->in_buf = NULL; 00425 00426 if (data->out_buf == NULL) { 00427 data->out_buf = ikev2_responder_build(&data->ikev2); 00428 if (data->out_buf == NULL) { 00429 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to generate " 00430 "IKEv2 message"); 00431 return NULL; 00432 } 00433 data->out_used = 0; 00434 } 00435 00436 eap_ikev2_state(data, PROC_MSG); 00437 return eap_ikev2_build_msg(data, ret, id); 00438 } 00439 00440 00441 static Boolean eap_ikev2_isKeyAvailable(struct eap_sm *sm, void *priv) 00442 { 00443 struct eap_ikev2_data *data = priv; 00444 return data->state == DONE && data->keymat_ok; 00445 } 00446 00447 00448 static u8 * eap_ikev2_getKey(struct eap_sm *sm, void *priv, size_t *len) 00449 { 00450 struct eap_ikev2_data *data = priv; 00451 u8 *key; 00452 00453 if (data->state != DONE || !data->keymat_ok) 00454 return NULL; 00455 00456 key = os_malloc(EAP_MSK_LEN); 00457 if (key) { 00458 os_memcpy(key, data->keymat, EAP_MSK_LEN); 00459 *len = EAP_MSK_LEN; 00460 } 00461 00462 return key; 00463 } 00464 00465 00466 static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 00467 { 00468 struct eap_ikev2_data *data = priv; 00469 u8 *key; 00470 00471 if (data->state != DONE || !data->keymat_ok) 00472 return NULL; 00473 00474 key = os_malloc(EAP_EMSK_LEN); 00475 if (key) { 00476 os_memcpy(key, data->keymat + EAP_MSK_LEN, EAP_EMSK_LEN); 00477 *len = EAP_EMSK_LEN; 00478 } 00479 00480 return key; 00481 } 00482 00483 00484 int eap_peer_ikev2_register(void) 00485 { 00486 struct eap_method *eap; 00487 int ret; 00488 00489 eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 00490 EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 00491 "IKEV2"); 00492 if (eap == NULL) 00493 return -1; 00494 00495 eap->init = eap_ikev2_init; 00496 eap->deinit = eap_ikev2_deinit; 00497 eap->process = eap_ikev2_process; 00498 eap->isKeyAvailable = eap_ikev2_isKeyAvailable; 00499 eap->getKey = eap_ikev2_getKey; 00500 eap->get_emsk = eap_ikev2_get_emsk; 00501 00502 ret = eap_peer_method_register(eap); 00503 if (ret) 00504 eap_peer_method_free(eap); 00505 return ret; 00506 }