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