1 /* 2 * hostapd / EAP-SIM database/authenticator gateway 3 * Copyright (c) 2005-2010, 2012, Jouni Malinen <j@w1.fi> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * Alternatively, this software may be distributed under the terms of BSD 10 * license. 11 * 12 * See README and COPYING for more details. 13 * 14 * This is an example implementation of the EAP-SIM/AKA database/authentication 15 * gateway interface that is using an external program as an SS7 gateway to 16 * GSM/UMTS authentication center (HLR/AuC). hlr_auc_gw is an example 17 * implementation of such a gateway program. This eap_sim_db.c takes care of 18 * EAP-SIM/AKA pseudonyms and re-auth identities. It can be used with different 19 * gateway implementations for HLR/AuC access. Alternatively, it can also be 20 * completely replaced if the in-memory database of pseudonyms/re-auth 21 * identities is not suitable for some cases. 22 */ 23 24 #include "includes.h" 25 #include <sys/un.h> 26 27 #include "common.h" 28 #include "crypto/random.h" 29 #include "eap_common/eap_sim_common.h" 30 #include "eap_server/eap_sim_db.h" 31 #include "eloop.h" 32 33 struct eap_sim_pseudonym { 34 struct eap_sim_pseudonym *next; 35 u8 *identity; 36 size_t identity_len; 37 char *pseudonym; 38 }; 39 40 struct eap_sim_db_pending { 41 struct eap_sim_db_pending *next; 42 u8 imsi[20]; 43 size_t imsi_len; 44 enum { PENDING, SUCCESS, FAILURE } state; 45 void *cb_session_ctx; 46 struct os_time timestamp; 47 int aka; 48 union { 49 struct { 50 u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN]; 51 u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN]; 52 u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN]; 53 int num_chal; 54 } sim; 55 struct { 56 u8 rand[EAP_AKA_RAND_LEN]; 57 u8 autn[EAP_AKA_AUTN_LEN]; 58 u8 ik[EAP_AKA_IK_LEN]; 59 u8 ck[EAP_AKA_CK_LEN]; 60 u8 res[EAP_AKA_RES_MAX_LEN]; 61 size_t res_len; 62 } aka; 63 } u; 64 }; 65 66 struct eap_sim_db_data { 67 int sock; 68 char *fname; 69 char *local_sock; 70 void (*get_complete_cb)(void *ctx, void *session_ctx); 71 void *ctx; 72 struct eap_sim_pseudonym *pseudonyms; 73 struct eap_sim_reauth *reauths; 74 struct eap_sim_db_pending *pending; 75 }; 76 77 78 static struct eap_sim_db_pending * 79 eap_sim_db_get_pending(struct eap_sim_db_data *data, const u8 *imsi, 80 size_t imsi_len, int aka) 81 { 82 struct eap_sim_db_pending *entry, *prev = NULL; 83 84 entry = data->pending; 85 while (entry) { 86 if (entry->aka == aka && entry->imsi_len == imsi_len && 87 os_memcmp(entry->imsi, imsi, imsi_len) == 0) { 88 if (prev) 89 prev->next = entry->next; 90 else 91 data->pending = entry->next; 92 break; 93 } 94 prev = entry; 95 entry = entry->next; 96 } 97 return entry; 98 } 99 100 101 static void eap_sim_db_add_pending(struct eap_sim_db_data *data, 102 struct eap_sim_db_pending *entry) 103 { 104 entry->next = data->pending; 105 data->pending = entry; 106 } 107 108 109 static void eap_sim_db_sim_resp_auth(struct eap_sim_db_data *data, 110 const char *imsi, char *buf) 111 { 112 char *start, *end, *pos; 113 struct eap_sim_db_pending *entry; 114 int num_chal; 115 116 /* 117 * SIM-RESP-AUTH <IMSI> Kc(i):SRES(i):RAND(i) ... 118 * SIM-RESP-AUTH <IMSI> FAILURE 119 * (IMSI = ASCII string, Kc/SRES/RAND = hex string) 120 */ 121 122 entry = eap_sim_db_get_pending(data, (u8 *) imsi, os_strlen(imsi), 0); 123 if (entry == NULL) { 124 wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the " 125 "received message found"); 126 return; 127 } 128 129 start = buf; 130 if (os_strncmp(start, "FAILURE", 7) == 0) { 131 wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported " 132 "failure"); 133 entry->state = FAILURE; 134 eap_sim_db_add_pending(data, entry); 135 data->get_complete_cb(data->ctx, entry->cb_session_ctx); 136 return; 137 } 138 139 num_chal = 0; 140 while (num_chal < EAP_SIM_MAX_CHAL) { 141 end = os_strchr(start, ' '); 142 if (end) 143 *end = '\0'; 144 145 pos = os_strchr(start, ':'); 146 if (pos == NULL) 147 goto parse_fail; 148 *pos = '\0'; 149 if (hexstr2bin(start, entry->u.sim.kc[num_chal], 150 EAP_SIM_KC_LEN)) 151 goto parse_fail; 152 153 start = pos + 1; 154 pos = os_strchr(start, ':'); 155 if (pos == NULL) 156 goto parse_fail; 157 *pos = '\0'; 158 if (hexstr2bin(start, entry->u.sim.sres[num_chal], 159 EAP_SIM_SRES_LEN)) 160 goto parse_fail; 161 162 start = pos + 1; 163 if (hexstr2bin(start, entry->u.sim.rand[num_chal], 164 GSM_RAND_LEN)) 165 goto parse_fail; 166 167 num_chal++; 168 if (end == NULL) 169 break; 170 else 171 start = end + 1; 172 } 173 entry->u.sim.num_chal = num_chal; 174 175 entry->state = SUCCESS; 176 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed " 177 "successfully - callback"); 178 eap_sim_db_add_pending(data, entry); 179 data->get_complete_cb(data->ctx, entry->cb_session_ctx); 180 return; 181 182 parse_fail: 183 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string"); 184 os_free(entry); 185 } 186 187 188 static void eap_sim_db_aka_resp_auth(struct eap_sim_db_data *data, 189 const char *imsi, char *buf) 190 { 191 char *start, *end; 192 struct eap_sim_db_pending *entry; 193 194 /* 195 * AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES> 196 * AKA-RESP-AUTH <IMSI> FAILURE 197 * (IMSI = ASCII string, RAND/AUTN/IK/CK/RES = hex string) 198 */ 199 200 entry = eap_sim_db_get_pending(data, (u8 *) imsi, os_strlen(imsi), 1); 201 if (entry == NULL) { 202 wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the " 203 "received message found"); 204 return; 205 } 206 207 start = buf; 208 if (os_strncmp(start, "FAILURE", 7) == 0) { 209 wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported " 210 "failure"); 211 entry->state = FAILURE; 212 eap_sim_db_add_pending(data, entry); 213 data->get_complete_cb(data->ctx, entry->cb_session_ctx); 214 return; 215 } 216 217 end = os_strchr(start, ' '); 218 if (end == NULL) 219 goto parse_fail; 220 *end = '\0'; 221 if (hexstr2bin(start, entry->u.aka.rand, EAP_AKA_RAND_LEN)) 222 goto parse_fail; 223 224 start = end + 1; 225 end = os_strchr(start, ' '); 226 if (end == NULL) 227 goto parse_fail; 228 *end = '\0'; 229 if (hexstr2bin(start, entry->u.aka.autn, EAP_AKA_AUTN_LEN)) 230 goto parse_fail; 231 232 start = end + 1; 233 end = os_strchr(start, ' '); 234 if (end == NULL) 235 goto parse_fail; 236 *end = '\0'; 237 if (hexstr2bin(start, entry->u.aka.ik, EAP_AKA_IK_LEN)) 238 goto parse_fail; 239 240 start = end + 1; 241 end = os_strchr(start, ' '); 242 if (end == NULL) 243 goto parse_fail; 244 *end = '\0'; 245 if (hexstr2bin(start, entry->u.aka.ck, EAP_AKA_CK_LEN)) 246 goto parse_fail; 247 248 start = end + 1; 249 end = os_strchr(start, ' '); 250 if (end) 251 *end = '\0'; 252 else { 253 end = start; 254 while (*end) 255 end++; 256 } 257 entry->u.aka.res_len = (end - start) / 2; 258 if (entry->u.aka.res_len > EAP_AKA_RES_MAX_LEN) { 259 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Too long RES"); 260 entry->u.aka.res_len = 0; 261 goto parse_fail; 262 } 263 if (hexstr2bin(start, entry->u.aka.res, entry->u.aka.res_len)) 264 goto parse_fail; 265 266 entry->state = SUCCESS; 267 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed " 268 "successfully - callback"); 269 eap_sim_db_add_pending(data, entry); 270 data->get_complete_cb(data->ctx, entry->cb_session_ctx); 271 return; 272 273 parse_fail: 274 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string"); 275 os_free(entry); 276 } 277 278 279 static void eap_sim_db_receive(int sock, void *eloop_ctx, void *sock_ctx) 280 { 281 struct eap_sim_db_data *data = eloop_ctx; 282 char buf[1000], *pos, *cmd, *imsi; 283 int res; 284 285 res = recv(sock, buf, sizeof(buf), 0); 286 if (res < 0) 287 return; 288 wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-SIM DB: Received from an " 289 "external source", (u8 *) buf, res); 290 if (res == 0) 291 return; 292 if (res >= (int) sizeof(buf)) 293 res = sizeof(buf) - 1; 294 buf[res] = '\0'; 295 296 if (data->get_complete_cb == NULL) { 297 wpa_printf(MSG_DEBUG, "EAP-SIM DB: No get_complete_cb " 298 "registered"); 299 return; 300 } 301 302 /* <cmd> <IMSI> ... */ 303 304 cmd = buf; 305 pos = os_strchr(cmd, ' '); 306 if (pos == NULL) 307 goto parse_fail; 308 *pos = '\0'; 309 imsi = pos + 1; 310 pos = os_strchr(imsi, ' '); 311 if (pos == NULL) 312 goto parse_fail; 313 *pos = '\0'; 314 wpa_printf(MSG_DEBUG, "EAP-SIM DB: External response=%s for IMSI %s", 315 cmd, imsi); 316 317 if (os_strcmp(cmd, "SIM-RESP-AUTH") == 0) 318 eap_sim_db_sim_resp_auth(data, imsi, pos + 1); 319 else if (os_strcmp(cmd, "AKA-RESP-AUTH") == 0) 320 eap_sim_db_aka_resp_auth(data, imsi, pos + 1); 321 else 322 wpa_printf(MSG_INFO, "EAP-SIM DB: Unknown external response " 323 "'%s'", cmd); 324 return; 325 326 parse_fail: 327 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string"); 328 } 329 330 331 static int eap_sim_db_open_socket(struct eap_sim_db_data *data) 332 { 333 struct sockaddr_un addr; 334 static int counter = 0; 335 336 if (os_strncmp(data->fname, "unix:", 5) != 0) 337 return -1; 338 339 data->sock = socket(PF_UNIX, SOCK_DGRAM, 0); 340 if (data->sock < 0) { 341 perror("socket(eap_sim_db)"); 342 return -1; 343 } 344 345 os_memset(&addr, 0, sizeof(addr)); 346 addr.sun_family = AF_UNIX; 347 os_snprintf(addr.sun_path, sizeof(addr.sun_path), 348 "/tmp/eap_sim_db_%d-%d", getpid(), counter++); 349 data->local_sock = os_strdup(addr.sun_path); 350 if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 351 perror("bind(eap_sim_db)"); 352 close(data->sock); 353 data->sock = -1; 354 return -1; 355 } 356 357 os_memset(&addr, 0, sizeof(addr)); 358 addr.sun_family = AF_UNIX; 359 os_strlcpy(addr.sun_path, data->fname + 5, sizeof(addr.sun_path)); 360 if (connect(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 361 perror("connect(eap_sim_db)"); 362 wpa_hexdump_ascii(MSG_INFO, "HLR/AuC GW socket", 363 (u8 *) addr.sun_path, 364 os_strlen(addr.sun_path)); 365 close(data->sock); 366 data->sock = -1; 367 return -1; 368 } 369 370 eloop_register_read_sock(data->sock, eap_sim_db_receive, data, NULL); 371 372 return 0; 373 } 374 375 376 static void eap_sim_db_close_socket(struct eap_sim_db_data *data) 377 { 378 if (data->sock >= 0) { 379 eloop_unregister_read_sock(data->sock); 380 close(data->sock); 381 data->sock = -1; 382 } 383 if (data->local_sock) { 384 unlink(data->local_sock); 385 os_free(data->local_sock); 386 data->local_sock = NULL; 387 } 388 } 389 390 391 /** 392 * eap_sim_db_init - Initialize EAP-SIM DB / authentication gateway interface 393 * @config: Configuration data (e.g., file name) 394 * @get_complete_cb: Callback function for reporting availability of triplets 395 * @ctx: Context pointer for get_complete_cb 396 * Returns: Pointer to a private data structure or %NULL on failure 397 */ 398 void * eap_sim_db_init(const char *config, 399 void (*get_complete_cb)(void *ctx, void *session_ctx), 400 void *ctx) 401 { 402 struct eap_sim_db_data *data; 403 404 data = os_zalloc(sizeof(*data)); 405 if (data == NULL) 406 return NULL; 407 408 data->sock = -1; 409 data->get_complete_cb = get_complete_cb; 410 data->ctx = ctx; 411 data->fname = os_strdup(config); 412 if (data->fname == NULL) 413 goto fail; 414 415 if (os_strncmp(data->fname, "unix:", 5) == 0) { 416 if (eap_sim_db_open_socket(data)) 417 goto fail; 418 } 419 420 return data; 421 422 fail: 423 eap_sim_db_close_socket(data); 424 os_free(data->fname); 425 os_free(data); 426 return NULL; 427 } 428 429 430 static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p) 431 { 432 os_free(p->identity); 433 os_free(p->pseudonym); 434 os_free(p); 435 } 436 437 438 static void eap_sim_db_free_reauth(struct eap_sim_reauth *r) 439 { 440 os_free(r->identity); 441 os_free(r->reauth_id); 442 os_free(r); 443 } 444 445 446 /** 447 * eap_sim_db_deinit - Deinitialize EAP-SIM DB/authentication gw interface 448 * @priv: Private data pointer from eap_sim_db_init() 449 */ 450 void eap_sim_db_deinit(void *priv) 451 { 452 struct eap_sim_db_data *data = priv; 453 struct eap_sim_pseudonym *p, *prev; 454 struct eap_sim_reauth *r, *prevr; 455 struct eap_sim_db_pending *pending, *prev_pending; 456 457 eap_sim_db_close_socket(data); 458 os_free(data->fname); 459 460 p = data->pseudonyms; 461 while (p) { 462 prev = p; 463 p = p->next; 464 eap_sim_db_free_pseudonym(prev); 465 } 466 467 r = data->reauths; 468 while (r) { 469 prevr = r; 470 r = r->next; 471 eap_sim_db_free_reauth(prevr); 472 } 473 474 pending = data->pending; 475 while (pending) { 476 prev_pending = pending; 477 pending = pending->next; 478 os_free(prev_pending); 479 } 480 481 os_free(data); 482 } 483 484 485 static int eap_sim_db_send(struct eap_sim_db_data *data, const char *msg, 486 size_t len) 487 { 488 int _errno = 0; 489 490 if (send(data->sock, msg, len, 0) < 0) { 491 _errno = errno; 492 perror("send[EAP-SIM DB UNIX]"); 493 } 494 495 if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL || 496 _errno == ECONNREFUSED) { 497 /* Try to reconnect */ 498 eap_sim_db_close_socket(data); 499 if (eap_sim_db_open_socket(data) < 0) 500 return -1; 501 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Reconnected to the " 502 "external server"); 503 if (send(data->sock, msg, len, 0) < 0) { 504 perror("send[EAP-SIM DB UNIX]"); 505 return -1; 506 } 507 } 508 509 return 0; 510 } 511 512 513 static void eap_sim_db_expire_pending(struct eap_sim_db_data *data) 514 { 515 /* TODO: add limit for maximum length for pending list; remove latest 516 * (i.e., last) entry from the list if the limit is reached; could also 517 * use timeout to expire pending entries */ 518 } 519 520 521 /** 522 * eap_sim_db_get_gsm_triplets - Get GSM triplets 523 * @priv: Private data pointer from eap_sim_db_init() 524 * @identity: User name identity 525 * @identity_len: Length of identity in bytes 526 * @max_chal: Maximum number of triplets 527 * @_rand: Buffer for RAND values 528 * @kc: Buffer for Kc values 529 * @sres: Buffer for SRES values 530 * @cb_session_ctx: Session callback context for get_complete_cb() 531 * Returns: Number of triplets received (has to be less than or equal to 532 * max_chal), -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not found), or 533 * -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this case, the 534 * callback function registered with eap_sim_db_init() will be called once the 535 * results become available. 536 * 537 * In most cases, the user name is '1' | IMSI, i.e., 1 followed by the IMSI in 538 * ASCII format. 539 * 540 * When using an external server for GSM triplets, this function can always 541 * start a request and return EAP_SIM_DB_PENDING immediately if authentication 542 * triplets are not available. Once the triplets are received, callback 543 * function registered with eap_sim_db_init() is called to notify EAP state 544 * machine to reprocess the message. This eap_sim_db_get_gsm_triplets() 545 * function will then be called again and the newly received triplets will then 546 * be given to the caller. 547 */ 548 int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity, 549 size_t identity_len, int max_chal, 550 u8 *_rand, u8 *kc, u8 *sres, 551 void *cb_session_ctx) 552 { 553 struct eap_sim_db_data *data = priv; 554 struct eap_sim_db_pending *entry; 555 int len, ret; 556 size_t i; 557 char msg[40]; 558 559 if (identity_len < 2 || identity[0] != EAP_SIM_PERMANENT_PREFIX) { 560 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", 561 identity, identity_len); 562 return EAP_SIM_DB_FAILURE; 563 } 564 identity++; 565 identity_len--; 566 for (i = 0; i < identity_len; i++) { 567 if (identity[i] == '@') { 568 identity_len = i; 569 break; 570 } 571 } 572 if (identity_len + 1 > sizeof(entry->imsi)) { 573 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", 574 identity, identity_len); 575 return EAP_SIM_DB_FAILURE; 576 } 577 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI", 578 identity, identity_len); 579 580 entry = eap_sim_db_get_pending(data, identity, identity_len, 0); 581 if (entry) { 582 int num_chal; 583 if (entry->state == FAILURE) { 584 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> " 585 "failure"); 586 os_free(entry); 587 return EAP_SIM_DB_FAILURE; 588 } 589 590 if (entry->state == PENDING) { 591 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> " 592 "still pending"); 593 eap_sim_db_add_pending(data, entry); 594 return EAP_SIM_DB_PENDING; 595 } 596 597 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> " 598 "%d challenges", entry->u.sim.num_chal); 599 num_chal = entry->u.sim.num_chal; 600 if (num_chal > max_chal) 601 num_chal = max_chal; 602 os_memcpy(_rand, entry->u.sim.rand, num_chal * GSM_RAND_LEN); 603 os_memcpy(sres, entry->u.sim.sres, 604 num_chal * EAP_SIM_SRES_LEN); 605 os_memcpy(kc, entry->u.sim.kc, num_chal * EAP_SIM_KC_LEN); 606 os_free(entry); 607 return num_chal; 608 } 609 610 if (data->sock < 0) { 611 if (eap_sim_db_open_socket(data) < 0) 612 return EAP_SIM_DB_FAILURE; 613 } 614 615 len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH "); 616 if (len < 0 || len + identity_len >= sizeof(msg)) 617 return EAP_SIM_DB_FAILURE; 618 os_memcpy(msg + len, identity, identity_len); 619 len += identity_len; 620 ret = os_snprintf(msg + len, sizeof(msg) - len, " %d", max_chal); 621 if (ret < 0 || (size_t) ret >= sizeof(msg) - len) 622 return EAP_SIM_DB_FAILURE; 623 len += ret; 624 625 wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication " 626 "data for IMSI", identity, identity_len); 627 if (eap_sim_db_send(data, msg, len) < 0) 628 return EAP_SIM_DB_FAILURE; 629 630 entry = os_zalloc(sizeof(*entry)); 631 if (entry == NULL) 632 return EAP_SIM_DB_FAILURE; 633 634 os_get_time(&entry->timestamp); 635 os_memcpy(entry->imsi, identity, identity_len); 636 entry->imsi_len = identity_len; 637 entry->cb_session_ctx = cb_session_ctx; 638 entry->state = PENDING; 639 eap_sim_db_add_pending(data, entry); 640 eap_sim_db_expire_pending(data); 641 642 return EAP_SIM_DB_PENDING; 643 } 644 645 646 static struct eap_sim_pseudonym * 647 eap_sim_db_get_pseudonym(struct eap_sim_db_data *data, const u8 *identity, 648 size_t identity_len) 649 { 650 char *pseudonym; 651 size_t len; 652 struct eap_sim_pseudonym *p; 653 654 if (identity_len == 0 || 655 (identity[0] != EAP_SIM_PSEUDONYM_PREFIX && 656 identity[0] != EAP_AKA_PSEUDONYM_PREFIX && 657 identity[0] != EAP_AKA_PRIME_PSEUDONYM_PREFIX)) 658 return NULL; 659 660 /* Remove possible realm from identity */ 661 len = 0; 662 while (len < identity_len) { 663 if (identity[len] == '@') 664 break; 665 len++; 666 } 667 668 pseudonym = os_malloc(len + 1); 669 if (pseudonym == NULL) 670 return NULL; 671 os_memcpy(pseudonym, identity, len); 672 pseudonym[len] = '\0'; 673 674 p = data->pseudonyms; 675 while (p) { 676 if (os_strcmp(p->pseudonym, pseudonym) == 0) 677 break; 678 p = p->next; 679 } 680 681 os_free(pseudonym); 682 683 return p; 684 } 685 686 687 static struct eap_sim_pseudonym * 688 eap_sim_db_get_pseudonym_id(struct eap_sim_db_data *data, const u8 *identity, 689 size_t identity_len) 690 { 691 struct eap_sim_pseudonym *p; 692 693 if (identity_len == 0 || 694 (identity[0] != EAP_SIM_PERMANENT_PREFIX && 695 identity[0] != EAP_AKA_PERMANENT_PREFIX && 696 identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX)) 697 return NULL; 698 699 p = data->pseudonyms; 700 while (p) { 701 if (identity_len == p->identity_len && 702 os_memcmp(p->identity, identity, identity_len) == 0) 703 break; 704 p = p->next; 705 } 706 707 return p; 708 } 709 710 711 static struct eap_sim_reauth * 712 eap_sim_db_get_reauth(struct eap_sim_db_data *data, const u8 *identity, 713 size_t identity_len) 714 { 715 char *reauth_id; 716 size_t len; 717 struct eap_sim_reauth *r; 718 719 if (identity_len == 0 || 720 (identity[0] != EAP_SIM_REAUTH_ID_PREFIX && 721 identity[0] != EAP_AKA_REAUTH_ID_PREFIX && 722 identity[0] != EAP_AKA_PRIME_REAUTH_ID_PREFIX)) 723 return NULL; 724 725 /* Remove possible realm from identity */ 726 len = 0; 727 while (len < identity_len) { 728 if (identity[len] == '@') 729 break; 730 len++; 731 } 732 733 reauth_id = os_malloc(len + 1); 734 if (reauth_id == NULL) 735 return NULL; 736 os_memcpy(reauth_id, identity, len); 737 reauth_id[len] = '\0'; 738 739 r = data->reauths; 740 while (r) { 741 if (os_strcmp(r->reauth_id, reauth_id) == 0) 742 break; 743 r = r->next; 744 } 745 746 os_free(reauth_id); 747 748 return r; 749 } 750 751 752 static struct eap_sim_reauth * 753 eap_sim_db_get_reauth_id(struct eap_sim_db_data *data, const u8 *identity, 754 size_t identity_len) 755 { 756 struct eap_sim_pseudonym *p; 757 struct eap_sim_reauth *r; 758 759 if (identity_len == 0) 760 return NULL; 761 762 p = eap_sim_db_get_pseudonym(data, identity, identity_len); 763 if (p == NULL) 764 p = eap_sim_db_get_pseudonym_id(data, identity, identity_len); 765 if (p) { 766 identity = p->identity; 767 identity_len = p->identity_len; 768 } 769 770 r = data->reauths; 771 while (r) { 772 if (identity_len == r->identity_len && 773 os_memcmp(r->identity, identity, identity_len) == 0) 774 break; 775 r = r->next; 776 } 777 778 return r; 779 } 780 781 782 /** 783 * eap_sim_db_identity_known - Verify whether the given identity is known 784 * @priv: Private data pointer from eap_sim_db_init() 785 * @identity: User name identity 786 * @identity_len: Length of identity in bytes 787 * Returns: 0 if the user is found or -1 on failure 788 * 789 * In most cases, the user name is ['0','1','6'] | IMSI, i.e., 1 followed by 790 * the IMSI in ASCII format for EAP-SIM, ['2','3','7'] | pseudonym, or 791 * ['4','5','7'] | reauth_id. 792 */ 793 int eap_sim_db_identity_known(void *priv, const u8 *identity, 794 size_t identity_len) 795 { 796 struct eap_sim_db_data *data = priv; 797 798 if (identity == NULL || identity_len < 2) 799 return -1; 800 801 if (identity[0] == EAP_SIM_PSEUDONYM_PREFIX || 802 identity[0] == EAP_AKA_PSEUDONYM_PREFIX || 803 identity[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) { 804 struct eap_sim_pseudonym *p = 805 eap_sim_db_get_pseudonym(data, identity, identity_len); 806 return p ? 0 : -1; 807 } 808 809 if (identity[0] == EAP_SIM_REAUTH_ID_PREFIX || 810 identity[0] == EAP_AKA_REAUTH_ID_PREFIX || 811 identity[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX) { 812 struct eap_sim_reauth *r = 813 eap_sim_db_get_reauth(data, identity, identity_len); 814 return r ? 0 : -1; 815 } 816 817 if (identity[0] != EAP_SIM_PERMANENT_PREFIX && 818 identity[0] != EAP_AKA_PERMANENT_PREFIX && 819 identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) { 820 /* Unknown identity prefix */ 821 return -1; 822 } 823 824 /* TODO: Should consider asking HLR/AuC gateway whether this permanent 825 * identity is known. If it is, EAP-SIM/AKA can skip identity request. 826 * In case of EAP-AKA, this would reduce number of needed round-trips. 827 * Ideally, this would be done with one wait, i.e., just request 828 * authentication data and store it for the next use. This would then 829 * need to use similar pending-request functionality as the normal 830 * request for authentication data at later phase. 831 */ 832 return -1; 833 } 834 835 836 static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix) 837 { 838 char *id, *pos, *end; 839 u8 buf[10]; 840 841 if (random_get_bytes(buf, sizeof(buf))) 842 return NULL; 843 id = os_malloc(sizeof(buf) * 2 + 2); 844 if (id == NULL) 845 return NULL; 846 847 pos = id; 848 end = id + sizeof(buf) * 2 + 2; 849 *pos++ = prefix; 850 pos += wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf)); 851 852 return id; 853 } 854 855 856 /** 857 * eap_sim_db_get_next_pseudonym - EAP-SIM DB: Get next pseudonym 858 * @priv: Private data pointer from eap_sim_db_init() 859 * @method: EAP method (SIM/AKA/AKA') 860 * Returns: Next pseudonym (allocated string) or %NULL on failure 861 * 862 * This function is used to generate a pseudonym for EAP-SIM. The returned 863 * pseudonym is not added to database at this point; it will need to be added 864 * with eap_sim_db_add_pseudonym() once the authentication has been completed 865 * successfully. Caller is responsible for freeing the returned buffer. 866 */ 867 char * eap_sim_db_get_next_pseudonym(void *priv, enum eap_sim_db_method method) 868 { 869 struct eap_sim_db_data *data = priv; 870 char prefix = EAP_SIM_REAUTH_ID_PREFIX; 871 872 switch (method) { 873 case EAP_SIM_DB_SIM: 874 prefix = EAP_SIM_PSEUDONYM_PREFIX; 875 break; 876 case EAP_SIM_DB_AKA: 877 prefix = EAP_AKA_PSEUDONYM_PREFIX; 878 break; 879 case EAP_SIM_DB_AKA_PRIME: 880 prefix = EAP_AKA_PRIME_PSEUDONYM_PREFIX; 881 break; 882 } 883 884 return eap_sim_db_get_next(data, prefix); 885 } 886 887 888 /** 889 * eap_sim_db_get_next_reauth_id - EAP-SIM DB: Get next reauth_id 890 * @priv: Private data pointer from eap_sim_db_init() 891 * @method: EAP method (SIM/AKA/AKA') 892 * Returns: Next reauth_id (allocated string) or %NULL on failure 893 * 894 * This function is used to generate a fast re-authentication identity for 895 * EAP-SIM. The returned reauth_id is not added to database at this point; it 896 * will need to be added with eap_sim_db_add_reauth() once the authentication 897 * has been completed successfully. Caller is responsible for freeing the 898 * returned buffer. 899 */ 900 char * eap_sim_db_get_next_reauth_id(void *priv, enum eap_sim_db_method method) 901 { 902 struct eap_sim_db_data *data = priv; 903 char prefix = EAP_SIM_REAUTH_ID_PREFIX; 904 905 switch (method) { 906 case EAP_SIM_DB_SIM: 907 prefix = EAP_SIM_REAUTH_ID_PREFIX; 908 break; 909 case EAP_SIM_DB_AKA: 910 prefix = EAP_AKA_REAUTH_ID_PREFIX; 911 break; 912 case EAP_SIM_DB_AKA_PRIME: 913 prefix = EAP_AKA_PRIME_REAUTH_ID_PREFIX; 914 break; 915 } 916 917 return eap_sim_db_get_next(data, prefix); 918 } 919 920 921 /** 922 * eap_sim_db_add_pseudonym - EAP-SIM DB: Add new pseudonym 923 * @priv: Private data pointer from eap_sim_db_init() 924 * @identity: Identity of the user (may be permanent identity or pseudonym) 925 * @identity_len: Length of identity 926 * @pseudonym: Pseudonym for this user. This needs to be an allocated buffer, 927 * e.g., return value from eap_sim_db_get_next_pseudonym(). Caller must not 928 * free it. 929 * Returns: 0 on success, -1 on failure 930 * 931 * This function adds a new pseudonym for EAP-SIM user. EAP-SIM DB is 932 * responsible of freeing pseudonym buffer once it is not needed anymore. 933 */ 934 int eap_sim_db_add_pseudonym(void *priv, const u8 *identity, 935 size_t identity_len, char *pseudonym) 936 { 937 struct eap_sim_db_data *data = priv; 938 struct eap_sim_pseudonym *p; 939 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add pseudonym for identity", 940 identity, identity_len); 941 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pseudonym: %s", pseudonym); 942 943 /* TODO: could store last two pseudonyms */ 944 p = eap_sim_db_get_pseudonym(data, identity, identity_len); 945 if (p == NULL) 946 p = eap_sim_db_get_pseudonym_id(data, identity, identity_len); 947 948 if (p) { 949 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous " 950 "pseudonym: %s", p->pseudonym); 951 os_free(p->pseudonym); 952 p->pseudonym = pseudonym; 953 return 0; 954 } 955 956 p = os_zalloc(sizeof(*p)); 957 if (p == NULL) { 958 os_free(pseudonym); 959 return -1; 960 } 961 962 p->next = data->pseudonyms; 963 p->identity = os_malloc(identity_len); 964 if (p->identity == NULL) { 965 os_free(p); 966 os_free(pseudonym); 967 return -1; 968 } 969 os_memcpy(p->identity, identity, identity_len); 970 p->identity_len = identity_len; 971 p->pseudonym = pseudonym; 972 data->pseudonyms = p; 973 974 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new pseudonym entry"); 975 return 0; 976 } 977 978 979 static struct eap_sim_reauth * 980 eap_sim_db_add_reauth_data(struct eap_sim_db_data *data, const u8 *identity, 981 size_t identity_len, char *reauth_id, u16 counter) 982 { 983 struct eap_sim_reauth *r; 984 985 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add reauth_id for identity", 986 identity, identity_len); 987 wpa_printf(MSG_DEBUG, "EAP-SIM DB: reauth_id: %s", reauth_id); 988 989 r = eap_sim_db_get_reauth(data, identity, identity_len); 990 if (r == NULL) 991 r = eap_sim_db_get_reauth_id(data, identity, identity_len); 992 993 if (r) { 994 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous " 995 "reauth_id: %s", r->reauth_id); 996 os_free(r->reauth_id); 997 r->reauth_id = reauth_id; 998 } else { 999 r = os_zalloc(sizeof(*r)); 1000 if (r == NULL) { 1001 os_free(reauth_id); 1002 return NULL; 1003 } 1004 1005 r->next = data->reauths; 1006 r->identity = os_malloc(identity_len); 1007 if (r->identity == NULL) { 1008 os_free(r); 1009 os_free(reauth_id); 1010 return NULL; 1011 } 1012 os_memcpy(r->identity, identity, identity_len); 1013 r->identity_len = identity_len; 1014 r->reauth_id = reauth_id; 1015 data->reauths = r; 1016 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new reauth entry"); 1017 } 1018 1019 r->counter = counter; 1020 1021 return r; 1022 } 1023 1024 1025 /** 1026 * eap_sim_db_add_reauth - EAP-SIM DB: Add new re-authentication entry 1027 * @priv: Private data pointer from eap_sim_db_init() 1028 * @identity: Identity of the user (may be permanent identity or pseudonym) 1029 * @identity_len: Length of identity 1030 * @reauth_id: reauth_id for this user. This needs to be an allocated buffer, 1031 * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not 1032 * free it. 1033 * @counter: AT_COUNTER value for fast re-authentication 1034 * @mk: 16-byte MK from the previous full authentication or %NULL 1035 * Returns: 0 on success, -1 on failure 1036 * 1037 * This function adds a new re-authentication entry for an EAP-SIM user. 1038 * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed 1039 * anymore. 1040 */ 1041 int eap_sim_db_add_reauth(void *priv, const u8 *identity, 1042 size_t identity_len, char *reauth_id, u16 counter, 1043 const u8 *mk) 1044 { 1045 struct eap_sim_db_data *data = priv; 1046 struct eap_sim_reauth *r; 1047 1048 r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id, 1049 counter); 1050 if (r == NULL) 1051 return -1; 1052 1053 os_memcpy(r->mk, mk, EAP_SIM_MK_LEN); 1054 r->aka_prime = 0; 1055 1056 return 0; 1057 } 1058 1059 1060 #ifdef EAP_SERVER_AKA_PRIME 1061 /** 1062 * eap_sim_db_add_reauth_prime - EAP-AKA' DB: Add new re-authentication entry 1063 * @priv: Private data pointer from eap_sim_db_init() 1064 * @identity: Identity of the user (may be permanent identity or pseudonym) 1065 * @identity_len: Length of identity 1066 * @reauth_id: reauth_id for this user. This needs to be an allocated buffer, 1067 * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not 1068 * free it. 1069 * @counter: AT_COUNTER value for fast re-authentication 1070 * @k_encr: K_encr from the previous full authentication 1071 * @k_aut: K_aut from the previous full authentication 1072 * @k_re: 32-byte K_re from the previous full authentication 1073 * Returns: 0 on success, -1 on failure 1074 * 1075 * This function adds a new re-authentication entry for an EAP-AKA' user. 1076 * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed 1077 * anymore. 1078 */ 1079 int eap_sim_db_add_reauth_prime(void *priv, const u8 *identity, 1080 size_t identity_len, char *reauth_id, 1081 u16 counter, const u8 *k_encr, const u8 *k_aut, 1082 const u8 *k_re) 1083 { 1084 struct eap_sim_db_data *data = priv; 1085 struct eap_sim_reauth *r; 1086 1087 r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id, 1088 counter); 1089 if (r == NULL) 1090 return -1; 1091 1092 r->aka_prime = 1; 1093 os_memcpy(r->k_encr, k_encr, EAP_SIM_K_ENCR_LEN); 1094 os_memcpy(r->k_aut, k_aut, EAP_AKA_PRIME_K_AUT_LEN); 1095 os_memcpy(r->k_re, k_re, EAP_AKA_PRIME_K_RE_LEN); 1096 1097 return 0; 1098 } 1099 #endif /* EAP_SERVER_AKA_PRIME */ 1100 1101 1102 /** 1103 * eap_sim_db_get_permanent - EAP-SIM DB: Get permanent identity 1104 * @priv: Private data pointer from eap_sim_db_init() 1105 * @identity: Identity of the user (may be permanent identity or pseudonym) 1106 * @identity_len: Length of identity 1107 * @len: Buffer for length of the returned permanent identity 1108 * Returns: Pointer to the permanent identity, or %NULL if not found 1109 */ 1110 const u8 * eap_sim_db_get_permanent(void *priv, const u8 *identity, 1111 size_t identity_len, size_t *len) 1112 { 1113 struct eap_sim_db_data *data = priv; 1114 struct eap_sim_pseudonym *p; 1115 1116 if (identity == NULL) 1117 return NULL; 1118 1119 p = eap_sim_db_get_pseudonym(data, identity, identity_len); 1120 if (p == NULL) 1121 p = eap_sim_db_get_pseudonym_id(data, identity, identity_len); 1122 if (p == NULL) 1123 return NULL; 1124 1125 *len = p->identity_len; 1126 return p->identity; 1127 } 1128 1129 1130 /** 1131 * eap_sim_db_get_reauth_entry - EAP-SIM DB: Get re-authentication entry 1132 * @priv: Private data pointer from eap_sim_db_init() 1133 * @identity: Identity of the user (may be permanent identity, pseudonym, or 1134 * reauth_id) 1135 * @identity_len: Length of identity 1136 * Returns: Pointer to the re-auth entry, or %NULL if not found 1137 */ 1138 struct eap_sim_reauth * 1139 eap_sim_db_get_reauth_entry(void *priv, const u8 *identity, 1140 size_t identity_len) 1141 { 1142 struct eap_sim_db_data *data = priv; 1143 struct eap_sim_reauth *r; 1144 1145 if (identity == NULL) 1146 return NULL; 1147 r = eap_sim_db_get_reauth(data, identity, identity_len); 1148 if (r == NULL) 1149 r = eap_sim_db_get_reauth_id(data, identity, identity_len); 1150 return r; 1151 } 1152 1153 1154 /** 1155 * eap_sim_db_remove_reauth - EAP-SIM DB: Remove re-authentication entry 1156 * @priv: Private data pointer from eap_sim_db_init() 1157 * @reauth: Pointer to re-authentication entry from 1158 * eap_sim_db_get_reauth_entry() 1159 */ 1160 void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth) 1161 { 1162 struct eap_sim_db_data *data = priv; 1163 struct eap_sim_reauth *r, *prev = NULL; 1164 r = data->reauths; 1165 while (r) { 1166 if (r == reauth) { 1167 if (prev) 1168 prev->next = r->next; 1169 else 1170 data->reauths = r->next; 1171 eap_sim_db_free_reauth(r); 1172 return; 1173 } 1174 prev = r; 1175 r = r->next; 1176 } 1177 } 1178 1179 1180 /** 1181 * eap_sim_db_get_aka_auth - Get AKA authentication values 1182 * @priv: Private data pointer from eap_sim_db_init() 1183 * @identity: User name identity 1184 * @identity_len: Length of identity in bytes 1185 * @_rand: Buffer for RAND value 1186 * @autn: Buffer for AUTN value 1187 * @ik: Buffer for IK value 1188 * @ck: Buffer for CK value 1189 * @res: Buffer for RES value 1190 * @res_len: Buffer for RES length 1191 * @cb_session_ctx: Session callback context for get_complete_cb() 1192 * Returns: 0 on success, -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not 1193 * found), or -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this 1194 * case, the callback function registered with eap_sim_db_init() will be 1195 * called once the results become available. 1196 * 1197 * In most cases, the user name is '0' | IMSI, i.e., 0 followed by the IMSI in 1198 * ASCII format for EAP-AKA and '6' | IMSI for EAP-AKA'. 1199 * 1200 * When using an external server for AKA authentication, this function can 1201 * always start a request and return EAP_SIM_DB_PENDING immediately if 1202 * authentication triplets are not available. Once the authentication data are 1203 * received, callback function registered with eap_sim_db_init() is called to 1204 * notify EAP state machine to reprocess the message. This 1205 * eap_sim_db_get_aka_auth() function will then be called again and the newly 1206 * received triplets will then be given to the caller. 1207 */ 1208 int eap_sim_db_get_aka_auth(void *priv, const u8 *identity, 1209 size_t identity_len, u8 *_rand, u8 *autn, u8 *ik, 1210 u8 *ck, u8 *res, size_t *res_len, 1211 void *cb_session_ctx) 1212 { 1213 struct eap_sim_db_data *data = priv; 1214 struct eap_sim_db_pending *entry; 1215 int len; 1216 size_t i; 1217 char msg[40]; 1218 1219 if (identity_len < 2 || identity == NULL || 1220 (identity[0] != EAP_AKA_PERMANENT_PREFIX && 1221 identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX)) { 1222 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", 1223 identity, identity_len); 1224 return EAP_SIM_DB_FAILURE; 1225 } 1226 identity++; 1227 identity_len--; 1228 for (i = 0; i < identity_len; i++) { 1229 if (identity[i] == '@') { 1230 identity_len = i; 1231 break; 1232 } 1233 } 1234 if (identity_len + 1 > sizeof(entry->imsi)) { 1235 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", 1236 identity, identity_len); 1237 return EAP_SIM_DB_FAILURE; 1238 } 1239 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI", 1240 identity, identity_len); 1241 1242 entry = eap_sim_db_get_pending(data, identity, identity_len, 1); 1243 if (entry) { 1244 if (entry->state == FAILURE) { 1245 os_free(entry); 1246 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failure"); 1247 return EAP_SIM_DB_FAILURE; 1248 } 1249 1250 if (entry->state == PENDING) { 1251 eap_sim_db_add_pending(data, entry); 1252 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending"); 1253 return EAP_SIM_DB_PENDING; 1254 } 1255 1256 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Returning successfully " 1257 "received authentication data"); 1258 os_memcpy(_rand, entry->u.aka.rand, EAP_AKA_RAND_LEN); 1259 os_memcpy(autn, entry->u.aka.autn, EAP_AKA_AUTN_LEN); 1260 os_memcpy(ik, entry->u.aka.ik, EAP_AKA_IK_LEN); 1261 os_memcpy(ck, entry->u.aka.ck, EAP_AKA_CK_LEN); 1262 os_memcpy(res, entry->u.aka.res, EAP_AKA_RES_MAX_LEN); 1263 *res_len = entry->u.aka.res_len; 1264 os_free(entry); 1265 return 0; 1266 } 1267 1268 if (data->sock < 0) { 1269 if (eap_sim_db_open_socket(data) < 0) 1270 return EAP_SIM_DB_FAILURE; 1271 } 1272 1273 len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH "); 1274 if (len < 0 || len + identity_len >= sizeof(msg)) 1275 return EAP_SIM_DB_FAILURE; 1276 os_memcpy(msg + len, identity, identity_len); 1277 len += identity_len; 1278 1279 wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication " 1280 "data for IMSI", identity, identity_len); 1281 if (eap_sim_db_send(data, msg, len) < 0) 1282 return EAP_SIM_DB_FAILURE; 1283 1284 entry = os_zalloc(sizeof(*entry)); 1285 if (entry == NULL) 1286 return EAP_SIM_DB_FAILURE; 1287 1288 os_get_time(&entry->timestamp); 1289 entry->aka = 1; 1290 os_memcpy(entry->imsi, identity, identity_len); 1291 entry->imsi_len = identity_len; 1292 entry->cb_session_ctx = cb_session_ctx; 1293 entry->state = PENDING; 1294 eap_sim_db_add_pending(data, entry); 1295 eap_sim_db_expire_pending(data); 1296 1297 return EAP_SIM_DB_PENDING; 1298 } 1299 1300 1301 /** 1302 * eap_sim_db_resynchronize - Resynchronize AKA AUTN 1303 * @priv: Private data pointer from eap_sim_db_init() 1304 * @identity: User name identity 1305 * @identity_len: Length of identity in bytes 1306 * @auts: AUTS value from the peer 1307 * @_rand: RAND value used in the rejected message 1308 * Returns: 0 on success, -1 on failure 1309 * 1310 * This function is called when the peer reports synchronization failure in the 1311 * AUTN value by sending AUTS. The AUTS and RAND values should be sent to 1312 * HLR/AuC to allow it to resynchronize with the peer. After this, 1313 * eap_sim_db_get_aka_auth() will be called again to to fetch updated 1314 * RAND/AUTN values for the next challenge. 1315 */ 1316 int eap_sim_db_resynchronize(void *priv, const u8 *identity, 1317 size_t identity_len, const u8 *auts, 1318 const u8 *_rand) 1319 { 1320 struct eap_sim_db_data *data = priv; 1321 size_t i; 1322 1323 if (identity_len < 2 || identity == NULL || 1324 (identity[0] != EAP_AKA_PERMANENT_PREFIX && 1325 identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX)) { 1326 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", 1327 identity, identity_len); 1328 return -1; 1329 } 1330 identity++; 1331 identity_len--; 1332 for (i = 0; i < identity_len; i++) { 1333 if (identity[i] == '@') { 1334 identity_len = i; 1335 break; 1336 } 1337 } 1338 if (identity_len > 20) { 1339 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", 1340 identity, identity_len); 1341 return -1; 1342 } 1343 1344 if (data->sock >= 0) { 1345 char msg[100]; 1346 int len, ret; 1347 1348 len = os_snprintf(msg, sizeof(msg), "AKA-AUTS "); 1349 if (len < 0 || len + identity_len >= sizeof(msg)) 1350 return -1; 1351 os_memcpy(msg + len, identity, identity_len); 1352 len += identity_len; 1353 1354 ret = os_snprintf(msg + len, sizeof(msg) - len, " "); 1355 if (ret < 0 || (size_t) ret >= sizeof(msg) - len) 1356 return -1; 1357 len += ret; 1358 len += wpa_snprintf_hex(msg + len, sizeof(msg) - len, 1359 auts, EAP_AKA_AUTS_LEN); 1360 ret = os_snprintf(msg + len, sizeof(msg) - len, " "); 1361 if (ret < 0 || (size_t) ret >= sizeof(msg) - len) 1362 return -1; 1363 len += ret; 1364 len += wpa_snprintf_hex(msg + len, sizeof(msg) - len, 1365 _rand, EAP_AKA_RAND_LEN); 1366 wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for " 1367 "IMSI", identity, identity_len); 1368 if (eap_sim_db_send(data, msg, len) < 0) 1369 return -1; 1370 } 1371 1372 return 0; 1373 } 1374