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 "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 		return NULL;
    658 
    659 	/* Remove possible realm from identity */
    660 	len = 0;
    661 	while (len < identity_len) {
    662 		if (identity[len] == '@')
    663 			break;
    664 		len++;
    665 	}
    666 
    667 	pseudonym = os_malloc(len + 1);
    668 	if (pseudonym == NULL)
    669 		return NULL;
    670 	os_memcpy(pseudonym, identity, len);
    671 	pseudonym[len] = '\0';
    672 
    673 	p = data->pseudonyms;
    674 	while (p) {
    675 		if (os_strcmp(p->pseudonym, pseudonym) == 0)
    676 			break;
    677 		p = p->next;
    678 	}
    679 
    680 	os_free(pseudonym);
    681 
    682 	return p;
    683 }
    684 
    685 
    686 static struct eap_sim_pseudonym *
    687 eap_sim_db_get_pseudonym_id(struct eap_sim_db_data *data, const u8 *identity,
    688 			    size_t identity_len)
    689 {
    690 	struct eap_sim_pseudonym *p;
    691 
    692 	if (identity_len == 0 ||
    693 	    (identity[0] != EAP_SIM_PERMANENT_PREFIX &&
    694 	     identity[0] != EAP_AKA_PERMANENT_PREFIX))
    695 		return NULL;
    696 
    697 	p = data->pseudonyms;
    698 	while (p) {
    699 		if (identity_len == p->identity_len &&
    700 		    os_memcmp(p->identity, identity, identity_len) == 0)
    701 			break;
    702 		p = p->next;
    703 	}
    704 
    705 	return p;
    706 }
    707 
    708 
    709 static struct eap_sim_reauth *
    710 eap_sim_db_get_reauth(struct eap_sim_db_data *data, const u8 *identity,
    711 		      size_t identity_len)
    712 {
    713 	char *reauth_id;
    714 	size_t len;
    715 	struct eap_sim_reauth *r;
    716 
    717 	if (identity_len == 0 ||
    718 	    (identity[0] != EAP_SIM_REAUTH_ID_PREFIX &&
    719 	     identity[0] != EAP_AKA_REAUTH_ID_PREFIX))
    720 		return NULL;
    721 
    722 	/* Remove possible realm from identity */
    723 	len = 0;
    724 	while (len < identity_len) {
    725 		if (identity[len] == '@')
    726 			break;
    727 		len++;
    728 	}
    729 
    730 	reauth_id = os_malloc(len + 1);
    731 	if (reauth_id == NULL)
    732 		return NULL;
    733 	os_memcpy(reauth_id, identity, len);
    734 	reauth_id[len] = '\0';
    735 
    736 	r = data->reauths;
    737 	while (r) {
    738 		if (os_strcmp(r->reauth_id, reauth_id) == 0)
    739 			break;
    740 		r = r->next;
    741 	}
    742 
    743 	os_free(reauth_id);
    744 
    745 	return r;
    746 }
    747 
    748 
    749 static struct eap_sim_reauth *
    750 eap_sim_db_get_reauth_id(struct eap_sim_db_data *data, const u8 *identity,
    751 			 size_t identity_len)
    752 {
    753 	struct eap_sim_pseudonym *p;
    754 	struct eap_sim_reauth *r;
    755 
    756 	if (identity_len == 0)
    757 		return NULL;
    758 
    759 	p = eap_sim_db_get_pseudonym(data, identity, identity_len);
    760 	if (p == NULL)
    761 		p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
    762 	if (p) {
    763 		identity = p->identity;
    764 		identity_len = p->identity_len;
    765 	}
    766 
    767 	r = data->reauths;
    768 	while (r) {
    769 		if (identity_len == r->identity_len &&
    770 		    os_memcmp(r->identity, identity, identity_len) == 0)
    771 			break;
    772 		r = r->next;
    773 	}
    774 
    775 	return r;
    776 }
    777 
    778 
    779 /**
    780  * eap_sim_db_identity_known - Verify whether the given identity is known
    781  * @priv: Private data pointer from eap_sim_db_init()
    782  * @identity: User name identity
    783  * @identity_len: Length of identity in bytes
    784  * Returns: 0 if the user is found or -1 on failure
    785  *
    786  * In most cases, the user name is ['0','1'] | IMSI, i.e., 1 followed by the
    787  * IMSI in ASCII format, ['2','3'] | pseudonym, or ['4','5'] | reauth_id.
    788  */
    789 int eap_sim_db_identity_known(void *priv, const u8 *identity,
    790 			      size_t identity_len)
    791 {
    792 	struct eap_sim_db_data *data = priv;
    793 
    794 	if (identity == NULL || identity_len < 2)
    795 		return -1;
    796 
    797 	if (identity[0] == EAP_SIM_PSEUDONYM_PREFIX ||
    798 	    identity[0] == EAP_AKA_PSEUDONYM_PREFIX) {
    799 		struct eap_sim_pseudonym *p =
    800 			eap_sim_db_get_pseudonym(data, identity, identity_len);
    801 		return p ? 0 : -1;
    802 	}
    803 
    804 	if (identity[0] == EAP_SIM_REAUTH_ID_PREFIX ||
    805 	    identity[0] == EAP_AKA_REAUTH_ID_PREFIX) {
    806 		struct eap_sim_reauth *r =
    807 			eap_sim_db_get_reauth(data, identity, identity_len);
    808 		return r ? 0 : -1;
    809 	}
    810 
    811 	if (identity[0] != EAP_SIM_PERMANENT_PREFIX &&
    812 	    identity[0] != EAP_AKA_PERMANENT_PREFIX) {
    813 		/* Unknown identity prefix */
    814 		return -1;
    815 	}
    816 
    817 	/* TODO: Should consider asking HLR/AuC gateway whether this permanent
    818 	 * identity is known. If it is, EAP-SIM/AKA can skip identity request.
    819 	 * In case of EAP-AKA, this would reduce number of needed round-trips.
    820 	 * Ideally, this would be done with one wait, i.e., just request
    821 	 * authentication data and store it for the next use. This would then
    822 	 * need to use similar pending-request functionality as the normal
    823 	 * request for authentication data at later phase.
    824 	 */
    825 	return -1;
    826 }
    827 
    828 
    829 static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix)
    830 {
    831 	char *id, *pos, *end;
    832 	u8 buf[10];
    833 
    834 	if (random_get_bytes(buf, sizeof(buf)))
    835 		return NULL;
    836 	id = os_malloc(sizeof(buf) * 2 + 2);
    837 	if (id == NULL)
    838 		return NULL;
    839 
    840 	pos = id;
    841 	end = id + sizeof(buf) * 2 + 2;
    842 	*pos++ = prefix;
    843 	pos += wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf));
    844 
    845 	return id;
    846 }
    847 
    848 
    849 /**
    850  * eap_sim_db_get_next_pseudonym - EAP-SIM DB: Get next pseudonym
    851  * @priv: Private data pointer from eap_sim_db_init()
    852  * @aka: Using EAP-AKA instead of EAP-SIM
    853  * Returns: Next pseudonym (allocated string) or %NULL on failure
    854  *
    855  * This function is used to generate a pseudonym for EAP-SIM. The returned
    856  * pseudonym is not added to database at this point; it will need to be added
    857  * with eap_sim_db_add_pseudonym() once the authentication has been completed
    858  * successfully. Caller is responsible for freeing the returned buffer.
    859  */
    860 char * eap_sim_db_get_next_pseudonym(void *priv, int aka)
    861 {
    862 	struct eap_sim_db_data *data = priv;
    863 	return eap_sim_db_get_next(data, aka ? EAP_AKA_PSEUDONYM_PREFIX :
    864 				   EAP_SIM_PSEUDONYM_PREFIX);
    865 }
    866 
    867 
    868 /**
    869  * eap_sim_db_get_next_reauth_id - EAP-SIM DB: Get next reauth_id
    870  * @priv: Private data pointer from eap_sim_db_init()
    871  * @aka: Using EAP-AKA instead of EAP-SIM
    872  * Returns: Next reauth_id (allocated string) or %NULL on failure
    873  *
    874  * This function is used to generate a fast re-authentication identity for
    875  * EAP-SIM. The returned reauth_id is not added to database at this point; it
    876  * will need to be added with eap_sim_db_add_reauth() once the authentication
    877  * has been completed successfully. Caller is responsible for freeing the
    878  * returned buffer.
    879  */
    880 char * eap_sim_db_get_next_reauth_id(void *priv, int aka)
    881 {
    882 	struct eap_sim_db_data *data = priv;
    883 	return eap_sim_db_get_next(data, aka ? EAP_AKA_REAUTH_ID_PREFIX :
    884 				   EAP_SIM_REAUTH_ID_PREFIX);
    885 }
    886 
    887 
    888 /**
    889  * eap_sim_db_add_pseudonym - EAP-SIM DB: Add new pseudonym
    890  * @priv: Private data pointer from eap_sim_db_init()
    891  * @identity: Identity of the user (may be permanent identity or pseudonym)
    892  * @identity_len: Length of identity
    893  * @pseudonym: Pseudonym for this user. This needs to be an allocated buffer,
    894  * e.g., return value from eap_sim_db_get_next_pseudonym(). Caller must not
    895  * free it.
    896  * Returns: 0 on success, -1 on failure
    897  *
    898  * This function adds a new pseudonym for EAP-SIM user. EAP-SIM DB is
    899  * responsible of freeing pseudonym buffer once it is not needed anymore.
    900  */
    901 int eap_sim_db_add_pseudonym(void *priv, const u8 *identity,
    902 			     size_t identity_len, char *pseudonym)
    903 {
    904 	struct eap_sim_db_data *data = priv;
    905 	struct eap_sim_pseudonym *p;
    906 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add pseudonym for identity",
    907 			  identity, identity_len);
    908 	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pseudonym: %s", pseudonym);
    909 
    910 	/* TODO: could store last two pseudonyms */
    911 	p = eap_sim_db_get_pseudonym(data, identity, identity_len);
    912 	if (p == NULL)
    913 		p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
    914 
    915 	if (p) {
    916 		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
    917 			   "pseudonym: %s", p->pseudonym);
    918 		os_free(p->pseudonym);
    919 		p->pseudonym = pseudonym;
    920 		return 0;
    921 	}
    922 
    923 	p = os_zalloc(sizeof(*p));
    924 	if (p == NULL) {
    925 		os_free(pseudonym);
    926 		return -1;
    927 	}
    928 
    929 	p->next = data->pseudonyms;
    930 	p->identity = os_malloc(identity_len);
    931 	if (p->identity == NULL) {
    932 		os_free(p);
    933 		os_free(pseudonym);
    934 		return -1;
    935 	}
    936 	os_memcpy(p->identity, identity, identity_len);
    937 	p->identity_len = identity_len;
    938 	p->pseudonym = pseudonym;
    939 	data->pseudonyms = p;
    940 
    941 	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new pseudonym entry");
    942 	return 0;
    943 }
    944 
    945 
    946 static struct eap_sim_reauth *
    947 eap_sim_db_add_reauth_data(struct eap_sim_db_data *data, const u8 *identity,
    948 			   size_t identity_len, char *reauth_id, u16 counter)
    949 {
    950 	struct eap_sim_reauth *r;
    951 
    952 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add reauth_id for identity",
    953 			  identity, identity_len);
    954 	wpa_printf(MSG_DEBUG, "EAP-SIM DB: reauth_id: %s", reauth_id);
    955 
    956 	r = eap_sim_db_get_reauth(data, identity, identity_len);
    957 	if (r == NULL)
    958 		r = eap_sim_db_get_reauth_id(data, identity, identity_len);
    959 
    960 	if (r) {
    961 		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
    962 			   "reauth_id: %s", r->reauth_id);
    963 		os_free(r->reauth_id);
    964 		r->reauth_id = reauth_id;
    965 	} else {
    966 		r = os_zalloc(sizeof(*r));
    967 		if (r == NULL) {
    968 			os_free(reauth_id);
    969 			return NULL;
    970 		}
    971 
    972 		r->next = data->reauths;
    973 		r->identity = os_malloc(identity_len);
    974 		if (r->identity == NULL) {
    975 			os_free(r);
    976 			os_free(reauth_id);
    977 			return NULL;
    978 		}
    979 		os_memcpy(r->identity, identity, identity_len);
    980 		r->identity_len = identity_len;
    981 		r->reauth_id = reauth_id;
    982 		data->reauths = r;
    983 		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new reauth entry");
    984 	}
    985 
    986 	r->counter = counter;
    987 
    988 	return r;
    989 }
    990 
    991 
    992 /**
    993  * eap_sim_db_add_reauth - EAP-SIM DB: Add new re-authentication entry
    994  * @priv: Private data pointer from eap_sim_db_init()
    995  * @identity: Identity of the user (may be permanent identity or pseudonym)
    996  * @identity_len: Length of identity
    997  * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
    998  * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
    999  * free it.
   1000  * @counter: AT_COUNTER value for fast re-authentication
   1001  * @mk: 16-byte MK from the previous full authentication or %NULL
   1002  * Returns: 0 on success, -1 on failure
   1003  *
   1004  * This function adds a new re-authentication entry for an EAP-SIM user.
   1005  * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
   1006  * anymore.
   1007  */
   1008 int eap_sim_db_add_reauth(void *priv, const u8 *identity,
   1009 			  size_t identity_len, char *reauth_id, u16 counter,
   1010 			  const u8 *mk)
   1011 {
   1012 	struct eap_sim_db_data *data = priv;
   1013 	struct eap_sim_reauth *r;
   1014 
   1015 	r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id,
   1016 				       counter);
   1017 	if (r == NULL)
   1018 		return -1;
   1019 
   1020 	os_memcpy(r->mk, mk, EAP_SIM_MK_LEN);
   1021 	r->aka_prime = 0;
   1022 
   1023 	return 0;
   1024 }
   1025 
   1026 
   1027 #ifdef EAP_SERVER_AKA_PRIME
   1028 /**
   1029  * eap_sim_db_add_reauth_prime - EAP-AKA' DB: Add new re-authentication entry
   1030  * @priv: Private data pointer from eap_sim_db_init()
   1031  * @identity: Identity of the user (may be permanent identity or pseudonym)
   1032  * @identity_len: Length of identity
   1033  * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
   1034  * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
   1035  * free it.
   1036  * @counter: AT_COUNTER value for fast re-authentication
   1037  * @k_encr: K_encr from the previous full authentication
   1038  * @k_aut: K_aut from the previous full authentication
   1039  * @k_re: 32-byte K_re from the previous full authentication
   1040  * Returns: 0 on success, -1 on failure
   1041  *
   1042  * This function adds a new re-authentication entry for an EAP-AKA' user.
   1043  * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
   1044  * anymore.
   1045  */
   1046 int eap_sim_db_add_reauth_prime(void *priv, const u8 *identity,
   1047 				size_t identity_len, char *reauth_id,
   1048 				u16 counter, const u8 *k_encr, const u8 *k_aut,
   1049 				const u8 *k_re)
   1050 {
   1051 	struct eap_sim_db_data *data = priv;
   1052 	struct eap_sim_reauth *r;
   1053 
   1054 	r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id,
   1055 				       counter);
   1056 	if (r == NULL)
   1057 		return -1;
   1058 
   1059 	r->aka_prime = 1;
   1060 	os_memcpy(r->k_encr, k_encr, EAP_SIM_K_ENCR_LEN);
   1061 	os_memcpy(r->k_aut, k_aut, EAP_AKA_PRIME_K_AUT_LEN);
   1062 	os_memcpy(r->k_re, k_re, EAP_AKA_PRIME_K_RE_LEN);
   1063 
   1064 	return 0;
   1065 }
   1066 #endif /* EAP_SERVER_AKA_PRIME */
   1067 
   1068 
   1069 /**
   1070  * eap_sim_db_get_permanent - EAP-SIM DB: Get permanent identity
   1071  * @priv: Private data pointer from eap_sim_db_init()
   1072  * @identity: Identity of the user (may be permanent identity or pseudonym)
   1073  * @identity_len: Length of identity
   1074  * @len: Buffer for length of the returned permanent identity
   1075  * Returns: Pointer to the permanent identity, or %NULL if not found
   1076  */
   1077 const u8 * eap_sim_db_get_permanent(void *priv, const u8 *identity,
   1078 				    size_t identity_len, size_t *len)
   1079 {
   1080 	struct eap_sim_db_data *data = priv;
   1081 	struct eap_sim_pseudonym *p;
   1082 
   1083 	if (identity == NULL)
   1084 		return NULL;
   1085 
   1086 	p = eap_sim_db_get_pseudonym(data, identity, identity_len);
   1087 	if (p == NULL)
   1088 		p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
   1089 	if (p == NULL)
   1090 		return NULL;
   1091 
   1092 	*len = p->identity_len;
   1093 	return p->identity;
   1094 }
   1095 
   1096 
   1097 /**
   1098  * eap_sim_db_get_reauth_entry - EAP-SIM DB: Get re-authentication entry
   1099  * @priv: Private data pointer from eap_sim_db_init()
   1100  * @identity: Identity of the user (may be permanent identity, pseudonym, or
   1101  * reauth_id)
   1102  * @identity_len: Length of identity
   1103  * Returns: Pointer to the re-auth entry, or %NULL if not found
   1104  */
   1105 struct eap_sim_reauth *
   1106 eap_sim_db_get_reauth_entry(void *priv, const u8 *identity,
   1107 			    size_t identity_len)
   1108 {
   1109 	struct eap_sim_db_data *data = priv;
   1110 	struct eap_sim_reauth *r;
   1111 
   1112 	if (identity == NULL)
   1113 		return NULL;
   1114 	r = eap_sim_db_get_reauth(data, identity, identity_len);
   1115 	if (r == NULL)
   1116 		r = eap_sim_db_get_reauth_id(data, identity, identity_len);
   1117 	return r;
   1118 }
   1119 
   1120 
   1121 /**
   1122  * eap_sim_db_remove_reauth - EAP-SIM DB: Remove re-authentication entry
   1123  * @priv: Private data pointer from eap_sim_db_init()
   1124  * @reauth: Pointer to re-authentication entry from
   1125  * eap_sim_db_get_reauth_entry()
   1126  */
   1127 void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth)
   1128 {
   1129 	struct eap_sim_db_data *data = priv;
   1130 	struct eap_sim_reauth *r, *prev = NULL;
   1131 	r = data->reauths;
   1132 	while (r) {
   1133 		if (r == reauth) {
   1134 			if (prev)
   1135 				prev->next = r->next;
   1136 			else
   1137 				data->reauths = r->next;
   1138 			eap_sim_db_free_reauth(r);
   1139 			return;
   1140 		}
   1141 		prev = r;
   1142 		r = r->next;
   1143 	}
   1144 }
   1145 
   1146 
   1147 /**
   1148  * eap_sim_db_get_aka_auth - Get AKA authentication values
   1149  * @priv: Private data pointer from eap_sim_db_init()
   1150  * @identity: User name identity
   1151  * @identity_len: Length of identity in bytes
   1152  * @_rand: Buffer for RAND value
   1153  * @autn: Buffer for AUTN value
   1154  * @ik: Buffer for IK value
   1155  * @ck: Buffer for CK value
   1156  * @res: Buffer for RES value
   1157  * @res_len: Buffer for RES length
   1158  * @cb_session_ctx: Session callback context for get_complete_cb()
   1159  * Returns: 0 on success, -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not
   1160  * found), or -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this
   1161  * case, the callback function registered with eap_sim_db_init() will be
   1162  * called once the results become available.
   1163  *
   1164  * In most cases, the user name is '0' | IMSI, i.e., 0 followed by the IMSI in
   1165  * ASCII format.
   1166  *
   1167  * When using an external server for AKA authentication, this function can
   1168  * always start a request and return EAP_SIM_DB_PENDING immediately if
   1169  * authentication triplets are not available. Once the authentication data are
   1170  * received, callback function registered with eap_sim_db_init() is called to
   1171  * notify EAP state machine to reprocess the message. This
   1172  * eap_sim_db_get_aka_auth() function will then be called again and the newly
   1173  * received triplets will then be given to the caller.
   1174  */
   1175 int eap_sim_db_get_aka_auth(void *priv, const u8 *identity,
   1176 			    size_t identity_len, u8 *_rand, u8 *autn, u8 *ik,
   1177 			    u8 *ck, u8 *res, size_t *res_len,
   1178 			    void *cb_session_ctx)
   1179 {
   1180 	struct eap_sim_db_data *data = priv;
   1181 	struct eap_sim_db_pending *entry;
   1182 	int len;
   1183 	size_t i;
   1184 	char msg[40];
   1185 
   1186 	if (identity_len < 2 || identity == NULL ||
   1187 	    identity[0] != EAP_AKA_PERMANENT_PREFIX) {
   1188 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
   1189 				  identity, identity_len);
   1190 		return EAP_SIM_DB_FAILURE;
   1191 	}
   1192 	identity++;
   1193 	identity_len--;
   1194 	for (i = 0; i < identity_len; i++) {
   1195 		if (identity[i] == '@') {
   1196 			identity_len = i;
   1197 			break;
   1198 		}
   1199 	}
   1200 	if (identity_len + 1 > sizeof(entry->imsi)) {
   1201 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
   1202 				  identity, identity_len);
   1203 		return EAP_SIM_DB_FAILURE;
   1204 	}
   1205 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI",
   1206 			  identity, identity_len);
   1207 
   1208 	entry = eap_sim_db_get_pending(data, identity, identity_len, 1);
   1209 	if (entry) {
   1210 		if (entry->state == FAILURE) {
   1211 			os_free(entry);
   1212 			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failure");
   1213 			return EAP_SIM_DB_FAILURE;
   1214 		}
   1215 
   1216 		if (entry->state == PENDING) {
   1217 			eap_sim_db_add_pending(data, entry);
   1218 			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending");
   1219 			return EAP_SIM_DB_PENDING;
   1220 		}
   1221 
   1222 		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Returning successfully "
   1223 			   "received authentication data");
   1224 		os_memcpy(_rand, entry->u.aka.rand, EAP_AKA_RAND_LEN);
   1225 		os_memcpy(autn, entry->u.aka.autn, EAP_AKA_AUTN_LEN);
   1226 		os_memcpy(ik, entry->u.aka.ik, EAP_AKA_IK_LEN);
   1227 		os_memcpy(ck, entry->u.aka.ck, EAP_AKA_CK_LEN);
   1228 		os_memcpy(res, entry->u.aka.res, EAP_AKA_RES_MAX_LEN);
   1229 		*res_len = entry->u.aka.res_len;
   1230 		os_free(entry);
   1231 		return 0;
   1232 	}
   1233 
   1234 	if (data->sock < 0) {
   1235 		if (eap_sim_db_open_socket(data) < 0)
   1236 			return EAP_SIM_DB_FAILURE;
   1237 	}
   1238 
   1239 	len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH ");
   1240 	if (len < 0 || len + identity_len >= sizeof(msg))
   1241 		return EAP_SIM_DB_FAILURE;
   1242 	os_memcpy(msg + len, identity, identity_len);
   1243 	len += identity_len;
   1244 
   1245 	wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication "
   1246 		    "data for IMSI", identity, identity_len);
   1247 	if (eap_sim_db_send(data, msg, len) < 0)
   1248 		return EAP_SIM_DB_FAILURE;
   1249 
   1250 	entry = os_zalloc(sizeof(*entry));
   1251 	if (entry == NULL)
   1252 		return EAP_SIM_DB_FAILURE;
   1253 
   1254 	os_get_time(&entry->timestamp);
   1255 	entry->aka = 1;
   1256 	os_memcpy(entry->imsi, identity, identity_len);
   1257 	entry->imsi_len = identity_len;
   1258 	entry->cb_session_ctx = cb_session_ctx;
   1259 	entry->state = PENDING;
   1260 	eap_sim_db_add_pending(data, entry);
   1261 	eap_sim_db_expire_pending(data);
   1262 
   1263 	return EAP_SIM_DB_PENDING;
   1264 }
   1265 
   1266 
   1267 /**
   1268  * eap_sim_db_resynchronize - Resynchronize AKA AUTN
   1269  * @priv: Private data pointer from eap_sim_db_init()
   1270  * @identity: User name identity
   1271  * @identity_len: Length of identity in bytes
   1272  * @auts: AUTS value from the peer
   1273  * @_rand: RAND value used in the rejected message
   1274  * Returns: 0 on success, -1 on failure
   1275  *
   1276  * This function is called when the peer reports synchronization failure in the
   1277  * AUTN value by sending AUTS. The AUTS and RAND values should be sent to
   1278  * HLR/AuC to allow it to resynchronize with the peer. After this,
   1279  * eap_sim_db_get_aka_auth() will be called again to to fetch updated
   1280  * RAND/AUTN values for the next challenge.
   1281  */
   1282 int eap_sim_db_resynchronize(void *priv, const u8 *identity,
   1283 			     size_t identity_len, const u8 *auts,
   1284 			     const u8 *_rand)
   1285 {
   1286 	struct eap_sim_db_data *data = priv;
   1287 	size_t i;
   1288 
   1289 	if (identity_len < 2 || identity == NULL ||
   1290 	    identity[0] != EAP_AKA_PERMANENT_PREFIX) {
   1291 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
   1292 				  identity, identity_len);
   1293 		return -1;
   1294 	}
   1295 	identity++;
   1296 	identity_len--;
   1297 	for (i = 0; i < identity_len; i++) {
   1298 		if (identity[i] == '@') {
   1299 			identity_len = i;
   1300 			break;
   1301 		}
   1302 	}
   1303 	if (identity_len > 20) {
   1304 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
   1305 				  identity, identity_len);
   1306 		return -1;
   1307 	}
   1308 
   1309 	if (data->sock >= 0) {
   1310 		char msg[100];
   1311 		int len, ret;
   1312 
   1313 		len = os_snprintf(msg, sizeof(msg), "AKA-AUTS ");
   1314 		if (len < 0 || len + identity_len >= sizeof(msg))
   1315 			return -1;
   1316 		os_memcpy(msg + len, identity, identity_len);
   1317 		len += identity_len;
   1318 
   1319 		ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
   1320 		if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
   1321 			return -1;
   1322 		len += ret;
   1323 		len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
   1324 					auts, EAP_AKA_AUTS_LEN);
   1325 		ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
   1326 		if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
   1327 			return -1;
   1328 		len += ret;
   1329 		len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
   1330 					_rand, EAP_AKA_RAND_LEN);
   1331 		wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for "
   1332 			    "IMSI", identity, identity_len);
   1333 		if (eap_sim_db_send(data, msg, len) < 0)
   1334 			return -1;
   1335 	}
   1336 
   1337 	return 0;
   1338 }
   1339