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