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