Home | History | Annotate | Download | only in eap_server
      1 /*
      2  * hostapd / EAP-SIM database/authenticator gateway
      3  * Copyright (c) 2005-2007, Jouni Malinen <j (at) 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