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 bin_clear_free(data, sizeof(*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 158 plen = 1 + send_len; 159 if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) 160 plen += 4; 161 if (data->keys_ready) { 162 const struct ikev2_integ_alg *integ; 163 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Add Integrity Checksum " 164 "Data"); 165 flags |= IKEV2_FLAGS_ICV_INCLUDED; 166 integ = ikev2_get_integ(data->ikev2.proposal.integ); 167 if (integ == NULL) { 168 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG " 169 "transform / cannot generate ICV"); 170 return NULL; 171 } 172 icv_len = integ->hash_len; 173 174 plen += icv_len; 175 } 176 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, plen, 177 EAP_CODE_RESPONSE, id); 178 if (resp == NULL) 179 return NULL; 180 181 wpabuf_put_u8(resp, flags); /* Flags */ 182 if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) 183 wpabuf_put_be32(resp, wpabuf_len(data->out_buf)); 184 185 wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used, 186 send_len); 187 data->out_used += send_len; 188 189 if (flags & IKEV2_FLAGS_ICV_INCLUDED) { 190 const u8 *msg = wpabuf_head(resp); 191 size_t len = wpabuf_len(resp); 192 ikev2_integ_hash(data->ikev2.proposal.integ, 193 data->ikev2.keys.SK_ar, 194 data->ikev2.keys.SK_integ_len, 195 msg, len, wpabuf_put(resp, icv_len)); 196 } 197 198 ret->methodState = METHOD_MAY_CONT; 199 ret->decision = DECISION_FAIL; 200 201 if (data->out_used == wpabuf_len(data->out_buf)) { 202 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes " 203 "(message sent completely)", 204 (unsigned long) send_len); 205 wpabuf_free(data->out_buf); 206 data->out_buf = NULL; 207 data->out_used = 0; 208 switch (data->ikev2.state) { 209 case SA_AUTH: 210 /* SA_INIT was sent out, so message have to be 211 * integrity protected from now on. */ 212 data->keys_ready = 1; 213 break; 214 case IKEV2_DONE: 215 ret->methodState = METHOD_DONE; 216 if (data->state == FAIL) 217 break; 218 ret->decision = DECISION_COND_SUCC; 219 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication " 220 "completed successfully"); 221 if (eap_ikev2_peer_keymat(data)) 222 break; 223 eap_ikev2_state(data, DONE); 224 break; 225 case IKEV2_FAILED: 226 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication " 227 "failed"); 228 ret->methodState = METHOD_DONE; 229 ret->decision = DECISION_FAIL; 230 break; 231 default: 232 break; 233 } 234 } else { 235 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes " 236 "(%lu more to send)", (unsigned long) send_len, 237 (unsigned long) wpabuf_len(data->out_buf) - 238 data->out_used); 239 eap_ikev2_state(data, WAIT_FRAG_ACK); 240 } 241 242 return resp; 243} 244 245 246static int eap_ikev2_process_icv(struct eap_ikev2_data *data, 247 const struct wpabuf *reqData, 248 u8 flags, const u8 *pos, const u8 **end, 249 int frag_ack) 250{ 251 if (flags & IKEV2_FLAGS_ICV_INCLUDED) { 252 int icv_len = eap_ikev2_validate_icv( 253 data->ikev2.proposal.integ, &data->ikev2.keys, 1, 254 reqData, pos, *end); 255 if (icv_len < 0) 256 return -1; 257 /* Hide Integrity Checksum Data from further processing */ 258 *end -= icv_len; 259 } else if (data->keys_ready && !frag_ack) { 260 wpa_printf(MSG_INFO, "EAP-IKEV2: The message should have " 261 "included integrity checksum"); 262 return -1; 263 } 264 265 return 0; 266} 267 268 269static int eap_ikev2_process_cont(struct eap_ikev2_data *data, 270 const u8 *buf, size_t len) 271{ 272 /* Process continuation of a pending message */ 273 if (len > wpabuf_tailroom(data->in_buf)) { 274 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment overflow"); 275 eap_ikev2_state(data, FAIL); 276 return -1; 277 } 278 279 wpabuf_put_data(data->in_buf, buf, len); 280 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes, waiting " 281 "for %lu bytes more", (unsigned long) len, 282 (unsigned long) wpabuf_tailroom(data->in_buf)); 283 284 return 0; 285} 286 287 288static struct wpabuf * eap_ikev2_process_fragment(struct eap_ikev2_data *data, 289 struct eap_method_ret *ret, 290 u8 id, u8 flags, 291 u32 message_length, 292 const u8 *buf, size_t len) 293{ 294 /* Process a fragment that is not the last one of the message */ 295 if (data->in_buf == NULL && !(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) { 296 wpa_printf(MSG_DEBUG, "EAP-IKEV2: No Message Length field in " 297 "a fragmented packet"); 298 ret->ignore = TRUE; 299 return NULL; 300 } 301 302 if (data->in_buf == NULL) { 303 /* First fragment of the message */ 304 if (message_length > 50000) { 305 /* Limit maximum memory allocation */ 306 wpa_printf(MSG_DEBUG, 307 "EAP-IKEV2: Ignore too long message"); 308 ret->ignore = TRUE; 309 return NULL; 310 } 311 data->in_buf = wpabuf_alloc(message_length); 312 if (data->in_buf == NULL) { 313 wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for " 314 "message"); 315 ret->ignore = TRUE; 316 return NULL; 317 } 318 wpabuf_put_data(data->in_buf, buf, len); 319 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes in first " 320 "fragment, waiting for %lu bytes more", 321 (unsigned long) len, 322 (unsigned long) wpabuf_tailroom(data->in_buf)); 323 } 324 325 ret->ignore = FALSE; 326 return eap_ikev2_build_frag_ack(id, EAP_CODE_RESPONSE); 327} 328 329 330static struct wpabuf * eap_ikev2_process(struct eap_sm *sm, void *priv, 331 struct eap_method_ret *ret, 332 const struct wpabuf *reqData) 333{ 334 struct eap_ikev2_data *data = priv; 335 const u8 *start, *pos, *end; 336 size_t len; 337 u8 flags, id; 338 u32 message_length = 0; 339 struct wpabuf tmpbuf; 340 341 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, reqData, &len); 342 if (pos == NULL) { 343 ret->ignore = TRUE; 344 return NULL; 345 } 346 347 id = eap_get_id(reqData); 348 349 start = pos; 350 end = start + len; 351 352 if (len == 0) 353 flags = 0; /* fragment ack */ 354 else 355 flags = *pos++; 356 357 if (eap_ikev2_process_icv(data, reqData, flags, pos, &end, 358 data->state == WAIT_FRAG_ACK && len == 0) < 0) 359 { 360 ret->ignore = TRUE; 361 return NULL; 362 } 363 364 if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) { 365 if (end - pos < 4) { 366 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow"); 367 ret->ignore = TRUE; 368 return NULL; 369 } 370 message_length = WPA_GET_BE32(pos); 371 pos += 4; 372 373 if (message_length < (u32) (end - pos)) { 374 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message " 375 "Length (%d; %ld remaining in this msg)", 376 message_length, (long) (end - pos)); 377 ret->ignore = TRUE; 378 return NULL; 379 } 380 } 381 382 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x " 383 "Message Length %u", flags, message_length); 384 385 if (data->state == WAIT_FRAG_ACK) { 386 if (len != 0) { 387 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload " 388 "in WAIT_FRAG_ACK state"); 389 ret->ignore = TRUE; 390 return NULL; 391 } 392 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged"); 393 eap_ikev2_state(data, PROC_MSG); 394 return eap_ikev2_build_msg(data, ret, id); 395 } 396 397 if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) { 398 ret->ignore = TRUE; 399 return NULL; 400 } 401 402 if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) { 403 return eap_ikev2_process_fragment(data, ret, id, flags, 404 message_length, pos, 405 end - pos); 406 } 407 408 if (data->in_buf == NULL) { 409 /* Wrap unfragmented messages as wpabuf without extra copy */ 410 wpabuf_set(&tmpbuf, pos, end - pos); 411 data->in_buf = &tmpbuf; 412 } 413 414 if (ikev2_responder_process(&data->ikev2, data->in_buf) < 0) { 415 if (data->in_buf == &tmpbuf) 416 data->in_buf = NULL; 417 eap_ikev2_state(data, FAIL); 418 return NULL; 419 } 420 421 if (data->in_buf != &tmpbuf) 422 wpabuf_free(data->in_buf); 423 data->in_buf = NULL; 424 425 if (data->out_buf == NULL) { 426 data->out_buf = ikev2_responder_build(&data->ikev2); 427 if (data->out_buf == NULL) { 428 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to generate " 429 "IKEv2 message"); 430 return NULL; 431 } 432 data->out_used = 0; 433 } 434 435 eap_ikev2_state(data, PROC_MSG); 436 return eap_ikev2_build_msg(data, ret, id); 437} 438 439 440static Boolean eap_ikev2_isKeyAvailable(struct eap_sm *sm, void *priv) 441{ 442 struct eap_ikev2_data *data = priv; 443 return data->state == DONE && data->keymat_ok; 444} 445 446 447static u8 * eap_ikev2_getKey(struct eap_sm *sm, void *priv, size_t *len) 448{ 449 struct eap_ikev2_data *data = priv; 450 u8 *key; 451 452 if (data->state != DONE || !data->keymat_ok) 453 return NULL; 454 455 key = os_malloc(EAP_MSK_LEN); 456 if (key) { 457 os_memcpy(key, data->keymat, EAP_MSK_LEN); 458 *len = EAP_MSK_LEN; 459 } 460 461 return key; 462} 463 464 465static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 466{ 467 struct eap_ikev2_data *data = priv; 468 u8 *key; 469 470 if (data->state != DONE || !data->keymat_ok) 471 return NULL; 472 473 key = os_malloc(EAP_EMSK_LEN); 474 if (key) { 475 os_memcpy(key, data->keymat + EAP_MSK_LEN, EAP_EMSK_LEN); 476 *len = EAP_EMSK_LEN; 477 } 478 479 return key; 480} 481 482 483static u8 * eap_ikev2_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 484{ 485 struct eap_ikev2_data *data = priv; 486 u8 *sid; 487 size_t sid_len; 488 size_t offset; 489 490 if (data->state != DONE || !data->keymat_ok) 491 return NULL; 492 493 sid_len = 1 + data->ikev2.i_nonce_len + data->ikev2.r_nonce_len; 494 sid = os_malloc(sid_len); 495 if (sid) { 496 offset = 0; 497 sid[offset] = EAP_TYPE_IKEV2; 498 offset++; 499 os_memcpy(sid + offset, data->ikev2.i_nonce, 500 data->ikev2.i_nonce_len); 501 offset += data->ikev2.i_nonce_len; 502 os_memcpy(sid + offset, data->ikev2.r_nonce, 503 data->ikev2.r_nonce_len); 504 *len = sid_len; 505 wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Derived Session-Id", 506 sid, sid_len); 507 } 508 509 return sid; 510} 511 512 513int eap_peer_ikev2_register(void) 514{ 515 struct eap_method *eap; 516 517 eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 518 EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 519 "IKEV2"); 520 if (eap == NULL) 521 return -1; 522 523 eap->init = eap_ikev2_init; 524 eap->deinit = eap_ikev2_deinit; 525 eap->process = eap_ikev2_process; 526 eap->isKeyAvailable = eap_ikev2_isKeyAvailable; 527 eap->getKey = eap_ikev2_getKey; 528 eap->get_emsk = eap_ikev2_get_emsk; 529 eap->getSessionId = eap_ikev2_get_session_id; 530 531 return eap_peer_method_register(eap); 532} 533