Updated to hostap_2_6
[mech_eap.git] / libeap / hostapd / hlr_auc_gw.c
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 static int db_table_exists(sqlite3 *db, const char *name)
113 {
114         char cmd[128];
115         os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
116         return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
117 }
118
119
120 static int db_table_create_milenage(sqlite3 *db)
121 {
122         char *err = NULL;
123         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         printf("Adding database table for milenage information\n");
134         if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
135                 printf("SQLite error: %s\n", err);
136                 sqlite3_free(err);
137                 return -1;
138         }
139
140         return 0;
141 }
142
143
144 static sqlite3 * db_open(const char *db_file)
145 {
146         sqlite3 *db;
147
148         if (sqlite3_open(db_file, &db)) {
149                 printf("Failed to open database %s: %s\n",
150                        db_file, sqlite3_errmsg(db));
151                 sqlite3_close(db);
152                 return NULL;
153         }
154
155         if (!db_table_exists(db, "milenage") &&
156             db_table_create_milenage(db) < 0) {
157                 sqlite3_close(db);
158                 return NULL;
159         }
160
161         return db;
162 }
163
164
165 static int get_milenage_cb(void *ctx, int argc, char *argv[], char *col[])
166 {
167         struct milenage_parameters *m = ctx;
168         int i;
169
170         m->set = 1;
171
172         for (i = 0; i < argc; i++) {
173                 if (os_strcmp(col[i], "ki") == 0 && argv[i] &&
174                     hexstr2bin(argv[i], m->ki, sizeof(m->ki))) {
175                         printf("Invalid ki value in database\n");
176                         return -1;
177                 }
178
179                 if (os_strcmp(col[i], "opc") == 0 && argv[i] &&
180                     hexstr2bin(argv[i], m->opc, sizeof(m->opc))) {
181                         printf("Invalid opcvalue in database\n");
182                         return -1;
183                 }
184
185                 if (os_strcmp(col[i], "amf") == 0 && argv[i] &&
186                     hexstr2bin(argv[i], m->amf, sizeof(m->amf))) {
187                         printf("Invalid amf value in database\n");
188                         return -1;
189                 }
190
191                 if (os_strcmp(col[i], "sqn") == 0 && argv[i] &&
192                     hexstr2bin(argv[i], m->sqn, sizeof(m->sqn))) {
193                         printf("Invalid sqn value in database\n");
194                         return -1;
195                 }
196
197                 if (os_strcmp(col[i], "res_len") == 0 && argv[i]) {
198                         m->res_len = atoi(argv[i]);
199                 }
200         }
201
202         return 0;
203 }
204
205
206 static struct milenage_parameters * db_get_milenage(const char *imsi_txt)
207 {
208         char cmd[128];
209         unsigned long long imsi;
210
211         os_memset(&db_tmp_milenage, 0, sizeof(db_tmp_milenage));
212         imsi = atoll(imsi_txt);
213         os_snprintf(db_tmp_milenage.imsi, sizeof(db_tmp_milenage.imsi),
214                     "%llu", imsi);
215         os_snprintf(cmd, sizeof(cmd),
216                     "SELECT * FROM milenage WHERE imsi=%llu;", imsi);
217         if (sqlite3_exec(sqlite_db, cmd, get_milenage_cb, &db_tmp_milenage,
218                          NULL) != SQLITE_OK)
219                 return NULL;
220
221         if (!db_tmp_milenage.set)
222                 return NULL;
223         return &db_tmp_milenage;
224 }
225
226
227 static int db_update_milenage_sqn(struct milenage_parameters *m)
228 {
229         char cmd[128], val[13], *pos;
230
231         if (sqlite_db == NULL)
232                 return 0;
233
234         pos = val;
235         pos += wpa_snprintf_hex(pos, sizeof(val), m->sqn, 6);
236         *pos = '\0';
237         os_snprintf(cmd, sizeof(cmd),
238                     "UPDATE milenage SET sqn='%s' WHERE imsi=%s;",
239                     val, m->imsi);
240         if (sqlite3_exec(sqlite_db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
241                 printf("Failed to update SQN in database for IMSI %s\n",
242                        m->imsi);
243                 return -1;
244         }
245         return 0;
246 }
247
248 #endif /* CONFIG_SQLITE */
249
250
251 static int open_socket(const char *path)
252 {
253         struct sockaddr_un addr;
254         int s;
255
256         s = socket(PF_UNIX, SOCK_DGRAM, 0);
257         if (s < 0) {
258                 perror("socket(PF_UNIX)");
259                 return -1;
260         }
261
262         memset(&addr, 0, sizeof(addr));
263         addr.sun_family = AF_UNIX;
264         os_strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
265         if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
266                 perror("hlr-auc-gw: bind(PF_UNIX)");
267                 close(s);
268                 return -1;
269         }
270
271         return s;
272 }
273
274
275 static int read_gsm_triplets(const char *fname)
276 {
277         FILE *f;
278         char buf[200], *pos, *pos2;
279         struct gsm_triplet *g = NULL;
280         int line, ret = 0;
281
282         if (fname == NULL)
283                 return -1;
284
285         f = fopen(fname, "r");
286         if (f == NULL) {
287                 printf("Could not open GSM triplet data file '%s'\n", fname);
288                 return -1;
289         }
290
291         line = 0;
292         while (fgets(buf, sizeof(buf), f)) {
293                 line++;
294
295                 /* Parse IMSI:Kc:SRES:RAND */
296                 buf[sizeof(buf) - 1] = '\0';
297                 if (buf[0] == '#')
298                         continue;
299                 pos = buf;
300                 while (*pos != '\0' && *pos != '\n')
301                         pos++;
302                 if (*pos == '\n')
303                         *pos = '\0';
304                 pos = buf;
305                 if (*pos == '\0')
306                         continue;
307
308                 g = os_zalloc(sizeof(*g));
309                 if (g == NULL) {
310                         ret = -1;
311                         break;
312                 }
313
314                 /* IMSI */
315                 pos2 = NULL;
316                 pos = str_token(buf, ":", &pos2);
317                 if (!pos || os_strlen(pos) >= sizeof(g->imsi)) {
318                         printf("%s:%d - Invalid IMSI\n", fname, line);
319                         ret = -1;
320                         break;
321                 }
322                 os_strlcpy(g->imsi, pos, sizeof(g->imsi));
323
324                 /* Kc */
325                 pos = str_token(buf, ":", &pos2);
326                 if (!pos || os_strlen(pos) != 16 || hexstr2bin(pos, g->kc, 8)) {
327                         printf("%s:%d - Invalid Kc\n", fname, line);
328                         ret = -1;
329                         break;
330                 }
331
332                 /* SRES */
333                 pos = str_token(buf, ":", &pos2);
334                 if (!pos || os_strlen(pos) != 8 ||
335                     hexstr2bin(pos, g->sres, 4)) {
336                         printf("%s:%d - Invalid SRES\n", fname, line);
337                         ret = -1;
338                         break;
339                 }
340
341                 /* RAND */
342                 pos = str_token(buf, ":", &pos2);
343                 if (!pos || os_strlen(pos) != 32 ||
344                     hexstr2bin(pos, g->_rand, 16)) {
345                         printf("%s:%d - Invalid RAND\n", fname, line);
346                         ret = -1;
347                         break;
348                 }
349
350                 g->next = gsm_db;
351                 gsm_db = g;
352                 g = NULL;
353         }
354         os_free(g);
355
356         fclose(f);
357
358         return ret;
359 }
360
361
362 static struct gsm_triplet * get_gsm_triplet(const char *imsi)
363 {
364         struct gsm_triplet *g = gsm_db_pos;
365
366         while (g) {
367                 if (strcmp(g->imsi, imsi) == 0) {
368                         gsm_db_pos = g->next;
369                         return g;
370                 }
371                 g = g->next;
372         }
373
374         g = gsm_db;
375         while (g && g != gsm_db_pos) {
376                 if (strcmp(g->imsi, imsi) == 0) {
377                         gsm_db_pos = g->next;
378                         return g;
379                 }
380                 g = g->next;
381         }
382
383         return NULL;
384 }
385
386
387 static int read_milenage(const char *fname)
388 {
389         FILE *f;
390         char buf[200], *pos, *pos2;
391         struct milenage_parameters *m = NULL;
392         int line, ret = 0;
393
394         if (fname == NULL)
395                 return -1;
396
397         f = fopen(fname, "r");
398         if (f == NULL) {
399                 printf("Could not open Milenage data file '%s'\n", fname);
400                 return -1;
401         }
402
403         line = 0;
404         while (fgets(buf, sizeof(buf), f)) {
405                 line++;
406
407                 /* Parse IMSI Ki OPc AMF SQN [RES_len] */
408                 buf[sizeof(buf) - 1] = '\0';
409                 if (buf[0] == '#')
410                         continue;
411                 pos = buf;
412                 while (*pos != '\0' && *pos != '\n')
413                         pos++;
414                 if (*pos == '\n')
415                         *pos = '\0';
416                 pos = buf;
417                 if (*pos == '\0')
418                         continue;
419
420                 m = os_zalloc(sizeof(*m));
421                 if (m == NULL) {
422                         ret = -1;
423                         break;
424                 }
425
426                 /* IMSI */
427                 pos2 = NULL;
428                 pos = str_token(buf, " ", &pos2);
429                 if (!pos || os_strlen(pos) >= sizeof(m->imsi)) {
430                         printf("%s:%d - Invalid IMSI\n", fname, line);
431                         ret = -1;
432                         break;
433                 }
434                 os_strlcpy(m->imsi, pos, sizeof(m->imsi));
435
436                 /* Ki */
437                 pos = str_token(buf, " ", &pos2);
438                 if (!pos || os_strlen(pos) != 32 ||
439                     hexstr2bin(pos, m->ki, 16)) {
440                         printf("%s:%d - Invalid Ki\n", fname, line);
441                         ret = -1;
442                         break;
443                 }
444
445                 /* OPc */
446                 pos = str_token(buf, " ", &pos2);
447                 if (!pos || os_strlen(pos) != 32 ||
448                     hexstr2bin(pos, m->opc, 16)) {
449                         printf("%s:%d - Invalid OPc\n", fname, line);
450                         ret = -1;
451                         break;
452                 }
453
454                 /* AMF */
455                 pos = str_token(buf, " ", &pos2);
456                 if (!pos || os_strlen(pos) != 4 || hexstr2bin(pos, m->amf, 2)) {
457                         printf("%s:%d - Invalid AMF\n", fname, line);
458                         ret = -1;
459                         break;
460                 }
461
462                 /* SQN */
463                 pos = str_token(buf, " ", &pos2);
464                 if (!pos || os_strlen(pos) != 12 ||
465                     hexstr2bin(pos, m->sqn, 6)) {
466                         printf("%s:%d - Invalid SEQ\n", fname, line);
467                         ret = -1;
468                         break;
469                 }
470
471                 pos = str_token(buf, " ", &pos2);
472                 if (pos) {
473                         m->res_len = atoi(pos);
474                         if (m->res_len &&
475                             (m->res_len < EAP_AKA_RES_MIN_LEN ||
476                              m->res_len > EAP_AKA_RES_MAX_LEN)) {
477                                 printf("%s:%d - Invalid RES_len\n",
478                                        fname, line);
479                                 ret = -1;
480                                 break;
481                         }
482                 }
483
484                 m->next = milenage_db;
485                 milenage_db = m;
486                 m = NULL;
487         }
488         os_free(m);
489
490         fclose(f);
491
492         return ret;
493 }
494
495
496 static void update_milenage_file(const char *fname)
497 {
498         FILE *f, *f2;
499         char name[500], buf[500], *pos;
500         char *end = buf + sizeof(buf);
501         struct milenage_parameters *m;
502         size_t imsi_len;
503
504         f = fopen(fname, "r");
505         if (f == NULL) {
506                 printf("Could not open Milenage data file '%s'\n", fname);
507                 return;
508         }
509
510         snprintf(name, sizeof(name), "%s.new", fname);
511         f2 = fopen(name, "w");
512         if (f2 == NULL) {
513                 printf("Could not write Milenage data file '%s'\n", name);
514                 fclose(f);
515                 return;
516         }
517
518         while (fgets(buf, sizeof(buf), f)) {
519                 /* IMSI Ki OPc AMF SQN */
520                 buf[sizeof(buf) - 1] = '\0';
521
522                 pos = strchr(buf, ' ');
523                 if (buf[0] == '#' || pos == NULL || pos - buf >= 20)
524                         goto no_update;
525
526                 imsi_len = pos - buf;
527
528                 for (m = milenage_db; m; m = m->next) {
529                         if (strncmp(buf, m->imsi, imsi_len) == 0 &&
530                             m->imsi[imsi_len] == '\0')
531                                 break;
532                 }
533
534                 if (!m)
535                         goto no_update;
536
537                 pos = buf;
538                 pos += snprintf(pos, end - pos, "%s ", m->imsi);
539                 pos += wpa_snprintf_hex(pos, end - pos, m->ki, 16);
540                 *pos++ = ' ';
541                 pos += wpa_snprintf_hex(pos, end - pos, m->opc, 16);
542                 *pos++ = ' ';
543                 pos += wpa_snprintf_hex(pos, end - pos, m->amf, 2);
544                 *pos++ = ' ';
545                 pos += wpa_snprintf_hex(pos, end - pos, m->sqn, 6);
546                 *pos++ = '\n';
547
548         no_update:
549                 fprintf(f2, "%s", buf);
550         }
551
552         fclose(f2);
553         fclose(f);
554
555         snprintf(name, sizeof(name), "%s.bak", fname);
556         if (rename(fname, name) < 0) {
557                 perror("rename");
558                 return;
559         }
560
561         snprintf(name, sizeof(name), "%s.new", fname);
562         if (rename(name, fname) < 0) {
563                 perror("rename");
564                 return;
565         }
566
567 }
568
569
570 static struct milenage_parameters * get_milenage(const char *imsi)
571 {
572         struct milenage_parameters *m = milenage_db;
573
574         while (m) {
575                 if (strcmp(m->imsi, imsi) == 0)
576                         break;
577                 m = m->next;
578         }
579
580 #ifdef CONFIG_SQLITE
581         if (!m)
582                 m = db_get_milenage(imsi);
583 #endif /* CONFIG_SQLITE */
584
585         return m;
586 }
587
588
589 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         resp[0] = '\0';
598
599         pos = strchr(imsi, ' ');
600         if (pos) {
601                 *pos++ = '\0';
602                 max_chal = atoi(pos);
603                 if (max_chal < 1 || max_chal > EAP_SIM_MAX_CHAL)
604                         max_chal = EAP_SIM_MAX_CHAL;
605         } else
606                 max_chal = EAP_SIM_MAX_CHAL;
607
608         rend = resp + resp_len;
609         rpos = resp;
610         ret = snprintf(rpos, rend - rpos, "SIM-RESP-AUTH %s", imsi);
611         if (ret < 0 || ret >= rend - rpos)
612                 return -1;
613         rpos += ret;
614
615         m = get_milenage(imsi);
616         if (m) {
617                 u8 _rand[16], sres[4], kc[8];
618                 for (count = 0; count < max_chal; count++) {
619                         if (random_get_bytes(_rand, 16) < 0)
620                                 return -1;
621                         gsm_milenage(m->opc, m->ki, _rand, sres, kc);
622                         *rpos++ = ' ';
623                         rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8);
624                         *rpos++ = ':';
625                         rpos += wpa_snprintf_hex(rpos, rend - rpos, sres, 4);
626                         *rpos++ = ':';
627                         rpos += wpa_snprintf_hex(rpos, rend - rpos, _rand, 16);
628                 }
629                 *rpos = '\0';
630                 return 0;
631         }
632
633         count = 0;
634         while (count < max_chal && (g = get_gsm_triplet(imsi))) {
635                 if (strcmp(g->imsi, imsi) != 0)
636                         continue;
637
638                 if (rpos < rend)
639                         *rpos++ = ' ';
640                 rpos += wpa_snprintf_hex(rpos, rend - rpos, g->kc, 8);
641                 if (rpos < rend)
642                         *rpos++ = ':';
643                 rpos += wpa_snprintf_hex(rpos, rend - rpos, g->sres, 4);
644                 if (rpos < rend)
645                         *rpos++ = ':';
646                 rpos += wpa_snprintf_hex(rpos, rend - rpos, g->_rand, 16);
647                 count++;
648         }
649
650         if (count == 0) {
651                 printf("No GSM triplets found for %s\n", imsi);
652                 ret = snprintf(rpos, rend - rpos, " FAILURE");
653                 if (ret < 0 || ret >= rend - rpos)
654                         return -1;
655                 rpos += ret;
656         }
657
658         return 0;
659 }
660
661
662 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         resp[0] = '\0';
669
670         pos = os_strchr(imsi, ' ');
671         if (!pos)
672                 return -1;
673         *pos++ = '\0';
674
675         rend = resp + resp_len;
676         rpos = resp;
677         ret = os_snprintf(rpos, rend - rpos, "GSM-AUTH-RESP %s", imsi);
678         if (os_snprintf_error(rend - rpos, ret))
679                 return -1;
680         rpos += ret;
681
682         m = get_milenage(imsi);
683         if (m) {
684                 u8 _rand[16], sres[4], kc[8];
685                 for (count = 0; count < EAP_SIM_MAX_CHAL; count++) {
686                         if (hexstr2bin(pos, _rand, 16) != 0)
687                                 return -1;
688                         gsm_milenage(m->opc, m->ki, _rand, sres, kc);
689                         *rpos++ = count == 0 ? ' ' : ':';
690                         rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8);
691                         *rpos++ = ':';
692                         rpos += wpa_snprintf_hex(rpos, rend - rpos, sres, 4);
693                         pos += 16 * 2;
694                         if (*pos != ':')
695                                 break;
696                         pos++;
697                 }
698                 *rpos = '\0';
699                 return 0;
700         }
701
702         printf("No GSM triplets found for %s\n", imsi);
703         ret = os_snprintf(rpos, rend - rpos, " FAILURE");
704         if (os_snprintf_error(rend - rpos, ret))
705                 return -1;
706         rpos += ret;
707
708         return 0;
709 }
710
711
712 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         val = ((u64) WPA_GET_BE32(sqn) << 16) | ((u64) WPA_GET_BE16(sqn + 4));
726         seq = (val >> ind_len) + 1;
727         ind = (val + 1) & ((1 << ind_len) - 1);
728         val = (seq << ind_len) | ind;
729         WPA_PUT_BE32(sqn, val >> 16);
730         WPA_PUT_BE16(sqn + 4, val & 0xffff);
731 }
732
733
734 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         int failed = 0;
747
748         m = get_milenage(imsi);
749         if (m) {
750                 if (random_get_bytes(_rand, EAP_AKA_RAND_LEN) < 0)
751                         return -1;
752                 res_len = EAP_AKA_RES_MAX_LEN;
753                 inc_sqn(m->sqn);
754 #ifdef CONFIG_SQLITE
755                 db_update_milenage_sqn(m);
756 #endif /* CONFIG_SQLITE */
757                 sqn_changes = 1;
758                 if (stdout_debug) {
759                         printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
760                                m->sqn[0], m->sqn[1], m->sqn[2],
761                                m->sqn[3], m->sqn[4], m->sqn[5]);
762                 }
763                 milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand,
764                                   autn, ik, ck, res, &res_len);
765                 if (m->res_len >= EAP_AKA_RES_MIN_LEN &&
766                     m->res_len <= EAP_AKA_RES_MAX_LEN &&
767                     m->res_len < res_len)
768                         res_len = m->res_len;
769         } else {
770                 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                 failed = 1;
781 #endif /* AKA_USE_FIXED_TEST_VALUES */
782         }
783
784         pos = resp;
785         end = resp + resp_len;
786         ret = snprintf(pos, end - pos, "AKA-RESP-AUTH %s ", imsi);
787         if (ret < 0 || ret >= end - pos)
788                 return -1;
789         pos += ret;
790         if (failed) {
791                 ret = snprintf(pos, end - pos, "FAILURE");
792                 if (ret < 0 || ret >= end - pos)
793                         return -1;
794                 pos += ret;
795                 return 0;
796         }
797         pos += wpa_snprintf_hex(pos, end - pos, _rand, EAP_AKA_RAND_LEN);
798         *pos++ = ' ';
799         pos += wpa_snprintf_hex(pos, end - pos, autn, EAP_AKA_AUTN_LEN);
800         *pos++ = ' ';
801         pos += wpa_snprintf_hex(pos, end - pos, ik, EAP_AKA_IK_LEN);
802         *pos++ = ' ';
803         pos += wpa_snprintf_hex(pos, end - pos, ck, EAP_AKA_CK_LEN);
804         *pos++ = ' ';
805         pos += wpa_snprintf_hex(pos, end - pos, res, res_len);
806
807         return 0;
808 }
809
810
811 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         resp[0] = '\0';
818
819         /* AKA-AUTS <IMSI> <AUTS> <RAND> */
820
821         auts = strchr(imsi, ' ');
822         if (auts == NULL)
823                 return -1;
824         *auts++ = '\0';
825
826         __rand = strchr(auts, ' ');
827         if (__rand == NULL)
828                 return -1;
829         *__rand++ = '\0';
830
831         if (stdout_debug) {
832                 printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n",
833                        imsi, auts, __rand);
834         }
835         if (hexstr2bin(auts, _auts, EAP_AKA_AUTS_LEN) ||
836             hexstr2bin(__rand, _rand, EAP_AKA_RAND_LEN)) {
837                 printf("Could not parse AUTS/RAND\n");
838                 return -1;
839         }
840
841         m = get_milenage(imsi);
842         if (m == NULL) {
843                 printf("Unknown IMSI: %s\n", imsi);
844                 return -1;
845         }
846
847         if (milenage_auts(m->opc, m->ki, _rand, _auts, sqn)) {
848                 printf("AKA-AUTS: Incorrect MAC-S\n");
849         } else {
850                 memcpy(m->sqn, sqn, 6);
851                 if (stdout_debug) {
852                         printf("AKA-AUTS: Re-synchronized: "
853                                "SQN=%02x%02x%02x%02x%02x%02x\n",
854                                sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
855                 }
856 #ifdef CONFIG_SQLITE
857                 db_update_milenage_sqn(m);
858 #endif /* CONFIG_SQLITE */
859                 sqn_changes = 1;
860         }
861
862         return 0;
863 }
864
865
866 static int process_cmd(char *cmd, char *resp, size_t resp_len)
867 {
868         if (os_strncmp(cmd, "SIM-REQ-AUTH ", 13) == 0)
869                 return sim_req_auth(cmd + 13, resp, resp_len);
870
871         if (os_strncmp(cmd, "GSM-AUTH-REQ ", 13) == 0)
872                 return gsm_auth_req(cmd + 13, resp, resp_len);
873
874         if (os_strncmp(cmd, "AKA-REQ-AUTH ", 13) == 0)
875                 return aka_req_auth(cmd + 13, resp, resp_len);
876
877         if (os_strncmp(cmd, "AKA-AUTS ", 9) == 0)
878                 return aka_auts(cmd + 9, resp, resp_len);
879
880         printf("Unknown request: %s\n", cmd);
881         return -1;
882 }
883
884
885 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         fromlen = sizeof(from);
893         res = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *) &from,
894                        &fromlen);
895         if (res < 0) {
896                 perror("recvfrom");
897                 return -1;
898         }
899
900         if (res == 0)
901                 return 0;
902
903         if ((size_t) res >= sizeof(buf))
904                 res = sizeof(buf) - 1;
905         buf[res] = '\0';
906
907         printf("Received: %s\n", buf);
908
909         if (process_cmd(buf, resp, sizeof(resp)) < 0) {
910                 printf("Failed to process request\n");
911                 return -1;
912         }
913
914         if (resp[0] == '\0') {
915                 printf("No response\n");
916                 return 0;
917         }
918
919         printf("Send: %s\n", resp);
920
921         if (sendto(s, resp, os_strlen(resp), 0, (struct sockaddr *) &from,
922                    fromlen) < 0)
923                 perror("send");
924
925         return 0;
926 }
927
928
929 static void cleanup(void)
930 {
931         struct gsm_triplet *g, *gprev;
932         struct milenage_parameters *m, *prev;
933
934         if (update_milenage && milenage_file && sqn_changes)
935                 update_milenage_file(milenage_file);
936
937         g = gsm_db;
938         while (g) {
939                 gprev = g;
940                 g = g->next;
941                 os_free(gprev);
942         }
943
944         m = milenage_db;
945         while (m) {
946                 prev = m;
947                 m = m->next;
948                 os_free(prev);
949         }
950
951         if (serv_sock >= 0)
952                 close(serv_sock);
953         if (socket_path)
954                 unlink(socket_path);
955
956 #ifdef CONFIG_SQLITE
957         if (sqlite_db) {
958                 sqlite3_close(sqlite_db);
959                 sqlite_db = NULL;
960         }
961 #endif /* CONFIG_SQLITE */
962 }
963
964
965 static void handle_term(int sig)
966 {
967         printf("Signal %d - terminate\n", sig);
968         exit(0);
969 }
970
971
972 static void usage(void)
973 {
974         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 }
1002
1003
1004 int main(int argc, char *argv[])
1005 {
1006         int c;
1007         char *gsm_triplet_file = NULL;
1008         char *sqlite_db_file = NULL;
1009         int ret = 0;
1010
1011         if (os_program_init())
1012                 return -1;
1013
1014         socket_path = default_socket_path;
1015
1016         for (;;) {
1017                 c = getopt(argc, argv, "D:g:hi:m:s:u");
1018                 if (c < 0)
1019                         break;
1020                 switch (c) {
1021                 case 'D':
1022 #ifdef CONFIG_SQLITE
1023                         sqlite_db_file = optarg;
1024                         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                         gsm_triplet_file = optarg;
1031                         break;
1032                 case 'h':
1033                         usage();
1034                         return 0;
1035                 case 'i':
1036                         ind_len = atoi(optarg);
1037                         if (ind_len < 0 || ind_len > 32) {
1038                                 printf("Invalid IND length\n");
1039                                 return -1;
1040                         }
1041                         break;
1042                 case 'm':
1043                         milenage_file = optarg;
1044                         break;
1045                 case 's':
1046                         socket_path = optarg;
1047                         break;
1048                 case 'u':
1049                         update_milenage = 1;
1050                         break;
1051                 default:
1052                         usage();
1053                         return -1;
1054                 }
1055         }
1056
1057         if (!gsm_triplet_file && !milenage_file && !sqlite_db_file) {
1058                 usage();
1059                 return -1;
1060         }
1061
1062 #ifdef CONFIG_SQLITE
1063         if (sqlite_db_file && (sqlite_db = db_open(sqlite_db_file)) == NULL)
1064                 return -1;
1065 #endif /* CONFIG_SQLITE */
1066
1067         if (gsm_triplet_file && read_gsm_triplets(gsm_triplet_file) < 0)
1068                 return -1;
1069
1070         if (milenage_file && read_milenage(milenage_file) < 0)
1071                 return -1;
1072
1073         if (optind == argc) {
1074                 serv_sock = open_socket(socket_path);
1075                 if (serv_sock < 0)
1076                         return -1;
1077
1078                 printf("Listening for requests on %s\n", socket_path);
1079
1080                 atexit(cleanup);
1081                 signal(SIGTERM, handle_term);
1082                 signal(SIGINT, handle_term);
1083
1084                 for (;;)
1085                         process(serv_sock);
1086         } else {
1087                 char buf[1000];
1088                 socket_path = NULL;
1089                 stdout_debug = 0;
1090                 if (process_cmd(argv[optind], buf, sizeof(buf)) < 0) {
1091                         printf("FAIL\n");
1092                         ret = -1;
1093                 } else {
1094                         printf("%s\n", buf);
1095                 }
1096                 cleanup();
1097         }
1098
1099 #ifdef CONFIG_SQLITE
1100         if (sqlite_db) {
1101                 sqlite3_close(sqlite_db);
1102                 sqlite_db = NULL;
1103         }
1104 #endif /* CONFIG_SQLITE */
1105
1106         os_program_deinit();
1107
1108         return ret;
1109 }