1 /* 2 * hostapd / EAP-SIM database/authenticator gateway 3 * Copyright (c) 2005-2010, 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 * 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) - 1, 0); 577 if (res < 0) 578 return; 579 buf[res] = '\0'; 580 wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-SIM DB: Received from an " 581 "external source", (u8 *) buf, res); 582 if (res == 0) 583 return; 584 585 if (data->get_complete_cb == NULL) { 586 wpa_printf(MSG_DEBUG, "EAP-SIM DB: No get_complete_cb " 587 "registered"); 588 return; 589 } 590 591 /* <cmd> <IMSI> ... */ 592 593 cmd = buf; 594 pos = os_strchr(cmd, ' '); 595 if (pos == NULL) 596 goto parse_fail; 597 *pos = '\0'; 598 imsi = pos + 1; 599 pos = os_strchr(imsi, ' '); 600 if (pos == NULL) 601 goto parse_fail; 602 *pos = '\0'; 603 wpa_printf(MSG_DEBUG, "EAP-SIM DB: External response=%s for IMSI %s", 604 cmd, imsi); 605 606 if (os_strcmp(cmd, "SIM-RESP-AUTH") == 0) 607 eap_sim_db_sim_resp_auth(data, imsi, pos + 1); 608 else if (os_strcmp(cmd, "AKA-RESP-AUTH") == 0) 609 eap_sim_db_aka_resp_auth(data, imsi, pos + 1); 610 else 611 wpa_printf(MSG_INFO, "EAP-SIM DB: Unknown external response " 612 "'%s'", cmd); 613 return; 614 615 parse_fail: 616 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string"); 617 } 618 619 620 static int eap_sim_db_open_socket(struct eap_sim_db_data *data) 621 { 622 struct sockaddr_un addr; 623 static int counter = 0; 624 625 if (os_strncmp(data->fname, "unix:", 5) != 0) 626 return -1; 627 628 data->sock = socket(PF_UNIX, SOCK_DGRAM, 0); 629 if (data->sock < 0) { 630 wpa_printf(MSG_INFO, "socket(eap_sim_db): %s", strerror(errno)); 631 return -1; 632 } 633 634 os_memset(&addr, 0, sizeof(addr)); 635 addr.sun_family = AF_UNIX; 636 os_snprintf(addr.sun_path, sizeof(addr.sun_path), 637 "/tmp/eap_sim_db_%d-%d", getpid(), counter++); 638 os_free(data->local_sock); 639 data->local_sock = os_strdup(addr.sun_path); 640 if (data->local_sock == NULL) { 641 close(data->sock); 642 data->sock = -1; 643 return -1; 644 } 645 if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 646 wpa_printf(MSG_INFO, "bind(eap_sim_db): %s", strerror(errno)); 647 close(data->sock); 648 data->sock = -1; 649 return -1; 650 } 651 652 os_memset(&addr, 0, sizeof(addr)); 653 addr.sun_family = AF_UNIX; 654 os_strlcpy(addr.sun_path, data->fname + 5, sizeof(addr.sun_path)); 655 if (connect(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 656 wpa_printf(MSG_INFO, "connect(eap_sim_db): %s", 657 strerror(errno)); 658 wpa_hexdump_ascii(MSG_INFO, "HLR/AuC GW socket", 659 (u8 *) addr.sun_path, 660 os_strlen(addr.sun_path)); 661 close(data->sock); 662 data->sock = -1; 663 unlink(data->local_sock); 664 os_free(data->local_sock); 665 data->local_sock = NULL; 666 return -1; 667 } 668 669 eloop_register_read_sock(data->sock, eap_sim_db_receive, data, NULL); 670 671 return 0; 672 } 673 674 675 static void eap_sim_db_close_socket(struct eap_sim_db_data *data) 676 { 677 if (data->sock >= 0) { 678 eloop_unregister_read_sock(data->sock); 679 close(data->sock); 680 data->sock = -1; 681 } 682 if (data->local_sock) { 683 unlink(data->local_sock); 684 os_free(data->local_sock); 685 data->local_sock = NULL; 686 } 687 } 688 689 690 /** 691 * eap_sim_db_init - Initialize EAP-SIM DB / authentication gateway interface 692 * @config: Configuration data (e.g., file name) 693 * @get_complete_cb: Callback function for reporting availability of triplets 694 * @ctx: Context pointer for get_complete_cb 695 * Returns: Pointer to a private data structure or %NULL on failure 696 */ 697 struct eap_sim_db_data * 698 eap_sim_db_init(const char *config, 699 void (*get_complete_cb)(void *ctx, void *session_ctx), 700 void *ctx) 701 { 702 struct eap_sim_db_data *data; 703 char *pos; 704 705 data = os_zalloc(sizeof(*data)); 706 if (data == NULL) 707 return NULL; 708 709 data->sock = -1; 710 data->get_complete_cb = get_complete_cb; 711 data->ctx = ctx; 712 data->fname = os_strdup(config); 713 if (data->fname == NULL) 714 goto fail; 715 pos = os_strstr(data->fname, " db="); 716 if (pos) { 717 *pos = '\0'; 718 #ifdef CONFIG_SQLITE 719 pos += 4; 720 data->sqlite_db = db_open(pos); 721 if (data->sqlite_db == NULL) 722 goto fail; 723 #endif /* CONFIG_SQLITE */ 724 } 725 726 if (os_strncmp(data->fname, "unix:", 5) == 0) { 727 if (eap_sim_db_open_socket(data)) { 728 wpa_printf(MSG_DEBUG, "EAP-SIM DB: External database " 729 "connection not available - will retry " 730 "later"); 731 } 732 } 733 734 return data; 735 736 fail: 737 eap_sim_db_close_socket(data); 738 os_free(data->fname); 739 os_free(data); 740 return NULL; 741 } 742 743 744 static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p) 745 { 746 os_free(p->permanent); 747 os_free(p->pseudonym); 748 os_free(p); 749 } 750 751 752 static void eap_sim_db_free_reauth(struct eap_sim_reauth *r) 753 { 754 os_free(r->permanent); 755 os_free(r->reauth_id); 756 os_free(r); 757 } 758 759 760 /** 761 * eap_sim_db_deinit - Deinitialize EAP-SIM DB/authentication gw interface 762 * @priv: Private data pointer from eap_sim_db_init() 763 */ 764 void eap_sim_db_deinit(void *priv) 765 { 766 struct eap_sim_db_data *data = priv; 767 struct eap_sim_pseudonym *p, *prev; 768 struct eap_sim_reauth *r, *prevr; 769 struct eap_sim_db_pending *pending, *prev_pending; 770 771 #ifdef CONFIG_SQLITE 772 if (data->sqlite_db) { 773 sqlite3_close(data->sqlite_db); 774 data->sqlite_db = NULL; 775 } 776 #endif /* CONFIG_SQLITE */ 777 778 eap_sim_db_close_socket(data); 779 os_free(data->fname); 780 781 p = data->pseudonyms; 782 while (p) { 783 prev = p; 784 p = p->next; 785 eap_sim_db_free_pseudonym(prev); 786 } 787 788 r = data->reauths; 789 while (r) { 790 prevr = r; 791 r = r->next; 792 eap_sim_db_free_reauth(prevr); 793 } 794 795 pending = data->pending; 796 while (pending) { 797 prev_pending = pending; 798 pending = pending->next; 799 os_free(prev_pending); 800 } 801 802 os_free(data); 803 } 804 805 806 static int eap_sim_db_send(struct eap_sim_db_data *data, const char *msg, 807 size_t len) 808 { 809 int _errno = 0; 810 811 if (send(data->sock, msg, len, 0) < 0) { 812 _errno = errno; 813 wpa_printf(MSG_INFO, "send[EAP-SIM DB UNIX]: %s", 814 strerror(errno)); 815 } 816 817 if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL || 818 _errno == ECONNREFUSED) { 819 /* Try to reconnect */ 820 eap_sim_db_close_socket(data); 821 if (eap_sim_db_open_socket(data) < 0) 822 return -1; 823 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Reconnected to the " 824 "external server"); 825 if (send(data->sock, msg, len, 0) < 0) { 826 wpa_printf(MSG_INFO, "send[EAP-SIM DB UNIX]: %s", 827 strerror(errno)); 828 return -1; 829 } 830 } 831 832 return 0; 833 } 834 835 836 static void eap_sim_db_expire_pending(struct eap_sim_db_data *data) 837 { 838 /* TODO: add limit for maximum length for pending list; remove latest 839 * (i.e., last) entry from the list if the limit is reached; could also 840 * use timeout to expire pending entries */ 841 } 842 843 844 /** 845 * eap_sim_db_get_gsm_triplets - Get GSM triplets 846 * @data: Private data pointer from eap_sim_db_init() 847 * @username: Permanent username (prefix | IMSI) 848 * @max_chal: Maximum number of triplets 849 * @_rand: Buffer for RAND values 850 * @kc: Buffer for Kc values 851 * @sres: Buffer for SRES values 852 * @cb_session_ctx: Session callback context for get_complete_cb() 853 * Returns: Number of triplets received (has to be less than or equal to 854 * max_chal), -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not found), or 855 * -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this case, the 856 * callback function registered with eap_sim_db_init() will be called once the 857 * results become available. 858 * 859 * When using an external server for GSM triplets, this function can always 860 * start a request and return EAP_SIM_DB_PENDING immediately if authentication 861 * triplets are not available. Once the triplets are received, callback 862 * function registered with eap_sim_db_init() is called to notify EAP state 863 * machine to reprocess the message. This eap_sim_db_get_gsm_triplets() 864 * function will then be called again and the newly received triplets will then 865 * be given to the caller. 866 */ 867 int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data, 868 const char *username, int max_chal, 869 u8 *_rand, u8 *kc, u8 *sres, 870 void *cb_session_ctx) 871 { 872 struct eap_sim_db_pending *entry; 873 int len, ret; 874 char msg[40]; 875 const char *imsi; 876 size_t imsi_len; 877 878 if (username == NULL || username[0] != EAP_SIM_PERMANENT_PREFIX || 879 username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) { 880 wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'", 881 username); 882 return EAP_SIM_DB_FAILURE; 883 } 884 imsi = username + 1; 885 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI '%s'", 886 imsi); 887 888 entry = eap_sim_db_get_pending(data, imsi, 0); 889 if (entry) { 890 int num_chal; 891 if (entry->state == FAILURE) { 892 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> " 893 "failure"); 894 os_free(entry); 895 return EAP_SIM_DB_FAILURE; 896 } 897 898 if (entry->state == PENDING) { 899 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> " 900 "still pending"); 901 eap_sim_db_add_pending(data, entry); 902 return EAP_SIM_DB_PENDING; 903 } 904 905 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> " 906 "%d challenges", entry->u.sim.num_chal); 907 num_chal = entry->u.sim.num_chal; 908 if (num_chal > max_chal) 909 num_chal = max_chal; 910 os_memcpy(_rand, entry->u.sim.rand, num_chal * GSM_RAND_LEN); 911 os_memcpy(sres, entry->u.sim.sres, 912 num_chal * EAP_SIM_SRES_LEN); 913 os_memcpy(kc, entry->u.sim.kc, num_chal * EAP_SIM_KC_LEN); 914 os_free(entry); 915 return num_chal; 916 } 917 918 if (data->sock < 0) { 919 if (eap_sim_db_open_socket(data) < 0) 920 return EAP_SIM_DB_FAILURE; 921 } 922 923 imsi_len = os_strlen(imsi); 924 len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH "); 925 if (os_snprintf_error(sizeof(msg), len) || 926 len + imsi_len >= sizeof(msg)) 927 return EAP_SIM_DB_FAILURE; 928 os_memcpy(msg + len, imsi, imsi_len); 929 len += imsi_len; 930 ret = os_snprintf(msg + len, sizeof(msg) - len, " %d", max_chal); 931 if (os_snprintf_error(sizeof(msg) - len, ret)) 932 return EAP_SIM_DB_FAILURE; 933 len += ret; 934 935 wpa_printf(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication " 936 "data for IMSI '%s'", imsi); 937 if (eap_sim_db_send(data, msg, len) < 0) 938 return EAP_SIM_DB_FAILURE; 939 940 entry = os_zalloc(sizeof(*entry)); 941 if (entry == NULL) 942 return EAP_SIM_DB_FAILURE; 943 944 os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi)); 945 entry->cb_session_ctx = cb_session_ctx; 946 entry->state = PENDING; 947 eap_sim_db_add_pending(data, entry); 948 eap_sim_db_expire_pending(data); 949 950 return EAP_SIM_DB_PENDING; 951 } 952 953 954 static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix) 955 { 956 char *id, *pos, *end; 957 u8 buf[10]; 958 959 if (random_get_bytes(buf, sizeof(buf))) 960 return NULL; 961 id = os_malloc(sizeof(buf) * 2 + 2); 962 if (id == NULL) 963 return NULL; 964 965 pos = id; 966 end = id + sizeof(buf) * 2 + 2; 967 *pos++ = prefix; 968 wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf)); 969 970 return id; 971 } 972 973 974 /** 975 * eap_sim_db_get_next_pseudonym - EAP-SIM DB: Get next pseudonym 976 * @data: Private data pointer from eap_sim_db_init() 977 * @method: EAP method (SIM/AKA/AKA') 978 * Returns: Next pseudonym (allocated string) or %NULL on failure 979 * 980 * This function is used to generate a pseudonym for EAP-SIM. The returned 981 * pseudonym is not added to database at this point; it will need to be added 982 * with eap_sim_db_add_pseudonym() once the authentication has been completed 983 * successfully. Caller is responsible for freeing the returned buffer. 984 */ 985 char * eap_sim_db_get_next_pseudonym(struct eap_sim_db_data *data, 986 enum eap_sim_db_method method) 987 { 988 char prefix = EAP_SIM_REAUTH_ID_PREFIX; 989 990 switch (method) { 991 case EAP_SIM_DB_SIM: 992 prefix = EAP_SIM_PSEUDONYM_PREFIX; 993 break; 994 case EAP_SIM_DB_AKA: 995 prefix = EAP_AKA_PSEUDONYM_PREFIX; 996 break; 997 case EAP_SIM_DB_AKA_PRIME: 998 prefix = EAP_AKA_PRIME_PSEUDONYM_PREFIX; 999 break; 1000 } 1001 1002 return eap_sim_db_get_next(data, prefix); 1003 } 1004 1005 1006 /** 1007 * eap_sim_db_get_next_reauth_id - EAP-SIM DB: Get next reauth_id 1008 * @data: Private data pointer from eap_sim_db_init() 1009 * @method: EAP method (SIM/AKA/AKA') 1010 * Returns: Next reauth_id (allocated string) or %NULL on failure 1011 * 1012 * This function is used to generate a fast re-authentication identity for 1013 * EAP-SIM. The returned reauth_id is not added to database at this point; it 1014 * will need to be added with eap_sim_db_add_reauth() once the authentication 1015 * has been completed successfully. Caller is responsible for freeing the 1016 * returned buffer. 1017 */ 1018 char * eap_sim_db_get_next_reauth_id(struct eap_sim_db_data *data, 1019 enum eap_sim_db_method method) 1020 { 1021 char prefix = EAP_SIM_REAUTH_ID_PREFIX; 1022 1023 switch (method) { 1024 case EAP_SIM_DB_SIM: 1025 prefix = EAP_SIM_REAUTH_ID_PREFIX; 1026 break; 1027 case EAP_SIM_DB_AKA: 1028 prefix = EAP_AKA_REAUTH_ID_PREFIX; 1029 break; 1030 case EAP_SIM_DB_AKA_PRIME: 1031 prefix = EAP_AKA_PRIME_REAUTH_ID_PREFIX; 1032 break; 1033 } 1034 1035 return eap_sim_db_get_next(data, prefix); 1036 } 1037 1038 1039 /** 1040 * eap_sim_db_add_pseudonym - EAP-SIM DB: Add new pseudonym 1041 * @data: Private data pointer from eap_sim_db_init() 1042 * @permanent: Permanent username 1043 * @pseudonym: Pseudonym for this user. This needs to be an allocated buffer, 1044 * e.g., return value from eap_sim_db_get_next_pseudonym(). Caller must not 1045 * free it. 1046 * Returns: 0 on success, -1 on failure 1047 * 1048 * This function adds a new pseudonym for EAP-SIM user. EAP-SIM DB is 1049 * responsible of freeing pseudonym buffer once it is not needed anymore. 1050 */ 1051 int eap_sim_db_add_pseudonym(struct eap_sim_db_data *data, 1052 const char *permanent, char *pseudonym) 1053 { 1054 struct eap_sim_pseudonym *p; 1055 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add pseudonym '%s' for permanent " 1056 "username '%s'", pseudonym, permanent); 1057 1058 /* TODO: could store last two pseudonyms */ 1059 #ifdef CONFIG_SQLITE 1060 if (data->sqlite_db) 1061 return db_add_pseudonym(data, permanent, pseudonym); 1062 #endif /* CONFIG_SQLITE */ 1063 for (p = data->pseudonyms; p; p = p->next) { 1064 if (os_strcmp(permanent, p->permanent) == 0) 1065 break; 1066 } 1067 if (p) { 1068 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous " 1069 "pseudonym: %s", p->pseudonym); 1070 os_free(p->pseudonym); 1071 p->pseudonym = pseudonym; 1072 return 0; 1073 } 1074 1075 p = os_zalloc(sizeof(*p)); 1076 if (p == NULL) { 1077 os_free(pseudonym); 1078 return -1; 1079 } 1080 1081 p->next = data->pseudonyms; 1082 p->permanent = os_strdup(permanent); 1083 if (p->permanent == NULL) { 1084 os_free(p); 1085 os_free(pseudonym); 1086 return -1; 1087 } 1088 p->pseudonym = pseudonym; 1089 data->pseudonyms = p; 1090 1091 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new pseudonym entry"); 1092 return 0; 1093 } 1094 1095 1096 static struct eap_sim_reauth * 1097 eap_sim_db_add_reauth_data(struct eap_sim_db_data *data, 1098 const char *permanent, 1099 char *reauth_id, u16 counter) 1100 { 1101 struct eap_sim_reauth *r; 1102 1103 for (r = data->reauths; r; r = r->next) { 1104 if (os_strcmp(r->permanent, permanent) == 0) 1105 break; 1106 } 1107 1108 if (r) { 1109 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous " 1110 "reauth_id: %s", r->reauth_id); 1111 os_free(r->reauth_id); 1112 r->reauth_id = reauth_id; 1113 } else { 1114 r = os_zalloc(sizeof(*r)); 1115 if (r == NULL) { 1116 os_free(reauth_id); 1117 return NULL; 1118 } 1119 1120 r->next = data->reauths; 1121 r->permanent = os_strdup(permanent); 1122 if (r->permanent == NULL) { 1123 os_free(r); 1124 os_free(reauth_id); 1125 return NULL; 1126 } 1127 r->reauth_id = reauth_id; 1128 data->reauths = r; 1129 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new reauth entry"); 1130 } 1131 1132 r->counter = counter; 1133 1134 return r; 1135 } 1136 1137 1138 /** 1139 * eap_sim_db_add_reauth - EAP-SIM DB: Add new re-authentication entry 1140 * @priv: Private data pointer from eap_sim_db_init() 1141 * @permanent: Permanent username 1142 * @identity_len: Length of identity 1143 * @reauth_id: reauth_id for this user. This needs to be an allocated buffer, 1144 * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not 1145 * free it. 1146 * @counter: AT_COUNTER value for fast re-authentication 1147 * @mk: 16-byte MK from the previous full authentication or %NULL 1148 * Returns: 0 on success, -1 on failure 1149 * 1150 * This function adds a new re-authentication entry for an EAP-SIM user. 1151 * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed 1152 * anymore. 1153 */ 1154 int eap_sim_db_add_reauth(struct eap_sim_db_data *data, const char *permanent, 1155 char *reauth_id, u16 counter, const u8 *mk) 1156 { 1157 struct eap_sim_reauth *r; 1158 1159 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add reauth_id '%s' for permanent " 1160 "identity '%s'", reauth_id, permanent); 1161 1162 #ifdef CONFIG_SQLITE 1163 if (data->sqlite_db) 1164 return db_add_reauth(data, permanent, reauth_id, counter, mk, 1165 NULL, NULL, NULL); 1166 #endif /* CONFIG_SQLITE */ 1167 r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter); 1168 if (r == NULL) 1169 return -1; 1170 1171 os_memcpy(r->mk, mk, EAP_SIM_MK_LEN); 1172 1173 return 0; 1174 } 1175 1176 1177 #ifdef EAP_SERVER_AKA_PRIME 1178 /** 1179 * eap_sim_db_add_reauth_prime - EAP-AKA' DB: Add new re-authentication entry 1180 * @data: Private data pointer from eap_sim_db_init() 1181 * @permanent: Permanent username 1182 * @reauth_id: reauth_id for this user. This needs to be an allocated buffer, 1183 * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not 1184 * free it. 1185 * @counter: AT_COUNTER value for fast re-authentication 1186 * @k_encr: K_encr from the previous full authentication 1187 * @k_aut: K_aut from the previous full authentication 1188 * @k_re: 32-byte K_re from the previous full authentication 1189 * Returns: 0 on success, -1 on failure 1190 * 1191 * This function adds a new re-authentication entry for an EAP-AKA' user. 1192 * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed 1193 * anymore. 1194 */ 1195 int eap_sim_db_add_reauth_prime(struct eap_sim_db_data *data, 1196 const char *permanent, char *reauth_id, 1197 u16 counter, const u8 *k_encr, 1198 const u8 *k_aut, const u8 *k_re) 1199 { 1200 struct eap_sim_reauth *r; 1201 1202 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add reauth_id '%s' for permanent " 1203 "identity '%s'", reauth_id, permanent); 1204 1205 #ifdef CONFIG_SQLITE 1206 if (data->sqlite_db) 1207 return db_add_reauth(data, permanent, reauth_id, counter, NULL, 1208 k_encr, k_aut, k_re); 1209 #endif /* CONFIG_SQLITE */ 1210 r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter); 1211 if (r == NULL) 1212 return -1; 1213 1214 os_memcpy(r->k_encr, k_encr, EAP_SIM_K_ENCR_LEN); 1215 os_memcpy(r->k_aut, k_aut, EAP_AKA_PRIME_K_AUT_LEN); 1216 os_memcpy(r->k_re, k_re, EAP_AKA_PRIME_K_RE_LEN); 1217 1218 return 0; 1219 } 1220 #endif /* EAP_SERVER_AKA_PRIME */ 1221 1222 1223 /** 1224 * eap_sim_db_get_permanent - EAP-SIM DB: Get permanent identity 1225 * @data: Private data pointer from eap_sim_db_init() 1226 * @pseudonym: Pseudonym username 1227 * Returns: Pointer to permanent username or %NULL if not found 1228 */ 1229 const char * 1230 eap_sim_db_get_permanent(struct eap_sim_db_data *data, const char *pseudonym) 1231 { 1232 struct eap_sim_pseudonym *p; 1233 1234 #ifdef CONFIG_SQLITE 1235 if (data->sqlite_db) 1236 return db_get_pseudonym(data, pseudonym); 1237 #endif /* CONFIG_SQLITE */ 1238 1239 p = data->pseudonyms; 1240 while (p) { 1241 if (os_strcmp(p->pseudonym, pseudonym) == 0) 1242 return p->permanent; 1243 p = p->next; 1244 } 1245 1246 return NULL; 1247 } 1248 1249 1250 /** 1251 * eap_sim_db_get_reauth_entry - EAP-SIM DB: Get re-authentication entry 1252 * @data: Private data pointer from eap_sim_db_init() 1253 * @reauth_id: Fast re-authentication username 1254 * Returns: Pointer to the re-auth entry, or %NULL if not found 1255 */ 1256 struct eap_sim_reauth * 1257 eap_sim_db_get_reauth_entry(struct eap_sim_db_data *data, 1258 const char *reauth_id) 1259 { 1260 struct eap_sim_reauth *r; 1261 1262 #ifdef CONFIG_SQLITE 1263 if (data->sqlite_db) 1264 return db_get_reauth(data, reauth_id); 1265 #endif /* CONFIG_SQLITE */ 1266 1267 r = data->reauths; 1268 while (r) { 1269 if (os_strcmp(r->reauth_id, reauth_id) == 0) 1270 break; 1271 r = r->next; 1272 } 1273 1274 return r; 1275 } 1276 1277 1278 /** 1279 * eap_sim_db_remove_reauth - EAP-SIM DB: Remove re-authentication entry 1280 * @data: Private data pointer from eap_sim_db_init() 1281 * @reauth: Pointer to re-authentication entry from 1282 * eap_sim_db_get_reauth_entry() 1283 */ 1284 void eap_sim_db_remove_reauth(struct eap_sim_db_data *data, 1285 struct eap_sim_reauth *reauth) 1286 { 1287 struct eap_sim_reauth *r, *prev = NULL; 1288 #ifdef CONFIG_SQLITE 1289 if (data->sqlite_db) { 1290 db_remove_reauth(data, reauth); 1291 return; 1292 } 1293 #endif /* CONFIG_SQLITE */ 1294 r = data->reauths; 1295 while (r) { 1296 if (r == reauth) { 1297 if (prev) 1298 prev->next = r->next; 1299 else 1300 data->reauths = r->next; 1301 eap_sim_db_free_reauth(r); 1302 return; 1303 } 1304 prev = r; 1305 r = r->next; 1306 } 1307 } 1308 1309 1310 /** 1311 * eap_sim_db_get_aka_auth - Get AKA authentication values 1312 * @data: Private data pointer from eap_sim_db_init() 1313 * @username: Permanent username (prefix | IMSI) 1314 * @_rand: Buffer for RAND value 1315 * @autn: Buffer for AUTN value 1316 * @ik: Buffer for IK value 1317 * @ck: Buffer for CK value 1318 * @res: Buffer for RES value 1319 * @res_len: Buffer for RES length 1320 * @cb_session_ctx: Session callback context for get_complete_cb() 1321 * Returns: 0 on success, -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not 1322 * found), or -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this 1323 * case, the callback function registered with eap_sim_db_init() will be 1324 * called once the results become available. 1325 * 1326 * When using an external server for AKA authentication, this function can 1327 * always start a request and return EAP_SIM_DB_PENDING immediately if 1328 * authentication triplets are not available. Once the authentication data are 1329 * received, callback function registered with eap_sim_db_init() is called to 1330 * notify EAP state machine to reprocess the message. This 1331 * eap_sim_db_get_aka_auth() function will then be called again and the newly 1332 * received triplets will then be given to the caller. 1333 */ 1334 int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username, 1335 u8 *_rand, u8 *autn, u8 *ik, u8 *ck, 1336 u8 *res, size_t *res_len, void *cb_session_ctx) 1337 { 1338 struct eap_sim_db_pending *entry; 1339 int len; 1340 char msg[40]; 1341 const char *imsi; 1342 size_t imsi_len; 1343 1344 if (username == NULL || 1345 (username[0] != EAP_AKA_PERMANENT_PREFIX && 1346 username[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) || 1347 username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) { 1348 wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'", 1349 username); 1350 return EAP_SIM_DB_FAILURE; 1351 } 1352 imsi = username + 1; 1353 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI '%s'", 1354 imsi); 1355 1356 entry = eap_sim_db_get_pending(data, imsi, 1); 1357 if (entry) { 1358 if (entry->state == FAILURE) { 1359 os_free(entry); 1360 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failure"); 1361 return EAP_SIM_DB_FAILURE; 1362 } 1363 1364 if (entry->state == PENDING) { 1365 eap_sim_db_add_pending(data, entry); 1366 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending"); 1367 return EAP_SIM_DB_PENDING; 1368 } 1369 1370 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Returning successfully " 1371 "received authentication data"); 1372 os_memcpy(_rand, entry->u.aka.rand, EAP_AKA_RAND_LEN); 1373 os_memcpy(autn, entry->u.aka.autn, EAP_AKA_AUTN_LEN); 1374 os_memcpy(ik, entry->u.aka.ik, EAP_AKA_IK_LEN); 1375 os_memcpy(ck, entry->u.aka.ck, EAP_AKA_CK_LEN); 1376 os_memcpy(res, entry->u.aka.res, EAP_AKA_RES_MAX_LEN); 1377 *res_len = entry->u.aka.res_len; 1378 os_free(entry); 1379 return 0; 1380 } 1381 1382 if (data->sock < 0) { 1383 if (eap_sim_db_open_socket(data) < 0) 1384 return EAP_SIM_DB_FAILURE; 1385 } 1386 1387 imsi_len = os_strlen(imsi); 1388 len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH "); 1389 if (os_snprintf_error(sizeof(msg), len) || 1390 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 (os_snprintf_error(sizeof(msg), len) || 1455 len + imsi_len >= sizeof(msg)) 1456 return -1; 1457 os_memcpy(msg + len, imsi, imsi_len); 1458 len += imsi_len; 1459 1460 ret = os_snprintf(msg + len, sizeof(msg) - len, " "); 1461 if (os_snprintf_error(sizeof(msg) - len, ret)) 1462 return -1; 1463 len += ret; 1464 len += wpa_snprintf_hex(msg + len, sizeof(msg) - len, 1465 auts, EAP_AKA_AUTS_LEN); 1466 ret = os_snprintf(msg + len, sizeof(msg) - len, " "); 1467 if (os_snprintf_error(sizeof(msg) - len, ret)) 1468 return -1; 1469 len += ret; 1470 len += wpa_snprintf_hex(msg + len, sizeof(msg) - len, 1471 _rand, EAP_AKA_RAND_LEN); 1472 wpa_printf(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for " 1473 "IMSI '%s'", imsi); 1474 if (eap_sim_db_send(data, msg, len) < 0) 1475 return -1; 1476 } 1477 1478 return 0; 1479 } 1480 1481 1482 /** 1483 * sim_get_username - Extract username from SIM identity 1484 * @identity: Identity 1485 * @identity_len: Identity length 1486 * Returns: Allocated buffer with the username part of the identity 1487 * 1488 * Caller is responsible for freeing the returned buffer with os_free(). 1489 */ 1490 char * sim_get_username(const u8 *identity, size_t identity_len) 1491 { 1492 size_t pos; 1493 1494 if (identity == NULL) 1495 return NULL; 1496 1497 for (pos = 0; pos < identity_len; pos++) { 1498 if (identity[pos] == '@' || identity[pos] == '\0') 1499 break; 1500 } 1501 1502 return dup_binstr(identity, pos); 1503 } 1504