1 1.1 christos /* 2 1.1 christos * HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator 3 1.1.1.8 christos * Copyright (c) 2005-2007, 2012-2017, Jouni Malinen <j (at) w1.fi> 4 1.1 christos * 5 1.1.1.4 christos * This software may be distributed under the terms of the BSD license. 6 1.1.1.4 christos * See README for more details. 7 1.1 christos * 8 1.1 christos * This is an example implementation of the EAP-SIM/AKA database/authentication 9 1.1 christos * gateway interface to HLR/AuC. It is expected to be replaced with an 10 1.1 christos * implementation of SS7 gateway to GSM/UMTS authentication center (HLR/AuC) or 11 1.1 christos * a local implementation of SIM triplet and AKA authentication data generator. 12 1.1 christos * 13 1.1 christos * hostapd will send SIM/AKA authentication queries over a UNIX domain socket 14 1.1 christos * to and external program, e.g., this hlr_auc_gw. This interface uses simple 15 1.1 christos * text-based format: 16 1.1 christos * 17 1.1 christos * EAP-SIM / GSM triplet query/response: 18 1.1 christos * SIM-REQ-AUTH <IMSI> <max_chal> 19 1.1 christos * SIM-RESP-AUTH <IMSI> Kc1:SRES1:RAND1 Kc2:SRES2:RAND2 [Kc3:SRES3:RAND3] 20 1.1 christos * SIM-RESP-AUTH <IMSI> FAILURE 21 1.1.1.5 christos * GSM-AUTH-REQ <IMSI> RAND1:RAND2[:RAND3] 22 1.1.1.5 christos * GSM-AUTH-RESP <IMSI> Kc1:SRES1:Kc2:SRES2[:Kc3:SRES3] 23 1.1.1.5 christos * GSM-AUTH-RESP <IMSI> FAILURE 24 1.1 christos * 25 1.1 christos * EAP-AKA / UMTS query/response: 26 1.1 christos * AKA-REQ-AUTH <IMSI> 27 1.1 christos * AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES> 28 1.1 christos * AKA-RESP-AUTH <IMSI> FAILURE 29 1.1 christos * 30 1.1 christos * EAP-AKA / UMTS AUTS (re-synchronization): 31 1.1 christos * AKA-AUTS <IMSI> <AUTS> <RAND> 32 1.1 christos * 33 1.1 christos * IMSI and max_chal are sent as an ASCII string, 34 1.1 christos * Kc/SRES/RAND/AUTN/IK/CK/RES/AUTS as hex strings. 35 1.1 christos * 36 1.1.1.5 christos * An example implementation here reads GSM authentication triplets from a 37 1.1 christos * text file in IMSI:Kc:SRES:RAND format, IMSI in ASCII, other fields as hex 38 1.1 christos * strings. This is used to simulate an HLR/AuC. As such, it is not very useful 39 1.1 christos * for real life authentication, but it is useful both as an example 40 1.1.1.3 adam * implementation and for EAP-SIM/AKA/AKA' testing. 41 1.1.1.3 adam * 42 1.1.1.5 christos * For a stronger example design, Milenage and GSM-Milenage algorithms can be 43 1.1.1.5 christos * used to dynamically generate authenticatipn information for EAP-AKA/AKA' and 44 1.1.1.5 christos * EAP-SIM, respectively, if Ki is known. 45 1.1.1.5 christos * 46 1.1.1.3 adam * SQN generation follows the not time-based Profile 2 described in 47 1.1.1.3 adam * 3GPP TS 33.102 Annex C.3.2. The length of IND is 5 bits by default, but this 48 1.1.1.3 adam * can be changed with a command line options if needed. 49 1.1 christos */ 50 1.1 christos 51 1.1 christos #include "includes.h" 52 1.1 christos #include <sys/un.h> 53 1.1.1.4 christos #ifdef CONFIG_SQLITE 54 1.1.1.4 christos #include <sqlite3.h> 55 1.1.1.4 christos #endif /* CONFIG_SQLITE */ 56 1.1 christos 57 1.1 christos #include "common.h" 58 1.1 christos #include "crypto/milenage.h" 59 1.1.1.2 christos #include "crypto/random.h" 60 1.1 christos 61 1.1 christos static const char *default_socket_path = "/tmp/hlr_auc_gw.sock"; 62 1.1 christos static const char *socket_path; 63 1.1 christos static int serv_sock = -1; 64 1.1.1.4 christos static char *milenage_file = NULL; 65 1.1.1.4 christos static int update_milenage = 0; 66 1.1.1.4 christos static int sqn_changes = 0; 67 1.1.1.3 adam static int ind_len = 5; 68 1.1.1.5 christos static int stdout_debug = 1; 69 1.1 christos 70 1.1 christos /* GSM triplets */ 71 1.1 christos struct gsm_triplet { 72 1.1 christos struct gsm_triplet *next; 73 1.1 christos char imsi[20]; 74 1.1 christos u8 kc[8]; 75 1.1 christos u8 sres[4]; 76 1.1 christos u8 _rand[16]; 77 1.1 christos }; 78 1.1 christos 79 1.1 christos static struct gsm_triplet *gsm_db = NULL, *gsm_db_pos = NULL; 80 1.1 christos 81 1.1 christos /* OPc and AMF parameters for Milenage (Example algorithms for AKA). */ 82 1.1 christos struct milenage_parameters { 83 1.1 christos struct milenage_parameters *next; 84 1.1 christos char imsi[20]; 85 1.1 christos u8 ki[16]; 86 1.1 christos u8 opc[16]; 87 1.1 christos u8 amf[2]; 88 1.1 christos u8 sqn[6]; 89 1.1.1.4 christos int set; 90 1.1.1.7 christos size_t res_len; 91 1.1 christos }; 92 1.1 christos 93 1.1 christos static struct milenage_parameters *milenage_db = NULL; 94 1.1 christos 95 1.1 christos #define EAP_SIM_MAX_CHAL 3 96 1.1 christos 97 1.1 christos #define EAP_AKA_RAND_LEN 16 98 1.1 christos #define EAP_AKA_AUTN_LEN 16 99 1.1 christos #define EAP_AKA_AUTS_LEN 14 100 1.1.1.7 christos #define EAP_AKA_RES_MIN_LEN 4 101 1.1 christos #define EAP_AKA_RES_MAX_LEN 16 102 1.1 christos #define EAP_AKA_IK_LEN 16 103 1.1 christos #define EAP_AKA_CK_LEN 16 104 1.1 christos 105 1.1 christos 106 1.1.1.4 christos #ifdef CONFIG_SQLITE 107 1.1.1.4 christos 108 1.1.1.4 christos static sqlite3 *sqlite_db = NULL; 109 1.1.1.4 christos static struct milenage_parameters db_tmp_milenage; 110 1.1.1.4 christos 111 1.1.1.4 christos 112 1.1.1.4 christos static int db_table_exists(sqlite3 *db, const char *name) 113 1.1.1.4 christos { 114 1.1.1.4 christos char cmd[128]; 115 1.1.1.4 christos os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name); 116 1.1.1.4 christos return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK; 117 1.1.1.4 christos } 118 1.1.1.4 christos 119 1.1.1.4 christos 120 1.1.1.4 christos static int db_table_create_milenage(sqlite3 *db) 121 1.1.1.4 christos { 122 1.1.1.4 christos char *err = NULL; 123 1.1.1.4 christos const char *sql = 124 1.1.1.4 christos "CREATE TABLE milenage(" 125 1.1.1.4 christos " imsi INTEGER PRIMARY KEY NOT NULL," 126 1.1.1.4 christos " ki CHAR(32) NOT NULL," 127 1.1.1.4 christos " opc CHAR(32) NOT NULL," 128 1.1.1.4 christos " amf CHAR(4) NOT NULL," 129 1.1.1.7 christos " sqn CHAR(12) NOT NULL," 130 1.1.1.7 christos " res_len INTEGER" 131 1.1.1.4 christos ");"; 132 1.1.1.4 christos 133 1.1.1.4 christos printf("Adding database table for milenage information\n"); 134 1.1.1.4 christos if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) { 135 1.1.1.4 christos printf("SQLite error: %s\n", err); 136 1.1.1.4 christos sqlite3_free(err); 137 1.1.1.4 christos return -1; 138 1.1.1.4 christos } 139 1.1.1.4 christos 140 1.1.1.4 christos return 0; 141 1.1.1.4 christos } 142 1.1.1.4 christos 143 1.1.1.4 christos 144 1.1.1.4 christos static sqlite3 * db_open(const char *db_file) 145 1.1.1.4 christos { 146 1.1.1.4 christos sqlite3 *db; 147 1.1.1.4 christos 148 1.1.1.4 christos if (sqlite3_open(db_file, &db)) { 149 1.1.1.4 christos printf("Failed to open database %s: %s\n", 150 1.1.1.4 christos db_file, sqlite3_errmsg(db)); 151 1.1.1.4 christos sqlite3_close(db); 152 1.1.1.4 christos return NULL; 153 1.1.1.4 christos } 154 1.1.1.4 christos 155 1.1.1.4 christos if (!db_table_exists(db, "milenage") && 156 1.1.1.4 christos db_table_create_milenage(db) < 0) { 157 1.1.1.4 christos sqlite3_close(db); 158 1.1.1.4 christos return NULL; 159 1.1.1.4 christos } 160 1.1.1.4 christos 161 1.1.1.4 christos return db; 162 1.1.1.4 christos } 163 1.1.1.4 christos 164 1.1.1.4 christos 165 1.1.1.4 christos static int get_milenage_cb(void *ctx, int argc, char *argv[], char *col[]) 166 1.1.1.4 christos { 167 1.1.1.4 christos struct milenage_parameters *m = ctx; 168 1.1.1.4 christos int i; 169 1.1.1.4 christos 170 1.1.1.4 christos m->set = 1; 171 1.1.1.4 christos 172 1.1.1.4 christos for (i = 0; i < argc; i++) { 173 1.1.1.4 christos if (os_strcmp(col[i], "ki") == 0 && argv[i] && 174 1.1.1.4 christos hexstr2bin(argv[i], m->ki, sizeof(m->ki))) { 175 1.1.1.4 christos printf("Invalid ki value in database\n"); 176 1.1.1.4 christos return -1; 177 1.1.1.4 christos } 178 1.1.1.4 christos 179 1.1.1.4 christos if (os_strcmp(col[i], "opc") == 0 && argv[i] && 180 1.1.1.4 christos hexstr2bin(argv[i], m->opc, sizeof(m->opc))) { 181 1.1.1.4 christos printf("Invalid opcvalue in database\n"); 182 1.1.1.4 christos return -1; 183 1.1.1.4 christos } 184 1.1.1.4 christos 185 1.1.1.4 christos if (os_strcmp(col[i], "amf") == 0 && argv[i] && 186 1.1.1.4 christos hexstr2bin(argv[i], m->amf, sizeof(m->amf))) { 187 1.1.1.4 christos printf("Invalid amf value in database\n"); 188 1.1.1.4 christos return -1; 189 1.1.1.4 christos } 190 1.1.1.4 christos 191 1.1.1.4 christos if (os_strcmp(col[i], "sqn") == 0 && argv[i] && 192 1.1.1.4 christos hexstr2bin(argv[i], m->sqn, sizeof(m->sqn))) { 193 1.1.1.4 christos printf("Invalid sqn value in database\n"); 194 1.1.1.4 christos return -1; 195 1.1.1.4 christos } 196 1.1.1.7 christos 197 1.1.1.7 christos if (os_strcmp(col[i], "res_len") == 0 && argv[i]) { 198 1.1.1.7 christos m->res_len = atoi(argv[i]); 199 1.1.1.7 christos } 200 1.1.1.4 christos } 201 1.1.1.4 christos 202 1.1.1.4 christos return 0; 203 1.1.1.4 christos } 204 1.1.1.4 christos 205 1.1.1.4 christos 206 1.1.1.4 christos static struct milenage_parameters * db_get_milenage(const char *imsi_txt) 207 1.1.1.4 christos { 208 1.1.1.4 christos char cmd[128]; 209 1.1.1.4 christos unsigned long long imsi; 210 1.1.1.4 christos 211 1.1.1.4 christos os_memset(&db_tmp_milenage, 0, sizeof(db_tmp_milenage)); 212 1.1.1.4 christos imsi = atoll(imsi_txt); 213 1.1.1.4 christos os_snprintf(db_tmp_milenage.imsi, sizeof(db_tmp_milenage.imsi), 214 1.1.1.4 christos "%llu", imsi); 215 1.1.1.4 christos os_snprintf(cmd, sizeof(cmd), 216 1.1.1.7 christos "SELECT * FROM milenage WHERE imsi=%llu;", imsi); 217 1.1.1.4 christos if (sqlite3_exec(sqlite_db, cmd, get_milenage_cb, &db_tmp_milenage, 218 1.1.1.4 christos NULL) != SQLITE_OK) 219 1.1.1.4 christos return NULL; 220 1.1.1.4 christos 221 1.1.1.4 christos if (!db_tmp_milenage.set) 222 1.1.1.4 christos return NULL; 223 1.1.1.4 christos return &db_tmp_milenage; 224 1.1.1.4 christos } 225 1.1.1.4 christos 226 1.1.1.4 christos 227 1.1.1.4 christos static int db_update_milenage_sqn(struct milenage_parameters *m) 228 1.1.1.4 christos { 229 1.1.1.4 christos char cmd[128], val[13], *pos; 230 1.1.1.4 christos 231 1.1.1.5 christos if (sqlite_db == NULL) 232 1.1.1.5 christos return 0; 233 1.1.1.5 christos 234 1.1.1.4 christos pos = val; 235 1.1.1.4 christos pos += wpa_snprintf_hex(pos, sizeof(val), m->sqn, 6); 236 1.1.1.4 christos *pos = '\0'; 237 1.1.1.4 christos os_snprintf(cmd, sizeof(cmd), 238 1.1.1.4 christos "UPDATE milenage SET sqn='%s' WHERE imsi=%s;", 239 1.1.1.4 christos val, m->imsi); 240 1.1.1.4 christos if (sqlite3_exec(sqlite_db, cmd, NULL, NULL, NULL) != SQLITE_OK) { 241 1.1.1.4 christos printf("Failed to update SQN in database for IMSI %s\n", 242 1.1.1.4 christos m->imsi); 243 1.1.1.4 christos return -1; 244 1.1.1.4 christos } 245 1.1.1.4 christos return 0; 246 1.1.1.4 christos } 247 1.1.1.4 christos 248 1.1.1.4 christos #endif /* CONFIG_SQLITE */ 249 1.1.1.4 christos 250 1.1.1.4 christos 251 1.1 christos static int open_socket(const char *path) 252 1.1 christos { 253 1.1 christos struct sockaddr_un addr; 254 1.1 christos int s; 255 1.1 christos 256 1.1 christos s = socket(PF_UNIX, SOCK_DGRAM, 0); 257 1.1 christos if (s < 0) { 258 1.1 christos perror("socket(PF_UNIX)"); 259 1.1 christos return -1; 260 1.1 christos } 261 1.1 christos 262 1.1 christos memset(&addr, 0, sizeof(addr)); 263 1.1 christos addr.sun_family = AF_UNIX; 264 1.1 christos os_strlcpy(addr.sun_path, path, sizeof(addr.sun_path)); 265 1.1 christos if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 266 1.1.1.4 christos perror("hlr-auc-gw: bind(PF_UNIX)"); 267 1.1 christos close(s); 268 1.1 christos return -1; 269 1.1 christos } 270 1.1 christos 271 1.1 christos return s; 272 1.1 christos } 273 1.1 christos 274 1.1 christos 275 1.1 christos static int read_gsm_triplets(const char *fname) 276 1.1 christos { 277 1.1 christos FILE *f; 278 1.1 christos char buf[200], *pos, *pos2; 279 1.1 christos struct gsm_triplet *g = NULL; 280 1.1 christos int line, ret = 0; 281 1.1 christos 282 1.1 christos if (fname == NULL) 283 1.1 christos return -1; 284 1.1 christos 285 1.1 christos f = fopen(fname, "r"); 286 1.1 christos if (f == NULL) { 287 1.1.1.7 christos printf("Could not open GSM triplet data file '%s'\n", fname); 288 1.1 christos return -1; 289 1.1 christos } 290 1.1 christos 291 1.1 christos line = 0; 292 1.1 christos while (fgets(buf, sizeof(buf), f)) { 293 1.1 christos line++; 294 1.1 christos 295 1.1 christos /* Parse IMSI:Kc:SRES:RAND */ 296 1.1 christos buf[sizeof(buf) - 1] = '\0'; 297 1.1 christos if (buf[0] == '#') 298 1.1 christos continue; 299 1.1 christos pos = buf; 300 1.1 christos while (*pos != '\0' && *pos != '\n') 301 1.1 christos pos++; 302 1.1 christos if (*pos == '\n') 303 1.1 christos *pos = '\0'; 304 1.1 christos pos = buf; 305 1.1 christos if (*pos == '\0') 306 1.1 christos continue; 307 1.1 christos 308 1.1 christos g = os_zalloc(sizeof(*g)); 309 1.1 christos if (g == NULL) { 310 1.1 christos ret = -1; 311 1.1 christos break; 312 1.1 christos } 313 1.1 christos 314 1.1 christos /* IMSI */ 315 1.1.1.7 christos pos2 = NULL; 316 1.1.1.7 christos pos = str_token(buf, ":", &pos2); 317 1.1.1.7 christos if (!pos || os_strlen(pos) >= sizeof(g->imsi)) { 318 1.1.1.7 christos printf("%s:%d - Invalid IMSI\n", fname, line); 319 1.1 christos ret = -1; 320 1.1 christos break; 321 1.1 christos } 322 1.1 christos os_strlcpy(g->imsi, pos, sizeof(g->imsi)); 323 1.1 christos 324 1.1 christos /* Kc */ 325 1.1.1.7 christos pos = str_token(buf, ":", &pos2); 326 1.1.1.7 christos if (!pos || os_strlen(pos) != 16 || hexstr2bin(pos, g->kc, 8)) { 327 1.1.1.7 christos printf("%s:%d - Invalid Kc\n", fname, line); 328 1.1 christos ret = -1; 329 1.1 christos break; 330 1.1 christos } 331 1.1 christos 332 1.1 christos /* SRES */ 333 1.1.1.7 christos pos = str_token(buf, ":", &pos2); 334 1.1.1.7 christos if (!pos || os_strlen(pos) != 8 || 335 1.1.1.7 christos hexstr2bin(pos, g->sres, 4)) { 336 1.1.1.7 christos printf("%s:%d - Invalid SRES\n", fname, line); 337 1.1 christos ret = -1; 338 1.1 christos break; 339 1.1 christos } 340 1.1 christos 341 1.1 christos /* RAND */ 342 1.1.1.7 christos pos = str_token(buf, ":", &pos2); 343 1.1.1.7 christos if (!pos || os_strlen(pos) != 32 || 344 1.1.1.7 christos hexstr2bin(pos, g->_rand, 16)) { 345 1.1.1.7 christos printf("%s:%d - Invalid RAND\n", fname, line); 346 1.1 christos ret = -1; 347 1.1 christos break; 348 1.1 christos } 349 1.1 christos 350 1.1 christos g->next = gsm_db; 351 1.1 christos gsm_db = g; 352 1.1 christos g = NULL; 353 1.1 christos } 354 1.1.1.4 christos os_free(g); 355 1.1 christos 356 1.1 christos fclose(f); 357 1.1 christos 358 1.1 christos return ret; 359 1.1 christos } 360 1.1 christos 361 1.1 christos 362 1.1 christos static struct gsm_triplet * get_gsm_triplet(const char *imsi) 363 1.1 christos { 364 1.1 christos struct gsm_triplet *g = gsm_db_pos; 365 1.1 christos 366 1.1 christos while (g) { 367 1.1 christos if (strcmp(g->imsi, imsi) == 0) { 368 1.1 christos gsm_db_pos = g->next; 369 1.1 christos return g; 370 1.1 christos } 371 1.1 christos g = g->next; 372 1.1 christos } 373 1.1 christos 374 1.1 christos g = gsm_db; 375 1.1 christos while (g && g != gsm_db_pos) { 376 1.1 christos if (strcmp(g->imsi, imsi) == 0) { 377 1.1 christos gsm_db_pos = g->next; 378 1.1 christos return g; 379 1.1 christos } 380 1.1 christos g = g->next; 381 1.1 christos } 382 1.1 christos 383 1.1 christos return NULL; 384 1.1 christos } 385 1.1 christos 386 1.1 christos 387 1.1 christos static int read_milenage(const char *fname) 388 1.1 christos { 389 1.1 christos FILE *f; 390 1.1 christos char buf[200], *pos, *pos2; 391 1.1 christos struct milenage_parameters *m = NULL; 392 1.1 christos int line, ret = 0; 393 1.1 christos 394 1.1 christos if (fname == NULL) 395 1.1 christos return -1; 396 1.1 christos 397 1.1 christos f = fopen(fname, "r"); 398 1.1 christos if (f == NULL) { 399 1.1 christos printf("Could not open Milenage data file '%s'\n", fname); 400 1.1 christos return -1; 401 1.1 christos } 402 1.1 christos 403 1.1 christos line = 0; 404 1.1 christos while (fgets(buf, sizeof(buf), f)) { 405 1.1 christos line++; 406 1.1 christos 407 1.1.1.7 christos /* Parse IMSI Ki OPc AMF SQN [RES_len] */ 408 1.1 christos buf[sizeof(buf) - 1] = '\0'; 409 1.1 christos if (buf[0] == '#') 410 1.1 christos continue; 411 1.1 christos pos = buf; 412 1.1 christos while (*pos != '\0' && *pos != '\n') 413 1.1 christos pos++; 414 1.1 christos if (*pos == '\n') 415 1.1 christos *pos = '\0'; 416 1.1 christos pos = buf; 417 1.1 christos if (*pos == '\0') 418 1.1 christos continue; 419 1.1 christos 420 1.1 christos m = os_zalloc(sizeof(*m)); 421 1.1 christos if (m == NULL) { 422 1.1 christos ret = -1; 423 1.1 christos break; 424 1.1 christos } 425 1.1 christos 426 1.1 christos /* IMSI */ 427 1.1.1.7 christos pos2 = NULL; 428 1.1.1.7 christos pos = str_token(buf, " ", &pos2); 429 1.1.1.7 christos if (!pos || os_strlen(pos) >= sizeof(m->imsi)) { 430 1.1.1.7 christos printf("%s:%d - Invalid IMSI\n", fname, line); 431 1.1 christos ret = -1; 432 1.1 christos break; 433 1.1 christos } 434 1.1 christos os_strlcpy(m->imsi, pos, sizeof(m->imsi)); 435 1.1 christos 436 1.1 christos /* Ki */ 437 1.1.1.7 christos pos = str_token(buf, " ", &pos2); 438 1.1.1.7 christos if (!pos || os_strlen(pos) != 32 || 439 1.1.1.7 christos hexstr2bin(pos, m->ki, 16)) { 440 1.1.1.7 christos printf("%s:%d - Invalid Ki\n", fname, line); 441 1.1 christos ret = -1; 442 1.1 christos break; 443 1.1 christos } 444 1.1 christos 445 1.1 christos /* OPc */ 446 1.1.1.7 christos pos = str_token(buf, " ", &pos2); 447 1.1.1.7 christos if (!pos || os_strlen(pos) != 32 || 448 1.1.1.7 christos hexstr2bin(pos, m->opc, 16)) { 449 1.1.1.7 christos printf("%s:%d - Invalid OPc\n", fname, line); 450 1.1 christos ret = -1; 451 1.1 christos break; 452 1.1 christos } 453 1.1 christos 454 1.1 christos /* AMF */ 455 1.1.1.7 christos pos = str_token(buf, " ", &pos2); 456 1.1.1.7 christos if (!pos || os_strlen(pos) != 4 || hexstr2bin(pos, m->amf, 2)) { 457 1.1.1.7 christos printf("%s:%d - Invalid AMF\n", fname, line); 458 1.1 christos ret = -1; 459 1.1 christos break; 460 1.1 christos } 461 1.1 christos 462 1.1 christos /* SQN */ 463 1.1.1.7 christos pos = str_token(buf, " ", &pos2); 464 1.1.1.7 christos if (!pos || os_strlen(pos) != 12 || 465 1.1.1.7 christos hexstr2bin(pos, m->sqn, 6)) { 466 1.1.1.7 christos printf("%s:%d - Invalid SEQ\n", fname, line); 467 1.1 christos ret = -1; 468 1.1 christos break; 469 1.1 christos } 470 1.1.1.7 christos 471 1.1.1.7 christos pos = str_token(buf, " ", &pos2); 472 1.1.1.7 christos if (pos) { 473 1.1.1.7 christos m->res_len = atoi(pos); 474 1.1.1.7 christos if (m->res_len && 475 1.1.1.7 christos (m->res_len < EAP_AKA_RES_MIN_LEN || 476 1.1.1.7 christos m->res_len > EAP_AKA_RES_MAX_LEN)) { 477 1.1.1.7 christos printf("%s:%d - Invalid RES_len\n", 478 1.1.1.7 christos fname, line); 479 1.1.1.7 christos ret = -1; 480 1.1.1.7 christos break; 481 1.1.1.7 christos } 482 1.1.1.7 christos } 483 1.1 christos 484 1.1 christos m->next = milenage_db; 485 1.1 christos milenage_db = m; 486 1.1 christos m = NULL; 487 1.1 christos } 488 1.1.1.4 christos os_free(m); 489 1.1 christos 490 1.1 christos fclose(f); 491 1.1 christos 492 1.1 christos return ret; 493 1.1 christos } 494 1.1 christos 495 1.1 christos 496 1.1.1.4 christos static void update_milenage_file(const char *fname) 497 1.1.1.4 christos { 498 1.1.1.4 christos FILE *f, *f2; 499 1.1.1.7 christos char name[500], buf[500], *pos; 500 1.1.1.4 christos char *end = buf + sizeof(buf); 501 1.1.1.4 christos struct milenage_parameters *m; 502 1.1.1.4 christos size_t imsi_len; 503 1.1.1.4 christos 504 1.1.1.4 christos f = fopen(fname, "r"); 505 1.1.1.4 christos if (f == NULL) { 506 1.1.1.4 christos printf("Could not open Milenage data file '%s'\n", fname); 507 1.1.1.4 christos return; 508 1.1.1.4 christos } 509 1.1.1.4 christos 510 1.1.1.7 christos snprintf(name, sizeof(name), "%s.new", fname); 511 1.1.1.7 christos f2 = fopen(name, "w"); 512 1.1.1.4 christos if (f2 == NULL) { 513 1.1.1.7 christos printf("Could not write Milenage data file '%s'\n", name); 514 1.1.1.4 christos fclose(f); 515 1.1.1.4 christos return; 516 1.1.1.4 christos } 517 1.1.1.4 christos 518 1.1.1.4 christos while (fgets(buf, sizeof(buf), f)) { 519 1.1.1.4 christos /* IMSI Ki OPc AMF SQN */ 520 1.1.1.4 christos buf[sizeof(buf) - 1] = '\0'; 521 1.1.1.4 christos 522 1.1.1.4 christos pos = strchr(buf, ' '); 523 1.1.1.4 christos if (buf[0] == '#' || pos == NULL || pos - buf >= 20) 524 1.1.1.4 christos goto no_update; 525 1.1.1.4 christos 526 1.1.1.4 christos imsi_len = pos - buf; 527 1.1.1.4 christos 528 1.1.1.4 christos for (m = milenage_db; m; m = m->next) { 529 1.1.1.4 christos if (strncmp(buf, m->imsi, imsi_len) == 0 && 530 1.1.1.4 christos m->imsi[imsi_len] == '\0') 531 1.1.1.4 christos break; 532 1.1.1.4 christos } 533 1.1.1.4 christos 534 1.1.1.4 christos if (!m) 535 1.1.1.4 christos goto no_update; 536 1.1.1.4 christos 537 1.1.1.4 christos pos = buf; 538 1.1.1.4 christos pos += snprintf(pos, end - pos, "%s ", m->imsi); 539 1.1.1.4 christos pos += wpa_snprintf_hex(pos, end - pos, m->ki, 16); 540 1.1.1.4 christos *pos++ = ' '; 541 1.1.1.4 christos pos += wpa_snprintf_hex(pos, end - pos, m->opc, 16); 542 1.1.1.4 christos *pos++ = ' '; 543 1.1.1.4 christos pos += wpa_snprintf_hex(pos, end - pos, m->amf, 2); 544 1.1.1.4 christos *pos++ = ' '; 545 1.1.1.4 christos pos += wpa_snprintf_hex(pos, end - pos, m->sqn, 6); 546 1.1.1.4 christos *pos++ = '\n'; 547 1.1.1.4 christos 548 1.1.1.4 christos no_update: 549 1.1.1.4 christos fprintf(f2, "%s", buf); 550 1.1.1.4 christos } 551 1.1.1.4 christos 552 1.1.1.4 christos fclose(f2); 553 1.1.1.4 christos fclose(f); 554 1.1.1.4 christos 555 1.1.1.7 christos snprintf(name, sizeof(name), "%s.bak", fname); 556 1.1.1.7 christos if (rename(fname, name) < 0) { 557 1.1.1.4 christos perror("rename"); 558 1.1.1.4 christos return; 559 1.1.1.4 christos } 560 1.1.1.4 christos 561 1.1.1.7 christos snprintf(name, sizeof(name), "%s.new", fname); 562 1.1.1.7 christos if (rename(name, fname) < 0) { 563 1.1.1.4 christos perror("rename"); 564 1.1.1.4 christos return; 565 1.1.1.4 christos } 566 1.1.1.4 christos 567 1.1.1.4 christos } 568 1.1.1.4 christos 569 1.1.1.4 christos 570 1.1 christos static struct milenage_parameters * get_milenage(const char *imsi) 571 1.1 christos { 572 1.1 christos struct milenage_parameters *m = milenage_db; 573 1.1 christos 574 1.1 christos while (m) { 575 1.1 christos if (strcmp(m->imsi, imsi) == 0) 576 1.1 christos break; 577 1.1 christos m = m->next; 578 1.1 christos } 579 1.1 christos 580 1.1.1.4 christos #ifdef CONFIG_SQLITE 581 1.1.1.4 christos if (!m) 582 1.1.1.4 christos m = db_get_milenage(imsi); 583 1.1.1.4 christos #endif /* CONFIG_SQLITE */ 584 1.1.1.4 christos 585 1.1 christos return m; 586 1.1 christos } 587 1.1 christos 588 1.1 christos 589 1.1.1.5 christos static int sim_req_auth(char *imsi, char *resp, size_t resp_len) 590 1.1 christos { 591 1.1 christos int count, max_chal, ret; 592 1.1 christos char *pos; 593 1.1.1.5 christos char *rpos, *rend; 594 1.1 christos struct milenage_parameters *m; 595 1.1 christos struct gsm_triplet *g; 596 1.1 christos 597 1.1.1.5 christos resp[0] = '\0'; 598 1.1 christos 599 1.1 christos pos = strchr(imsi, ' '); 600 1.1 christos if (pos) { 601 1.1 christos *pos++ = '\0'; 602 1.1 christos max_chal = atoi(pos); 603 1.1.1.5 christos if (max_chal < 1 || max_chal > EAP_SIM_MAX_CHAL) 604 1.1 christos max_chal = EAP_SIM_MAX_CHAL; 605 1.1 christos } else 606 1.1 christos max_chal = EAP_SIM_MAX_CHAL; 607 1.1 christos 608 1.1.1.5 christos rend = resp + resp_len; 609 1.1.1.5 christos rpos = resp; 610 1.1 christos ret = snprintf(rpos, rend - rpos, "SIM-RESP-AUTH %s", imsi); 611 1.1 christos if (ret < 0 || ret >= rend - rpos) 612 1.1.1.5 christos return -1; 613 1.1 christos rpos += ret; 614 1.1 christos 615 1.1 christos m = get_milenage(imsi); 616 1.1 christos if (m) { 617 1.1 christos u8 _rand[16], sres[4], kc[8]; 618 1.1 christos for (count = 0; count < max_chal; count++) { 619 1.1.1.2 christos if (random_get_bytes(_rand, 16) < 0) 620 1.1.1.5 christos return -1; 621 1.1 christos gsm_milenage(m->opc, m->ki, _rand, sres, kc); 622 1.1 christos *rpos++ = ' '; 623 1.1 christos rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8); 624 1.1 christos *rpos++ = ':'; 625 1.1 christos rpos += wpa_snprintf_hex(rpos, rend - rpos, sres, 4); 626 1.1 christos *rpos++ = ':'; 627 1.1 christos rpos += wpa_snprintf_hex(rpos, rend - rpos, _rand, 16); 628 1.1 christos } 629 1.1 christos *rpos = '\0'; 630 1.1.1.5 christos return 0; 631 1.1 christos } 632 1.1 christos 633 1.1 christos count = 0; 634 1.1 christos while (count < max_chal && (g = get_gsm_triplet(imsi))) { 635 1.1 christos if (strcmp(g->imsi, imsi) != 0) 636 1.1 christos continue; 637 1.1 christos 638 1.1 christos if (rpos < rend) 639 1.1 christos *rpos++ = ' '; 640 1.1 christos rpos += wpa_snprintf_hex(rpos, rend - rpos, g->kc, 8); 641 1.1 christos if (rpos < rend) 642 1.1 christos *rpos++ = ':'; 643 1.1 christos rpos += wpa_snprintf_hex(rpos, rend - rpos, g->sres, 4); 644 1.1 christos if (rpos < rend) 645 1.1 christos *rpos++ = ':'; 646 1.1 christos rpos += wpa_snprintf_hex(rpos, rend - rpos, g->_rand, 16); 647 1.1 christos count++; 648 1.1 christos } 649 1.1 christos 650 1.1 christos if (count == 0) { 651 1.1 christos printf("No GSM triplets found for %s\n", imsi); 652 1.1 christos ret = snprintf(rpos, rend - rpos, " FAILURE"); 653 1.1 christos if (ret < 0 || ret >= rend - rpos) 654 1.1.1.5 christos return -1; 655 1.1 christos rpos += ret; 656 1.1 christos } 657 1.1 christos 658 1.1.1.5 christos return 0; 659 1.1.1.5 christos } 660 1.1.1.5 christos 661 1.1.1.5 christos 662 1.1.1.5 christos static int gsm_auth_req(char *imsi, char *resp, size_t resp_len) 663 1.1.1.5 christos { 664 1.1.1.5 christos int count, ret; 665 1.1.1.5 christos char *pos, *rpos, *rend; 666 1.1.1.5 christos struct milenage_parameters *m; 667 1.1.1.5 christos 668 1.1.1.5 christos resp[0] = '\0'; 669 1.1.1.5 christos 670 1.1.1.5 christos pos = os_strchr(imsi, ' '); 671 1.1.1.5 christos if (!pos) 672 1.1.1.5 christos return -1; 673 1.1.1.5 christos *pos++ = '\0'; 674 1.1.1.5 christos 675 1.1.1.5 christos rend = resp + resp_len; 676 1.1.1.5 christos rpos = resp; 677 1.1.1.5 christos ret = os_snprintf(rpos, rend - rpos, "GSM-AUTH-RESP %s", imsi); 678 1.1.1.6 christos if (os_snprintf_error(rend - rpos, ret)) 679 1.1.1.5 christos return -1; 680 1.1.1.5 christos rpos += ret; 681 1.1.1.5 christos 682 1.1.1.5 christos m = get_milenage(imsi); 683 1.1.1.5 christos if (m) { 684 1.1.1.5 christos u8 _rand[16], sres[4], kc[8]; 685 1.1.1.5 christos for (count = 0; count < EAP_SIM_MAX_CHAL; count++) { 686 1.1.1.5 christos if (hexstr2bin(pos, _rand, 16) != 0) 687 1.1.1.5 christos return -1; 688 1.1.1.5 christos gsm_milenage(m->opc, m->ki, _rand, sres, kc); 689 1.1.1.5 christos *rpos++ = count == 0 ? ' ' : ':'; 690 1.1.1.5 christos rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8); 691 1.1.1.5 christos *rpos++ = ':'; 692 1.1.1.5 christos rpos += wpa_snprintf_hex(rpos, rend - rpos, sres, 4); 693 1.1.1.5 christos pos += 16 * 2; 694 1.1.1.5 christos if (*pos != ':') 695 1.1.1.5 christos break; 696 1.1.1.5 christos pos++; 697 1.1.1.5 christos } 698 1.1.1.5 christos *rpos = '\0'; 699 1.1.1.5 christos return 0; 700 1.1.1.5 christos } 701 1.1.1.5 christos 702 1.1.1.5 christos printf("No GSM triplets found for %s\n", imsi); 703 1.1.1.5 christos ret = os_snprintf(rpos, rend - rpos, " FAILURE"); 704 1.1.1.6 christos if (os_snprintf_error(rend - rpos, ret)) 705 1.1.1.5 christos return -1; 706 1.1.1.5 christos rpos += ret; 707 1.1.1.5 christos 708 1.1.1.5 christos return 0; 709 1.1 christos } 710 1.1 christos 711 1.1 christos 712 1.1.1.3 adam static void inc_sqn(u8 *sqn) 713 1.1.1.3 adam { 714 1.1.1.3 adam u64 val, seq, ind; 715 1.1.1.3 adam 716 1.1.1.3 adam /* 717 1.1.1.3 adam * SQN = SEQ | IND = SEQ1 | SEQ2 | IND 718 1.1.1.3 adam * 719 1.1.1.3 adam * The mechanism used here is not time-based, so SEQ2 is void and 720 1.1.1.3 adam * SQN = SEQ1 | IND. The length of IND is ind_len bits and the length 721 1.1.1.3 adam * of SEQ1 is 48 - ind_len bits. 722 1.1.1.3 adam */ 723 1.1.1.3 adam 724 1.1.1.3 adam /* Increment both SEQ and IND by one */ 725 1.1.1.3 adam val = ((u64) WPA_GET_BE32(sqn) << 16) | ((u64) WPA_GET_BE16(sqn + 4)); 726 1.1.1.3 adam seq = (val >> ind_len) + 1; 727 1.1.1.3 adam ind = (val + 1) & ((1 << ind_len) - 1); 728 1.1.1.3 adam val = (seq << ind_len) | ind; 729 1.1.1.3 adam WPA_PUT_BE32(sqn, val >> 16); 730 1.1.1.3 adam WPA_PUT_BE16(sqn + 4, val & 0xffff); 731 1.1.1.3 adam } 732 1.1.1.3 adam 733 1.1.1.3 adam 734 1.1.1.5 christos static int aka_req_auth(char *imsi, char *resp, size_t resp_len) 735 1.1 christos { 736 1.1 christos /* AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES> */ 737 1.1.1.5 christos char *pos, *end; 738 1.1 christos u8 _rand[EAP_AKA_RAND_LEN]; 739 1.1 christos u8 autn[EAP_AKA_AUTN_LEN]; 740 1.1 christos u8 ik[EAP_AKA_IK_LEN]; 741 1.1 christos u8 ck[EAP_AKA_CK_LEN]; 742 1.1 christos u8 res[EAP_AKA_RES_MAX_LEN]; 743 1.1 christos size_t res_len; 744 1.1 christos int ret; 745 1.1 christos struct milenage_parameters *m; 746 1.1.1.4 christos int failed = 0; 747 1.1 christos 748 1.1 christos m = get_milenage(imsi); 749 1.1 christos if (m) { 750 1.1.1.2 christos if (random_get_bytes(_rand, EAP_AKA_RAND_LEN) < 0) 751 1.1.1.5 christos return -1; 752 1.1 christos res_len = EAP_AKA_RES_MAX_LEN; 753 1.1.1.3 adam inc_sqn(m->sqn); 754 1.1.1.4 christos #ifdef CONFIG_SQLITE 755 1.1.1.4 christos db_update_milenage_sqn(m); 756 1.1.1.4 christos #endif /* CONFIG_SQLITE */ 757 1.1.1.4 christos sqn_changes = 1; 758 1.1.1.5 christos if (stdout_debug) { 759 1.1.1.5 christos printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n", 760 1.1.1.5 christos m->sqn[0], m->sqn[1], m->sqn[2], 761 1.1.1.5 christos m->sqn[3], m->sqn[4], m->sqn[5]); 762 1.1.1.5 christos } 763 1.1 christos milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand, 764 1.1 christos autn, ik, ck, res, &res_len); 765 1.1.1.7 christos if (m->res_len >= EAP_AKA_RES_MIN_LEN && 766 1.1.1.7 christos m->res_len <= EAP_AKA_RES_MAX_LEN && 767 1.1.1.7 christos m->res_len < res_len) 768 1.1.1.7 christos res_len = m->res_len; 769 1.1 christos } else { 770 1.1 christos printf("Unknown IMSI: %s\n", imsi); 771 1.1 christos #ifdef AKA_USE_FIXED_TEST_VALUES 772 1.1 christos printf("Using fixed test values for AKA\n"); 773 1.1 christos memset(_rand, '0', EAP_AKA_RAND_LEN); 774 1.1 christos memset(autn, '1', EAP_AKA_AUTN_LEN); 775 1.1 christos memset(ik, '3', EAP_AKA_IK_LEN); 776 1.1 christos memset(ck, '4', EAP_AKA_CK_LEN); 777 1.1 christos memset(res, '2', EAP_AKA_RES_MAX_LEN); 778 1.1 christos res_len = EAP_AKA_RES_MAX_LEN; 779 1.1 christos #else /* AKA_USE_FIXED_TEST_VALUES */ 780 1.1.1.4 christos failed = 1; 781 1.1 christos #endif /* AKA_USE_FIXED_TEST_VALUES */ 782 1.1 christos } 783 1.1 christos 784 1.1.1.5 christos pos = resp; 785 1.1.1.5 christos end = resp + resp_len; 786 1.1 christos ret = snprintf(pos, end - pos, "AKA-RESP-AUTH %s ", imsi); 787 1.1 christos if (ret < 0 || ret >= end - pos) 788 1.1.1.5 christos return -1; 789 1.1 christos pos += ret; 790 1.1.1.4 christos if (failed) { 791 1.1.1.4 christos ret = snprintf(pos, end - pos, "FAILURE"); 792 1.1.1.4 christos if (ret < 0 || ret >= end - pos) 793 1.1.1.5 christos return -1; 794 1.1.1.4 christos pos += ret; 795 1.1.1.5 christos return 0; 796 1.1.1.4 christos } 797 1.1 christos pos += wpa_snprintf_hex(pos, end - pos, _rand, EAP_AKA_RAND_LEN); 798 1.1 christos *pos++ = ' '; 799 1.1 christos pos += wpa_snprintf_hex(pos, end - pos, autn, EAP_AKA_AUTN_LEN); 800 1.1 christos *pos++ = ' '; 801 1.1 christos pos += wpa_snprintf_hex(pos, end - pos, ik, EAP_AKA_IK_LEN); 802 1.1 christos *pos++ = ' '; 803 1.1 christos pos += wpa_snprintf_hex(pos, end - pos, ck, EAP_AKA_CK_LEN); 804 1.1 christos *pos++ = ' '; 805 1.1 christos pos += wpa_snprintf_hex(pos, end - pos, res, res_len); 806 1.1 christos 807 1.1.1.5 christos return 0; 808 1.1 christos } 809 1.1 christos 810 1.1 christos 811 1.1.1.5 christos static int aka_auts(char *imsi, char *resp, size_t resp_len) 812 1.1 christos { 813 1.1 christos char *auts, *__rand; 814 1.1 christos u8 _auts[EAP_AKA_AUTS_LEN], _rand[EAP_AKA_RAND_LEN], sqn[6]; 815 1.1 christos struct milenage_parameters *m; 816 1.1 christos 817 1.1.1.5 christos resp[0] = '\0'; 818 1.1.1.5 christos 819 1.1 christos /* AKA-AUTS <IMSI> <AUTS> <RAND> */ 820 1.1 christos 821 1.1 christos auts = strchr(imsi, ' '); 822 1.1 christos if (auts == NULL) 823 1.1.1.5 christos return -1; 824 1.1 christos *auts++ = '\0'; 825 1.1 christos 826 1.1 christos __rand = strchr(auts, ' '); 827 1.1 christos if (__rand == NULL) 828 1.1.1.5 christos return -1; 829 1.1 christos *__rand++ = '\0'; 830 1.1 christos 831 1.1.1.5 christos if (stdout_debug) { 832 1.1.1.5 christos printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n", 833 1.1.1.5 christos imsi, auts, __rand); 834 1.1.1.5 christos } 835 1.1 christos if (hexstr2bin(auts, _auts, EAP_AKA_AUTS_LEN) || 836 1.1 christos hexstr2bin(__rand, _rand, EAP_AKA_RAND_LEN)) { 837 1.1 christos printf("Could not parse AUTS/RAND\n"); 838 1.1.1.5 christos return -1; 839 1.1 christos } 840 1.1 christos 841 1.1 christos m = get_milenage(imsi); 842 1.1 christos if (m == NULL) { 843 1.1 christos printf("Unknown IMSI: %s\n", imsi); 844 1.1.1.5 christos return -1; 845 1.1 christos } 846 1.1 christos 847 1.1 christos if (milenage_auts(m->opc, m->ki, _rand, _auts, sqn)) { 848 1.1 christos printf("AKA-AUTS: Incorrect MAC-S\n"); 849 1.1 christos } else { 850 1.1 christos memcpy(m->sqn, sqn, 6); 851 1.1.1.5 christos if (stdout_debug) { 852 1.1.1.5 christos printf("AKA-AUTS: Re-synchronized: " 853 1.1.1.5 christos "SQN=%02x%02x%02x%02x%02x%02x\n", 854 1.1.1.5 christos sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]); 855 1.1.1.5 christos } 856 1.1.1.4 christos #ifdef CONFIG_SQLITE 857 1.1.1.4 christos db_update_milenage_sqn(m); 858 1.1.1.4 christos #endif /* CONFIG_SQLITE */ 859 1.1.1.4 christos sqn_changes = 1; 860 1.1 christos } 861 1.1.1.5 christos 862 1.1.1.5 christos return 0; 863 1.1.1.5 christos } 864 1.1.1.5 christos 865 1.1.1.5 christos 866 1.1.1.5 christos static int process_cmd(char *cmd, char *resp, size_t resp_len) 867 1.1.1.5 christos { 868 1.1.1.5 christos if (os_strncmp(cmd, "SIM-REQ-AUTH ", 13) == 0) 869 1.1.1.5 christos return sim_req_auth(cmd + 13, resp, resp_len); 870 1.1.1.5 christos 871 1.1.1.5 christos if (os_strncmp(cmd, "GSM-AUTH-REQ ", 13) == 0) 872 1.1.1.5 christos return gsm_auth_req(cmd + 13, resp, resp_len); 873 1.1.1.5 christos 874 1.1.1.5 christos if (os_strncmp(cmd, "AKA-REQ-AUTH ", 13) == 0) 875 1.1.1.5 christos return aka_req_auth(cmd + 13, resp, resp_len); 876 1.1.1.5 christos 877 1.1.1.5 christos if (os_strncmp(cmd, "AKA-AUTS ", 9) == 0) 878 1.1.1.5 christos return aka_auts(cmd + 9, resp, resp_len); 879 1.1.1.5 christos 880 1.1.1.5 christos printf("Unknown request: %s\n", cmd); 881 1.1.1.5 christos return -1; 882 1.1 christos } 883 1.1 christos 884 1.1 christos 885 1.1 christos static int process(int s) 886 1.1 christos { 887 1.1.1.5 christos char buf[1000], resp[1000]; 888 1.1 christos struct sockaddr_un from; 889 1.1 christos socklen_t fromlen; 890 1.1 christos ssize_t res; 891 1.1 christos 892 1.1 christos fromlen = sizeof(from); 893 1.1 christos res = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *) &from, 894 1.1 christos &fromlen); 895 1.1 christos if (res < 0) { 896 1.1 christos perror("recvfrom"); 897 1.1 christos return -1; 898 1.1 christos } 899 1.1 christos 900 1.1 christos if (res == 0) 901 1.1 christos return 0; 902 1.1 christos 903 1.1 christos if ((size_t) res >= sizeof(buf)) 904 1.1 christos res = sizeof(buf) - 1; 905 1.1 christos buf[res] = '\0'; 906 1.1 christos 907 1.1 christos printf("Received: %s\n", buf); 908 1.1 christos 909 1.1.1.5 christos if (process_cmd(buf, resp, sizeof(resp)) < 0) { 910 1.1.1.5 christos printf("Failed to process request\n"); 911 1.1.1.5 christos return -1; 912 1.1.1.5 christos } 913 1.1.1.5 christos 914 1.1.1.5 christos if (resp[0] == '\0') { 915 1.1.1.5 christos printf("No response\n"); 916 1.1.1.5 christos return 0; 917 1.1.1.5 christos } 918 1.1.1.5 christos 919 1.1.1.5 christos printf("Send: %s\n", resp); 920 1.1.1.5 christos 921 1.1.1.5 christos if (sendto(s, resp, os_strlen(resp), 0, (struct sockaddr *) &from, 922 1.1.1.5 christos fromlen) < 0) 923 1.1.1.5 christos perror("send"); 924 1.1 christos 925 1.1 christos return 0; 926 1.1 christos } 927 1.1 christos 928 1.1 christos 929 1.1 christos static void cleanup(void) 930 1.1 christos { 931 1.1 christos struct gsm_triplet *g, *gprev; 932 1.1 christos struct milenage_parameters *m, *prev; 933 1.1 christos 934 1.1.1.4 christos if (update_milenage && milenage_file && sqn_changes) 935 1.1.1.4 christos update_milenage_file(milenage_file); 936 1.1.1.4 christos 937 1.1 christos g = gsm_db; 938 1.1 christos while (g) { 939 1.1 christos gprev = g; 940 1.1 christos g = g->next; 941 1.1.1.4 christos os_free(gprev); 942 1.1 christos } 943 1.1 christos 944 1.1 christos m = milenage_db; 945 1.1 christos while (m) { 946 1.1 christos prev = m; 947 1.1 christos m = m->next; 948 1.1.1.4 christos os_free(prev); 949 1.1 christos } 950 1.1 christos 951 1.1.1.5 christos if (serv_sock >= 0) 952 1.1.1.5 christos close(serv_sock); 953 1.1.1.5 christos if (socket_path) 954 1.1.1.5 christos unlink(socket_path); 955 1.1.1.4 christos 956 1.1.1.4 christos #ifdef CONFIG_SQLITE 957 1.1.1.4 christos if (sqlite_db) { 958 1.1.1.4 christos sqlite3_close(sqlite_db); 959 1.1.1.4 christos sqlite_db = NULL; 960 1.1.1.4 christos } 961 1.1.1.4 christos #endif /* CONFIG_SQLITE */ 962 1.1 christos } 963 1.1 christos 964 1.1 christos 965 1.1 christos static void handle_term(int sig) 966 1.1 christos { 967 1.1 christos printf("Signal %d - terminate\n", sig); 968 1.1 christos exit(0); 969 1.1 christos } 970 1.1 christos 971 1.1 christos 972 1.1 christos static void usage(void) 973 1.1 christos { 974 1.1 christos printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA " 975 1.1 christos "database/authenticator\n" 976 1.1.1.8 christos "Copyright (c) 2005-2017, Jouni Malinen <j (at) w1.fi>\n" 977 1.1 christos "\n" 978 1.1 christos "usage:\n" 979 1.1.1.4 christos "hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] " 980 1.1.1.3 adam "[-m<milenage file>] \\\n" 981 1.1.1.5 christos " [-D<DB file>] [-i<IND len in bits>] [command]\n" 982 1.1 christos "\n" 983 1.1 christos "options:\n" 984 1.1 christos " -h = show this usage help\n" 985 1.1.1.4 christos " -u = update SQN in Milenage file on exit\n" 986 1.1 christos " -s<socket path> = path for UNIX domain socket\n" 987 1.1 christos " (default: %s)\n" 988 1.1 christos " -g<triplet file> = path for GSM authentication triplets\n" 989 1.1.1.3 adam " -m<milenage file> = path for Milenage keys\n" 990 1.1.1.4 christos " -D<DB file> = path to SQLite database\n" 991 1.1.1.5 christos " -i<IND len in bits> = IND length for SQN (default: 5)\n" 992 1.1.1.5 christos "\n" 993 1.1.1.5 christos "If the optional command argument, like " 994 1.1.1.5 christos "\"AKA-REQ-AUTH <IMSI>\" is used, a single\n" 995 1.1.1.5 christos "command is processed with response sent to stdout. Otherwise, " 996 1.1.1.5 christos "hlr_auc_gw opens\n" 997 1.1.1.5 christos "a control interface and processes commands sent through it " 998 1.1.1.5 christos "(e.g., by EAP server\n" 999 1.1.1.5 christos "in hostapd).\n", 1000 1.1 christos default_socket_path); 1001 1.1 christos } 1002 1.1 christos 1003 1.1 christos 1004 1.1 christos int main(int argc, char *argv[]) 1005 1.1 christos { 1006 1.1 christos int c; 1007 1.1 christos char *gsm_triplet_file = NULL; 1008 1.1.1.4 christos char *sqlite_db_file = NULL; 1009 1.1.1.5 christos int ret = 0; 1010 1.1.1.4 christos 1011 1.1.1.4 christos if (os_program_init()) 1012 1.1.1.4 christos return -1; 1013 1.1 christos 1014 1.1 christos socket_path = default_socket_path; 1015 1.1 christos 1016 1.1 christos for (;;) { 1017 1.1.1.4 christos c = getopt(argc, argv, "D:g:hi:m:s:u"); 1018 1.1 christos if (c < 0) 1019 1.1 christos break; 1020 1.1 christos switch (c) { 1021 1.1.1.4 christos case 'D': 1022 1.1.1.4 christos #ifdef CONFIG_SQLITE 1023 1.1.1.4 christos sqlite_db_file = optarg; 1024 1.1.1.4 christos break; 1025 1.1.1.4 christos #else /* CONFIG_SQLITE */ 1026 1.1.1.4 christos printf("No SQLite support included in the build\n"); 1027 1.1.1.4 christos return -1; 1028 1.1.1.4 christos #endif /* CONFIG_SQLITE */ 1029 1.1 christos case 'g': 1030 1.1 christos gsm_triplet_file = optarg; 1031 1.1 christos break; 1032 1.1 christos case 'h': 1033 1.1 christos usage(); 1034 1.1 christos return 0; 1035 1.1.1.3 adam case 'i': 1036 1.1.1.3 adam ind_len = atoi(optarg); 1037 1.1.1.3 adam if (ind_len < 0 || ind_len > 32) { 1038 1.1.1.3 adam printf("Invalid IND length\n"); 1039 1.1.1.3 adam return -1; 1040 1.1.1.3 adam } 1041 1.1.1.3 adam break; 1042 1.1 christos case 'm': 1043 1.1 christos milenage_file = optarg; 1044 1.1 christos break; 1045 1.1 christos case 's': 1046 1.1 christos socket_path = optarg; 1047 1.1 christos break; 1048 1.1.1.4 christos case 'u': 1049 1.1.1.4 christos update_milenage = 1; 1050 1.1.1.4 christos break; 1051 1.1 christos default: 1052 1.1 christos usage(); 1053 1.1 christos return -1; 1054 1.1 christos } 1055 1.1 christos } 1056 1.1 christos 1057 1.1.1.4 christos if (!gsm_triplet_file && !milenage_file && !sqlite_db_file) { 1058 1.1.1.4 christos usage(); 1059 1.1.1.4 christos return -1; 1060 1.1.1.4 christos } 1061 1.1.1.4 christos 1062 1.1.1.4 christos #ifdef CONFIG_SQLITE 1063 1.1.1.4 christos if (sqlite_db_file && (sqlite_db = db_open(sqlite_db_file)) == NULL) 1064 1.1.1.4 christos return -1; 1065 1.1.1.4 christos #endif /* CONFIG_SQLITE */ 1066 1.1.1.4 christos 1067 1.1 christos if (gsm_triplet_file && read_gsm_triplets(gsm_triplet_file) < 0) 1068 1.1 christos return -1; 1069 1.1 christos 1070 1.1 christos if (milenage_file && read_milenage(milenage_file) < 0) 1071 1.1 christos return -1; 1072 1.1 christos 1073 1.1.1.5 christos if (optind == argc) { 1074 1.1.1.5 christos serv_sock = open_socket(socket_path); 1075 1.1.1.5 christos if (serv_sock < 0) 1076 1.1.1.5 christos return -1; 1077 1.1 christos 1078 1.1.1.5 christos printf("Listening for requests on %s\n", socket_path); 1079 1.1 christos 1080 1.1.1.5 christos atexit(cleanup); 1081 1.1.1.5 christos signal(SIGTERM, handle_term); 1082 1.1.1.5 christos signal(SIGINT, handle_term); 1083 1.1 christos 1084 1.1.1.5 christos for (;;) 1085 1.1.1.5 christos process(serv_sock); 1086 1.1.1.5 christos } else { 1087 1.1.1.5 christos char buf[1000]; 1088 1.1.1.5 christos socket_path = NULL; 1089 1.1.1.5 christos stdout_debug = 0; 1090 1.1.1.5 christos if (process_cmd(argv[optind], buf, sizeof(buf)) < 0) { 1091 1.1.1.5 christos printf("FAIL\n"); 1092 1.1.1.5 christos ret = -1; 1093 1.1.1.5 christos } else { 1094 1.1.1.5 christos printf("%s\n", buf); 1095 1.1.1.5 christos } 1096 1.1.1.5 christos cleanup(); 1097 1.1.1.5 christos } 1098 1.1 christos 1099 1.1.1.4 christos #ifdef CONFIG_SQLITE 1100 1.1.1.4 christos if (sqlite_db) { 1101 1.1.1.4 christos sqlite3_close(sqlite_db); 1102 1.1.1.4 christos sqlite_db = NULL; 1103 1.1.1.4 christos } 1104 1.1.1.4 christos #endif /* CONFIG_SQLITE */ 1105 1.1.1.4 christos 1106 1.1.1.4 christos os_program_deinit(); 1107 1.1.1.4 christos 1108 1.1.1.5 christos return ret; 1109 1.1 christos } 1110