1/* 2 * hostapd / EAP-SIM (RFC 4186) 3 * Copyright (c) 2005-2012, 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 "crypto/random.h" 13#include "eap_server/eap_i.h" 14#include "eap_common/eap_sim_common.h" 15#include "eap_server/eap_sim_db.h" 16 17 18struct eap_sim_data { 19 u8 mk[EAP_SIM_MK_LEN]; 20 u8 nonce_mt[EAP_SIM_NONCE_MT_LEN]; 21 u8 nonce_s[EAP_SIM_NONCE_S_LEN]; 22 u8 k_aut[EAP_SIM_K_AUT_LEN]; 23 u8 k_encr[EAP_SIM_K_ENCR_LEN]; 24 u8 msk[EAP_SIM_KEYING_DATA_LEN]; 25 u8 emsk[EAP_EMSK_LEN]; 26 u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN]; 27 u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN]; 28 u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN]; 29 int num_chal; 30 enum { 31 START, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE 32 } state; 33 char *next_pseudonym; 34 char *next_reauth_id; 35 u16 counter; 36 struct eap_sim_reauth *reauth; 37 u16 notification; 38 int use_result_ind; 39 int start_round; 40 char permanent[20]; /* Permanent username */ 41}; 42 43 44static const char * eap_sim_state_txt(int state) 45{ 46 switch (state) { 47 case START: 48 return "START"; 49 case CHALLENGE: 50 return "CHALLENGE"; 51 case REAUTH: 52 return "REAUTH"; 53 case SUCCESS: 54 return "SUCCESS"; 55 case FAILURE: 56 return "FAILURE"; 57 case NOTIFICATION: 58 return "NOTIFICATION"; 59 default: 60 return "Unknown?!"; 61 } 62} 63 64 65static void eap_sim_state(struct eap_sim_data *data, int state) 66{ 67 wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s", 68 eap_sim_state_txt(data->state), 69 eap_sim_state_txt(state)); 70 data->state = state; 71} 72 73 74static void * eap_sim_init(struct eap_sm *sm) 75{ 76 struct eap_sim_data *data; 77 78 if (sm->eap_sim_db_priv == NULL) { 79 wpa_printf(MSG_WARNING, "EAP-SIM: eap_sim_db not configured"); 80 return NULL; 81 } 82 83 data = os_zalloc(sizeof(*data)); 84 if (data == NULL) 85 return NULL; 86 data->state = START; 87 88 return data; 89} 90 91 92static void eap_sim_reset(struct eap_sm *sm, void *priv) 93{ 94 struct eap_sim_data *data = priv; 95 os_free(data->next_pseudonym); 96 os_free(data->next_reauth_id); 97 os_free(data); 98} 99 100 101static struct wpabuf * eap_sim_build_start(struct eap_sm *sm, 102 struct eap_sim_data *data, u8 id) 103{ 104 struct eap_sim_msg *msg; 105 u8 ver[2]; 106 107 wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Start"); 108 msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM, 109 EAP_SIM_SUBTYPE_START); 110 data->start_round++; 111 if (data->start_round == 1) { 112 /* 113 * RFC 4186, Chap. 4.2.4 recommends that identity from EAP is 114 * ignored and the SIM/Start is used to request the identity. 115 */ 116 wpa_printf(MSG_DEBUG, " AT_ANY_ID_REQ"); 117 eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0); 118 } else if (data->start_round > 3) { 119 /* Cannot use more than three rounds of Start messages */ 120 eap_sim_msg_free(msg); 121 return NULL; 122 } else if (data->start_round == 0) { 123 /* 124 * This is a special case that is used to recover from 125 * AT_COUNTER_TOO_SMALL during re-authentication. Since we 126 * already know the identity of the peer, there is no need to 127 * request any identity in this case. 128 */ 129 } else if (sm->identity && sm->identity_len > 0 && 130 sm->identity[0] == EAP_SIM_REAUTH_ID_PREFIX) { 131 /* Reauth id may have expired - try fullauth */ 132 wpa_printf(MSG_DEBUG, " AT_FULLAUTH_ID_REQ"); 133 eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0, NULL, 0); 134 } else { 135 wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ"); 136 eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0); 137 } 138 wpa_printf(MSG_DEBUG, " AT_VERSION_LIST"); 139 ver[0] = 0; 140 ver[1] = EAP_SIM_VERSION; 141 eap_sim_msg_add(msg, EAP_SIM_AT_VERSION_LIST, sizeof(ver), 142 ver, sizeof(ver)); 143 return eap_sim_msg_finish(msg, NULL, NULL, 0); 144} 145 146 147static int eap_sim_build_encr(struct eap_sm *sm, struct eap_sim_data *data, 148 struct eap_sim_msg *msg, u16 counter, 149 const u8 *nonce_s) 150{ 151 os_free(data->next_pseudonym); 152 if (nonce_s == NULL) { 153 data->next_pseudonym = 154 eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 155 EAP_SIM_DB_SIM); 156 } else { 157 /* Do not update pseudonym during re-authentication */ 158 data->next_pseudonym = NULL; 159 } 160 os_free(data->next_reauth_id); 161 if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) { 162 data->next_reauth_id = 163 eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 164 EAP_SIM_DB_SIM); 165 } else { 166 wpa_printf(MSG_DEBUG, "EAP-SIM: Max fast re-authentication " 167 "count exceeded - force full authentication"); 168 data->next_reauth_id = NULL; 169 } 170 171 if (data->next_pseudonym == NULL && data->next_reauth_id == NULL && 172 counter == 0 && nonce_s == NULL) 173 return 0; 174 175 wpa_printf(MSG_DEBUG, " AT_IV"); 176 wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); 177 eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA); 178 179 if (counter > 0) { 180 wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)", counter); 181 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0); 182 } 183 184 if (nonce_s) { 185 wpa_printf(MSG_DEBUG, " *AT_NONCE_S"); 186 eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s, 187 EAP_SIM_NONCE_S_LEN); 188 } 189 190 if (data->next_pseudonym) { 191 wpa_printf(MSG_DEBUG, " *AT_NEXT_PSEUDONYM (%s)", 192 data->next_pseudonym); 193 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM, 194 os_strlen(data->next_pseudonym), 195 (u8 *) data->next_pseudonym, 196 os_strlen(data->next_pseudonym)); 197 } 198 199 if (data->next_reauth_id) { 200 wpa_printf(MSG_DEBUG, " *AT_NEXT_REAUTH_ID (%s)", 201 data->next_reauth_id); 202 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID, 203 os_strlen(data->next_reauth_id), 204 (u8 *) data->next_reauth_id, 205 os_strlen(data->next_reauth_id)); 206 } 207 208 if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) { 209 wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt " 210 "AT_ENCR_DATA"); 211 return -1; 212 } 213 214 return 0; 215} 216 217 218static struct wpabuf * eap_sim_build_challenge(struct eap_sm *sm, 219 struct eap_sim_data *data, 220 u8 id) 221{ 222 struct eap_sim_msg *msg; 223 224 wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Challenge"); 225 msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM, 226 EAP_SIM_SUBTYPE_CHALLENGE); 227 wpa_printf(MSG_DEBUG, " AT_RAND"); 228 eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, (u8 *) data->rand, 229 data->num_chal * GSM_RAND_LEN); 230 231 if (eap_sim_build_encr(sm, data, msg, 0, NULL)) { 232 eap_sim_msg_free(msg); 233 return NULL; 234 } 235 236 if (sm->eap_sim_aka_result_ind) { 237 wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); 238 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); 239 } 240 241 wpa_printf(MSG_DEBUG, " AT_MAC"); 242 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); 243 return eap_sim_msg_finish(msg, data->k_aut, data->nonce_mt, 244 EAP_SIM_NONCE_MT_LEN); 245} 246 247 248static struct wpabuf * eap_sim_build_reauth(struct eap_sm *sm, 249 struct eap_sim_data *data, u8 id) 250{ 251 struct eap_sim_msg *msg; 252 253 wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Re-authentication"); 254 255 if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN)) 256 return NULL; 257 wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: NONCE_S", 258 data->nonce_s, EAP_SIM_NONCE_S_LEN); 259 260 eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk, 261 data->emsk); 262 eap_sim_derive_keys_reauth(data->counter, sm->identity, 263 sm->identity_len, data->nonce_s, data->mk, 264 data->msk, data->emsk); 265 266 msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM, 267 EAP_SIM_SUBTYPE_REAUTHENTICATION); 268 269 if (eap_sim_build_encr(sm, data, msg, data->counter, data->nonce_s)) { 270 eap_sim_msg_free(msg); 271 return NULL; 272 } 273 274 if (sm->eap_sim_aka_result_ind) { 275 wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); 276 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); 277 } 278 279 wpa_printf(MSG_DEBUG, " AT_MAC"); 280 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); 281 return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); 282} 283 284 285static struct wpabuf * eap_sim_build_notification(struct eap_sm *sm, 286 struct eap_sim_data *data, 287 u8 id) 288{ 289 struct eap_sim_msg *msg; 290 291 wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Notification"); 292 msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM, 293 EAP_SIM_SUBTYPE_NOTIFICATION); 294 wpa_printf(MSG_DEBUG, " AT_NOTIFICATION (%d)", data->notification); 295 eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification, 296 NULL, 0); 297 if (data->use_result_ind) { 298 if (data->reauth) { 299 wpa_printf(MSG_DEBUG, " AT_IV"); 300 wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); 301 eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, 302 EAP_SIM_AT_ENCR_DATA); 303 wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)", 304 data->counter); 305 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter, 306 NULL, 0); 307 308 if (eap_sim_msg_add_encr_end(msg, data->k_encr, 309 EAP_SIM_AT_PADDING)) { 310 wpa_printf(MSG_WARNING, "EAP-SIM: Failed to " 311 "encrypt AT_ENCR_DATA"); 312 eap_sim_msg_free(msg); 313 return NULL; 314 } 315 } 316 317 wpa_printf(MSG_DEBUG, " AT_MAC"); 318 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); 319 } 320 return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); 321} 322 323 324static struct wpabuf * eap_sim_buildReq(struct eap_sm *sm, void *priv, u8 id) 325{ 326 struct eap_sim_data *data = priv; 327 328 switch (data->state) { 329 case START: 330 return eap_sim_build_start(sm, data, id); 331 case CHALLENGE: 332 return eap_sim_build_challenge(sm, data, id); 333 case REAUTH: 334 return eap_sim_build_reauth(sm, data, id); 335 case NOTIFICATION: 336 return eap_sim_build_notification(sm, data, id); 337 default: 338 wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in " 339 "buildReq", data->state); 340 break; 341 } 342 return NULL; 343} 344 345 346static Boolean eap_sim_check(struct eap_sm *sm, void *priv, 347 struct wpabuf *respData) 348{ 349 const u8 *pos; 350 size_t len; 351 352 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len); 353 if (pos == NULL || len < 3) { 354 wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame"); 355 return TRUE; 356 } 357 358 return FALSE; 359} 360 361 362static Boolean eap_sim_unexpected_subtype(struct eap_sim_data *data, 363 u8 subtype) 364{ 365 if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) 366 return FALSE; 367 368 switch (data->state) { 369 case START: 370 if (subtype != EAP_SIM_SUBTYPE_START) { 371 wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response " 372 "subtype %d", subtype); 373 return TRUE; 374 } 375 break; 376 case CHALLENGE: 377 if (subtype != EAP_SIM_SUBTYPE_CHALLENGE) { 378 wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response " 379 "subtype %d", subtype); 380 return TRUE; 381 } 382 break; 383 case REAUTH: 384 if (subtype != EAP_SIM_SUBTYPE_REAUTHENTICATION) { 385 wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response " 386 "subtype %d", subtype); 387 return TRUE; 388 } 389 break; 390 case NOTIFICATION: 391 if (subtype != EAP_SIM_SUBTYPE_NOTIFICATION) { 392 wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response " 393 "subtype %d", subtype); 394 return TRUE; 395 } 396 break; 397 default: 398 wpa_printf(MSG_INFO, "EAP-SIM: Unexpected state (%d) for " 399 "processing a response", data->state); 400 return TRUE; 401 } 402 403 return FALSE; 404} 405 406 407static int eap_sim_supported_ver(struct eap_sim_data *data, int version) 408{ 409 return version == EAP_SIM_VERSION; 410} 411 412 413static void eap_sim_process_start(struct eap_sm *sm, 414 struct eap_sim_data *data, 415 struct wpabuf *respData, 416 struct eap_sim_attrs *attr) 417{ 418 size_t identity_len; 419 u8 ver_list[2]; 420 u8 *new_identity; 421 char *username; 422 423 wpa_printf(MSG_DEBUG, "EAP-SIM: Receive start response"); 424 425 if (data->start_round == 0) { 426 /* 427 * Special case for AT_COUNTER_TOO_SMALL recovery - no identity 428 * was requested since we already know it. 429 */ 430 goto skip_id_update; 431 } 432 433 /* 434 * We always request identity in SIM/Start, so the peer is required to 435 * have replied with one. 436 */ 437 if (!attr->identity || attr->identity_len == 0) { 438 wpa_printf(MSG_DEBUG, "EAP-SIM: Peer did not provide any " 439 "identity"); 440 goto failed; 441 } 442 443 new_identity = os_malloc(attr->identity_len); 444 if (new_identity == NULL) 445 goto failed; 446 os_free(sm->identity); 447 sm->identity = new_identity; 448 os_memcpy(sm->identity, attr->identity, attr->identity_len); 449 sm->identity_len = attr->identity_len; 450 451 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity", 452 sm->identity, sm->identity_len); 453 username = sim_get_username(sm->identity, sm->identity_len); 454 if (username == NULL) 455 goto failed; 456 457 if (username[0] == EAP_SIM_REAUTH_ID_PREFIX) { 458 wpa_printf(MSG_DEBUG, "EAP-SIM: Reauth username '%s'", 459 username); 460 data->reauth = eap_sim_db_get_reauth_entry( 461 sm->eap_sim_db_priv, username); 462 os_free(username); 463 if (data->reauth == NULL) { 464 wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown reauth " 465 "identity - request full auth identity"); 466 /* Remain in START state for another round */ 467 return; 468 } 469 wpa_printf(MSG_DEBUG, "EAP-SIM: Using fast re-authentication"); 470 os_strlcpy(data->permanent, data->reauth->permanent, 471 sizeof(data->permanent)); 472 data->counter = data->reauth->counter; 473 os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN); 474 eap_sim_state(data, REAUTH); 475 return; 476 } 477 478 if (username[0] == EAP_SIM_PSEUDONYM_PREFIX) { 479 const char *permanent; 480 wpa_printf(MSG_DEBUG, "EAP-SIM: Pseudonym username '%s'", 481 username); 482 permanent = eap_sim_db_get_permanent( 483 sm->eap_sim_db_priv, username); 484 os_free(username); 485 if (permanent == NULL) { 486 wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown pseudonym " 487 "identity - request permanent identity"); 488 /* Remain in START state for another round */ 489 return; 490 } 491 os_strlcpy(data->permanent, permanent, 492 sizeof(data->permanent)); 493 } else if (username[0] == EAP_SIM_PERMANENT_PREFIX) { 494 wpa_printf(MSG_DEBUG, "EAP-SIM: Permanent username '%s'", 495 username); 496 os_strlcpy(data->permanent, username, sizeof(data->permanent)); 497 os_free(username); 498 } else { 499 wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized username '%s'", 500 username); 501 os_free(username); 502 goto failed; 503 } 504 505skip_id_update: 506 /* Full authentication */ 507 508 if (attr->nonce_mt == NULL || attr->selected_version < 0) { 509 wpa_printf(MSG_DEBUG, "EAP-SIM: Start/Response missing " 510 "required attributes"); 511 goto failed; 512 } 513 514 if (!eap_sim_supported_ver(data, attr->selected_version)) { 515 wpa_printf(MSG_DEBUG, "EAP-SIM: Peer selected unsupported " 516 "version %d", attr->selected_version); 517 goto failed; 518 } 519 520 data->counter = 0; /* reset re-auth counter since this is full auth */ 521 data->reauth = NULL; 522 523 data->num_chal = eap_sim_db_get_gsm_triplets( 524 sm->eap_sim_db_priv, data->permanent, EAP_SIM_MAX_CHAL, 525 (u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm); 526 if (data->num_chal == EAP_SIM_DB_PENDING) { 527 wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets " 528 "not yet available - pending request"); 529 sm->method_pending = METHOD_PENDING_WAIT; 530 return; 531 } 532 if (data->num_chal < 2) { 533 wpa_printf(MSG_INFO, "EAP-SIM: Failed to get GSM " 534 "authentication triplets for the peer"); 535 goto failed; 536 } 537 538 identity_len = sm->identity_len; 539 while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') { 540 wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop last null " 541 "character from identity"); 542 identity_len--; 543 } 544 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity for MK derivation", 545 sm->identity, identity_len); 546 547 os_memcpy(data->nonce_mt, attr->nonce_mt, EAP_SIM_NONCE_MT_LEN); 548 WPA_PUT_BE16(ver_list, EAP_SIM_VERSION); 549 eap_sim_derive_mk(sm->identity, identity_len, attr->nonce_mt, 550 attr->selected_version, ver_list, sizeof(ver_list), 551 data->num_chal, (const u8 *) data->kc, data->mk); 552 eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk, 553 data->emsk); 554 555 eap_sim_state(data, CHALLENGE); 556 return; 557 558failed: 559 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 560 eap_sim_state(data, NOTIFICATION); 561} 562 563 564static void eap_sim_process_challenge(struct eap_sm *sm, 565 struct eap_sim_data *data, 566 struct wpabuf *respData, 567 struct eap_sim_attrs *attr) 568{ 569 if (attr->mac == NULL || 570 eap_sim_verify_mac(data->k_aut, respData, attr->mac, 571 (u8 *) data->sres, 572 data->num_chal * EAP_SIM_SRES_LEN)) { 573 wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message " 574 "did not include valid AT_MAC"); 575 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 576 eap_sim_state(data, NOTIFICATION); 577 return; 578 } 579 580 wpa_printf(MSG_DEBUG, "EAP-SIM: Challenge response includes the " 581 "correct AT_MAC"); 582 if (sm->eap_sim_aka_result_ind && attr->result_ind) { 583 data->use_result_ind = 1; 584 data->notification = EAP_SIM_SUCCESS; 585 eap_sim_state(data, NOTIFICATION); 586 } else 587 eap_sim_state(data, SUCCESS); 588 589 if (data->next_pseudonym) { 590 eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent, 591 data->next_pseudonym); 592 data->next_pseudonym = NULL; 593 } 594 if (data->next_reauth_id) { 595 eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent, 596 data->next_reauth_id, data->counter + 1, 597 data->mk); 598 data->next_reauth_id = NULL; 599 } 600} 601 602 603static void eap_sim_process_reauth(struct eap_sm *sm, 604 struct eap_sim_data *data, 605 struct wpabuf *respData, 606 struct eap_sim_attrs *attr) 607{ 608 struct eap_sim_attrs eattr; 609 u8 *decrypted = NULL; 610 611 if (attr->mac == NULL || 612 eap_sim_verify_mac(data->k_aut, respData, attr->mac, data->nonce_s, 613 EAP_SIM_NONCE_S_LEN)) { 614 wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message " 615 "did not include valid AT_MAC"); 616 goto fail; 617 } 618 619 if (attr->encr_data == NULL || attr->iv == NULL) { 620 wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication " 621 "message did not include encrypted data"); 622 goto fail; 623 } 624 625 decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, 626 attr->encr_data_len, attr->iv, &eattr, 627 0); 628 if (decrypted == NULL) { 629 wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted " 630 "data from reauthentication message"); 631 goto fail; 632 } 633 634 if (eattr.counter != data->counter) { 635 wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message " 636 "used incorrect counter %u, expected %u", 637 eattr.counter, data->counter); 638 goto fail; 639 } 640 os_free(decrypted); 641 decrypted = NULL; 642 643 wpa_printf(MSG_DEBUG, "EAP-SIM: Re-authentication response includes " 644 "the correct AT_MAC"); 645 646 if (eattr.counter_too_small) { 647 wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response " 648 "included AT_COUNTER_TOO_SMALL - starting full " 649 "authentication"); 650 data->start_round = -1; 651 eap_sim_state(data, START); 652 return; 653 } 654 655 if (sm->eap_sim_aka_result_ind && attr->result_ind) { 656 data->use_result_ind = 1; 657 data->notification = EAP_SIM_SUCCESS; 658 eap_sim_state(data, NOTIFICATION); 659 } else 660 eap_sim_state(data, SUCCESS); 661 662 if (data->next_reauth_id) { 663 eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent, 664 data->next_reauth_id, 665 data->counter + 1, data->mk); 666 data->next_reauth_id = NULL; 667 } else { 668 eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); 669 data->reauth = NULL; 670 } 671 672 return; 673 674fail: 675 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 676 eap_sim_state(data, NOTIFICATION); 677 eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); 678 data->reauth = NULL; 679 os_free(decrypted); 680} 681 682 683static void eap_sim_process_client_error(struct eap_sm *sm, 684 struct eap_sim_data *data, 685 struct wpabuf *respData, 686 struct eap_sim_attrs *attr) 687{ 688 wpa_printf(MSG_DEBUG, "EAP-SIM: Client reported error %d", 689 attr->client_error_code); 690 if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind) 691 eap_sim_state(data, SUCCESS); 692 else 693 eap_sim_state(data, FAILURE); 694} 695 696 697static void eap_sim_process_notification(struct eap_sm *sm, 698 struct eap_sim_data *data, 699 struct wpabuf *respData, 700 struct eap_sim_attrs *attr) 701{ 702 wpa_printf(MSG_DEBUG, "EAP-SIM: Client replied to notification"); 703 if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind) 704 eap_sim_state(data, SUCCESS); 705 else 706 eap_sim_state(data, FAILURE); 707} 708 709 710static void eap_sim_process(struct eap_sm *sm, void *priv, 711 struct wpabuf *respData) 712{ 713 struct eap_sim_data *data = priv; 714 const u8 *pos, *end; 715 u8 subtype; 716 size_t len; 717 struct eap_sim_attrs attr; 718 719 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len); 720 if (pos == NULL || len < 3) 721 return; 722 723 end = pos + len; 724 subtype = *pos; 725 pos += 3; 726 727 if (eap_sim_unexpected_subtype(data, subtype)) { 728 wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized or unexpected " 729 "EAP-SIM Subtype in EAP Response"); 730 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 731 eap_sim_state(data, NOTIFICATION); 732 return; 733 } 734 735 if (eap_sim_parse_attr(pos, end, &attr, 0, 0)) { 736 wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to parse attributes"); 737 if (subtype != EAP_SIM_SUBTYPE_CLIENT_ERROR && 738 (data->state == START || data->state == CHALLENGE || 739 data->state == REAUTH)) { 740 data->notification = 741 EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 742 eap_sim_state(data, NOTIFICATION); 743 return; 744 } 745 eap_sim_state(data, FAILURE); 746 return; 747 } 748 749 if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) { 750 eap_sim_process_client_error(sm, data, respData, &attr); 751 return; 752 } 753 754 switch (data->state) { 755 case START: 756 eap_sim_process_start(sm, data, respData, &attr); 757 break; 758 case CHALLENGE: 759 eap_sim_process_challenge(sm, data, respData, &attr); 760 break; 761 case REAUTH: 762 eap_sim_process_reauth(sm, data, respData, &attr); 763 break; 764 case NOTIFICATION: 765 eap_sim_process_notification(sm, data, respData, &attr); 766 break; 767 default: 768 wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in " 769 "process", data->state); 770 break; 771 } 772} 773 774 775static Boolean eap_sim_isDone(struct eap_sm *sm, void *priv) 776{ 777 struct eap_sim_data *data = priv; 778 return data->state == SUCCESS || data->state == FAILURE; 779} 780 781 782static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len) 783{ 784 struct eap_sim_data *data = priv; 785 u8 *key; 786 787 if (data->state != SUCCESS) 788 return NULL; 789 790 key = os_malloc(EAP_SIM_KEYING_DATA_LEN); 791 if (key == NULL) 792 return NULL; 793 os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN); 794 *len = EAP_SIM_KEYING_DATA_LEN; 795 return key; 796} 797 798 799static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 800{ 801 struct eap_sim_data *data = priv; 802 u8 *key; 803 804 if (data->state != SUCCESS) 805 return NULL; 806 807 key = os_malloc(EAP_EMSK_LEN); 808 if (key == NULL) 809 return NULL; 810 os_memcpy(key, data->emsk, EAP_EMSK_LEN); 811 *len = EAP_EMSK_LEN; 812 return key; 813} 814 815 816static Boolean eap_sim_isSuccess(struct eap_sm *sm, void *priv) 817{ 818 struct eap_sim_data *data = priv; 819 return data->state == SUCCESS; 820} 821 822 823int eap_server_sim_register(void) 824{ 825 struct eap_method *eap; 826 int ret; 827 828 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 829 EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM"); 830 if (eap == NULL) 831 return -1; 832 833 eap->init = eap_sim_init; 834 eap->reset = eap_sim_reset; 835 eap->buildReq = eap_sim_buildReq; 836 eap->check = eap_sim_check; 837 eap->process = eap_sim_process; 838 eap->isDone = eap_sim_isDone; 839 eap->getKey = eap_sim_getKey; 840 eap->isSuccess = eap_sim_isSuccess; 841 eap->get_emsk = eap_sim_get_emsk; 842 843 ret = eap_server_method_register(eap); 844 if (ret) 845 eap_server_method_free(eap); 846 return ret; 847} 848