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