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