xref: /freebsd/contrib/wpa/src/eap_peer/eap_sim.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
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"
12*a90b9d01SCy Schubert #include "utils/base64.h"
13e28a4053SRui Paulo #include "pcsc_funcs.h"
14*a90b9d01SCy Schubert #include "crypto/crypto.h"
15e28a4053SRui Paulo #include "crypto/milenage.h"
16f05cddf9SRui Paulo #include "crypto/random.h"
1739beb93cSSam Leffler #include "eap_peer/eap_i.h"
1839beb93cSSam Leffler #include "eap_config.h"
1939beb93cSSam Leffler #include "eap_common/eap_sim_common.h"
2039beb93cSSam Leffler 
2139beb93cSSam Leffler 
2239beb93cSSam Leffler struct eap_sim_data {
2339beb93cSSam Leffler 	u8 *ver_list;
2439beb93cSSam Leffler 	size_t ver_list_len;
2539beb93cSSam Leffler 	int selected_version;
2639beb93cSSam Leffler 	size_t min_num_chal, num_chal;
2739beb93cSSam Leffler 
2839beb93cSSam Leffler 	u8 kc[3][EAP_SIM_KC_LEN];
2939beb93cSSam Leffler 	u8 sres[3][EAP_SIM_SRES_LEN];
3039beb93cSSam Leffler 	u8 nonce_mt[EAP_SIM_NONCE_MT_LEN], nonce_s[EAP_SIM_NONCE_S_LEN];
3139beb93cSSam Leffler 	u8 mk[EAP_SIM_MK_LEN];
3239beb93cSSam Leffler 	u8 k_aut[EAP_SIM_K_AUT_LEN];
3339beb93cSSam Leffler 	u8 k_encr[EAP_SIM_K_ENCR_LEN];
3439beb93cSSam Leffler 	u8 msk[EAP_SIM_KEYING_DATA_LEN];
3539beb93cSSam Leffler 	u8 emsk[EAP_EMSK_LEN];
3639beb93cSSam Leffler 	u8 rand[3][GSM_RAND_LEN];
37206b73d0SCy Schubert 	u8 reauth_mac[EAP_SIM_MAC_LEN];
3839beb93cSSam Leffler 
3939beb93cSSam Leffler 	int num_id_req, num_notification;
4039beb93cSSam Leffler 	u8 *pseudonym;
4139beb93cSSam Leffler 	size_t pseudonym_len;
4239beb93cSSam Leffler 	u8 *reauth_id;
4339beb93cSSam Leffler 	size_t reauth_id_len;
4439beb93cSSam Leffler 	int reauth;
4539beb93cSSam Leffler 	unsigned int counter, counter_too_small;
46*a90b9d01SCy Schubert 	u8 *mk_identity;
47*a90b9d01SCy Schubert 	size_t mk_identity_len;
4839beb93cSSam Leffler 	enum {
49c1d255d3SCy Schubert 		CONTINUE, START_DONE, RESULT_SUCCESS, SUCCESS, FAILURE
5039beb93cSSam Leffler 	} state;
5139beb93cSSam Leffler 	int result_ind, use_result_ind;
5285732ac8SCy Schubert 	int use_pseudonym;
5385732ac8SCy Schubert 	int error_code;
54*a90b9d01SCy Schubert 	struct crypto_rsa_key *imsi_privacy_key;
5539beb93cSSam Leffler };
5639beb93cSSam Leffler 
5739beb93cSSam Leffler 
5839beb93cSSam Leffler #ifndef CONFIG_NO_STDOUT_DEBUG
eap_sim_state_txt(int state)5939beb93cSSam Leffler static const char * eap_sim_state_txt(int state)
6039beb93cSSam Leffler {
6139beb93cSSam Leffler 	switch (state) {
6239beb93cSSam Leffler 	case CONTINUE:
6339beb93cSSam Leffler 		return "CONTINUE";
64c1d255d3SCy Schubert 	case START_DONE:
65c1d255d3SCy Schubert 		return "START_DONE";
6639beb93cSSam Leffler 	case RESULT_SUCCESS:
6739beb93cSSam Leffler 		return "RESULT_SUCCESS";
6839beb93cSSam Leffler 	case SUCCESS:
6939beb93cSSam Leffler 		return "SUCCESS";
7039beb93cSSam Leffler 	case FAILURE:
7139beb93cSSam Leffler 		return "FAILURE";
7239beb93cSSam Leffler 	default:
7339beb93cSSam Leffler 		return "?";
7439beb93cSSam Leffler 	}
7539beb93cSSam Leffler }
7639beb93cSSam Leffler #endif /* CONFIG_NO_STDOUT_DEBUG */
7739beb93cSSam Leffler 
7839beb93cSSam Leffler 
eap_sim_state(struct eap_sim_data * data,int state)7939beb93cSSam Leffler static void eap_sim_state(struct eap_sim_data *data, int state)
8039beb93cSSam Leffler {
8139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s",
8239beb93cSSam Leffler 		   eap_sim_state_txt(data->state),
8339beb93cSSam Leffler 		   eap_sim_state_txt(state));
8439beb93cSSam Leffler 	data->state = state;
8539beb93cSSam Leffler }
8639beb93cSSam Leffler 
8739beb93cSSam Leffler 
eap_sim_init(struct eap_sm * sm)8839beb93cSSam Leffler static void * eap_sim_init(struct eap_sm *sm)
8939beb93cSSam Leffler {
9039beb93cSSam Leffler 	struct eap_sim_data *data;
9139beb93cSSam Leffler 	struct eap_peer_config *config = eap_get_config(sm);
9239beb93cSSam Leffler 
9339beb93cSSam Leffler 	data = os_zalloc(sizeof(*data));
9439beb93cSSam Leffler 	if (data == NULL)
9539beb93cSSam Leffler 		return NULL;
9639beb93cSSam Leffler 
97f05cddf9SRui Paulo 	if (random_get_bytes(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
9839beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data "
9939beb93cSSam Leffler 			   "for NONCE_MT");
10039beb93cSSam Leffler 		os_free(data);
10139beb93cSSam Leffler 		return NULL;
10239beb93cSSam Leffler 	}
10339beb93cSSam Leffler 
104*a90b9d01SCy Schubert 	if (config && config->imsi_privacy_cert) {
105*a90b9d01SCy Schubert #ifdef CRYPTO_RSA_OAEP_SHA256
106*a90b9d01SCy Schubert 		data->imsi_privacy_key = crypto_rsa_key_read(
107*a90b9d01SCy Schubert 			config->imsi_privacy_cert, false);
108*a90b9d01SCy Schubert 		if (!data->imsi_privacy_key) {
109*a90b9d01SCy Schubert 			wpa_printf(MSG_ERROR,
110*a90b9d01SCy Schubert 				   "EAP-SIM: Failed to read/parse IMSI privacy certificate %s",
111*a90b9d01SCy Schubert 				   config->imsi_privacy_cert);
112*a90b9d01SCy Schubert 			os_free(data);
113*a90b9d01SCy Schubert 			return NULL;
114*a90b9d01SCy Schubert 		}
115*a90b9d01SCy Schubert #else /* CRYPTO_RSA_OAEP_SHA256 */
116*a90b9d01SCy Schubert 		wpa_printf(MSG_ERROR,
117*a90b9d01SCy Schubert 			   "EAP-SIM: No support for imsi_privacy_cert in the build");
118*a90b9d01SCy Schubert 		os_free(data);
119*a90b9d01SCy Schubert 		return NULL;
120*a90b9d01SCy Schubert #endif /* CRYPTO_RSA_OAEP_SHA256 */
121*a90b9d01SCy Schubert 	}
122*a90b9d01SCy Schubert 
12385732ac8SCy Schubert 	/* Zero is a valid error code, so we need to initialize */
12485732ac8SCy Schubert 	data->error_code = NO_EAP_METHOD_ERROR;
12585732ac8SCy Schubert 
12639beb93cSSam Leffler 	data->min_num_chal = 2;
12739beb93cSSam Leffler 	if (config && config->phase1) {
12839beb93cSSam Leffler 		char *pos = os_strstr(config->phase1, "sim_min_num_chal=");
12939beb93cSSam Leffler 		if (pos) {
13039beb93cSSam Leffler 			data->min_num_chal = atoi(pos + 17);
13139beb93cSSam Leffler 			if (data->min_num_chal < 2 || data->min_num_chal > 3) {
13239beb93cSSam Leffler 				wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
13339beb93cSSam Leffler 					   "sim_min_num_chal configuration "
13439beb93cSSam Leffler 					   "(%lu, expected 2 or 3)",
13539beb93cSSam Leffler 					   (unsigned long) data->min_num_chal);
136*a90b9d01SCy Schubert #ifdef CRYPTO_RSA_OAEP_SHA256
137*a90b9d01SCy Schubert 				crypto_rsa_key_free(data->imsi_privacy_key);
138*a90b9d01SCy Schubert #endif /* CRYPTO_RSA_OAEP_SHA256 */
13939beb93cSSam Leffler 				os_free(data);
14039beb93cSSam Leffler 				return NULL;
14139beb93cSSam Leffler 			}
14239beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-SIM: Set minimum number of "
14339beb93cSSam Leffler 				   "challenges to %lu",
14439beb93cSSam Leffler 				   (unsigned long) data->min_num_chal);
14539beb93cSSam Leffler 		}
14639beb93cSSam Leffler 
14739beb93cSSam Leffler 		data->result_ind = os_strstr(config->phase1, "result_ind=1") !=
14839beb93cSSam Leffler 			NULL;
14939beb93cSSam Leffler 	}
15039beb93cSSam Leffler 
15185732ac8SCy Schubert 	data->use_pseudonym = !sm->init_phase2;
15285732ac8SCy Schubert 	if (config && config->anonymous_identity && data->use_pseudonym) {
153f05cddf9SRui Paulo 		data->pseudonym = os_malloc(config->anonymous_identity_len);
154f05cddf9SRui Paulo 		if (data->pseudonym) {
155f05cddf9SRui Paulo 			os_memcpy(data->pseudonym, config->anonymous_identity,
156f05cddf9SRui Paulo 				  config->anonymous_identity_len);
157f05cddf9SRui Paulo 			data->pseudonym_len = config->anonymous_identity_len;
158f05cddf9SRui Paulo 		}
159f05cddf9SRui Paulo 	}
160f05cddf9SRui Paulo 
161*a90b9d01SCy Schubert 	if (sm->identity) {
162*a90b9d01SCy Schubert 		/* Use the EAP-Response/Identity in MK derivation if AT_IDENTITY
163*a90b9d01SCy Schubert 		 * is not used. */
164*a90b9d01SCy Schubert 		data->mk_identity = os_memdup(sm->identity, sm->identity_len);
165*a90b9d01SCy Schubert 		data->mk_identity_len = sm->identity_len;
166*a90b9d01SCy Schubert 	}
167*a90b9d01SCy Schubert 
16839beb93cSSam Leffler 	eap_sim_state(data, CONTINUE);
16939beb93cSSam Leffler 
17039beb93cSSam Leffler 	return data;
17139beb93cSSam Leffler }
17239beb93cSSam Leffler 
17339beb93cSSam Leffler 
eap_sim_clear_keys(struct eap_sim_data * data,int reauth)1745b9c547cSRui Paulo static void eap_sim_clear_keys(struct eap_sim_data *data, int reauth)
1755b9c547cSRui Paulo {
1765b9c547cSRui Paulo 	if (!reauth) {
1775b9c547cSRui Paulo 		os_memset(data->mk, 0, EAP_SIM_MK_LEN);
1785b9c547cSRui Paulo 		os_memset(data->k_aut, 0, EAP_SIM_K_AUT_LEN);
1795b9c547cSRui Paulo 		os_memset(data->k_encr, 0, EAP_SIM_K_ENCR_LEN);
1805b9c547cSRui Paulo 	}
1815b9c547cSRui Paulo 	os_memset(data->kc, 0, 3 * EAP_SIM_KC_LEN);
1825b9c547cSRui Paulo 	os_memset(data->sres, 0, 3 * EAP_SIM_SRES_LEN);
1835b9c547cSRui Paulo 	os_memset(data->msk, 0, EAP_SIM_KEYING_DATA_LEN);
1845b9c547cSRui Paulo 	os_memset(data->emsk, 0, EAP_EMSK_LEN);
1855b9c547cSRui Paulo }
1865b9c547cSRui Paulo 
1875b9c547cSRui Paulo 
eap_sim_deinit(struct eap_sm * sm,void * priv)18839beb93cSSam Leffler static void eap_sim_deinit(struct eap_sm *sm, void *priv)
18939beb93cSSam Leffler {
19039beb93cSSam Leffler 	struct eap_sim_data *data = priv;
19139beb93cSSam Leffler 	if (data) {
19239beb93cSSam Leffler 		os_free(data->ver_list);
19339beb93cSSam Leffler 		os_free(data->pseudonym);
19439beb93cSSam Leffler 		os_free(data->reauth_id);
195*a90b9d01SCy Schubert 		os_free(data->mk_identity);
1965b9c547cSRui Paulo 		eap_sim_clear_keys(data, 0);
197*a90b9d01SCy Schubert #ifdef CRYPTO_RSA_OAEP_SHA256
198*a90b9d01SCy Schubert 		crypto_rsa_key_free(data->imsi_privacy_key);
199*a90b9d01SCy Schubert #endif /* CRYPTO_RSA_OAEP_SHA256 */
20039beb93cSSam Leffler 		os_free(data);
20139beb93cSSam Leffler 	}
20239beb93cSSam Leffler }
20339beb93cSSam Leffler 
20439beb93cSSam Leffler 
eap_sim_ext_sim_req(struct eap_sm * sm,struct eap_sim_data * data)2055b9c547cSRui Paulo static int eap_sim_ext_sim_req(struct eap_sm *sm, struct eap_sim_data *data)
2065b9c547cSRui Paulo {
2075b9c547cSRui Paulo 	char req[200], *pos, *end;
2085b9c547cSRui Paulo 	size_t i;
2095b9c547cSRui Paulo 
2105b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "EAP-SIM: Use external SIM processing");
2115b9c547cSRui Paulo 	pos = req;
2125b9c547cSRui Paulo 	end = pos + sizeof(req);
2135b9c547cSRui Paulo 	pos += os_snprintf(pos, end - pos, "GSM-AUTH");
2145b9c547cSRui Paulo 	for (i = 0; i < data->num_chal; i++) {
2155b9c547cSRui Paulo 		pos += os_snprintf(pos, end - pos, ":");
2165b9c547cSRui Paulo 		pos += wpa_snprintf_hex(pos, end - pos, data->rand[i],
2175b9c547cSRui Paulo 					GSM_RAND_LEN);
2185b9c547cSRui Paulo 	}
2195b9c547cSRui Paulo 
2205b9c547cSRui Paulo 	eap_sm_request_sim(sm, req);
2215b9c547cSRui Paulo 	return 1;
2225b9c547cSRui Paulo }
2235b9c547cSRui Paulo 
2245b9c547cSRui Paulo 
eap_sim_ext_sim_result(struct eap_sm * sm,struct eap_sim_data * data,struct eap_peer_config * conf)2255b9c547cSRui Paulo static int eap_sim_ext_sim_result(struct eap_sm *sm, struct eap_sim_data *data,
2265b9c547cSRui Paulo 				  struct eap_peer_config *conf)
2275b9c547cSRui Paulo {
2285b9c547cSRui Paulo 	char *resp, *pos;
2295b9c547cSRui Paulo 	size_t i;
2305b9c547cSRui Paulo 
2315b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG,
2325b9c547cSRui Paulo 		   "EAP-SIM: Use result from external SIM processing");
2335b9c547cSRui Paulo 
2345b9c547cSRui Paulo 	resp = conf->external_sim_resp;
2355b9c547cSRui Paulo 	conf->external_sim_resp = NULL;
2365b9c547cSRui Paulo 
2375b9c547cSRui Paulo 	if (os_strncmp(resp, "GSM-AUTH:", 9) != 0) {
2385b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized external SIM processing response");
2395b9c547cSRui Paulo 		os_free(resp);
2405b9c547cSRui Paulo 		return -1;
2415b9c547cSRui Paulo 	}
2425b9c547cSRui Paulo 
2435b9c547cSRui Paulo 	pos = resp + 9;
2445b9c547cSRui Paulo 	for (i = 0; i < data->num_chal; i++) {
2455b9c547cSRui Paulo 		wpa_hexdump(MSG_DEBUG, "EAP-SIM: RAND",
2465b9c547cSRui Paulo 			    data->rand[i], GSM_RAND_LEN);
2475b9c547cSRui Paulo 
2485b9c547cSRui Paulo 		if (hexstr2bin(pos, data->kc[i], EAP_SIM_KC_LEN) < 0)
2495b9c547cSRui Paulo 			goto invalid;
2505b9c547cSRui Paulo 		wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: Kc",
2515b9c547cSRui Paulo 				data->kc[i], EAP_SIM_KC_LEN);
2525b9c547cSRui Paulo 		pos += EAP_SIM_KC_LEN * 2;
2535b9c547cSRui Paulo 		if (*pos != ':')
2545b9c547cSRui Paulo 			goto invalid;
2555b9c547cSRui Paulo 		pos++;
2565b9c547cSRui Paulo 
2575b9c547cSRui Paulo 		if (hexstr2bin(pos, data->sres[i], EAP_SIM_SRES_LEN) < 0)
2585b9c547cSRui Paulo 			goto invalid;
2595b9c547cSRui Paulo 		wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: SRES",
2605b9c547cSRui Paulo 				data->sres[i], EAP_SIM_SRES_LEN);
2615b9c547cSRui Paulo 		pos += EAP_SIM_SRES_LEN * 2;
2625b9c547cSRui Paulo 		if (i + 1 < data->num_chal) {
2635b9c547cSRui Paulo 			if (*pos != ':')
2645b9c547cSRui Paulo 				goto invalid;
2655b9c547cSRui Paulo 			pos++;
2665b9c547cSRui Paulo 		}
2675b9c547cSRui Paulo 	}
2685b9c547cSRui Paulo 
2695b9c547cSRui Paulo 	os_free(resp);
2705b9c547cSRui Paulo 	return 0;
2715b9c547cSRui Paulo 
2725b9c547cSRui Paulo invalid:
2735b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "EAP-SIM: Invalid external SIM processing GSM-AUTH response");
2745b9c547cSRui Paulo 	os_free(resp);
2755b9c547cSRui Paulo 	return -1;
2765b9c547cSRui Paulo }
2775b9c547cSRui Paulo 
2785b9c547cSRui Paulo 
eap_sim_gsm_auth(struct eap_sm * sm,struct eap_sim_data * data)27939beb93cSSam Leffler static int eap_sim_gsm_auth(struct eap_sm *sm, struct eap_sim_data *data)
28039beb93cSSam Leffler {
28139beb93cSSam Leffler 	struct eap_peer_config *conf;
28239beb93cSSam Leffler 
28339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication algorithm");
28439beb93cSSam Leffler 
28539beb93cSSam Leffler 	conf = eap_get_config(sm);
28639beb93cSSam Leffler 	if (conf == NULL)
28739beb93cSSam Leffler 		return -1;
2885b9c547cSRui Paulo 
2895b9c547cSRui Paulo 	if (sm->external_sim) {
2905b9c547cSRui Paulo 		if (conf->external_sim_resp)
2915b9c547cSRui Paulo 			return eap_sim_ext_sim_result(sm, data, conf);
2925b9c547cSRui Paulo 		else
2935b9c547cSRui Paulo 			return eap_sim_ext_sim_req(sm, data);
2945b9c547cSRui Paulo 	}
2955b9c547cSRui Paulo 
296780fb4a2SCy Schubert #ifdef PCSC_FUNCS
29739beb93cSSam Leffler 	if (conf->pcsc) {
29839beb93cSSam Leffler 		if (scard_gsm_auth(sm->scard_ctx, data->rand[0],
29939beb93cSSam Leffler 				   data->sres[0], data->kc[0]) ||
30039beb93cSSam Leffler 		    scard_gsm_auth(sm->scard_ctx, data->rand[1],
30139beb93cSSam Leffler 				   data->sres[1], data->kc[1]) ||
30239beb93cSSam Leffler 		    (data->num_chal > 2 &&
30339beb93cSSam Leffler 		     scard_gsm_auth(sm->scard_ctx, data->rand[2],
30439beb93cSSam Leffler 				    data->sres[2], data->kc[2]))) {
30539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-SIM: GSM SIM "
30639beb93cSSam Leffler 				   "authentication could not be completed");
30739beb93cSSam Leffler 			return -1;
30839beb93cSSam Leffler 		}
30939beb93cSSam Leffler 		return 0;
31039beb93cSSam Leffler 	}
311780fb4a2SCy Schubert #endif /* PCSC_FUNCS */
31239beb93cSSam Leffler 
31339beb93cSSam Leffler #ifdef CONFIG_SIM_SIMULATOR
31439beb93cSSam Leffler 	if (conf->password) {
31539beb93cSSam Leffler 		u8 opc[16], k[16];
31639beb93cSSam Leffler 		const char *pos;
31739beb93cSSam Leffler 		size_t i;
31839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM: Use internal GSM-Milenage "
31939beb93cSSam Leffler 			   "implementation for authentication");
32039beb93cSSam Leffler 		if (conf->password_len < 65) {
32139beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-SIM: invalid GSM-Milenage "
32239beb93cSSam Leffler 				   "password");
32339beb93cSSam Leffler 			return -1;
32439beb93cSSam Leffler 		}
32539beb93cSSam Leffler 		pos = (const char *) conf->password;
32639beb93cSSam Leffler 		if (hexstr2bin(pos, k, 16))
32739beb93cSSam Leffler 			return -1;
32839beb93cSSam Leffler 		pos += 32;
32939beb93cSSam Leffler 		if (*pos != ':')
33039beb93cSSam Leffler 			return -1;
33139beb93cSSam Leffler 		pos++;
33239beb93cSSam Leffler 
33339beb93cSSam Leffler 		if (hexstr2bin(pos, opc, 16))
33439beb93cSSam Leffler 			return -1;
33539beb93cSSam Leffler 
33639beb93cSSam Leffler 		for (i = 0; i < data->num_chal; i++) {
33739beb93cSSam Leffler 			if (gsm_milenage(opc, k, data->rand[i],
33839beb93cSSam Leffler 					 data->sres[i], data->kc[i])) {
33939beb93cSSam Leffler 				wpa_printf(MSG_DEBUG, "EAP-SIM: "
34039beb93cSSam Leffler 					   "GSM-Milenage authentication "
34139beb93cSSam Leffler 					   "could not be completed");
34239beb93cSSam Leffler 				return -1;
34339beb93cSSam Leffler 			}
34439beb93cSSam Leffler 			wpa_hexdump(MSG_DEBUG, "EAP-SIM: RAND",
34539beb93cSSam Leffler 				    data->rand[i], GSM_RAND_LEN);
34639beb93cSSam Leffler 			wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: SRES",
34739beb93cSSam Leffler 					data->sres[i], EAP_SIM_SRES_LEN);
34839beb93cSSam Leffler 			wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: Kc",
34939beb93cSSam Leffler 					data->kc[i], EAP_SIM_KC_LEN);
35039beb93cSSam Leffler 		}
35139beb93cSSam Leffler 		return 0;
35239beb93cSSam Leffler 	}
35339beb93cSSam Leffler #endif /* CONFIG_SIM_SIMULATOR */
35439beb93cSSam Leffler 
35539beb93cSSam Leffler #ifdef CONFIG_SIM_HARDCODED
35639beb93cSSam Leffler 	/* These hardcoded Kc and SRES values are used for testing. RAND to
35739beb93cSSam Leffler 	 * KC/SREC mapping is very bogus as far as real authentication is
35839beb93cSSam Leffler 	 * concerned, but it is quite useful for cases where the AS is rotating
35939beb93cSSam Leffler 	 * the order of pre-configured values. */
36039beb93cSSam Leffler 	{
36139beb93cSSam Leffler 		size_t i;
36239beb93cSSam Leffler 
36339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM: Use hardcoded Kc and SRES "
36439beb93cSSam Leffler 			   "values for testing");
36539beb93cSSam Leffler 
36639beb93cSSam Leffler 		for (i = 0; i < data->num_chal; i++) {
36739beb93cSSam Leffler 			if (data->rand[i][0] == 0xaa) {
36839beb93cSSam Leffler 				os_memcpy(data->kc[i],
36939beb93cSSam Leffler 					  "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7",
37039beb93cSSam Leffler 					  EAP_SIM_KC_LEN);
37139beb93cSSam Leffler 				os_memcpy(data->sres[i], "\xd1\xd2\xd3\xd4",
37239beb93cSSam Leffler 					  EAP_SIM_SRES_LEN);
37339beb93cSSam Leffler 			} else if (data->rand[i][0] == 0xbb) {
37439beb93cSSam Leffler 				os_memcpy(data->kc[i],
37539beb93cSSam Leffler 					  "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7",
37639beb93cSSam Leffler 					  EAP_SIM_KC_LEN);
37739beb93cSSam Leffler 				os_memcpy(data->sres[i], "\xe1\xe2\xe3\xe4",
37839beb93cSSam Leffler 					  EAP_SIM_SRES_LEN);
37939beb93cSSam Leffler 			} else {
38039beb93cSSam Leffler 				os_memcpy(data->kc[i],
38139beb93cSSam Leffler 					  "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7",
38239beb93cSSam Leffler 					  EAP_SIM_KC_LEN);
38339beb93cSSam Leffler 				os_memcpy(data->sres[i], "\xf1\xf2\xf3\xf4",
38439beb93cSSam Leffler 					  EAP_SIM_SRES_LEN);
38539beb93cSSam Leffler 			}
38639beb93cSSam Leffler 		}
38739beb93cSSam Leffler 	}
38839beb93cSSam Leffler 
38939beb93cSSam Leffler 	return 0;
39039beb93cSSam Leffler 
39139beb93cSSam Leffler #else /* CONFIG_SIM_HARDCODED */
39239beb93cSSam Leffler 
39339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: No GSM authentication algorithm "
39439beb93cSSam Leffler 		   "enabled");
39539beb93cSSam Leffler 	return -1;
39639beb93cSSam Leffler 
39739beb93cSSam Leffler #endif /* CONFIG_SIM_HARDCODED */
39839beb93cSSam Leffler }
39939beb93cSSam Leffler 
40039beb93cSSam Leffler 
eap_sim_supported_ver(int version)40139beb93cSSam Leffler static int eap_sim_supported_ver(int version)
40239beb93cSSam Leffler {
40339beb93cSSam Leffler 	return version == EAP_SIM_VERSION;
40439beb93cSSam Leffler }
40539beb93cSSam Leffler 
40639beb93cSSam Leffler 
40739beb93cSSam Leffler #define CLEAR_PSEUDONYM	0x01
40839beb93cSSam Leffler #define CLEAR_REAUTH_ID	0x02
40939beb93cSSam Leffler 
eap_sim_clear_identities(struct eap_sm * sm,struct eap_sim_data * data,int id)410f05cddf9SRui Paulo static void eap_sim_clear_identities(struct eap_sm *sm,
411f05cddf9SRui Paulo 				     struct eap_sim_data *data, int id)
41239beb93cSSam Leffler {
413f05cddf9SRui Paulo 	if ((id & CLEAR_PSEUDONYM) && data->pseudonym) {
414f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old pseudonym");
41539beb93cSSam Leffler 		os_free(data->pseudonym);
41639beb93cSSam Leffler 		data->pseudonym = NULL;
41739beb93cSSam Leffler 		data->pseudonym_len = 0;
41885732ac8SCy Schubert 		if (data->use_pseudonym)
419f05cddf9SRui Paulo 			eap_set_anon_id(sm, NULL, 0);
42039beb93cSSam Leffler 	}
421f05cddf9SRui Paulo 	if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
422f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old reauth_id");
42339beb93cSSam Leffler 		os_free(data->reauth_id);
42439beb93cSSam Leffler 		data->reauth_id = NULL;
42539beb93cSSam Leffler 		data->reauth_id_len = 0;
42639beb93cSSam Leffler 	}
42739beb93cSSam Leffler }
42839beb93cSSam Leffler 
42939beb93cSSam Leffler 
eap_sim_learn_ids(struct eap_sm * sm,struct eap_sim_data * data,struct eap_sim_attrs * attr)430f05cddf9SRui Paulo static int eap_sim_learn_ids(struct eap_sm *sm, struct eap_sim_data *data,
43139beb93cSSam Leffler 			     struct eap_sim_attrs *attr)
43239beb93cSSam Leffler {
43339beb93cSSam Leffler 	if (attr->next_pseudonym) {
434f05cddf9SRui Paulo 		const u8 *identity = NULL;
435f05cddf9SRui Paulo 		size_t identity_len = 0;
436f05cddf9SRui Paulo 		const u8 *realm = NULL;
437f05cddf9SRui Paulo 		size_t realm_len = 0;
438f05cddf9SRui Paulo 
439f05cddf9SRui Paulo 		wpa_hexdump_ascii(MSG_DEBUG,
440f05cddf9SRui Paulo 				  "EAP-SIM: (encr) AT_NEXT_PSEUDONYM",
441f05cddf9SRui Paulo 				  attr->next_pseudonym,
442f05cddf9SRui Paulo 				  attr->next_pseudonym_len);
44339beb93cSSam Leffler 		os_free(data->pseudonym);
444f05cddf9SRui Paulo 		/* Look for the realm of the permanent identity */
445f05cddf9SRui Paulo 		identity = eap_get_config_identity(sm, &identity_len);
446f05cddf9SRui Paulo 		if (identity) {
447f05cddf9SRui Paulo 			for (realm = identity, realm_len = identity_len;
448f05cddf9SRui Paulo 			     realm_len > 0; realm_len--, realm++) {
449f05cddf9SRui Paulo 				if (*realm == '@')
450f05cddf9SRui Paulo 					break;
451f05cddf9SRui Paulo 			}
452f05cddf9SRui Paulo 		}
453f05cddf9SRui Paulo 		data->pseudonym = os_malloc(attr->next_pseudonym_len +
454f05cddf9SRui Paulo 					    realm_len);
45539beb93cSSam Leffler 		if (data->pseudonym == NULL) {
45639beb93cSSam Leffler 			wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for "
45739beb93cSSam Leffler 				   "next pseudonym");
458f05cddf9SRui Paulo 			data->pseudonym_len = 0;
45939beb93cSSam Leffler 			return -1;
46039beb93cSSam Leffler 		}
46139beb93cSSam Leffler 		os_memcpy(data->pseudonym, attr->next_pseudonym,
46239beb93cSSam Leffler 			  attr->next_pseudonym_len);
463f05cddf9SRui Paulo 		if (realm_len) {
464f05cddf9SRui Paulo 			os_memcpy(data->pseudonym + attr->next_pseudonym_len,
465f05cddf9SRui Paulo 				  realm, realm_len);
466f05cddf9SRui Paulo 		}
467f05cddf9SRui Paulo 		data->pseudonym_len = attr->next_pseudonym_len + realm_len;
46885732ac8SCy Schubert 		if (data->use_pseudonym)
46985732ac8SCy Schubert 			eap_set_anon_id(sm, data->pseudonym,
47085732ac8SCy Schubert 					data->pseudonym_len);
47139beb93cSSam Leffler 	}
47239beb93cSSam Leffler 
47339beb93cSSam Leffler 	if (attr->next_reauth_id) {
47439beb93cSSam Leffler 		os_free(data->reauth_id);
47585732ac8SCy Schubert 		data->reauth_id = os_memdup(attr->next_reauth_id,
47685732ac8SCy Schubert 					    attr->next_reauth_id_len);
47739beb93cSSam Leffler 		if (data->reauth_id == NULL) {
47839beb93cSSam Leffler 			wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for "
47939beb93cSSam Leffler 				   "next reauth_id");
480f05cddf9SRui Paulo 			data->reauth_id_len = 0;
48139beb93cSSam Leffler 			return -1;
48239beb93cSSam Leffler 		}
48339beb93cSSam Leffler 		data->reauth_id_len = attr->next_reauth_id_len;
48439beb93cSSam Leffler 		wpa_hexdump_ascii(MSG_DEBUG,
48539beb93cSSam Leffler 				  "EAP-SIM: (encr) AT_NEXT_REAUTH_ID",
48639beb93cSSam Leffler 				  data->reauth_id,
48739beb93cSSam Leffler 				  data->reauth_id_len);
48839beb93cSSam Leffler 	}
48939beb93cSSam Leffler 
49039beb93cSSam Leffler 	return 0;
49139beb93cSSam Leffler }
49239beb93cSSam Leffler 
49339beb93cSSam Leffler 
eap_sim_client_error(struct eap_sim_data * data,u8 id,int err)49439beb93cSSam Leffler static struct wpabuf * eap_sim_client_error(struct eap_sim_data *data, u8 id,
49539beb93cSSam Leffler 					    int err)
49639beb93cSSam Leffler {
49739beb93cSSam Leffler 	struct eap_sim_msg *msg;
49839beb93cSSam Leffler 
49939beb93cSSam Leffler 	eap_sim_state(data, FAILURE);
50039beb93cSSam Leffler 	data->num_id_req = 0;
50139beb93cSSam Leffler 	data->num_notification = 0;
50239beb93cSSam Leffler 
503f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "EAP-SIM: Send Client-Error (error code %d)",
504f05cddf9SRui Paulo 		   err);
50539beb93cSSam Leffler 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
50639beb93cSSam Leffler 			       EAP_SIM_SUBTYPE_CLIENT_ERROR);
50739beb93cSSam Leffler 	eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
5085b9c547cSRui Paulo 	return eap_sim_msg_finish(msg, EAP_TYPE_SIM, NULL, NULL, 0);
50939beb93cSSam Leffler }
51039beb93cSSam Leffler 
51139beb93cSSam Leffler 
512*a90b9d01SCy Schubert #ifdef CRYPTO_RSA_OAEP_SHA256
513*a90b9d01SCy Schubert static struct wpabuf *
eap_sim_encrypt_identity(struct crypto_rsa_key * imsi_privacy_key,const u8 * identity,size_t identity_len,const char * attr)514*a90b9d01SCy Schubert eap_sim_encrypt_identity(struct crypto_rsa_key *imsi_privacy_key,
515*a90b9d01SCy Schubert 			 const u8 *identity, size_t identity_len,
516*a90b9d01SCy Schubert 			 const char *attr)
517*a90b9d01SCy Schubert {
518*a90b9d01SCy Schubert 	struct wpabuf *imsi_buf, *enc;
519*a90b9d01SCy Schubert 	char *b64;
520*a90b9d01SCy Schubert 	size_t b64_len, len;
521*a90b9d01SCy Schubert 
522*a90b9d01SCy Schubert 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Encrypt permanent identity",
523*a90b9d01SCy Schubert 			  identity, identity_len);
524*a90b9d01SCy Schubert 
525*a90b9d01SCy Schubert 	imsi_buf = wpabuf_alloc_copy(identity, identity_len);
526*a90b9d01SCy Schubert 	if (!imsi_buf)
527*a90b9d01SCy Schubert 		return NULL;
528*a90b9d01SCy Schubert 	enc = crypto_rsa_oaep_sha256_encrypt(imsi_privacy_key, imsi_buf);
529*a90b9d01SCy Schubert 	wpabuf_free(imsi_buf);
530*a90b9d01SCy Schubert 	if (!enc)
531*a90b9d01SCy Schubert 		return NULL;
532*a90b9d01SCy Schubert 
533*a90b9d01SCy Schubert 	b64 = base64_encode_no_lf(wpabuf_head(enc), wpabuf_len(enc), &b64_len);
534*a90b9d01SCy Schubert 	wpabuf_free(enc);
535*a90b9d01SCy Schubert 	if (!b64)
536*a90b9d01SCy Schubert 		return NULL;
537*a90b9d01SCy Schubert 
538*a90b9d01SCy Schubert 	len = 1 + b64_len;
539*a90b9d01SCy Schubert 	if (attr)
540*a90b9d01SCy Schubert 		len += 1 + os_strlen(attr);
541*a90b9d01SCy Schubert 	enc = wpabuf_alloc(len);
542*a90b9d01SCy Schubert 	if (!enc) {
543*a90b9d01SCy Schubert 		os_free(b64);
544*a90b9d01SCy Schubert 		return NULL;
545*a90b9d01SCy Schubert 	}
546*a90b9d01SCy Schubert 	wpabuf_put_u8(enc, '\0');
547*a90b9d01SCy Schubert 	wpabuf_put_data(enc, b64, b64_len);
548*a90b9d01SCy Schubert 	os_free(b64);
549*a90b9d01SCy Schubert 	if (attr) {
550*a90b9d01SCy Schubert 		wpabuf_put_u8(enc, ',');
551*a90b9d01SCy Schubert 		wpabuf_put_str(enc, attr);
552*a90b9d01SCy Schubert 	}
553*a90b9d01SCy Schubert 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Encrypted permanent identity",
554*a90b9d01SCy Schubert 			  wpabuf_head(enc), wpabuf_len(enc));
555*a90b9d01SCy Schubert 
556*a90b9d01SCy Schubert 	return enc;
557*a90b9d01SCy Schubert }
558*a90b9d01SCy Schubert #endif /* CRYPTO_RSA_OAEP_SHA256 */
559*a90b9d01SCy Schubert 
560*a90b9d01SCy Schubert 
eap_sim_response_start(struct eap_sm * sm,struct eap_sim_data * data,u8 id,enum eap_sim_id_req id_req)56139beb93cSSam Leffler static struct wpabuf * eap_sim_response_start(struct eap_sm *sm,
56239beb93cSSam Leffler 					      struct eap_sim_data *data, u8 id,
56339beb93cSSam Leffler 					      enum eap_sim_id_req id_req)
56439beb93cSSam Leffler {
56539beb93cSSam Leffler 	const u8 *identity = NULL;
56639beb93cSSam Leffler 	size_t identity_len = 0;
56739beb93cSSam Leffler 	struct eap_sim_msg *msg;
568c1d255d3SCy Schubert 	struct wpabuf *resp;
569*a90b9d01SCy Schubert 	struct wpabuf *enc_identity = NULL;
570*a90b9d01SCy Schubert 	struct eap_peer_config *config = NULL;
571*a90b9d01SCy Schubert 	bool use_imsi_identity = false;
57239beb93cSSam Leffler 
57339beb93cSSam Leffler 	data->reauth = 0;
57439beb93cSSam Leffler 	if (id_req == ANY_ID && data->reauth_id) {
57539beb93cSSam Leffler 		identity = data->reauth_id;
57639beb93cSSam Leffler 		identity_len = data->reauth_id_len;
57739beb93cSSam Leffler 		data->reauth = 1;
57839beb93cSSam Leffler 	} else if ((id_req == ANY_ID || id_req == FULLAUTH_ID) &&
579206b73d0SCy Schubert 		   data->pseudonym &&
580206b73d0SCy Schubert 		   !eap_sim_anonymous_username(data->pseudonym,
581206b73d0SCy Schubert 					       data->pseudonym_len)) {
58239beb93cSSam Leffler 		identity = data->pseudonym;
58339beb93cSSam Leffler 		identity_len = data->pseudonym_len;
584f05cddf9SRui Paulo 		eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID);
58539beb93cSSam Leffler 	} else if (id_req != NO_ID_REQ) {
58639beb93cSSam Leffler 		identity = eap_get_config_identity(sm, &identity_len);
58739beb93cSSam Leffler 		if (identity) {
588206b73d0SCy Schubert 			int ids = CLEAR_PSEUDONYM | CLEAR_REAUTH_ID;
589206b73d0SCy Schubert 
590206b73d0SCy Schubert 			if (data->pseudonym &&
591206b73d0SCy Schubert 			    eap_sim_anonymous_username(data->pseudonym,
592206b73d0SCy Schubert 						       data->pseudonym_len))
593206b73d0SCy Schubert 				ids &= ~CLEAR_PSEUDONYM;
594206b73d0SCy Schubert 			eap_sim_clear_identities(sm, data, ids);
595*a90b9d01SCy Schubert 
596*a90b9d01SCy Schubert 			config = eap_get_config(sm);
597*a90b9d01SCy Schubert 			if (config && config->imsi_identity)
598*a90b9d01SCy Schubert 				use_imsi_identity = true;
59939beb93cSSam Leffler 		}
600*a90b9d01SCy Schubert #ifdef CRYPTO_RSA_OAEP_SHA256
601*a90b9d01SCy Schubert 		if (identity && data->imsi_privacy_key) {
602*a90b9d01SCy Schubert 			const char *attr = NULL;
603*a90b9d01SCy Schubert 
604*a90b9d01SCy Schubert 			config = eap_get_config(sm);
605*a90b9d01SCy Schubert 			if (config)
606*a90b9d01SCy Schubert 				attr = config->imsi_privacy_attr;
607*a90b9d01SCy Schubert 			enc_identity = eap_sim_encrypt_identity(
608*a90b9d01SCy Schubert 				data->imsi_privacy_key,
609*a90b9d01SCy Schubert 				identity, identity_len, attr);
610*a90b9d01SCy Schubert 			if (!enc_identity) {
611*a90b9d01SCy Schubert 				wpa_printf(MSG_INFO,
612*a90b9d01SCy Schubert 					   "EAP-SIM: Failed to encrypt permanent identity");
613*a90b9d01SCy Schubert 				return eap_sim_client_error(
614*a90b9d01SCy Schubert 					data, id,
615*a90b9d01SCy Schubert 					EAP_SIM_UNABLE_TO_PROCESS_PACKET);
61639beb93cSSam Leffler 			}
617*a90b9d01SCy Schubert 			/* Use the real identity, not the encrypted one, in MK
618*a90b9d01SCy Schubert 			 * derivation. */
619*a90b9d01SCy Schubert 			os_free(data->mk_identity);
620*a90b9d01SCy Schubert 			data->mk_identity = os_memdup(identity, identity_len);
621*a90b9d01SCy Schubert 			data->mk_identity_len = identity_len;
622*a90b9d01SCy Schubert 			identity = wpabuf_head(enc_identity);
623*a90b9d01SCy Schubert 			identity_len = wpabuf_len(enc_identity);
624*a90b9d01SCy Schubert 		}
625*a90b9d01SCy Schubert #endif /* CRYPTO_RSA_OAEP_SHA256 */
626*a90b9d01SCy Schubert 	}
62739beb93cSSam Leffler 
62839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Start (id=%d)", id);
62939beb93cSSam Leffler 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id,
63039beb93cSSam Leffler 			       EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START);
631c1d255d3SCy Schubert 	if (identity) {
632c1d255d3SCy Schubert 		wpa_hexdump_ascii(MSG_DEBUG, "   AT_IDENTITY",
633c1d255d3SCy Schubert 				  identity, identity_len);
634c1d255d3SCy Schubert 		eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
635c1d255d3SCy Schubert 				identity, identity_len);
636*a90b9d01SCy Schubert 		if (use_imsi_identity && config && config->imsi_identity) {
637*a90b9d01SCy Schubert 			/* Use the IMSI identity override, i.e., the not
638*a90b9d01SCy Schubert 			 * encrypted one, in MK derivation, when using
639*a90b9d01SCy Schubert 			 * externally encrypted identity in configuration. */
640*a90b9d01SCy Schubert 			os_free(data->mk_identity);
641*a90b9d01SCy Schubert 			data->mk_identity = os_memdup(
642*a90b9d01SCy Schubert 				config->imsi_identity,
643*a90b9d01SCy Schubert 				config->imsi_identity_len);
644*a90b9d01SCy Schubert 			data->mk_identity_len = config->imsi_identity_len;
645*a90b9d01SCy Schubert 		} else if (!enc_identity) {
646*a90b9d01SCy Schubert 			/* Use the last AT_IDENTITY value as the identity in
647*a90b9d01SCy Schubert 			 * MK derivation. */
648*a90b9d01SCy Schubert 			os_free(data->mk_identity);
649*a90b9d01SCy Schubert 			data->mk_identity = os_memdup(identity, identity_len);
650*a90b9d01SCy Schubert 			data->mk_identity_len = identity_len;
651c1d255d3SCy Schubert 		}
652*a90b9d01SCy Schubert 	}
653*a90b9d01SCy Schubert 	wpabuf_free(enc_identity);
65439beb93cSSam Leffler 	if (!data->reauth) {
65539beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "   AT_NONCE_MT",
65639beb93cSSam Leffler 			    data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
65739beb93cSSam Leffler 		eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_MT, 0,
65839beb93cSSam Leffler 				data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
65939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   AT_SELECTED_VERSION %d",
66039beb93cSSam Leffler 			   data->selected_version);
66139beb93cSSam Leffler 		eap_sim_msg_add(msg, EAP_SIM_AT_SELECTED_VERSION,
66239beb93cSSam Leffler 				data->selected_version, NULL, 0);
66339beb93cSSam Leffler 	}
66439beb93cSSam Leffler 
665c1d255d3SCy Schubert 	resp = eap_sim_msg_finish(msg, EAP_TYPE_SIM, NULL, NULL, 0);
666c1d255d3SCy Schubert 	if (resp)
667c1d255d3SCy Schubert 		eap_sim_state(data, START_DONE);
668c1d255d3SCy Schubert 	return resp;
66939beb93cSSam Leffler }
67039beb93cSSam Leffler 
67139beb93cSSam Leffler 
eap_sim_response_challenge(struct eap_sim_data * data,u8 id)67239beb93cSSam Leffler static struct wpabuf * eap_sim_response_challenge(struct eap_sim_data *data,
67339beb93cSSam Leffler 						  u8 id)
67439beb93cSSam Leffler {
67539beb93cSSam Leffler 	struct eap_sim_msg *msg;
67639beb93cSSam Leffler 
67739beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Challenge (id=%d)", id);
67839beb93cSSam Leffler 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
67939beb93cSSam Leffler 			       EAP_SIM_SUBTYPE_CHALLENGE);
68039beb93cSSam Leffler 	if (data->use_result_ind) {
68139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
68239beb93cSSam Leffler 		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
68339beb93cSSam Leffler 	}
68439beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "   AT_MAC");
68539beb93cSSam Leffler 	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
6865b9c547cSRui Paulo 	return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut,
6875b9c547cSRui Paulo 				  (u8 *) data->sres,
68839beb93cSSam Leffler 				  data->num_chal * EAP_SIM_SRES_LEN);
68939beb93cSSam Leffler }
69039beb93cSSam Leffler 
69139beb93cSSam Leffler 
eap_sim_response_reauth(struct eap_sim_data * data,u8 id,int counter_too_small,const u8 * nonce_s)69239beb93cSSam Leffler static struct wpabuf * eap_sim_response_reauth(struct eap_sim_data *data,
693f05cddf9SRui Paulo 					       u8 id, int counter_too_small,
694f05cddf9SRui Paulo 					       const u8 *nonce_s)
69539beb93cSSam Leffler {
69639beb93cSSam Leffler 	struct eap_sim_msg *msg;
69739beb93cSSam Leffler 	unsigned int counter;
69839beb93cSSam Leffler 
69939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Reauthentication (id=%d)",
70039beb93cSSam Leffler 		   id);
70139beb93cSSam Leffler 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
70239beb93cSSam Leffler 			       EAP_SIM_SUBTYPE_REAUTHENTICATION);
70339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "   AT_IV");
70439beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
70539beb93cSSam Leffler 	eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
70639beb93cSSam Leffler 
70739beb93cSSam Leffler 	if (counter_too_small) {
70839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   *AT_COUNTER_TOO_SMALL");
70939beb93cSSam Leffler 		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER_TOO_SMALL, 0, NULL, 0);
71039beb93cSSam Leffler 		counter = data->counter_too_small;
71139beb93cSSam Leffler 	} else
71239beb93cSSam Leffler 		counter = data->counter;
71339beb93cSSam Leffler 
71439beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", counter);
71539beb93cSSam Leffler 	eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
71639beb93cSSam Leffler 
71739beb93cSSam Leffler 	if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
71839beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
71939beb93cSSam Leffler 			   "AT_ENCR_DATA");
72039beb93cSSam Leffler 		eap_sim_msg_free(msg);
72139beb93cSSam Leffler 		return NULL;
72239beb93cSSam Leffler 	}
72339beb93cSSam Leffler 	if (data->use_result_ind) {
72439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
72539beb93cSSam Leffler 		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
72639beb93cSSam Leffler 	}
72739beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "   AT_MAC");
72839beb93cSSam Leffler 	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
7295b9c547cSRui Paulo 	return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut, nonce_s,
73039beb93cSSam Leffler 				  EAP_SIM_NONCE_S_LEN);
73139beb93cSSam Leffler }
73239beb93cSSam Leffler 
73339beb93cSSam Leffler 
eap_sim_response_notification(struct eap_sim_data * data,u8 id,u16 notification)73439beb93cSSam Leffler static struct wpabuf * eap_sim_response_notification(struct eap_sim_data *data,
73539beb93cSSam Leffler 						     u8 id, u16 notification)
73639beb93cSSam Leffler {
73739beb93cSSam Leffler 	struct eap_sim_msg *msg;
73839beb93cSSam Leffler 	u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL;
73939beb93cSSam Leffler 
74039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Notification (id=%d)", id);
74139beb93cSSam Leffler 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id,
74239beb93cSSam Leffler 			       EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION);
74339beb93cSSam Leffler 	if (k_aut && data->reauth) {
74439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   AT_IV");
74539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
74639beb93cSSam Leffler 		eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
74739beb93cSSam Leffler 					   EAP_SIM_AT_ENCR_DATA);
74839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", data->counter);
74939beb93cSSam Leffler 		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
75039beb93cSSam Leffler 				NULL, 0);
75139beb93cSSam Leffler 		if (eap_sim_msg_add_encr_end(msg, data->k_encr,
75239beb93cSSam Leffler 					     EAP_SIM_AT_PADDING)) {
75339beb93cSSam Leffler 			wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
75439beb93cSSam Leffler 				   "AT_ENCR_DATA");
75539beb93cSSam Leffler 			eap_sim_msg_free(msg);
75639beb93cSSam Leffler 			return NULL;
75739beb93cSSam Leffler 		}
75839beb93cSSam Leffler 	}
75939beb93cSSam Leffler 	if (k_aut) {
76039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   AT_MAC");
76139beb93cSSam Leffler 		eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
76239beb93cSSam Leffler 	}
7635b9c547cSRui Paulo 	return eap_sim_msg_finish(msg, EAP_TYPE_SIM, k_aut, (u8 *) "", 0);
76439beb93cSSam Leffler }
76539beb93cSSam Leffler 
76639beb93cSSam Leffler 
eap_sim_process_start(struct eap_sm * sm,struct eap_sim_data * data,u8 id,struct eap_sim_attrs * attr)76739beb93cSSam Leffler static struct wpabuf * eap_sim_process_start(struct eap_sm *sm,
76839beb93cSSam Leffler 					     struct eap_sim_data *data, u8 id,
76939beb93cSSam Leffler 					     struct eap_sim_attrs *attr)
77039beb93cSSam Leffler {
77139beb93cSSam Leffler 	int selected_version = -1, id_error;
77239beb93cSSam Leffler 	size_t i;
77339beb93cSSam Leffler 	u8 *pos;
77439beb93cSSam Leffler 
77539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Start");
77639beb93cSSam Leffler 	if (attr->version_list == NULL) {
77739beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: No AT_VERSION_LIST in "
77839beb93cSSam Leffler 			   "SIM/Start");
77939beb93cSSam Leffler 		return eap_sim_client_error(data, id,
78039beb93cSSam Leffler 					    EAP_SIM_UNSUPPORTED_VERSION);
78139beb93cSSam Leffler 	}
78239beb93cSSam Leffler 
78339beb93cSSam Leffler 	os_free(data->ver_list);
78485732ac8SCy Schubert 	data->ver_list = os_memdup(attr->version_list, attr->version_list_len);
78539beb93cSSam Leffler 	if (data->ver_list == NULL) {
78639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to allocate "
78739beb93cSSam Leffler 			   "memory for version list");
78839beb93cSSam Leffler 		return eap_sim_client_error(data, id,
78939beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
79039beb93cSSam Leffler 	}
79139beb93cSSam Leffler 	data->ver_list_len = attr->version_list_len;
79239beb93cSSam Leffler 	pos = data->ver_list;
79339beb93cSSam Leffler 	for (i = 0; i < data->ver_list_len / 2; i++) {
79439beb93cSSam Leffler 		int ver = pos[0] * 256 + pos[1];
79539beb93cSSam Leffler 		pos += 2;
79639beb93cSSam Leffler 		if (eap_sim_supported_ver(ver)) {
79739beb93cSSam Leffler 			selected_version = ver;
79839beb93cSSam Leffler 			break;
79939beb93cSSam Leffler 		}
80039beb93cSSam Leffler 	}
80139beb93cSSam Leffler 	if (selected_version < 0) {
80239beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: Could not find a supported "
80339beb93cSSam Leffler 			   "version");
80439beb93cSSam Leffler 		return eap_sim_client_error(data, id,
80539beb93cSSam Leffler 					    EAP_SIM_UNSUPPORTED_VERSION);
80639beb93cSSam Leffler 	}
80739beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: Selected Version %d",
80839beb93cSSam Leffler 		   selected_version);
80939beb93cSSam Leffler 	data->selected_version = selected_version;
81039beb93cSSam Leffler 
81139beb93cSSam Leffler 	id_error = 0;
81239beb93cSSam Leffler 	switch (attr->id_req) {
81339beb93cSSam Leffler 	case NO_ID_REQ:
81439beb93cSSam Leffler 		break;
81539beb93cSSam Leffler 	case ANY_ID:
81639beb93cSSam Leffler 		if (data->num_id_req > 0)
81739beb93cSSam Leffler 			id_error++;
81839beb93cSSam Leffler 		data->num_id_req++;
81939beb93cSSam Leffler 		break;
82039beb93cSSam Leffler 	case FULLAUTH_ID:
82139beb93cSSam Leffler 		if (data->num_id_req > 1)
82239beb93cSSam Leffler 			id_error++;
82339beb93cSSam Leffler 		data->num_id_req++;
82439beb93cSSam Leffler 		break;
82539beb93cSSam Leffler 	case PERMANENT_ID:
82639beb93cSSam Leffler 		if (data->num_id_req > 2)
82739beb93cSSam Leffler 			id_error++;
82839beb93cSSam Leffler 		data->num_id_req++;
82939beb93cSSam Leffler 		break;
83039beb93cSSam Leffler 	}
83139beb93cSSam Leffler 	if (id_error) {
83239beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: Too many ID requests "
83339beb93cSSam Leffler 			   "used within one authentication");
83439beb93cSSam Leffler 		return eap_sim_client_error(data, id,
83539beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
83639beb93cSSam Leffler 	}
83739beb93cSSam Leffler 
83839beb93cSSam Leffler 	return eap_sim_response_start(sm, data, id, attr->id_req);
83939beb93cSSam Leffler }
84039beb93cSSam Leffler 
84139beb93cSSam Leffler 
eap_sim_process_challenge(struct eap_sm * sm,struct eap_sim_data * data,u8 id,const struct wpabuf * reqData,struct eap_sim_attrs * attr)84239beb93cSSam Leffler static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm,
84339beb93cSSam Leffler 						 struct eap_sim_data *data,
84439beb93cSSam Leffler 						 u8 id,
84539beb93cSSam Leffler 						 const struct wpabuf *reqData,
84639beb93cSSam Leffler 						 struct eap_sim_attrs *attr)
84739beb93cSSam Leffler {
84839beb93cSSam Leffler 	const u8 *identity;
84939beb93cSSam Leffler 	size_t identity_len;
85039beb93cSSam Leffler 	struct eap_sim_attrs eattr;
8515b9c547cSRui Paulo 	int res;
85239beb93cSSam Leffler 
85339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Challenge");
854c1d255d3SCy Schubert 	if (data->state != START_DONE) {
855c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
856c1d255d3SCy Schubert 			   "EAP-SIM: Unexpected Challenge in state %s",
857c1d255d3SCy Schubert 			   eap_sim_state_txt(data->state));
858c1d255d3SCy Schubert 		return eap_sim_client_error(data, id,
859c1d255d3SCy Schubert 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
860c1d255d3SCy Schubert 	}
86139beb93cSSam Leffler 	data->reauth = 0;
86239beb93cSSam Leffler 	if (!attr->mac || !attr->rand) {
86339beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
86439beb93cSSam Leffler 			   "did not include%s%s",
86539beb93cSSam Leffler 			   !attr->mac ? " AT_MAC" : "",
86639beb93cSSam Leffler 			   !attr->rand ? " AT_RAND" : "");
86739beb93cSSam Leffler 		return eap_sim_client_error(data, id,
86839beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
86939beb93cSSam Leffler 	}
87039beb93cSSam Leffler 
87139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: %lu challenges",
87239beb93cSSam Leffler 		   (unsigned long) attr->num_chal);
87339beb93cSSam Leffler 	if (attr->num_chal < data->min_num_chal) {
87439beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: Insufficient number of "
87539beb93cSSam Leffler 			   "challenges (%lu)", (unsigned long) attr->num_chal);
87639beb93cSSam Leffler 		return eap_sim_client_error(data, id,
87739beb93cSSam Leffler 					    EAP_SIM_INSUFFICIENT_NUM_OF_CHAL);
87839beb93cSSam Leffler 	}
87939beb93cSSam Leffler 	if (attr->num_chal > 3) {
88039beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: Too many challenges "
88139beb93cSSam Leffler 			   "(%lu)", (unsigned long) attr->num_chal);
88239beb93cSSam Leffler 		return eap_sim_client_error(data, id,
88339beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
88439beb93cSSam Leffler 	}
88539beb93cSSam Leffler 
88639beb93cSSam Leffler 	/* Verify that RANDs are different */
88739beb93cSSam Leffler 	if (os_memcmp(attr->rand, attr->rand + GSM_RAND_LEN,
88839beb93cSSam Leffler 		   GSM_RAND_LEN) == 0 ||
88939beb93cSSam Leffler 	    (attr->num_chal > 2 &&
89039beb93cSSam Leffler 	     (os_memcmp(attr->rand, attr->rand + 2 * GSM_RAND_LEN,
89139beb93cSSam Leffler 			GSM_RAND_LEN) == 0 ||
89239beb93cSSam Leffler 	      os_memcmp(attr->rand + GSM_RAND_LEN,
89339beb93cSSam Leffler 			attr->rand + 2 * GSM_RAND_LEN,
89439beb93cSSam Leffler 			GSM_RAND_LEN) == 0))) {
89539beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: Same RAND used multiple times");
89639beb93cSSam Leffler 		return eap_sim_client_error(data, id,
89739beb93cSSam Leffler 					    EAP_SIM_RAND_NOT_FRESH);
89839beb93cSSam Leffler 	}
89939beb93cSSam Leffler 
90039beb93cSSam Leffler 	os_memcpy(data->rand, attr->rand, attr->num_chal * GSM_RAND_LEN);
90139beb93cSSam Leffler 	data->num_chal = attr->num_chal;
90239beb93cSSam Leffler 
9035b9c547cSRui Paulo 	res = eap_sim_gsm_auth(sm, data);
9045b9c547cSRui Paulo 	if (res > 0) {
9055b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-SIM: Wait for external SIM processing");
9065b9c547cSRui Paulo 		return NULL;
9075b9c547cSRui Paulo 	}
9085b9c547cSRui Paulo 	if (res) {
90939beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: GSM authentication failed");
91039beb93cSSam Leffler 		return eap_sim_client_error(data, id,
91139beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
91239beb93cSSam Leffler 	}
91385732ac8SCy Schubert 
914*a90b9d01SCy Schubert 	identity = data->mk_identity;
915*a90b9d01SCy Schubert 	identity_len = data->mk_identity_len;
91639beb93cSSam Leffler 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Selected identity for MK "
91739beb93cSSam Leffler 			  "derivation", identity, identity_len);
91839beb93cSSam Leffler 	eap_sim_derive_mk(identity, identity_len, data->nonce_mt,
91939beb93cSSam Leffler 			  data->selected_version, data->ver_list,
92039beb93cSSam Leffler 			  data->ver_list_len, data->num_chal,
92139beb93cSSam Leffler 			  (const u8 *) data->kc, data->mk);
92239beb93cSSam Leffler 	eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
92339beb93cSSam Leffler 			    data->emsk);
92439beb93cSSam Leffler 	if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, data->nonce_mt,
92539beb93cSSam Leffler 			       EAP_SIM_NONCE_MT_LEN)) {
92639beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
92739beb93cSSam Leffler 			   "used invalid AT_MAC");
928206b73d0SCy Schubert #ifdef TEST_FUZZ
929206b73d0SCy Schubert 		wpa_printf(MSG_INFO,
930206b73d0SCy Schubert 			   "TEST: Ignore AT_MAC mismatch for fuzz testing");
931206b73d0SCy Schubert #else /* TEST_FUZZ */
93239beb93cSSam Leffler 		return eap_sim_client_error(data, id,
93339beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
934206b73d0SCy Schubert #endif /* TEST_FUZZ */
93539beb93cSSam Leffler 	}
93639beb93cSSam Leffler 
937f05cddf9SRui Paulo 	/* Old reauthentication identity must not be used anymore. In
938f05cddf9SRui Paulo 	 * other words, if no new reauth identity is received, full
939f05cddf9SRui Paulo 	 * authentication will be used on next reauthentication (using
940f05cddf9SRui Paulo 	 * pseudonym identity or permanent identity). */
941*a90b9d01SCy Schubert 	eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID);
94239beb93cSSam Leffler 
94339beb93cSSam Leffler 	if (attr->encr_data) {
94439beb93cSSam Leffler 		u8 *decrypted;
94539beb93cSSam Leffler 		decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
94639beb93cSSam Leffler 					       attr->encr_data_len, attr->iv,
94739beb93cSSam Leffler 					       &eattr, 0);
94839beb93cSSam Leffler 		if (decrypted == NULL) {
94939beb93cSSam Leffler 			return eap_sim_client_error(
95039beb93cSSam Leffler 				data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET);
95139beb93cSSam Leffler 		}
952f05cddf9SRui Paulo 		eap_sim_learn_ids(sm, data, &eattr);
95339beb93cSSam Leffler 		os_free(decrypted);
95439beb93cSSam Leffler 	}
95539beb93cSSam Leffler 
95639beb93cSSam Leffler 	if (data->result_ind && attr->result_ind)
95739beb93cSSam Leffler 		data->use_result_ind = 1;
95839beb93cSSam Leffler 
9595b9c547cSRui Paulo 	if (data->state != FAILURE) {
96039beb93cSSam Leffler 		eap_sim_state(data, data->use_result_ind ?
96139beb93cSSam Leffler 			      RESULT_SUCCESS : SUCCESS);
96239beb93cSSam Leffler 	}
96339beb93cSSam Leffler 
96439beb93cSSam Leffler 	data->num_id_req = 0;
96539beb93cSSam Leffler 	data->num_notification = 0;
96639beb93cSSam Leffler 	/* RFC 4186 specifies that counter is initialized to one after
96739beb93cSSam Leffler 	 * fullauth, but initializing it to zero makes it easier to implement
96839beb93cSSam Leffler 	 * reauth verification. */
96939beb93cSSam Leffler 	data->counter = 0;
97039beb93cSSam Leffler 	return eap_sim_response_challenge(data, id);
97139beb93cSSam Leffler }
97239beb93cSSam Leffler 
97339beb93cSSam Leffler 
eap_sim_process_notification_reauth(struct eap_sim_data * data,struct eap_sim_attrs * attr)97439beb93cSSam Leffler static int eap_sim_process_notification_reauth(struct eap_sim_data *data,
97539beb93cSSam Leffler 					       struct eap_sim_attrs *attr)
97639beb93cSSam Leffler {
97739beb93cSSam Leffler 	struct eap_sim_attrs eattr;
97839beb93cSSam Leffler 	u8 *decrypted;
97939beb93cSSam Leffler 
98039beb93cSSam Leffler 	if (attr->encr_data == NULL || attr->iv == NULL) {
98139beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Notification message after "
98239beb93cSSam Leffler 			   "reauth did not include encrypted data");
98339beb93cSSam Leffler 		return -1;
98439beb93cSSam Leffler 	}
98539beb93cSSam Leffler 
98639beb93cSSam Leffler 	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
98739beb93cSSam Leffler 				       attr->encr_data_len, attr->iv, &eattr,
98839beb93cSSam Leffler 				       0);
98939beb93cSSam Leffler 	if (decrypted == NULL) {
99039beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
99139beb93cSSam Leffler 			   "data from notification message");
99239beb93cSSam Leffler 		return -1;
99339beb93cSSam Leffler 	}
99439beb93cSSam Leffler 
99539beb93cSSam Leffler 	if (eattr.counter < 0 || (size_t) eattr.counter != data->counter) {
99639beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Counter in notification "
99739beb93cSSam Leffler 			   "message does not match with counter in reauth "
99839beb93cSSam Leffler 			   "message");
99939beb93cSSam Leffler 		os_free(decrypted);
100039beb93cSSam Leffler 		return -1;
100139beb93cSSam Leffler 	}
100239beb93cSSam Leffler 
100339beb93cSSam Leffler 	os_free(decrypted);
100439beb93cSSam Leffler 	return 0;
100539beb93cSSam Leffler }
100639beb93cSSam Leffler 
100739beb93cSSam Leffler 
eap_sim_process_notification_auth(struct eap_sim_data * data,const struct wpabuf * reqData,struct eap_sim_attrs * attr)100839beb93cSSam Leffler static int eap_sim_process_notification_auth(struct eap_sim_data *data,
100939beb93cSSam Leffler 					     const struct wpabuf *reqData,
101039beb93cSSam Leffler 					     struct eap_sim_attrs *attr)
101139beb93cSSam Leffler {
101239beb93cSSam Leffler 	if (attr->mac == NULL) {
101339beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: no AT_MAC in after_auth "
101439beb93cSSam Leffler 			   "Notification message");
101539beb93cSSam Leffler 		return -1;
101639beb93cSSam Leffler 	}
101739beb93cSSam Leffler 
101839beb93cSSam Leffler 	if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0))
101939beb93cSSam Leffler 	{
102039beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Notification message "
102139beb93cSSam Leffler 			   "used invalid AT_MAC");
102239beb93cSSam Leffler 		return -1;
102339beb93cSSam Leffler 	}
102439beb93cSSam Leffler 
102539beb93cSSam Leffler 	if (data->reauth &&
102639beb93cSSam Leffler 	    eap_sim_process_notification_reauth(data, attr)) {
102739beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Invalid notification "
102839beb93cSSam Leffler 			   "message after reauth");
102939beb93cSSam Leffler 		return -1;
103039beb93cSSam Leffler 	}
103139beb93cSSam Leffler 
103239beb93cSSam Leffler 	return 0;
103339beb93cSSam Leffler }
103439beb93cSSam Leffler 
103539beb93cSSam Leffler 
eap_sim_process_notification(struct eap_sm * sm,struct eap_sim_data * data,u8 id,const struct wpabuf * reqData,struct eap_sim_attrs * attr)103639beb93cSSam Leffler static struct wpabuf * eap_sim_process_notification(
103739beb93cSSam Leffler 	struct eap_sm *sm, struct eap_sim_data *data, u8 id,
103839beb93cSSam Leffler 	const struct wpabuf *reqData, struct eap_sim_attrs *attr)
103939beb93cSSam Leffler {
104039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Notification");
104139beb93cSSam Leffler 	if (data->num_notification > 0) {
104239beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: too many notification "
104339beb93cSSam Leffler 			   "rounds (only one allowed)");
104439beb93cSSam Leffler 		return eap_sim_client_error(data, id,
104539beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
104639beb93cSSam Leffler 	}
104739beb93cSSam Leffler 	data->num_notification++;
104839beb93cSSam Leffler 	if (attr->notification == -1) {
104939beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: no AT_NOTIFICATION in "
105039beb93cSSam Leffler 			   "Notification message");
105139beb93cSSam Leffler 		return eap_sim_client_error(data, id,
105239beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
105339beb93cSSam Leffler 	}
105439beb93cSSam Leffler 
105539beb93cSSam Leffler 	if ((attr->notification & 0x4000) == 0 &&
105639beb93cSSam Leffler 	    eap_sim_process_notification_auth(data, reqData, attr)) {
105739beb93cSSam Leffler 		return eap_sim_client_error(data, id,
105839beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
105939beb93cSSam Leffler 	}
106039beb93cSSam Leffler 
106139beb93cSSam Leffler 	eap_sim_report_notification(sm->msg_ctx, attr->notification, 0);
106239beb93cSSam Leffler 	if (attr->notification >= 0 && attr->notification < 32768) {
106385732ac8SCy Schubert 		data->error_code = attr->notification;
106439beb93cSSam Leffler 		eap_sim_state(data, FAILURE);
106539beb93cSSam Leffler 	} else if (attr->notification == EAP_SIM_SUCCESS &&
106639beb93cSSam Leffler 		   data->state == RESULT_SUCCESS)
106739beb93cSSam Leffler 		eap_sim_state(data, SUCCESS);
106839beb93cSSam Leffler 	return eap_sim_response_notification(data, id, attr->notification);
106939beb93cSSam Leffler }
107039beb93cSSam Leffler 
107139beb93cSSam Leffler 
eap_sim_process_reauthentication(struct eap_sm * sm,struct eap_sim_data * data,u8 id,const struct wpabuf * reqData,struct eap_sim_attrs * attr)107239beb93cSSam Leffler static struct wpabuf * eap_sim_process_reauthentication(
107339beb93cSSam Leffler 	struct eap_sm *sm, struct eap_sim_data *data, u8 id,
107439beb93cSSam Leffler 	const struct wpabuf *reqData, struct eap_sim_attrs *attr)
107539beb93cSSam Leffler {
107639beb93cSSam Leffler 	struct eap_sim_attrs eattr;
107739beb93cSSam Leffler 	u8 *decrypted;
107839beb93cSSam Leffler 
107939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Reauthentication");
108039beb93cSSam Leffler 
108139beb93cSSam Leffler 	if (data->reauth_id == NULL) {
108239beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Server is trying "
108339beb93cSSam Leffler 			   "reauthentication, but no reauth_id available");
108439beb93cSSam Leffler 		return eap_sim_client_error(data, id,
108539beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
108639beb93cSSam Leffler 	}
108739beb93cSSam Leffler 
108839beb93cSSam Leffler 	data->reauth = 1;
108939beb93cSSam Leffler 	if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0))
109039beb93cSSam Leffler 	{
109139beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
109239beb93cSSam Leffler 			   "did not have valid AT_MAC");
1093206b73d0SCy Schubert #ifdef TEST_FUZZ
1094206b73d0SCy Schubert 		wpa_printf(MSG_INFO,
1095206b73d0SCy Schubert 			   "TEST: Ignore AT_MAC mismatch for fuzz testing");
1096206b73d0SCy Schubert #else /* TEST_FUZZ */
109739beb93cSSam Leffler 		return eap_sim_client_error(data, id,
109839beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
1099206b73d0SCy Schubert #endif /* TEST_FUZZ */
110039beb93cSSam Leffler 	}
110139beb93cSSam Leffler 
1102206b73d0SCy Schubert 	/* At this stage the received MAC has been verified. Use this MAC for
1103206b73d0SCy Schubert 	 * reauth Session-Id calculation if all other checks pass.
1104206b73d0SCy Schubert 	 * The peer does not use the local MAC but the received MAC in deriving
1105206b73d0SCy Schubert 	 * Session-Id. */
1106206b73d0SCy Schubert #ifdef TEST_FUZZ
1107206b73d0SCy Schubert 	if (attr->mac)
1108206b73d0SCy Schubert 		os_memcpy(data->reauth_mac, attr->mac, EAP_SIM_MAC_LEN);
1109206b73d0SCy Schubert 	else
1110206b73d0SCy Schubert 		os_memset(data->reauth_mac, 0x12, EAP_SIM_MAC_LEN);
1111206b73d0SCy Schubert #else /* TEST_FUZZ */
1112206b73d0SCy Schubert 	os_memcpy(data->reauth_mac, attr->mac, EAP_SIM_MAC_LEN);
1113206b73d0SCy Schubert #endif /* TEST_FUZZ */
1114206b73d0SCy Schubert 	wpa_hexdump(MSG_DEBUG, "EAP-SIM: Server MAC",
1115206b73d0SCy Schubert 		    data->reauth_mac, EAP_SIM_MAC_LEN);
1116206b73d0SCy Schubert 
111739beb93cSSam Leffler 	if (attr->encr_data == NULL || attr->iv == NULL) {
111839beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
111939beb93cSSam Leffler 			   "message did not include encrypted data");
112039beb93cSSam Leffler 		return eap_sim_client_error(data, id,
112139beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
112239beb93cSSam Leffler 	}
112339beb93cSSam Leffler 
112439beb93cSSam Leffler 	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
112539beb93cSSam Leffler 				       attr->encr_data_len, attr->iv, &eattr,
112639beb93cSSam Leffler 				       0);
112739beb93cSSam Leffler 	if (decrypted == NULL) {
112839beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
112939beb93cSSam Leffler 			   "data from reauthentication message");
113039beb93cSSam Leffler 		return eap_sim_client_error(data, id,
113139beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
113239beb93cSSam Leffler 	}
113339beb93cSSam Leffler 
113439beb93cSSam Leffler 	if (eattr.nonce_s == NULL || eattr.counter < 0) {
113539beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: (encr) No%s%s in reauth packet",
113639beb93cSSam Leffler 			   !eattr.nonce_s ? " AT_NONCE_S" : "",
113739beb93cSSam Leffler 			   eattr.counter < 0 ? " AT_COUNTER" : "");
113839beb93cSSam Leffler 		os_free(decrypted);
113939beb93cSSam Leffler 		return eap_sim_client_error(data, id,
114039beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
114139beb93cSSam Leffler 	}
114239beb93cSSam Leffler 
114339beb93cSSam Leffler 	if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) {
11445b9c547cSRui Paulo 		struct wpabuf *res;
114539beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid counter "
114639beb93cSSam Leffler 			   "(%d <= %d)", eattr.counter, data->counter);
114739beb93cSSam Leffler 		data->counter_too_small = eattr.counter;
11485b9c547cSRui Paulo 
114939beb93cSSam Leffler 		/* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
115039beb93cSSam Leffler 		 * reauth_id must not be used to start a new reauthentication.
1151*a90b9d01SCy Schubert 		 */
1152*a90b9d01SCy Schubert 		eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID);
11535b9c547cSRui Paulo 
11545b9c547cSRui Paulo 		res = eap_sim_response_reauth(data, id, 1, eattr.nonce_s);
115539beb93cSSam Leffler 		os_free(decrypted);
11565b9c547cSRui Paulo 
11575b9c547cSRui Paulo 		return res;
115839beb93cSSam Leffler 	}
115939beb93cSSam Leffler 	data->counter = eattr.counter;
116039beb93cSSam Leffler 
116139beb93cSSam Leffler 	os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN);
116239beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-SIM: (encr) AT_NONCE_S",
116339beb93cSSam Leffler 		    data->nonce_s, EAP_SIM_NONCE_S_LEN);
116439beb93cSSam Leffler 
116539beb93cSSam Leffler 	eap_sim_derive_keys_reauth(data->counter,
116639beb93cSSam Leffler 				   data->reauth_id, data->reauth_id_len,
116739beb93cSSam Leffler 				   data->nonce_s, data->mk, data->msk,
116839beb93cSSam Leffler 				   data->emsk);
1169*a90b9d01SCy Schubert 	eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID);
1170f05cddf9SRui Paulo 	eap_sim_learn_ids(sm, data, &eattr);
117139beb93cSSam Leffler 
117239beb93cSSam Leffler 	if (data->result_ind && attr->result_ind)
117339beb93cSSam Leffler 		data->use_result_ind = 1;
117439beb93cSSam Leffler 
11755b9c547cSRui Paulo 	if (data->state != FAILURE) {
117639beb93cSSam Leffler 		eap_sim_state(data, data->use_result_ind ?
117739beb93cSSam Leffler 			      RESULT_SUCCESS : SUCCESS);
117839beb93cSSam Leffler 	}
117939beb93cSSam Leffler 
118039beb93cSSam Leffler 	data->num_id_req = 0;
118139beb93cSSam Leffler 	data->num_notification = 0;
118239beb93cSSam Leffler 	if (data->counter > EAP_SIM_MAX_FAST_REAUTHS) {
118339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM: Maximum number of "
118439beb93cSSam Leffler 			   "fast reauths performed - force fullauth");
1185*a90b9d01SCy Schubert 		eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID);
118639beb93cSSam Leffler 	}
118739beb93cSSam Leffler 	os_free(decrypted);
1188f05cddf9SRui Paulo 	return eap_sim_response_reauth(data, id, 0, data->nonce_s);
118939beb93cSSam Leffler }
119039beb93cSSam Leffler 
119139beb93cSSam Leffler 
eap_sim_process(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)119239beb93cSSam Leffler static struct wpabuf * eap_sim_process(struct eap_sm *sm, void *priv,
119339beb93cSSam Leffler 				       struct eap_method_ret *ret,
119439beb93cSSam Leffler 				       const struct wpabuf *reqData)
119539beb93cSSam Leffler {
119639beb93cSSam Leffler 	struct eap_sim_data *data = priv;
119739beb93cSSam Leffler 	const struct eap_hdr *req;
119839beb93cSSam Leffler 	u8 subtype, id;
119939beb93cSSam Leffler 	struct wpabuf *res;
120039beb93cSSam Leffler 	const u8 *pos;
120139beb93cSSam Leffler 	struct eap_sim_attrs attr;
120239beb93cSSam Leffler 	size_t len;
120339beb93cSSam Leffler 
120439beb93cSSam Leffler 	wpa_hexdump_buf(MSG_DEBUG, "EAP-SIM: EAP data", reqData);
120539beb93cSSam Leffler 	if (eap_get_config_identity(sm, &len) == NULL) {
120639beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: Identity not configured");
120739beb93cSSam Leffler 		eap_sm_request_identity(sm);
1208c1d255d3SCy Schubert 		ret->ignore = true;
120939beb93cSSam Leffler 		return NULL;
121039beb93cSSam Leffler 	}
121139beb93cSSam Leffler 
121239beb93cSSam Leffler 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, reqData, &len);
1213325151a3SRui Paulo 	if (pos == NULL || len < 3) {
1214c1d255d3SCy Schubert 		ret->ignore = true;
121539beb93cSSam Leffler 		return NULL;
121639beb93cSSam Leffler 	}
121739beb93cSSam Leffler 	req = wpabuf_head(reqData);
121839beb93cSSam Leffler 	id = req->identifier;
121939beb93cSSam Leffler 	len = be_to_host16(req->length);
122039beb93cSSam Leffler 
1221c1d255d3SCy Schubert 	ret->ignore = false;
122239beb93cSSam Leffler 	ret->methodState = METHOD_MAY_CONT;
122339beb93cSSam Leffler 	ret->decision = DECISION_FAIL;
1224c1d255d3SCy Schubert 	ret->allowNotifications = true;
122539beb93cSSam Leffler 
122639beb93cSSam Leffler 	subtype = *pos++;
122739beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: Subtype=%d", subtype);
122839beb93cSSam Leffler 	pos += 2; /* Reserved */
122939beb93cSSam Leffler 
123039beb93cSSam Leffler 	if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr, 0,
123139beb93cSSam Leffler 			       0)) {
123239beb93cSSam Leffler 		res = eap_sim_client_error(data, id,
123339beb93cSSam Leffler 					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
123439beb93cSSam Leffler 		goto done;
123539beb93cSSam Leffler 	}
123639beb93cSSam Leffler 
123739beb93cSSam Leffler 	switch (subtype) {
123839beb93cSSam Leffler 	case EAP_SIM_SUBTYPE_START:
123939beb93cSSam Leffler 		res = eap_sim_process_start(sm, data, id, &attr);
124039beb93cSSam Leffler 		break;
124139beb93cSSam Leffler 	case EAP_SIM_SUBTYPE_CHALLENGE:
124239beb93cSSam Leffler 		res = eap_sim_process_challenge(sm, data, id, reqData, &attr);
124339beb93cSSam Leffler 		break;
124439beb93cSSam Leffler 	case EAP_SIM_SUBTYPE_NOTIFICATION:
124539beb93cSSam Leffler 		res = eap_sim_process_notification(sm, data, id, reqData,
124639beb93cSSam Leffler 						   &attr);
124739beb93cSSam Leffler 		break;
124839beb93cSSam Leffler 	case EAP_SIM_SUBTYPE_REAUTHENTICATION:
124939beb93cSSam Leffler 		res = eap_sim_process_reauthentication(sm, data, id, reqData,
125039beb93cSSam Leffler 						       &attr);
125139beb93cSSam Leffler 		break;
125239beb93cSSam Leffler 	case EAP_SIM_SUBTYPE_CLIENT_ERROR:
125339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Client-Error");
125439beb93cSSam Leffler 		res = eap_sim_client_error(data, id,
125539beb93cSSam Leffler 					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
125639beb93cSSam Leffler 		break;
125739beb93cSSam Leffler 	default:
125839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown subtype=%d", subtype);
125939beb93cSSam Leffler 		res = eap_sim_client_error(data, id,
126039beb93cSSam Leffler 					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
126139beb93cSSam Leffler 		break;
126239beb93cSSam Leffler 	}
126339beb93cSSam Leffler 
126439beb93cSSam Leffler done:
126539beb93cSSam Leffler 	if (data->state == FAILURE) {
126639beb93cSSam Leffler 		ret->decision = DECISION_FAIL;
126739beb93cSSam Leffler 		ret->methodState = METHOD_DONE;
126839beb93cSSam Leffler 	} else if (data->state == SUCCESS) {
126939beb93cSSam Leffler 		ret->decision = data->use_result_ind ?
127039beb93cSSam Leffler 			DECISION_UNCOND_SUCC : DECISION_COND_SUCC;
127139beb93cSSam Leffler 		ret->methodState = data->use_result_ind ?
127239beb93cSSam Leffler 			METHOD_DONE : METHOD_MAY_CONT;
12735b9c547cSRui Paulo 	} else if (data->state == RESULT_SUCCESS)
127439beb93cSSam Leffler 		ret->methodState = METHOD_CONT;
127539beb93cSSam Leffler 
127639beb93cSSam Leffler 	if (ret->methodState == METHOD_DONE) {
1277c1d255d3SCy Schubert 		ret->allowNotifications = false;
127839beb93cSSam Leffler 	}
127939beb93cSSam Leffler 
128039beb93cSSam Leffler 	return res;
128139beb93cSSam Leffler }
128239beb93cSSam Leffler 
128339beb93cSSam Leffler 
eap_sim_has_reauth_data(struct eap_sm * sm,void * priv)1284c1d255d3SCy Schubert static bool eap_sim_has_reauth_data(struct eap_sm *sm, void *priv)
128539beb93cSSam Leffler {
128639beb93cSSam Leffler 	struct eap_sim_data *data = priv;
128739beb93cSSam Leffler 	return data->pseudonym || data->reauth_id;
128839beb93cSSam Leffler }
128939beb93cSSam Leffler 
129039beb93cSSam Leffler 
eap_sim_deinit_for_reauth(struct eap_sm * sm,void * priv)129139beb93cSSam Leffler static void eap_sim_deinit_for_reauth(struct eap_sm *sm, void *priv)
129239beb93cSSam Leffler {
129339beb93cSSam Leffler 	struct eap_sim_data *data = priv;
1294*a90b9d01SCy Schubert 
1295*a90b9d01SCy Schubert 	os_free(data->mk_identity);
1296*a90b9d01SCy Schubert 	data->mk_identity = NULL;
1297*a90b9d01SCy Schubert 	data->mk_identity_len = 0;
129839beb93cSSam Leffler 	data->use_result_ind = 0;
12995b9c547cSRui Paulo 	eap_sim_clear_keys(data, 1);
130039beb93cSSam Leffler }
130139beb93cSSam Leffler 
130239beb93cSSam Leffler 
eap_sim_init_for_reauth(struct eap_sm * sm,void * priv)130339beb93cSSam Leffler static void * eap_sim_init_for_reauth(struct eap_sm *sm, void *priv)
130439beb93cSSam Leffler {
130539beb93cSSam Leffler 	struct eap_sim_data *data = priv;
1306f05cddf9SRui Paulo 	if (random_get_bytes(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
130739beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data "
130839beb93cSSam Leffler 			   "for NONCE_MT");
1309780fb4a2SCy Schubert 		eap_sim_deinit(sm, data);
131039beb93cSSam Leffler 		return NULL;
131139beb93cSSam Leffler 	}
1312*a90b9d01SCy Schubert 
1313*a90b9d01SCy Schubert 	if (sm->identity) {
1314*a90b9d01SCy Schubert 		/* Use the EAP-Response/Identity in MK derivation if AT_IDENTITY
1315*a90b9d01SCy Schubert 		 * is not used. */
1316*a90b9d01SCy Schubert 		os_free(data->mk_identity);
1317*a90b9d01SCy Schubert 		data->mk_identity = os_memdup(sm->identity, sm->identity_len);
1318*a90b9d01SCy Schubert 		data->mk_identity_len = sm->identity_len;
1319*a90b9d01SCy Schubert 	}
1320*a90b9d01SCy Schubert 
132139beb93cSSam Leffler 	data->num_id_req = 0;
132239beb93cSSam Leffler 	data->num_notification = 0;
132339beb93cSSam Leffler 	eap_sim_state(data, CONTINUE);
132439beb93cSSam Leffler 	return priv;
132539beb93cSSam Leffler }
132639beb93cSSam Leffler 
132739beb93cSSam Leffler 
eap_sim_get_identity(struct eap_sm * sm,void * priv,size_t * len)132839beb93cSSam Leffler static const u8 * eap_sim_get_identity(struct eap_sm *sm, void *priv,
132939beb93cSSam Leffler 				       size_t *len)
133039beb93cSSam Leffler {
133139beb93cSSam Leffler 	struct eap_sim_data *data = priv;
133239beb93cSSam Leffler 
133339beb93cSSam Leffler 	if (data->reauth_id) {
133439beb93cSSam Leffler 		*len = data->reauth_id_len;
133539beb93cSSam Leffler 		return data->reauth_id;
133639beb93cSSam Leffler 	}
133739beb93cSSam Leffler 
133839beb93cSSam Leffler 	if (data->pseudonym) {
133939beb93cSSam Leffler 		*len = data->pseudonym_len;
134039beb93cSSam Leffler 		return data->pseudonym;
134139beb93cSSam Leffler 	}
134239beb93cSSam Leffler 
134339beb93cSSam Leffler 	return NULL;
134439beb93cSSam Leffler }
134539beb93cSSam Leffler 
134639beb93cSSam Leffler 
eap_sim_isKeyAvailable(struct eap_sm * sm,void * priv)1347c1d255d3SCy Schubert static bool eap_sim_isKeyAvailable(struct eap_sm *sm, void *priv)
134839beb93cSSam Leffler {
134939beb93cSSam Leffler 	struct eap_sim_data *data = priv;
135039beb93cSSam Leffler 	return data->state == SUCCESS;
135139beb93cSSam Leffler }
135239beb93cSSam Leffler 
135339beb93cSSam Leffler 
eap_sim_getKey(struct eap_sm * sm,void * priv,size_t * len)135439beb93cSSam Leffler static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
135539beb93cSSam Leffler {
135639beb93cSSam Leffler 	struct eap_sim_data *data = priv;
135739beb93cSSam Leffler 	u8 *key;
135839beb93cSSam Leffler 
135939beb93cSSam Leffler 	if (data->state != SUCCESS)
136039beb93cSSam Leffler 		return NULL;
136139beb93cSSam Leffler 
136285732ac8SCy Schubert 	key = os_memdup(data->msk, EAP_SIM_KEYING_DATA_LEN);
136339beb93cSSam Leffler 	if (key == NULL)
136439beb93cSSam Leffler 		return NULL;
136539beb93cSSam Leffler 
136639beb93cSSam Leffler 	*len = EAP_SIM_KEYING_DATA_LEN;
136739beb93cSSam Leffler 
136839beb93cSSam Leffler 	return key;
136939beb93cSSam Leffler }
137039beb93cSSam Leffler 
137139beb93cSSam Leffler 
eap_sim_get_session_id(struct eap_sm * sm,void * priv,size_t * len)13725b9c547cSRui Paulo static u8 * eap_sim_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
13735b9c547cSRui Paulo {
13745b9c547cSRui Paulo 	struct eap_sim_data *data = priv;
13755b9c547cSRui Paulo 	u8 *id;
13765b9c547cSRui Paulo 
13775b9c547cSRui Paulo 	if (data->state != SUCCESS)
13785b9c547cSRui Paulo 		return NULL;
13795b9c547cSRui Paulo 
1380206b73d0SCy Schubert 	if (!data->reauth)
13815b9c547cSRui Paulo 		*len = 1 + data->num_chal * GSM_RAND_LEN + EAP_SIM_NONCE_MT_LEN;
1382206b73d0SCy Schubert 	else
1383206b73d0SCy Schubert 		*len = 1 + EAP_SIM_NONCE_S_LEN + EAP_SIM_MAC_LEN;
13845b9c547cSRui Paulo 	id = os_malloc(*len);
13855b9c547cSRui Paulo 	if (id == NULL)
13865b9c547cSRui Paulo 		return NULL;
13875b9c547cSRui Paulo 
13885b9c547cSRui Paulo 	id[0] = EAP_TYPE_SIM;
1389206b73d0SCy Schubert 	if (!data->reauth) {
13905b9c547cSRui Paulo 		os_memcpy(id + 1, data->rand, data->num_chal * GSM_RAND_LEN);
1391206b73d0SCy Schubert 		os_memcpy(id + 1 + data->num_chal * GSM_RAND_LEN,
1392206b73d0SCy Schubert 			  data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
1393206b73d0SCy Schubert 	} else {
1394206b73d0SCy Schubert 		os_memcpy(id + 1, data->nonce_s, EAP_SIM_NONCE_S_LEN);
1395206b73d0SCy Schubert 		os_memcpy(id + 1 + EAP_SIM_NONCE_S_LEN, data->reauth_mac,
1396206b73d0SCy Schubert 			  EAP_SIM_MAC_LEN);
1397206b73d0SCy Schubert 	}
13985b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "EAP-SIM: Derived Session-Id", id, *len);
13995b9c547cSRui Paulo 
14005b9c547cSRui Paulo 	return id;
14015b9c547cSRui Paulo }
14025b9c547cSRui Paulo 
14035b9c547cSRui Paulo 
eap_sim_get_emsk(struct eap_sm * sm,void * priv,size_t * len)140439beb93cSSam Leffler static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
140539beb93cSSam Leffler {
140639beb93cSSam Leffler 	struct eap_sim_data *data = priv;
140739beb93cSSam Leffler 	u8 *key;
140839beb93cSSam Leffler 
140939beb93cSSam Leffler 	if (data->state != SUCCESS)
141039beb93cSSam Leffler 		return NULL;
141139beb93cSSam Leffler 
141285732ac8SCy Schubert 	key = os_memdup(data->emsk, EAP_EMSK_LEN);
141339beb93cSSam Leffler 	if (key == NULL)
141439beb93cSSam Leffler 		return NULL;
141539beb93cSSam Leffler 
141639beb93cSSam Leffler 	*len = EAP_EMSK_LEN;
141739beb93cSSam Leffler 
141839beb93cSSam Leffler 	return key;
141939beb93cSSam Leffler }
142039beb93cSSam Leffler 
142139beb93cSSam Leffler 
eap_sim_get_error_code(void * priv)142285732ac8SCy Schubert static int eap_sim_get_error_code(void *priv)
142385732ac8SCy Schubert {
142485732ac8SCy Schubert 	struct eap_sim_data *data = priv;
142585732ac8SCy Schubert 	int current_data_error;
142685732ac8SCy Schubert 
142785732ac8SCy Schubert 	if (!data)
142885732ac8SCy Schubert 		return NO_EAP_METHOD_ERROR;
142985732ac8SCy Schubert 
143085732ac8SCy Schubert 	current_data_error = data->error_code;
143185732ac8SCy Schubert 
143285732ac8SCy Schubert 	/* Now reset for next transaction */
143385732ac8SCy Schubert 	data->error_code = NO_EAP_METHOD_ERROR;
143485732ac8SCy Schubert 
143585732ac8SCy Schubert 	return current_data_error;
143685732ac8SCy Schubert }
143785732ac8SCy Schubert 
143885732ac8SCy Schubert 
eap_peer_sim_register(void)143939beb93cSSam Leffler int eap_peer_sim_register(void)
144039beb93cSSam Leffler {
144139beb93cSSam Leffler 	struct eap_method *eap;
144239beb93cSSam Leffler 
144339beb93cSSam Leffler 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
144439beb93cSSam Leffler 				    EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM");
144539beb93cSSam Leffler 	if (eap == NULL)
144639beb93cSSam Leffler 		return -1;
144739beb93cSSam Leffler 
144839beb93cSSam Leffler 	eap->init = eap_sim_init;
144939beb93cSSam Leffler 	eap->deinit = eap_sim_deinit;
145039beb93cSSam Leffler 	eap->process = eap_sim_process;
145139beb93cSSam Leffler 	eap->isKeyAvailable = eap_sim_isKeyAvailable;
145239beb93cSSam Leffler 	eap->getKey = eap_sim_getKey;
14535b9c547cSRui Paulo 	eap->getSessionId = eap_sim_get_session_id;
145439beb93cSSam Leffler 	eap->has_reauth_data = eap_sim_has_reauth_data;
145539beb93cSSam Leffler 	eap->deinit_for_reauth = eap_sim_deinit_for_reauth;
145639beb93cSSam Leffler 	eap->init_for_reauth = eap_sim_init_for_reauth;
145739beb93cSSam Leffler 	eap->get_identity = eap_sim_get_identity;
145839beb93cSSam Leffler 	eap->get_emsk = eap_sim_get_emsk;
145985732ac8SCy Schubert 	eap->get_error_code = eap_sim_get_error_code;
146039beb93cSSam Leffler 
1461780fb4a2SCy Schubert 	return eap_peer_method_register(eap);
146239beb93cSSam Leffler }
1463