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