LCOV - code coverage report
Current view: top level - hostapd - hlr_auc_gw.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1475438200 Lines: 358 562 63.7 %
Date: 2016-10-02 Functions: 18 23 78.3 %

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

Generated by: LCOV version 1.10