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