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