eap_ikev2.c revision 5a1480c7c46c4236d93bfd303dde32062bee04ac
1/* 2 * EAP-IKEv2 peer (RFC 5106) 3 * Copyright (c) 2007-2014, Jouni Malinen <j@w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9#include "includes.h" 10 11#include "common.h" 12#include "eap_i.h" 13#include "eap_common/eap_ikev2_common.h" 14#include "ikev2.h" 15 16 17struct eap_ikev2_data { 18 struct ikev2_responder_data ikev2; 19 enum { WAIT_START, PROC_MSG, WAIT_FRAG_ACK, DONE, FAIL } state; 20 struct wpabuf *in_buf; 21 struct wpabuf *out_buf; 22 size_t out_used; 23 size_t fragment_size; 24 int keys_ready; 25 u8 keymat[EAP_MSK_LEN + EAP_EMSK_LEN]; 26 int keymat_ok; 27}; 28 29 30static const char * eap_ikev2_state_txt(int state) 31{ 32 switch (state) { 33 case WAIT_START: 34 return "WAIT_START"; 35 case PROC_MSG: 36 return "PROC_MSG"; 37 case WAIT_FRAG_ACK: 38 return "WAIT_FRAG_ACK"; 39 case DONE: 40 return "DONE"; 41 case FAIL: 42 return "FAIL"; 43 default: 44 return "?"; 45 } 46} 47 48 49static void eap_ikev2_state(struct eap_ikev2_data *data, int state) 50{ 51 wpa_printf(MSG_DEBUG, "EAP-IKEV2: %s -> %s", 52 eap_ikev2_state_txt(data->state), 53 eap_ikev2_state_txt(state)); 54 data->state = state; 55} 56 57 58static void * eap_ikev2_init(struct eap_sm *sm) 59{ 60 struct eap_ikev2_data *data; 61 const u8 *identity, *password; 62 size_t identity_len, password_len; 63 int fragment_size; 64 65 identity = eap_get_config_identity(sm, &identity_len); 66 if (identity == NULL) { 67 wpa_printf(MSG_INFO, "EAP-IKEV2: No identity available"); 68 return NULL; 69 } 70 71 data = os_zalloc(sizeof(*data)); 72 if (data == NULL) 73 return NULL; 74 data->state = WAIT_START; 75 fragment_size = eap_get_config_fragment_size(sm); 76 if (fragment_size <= 0) 77 data->fragment_size = IKEV2_FRAGMENT_SIZE; 78 else 79 data->fragment_size = fragment_size; 80 data->ikev2.state = SA_INIT; 81 data->ikev2.peer_auth = PEER_AUTH_SECRET; 82 data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2"); 83 if (data->ikev2.key_pad == NULL) 84 goto failed; 85 data->ikev2.key_pad_len = 21; 86 data->ikev2.IDr = os_malloc(identity_len); 87 if (data->ikev2.IDr == NULL) 88 goto failed; 89 os_memcpy(data->ikev2.IDr, identity, identity_len); 90 data->ikev2.IDr_len = identity_len; 91 92 password = eap_get_config_password(sm, &password_len); 93 if (password) { 94 data->ikev2.shared_secret = os_malloc(password_len); 95 if (data->ikev2.shared_secret == NULL) 96 goto failed; 97 os_memcpy(data->ikev2.shared_secret, password, password_len); 98 data->ikev2.shared_secret_len = password_len; 99 } 100 101 return data; 102 103failed: 104 ikev2_responder_deinit(&data->ikev2); 105 os_free(data); 106 return NULL; 107} 108 109 110static void eap_ikev2_deinit(struct eap_sm *sm, void *priv) 111{ 112 struct eap_ikev2_data *data = priv; 113 wpabuf_free(data->in_buf); 114 wpabuf_free(data->out_buf); 115 ikev2_responder_deinit(&data->ikev2); 116 os_free(data); 117} 118 119 120static int eap_ikev2_peer_keymat(struct eap_ikev2_data *data) 121{ 122 if (eap_ikev2_derive_keymat( 123 data->ikev2.proposal.prf, &data->ikev2.keys, 124 data->ikev2.i_nonce, data->ikev2.i_nonce_len, 125 data->ikev2.r_nonce, data->ikev2.r_nonce_len, 126 data->keymat) < 0) { 127 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to " 128 "derive key material"); 129 return -1; 130 } 131 data->keymat_ok = 1; 132 return 0; 133} 134 135 136static struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data, 137 struct eap_method_ret *ret, u8 id) 138{ 139 struct wpabuf *resp; 140 u8 flags; 141 size_t send_len, plen, icv_len = 0; 142 143 ret->ignore = FALSE; 144 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Generating Response"); 145 ret->allowNotifications = TRUE; 146 147 flags = 0; 148 send_len = wpabuf_len(data->out_buf) - data->out_used; 149 if (1 + send_len > data->fragment_size) { 150 send_len = data->fragment_size - 1; 151 flags |= IKEV2_FLAGS_MORE_FRAGMENTS; 152 if (data->out_used == 0) { 153 flags |= IKEV2_FLAGS_LENGTH_INCLUDED; 154 send_len -= 4; 155 } 156 } 157#ifdef CCNS_PL 158 /* Some issues figuring out the length of the message if Message Length 159 * field not included?! */ 160 if (!(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) 161 flags |= IKEV2_FLAGS_LENGTH_INCLUDED; 162#endif /* CCNS_PL */ 163 164 plen = 1 + send_len; 165 if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) 166 plen += 4; 167 if (data->keys_ready) { 168 const struct ikev2_integ_alg *integ; 169 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Add Integrity Checksum " 170 "Data"); 171 flags |= IKEV2_FLAGS_ICV_INCLUDED; 172 integ = ikev2_get_integ(data->ikev2.proposal.integ); 173 if (integ == NULL) { 174 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG " 175 "transform / cannot generate ICV"); 176 return NULL; 177 } 178 icv_len = integ->hash_len; 179 180 plen += icv_len; 181 } 182 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, plen, 183 EAP_CODE_RESPONSE, id); 184 if (resp == NULL) 185 return NULL; 186 187 wpabuf_put_u8(resp, flags); /* Flags */ 188 if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) 189 wpabuf_put_be32(resp, wpabuf_len(data->out_buf)); 190 191 wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used, 192 send_len); 193 data->out_used += send_len; 194 195 if (flags & IKEV2_FLAGS_ICV_INCLUDED) { 196 const u8 *msg = wpabuf_head(resp); 197 size_t len = wpabuf_len(resp); 198 ikev2_integ_hash(data->ikev2.proposal.integ, 199 data->ikev2.keys.SK_ar, 200 data->ikev2.keys.SK_integ_len, 201 msg, len, wpabuf_put(resp, icv_len)); 202 } 203 204 ret->methodState = METHOD_MAY_CONT; 205 ret->decision = DECISION_FAIL; 206 207 if (data->out_used == wpabuf_len(data->out_buf)) { 208 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes " 209 "(message sent completely)", 210 (unsigned long) send_len); 211 wpabuf_free(data->out_buf); 212 data->out_buf = NULL; 213 data->out_used = 0; 214 switch (data->ikev2.state) { 215 case SA_AUTH: 216 /* SA_INIT was sent out, so message have to be 217 * integrity protected from now on. */ 218 data->keys_ready = 1; 219 break; 220 case IKEV2_DONE: 221 ret->methodState = METHOD_DONE; 222 if (data->state == FAIL) 223 break; 224 ret->decision = DECISION_COND_SUCC; 225 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication " 226 "completed successfully"); 227 if (eap_ikev2_peer_keymat(data)) 228 break; 229 eap_ikev2_state(data, DONE); 230 break; 231 case IKEV2_FAILED: 232 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication " 233 "failed"); 234 ret->methodState = METHOD_DONE; 235 ret->decision = DECISION_FAIL; 236 break; 237 default: 238 break; 239 } 240 } else { 241 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes " 242 "(%lu more to send)", (unsigned long) send_len, 243 (unsigned long) wpabuf_len(data->out_buf) - 244 data->out_used); 245 eap_ikev2_state(data, WAIT_FRAG_ACK); 246 } 247 248 return resp; 249} 250 251 252static int eap_ikev2_process_icv(struct eap_ikev2_data *data, 253 const struct wpabuf *reqData, 254 u8 flags, const u8 *pos, const u8 **end, 255 int frag_ack) 256{ 257 if (flags & IKEV2_FLAGS_ICV_INCLUDED) { 258 int icv_len = eap_ikev2_validate_icv( 259 data->ikev2.proposal.integ, &data->ikev2.keys, 1, 260 reqData, pos, *end); 261 if (icv_len < 0) 262 return -1; 263 /* Hide Integrity Checksum Data from further processing */ 264 *end -= icv_len; 265 } else if (data->keys_ready && !frag_ack) { 266 wpa_printf(MSG_INFO, "EAP-IKEV2: The message should have " 267 "included integrity checksum"); 268 return -1; 269 } 270 271 return 0; 272} 273 274 275static int eap_ikev2_process_cont(struct eap_ikev2_data *data, 276 const u8 *buf, size_t len) 277{ 278 /* Process continuation of a pending message */ 279 if (len > wpabuf_tailroom(data->in_buf)) { 280 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment overflow"); 281 eap_ikev2_state(data, FAIL); 282 return -1; 283 } 284 285 wpabuf_put_data(data->in_buf, buf, len); 286 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes, waiting " 287 "for %lu bytes more", (unsigned long) len, 288 (unsigned long) wpabuf_tailroom(data->in_buf)); 289 290 return 0; 291} 292 293 294static struct wpabuf * eap_ikev2_process_fragment(struct eap_ikev2_data *data, 295 struct eap_method_ret *ret, 296 u8 id, u8 flags, 297 u32 message_length, 298 const u8 *buf, size_t len) 299{ 300 /* Process a fragment that is not the last one of the message */ 301 if (data->in_buf == NULL && !(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) { 302 wpa_printf(MSG_DEBUG, "EAP-IKEV2: No Message Length field in " 303 "a fragmented packet"); 304 ret->ignore = TRUE; 305 return NULL; 306 } 307 308 if (data->in_buf == NULL) { 309 /* First fragment of the message */ 310 data->in_buf = wpabuf_alloc(message_length); 311 if (data->in_buf == NULL) { 312 wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for " 313 "message"); 314 ret->ignore = TRUE; 315 return NULL; 316 } 317 wpabuf_put_data(data->in_buf, buf, len); 318 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes in first " 319 "fragment, waiting for %lu bytes more", 320 (unsigned long) len, 321 (unsigned long) wpabuf_tailroom(data->in_buf)); 322 } 323 324 return eap_ikev2_build_frag_ack(id, EAP_CODE_RESPONSE); 325} 326 327 328static struct wpabuf * eap_ikev2_process(struct eap_sm *sm, void *priv, 329 struct eap_method_ret *ret, 330 const struct wpabuf *reqData) 331{ 332 struct eap_ikev2_data *data = priv; 333 const u8 *start, *pos, *end; 334 size_t len; 335 u8 flags, id; 336 u32 message_length = 0; 337 struct wpabuf tmpbuf; 338 339 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, reqData, &len); 340 if (pos == NULL) { 341 ret->ignore = TRUE; 342 return NULL; 343 } 344 345 id = eap_get_id(reqData); 346 347 start = pos; 348 end = start + len; 349 350 if (len == 0) 351 flags = 0; /* fragment ack */ 352 else 353 flags = *pos++; 354 355 if (eap_ikev2_process_icv(data, reqData, flags, pos, &end, 356 data->state == WAIT_FRAG_ACK && len == 0) < 0) 357 { 358 ret->ignore = TRUE; 359 return NULL; 360 } 361 362 if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) { 363 if (end - pos < 4) { 364 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow"); 365 ret->ignore = TRUE; 366 return NULL; 367 } 368 message_length = WPA_GET_BE32(pos); 369 pos += 4; 370 371 if (message_length < (u32) (end - pos)) { 372 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message " 373 "Length (%d; %ld remaining in this msg)", 374 message_length, (long) (end - pos)); 375 ret->ignore = TRUE; 376 return NULL; 377 } 378 } 379 380 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x " 381 "Message Length %u", flags, message_length); 382 383 if (data->state == WAIT_FRAG_ACK) { 384#ifdef CCNS_PL 385 if (len > 1) /* Empty Flags field included in ACK */ 386#else /* CCNS_PL */ 387 if (len != 0) 388#endif /* CCNS_PL */ 389 { 390 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload " 391 "in WAIT_FRAG_ACK state"); 392 ret->ignore = TRUE; 393 return NULL; 394 } 395 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged"); 396 eap_ikev2_state(data, PROC_MSG); 397 return eap_ikev2_build_msg(data, ret, id); 398 } 399 400 if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) { 401 ret->ignore = TRUE; 402 return NULL; 403 } 404 405 if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) { 406 return eap_ikev2_process_fragment(data, ret, id, flags, 407 message_length, pos, 408 end - pos); 409 } 410 411 if (data->in_buf == NULL) { 412 /* Wrap unfragmented messages as wpabuf without extra copy */ 413 wpabuf_set(&tmpbuf, pos, end - pos); 414 data->in_buf = &tmpbuf; 415 } 416 417 if (ikev2_responder_process(&data->ikev2, data->in_buf) < 0) { 418 if (data->in_buf == &tmpbuf) 419 data->in_buf = NULL; 420 eap_ikev2_state(data, FAIL); 421 return NULL; 422 } 423 424 if (data->in_buf != &tmpbuf) 425 wpabuf_free(data->in_buf); 426 data->in_buf = NULL; 427 428 if (data->out_buf == NULL) { 429 data->out_buf = ikev2_responder_build(&data->ikev2); 430 if (data->out_buf == NULL) { 431 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to generate " 432 "IKEv2 message"); 433 return NULL; 434 } 435 data->out_used = 0; 436 } 437 438 eap_ikev2_state(data, PROC_MSG); 439 return eap_ikev2_build_msg(data, ret, id); 440} 441 442 443static Boolean eap_ikev2_isKeyAvailable(struct eap_sm *sm, void *priv) 444{ 445 struct eap_ikev2_data *data = priv; 446 return data->state == DONE && data->keymat_ok; 447} 448 449 450static u8 * eap_ikev2_getKey(struct eap_sm *sm, void *priv, size_t *len) 451{ 452 struct eap_ikev2_data *data = priv; 453 u8 *key; 454 455 if (data->state != DONE || !data->keymat_ok) 456 return NULL; 457 458 key = os_malloc(EAP_MSK_LEN); 459 if (key) { 460 os_memcpy(key, data->keymat, EAP_MSK_LEN); 461 *len = EAP_MSK_LEN; 462 } 463 464 return key; 465} 466 467 468static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 469{ 470 struct eap_ikev2_data *data = priv; 471 u8 *key; 472 473 if (data->state != DONE || !data->keymat_ok) 474 return NULL; 475 476 key = os_malloc(EAP_EMSK_LEN); 477 if (key) { 478 os_memcpy(key, data->keymat + EAP_MSK_LEN, EAP_EMSK_LEN); 479 *len = EAP_EMSK_LEN; 480 } 481 482 return key; 483} 484 485 486static u8 * eap_ikev2_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 487{ 488 struct eap_ikev2_data *data = priv; 489 u8 *sid; 490 size_t sid_len; 491 size_t offset; 492 493 if (data->state != DONE || !data->keymat_ok) 494 return NULL; 495 496 sid_len = 1 + data->ikev2.i_nonce_len + data->ikev2.r_nonce_len; 497 sid = os_malloc(sid_len); 498 if (sid) { 499 offset = 0; 500 sid[offset] = EAP_TYPE_IKEV2; 501 offset++; 502 os_memcpy(sid + offset, data->ikev2.i_nonce, 503 data->ikev2.i_nonce_len); 504 offset += data->ikev2.i_nonce_len; 505 os_memcpy(sid + offset, data->ikev2.r_nonce, 506 data->ikev2.r_nonce_len); 507 *len = sid_len; 508 wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Derived Session-Id", 509 sid, sid_len); 510 } 511 512 return sid; 513} 514 515 516int eap_peer_ikev2_register(void) 517{ 518 struct eap_method *eap; 519 int ret; 520 521 eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 522 EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 523 "IKEV2"); 524 if (eap == NULL) 525 return -1; 526 527 eap->init = eap_ikev2_init; 528 eap->deinit = eap_ikev2_deinit; 529 eap->process = eap_ikev2_process; 530 eap->isKeyAvailable = eap_ikev2_isKeyAvailable; 531 eap->getKey = eap_ikev2_getKey; 532 eap->get_emsk = eap_ikev2_get_emsk; 533 eap->getSessionId = eap_ikev2_get_session_id; 534 535 ret = eap_peer_method_register(eap); 536 if (ret) 537 eap_peer_method_free(eap); 538 return ret; 539} 540