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