Home | History | Annotate | Line # | Download | only in hostapd
hlr_auc_gw.c revision 1.1.1.1.12.1
      1           1.1  christos /*
      2           1.1  christos  * HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
      3           1.1  christos  * Copyright (c) 2005-2007, Jouni Malinen <j (at) w1.fi>
      4           1.1  christos  *
      5           1.1  christos  * This program is free software; you can redistribute it and/or modify
      6           1.1  christos  * it under the terms of the GNU General Public License version 2 as
      7           1.1  christos  * published by the Free Software Foundation.
      8           1.1  christos  *
      9           1.1  christos  * Alternatively, this software may be distributed under the terms of BSD
     10           1.1  christos  * license.
     11           1.1  christos  *
     12           1.1  christos  * See README and COPYING for more details.
     13           1.1  christos  *
     14           1.1  christos  * This is an example implementation of the EAP-SIM/AKA database/authentication
     15           1.1  christos  * gateway interface to HLR/AuC. It is expected to be replaced with an
     16           1.1  christos  * implementation of SS7 gateway to GSM/UMTS authentication center (HLR/AuC) or
     17           1.1  christos  * a local implementation of SIM triplet and AKA authentication data generator.
     18           1.1  christos  *
     19           1.1  christos  * hostapd will send SIM/AKA authentication queries over a UNIX domain socket
     20           1.1  christos  * to and external program, e.g., this hlr_auc_gw. This interface uses simple
     21           1.1  christos  * text-based format:
     22           1.1  christos  *
     23           1.1  christos  * EAP-SIM / GSM triplet query/response:
     24           1.1  christos  * SIM-REQ-AUTH <IMSI> <max_chal>
     25           1.1  christos  * SIM-RESP-AUTH <IMSI> Kc1:SRES1:RAND1 Kc2:SRES2:RAND2 [Kc3:SRES3:RAND3]
     26           1.1  christos  * SIM-RESP-AUTH <IMSI> FAILURE
     27           1.1  christos  *
     28           1.1  christos  * EAP-AKA / UMTS query/response:
     29           1.1  christos  * AKA-REQ-AUTH <IMSI>
     30           1.1  christos  * AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES>
     31           1.1  christos  * AKA-RESP-AUTH <IMSI> FAILURE
     32           1.1  christos  *
     33           1.1  christos  * EAP-AKA / UMTS AUTS (re-synchronization):
     34           1.1  christos  * AKA-AUTS <IMSI> <AUTS> <RAND>
     35           1.1  christos  *
     36           1.1  christos  * IMSI and max_chal are sent as an ASCII string,
     37           1.1  christos  * Kc/SRES/RAND/AUTN/IK/CK/RES/AUTS as hex strings.
     38           1.1  christos  *
     39           1.1  christos  * The example implementation here reads GSM authentication triplets from a
     40           1.1  christos  * text file in IMSI:Kc:SRES:RAND format, IMSI in ASCII, other fields as hex
     41           1.1  christos  * strings. This is used to simulate an HLR/AuC. As such, it is not very useful
     42           1.1  christos  * for real life authentication, but it is useful both as an example
     43           1.1  christos  * implementation and for EAP-SIM testing.
     44           1.1  christos  */
     45           1.1  christos 
     46           1.1  christos #include "includes.h"
     47           1.1  christos #include <sys/un.h>
     48           1.1  christos 
     49           1.1  christos #include "common.h"
     50           1.1  christos #include "crypto/milenage.h"
     51  1.1.1.1.12.1       tls #include "crypto/random.h"
     52           1.1  christos 
     53           1.1  christos static const char *default_socket_path = "/tmp/hlr_auc_gw.sock";
     54           1.1  christos static const char *socket_path;
     55           1.1  christos static int serv_sock = -1;
     56           1.1  christos 
     57           1.1  christos /* GSM triplets */
     58           1.1  christos struct gsm_triplet {
     59           1.1  christos 	struct gsm_triplet *next;
     60           1.1  christos 	char imsi[20];
     61           1.1  christos 	u8 kc[8];
     62           1.1  christos 	u8 sres[4];
     63           1.1  christos 	u8 _rand[16];
     64           1.1  christos };
     65           1.1  christos 
     66           1.1  christos static struct gsm_triplet *gsm_db = NULL, *gsm_db_pos = NULL;
     67           1.1  christos 
     68           1.1  christos /* OPc and AMF parameters for Milenage (Example algorithms for AKA). */
     69           1.1  christos struct milenage_parameters {
     70           1.1  christos 	struct milenage_parameters *next;
     71           1.1  christos 	char imsi[20];
     72           1.1  christos 	u8 ki[16];
     73           1.1  christos 	u8 opc[16];
     74           1.1  christos 	u8 amf[2];
     75           1.1  christos 	u8 sqn[6];
     76           1.1  christos };
     77           1.1  christos 
     78           1.1  christos static struct milenage_parameters *milenage_db = NULL;
     79           1.1  christos 
     80           1.1  christos #define EAP_SIM_MAX_CHAL 3
     81           1.1  christos 
     82           1.1  christos #define EAP_AKA_RAND_LEN 16
     83           1.1  christos #define EAP_AKA_AUTN_LEN 16
     84           1.1  christos #define EAP_AKA_AUTS_LEN 14
     85           1.1  christos #define EAP_AKA_RES_MAX_LEN 16
     86           1.1  christos #define EAP_AKA_IK_LEN 16
     87           1.1  christos #define EAP_AKA_CK_LEN 16
     88           1.1  christos 
     89           1.1  christos 
     90           1.1  christos static int open_socket(const char *path)
     91           1.1  christos {
     92           1.1  christos 	struct sockaddr_un addr;
     93           1.1  christos 	int s;
     94           1.1  christos 
     95           1.1  christos 	s = socket(PF_UNIX, SOCK_DGRAM, 0);
     96           1.1  christos 	if (s < 0) {
     97           1.1  christos 		perror("socket(PF_UNIX)");
     98           1.1  christos 		return -1;
     99           1.1  christos 	}
    100           1.1  christos 
    101           1.1  christos 	memset(&addr, 0, sizeof(addr));
    102           1.1  christos 	addr.sun_family = AF_UNIX;
    103           1.1  christos 	os_strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
    104           1.1  christos 	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
    105           1.1  christos 		perror("bind(PF_UNIX)");
    106           1.1  christos 		close(s);
    107           1.1  christos 		return -1;
    108           1.1  christos 	}
    109           1.1  christos 
    110           1.1  christos 	return s;
    111           1.1  christos }
    112           1.1  christos 
    113           1.1  christos 
    114           1.1  christos static int read_gsm_triplets(const char *fname)
    115           1.1  christos {
    116           1.1  christos 	FILE *f;
    117           1.1  christos 	char buf[200], *pos, *pos2;
    118           1.1  christos 	struct gsm_triplet *g = NULL;
    119           1.1  christos 	int line, ret = 0;
    120           1.1  christos 
    121           1.1  christos 	if (fname == NULL)
    122           1.1  christos 		return -1;
    123           1.1  christos 
    124           1.1  christos 	f = fopen(fname, "r");
    125           1.1  christos 	if (f == NULL) {
    126           1.1  christos 		printf("Could not open GSM tripler data file '%s'\n", fname);
    127           1.1  christos 		return -1;
    128           1.1  christos 	}
    129           1.1  christos 
    130           1.1  christos 	line = 0;
    131           1.1  christos 	while (fgets(buf, sizeof(buf), f)) {
    132           1.1  christos 		line++;
    133           1.1  christos 
    134           1.1  christos 		/* Parse IMSI:Kc:SRES:RAND */
    135           1.1  christos 		buf[sizeof(buf) - 1] = '\0';
    136           1.1  christos 		if (buf[0] == '#')
    137           1.1  christos 			continue;
    138           1.1  christos 		pos = buf;
    139           1.1  christos 		while (*pos != '\0' && *pos != '\n')
    140           1.1  christos 			pos++;
    141           1.1  christos 		if (*pos == '\n')
    142           1.1  christos 			*pos = '\0';
    143           1.1  christos 		pos = buf;
    144           1.1  christos 		if (*pos == '\0')
    145           1.1  christos 			continue;
    146           1.1  christos 
    147           1.1  christos 		g = os_zalloc(sizeof(*g));
    148           1.1  christos 		if (g == NULL) {
    149           1.1  christos 			ret = -1;
    150           1.1  christos 			break;
    151           1.1  christos 		}
    152           1.1  christos 
    153           1.1  christos 		/* IMSI */
    154           1.1  christos 		pos2 = strchr(pos, ':');
    155           1.1  christos 		if (pos2 == NULL) {
    156           1.1  christos 			printf("%s:%d - Invalid IMSI (%s)\n",
    157           1.1  christos 			       fname, line, pos);
    158           1.1  christos 			ret = -1;
    159           1.1  christos 			break;
    160           1.1  christos 		}
    161           1.1  christos 		*pos2 = '\0';
    162           1.1  christos 		if (strlen(pos) >= sizeof(g->imsi)) {
    163           1.1  christos 			printf("%s:%d - Too long IMSI (%s)\n",
    164           1.1  christos 			       fname, line, pos);
    165           1.1  christos 			ret = -1;
    166           1.1  christos 			break;
    167           1.1  christos 		}
    168           1.1  christos 		os_strlcpy(g->imsi, pos, sizeof(g->imsi));
    169           1.1  christos 		pos = pos2 + 1;
    170           1.1  christos 
    171           1.1  christos 		/* Kc */
    172           1.1  christos 		pos2 = strchr(pos, ':');
    173           1.1  christos 		if (pos2 == NULL) {
    174           1.1  christos 			printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos);
    175           1.1  christos 			ret = -1;
    176           1.1  christos 			break;
    177           1.1  christos 		}
    178           1.1  christos 		*pos2 = '\0';
    179           1.1  christos 		if (strlen(pos) != 16 || hexstr2bin(pos, g->kc, 8)) {
    180           1.1  christos 			printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos);
    181           1.1  christos 			ret = -1;
    182           1.1  christos 			break;
    183           1.1  christos 		}
    184           1.1  christos 		pos = pos2 + 1;
    185           1.1  christos 
    186           1.1  christos 		/* SRES */
    187           1.1  christos 		pos2 = strchr(pos, ':');
    188           1.1  christos 		if (pos2 == NULL) {
    189           1.1  christos 			printf("%s:%d - Invalid SRES (%s)\n", fname, line,
    190           1.1  christos 			       pos);
    191           1.1  christos 			ret = -1;
    192           1.1  christos 			break;
    193           1.1  christos 		}
    194           1.1  christos 		*pos2 = '\0';
    195           1.1  christos 		if (strlen(pos) != 8 || hexstr2bin(pos, g->sres, 4)) {
    196           1.1  christos 			printf("%s:%d - Invalid SRES (%s)\n", fname, line,
    197           1.1  christos 			       pos);
    198           1.1  christos 			ret = -1;
    199           1.1  christos 			break;
    200           1.1  christos 		}
    201           1.1  christos 		pos = pos2 + 1;
    202           1.1  christos 
    203           1.1  christos 		/* RAND */
    204           1.1  christos 		pos2 = strchr(pos, ':');
    205           1.1  christos 		if (pos2)
    206           1.1  christos 			*pos2 = '\0';
    207           1.1  christos 		if (strlen(pos) != 32 || hexstr2bin(pos, g->_rand, 16)) {
    208           1.1  christos 			printf("%s:%d - Invalid RAND (%s)\n", fname, line,
    209           1.1  christos 			       pos);
    210           1.1  christos 			ret = -1;
    211           1.1  christos 			break;
    212           1.1  christos 		}
    213           1.1  christos 		pos = pos2 + 1;
    214           1.1  christos 
    215           1.1  christos 		g->next = gsm_db;
    216           1.1  christos 		gsm_db = g;
    217           1.1  christos 		g = NULL;
    218           1.1  christos 	}
    219           1.1  christos 	free(g);
    220           1.1  christos 
    221           1.1  christos 	fclose(f);
    222           1.1  christos 
    223           1.1  christos 	return ret;
    224           1.1  christos }
    225           1.1  christos 
    226           1.1  christos 
    227           1.1  christos static struct gsm_triplet * get_gsm_triplet(const char *imsi)
    228           1.1  christos {
    229           1.1  christos 	struct gsm_triplet *g = gsm_db_pos;
    230           1.1  christos 
    231           1.1  christos 	while (g) {
    232           1.1  christos 		if (strcmp(g->imsi, imsi) == 0) {
    233           1.1  christos 			gsm_db_pos = g->next;
    234           1.1  christos 			return g;
    235           1.1  christos 		}
    236           1.1  christos 		g = g->next;
    237           1.1  christos 	}
    238           1.1  christos 
    239           1.1  christos 	g = gsm_db;
    240           1.1  christos 	while (g && g != gsm_db_pos) {
    241           1.1  christos 		if (strcmp(g->imsi, imsi) == 0) {
    242           1.1  christos 			gsm_db_pos = g->next;
    243           1.1  christos 			return g;
    244           1.1  christos 		}
    245           1.1  christos 		g = g->next;
    246           1.1  christos 	}
    247           1.1  christos 
    248           1.1  christos 	return NULL;
    249           1.1  christos }
    250           1.1  christos 
    251           1.1  christos 
    252           1.1  christos static int read_milenage(const char *fname)
    253           1.1  christos {
    254           1.1  christos 	FILE *f;
    255           1.1  christos 	char buf[200], *pos, *pos2;
    256           1.1  christos 	struct milenage_parameters *m = NULL;
    257           1.1  christos 	int line, ret = 0;
    258           1.1  christos 
    259           1.1  christos 	if (fname == NULL)
    260           1.1  christos 		return -1;
    261           1.1  christos 
    262           1.1  christos 	f = fopen(fname, "r");
    263           1.1  christos 	if (f == NULL) {
    264           1.1  christos 		printf("Could not open Milenage data file '%s'\n", fname);
    265           1.1  christos 		return -1;
    266           1.1  christos 	}
    267           1.1  christos 
    268           1.1  christos 	line = 0;
    269           1.1  christos 	while (fgets(buf, sizeof(buf), f)) {
    270           1.1  christos 		line++;
    271           1.1  christos 
    272           1.1  christos 		/* Parse IMSI Ki OPc AMF SQN */
    273           1.1  christos 		buf[sizeof(buf) - 1] = '\0';
    274           1.1  christos 		if (buf[0] == '#')
    275           1.1  christos 			continue;
    276           1.1  christos 		pos = buf;
    277           1.1  christos 		while (*pos != '\0' && *pos != '\n')
    278           1.1  christos 			pos++;
    279           1.1  christos 		if (*pos == '\n')
    280           1.1  christos 			*pos = '\0';
    281           1.1  christos 		pos = buf;
    282           1.1  christos 		if (*pos == '\0')
    283           1.1  christos 			continue;
    284           1.1  christos 
    285           1.1  christos 		m = os_zalloc(sizeof(*m));
    286           1.1  christos 		if (m == NULL) {
    287           1.1  christos 			ret = -1;
    288           1.1  christos 			break;
    289           1.1  christos 		}
    290           1.1  christos 
    291           1.1  christos 		/* IMSI */
    292           1.1  christos 		pos2 = strchr(pos, ' ');
    293           1.1  christos 		if (pos2 == NULL) {
    294           1.1  christos 			printf("%s:%d - Invalid IMSI (%s)\n",
    295           1.1  christos 			       fname, line, pos);
    296           1.1  christos 			ret = -1;
    297           1.1  christos 			break;
    298           1.1  christos 		}
    299           1.1  christos 		*pos2 = '\0';
    300           1.1  christos 		if (strlen(pos) >= sizeof(m->imsi)) {
    301           1.1  christos 			printf("%s:%d - Too long IMSI (%s)\n",
    302           1.1  christos 			       fname, line, pos);
    303           1.1  christos 			ret = -1;
    304           1.1  christos 			break;
    305           1.1  christos 		}
    306           1.1  christos 		os_strlcpy(m->imsi, pos, sizeof(m->imsi));
    307           1.1  christos 		pos = pos2 + 1;
    308           1.1  christos 
    309           1.1  christos 		/* Ki */
    310           1.1  christos 		pos2 = strchr(pos, ' ');
    311           1.1  christos 		if (pos2 == NULL) {
    312           1.1  christos 			printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos);
    313           1.1  christos 			ret = -1;
    314           1.1  christos 			break;
    315           1.1  christos 		}
    316           1.1  christos 		*pos2 = '\0';
    317           1.1  christos 		if (strlen(pos) != 32 || hexstr2bin(pos, m->ki, 16)) {
    318           1.1  christos 			printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos);
    319           1.1  christos 			ret = -1;
    320           1.1  christos 			break;
    321           1.1  christos 		}
    322           1.1  christos 		pos = pos2 + 1;
    323           1.1  christos 
    324           1.1  christos 		/* OPc */
    325           1.1  christos 		pos2 = strchr(pos, ' ');
    326           1.1  christos 		if (pos2 == NULL) {
    327           1.1  christos 			printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos);
    328           1.1  christos 			ret = -1;
    329           1.1  christos 			break;
    330           1.1  christos 		}
    331           1.1  christos 		*pos2 = '\0';
    332           1.1  christos 		if (strlen(pos) != 32 || hexstr2bin(pos, m->opc, 16)) {
    333           1.1  christos 			printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos);
    334           1.1  christos 			ret = -1;
    335           1.1  christos 			break;
    336           1.1  christos 		}
    337           1.1  christos 		pos = pos2 + 1;
    338           1.1  christos 
    339           1.1  christos 		/* AMF */
    340           1.1  christos 		pos2 = strchr(pos, ' ');
    341           1.1  christos 		if (pos2 == NULL) {
    342           1.1  christos 			printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos);
    343           1.1  christos 			ret = -1;
    344           1.1  christos 			break;
    345           1.1  christos 		}
    346           1.1  christos 		*pos2 = '\0';
    347           1.1  christos 		if (strlen(pos) != 4 || hexstr2bin(pos, m->amf, 2)) {
    348           1.1  christos 			printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos);
    349           1.1  christos 			ret = -1;
    350           1.1  christos 			break;
    351           1.1  christos 		}
    352           1.1  christos 		pos = pos2 + 1;
    353           1.1  christos 
    354           1.1  christos 		/* SQN */
    355           1.1  christos 		pos2 = strchr(pos, ' ');
    356           1.1  christos 		if (pos2)
    357           1.1  christos 			*pos2 = '\0';
    358           1.1  christos 		if (strlen(pos) != 12 || hexstr2bin(pos, m->sqn, 6)) {
    359           1.1  christos 			printf("%s:%d - Invalid SEQ (%s)\n", fname, line, pos);
    360           1.1  christos 			ret = -1;
    361           1.1  christos 			break;
    362           1.1  christos 		}
    363           1.1  christos 		pos = pos2 + 1;
    364           1.1  christos 
    365           1.1  christos 		m->next = milenage_db;
    366           1.1  christos 		milenage_db = m;
    367           1.1  christos 		m = NULL;
    368           1.1  christos 	}
    369           1.1  christos 	free(m);
    370           1.1  christos 
    371           1.1  christos 	fclose(f);
    372           1.1  christos 
    373           1.1  christos 	return ret;
    374           1.1  christos }
    375           1.1  christos 
    376           1.1  christos 
    377           1.1  christos static struct milenage_parameters * get_milenage(const char *imsi)
    378           1.1  christos {
    379           1.1  christos 	struct milenage_parameters *m = milenage_db;
    380           1.1  christos 
    381           1.1  christos 	while (m) {
    382           1.1  christos 		if (strcmp(m->imsi, imsi) == 0)
    383           1.1  christos 			break;
    384           1.1  christos 		m = m->next;
    385           1.1  christos 	}
    386           1.1  christos 
    387           1.1  christos 	return m;
    388           1.1  christos }
    389           1.1  christos 
    390           1.1  christos 
    391           1.1  christos static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
    392           1.1  christos 			 char *imsi)
    393           1.1  christos {
    394           1.1  christos 	int count, max_chal, ret;
    395           1.1  christos 	char *pos;
    396           1.1  christos 	char reply[1000], *rpos, *rend;
    397           1.1  christos 	struct milenage_parameters *m;
    398           1.1  christos 	struct gsm_triplet *g;
    399           1.1  christos 
    400           1.1  christos 	reply[0] = '\0';
    401           1.1  christos 
    402           1.1  christos 	pos = strchr(imsi, ' ');
    403           1.1  christos 	if (pos) {
    404           1.1  christos 		*pos++ = '\0';
    405           1.1  christos 		max_chal = atoi(pos);
    406           1.1  christos 		if (max_chal < 1 || max_chal < EAP_SIM_MAX_CHAL)
    407           1.1  christos 			max_chal = EAP_SIM_MAX_CHAL;
    408           1.1  christos 	} else
    409           1.1  christos 		max_chal = EAP_SIM_MAX_CHAL;
    410           1.1  christos 
    411           1.1  christos 	rend = &reply[sizeof(reply)];
    412           1.1  christos 	rpos = reply;
    413           1.1  christos 	ret = snprintf(rpos, rend - rpos, "SIM-RESP-AUTH %s", imsi);
    414           1.1  christos 	if (ret < 0 || ret >= rend - rpos)
    415           1.1  christos 		return;
    416           1.1  christos 	rpos += ret;
    417           1.1  christos 
    418           1.1  christos 	m = get_milenage(imsi);
    419           1.1  christos 	if (m) {
    420           1.1  christos 		u8 _rand[16], sres[4], kc[8];
    421           1.1  christos 		for (count = 0; count < max_chal; count++) {
    422  1.1.1.1.12.1       tls 			if (random_get_bytes(_rand, 16) < 0)
    423           1.1  christos 				return;
    424           1.1  christos 			gsm_milenage(m->opc, m->ki, _rand, sres, kc);
    425           1.1  christos 			*rpos++ = ' ';
    426           1.1  christos 			rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8);
    427           1.1  christos 			*rpos++ = ':';
    428           1.1  christos 			rpos += wpa_snprintf_hex(rpos, rend - rpos, sres, 4);
    429           1.1  christos 			*rpos++ = ':';
    430           1.1  christos 			rpos += wpa_snprintf_hex(rpos, rend - rpos, _rand, 16);
    431           1.1  christos 		}
    432           1.1  christos 		*rpos = '\0';
    433           1.1  christos 		goto send;
    434           1.1  christos 	}
    435           1.1  christos 
    436           1.1  christos 	count = 0;
    437           1.1  christos 	while (count < max_chal && (g = get_gsm_triplet(imsi))) {
    438           1.1  christos 		if (strcmp(g->imsi, imsi) != 0)
    439           1.1  christos 			continue;
    440           1.1  christos 
    441           1.1  christos 		if (rpos < rend)
    442           1.1  christos 			*rpos++ = ' ';
    443           1.1  christos 		rpos += wpa_snprintf_hex(rpos, rend - rpos, g->kc, 8);
    444           1.1  christos 		if (rpos < rend)
    445           1.1  christos 			*rpos++ = ':';
    446           1.1  christos 		rpos += wpa_snprintf_hex(rpos, rend - rpos, g->sres, 4);
    447           1.1  christos 		if (rpos < rend)
    448           1.1  christos 			*rpos++ = ':';
    449           1.1  christos 		rpos += wpa_snprintf_hex(rpos, rend - rpos, g->_rand, 16);
    450           1.1  christos 		count++;
    451           1.1  christos 	}
    452           1.1  christos 
    453           1.1  christos 	if (count == 0) {
    454           1.1  christos 		printf("No GSM triplets found for %s\n", imsi);
    455           1.1  christos 		ret = snprintf(rpos, rend - rpos, " FAILURE");
    456           1.1  christos 		if (ret < 0 || ret >= rend - rpos)
    457           1.1  christos 			return;
    458           1.1  christos 		rpos += ret;
    459           1.1  christos 	}
    460           1.1  christos 
    461           1.1  christos send:
    462           1.1  christos 	printf("Send: %s\n", reply);
    463           1.1  christos 	if (sendto(s, reply, rpos - reply, 0,
    464           1.1  christos 		   (struct sockaddr *) from, fromlen) < 0)
    465           1.1  christos 		perror("send");
    466           1.1  christos }
    467           1.1  christos 
    468           1.1  christos 
    469           1.1  christos static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
    470           1.1  christos 			 char *imsi)
    471           1.1  christos {
    472           1.1  christos 	/* AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES> */
    473           1.1  christos 	char reply[1000], *pos, *end;
    474           1.1  christos 	u8 _rand[EAP_AKA_RAND_LEN];
    475           1.1  christos 	u8 autn[EAP_AKA_AUTN_LEN];
    476           1.1  christos 	u8 ik[EAP_AKA_IK_LEN];
    477           1.1  christos 	u8 ck[EAP_AKA_CK_LEN];
    478           1.1  christos 	u8 res[EAP_AKA_RES_MAX_LEN];
    479           1.1  christos 	size_t res_len;
    480           1.1  christos 	int ret;
    481           1.1  christos 	struct milenage_parameters *m;
    482           1.1  christos 
    483           1.1  christos 	m = get_milenage(imsi);
    484           1.1  christos 	if (m) {
    485  1.1.1.1.12.1       tls 		if (random_get_bytes(_rand, EAP_AKA_RAND_LEN) < 0)
    486           1.1  christos 			return;
    487           1.1  christos 		res_len = EAP_AKA_RES_MAX_LEN;
    488           1.1  christos 		inc_byte_array(m->sqn, 6);
    489           1.1  christos 		printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
    490           1.1  christos 		       m->sqn[0], m->sqn[1], m->sqn[2],
    491           1.1  christos 		       m->sqn[3], m->sqn[4], m->sqn[5]);
    492           1.1  christos 		milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand,
    493           1.1  christos 				  autn, ik, ck, res, &res_len);
    494           1.1  christos 	} else {
    495           1.1  christos 		printf("Unknown IMSI: %s\n", imsi);
    496           1.1  christos #ifdef AKA_USE_FIXED_TEST_VALUES
    497           1.1  christos 		printf("Using fixed test values for AKA\n");
    498           1.1  christos 		memset(_rand, '0', EAP_AKA_RAND_LEN);
    499           1.1  christos 		memset(autn, '1', EAP_AKA_AUTN_LEN);
    500           1.1  christos 		memset(ik, '3', EAP_AKA_IK_LEN);
    501           1.1  christos 		memset(ck, '4', EAP_AKA_CK_LEN);
    502           1.1  christos 		memset(res, '2', EAP_AKA_RES_MAX_LEN);
    503           1.1  christos 		res_len = EAP_AKA_RES_MAX_LEN;
    504           1.1  christos #else /* AKA_USE_FIXED_TEST_VALUES */
    505           1.1  christos 		return;
    506           1.1  christos #endif /* AKA_USE_FIXED_TEST_VALUES */
    507           1.1  christos 	}
    508           1.1  christos 
    509           1.1  christos 	pos = reply;
    510           1.1  christos 	end = &reply[sizeof(reply)];
    511           1.1  christos 	ret = snprintf(pos, end - pos, "AKA-RESP-AUTH %s ", imsi);
    512           1.1  christos 	if (ret < 0 || ret >= end - pos)
    513           1.1  christos 		return;
    514           1.1  christos 	pos += ret;
    515           1.1  christos 	pos += wpa_snprintf_hex(pos, end - pos, _rand, EAP_AKA_RAND_LEN);
    516           1.1  christos 	*pos++ = ' ';
    517           1.1  christos 	pos += wpa_snprintf_hex(pos, end - pos, autn, EAP_AKA_AUTN_LEN);
    518           1.1  christos 	*pos++ = ' ';
    519           1.1  christos 	pos += wpa_snprintf_hex(pos, end - pos, ik, EAP_AKA_IK_LEN);
    520           1.1  christos 	*pos++ = ' ';
    521           1.1  christos 	pos += wpa_snprintf_hex(pos, end - pos, ck, EAP_AKA_CK_LEN);
    522           1.1  christos 	*pos++ = ' ';
    523           1.1  christos 	pos += wpa_snprintf_hex(pos, end - pos, res, res_len);
    524           1.1  christos 
    525           1.1  christos 	printf("Send: %s\n", reply);
    526           1.1  christos 
    527           1.1  christos 	if (sendto(s, reply, pos - reply, 0, (struct sockaddr *) from,
    528           1.1  christos 		   fromlen) < 0)
    529           1.1  christos 		perror("send");
    530           1.1  christos }
    531           1.1  christos 
    532           1.1  christos 
    533           1.1  christos static void aka_auts(int s, struct sockaddr_un *from, socklen_t fromlen,
    534           1.1  christos 		     char *imsi)
    535           1.1  christos {
    536           1.1  christos 	char *auts, *__rand;
    537           1.1  christos 	u8 _auts[EAP_AKA_AUTS_LEN], _rand[EAP_AKA_RAND_LEN], sqn[6];
    538           1.1  christos 	struct milenage_parameters *m;
    539           1.1  christos 
    540           1.1  christos 	/* AKA-AUTS <IMSI> <AUTS> <RAND> */
    541           1.1  christos 
    542           1.1  christos 	auts = strchr(imsi, ' ');
    543           1.1  christos 	if (auts == NULL)
    544           1.1  christos 		return;
    545           1.1  christos 	*auts++ = '\0';
    546           1.1  christos 
    547           1.1  christos 	__rand = strchr(auts, ' ');
    548           1.1  christos 	if (__rand == NULL)
    549           1.1  christos 		return;
    550           1.1  christos 	*__rand++ = '\0';
    551           1.1  christos 
    552           1.1  christos 	printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n", imsi, auts, __rand);
    553           1.1  christos 	if (hexstr2bin(auts, _auts, EAP_AKA_AUTS_LEN) ||
    554           1.1  christos 	    hexstr2bin(__rand, _rand, EAP_AKA_RAND_LEN)) {
    555           1.1  christos 		printf("Could not parse AUTS/RAND\n");
    556           1.1  christos 		return;
    557           1.1  christos 	}
    558           1.1  christos 
    559           1.1  christos 	m = get_milenage(imsi);
    560           1.1  christos 	if (m == NULL) {
    561           1.1  christos 		printf("Unknown IMSI: %s\n", imsi);
    562           1.1  christos 		return;
    563           1.1  christos 	}
    564           1.1  christos 
    565           1.1  christos 	if (milenage_auts(m->opc, m->ki, _rand, _auts, sqn)) {
    566           1.1  christos 		printf("AKA-AUTS: Incorrect MAC-S\n");
    567           1.1  christos 	} else {
    568           1.1  christos 		memcpy(m->sqn, sqn, 6);
    569           1.1  christos 		printf("AKA-AUTS: Re-synchronized: "
    570           1.1  christos 		       "SQN=%02x%02x%02x%02x%02x%02x\n",
    571           1.1  christos 		       sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
    572           1.1  christos 	}
    573           1.1  christos }
    574           1.1  christos 
    575           1.1  christos 
    576           1.1  christos static int process(int s)
    577           1.1  christos {
    578           1.1  christos 	char buf[1000];
    579           1.1  christos 	struct sockaddr_un from;
    580           1.1  christos 	socklen_t fromlen;
    581           1.1  christos 	ssize_t res;
    582           1.1  christos 
    583           1.1  christos 	fromlen = sizeof(from);
    584           1.1  christos 	res = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *) &from,
    585           1.1  christos 		       &fromlen);
    586           1.1  christos 	if (res < 0) {
    587           1.1  christos 		perror("recvfrom");
    588           1.1  christos 		return -1;
    589           1.1  christos 	}
    590           1.1  christos 
    591           1.1  christos 	if (res == 0)
    592           1.1  christos 		return 0;
    593           1.1  christos 
    594           1.1  christos 	if ((size_t) res >= sizeof(buf))
    595           1.1  christos 		res = sizeof(buf) - 1;
    596           1.1  christos 	buf[res] = '\0';
    597           1.1  christos 
    598           1.1  christos 	printf("Received: %s\n", buf);
    599           1.1  christos 
    600           1.1  christos 	if (strncmp(buf, "SIM-REQ-AUTH ", 13) == 0)
    601           1.1  christos 		sim_req_auth(s, &from, fromlen, buf + 13);
    602           1.1  christos 	else if (strncmp(buf, "AKA-REQ-AUTH ", 13) == 0)
    603           1.1  christos 		aka_req_auth(s, &from, fromlen, buf + 13);
    604           1.1  christos 	else if (strncmp(buf, "AKA-AUTS ", 9) == 0)
    605           1.1  christos 		aka_auts(s, &from, fromlen, buf + 9);
    606           1.1  christos 	else
    607           1.1  christos 		printf("Unknown request: %s\n", buf);
    608           1.1  christos 
    609           1.1  christos 	return 0;
    610           1.1  christos }
    611           1.1  christos 
    612           1.1  christos 
    613           1.1  christos static void cleanup(void)
    614           1.1  christos {
    615           1.1  christos 	struct gsm_triplet *g, *gprev;
    616           1.1  christos 	struct milenage_parameters *m, *prev;
    617           1.1  christos 
    618           1.1  christos 	g = gsm_db;
    619           1.1  christos 	while (g) {
    620           1.1  christos 		gprev = g;
    621           1.1  christos 		g = g->next;
    622           1.1  christos 		free(gprev);
    623           1.1  christos 	}
    624           1.1  christos 
    625           1.1  christos 	m = milenage_db;
    626           1.1  christos 	while (m) {
    627           1.1  christos 		prev = m;
    628           1.1  christos 		m = m->next;
    629           1.1  christos 		free(prev);
    630           1.1  christos 	}
    631           1.1  christos 
    632           1.1  christos 	close(serv_sock);
    633           1.1  christos 	unlink(socket_path);
    634           1.1  christos }
    635           1.1  christos 
    636           1.1  christos 
    637           1.1  christos static void handle_term(int sig)
    638           1.1  christos {
    639           1.1  christos 	printf("Signal %d - terminate\n", sig);
    640           1.1  christos 	exit(0);
    641           1.1  christos }
    642           1.1  christos 
    643           1.1  christos 
    644           1.1  christos static void usage(void)
    645           1.1  christos {
    646           1.1  christos 	printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
    647           1.1  christos 	       "database/authenticator\n"
    648           1.1  christos 	       "Copyright (c) 2005-2007, Jouni Malinen <j (at) w1.fi>\n"
    649           1.1  christos 	       "\n"
    650           1.1  christos 	       "usage:\n"
    651           1.1  christos 	       "hlr_auc_gw [-h] [-s<socket path>] [-g<triplet file>] "
    652           1.1  christos 	       "[-m<milenage file>]\n"
    653           1.1  christos 	       "\n"
    654           1.1  christos 	       "options:\n"
    655           1.1  christos 	       "  -h = show this usage help\n"
    656           1.1  christos 	       "  -s<socket path> = path for UNIX domain socket\n"
    657           1.1  christos 	       "                    (default: %s)\n"
    658           1.1  christos 	       "  -g<triplet file> = path for GSM authentication triplets\n"
    659           1.1  christos 	       "  -m<milenage file> = path for Milenage keys\n",
    660           1.1  christos 	       default_socket_path);
    661           1.1  christos }
    662           1.1  christos 
    663           1.1  christos 
    664           1.1  christos int main(int argc, char *argv[])
    665           1.1  christos {
    666           1.1  christos 	int c;
    667           1.1  christos 	char *milenage_file = NULL;
    668           1.1  christos 	char *gsm_triplet_file = NULL;
    669           1.1  christos 
    670           1.1  christos 	socket_path = default_socket_path;
    671           1.1  christos 
    672           1.1  christos 	for (;;) {
    673           1.1  christos 		c = getopt(argc, argv, "g:hm:s:");
    674           1.1  christos 		if (c < 0)
    675           1.1  christos 			break;
    676           1.1  christos 		switch (c) {
    677           1.1  christos 		case 'g':
    678           1.1  christos 			gsm_triplet_file = optarg;
    679           1.1  christos 			break;
    680           1.1  christos 		case 'h':
    681           1.1  christos 			usage();
    682           1.1  christos 			return 0;
    683           1.1  christos 		case 'm':
    684           1.1  christos 			milenage_file = optarg;
    685           1.1  christos 			break;
    686           1.1  christos 		case 's':
    687           1.1  christos 			socket_path = optarg;
    688           1.1  christos 			break;
    689           1.1  christos 		default:
    690           1.1  christos 			usage();
    691           1.1  christos 			return -1;
    692           1.1  christos 		}
    693           1.1  christos 	}
    694           1.1  christos 
    695           1.1  christos 	if (gsm_triplet_file && read_gsm_triplets(gsm_triplet_file) < 0)
    696           1.1  christos 		return -1;
    697           1.1  christos 
    698           1.1  christos 	if (milenage_file && read_milenage(milenage_file) < 0)
    699           1.1  christos 		return -1;
    700           1.1  christos 
    701           1.1  christos 	serv_sock = open_socket(socket_path);
    702           1.1  christos 	if (serv_sock < 0)
    703           1.1  christos 		return -1;
    704           1.1  christos 
    705           1.1  christos 	printf("Listening for requests on %s\n", socket_path);
    706           1.1  christos 
    707           1.1  christos 	atexit(cleanup);
    708           1.1  christos 	signal(SIGTERM, handle_term);
    709           1.1  christos 	signal(SIGINT, handle_term);
    710           1.1  christos 
    711           1.1  christos 	for (;;)
    712           1.1  christos 		process(serv_sock);
    713           1.1  christos 
    714           1.1  christos 	return 0;
    715           1.1  christos }
    716