Home | History | Annotate | Download | only in eap_server
      1 /*
      2  * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf)
      3  * Copyright (c) 2005-2008, 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 
     15 #include "includes.h"
     16 
     17 #include "common.h"
     18 #include "eap_server/eap_i.h"
     19 #include "eap_common/eap_sim_common.h"
     20 #include "eap_server/eap_sim_db.h"
     21 #include "sha1.h"
     22 #include "sha256.h"
     23 #include "crypto.h"
     24 
     25 
     26 struct eap_aka_data {
     27 	u8 mk[EAP_SIM_MK_LEN];
     28 	u8 nonce_s[EAP_SIM_NONCE_S_LEN];
     29 	u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
     30 	u8 k_encr[EAP_SIM_K_ENCR_LEN];
     31 	u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */
     32 	u8 msk[EAP_SIM_KEYING_DATA_LEN];
     33 	u8 emsk[EAP_EMSK_LEN];
     34 	u8 rand[EAP_AKA_RAND_LEN];
     35 	u8 autn[EAP_AKA_AUTN_LEN];
     36 	u8 ck[EAP_AKA_CK_LEN];
     37 	u8 ik[EAP_AKA_IK_LEN];
     38 	u8 res[EAP_AKA_RES_MAX_LEN];
     39 	size_t res_len;
     40 	enum {
     41 		IDENTITY, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE
     42 	} state;
     43 	char *next_pseudonym;
     44 	char *next_reauth_id;
     45 	u16 counter;
     46 	struct eap_sim_reauth *reauth;
     47 	int auts_reported; /* whether the current AUTS has been reported to the
     48 			    * eap_sim_db */
     49 	u16 notification;
     50 	int use_result_ind;
     51 
     52 	struct wpabuf *id_msgs;
     53 	int pending_id;
     54 	u8 eap_method;
     55 	u8 *network_name;
     56 	size_t network_name_len;
     57 	u16 kdf;
     58 };
     59 
     60 
     61 static void eap_aka_determine_identity(struct eap_sm *sm,
     62 				       struct eap_aka_data *data,
     63 				       int before_identity, int after_reauth);
     64 
     65 
     66 static const char * eap_aka_state_txt(int state)
     67 {
     68 	switch (state) {
     69 	case IDENTITY:
     70 		return "IDENTITY";
     71 	case CHALLENGE:
     72 		return "CHALLENGE";
     73 	case REAUTH:
     74 		return "REAUTH";
     75 	case SUCCESS:
     76 		return "SUCCESS";
     77 	case FAILURE:
     78 		return "FAILURE";
     79 	case NOTIFICATION:
     80 		return "NOTIFICATION";
     81 	default:
     82 		return "Unknown?!";
     83 	}
     84 }
     85 
     86 
     87 static void eap_aka_state(struct eap_aka_data *data, int state)
     88 {
     89 	wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s",
     90 		   eap_aka_state_txt(data->state),
     91 		   eap_aka_state_txt(state));
     92 	data->state = state;
     93 }
     94 
     95 
     96 static void * eap_aka_init(struct eap_sm *sm)
     97 {
     98 	struct eap_aka_data *data;
     99 
    100 	if (sm->eap_sim_db_priv == NULL) {
    101 		wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
    102 		return NULL;
    103 	}
    104 
    105 	data = os_zalloc(sizeof(*data));
    106 	if (data == NULL)
    107 		return NULL;
    108 
    109 	data->eap_method = EAP_TYPE_AKA;
    110 
    111 	data->state = IDENTITY;
    112 	eap_aka_determine_identity(sm, data, 1, 0);
    113 	data->pending_id = -1;
    114 
    115 	return data;
    116 }
    117 
    118 
    119 #ifdef EAP_AKA_PRIME
    120 static void * eap_aka_prime_init(struct eap_sm *sm)
    121 {
    122 	struct eap_aka_data *data;
    123 	/* TODO: make ANID configurable; see 3GPP TS 24.302 */
    124 	char *network_name = "WLAN";
    125 
    126 	if (sm->eap_sim_db_priv == NULL) {
    127 		wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
    128 		return NULL;
    129 	}
    130 
    131 	data = os_zalloc(sizeof(*data));
    132 	if (data == NULL)
    133 		return NULL;
    134 
    135 	data->eap_method = EAP_TYPE_AKA_PRIME;
    136 	data->network_name = os_malloc(os_strlen(network_name));
    137 	if (data->network_name == NULL) {
    138 		os_free(data);
    139 		return NULL;
    140 	}
    141 
    142 	data->network_name_len = os_strlen(network_name);
    143 	os_memcpy(data->network_name, network_name, data->network_name_len);
    144 
    145 	data->state = IDENTITY;
    146 	eap_aka_determine_identity(sm, data, 1, 0);
    147 	data->pending_id = -1;
    148 
    149 	return data;
    150 }
    151 #endif /* EAP_AKA_PRIME */
    152 
    153 
    154 static void eap_aka_reset(struct eap_sm *sm, void *priv)
    155 {
    156 	struct eap_aka_data *data = priv;
    157 	os_free(data->next_pseudonym);
    158 	os_free(data->next_reauth_id);
    159 	wpabuf_free(data->id_msgs);
    160 	os_free(data->network_name);
    161 	os_free(data);
    162 }
    163 
    164 
    165 static int eap_aka_add_id_msg(struct eap_aka_data *data,
    166 			      const struct wpabuf *msg)
    167 {
    168 	if (msg == NULL)
    169 		return -1;
    170 
    171 	if (data->id_msgs == NULL) {
    172 		data->id_msgs = wpabuf_dup(msg);
    173 		return data->id_msgs == NULL ? -1 : 0;
    174 	}
    175 
    176 	if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0)
    177 		return -1;
    178 	wpabuf_put_buf(data->id_msgs, msg);
    179 
    180 	return 0;
    181 }
    182 
    183 
    184 static void eap_aka_add_checkcode(struct eap_aka_data *data,
    185 				  struct eap_sim_msg *msg)
    186 {
    187 	const u8 *addr;
    188 	size_t len;
    189 	u8 hash[SHA256_MAC_LEN];
    190 
    191 	wpa_printf(MSG_DEBUG, "   AT_CHECKCODE");
    192 
    193 	if (data->id_msgs == NULL) {
    194 		/*
    195 		 * No EAP-AKA/Identity packets were exchanged - send empty
    196 		 * checkcode.
    197 		 */
    198 		eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0);
    199 		return;
    200 	}
    201 
    202 	/* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
    203 	addr = wpabuf_head(data->id_msgs);
    204 	len = wpabuf_len(data->id_msgs);
    205 	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len);
    206 	if (data->eap_method == EAP_TYPE_AKA_PRIME)
    207 		sha256_vector(1, &addr, &len, hash);
    208 	else
    209 		sha1_vector(1, &addr, &len, hash);
    210 
    211 	eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash,
    212 			data->eap_method == EAP_TYPE_AKA_PRIME ?
    213 			EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN);
    214 }
    215 
    216 
    217 static int eap_aka_verify_checkcode(struct eap_aka_data *data,
    218 				    const u8 *checkcode, size_t checkcode_len)
    219 {
    220 	const u8 *addr;
    221 	size_t len;
    222 	u8 hash[SHA256_MAC_LEN];
    223 	size_t hash_len;
    224 
    225 	if (checkcode == NULL)
    226 		return -1;
    227 
    228 	if (data->id_msgs == NULL) {
    229 		if (checkcode_len != 0) {
    230 			wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer "
    231 				   "indicates that AKA/Identity messages were "
    232 				   "used, but they were not");
    233 			return -1;
    234 		}
    235 		return 0;
    236 	}
    237 
    238 	hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ?
    239 		EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN;
    240 
    241 	if (checkcode_len != hash_len) {
    242 		wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer indicates "
    243 			   "that AKA/Identity message were not used, but they "
    244 			   "were");
    245 		return -1;
    246 	}
    247 
    248 	/* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
    249 	addr = wpabuf_head(data->id_msgs);
    250 	len = wpabuf_len(data->id_msgs);
    251 	if (data->eap_method == EAP_TYPE_AKA_PRIME)
    252 		sha256_vector(1, &addr, &len, hash);
    253 	else
    254 		sha1_vector(1, &addr, &len, hash);
    255 
    256 	if (os_memcmp(hash, checkcode, hash_len) != 0) {
    257 		wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
    258 		return -1;
    259 	}
    260 
    261 	return 0;
    262 }
    263 
    264 
    265 static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm,
    266 					      struct eap_aka_data *data, u8 id)
    267 {
    268 	struct eap_sim_msg *msg;
    269 	struct wpabuf *buf;
    270 
    271 	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity");
    272 	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
    273 			       EAP_AKA_SUBTYPE_IDENTITY);
    274 	if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
    275 				      sm->identity_len)) {
    276 		wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
    277 		eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
    278 	} else {
    279 		/*
    280 		 * RFC 4187, Chap. 4.1.4 recommends that identity from EAP is
    281 		 * ignored and the AKA/Identity is used to request the
    282 		 * identity.
    283 		 */
    284 		wpa_printf(MSG_DEBUG, "   AT_ANY_ID_REQ");
    285 		eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
    286 	}
    287 	buf = eap_sim_msg_finish(msg, NULL, NULL, 0);
    288 	if (eap_aka_add_id_msg(data, buf) < 0) {
    289 		wpabuf_free(buf);
    290 		return NULL;
    291 	}
    292 	data->pending_id = id;
    293 	return buf;
    294 }
    295 
    296 
    297 static int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data,
    298 			      struct eap_sim_msg *msg, u16 counter,
    299 			      const u8 *nonce_s)
    300 {
    301 	os_free(data->next_pseudonym);
    302 	data->next_pseudonym =
    303 		eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 1);
    304 	os_free(data->next_reauth_id);
    305 	if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) {
    306 		data->next_reauth_id =
    307 			eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 1);
    308 	} else {
    309 		wpa_printf(MSG_DEBUG, "EAP-AKA: Max fast re-authentication "
    310 			   "count exceeded - force full authentication");
    311 		data->next_reauth_id = NULL;
    312 	}
    313 
    314 	if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
    315 	    counter == 0 && nonce_s == NULL)
    316 		return 0;
    317 
    318 	wpa_printf(MSG_DEBUG, "   AT_IV");
    319 	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
    320 	eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
    321 
    322 	if (counter > 0) {
    323 		wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)", counter);
    324 		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
    325 	}
    326 
    327 	if (nonce_s) {
    328 		wpa_printf(MSG_DEBUG, "   *AT_NONCE_S");
    329 		eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
    330 				EAP_SIM_NONCE_S_LEN);
    331 	}
    332 
    333 	if (data->next_pseudonym) {
    334 		wpa_printf(MSG_DEBUG, "   *AT_NEXT_PSEUDONYM (%s)",
    335 			   data->next_pseudonym);
    336 		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
    337 				os_strlen(data->next_pseudonym),
    338 				(u8 *) data->next_pseudonym,
    339 				os_strlen(data->next_pseudonym));
    340 	}
    341 
    342 	if (data->next_reauth_id) {
    343 		wpa_printf(MSG_DEBUG, "   *AT_NEXT_REAUTH_ID (%s)",
    344 			   data->next_reauth_id);
    345 		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
    346 				os_strlen(data->next_reauth_id),
    347 				(u8 *) data->next_reauth_id,
    348 				os_strlen(data->next_reauth_id));
    349 	}
    350 
    351 	if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
    352 		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
    353 			   "AT_ENCR_DATA");
    354 		return -1;
    355 	}
    356 
    357 	return 0;
    358 }
    359 
    360 
    361 static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm,
    362 					       struct eap_aka_data *data,
    363 					       u8 id)
    364 {
    365 	struct eap_sim_msg *msg;
    366 
    367 	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Challenge");
    368 	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
    369 			       EAP_AKA_SUBTYPE_CHALLENGE);
    370 	wpa_printf(MSG_DEBUG, "   AT_RAND");
    371 	eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, data->rand, EAP_AKA_RAND_LEN);
    372 	wpa_printf(MSG_DEBUG, "   AT_AUTN");
    373 	eap_sim_msg_add(msg, EAP_SIM_AT_AUTN, 0, data->autn, EAP_AKA_AUTN_LEN);
    374 	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
    375 		if (data->kdf) {
    376 			/* Add the selected KDF into the beginning */
    377 			wpa_printf(MSG_DEBUG, "   AT_KDF");
    378 			eap_sim_msg_add(msg, EAP_SIM_AT_KDF, data->kdf,
    379 					NULL, 0);
    380 		}
    381 		wpa_printf(MSG_DEBUG, "   AT_KDF");
    382 		eap_sim_msg_add(msg, EAP_SIM_AT_KDF, EAP_AKA_PRIME_KDF,
    383 				NULL, 0);
    384 		wpa_printf(MSG_DEBUG, "   AT_KDF_INPUT");
    385 		eap_sim_msg_add(msg, EAP_SIM_AT_KDF_INPUT,
    386 				data->network_name_len,
    387 				data->network_name, data->network_name_len);
    388 	}
    389 
    390 	if (eap_aka_build_encr(sm, data, msg, 0, NULL)) {
    391 		eap_sim_msg_free(msg);
    392 		return NULL;
    393 	}
    394 
    395 	eap_aka_add_checkcode(data, msg);
    396 
    397 	if (sm->eap_sim_aka_result_ind) {
    398 		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
    399 		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
    400 	}
    401 
    402 #ifdef EAP_AKA_PRIME
    403 	if (data->eap_method == EAP_TYPE_AKA) {
    404 		u16 flags = 0;
    405 		int i;
    406 		int aka_prime_preferred = 0;
    407 
    408 		i = 0;
    409 		while (sm->user && i < EAP_MAX_METHODS &&
    410 		       (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
    411 			sm->user->methods[i].method != EAP_TYPE_NONE)) {
    412 			if (sm->user->methods[i].vendor == EAP_VENDOR_IETF) {
    413 				if (sm->user->methods[i].method ==
    414 				    EAP_TYPE_AKA)
    415 					break;
    416 				if (sm->user->methods[i].method ==
    417 				    EAP_TYPE_AKA_PRIME) {
    418 					aka_prime_preferred = 1;
    419 					break;
    420 				}
    421 			}
    422 			i++;
    423 		}
    424 
    425 		if (aka_prime_preferred)
    426 			flags |= EAP_AKA_BIDDING_FLAG_D;
    427 		eap_sim_msg_add(msg, EAP_SIM_AT_BIDDING, flags, NULL, 0);
    428 	}
    429 #endif /* EAP_AKA_PRIME */
    430 
    431 	wpa_printf(MSG_DEBUG, "   AT_MAC");
    432 	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
    433 	return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
    434 }
    435 
    436 
    437 static struct wpabuf * eap_aka_build_reauth(struct eap_sm *sm,
    438 					    struct eap_aka_data *data, u8 id)
    439 {
    440 	struct eap_sim_msg *msg;
    441 
    442 	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Re-authentication");
    443 
    444 	if (os_get_random(data->nonce_s, EAP_SIM_NONCE_S_LEN))
    445 		return NULL;
    446 	wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA: NONCE_S",
    447 			data->nonce_s, EAP_SIM_NONCE_S_LEN);
    448 
    449 	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
    450 		eap_aka_prime_derive_keys_reauth(data->k_re, data->counter,
    451 						 sm->identity,
    452 						 sm->identity_len,
    453 						 data->nonce_s,
    454 						 data->msk, data->emsk);
    455 	} else {
    456 		eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
    457 				    data->msk, data->emsk);
    458 		eap_sim_derive_keys_reauth(data->counter, sm->identity,
    459 					   sm->identity_len, data->nonce_s,
    460 					   data->mk, data->msk, data->emsk);
    461 	}
    462 
    463 	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
    464 			       EAP_AKA_SUBTYPE_REAUTHENTICATION);
    465 
    466 	if (eap_aka_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
    467 		eap_sim_msg_free(msg);
    468 		return NULL;
    469 	}
    470 
    471 	eap_aka_add_checkcode(data, msg);
    472 
    473 	if (sm->eap_sim_aka_result_ind) {
    474 		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
    475 		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
    476 	}
    477 
    478 	wpa_printf(MSG_DEBUG, "   AT_MAC");
    479 	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
    480 	return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
    481 }
    482 
    483 
    484 static struct wpabuf * eap_aka_build_notification(struct eap_sm *sm,
    485 						  struct eap_aka_data *data,
    486 						  u8 id)
    487 {
    488 	struct eap_sim_msg *msg;
    489 
    490 	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Notification");
    491 	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
    492 			       EAP_AKA_SUBTYPE_NOTIFICATION);
    493 	wpa_printf(MSG_DEBUG, "   AT_NOTIFICATION (%d)", data->notification);
    494 	eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification,
    495 			NULL, 0);
    496 	if (data->use_result_ind) {
    497 		if (data->reauth) {
    498 			wpa_printf(MSG_DEBUG, "   AT_IV");
    499 			wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
    500 			eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
    501 						   EAP_SIM_AT_ENCR_DATA);
    502 			wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)",
    503 				   data->counter);
    504 			eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
    505 					NULL, 0);
    506 
    507 			if (eap_sim_msg_add_encr_end(msg, data->k_encr,
    508 						     EAP_SIM_AT_PADDING)) {
    509 				wpa_printf(MSG_WARNING, "EAP-AKA: Failed to "
    510 					   "encrypt AT_ENCR_DATA");
    511 				eap_sim_msg_free(msg);
    512 				return NULL;
    513 			}
    514 		}
    515 
    516 		wpa_printf(MSG_DEBUG, "   AT_MAC");
    517 		eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
    518 	}
    519 	return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
    520 }
    521 
    522 
    523 static struct wpabuf * eap_aka_buildReq(struct eap_sm *sm, void *priv, u8 id)
    524 {
    525 	struct eap_aka_data *data = priv;
    526 
    527 	data->auts_reported = 0;
    528 	switch (data->state) {
    529 	case IDENTITY:
    530 		return eap_aka_build_identity(sm, data, id);
    531 	case CHALLENGE:
    532 		return eap_aka_build_challenge(sm, data, id);
    533 	case REAUTH:
    534 		return eap_aka_build_reauth(sm, data, id);
    535 	case NOTIFICATION:
    536 		return eap_aka_build_notification(sm, data, id);
    537 	default:
    538 		wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
    539 			   "buildReq", data->state);
    540 		break;
    541 	}
    542 	return NULL;
    543 }
    544 
    545 
    546 static Boolean eap_aka_check(struct eap_sm *sm, void *priv,
    547 			     struct wpabuf *respData)
    548 {
    549 	struct eap_aka_data *data = priv;
    550 	const u8 *pos;
    551 	size_t len;
    552 
    553 	pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
    554 			       &len);
    555 	if (pos == NULL || len < 3) {
    556 		wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame");
    557 		return TRUE;
    558 	}
    559 
    560 	return FALSE;
    561 }
    562 
    563 
    564 static Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype)
    565 {
    566 	if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR ||
    567 	    subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT)
    568 		return FALSE;
    569 
    570 	switch (data->state) {
    571 	case IDENTITY:
    572 		if (subtype != EAP_AKA_SUBTYPE_IDENTITY) {
    573 			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
    574 				   "subtype %d", subtype);
    575 			return TRUE;
    576 		}
    577 		break;
    578 	case CHALLENGE:
    579 		if (subtype != EAP_AKA_SUBTYPE_CHALLENGE &&
    580 		    subtype != EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
    581 			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
    582 				   "subtype %d", subtype);
    583 			return TRUE;
    584 		}
    585 		break;
    586 	case REAUTH:
    587 		if (subtype != EAP_AKA_SUBTYPE_REAUTHENTICATION) {
    588 			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
    589 				   "subtype %d", subtype);
    590 			return TRUE;
    591 		}
    592 		break;
    593 	case NOTIFICATION:
    594 		if (subtype != EAP_AKA_SUBTYPE_NOTIFICATION) {
    595 			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
    596 				   "subtype %d", subtype);
    597 			return TRUE;
    598 		}
    599 		break;
    600 	default:
    601 		wpa_printf(MSG_INFO, "EAP-AKA: Unexpected state (%d) for "
    602 			   "processing a response", data->state);
    603 		return TRUE;
    604 	}
    605 
    606 	return FALSE;
    607 }
    608 
    609 
    610 static void eap_aka_determine_identity(struct eap_sm *sm,
    611 				       struct eap_aka_data *data,
    612 				       int before_identity, int after_reauth)
    613 {
    614 	const u8 *identity;
    615 	size_t identity_len;
    616 	int res;
    617 
    618 	identity = NULL;
    619 	identity_len = 0;
    620 
    621 	if (after_reauth && data->reauth) {
    622 		identity = data->reauth->identity;
    623 		identity_len = data->reauth->identity_len;
    624 	} else if (sm->identity && sm->identity_len > 0 &&
    625 		   sm->identity[0] == EAP_AKA_PERMANENT_PREFIX) {
    626 		identity = sm->identity;
    627 		identity_len = sm->identity_len;
    628 	} else {
    629 		identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv,
    630 						    sm->identity,
    631 						    sm->identity_len,
    632 						    &identity_len);
    633 		if (identity == NULL) {
    634 			data->reauth = eap_sim_db_get_reauth_entry(
    635 				sm->eap_sim_db_priv, sm->identity,
    636 				sm->identity_len);
    637 			if (data->reauth &&
    638 			    data->reauth->aka_prime !=
    639 			    (data->eap_method == EAP_TYPE_AKA_PRIME)) {
    640 				wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth data "
    641 					   "was for different AKA version");
    642 				data->reauth = NULL;
    643 			}
    644 			if (data->reauth) {
    645 				wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast "
    646 					   "re-authentication");
    647 				identity = data->reauth->identity;
    648 				identity_len = data->reauth->identity_len;
    649 				data->counter = data->reauth->counter;
    650 				if (data->eap_method == EAP_TYPE_AKA_PRIME) {
    651 					os_memcpy(data->k_encr,
    652 						  data->reauth->k_encr,
    653 						  EAP_SIM_K_ENCR_LEN);
    654 					os_memcpy(data->k_aut,
    655 						  data->reauth->k_aut,
    656 						  EAP_AKA_PRIME_K_AUT_LEN);
    657 					os_memcpy(data->k_re,
    658 						  data->reauth->k_re,
    659 						  EAP_AKA_PRIME_K_RE_LEN);
    660 				} else {
    661 					os_memcpy(data->mk, data->reauth->mk,
    662 						  EAP_SIM_MK_LEN);
    663 				}
    664 			}
    665 		}
    666 	}
    667 
    668 	if (identity == NULL ||
    669 	    eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
    670 				      sm->identity_len) < 0) {
    671 		if (before_identity) {
    672 			wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent user name "
    673 				   "not known - send AKA-Identity request");
    674 			eap_aka_state(data, IDENTITY);
    675 			return;
    676 		} else {
    677 			wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown whether the "
    678 				   "permanent user name is known; try to use "
    679 				   "it");
    680 			/* eap_sim_db_get_aka_auth() will report failure, if
    681 			 * this identity is not known. */
    682 		}
    683 	}
    684 
    685 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity",
    686 			  identity, identity_len);
    687 
    688 	if (!after_reauth && data->reauth) {
    689 		eap_aka_state(data, REAUTH);
    690 		return;
    691 	}
    692 
    693 	res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, identity,
    694 				      identity_len, data->rand, data->autn,
    695 				      data->ik, data->ck, data->res,
    696 				      &data->res_len, sm);
    697 	if (res == EAP_SIM_DB_PENDING) {
    698 		wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
    699 			   "not yet available - pending request");
    700 		sm->method_pending = METHOD_PENDING_WAIT;
    701 		return;
    702 	}
    703 
    704 #ifdef EAP_AKA_PRIME
    705 	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
    706 		/* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
    707 		 * needed 6-octet SQN ^AK for CK',IK' derivation */
    708 		eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
    709 						 data->autn,
    710 						 data->network_name,
    711 						 data->network_name_len);
    712 	}
    713 #endif /* EAP_AKA_PRIME */
    714 
    715 	data->reauth = NULL;
    716 	data->counter = 0; /* reset re-auth counter since this is full auth */
    717 
    718 	if (res != 0) {
    719 		wpa_printf(MSG_INFO, "EAP-AKA: Failed to get AKA "
    720 			   "authentication data for the peer");
    721 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
    722 		eap_aka_state(data, NOTIFICATION);
    723 		return;
    724 	}
    725 	if (sm->method_pending == METHOD_PENDING_WAIT) {
    726 		wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
    727 			   "available - abort pending wait");
    728 		sm->method_pending = METHOD_PENDING_NONE;
    729 	}
    730 
    731 	identity_len = sm->identity_len;
    732 	while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') {
    733 		wpa_printf(MSG_DEBUG, "EAP-AKA: Workaround - drop last null "
    734 			   "character from identity");
    735 		identity_len--;
    736 	}
    737 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation",
    738 			  sm->identity, identity_len);
    739 
    740 	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
    741 		eap_aka_prime_derive_keys(identity, identity_len, data->ik,
    742 					  data->ck, data->k_encr, data->k_aut,
    743 					  data->k_re, data->msk, data->emsk);
    744 	} else {
    745 		eap_aka_derive_mk(sm->identity, identity_len, data->ik,
    746 				  data->ck, data->mk);
    747 		eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
    748 				    data->msk, data->emsk);
    749 	}
    750 
    751 	eap_aka_state(data, CHALLENGE);
    752 }
    753 
    754 
    755 static void eap_aka_process_identity(struct eap_sm *sm,
    756 				     struct eap_aka_data *data,
    757 				     struct wpabuf *respData,
    758 				     struct eap_sim_attrs *attr)
    759 {
    760 	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Identity");
    761 
    762 	if (attr->mac || attr->iv || attr->encr_data) {
    763 		wpa_printf(MSG_WARNING, "EAP-AKA: Unexpected attribute "
    764 			   "received in EAP-Response/AKA-Identity");
    765 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
    766 		eap_aka_state(data, NOTIFICATION);
    767 		return;
    768 	}
    769 
    770 	if (attr->identity) {
    771 		os_free(sm->identity);
    772 		sm->identity = os_malloc(attr->identity_len);
    773 		if (sm->identity) {
    774 			os_memcpy(sm->identity, attr->identity,
    775 				  attr->identity_len);
    776 			sm->identity_len = attr->identity_len;
    777 		}
    778 	}
    779 
    780 	eap_aka_determine_identity(sm, data, 0, 0);
    781 	if (eap_get_id(respData) == data->pending_id) {
    782 		data->pending_id = -1;
    783 		eap_aka_add_id_msg(data, respData);
    784 	}
    785 }
    786 
    787 
    788 static int eap_aka_verify_mac(struct eap_aka_data *data,
    789 			      const struct wpabuf *req,
    790 			      const u8 *mac, const u8 *extra,
    791 			      size_t extra_len)
    792 {
    793 	if (data->eap_method == EAP_TYPE_AKA_PRIME)
    794 		return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra,
    795 						 extra_len);
    796 	return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len);
    797 }
    798 
    799 
    800 static void eap_aka_process_challenge(struct eap_sm *sm,
    801 				      struct eap_aka_data *data,
    802 				      struct wpabuf *respData,
    803 				      struct eap_sim_attrs *attr)
    804 {
    805 	const u8 *identity;
    806 	size_t identity_len;
    807 
    808 	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge");
    809 
    810 #ifdef EAP_AKA_PRIME
    811 #if 0
    812 	/* KDF negotiation; to be enabled only after more than one KDF is
    813 	 * supported */
    814 	if (data->eap_method == EAP_TYPE_AKA_PRIME &&
    815 	    attr->kdf_count == 1 && attr->mac == NULL) {
    816 		if (attr->kdf[0] != EAP_AKA_PRIME_KDF) {
    817 			wpa_printf(MSG_WARNING, "EAP-AKA': Peer selected "
    818 				   "unknown KDF");
    819 			data->notification =
    820 				EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
    821 			eap_aka_state(data, NOTIFICATION);
    822 			return;
    823 		}
    824 
    825 		data->kdf = attr->kdf[0];
    826 
    827 		/* Allow negotiation to continue with the selected KDF by
    828 		 * sending another Challenge message */
    829 		wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf);
    830 		return;
    831 	}
    832 #endif
    833 #endif /* EAP_AKA_PRIME */
    834 
    835 	if (attr->checkcode &&
    836 	    eap_aka_verify_checkcode(data, attr->checkcode,
    837 				     attr->checkcode_len)) {
    838 		wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
    839 			   "message");
    840 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
    841 		eap_aka_state(data, NOTIFICATION);
    842 		return;
    843 	}
    844 	if (attr->mac == NULL ||
    845 	    eap_aka_verify_mac(data, respData, attr->mac, NULL, 0)) {
    846 		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
    847 			   "did not include valid AT_MAC");
    848 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
    849 		eap_aka_state(data, NOTIFICATION);
    850 		return;
    851 	}
    852 
    853 	/*
    854 	 * AT_RES is padded, so verify that there is enough room for RES and
    855 	 * that the RES length in bits matches with the expected RES.
    856 	 */
    857 	if (attr->res == NULL || attr->res_len < data->res_len ||
    858 	    attr->res_len_bits != data->res_len * 8 ||
    859 	    os_memcmp(attr->res, data->res, data->res_len) != 0) {
    860 		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message did not "
    861 			   "include valid AT_RES (attr len=%lu, res len=%lu "
    862 			   "bits, expected %lu bits)",
    863 			   (unsigned long) attr->res_len,
    864 			   (unsigned long) attr->res_len_bits,
    865 			   (unsigned long) data->res_len * 8);
    866 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
    867 		eap_aka_state(data, NOTIFICATION);
    868 		return;
    869 	}
    870 
    871 	wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the "
    872 		   "correct AT_MAC");
    873 	if (sm->eap_sim_aka_result_ind && attr->result_ind) {
    874 		data->use_result_ind = 1;
    875 		data->notification = EAP_SIM_SUCCESS;
    876 		eap_aka_state(data, NOTIFICATION);
    877 	} else
    878 		eap_aka_state(data, SUCCESS);
    879 
    880 	identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity,
    881 					    sm->identity_len, &identity_len);
    882 	if (identity == NULL) {
    883 		identity = sm->identity;
    884 		identity_len = sm->identity_len;
    885 	}
    886 
    887 	if (data->next_pseudonym) {
    888 		eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
    889 					 identity_len,
    890 					 data->next_pseudonym);
    891 		data->next_pseudonym = NULL;
    892 	}
    893 	if (data->next_reauth_id) {
    894 		if (data->eap_method == EAP_TYPE_AKA_PRIME) {
    895 #ifdef EAP_AKA_PRIME
    896 			eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
    897 						    identity,
    898 						    identity_len,
    899 						    data->next_reauth_id,
    900 						    data->counter + 1,
    901 						    data->k_encr, data->k_aut,
    902 						    data->k_re);
    903 #endif /* EAP_AKA_PRIME */
    904 		} else {
    905 			eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
    906 					      identity_len,
    907 					      data->next_reauth_id,
    908 					      data->counter + 1,
    909 					      data->mk);
    910 		}
    911 		data->next_reauth_id = NULL;
    912 	}
    913 }
    914 
    915 
    916 static void eap_aka_process_sync_failure(struct eap_sm *sm,
    917 					 struct eap_aka_data *data,
    918 					 struct wpabuf *respData,
    919 					 struct eap_sim_attrs *attr)
    920 {
    921 	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Synchronization-Failure");
    922 
    923 	if (attr->auts == NULL) {
    924 		wpa_printf(MSG_WARNING, "EAP-AKA: Synchronization-Failure "
    925 			   "message did not include valid AT_AUTS");
    926 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
    927 		eap_aka_state(data, NOTIFICATION);
    928 		return;
    929 	}
    930 
    931 	/* Avoid re-reporting AUTS when processing pending EAP packet by
    932 	 * maintaining a local flag stating whether this AUTS has already been
    933 	 * reported. */
    934 	if (!data->auts_reported &&
    935 	    eap_sim_db_resynchronize(sm->eap_sim_db_priv, sm->identity,
    936 				     sm->identity_len, attr->auts,
    937 				     data->rand)) {
    938 		wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed");
    939 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
    940 		eap_aka_state(data, NOTIFICATION);
    941 		return;
    942 	}
    943 	data->auts_reported = 1;
    944 
    945 	/* Try again after resynchronization */
    946 	eap_aka_determine_identity(sm, data, 0, 0);
    947 }
    948 
    949 
    950 static void eap_aka_process_reauth(struct eap_sm *sm,
    951 				   struct eap_aka_data *data,
    952 				   struct wpabuf *respData,
    953 				   struct eap_sim_attrs *attr)
    954 {
    955 	struct eap_sim_attrs eattr;
    956 	u8 *decrypted = NULL;
    957 	const u8 *identity, *id2;
    958 	size_t identity_len, id2_len;
    959 
    960 	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication");
    961 
    962 	if (attr->mac == NULL ||
    963 	    eap_aka_verify_mac(data, respData, attr->mac, data->nonce_s,
    964 			       EAP_SIM_NONCE_S_LEN)) {
    965 		wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
    966 			   "did not include valid AT_MAC");
    967 		goto fail;
    968 	}
    969 
    970 	if (attr->encr_data == NULL || attr->iv == NULL) {
    971 		wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
    972 			   "message did not include encrypted data");
    973 		goto fail;
    974 	}
    975 
    976 	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
    977 				       attr->encr_data_len, attr->iv, &eattr,
    978 				       0);
    979 	if (decrypted == NULL) {
    980 		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
    981 			   "data from reauthentication message");
    982 		goto fail;
    983 	}
    984 
    985 	if (eattr.counter != data->counter) {
    986 		wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
    987 			   "used incorrect counter %u, expected %u",
    988 			   eattr.counter, data->counter);
    989 		goto fail;
    990 	}
    991 	os_free(decrypted);
    992 	decrypted = NULL;
    993 
    994 	wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response includes "
    995 		   "the correct AT_MAC");
    996 
    997 	if (eattr.counter_too_small) {
    998 		wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response "
    999 			   "included AT_COUNTER_TOO_SMALL - starting full "
   1000 			   "authentication");
   1001 		eap_aka_determine_identity(sm, data, 0, 1);
   1002 		return;
   1003 	}
   1004 
   1005 	if (sm->eap_sim_aka_result_ind && attr->result_ind) {
   1006 		data->use_result_ind = 1;
   1007 		data->notification = EAP_SIM_SUCCESS;
   1008 		eap_aka_state(data, NOTIFICATION);
   1009 	} else
   1010 		eap_aka_state(data, SUCCESS);
   1011 
   1012 	if (data->reauth) {
   1013 		identity = data->reauth->identity;
   1014 		identity_len = data->reauth->identity_len;
   1015 	} else {
   1016 		identity = sm->identity;
   1017 		identity_len = sm->identity_len;
   1018 	}
   1019 
   1020 	id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity,
   1021 				       identity_len, &id2_len);
   1022 	if (id2) {
   1023 		identity = id2;
   1024 		identity_len = id2_len;
   1025 	}
   1026 
   1027 	if (data->next_pseudonym) {
   1028 		eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
   1029 					 identity_len, data->next_pseudonym);
   1030 		data->next_pseudonym = NULL;
   1031 	}
   1032 	if (data->next_reauth_id) {
   1033 		if (data->eap_method == EAP_TYPE_AKA_PRIME) {
   1034 #ifdef EAP_AKA_PRIME
   1035 			eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
   1036 						    identity,
   1037 						    identity_len,
   1038 						    data->next_reauth_id,
   1039 						    data->counter + 1,
   1040 						    data->k_encr, data->k_aut,
   1041 						    data->k_re);
   1042 #endif /* EAP_AKA_PRIME */
   1043 		} else {
   1044 			eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
   1045 					      identity_len,
   1046 					      data->next_reauth_id,
   1047 					      data->counter + 1,
   1048 					      data->mk);
   1049 		}
   1050 		data->next_reauth_id = NULL;
   1051 	} else {
   1052 		eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
   1053 		data->reauth = NULL;
   1054 	}
   1055 
   1056 	return;
   1057 
   1058 fail:
   1059 	data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
   1060 	eap_aka_state(data, NOTIFICATION);
   1061 	eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
   1062 	data->reauth = NULL;
   1063 	os_free(decrypted);
   1064 }
   1065 
   1066 
   1067 static void eap_aka_process_client_error(struct eap_sm *sm,
   1068 					 struct eap_aka_data *data,
   1069 					 struct wpabuf *respData,
   1070 					 struct eap_sim_attrs *attr)
   1071 {
   1072 	wpa_printf(MSG_DEBUG, "EAP-AKA: Client reported error %d",
   1073 		   attr->client_error_code);
   1074 	if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
   1075 		eap_aka_state(data, SUCCESS);
   1076 	else
   1077 		eap_aka_state(data, FAILURE);
   1078 }
   1079 
   1080 
   1081 static void eap_aka_process_authentication_reject(
   1082 	struct eap_sm *sm, struct eap_aka_data *data,
   1083 	struct wpabuf *respData, struct eap_sim_attrs *attr)
   1084 {
   1085 	wpa_printf(MSG_DEBUG, "EAP-AKA: Client rejected authentication");
   1086 	eap_aka_state(data, FAILURE);
   1087 }
   1088 
   1089 
   1090 static void eap_aka_process_notification(struct eap_sm *sm,
   1091 					 struct eap_aka_data *data,
   1092 					 struct wpabuf *respData,
   1093 					 struct eap_sim_attrs *attr)
   1094 {
   1095 	wpa_printf(MSG_DEBUG, "EAP-AKA: Client replied to notification");
   1096 	if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
   1097 		eap_aka_state(data, SUCCESS);
   1098 	else
   1099 		eap_aka_state(data, FAILURE);
   1100 }
   1101 
   1102 
   1103 static void eap_aka_process(struct eap_sm *sm, void *priv,
   1104 			    struct wpabuf *respData)
   1105 {
   1106 	struct eap_aka_data *data = priv;
   1107 	const u8 *pos, *end;
   1108 	u8 subtype;
   1109 	size_t len;
   1110 	struct eap_sim_attrs attr;
   1111 
   1112 	pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
   1113 			       &len);
   1114 	if (pos == NULL || len < 3)
   1115 		return;
   1116 
   1117 	end = pos + len;
   1118 	subtype = *pos;
   1119 	pos += 3;
   1120 
   1121 	if (eap_aka_subtype_ok(data, subtype)) {
   1122 		wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized or unexpected "
   1123 			   "EAP-AKA Subtype in EAP Response");
   1124 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
   1125 		eap_aka_state(data, NOTIFICATION);
   1126 		return;
   1127 	}
   1128 
   1129 	if (eap_sim_parse_attr(pos, end, &attr,
   1130 			       data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1,
   1131 			       0)) {
   1132 		wpa_printf(MSG_DEBUG, "EAP-AKA: Failed to parse attributes");
   1133 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
   1134 		eap_aka_state(data, NOTIFICATION);
   1135 		return;
   1136 	}
   1137 
   1138 	if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR) {
   1139 		eap_aka_process_client_error(sm, data, respData, &attr);
   1140 		return;
   1141 	}
   1142 
   1143 	if (subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) {
   1144 		eap_aka_process_authentication_reject(sm, data, respData,
   1145 						      &attr);
   1146 		return;
   1147 	}
   1148 
   1149 	switch (data->state) {
   1150 	case IDENTITY:
   1151 		eap_aka_process_identity(sm, data, respData, &attr);
   1152 		break;
   1153 	case CHALLENGE:
   1154 		if (subtype == EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
   1155 			eap_aka_process_sync_failure(sm, data, respData,
   1156 						     &attr);
   1157 		} else {
   1158 			eap_aka_process_challenge(sm, data, respData, &attr);
   1159 		}
   1160 		break;
   1161 	case REAUTH:
   1162 		eap_aka_process_reauth(sm, data, respData, &attr);
   1163 		break;
   1164 	case NOTIFICATION:
   1165 		eap_aka_process_notification(sm, data, respData, &attr);
   1166 		break;
   1167 	default:
   1168 		wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
   1169 			   "process", data->state);
   1170 		break;
   1171 	}
   1172 }
   1173 
   1174 
   1175 static Boolean eap_aka_isDone(struct eap_sm *sm, void *priv)
   1176 {
   1177 	struct eap_aka_data *data = priv;
   1178 	return data->state == SUCCESS || data->state == FAILURE;
   1179 }
   1180 
   1181 
   1182 static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
   1183 {
   1184 	struct eap_aka_data *data = priv;
   1185 	u8 *key;
   1186 
   1187 	if (data->state != SUCCESS)
   1188 		return NULL;
   1189 
   1190 	key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
   1191 	if (key == NULL)
   1192 		return NULL;
   1193 	os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
   1194 	*len = EAP_SIM_KEYING_DATA_LEN;
   1195 	return key;
   1196 }
   1197 
   1198 
   1199 static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
   1200 {
   1201 	struct eap_aka_data *data = priv;
   1202 	u8 *key;
   1203 
   1204 	if (data->state != SUCCESS)
   1205 		return NULL;
   1206 
   1207 	key = os_malloc(EAP_EMSK_LEN);
   1208 	if (key == NULL)
   1209 		return NULL;
   1210 	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
   1211 	*len = EAP_EMSK_LEN;
   1212 	return key;
   1213 }
   1214 
   1215 
   1216 static Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv)
   1217 {
   1218 	struct eap_aka_data *data = priv;
   1219 	return data->state == SUCCESS;
   1220 }
   1221 
   1222 
   1223 int eap_server_aka_register(void)
   1224 {
   1225 	struct eap_method *eap;
   1226 	int ret;
   1227 
   1228 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
   1229 				      EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
   1230 	if (eap == NULL)
   1231 		return -1;
   1232 
   1233 	eap->init = eap_aka_init;
   1234 	eap->reset = eap_aka_reset;
   1235 	eap->buildReq = eap_aka_buildReq;
   1236 	eap->check = eap_aka_check;
   1237 	eap->process = eap_aka_process;
   1238 	eap->isDone = eap_aka_isDone;
   1239 	eap->getKey = eap_aka_getKey;
   1240 	eap->isSuccess = eap_aka_isSuccess;
   1241 	eap->get_emsk = eap_aka_get_emsk;
   1242 
   1243 	ret = eap_server_method_register(eap);
   1244 	if (ret)
   1245 		eap_server_method_free(eap);
   1246 	return ret;
   1247 }
   1248 
   1249 
   1250 #ifdef EAP_AKA_PRIME
   1251 int eap_server_aka_prime_register(void)
   1252 {
   1253 	struct eap_method *eap;
   1254 	int ret;
   1255 
   1256 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
   1257 				      EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
   1258 				      "AKA'");
   1259 	if (eap == NULL)
   1260 		return -1;
   1261 
   1262 	eap->init = eap_aka_prime_init;
   1263 	eap->reset = eap_aka_reset;
   1264 	eap->buildReq = eap_aka_buildReq;
   1265 	eap->check = eap_aka_check;
   1266 	eap->process = eap_aka_process;
   1267 	eap->isDone = eap_aka_isDone;
   1268 	eap->getKey = eap_aka_getKey;
   1269 	eap->isSuccess = eap_aka_isSuccess;
   1270 	eap->get_emsk = eap_aka_get_emsk;
   1271 
   1272 	ret = eap_server_method_register(eap);
   1273 	if (ret)
   1274 		eap_server_method_free(eap);
   1275 
   1276 	return ret;
   1277 }
   1278 #endif /* EAP_AKA_PRIME */
   1279