]> git.ipfire.org Git - thirdparty/hostap.git/blame - src/eap_server/eap_sim_db.c
EAP-SIM DB: Optional use of SQLite database for pseudonyms
[thirdparty/hostap.git] / src / eap_server / eap_sim_db.c
CommitLineData
6fc6879b
JM
1/*
2 * hostapd / EAP-SIM database/authenticator gateway
762e4ce6 3 * Copyright (c) 2005-2010, 2012, Jouni Malinen <j@w1.fi>
6fc6879b 4 *
0f3d578e
JM
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
6fc6879b
JM
7 *
8 * This is an example implementation of the EAP-SIM/AKA database/authentication
9 * gateway interface that is using an external program as an SS7 gateway to
10 * GSM/UMTS authentication center (HLR/AuC). hlr_auc_gw is an example
11 * implementation of such a gateway program. This eap_sim_db.c takes care of
12 * EAP-SIM/AKA pseudonyms and re-auth identities. It can be used with different
13 * gateway implementations for HLR/AuC access. Alternatively, it can also be
14 * completely replaced if the in-memory database of pseudonyms/re-auth
15 * identities is not suitable for some cases.
16 */
17
18#include "includes.h"
19#include <sys/un.h>
66979bb8
JM
20#ifdef CONFIG_SQLITE
21#include <sqlite3.h>
22#endif /* CONFIG_SQLITE */
6fc6879b
JM
23
24#include "common.h"
3642c431 25#include "crypto/random.h"
6fc6879b
JM
26#include "eap_common/eap_sim_common.h"
27#include "eap_server/eap_sim_db.h"
28#include "eloop.h"
29
30struct eap_sim_pseudonym {
31 struct eap_sim_pseudonym *next;
32 u8 *identity;
33 size_t identity_len;
34 char *pseudonym;
35};
36
37struct eap_sim_db_pending {
38 struct eap_sim_db_pending *next;
39 u8 imsi[20];
40 size_t imsi_len;
41 enum { PENDING, SUCCESS, FAILURE } state;
42 void *cb_session_ctx;
43 struct os_time timestamp;
44 int aka;
45 union {
46 struct {
47 u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
48 u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
49 u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
50 int num_chal;
51 } sim;
52 struct {
53 u8 rand[EAP_AKA_RAND_LEN];
54 u8 autn[EAP_AKA_AUTN_LEN];
55 u8 ik[EAP_AKA_IK_LEN];
56 u8 ck[EAP_AKA_CK_LEN];
57 u8 res[EAP_AKA_RES_MAX_LEN];
58 size_t res_len;
59 } aka;
60 } u;
61};
62
63struct eap_sim_db_data {
64 int sock;
65 char *fname;
66 char *local_sock;
67 void (*get_complete_cb)(void *ctx, void *session_ctx);
68 void *ctx;
69 struct eap_sim_pseudonym *pseudonyms;
70 struct eap_sim_reauth *reauths;
71 struct eap_sim_db_pending *pending;
66979bb8
JM
72#ifdef CONFIG_SQLITE
73 sqlite3 *sqlite_db;
74 u8 db_tmp_identity[100];
75 char db_tmp_pseudonym_str[100];
76 struct eap_sim_pseudonym db_tmp_pseudonym;
77#endif /* CONFIG_SQLITE */
6fc6879b
JM
78};
79
80
66979bb8
JM
81#ifdef CONFIG_SQLITE
82
83static int db_table_exists(sqlite3 *db, const char *name)
84{
85 char cmd[128];
86 os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
87 return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
88}
89
90
91static int db_table_create_pseudonym(sqlite3 *db)
92{
93 char *err = NULL;
94 const char *sql =
95 "CREATE TABLE pseudonyms("
96 " imsi INTEGER PRIMARY KEY NOT NULL,"
97 " pseudonym CHAR(21) NOT NULL"
98 ");";
99
100 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Adding database table for "
101 "pseudonym information");
102 if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
103 wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
104 sqlite3_free(err);
105 return -1;
106 }
107
108 return 0;
109}
110
111
112static sqlite3 * db_open(const char *db_file)
113{
114 sqlite3 *db;
115
116 if (sqlite3_open(db_file, &db)) {
117 wpa_printf(MSG_ERROR, "EAP-SIM DB: Failed to open database "
118 "%s: %s", db_file, sqlite3_errmsg(db));
119 sqlite3_close(db);
120 return NULL;
121 }
122
123 if (!db_table_exists(db, "pseudonyms") &&
124 db_table_create_pseudonym(db) < 0) {
125 sqlite3_close(db);
126 return NULL;
127 }
128
129 return db;
130}
131
132
133static int valid_pseudonym_string(const char *pseudonym)
134{
135 const char *pos = pseudonym;
136 while (*pos) {
137 if ((*pos < '0' || *pos > '9') &&
138 (*pos < 'a' || *pos > 'f'))
139 return 0;
140 pos++;
141 }
142 return 1;
143}
144
145
146static int db_add_pseudonym(struct eap_sim_db_data *data, const u8 *identity,
147 size_t identity_len, char *pseudonym)
148{
149 char cmd[128];
150 unsigned long long imsi;
151
152 if (!valid_pseudonym_string(pseudonym) || identity_len >= sizeof(cmd))
153 {
154 os_free(pseudonym);
155 return -1;
156 }
157 os_memcpy(cmd, identity, identity_len);
158 cmd[identity_len] = '\0';
159 imsi = atoll(cmd);
160
161 os_snprintf(cmd, sizeof(cmd), "INSERT OR REPLACE INTO pseudonyms "
162 "(imsi, pseudonym) VALUES (%llu , '%s');",
163 imsi, pseudonym);
164 os_free(pseudonym);
165 if (sqlite3_exec(data->sqlite_db, cmd, NULL, data, NULL) != SQLITE_OK)
166 return -1;
167
168 return 0;
169}
170
171
172static int get_pseudonym_cb(void *ctx, int argc, char *argv[], char *col[])
173{
174 struct eap_sim_db_data *data = ctx;
175 int i;
176 size_t len;
177
178 for (i = 0; i < argc; i++) {
179 if (os_strcmp(col[i], "imsi") == 0 && argv[i]) {
180 len = os_strlen(argv[i]);
181 if (len > sizeof(data->db_tmp_identity))
182 continue;
183 os_memcpy(data->db_tmp_identity, argv[i], len);
184 data->db_tmp_pseudonym.identity =
185 data->db_tmp_identity;
186 data->db_tmp_pseudonym.identity_len = len;
187 } else if (os_strcmp(col[i], "pseudonym") == 0 && argv[i]) {
188 len = os_strlen(argv[i]);
189 if (len >= sizeof(data->db_tmp_pseudonym_str))
190 continue;
191 os_memcpy(data->db_tmp_pseudonym_str, argv[i], len);
192 data->db_tmp_pseudonym_str[len] = '\0';
193 data->db_tmp_pseudonym.pseudonym =
194 data->db_tmp_pseudonym_str;
195 }
196 }
197
198 return 0;
199}
200
201
202static struct eap_sim_pseudonym *
203db_get_pseudonym(struct eap_sim_db_data *data, const char *pseudonym)
204{
205 char cmd[128];
206
207 if (!valid_pseudonym_string(pseudonym))
208 return NULL;
209 os_memset(&data->db_tmp_pseudonym, 0, sizeof(data->db_tmp_pseudonym));
210 os_strlcpy(data->db_tmp_pseudonym_str, pseudonym,
211 sizeof(data->db_tmp_pseudonym_str));
212 data->db_tmp_pseudonym.pseudonym = data->db_tmp_pseudonym_str;
213 os_snprintf(cmd, sizeof(cmd),
214 "SELECT imsi FROM pseudonyms WHERE pseudonym='%s';",
215 pseudonym);
216 if (sqlite3_exec(data->sqlite_db, cmd, get_pseudonym_cb, data, NULL) !=
217 SQLITE_OK)
218 return NULL;
219 if (data->db_tmp_pseudonym.identity == NULL)
220 return NULL;
221 return &data->db_tmp_pseudonym;
222}
223
224
225static struct eap_sim_pseudonym *
226db_get_pseudonym_id(struct eap_sim_db_data *data, const u8 *identity,
227 size_t identity_len)
228{
229 char cmd[128];
230 unsigned long long imsi;
231
232 if (identity_len >= sizeof(cmd))
233 return NULL;
234 os_memcpy(cmd, identity, identity_len);
235 cmd[identity_len] = '\0';
236 imsi = atoll(cmd);
237
238 os_memset(&data->db_tmp_pseudonym, 0, sizeof(data->db_tmp_pseudonym));
239 if (identity_len > sizeof(data->db_tmp_identity))
240 return NULL;
241 os_memcpy(data->db_tmp_identity, identity, identity_len);
242 data->db_tmp_pseudonym.identity = data->db_tmp_identity;
243 data->db_tmp_pseudonym.identity_len = identity_len;
244 os_snprintf(cmd, sizeof(cmd),
245 "SELECT pseudonym FROM pseudonyms WHERE imsi=%llu;", imsi);
246 if (sqlite3_exec(data->sqlite_db, cmd, get_pseudonym_cb, data, NULL) !=
247 SQLITE_OK)
248 return NULL;
249 if (data->db_tmp_pseudonym.pseudonym == NULL)
250 return NULL;
251 return &data->db_tmp_pseudonym;
252}
253
254#endif /* CONFIG_SQLITE */
255
6fc6879b
JM
256static struct eap_sim_db_pending *
257eap_sim_db_get_pending(struct eap_sim_db_data *data, const u8 *imsi,
258 size_t imsi_len, int aka)
259{
260 struct eap_sim_db_pending *entry, *prev = NULL;
261
262 entry = data->pending;
263 while (entry) {
264 if (entry->aka == aka && entry->imsi_len == imsi_len &&
265 os_memcmp(entry->imsi, imsi, imsi_len) == 0) {
266 if (prev)
267 prev->next = entry->next;
268 else
269 data->pending = entry->next;
270 break;
271 }
272 prev = entry;
273 entry = entry->next;
274 }
275 return entry;
276}
277
278
279static void eap_sim_db_add_pending(struct eap_sim_db_data *data,
280 struct eap_sim_db_pending *entry)
281{
282 entry->next = data->pending;
283 data->pending = entry;
284}
285
286
287static void eap_sim_db_sim_resp_auth(struct eap_sim_db_data *data,
288 const char *imsi, char *buf)
289{
290 char *start, *end, *pos;
291 struct eap_sim_db_pending *entry;
292 int num_chal;
293
294 /*
295 * SIM-RESP-AUTH <IMSI> Kc(i):SRES(i):RAND(i) ...
296 * SIM-RESP-AUTH <IMSI> FAILURE
297 * (IMSI = ASCII string, Kc/SRES/RAND = hex string)
298 */
299
300 entry = eap_sim_db_get_pending(data, (u8 *) imsi, os_strlen(imsi), 0);
301 if (entry == NULL) {
302 wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
303 "received message found");
304 return;
305 }
306
307 start = buf;
308 if (os_strncmp(start, "FAILURE", 7) == 0) {
309 wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
310 "failure");
311 entry->state = FAILURE;
312 eap_sim_db_add_pending(data, entry);
313 data->get_complete_cb(data->ctx, entry->cb_session_ctx);
314 return;
315 }
316
317 num_chal = 0;
318 while (num_chal < EAP_SIM_MAX_CHAL) {
319 end = os_strchr(start, ' ');
320 if (end)
321 *end = '\0';
322
323 pos = os_strchr(start, ':');
324 if (pos == NULL)
325 goto parse_fail;
326 *pos = '\0';
327 if (hexstr2bin(start, entry->u.sim.kc[num_chal],
328 EAP_SIM_KC_LEN))
329 goto parse_fail;
330
331 start = pos + 1;
332 pos = os_strchr(start, ':');
333 if (pos == NULL)
334 goto parse_fail;
335 *pos = '\0';
336 if (hexstr2bin(start, entry->u.sim.sres[num_chal],
337 EAP_SIM_SRES_LEN))
338 goto parse_fail;
339
340 start = pos + 1;
341 if (hexstr2bin(start, entry->u.sim.rand[num_chal],
342 GSM_RAND_LEN))
343 goto parse_fail;
344
345 num_chal++;
346 if (end == NULL)
347 break;
348 else
349 start = end + 1;
350 }
351 entry->u.sim.num_chal = num_chal;
352
353 entry->state = SUCCESS;
354 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
355 "successfully - callback");
356 eap_sim_db_add_pending(data, entry);
357 data->get_complete_cb(data->ctx, entry->cb_session_ctx);
358 return;
359
360parse_fail:
361 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
362 os_free(entry);
363}
364
365
366static void eap_sim_db_aka_resp_auth(struct eap_sim_db_data *data,
367 const char *imsi, char *buf)
368{
369 char *start, *end;
370 struct eap_sim_db_pending *entry;
371
372 /*
373 * AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES>
374 * AKA-RESP-AUTH <IMSI> FAILURE
375 * (IMSI = ASCII string, RAND/AUTN/IK/CK/RES = hex string)
376 */
377
378 entry = eap_sim_db_get_pending(data, (u8 *) imsi, os_strlen(imsi), 1);
379 if (entry == NULL) {
380 wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
381 "received message found");
382 return;
383 }
384
385 start = buf;
386 if (os_strncmp(start, "FAILURE", 7) == 0) {
387 wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
388 "failure");
389 entry->state = FAILURE;
390 eap_sim_db_add_pending(data, entry);
391 data->get_complete_cb(data->ctx, entry->cb_session_ctx);
392 return;
393 }
394
395 end = os_strchr(start, ' ');
396 if (end == NULL)
397 goto parse_fail;
398 *end = '\0';
399 if (hexstr2bin(start, entry->u.aka.rand, EAP_AKA_RAND_LEN))
400 goto parse_fail;
401
402 start = end + 1;
403 end = os_strchr(start, ' ');
404 if (end == NULL)
405 goto parse_fail;
406 *end = '\0';
407 if (hexstr2bin(start, entry->u.aka.autn, EAP_AKA_AUTN_LEN))
408 goto parse_fail;
409
410 start = end + 1;
411 end = os_strchr(start, ' ');
412 if (end == NULL)
413 goto parse_fail;
414 *end = '\0';
415 if (hexstr2bin(start, entry->u.aka.ik, EAP_AKA_IK_LEN))
416 goto parse_fail;
417
418 start = end + 1;
419 end = os_strchr(start, ' ');
420 if (end == NULL)
421 goto parse_fail;
422 *end = '\0';
423 if (hexstr2bin(start, entry->u.aka.ck, EAP_AKA_CK_LEN))
424 goto parse_fail;
425
426 start = end + 1;
427 end = os_strchr(start, ' ');
428 if (end)
429 *end = '\0';
430 else {
431 end = start;
432 while (*end)
433 end++;
434 }
435 entry->u.aka.res_len = (end - start) / 2;
436 if (entry->u.aka.res_len > EAP_AKA_RES_MAX_LEN) {
437 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Too long RES");
438 entry->u.aka.res_len = 0;
439 goto parse_fail;
440 }
441 if (hexstr2bin(start, entry->u.aka.res, entry->u.aka.res_len))
442 goto parse_fail;
443
444 entry->state = SUCCESS;
445 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
446 "successfully - callback");
447 eap_sim_db_add_pending(data, entry);
448 data->get_complete_cb(data->ctx, entry->cb_session_ctx);
449 return;
450
451parse_fail:
452 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
453 os_free(entry);
454}
455
456
457static void eap_sim_db_receive(int sock, void *eloop_ctx, void *sock_ctx)
458{
459 struct eap_sim_db_data *data = eloop_ctx;
460 char buf[1000], *pos, *cmd, *imsi;
461 int res;
462
463 res = recv(sock, buf, sizeof(buf), 0);
464 if (res < 0)
465 return;
466 wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-SIM DB: Received from an "
467 "external source", (u8 *) buf, res);
468 if (res == 0)
469 return;
470 if (res >= (int) sizeof(buf))
471 res = sizeof(buf) - 1;
472 buf[res] = '\0';
473
474 if (data->get_complete_cb == NULL) {
475 wpa_printf(MSG_DEBUG, "EAP-SIM DB: No get_complete_cb "
476 "registered");
477 return;
478 }
479
480 /* <cmd> <IMSI> ... */
481
482 cmd = buf;
483 pos = os_strchr(cmd, ' ');
484 if (pos == NULL)
485 goto parse_fail;
486 *pos = '\0';
487 imsi = pos + 1;
488 pos = os_strchr(imsi, ' ');
489 if (pos == NULL)
490 goto parse_fail;
491 *pos = '\0';
492 wpa_printf(MSG_DEBUG, "EAP-SIM DB: External response=%s for IMSI %s",
493 cmd, imsi);
494
495 if (os_strcmp(cmd, "SIM-RESP-AUTH") == 0)
496 eap_sim_db_sim_resp_auth(data, imsi, pos + 1);
497 else if (os_strcmp(cmd, "AKA-RESP-AUTH") == 0)
498 eap_sim_db_aka_resp_auth(data, imsi, pos + 1);
499 else
500 wpa_printf(MSG_INFO, "EAP-SIM DB: Unknown external response "
501 "'%s'", cmd);
502 return;
503
504parse_fail:
505 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
506}
507
508
509static int eap_sim_db_open_socket(struct eap_sim_db_data *data)
510{
511 struct sockaddr_un addr;
512 static int counter = 0;
513
514 if (os_strncmp(data->fname, "unix:", 5) != 0)
515 return -1;
516
517 data->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
518 if (data->sock < 0) {
519 perror("socket(eap_sim_db)");
520 return -1;
521 }
522
523 os_memset(&addr, 0, sizeof(addr));
524 addr.sun_family = AF_UNIX;
525 os_snprintf(addr.sun_path, sizeof(addr.sun_path),
526 "/tmp/eap_sim_db_%d-%d", getpid(), counter++);
c13f0a3e 527 os_free(data->local_sock);
6fc6879b
JM
528 data->local_sock = os_strdup(addr.sun_path);
529 if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
530 perror("bind(eap_sim_db)");
531 close(data->sock);
532 data->sock = -1;
533 return -1;
534 }
535
536 os_memset(&addr, 0, sizeof(addr));
537 addr.sun_family = AF_UNIX;
538 os_strlcpy(addr.sun_path, data->fname + 5, sizeof(addr.sun_path));
539 if (connect(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
540 perror("connect(eap_sim_db)");
541 wpa_hexdump_ascii(MSG_INFO, "HLR/AuC GW socket",
542 (u8 *) addr.sun_path,
543 os_strlen(addr.sun_path));
544 close(data->sock);
545 data->sock = -1;
546 return -1;
547 }
548
549 eloop_register_read_sock(data->sock, eap_sim_db_receive, data, NULL);
550
551 return 0;
552}
553
554
555static void eap_sim_db_close_socket(struct eap_sim_db_data *data)
556{
557 if (data->sock >= 0) {
558 eloop_unregister_read_sock(data->sock);
559 close(data->sock);
560 data->sock = -1;
561 }
562 if (data->local_sock) {
563 unlink(data->local_sock);
564 os_free(data->local_sock);
565 data->local_sock = NULL;
566 }
567}
568
569
570/**
571 * eap_sim_db_init - Initialize EAP-SIM DB / authentication gateway interface
572 * @config: Configuration data (e.g., file name)
573 * @get_complete_cb: Callback function for reporting availability of triplets
574 * @ctx: Context pointer for get_complete_cb
575 * Returns: Pointer to a private data structure or %NULL on failure
576 */
577void * eap_sim_db_init(const char *config,
578 void (*get_complete_cb)(void *ctx, void *session_ctx),
579 void *ctx)
580{
581 struct eap_sim_db_data *data;
66979bb8 582 char *pos;
6fc6879b
JM
583
584 data = os_zalloc(sizeof(*data));
585 if (data == NULL)
586 return NULL;
587
588 data->sock = -1;
589 data->get_complete_cb = get_complete_cb;
590 data->ctx = ctx;
591 data->fname = os_strdup(config);
592 if (data->fname == NULL)
593 goto fail;
66979bb8
JM
594 pos = os_strstr(data->fname, " db=");
595 if (pos) {
596 *pos = '\0';
597#ifdef CONFIG_SQLITE
598 pos += 4;
599 data->sqlite_db = db_open(pos);
600 if (data->sqlite_db == NULL)
601 goto fail;
602#endif /* CONFIG_SQLITE */
603 }
6fc6879b
JM
604
605 if (os_strncmp(data->fname, "unix:", 5) == 0) {
704b8762
JM
606 if (eap_sim_db_open_socket(data)) {
607 wpa_printf(MSG_DEBUG, "EAP-SIM DB: External database "
608 "connection not available - will retry "
609 "later");
610 }
6fc6879b
JM
611 }
612
613 return data;
614
615fail:
616 eap_sim_db_close_socket(data);
617 os_free(data->fname);
618 os_free(data);
619 return NULL;
620}
621
622
623static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p)
624{
625 os_free(p->identity);
626 os_free(p->pseudonym);
627 os_free(p);
628}
629
630
631static void eap_sim_db_free_reauth(struct eap_sim_reauth *r)
632{
633 os_free(r->identity);
634 os_free(r->reauth_id);
635 os_free(r);
636}
637
638
639/**
640 * eap_sim_db_deinit - Deinitialize EAP-SIM DB/authentication gw interface
641 * @priv: Private data pointer from eap_sim_db_init()
642 */
643void eap_sim_db_deinit(void *priv)
644{
645 struct eap_sim_db_data *data = priv;
646 struct eap_sim_pseudonym *p, *prev;
647 struct eap_sim_reauth *r, *prevr;
648 struct eap_sim_db_pending *pending, *prev_pending;
649
66979bb8
JM
650#ifdef CONFIG_SQLITE
651 if (data->sqlite_db) {
652 sqlite3_close(data->sqlite_db);
653 data->sqlite_db = NULL;
654 }
655#endif /* CONFIG_SQLITE */
656
6fc6879b
JM
657 eap_sim_db_close_socket(data);
658 os_free(data->fname);
659
660 p = data->pseudonyms;
661 while (p) {
662 prev = p;
663 p = p->next;
664 eap_sim_db_free_pseudonym(prev);
665 }
666
667 r = data->reauths;
668 while (r) {
669 prevr = r;
670 r = r->next;
671 eap_sim_db_free_reauth(prevr);
672 }
673
674 pending = data->pending;
675 while (pending) {
676 prev_pending = pending;
677 pending = pending->next;
678 os_free(prev_pending);
679 }
680
681 os_free(data);
682}
683
684
685static int eap_sim_db_send(struct eap_sim_db_data *data, const char *msg,
686 size_t len)
687{
688 int _errno = 0;
689
690 if (send(data->sock, msg, len, 0) < 0) {
691 _errno = errno;
692 perror("send[EAP-SIM DB UNIX]");
693 }
694
695 if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
696 _errno == ECONNREFUSED) {
697 /* Try to reconnect */
698 eap_sim_db_close_socket(data);
699 if (eap_sim_db_open_socket(data) < 0)
700 return -1;
701 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Reconnected to the "
702 "external server");
703 if (send(data->sock, msg, len, 0) < 0) {
704 perror("send[EAP-SIM DB UNIX]");
705 return -1;
706 }
707 }
708
709 return 0;
710}
711
712
713static void eap_sim_db_expire_pending(struct eap_sim_db_data *data)
714{
715 /* TODO: add limit for maximum length for pending list; remove latest
716 * (i.e., last) entry from the list if the limit is reached; could also
717 * use timeout to expire pending entries */
718}
719
720
721/**
722 * eap_sim_db_get_gsm_triplets - Get GSM triplets
723 * @priv: Private data pointer from eap_sim_db_init()
724 * @identity: User name identity
725 * @identity_len: Length of identity in bytes
726 * @max_chal: Maximum number of triplets
727 * @_rand: Buffer for RAND values
728 * @kc: Buffer for Kc values
729 * @sres: Buffer for SRES values
730 * @cb_session_ctx: Session callback context for get_complete_cb()
731 * Returns: Number of triplets received (has to be less than or equal to
732 * max_chal), -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not found), or
733 * -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this case, the
734 * callback function registered with eap_sim_db_init() will be called once the
735 * results become available.
736 *
737 * In most cases, the user name is '1' | IMSI, i.e., 1 followed by the IMSI in
738 * ASCII format.
739 *
740 * When using an external server for GSM triplets, this function can always
741 * start a request and return EAP_SIM_DB_PENDING immediately if authentication
742 * triplets are not available. Once the triplets are received, callback
743 * function registered with eap_sim_db_init() is called to notify EAP state
744 * machine to reprocess the message. This eap_sim_db_get_gsm_triplets()
745 * function will then be called again and the newly received triplets will then
746 * be given to the caller.
747 */
748int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity,
749 size_t identity_len, int max_chal,
750 u8 *_rand, u8 *kc, u8 *sres,
751 void *cb_session_ctx)
752{
753 struct eap_sim_db_data *data = priv;
754 struct eap_sim_db_pending *entry;
755 int len, ret;
756 size_t i;
757 char msg[40];
758
759 if (identity_len < 2 || identity[0] != EAP_SIM_PERMANENT_PREFIX) {
760 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
761 identity, identity_len);
762 return EAP_SIM_DB_FAILURE;
763 }
764 identity++;
765 identity_len--;
766 for (i = 0; i < identity_len; i++) {
767 if (identity[i] == '@') {
768 identity_len = i;
769 break;
770 }
771 }
772 if (identity_len + 1 > sizeof(entry->imsi)) {
773 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
774 identity, identity_len);
775 return EAP_SIM_DB_FAILURE;
776 }
777 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI",
778 identity, identity_len);
779
780 entry = eap_sim_db_get_pending(data, identity, identity_len, 0);
781 if (entry) {
782 int num_chal;
783 if (entry->state == FAILURE) {
784 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
785 "failure");
786 os_free(entry);
787 return EAP_SIM_DB_FAILURE;
788 }
789
790 if (entry->state == PENDING) {
791 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
792 "still pending");
793 eap_sim_db_add_pending(data, entry);
794 return EAP_SIM_DB_PENDING;
795 }
796
797 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
798 "%d challenges", entry->u.sim.num_chal);
799 num_chal = entry->u.sim.num_chal;
800 if (num_chal > max_chal)
801 num_chal = max_chal;
802 os_memcpy(_rand, entry->u.sim.rand, num_chal * GSM_RAND_LEN);
803 os_memcpy(sres, entry->u.sim.sres,
804 num_chal * EAP_SIM_SRES_LEN);
805 os_memcpy(kc, entry->u.sim.kc, num_chal * EAP_SIM_KC_LEN);
806 os_free(entry);
807 return num_chal;
808 }
809
810 if (data->sock < 0) {
811 if (eap_sim_db_open_socket(data) < 0)
812 return EAP_SIM_DB_FAILURE;
813 }
814
815 len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH ");
816 if (len < 0 || len + identity_len >= sizeof(msg))
817 return EAP_SIM_DB_FAILURE;
818 os_memcpy(msg + len, identity, identity_len);
819 len += identity_len;
820 ret = os_snprintf(msg + len, sizeof(msg) - len, " %d", max_chal);
821 if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
822 return EAP_SIM_DB_FAILURE;
823 len += ret;
824
825 wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication "
826 "data for IMSI", identity, identity_len);
827 if (eap_sim_db_send(data, msg, len) < 0)
828 return EAP_SIM_DB_FAILURE;
829
830 entry = os_zalloc(sizeof(*entry));
831 if (entry == NULL)
832 return EAP_SIM_DB_FAILURE;
833
834 os_get_time(&entry->timestamp);
835 os_memcpy(entry->imsi, identity, identity_len);
836 entry->imsi_len = identity_len;
837 entry->cb_session_ctx = cb_session_ctx;
838 entry->state = PENDING;
839 eap_sim_db_add_pending(data, entry);
840 eap_sim_db_expire_pending(data);
841
842 return EAP_SIM_DB_PENDING;
843}
844
845
846static struct eap_sim_pseudonym *
847eap_sim_db_get_pseudonym(struct eap_sim_db_data *data, const u8 *identity,
848 size_t identity_len)
849{
850 char *pseudonym;
851 size_t len;
852 struct eap_sim_pseudonym *p;
853
854 if (identity_len == 0 ||
855 (identity[0] != EAP_SIM_PSEUDONYM_PREFIX &&
762e4ce6
JM
856 identity[0] != EAP_AKA_PSEUDONYM_PREFIX &&
857 identity[0] != EAP_AKA_PRIME_PSEUDONYM_PREFIX))
6fc6879b
JM
858 return NULL;
859
860 /* Remove possible realm from identity */
861 len = 0;
862 while (len < identity_len) {
863 if (identity[len] == '@')
864 break;
865 len++;
866 }
867
868 pseudonym = os_malloc(len + 1);
869 if (pseudonym == NULL)
870 return NULL;
871 os_memcpy(pseudonym, identity, len);
872 pseudonym[len] = '\0';
873
66979bb8
JM
874#ifdef CONFIG_SQLITE
875 if (data->sqlite_db) {
876 p = db_get_pseudonym(data, pseudonym);
877 os_free(pseudonym);
878 return p;
879 }
880#endif /* CONFIG_SQLITE */
881
6fc6879b
JM
882 p = data->pseudonyms;
883 while (p) {
884 if (os_strcmp(p->pseudonym, pseudonym) == 0)
885 break;
886 p = p->next;
887 }
888
889 os_free(pseudonym);
890
891 return p;
892}
893
894
895static struct eap_sim_pseudonym *
896eap_sim_db_get_pseudonym_id(struct eap_sim_db_data *data, const u8 *identity,
897 size_t identity_len)
898{
899 struct eap_sim_pseudonym *p;
900
901 if (identity_len == 0 ||
902 (identity[0] != EAP_SIM_PERMANENT_PREFIX &&
762e4ce6
JM
903 identity[0] != EAP_AKA_PERMANENT_PREFIX &&
904 identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX))
6fc6879b
JM
905 return NULL;
906
66979bb8
JM
907#ifdef CONFIG_SQLITE
908 if (data->sqlite_db)
909 return db_get_pseudonym_id(data, identity, identity_len);
910#endif /* CONFIG_SQLITE */
911
6fc6879b
JM
912 p = data->pseudonyms;
913 while (p) {
914 if (identity_len == p->identity_len &&
915 os_memcmp(p->identity, identity, identity_len) == 0)
916 break;
917 p = p->next;
918 }
919
920 return p;
921}
922
923
924static struct eap_sim_reauth *
925eap_sim_db_get_reauth(struct eap_sim_db_data *data, const u8 *identity,
926 size_t identity_len)
927{
928 char *reauth_id;
929 size_t len;
930 struct eap_sim_reauth *r;
931
932 if (identity_len == 0 ||
933 (identity[0] != EAP_SIM_REAUTH_ID_PREFIX &&
762e4ce6
JM
934 identity[0] != EAP_AKA_REAUTH_ID_PREFIX &&
935 identity[0] != EAP_AKA_PRIME_REAUTH_ID_PREFIX))
6fc6879b
JM
936 return NULL;
937
938 /* Remove possible realm from identity */
939 len = 0;
940 while (len < identity_len) {
941 if (identity[len] == '@')
942 break;
943 len++;
944 }
945
946 reauth_id = os_malloc(len + 1);
947 if (reauth_id == NULL)
948 return NULL;
949 os_memcpy(reauth_id, identity, len);
950 reauth_id[len] = '\0';
951
952 r = data->reauths;
953 while (r) {
954 if (os_strcmp(r->reauth_id, reauth_id) == 0)
955 break;
956 r = r->next;
957 }
958
959 os_free(reauth_id);
960
961 return r;
962}
963
964
965static struct eap_sim_reauth *
966eap_sim_db_get_reauth_id(struct eap_sim_db_data *data, const u8 *identity,
967 size_t identity_len)
968{
969 struct eap_sim_pseudonym *p;
970 struct eap_sim_reauth *r;
971
972 if (identity_len == 0)
973 return NULL;
974
975 p = eap_sim_db_get_pseudonym(data, identity, identity_len);
976 if (p == NULL)
977 p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
978 if (p) {
979 identity = p->identity;
980 identity_len = p->identity_len;
981 }
982
983 r = data->reauths;
984 while (r) {
985 if (identity_len == r->identity_len &&
986 os_memcmp(r->identity, identity, identity_len) == 0)
987 break;
988 r = r->next;
989 }
990
991 return r;
992}
993
994
995/**
996 * eap_sim_db_identity_known - Verify whether the given identity is known
997 * @priv: Private data pointer from eap_sim_db_init()
998 * @identity: User name identity
999 * @identity_len: Length of identity in bytes
1000 * Returns: 0 if the user is found or -1 on failure
1001 *
762e4ce6
JM
1002 * In most cases, the user name is ['0','1','6'] | IMSI, i.e., 1 followed by
1003 * the IMSI in ASCII format for EAP-SIM, ['2','3','7'] | pseudonym, or
1004 * ['4','5','7'] | reauth_id.
6fc6879b
JM
1005 */
1006int eap_sim_db_identity_known(void *priv, const u8 *identity,
1007 size_t identity_len)
1008{
1009 struct eap_sim_db_data *data = priv;
1010
1011 if (identity == NULL || identity_len < 2)
1012 return -1;
1013
1014 if (identity[0] == EAP_SIM_PSEUDONYM_PREFIX ||
762e4ce6
JM
1015 identity[0] == EAP_AKA_PSEUDONYM_PREFIX ||
1016 identity[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) {
6fc6879b
JM
1017 struct eap_sim_pseudonym *p =
1018 eap_sim_db_get_pseudonym(data, identity, identity_len);
1019 return p ? 0 : -1;
1020 }
1021
1022 if (identity[0] == EAP_SIM_REAUTH_ID_PREFIX ||
762e4ce6
JM
1023 identity[0] == EAP_AKA_REAUTH_ID_PREFIX ||
1024 identity[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX) {
6fc6879b
JM
1025 struct eap_sim_reauth *r =
1026 eap_sim_db_get_reauth(data, identity, identity_len);
1027 return r ? 0 : -1;
1028 }
1029
1030 if (identity[0] != EAP_SIM_PERMANENT_PREFIX &&
762e4ce6
JM
1031 identity[0] != EAP_AKA_PERMANENT_PREFIX &&
1032 identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) {
6fc6879b
JM
1033 /* Unknown identity prefix */
1034 return -1;
1035 }
1036
1037 /* TODO: Should consider asking HLR/AuC gateway whether this permanent
1038 * identity is known. If it is, EAP-SIM/AKA can skip identity request.
1039 * In case of EAP-AKA, this would reduce number of needed round-trips.
1040 * Ideally, this would be done with one wait, i.e., just request
1041 * authentication data and store it for the next use. This would then
1042 * need to use similar pending-request functionality as the normal
1043 * request for authentication data at later phase.
1044 */
1045 return -1;
1046}
1047
1048
1049static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix)
1050{
1051 char *id, *pos, *end;
1052 u8 buf[10];
1053
3642c431 1054 if (random_get_bytes(buf, sizeof(buf)))
6fc6879b
JM
1055 return NULL;
1056 id = os_malloc(sizeof(buf) * 2 + 2);
1057 if (id == NULL)
1058 return NULL;
1059
1060 pos = id;
1061 end = id + sizeof(buf) * 2 + 2;
1062 *pos++ = prefix;
1063 pos += wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf));
1064
1065 return id;
1066}
1067
1068
1069/**
1070 * eap_sim_db_get_next_pseudonym - EAP-SIM DB: Get next pseudonym
1071 * @priv: Private data pointer from eap_sim_db_init()
762e4ce6 1072 * @method: EAP method (SIM/AKA/AKA')
6fc6879b
JM
1073 * Returns: Next pseudonym (allocated string) or %NULL on failure
1074 *
1075 * This function is used to generate a pseudonym for EAP-SIM. The returned
1076 * pseudonym is not added to database at this point; it will need to be added
1077 * with eap_sim_db_add_pseudonym() once the authentication has been completed
1078 * successfully. Caller is responsible for freeing the returned buffer.
1079 */
762e4ce6 1080char * eap_sim_db_get_next_pseudonym(void *priv, enum eap_sim_db_method method)
6fc6879b
JM
1081{
1082 struct eap_sim_db_data *data = priv;
762e4ce6
JM
1083 char prefix = EAP_SIM_REAUTH_ID_PREFIX;
1084
1085 switch (method) {
1086 case EAP_SIM_DB_SIM:
1087 prefix = EAP_SIM_PSEUDONYM_PREFIX;
1088 break;
1089 case EAP_SIM_DB_AKA:
1090 prefix = EAP_AKA_PSEUDONYM_PREFIX;
1091 break;
1092 case EAP_SIM_DB_AKA_PRIME:
1093 prefix = EAP_AKA_PRIME_PSEUDONYM_PREFIX;
1094 break;
1095 }
1096
1097 return eap_sim_db_get_next(data, prefix);
6fc6879b
JM
1098}
1099
1100
1101/**
1102 * eap_sim_db_get_next_reauth_id - EAP-SIM DB: Get next reauth_id
1103 * @priv: Private data pointer from eap_sim_db_init()
762e4ce6 1104 * @method: EAP method (SIM/AKA/AKA')
6fc6879b
JM
1105 * Returns: Next reauth_id (allocated string) or %NULL on failure
1106 *
1107 * This function is used to generate a fast re-authentication identity for
1108 * EAP-SIM. The returned reauth_id is not added to database at this point; it
1109 * will need to be added with eap_sim_db_add_reauth() once the authentication
1110 * has been completed successfully. Caller is responsible for freeing the
1111 * returned buffer.
1112 */
762e4ce6 1113char * eap_sim_db_get_next_reauth_id(void *priv, enum eap_sim_db_method method)
6fc6879b
JM
1114{
1115 struct eap_sim_db_data *data = priv;
762e4ce6
JM
1116 char prefix = EAP_SIM_REAUTH_ID_PREFIX;
1117
1118 switch (method) {
1119 case EAP_SIM_DB_SIM:
1120 prefix = EAP_SIM_REAUTH_ID_PREFIX;
1121 break;
1122 case EAP_SIM_DB_AKA:
1123 prefix = EAP_AKA_REAUTH_ID_PREFIX;
1124 break;
1125 case EAP_SIM_DB_AKA_PRIME:
1126 prefix = EAP_AKA_PRIME_REAUTH_ID_PREFIX;
1127 break;
1128 }
1129
1130 return eap_sim_db_get_next(data, prefix);
6fc6879b
JM
1131}
1132
1133
1134/**
1135 * eap_sim_db_add_pseudonym - EAP-SIM DB: Add new pseudonym
1136 * @priv: Private data pointer from eap_sim_db_init()
1137 * @identity: Identity of the user (may be permanent identity or pseudonym)
1138 * @identity_len: Length of identity
1139 * @pseudonym: Pseudonym for this user. This needs to be an allocated buffer,
1140 * e.g., return value from eap_sim_db_get_next_pseudonym(). Caller must not
1141 * free it.
1142 * Returns: 0 on success, -1 on failure
1143 *
1144 * This function adds a new pseudonym for EAP-SIM user. EAP-SIM DB is
1145 * responsible of freeing pseudonym buffer once it is not needed anymore.
1146 */
1147int eap_sim_db_add_pseudonym(void *priv, const u8 *identity,
1148 size_t identity_len, char *pseudonym)
1149{
1150 struct eap_sim_db_data *data = priv;
1151 struct eap_sim_pseudonym *p;
1152 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add pseudonym for identity",
1153 identity, identity_len);
1154 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pseudonym: %s", pseudonym);
1155
1156 /* TODO: could store last two pseudonyms */
66979bb8
JM
1157#ifdef CONFIG_SQLITE
1158 if (data->sqlite_db)
1159 return db_add_pseudonym(data, identity, identity_len,
1160 pseudonym);
1161#endif /* CONFIG_SQLITE */
6fc6879b
JM
1162 p = eap_sim_db_get_pseudonym(data, identity, identity_len);
1163 if (p == NULL)
1164 p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
1165
1166 if (p) {
1167 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
1168 "pseudonym: %s", p->pseudonym);
1169 os_free(p->pseudonym);
1170 p->pseudonym = pseudonym;
1171 return 0;
1172 }
1173
1174 p = os_zalloc(sizeof(*p));
1175 if (p == NULL) {
1176 os_free(pseudonym);
1177 return -1;
1178 }
1179
1180 p->next = data->pseudonyms;
1181 p->identity = os_malloc(identity_len);
1182 if (p->identity == NULL) {
1183 os_free(p);
1184 os_free(pseudonym);
1185 return -1;
1186 }
1187 os_memcpy(p->identity, identity, identity_len);
1188 p->identity_len = identity_len;
1189 p->pseudonym = pseudonym;
1190 data->pseudonyms = p;
1191
1192 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new pseudonym entry");
1193 return 0;
1194}
1195
1196
9881795e
JM
1197static struct eap_sim_reauth *
1198eap_sim_db_add_reauth_data(struct eap_sim_db_data *data, const u8 *identity,
1199 size_t identity_len, char *reauth_id, u16 counter)
6fc6879b 1200{
6fc6879b 1201 struct eap_sim_reauth *r;
9881795e 1202
6fc6879b
JM
1203 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add reauth_id for identity",
1204 identity, identity_len);
1205 wpa_printf(MSG_DEBUG, "EAP-SIM DB: reauth_id: %s", reauth_id);
1206
1207 r = eap_sim_db_get_reauth(data, identity, identity_len);
1208 if (r == NULL)
1209 r = eap_sim_db_get_reauth_id(data, identity, identity_len);
1210
1211 if (r) {
1212 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
1213 "reauth_id: %s", r->reauth_id);
1214 os_free(r->reauth_id);
1215 r->reauth_id = reauth_id;
1216 } else {
1217 r = os_zalloc(sizeof(*r));
1218 if (r == NULL) {
1219 os_free(reauth_id);
9881795e 1220 return NULL;
6fc6879b
JM
1221 }
1222
1223 r->next = data->reauths;
1224 r->identity = os_malloc(identity_len);
1225 if (r->identity == NULL) {
1226 os_free(r);
1227 os_free(reauth_id);
9881795e 1228 return NULL;
6fc6879b
JM
1229 }
1230 os_memcpy(r->identity, identity, identity_len);
1231 r->identity_len = identity_len;
1232 r->reauth_id = reauth_id;
1233 data->reauths = r;
1234 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new reauth entry");
1235 }
1236
1237 r->counter = counter;
9881795e
JM
1238
1239 return r;
1240}
1241
1242
1243/**
1244 * eap_sim_db_add_reauth - EAP-SIM DB: Add new re-authentication entry
1245 * @priv: Private data pointer from eap_sim_db_init()
1246 * @identity: Identity of the user (may be permanent identity or pseudonym)
1247 * @identity_len: Length of identity
1248 * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
1249 * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
1250 * free it.
a17df5fb 1251 * @counter: AT_COUNTER value for fast re-authentication
9881795e
JM
1252 * @mk: 16-byte MK from the previous full authentication or %NULL
1253 * Returns: 0 on success, -1 on failure
1254 *
1255 * This function adds a new re-authentication entry for an EAP-SIM user.
1256 * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
1257 * anymore.
1258 */
1259int eap_sim_db_add_reauth(void *priv, const u8 *identity,
1260 size_t identity_len, char *reauth_id, u16 counter,
1261 const u8 *mk)
1262{
1263 struct eap_sim_db_data *data = priv;
1264 struct eap_sim_reauth *r;
1265
1266 r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id,
1267 counter);
1268 if (r == NULL)
1269 return -1;
1270
6fc6879b 1271 os_memcpy(r->mk, mk, EAP_SIM_MK_LEN);
9881795e
JM
1272 r->aka_prime = 0;
1273
1274 return 0;
1275}
1276
1277
1e5839e0 1278#ifdef EAP_SERVER_AKA_PRIME
9881795e
JM
1279/**
1280 * eap_sim_db_add_reauth_prime - EAP-AKA' DB: Add new re-authentication entry
1281 * @priv: Private data pointer from eap_sim_db_init()
1282 * @identity: Identity of the user (may be permanent identity or pseudonym)
1283 * @identity_len: Length of identity
1284 * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
1285 * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
1286 * free it.
a17df5fb
JM
1287 * @counter: AT_COUNTER value for fast re-authentication
1288 * @k_encr: K_encr from the previous full authentication
1289 * @k_aut: K_aut from the previous full authentication
1290 * @k_re: 32-byte K_re from the previous full authentication
9881795e
JM
1291 * Returns: 0 on success, -1 on failure
1292 *
1293 * This function adds a new re-authentication entry for an EAP-AKA' user.
1294 * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
1295 * anymore.
1296 */
1297int eap_sim_db_add_reauth_prime(void *priv, const u8 *identity,
1298 size_t identity_len, char *reauth_id,
1299 u16 counter, const u8 *k_encr, const u8 *k_aut,
1300 const u8 *k_re)
1301{
1302 struct eap_sim_db_data *data = priv;
1303 struct eap_sim_reauth *r;
1304
1305 r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id,
1306 counter);
1307 if (r == NULL)
1308 return -1;
1309
1310 r->aka_prime = 1;
1311 os_memcpy(r->k_encr, k_encr, EAP_SIM_K_ENCR_LEN);
1312 os_memcpy(r->k_aut, k_aut, EAP_AKA_PRIME_K_AUT_LEN);
1313 os_memcpy(r->k_re, k_re, EAP_AKA_PRIME_K_RE_LEN);
6fc6879b
JM
1314
1315 return 0;
1316}
1e5839e0 1317#endif /* EAP_SERVER_AKA_PRIME */
6fc6879b
JM
1318
1319
1320/**
1321 * eap_sim_db_get_permanent - EAP-SIM DB: Get permanent identity
1322 * @priv: Private data pointer from eap_sim_db_init()
1323 * @identity: Identity of the user (may be permanent identity or pseudonym)
1324 * @identity_len: Length of identity
1325 * @len: Buffer for length of the returned permanent identity
1326 * Returns: Pointer to the permanent identity, or %NULL if not found
1327 */
1328const u8 * eap_sim_db_get_permanent(void *priv, const u8 *identity,
1329 size_t identity_len, size_t *len)
1330{
1331 struct eap_sim_db_data *data = priv;
1332 struct eap_sim_pseudonym *p;
1333
1334 if (identity == NULL)
1335 return NULL;
1336
1337 p = eap_sim_db_get_pseudonym(data, identity, identity_len);
1338 if (p == NULL)
1339 p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
1340 if (p == NULL)
1341 return NULL;
1342
1343 *len = p->identity_len;
1344 return p->identity;
1345}
1346
1347
1348/**
1349 * eap_sim_db_get_reauth_entry - EAP-SIM DB: Get re-authentication entry
1350 * @priv: Private data pointer from eap_sim_db_init()
1351 * @identity: Identity of the user (may be permanent identity, pseudonym, or
1352 * reauth_id)
1353 * @identity_len: Length of identity
6fc6879b
JM
1354 * Returns: Pointer to the re-auth entry, or %NULL if not found
1355 */
1356struct eap_sim_reauth *
1357eap_sim_db_get_reauth_entry(void *priv, const u8 *identity,
1358 size_t identity_len)
1359{
1360 struct eap_sim_db_data *data = priv;
1361 struct eap_sim_reauth *r;
1362
1363 if (identity == NULL)
1364 return NULL;
1365 r = eap_sim_db_get_reauth(data, identity, identity_len);
1366 if (r == NULL)
1367 r = eap_sim_db_get_reauth_id(data, identity, identity_len);
1368 return r;
1369}
1370
1371
1372/**
1373 * eap_sim_db_remove_reauth - EAP-SIM DB: Remove re-authentication entry
1374 * @priv: Private data pointer from eap_sim_db_init()
1375 * @reauth: Pointer to re-authentication entry from
1376 * eap_sim_db_get_reauth_entry()
1377 */
1378void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth)
1379{
1380 struct eap_sim_db_data *data = priv;
1381 struct eap_sim_reauth *r, *prev = NULL;
1382 r = data->reauths;
1383 while (r) {
1384 if (r == reauth) {
1385 if (prev)
1386 prev->next = r->next;
1387 else
1388 data->reauths = r->next;
1389 eap_sim_db_free_reauth(r);
1390 return;
1391 }
1392 prev = r;
1393 r = r->next;
1394 }
1395}
1396
1397
1398/**
1399 * eap_sim_db_get_aka_auth - Get AKA authentication values
1400 * @priv: Private data pointer from eap_sim_db_init()
1401 * @identity: User name identity
1402 * @identity_len: Length of identity in bytes
1403 * @_rand: Buffer for RAND value
1404 * @autn: Buffer for AUTN value
1405 * @ik: Buffer for IK value
1406 * @ck: Buffer for CK value
1407 * @res: Buffer for RES value
1408 * @res_len: Buffer for RES length
1409 * @cb_session_ctx: Session callback context for get_complete_cb()
1410 * Returns: 0 on success, -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not
1411 * found), or -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this
1412 * case, the callback function registered with eap_sim_db_init() will be
1413 * called once the results become available.
1414 *
1415 * In most cases, the user name is '0' | IMSI, i.e., 0 followed by the IMSI in
762e4ce6 1416 * ASCII format for EAP-AKA and '6' | IMSI for EAP-AKA'.
6fc6879b
JM
1417 *
1418 * When using an external server for AKA authentication, this function can
1419 * always start a request and return EAP_SIM_DB_PENDING immediately if
1420 * authentication triplets are not available. Once the authentication data are
1421 * received, callback function registered with eap_sim_db_init() is called to
1422 * notify EAP state machine to reprocess the message. This
1423 * eap_sim_db_get_aka_auth() function will then be called again and the newly
1424 * received triplets will then be given to the caller.
1425 */
1426int eap_sim_db_get_aka_auth(void *priv, const u8 *identity,
1427 size_t identity_len, u8 *_rand, u8 *autn, u8 *ik,
1428 u8 *ck, u8 *res, size_t *res_len,
1429 void *cb_session_ctx)
1430{
1431 struct eap_sim_db_data *data = priv;
1432 struct eap_sim_db_pending *entry;
1433 int len;
1434 size_t i;
1435 char msg[40];
1436
1437 if (identity_len < 2 || identity == NULL ||
762e4ce6
JM
1438 (identity[0] != EAP_AKA_PERMANENT_PREFIX &&
1439 identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX)) {
6fc6879b
JM
1440 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
1441 identity, identity_len);
1442 return EAP_SIM_DB_FAILURE;
1443 }
1444 identity++;
1445 identity_len--;
1446 for (i = 0; i < identity_len; i++) {
1447 if (identity[i] == '@') {
1448 identity_len = i;
1449 break;
1450 }
1451 }
1452 if (identity_len + 1 > sizeof(entry->imsi)) {
1453 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
1454 identity, identity_len);
1455 return EAP_SIM_DB_FAILURE;
1456 }
1457 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI",
1458 identity, identity_len);
1459
1460 entry = eap_sim_db_get_pending(data, identity, identity_len, 1);
1461 if (entry) {
1462 if (entry->state == FAILURE) {
1463 os_free(entry);
1464 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failure");
1465 return EAP_SIM_DB_FAILURE;
1466 }
1467
1468 if (entry->state == PENDING) {
1469 eap_sim_db_add_pending(data, entry);
1470 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending");
1471 return EAP_SIM_DB_PENDING;
1472 }
1473
1474 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Returning successfully "
1475 "received authentication data");
1476 os_memcpy(_rand, entry->u.aka.rand, EAP_AKA_RAND_LEN);
1477 os_memcpy(autn, entry->u.aka.autn, EAP_AKA_AUTN_LEN);
1478 os_memcpy(ik, entry->u.aka.ik, EAP_AKA_IK_LEN);
1479 os_memcpy(ck, entry->u.aka.ck, EAP_AKA_CK_LEN);
1480 os_memcpy(res, entry->u.aka.res, EAP_AKA_RES_MAX_LEN);
1481 *res_len = entry->u.aka.res_len;
1482 os_free(entry);
1483 return 0;
1484 }
1485
1486 if (data->sock < 0) {
1487 if (eap_sim_db_open_socket(data) < 0)
1488 return EAP_SIM_DB_FAILURE;
1489 }
1490
1491 len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH ");
1492 if (len < 0 || len + identity_len >= sizeof(msg))
1493 return EAP_SIM_DB_FAILURE;
1494 os_memcpy(msg + len, identity, identity_len);
1495 len += identity_len;
1496
1497 wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication "
1498 "data for IMSI", identity, identity_len);
1499 if (eap_sim_db_send(data, msg, len) < 0)
1500 return EAP_SIM_DB_FAILURE;
1501
1502 entry = os_zalloc(sizeof(*entry));
1503 if (entry == NULL)
1504 return EAP_SIM_DB_FAILURE;
1505
1506 os_get_time(&entry->timestamp);
1507 entry->aka = 1;
1508 os_memcpy(entry->imsi, identity, identity_len);
1509 entry->imsi_len = identity_len;
1510 entry->cb_session_ctx = cb_session_ctx;
1511 entry->state = PENDING;
1512 eap_sim_db_add_pending(data, entry);
1513 eap_sim_db_expire_pending(data);
1514
1515 return EAP_SIM_DB_PENDING;
1516}
1517
1518
1519/**
1520 * eap_sim_db_resynchronize - Resynchronize AKA AUTN
1521 * @priv: Private data pointer from eap_sim_db_init()
1522 * @identity: User name identity
1523 * @identity_len: Length of identity in bytes
1524 * @auts: AUTS value from the peer
1525 * @_rand: RAND value used in the rejected message
1526 * Returns: 0 on success, -1 on failure
1527 *
1528 * This function is called when the peer reports synchronization failure in the
1529 * AUTN value by sending AUTS. The AUTS and RAND values should be sent to
1530 * HLR/AuC to allow it to resynchronize with the peer. After this,
1531 * eap_sim_db_get_aka_auth() will be called again to to fetch updated
1532 * RAND/AUTN values for the next challenge.
1533 */
1534int eap_sim_db_resynchronize(void *priv, const u8 *identity,
1535 size_t identity_len, const u8 *auts,
1536 const u8 *_rand)
1537{
1538 struct eap_sim_db_data *data = priv;
1539 size_t i;
1540
1541 if (identity_len < 2 || identity == NULL ||
762e4ce6
JM
1542 (identity[0] != EAP_AKA_PERMANENT_PREFIX &&
1543 identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX)) {
6fc6879b
JM
1544 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
1545 identity, identity_len);
1546 return -1;
1547 }
1548 identity++;
1549 identity_len--;
1550 for (i = 0; i < identity_len; i++) {
1551 if (identity[i] == '@') {
1552 identity_len = i;
1553 break;
1554 }
1555 }
1556 if (identity_len > 20) {
1557 wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
1558 identity, identity_len);
1559 return -1;
1560 }
1561
1562 if (data->sock >= 0) {
1563 char msg[100];
1564 int len, ret;
1565
1566 len = os_snprintf(msg, sizeof(msg), "AKA-AUTS ");
1567 if (len < 0 || len + identity_len >= sizeof(msg))
1568 return -1;
1569 os_memcpy(msg + len, identity, identity_len);
1570 len += identity_len;
1571
1572 ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
1573 if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
1574 return -1;
1575 len += ret;
1576 len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
1577 auts, EAP_AKA_AUTS_LEN);
1578 ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
1579 if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
1580 return -1;
1581 len += ret;
1582 len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
1583 _rand, EAP_AKA_RAND_LEN);
1584 wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for "
1585 "IMSI", identity, identity_len);
1586 if (eap_sim_db_send(data, msg, len) < 0)
1587 return -1;
1588 }
1589
1590 return 0;
1591}