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 18 struct 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 44 static 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 65 static 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 74 static 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 92 static 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 bin_clear_free(data, sizeof(*data)); 98 } 99 100 101 static 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, EAP_TYPE_SIM, NULL, NULL, 0); 144 } 145 146 147 static 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 218 static 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, EAP_TYPE_SIM, data->k_aut, 244 data->nonce_mt, EAP_SIM_NONCE_MT_LEN); 245 } 246 247 248 static 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, EAP_TYPE_SIM, data->k_aut, NULL, 0); 282 } 283 284 285 static 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, EAP_TYPE_SIM, data->k_aut, NULL, 0); 321 } 322 323 324 static 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 346 static 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 362 static 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 407 static int eap_sim_supported_ver(struct eap_sim_data *data, int version) 408 { 409 return version == EAP_SIM_VERSION; 410 } 411 412 413 static 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 505 skip_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 if (data->permanent[0] == EAP_SIM_PERMANENT_PREFIX) 539 os_strlcpy(sm->imsi, &data->permanent[1], sizeof(sm->imsi)); 540 541 identity_len = sm->identity_len; 542 while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') { 543 wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop last null " 544 "character from identity"); 545 identity_len--; 546 } 547 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity for MK derivation", 548 sm->identity, identity_len); 549 550 os_memcpy(data->nonce_mt, attr->nonce_mt, EAP_SIM_NONCE_MT_LEN); 551 WPA_PUT_BE16(ver_list, EAP_SIM_VERSION); 552 eap_sim_derive_mk(sm->identity, identity_len, attr->nonce_mt, 553 attr->selected_version, ver_list, sizeof(ver_list), 554 data->num_chal, (const u8 *) data->kc, data->mk); 555 eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk, 556 data->emsk); 557 558 eap_sim_state(data, CHALLENGE); 559 return; 560 561 failed: 562 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 563 eap_sim_state(data, NOTIFICATION); 564 } 565 566 567 static void eap_sim_process_challenge(struct eap_sm *sm, 568 struct eap_sim_data *data, 569 struct wpabuf *respData, 570 struct eap_sim_attrs *attr) 571 { 572 if (attr->mac == NULL || 573 eap_sim_verify_mac(data->k_aut, respData, attr->mac, 574 (u8 *) data->sres, 575 data->num_chal * EAP_SIM_SRES_LEN)) { 576 wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message " 577 "did not include valid AT_MAC"); 578 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 579 eap_sim_state(data, NOTIFICATION); 580 return; 581 } 582 583 wpa_printf(MSG_DEBUG, "EAP-SIM: Challenge response includes the " 584 "correct AT_MAC"); 585 if (sm->eap_sim_aka_result_ind && attr->result_ind) { 586 data->use_result_ind = 1; 587 data->notification = EAP_SIM_SUCCESS; 588 eap_sim_state(data, NOTIFICATION); 589 } else 590 eap_sim_state(data, SUCCESS); 591 592 if (data->next_pseudonym) { 593 eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent, 594 data->next_pseudonym); 595 data->next_pseudonym = NULL; 596 } 597 if (data->next_reauth_id) { 598 eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent, 599 data->next_reauth_id, data->counter + 1, 600 data->mk); 601 data->next_reauth_id = NULL; 602 } 603 } 604 605 606 static void eap_sim_process_reauth(struct eap_sm *sm, 607 struct eap_sim_data *data, 608 struct wpabuf *respData, 609 struct eap_sim_attrs *attr) 610 { 611 struct eap_sim_attrs eattr; 612 u8 *decrypted = NULL; 613 614 if (attr->mac == NULL || 615 eap_sim_verify_mac(data->k_aut, respData, attr->mac, data->nonce_s, 616 EAP_SIM_NONCE_S_LEN)) { 617 wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message " 618 "did not include valid AT_MAC"); 619 goto fail; 620 } 621 622 if (attr->encr_data == NULL || attr->iv == NULL) { 623 wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication " 624 "message did not include encrypted data"); 625 goto fail; 626 } 627 628 decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, 629 attr->encr_data_len, attr->iv, &eattr, 630 0); 631 if (decrypted == NULL) { 632 wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted " 633 "data from reauthentication message"); 634 goto fail; 635 } 636 637 if (eattr.counter != data->counter) { 638 wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message " 639 "used incorrect counter %u, expected %u", 640 eattr.counter, data->counter); 641 goto fail; 642 } 643 os_free(decrypted); 644 decrypted = NULL; 645 646 wpa_printf(MSG_DEBUG, "EAP-SIM: Re-authentication response includes " 647 "the correct AT_MAC"); 648 649 if (eattr.counter_too_small) { 650 wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response " 651 "included AT_COUNTER_TOO_SMALL - starting full " 652 "authentication"); 653 data->start_round = -1; 654 eap_sim_state(data, START); 655 return; 656 } 657 658 if (sm->eap_sim_aka_result_ind && attr->result_ind) { 659 data->use_result_ind = 1; 660 data->notification = EAP_SIM_SUCCESS; 661 eap_sim_state(data, NOTIFICATION); 662 } else 663 eap_sim_state(data, SUCCESS); 664 665 if (data->next_reauth_id) { 666 eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent, 667 data->next_reauth_id, 668 data->counter + 1, data->mk); 669 data->next_reauth_id = NULL; 670 } else { 671 eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); 672 data->reauth = NULL; 673 } 674 675 return; 676 677 fail: 678 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 679 eap_sim_state(data, NOTIFICATION); 680 eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); 681 data->reauth = NULL; 682 os_free(decrypted); 683 } 684 685 686 static void eap_sim_process_client_error(struct eap_sm *sm, 687 struct eap_sim_data *data, 688 struct wpabuf *respData, 689 struct eap_sim_attrs *attr) 690 { 691 wpa_printf(MSG_DEBUG, "EAP-SIM: Client reported error %d", 692 attr->client_error_code); 693 if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind) 694 eap_sim_state(data, SUCCESS); 695 else 696 eap_sim_state(data, FAILURE); 697 } 698 699 700 static void eap_sim_process_notification(struct eap_sm *sm, 701 struct eap_sim_data *data, 702 struct wpabuf *respData, 703 struct eap_sim_attrs *attr) 704 { 705 wpa_printf(MSG_DEBUG, "EAP-SIM: Client replied to notification"); 706 if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind) 707 eap_sim_state(data, SUCCESS); 708 else 709 eap_sim_state(data, FAILURE); 710 } 711 712 713 static void eap_sim_process(struct eap_sm *sm, void *priv, 714 struct wpabuf *respData) 715 { 716 struct eap_sim_data *data = priv; 717 const u8 *pos, *end; 718 u8 subtype; 719 size_t len; 720 struct eap_sim_attrs attr; 721 722 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len); 723 if (pos == NULL || len < 3) 724 return; 725 726 end = pos + len; 727 subtype = *pos; 728 pos += 3; 729 730 if (eap_sim_unexpected_subtype(data, subtype)) { 731 wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized or unexpected " 732 "EAP-SIM Subtype in EAP Response"); 733 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 734 eap_sim_state(data, NOTIFICATION); 735 return; 736 } 737 738 if (eap_sim_parse_attr(pos, end, &attr, 0, 0)) { 739 wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to parse attributes"); 740 if (subtype != EAP_SIM_SUBTYPE_CLIENT_ERROR && 741 (data->state == START || data->state == CHALLENGE || 742 data->state == REAUTH)) { 743 data->notification = 744 EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 745 eap_sim_state(data, NOTIFICATION); 746 return; 747 } 748 eap_sim_state(data, FAILURE); 749 return; 750 } 751 752 if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) { 753 eap_sim_process_client_error(sm, data, respData, &attr); 754 return; 755 } 756 757 switch (data->state) { 758 case START: 759 eap_sim_process_start(sm, data, respData, &attr); 760 break; 761 case CHALLENGE: 762 eap_sim_process_challenge(sm, data, respData, &attr); 763 break; 764 case REAUTH: 765 eap_sim_process_reauth(sm, data, respData, &attr); 766 break; 767 case NOTIFICATION: 768 eap_sim_process_notification(sm, data, respData, &attr); 769 break; 770 default: 771 wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in " 772 "process", data->state); 773 break; 774 } 775 } 776 777 778 static Boolean eap_sim_isDone(struct eap_sm *sm, void *priv) 779 { 780 struct eap_sim_data *data = priv; 781 return data->state == SUCCESS || data->state == FAILURE; 782 } 783 784 785 static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len) 786 { 787 struct eap_sim_data *data = priv; 788 u8 *key; 789 790 if (data->state != SUCCESS) 791 return NULL; 792 793 key = os_memdup(data->msk, EAP_SIM_KEYING_DATA_LEN); 794 if (key == NULL) 795 return NULL; 796 *len = EAP_SIM_KEYING_DATA_LEN; 797 return key; 798 } 799 800 801 static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 802 { 803 struct eap_sim_data *data = priv; 804 u8 *key; 805 806 if (data->state != SUCCESS) 807 return NULL; 808 809 key = os_memdup(data->emsk, EAP_EMSK_LEN); 810 if (key == NULL) 811 return NULL; 812 *len = EAP_EMSK_LEN; 813 return key; 814 } 815 816 817 static Boolean eap_sim_isSuccess(struct eap_sm *sm, void *priv) 818 { 819 struct eap_sim_data *data = priv; 820 return data->state == SUCCESS; 821 } 822 823 824 static u8 * eap_sim_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 825 { 826 struct eap_sim_data *data = priv; 827 u8 *id; 828 829 if (data->state != SUCCESS) 830 return NULL; 831 832 *len = 1 + data->num_chal * GSM_RAND_LEN + EAP_SIM_NONCE_MT_LEN; 833 id = os_malloc(*len); 834 if (id == NULL) 835 return NULL; 836 837 id[0] = EAP_TYPE_SIM; 838 os_memcpy(id + 1, data->rand, data->num_chal * GSM_RAND_LEN); 839 os_memcpy(id + 1 + data->num_chal * GSM_RAND_LEN, data->nonce_mt, 840 EAP_SIM_NONCE_MT_LEN); 841 wpa_hexdump(MSG_DEBUG, "EAP-SIM: Derived Session-Id", id, *len); 842 843 return id; 844 } 845 846 847 int eap_server_sim_register(void) 848 { 849 struct eap_method *eap; 850 851 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 852 EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM"); 853 if (eap == NULL) 854 return -1; 855 856 eap->init = eap_sim_init; 857 eap->reset = eap_sim_reset; 858 eap->buildReq = eap_sim_buildReq; 859 eap->check = eap_sim_check; 860 eap->process = eap_sim_process; 861 eap->isDone = eap_sim_isDone; 862 eap->getKey = eap_sim_getKey; 863 eap->isSuccess = eap_sim_isSuccess; 864 eap->get_emsk = eap_sim_get_emsk; 865 eap->getSessionId = eap_sim_get_session_id; 866 867 return eap_server_method_register(eap); 868 } 869