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