eap_sim_db.c revision bd14a57187b024f49f5b9ace55ef457d8d04650a
1bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch/*
2bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch * hostapd / EAP-SIM database/authenticator gateway
3bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch * Copyright (c) 2005-2010, 2012, Jouni Malinen <j@w1.fi>
4bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch *
5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * This software may be distributed under the terms of the BSD license.
6f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * See README for more details.
7f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *
8bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch * This is an example implementation of the EAP-SIM/AKA database/authentication
9bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch * gateway interface that is using an external program as an SS7 gateway to
10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * GSM/UMTS authentication center (HLR/AuC). hlr_auc_gw is an example
11bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch * implementation of such a gateway program. This eap_sim_db.c takes care of
12bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch * EAP-SIM/AKA pseudonyms and re-auth identities. It can be used with different
13bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch * gateway implementations for HLR/AuC access. Alternatively, it can also be
14bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch * completely replaced if the in-memory database of pseudonyms/re-auth
15bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch * identities is not suitable for some cases.
16bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch */
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "includes.h"
19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include <sys/un.h>
204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#ifdef CONFIG_SQLITE
21bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include <sqlite3.h>
22bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#endif /* CONFIG_SQLITE */
23bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
24bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "common.h"
25bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "crypto/random.h"
26bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "eap_common/eap_sim_common.h"
27bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "eap_server/eap_sim_db.h"
28bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "eloop.h"
29bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
30bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochstruct eap_sim_pseudonym {
31bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch	struct eap_sim_pseudonym *next;
32bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch	char *permanent; /* permanent username */
33bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch	char *pseudonym; /* pseudonym username */
34bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch};
35bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)struct eap_sim_db_pending {
37bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch	struct eap_sim_db_pending *next;
38bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch	char imsi[20];
39bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch	enum { PENDING, SUCCESS, FAILURE } state;
40bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch	void *cb_session_ctx;
41bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch	int aka;
42bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch	union {
43bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch		struct {
44bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch			u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
45bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch			u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
46bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch			u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
47bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch			int num_chal;
48bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch		} sim;
49bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch		struct {
50bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch			u8 rand[EAP_AKA_RAND_LEN];
51bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch			u8 autn[EAP_AKA_AUTN_LEN];
52bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch			u8 ik[EAP_AKA_IK_LEN];
53bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch			u8 ck[EAP_AKA_CK_LEN];
54bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch			u8 res[EAP_AKA_RES_MAX_LEN];
55bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch			size_t res_len;
56bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch		} aka;
57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)	} u;
58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)};
59bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
60bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochstruct eap_sim_db_data {
61bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch	int sock;
62bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch	char *fname;
63bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch	char *local_sock;
64bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch	void (*get_complete_cb)(void *ctx, void *session_ctx);
65bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch	void *ctx;
66bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch	struct eap_sim_pseudonym *pseudonyms;
67bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch	struct eap_sim_reauth *reauths;
68bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch	struct eap_sim_db_pending *pending;
69bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#ifdef CONFIG_SQLITE
70bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch	sqlite3 *sqlite_db;
71bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch	char db_tmp_identity[100];
72bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch	char db_tmp_pseudonym_str[100];
73bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch	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 (data->local_sock == NULL) {
643		close(data->sock);
644		data->sock = -1;
645		return -1;
646	}
647	if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
648		wpa_printf(MSG_INFO, "bind(eap_sim_db): %s", strerror(errno));
649		close(data->sock);
650		data->sock = -1;
651		return -1;
652	}
653
654	os_memset(&addr, 0, sizeof(addr));
655	addr.sun_family = AF_UNIX;
656	os_strlcpy(addr.sun_path, data->fname + 5, sizeof(addr.sun_path));
657	if (connect(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
658		wpa_printf(MSG_INFO, "connect(eap_sim_db): %s",
659			   strerror(errno));
660		wpa_hexdump_ascii(MSG_INFO, "HLR/AuC GW socket",
661				  (u8 *) addr.sun_path,
662				  os_strlen(addr.sun_path));
663		close(data->sock);
664		data->sock = -1;
665		unlink(data->local_sock);
666		os_free(data->local_sock);
667		data->local_sock = NULL;
668		return -1;
669	}
670
671	eloop_register_read_sock(data->sock, eap_sim_db_receive, data, NULL);
672
673	return 0;
674}
675
676
677static void eap_sim_db_close_socket(struct eap_sim_db_data *data)
678{
679	if (data->sock >= 0) {
680		eloop_unregister_read_sock(data->sock);
681		close(data->sock);
682		data->sock = -1;
683	}
684	if (data->local_sock) {
685		unlink(data->local_sock);
686		os_free(data->local_sock);
687		data->local_sock = NULL;
688	}
689}
690
691
692/**
693 * eap_sim_db_init - Initialize EAP-SIM DB / authentication gateway interface
694 * @config: Configuration data (e.g., file name)
695 * @get_complete_cb: Callback function for reporting availability of triplets
696 * @ctx: Context pointer for get_complete_cb
697 * Returns: Pointer to a private data structure or %NULL on failure
698 */
699struct eap_sim_db_data *
700eap_sim_db_init(const char *config,
701		void (*get_complete_cb)(void *ctx, void *session_ctx),
702		void *ctx)
703{
704	struct eap_sim_db_data *data;
705	char *pos;
706
707	data = os_zalloc(sizeof(*data));
708	if (data == NULL)
709		return NULL;
710
711	data->sock = -1;
712	data->get_complete_cb = get_complete_cb;
713	data->ctx = ctx;
714	data->fname = os_strdup(config);
715	if (data->fname == NULL)
716		goto fail;
717	pos = os_strstr(data->fname, " db=");
718	if (pos) {
719		*pos = '\0';
720#ifdef CONFIG_SQLITE
721		pos += 4;
722		data->sqlite_db = db_open(pos);
723		if (data->sqlite_db == NULL)
724			goto fail;
725#endif /* CONFIG_SQLITE */
726	}
727
728	if (os_strncmp(data->fname, "unix:", 5) == 0) {
729		if (eap_sim_db_open_socket(data)) {
730			wpa_printf(MSG_DEBUG, "EAP-SIM DB: External database "
731				   "connection not available - will retry "
732				   "later");
733		}
734	}
735
736	return data;
737
738fail:
739	eap_sim_db_close_socket(data);
740	os_free(data->fname);
741	os_free(data);
742	return NULL;
743}
744
745
746static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p)
747{
748	os_free(p->permanent);
749	os_free(p->pseudonym);
750	os_free(p);
751}
752
753
754static void eap_sim_db_free_reauth(struct eap_sim_reauth *r)
755{
756	os_free(r->permanent);
757	os_free(r->reauth_id);
758	os_free(r);
759}
760
761
762/**
763 * eap_sim_db_deinit - Deinitialize EAP-SIM DB/authentication gw interface
764 * @priv: Private data pointer from eap_sim_db_init()
765 */
766void eap_sim_db_deinit(void *priv)
767{
768	struct eap_sim_db_data *data = priv;
769	struct eap_sim_pseudonym *p, *prev;
770	struct eap_sim_reauth *r, *prevr;
771	struct eap_sim_db_pending *pending, *prev_pending;
772
773#ifdef CONFIG_SQLITE
774	if (data->sqlite_db) {
775		sqlite3_close(data->sqlite_db);
776		data->sqlite_db = NULL;
777	}
778#endif /* CONFIG_SQLITE */
779
780	eap_sim_db_close_socket(data);
781	os_free(data->fname);
782
783	p = data->pseudonyms;
784	while (p) {
785		prev = p;
786		p = p->next;
787		eap_sim_db_free_pseudonym(prev);
788	}
789
790	r = data->reauths;
791	while (r) {
792		prevr = r;
793		r = r->next;
794		eap_sim_db_free_reauth(prevr);
795	}
796
797	pending = data->pending;
798	while (pending) {
799		prev_pending = pending;
800		pending = pending->next;
801		os_free(prev_pending);
802	}
803
804	os_free(data);
805}
806
807
808static int eap_sim_db_send(struct eap_sim_db_data *data, const char *msg,
809			   size_t len)
810{
811	int _errno = 0;
812
813	if (send(data->sock, msg, len, 0) < 0) {
814		_errno = errno;
815		wpa_printf(MSG_INFO, "send[EAP-SIM DB UNIX]: %s",
816			   strerror(errno));
817	}
818
819	if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
820	    _errno == ECONNREFUSED) {
821		/* Try to reconnect */
822		eap_sim_db_close_socket(data);
823		if (eap_sim_db_open_socket(data) < 0)
824			return -1;
825		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Reconnected to the "
826			   "external server");
827		if (send(data->sock, msg, len, 0) < 0) {
828			wpa_printf(MSG_INFO, "send[EAP-SIM DB UNIX]: %s",
829				   strerror(errno));
830			return -1;
831		}
832	}
833
834	return 0;
835}
836
837
838static void eap_sim_db_expire_pending(struct eap_sim_db_data *data)
839{
840	/* TODO: add limit for maximum length for pending list; remove latest
841	 * (i.e., last) entry from the list if the limit is reached; could also
842	 * use timeout to expire pending entries */
843}
844
845
846/**
847 * eap_sim_db_get_gsm_triplets - Get GSM triplets
848 * @data: Private data pointer from eap_sim_db_init()
849 * @username: Permanent username (prefix | IMSI)
850 * @max_chal: Maximum number of triplets
851 * @_rand: Buffer for RAND values
852 * @kc: Buffer for Kc values
853 * @sres: Buffer for SRES values
854 * @cb_session_ctx: Session callback context for get_complete_cb()
855 * Returns: Number of triplets received (has to be less than or equal to
856 * max_chal), -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not found), or
857 * -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this case, the
858 * callback function registered with eap_sim_db_init() will be called once the
859 * results become available.
860 *
861 * When using an external server for GSM triplets, this function can always
862 * start a request and return EAP_SIM_DB_PENDING immediately if authentication
863 * triplets are not available. Once the triplets are received, callback
864 * function registered with eap_sim_db_init() is called to notify EAP state
865 * machine to reprocess the message. This eap_sim_db_get_gsm_triplets()
866 * function will then be called again and the newly received triplets will then
867 * be given to the caller.
868 */
869int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data,
870				const char *username, int max_chal,
871				u8 *_rand, u8 *kc, u8 *sres,
872				void *cb_session_ctx)
873{
874	struct eap_sim_db_pending *entry;
875	int len, ret;
876	char msg[40];
877	const char *imsi;
878	size_t imsi_len;
879
880	if (username == NULL || username[0] != EAP_SIM_PERMANENT_PREFIX ||
881	    username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) {
882		wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
883			   username);
884		return EAP_SIM_DB_FAILURE;
885	}
886	imsi = username + 1;
887	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI '%s'",
888		   imsi);
889
890	entry = eap_sim_db_get_pending(data, imsi, 0);
891	if (entry) {
892		int num_chal;
893		if (entry->state == FAILURE) {
894			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
895				   "failure");
896			os_free(entry);
897			return EAP_SIM_DB_FAILURE;
898		}
899
900		if (entry->state == PENDING) {
901			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
902				   "still pending");
903			eap_sim_db_add_pending(data, entry);
904			return EAP_SIM_DB_PENDING;
905		}
906
907		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
908			   "%d challenges", entry->u.sim.num_chal);
909		num_chal = entry->u.sim.num_chal;
910		if (num_chal > max_chal)
911			num_chal = max_chal;
912		os_memcpy(_rand, entry->u.sim.rand, num_chal * GSM_RAND_LEN);
913		os_memcpy(sres, entry->u.sim.sres,
914			  num_chal * EAP_SIM_SRES_LEN);
915		os_memcpy(kc, entry->u.sim.kc, num_chal * EAP_SIM_KC_LEN);
916		os_free(entry);
917		return num_chal;
918	}
919
920	if (data->sock < 0) {
921		if (eap_sim_db_open_socket(data) < 0)
922			return EAP_SIM_DB_FAILURE;
923	}
924
925	imsi_len = os_strlen(imsi);
926	len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH ");
927	if (len < 0 || len + imsi_len >= sizeof(msg))
928		return EAP_SIM_DB_FAILURE;
929	os_memcpy(msg + len, imsi, imsi_len);
930	len += imsi_len;
931	ret = os_snprintf(msg + len, sizeof(msg) - len, " %d", max_chal);
932	if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
933		return EAP_SIM_DB_FAILURE;
934	len += ret;
935
936	wpa_printf(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication "
937		   "data for IMSI '%s'", imsi);
938	if (eap_sim_db_send(data, msg, len) < 0)
939		return EAP_SIM_DB_FAILURE;
940
941	entry = os_zalloc(sizeof(*entry));
942	if (entry == NULL)
943		return EAP_SIM_DB_FAILURE;
944
945	os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi));
946	entry->cb_session_ctx = cb_session_ctx;
947	entry->state = PENDING;
948	eap_sim_db_add_pending(data, entry);
949	eap_sim_db_expire_pending(data);
950
951	return EAP_SIM_DB_PENDING;
952}
953
954
955static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix)
956{
957	char *id, *pos, *end;
958	u8 buf[10];
959
960	if (random_get_bytes(buf, sizeof(buf)))
961		return NULL;
962	id = os_malloc(sizeof(buf) * 2 + 2);
963	if (id == NULL)
964		return NULL;
965
966	pos = id;
967	end = id + sizeof(buf) * 2 + 2;
968	*pos++ = prefix;
969	pos += wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf));
970
971	return id;
972}
973
974
975/**
976 * eap_sim_db_get_next_pseudonym - EAP-SIM DB: Get next pseudonym
977 * @data: Private data pointer from eap_sim_db_init()
978 * @method: EAP method (SIM/AKA/AKA')
979 * Returns: Next pseudonym (allocated string) or %NULL on failure
980 *
981 * This function is used to generate a pseudonym for EAP-SIM. The returned
982 * pseudonym is not added to database at this point; it will need to be added
983 * with eap_sim_db_add_pseudonym() once the authentication has been completed
984 * successfully. Caller is responsible for freeing the returned buffer.
985 */
986char * eap_sim_db_get_next_pseudonym(struct eap_sim_db_data *data,
987				     enum eap_sim_db_method method)
988{
989	char prefix = EAP_SIM_REAUTH_ID_PREFIX;
990
991	switch (method) {
992	case EAP_SIM_DB_SIM:
993		prefix = EAP_SIM_PSEUDONYM_PREFIX;
994		break;
995	case EAP_SIM_DB_AKA:
996		prefix = EAP_AKA_PSEUDONYM_PREFIX;
997		break;
998	case EAP_SIM_DB_AKA_PRIME:
999		prefix = EAP_AKA_PRIME_PSEUDONYM_PREFIX;
1000		break;
1001	}
1002
1003	return eap_sim_db_get_next(data, prefix);
1004}
1005
1006
1007/**
1008 * eap_sim_db_get_next_reauth_id - EAP-SIM DB: Get next reauth_id
1009 * @data: Private data pointer from eap_sim_db_init()
1010 * @method: EAP method (SIM/AKA/AKA')
1011 * Returns: Next reauth_id (allocated string) or %NULL on failure
1012 *
1013 * This function is used to generate a fast re-authentication identity for
1014 * EAP-SIM. The returned reauth_id is not added to database at this point; it
1015 * will need to be added with eap_sim_db_add_reauth() once the authentication
1016 * has been completed successfully. Caller is responsible for freeing the
1017 * returned buffer.
1018 */
1019char * eap_sim_db_get_next_reauth_id(struct eap_sim_db_data *data,
1020				     enum eap_sim_db_method method)
1021{
1022	char prefix = EAP_SIM_REAUTH_ID_PREFIX;
1023
1024	switch (method) {
1025	case EAP_SIM_DB_SIM:
1026		prefix = EAP_SIM_REAUTH_ID_PREFIX;
1027		break;
1028	case EAP_SIM_DB_AKA:
1029		prefix = EAP_AKA_REAUTH_ID_PREFIX;
1030		break;
1031	case EAP_SIM_DB_AKA_PRIME:
1032		prefix = EAP_AKA_PRIME_REAUTH_ID_PREFIX;
1033		break;
1034	}
1035
1036	return eap_sim_db_get_next(data, prefix);
1037}
1038
1039
1040/**
1041 * eap_sim_db_add_pseudonym - EAP-SIM DB: Add new pseudonym
1042 * @data: Private data pointer from eap_sim_db_init()
1043 * @permanent: Permanent username
1044 * @pseudonym: Pseudonym for this user. This needs to be an allocated buffer,
1045 * e.g., return value from eap_sim_db_get_next_pseudonym(). Caller must not
1046 * free it.
1047 * Returns: 0 on success, -1 on failure
1048 *
1049 * This function adds a new pseudonym for EAP-SIM user. EAP-SIM DB is
1050 * responsible of freeing pseudonym buffer once it is not needed anymore.
1051 */
1052int eap_sim_db_add_pseudonym(struct eap_sim_db_data *data,
1053			     const char *permanent, char *pseudonym)
1054{
1055	struct eap_sim_pseudonym *p;
1056	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add pseudonym '%s' for permanent "
1057		   "username '%s'", pseudonym, permanent);
1058
1059	/* TODO: could store last two pseudonyms */
1060#ifdef CONFIG_SQLITE
1061	if (data->sqlite_db)
1062		return db_add_pseudonym(data, permanent, pseudonym);
1063#endif /* CONFIG_SQLITE */
1064	for (p = data->pseudonyms; p; p = p->next) {
1065		if (os_strcmp(permanent, p->permanent) == 0)
1066			break;
1067	}
1068	if (p) {
1069		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
1070			   "pseudonym: %s", p->pseudonym);
1071		os_free(p->pseudonym);
1072		p->pseudonym = pseudonym;
1073		return 0;
1074	}
1075
1076	p = os_zalloc(sizeof(*p));
1077	if (p == NULL) {
1078		os_free(pseudonym);
1079		return -1;
1080	}
1081
1082	p->next = data->pseudonyms;
1083	p->permanent = os_strdup(permanent);
1084	if (p->permanent == NULL) {
1085		os_free(p);
1086		os_free(pseudonym);
1087		return -1;
1088	}
1089	p->pseudonym = pseudonym;
1090	data->pseudonyms = p;
1091
1092	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new pseudonym entry");
1093	return 0;
1094}
1095
1096
1097static struct eap_sim_reauth *
1098eap_sim_db_add_reauth_data(struct eap_sim_db_data *data,
1099			   const char *permanent,
1100			   char *reauth_id, u16 counter)
1101{
1102	struct eap_sim_reauth *r;
1103
1104	for (r = data->reauths; r; r = r->next) {
1105		if (os_strcmp(r->permanent, permanent) == 0)
1106			break;
1107	}
1108
1109	if (r) {
1110		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
1111			   "reauth_id: %s", r->reauth_id);
1112		os_free(r->reauth_id);
1113		r->reauth_id = reauth_id;
1114	} else {
1115		r = os_zalloc(sizeof(*r));
1116		if (r == NULL) {
1117			os_free(reauth_id);
1118			return NULL;
1119		}
1120
1121		r->next = data->reauths;
1122		r->permanent = os_strdup(permanent);
1123		if (r->permanent == NULL) {
1124			os_free(r);
1125			os_free(reauth_id);
1126			return NULL;
1127		}
1128		r->reauth_id = reauth_id;
1129		data->reauths = r;
1130		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new reauth entry");
1131	}
1132
1133	r->counter = counter;
1134
1135	return r;
1136}
1137
1138
1139/**
1140 * eap_sim_db_add_reauth - EAP-SIM DB: Add new re-authentication entry
1141 * @priv: Private data pointer from eap_sim_db_init()
1142 * @permanent: Permanent username
1143 * @identity_len: Length of identity
1144 * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
1145 * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
1146 * free it.
1147 * @counter: AT_COUNTER value for fast re-authentication
1148 * @mk: 16-byte MK from the previous full authentication or %NULL
1149 * Returns: 0 on success, -1 on failure
1150 *
1151 * This function adds a new re-authentication entry for an EAP-SIM user.
1152 * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
1153 * anymore.
1154 */
1155int eap_sim_db_add_reauth(struct eap_sim_db_data *data, const char *permanent,
1156			  char *reauth_id, u16 counter, const u8 *mk)
1157{
1158	struct eap_sim_reauth *r;
1159
1160	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add reauth_id '%s' for permanent "
1161		   "identity '%s'", reauth_id, permanent);
1162
1163#ifdef CONFIG_SQLITE
1164	if (data->sqlite_db)
1165		return db_add_reauth(data, permanent, reauth_id, counter, mk,
1166				     NULL, NULL, NULL);
1167#endif /* CONFIG_SQLITE */
1168	r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter);
1169	if (r == NULL)
1170		return -1;
1171
1172	os_memcpy(r->mk, mk, EAP_SIM_MK_LEN);
1173
1174	return 0;
1175}
1176
1177
1178#ifdef EAP_SERVER_AKA_PRIME
1179/**
1180 * eap_sim_db_add_reauth_prime - EAP-AKA' DB: Add new re-authentication entry
1181 * @data: Private data pointer from eap_sim_db_init()
1182 * @permanent: Permanent username
1183 * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
1184 * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
1185 * free it.
1186 * @counter: AT_COUNTER value for fast re-authentication
1187 * @k_encr: K_encr from the previous full authentication
1188 * @k_aut: K_aut from the previous full authentication
1189 * @k_re: 32-byte K_re from the previous full authentication
1190 * Returns: 0 on success, -1 on failure
1191 *
1192 * This function adds a new re-authentication entry for an EAP-AKA' user.
1193 * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
1194 * anymore.
1195 */
1196int eap_sim_db_add_reauth_prime(struct eap_sim_db_data *data,
1197				const char *permanent, char *reauth_id,
1198				u16 counter, const u8 *k_encr,
1199				const u8 *k_aut, const u8 *k_re)
1200{
1201	struct eap_sim_reauth *r;
1202
1203	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add reauth_id '%s' for permanent "
1204		   "identity '%s'", reauth_id, permanent);
1205
1206#ifdef CONFIG_SQLITE
1207	if (data->sqlite_db)
1208		return db_add_reauth(data, permanent, reauth_id, counter, NULL,
1209				     k_encr, k_aut, k_re);
1210#endif /* CONFIG_SQLITE */
1211	r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter);
1212	if (r == NULL)
1213		return -1;
1214
1215	os_memcpy(r->k_encr, k_encr, EAP_SIM_K_ENCR_LEN);
1216	os_memcpy(r->k_aut, k_aut, EAP_AKA_PRIME_K_AUT_LEN);
1217	os_memcpy(r->k_re, k_re, EAP_AKA_PRIME_K_RE_LEN);
1218
1219	return 0;
1220}
1221#endif /* EAP_SERVER_AKA_PRIME */
1222
1223
1224/**
1225 * eap_sim_db_get_permanent - EAP-SIM DB: Get permanent identity
1226 * @data: Private data pointer from eap_sim_db_init()
1227 * @pseudonym: Pseudonym username
1228 * Returns: Pointer to permanent username or %NULL if not found
1229 */
1230const char *
1231eap_sim_db_get_permanent(struct eap_sim_db_data *data, const char *pseudonym)
1232{
1233	struct eap_sim_pseudonym *p;
1234
1235#ifdef CONFIG_SQLITE
1236	if (data->sqlite_db)
1237		return db_get_pseudonym(data, pseudonym);
1238#endif /* CONFIG_SQLITE */
1239
1240	p = data->pseudonyms;
1241	while (p) {
1242		if (os_strcmp(p->pseudonym, pseudonym) == 0)
1243			return p->permanent;
1244		p = p->next;
1245	}
1246
1247	return NULL;
1248}
1249
1250
1251/**
1252 * eap_sim_db_get_reauth_entry - EAP-SIM DB: Get re-authentication entry
1253 * @data: Private data pointer from eap_sim_db_init()
1254 * @reauth_id: Fast re-authentication username
1255 * Returns: Pointer to the re-auth entry, or %NULL if not found
1256 */
1257struct eap_sim_reauth *
1258eap_sim_db_get_reauth_entry(struct eap_sim_db_data *data,
1259			    const char *reauth_id)
1260{
1261	struct eap_sim_reauth *r;
1262
1263#ifdef CONFIG_SQLITE
1264	if (data->sqlite_db)
1265		return db_get_reauth(data, reauth_id);
1266#endif /* CONFIG_SQLITE */
1267
1268	r = data->reauths;
1269	while (r) {
1270		if (os_strcmp(r->reauth_id, reauth_id) == 0)
1271			break;
1272		r = r->next;
1273	}
1274
1275	return r;
1276}
1277
1278
1279/**
1280 * eap_sim_db_remove_reauth - EAP-SIM DB: Remove re-authentication entry
1281 * @data: Private data pointer from eap_sim_db_init()
1282 * @reauth: Pointer to re-authentication entry from
1283 * eap_sim_db_get_reauth_entry()
1284 */
1285void eap_sim_db_remove_reauth(struct eap_sim_db_data *data,
1286			      struct eap_sim_reauth *reauth)
1287{
1288	struct eap_sim_reauth *r, *prev = NULL;
1289#ifdef CONFIG_SQLITE
1290	if (data->sqlite_db) {
1291		db_remove_reauth(data, reauth);
1292		return;
1293	}
1294#endif /* CONFIG_SQLITE */
1295	r = data->reauths;
1296	while (r) {
1297		if (r == reauth) {
1298			if (prev)
1299				prev->next = r->next;
1300			else
1301				data->reauths = r->next;
1302			eap_sim_db_free_reauth(r);
1303			return;
1304		}
1305		prev = r;
1306		r = r->next;
1307	}
1308}
1309
1310
1311/**
1312 * eap_sim_db_get_aka_auth - Get AKA authentication values
1313 * @data: Private data pointer from eap_sim_db_init()
1314 * @username: Permanent username (prefix | IMSI)
1315 * @_rand: Buffer for RAND value
1316 * @autn: Buffer for AUTN value
1317 * @ik: Buffer for IK value
1318 * @ck: Buffer for CK value
1319 * @res: Buffer for RES value
1320 * @res_len: Buffer for RES length
1321 * @cb_session_ctx: Session callback context for get_complete_cb()
1322 * Returns: 0 on success, -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not
1323 * found), or -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this
1324 * case, the callback function registered with eap_sim_db_init() will be
1325 * called once the results become available.
1326 *
1327 * When using an external server for AKA authentication, this function can
1328 * always start a request and return EAP_SIM_DB_PENDING immediately if
1329 * authentication triplets are not available. Once the authentication data are
1330 * received, callback function registered with eap_sim_db_init() is called to
1331 * notify EAP state machine to reprocess the message. This
1332 * eap_sim_db_get_aka_auth() function will then be called again and the newly
1333 * received triplets will then be given to the caller.
1334 */
1335int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username,
1336			    u8 *_rand, u8 *autn, u8 *ik, u8 *ck,
1337			    u8 *res, size_t *res_len, void *cb_session_ctx)
1338{
1339	struct eap_sim_db_pending *entry;
1340	int len;
1341	char msg[40];
1342	const char *imsi;
1343	size_t imsi_len;
1344
1345	if (username == NULL ||
1346	    (username[0] != EAP_AKA_PERMANENT_PREFIX &&
1347	     username[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) ||
1348	    username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) {
1349		wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
1350			   username);
1351		return EAP_SIM_DB_FAILURE;
1352	}
1353	imsi = username + 1;
1354	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI '%s'",
1355		   imsi);
1356
1357	entry = eap_sim_db_get_pending(data, imsi, 1);
1358	if (entry) {
1359		if (entry->state == FAILURE) {
1360			os_free(entry);
1361			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failure");
1362			return EAP_SIM_DB_FAILURE;
1363		}
1364
1365		if (entry->state == PENDING) {
1366			eap_sim_db_add_pending(data, entry);
1367			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending");
1368			return EAP_SIM_DB_PENDING;
1369		}
1370
1371		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Returning successfully "
1372			   "received authentication data");
1373		os_memcpy(_rand, entry->u.aka.rand, EAP_AKA_RAND_LEN);
1374		os_memcpy(autn, entry->u.aka.autn, EAP_AKA_AUTN_LEN);
1375		os_memcpy(ik, entry->u.aka.ik, EAP_AKA_IK_LEN);
1376		os_memcpy(ck, entry->u.aka.ck, EAP_AKA_CK_LEN);
1377		os_memcpy(res, entry->u.aka.res, EAP_AKA_RES_MAX_LEN);
1378		*res_len = entry->u.aka.res_len;
1379		os_free(entry);
1380		return 0;
1381	}
1382
1383	if (data->sock < 0) {
1384		if (eap_sim_db_open_socket(data) < 0)
1385			return EAP_SIM_DB_FAILURE;
1386	}
1387
1388	imsi_len = os_strlen(imsi);
1389	len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH ");
1390	if (len < 0 || 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 (len < 0 || len + imsi_len >= sizeof(msg))
1455			return -1;
1456		os_memcpy(msg + len, imsi, imsi_len);
1457		len += imsi_len;
1458
1459		ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
1460		if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
1461			return -1;
1462		len += ret;
1463		len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
1464					auts, EAP_AKA_AUTS_LEN);
1465		ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
1466		if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
1467			return -1;
1468		len += ret;
1469		len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
1470					_rand, EAP_AKA_RAND_LEN);
1471		wpa_printf(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for "
1472			   "IMSI '%s'", imsi);
1473		if (eap_sim_db_send(data, msg, len) < 0)
1474			return -1;
1475	}
1476
1477	return 0;
1478}
1479
1480
1481/**
1482 * sim_get_username - Extract username from SIM identity
1483 * @identity: Identity
1484 * @identity_len: Identity length
1485 * Returns: Allocated buffer with the username part of the identity
1486 *
1487 * Caller is responsible for freeing the returned buffer with os_free().
1488 */
1489char * sim_get_username(const u8 *identity, size_t identity_len)
1490{
1491	size_t pos;
1492
1493	if (identity == NULL)
1494		return NULL;
1495
1496	for (pos = 0; pos < identity_len; pos++) {
1497		if (identity[pos] == '@' || identity[pos] == '\0')
1498			break;
1499	}
1500
1501	return dup_binstr(identity, pos);
1502}
1503