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