xref: /netbsd/external/bsd/wpa/dist/src/eap_peer/eap_aka.c (revision 0d69f216)
18dbcf02cSchristos /*
221a80aedSadam  * EAP peer method: EAP-AKA (RFC 4187) and EAP-AKA' (RFC 5448)
321a80aedSadam  * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
48dbcf02cSchristos  *
562a52023Schristos  * This software may be distributed under the terms of the BSD license.
662a52023Schristos  * See README for more details.
78dbcf02cSchristos  */
88dbcf02cSchristos 
98dbcf02cSchristos #include "includes.h"
108dbcf02cSchristos 
118dbcf02cSchristos #include "common.h"
128dbcf02cSchristos #include "pcsc_funcs.h"
138dbcf02cSchristos #include "crypto/crypto.h"
148dbcf02cSchristos #include "crypto/sha1.h"
158dbcf02cSchristos #include "crypto/sha256.h"
168dbcf02cSchristos #include "crypto/milenage.h"
178dbcf02cSchristos #include "eap_common/eap_sim_common.h"
188dbcf02cSchristos #include "eap_config.h"
198dbcf02cSchristos #include "eap_i.h"
208dbcf02cSchristos 
218dbcf02cSchristos 
228dbcf02cSchristos struct eap_aka_data {
238dbcf02cSchristos 	u8 ik[EAP_AKA_IK_LEN], ck[EAP_AKA_CK_LEN], res[EAP_AKA_RES_MAX_LEN];
248dbcf02cSchristos 	size_t res_len;
258dbcf02cSchristos 	u8 nonce_s[EAP_SIM_NONCE_S_LEN];
268dbcf02cSchristos 	u8 mk[EAP_SIM_MK_LEN];
278dbcf02cSchristos 	u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
288dbcf02cSchristos 	u8 k_encr[EAP_SIM_K_ENCR_LEN];
298dbcf02cSchristos 	u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */
308dbcf02cSchristos 	u8 msk[EAP_SIM_KEYING_DATA_LEN];
318dbcf02cSchristos 	u8 emsk[EAP_EMSK_LEN];
328dbcf02cSchristos 	u8 rand[EAP_AKA_RAND_LEN], autn[EAP_AKA_AUTN_LEN];
338dbcf02cSchristos 	u8 auts[EAP_AKA_AUTS_LEN];
34*0d69f216Schristos 	u8 reauth_mac[EAP_SIM_MAC_LEN];
358dbcf02cSchristos 
368dbcf02cSchristos 	int num_id_req, num_notification;
378dbcf02cSchristos 	u8 *pseudonym;
388dbcf02cSchristos 	size_t pseudonym_len;
398dbcf02cSchristos 	u8 *reauth_id;
408dbcf02cSchristos 	size_t reauth_id_len;
418dbcf02cSchristos 	int reauth;
428dbcf02cSchristos 	unsigned int counter, counter_too_small;
438dbcf02cSchristos 	u8 *last_eap_identity;
448dbcf02cSchristos 	size_t last_eap_identity_len;
458dbcf02cSchristos 	enum {
4636d97821Schristos 		CONTINUE, RESULT_SUCCESS, SUCCESS, FAILURE
478dbcf02cSchristos 	} state;
488dbcf02cSchristos 
498dbcf02cSchristos 	struct wpabuf *id_msgs;
508dbcf02cSchristos 	int prev_id;
518dbcf02cSchristos 	int result_ind, use_result_ind;
52ebb5671cSchristos 	int use_pseudonym;
538dbcf02cSchristos 	u8 eap_method;
548dbcf02cSchristos 	u8 *network_name;
558dbcf02cSchristos 	size_t network_name_len;
568dbcf02cSchristos 	u16 kdf;
578dbcf02cSchristos 	int kdf_negotiation;
58ebb5671cSchristos 	u16 last_kdf_attrs[EAP_AKA_PRIME_KDF_MAX];
59ebb5671cSchristos 	size_t last_kdf_count;
60ebb5671cSchristos 	int error_code;
618dbcf02cSchristos };
628dbcf02cSchristos 
638dbcf02cSchristos 
648dbcf02cSchristos #ifndef CONFIG_NO_STDOUT_DEBUG
eap_aka_state_txt(int state)658dbcf02cSchristos static const char * eap_aka_state_txt(int state)
668dbcf02cSchristos {
678dbcf02cSchristos 	switch (state) {
688dbcf02cSchristos 	case CONTINUE:
698dbcf02cSchristos 		return "CONTINUE";
708dbcf02cSchristos 	case RESULT_SUCCESS:
718dbcf02cSchristos 		return "RESULT_SUCCESS";
728dbcf02cSchristos 	case SUCCESS:
738dbcf02cSchristos 		return "SUCCESS";
748dbcf02cSchristos 	case FAILURE:
758dbcf02cSchristos 		return "FAILURE";
768dbcf02cSchristos 	default:
778dbcf02cSchristos 		return "?";
788dbcf02cSchristos 	}
798dbcf02cSchristos }
808dbcf02cSchristos #endif /* CONFIG_NO_STDOUT_DEBUG */
818dbcf02cSchristos 
828dbcf02cSchristos 
eap_aka_state(struct eap_aka_data * data,int state)838dbcf02cSchristos static void eap_aka_state(struct eap_aka_data *data, int state)
848dbcf02cSchristos {
858dbcf02cSchristos 	wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s",
868dbcf02cSchristos 		   eap_aka_state_txt(data->state),
878dbcf02cSchristos 		   eap_aka_state_txt(state));
888dbcf02cSchristos 	data->state = state;
898dbcf02cSchristos }
908dbcf02cSchristos 
918dbcf02cSchristos 
eap_aka_init(struct eap_sm * sm)928dbcf02cSchristos static void * eap_aka_init(struct eap_sm *sm)
938dbcf02cSchristos {
948dbcf02cSchristos 	struct eap_aka_data *data;
958dbcf02cSchristos 	const char *phase1 = eap_get_config_phase1(sm);
9662a52023Schristos 	struct eap_peer_config *config = eap_get_config(sm);
978dbcf02cSchristos 
988dbcf02cSchristos 	data = os_zalloc(sizeof(*data));
998dbcf02cSchristos 	if (data == NULL)
1008dbcf02cSchristos 		return NULL;
1018dbcf02cSchristos 
1028dbcf02cSchristos 	data->eap_method = EAP_TYPE_AKA;
1038dbcf02cSchristos 
104ebb5671cSchristos 	/* Zero is a valid error code, so we need to initialize */
105ebb5671cSchristos 	data->error_code = NO_EAP_METHOD_ERROR;
106ebb5671cSchristos 
1078dbcf02cSchristos 	eap_aka_state(data, CONTINUE);
1088dbcf02cSchristos 	data->prev_id = -1;
1098dbcf02cSchristos 
1108dbcf02cSchristos 	data->result_ind = phase1 && os_strstr(phase1, "result_ind=1") != NULL;
1118dbcf02cSchristos 
112ebb5671cSchristos 	data->use_pseudonym = !sm->init_phase2;
113ebb5671cSchristos 	if (config && config->anonymous_identity && data->use_pseudonym) {
11462a52023Schristos 		data->pseudonym = os_malloc(config->anonymous_identity_len);
11562a52023Schristos 		if (data->pseudonym) {
11662a52023Schristos 			os_memcpy(data->pseudonym, config->anonymous_identity,
11762a52023Schristos 				  config->anonymous_identity_len);
11862a52023Schristos 			data->pseudonym_len = config->anonymous_identity_len;
11962a52023Schristos 		}
12062a52023Schristos 	}
12162a52023Schristos 
1228dbcf02cSchristos 	return data;
1238dbcf02cSchristos }
1248dbcf02cSchristos 
1258dbcf02cSchristos 
1268dbcf02cSchristos #ifdef EAP_AKA_PRIME
eap_aka_prime_init(struct eap_sm * sm)1278dbcf02cSchristos static void * eap_aka_prime_init(struct eap_sm *sm)
1288dbcf02cSchristos {
1298dbcf02cSchristos 	struct eap_aka_data *data = eap_aka_init(sm);
1308dbcf02cSchristos 	if (data == NULL)
1318dbcf02cSchristos 		return NULL;
1328dbcf02cSchristos 	data->eap_method = EAP_TYPE_AKA_PRIME;
1338dbcf02cSchristos 	return data;
1348dbcf02cSchristos }
1358dbcf02cSchristos #endif /* EAP_AKA_PRIME */
1368dbcf02cSchristos 
1378dbcf02cSchristos 
eap_aka_clear_keys(struct eap_aka_data * data,int reauth)13836d97821Schristos static void eap_aka_clear_keys(struct eap_aka_data *data, int reauth)
13936d97821Schristos {
14036d97821Schristos 	if (!reauth) {
14136d97821Schristos 		os_memset(data->mk, 0, EAP_SIM_MK_LEN);
14236d97821Schristos 		os_memset(data->k_aut, 0, EAP_AKA_PRIME_K_AUT_LEN);
14336d97821Schristos 		os_memset(data->k_encr, 0, EAP_SIM_K_ENCR_LEN);
14436d97821Schristos 		os_memset(data->k_re, 0, EAP_AKA_PRIME_K_RE_LEN);
14536d97821Schristos 	}
14636d97821Schristos 	os_memset(data->msk, 0, EAP_SIM_KEYING_DATA_LEN);
14736d97821Schristos 	os_memset(data->emsk, 0, EAP_EMSK_LEN);
14836d97821Schristos 	os_memset(data->autn, 0, EAP_AKA_AUTN_LEN);
14936d97821Schristos 	os_memset(data->auts, 0, EAP_AKA_AUTS_LEN);
15036d97821Schristos }
15136d97821Schristos 
15236d97821Schristos 
eap_aka_deinit(struct eap_sm * sm,void * priv)1538dbcf02cSchristos static void eap_aka_deinit(struct eap_sm *sm, void *priv)
1548dbcf02cSchristos {
1558dbcf02cSchristos 	struct eap_aka_data *data = priv;
1568dbcf02cSchristos 	if (data) {
1578dbcf02cSchristos 		os_free(data->pseudonym);
1588dbcf02cSchristos 		os_free(data->reauth_id);
1598dbcf02cSchristos 		os_free(data->last_eap_identity);
1608dbcf02cSchristos 		wpabuf_free(data->id_msgs);
1618dbcf02cSchristos 		os_free(data->network_name);
16236d97821Schristos 		eap_aka_clear_keys(data, 0);
1638dbcf02cSchristos 		os_free(data);
1648dbcf02cSchristos 	}
1658dbcf02cSchristos }
1668dbcf02cSchristos 
1678dbcf02cSchristos 
eap_aka_ext_sim_req(struct eap_sm * sm,struct eap_aka_data * data)16836d97821Schristos static int eap_aka_ext_sim_req(struct eap_sm *sm, struct eap_aka_data *data)
16936d97821Schristos {
17036d97821Schristos 	char req[200], *pos, *end;
17136d97821Schristos 
17236d97821Schristos 	wpa_printf(MSG_DEBUG, "EAP-AKA: Use external USIM processing");
17336d97821Schristos 	pos = req;
17436d97821Schristos 	end = pos + sizeof(req);
17536d97821Schristos 	pos += os_snprintf(pos, end - pos, "UMTS-AUTH");
17636d97821Schristos 	pos += os_snprintf(pos, end - pos, ":");
17736d97821Schristos 	pos += wpa_snprintf_hex(pos, end - pos, data->rand, EAP_AKA_RAND_LEN);
17836d97821Schristos 	pos += os_snprintf(pos, end - pos, ":");
17936d97821Schristos 	wpa_snprintf_hex(pos, end - pos, data->autn, EAP_AKA_AUTN_LEN);
18036d97821Schristos 
18136d97821Schristos 	eap_sm_request_sim(sm, req);
18236d97821Schristos 	return 1;
18336d97821Schristos }
18436d97821Schristos 
18536d97821Schristos 
eap_aka_ext_sim_result(struct eap_sm * sm,struct eap_aka_data * data,struct eap_peer_config * conf)18636d97821Schristos static int eap_aka_ext_sim_result(struct eap_sm *sm, struct eap_aka_data *data,
18736d97821Schristos 				  struct eap_peer_config *conf)
18836d97821Schristos {
18936d97821Schristos 	char *resp, *pos;
19036d97821Schristos 
19136d97821Schristos 	wpa_printf(MSG_DEBUG,
19236d97821Schristos 		   "EAP-AKA: Use result from external USIM processing");
19336d97821Schristos 
19436d97821Schristos 	resp = conf->external_sim_resp;
19536d97821Schristos 	conf->external_sim_resp = NULL;
19636d97821Schristos 
19736d97821Schristos 	if (os_strncmp(resp, "UMTS-AUTS:", 10) == 0) {
19836d97821Schristos 		pos = resp + 10;
19936d97821Schristos 		if (hexstr2bin(pos, data->auts, EAP_AKA_AUTS_LEN) < 0)
20036d97821Schristos 			goto invalid;
20136d97821Schristos 		wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: AUTS", data->auts,
20236d97821Schristos 				EAP_AKA_AUTS_LEN);
20336d97821Schristos 		os_free(resp);
20436d97821Schristos 		return -2;
20536d97821Schristos 	}
20636d97821Schristos 
20736d97821Schristos 	if (os_strncmp(resp, "UMTS-AUTH:", 10) != 0) {
20836d97821Schristos 		wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized external USIM processing response");
20936d97821Schristos 		os_free(resp);
21036d97821Schristos 		return -1;
21136d97821Schristos 	}
21236d97821Schristos 
21336d97821Schristos 	pos = resp + 10;
21436d97821Schristos 	wpa_hexdump(MSG_DEBUG, "EAP-AKA: RAND", data->rand, EAP_AKA_RAND_LEN);
21536d97821Schristos 
21636d97821Schristos 	if (hexstr2bin(pos, data->ik, EAP_AKA_IK_LEN) < 0)
21736d97821Schristos 		goto invalid;
21836d97821Schristos 	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: IK", data->ik, EAP_AKA_IK_LEN);
21936d97821Schristos 	pos += EAP_AKA_IK_LEN * 2;
22036d97821Schristos 	if (*pos != ':')
22136d97821Schristos 		goto invalid;
22236d97821Schristos 	pos++;
22336d97821Schristos 
22436d97821Schristos 	if (hexstr2bin(pos, data->ck, EAP_AKA_CK_LEN) < 0)
22536d97821Schristos 		goto invalid;
22636d97821Schristos 	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: CK", data->ck, EAP_AKA_CK_LEN);
22736d97821Schristos 	pos += EAP_AKA_CK_LEN * 2;
22836d97821Schristos 	if (*pos != ':')
22936d97821Schristos 		goto invalid;
23036d97821Schristos 	pos++;
23136d97821Schristos 
23236d97821Schristos 	data->res_len = os_strlen(pos) / 2;
23336d97821Schristos 	if (data->res_len > EAP_AKA_RES_MAX_LEN) {
23436d97821Schristos 		data->res_len = 0;
23536d97821Schristos 		goto invalid;
23636d97821Schristos 	}
23736d97821Schristos 	if (hexstr2bin(pos, data->res, data->res_len) < 0)
23836d97821Schristos 		goto invalid;
23936d97821Schristos 	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: RES", data->res, data->res_len);
24036d97821Schristos 
24136d97821Schristos 	os_free(resp);
24236d97821Schristos 	return 0;
24336d97821Schristos 
24436d97821Schristos invalid:
24536d97821Schristos 	wpa_printf(MSG_DEBUG, "EAP-AKA: Invalid external USIM processing UMTS-AUTH response");
24636d97821Schristos 	os_free(resp);
24736d97821Schristos 	return -1;
24836d97821Schristos }
24936d97821Schristos 
25036d97821Schristos 
eap_aka_umts_auth(struct eap_sm * sm,struct eap_aka_data * data)2518dbcf02cSchristos static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data)
2528dbcf02cSchristos {
2538dbcf02cSchristos 	struct eap_peer_config *conf;
2548dbcf02cSchristos 
2558dbcf02cSchristos 	wpa_printf(MSG_DEBUG, "EAP-AKA: UMTS authentication algorithm");
2568dbcf02cSchristos 
2578dbcf02cSchristos 	conf = eap_get_config(sm);
2588dbcf02cSchristos 	if (conf == NULL)
2598dbcf02cSchristos 		return -1;
26036d97821Schristos 
26136d97821Schristos 	if (sm->external_sim) {
26236d97821Schristos 		if (conf->external_sim_resp)
26336d97821Schristos 			return eap_aka_ext_sim_result(sm, data, conf);
26436d97821Schristos 		else
26536d97821Schristos 			return eap_aka_ext_sim_req(sm, data);
26636d97821Schristos 	}
26736d97821Schristos 
2688dbcf02cSchristos 	if (conf->pcsc) {
2698dbcf02cSchristos 		return scard_umts_auth(sm->scard_ctx, data->rand,
2708dbcf02cSchristos 				       data->autn, data->res, &data->res_len,
2718dbcf02cSchristos 				       data->ik, data->ck, data->auts);
2728dbcf02cSchristos 	}
2738dbcf02cSchristos 
2748dbcf02cSchristos #ifdef CONFIG_USIM_SIMULATOR
2758dbcf02cSchristos 	if (conf->password) {
2768dbcf02cSchristos 		u8 opc[16], k[16], sqn[6];
2778dbcf02cSchristos 		const char *pos;
2788dbcf02cSchristos 		wpa_printf(MSG_DEBUG, "EAP-AKA: Use internal Milenage "
2798dbcf02cSchristos 			   "implementation for UMTS authentication");
2808dbcf02cSchristos 		if (conf->password_len < 78) {
2818dbcf02cSchristos 			wpa_printf(MSG_DEBUG, "EAP-AKA: invalid Milenage "
2828dbcf02cSchristos 				   "password");
2838dbcf02cSchristos 			return -1;
2848dbcf02cSchristos 		}
2858dbcf02cSchristos 		pos = (const char *) conf->password;
2868dbcf02cSchristos 		if (hexstr2bin(pos, k, 16))
2878dbcf02cSchristos 			return -1;
2888dbcf02cSchristos 		pos += 32;
2898dbcf02cSchristos 		if (*pos != ':')
2908dbcf02cSchristos 			return -1;
2918dbcf02cSchristos 		pos++;
2928dbcf02cSchristos 
2938dbcf02cSchristos 		if (hexstr2bin(pos, opc, 16))
2948dbcf02cSchristos 			return -1;
2958dbcf02cSchristos 		pos += 32;
2968dbcf02cSchristos 		if (*pos != ':')
2978dbcf02cSchristos 			return -1;
2988dbcf02cSchristos 		pos++;
2998dbcf02cSchristos 
3008dbcf02cSchristos 		if (hexstr2bin(pos, sqn, 6))
3018dbcf02cSchristos 			return -1;
3028dbcf02cSchristos 
3038dbcf02cSchristos 		return milenage_check(opc, k, sqn, data->rand, data->autn,
3048dbcf02cSchristos 				      data->ik, data->ck,
3058dbcf02cSchristos 				      data->res, &data->res_len, data->auts);
3068dbcf02cSchristos 	}
3078dbcf02cSchristos #endif /* CONFIG_USIM_SIMULATOR */
3088dbcf02cSchristos 
3098dbcf02cSchristos #ifdef CONFIG_USIM_HARDCODED
3108dbcf02cSchristos 	wpa_printf(MSG_DEBUG, "EAP-AKA: Use hardcoded Kc and SRES values for "
3118dbcf02cSchristos 		   "testing");
3128dbcf02cSchristos 
3138dbcf02cSchristos 	/* These hardcoded Kc and SRES values are used for testing.
3148dbcf02cSchristos 	 * Could consider making them configurable. */
3158dbcf02cSchristos 	os_memset(data->res, '2', EAP_AKA_RES_MAX_LEN);
3168dbcf02cSchristos 	data->res_len = EAP_AKA_RES_MAX_LEN;
3178dbcf02cSchristos 	os_memset(data->ik, '3', EAP_AKA_IK_LEN);
3188dbcf02cSchristos 	os_memset(data->ck, '4', EAP_AKA_CK_LEN);
3198dbcf02cSchristos 	{
3208dbcf02cSchristos 		u8 autn[EAP_AKA_AUTN_LEN];
3218dbcf02cSchristos 		os_memset(autn, '1', EAP_AKA_AUTN_LEN);
32236d97821Schristos 		if (os_memcmp_const(autn, data->autn, EAP_AKA_AUTN_LEN) != 0) {
3238dbcf02cSchristos 			wpa_printf(MSG_WARNING, "EAP-AKA: AUTN did not match "
3248dbcf02cSchristos 				   "with expected value");
3258dbcf02cSchristos 			return -1;
3268dbcf02cSchristos 		}
3278dbcf02cSchristos 	}
3288dbcf02cSchristos #if 0
3298dbcf02cSchristos 	{
3308dbcf02cSchristos 		static int test_resync = 1;
3318dbcf02cSchristos 		if (test_resync) {
3328dbcf02cSchristos 			/* Test Resynchronization */
3338dbcf02cSchristos 			test_resync = 0;
3348dbcf02cSchristos 			return -2;
3358dbcf02cSchristos 		}
3368dbcf02cSchristos 	}
3378dbcf02cSchristos #endif
3388dbcf02cSchristos 	return 0;
3398dbcf02cSchristos 
3408dbcf02cSchristos #else /* CONFIG_USIM_HARDCODED */
3418dbcf02cSchristos 
34236d97821Schristos 	wpa_printf(MSG_DEBUG, "EAP-AKA: No UMTS authentication algorithm "
3438dbcf02cSchristos 		   "enabled");
3448dbcf02cSchristos 	return -1;
3458dbcf02cSchristos 
3468dbcf02cSchristos #endif /* CONFIG_USIM_HARDCODED */
3478dbcf02cSchristos }
3488dbcf02cSchristos 
3498dbcf02cSchristos 
3508dbcf02cSchristos #define CLEAR_PSEUDONYM	0x01
3518dbcf02cSchristos #define CLEAR_REAUTH_ID	0x02
3528dbcf02cSchristos #define CLEAR_EAP_ID	0x04
3538dbcf02cSchristos 
eap_aka_clear_identities(struct eap_sm * sm,struct eap_aka_data * data,int id)35462a52023Schristos static void eap_aka_clear_identities(struct eap_sm *sm,
35562a52023Schristos 				     struct eap_aka_data *data, int id)
3568dbcf02cSchristos {
35742669be3Schristos 	if ((id & CLEAR_PSEUDONYM) && data->pseudonym) {
35842669be3Schristos 		wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old pseudonym");
3598dbcf02cSchristos 		os_free(data->pseudonym);
3608dbcf02cSchristos 		data->pseudonym = NULL;
3618dbcf02cSchristos 		data->pseudonym_len = 0;
362ebb5671cSchristos 		if (data->use_pseudonym)
36362a52023Schristos 			eap_set_anon_id(sm, NULL, 0);
3648dbcf02cSchristos 	}
36542669be3Schristos 	if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
36642669be3Schristos 		wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old reauth_id");
3678dbcf02cSchristos 		os_free(data->reauth_id);
3688dbcf02cSchristos 		data->reauth_id = NULL;
3698dbcf02cSchristos 		data->reauth_id_len = 0;
3708dbcf02cSchristos 	}
37142669be3Schristos 	if ((id & CLEAR_EAP_ID) && data->last_eap_identity) {
37242669be3Schristos 		wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old eap_id");
3738dbcf02cSchristos 		os_free(data->last_eap_identity);
3748dbcf02cSchristos 		data->last_eap_identity = NULL;
3758dbcf02cSchristos 		data->last_eap_identity_len = 0;
3768dbcf02cSchristos 	}
3778dbcf02cSchristos }
3788dbcf02cSchristos 
3798dbcf02cSchristos 
eap_aka_learn_ids(struct eap_sm * sm,struct eap_aka_data * data,struct eap_sim_attrs * attr)38042669be3Schristos static int eap_aka_learn_ids(struct eap_sm *sm, struct eap_aka_data *data,
3818dbcf02cSchristos 			     struct eap_sim_attrs *attr)
3828dbcf02cSchristos {
3838dbcf02cSchristos 	if (attr->next_pseudonym) {
38442669be3Schristos 		const u8 *identity = NULL;
38542669be3Schristos 		size_t identity_len = 0;
38642669be3Schristos 		const u8 *realm = NULL;
38742669be3Schristos 		size_t realm_len = 0;
38842669be3Schristos 
38942669be3Schristos 		wpa_hexdump_ascii(MSG_DEBUG,
39042669be3Schristos 				  "EAP-AKA: (encr) AT_NEXT_PSEUDONYM",
39142669be3Schristos 				  attr->next_pseudonym,
39242669be3Schristos 				  attr->next_pseudonym_len);
3938dbcf02cSchristos 		os_free(data->pseudonym);
39442669be3Schristos 		/* Look for the realm of the permanent identity */
39542669be3Schristos 		identity = eap_get_config_identity(sm, &identity_len);
39642669be3Schristos 		if (identity) {
39742669be3Schristos 			for (realm = identity, realm_len = identity_len;
39842669be3Schristos 			     realm_len > 0; realm_len--, realm++) {
39942669be3Schristos 				if (*realm == '@')
40042669be3Schristos 					break;
40142669be3Schristos 			}
40242669be3Schristos 		}
40342669be3Schristos 		data->pseudonym = os_malloc(attr->next_pseudonym_len +
40442669be3Schristos 					    realm_len);
4058dbcf02cSchristos 		if (data->pseudonym == NULL) {
4068dbcf02cSchristos 			wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for "
4078dbcf02cSchristos 				   "next pseudonym");
40842669be3Schristos 			data->pseudonym_len = 0;
4098dbcf02cSchristos 			return -1;
4108dbcf02cSchristos 		}
4118dbcf02cSchristos 		os_memcpy(data->pseudonym, attr->next_pseudonym,
4128dbcf02cSchristos 			  attr->next_pseudonym_len);
41342669be3Schristos 		if (realm_len) {
41442669be3Schristos 			os_memcpy(data->pseudonym + attr->next_pseudonym_len,
41542669be3Schristos 				  realm, realm_len);
41642669be3Schristos 		}
41742669be3Schristos 		data->pseudonym_len = attr->next_pseudonym_len + realm_len;
418ebb5671cSchristos 		if (data->use_pseudonym)
419ebb5671cSchristos 			eap_set_anon_id(sm, data->pseudonym,
420ebb5671cSchristos 					data->pseudonym_len);
4218dbcf02cSchristos 	}
4228dbcf02cSchristos 
4238dbcf02cSchristos 	if (attr->next_reauth_id) {
4248dbcf02cSchristos 		os_free(data->reauth_id);
425ebb5671cSchristos 		data->reauth_id = os_memdup(attr->next_reauth_id,
426ebb5671cSchristos 					    attr->next_reauth_id_len);
4278dbcf02cSchristos 		if (data->reauth_id == NULL) {
4288dbcf02cSchristos 			wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for "
4298dbcf02cSchristos 				   "next reauth_id");
43042669be3Schristos 			data->reauth_id_len = 0;
4318dbcf02cSchristos 			return -1;
4328dbcf02cSchristos 		}
4338dbcf02cSchristos 		data->reauth_id_len = attr->next_reauth_id_len;
4348dbcf02cSchristos 		wpa_hexdump_ascii(MSG_DEBUG,
4358dbcf02cSchristos 				  "EAP-AKA: (encr) AT_NEXT_REAUTH_ID",
4368dbcf02cSchristos 				  data->reauth_id,
4378dbcf02cSchristos 				  data->reauth_id_len);
4388dbcf02cSchristos 	}
4398dbcf02cSchristos 
4408dbcf02cSchristos 	return 0;
4418dbcf02cSchristos }
4428dbcf02cSchristos 
4438dbcf02cSchristos 
eap_aka_add_id_msg(struct eap_aka_data * data,const struct wpabuf * msg)4448dbcf02cSchristos static int eap_aka_add_id_msg(struct eap_aka_data *data,
4458dbcf02cSchristos 			      const struct wpabuf *msg)
4468dbcf02cSchristos {
4478dbcf02cSchristos 	if (msg == NULL)
4488dbcf02cSchristos 		return -1;
4498dbcf02cSchristos 
4508dbcf02cSchristos 	if (data->id_msgs == NULL) {
4518dbcf02cSchristos 		data->id_msgs = wpabuf_dup(msg);
4528dbcf02cSchristos 		return data->id_msgs == NULL ? -1 : 0;
4538dbcf02cSchristos 	}
4548dbcf02cSchristos 
4558dbcf02cSchristos 	if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0)
4568dbcf02cSchristos 		return -1;
4578dbcf02cSchristos 	wpabuf_put_buf(data->id_msgs, msg);
4588dbcf02cSchristos 
4598dbcf02cSchristos 	return 0;
4608dbcf02cSchristos }
4618dbcf02cSchristos 
4628dbcf02cSchristos 
eap_aka_add_checkcode(struct eap_aka_data * data,struct eap_sim_msg * msg)4638dbcf02cSchristos static void eap_aka_add_checkcode(struct eap_aka_data *data,
4648dbcf02cSchristos 				  struct eap_sim_msg *msg)
4658dbcf02cSchristos {
4668dbcf02cSchristos 	const u8 *addr;
4678dbcf02cSchristos 	size_t len;
4688dbcf02cSchristos 	u8 hash[SHA256_MAC_LEN];
4698dbcf02cSchristos 
4708dbcf02cSchristos 	wpa_printf(MSG_DEBUG, "   AT_CHECKCODE");
4718dbcf02cSchristos 
4728dbcf02cSchristos 	if (data->id_msgs == NULL) {
4738dbcf02cSchristos 		/*
4748dbcf02cSchristos 		 * No EAP-AKA/Identity packets were exchanged - send empty
4758dbcf02cSchristos 		 * checkcode.
4768dbcf02cSchristos 		 */
4778dbcf02cSchristos 		eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0);
4788dbcf02cSchristos 		return;
4798dbcf02cSchristos 	}
4808dbcf02cSchristos 
4818dbcf02cSchristos 	/* Checkcode is SHA1/SHA256 hash over all EAP-AKA/Identity packets. */
4828dbcf02cSchristos 	addr = wpabuf_head(data->id_msgs);
4838dbcf02cSchristos 	len = wpabuf_len(data->id_msgs);
4848dbcf02cSchristos 	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len);
4858dbcf02cSchristos #ifdef EAP_AKA_PRIME
4868dbcf02cSchristos 	if (data->eap_method == EAP_TYPE_AKA_PRIME)
4878dbcf02cSchristos 		sha256_vector(1, &addr, &len, hash);
4888dbcf02cSchristos 	else
4898dbcf02cSchristos #endif /* EAP_AKA_PRIME */
4908dbcf02cSchristos 		sha1_vector(1, &addr, &len, hash);
4918dbcf02cSchristos 
4928dbcf02cSchristos 	eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash,
4938dbcf02cSchristos 			data->eap_method == EAP_TYPE_AKA_PRIME ?
4948dbcf02cSchristos 			EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN);
4958dbcf02cSchristos }
4968dbcf02cSchristos 
4978dbcf02cSchristos 
eap_aka_verify_checkcode(struct eap_aka_data * data,const u8 * checkcode,size_t checkcode_len)4988dbcf02cSchristos static int eap_aka_verify_checkcode(struct eap_aka_data *data,
4998dbcf02cSchristos 				    const u8 *checkcode, size_t checkcode_len)
5008dbcf02cSchristos {
5018dbcf02cSchristos 	const u8 *addr;
5028dbcf02cSchristos 	size_t len;
5038dbcf02cSchristos 	u8 hash[SHA256_MAC_LEN];
5048dbcf02cSchristos 	size_t hash_len;
5058dbcf02cSchristos 
5068dbcf02cSchristos 	if (checkcode == NULL)
5078dbcf02cSchristos 		return -1;
5088dbcf02cSchristos 
5098dbcf02cSchristos 	if (data->id_msgs == NULL) {
5108dbcf02cSchristos 		if (checkcode_len != 0) {
5118dbcf02cSchristos 			wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from server "
5128dbcf02cSchristos 				   "indicates that AKA/Identity messages were "
5138dbcf02cSchristos 				   "used, but they were not");
5148dbcf02cSchristos 			return -1;
5158dbcf02cSchristos 		}
5168dbcf02cSchristos 		return 0;
5178dbcf02cSchristos 	}
5188dbcf02cSchristos 
5198dbcf02cSchristos 	hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ?
5208dbcf02cSchristos 		EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN;
5218dbcf02cSchristos 
5228dbcf02cSchristos 	if (checkcode_len != hash_len) {
5238dbcf02cSchristos 		wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from server "
5248dbcf02cSchristos 			   "indicates that AKA/Identity message were not "
5258dbcf02cSchristos 			   "used, but they were");
5268dbcf02cSchristos 		return -1;
5278dbcf02cSchristos 	}
5288dbcf02cSchristos 
5298dbcf02cSchristos 	/* Checkcode is SHA1/SHA256 hash over all EAP-AKA/Identity packets. */
5308dbcf02cSchristos 	addr = wpabuf_head(data->id_msgs);
5318dbcf02cSchristos 	len = wpabuf_len(data->id_msgs);
5328dbcf02cSchristos #ifdef EAP_AKA_PRIME
5338dbcf02cSchristos 	if (data->eap_method == EAP_TYPE_AKA_PRIME)
5348dbcf02cSchristos 		sha256_vector(1, &addr, &len, hash);
5358dbcf02cSchristos 	else
5368dbcf02cSchristos #endif /* EAP_AKA_PRIME */
5378dbcf02cSchristos 		sha1_vector(1, &addr, &len, hash);
5388dbcf02cSchristos 
53936d97821Schristos 	if (os_memcmp_const(hash, checkcode, hash_len) != 0) {
5408dbcf02cSchristos 		wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
5418dbcf02cSchristos 		return -1;
5428dbcf02cSchristos 	}
5438dbcf02cSchristos 
5448dbcf02cSchristos 	return 0;
5458dbcf02cSchristos }
5468dbcf02cSchristos 
5478dbcf02cSchristos 
eap_aka_client_error(struct eap_aka_data * data,u8 id,int err)5488dbcf02cSchristos static struct wpabuf * eap_aka_client_error(struct eap_aka_data *data, u8 id,
5498dbcf02cSchristos 					    int err)
5508dbcf02cSchristos {
5518dbcf02cSchristos 	struct eap_sim_msg *msg;
5528dbcf02cSchristos 
5538dbcf02cSchristos 	eap_aka_state(data, FAILURE);
5548dbcf02cSchristos 	data->num_id_req = 0;
5558dbcf02cSchristos 	data->num_notification = 0;
5568dbcf02cSchristos 
55762a52023Schristos 	wpa_printf(MSG_DEBUG, "EAP-AKA: Send Client-Error (error code %d)",
55862a52023Schristos 		   err);
5598dbcf02cSchristos 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
5608dbcf02cSchristos 			       EAP_AKA_SUBTYPE_CLIENT_ERROR);
5618dbcf02cSchristos 	eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
56236d97821Schristos 	return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
5638dbcf02cSchristos }
5648dbcf02cSchristos 
5658dbcf02cSchristos 
eap_aka_authentication_reject(struct eap_aka_data * data,u8 id)5668dbcf02cSchristos static struct wpabuf * eap_aka_authentication_reject(struct eap_aka_data *data,
5678dbcf02cSchristos 						     u8 id)
5688dbcf02cSchristos {
5698dbcf02cSchristos 	struct eap_sim_msg *msg;
5708dbcf02cSchristos 
5718dbcf02cSchristos 	eap_aka_state(data, FAILURE);
5728dbcf02cSchristos 	data->num_id_req = 0;
5738dbcf02cSchristos 	data->num_notification = 0;
5748dbcf02cSchristos 
5758dbcf02cSchristos 	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Authentication-Reject "
5768dbcf02cSchristos 		   "(id=%d)", id);
5778dbcf02cSchristos 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
5788dbcf02cSchristos 			       EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT);
57936d97821Schristos 	return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
5808dbcf02cSchristos }
5818dbcf02cSchristos 
5828dbcf02cSchristos 
eap_aka_synchronization_failure(struct eap_aka_data * data,u8 id,struct eap_sim_attrs * attr)5838dbcf02cSchristos static struct wpabuf * eap_aka_synchronization_failure(
584ebb5671cSchristos 	struct eap_aka_data *data, u8 id, struct eap_sim_attrs *attr)
5858dbcf02cSchristos {
5868dbcf02cSchristos 	struct eap_sim_msg *msg;
5878dbcf02cSchristos 
5888dbcf02cSchristos 	data->num_id_req = 0;
5898dbcf02cSchristos 	data->num_notification = 0;
5908dbcf02cSchristos 
5918dbcf02cSchristos 	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Synchronization-Failure "
5928dbcf02cSchristos 		   "(id=%d)", id);
5938dbcf02cSchristos 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
5948dbcf02cSchristos 			       EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE);
5958dbcf02cSchristos 	wpa_printf(MSG_DEBUG, "   AT_AUTS");
5968dbcf02cSchristos 	eap_sim_msg_add_full(msg, EAP_SIM_AT_AUTS, data->auts,
5978dbcf02cSchristos 			     EAP_AKA_AUTS_LEN);
598ebb5671cSchristos 	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
599ebb5671cSchristos 		size_t i;
600ebb5671cSchristos 
601ebb5671cSchristos 		for (i = 0; i < attr->kdf_count; i++) {
602ebb5671cSchristos 			wpa_printf(MSG_DEBUG, "   AT_KDF");
603ebb5671cSchristos 			eap_sim_msg_add(msg, EAP_SIM_AT_KDF, attr->kdf[i],
604ebb5671cSchristos 					NULL, 0);
605ebb5671cSchristos 		}
606ebb5671cSchristos 	}
60736d97821Schristos 	return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
6088dbcf02cSchristos }
6098dbcf02cSchristos 
6108dbcf02cSchristos 
eap_aka_response_identity(struct eap_sm * sm,struct eap_aka_data * data,u8 id,enum eap_sim_id_req id_req)6118dbcf02cSchristos static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm,
6128dbcf02cSchristos 						 struct eap_aka_data *data,
6138dbcf02cSchristos 						 u8 id,
6148dbcf02cSchristos 						 enum eap_sim_id_req id_req)
6158dbcf02cSchristos {
6168dbcf02cSchristos 	const u8 *identity = NULL;
6178dbcf02cSchristos 	size_t identity_len = 0;
6188dbcf02cSchristos 	struct eap_sim_msg *msg;
6198dbcf02cSchristos 
6208dbcf02cSchristos 	data->reauth = 0;
6218dbcf02cSchristos 	if (id_req == ANY_ID && data->reauth_id) {
6228dbcf02cSchristos 		identity = data->reauth_id;
6238dbcf02cSchristos 		identity_len = data->reauth_id_len;
6248dbcf02cSchristos 		data->reauth = 1;
6258dbcf02cSchristos 	} else if ((id_req == ANY_ID || id_req == FULLAUTH_ID) &&
626*0d69f216Schristos 		   data->pseudonym &&
627*0d69f216Schristos 		   !eap_sim_anonymous_username(data->pseudonym,
628*0d69f216Schristos 					       data->pseudonym_len)) {
6298dbcf02cSchristos 		identity = data->pseudonym;
6308dbcf02cSchristos 		identity_len = data->pseudonym_len;
63162a52023Schristos 		eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID);
6328dbcf02cSchristos 	} else if (id_req != NO_ID_REQ) {
6338dbcf02cSchristos 		identity = eap_get_config_identity(sm, &identity_len);
6348dbcf02cSchristos 		if (identity) {
635*0d69f216Schristos 			int ids = CLEAR_PSEUDONYM | CLEAR_REAUTH_ID;
636*0d69f216Schristos 
637*0d69f216Schristos 			if (data->pseudonym &&
638*0d69f216Schristos 			    eap_sim_anonymous_username(data->pseudonym,
639*0d69f216Schristos 						       data->pseudonym_len))
640*0d69f216Schristos 				ids &= ~CLEAR_PSEUDONYM;
641*0d69f216Schristos 			eap_aka_clear_identities(sm, data, ids);
6428dbcf02cSchristos 		}
6438dbcf02cSchristos 	}
6448dbcf02cSchristos 	if (id_req != NO_ID_REQ)
64562a52023Schristos 		eap_aka_clear_identities(sm, data, CLEAR_EAP_ID);
6468dbcf02cSchristos 
6478dbcf02cSchristos 	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Identity (id=%d)", id);
6488dbcf02cSchristos 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
6498dbcf02cSchristos 			       EAP_AKA_SUBTYPE_IDENTITY);
6508dbcf02cSchristos 
6518dbcf02cSchristos 	if (identity) {
6528dbcf02cSchristos 		wpa_hexdump_ascii(MSG_DEBUG, "   AT_IDENTITY",
6538dbcf02cSchristos 				  identity, identity_len);
6548dbcf02cSchristos 		eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
6558dbcf02cSchristos 				identity, identity_len);
6568dbcf02cSchristos 	}
6578dbcf02cSchristos 
65836d97821Schristos 	return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
6598dbcf02cSchristos }
6608dbcf02cSchristos 
6618dbcf02cSchristos 
eap_aka_response_challenge(struct eap_aka_data * data,u8 id)6628dbcf02cSchristos static struct wpabuf * eap_aka_response_challenge(struct eap_aka_data *data,
6638dbcf02cSchristos 						  u8 id)
6648dbcf02cSchristos {
6658dbcf02cSchristos 	struct eap_sim_msg *msg;
6668dbcf02cSchristos 
6678dbcf02cSchristos 	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d)", id);
6688dbcf02cSchristos 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
6698dbcf02cSchristos 			       EAP_AKA_SUBTYPE_CHALLENGE);
6708dbcf02cSchristos 	wpa_printf(MSG_DEBUG, "   AT_RES");
6718dbcf02cSchristos 	eap_sim_msg_add(msg, EAP_SIM_AT_RES, data->res_len * 8,
6728dbcf02cSchristos 			data->res, data->res_len);
6738dbcf02cSchristos 	eap_aka_add_checkcode(data, msg);
6748dbcf02cSchristos 	if (data->use_result_ind) {
6758dbcf02cSchristos 		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
6768dbcf02cSchristos 		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
6778dbcf02cSchristos 	}
6788dbcf02cSchristos 	wpa_printf(MSG_DEBUG, "   AT_MAC");
6798dbcf02cSchristos 	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
68036d97821Schristos 	return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, (u8 *) "",
68136d97821Schristos 				  0);
6828dbcf02cSchristos }
6838dbcf02cSchristos 
6848dbcf02cSchristos 
eap_aka_response_reauth(struct eap_aka_data * data,u8 id,int counter_too_small,const u8 * nonce_s)6858dbcf02cSchristos static struct wpabuf * eap_aka_response_reauth(struct eap_aka_data *data,
6868dbcf02cSchristos 					       u8 id, int counter_too_small,
6878dbcf02cSchristos 					       const u8 *nonce_s)
6888dbcf02cSchristos {
6898dbcf02cSchristos 	struct eap_sim_msg *msg;
6908dbcf02cSchristos 	unsigned int counter;
6918dbcf02cSchristos 
6928dbcf02cSchristos 	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Reauthentication (id=%d)",
6938dbcf02cSchristos 		   id);
6948dbcf02cSchristos 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
6958dbcf02cSchristos 			       EAP_AKA_SUBTYPE_REAUTHENTICATION);
6968dbcf02cSchristos 	wpa_printf(MSG_DEBUG, "   AT_IV");
6978dbcf02cSchristos 	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
6988dbcf02cSchristos 	eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
6998dbcf02cSchristos 
7008dbcf02cSchristos 	if (counter_too_small) {
7018dbcf02cSchristos 		wpa_printf(MSG_DEBUG, "   *AT_COUNTER_TOO_SMALL");
7028dbcf02cSchristos 		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER_TOO_SMALL, 0, NULL, 0);
7038dbcf02cSchristos 		counter = data->counter_too_small;
7048dbcf02cSchristos 	} else
7058dbcf02cSchristos 		counter = data->counter;
7068dbcf02cSchristos 
7078dbcf02cSchristos 	wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", counter);
7088dbcf02cSchristos 	eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
7098dbcf02cSchristos 
7108dbcf02cSchristos 	if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
7118dbcf02cSchristos 		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
7128dbcf02cSchristos 			   "AT_ENCR_DATA");
7138dbcf02cSchristos 		eap_sim_msg_free(msg);
7148dbcf02cSchristos 		return NULL;
7158dbcf02cSchristos 	}
7168dbcf02cSchristos 	eap_aka_add_checkcode(data, msg);
7178dbcf02cSchristos 	if (data->use_result_ind) {
7188dbcf02cSchristos 		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
7198dbcf02cSchristos 		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
7208dbcf02cSchristos 	}
7218dbcf02cSchristos 	wpa_printf(MSG_DEBUG, "   AT_MAC");
7228dbcf02cSchristos 	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
72336d97821Schristos 	return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, nonce_s,
7248dbcf02cSchristos 				  EAP_SIM_NONCE_S_LEN);
7258dbcf02cSchristos }
7268dbcf02cSchristos 
7278dbcf02cSchristos 
eap_aka_response_notification(struct eap_aka_data * data,u8 id,u16 notification)7288dbcf02cSchristos static struct wpabuf * eap_aka_response_notification(struct eap_aka_data *data,
7298dbcf02cSchristos 						     u8 id, u16 notification)
7308dbcf02cSchristos {
7318dbcf02cSchristos 	struct eap_sim_msg *msg;
7328dbcf02cSchristos 	u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL;
7338dbcf02cSchristos 
7348dbcf02cSchristos 	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Notification (id=%d)", id);
7358dbcf02cSchristos 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
7368dbcf02cSchristos 			       EAP_AKA_SUBTYPE_NOTIFICATION);
7378dbcf02cSchristos 	if (k_aut && data->reauth) {
7388dbcf02cSchristos 		wpa_printf(MSG_DEBUG, "   AT_IV");
7398dbcf02cSchristos 		wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
7408dbcf02cSchristos 		eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
7418dbcf02cSchristos 					   EAP_SIM_AT_ENCR_DATA);
7428dbcf02cSchristos 		wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", data->counter);
7438dbcf02cSchristos 		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
7448dbcf02cSchristos 				NULL, 0);
7458dbcf02cSchristos 		if (eap_sim_msg_add_encr_end(msg, data->k_encr,
7468dbcf02cSchristos 					     EAP_SIM_AT_PADDING)) {
7478dbcf02cSchristos 			wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
7488dbcf02cSchristos 				   "AT_ENCR_DATA");
7498dbcf02cSchristos 			eap_sim_msg_free(msg);
7508dbcf02cSchristos 			return NULL;
7518dbcf02cSchristos 		}
7528dbcf02cSchristos 	}
7538dbcf02cSchristos 	if (k_aut) {
7548dbcf02cSchristos 		wpa_printf(MSG_DEBUG, "   AT_MAC");
7558dbcf02cSchristos 		eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
7568dbcf02cSchristos 	}
75736d97821Schristos 	return eap_sim_msg_finish(msg, data->eap_method, k_aut, (u8 *) "", 0);
7588dbcf02cSchristos }
7598dbcf02cSchristos 
7608dbcf02cSchristos 
eap_aka_process_identity(struct eap_sm * sm,struct eap_aka_data * data,u8 id,const struct wpabuf * reqData,struct eap_sim_attrs * attr)7618dbcf02cSchristos static struct wpabuf * eap_aka_process_identity(struct eap_sm *sm,
7628dbcf02cSchristos 						struct eap_aka_data *data,
7638dbcf02cSchristos 						u8 id,
7648dbcf02cSchristos 						const struct wpabuf *reqData,
7658dbcf02cSchristos 						struct eap_sim_attrs *attr)
7668dbcf02cSchristos {
7678dbcf02cSchristos 	int id_error;
7688dbcf02cSchristos 	struct wpabuf *buf;
7698dbcf02cSchristos 
7708dbcf02cSchristos 	wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Identity");
7718dbcf02cSchristos 
7728dbcf02cSchristos 	id_error = 0;
7738dbcf02cSchristos 	switch (attr->id_req) {
7748dbcf02cSchristos 	case NO_ID_REQ:
7758dbcf02cSchristos 		break;
7768dbcf02cSchristos 	case ANY_ID:
7778dbcf02cSchristos 		if (data->num_id_req > 0)
7788dbcf02cSchristos 			id_error++;
7798dbcf02cSchristos 		data->num_id_req++;
7808dbcf02cSchristos 		break;
7818dbcf02cSchristos 	case FULLAUTH_ID:
7828dbcf02cSchristos 		if (data->num_id_req > 1)
7838dbcf02cSchristos 			id_error++;
7848dbcf02cSchristos 		data->num_id_req++;
7858dbcf02cSchristos 		break;
7868dbcf02cSchristos 	case PERMANENT_ID:
7878dbcf02cSchristos 		if (data->num_id_req > 2)
7888dbcf02cSchristos 			id_error++;
7898dbcf02cSchristos 		data->num_id_req++;
7908dbcf02cSchristos 		break;
7918dbcf02cSchristos 	}
7928dbcf02cSchristos 	if (id_error) {
7938dbcf02cSchristos 		wpa_printf(MSG_INFO, "EAP-AKA: Too many ID requests "
7948dbcf02cSchristos 			   "used within one authentication");
7958dbcf02cSchristos 		return eap_aka_client_error(data, id,
7968dbcf02cSchristos 					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
7978dbcf02cSchristos 	}
7988dbcf02cSchristos 
7998dbcf02cSchristos 	buf = eap_aka_response_identity(sm, data, id, attr->id_req);
8008dbcf02cSchristos 
8018dbcf02cSchristos 	if (data->prev_id != id) {
8028dbcf02cSchristos 		eap_aka_add_id_msg(data, reqData);
8038dbcf02cSchristos 		eap_aka_add_id_msg(data, buf);
8048dbcf02cSchristos 		data->prev_id = id;
8058dbcf02cSchristos 	}
8068dbcf02cSchristos 
8078dbcf02cSchristos 	return buf;
8088dbcf02cSchristos }
8098dbcf02cSchristos 
8108dbcf02cSchristos 
eap_aka_verify_mac(struct eap_aka_data * data,const struct wpabuf * req,const u8 * mac,const u8 * extra,size_t extra_len)8118dbcf02cSchristos static int eap_aka_verify_mac(struct eap_aka_data *data,
8128dbcf02cSchristos 			      const struct wpabuf *req,
8138dbcf02cSchristos 			      const u8 *mac, const u8 *extra,
8148dbcf02cSchristos 			      size_t extra_len)
8158dbcf02cSchristos {
8168dbcf02cSchristos 	if (data->eap_method == EAP_TYPE_AKA_PRIME)
8178dbcf02cSchristos 		return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra,
8188dbcf02cSchristos 						 extra_len);
8198dbcf02cSchristos 	return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len);
8208dbcf02cSchristos }
8218dbcf02cSchristos 
8228dbcf02cSchristos 
8238dbcf02cSchristos #ifdef EAP_AKA_PRIME
eap_aka_prime_kdf_select(struct eap_aka_data * data,u8 id,u16 kdf)8248dbcf02cSchristos static struct wpabuf * eap_aka_prime_kdf_select(struct eap_aka_data *data,
8258dbcf02cSchristos 						u8 id, u16 kdf)
8268dbcf02cSchristos {
8278dbcf02cSchristos 	struct eap_sim_msg *msg;
8288dbcf02cSchristos 
8298dbcf02cSchristos 	data->kdf_negotiation = 1;
8308dbcf02cSchristos 	data->kdf = kdf;
8318dbcf02cSchristos 	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d) (KDF "
8328dbcf02cSchristos 		   "select)", id);
8338dbcf02cSchristos 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
8348dbcf02cSchristos 			       EAP_AKA_SUBTYPE_CHALLENGE);
8358dbcf02cSchristos 	wpa_printf(MSG_DEBUG, "   AT_KDF");
8368dbcf02cSchristos 	eap_sim_msg_add(msg, EAP_SIM_AT_KDF, kdf, NULL, 0);
83736d97821Schristos 	return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
8388dbcf02cSchristos }
8398dbcf02cSchristos 
8408dbcf02cSchristos 
eap_aka_prime_kdf_neg(struct eap_aka_data * data,u8 id,struct eap_sim_attrs * attr)8418dbcf02cSchristos static struct wpabuf * eap_aka_prime_kdf_neg(struct eap_aka_data *data,
8428dbcf02cSchristos 					     u8 id, struct eap_sim_attrs *attr)
8438dbcf02cSchristos {
8448dbcf02cSchristos 	size_t i;
8458dbcf02cSchristos 
8468dbcf02cSchristos 	for (i = 0; i < attr->kdf_count; i++) {
847ebb5671cSchristos 		if (attr->kdf[i] == EAP_AKA_PRIME_KDF) {
848ebb5671cSchristos 			os_memcpy(data->last_kdf_attrs, attr->kdf,
849ebb5671cSchristos 				  sizeof(u16) * attr->kdf_count);
850ebb5671cSchristos 			data->last_kdf_count = attr->kdf_count;
8518dbcf02cSchristos 			return eap_aka_prime_kdf_select(data, id,
8528dbcf02cSchristos 							EAP_AKA_PRIME_KDF);
8538dbcf02cSchristos 		}
854ebb5671cSchristos 	}
8558dbcf02cSchristos 
8568dbcf02cSchristos 	/* No matching KDF found - fail authentication as if AUTN had been
8578dbcf02cSchristos 	 * incorrect */
8588dbcf02cSchristos 	return eap_aka_authentication_reject(data, id);
8598dbcf02cSchristos }
8608dbcf02cSchristos 
8618dbcf02cSchristos 
eap_aka_prime_kdf_valid(struct eap_aka_data * data,struct eap_sim_attrs * attr)8628dbcf02cSchristos static int eap_aka_prime_kdf_valid(struct eap_aka_data *data,
8638dbcf02cSchristos 				   struct eap_sim_attrs *attr)
8648dbcf02cSchristos {
8658dbcf02cSchristos 	size_t i, j;
8668dbcf02cSchristos 
8678dbcf02cSchristos 	if (attr->kdf_count == 0)
8688dbcf02cSchristos 		return 0;
8698dbcf02cSchristos 
8708dbcf02cSchristos 	/* The only allowed (and required) duplication of a KDF is the addition
8718dbcf02cSchristos 	 * of the selected KDF into the beginning of the list. */
8728dbcf02cSchristos 
8738dbcf02cSchristos 	if (data->kdf_negotiation) {
874ebb5671cSchristos 		/* When the peer receives the new EAP-Request/AKA'-Challenge
875ebb5671cSchristos 		 * message, must check only requested change occurred in the
876ebb5671cSchristos 		 * list of AT_KDF attributes. If there are any other changes,
877ebb5671cSchristos 		 * the peer must behave like the case that AT_MAC had been
878ebb5671cSchristos 		 * incorrect and authentication is failed. These are defined in
879ebb5671cSchristos 		 * EAP-AKA' specification RFC 5448, Section 3.2. */
8808dbcf02cSchristos 		if (attr->kdf[0] != data->kdf) {
8818dbcf02cSchristos 			wpa_printf(MSG_WARNING, "EAP-AKA': The server did not "
8828dbcf02cSchristos 				   "accept the selected KDF");
883ebb5671cSchristos 			return -1;
884ebb5671cSchristos 		}
885ebb5671cSchristos 
886ebb5671cSchristos 		if (attr->kdf_count > EAP_AKA_PRIME_KDF_MAX ||
887ebb5671cSchristos 		    attr->kdf_count != data->last_kdf_count + 1) {
888ebb5671cSchristos 			wpa_printf(MSG_WARNING,
889ebb5671cSchristos 				   "EAP-AKA': The length of KDF attributes is wrong");
890ebb5671cSchristos 			return -1;
8918dbcf02cSchristos 		}
8928dbcf02cSchristos 
8938dbcf02cSchristos 		for (i = 1; i < attr->kdf_count; i++) {
894ebb5671cSchristos 			if (attr->kdf[i] != data->last_kdf_attrs[i - 1]) {
895ebb5671cSchristos 				wpa_printf(MSG_WARNING,
896ebb5671cSchristos 					   "EAP-AKA': The KDF attributes except selected KDF are not same as original one");
897ebb5671cSchristos 				return -1;
8988dbcf02cSchristos 			}
8998dbcf02cSchristos 		}
9008dbcf02cSchristos 	}
9018dbcf02cSchristos 
9028dbcf02cSchristos 	for (i = data->kdf ? 1 : 0; i < attr->kdf_count; i++) {
9038dbcf02cSchristos 		for (j = i + 1; j < attr->kdf_count; j++) {
9048dbcf02cSchristos 			if (attr->kdf[i] == attr->kdf[j]) {
9058dbcf02cSchristos 				wpa_printf(MSG_WARNING, "EAP-AKA': The server "
9068dbcf02cSchristos 					   "included a duplicated KDF");
9078dbcf02cSchristos 				return 0;
9088dbcf02cSchristos 			}
9098dbcf02cSchristos 		}
9108dbcf02cSchristos 	}
9118dbcf02cSchristos 
9128dbcf02cSchristos 	return 1;
9138dbcf02cSchristos }
9148dbcf02cSchristos #endif /* EAP_AKA_PRIME */
9158dbcf02cSchristos 
9168dbcf02cSchristos 
eap_aka_process_challenge(struct eap_sm * sm,struct eap_aka_data * data,u8 id,const struct wpabuf * reqData,struct eap_sim_attrs * attr)9178dbcf02cSchristos static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
9188dbcf02cSchristos 						 struct eap_aka_data *data,
9198dbcf02cSchristos 						 u8 id,
9208dbcf02cSchristos 						 const struct wpabuf *reqData,
9218dbcf02cSchristos 						 struct eap_sim_attrs *attr)
9228dbcf02cSchristos {
9238dbcf02cSchristos 	const u8 *identity;
9248dbcf02cSchristos 	size_t identity_len;
9258dbcf02cSchristos 	int res;
9268dbcf02cSchristos 	struct eap_sim_attrs eattr;
9278dbcf02cSchristos 
9288dbcf02cSchristos 	wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Challenge");
9298dbcf02cSchristos 
9308dbcf02cSchristos 	if (attr->checkcode &&
9318dbcf02cSchristos 	    eap_aka_verify_checkcode(data, attr->checkcode,
9328dbcf02cSchristos 				     attr->checkcode_len)) {
9338dbcf02cSchristos 		wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
9348dbcf02cSchristos 			   "message");
935*0d69f216Schristos #ifdef TEST_FUZZ
936*0d69f216Schristos 		wpa_printf(MSG_INFO,
937*0d69f216Schristos 			   "TEST: Ignore AT_CHECKCODE mismatch for fuzz testing");
938*0d69f216Schristos #else /* TEST_FUZZ */
9398dbcf02cSchristos 		return eap_aka_client_error(data, id,
9408dbcf02cSchristos 					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
941*0d69f216Schristos #endif /* TEST_FUZZ */
9428dbcf02cSchristos 	}
9438dbcf02cSchristos 
9448dbcf02cSchristos #ifdef EAP_AKA_PRIME
9458dbcf02cSchristos 	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
9468dbcf02cSchristos 		if (!attr->kdf_input || attr->kdf_input_len == 0) {
9478dbcf02cSchristos 			wpa_printf(MSG_WARNING, "EAP-AKA': Challenge message "
9488dbcf02cSchristos 				   "did not include non-empty AT_KDF_INPUT");
9498dbcf02cSchristos 			/* Fail authentication as if AUTN had been incorrect */
9508dbcf02cSchristos 			return eap_aka_authentication_reject(data, id);
9518dbcf02cSchristos 		}
9528dbcf02cSchristos 		os_free(data->network_name);
953ebb5671cSchristos 		data->network_name = os_memdup(attr->kdf_input,
954ebb5671cSchristos 					       attr->kdf_input_len);
9558dbcf02cSchristos 		if (data->network_name == NULL) {
9568dbcf02cSchristos 			wpa_printf(MSG_WARNING, "EAP-AKA': No memory for "
9578dbcf02cSchristos 				   "storing Network Name");
9588dbcf02cSchristos 			return eap_aka_authentication_reject(data, id);
9598dbcf02cSchristos 		}
9608dbcf02cSchristos 		data->network_name_len = attr->kdf_input_len;
9618dbcf02cSchristos 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA': Network Name "
9628dbcf02cSchristos 				  "(AT_KDF_INPUT)",
9638dbcf02cSchristos 				  data->network_name, data->network_name_len);
9648dbcf02cSchristos 		/* TODO: check Network Name per 3GPP.33.402 */
9658dbcf02cSchristos 
966ebb5671cSchristos 		res = eap_aka_prime_kdf_valid(data, attr);
967ebb5671cSchristos 		if (res == 0)
9688dbcf02cSchristos 			return eap_aka_authentication_reject(data, id);
969ebb5671cSchristos 		else if (res == -1)
970ebb5671cSchristos 			return eap_aka_client_error(
971ebb5671cSchristos 				data, id, EAP_AKA_UNABLE_TO_PROCESS_PACKET);
9728dbcf02cSchristos 
9738dbcf02cSchristos 		if (attr->kdf[0] != EAP_AKA_PRIME_KDF)
9748dbcf02cSchristos 			return eap_aka_prime_kdf_neg(data, id, attr);
9758dbcf02cSchristos 
9768dbcf02cSchristos 		data->kdf = EAP_AKA_PRIME_KDF;
9778dbcf02cSchristos 		wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf);
9788dbcf02cSchristos 	}
9798dbcf02cSchristos 
9808dbcf02cSchristos 	if (data->eap_method == EAP_TYPE_AKA && attr->bidding) {
9818dbcf02cSchristos 		u16 flags = WPA_GET_BE16(attr->bidding);
9828dbcf02cSchristos 		if ((flags & EAP_AKA_BIDDING_FLAG_D) &&
9838dbcf02cSchristos 		    eap_allowed_method(sm, EAP_VENDOR_IETF,
9848dbcf02cSchristos 				       EAP_TYPE_AKA_PRIME)) {
9858dbcf02cSchristos 			wpa_printf(MSG_WARNING, "EAP-AKA: Bidding down from "
9868dbcf02cSchristos 				   "AKA' to AKA detected");
9878dbcf02cSchristos 			/* Fail authentication as if AUTN had been incorrect */
9888dbcf02cSchristos 			return eap_aka_authentication_reject(data, id);
9898dbcf02cSchristos 		}
9908dbcf02cSchristos 	}
9918dbcf02cSchristos #endif /* EAP_AKA_PRIME */
9928dbcf02cSchristos 
9938dbcf02cSchristos 	data->reauth = 0;
9948dbcf02cSchristos 	if (!attr->mac || !attr->rand || !attr->autn) {
9958dbcf02cSchristos 		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
9968dbcf02cSchristos 			   "did not include%s%s%s",
9978dbcf02cSchristos 			   !attr->mac ? " AT_MAC" : "",
9988dbcf02cSchristos 			   !attr->rand ? " AT_RAND" : "",
9998dbcf02cSchristos 			   !attr->autn ? " AT_AUTN" : "");
10008dbcf02cSchristos 		return eap_aka_client_error(data, id,
10018dbcf02cSchristos 					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
10028dbcf02cSchristos 	}
10038dbcf02cSchristos 	os_memcpy(data->rand, attr->rand, EAP_AKA_RAND_LEN);
10048dbcf02cSchristos 	os_memcpy(data->autn, attr->autn, EAP_AKA_AUTN_LEN);
10058dbcf02cSchristos 
10068dbcf02cSchristos 	res = eap_aka_umts_auth(sm, data);
10078dbcf02cSchristos 	if (res == -1) {
10088dbcf02cSchristos 		wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
10098dbcf02cSchristos 			   "failed (AUTN)");
10108dbcf02cSchristos 		return eap_aka_authentication_reject(data, id);
10118dbcf02cSchristos 	} else if (res == -2) {
10128dbcf02cSchristos 		wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
10138dbcf02cSchristos 			   "failed (AUTN seq# -> AUTS)");
1014ebb5671cSchristos 		return eap_aka_synchronization_failure(data, id, attr);
101536d97821Schristos 	} else if (res > 0) {
101636d97821Schristos 		wpa_printf(MSG_DEBUG, "EAP-AKA: Wait for external USIM processing");
101736d97821Schristos 		return NULL;
10188dbcf02cSchristos 	} else if (res) {
10198dbcf02cSchristos 		wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication failed");
10208dbcf02cSchristos 		return eap_aka_client_error(data, id,
10218dbcf02cSchristos 					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
10228dbcf02cSchristos 	}
10238dbcf02cSchristos #ifdef EAP_AKA_PRIME
10248dbcf02cSchristos 	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
10258dbcf02cSchristos 		/* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
10268dbcf02cSchristos 		 * needed 6-octet SQN ^ AK for CK',IK' derivation */
10278dbcf02cSchristos 		u16 amf = WPA_GET_BE16(data->autn + 6);
10288dbcf02cSchristos 		if (!(amf & 0x8000)) {
10298dbcf02cSchristos 			wpa_printf(MSG_WARNING, "EAP-AKA': AMF separation bit "
10308dbcf02cSchristos 				   "not set (AMF=0x%4x)", amf);
10318dbcf02cSchristos 			return eap_aka_authentication_reject(data, id);
10328dbcf02cSchristos 		}
10338dbcf02cSchristos 		eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
10348dbcf02cSchristos 						 data->autn,
10358dbcf02cSchristos 						 data->network_name,
10368dbcf02cSchristos 						 data->network_name_len);
10378dbcf02cSchristos 	}
10388dbcf02cSchristos #endif /* EAP_AKA_PRIME */
10398dbcf02cSchristos 	if (data->last_eap_identity) {
10408dbcf02cSchristos 		identity = data->last_eap_identity;
10418dbcf02cSchristos 		identity_len = data->last_eap_identity_len;
1042*0d69f216Schristos 	} else if (data->pseudonym &&
1043*0d69f216Schristos 		   !eap_sim_anonymous_username(data->pseudonym,
1044*0d69f216Schristos 					       data->pseudonym_len)) {
10458dbcf02cSchristos 		identity = data->pseudonym;
10468dbcf02cSchristos 		identity_len = data->pseudonym_len;
1047ebb5671cSchristos 	} else {
1048ebb5671cSchristos 		struct eap_peer_config *config;
1049ebb5671cSchristos 
1050ebb5671cSchristos 		config = eap_get_config(sm);
1051ebb5671cSchristos 		if (config && config->imsi_identity) {
1052ebb5671cSchristos 			identity = config->imsi_identity;
1053ebb5671cSchristos 			identity_len = config->imsi_identity_len;
1054ebb5671cSchristos 		} else {
10558dbcf02cSchristos 			identity = eap_get_config_identity(sm, &identity_len);
1056ebb5671cSchristos 		}
1057ebb5671cSchristos 	}
10588dbcf02cSchristos 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Selected identity for MK "
10598dbcf02cSchristos 			  "derivation", identity, identity_len);
10608dbcf02cSchristos 	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
10618dbcf02cSchristos 		eap_aka_prime_derive_keys(identity, identity_len, data->ik,
10628dbcf02cSchristos 					  data->ck, data->k_encr, data->k_aut,
10638dbcf02cSchristos 					  data->k_re, data->msk, data->emsk);
10648dbcf02cSchristos 	} else {
10658dbcf02cSchristos 		eap_aka_derive_mk(identity, identity_len, data->ik, data->ck,
10668dbcf02cSchristos 				  data->mk);
10678dbcf02cSchristos 		eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
10688dbcf02cSchristos 				    data->msk, data->emsk);
10698dbcf02cSchristos 	}
10708dbcf02cSchristos 	if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
10718dbcf02cSchristos 		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
10728dbcf02cSchristos 			   "used invalid AT_MAC");
1073*0d69f216Schristos #ifdef TEST_FUZZ
1074*0d69f216Schristos 		wpa_printf(MSG_INFO,
1075*0d69f216Schristos 			   "TEST: Ignore AT_MAC mismatch for fuzz testing");
1076*0d69f216Schristos #else /* TEST_FUZZ */
10778dbcf02cSchristos 		return eap_aka_client_error(data, id,
10788dbcf02cSchristos 					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
1079*0d69f216Schristos #endif /* TEST_FUZZ */
10808dbcf02cSchristos 	}
10818dbcf02cSchristos 
108242669be3Schristos 	/* Old reauthentication identity must not be used anymore. In
108342669be3Schristos 	 * other words, if no new identities are received, full
108442669be3Schristos 	 * authentication will be used on next reauthentication (using
108542669be3Schristos 	 * pseudonym identity or permanent identity). */
108662a52023Schristos 	eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
10878dbcf02cSchristos 
10888dbcf02cSchristos 	if (attr->encr_data) {
10898dbcf02cSchristos 		u8 *decrypted;
10908dbcf02cSchristos 		decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
10918dbcf02cSchristos 					       attr->encr_data_len, attr->iv,
10928dbcf02cSchristos 					       &eattr, 0);
10938dbcf02cSchristos 		if (decrypted == NULL) {
10948dbcf02cSchristos 			return eap_aka_client_error(
10958dbcf02cSchristos 				data, id, EAP_AKA_UNABLE_TO_PROCESS_PACKET);
10968dbcf02cSchristos 		}
109742669be3Schristos 		eap_aka_learn_ids(sm, data, &eattr);
10988dbcf02cSchristos 		os_free(decrypted);
10998dbcf02cSchristos 	}
11008dbcf02cSchristos 
11018dbcf02cSchristos 	if (data->result_ind && attr->result_ind)
11028dbcf02cSchristos 		data->use_result_ind = 1;
11038dbcf02cSchristos 
110436d97821Schristos 	if (data->state != FAILURE) {
11058dbcf02cSchristos 		eap_aka_state(data, data->use_result_ind ?
11068dbcf02cSchristos 			      RESULT_SUCCESS : SUCCESS);
11078dbcf02cSchristos 	}
11088dbcf02cSchristos 
11098dbcf02cSchristos 	data->num_id_req = 0;
11108dbcf02cSchristos 	data->num_notification = 0;
11118dbcf02cSchristos 	/* RFC 4187 specifies that counter is initialized to one after
11128dbcf02cSchristos 	 * fullauth, but initializing it to zero makes it easier to implement
11138dbcf02cSchristos 	 * reauth verification. */
11148dbcf02cSchristos 	data->counter = 0;
11158dbcf02cSchristos 	return eap_aka_response_challenge(data, id);
11168dbcf02cSchristos }
11178dbcf02cSchristos 
11188dbcf02cSchristos 
eap_aka_process_notification_reauth(struct eap_aka_data * data,struct eap_sim_attrs * attr)11198dbcf02cSchristos static int eap_aka_process_notification_reauth(struct eap_aka_data *data,
11208dbcf02cSchristos 					       struct eap_sim_attrs *attr)
11218dbcf02cSchristos {
11228dbcf02cSchristos 	struct eap_sim_attrs eattr;
11238dbcf02cSchristos 	u8 *decrypted;
11248dbcf02cSchristos 
11258dbcf02cSchristos 	if (attr->encr_data == NULL || attr->iv == NULL) {
11268dbcf02cSchristos 		wpa_printf(MSG_WARNING, "EAP-AKA: Notification message after "
11278dbcf02cSchristos 			   "reauth did not include encrypted data");
11288dbcf02cSchristos 		return -1;
11298dbcf02cSchristos 	}
11308dbcf02cSchristos 
11318dbcf02cSchristos 	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
11328dbcf02cSchristos 				       attr->encr_data_len, attr->iv, &eattr,
11338dbcf02cSchristos 				       0);
11348dbcf02cSchristos 	if (decrypted == NULL) {
11358dbcf02cSchristos 		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
11368dbcf02cSchristos 			   "data from notification message");
11378dbcf02cSchristos 		return -1;
11388dbcf02cSchristos 	}
11398dbcf02cSchristos 
11408dbcf02cSchristos 	if (eattr.counter < 0 || (size_t) eattr.counter != data->counter) {
11418dbcf02cSchristos 		wpa_printf(MSG_WARNING, "EAP-AKA: Counter in notification "
11428dbcf02cSchristos 			   "message does not match with counter in reauth "
11438dbcf02cSchristos 			   "message");
11448dbcf02cSchristos 		os_free(decrypted);
11458dbcf02cSchristos 		return -1;
11468dbcf02cSchristos 	}
11478dbcf02cSchristos 
11488dbcf02cSchristos 	os_free(decrypted);
11498dbcf02cSchristos 	return 0;
11508dbcf02cSchristos }
11518dbcf02cSchristos 
11528dbcf02cSchristos 
eap_aka_process_notification_auth(struct eap_aka_data * data,const struct wpabuf * reqData,struct eap_sim_attrs * attr)11538dbcf02cSchristos static int eap_aka_process_notification_auth(struct eap_aka_data *data,
11548dbcf02cSchristos 					     const struct wpabuf *reqData,
11558dbcf02cSchristos 					     struct eap_sim_attrs *attr)
11568dbcf02cSchristos {
11578dbcf02cSchristos 	if (attr->mac == NULL) {
11588dbcf02cSchristos 		wpa_printf(MSG_INFO, "EAP-AKA: no AT_MAC in after_auth "
11598dbcf02cSchristos 			   "Notification message");
11608dbcf02cSchristos 		return -1;
11618dbcf02cSchristos 	}
11628dbcf02cSchristos 
11638dbcf02cSchristos 	if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
11648dbcf02cSchristos 		wpa_printf(MSG_WARNING, "EAP-AKA: Notification message "
11658dbcf02cSchristos 			   "used invalid AT_MAC");
11668dbcf02cSchristos 		return -1;
11678dbcf02cSchristos 	}
11688dbcf02cSchristos 
11698dbcf02cSchristos 	if (data->reauth &&
11708dbcf02cSchristos 	    eap_aka_process_notification_reauth(data, attr)) {
11718dbcf02cSchristos 		wpa_printf(MSG_WARNING, "EAP-AKA: Invalid notification "
11728dbcf02cSchristos 			   "message after reauth");
11738dbcf02cSchristos 		return -1;
11748dbcf02cSchristos 	}
11758dbcf02cSchristos 
11768dbcf02cSchristos 	return 0;
11778dbcf02cSchristos }
11788dbcf02cSchristos 
11798dbcf02cSchristos 
eap_aka_process_notification(struct eap_sm * sm,struct eap_aka_data * data,u8 id,const struct wpabuf * reqData,struct eap_sim_attrs * attr)11808dbcf02cSchristos static struct wpabuf * eap_aka_process_notification(
11818dbcf02cSchristos 	struct eap_sm *sm, struct eap_aka_data *data, u8 id,
11828dbcf02cSchristos 	const struct wpabuf *reqData, struct eap_sim_attrs *attr)
11838dbcf02cSchristos {
11848dbcf02cSchristos 	wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Notification");
11858dbcf02cSchristos 	if (data->num_notification > 0) {
11868dbcf02cSchristos 		wpa_printf(MSG_INFO, "EAP-AKA: too many notification "
11878dbcf02cSchristos 			   "rounds (only one allowed)");
11888dbcf02cSchristos 		return eap_aka_client_error(data, id,
11898dbcf02cSchristos 					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
11908dbcf02cSchristos 	}
11918dbcf02cSchristos 	data->num_notification++;
11928dbcf02cSchristos 	if (attr->notification == -1) {
11938dbcf02cSchristos 		wpa_printf(MSG_INFO, "EAP-AKA: no AT_NOTIFICATION in "
11948dbcf02cSchristos 			   "Notification message");
11958dbcf02cSchristos 		return eap_aka_client_error(data, id,
11968dbcf02cSchristos 					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
11978dbcf02cSchristos 	}
11988dbcf02cSchristos 
11998dbcf02cSchristos 	if ((attr->notification & 0x4000) == 0 &&
12008dbcf02cSchristos 	    eap_aka_process_notification_auth(data, reqData, attr)) {
12018dbcf02cSchristos 		return eap_aka_client_error(data, id,
12028dbcf02cSchristos 					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
12038dbcf02cSchristos 	}
12048dbcf02cSchristos 
12058dbcf02cSchristos 	eap_sim_report_notification(sm->msg_ctx, attr->notification, 1);
12068dbcf02cSchristos 	if (attr->notification >= 0 && attr->notification < 32768) {
1207ebb5671cSchristos 		data->error_code = attr->notification;
12088dbcf02cSchristos 		eap_aka_state(data, FAILURE);
12098dbcf02cSchristos 	} else if (attr->notification == EAP_SIM_SUCCESS &&
12108dbcf02cSchristos 		   data->state == RESULT_SUCCESS)
12118dbcf02cSchristos 		eap_aka_state(data, SUCCESS);
12128dbcf02cSchristos 	return eap_aka_response_notification(data, id, attr->notification);
12138dbcf02cSchristos }
12148dbcf02cSchristos 
12158dbcf02cSchristos 
eap_aka_process_reauthentication(struct eap_sm * sm,struct eap_aka_data * data,u8 id,const struct wpabuf * reqData,struct eap_sim_attrs * attr)12168dbcf02cSchristos static struct wpabuf * eap_aka_process_reauthentication(
12178dbcf02cSchristos 	struct eap_sm *sm, struct eap_aka_data *data, u8 id,
12188dbcf02cSchristos 	const struct wpabuf *reqData, struct eap_sim_attrs *attr)
12198dbcf02cSchristos {
12208dbcf02cSchristos 	struct eap_sim_attrs eattr;
12218dbcf02cSchristos 	u8 *decrypted;
12228dbcf02cSchristos 
12238dbcf02cSchristos 	wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Reauthentication");
12248dbcf02cSchristos 
12258dbcf02cSchristos 	if (attr->checkcode &&
12268dbcf02cSchristos 	    eap_aka_verify_checkcode(data, attr->checkcode,
12278dbcf02cSchristos 				     attr->checkcode_len)) {
1228*0d69f216Schristos #ifdef TEST_FUZZ
1229*0d69f216Schristos 		wpa_printf(MSG_INFO,
1230*0d69f216Schristos 			   "TEST: Ignore AT_CHECKCODE mismatch for fuzz testing");
1231*0d69f216Schristos #else /* TEST_FUZZ */
12328dbcf02cSchristos 		wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
12338dbcf02cSchristos 			   "message");
1234*0d69f216Schristos #endif /* TEST_FUZZ */
12358dbcf02cSchristos 		return eap_aka_client_error(data, id,
12368dbcf02cSchristos 					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
12378dbcf02cSchristos 	}
12388dbcf02cSchristos 
12398dbcf02cSchristos 	if (data->reauth_id == NULL) {
12408dbcf02cSchristos 		wpa_printf(MSG_WARNING, "EAP-AKA: Server is trying "
12418dbcf02cSchristos 			   "reauthentication, but no reauth_id available");
12428dbcf02cSchristos 		return eap_aka_client_error(data, id,
12438dbcf02cSchristos 					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
12448dbcf02cSchristos 	}
12458dbcf02cSchristos 
12468dbcf02cSchristos 	data->reauth = 1;
12478dbcf02cSchristos 	if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
12488dbcf02cSchristos 		wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
12498dbcf02cSchristos 			   "did not have valid AT_MAC");
12508dbcf02cSchristos 		return eap_aka_client_error(data, id,
12518dbcf02cSchristos 					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
12528dbcf02cSchristos 	}
12538dbcf02cSchristos 
1254*0d69f216Schristos 	/* At this stage the received MAC has been verified. Use this MAC for
1255*0d69f216Schristos 	 * reauth Session-Id calculation if all other checks pass.
1256*0d69f216Schristos 	 * The peer does not use the local MAC but the received MAC in deriving
1257*0d69f216Schristos 	 * Session-Id. */
1258*0d69f216Schristos 	os_memcpy(data->reauth_mac, attr->mac, EAP_SIM_MAC_LEN);
1259*0d69f216Schristos 	wpa_hexdump(MSG_DEBUG, "EAP-AKA: Server MAC",
1260*0d69f216Schristos 		    data->reauth_mac, EAP_SIM_MAC_LEN);
1261*0d69f216Schristos 
12628dbcf02cSchristos 	if (attr->encr_data == NULL || attr->iv == NULL) {
12638dbcf02cSchristos 		wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
12648dbcf02cSchristos 			   "message did not include encrypted data");
12658dbcf02cSchristos 		return eap_aka_client_error(data, id,
12668dbcf02cSchristos 					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
12678dbcf02cSchristos 	}
12688dbcf02cSchristos 
12698dbcf02cSchristos 	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
12708dbcf02cSchristos 				       attr->encr_data_len, attr->iv, &eattr,
12718dbcf02cSchristos 				       0);
12728dbcf02cSchristos 	if (decrypted == NULL) {
12738dbcf02cSchristos 		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
12748dbcf02cSchristos 			   "data from reauthentication message");
12758dbcf02cSchristos 		return eap_aka_client_error(data, id,
12768dbcf02cSchristos 					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
12778dbcf02cSchristos 	}
12788dbcf02cSchristos 
12798dbcf02cSchristos 	if (eattr.nonce_s == NULL || eattr.counter < 0) {
12808dbcf02cSchristos 		wpa_printf(MSG_INFO, "EAP-AKA: (encr) No%s%s in reauth packet",
12818dbcf02cSchristos 			   !eattr.nonce_s ? " AT_NONCE_S" : "",
12828dbcf02cSchristos 			   eattr.counter < 0 ? " AT_COUNTER" : "");
12838dbcf02cSchristos 		os_free(decrypted);
12848dbcf02cSchristos 		return eap_aka_client_error(data, id,
12858dbcf02cSchristos 					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
12868dbcf02cSchristos 	}
12878dbcf02cSchristos 
12888dbcf02cSchristos 	if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) {
12898dbcf02cSchristos 		struct wpabuf *res;
12908dbcf02cSchristos 		wpa_printf(MSG_INFO, "EAP-AKA: (encr) Invalid counter "
12918dbcf02cSchristos 			   "(%d <= %d)", eattr.counter, data->counter);
12928dbcf02cSchristos 		data->counter_too_small = eattr.counter;
12938dbcf02cSchristos 
12948dbcf02cSchristos 		/* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
12958dbcf02cSchristos 		 * reauth_id must not be used to start a new reauthentication.
12968dbcf02cSchristos 		 * However, since it was used in the last EAP-Response-Identity
12978dbcf02cSchristos 		 * packet, it has to saved for the following fullauth to be
12988dbcf02cSchristos 		 * used in MK derivation. */
12998dbcf02cSchristos 		os_free(data->last_eap_identity);
13008dbcf02cSchristos 		data->last_eap_identity = data->reauth_id;
13018dbcf02cSchristos 		data->last_eap_identity_len = data->reauth_id_len;
13028dbcf02cSchristos 		data->reauth_id = NULL;
13038dbcf02cSchristos 		data->reauth_id_len = 0;
13048dbcf02cSchristos 
13058dbcf02cSchristos 		res = eap_aka_response_reauth(data, id, 1, eattr.nonce_s);
13068dbcf02cSchristos 		os_free(decrypted);
13078dbcf02cSchristos 
13088dbcf02cSchristos 		return res;
13098dbcf02cSchristos 	}
13108dbcf02cSchristos 	data->counter = eattr.counter;
13118dbcf02cSchristos 
13128dbcf02cSchristos 	os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN);
13138dbcf02cSchristos 	wpa_hexdump(MSG_DEBUG, "EAP-AKA: (encr) AT_NONCE_S",
13148dbcf02cSchristos 		    data->nonce_s, EAP_SIM_NONCE_S_LEN);
13158dbcf02cSchristos 
13168dbcf02cSchristos 	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
13178dbcf02cSchristos 		eap_aka_prime_derive_keys_reauth(data->k_re, data->counter,
13188dbcf02cSchristos 						 data->reauth_id,
13198dbcf02cSchristos 						 data->reauth_id_len,
13208dbcf02cSchristos 						 data->nonce_s,
13218dbcf02cSchristos 						 data->msk, data->emsk);
13228dbcf02cSchristos 	} else {
13238dbcf02cSchristos 		eap_sim_derive_keys_reauth(data->counter, data->reauth_id,
13248dbcf02cSchristos 					   data->reauth_id_len,
13258dbcf02cSchristos 					   data->nonce_s, data->mk,
13268dbcf02cSchristos 					   data->msk, data->emsk);
13278dbcf02cSchristos 	}
132862a52023Schristos 	eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
132942669be3Schristos 	eap_aka_learn_ids(sm, data, &eattr);
13308dbcf02cSchristos 
13318dbcf02cSchristos 	if (data->result_ind && attr->result_ind)
13328dbcf02cSchristos 		data->use_result_ind = 1;
13338dbcf02cSchristos 
133436d97821Schristos 	if (data->state != FAILURE) {
13358dbcf02cSchristos 		eap_aka_state(data, data->use_result_ind ?
13368dbcf02cSchristos 			      RESULT_SUCCESS : SUCCESS);
13378dbcf02cSchristos 	}
13388dbcf02cSchristos 
13398dbcf02cSchristos 	data->num_id_req = 0;
13408dbcf02cSchristos 	data->num_notification = 0;
13418dbcf02cSchristos 	if (data->counter > EAP_AKA_MAX_FAST_REAUTHS) {
13428dbcf02cSchristos 		wpa_printf(MSG_DEBUG, "EAP-AKA: Maximum number of "
13438dbcf02cSchristos 			   "fast reauths performed - force fullauth");
134462a52023Schristos 		eap_aka_clear_identities(sm, data,
134562a52023Schristos 					 CLEAR_REAUTH_ID | CLEAR_EAP_ID);
13468dbcf02cSchristos 	}
13478dbcf02cSchristos 	os_free(decrypted);
13488dbcf02cSchristos 	return eap_aka_response_reauth(data, id, 0, data->nonce_s);
13498dbcf02cSchristos }
13508dbcf02cSchristos 
13518dbcf02cSchristos 
eap_aka_process(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)13528dbcf02cSchristos static struct wpabuf * eap_aka_process(struct eap_sm *sm, void *priv,
13538dbcf02cSchristos 				       struct eap_method_ret *ret,
13548dbcf02cSchristos 				       const struct wpabuf *reqData)
13558dbcf02cSchristos {
13568dbcf02cSchristos 	struct eap_aka_data *data = priv;
13578dbcf02cSchristos 	const struct eap_hdr *req;
13588dbcf02cSchristos 	u8 subtype, id;
13598dbcf02cSchristos 	struct wpabuf *res;
13608dbcf02cSchristos 	const u8 *pos;
13618dbcf02cSchristos 	struct eap_sim_attrs attr;
13628dbcf02cSchristos 	size_t len;
13638dbcf02cSchristos 
13648dbcf02cSchristos 	wpa_hexdump_buf(MSG_DEBUG, "EAP-AKA: EAP data", reqData);
13658dbcf02cSchristos 	if (eap_get_config_identity(sm, &len) == NULL) {
13668dbcf02cSchristos 		wpa_printf(MSG_INFO, "EAP-AKA: Identity not configured");
13678dbcf02cSchristos 		eap_sm_request_identity(sm);
13688dbcf02cSchristos 		ret->ignore = TRUE;
13698dbcf02cSchristos 		return NULL;
13708dbcf02cSchristos 	}
13718dbcf02cSchristos 
13728dbcf02cSchristos 	pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, reqData,
13738dbcf02cSchristos 			       &len);
1374928750b6Schristos 	if (pos == NULL || len < 3) {
13758dbcf02cSchristos 		ret->ignore = TRUE;
13768dbcf02cSchristos 		return NULL;
13778dbcf02cSchristos 	}
13788dbcf02cSchristos 	req = wpabuf_head(reqData);
13798dbcf02cSchristos 	id = req->identifier;
13808dbcf02cSchristos 	len = be_to_host16(req->length);
13818dbcf02cSchristos 
13828dbcf02cSchristos 	ret->ignore = FALSE;
13838dbcf02cSchristos 	ret->methodState = METHOD_MAY_CONT;
13848dbcf02cSchristos 	ret->decision = DECISION_FAIL;
13858dbcf02cSchristos 	ret->allowNotifications = TRUE;
13868dbcf02cSchristos 
13878dbcf02cSchristos 	subtype = *pos++;
13888dbcf02cSchristos 	wpa_printf(MSG_DEBUG, "EAP-AKA: Subtype=%d", subtype);
13898dbcf02cSchristos 	pos += 2; /* Reserved */
13908dbcf02cSchristos 
13918dbcf02cSchristos 	if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr,
13928dbcf02cSchristos 			       data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1,
13938dbcf02cSchristos 			       0)) {
13948dbcf02cSchristos 		res = eap_aka_client_error(data, id,
13958dbcf02cSchristos 					   EAP_AKA_UNABLE_TO_PROCESS_PACKET);
13968dbcf02cSchristos 		goto done;
13978dbcf02cSchristos 	}
13988dbcf02cSchristos 
13998dbcf02cSchristos 	switch (subtype) {
14008dbcf02cSchristos 	case EAP_AKA_SUBTYPE_IDENTITY:
14018dbcf02cSchristos 		res = eap_aka_process_identity(sm, data, id, reqData, &attr);
14028dbcf02cSchristos 		break;
14038dbcf02cSchristos 	case EAP_AKA_SUBTYPE_CHALLENGE:
14048dbcf02cSchristos 		res = eap_aka_process_challenge(sm, data, id, reqData, &attr);
14058dbcf02cSchristos 		break;
14068dbcf02cSchristos 	case EAP_AKA_SUBTYPE_NOTIFICATION:
14078dbcf02cSchristos 		res = eap_aka_process_notification(sm, data, id, reqData,
14088dbcf02cSchristos 						   &attr);
14098dbcf02cSchristos 		break;
14108dbcf02cSchristos 	case EAP_AKA_SUBTYPE_REAUTHENTICATION:
14118dbcf02cSchristos 		res = eap_aka_process_reauthentication(sm, data, id, reqData,
14128dbcf02cSchristos 						       &attr);
14138dbcf02cSchristos 		break;
14148dbcf02cSchristos 	case EAP_AKA_SUBTYPE_CLIENT_ERROR:
14158dbcf02cSchristos 		wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Client-Error");
14168dbcf02cSchristos 		res = eap_aka_client_error(data, id,
14178dbcf02cSchristos 					   EAP_AKA_UNABLE_TO_PROCESS_PACKET);
14188dbcf02cSchristos 		break;
14198dbcf02cSchristos 	default:
14208dbcf02cSchristos 		wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown subtype=%d", subtype);
14218dbcf02cSchristos 		res = eap_aka_client_error(data, id,
14228dbcf02cSchristos 					   EAP_AKA_UNABLE_TO_PROCESS_PACKET);
14238dbcf02cSchristos 		break;
14248dbcf02cSchristos 	}
14258dbcf02cSchristos 
14268dbcf02cSchristos done:
14278dbcf02cSchristos 	if (data->state == FAILURE) {
14288dbcf02cSchristos 		ret->decision = DECISION_FAIL;
14298dbcf02cSchristos 		ret->methodState = METHOD_DONE;
14308dbcf02cSchristos 	} else if (data->state == SUCCESS) {
14318dbcf02cSchristos 		ret->decision = data->use_result_ind ?
14328dbcf02cSchristos 			DECISION_UNCOND_SUCC : DECISION_COND_SUCC;
14338dbcf02cSchristos 		/*
14348dbcf02cSchristos 		 * It is possible for the server to reply with AKA
14358dbcf02cSchristos 		 * Notification, so we must allow the method to continue and
14368dbcf02cSchristos 		 * not only accept EAP-Success at this point.
14378dbcf02cSchristos 		 */
14388dbcf02cSchristos 		ret->methodState = data->use_result_ind ?
14398dbcf02cSchristos 			METHOD_DONE : METHOD_MAY_CONT;
144036d97821Schristos 	} else if (data->state == RESULT_SUCCESS)
14418dbcf02cSchristos 		ret->methodState = METHOD_CONT;
14428dbcf02cSchristos 
14438dbcf02cSchristos 	if (ret->methodState == METHOD_DONE) {
14448dbcf02cSchristos 		ret->allowNotifications = FALSE;
14458dbcf02cSchristos 	}
14468dbcf02cSchristos 
14478dbcf02cSchristos 	return res;
14488dbcf02cSchristos }
14498dbcf02cSchristos 
14508dbcf02cSchristos 
eap_aka_has_reauth_data(struct eap_sm * sm,void * priv)14518dbcf02cSchristos static Boolean eap_aka_has_reauth_data(struct eap_sm *sm, void *priv)
14528dbcf02cSchristos {
14538dbcf02cSchristos 	struct eap_aka_data *data = priv;
14548dbcf02cSchristos 	return data->pseudonym || data->reauth_id;
14558dbcf02cSchristos }
14568dbcf02cSchristos 
14578dbcf02cSchristos 
eap_aka_deinit_for_reauth(struct eap_sm * sm,void * priv)14588dbcf02cSchristos static void eap_aka_deinit_for_reauth(struct eap_sm *sm, void *priv)
14598dbcf02cSchristos {
14608dbcf02cSchristos 	struct eap_aka_data *data = priv;
146162a52023Schristos 	eap_aka_clear_identities(sm, data, CLEAR_EAP_ID);
14628dbcf02cSchristos 	data->prev_id = -1;
14638dbcf02cSchristos 	wpabuf_free(data->id_msgs);
14648dbcf02cSchristos 	data->id_msgs = NULL;
14658dbcf02cSchristos 	data->use_result_ind = 0;
14668dbcf02cSchristos 	data->kdf_negotiation = 0;
146736d97821Schristos 	eap_aka_clear_keys(data, 1);
14688dbcf02cSchristos }
14698dbcf02cSchristos 
14708dbcf02cSchristos 
eap_aka_init_for_reauth(struct eap_sm * sm,void * priv)14718dbcf02cSchristos static void * eap_aka_init_for_reauth(struct eap_sm *sm, void *priv)
14728dbcf02cSchristos {
14738dbcf02cSchristos 	struct eap_aka_data *data = priv;
14748dbcf02cSchristos 	data->num_id_req = 0;
14758dbcf02cSchristos 	data->num_notification = 0;
14768dbcf02cSchristos 	eap_aka_state(data, CONTINUE);
14778dbcf02cSchristos 	return priv;
14788dbcf02cSchristos }
14798dbcf02cSchristos 
14808dbcf02cSchristos 
eap_aka_get_identity(struct eap_sm * sm,void * priv,size_t * len)14818dbcf02cSchristos static const u8 * eap_aka_get_identity(struct eap_sm *sm, void *priv,
14828dbcf02cSchristos 				       size_t *len)
14838dbcf02cSchristos {
14848dbcf02cSchristos 	struct eap_aka_data *data = priv;
14858dbcf02cSchristos 
14868dbcf02cSchristos 	if (data->reauth_id) {
14878dbcf02cSchristos 		*len = data->reauth_id_len;
14888dbcf02cSchristos 		return data->reauth_id;
14898dbcf02cSchristos 	}
14908dbcf02cSchristos 
14918dbcf02cSchristos 	if (data->pseudonym) {
14928dbcf02cSchristos 		*len = data->pseudonym_len;
14938dbcf02cSchristos 		return data->pseudonym;
14948dbcf02cSchristos 	}
14958dbcf02cSchristos 
14968dbcf02cSchristos 	return NULL;
14978dbcf02cSchristos }
14988dbcf02cSchristos 
14998dbcf02cSchristos 
eap_aka_isKeyAvailable(struct eap_sm * sm,void * priv)15008dbcf02cSchristos static Boolean eap_aka_isKeyAvailable(struct eap_sm *sm, void *priv)
15018dbcf02cSchristos {
15028dbcf02cSchristos 	struct eap_aka_data *data = priv;
15038dbcf02cSchristos 	return data->state == SUCCESS;
15048dbcf02cSchristos }
15058dbcf02cSchristos 
15068dbcf02cSchristos 
eap_aka_getKey(struct eap_sm * sm,void * priv,size_t * len)15078dbcf02cSchristos static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
15088dbcf02cSchristos {
15098dbcf02cSchristos 	struct eap_aka_data *data = priv;
15108dbcf02cSchristos 	u8 *key;
15118dbcf02cSchristos 
15128dbcf02cSchristos 	if (data->state != SUCCESS)
15138dbcf02cSchristos 		return NULL;
15148dbcf02cSchristos 
1515ebb5671cSchristos 	key = os_memdup(data->msk, EAP_SIM_KEYING_DATA_LEN);
15168dbcf02cSchristos 	if (key == NULL)
15178dbcf02cSchristos 		return NULL;
15188dbcf02cSchristos 
15198dbcf02cSchristos 	*len = EAP_SIM_KEYING_DATA_LEN;
15208dbcf02cSchristos 
15218dbcf02cSchristos 	return key;
15228dbcf02cSchristos }
15238dbcf02cSchristos 
15248dbcf02cSchristos 
eap_aka_get_session_id(struct eap_sm * sm,void * priv,size_t * len)152536d97821Schristos static u8 * eap_aka_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
152636d97821Schristos {
152736d97821Schristos 	struct eap_aka_data *data = priv;
152836d97821Schristos 	u8 *id;
152936d97821Schristos 
153036d97821Schristos 	if (data->state != SUCCESS)
153136d97821Schristos 		return NULL;
153236d97821Schristos 
1533*0d69f216Schristos 	if (!data->reauth)
153436d97821Schristos 		*len = 1 + EAP_AKA_RAND_LEN + EAP_AKA_AUTN_LEN;
1535*0d69f216Schristos 	else
1536*0d69f216Schristos 		*len = 1 + EAP_SIM_NONCE_S_LEN + EAP_SIM_MAC_LEN;
153736d97821Schristos 	id = os_malloc(*len);
153836d97821Schristos 	if (id == NULL)
153936d97821Schristos 		return NULL;
154036d97821Schristos 
154136d97821Schristos 	id[0] = data->eap_method;
1542*0d69f216Schristos 	if (!data->reauth) {
154336d97821Schristos 		os_memcpy(id + 1, data->rand, EAP_AKA_RAND_LEN);
1544*0d69f216Schristos 		os_memcpy(id + 1 + EAP_AKA_RAND_LEN, data->autn,
1545*0d69f216Schristos 			  EAP_AKA_AUTN_LEN);
1546*0d69f216Schristos 	} else {
1547*0d69f216Schristos 		os_memcpy(id + 1, data->nonce_s, EAP_SIM_NONCE_S_LEN);
1548*0d69f216Schristos 		os_memcpy(id + 1 + EAP_SIM_NONCE_S_LEN, data->reauth_mac,
1549*0d69f216Schristos 			  EAP_SIM_MAC_LEN);
1550*0d69f216Schristos 	}
155136d97821Schristos 	wpa_hexdump(MSG_DEBUG, "EAP-AKA: Derived Session-Id", id, *len);
155236d97821Schristos 
155336d97821Schristos 	return id;
155436d97821Schristos }
155536d97821Schristos 
155636d97821Schristos 
eap_aka_get_emsk(struct eap_sm * sm,void * priv,size_t * len)15578dbcf02cSchristos static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
15588dbcf02cSchristos {
15598dbcf02cSchristos 	struct eap_aka_data *data = priv;
15608dbcf02cSchristos 	u8 *key;
15618dbcf02cSchristos 
15628dbcf02cSchristos 	if (data->state != SUCCESS)
15638dbcf02cSchristos 		return NULL;
15648dbcf02cSchristos 
1565ebb5671cSchristos 	key = os_memdup(data->emsk, EAP_EMSK_LEN);
15668dbcf02cSchristos 	if (key == NULL)
15678dbcf02cSchristos 		return NULL;
15688dbcf02cSchristos 
15698dbcf02cSchristos 	*len = EAP_EMSK_LEN;
15708dbcf02cSchristos 
15718dbcf02cSchristos 	return key;
15728dbcf02cSchristos }
15738dbcf02cSchristos 
15748dbcf02cSchristos 
eap_aka_get_error_code(void * priv)1575ebb5671cSchristos static int eap_aka_get_error_code(void *priv)
1576ebb5671cSchristos {
1577ebb5671cSchristos 	struct eap_aka_data *data = priv;
1578ebb5671cSchristos 	int current_data_error;
1579ebb5671cSchristos 
1580ebb5671cSchristos 	if (!data)
1581ebb5671cSchristos 		return NO_EAP_METHOD_ERROR;
1582ebb5671cSchristos 
1583ebb5671cSchristos 	current_data_error = data->error_code;
1584ebb5671cSchristos 
1585ebb5671cSchristos 	/* Now reset for next transaction */
1586ebb5671cSchristos 	data->error_code = NO_EAP_METHOD_ERROR;
1587ebb5671cSchristos 
1588ebb5671cSchristos 	return current_data_error;
1589ebb5671cSchristos }
1590ebb5671cSchristos 
1591ebb5671cSchristos 
eap_peer_aka_register(void)15928dbcf02cSchristos int eap_peer_aka_register(void)
15938dbcf02cSchristos {
15948dbcf02cSchristos 	struct eap_method *eap;
15958dbcf02cSchristos 
15968dbcf02cSchristos 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
15978dbcf02cSchristos 				    EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
15988dbcf02cSchristos 	if (eap == NULL)
15998dbcf02cSchristos 		return -1;
16008dbcf02cSchristos 
16018dbcf02cSchristos 	eap->init = eap_aka_init;
16028dbcf02cSchristos 	eap->deinit = eap_aka_deinit;
16038dbcf02cSchristos 	eap->process = eap_aka_process;
16048dbcf02cSchristos 	eap->isKeyAvailable = eap_aka_isKeyAvailable;
16058dbcf02cSchristos 	eap->getKey = eap_aka_getKey;
160636d97821Schristos 	eap->getSessionId = eap_aka_get_session_id;
16078dbcf02cSchristos 	eap->has_reauth_data = eap_aka_has_reauth_data;
16088dbcf02cSchristos 	eap->deinit_for_reauth = eap_aka_deinit_for_reauth;
16098dbcf02cSchristos 	eap->init_for_reauth = eap_aka_init_for_reauth;
16108dbcf02cSchristos 	eap->get_identity = eap_aka_get_identity;
16118dbcf02cSchristos 	eap->get_emsk = eap_aka_get_emsk;
1612ebb5671cSchristos 	eap->get_error_code = eap_aka_get_error_code;
16138dbcf02cSchristos 
1614928750b6Schristos 	return eap_peer_method_register(eap);
16158dbcf02cSchristos }
16168dbcf02cSchristos 
16178dbcf02cSchristos 
16188dbcf02cSchristos #ifdef EAP_AKA_PRIME
eap_peer_aka_prime_register(void)16198dbcf02cSchristos int eap_peer_aka_prime_register(void)
16208dbcf02cSchristos {
16218dbcf02cSchristos 	struct eap_method *eap;
16228dbcf02cSchristos 
16238dbcf02cSchristos 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
16248dbcf02cSchristos 				    EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
16258dbcf02cSchristos 				    "AKA'");
16268dbcf02cSchristos 	if (eap == NULL)
16278dbcf02cSchristos 		return -1;
16288dbcf02cSchristos 
16298dbcf02cSchristos 	eap->init = eap_aka_prime_init;
16308dbcf02cSchristos 	eap->deinit = eap_aka_deinit;
16318dbcf02cSchristos 	eap->process = eap_aka_process;
16328dbcf02cSchristos 	eap->isKeyAvailable = eap_aka_isKeyAvailable;
16338dbcf02cSchristos 	eap->getKey = eap_aka_getKey;
163436d97821Schristos 	eap->getSessionId = eap_aka_get_session_id;
16358dbcf02cSchristos 	eap->has_reauth_data = eap_aka_has_reauth_data;
16368dbcf02cSchristos 	eap->deinit_for_reauth = eap_aka_deinit_for_reauth;
16378dbcf02cSchristos 	eap->init_for_reauth = eap_aka_init_for_reauth;
16388dbcf02cSchristos 	eap->get_identity = eap_aka_get_identity;
16398dbcf02cSchristos 	eap->get_emsk = eap_aka_get_emsk;
1640ebb5671cSchristos 	eap->get_error_code = eap_aka_get_error_code;
16418dbcf02cSchristos 
1642928750b6Schristos 	return eap_peer_method_register(eap);
16438dbcf02cSchristos }
16448dbcf02cSchristos #endif /* EAP_AKA_PRIME */
1645