eap_sim_db.c revision fb79edc9df1f20461e90e478363d207348213d35
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), 0);
577	if (res < 0)
578		return;
579	wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-SIM DB: Received from an "
580			      "external source", (u8 *) buf, res);
581	if (res == 0)
582		return;
583	if (res >= (int) sizeof(buf))
584		res = sizeof(buf) - 1;
585	buf[res] = '\0';
586
587	if (data->get_complete_cb == NULL) {
588		wpa_printf(MSG_DEBUG, "EAP-SIM DB: No get_complete_cb "
589			   "registered");
590		return;
591	}
592
593	/* <cmd> <IMSI> ... */
594
595	cmd = buf;
596	pos = os_strchr(cmd, ' ');
597	if (pos == NULL)
598		goto parse_fail;
599	*pos = '\0';
600	imsi = pos + 1;
601	pos = os_strchr(imsi, ' ');
602	if (pos == NULL)
603		goto parse_fail;
604	*pos = '\0';
605	wpa_printf(MSG_DEBUG, "EAP-SIM DB: External response=%s for IMSI %s",
606		   cmd, imsi);
607
608	if (os_strcmp(cmd, "SIM-RESP-AUTH") == 0)
609		eap_sim_db_sim_resp_auth(data, imsi, pos + 1);
610	else if (os_strcmp(cmd, "AKA-RESP-AUTH") == 0)
611		eap_sim_db_aka_resp_auth(data, imsi, pos + 1);
612	else
613		wpa_printf(MSG_INFO, "EAP-SIM DB: Unknown external response "
614			   "'%s'", cmd);
615	return;
616
617parse_fail:
618	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
619}
620
621
622static int eap_sim_db_open_socket(struct eap_sim_db_data *data)
623{
624	struct sockaddr_un addr;
625	static int counter = 0;
626
627	if (os_strncmp(data->fname, "unix:", 5) != 0)
628		return -1;
629
630	data->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
631	if (data->sock < 0) {
632		wpa_printf(MSG_INFO, "socket(eap_sim_db): %s", strerror(errno));
633		return -1;
634	}
635
636	os_memset(&addr, 0, sizeof(addr));
637	addr.sun_family = AF_UNIX;
638	os_snprintf(addr.sun_path, sizeof(addr.sun_path),
639		    "/tmp/eap_sim_db_%d-%d", getpid(), counter++);
640	os_free(data->local_sock);
641	data->local_sock = os_strdup(addr.sun_path);
642	if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
643		wpa_printf(MSG_INFO, "bind(eap_sim_db): %s", strerror(errno));
644		close(data->sock);
645		data->sock = -1;
646		return -1;
647	}
648
649	os_memset(&addr, 0, sizeof(addr));
650	addr.sun_family = AF_UNIX;
651	os_strlcpy(addr.sun_path, data->fname + 5, sizeof(addr.sun_path));
652	if (connect(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
653		wpa_printf(MSG_INFO, "connect(eap_sim_db): %s",
654			   strerror(errno));
655		wpa_hexdump_ascii(MSG_INFO, "HLR/AuC GW socket",
656				  (u8 *) addr.sun_path,
657				  os_strlen(addr.sun_path));
658		close(data->sock);
659		data->sock = -1;
660		return -1;
661	}
662
663	eloop_register_read_sock(data->sock, eap_sim_db_receive, data, NULL);
664
665	return 0;
666}
667
668
669static void eap_sim_db_close_socket(struct eap_sim_db_data *data)
670{
671	if (data->sock >= 0) {
672		eloop_unregister_read_sock(data->sock);
673		close(data->sock);
674		data->sock = -1;
675	}
676	if (data->local_sock) {
677		unlink(data->local_sock);
678		os_free(data->local_sock);
679		data->local_sock = NULL;
680	}
681}
682
683
684/**
685 * eap_sim_db_init - Initialize EAP-SIM DB / authentication gateway interface
686 * @config: Configuration data (e.g., file name)
687 * @get_complete_cb: Callback function for reporting availability of triplets
688 * @ctx: Context pointer for get_complete_cb
689 * Returns: Pointer to a private data structure or %NULL on failure
690 */
691struct eap_sim_db_data *
692eap_sim_db_init(const char *config,
693		void (*get_complete_cb)(void *ctx, void *session_ctx),
694		void *ctx)
695{
696	struct eap_sim_db_data *data;
697	char *pos;
698
699	data = os_zalloc(sizeof(*data));
700	if (data == NULL)
701		return NULL;
702
703	data->sock = -1;
704	data->get_complete_cb = get_complete_cb;
705	data->ctx = ctx;
706	data->fname = os_strdup(config);
707	if (data->fname == NULL)
708		goto fail;
709	pos = os_strstr(data->fname, " db=");
710	if (pos) {
711		*pos = '\0';
712#ifdef CONFIG_SQLITE
713		pos += 4;
714		data->sqlite_db = db_open(pos);
715		if (data->sqlite_db == NULL)
716			goto fail;
717#endif /* CONFIG_SQLITE */
718	}
719
720	if (os_strncmp(data->fname, "unix:", 5) == 0) {
721		if (eap_sim_db_open_socket(data)) {
722			wpa_printf(MSG_DEBUG, "EAP-SIM DB: External database "
723				   "connection not available - will retry "
724				   "later");
725		}
726	}
727
728	return data;
729
730fail:
731	eap_sim_db_close_socket(data);
732	os_free(data->fname);
733	os_free(data);
734	return NULL;
735}
736
737
738static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p)
739{
740	os_free(p->permanent);
741	os_free(p->pseudonym);
742	os_free(p);
743}
744
745
746static void eap_sim_db_free_reauth(struct eap_sim_reauth *r)
747{
748	os_free(r->permanent);
749	os_free(r->reauth_id);
750	os_free(r);
751}
752
753
754/**
755 * eap_sim_db_deinit - Deinitialize EAP-SIM DB/authentication gw interface
756 * @priv: Private data pointer from eap_sim_db_init()
757 */
758void eap_sim_db_deinit(void *priv)
759{
760	struct eap_sim_db_data *data = priv;
761	struct eap_sim_pseudonym *p, *prev;
762	struct eap_sim_reauth *r, *prevr;
763	struct eap_sim_db_pending *pending, *prev_pending;
764
765#ifdef CONFIG_SQLITE
766	if (data->sqlite_db) {
767		sqlite3_close(data->sqlite_db);
768		data->sqlite_db = NULL;
769	}
770#endif /* CONFIG_SQLITE */
771
772	eap_sim_db_close_socket(data);
773	os_free(data->fname);
774
775	p = data->pseudonyms;
776	while (p) {
777		prev = p;
778		p = p->next;
779		eap_sim_db_free_pseudonym(prev);
780	}
781
782	r = data->reauths;
783	while (r) {
784		prevr = r;
785		r = r->next;
786		eap_sim_db_free_reauth(prevr);
787	}
788
789	pending = data->pending;
790	while (pending) {
791		prev_pending = pending;
792		pending = pending->next;
793		os_free(prev_pending);
794	}
795
796	os_free(data);
797}
798
799
800static int eap_sim_db_send(struct eap_sim_db_data *data, const char *msg,
801			   size_t len)
802{
803	int _errno = 0;
804
805	if (send(data->sock, msg, len, 0) < 0) {
806		_errno = errno;
807		wpa_printf(MSG_INFO, "send[EAP-SIM DB UNIX]: %s",
808			   strerror(errno));
809	}
810
811	if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
812	    _errno == ECONNREFUSED) {
813		/* Try to reconnect */
814		eap_sim_db_close_socket(data);
815		if (eap_sim_db_open_socket(data) < 0)
816			return -1;
817		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Reconnected to the "
818			   "external server");
819		if (send(data->sock, msg, len, 0) < 0) {
820			wpa_printf(MSG_INFO, "send[EAP-SIM DB UNIX]: %s",
821				   strerror(errno));
822			return -1;
823		}
824	}
825
826	return 0;
827}
828
829
830static void eap_sim_db_expire_pending(struct eap_sim_db_data *data)
831{
832	/* TODO: add limit for maximum length for pending list; remove latest
833	 * (i.e., last) entry from the list if the limit is reached; could also
834	 * use timeout to expire pending entries */
835}
836
837
838/**
839 * eap_sim_db_get_gsm_triplets - Get GSM triplets
840 * @data: Private data pointer from eap_sim_db_init()
841 * @username: Permanent username (prefix | IMSI)
842 * @max_chal: Maximum number of triplets
843 * @_rand: Buffer for RAND values
844 * @kc: Buffer for Kc values
845 * @sres: Buffer for SRES values
846 * @cb_session_ctx: Session callback context for get_complete_cb()
847 * Returns: Number of triplets received (has to be less than or equal to
848 * max_chal), -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not found), or
849 * -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this case, the
850 * callback function registered with eap_sim_db_init() will be called once the
851 * results become available.
852 *
853 * When using an external server for GSM triplets, this function can always
854 * start a request and return EAP_SIM_DB_PENDING immediately if authentication
855 * triplets are not available. Once the triplets are received, callback
856 * function registered with eap_sim_db_init() is called to notify EAP state
857 * machine to reprocess the message. This eap_sim_db_get_gsm_triplets()
858 * function will then be called again and the newly received triplets will then
859 * be given to the caller.
860 */
861int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data,
862				const char *username, int max_chal,
863				u8 *_rand, u8 *kc, u8 *sres,
864				void *cb_session_ctx)
865{
866	struct eap_sim_db_pending *entry;
867	int len, ret;
868	char msg[40];
869	const char *imsi;
870	size_t imsi_len;
871
872	if (username == NULL || username[0] != EAP_SIM_PERMANENT_PREFIX ||
873	    username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) {
874		wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
875			   username);
876		return EAP_SIM_DB_FAILURE;
877	}
878	imsi = username + 1;
879	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI '%s'",
880		   imsi);
881
882	entry = eap_sim_db_get_pending(data, imsi, 0);
883	if (entry) {
884		int num_chal;
885		if (entry->state == FAILURE) {
886			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
887				   "failure");
888			os_free(entry);
889			return EAP_SIM_DB_FAILURE;
890		}
891
892		if (entry->state == PENDING) {
893			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
894				   "still pending");
895			eap_sim_db_add_pending(data, entry);
896			return EAP_SIM_DB_PENDING;
897		}
898
899		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
900			   "%d challenges", entry->u.sim.num_chal);
901		num_chal = entry->u.sim.num_chal;
902		if (num_chal > max_chal)
903			num_chal = max_chal;
904		os_memcpy(_rand, entry->u.sim.rand, num_chal * GSM_RAND_LEN);
905		os_memcpy(sres, entry->u.sim.sres,
906			  num_chal * EAP_SIM_SRES_LEN);
907		os_memcpy(kc, entry->u.sim.kc, num_chal * EAP_SIM_KC_LEN);
908		os_free(entry);
909		return num_chal;
910	}
911
912	if (data->sock < 0) {
913		if (eap_sim_db_open_socket(data) < 0)
914			return EAP_SIM_DB_FAILURE;
915	}
916
917	imsi_len = os_strlen(imsi);
918	len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH ");
919	if (len < 0 || len + imsi_len >= sizeof(msg))
920		return EAP_SIM_DB_FAILURE;
921	os_memcpy(msg + len, imsi, imsi_len);
922	len += imsi_len;
923	ret = os_snprintf(msg + len, sizeof(msg) - len, " %d", max_chal);
924	if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
925		return EAP_SIM_DB_FAILURE;
926	len += ret;
927
928	wpa_printf(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication "
929		   "data for IMSI '%s'", imsi);
930	if (eap_sim_db_send(data, msg, len) < 0)
931		return EAP_SIM_DB_FAILURE;
932
933	entry = os_zalloc(sizeof(*entry));
934	if (entry == NULL)
935		return EAP_SIM_DB_FAILURE;
936
937	os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi));
938	entry->cb_session_ctx = cb_session_ctx;
939	entry->state = PENDING;
940	eap_sim_db_add_pending(data, entry);
941	eap_sim_db_expire_pending(data);
942
943	return EAP_SIM_DB_PENDING;
944}
945
946
947static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix)
948{
949	char *id, *pos, *end;
950	u8 buf[10];
951
952	if (random_get_bytes(buf, sizeof(buf)))
953		return NULL;
954	id = os_malloc(sizeof(buf) * 2 + 2);
955	if (id == NULL)
956		return NULL;
957
958	pos = id;
959	end = id + sizeof(buf) * 2 + 2;
960	*pos++ = prefix;
961	pos += wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf));
962
963	return id;
964}
965
966
967/**
968 * eap_sim_db_get_next_pseudonym - EAP-SIM DB: Get next pseudonym
969 * @data: Private data pointer from eap_sim_db_init()
970 * @method: EAP method (SIM/AKA/AKA')
971 * Returns: Next pseudonym (allocated string) or %NULL on failure
972 *
973 * This function is used to generate a pseudonym for EAP-SIM. The returned
974 * pseudonym is not added to database at this point; it will need to be added
975 * with eap_sim_db_add_pseudonym() once the authentication has been completed
976 * successfully. Caller is responsible for freeing the returned buffer.
977 */
978char * eap_sim_db_get_next_pseudonym(struct eap_sim_db_data *data,
979				     enum eap_sim_db_method method)
980{
981	char prefix = EAP_SIM_REAUTH_ID_PREFIX;
982
983	switch (method) {
984	case EAP_SIM_DB_SIM:
985		prefix = EAP_SIM_PSEUDONYM_PREFIX;
986		break;
987	case EAP_SIM_DB_AKA:
988		prefix = EAP_AKA_PSEUDONYM_PREFIX;
989		break;
990	case EAP_SIM_DB_AKA_PRIME:
991		prefix = EAP_AKA_PRIME_PSEUDONYM_PREFIX;
992		break;
993	}
994
995	return eap_sim_db_get_next(data, prefix);
996}
997
998
999/**
1000 * eap_sim_db_get_next_reauth_id - EAP-SIM DB: Get next reauth_id
1001 * @data: Private data pointer from eap_sim_db_init()
1002 * @method: EAP method (SIM/AKA/AKA')
1003 * Returns: Next reauth_id (allocated string) or %NULL on failure
1004 *
1005 * This function is used to generate a fast re-authentication identity for
1006 * EAP-SIM. The returned reauth_id is not added to database at this point; it
1007 * will need to be added with eap_sim_db_add_reauth() once the authentication
1008 * has been completed successfully. Caller is responsible for freeing the
1009 * returned buffer.
1010 */
1011char * eap_sim_db_get_next_reauth_id(struct eap_sim_db_data *data,
1012				     enum eap_sim_db_method method)
1013{
1014	char prefix = EAP_SIM_REAUTH_ID_PREFIX;
1015
1016	switch (method) {
1017	case EAP_SIM_DB_SIM:
1018		prefix = EAP_SIM_REAUTH_ID_PREFIX;
1019		break;
1020	case EAP_SIM_DB_AKA:
1021		prefix = EAP_AKA_REAUTH_ID_PREFIX;
1022		break;
1023	case EAP_SIM_DB_AKA_PRIME:
1024		prefix = EAP_AKA_PRIME_REAUTH_ID_PREFIX;
1025		break;
1026	}
1027
1028	return eap_sim_db_get_next(data, prefix);
1029}
1030
1031
1032/**
1033 * eap_sim_db_add_pseudonym - EAP-SIM DB: Add new pseudonym
1034 * @data: Private data pointer from eap_sim_db_init()
1035 * @permanent: Permanent username
1036 * @pseudonym: Pseudonym for this user. This needs to be an allocated buffer,
1037 * e.g., return value from eap_sim_db_get_next_pseudonym(). Caller must not
1038 * free it.
1039 * Returns: 0 on success, -1 on failure
1040 *
1041 * This function adds a new pseudonym for EAP-SIM user. EAP-SIM DB is
1042 * responsible of freeing pseudonym buffer once it is not needed anymore.
1043 */
1044int eap_sim_db_add_pseudonym(struct eap_sim_db_data *data,
1045			     const char *permanent, char *pseudonym)
1046{
1047	struct eap_sim_pseudonym *p;
1048	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add pseudonym '%s' for permanent "
1049		   "username '%s'", pseudonym, permanent);
1050
1051	/* TODO: could store last two pseudonyms */
1052#ifdef CONFIG_SQLITE
1053	if (data->sqlite_db)
1054		return db_add_pseudonym(data, permanent, pseudonym);
1055#endif /* CONFIG_SQLITE */
1056	for (p = data->pseudonyms; p; p = p->next) {
1057		if (os_strcmp(permanent, p->permanent) == 0)
1058			break;
1059	}
1060	if (p) {
1061		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
1062			   "pseudonym: %s", p->pseudonym);
1063		os_free(p->pseudonym);
1064		p->pseudonym = pseudonym;
1065		return 0;
1066	}
1067
1068	p = os_zalloc(sizeof(*p));
1069	if (p == NULL) {
1070		os_free(pseudonym);
1071		return -1;
1072	}
1073
1074	p->next = data->pseudonyms;
1075	p->permanent = os_strdup(permanent);
1076	if (p->permanent == NULL) {
1077		os_free(p);
1078		os_free(pseudonym);
1079		return -1;
1080	}
1081	p->pseudonym = pseudonym;
1082	data->pseudonyms = p;
1083
1084	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new pseudonym entry");
1085	return 0;
1086}
1087
1088
1089static struct eap_sim_reauth *
1090eap_sim_db_add_reauth_data(struct eap_sim_db_data *data,
1091			   const char *permanent,
1092			   char *reauth_id, u16 counter)
1093{
1094	struct eap_sim_reauth *r;
1095
1096	for (r = data->reauths; r; r = r->next) {
1097		if (os_strcmp(r->permanent, permanent) == 0)
1098			break;
1099	}
1100
1101	if (r) {
1102		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
1103			   "reauth_id: %s", r->reauth_id);
1104		os_free(r->reauth_id);
1105		r->reauth_id = reauth_id;
1106	} else {
1107		r = os_zalloc(sizeof(*r));
1108		if (r == NULL) {
1109			os_free(reauth_id);
1110			return NULL;
1111		}
1112
1113		r->next = data->reauths;
1114		r->permanent = os_strdup(permanent);
1115		if (r->permanent == NULL) {
1116			os_free(r);
1117			os_free(reauth_id);
1118			return NULL;
1119		}
1120		r->reauth_id = reauth_id;
1121		data->reauths = r;
1122		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new reauth entry");
1123	}
1124
1125	r->counter = counter;
1126
1127	return r;
1128}
1129
1130
1131/**
1132 * eap_sim_db_add_reauth - EAP-SIM DB: Add new re-authentication entry
1133 * @priv: Private data pointer from eap_sim_db_init()
1134 * @permanent: Permanent username
1135 * @identity_len: Length of identity
1136 * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
1137 * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
1138 * free it.
1139 * @counter: AT_COUNTER value for fast re-authentication
1140 * @mk: 16-byte MK from the previous full authentication or %NULL
1141 * Returns: 0 on success, -1 on failure
1142 *
1143 * This function adds a new re-authentication entry for an EAP-SIM user.
1144 * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
1145 * anymore.
1146 */
1147int eap_sim_db_add_reauth(struct eap_sim_db_data *data, const char *permanent,
1148			  char *reauth_id, u16 counter, const u8 *mk)
1149{
1150	struct eap_sim_reauth *r;
1151
1152	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add reauth_id '%s' for permanent "
1153		   "identity '%s'", reauth_id, permanent);
1154
1155#ifdef CONFIG_SQLITE
1156	if (data->sqlite_db)
1157		return db_add_reauth(data, permanent, reauth_id, counter, mk,
1158				     NULL, NULL, NULL);
1159#endif /* CONFIG_SQLITE */
1160	r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter);
1161	if (r == NULL)
1162		return -1;
1163
1164	os_memcpy(r->mk, mk, EAP_SIM_MK_LEN);
1165
1166	return 0;
1167}
1168
1169
1170#ifdef EAP_SERVER_AKA_PRIME
1171/**
1172 * eap_sim_db_add_reauth_prime - EAP-AKA' DB: Add new re-authentication entry
1173 * @data: Private data pointer from eap_sim_db_init()
1174 * @permanent: Permanent username
1175 * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
1176 * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
1177 * free it.
1178 * @counter: AT_COUNTER value for fast re-authentication
1179 * @k_encr: K_encr from the previous full authentication
1180 * @k_aut: K_aut from the previous full authentication
1181 * @k_re: 32-byte K_re from the previous full authentication
1182 * Returns: 0 on success, -1 on failure
1183 *
1184 * This function adds a new re-authentication entry for an EAP-AKA' user.
1185 * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
1186 * anymore.
1187 */
1188int eap_sim_db_add_reauth_prime(struct eap_sim_db_data *data,
1189				const char *permanent, char *reauth_id,
1190				u16 counter, const u8 *k_encr,
1191				const u8 *k_aut, const u8 *k_re)
1192{
1193	struct eap_sim_reauth *r;
1194
1195	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add reauth_id '%s' for permanent "
1196		   "identity '%s'", reauth_id, permanent);
1197
1198#ifdef CONFIG_SQLITE
1199	if (data->sqlite_db)
1200		return db_add_reauth(data, permanent, reauth_id, counter, NULL,
1201				     k_encr, k_aut, k_re);
1202#endif /* CONFIG_SQLITE */
1203	r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter);
1204	if (r == NULL)
1205		return -1;
1206
1207	os_memcpy(r->k_encr, k_encr, EAP_SIM_K_ENCR_LEN);
1208	os_memcpy(r->k_aut, k_aut, EAP_AKA_PRIME_K_AUT_LEN);
1209	os_memcpy(r->k_re, k_re, EAP_AKA_PRIME_K_RE_LEN);
1210
1211	return 0;
1212}
1213#endif /* EAP_SERVER_AKA_PRIME */
1214
1215
1216/**
1217 * eap_sim_db_get_permanent - EAP-SIM DB: Get permanent identity
1218 * @data: Private data pointer from eap_sim_db_init()
1219 * @pseudonym: Pseudonym username
1220 * Returns: Pointer to permanent username or %NULL if not found
1221 */
1222const char *
1223eap_sim_db_get_permanent(struct eap_sim_db_data *data, const char *pseudonym)
1224{
1225	struct eap_sim_pseudonym *p;
1226
1227#ifdef CONFIG_SQLITE
1228	if (data->sqlite_db)
1229		return db_get_pseudonym(data, pseudonym);
1230#endif /* CONFIG_SQLITE */
1231
1232	p = data->pseudonyms;
1233	while (p) {
1234		if (os_strcmp(p->pseudonym, pseudonym) == 0)
1235			return p->permanent;
1236		p = p->next;
1237	}
1238
1239	return NULL;
1240}
1241
1242
1243/**
1244 * eap_sim_db_get_reauth_entry - EAP-SIM DB: Get re-authentication entry
1245 * @data: Private data pointer from eap_sim_db_init()
1246 * @reauth_id: Fast re-authentication username
1247 * Returns: Pointer to the re-auth entry, or %NULL if not found
1248 */
1249struct eap_sim_reauth *
1250eap_sim_db_get_reauth_entry(struct eap_sim_db_data *data,
1251			    const char *reauth_id)
1252{
1253	struct eap_sim_reauth *r;
1254
1255#ifdef CONFIG_SQLITE
1256	if (data->sqlite_db)
1257		return db_get_reauth(data, reauth_id);
1258#endif /* CONFIG_SQLITE */
1259
1260	r = data->reauths;
1261	while (r) {
1262		if (os_strcmp(r->reauth_id, reauth_id) == 0)
1263			break;
1264		r = r->next;
1265	}
1266
1267	return r;
1268}
1269
1270
1271/**
1272 * eap_sim_db_remove_reauth - EAP-SIM DB: Remove re-authentication entry
1273 * @data: Private data pointer from eap_sim_db_init()
1274 * @reauth: Pointer to re-authentication entry from
1275 * eap_sim_db_get_reauth_entry()
1276 */
1277void eap_sim_db_remove_reauth(struct eap_sim_db_data *data,
1278			      struct eap_sim_reauth *reauth)
1279{
1280	struct eap_sim_reauth *r, *prev = NULL;
1281#ifdef CONFIG_SQLITE
1282	if (data->sqlite_db) {
1283		db_remove_reauth(data, reauth);
1284		return;
1285	}
1286#endif /* CONFIG_SQLITE */
1287	r = data->reauths;
1288	while (r) {
1289		if (r == reauth) {
1290			if (prev)
1291				prev->next = r->next;
1292			else
1293				data->reauths = r->next;
1294			eap_sim_db_free_reauth(r);
1295			return;
1296		}
1297		prev = r;
1298		r = r->next;
1299	}
1300}
1301
1302
1303/**
1304 * eap_sim_db_get_aka_auth - Get AKA authentication values
1305 * @data: Private data pointer from eap_sim_db_init()
1306 * @username: Permanent username (prefix | IMSI)
1307 * @_rand: Buffer for RAND value
1308 * @autn: Buffer for AUTN value
1309 * @ik: Buffer for IK value
1310 * @ck: Buffer for CK value
1311 * @res: Buffer for RES value
1312 * @res_len: Buffer for RES length
1313 * @cb_session_ctx: Session callback context for get_complete_cb()
1314 * Returns: 0 on success, -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not
1315 * found), or -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this
1316 * case, the callback function registered with eap_sim_db_init() will be
1317 * called once the results become available.
1318 *
1319 * When using an external server for AKA authentication, this function can
1320 * always start a request and return EAP_SIM_DB_PENDING immediately if
1321 * authentication triplets are not available. Once the authentication data are
1322 * received, callback function registered with eap_sim_db_init() is called to
1323 * notify EAP state machine to reprocess the message. This
1324 * eap_sim_db_get_aka_auth() function will then be called again and the newly
1325 * received triplets will then be given to the caller.
1326 */
1327int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username,
1328			    u8 *_rand, u8 *autn, u8 *ik, u8 *ck,
1329			    u8 *res, size_t *res_len, void *cb_session_ctx)
1330{
1331	struct eap_sim_db_pending *entry;
1332	int len;
1333	char msg[40];
1334	const char *imsi;
1335	size_t imsi_len;
1336
1337	if (username == NULL ||
1338	    (username[0] != EAP_AKA_PERMANENT_PREFIX &&
1339	     username[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) ||
1340	    username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) {
1341		wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
1342			   username);
1343		return EAP_SIM_DB_FAILURE;
1344	}
1345	imsi = username + 1;
1346	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI '%s'",
1347		   imsi);
1348
1349	entry = eap_sim_db_get_pending(data, imsi, 1);
1350	if (entry) {
1351		if (entry->state == FAILURE) {
1352			os_free(entry);
1353			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failure");
1354			return EAP_SIM_DB_FAILURE;
1355		}
1356
1357		if (entry->state == PENDING) {
1358			eap_sim_db_add_pending(data, entry);
1359			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending");
1360			return EAP_SIM_DB_PENDING;
1361		}
1362
1363		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Returning successfully "
1364			   "received authentication data");
1365		os_memcpy(_rand, entry->u.aka.rand, EAP_AKA_RAND_LEN);
1366		os_memcpy(autn, entry->u.aka.autn, EAP_AKA_AUTN_LEN);
1367		os_memcpy(ik, entry->u.aka.ik, EAP_AKA_IK_LEN);
1368		os_memcpy(ck, entry->u.aka.ck, EAP_AKA_CK_LEN);
1369		os_memcpy(res, entry->u.aka.res, EAP_AKA_RES_MAX_LEN);
1370		*res_len = entry->u.aka.res_len;
1371		os_free(entry);
1372		return 0;
1373	}
1374
1375	if (data->sock < 0) {
1376		if (eap_sim_db_open_socket(data) < 0)
1377			return EAP_SIM_DB_FAILURE;
1378	}
1379
1380	imsi_len = os_strlen(imsi);
1381	len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH ");
1382	if (len < 0 || len + imsi_len >= sizeof(msg))
1383		return EAP_SIM_DB_FAILURE;
1384	os_memcpy(msg + len, imsi, imsi_len);
1385	len += imsi_len;
1386
1387	wpa_printf(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication "
1388		    "data for IMSI '%s'", imsi);
1389	if (eap_sim_db_send(data, msg, len) < 0)
1390		return EAP_SIM_DB_FAILURE;
1391
1392	entry = os_zalloc(sizeof(*entry));
1393	if (entry == NULL)
1394		return EAP_SIM_DB_FAILURE;
1395
1396	entry->aka = 1;
1397	os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi));
1398	entry->cb_session_ctx = cb_session_ctx;
1399	entry->state = PENDING;
1400	eap_sim_db_add_pending(data, entry);
1401	eap_sim_db_expire_pending(data);
1402
1403	return EAP_SIM_DB_PENDING;
1404}
1405
1406
1407/**
1408 * eap_sim_db_resynchronize - Resynchronize AKA AUTN
1409 * @data: Private data pointer from eap_sim_db_init()
1410 * @username: Permanent username
1411 * @auts: AUTS value from the peer
1412 * @_rand: RAND value used in the rejected message
1413 * Returns: 0 on success, -1 on failure
1414 *
1415 * This function is called when the peer reports synchronization failure in the
1416 * AUTN value by sending AUTS. The AUTS and RAND values should be sent to
1417 * HLR/AuC to allow it to resynchronize with the peer. After this,
1418 * eap_sim_db_get_aka_auth() will be called again to to fetch updated
1419 * RAND/AUTN values for the next challenge.
1420 */
1421int eap_sim_db_resynchronize(struct eap_sim_db_data *data,
1422			     const char *username,
1423			     const u8 *auts, const u8 *_rand)
1424{
1425	const char *imsi;
1426	size_t imsi_len;
1427
1428	if (username == NULL ||
1429	    (username[0] != EAP_AKA_PERMANENT_PREFIX &&
1430	     username[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) ||
1431	    username[1] == '\0' || os_strlen(username) > 20) {
1432		wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
1433			   username);
1434		return -1;
1435	}
1436	imsi = username + 1;
1437	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI '%s'",
1438		   imsi);
1439
1440	if (data->sock >= 0) {
1441		char msg[100];
1442		int len, ret;
1443
1444		imsi_len = os_strlen(imsi);
1445		len = os_snprintf(msg, sizeof(msg), "AKA-AUTS ");
1446		if (len < 0 || len + imsi_len >= sizeof(msg))
1447			return -1;
1448		os_memcpy(msg + len, imsi, imsi_len);
1449		len += imsi_len;
1450
1451		ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
1452		if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
1453			return -1;
1454		len += ret;
1455		len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
1456					auts, EAP_AKA_AUTS_LEN);
1457		ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
1458		if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
1459			return -1;
1460		len += ret;
1461		len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
1462					_rand, EAP_AKA_RAND_LEN);
1463		wpa_printf(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for "
1464			   "IMSI '%s'", imsi);
1465		if (eap_sim_db_send(data, msg, len) < 0)
1466			return -1;
1467	}
1468
1469	return 0;
1470}
1471
1472
1473/**
1474 * sim_get_username - Extract username from SIM identity
1475 * @identity: Identity
1476 * @identity_len: Identity length
1477 * Returns: Allocated buffer with the username part of the identity
1478 *
1479 * Caller is responsible for freeing the returned buffer with os_free().
1480 */
1481char * sim_get_username(const u8 *identity, size_t identity_len)
1482{
1483	size_t pos;
1484
1485	if (identity == NULL)
1486		return NULL;
1487
1488	for (pos = 0; pos < identity_len; pos++) {
1489		if (identity[pos] == '@' || identity[pos] == '\0')
1490			break;
1491	}
1492
1493	return dup_binstr(identity, pos);
1494}
1495