xref: /freebsd/contrib/wpa/src/eap_peer/eap_sim.c (revision 5b9c547c072b84410b50897cc53710c75b2f6b74)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * EAP peer method: EAP-SIM (RFC 4186)
3f05cddf9SRui Paulo  * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  */
839beb93cSSam Leffler 
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler 
1139beb93cSSam Leffler #include "common.h"
12e28a4053SRui Paulo #include "pcsc_funcs.h"
13e28a4053SRui Paulo #include "crypto/milenage.h"
14f05cddf9SRui Paulo #include "crypto/random.h"
1539beb93cSSam Leffler #include "eap_peer/eap_i.h"
1639beb93cSSam Leffler #include "eap_config.h"
1739beb93cSSam Leffler #include "eap_common/eap_sim_common.h"
1839beb93cSSam Leffler 
1939beb93cSSam Leffler 
2039beb93cSSam Leffler struct eap_sim_data {
2139beb93cSSam Leffler 	u8 *ver_list;
2239beb93cSSam Leffler 	size_t ver_list_len;
2339beb93cSSam Leffler 	int selected_version;
2439beb93cSSam Leffler 	size_t min_num_chal, num_chal;
2539beb93cSSam Leffler 
2639beb93cSSam Leffler 	u8 kc[3][EAP_SIM_KC_LEN];
2739beb93cSSam Leffler 	u8 sres[3][EAP_SIM_SRES_LEN];
2839beb93cSSam Leffler 	u8 nonce_mt[EAP_SIM_NONCE_MT_LEN], nonce_s[EAP_SIM_NONCE_S_LEN];
2939beb93cSSam Leffler 	u8 mk[EAP_SIM_MK_LEN];
3039beb93cSSam Leffler 	u8 k_aut[EAP_SIM_K_AUT_LEN];
3139beb93cSSam Leffler 	u8 k_encr[EAP_SIM_K_ENCR_LEN];
3239beb93cSSam Leffler 	u8 msk[EAP_SIM_KEYING_DATA_LEN];
3339beb93cSSam Leffler 	u8 emsk[EAP_EMSK_LEN];
3439beb93cSSam Leffler 	u8 rand[3][GSM_RAND_LEN];
3539beb93cSSam Leffler 
3639beb93cSSam Leffler 	int num_id_req, num_notification;
3739beb93cSSam Leffler 	u8 *pseudonym;
3839beb93cSSam Leffler 	size_t pseudonym_len;
3939beb93cSSam Leffler 	u8 *reauth_id;
4039beb93cSSam Leffler 	size_t reauth_id_len;
4139beb93cSSam Leffler 	int reauth;
4239beb93cSSam Leffler 	unsigned int counter, counter_too_small;
4339beb93cSSam Leffler 	u8 *last_eap_identity;
4439beb93cSSam Leffler 	size_t last_eap_identity_len;
4539beb93cSSam Leffler 	enum {
46*5b9c547cSRui Paulo 		CONTINUE, RESULT_SUCCESS, SUCCESS, FAILURE
4739beb93cSSam Leffler 	} state;
4839beb93cSSam Leffler 	int result_ind, use_result_ind;
4939beb93cSSam Leffler };
5039beb93cSSam Leffler 
5139beb93cSSam Leffler 
5239beb93cSSam Leffler #ifndef CONFIG_NO_STDOUT_DEBUG
5339beb93cSSam Leffler static const char * eap_sim_state_txt(int state)
5439beb93cSSam Leffler {
5539beb93cSSam Leffler 	switch (state) {
5639beb93cSSam Leffler 	case CONTINUE:
5739beb93cSSam Leffler 		return "CONTINUE";
5839beb93cSSam Leffler 	case RESULT_SUCCESS:
5939beb93cSSam Leffler 		return "RESULT_SUCCESS";
6039beb93cSSam Leffler 	case SUCCESS:
6139beb93cSSam Leffler 		return "SUCCESS";
6239beb93cSSam Leffler 	case FAILURE:
6339beb93cSSam Leffler 		return "FAILURE";
6439beb93cSSam Leffler 	default:
6539beb93cSSam Leffler 		return "?";
6639beb93cSSam Leffler 	}
6739beb93cSSam Leffler }
6839beb93cSSam Leffler #endif /* CONFIG_NO_STDOUT_DEBUG */
6939beb93cSSam Leffler 
7039beb93cSSam Leffler 
7139beb93cSSam Leffler static void eap_sim_state(struct eap_sim_data *data, int state)
7239beb93cSSam Leffler {
7339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s",
7439beb93cSSam Leffler 		   eap_sim_state_txt(data->state),
7539beb93cSSam Leffler 		   eap_sim_state_txt(state));
7639beb93cSSam Leffler 	data->state = state;
7739beb93cSSam Leffler }
7839beb93cSSam Leffler 
7939beb93cSSam Leffler 
8039beb93cSSam Leffler static void * eap_sim_init(struct eap_sm *sm)
8139beb93cSSam Leffler {
8239beb93cSSam Leffler 	struct eap_sim_data *data;
8339beb93cSSam Leffler 	struct eap_peer_config *config = eap_get_config(sm);
8439beb93cSSam Leffler 
8539beb93cSSam Leffler 	data = os_zalloc(sizeof(*data));
8639beb93cSSam Leffler 	if (data == NULL)
8739beb93cSSam Leffler 		return NULL;
8839beb93cSSam Leffler 
89f05cddf9SRui Paulo 	if (random_get_bytes(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
9039beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data "
9139beb93cSSam Leffler 			   "for NONCE_MT");
9239beb93cSSam Leffler 		os_free(data);
9339beb93cSSam Leffler 		return NULL;
9439beb93cSSam Leffler 	}
9539beb93cSSam Leffler 
9639beb93cSSam Leffler 	data->min_num_chal = 2;
9739beb93cSSam Leffler 	if (config && config->phase1) {
9839beb93cSSam Leffler 		char *pos = os_strstr(config->phase1, "sim_min_num_chal=");
9939beb93cSSam Leffler 		if (pos) {
10039beb93cSSam Leffler 			data->min_num_chal = atoi(pos + 17);
10139beb93cSSam Leffler 			if (data->min_num_chal < 2 || data->min_num_chal > 3) {
10239beb93cSSam Leffler 				wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
10339beb93cSSam Leffler 					   "sim_min_num_chal configuration "
10439beb93cSSam Leffler 					   "(%lu, expected 2 or 3)",
10539beb93cSSam Leffler 					   (unsigned long) data->min_num_chal);
10639beb93cSSam Leffler 				os_free(data);
10739beb93cSSam Leffler 				return NULL;
10839beb93cSSam Leffler 			}
10939beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-SIM: Set minimum number of "
11039beb93cSSam Leffler 				   "challenges to %lu",
11139beb93cSSam Leffler 				   (unsigned long) data->min_num_chal);
11239beb93cSSam Leffler 		}
11339beb93cSSam Leffler 
11439beb93cSSam Leffler 		data->result_ind = os_strstr(config->phase1, "result_ind=1") !=
11539beb93cSSam Leffler 			NULL;
11639beb93cSSam Leffler 	}
11739beb93cSSam Leffler 
118f05cddf9SRui Paulo 	if (config && config->anonymous_identity) {
119f05cddf9SRui Paulo 		data->pseudonym = os_malloc(config->anonymous_identity_len);
120f05cddf9SRui Paulo 		if (data->pseudonym) {
121f05cddf9SRui Paulo 			os_memcpy(data->pseudonym, config->anonymous_identity,
122f05cddf9SRui Paulo 				  config->anonymous_identity_len);
123f05cddf9SRui Paulo 			data->pseudonym_len = config->anonymous_identity_len;
124f05cddf9SRui Paulo 		}
125f05cddf9SRui Paulo 	}
126f05cddf9SRui Paulo 
12739beb93cSSam Leffler 	eap_sim_state(data, CONTINUE);
12839beb93cSSam Leffler 
12939beb93cSSam Leffler 	return data;
13039beb93cSSam Leffler }
13139beb93cSSam Leffler 
13239beb93cSSam Leffler 
133*5b9c547cSRui Paulo static void eap_sim_clear_keys(struct eap_sim_data *data, int reauth)
134*5b9c547cSRui Paulo {
135*5b9c547cSRui Paulo 	if (!reauth) {
136*5b9c547cSRui Paulo 		os_memset(data->mk, 0, EAP_SIM_MK_LEN);
137*5b9c547cSRui Paulo 		os_memset(data->k_aut, 0, EAP_SIM_K_AUT_LEN);
138*5b9c547cSRui Paulo 		os_memset(data->k_encr, 0, EAP_SIM_K_ENCR_LEN);
139*5b9c547cSRui Paulo 	}
140*5b9c547cSRui Paulo 	os_memset(data->kc, 0, 3 * EAP_SIM_KC_LEN);
141*5b9c547cSRui Paulo 	os_memset(data->sres, 0, 3 * EAP_SIM_SRES_LEN);
142*5b9c547cSRui Paulo 	os_memset(data->msk, 0, EAP_SIM_KEYING_DATA_LEN);
143*5b9c547cSRui Paulo 	os_memset(data->emsk, 0, EAP_EMSK_LEN);
144*5b9c547cSRui Paulo }
145*5b9c547cSRui Paulo 
146*5b9c547cSRui Paulo 
14739beb93cSSam Leffler static void eap_sim_deinit(struct eap_sm *sm, void *priv)
14839beb93cSSam Leffler {
14939beb93cSSam Leffler 	struct eap_sim_data *data = priv;
15039beb93cSSam Leffler 	if (data) {
15139beb93cSSam Leffler 		os_free(data->ver_list);
15239beb93cSSam Leffler 		os_free(data->pseudonym);
15339beb93cSSam Leffler 		os_free(data->reauth_id);
15439beb93cSSam Leffler 		os_free(data->last_eap_identity);
155*5b9c547cSRui Paulo 		eap_sim_clear_keys(data, 0);
15639beb93cSSam Leffler 		os_free(data);
15739beb93cSSam Leffler 	}
15839beb93cSSam Leffler }
15939beb93cSSam Leffler 
16039beb93cSSam Leffler 
161*5b9c547cSRui Paulo static int eap_sim_ext_sim_req(struct eap_sm *sm, struct eap_sim_data *data)
162*5b9c547cSRui Paulo {
163*5b9c547cSRui Paulo 	char req[200], *pos, *end;
164*5b9c547cSRui Paulo 	size_t i;
165*5b9c547cSRui Paulo 
166*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "EAP-SIM: Use external SIM processing");
167*5b9c547cSRui Paulo 	pos = req;
168*5b9c547cSRui Paulo 	end = pos + sizeof(req);
169*5b9c547cSRui Paulo 	pos += os_snprintf(pos, end - pos, "GSM-AUTH");
170*5b9c547cSRui Paulo 	for (i = 0; i < data->num_chal; i++) {
171*5b9c547cSRui Paulo 		pos += os_snprintf(pos, end - pos, ":");
172*5b9c547cSRui Paulo 		pos += wpa_snprintf_hex(pos, end - pos, data->rand[i],
173*5b9c547cSRui Paulo 					GSM_RAND_LEN);
174*5b9c547cSRui Paulo 	}
175*5b9c547cSRui Paulo 
176*5b9c547cSRui Paulo 	eap_sm_request_sim(sm, req);
177*5b9c547cSRui Paulo 	return 1;
178*5b9c547cSRui Paulo }
179*5b9c547cSRui Paulo 
180*5b9c547cSRui Paulo 
181*5b9c547cSRui Paulo static int eap_sim_ext_sim_result(struct eap_sm *sm, struct eap_sim_data *data,
182*5b9c547cSRui Paulo 				  struct eap_peer_config *conf)
183*5b9c547cSRui Paulo {
184*5b9c547cSRui Paulo 	char *resp, *pos;
185*5b9c547cSRui Paulo 	size_t i;
186*5b9c547cSRui Paulo 
187*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG,
188*5b9c547cSRui Paulo 		   "EAP-SIM: Use result from external SIM processing");
189*5b9c547cSRui Paulo 
190*5b9c547cSRui Paulo 	resp = conf->external_sim_resp;
191*5b9c547cSRui Paulo 	conf->external_sim_resp = NULL;
192*5b9c547cSRui Paulo 
193*5b9c547cSRui Paulo 	if (os_strncmp(resp, "GSM-AUTH:", 9) != 0) {
194*5b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized external SIM processing response");
195*5b9c547cSRui Paulo 		os_free(resp);
196*5b9c547cSRui Paulo 		return -1;
197*5b9c547cSRui Paulo 	}
198*5b9c547cSRui Paulo 
199*5b9c547cSRui Paulo 	pos = resp + 9;
200*5b9c547cSRui Paulo 	for (i = 0; i < data->num_chal; i++) {
201*5b9c547cSRui Paulo 		wpa_hexdump(MSG_DEBUG, "EAP-SIM: RAND",
202*5b9c547cSRui Paulo 			    data->rand[i], GSM_RAND_LEN);
203*5b9c547cSRui Paulo 
204*5b9c547cSRui Paulo 		if (hexstr2bin(pos, data->kc[i], EAP_SIM_KC_LEN) < 0)
205*5b9c547cSRui Paulo 			goto invalid;
206*5b9c547cSRui Paulo 		wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: Kc",
207*5b9c547cSRui Paulo 				data->kc[i], EAP_SIM_KC_LEN);
208*5b9c547cSRui Paulo 		pos += EAP_SIM_KC_LEN * 2;
209*5b9c547cSRui Paulo 		if (*pos != ':')
210*5b9c547cSRui Paulo 			goto invalid;
211*5b9c547cSRui Paulo 		pos++;
212*5b9c547cSRui Paulo 
213*5b9c547cSRui Paulo 		if (hexstr2bin(pos, data->sres[i], EAP_SIM_SRES_LEN) < 0)
214*5b9c547cSRui Paulo 			goto invalid;
215*5b9c547cSRui Paulo 		wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: SRES",
216*5b9c547cSRui Paulo 				data->sres[i], EAP_SIM_SRES_LEN);
217*5b9c547cSRui Paulo 		pos += EAP_SIM_SRES_LEN * 2;
218*5b9c547cSRui Paulo 		if (i + 1 < data->num_chal) {
219*5b9c547cSRui Paulo 			if (*pos != ':')
220*5b9c547cSRui Paulo 				goto invalid;
221*5b9c547cSRui Paulo 			pos++;
222*5b9c547cSRui Paulo 		}
223*5b9c547cSRui Paulo 	}
224*5b9c547cSRui Paulo 
225*5b9c547cSRui Paulo 	os_free(resp);
226*5b9c547cSRui Paulo 	return 0;
227*5b9c547cSRui Paulo 
228*5b9c547cSRui Paulo invalid:
229*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "EAP-SIM: Invalid external SIM processing GSM-AUTH response");
230*5b9c547cSRui Paulo 	os_free(resp);
231*5b9c547cSRui Paulo 	return -1;
232*5b9c547cSRui Paulo }
233*5b9c547cSRui Paulo 
234*5b9c547cSRui Paulo 
23539beb93cSSam Leffler static int eap_sim_gsm_auth(struct eap_sm *sm, struct eap_sim_data *data)
23639beb93cSSam Leffler {
23739beb93cSSam Leffler 	struct eap_peer_config *conf;
23839beb93cSSam Leffler 
23939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication algorithm");
24039beb93cSSam Leffler 
24139beb93cSSam Leffler 	conf = eap_get_config(sm);
24239beb93cSSam Leffler 	if (conf == NULL)
24339beb93cSSam Leffler 		return -1;
244*5b9c547cSRui Paulo 
245*5b9c547cSRui Paulo 	if (sm->external_sim) {
246*5b9c547cSRui Paulo 		if (conf->external_sim_resp)
247*5b9c547cSRui Paulo 			return eap_sim_ext_sim_result(sm, data, conf);
248*5b9c547cSRui Paulo 		else
249*5b9c547cSRui Paulo 			return eap_sim_ext_sim_req(sm, data);
250*5b9c547cSRui Paulo 	}
251*5b9c547cSRui Paulo 
25239beb93cSSam Leffler 	if (conf->pcsc) {
25339beb93cSSam Leffler 		if (scard_gsm_auth(sm->scard_ctx, data->rand[0],
25439beb93cSSam Leffler 				   data->sres[0], data->kc[0]) ||
25539beb93cSSam Leffler 		    scard_gsm_auth(sm->scard_ctx, data->rand[1],
25639beb93cSSam Leffler 				   data->sres[1], data->kc[1]) ||
25739beb93cSSam Leffler 		    (data->num_chal > 2 &&
25839beb93cSSam Leffler 		     scard_gsm_auth(sm->scard_ctx, data->rand[2],
25939beb93cSSam Leffler 				    data->sres[2], data->kc[2]))) {
26039beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-SIM: GSM SIM "
26139beb93cSSam Leffler 				   "authentication could not be completed");
26239beb93cSSam Leffler 			return -1;
26339beb93cSSam Leffler 		}
26439beb93cSSam Leffler 		return 0;
26539beb93cSSam Leffler 	}
26639beb93cSSam Leffler 
26739beb93cSSam Leffler #ifdef CONFIG_SIM_SIMULATOR
26839beb93cSSam Leffler 	if (conf->password) {
26939beb93cSSam Leffler 		u8 opc[16], k[16];
27039beb93cSSam Leffler 		const char *pos;
27139beb93cSSam Leffler 		size_t i;
27239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM: Use internal GSM-Milenage "
27339beb93cSSam Leffler 			   "implementation for authentication");
27439beb93cSSam Leffler 		if (conf->password_len < 65) {
27539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-SIM: invalid GSM-Milenage "
27639beb93cSSam Leffler 				   "password");
27739beb93cSSam Leffler 			return -1;
27839beb93cSSam Leffler 		}
27939beb93cSSam Leffler 		pos = (const char *) conf->password;
28039beb93cSSam Leffler 		if (hexstr2bin(pos, k, 16))
28139beb93cSSam Leffler 			return -1;
28239beb93cSSam Leffler 		pos += 32;
28339beb93cSSam Leffler 		if (*pos != ':')
28439beb93cSSam Leffler 			return -1;
28539beb93cSSam Leffler 		pos++;
28639beb93cSSam Leffler 
28739beb93cSSam Leffler 		if (hexstr2bin(pos, opc, 16))
28839beb93cSSam Leffler 			return -1;
28939beb93cSSam Leffler 
29039beb93cSSam Leffler 		for (i = 0; i < data->num_chal; i++) {
29139beb93cSSam Leffler 			if (gsm_milenage(opc, k, data->rand[i],
29239beb93cSSam Leffler 					 data->sres[i], data->kc[i])) {
29339beb93cSSam Leffler 				wpa_printf(MSG_DEBUG, "EAP-SIM: "
29439beb93cSSam Leffler 					   "GSM-Milenage authentication "
29539beb93cSSam Leffler 					   "could not be completed");
29639beb93cSSam Leffler 				return -1;
29739beb93cSSam Leffler 			}
29839beb93cSSam Leffler 			wpa_hexdump(MSG_DEBUG, "EAP-SIM: RAND",
29939beb93cSSam Leffler 				    data->rand[i], GSM_RAND_LEN);
30039beb93cSSam Leffler 			wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: SRES",
30139beb93cSSam Leffler 					data->sres[i], EAP_SIM_SRES_LEN);
30239beb93cSSam Leffler 			wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: Kc",
30339beb93cSSam Leffler 					data->kc[i], EAP_SIM_KC_LEN);
30439beb93cSSam Leffler 		}
30539beb93cSSam Leffler 		return 0;
30639beb93cSSam Leffler 	}
30739beb93cSSam Leffler #endif /* CONFIG_SIM_SIMULATOR */
30839beb93cSSam Leffler 
30939beb93cSSam Leffler #ifdef CONFIG_SIM_HARDCODED
31039beb93cSSam Leffler 	/* These hardcoded Kc and SRES values are used for testing. RAND to
31139beb93cSSam Leffler 	 * KC/SREC mapping is very bogus as far as real authentication is
31239beb93cSSam Leffler 	 * concerned, but it is quite useful for cases where the AS is rotating
31339beb93cSSam Leffler 	 * the order of pre-configured values. */
31439beb93cSSam Leffler 	{
31539beb93cSSam Leffler 		size_t i;
31639beb93cSSam Leffler 
31739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM: Use hardcoded Kc and SRES "
31839beb93cSSam Leffler 			   "values for testing");
31939beb93cSSam Leffler 
32039beb93cSSam Leffler 		for (i = 0; i < data->num_chal; i++) {
32139beb93cSSam Leffler 			if (data->rand[i][0] == 0xaa) {
32239beb93cSSam Leffler 				os_memcpy(data->kc[i],
32339beb93cSSam Leffler 					  "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7",
32439beb93cSSam Leffler 					  EAP_SIM_KC_LEN);
32539beb93cSSam Leffler 				os_memcpy(data->sres[i], "\xd1\xd2\xd3\xd4",
32639beb93cSSam Leffler 					  EAP_SIM_SRES_LEN);
32739beb93cSSam Leffler 			} else if (data->rand[i][0] == 0xbb) {
32839beb93cSSam Leffler 				os_memcpy(data->kc[i],
32939beb93cSSam Leffler 					  "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7",
33039beb93cSSam Leffler 					  EAP_SIM_KC_LEN);
33139beb93cSSam Leffler 				os_memcpy(data->sres[i], "\xe1\xe2\xe3\xe4",
33239beb93cSSam Leffler 					  EAP_SIM_SRES_LEN);
33339beb93cSSam Leffler 			} else {
33439beb93cSSam Leffler 				os_memcpy(data->kc[i],
33539beb93cSSam Leffler 					  "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7",
33639beb93cSSam Leffler 					  EAP_SIM_KC_LEN);
33739beb93cSSam Leffler 				os_memcpy(data->sres[i], "\xf1\xf2\xf3\xf4",
33839beb93cSSam Leffler 					  EAP_SIM_SRES_LEN);
33939beb93cSSam Leffler 			}
34039beb93cSSam Leffler 		}
34139beb93cSSam Leffler 	}
34239beb93cSSam Leffler 
34339beb93cSSam Leffler 	return 0;
34439beb93cSSam Leffler 
34539beb93cSSam Leffler #else /* CONFIG_SIM_HARDCODED */
34639beb93cSSam Leffler 
34739beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: No GSM authentication algorithm "
34839beb93cSSam Leffler 		   "enabled");
34939beb93cSSam Leffler 	return -1;
35039beb93cSSam Leffler 
35139beb93cSSam Leffler #endif /* CONFIG_SIM_HARDCODED */
35239beb93cSSam Leffler }
35339beb93cSSam Leffler 
35439beb93cSSam Leffler 
35539beb93cSSam Leffler static int eap_sim_supported_ver(int version)
35639beb93cSSam Leffler {
35739beb93cSSam Leffler 	return version == EAP_SIM_VERSION;
35839beb93cSSam Leffler }
35939beb93cSSam Leffler 
36039beb93cSSam Leffler 
36139beb93cSSam Leffler #define CLEAR_PSEUDONYM	0x01
36239beb93cSSam Leffler #define CLEAR_REAUTH_ID	0x02
36339beb93cSSam Leffler #define CLEAR_EAP_ID	0x04
36439beb93cSSam Leffler 
365f05cddf9SRui Paulo static void eap_sim_clear_identities(struct eap_sm *sm,
366f05cddf9SRui Paulo 				     struct eap_sim_data *data, int id)
36739beb93cSSam Leffler {
368f05cddf9SRui Paulo 	if ((id & CLEAR_PSEUDONYM) && data->pseudonym) {
369f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old pseudonym");
37039beb93cSSam Leffler 		os_free(data->pseudonym);
37139beb93cSSam Leffler 		data->pseudonym = NULL;
37239beb93cSSam Leffler 		data->pseudonym_len = 0;
373f05cddf9SRui Paulo 		eap_set_anon_id(sm, NULL, 0);
37439beb93cSSam Leffler 	}
375f05cddf9SRui Paulo 	if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
376f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old reauth_id");
37739beb93cSSam Leffler 		os_free(data->reauth_id);
37839beb93cSSam Leffler 		data->reauth_id = NULL;
37939beb93cSSam Leffler 		data->reauth_id_len = 0;
38039beb93cSSam Leffler 	}
381f05cddf9SRui Paulo 	if ((id & CLEAR_EAP_ID) && data->last_eap_identity) {
382f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old eap_id");
38339beb93cSSam Leffler 		os_free(data->last_eap_identity);
38439beb93cSSam Leffler 		data->last_eap_identity = NULL;
38539beb93cSSam Leffler 		data->last_eap_identity_len = 0;
38639beb93cSSam Leffler 	}
38739beb93cSSam Leffler }
38839beb93cSSam Leffler 
38939beb93cSSam Leffler 
390f05cddf9SRui Paulo static int eap_sim_learn_ids(struct eap_sm *sm, struct eap_sim_data *data,
39139beb93cSSam Leffler 			     struct eap_sim_attrs *attr)
39239beb93cSSam Leffler {
39339beb93cSSam Leffler 	if (attr->next_pseudonym) {
394f05cddf9SRui Paulo 		const u8 *identity = NULL;
395f05cddf9SRui Paulo 		size_t identity_len = 0;
396f05cddf9SRui Paulo 		const u8 *realm = NULL;
397f05cddf9SRui Paulo 		size_t realm_len = 0;
398f05cddf9SRui Paulo 
399f05cddf9SRui Paulo 		wpa_hexdump_ascii(MSG_DEBUG,
400f05cddf9SRui Paulo 				  "EAP-SIM: (encr) AT_NEXT_PSEUDONYM",
401f05cddf9SRui Paulo 				  attr->next_pseudonym,
402f05cddf9SRui Paulo 				  attr->next_pseudonym_len);
40339beb93cSSam Leffler 		os_free(data->pseudonym);
404f05cddf9SRui Paulo 		/* Look for the realm of the permanent identity */
405f05cddf9SRui Paulo 		identity = eap_get_config_identity(sm, &identity_len);
406f05cddf9SRui Paulo 		if (identity) {
407f05cddf9SRui Paulo 			for (realm = identity, realm_len = identity_len;
408f05cddf9SRui Paulo 			     realm_len > 0; realm_len--, realm++) {
409f05cddf9SRui Paulo 				if (*realm == '@')
410f05cddf9SRui Paulo 					break;
411f05cddf9SRui Paulo 			}
412f05cddf9SRui Paulo 		}
413f05cddf9SRui Paulo 		data->pseudonym = os_malloc(attr->next_pseudonym_len +
414f05cddf9SRui Paulo 					    realm_len);
41539beb93cSSam Leffler 		if (data->pseudonym == NULL) {
41639beb93cSSam Leffler 			wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for "
41739beb93cSSam Leffler 				   "next pseudonym");
418f05cddf9SRui Paulo 			data->pseudonym_len = 0;
41939beb93cSSam Leffler 			return -1;
42039beb93cSSam Leffler 		}
42139beb93cSSam Leffler 		os_memcpy(data->pseudonym, attr->next_pseudonym,
42239beb93cSSam Leffler 			  attr->next_pseudonym_len);
423f05cddf9SRui Paulo 		if (realm_len) {
424f05cddf9SRui Paulo 			os_memcpy(data->pseudonym + attr->next_pseudonym_len,
425f05cddf9SRui Paulo 				  realm, realm_len);
426f05cddf9SRui Paulo 		}
427f05cddf9SRui Paulo 		data->pseudonym_len = attr->next_pseudonym_len + realm_len;
428f05cddf9SRui Paulo 		eap_set_anon_id(sm, data->pseudonym, data->pseudonym_len);
42939beb93cSSam Leffler 	}
43039beb93cSSam Leffler 
43139beb93cSSam Leffler 	if (attr->next_reauth_id) {
43239beb93cSSam Leffler 		os_free(data->reauth_id);
43339beb93cSSam Leffler 		data->reauth_id = os_malloc(attr->next_reauth_id_len);
43439beb93cSSam Leffler 		if (data->reauth_id == NULL) {
43539beb93cSSam Leffler 			wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for "
43639beb93cSSam Leffler 				   "next reauth_id");
437f05cddf9SRui Paulo 			data->reauth_id_len = 0;
43839beb93cSSam Leffler 			return -1;
43939beb93cSSam Leffler 		}
44039beb93cSSam Leffler 		os_memcpy(data->reauth_id, attr->next_reauth_id,
44139beb93cSSam Leffler 			  attr->next_reauth_id_len);
44239beb93cSSam Leffler 		data->reauth_id_len = attr->next_reauth_id_len;
44339beb93cSSam Leffler 		wpa_hexdump_ascii(MSG_DEBUG,
44439beb93cSSam Leffler 				  "EAP-SIM: (encr) AT_NEXT_REAUTH_ID",
44539beb93cSSam Leffler 				  data->reauth_id,
44639beb93cSSam Leffler 				  data->reauth_id_len);
44739beb93cSSam Leffler 	}
44839beb93cSSam Leffler 
44939beb93cSSam Leffler 	return 0;
45039beb93cSSam Leffler }
45139beb93cSSam Leffler 
45239beb93cSSam Leffler 
45339beb93cSSam Leffler static struct wpabuf * eap_sim_client_error(struct eap_sim_data *data, u8 id,
45439beb93cSSam Leffler 					    int err)
45539beb93cSSam Leffler {
45639beb93cSSam Leffler 	struct eap_sim_msg *msg;
45739beb93cSSam Leffler 
45839beb93cSSam Leffler 	eap_sim_state(data, FAILURE);
45939beb93cSSam Leffler 	data->num_id_req = 0;
46039beb93cSSam Leffler 	data->num_notification = 0;
46139beb93cSSam Leffler 
462f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "EAP-SIM: Send Client-Error (error code %d)",
463f05cddf9SRui Paulo 		   err);
46439beb93cSSam Leffler 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
46539beb93cSSam Leffler 			       EAP_SIM_SUBTYPE_CLIENT_ERROR);
46639beb93cSSam Leffler 	eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
467*5b9c547cSRui Paulo 	return eap_sim_msg_finish(msg, EAP_TYPE_SIM, NULL, NULL, 0);
46839beb93cSSam Leffler }
46939beb93cSSam Leffler 
47039beb93cSSam Leffler 
47139beb93cSSam Leffler static struct wpabuf * eap_sim_response_start(struct eap_sm *sm,
47239beb93cSSam Leffler 					      struct eap_sim_data *data, u8 id,
47339beb93cSSam Leffler 					      enum eap_sim_id_req id_req)
47439beb93cSSam Leffler {
47539beb93cSSam Leffler 	const u8 *identity = NULL;
47639beb93cSSam Leffler 	size_t identity_len = 0;
47739beb93cSSam Leffler 	struct eap_sim_msg *msg;
47839beb93cSSam Leffler 
47939beb93cSSam Leffler 	data->reauth = 0;
48039beb93cSSam Leffler 	if (id_req == ANY_ID && data->reauth_id) {
48139beb93cSSam Leffler 		identity = data->reauth_id;
48239beb93cSSam Leffler 		identity_len = data->reauth_id_len;
48339beb93cSSam Leffler 		data->reauth = 1;
48439beb93cSSam Leffler 	} else if ((id_req == ANY_ID || id_req == FULLAUTH_ID) &&
48539beb93cSSam Leffler 		   data->pseudonym) {
48639beb93cSSam Leffler 		identity = data->pseudonym;
48739beb93cSSam Leffler 		identity_len = data->pseudonym_len;
488f05cddf9SRui Paulo 		eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID);
48939beb93cSSam Leffler 	} else if (id_req != NO_ID_REQ) {
49039beb93cSSam Leffler 		identity = eap_get_config_identity(sm, &identity_len);
49139beb93cSSam Leffler 		if (identity) {
492f05cddf9SRui Paulo 			eap_sim_clear_identities(sm, data, CLEAR_PSEUDONYM |
49339beb93cSSam Leffler 						 CLEAR_REAUTH_ID);
49439beb93cSSam Leffler 		}
49539beb93cSSam Leffler 	}
49639beb93cSSam Leffler 	if (id_req != NO_ID_REQ)
497f05cddf9SRui Paulo 		eap_sim_clear_identities(sm, data, CLEAR_EAP_ID);
49839beb93cSSam Leffler 
49939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Start (id=%d)", id);
50039beb93cSSam Leffler 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id,
50139beb93cSSam Leffler 			       EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START);
50239beb93cSSam Leffler 	if (!data->reauth) {
50339beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "   AT_NONCE_MT",
50439beb93cSSam Leffler 			    data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
50539beb93cSSam Leffler 		eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_MT, 0,
50639beb93cSSam Leffler 				data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
50739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   AT_SELECTED_VERSION %d",
50839beb93cSSam Leffler 			   data->selected_version);
50939beb93cSSam Leffler 		eap_sim_msg_add(msg, EAP_SIM_AT_SELECTED_VERSION,
51039beb93cSSam Leffler 				data->selected_version, NULL, 0);
51139beb93cSSam Leffler 	}
51239beb93cSSam Leffler 
51339beb93cSSam Leffler 	if (identity) {
51439beb93cSSam Leffler 		wpa_hexdump_ascii(MSG_DEBUG, "   AT_IDENTITY",
51539beb93cSSam Leffler 				  identity, identity_len);
51639beb93cSSam Leffler 		eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
51739beb93cSSam Leffler 				identity, identity_len);
51839beb93cSSam Leffler 	}
51939beb93cSSam Leffler 
520*5b9c547cSRui Paulo 	return eap_sim_msg_finish(msg, EAP_TYPE_SIM, NULL, NULL, 0);
52139beb93cSSam Leffler }
52239beb93cSSam Leffler 
52339beb93cSSam Leffler 
52439beb93cSSam Leffler static struct wpabuf * eap_sim_response_challenge(struct eap_sim_data *data,
52539beb93cSSam Leffler 						  u8 id)
52639beb93cSSam Leffler {
52739beb93cSSam Leffler 	struct eap_sim_msg *msg;
52839beb93cSSam Leffler 
52939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Challenge (id=%d)", id);
53039beb93cSSam Leffler 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
53139beb93cSSam Leffler 			       EAP_SIM_SUBTYPE_CHALLENGE);
53239beb93cSSam Leffler 	if (data->use_result_ind) {
53339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
53439beb93cSSam Leffler 		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
53539beb93cSSam Leffler 	}
53639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "   AT_MAC");
53739beb93cSSam Leffler 	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
538*5b9c547cSRui Paulo 	return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut,
539*5b9c547cSRui Paulo 				  (u8 *) data->sres,
54039beb93cSSam Leffler 				  data->num_chal * EAP_SIM_SRES_LEN);
54139beb93cSSam Leffler }
54239beb93cSSam Leffler 
54339beb93cSSam Leffler 
54439beb93cSSam Leffler static struct wpabuf * eap_sim_response_reauth(struct eap_sim_data *data,
545f05cddf9SRui Paulo 					       u8 id, int counter_too_small,
546f05cddf9SRui Paulo 					       const u8 *nonce_s)
54739beb93cSSam Leffler {
54839beb93cSSam Leffler 	struct eap_sim_msg *msg;
54939beb93cSSam Leffler 	unsigned int counter;
55039beb93cSSam Leffler 
55139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Reauthentication (id=%d)",
55239beb93cSSam Leffler 		   id);
55339beb93cSSam Leffler 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
55439beb93cSSam Leffler 			       EAP_SIM_SUBTYPE_REAUTHENTICATION);
55539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "   AT_IV");
55639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
55739beb93cSSam Leffler 	eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
55839beb93cSSam Leffler 
55939beb93cSSam Leffler 	if (counter_too_small) {
56039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   *AT_COUNTER_TOO_SMALL");
56139beb93cSSam Leffler 		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER_TOO_SMALL, 0, NULL, 0);
56239beb93cSSam Leffler 		counter = data->counter_too_small;
56339beb93cSSam Leffler 	} else
56439beb93cSSam Leffler 		counter = data->counter;
56539beb93cSSam Leffler 
56639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", counter);
56739beb93cSSam Leffler 	eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
56839beb93cSSam Leffler 
56939beb93cSSam Leffler 	if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
57039beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
57139beb93cSSam Leffler 			   "AT_ENCR_DATA");
57239beb93cSSam Leffler 		eap_sim_msg_free(msg);
57339beb93cSSam Leffler 		return NULL;
57439beb93cSSam Leffler 	}
57539beb93cSSam Leffler 	if (data->use_result_ind) {
57639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
57739beb93cSSam Leffler 		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
57839beb93cSSam Leffler 	}
57939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "   AT_MAC");
58039beb93cSSam Leffler 	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
581*5b9c547cSRui Paulo 	return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut, nonce_s,
58239beb93cSSam Leffler 				  EAP_SIM_NONCE_S_LEN);
58339beb93cSSam Leffler }
58439beb93cSSam Leffler 
58539beb93cSSam Leffler 
58639beb93cSSam Leffler static struct wpabuf * eap_sim_response_notification(struct eap_sim_data *data,
58739beb93cSSam Leffler 						     u8 id, u16 notification)
58839beb93cSSam Leffler {
58939beb93cSSam Leffler 	struct eap_sim_msg *msg;
59039beb93cSSam Leffler 	u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL;
59139beb93cSSam Leffler 
59239beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Notification (id=%d)", id);
59339beb93cSSam Leffler 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id,
59439beb93cSSam Leffler 			       EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION);
59539beb93cSSam Leffler 	if (k_aut && data->reauth) {
59639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   AT_IV");
59739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
59839beb93cSSam Leffler 		eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
59939beb93cSSam Leffler 					   EAP_SIM_AT_ENCR_DATA);
60039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", data->counter);
60139beb93cSSam Leffler 		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
60239beb93cSSam Leffler 				NULL, 0);
60339beb93cSSam Leffler 		if (eap_sim_msg_add_encr_end(msg, data->k_encr,
60439beb93cSSam Leffler 					     EAP_SIM_AT_PADDING)) {
60539beb93cSSam Leffler 			wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
60639beb93cSSam Leffler 				   "AT_ENCR_DATA");
60739beb93cSSam Leffler 			eap_sim_msg_free(msg);
60839beb93cSSam Leffler 			return NULL;
60939beb93cSSam Leffler 		}
61039beb93cSSam Leffler 	}
61139beb93cSSam Leffler 	if (k_aut) {
61239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   AT_MAC");
61339beb93cSSam Leffler 		eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
61439beb93cSSam Leffler 	}
615*5b9c547cSRui Paulo 	return eap_sim_msg_finish(msg, EAP_TYPE_SIM, k_aut, (u8 *) "", 0);
61639beb93cSSam Leffler }
61739beb93cSSam Leffler 
61839beb93cSSam Leffler 
61939beb93cSSam Leffler static struct wpabuf * eap_sim_process_start(struct eap_sm *sm,
62039beb93cSSam Leffler 					     struct eap_sim_data *data, u8 id,
62139beb93cSSam Leffler 					     struct eap_sim_attrs *attr)
62239beb93cSSam Leffler {
62339beb93cSSam Leffler 	int selected_version = -1, id_error;
62439beb93cSSam Leffler 	size_t i;
62539beb93cSSam Leffler 	u8 *pos;
62639beb93cSSam Leffler 
62739beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Start");
62839beb93cSSam Leffler 	if (attr->version_list == NULL) {
62939beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: No AT_VERSION_LIST in "
63039beb93cSSam Leffler 			   "SIM/Start");
63139beb93cSSam Leffler 		return eap_sim_client_error(data, id,
63239beb93cSSam Leffler 					    EAP_SIM_UNSUPPORTED_VERSION);
63339beb93cSSam Leffler 	}
63439beb93cSSam Leffler 
63539beb93cSSam Leffler 	os_free(data->ver_list);
63639beb93cSSam Leffler 	data->ver_list = os_malloc(attr->version_list_len);
63739beb93cSSam Leffler 	if (data->ver_list == NULL) {
63839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to allocate "
63939beb93cSSam Leffler 			   "memory for version list");
64039beb93cSSam Leffler 		return eap_sim_client_error(data, id,
64139beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
64239beb93cSSam Leffler 	}
64339beb93cSSam Leffler 	os_memcpy(data->ver_list, attr->version_list, attr->version_list_len);
64439beb93cSSam Leffler 	data->ver_list_len = attr->version_list_len;
64539beb93cSSam Leffler 	pos = data->ver_list;
64639beb93cSSam Leffler 	for (i = 0; i < data->ver_list_len / 2; i++) {
64739beb93cSSam Leffler 		int ver = pos[0] * 256 + pos[1];
64839beb93cSSam Leffler 		pos += 2;
64939beb93cSSam Leffler 		if (eap_sim_supported_ver(ver)) {
65039beb93cSSam Leffler 			selected_version = ver;
65139beb93cSSam Leffler 			break;
65239beb93cSSam Leffler 		}
65339beb93cSSam Leffler 	}
65439beb93cSSam Leffler 	if (selected_version < 0) {
65539beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: Could not find a supported "
65639beb93cSSam Leffler 			   "version");
65739beb93cSSam Leffler 		return eap_sim_client_error(data, id,
65839beb93cSSam Leffler 					    EAP_SIM_UNSUPPORTED_VERSION);
65939beb93cSSam Leffler 	}
66039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: Selected Version %d",
66139beb93cSSam Leffler 		   selected_version);
66239beb93cSSam Leffler 	data->selected_version = selected_version;
66339beb93cSSam Leffler 
66439beb93cSSam Leffler 	id_error = 0;
66539beb93cSSam Leffler 	switch (attr->id_req) {
66639beb93cSSam Leffler 	case NO_ID_REQ:
66739beb93cSSam Leffler 		break;
66839beb93cSSam Leffler 	case ANY_ID:
66939beb93cSSam Leffler 		if (data->num_id_req > 0)
67039beb93cSSam Leffler 			id_error++;
67139beb93cSSam Leffler 		data->num_id_req++;
67239beb93cSSam Leffler 		break;
67339beb93cSSam Leffler 	case FULLAUTH_ID:
67439beb93cSSam Leffler 		if (data->num_id_req > 1)
67539beb93cSSam Leffler 			id_error++;
67639beb93cSSam Leffler 		data->num_id_req++;
67739beb93cSSam Leffler 		break;
67839beb93cSSam Leffler 	case PERMANENT_ID:
67939beb93cSSam Leffler 		if (data->num_id_req > 2)
68039beb93cSSam Leffler 			id_error++;
68139beb93cSSam Leffler 		data->num_id_req++;
68239beb93cSSam Leffler 		break;
68339beb93cSSam Leffler 	}
68439beb93cSSam Leffler 	if (id_error) {
68539beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: Too many ID requests "
68639beb93cSSam Leffler 			   "used within one authentication");
68739beb93cSSam Leffler 		return eap_sim_client_error(data, id,
68839beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
68939beb93cSSam Leffler 	}
69039beb93cSSam Leffler 
69139beb93cSSam Leffler 	return eap_sim_response_start(sm, data, id, attr->id_req);
69239beb93cSSam Leffler }
69339beb93cSSam Leffler 
69439beb93cSSam Leffler 
69539beb93cSSam Leffler static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm,
69639beb93cSSam Leffler 						 struct eap_sim_data *data,
69739beb93cSSam Leffler 						 u8 id,
69839beb93cSSam Leffler 						 const struct wpabuf *reqData,
69939beb93cSSam Leffler 						 struct eap_sim_attrs *attr)
70039beb93cSSam Leffler {
70139beb93cSSam Leffler 	const u8 *identity;
70239beb93cSSam Leffler 	size_t identity_len;
70339beb93cSSam Leffler 	struct eap_sim_attrs eattr;
704*5b9c547cSRui Paulo 	int res;
70539beb93cSSam Leffler 
70639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Challenge");
70739beb93cSSam Leffler 	data->reauth = 0;
70839beb93cSSam Leffler 	if (!attr->mac || !attr->rand) {
70939beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
71039beb93cSSam Leffler 			   "did not include%s%s",
71139beb93cSSam Leffler 			   !attr->mac ? " AT_MAC" : "",
71239beb93cSSam Leffler 			   !attr->rand ? " AT_RAND" : "");
71339beb93cSSam Leffler 		return eap_sim_client_error(data, id,
71439beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
71539beb93cSSam Leffler 	}
71639beb93cSSam Leffler 
71739beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: %lu challenges",
71839beb93cSSam Leffler 		   (unsigned long) attr->num_chal);
71939beb93cSSam Leffler 	if (attr->num_chal < data->min_num_chal) {
72039beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: Insufficient number of "
72139beb93cSSam Leffler 			   "challenges (%lu)", (unsigned long) attr->num_chal);
72239beb93cSSam Leffler 		return eap_sim_client_error(data, id,
72339beb93cSSam Leffler 					    EAP_SIM_INSUFFICIENT_NUM_OF_CHAL);
72439beb93cSSam Leffler 	}
72539beb93cSSam Leffler 	if (attr->num_chal > 3) {
72639beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: Too many challenges "
72739beb93cSSam Leffler 			   "(%lu)", (unsigned long) attr->num_chal);
72839beb93cSSam Leffler 		return eap_sim_client_error(data, id,
72939beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
73039beb93cSSam Leffler 	}
73139beb93cSSam Leffler 
73239beb93cSSam Leffler 	/* Verify that RANDs are different */
73339beb93cSSam Leffler 	if (os_memcmp(attr->rand, attr->rand + GSM_RAND_LEN,
73439beb93cSSam Leffler 		   GSM_RAND_LEN) == 0 ||
73539beb93cSSam Leffler 	    (attr->num_chal > 2 &&
73639beb93cSSam Leffler 	     (os_memcmp(attr->rand, attr->rand + 2 * GSM_RAND_LEN,
73739beb93cSSam Leffler 			GSM_RAND_LEN) == 0 ||
73839beb93cSSam Leffler 	      os_memcmp(attr->rand + GSM_RAND_LEN,
73939beb93cSSam Leffler 			attr->rand + 2 * GSM_RAND_LEN,
74039beb93cSSam Leffler 			GSM_RAND_LEN) == 0))) {
74139beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: Same RAND used multiple times");
74239beb93cSSam Leffler 		return eap_sim_client_error(data, id,
74339beb93cSSam Leffler 					    EAP_SIM_RAND_NOT_FRESH);
74439beb93cSSam Leffler 	}
74539beb93cSSam Leffler 
74639beb93cSSam Leffler 	os_memcpy(data->rand, attr->rand, attr->num_chal * GSM_RAND_LEN);
74739beb93cSSam Leffler 	data->num_chal = attr->num_chal;
74839beb93cSSam Leffler 
749*5b9c547cSRui Paulo 	res = eap_sim_gsm_auth(sm, data);
750*5b9c547cSRui Paulo 	if (res > 0) {
751*5b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-SIM: Wait for external SIM processing");
752*5b9c547cSRui Paulo 		return NULL;
753*5b9c547cSRui Paulo 	}
754*5b9c547cSRui Paulo 	if (res) {
75539beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: GSM authentication failed");
75639beb93cSSam Leffler 		return eap_sim_client_error(data, id,
75739beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
75839beb93cSSam Leffler 	}
75939beb93cSSam Leffler 	if (data->last_eap_identity) {
76039beb93cSSam Leffler 		identity = data->last_eap_identity;
76139beb93cSSam Leffler 		identity_len = data->last_eap_identity_len;
76239beb93cSSam Leffler 	} else if (data->pseudonym) {
76339beb93cSSam Leffler 		identity = data->pseudonym;
76439beb93cSSam Leffler 		identity_len = data->pseudonym_len;
76539beb93cSSam Leffler 	} else
76639beb93cSSam Leffler 		identity = eap_get_config_identity(sm, &identity_len);
76739beb93cSSam Leffler 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Selected identity for MK "
76839beb93cSSam Leffler 			  "derivation", identity, identity_len);
76939beb93cSSam Leffler 	eap_sim_derive_mk(identity, identity_len, data->nonce_mt,
77039beb93cSSam Leffler 			  data->selected_version, data->ver_list,
77139beb93cSSam Leffler 			  data->ver_list_len, data->num_chal,
77239beb93cSSam Leffler 			  (const u8 *) data->kc, data->mk);
77339beb93cSSam Leffler 	eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
77439beb93cSSam Leffler 			    data->emsk);
77539beb93cSSam Leffler 	if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, data->nonce_mt,
77639beb93cSSam Leffler 			       EAP_SIM_NONCE_MT_LEN)) {
77739beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
77839beb93cSSam Leffler 			   "used invalid AT_MAC");
77939beb93cSSam Leffler 		return eap_sim_client_error(data, id,
78039beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
78139beb93cSSam Leffler 	}
78239beb93cSSam Leffler 
783f05cddf9SRui Paulo 	/* Old reauthentication identity must not be used anymore. In
784f05cddf9SRui Paulo 	 * other words, if no new reauth identity is received, full
785f05cddf9SRui Paulo 	 * authentication will be used on next reauthentication (using
786f05cddf9SRui Paulo 	 * pseudonym identity or permanent identity). */
787f05cddf9SRui Paulo 	eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
78839beb93cSSam Leffler 
78939beb93cSSam Leffler 	if (attr->encr_data) {
79039beb93cSSam Leffler 		u8 *decrypted;
79139beb93cSSam Leffler 		decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
79239beb93cSSam Leffler 					       attr->encr_data_len, attr->iv,
79339beb93cSSam Leffler 					       &eattr, 0);
79439beb93cSSam Leffler 		if (decrypted == NULL) {
79539beb93cSSam Leffler 			return eap_sim_client_error(
79639beb93cSSam Leffler 				data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET);
79739beb93cSSam Leffler 		}
798f05cddf9SRui Paulo 		eap_sim_learn_ids(sm, data, &eattr);
79939beb93cSSam Leffler 		os_free(decrypted);
80039beb93cSSam Leffler 	}
80139beb93cSSam Leffler 
80239beb93cSSam Leffler 	if (data->result_ind && attr->result_ind)
80339beb93cSSam Leffler 		data->use_result_ind = 1;
80439beb93cSSam Leffler 
805*5b9c547cSRui Paulo 	if (data->state != FAILURE) {
80639beb93cSSam Leffler 		eap_sim_state(data, data->use_result_ind ?
80739beb93cSSam Leffler 			      RESULT_SUCCESS : SUCCESS);
80839beb93cSSam Leffler 	}
80939beb93cSSam Leffler 
81039beb93cSSam Leffler 	data->num_id_req = 0;
81139beb93cSSam Leffler 	data->num_notification = 0;
81239beb93cSSam Leffler 	/* RFC 4186 specifies that counter is initialized to one after
81339beb93cSSam Leffler 	 * fullauth, but initializing it to zero makes it easier to implement
81439beb93cSSam Leffler 	 * reauth verification. */
81539beb93cSSam Leffler 	data->counter = 0;
81639beb93cSSam Leffler 	return eap_sim_response_challenge(data, id);
81739beb93cSSam Leffler }
81839beb93cSSam Leffler 
81939beb93cSSam Leffler 
82039beb93cSSam Leffler static int eap_sim_process_notification_reauth(struct eap_sim_data *data,
82139beb93cSSam Leffler 					       struct eap_sim_attrs *attr)
82239beb93cSSam Leffler {
82339beb93cSSam Leffler 	struct eap_sim_attrs eattr;
82439beb93cSSam Leffler 	u8 *decrypted;
82539beb93cSSam Leffler 
82639beb93cSSam Leffler 	if (attr->encr_data == NULL || attr->iv == NULL) {
82739beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Notification message after "
82839beb93cSSam Leffler 			   "reauth did not include encrypted data");
82939beb93cSSam Leffler 		return -1;
83039beb93cSSam Leffler 	}
83139beb93cSSam Leffler 
83239beb93cSSam Leffler 	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
83339beb93cSSam Leffler 				       attr->encr_data_len, attr->iv, &eattr,
83439beb93cSSam Leffler 				       0);
83539beb93cSSam Leffler 	if (decrypted == NULL) {
83639beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
83739beb93cSSam Leffler 			   "data from notification message");
83839beb93cSSam Leffler 		return -1;
83939beb93cSSam Leffler 	}
84039beb93cSSam Leffler 
84139beb93cSSam Leffler 	if (eattr.counter < 0 || (size_t) eattr.counter != data->counter) {
84239beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Counter in notification "
84339beb93cSSam Leffler 			   "message does not match with counter in reauth "
84439beb93cSSam Leffler 			   "message");
84539beb93cSSam Leffler 		os_free(decrypted);
84639beb93cSSam Leffler 		return -1;
84739beb93cSSam Leffler 	}
84839beb93cSSam Leffler 
84939beb93cSSam Leffler 	os_free(decrypted);
85039beb93cSSam Leffler 	return 0;
85139beb93cSSam Leffler }
85239beb93cSSam Leffler 
85339beb93cSSam Leffler 
85439beb93cSSam Leffler static int eap_sim_process_notification_auth(struct eap_sim_data *data,
85539beb93cSSam Leffler 					     const struct wpabuf *reqData,
85639beb93cSSam Leffler 					     struct eap_sim_attrs *attr)
85739beb93cSSam Leffler {
85839beb93cSSam Leffler 	if (attr->mac == NULL) {
85939beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: no AT_MAC in after_auth "
86039beb93cSSam Leffler 			   "Notification message");
86139beb93cSSam Leffler 		return -1;
86239beb93cSSam Leffler 	}
86339beb93cSSam Leffler 
86439beb93cSSam Leffler 	if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0))
86539beb93cSSam Leffler 	{
86639beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Notification message "
86739beb93cSSam Leffler 			   "used invalid AT_MAC");
86839beb93cSSam Leffler 		return -1;
86939beb93cSSam Leffler 	}
87039beb93cSSam Leffler 
87139beb93cSSam Leffler 	if (data->reauth &&
87239beb93cSSam Leffler 	    eap_sim_process_notification_reauth(data, attr)) {
87339beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Invalid notification "
87439beb93cSSam Leffler 			   "message after reauth");
87539beb93cSSam Leffler 		return -1;
87639beb93cSSam Leffler 	}
87739beb93cSSam Leffler 
87839beb93cSSam Leffler 	return 0;
87939beb93cSSam Leffler }
88039beb93cSSam Leffler 
88139beb93cSSam Leffler 
88239beb93cSSam Leffler static struct wpabuf * eap_sim_process_notification(
88339beb93cSSam Leffler 	struct eap_sm *sm, struct eap_sim_data *data, u8 id,
88439beb93cSSam Leffler 	const struct wpabuf *reqData, struct eap_sim_attrs *attr)
88539beb93cSSam Leffler {
88639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Notification");
88739beb93cSSam Leffler 	if (data->num_notification > 0) {
88839beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: too many notification "
88939beb93cSSam Leffler 			   "rounds (only one allowed)");
89039beb93cSSam Leffler 		return eap_sim_client_error(data, id,
89139beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
89239beb93cSSam Leffler 	}
89339beb93cSSam Leffler 	data->num_notification++;
89439beb93cSSam Leffler 	if (attr->notification == -1) {
89539beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: no AT_NOTIFICATION in "
89639beb93cSSam Leffler 			   "Notification message");
89739beb93cSSam Leffler 		return eap_sim_client_error(data, id,
89839beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
89939beb93cSSam Leffler 	}
90039beb93cSSam Leffler 
90139beb93cSSam Leffler 	if ((attr->notification & 0x4000) == 0 &&
90239beb93cSSam Leffler 	    eap_sim_process_notification_auth(data, reqData, attr)) {
90339beb93cSSam Leffler 		return eap_sim_client_error(data, id,
90439beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
90539beb93cSSam Leffler 	}
90639beb93cSSam Leffler 
90739beb93cSSam Leffler 	eap_sim_report_notification(sm->msg_ctx, attr->notification, 0);
90839beb93cSSam Leffler 	if (attr->notification >= 0 && attr->notification < 32768) {
90939beb93cSSam Leffler 		eap_sim_state(data, FAILURE);
91039beb93cSSam Leffler 	} else if (attr->notification == EAP_SIM_SUCCESS &&
91139beb93cSSam Leffler 		   data->state == RESULT_SUCCESS)
91239beb93cSSam Leffler 		eap_sim_state(data, SUCCESS);
91339beb93cSSam Leffler 	return eap_sim_response_notification(data, id, attr->notification);
91439beb93cSSam Leffler }
91539beb93cSSam Leffler 
91639beb93cSSam Leffler 
91739beb93cSSam Leffler static struct wpabuf * eap_sim_process_reauthentication(
91839beb93cSSam Leffler 	struct eap_sm *sm, struct eap_sim_data *data, u8 id,
91939beb93cSSam Leffler 	const struct wpabuf *reqData, struct eap_sim_attrs *attr)
92039beb93cSSam Leffler {
92139beb93cSSam Leffler 	struct eap_sim_attrs eattr;
92239beb93cSSam Leffler 	u8 *decrypted;
92339beb93cSSam Leffler 
92439beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Reauthentication");
92539beb93cSSam Leffler 
92639beb93cSSam Leffler 	if (data->reauth_id == NULL) {
92739beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Server is trying "
92839beb93cSSam Leffler 			   "reauthentication, but no reauth_id available");
92939beb93cSSam Leffler 		return eap_sim_client_error(data, id,
93039beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
93139beb93cSSam Leffler 	}
93239beb93cSSam Leffler 
93339beb93cSSam Leffler 	data->reauth = 1;
93439beb93cSSam Leffler 	if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0))
93539beb93cSSam Leffler 	{
93639beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
93739beb93cSSam Leffler 			   "did not have valid AT_MAC");
93839beb93cSSam Leffler 		return eap_sim_client_error(data, id,
93939beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
94039beb93cSSam Leffler 	}
94139beb93cSSam Leffler 
94239beb93cSSam Leffler 	if (attr->encr_data == NULL || attr->iv == NULL) {
94339beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
94439beb93cSSam Leffler 			   "message did not include encrypted data");
94539beb93cSSam Leffler 		return eap_sim_client_error(data, id,
94639beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
94739beb93cSSam Leffler 	}
94839beb93cSSam Leffler 
94939beb93cSSam Leffler 	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
95039beb93cSSam Leffler 				       attr->encr_data_len, attr->iv, &eattr,
95139beb93cSSam Leffler 				       0);
95239beb93cSSam Leffler 	if (decrypted == NULL) {
95339beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
95439beb93cSSam Leffler 			   "data from reauthentication message");
95539beb93cSSam Leffler 		return eap_sim_client_error(data, id,
95639beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
95739beb93cSSam Leffler 	}
95839beb93cSSam Leffler 
95939beb93cSSam Leffler 	if (eattr.nonce_s == NULL || eattr.counter < 0) {
96039beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: (encr) No%s%s in reauth packet",
96139beb93cSSam Leffler 			   !eattr.nonce_s ? " AT_NONCE_S" : "",
96239beb93cSSam Leffler 			   eattr.counter < 0 ? " AT_COUNTER" : "");
96339beb93cSSam Leffler 		os_free(decrypted);
96439beb93cSSam Leffler 		return eap_sim_client_error(data, id,
96539beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
96639beb93cSSam Leffler 	}
96739beb93cSSam Leffler 
96839beb93cSSam Leffler 	if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) {
969*5b9c547cSRui Paulo 		struct wpabuf *res;
97039beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid counter "
97139beb93cSSam Leffler 			   "(%d <= %d)", eattr.counter, data->counter);
97239beb93cSSam Leffler 		data->counter_too_small = eattr.counter;
973*5b9c547cSRui Paulo 
97439beb93cSSam Leffler 		/* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
97539beb93cSSam Leffler 		 * reauth_id must not be used to start a new reauthentication.
97639beb93cSSam Leffler 		 * However, since it was used in the last EAP-Response-Identity
97739beb93cSSam Leffler 		 * packet, it has to saved for the following fullauth to be
97839beb93cSSam Leffler 		 * used in MK derivation. */
97939beb93cSSam Leffler 		os_free(data->last_eap_identity);
98039beb93cSSam Leffler 		data->last_eap_identity = data->reauth_id;
98139beb93cSSam Leffler 		data->last_eap_identity_len = data->reauth_id_len;
98239beb93cSSam Leffler 		data->reauth_id = NULL;
98339beb93cSSam Leffler 		data->reauth_id_len = 0;
984*5b9c547cSRui Paulo 
985*5b9c547cSRui Paulo 		res = eap_sim_response_reauth(data, id, 1, eattr.nonce_s);
98639beb93cSSam Leffler 		os_free(decrypted);
987*5b9c547cSRui Paulo 
988*5b9c547cSRui Paulo 		return res;
98939beb93cSSam Leffler 	}
99039beb93cSSam Leffler 	data->counter = eattr.counter;
99139beb93cSSam Leffler 
99239beb93cSSam Leffler 	os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN);
99339beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-SIM: (encr) AT_NONCE_S",
99439beb93cSSam Leffler 		    data->nonce_s, EAP_SIM_NONCE_S_LEN);
99539beb93cSSam Leffler 
99639beb93cSSam Leffler 	eap_sim_derive_keys_reauth(data->counter,
99739beb93cSSam Leffler 				   data->reauth_id, data->reauth_id_len,
99839beb93cSSam Leffler 				   data->nonce_s, data->mk, data->msk,
99939beb93cSSam Leffler 				   data->emsk);
1000f05cddf9SRui Paulo 	eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
1001f05cddf9SRui Paulo 	eap_sim_learn_ids(sm, data, &eattr);
100239beb93cSSam Leffler 
100339beb93cSSam Leffler 	if (data->result_ind && attr->result_ind)
100439beb93cSSam Leffler 		data->use_result_ind = 1;
100539beb93cSSam Leffler 
1006*5b9c547cSRui Paulo 	if (data->state != FAILURE) {
100739beb93cSSam Leffler 		eap_sim_state(data, data->use_result_ind ?
100839beb93cSSam Leffler 			      RESULT_SUCCESS : SUCCESS);
100939beb93cSSam Leffler 	}
101039beb93cSSam Leffler 
101139beb93cSSam Leffler 	data->num_id_req = 0;
101239beb93cSSam Leffler 	data->num_notification = 0;
101339beb93cSSam Leffler 	if (data->counter > EAP_SIM_MAX_FAST_REAUTHS) {
101439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM: Maximum number of "
101539beb93cSSam Leffler 			   "fast reauths performed - force fullauth");
1016f05cddf9SRui Paulo 		eap_sim_clear_identities(sm, data,
1017f05cddf9SRui Paulo 					 CLEAR_REAUTH_ID | CLEAR_EAP_ID);
101839beb93cSSam Leffler 	}
101939beb93cSSam Leffler 	os_free(decrypted);
1020f05cddf9SRui Paulo 	return eap_sim_response_reauth(data, id, 0, data->nonce_s);
102139beb93cSSam Leffler }
102239beb93cSSam Leffler 
102339beb93cSSam Leffler 
102439beb93cSSam Leffler static struct wpabuf * eap_sim_process(struct eap_sm *sm, void *priv,
102539beb93cSSam Leffler 				       struct eap_method_ret *ret,
102639beb93cSSam Leffler 				       const struct wpabuf *reqData)
102739beb93cSSam Leffler {
102839beb93cSSam Leffler 	struct eap_sim_data *data = priv;
102939beb93cSSam Leffler 	const struct eap_hdr *req;
103039beb93cSSam Leffler 	u8 subtype, id;
103139beb93cSSam Leffler 	struct wpabuf *res;
103239beb93cSSam Leffler 	const u8 *pos;
103339beb93cSSam Leffler 	struct eap_sim_attrs attr;
103439beb93cSSam Leffler 	size_t len;
103539beb93cSSam Leffler 
103639beb93cSSam Leffler 	wpa_hexdump_buf(MSG_DEBUG, "EAP-SIM: EAP data", reqData);
103739beb93cSSam Leffler 	if (eap_get_config_identity(sm, &len) == NULL) {
103839beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: Identity not configured");
103939beb93cSSam Leffler 		eap_sm_request_identity(sm);
104039beb93cSSam Leffler 		ret->ignore = TRUE;
104139beb93cSSam Leffler 		return NULL;
104239beb93cSSam Leffler 	}
104339beb93cSSam Leffler 
104439beb93cSSam Leffler 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, reqData, &len);
104539beb93cSSam Leffler 	if (pos == NULL || len < 1) {
104639beb93cSSam Leffler 		ret->ignore = TRUE;
104739beb93cSSam Leffler 		return NULL;
104839beb93cSSam Leffler 	}
104939beb93cSSam Leffler 	req = wpabuf_head(reqData);
105039beb93cSSam Leffler 	id = req->identifier;
105139beb93cSSam Leffler 	len = be_to_host16(req->length);
105239beb93cSSam Leffler 
105339beb93cSSam Leffler 	ret->ignore = FALSE;
105439beb93cSSam Leffler 	ret->methodState = METHOD_MAY_CONT;
105539beb93cSSam Leffler 	ret->decision = DECISION_FAIL;
105639beb93cSSam Leffler 	ret->allowNotifications = TRUE;
105739beb93cSSam Leffler 
105839beb93cSSam Leffler 	subtype = *pos++;
105939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: Subtype=%d", subtype);
106039beb93cSSam Leffler 	pos += 2; /* Reserved */
106139beb93cSSam Leffler 
106239beb93cSSam Leffler 	if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr, 0,
106339beb93cSSam Leffler 			       0)) {
106439beb93cSSam Leffler 		res = eap_sim_client_error(data, id,
106539beb93cSSam Leffler 					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
106639beb93cSSam Leffler 		goto done;
106739beb93cSSam Leffler 	}
106839beb93cSSam Leffler 
106939beb93cSSam Leffler 	switch (subtype) {
107039beb93cSSam Leffler 	case EAP_SIM_SUBTYPE_START:
107139beb93cSSam Leffler 		res = eap_sim_process_start(sm, data, id, &attr);
107239beb93cSSam Leffler 		break;
107339beb93cSSam Leffler 	case EAP_SIM_SUBTYPE_CHALLENGE:
107439beb93cSSam Leffler 		res = eap_sim_process_challenge(sm, data, id, reqData, &attr);
107539beb93cSSam Leffler 		break;
107639beb93cSSam Leffler 	case EAP_SIM_SUBTYPE_NOTIFICATION:
107739beb93cSSam Leffler 		res = eap_sim_process_notification(sm, data, id, reqData,
107839beb93cSSam Leffler 						   &attr);
107939beb93cSSam Leffler 		break;
108039beb93cSSam Leffler 	case EAP_SIM_SUBTYPE_REAUTHENTICATION:
108139beb93cSSam Leffler 		res = eap_sim_process_reauthentication(sm, data, id, reqData,
108239beb93cSSam Leffler 						       &attr);
108339beb93cSSam Leffler 		break;
108439beb93cSSam Leffler 	case EAP_SIM_SUBTYPE_CLIENT_ERROR:
108539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Client-Error");
108639beb93cSSam Leffler 		res = eap_sim_client_error(data, id,
108739beb93cSSam Leffler 					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
108839beb93cSSam Leffler 		break;
108939beb93cSSam Leffler 	default:
109039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown subtype=%d", subtype);
109139beb93cSSam Leffler 		res = eap_sim_client_error(data, id,
109239beb93cSSam Leffler 					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
109339beb93cSSam Leffler 		break;
109439beb93cSSam Leffler 	}
109539beb93cSSam Leffler 
109639beb93cSSam Leffler done:
109739beb93cSSam Leffler 	if (data->state == FAILURE) {
109839beb93cSSam Leffler 		ret->decision = DECISION_FAIL;
109939beb93cSSam Leffler 		ret->methodState = METHOD_DONE;
110039beb93cSSam Leffler 	} else if (data->state == SUCCESS) {
110139beb93cSSam Leffler 		ret->decision = data->use_result_ind ?
110239beb93cSSam Leffler 			DECISION_UNCOND_SUCC : DECISION_COND_SUCC;
110339beb93cSSam Leffler 		ret->methodState = data->use_result_ind ?
110439beb93cSSam Leffler 			METHOD_DONE : METHOD_MAY_CONT;
1105*5b9c547cSRui Paulo 	} else if (data->state == RESULT_SUCCESS)
110639beb93cSSam Leffler 		ret->methodState = METHOD_CONT;
110739beb93cSSam Leffler 
110839beb93cSSam Leffler 	if (ret->methodState == METHOD_DONE) {
110939beb93cSSam Leffler 		ret->allowNotifications = FALSE;
111039beb93cSSam Leffler 	}
111139beb93cSSam Leffler 
111239beb93cSSam Leffler 	return res;
111339beb93cSSam Leffler }
111439beb93cSSam Leffler 
111539beb93cSSam Leffler 
111639beb93cSSam Leffler static Boolean eap_sim_has_reauth_data(struct eap_sm *sm, void *priv)
111739beb93cSSam Leffler {
111839beb93cSSam Leffler 	struct eap_sim_data *data = priv;
111939beb93cSSam Leffler 	return data->pseudonym || data->reauth_id;
112039beb93cSSam Leffler }
112139beb93cSSam Leffler 
112239beb93cSSam Leffler 
112339beb93cSSam Leffler static void eap_sim_deinit_for_reauth(struct eap_sm *sm, void *priv)
112439beb93cSSam Leffler {
112539beb93cSSam Leffler 	struct eap_sim_data *data = priv;
1126f05cddf9SRui Paulo 	eap_sim_clear_identities(sm, data, CLEAR_EAP_ID);
112739beb93cSSam Leffler 	data->use_result_ind = 0;
1128*5b9c547cSRui Paulo 	eap_sim_clear_keys(data, 1);
112939beb93cSSam Leffler }
113039beb93cSSam Leffler 
113139beb93cSSam Leffler 
113239beb93cSSam Leffler static void * eap_sim_init_for_reauth(struct eap_sm *sm, void *priv)
113339beb93cSSam Leffler {
113439beb93cSSam Leffler 	struct eap_sim_data *data = priv;
1135f05cddf9SRui Paulo 	if (random_get_bytes(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
113639beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data "
113739beb93cSSam Leffler 			   "for NONCE_MT");
113839beb93cSSam Leffler 		os_free(data);
113939beb93cSSam Leffler 		return NULL;
114039beb93cSSam Leffler 	}
114139beb93cSSam Leffler 	data->num_id_req = 0;
114239beb93cSSam Leffler 	data->num_notification = 0;
114339beb93cSSam Leffler 	eap_sim_state(data, CONTINUE);
114439beb93cSSam Leffler 	return priv;
114539beb93cSSam Leffler }
114639beb93cSSam Leffler 
114739beb93cSSam Leffler 
114839beb93cSSam Leffler static const u8 * eap_sim_get_identity(struct eap_sm *sm, void *priv,
114939beb93cSSam Leffler 				       size_t *len)
115039beb93cSSam Leffler {
115139beb93cSSam Leffler 	struct eap_sim_data *data = priv;
115239beb93cSSam Leffler 
115339beb93cSSam Leffler 	if (data->reauth_id) {
115439beb93cSSam Leffler 		*len = data->reauth_id_len;
115539beb93cSSam Leffler 		return data->reauth_id;
115639beb93cSSam Leffler 	}
115739beb93cSSam Leffler 
115839beb93cSSam Leffler 	if (data->pseudonym) {
115939beb93cSSam Leffler 		*len = data->pseudonym_len;
116039beb93cSSam Leffler 		return data->pseudonym;
116139beb93cSSam Leffler 	}
116239beb93cSSam Leffler 
116339beb93cSSam Leffler 	return NULL;
116439beb93cSSam Leffler }
116539beb93cSSam Leffler 
116639beb93cSSam Leffler 
116739beb93cSSam Leffler static Boolean eap_sim_isKeyAvailable(struct eap_sm *sm, void *priv)
116839beb93cSSam Leffler {
116939beb93cSSam Leffler 	struct eap_sim_data *data = priv;
117039beb93cSSam Leffler 	return data->state == SUCCESS;
117139beb93cSSam Leffler }
117239beb93cSSam Leffler 
117339beb93cSSam Leffler 
117439beb93cSSam Leffler static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
117539beb93cSSam Leffler {
117639beb93cSSam Leffler 	struct eap_sim_data *data = priv;
117739beb93cSSam Leffler 	u8 *key;
117839beb93cSSam Leffler 
117939beb93cSSam Leffler 	if (data->state != SUCCESS)
118039beb93cSSam Leffler 		return NULL;
118139beb93cSSam Leffler 
118239beb93cSSam Leffler 	key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
118339beb93cSSam Leffler 	if (key == NULL)
118439beb93cSSam Leffler 		return NULL;
118539beb93cSSam Leffler 
118639beb93cSSam Leffler 	*len = EAP_SIM_KEYING_DATA_LEN;
118739beb93cSSam Leffler 	os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
118839beb93cSSam Leffler 
118939beb93cSSam Leffler 	return key;
119039beb93cSSam Leffler }
119139beb93cSSam Leffler 
119239beb93cSSam Leffler 
1193*5b9c547cSRui Paulo static u8 * eap_sim_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
1194*5b9c547cSRui Paulo {
1195*5b9c547cSRui Paulo 	struct eap_sim_data *data = priv;
1196*5b9c547cSRui Paulo 	u8 *id;
1197*5b9c547cSRui Paulo 
1198*5b9c547cSRui Paulo 	if (data->state != SUCCESS)
1199*5b9c547cSRui Paulo 		return NULL;
1200*5b9c547cSRui Paulo 
1201*5b9c547cSRui Paulo 	*len = 1 + data->num_chal * GSM_RAND_LEN + EAP_SIM_NONCE_MT_LEN;
1202*5b9c547cSRui Paulo 	id = os_malloc(*len);
1203*5b9c547cSRui Paulo 	if (id == NULL)
1204*5b9c547cSRui Paulo 		return NULL;
1205*5b9c547cSRui Paulo 
1206*5b9c547cSRui Paulo 	id[0] = EAP_TYPE_SIM;
1207*5b9c547cSRui Paulo 	os_memcpy(id + 1, data->rand, data->num_chal * GSM_RAND_LEN);
1208*5b9c547cSRui Paulo 	os_memcpy(id + 1 + data->num_chal * GSM_RAND_LEN, data->nonce_mt,
1209*5b9c547cSRui Paulo 		  EAP_SIM_NONCE_MT_LEN);
1210*5b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "EAP-SIM: Derived Session-Id", id, *len);
1211*5b9c547cSRui Paulo 
1212*5b9c547cSRui Paulo 	return id;
1213*5b9c547cSRui Paulo }
1214*5b9c547cSRui Paulo 
1215*5b9c547cSRui Paulo 
121639beb93cSSam Leffler static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
121739beb93cSSam Leffler {
121839beb93cSSam Leffler 	struct eap_sim_data *data = priv;
121939beb93cSSam Leffler 	u8 *key;
122039beb93cSSam Leffler 
122139beb93cSSam Leffler 	if (data->state != SUCCESS)
122239beb93cSSam Leffler 		return NULL;
122339beb93cSSam Leffler 
122439beb93cSSam Leffler 	key = os_malloc(EAP_EMSK_LEN);
122539beb93cSSam Leffler 	if (key == NULL)
122639beb93cSSam Leffler 		return NULL;
122739beb93cSSam Leffler 
122839beb93cSSam Leffler 	*len = EAP_EMSK_LEN;
122939beb93cSSam Leffler 	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
123039beb93cSSam Leffler 
123139beb93cSSam Leffler 	return key;
123239beb93cSSam Leffler }
123339beb93cSSam Leffler 
123439beb93cSSam Leffler 
123539beb93cSSam Leffler int eap_peer_sim_register(void)
123639beb93cSSam Leffler {
123739beb93cSSam Leffler 	struct eap_method *eap;
123839beb93cSSam Leffler 	int ret;
123939beb93cSSam Leffler 
124039beb93cSSam Leffler 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
124139beb93cSSam Leffler 				    EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM");
124239beb93cSSam Leffler 	if (eap == NULL)
124339beb93cSSam Leffler 		return -1;
124439beb93cSSam Leffler 
124539beb93cSSam Leffler 	eap->init = eap_sim_init;
124639beb93cSSam Leffler 	eap->deinit = eap_sim_deinit;
124739beb93cSSam Leffler 	eap->process = eap_sim_process;
124839beb93cSSam Leffler 	eap->isKeyAvailable = eap_sim_isKeyAvailable;
124939beb93cSSam Leffler 	eap->getKey = eap_sim_getKey;
1250*5b9c547cSRui Paulo 	eap->getSessionId = eap_sim_get_session_id;
125139beb93cSSam Leffler 	eap->has_reauth_data = eap_sim_has_reauth_data;
125239beb93cSSam Leffler 	eap->deinit_for_reauth = eap_sim_deinit_for_reauth;
125339beb93cSSam Leffler 	eap->init_for_reauth = eap_sim_init_for_reauth;
125439beb93cSSam Leffler 	eap->get_identity = eap_sim_get_identity;
125539beb93cSSam Leffler 	eap->get_emsk = eap_sim_get_emsk;
125639beb93cSSam Leffler 
125739beb93cSSam Leffler 	ret = eap_peer_method_register(eap);
125839beb93cSSam Leffler 	if (ret)
125939beb93cSSam Leffler 		eap_peer_method_free(eap);
126039beb93cSSam Leffler 	return ret;
126139beb93cSSam Leffler }
1262