xref: /freebsd/contrib/wpa/src/eap_peer/eap_sim.c (revision c1d255d3ffdbe447de3ab875bf4e7d7accc5bfc5)
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];
35206b73d0SCy Schubert 	u8 reauth_mac[EAP_SIM_MAC_LEN];
3639beb93cSSam Leffler 
3739beb93cSSam Leffler 	int num_id_req, num_notification;
3839beb93cSSam Leffler 	u8 *pseudonym;
3939beb93cSSam Leffler 	size_t pseudonym_len;
4039beb93cSSam Leffler 	u8 *reauth_id;
4139beb93cSSam Leffler 	size_t reauth_id_len;
4239beb93cSSam Leffler 	int reauth;
4339beb93cSSam Leffler 	unsigned int counter, counter_too_small;
4439beb93cSSam Leffler 	u8 *last_eap_identity;
4539beb93cSSam Leffler 	size_t last_eap_identity_len;
4639beb93cSSam Leffler 	enum {
47*c1d255d3SCy Schubert 		CONTINUE, START_DONE, RESULT_SUCCESS, SUCCESS, FAILURE
4839beb93cSSam Leffler 	} state;
4939beb93cSSam Leffler 	int result_ind, use_result_ind;
5085732ac8SCy Schubert 	int use_pseudonym;
5185732ac8SCy Schubert 	int error_code;
5239beb93cSSam Leffler };
5339beb93cSSam Leffler 
5439beb93cSSam Leffler 
5539beb93cSSam Leffler #ifndef CONFIG_NO_STDOUT_DEBUG
5639beb93cSSam Leffler static const char * eap_sim_state_txt(int state)
5739beb93cSSam Leffler {
5839beb93cSSam Leffler 	switch (state) {
5939beb93cSSam Leffler 	case CONTINUE:
6039beb93cSSam Leffler 		return "CONTINUE";
61*c1d255d3SCy Schubert 	case START_DONE:
62*c1d255d3SCy Schubert 		return "START_DONE";
6339beb93cSSam Leffler 	case RESULT_SUCCESS:
6439beb93cSSam Leffler 		return "RESULT_SUCCESS";
6539beb93cSSam Leffler 	case SUCCESS:
6639beb93cSSam Leffler 		return "SUCCESS";
6739beb93cSSam Leffler 	case FAILURE:
6839beb93cSSam Leffler 		return "FAILURE";
6939beb93cSSam Leffler 	default:
7039beb93cSSam Leffler 		return "?";
7139beb93cSSam Leffler 	}
7239beb93cSSam Leffler }
7339beb93cSSam Leffler #endif /* CONFIG_NO_STDOUT_DEBUG */
7439beb93cSSam Leffler 
7539beb93cSSam Leffler 
7639beb93cSSam Leffler static void eap_sim_state(struct eap_sim_data *data, int state)
7739beb93cSSam Leffler {
7839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s",
7939beb93cSSam Leffler 		   eap_sim_state_txt(data->state),
8039beb93cSSam Leffler 		   eap_sim_state_txt(state));
8139beb93cSSam Leffler 	data->state = state;
8239beb93cSSam Leffler }
8339beb93cSSam Leffler 
8439beb93cSSam Leffler 
8539beb93cSSam Leffler static void * eap_sim_init(struct eap_sm *sm)
8639beb93cSSam Leffler {
8739beb93cSSam Leffler 	struct eap_sim_data *data;
8839beb93cSSam Leffler 	struct eap_peer_config *config = eap_get_config(sm);
8939beb93cSSam Leffler 
9039beb93cSSam Leffler 	data = os_zalloc(sizeof(*data));
9139beb93cSSam Leffler 	if (data == NULL)
9239beb93cSSam Leffler 		return NULL;
9339beb93cSSam Leffler 
94f05cddf9SRui Paulo 	if (random_get_bytes(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
9539beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data "
9639beb93cSSam Leffler 			   "for NONCE_MT");
9739beb93cSSam Leffler 		os_free(data);
9839beb93cSSam Leffler 		return NULL;
9939beb93cSSam Leffler 	}
10039beb93cSSam Leffler 
10185732ac8SCy Schubert 	/* Zero is a valid error code, so we need to initialize */
10285732ac8SCy Schubert 	data->error_code = NO_EAP_METHOD_ERROR;
10385732ac8SCy Schubert 
10439beb93cSSam Leffler 	data->min_num_chal = 2;
10539beb93cSSam Leffler 	if (config && config->phase1) {
10639beb93cSSam Leffler 		char *pos = os_strstr(config->phase1, "sim_min_num_chal=");
10739beb93cSSam Leffler 		if (pos) {
10839beb93cSSam Leffler 			data->min_num_chal = atoi(pos + 17);
10939beb93cSSam Leffler 			if (data->min_num_chal < 2 || data->min_num_chal > 3) {
11039beb93cSSam Leffler 				wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
11139beb93cSSam Leffler 					   "sim_min_num_chal configuration "
11239beb93cSSam Leffler 					   "(%lu, expected 2 or 3)",
11339beb93cSSam Leffler 					   (unsigned long) data->min_num_chal);
11439beb93cSSam Leffler 				os_free(data);
11539beb93cSSam Leffler 				return NULL;
11639beb93cSSam Leffler 			}
11739beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-SIM: Set minimum number of "
11839beb93cSSam Leffler 				   "challenges to %lu",
11939beb93cSSam Leffler 				   (unsigned long) data->min_num_chal);
12039beb93cSSam Leffler 		}
12139beb93cSSam Leffler 
12239beb93cSSam Leffler 		data->result_ind = os_strstr(config->phase1, "result_ind=1") !=
12339beb93cSSam Leffler 			NULL;
12439beb93cSSam Leffler 	}
12539beb93cSSam Leffler 
12685732ac8SCy Schubert 	data->use_pseudonym = !sm->init_phase2;
12785732ac8SCy Schubert 	if (config && config->anonymous_identity && data->use_pseudonym) {
128f05cddf9SRui Paulo 		data->pseudonym = os_malloc(config->anonymous_identity_len);
129f05cddf9SRui Paulo 		if (data->pseudonym) {
130f05cddf9SRui Paulo 			os_memcpy(data->pseudonym, config->anonymous_identity,
131f05cddf9SRui Paulo 				  config->anonymous_identity_len);
132f05cddf9SRui Paulo 			data->pseudonym_len = config->anonymous_identity_len;
133f05cddf9SRui Paulo 		}
134f05cddf9SRui Paulo 	}
135f05cddf9SRui Paulo 
13639beb93cSSam Leffler 	eap_sim_state(data, CONTINUE);
13739beb93cSSam Leffler 
13839beb93cSSam Leffler 	return data;
13939beb93cSSam Leffler }
14039beb93cSSam Leffler 
14139beb93cSSam Leffler 
1425b9c547cSRui Paulo static void eap_sim_clear_keys(struct eap_sim_data *data, int reauth)
1435b9c547cSRui Paulo {
1445b9c547cSRui Paulo 	if (!reauth) {
1455b9c547cSRui Paulo 		os_memset(data->mk, 0, EAP_SIM_MK_LEN);
1465b9c547cSRui Paulo 		os_memset(data->k_aut, 0, EAP_SIM_K_AUT_LEN);
1475b9c547cSRui Paulo 		os_memset(data->k_encr, 0, EAP_SIM_K_ENCR_LEN);
1485b9c547cSRui Paulo 	}
1495b9c547cSRui Paulo 	os_memset(data->kc, 0, 3 * EAP_SIM_KC_LEN);
1505b9c547cSRui Paulo 	os_memset(data->sres, 0, 3 * EAP_SIM_SRES_LEN);
1515b9c547cSRui Paulo 	os_memset(data->msk, 0, EAP_SIM_KEYING_DATA_LEN);
1525b9c547cSRui Paulo 	os_memset(data->emsk, 0, EAP_EMSK_LEN);
1535b9c547cSRui Paulo }
1545b9c547cSRui Paulo 
1555b9c547cSRui Paulo 
15639beb93cSSam Leffler static void eap_sim_deinit(struct eap_sm *sm, void *priv)
15739beb93cSSam Leffler {
15839beb93cSSam Leffler 	struct eap_sim_data *data = priv;
15939beb93cSSam Leffler 	if (data) {
16039beb93cSSam Leffler 		os_free(data->ver_list);
16139beb93cSSam Leffler 		os_free(data->pseudonym);
16239beb93cSSam Leffler 		os_free(data->reauth_id);
16339beb93cSSam Leffler 		os_free(data->last_eap_identity);
1645b9c547cSRui Paulo 		eap_sim_clear_keys(data, 0);
16539beb93cSSam Leffler 		os_free(data);
16639beb93cSSam Leffler 	}
16739beb93cSSam Leffler }
16839beb93cSSam Leffler 
16939beb93cSSam Leffler 
1705b9c547cSRui Paulo static int eap_sim_ext_sim_req(struct eap_sm *sm, struct eap_sim_data *data)
1715b9c547cSRui Paulo {
1725b9c547cSRui Paulo 	char req[200], *pos, *end;
1735b9c547cSRui Paulo 	size_t i;
1745b9c547cSRui Paulo 
1755b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "EAP-SIM: Use external SIM processing");
1765b9c547cSRui Paulo 	pos = req;
1775b9c547cSRui Paulo 	end = pos + sizeof(req);
1785b9c547cSRui Paulo 	pos += os_snprintf(pos, end - pos, "GSM-AUTH");
1795b9c547cSRui Paulo 	for (i = 0; i < data->num_chal; i++) {
1805b9c547cSRui Paulo 		pos += os_snprintf(pos, end - pos, ":");
1815b9c547cSRui Paulo 		pos += wpa_snprintf_hex(pos, end - pos, data->rand[i],
1825b9c547cSRui Paulo 					GSM_RAND_LEN);
1835b9c547cSRui Paulo 	}
1845b9c547cSRui Paulo 
1855b9c547cSRui Paulo 	eap_sm_request_sim(sm, req);
1865b9c547cSRui Paulo 	return 1;
1875b9c547cSRui Paulo }
1885b9c547cSRui Paulo 
1895b9c547cSRui Paulo 
1905b9c547cSRui Paulo static int eap_sim_ext_sim_result(struct eap_sm *sm, struct eap_sim_data *data,
1915b9c547cSRui Paulo 				  struct eap_peer_config *conf)
1925b9c547cSRui Paulo {
1935b9c547cSRui Paulo 	char *resp, *pos;
1945b9c547cSRui Paulo 	size_t i;
1955b9c547cSRui Paulo 
1965b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG,
1975b9c547cSRui Paulo 		   "EAP-SIM: Use result from external SIM processing");
1985b9c547cSRui Paulo 
1995b9c547cSRui Paulo 	resp = conf->external_sim_resp;
2005b9c547cSRui Paulo 	conf->external_sim_resp = NULL;
2015b9c547cSRui Paulo 
2025b9c547cSRui Paulo 	if (os_strncmp(resp, "GSM-AUTH:", 9) != 0) {
2035b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized external SIM processing response");
2045b9c547cSRui Paulo 		os_free(resp);
2055b9c547cSRui Paulo 		return -1;
2065b9c547cSRui Paulo 	}
2075b9c547cSRui Paulo 
2085b9c547cSRui Paulo 	pos = resp + 9;
2095b9c547cSRui Paulo 	for (i = 0; i < data->num_chal; i++) {
2105b9c547cSRui Paulo 		wpa_hexdump(MSG_DEBUG, "EAP-SIM: RAND",
2115b9c547cSRui Paulo 			    data->rand[i], GSM_RAND_LEN);
2125b9c547cSRui Paulo 
2135b9c547cSRui Paulo 		if (hexstr2bin(pos, data->kc[i], EAP_SIM_KC_LEN) < 0)
2145b9c547cSRui Paulo 			goto invalid;
2155b9c547cSRui Paulo 		wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: Kc",
2165b9c547cSRui Paulo 				data->kc[i], EAP_SIM_KC_LEN);
2175b9c547cSRui Paulo 		pos += EAP_SIM_KC_LEN * 2;
2185b9c547cSRui Paulo 		if (*pos != ':')
2195b9c547cSRui Paulo 			goto invalid;
2205b9c547cSRui Paulo 		pos++;
2215b9c547cSRui Paulo 
2225b9c547cSRui Paulo 		if (hexstr2bin(pos, data->sres[i], EAP_SIM_SRES_LEN) < 0)
2235b9c547cSRui Paulo 			goto invalid;
2245b9c547cSRui Paulo 		wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: SRES",
2255b9c547cSRui Paulo 				data->sres[i], EAP_SIM_SRES_LEN);
2265b9c547cSRui Paulo 		pos += EAP_SIM_SRES_LEN * 2;
2275b9c547cSRui Paulo 		if (i + 1 < data->num_chal) {
2285b9c547cSRui Paulo 			if (*pos != ':')
2295b9c547cSRui Paulo 				goto invalid;
2305b9c547cSRui Paulo 			pos++;
2315b9c547cSRui Paulo 		}
2325b9c547cSRui Paulo 	}
2335b9c547cSRui Paulo 
2345b9c547cSRui Paulo 	os_free(resp);
2355b9c547cSRui Paulo 	return 0;
2365b9c547cSRui Paulo 
2375b9c547cSRui Paulo invalid:
2385b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "EAP-SIM: Invalid external SIM processing GSM-AUTH response");
2395b9c547cSRui Paulo 	os_free(resp);
2405b9c547cSRui Paulo 	return -1;
2415b9c547cSRui Paulo }
2425b9c547cSRui Paulo 
2435b9c547cSRui Paulo 
24439beb93cSSam Leffler static int eap_sim_gsm_auth(struct eap_sm *sm, struct eap_sim_data *data)
24539beb93cSSam Leffler {
24639beb93cSSam Leffler 	struct eap_peer_config *conf;
24739beb93cSSam Leffler 
24839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication algorithm");
24939beb93cSSam Leffler 
25039beb93cSSam Leffler 	conf = eap_get_config(sm);
25139beb93cSSam Leffler 	if (conf == NULL)
25239beb93cSSam Leffler 		return -1;
2535b9c547cSRui Paulo 
2545b9c547cSRui Paulo 	if (sm->external_sim) {
2555b9c547cSRui Paulo 		if (conf->external_sim_resp)
2565b9c547cSRui Paulo 			return eap_sim_ext_sim_result(sm, data, conf);
2575b9c547cSRui Paulo 		else
2585b9c547cSRui Paulo 			return eap_sim_ext_sim_req(sm, data);
2595b9c547cSRui Paulo 	}
2605b9c547cSRui Paulo 
261780fb4a2SCy Schubert #ifdef PCSC_FUNCS
26239beb93cSSam Leffler 	if (conf->pcsc) {
26339beb93cSSam Leffler 		if (scard_gsm_auth(sm->scard_ctx, data->rand[0],
26439beb93cSSam Leffler 				   data->sres[0], data->kc[0]) ||
26539beb93cSSam Leffler 		    scard_gsm_auth(sm->scard_ctx, data->rand[1],
26639beb93cSSam Leffler 				   data->sres[1], data->kc[1]) ||
26739beb93cSSam Leffler 		    (data->num_chal > 2 &&
26839beb93cSSam Leffler 		     scard_gsm_auth(sm->scard_ctx, data->rand[2],
26939beb93cSSam Leffler 				    data->sres[2], data->kc[2]))) {
27039beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-SIM: GSM SIM "
27139beb93cSSam Leffler 				   "authentication could not be completed");
27239beb93cSSam Leffler 			return -1;
27339beb93cSSam Leffler 		}
27439beb93cSSam Leffler 		return 0;
27539beb93cSSam Leffler 	}
276780fb4a2SCy Schubert #endif /* PCSC_FUNCS */
27739beb93cSSam Leffler 
27839beb93cSSam Leffler #ifdef CONFIG_SIM_SIMULATOR
27939beb93cSSam Leffler 	if (conf->password) {
28039beb93cSSam Leffler 		u8 opc[16], k[16];
28139beb93cSSam Leffler 		const char *pos;
28239beb93cSSam Leffler 		size_t i;
28339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM: Use internal GSM-Milenage "
28439beb93cSSam Leffler 			   "implementation for authentication");
28539beb93cSSam Leffler 		if (conf->password_len < 65) {
28639beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-SIM: invalid GSM-Milenage "
28739beb93cSSam Leffler 				   "password");
28839beb93cSSam Leffler 			return -1;
28939beb93cSSam Leffler 		}
29039beb93cSSam Leffler 		pos = (const char *) conf->password;
29139beb93cSSam Leffler 		if (hexstr2bin(pos, k, 16))
29239beb93cSSam Leffler 			return -1;
29339beb93cSSam Leffler 		pos += 32;
29439beb93cSSam Leffler 		if (*pos != ':')
29539beb93cSSam Leffler 			return -1;
29639beb93cSSam Leffler 		pos++;
29739beb93cSSam Leffler 
29839beb93cSSam Leffler 		if (hexstr2bin(pos, opc, 16))
29939beb93cSSam Leffler 			return -1;
30039beb93cSSam Leffler 
30139beb93cSSam Leffler 		for (i = 0; i < data->num_chal; i++) {
30239beb93cSSam Leffler 			if (gsm_milenage(opc, k, data->rand[i],
30339beb93cSSam Leffler 					 data->sres[i], data->kc[i])) {
30439beb93cSSam Leffler 				wpa_printf(MSG_DEBUG, "EAP-SIM: "
30539beb93cSSam Leffler 					   "GSM-Milenage authentication "
30639beb93cSSam Leffler 					   "could not be completed");
30739beb93cSSam Leffler 				return -1;
30839beb93cSSam Leffler 			}
30939beb93cSSam Leffler 			wpa_hexdump(MSG_DEBUG, "EAP-SIM: RAND",
31039beb93cSSam Leffler 				    data->rand[i], GSM_RAND_LEN);
31139beb93cSSam Leffler 			wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: SRES",
31239beb93cSSam Leffler 					data->sres[i], EAP_SIM_SRES_LEN);
31339beb93cSSam Leffler 			wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: Kc",
31439beb93cSSam Leffler 					data->kc[i], EAP_SIM_KC_LEN);
31539beb93cSSam Leffler 		}
31639beb93cSSam Leffler 		return 0;
31739beb93cSSam Leffler 	}
31839beb93cSSam Leffler #endif /* CONFIG_SIM_SIMULATOR */
31939beb93cSSam Leffler 
32039beb93cSSam Leffler #ifdef CONFIG_SIM_HARDCODED
32139beb93cSSam Leffler 	/* These hardcoded Kc and SRES values are used for testing. RAND to
32239beb93cSSam Leffler 	 * KC/SREC mapping is very bogus as far as real authentication is
32339beb93cSSam Leffler 	 * concerned, but it is quite useful for cases where the AS is rotating
32439beb93cSSam Leffler 	 * the order of pre-configured values. */
32539beb93cSSam Leffler 	{
32639beb93cSSam Leffler 		size_t i;
32739beb93cSSam Leffler 
32839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM: Use hardcoded Kc and SRES "
32939beb93cSSam Leffler 			   "values for testing");
33039beb93cSSam Leffler 
33139beb93cSSam Leffler 		for (i = 0; i < data->num_chal; i++) {
33239beb93cSSam Leffler 			if (data->rand[i][0] == 0xaa) {
33339beb93cSSam Leffler 				os_memcpy(data->kc[i],
33439beb93cSSam Leffler 					  "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7",
33539beb93cSSam Leffler 					  EAP_SIM_KC_LEN);
33639beb93cSSam Leffler 				os_memcpy(data->sres[i], "\xd1\xd2\xd3\xd4",
33739beb93cSSam Leffler 					  EAP_SIM_SRES_LEN);
33839beb93cSSam Leffler 			} else if (data->rand[i][0] == 0xbb) {
33939beb93cSSam Leffler 				os_memcpy(data->kc[i],
34039beb93cSSam Leffler 					  "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7",
34139beb93cSSam Leffler 					  EAP_SIM_KC_LEN);
34239beb93cSSam Leffler 				os_memcpy(data->sres[i], "\xe1\xe2\xe3\xe4",
34339beb93cSSam Leffler 					  EAP_SIM_SRES_LEN);
34439beb93cSSam Leffler 			} else {
34539beb93cSSam Leffler 				os_memcpy(data->kc[i],
34639beb93cSSam Leffler 					  "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7",
34739beb93cSSam Leffler 					  EAP_SIM_KC_LEN);
34839beb93cSSam Leffler 				os_memcpy(data->sres[i], "\xf1\xf2\xf3\xf4",
34939beb93cSSam Leffler 					  EAP_SIM_SRES_LEN);
35039beb93cSSam Leffler 			}
35139beb93cSSam Leffler 		}
35239beb93cSSam Leffler 	}
35339beb93cSSam Leffler 
35439beb93cSSam Leffler 	return 0;
35539beb93cSSam Leffler 
35639beb93cSSam Leffler #else /* CONFIG_SIM_HARDCODED */
35739beb93cSSam Leffler 
35839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: No GSM authentication algorithm "
35939beb93cSSam Leffler 		   "enabled");
36039beb93cSSam Leffler 	return -1;
36139beb93cSSam Leffler 
36239beb93cSSam Leffler #endif /* CONFIG_SIM_HARDCODED */
36339beb93cSSam Leffler }
36439beb93cSSam Leffler 
36539beb93cSSam Leffler 
36639beb93cSSam Leffler static int eap_sim_supported_ver(int version)
36739beb93cSSam Leffler {
36839beb93cSSam Leffler 	return version == EAP_SIM_VERSION;
36939beb93cSSam Leffler }
37039beb93cSSam Leffler 
37139beb93cSSam Leffler 
37239beb93cSSam Leffler #define CLEAR_PSEUDONYM	0x01
37339beb93cSSam Leffler #define CLEAR_REAUTH_ID	0x02
37439beb93cSSam Leffler #define CLEAR_EAP_ID	0x04
37539beb93cSSam Leffler 
376f05cddf9SRui Paulo static void eap_sim_clear_identities(struct eap_sm *sm,
377f05cddf9SRui Paulo 				     struct eap_sim_data *data, int id)
37839beb93cSSam Leffler {
379f05cddf9SRui Paulo 	if ((id & CLEAR_PSEUDONYM) && data->pseudonym) {
380f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old pseudonym");
38139beb93cSSam Leffler 		os_free(data->pseudonym);
38239beb93cSSam Leffler 		data->pseudonym = NULL;
38339beb93cSSam Leffler 		data->pseudonym_len = 0;
38485732ac8SCy Schubert 		if (data->use_pseudonym)
385f05cddf9SRui Paulo 			eap_set_anon_id(sm, NULL, 0);
38639beb93cSSam Leffler 	}
387f05cddf9SRui Paulo 	if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
388f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old reauth_id");
38939beb93cSSam Leffler 		os_free(data->reauth_id);
39039beb93cSSam Leffler 		data->reauth_id = NULL;
39139beb93cSSam Leffler 		data->reauth_id_len = 0;
39239beb93cSSam Leffler 	}
393f05cddf9SRui Paulo 	if ((id & CLEAR_EAP_ID) && data->last_eap_identity) {
394f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old eap_id");
39539beb93cSSam Leffler 		os_free(data->last_eap_identity);
39639beb93cSSam Leffler 		data->last_eap_identity = NULL;
39739beb93cSSam Leffler 		data->last_eap_identity_len = 0;
39839beb93cSSam Leffler 	}
39939beb93cSSam Leffler }
40039beb93cSSam Leffler 
40139beb93cSSam Leffler 
402f05cddf9SRui Paulo static int eap_sim_learn_ids(struct eap_sm *sm, struct eap_sim_data *data,
40339beb93cSSam Leffler 			     struct eap_sim_attrs *attr)
40439beb93cSSam Leffler {
40539beb93cSSam Leffler 	if (attr->next_pseudonym) {
406f05cddf9SRui Paulo 		const u8 *identity = NULL;
407f05cddf9SRui Paulo 		size_t identity_len = 0;
408f05cddf9SRui Paulo 		const u8 *realm = NULL;
409f05cddf9SRui Paulo 		size_t realm_len = 0;
410f05cddf9SRui Paulo 
411f05cddf9SRui Paulo 		wpa_hexdump_ascii(MSG_DEBUG,
412f05cddf9SRui Paulo 				  "EAP-SIM: (encr) AT_NEXT_PSEUDONYM",
413f05cddf9SRui Paulo 				  attr->next_pseudonym,
414f05cddf9SRui Paulo 				  attr->next_pseudonym_len);
41539beb93cSSam Leffler 		os_free(data->pseudonym);
416f05cddf9SRui Paulo 		/* Look for the realm of the permanent identity */
417f05cddf9SRui Paulo 		identity = eap_get_config_identity(sm, &identity_len);
418f05cddf9SRui Paulo 		if (identity) {
419f05cddf9SRui Paulo 			for (realm = identity, realm_len = identity_len;
420f05cddf9SRui Paulo 			     realm_len > 0; realm_len--, realm++) {
421f05cddf9SRui Paulo 				if (*realm == '@')
422f05cddf9SRui Paulo 					break;
423f05cddf9SRui Paulo 			}
424f05cddf9SRui Paulo 		}
425f05cddf9SRui Paulo 		data->pseudonym = os_malloc(attr->next_pseudonym_len +
426f05cddf9SRui Paulo 					    realm_len);
42739beb93cSSam Leffler 		if (data->pseudonym == NULL) {
42839beb93cSSam Leffler 			wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for "
42939beb93cSSam Leffler 				   "next pseudonym");
430f05cddf9SRui Paulo 			data->pseudonym_len = 0;
43139beb93cSSam Leffler 			return -1;
43239beb93cSSam Leffler 		}
43339beb93cSSam Leffler 		os_memcpy(data->pseudonym, attr->next_pseudonym,
43439beb93cSSam Leffler 			  attr->next_pseudonym_len);
435f05cddf9SRui Paulo 		if (realm_len) {
436f05cddf9SRui Paulo 			os_memcpy(data->pseudonym + attr->next_pseudonym_len,
437f05cddf9SRui Paulo 				  realm, realm_len);
438f05cddf9SRui Paulo 		}
439f05cddf9SRui Paulo 		data->pseudonym_len = attr->next_pseudonym_len + realm_len;
44085732ac8SCy Schubert 		if (data->use_pseudonym)
44185732ac8SCy Schubert 			eap_set_anon_id(sm, data->pseudonym,
44285732ac8SCy Schubert 					data->pseudonym_len);
44339beb93cSSam Leffler 	}
44439beb93cSSam Leffler 
44539beb93cSSam Leffler 	if (attr->next_reauth_id) {
44639beb93cSSam Leffler 		os_free(data->reauth_id);
44785732ac8SCy Schubert 		data->reauth_id = os_memdup(attr->next_reauth_id,
44885732ac8SCy Schubert 					    attr->next_reauth_id_len);
44939beb93cSSam Leffler 		if (data->reauth_id == NULL) {
45039beb93cSSam Leffler 			wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for "
45139beb93cSSam Leffler 				   "next reauth_id");
452f05cddf9SRui Paulo 			data->reauth_id_len = 0;
45339beb93cSSam Leffler 			return -1;
45439beb93cSSam Leffler 		}
45539beb93cSSam Leffler 		data->reauth_id_len = attr->next_reauth_id_len;
45639beb93cSSam Leffler 		wpa_hexdump_ascii(MSG_DEBUG,
45739beb93cSSam Leffler 				  "EAP-SIM: (encr) AT_NEXT_REAUTH_ID",
45839beb93cSSam Leffler 				  data->reauth_id,
45939beb93cSSam Leffler 				  data->reauth_id_len);
46039beb93cSSam Leffler 	}
46139beb93cSSam Leffler 
46239beb93cSSam Leffler 	return 0;
46339beb93cSSam Leffler }
46439beb93cSSam Leffler 
46539beb93cSSam Leffler 
46639beb93cSSam Leffler static struct wpabuf * eap_sim_client_error(struct eap_sim_data *data, u8 id,
46739beb93cSSam Leffler 					    int err)
46839beb93cSSam Leffler {
46939beb93cSSam Leffler 	struct eap_sim_msg *msg;
47039beb93cSSam Leffler 
47139beb93cSSam Leffler 	eap_sim_state(data, FAILURE);
47239beb93cSSam Leffler 	data->num_id_req = 0;
47339beb93cSSam Leffler 	data->num_notification = 0;
47439beb93cSSam Leffler 
475f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "EAP-SIM: Send Client-Error (error code %d)",
476f05cddf9SRui Paulo 		   err);
47739beb93cSSam Leffler 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
47839beb93cSSam Leffler 			       EAP_SIM_SUBTYPE_CLIENT_ERROR);
47939beb93cSSam Leffler 	eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
4805b9c547cSRui Paulo 	return eap_sim_msg_finish(msg, EAP_TYPE_SIM, NULL, NULL, 0);
48139beb93cSSam Leffler }
48239beb93cSSam Leffler 
48339beb93cSSam Leffler 
48439beb93cSSam Leffler static struct wpabuf * eap_sim_response_start(struct eap_sm *sm,
48539beb93cSSam Leffler 					      struct eap_sim_data *data, u8 id,
48639beb93cSSam Leffler 					      enum eap_sim_id_req id_req)
48739beb93cSSam Leffler {
48839beb93cSSam Leffler 	const u8 *identity = NULL;
48939beb93cSSam Leffler 	size_t identity_len = 0;
49039beb93cSSam Leffler 	struct eap_sim_msg *msg;
491*c1d255d3SCy Schubert 	struct wpabuf *resp;
49239beb93cSSam Leffler 
49339beb93cSSam Leffler 	data->reauth = 0;
49439beb93cSSam Leffler 	if (id_req == ANY_ID && data->reauth_id) {
49539beb93cSSam Leffler 		identity = data->reauth_id;
49639beb93cSSam Leffler 		identity_len = data->reauth_id_len;
49739beb93cSSam Leffler 		data->reauth = 1;
49839beb93cSSam Leffler 	} else if ((id_req == ANY_ID || id_req == FULLAUTH_ID) &&
499206b73d0SCy Schubert 		   data->pseudonym &&
500206b73d0SCy Schubert 		   !eap_sim_anonymous_username(data->pseudonym,
501206b73d0SCy Schubert 					       data->pseudonym_len)) {
50239beb93cSSam Leffler 		identity = data->pseudonym;
50339beb93cSSam Leffler 		identity_len = data->pseudonym_len;
504f05cddf9SRui Paulo 		eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID);
50539beb93cSSam Leffler 	} else if (id_req != NO_ID_REQ) {
50639beb93cSSam Leffler 		identity = eap_get_config_identity(sm, &identity_len);
50739beb93cSSam Leffler 		if (identity) {
508206b73d0SCy Schubert 			int ids = CLEAR_PSEUDONYM | CLEAR_REAUTH_ID;
509206b73d0SCy Schubert 
510206b73d0SCy Schubert 			if (data->pseudonym &&
511206b73d0SCy Schubert 			    eap_sim_anonymous_username(data->pseudonym,
512206b73d0SCy Schubert 						       data->pseudonym_len))
513206b73d0SCy Schubert 				ids &= ~CLEAR_PSEUDONYM;
514206b73d0SCy Schubert 			eap_sim_clear_identities(sm, data, ids);
51539beb93cSSam Leffler 		}
51639beb93cSSam Leffler 	}
51739beb93cSSam Leffler 	if (id_req != NO_ID_REQ)
518f05cddf9SRui Paulo 		eap_sim_clear_identities(sm, data, CLEAR_EAP_ID);
51939beb93cSSam Leffler 
52039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Start (id=%d)", id);
52139beb93cSSam Leffler 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id,
52239beb93cSSam Leffler 			       EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START);
523*c1d255d3SCy Schubert 	if (identity) {
524*c1d255d3SCy Schubert 		wpa_hexdump_ascii(MSG_DEBUG, "   AT_IDENTITY",
525*c1d255d3SCy Schubert 				  identity, identity_len);
526*c1d255d3SCy Schubert 		eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
527*c1d255d3SCy Schubert 				identity, identity_len);
528*c1d255d3SCy Schubert 	}
52939beb93cSSam Leffler 	if (!data->reauth) {
53039beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "   AT_NONCE_MT",
53139beb93cSSam Leffler 			    data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
53239beb93cSSam Leffler 		eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_MT, 0,
53339beb93cSSam Leffler 				data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
53439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   AT_SELECTED_VERSION %d",
53539beb93cSSam Leffler 			   data->selected_version);
53639beb93cSSam Leffler 		eap_sim_msg_add(msg, EAP_SIM_AT_SELECTED_VERSION,
53739beb93cSSam Leffler 				data->selected_version, NULL, 0);
53839beb93cSSam Leffler 	}
53939beb93cSSam Leffler 
540*c1d255d3SCy Schubert 	resp = eap_sim_msg_finish(msg, EAP_TYPE_SIM, NULL, NULL, 0);
541*c1d255d3SCy Schubert 	if (resp)
542*c1d255d3SCy Schubert 		eap_sim_state(data, START_DONE);
543*c1d255d3SCy Schubert 	return resp;
54439beb93cSSam Leffler }
54539beb93cSSam Leffler 
54639beb93cSSam Leffler 
54739beb93cSSam Leffler static struct wpabuf * eap_sim_response_challenge(struct eap_sim_data *data,
54839beb93cSSam Leffler 						  u8 id)
54939beb93cSSam Leffler {
55039beb93cSSam Leffler 	struct eap_sim_msg *msg;
55139beb93cSSam Leffler 
55239beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Challenge (id=%d)", id);
55339beb93cSSam Leffler 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
55439beb93cSSam Leffler 			       EAP_SIM_SUBTYPE_CHALLENGE);
55539beb93cSSam Leffler 	if (data->use_result_ind) {
55639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
55739beb93cSSam Leffler 		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
55839beb93cSSam Leffler 	}
55939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "   AT_MAC");
56039beb93cSSam Leffler 	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
5615b9c547cSRui Paulo 	return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut,
5625b9c547cSRui Paulo 				  (u8 *) data->sres,
56339beb93cSSam Leffler 				  data->num_chal * EAP_SIM_SRES_LEN);
56439beb93cSSam Leffler }
56539beb93cSSam Leffler 
56639beb93cSSam Leffler 
56739beb93cSSam Leffler static struct wpabuf * eap_sim_response_reauth(struct eap_sim_data *data,
568f05cddf9SRui Paulo 					       u8 id, int counter_too_small,
569f05cddf9SRui Paulo 					       const u8 *nonce_s)
57039beb93cSSam Leffler {
57139beb93cSSam Leffler 	struct eap_sim_msg *msg;
57239beb93cSSam Leffler 	unsigned int counter;
57339beb93cSSam Leffler 
57439beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Reauthentication (id=%d)",
57539beb93cSSam Leffler 		   id);
57639beb93cSSam Leffler 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
57739beb93cSSam Leffler 			       EAP_SIM_SUBTYPE_REAUTHENTICATION);
57839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "   AT_IV");
57939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
58039beb93cSSam Leffler 	eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
58139beb93cSSam Leffler 
58239beb93cSSam Leffler 	if (counter_too_small) {
58339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   *AT_COUNTER_TOO_SMALL");
58439beb93cSSam Leffler 		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER_TOO_SMALL, 0, NULL, 0);
58539beb93cSSam Leffler 		counter = data->counter_too_small;
58639beb93cSSam Leffler 	} else
58739beb93cSSam Leffler 		counter = data->counter;
58839beb93cSSam Leffler 
58939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", counter);
59039beb93cSSam Leffler 	eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
59139beb93cSSam Leffler 
59239beb93cSSam Leffler 	if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
59339beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
59439beb93cSSam Leffler 			   "AT_ENCR_DATA");
59539beb93cSSam Leffler 		eap_sim_msg_free(msg);
59639beb93cSSam Leffler 		return NULL;
59739beb93cSSam Leffler 	}
59839beb93cSSam Leffler 	if (data->use_result_ind) {
59939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
60039beb93cSSam Leffler 		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
60139beb93cSSam Leffler 	}
60239beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "   AT_MAC");
60339beb93cSSam Leffler 	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
6045b9c547cSRui Paulo 	return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut, nonce_s,
60539beb93cSSam Leffler 				  EAP_SIM_NONCE_S_LEN);
60639beb93cSSam Leffler }
60739beb93cSSam Leffler 
60839beb93cSSam Leffler 
60939beb93cSSam Leffler static struct wpabuf * eap_sim_response_notification(struct eap_sim_data *data,
61039beb93cSSam Leffler 						     u8 id, u16 notification)
61139beb93cSSam Leffler {
61239beb93cSSam Leffler 	struct eap_sim_msg *msg;
61339beb93cSSam Leffler 	u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL;
61439beb93cSSam Leffler 
61539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Notification (id=%d)", id);
61639beb93cSSam Leffler 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id,
61739beb93cSSam Leffler 			       EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION);
61839beb93cSSam Leffler 	if (k_aut && data->reauth) {
61939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   AT_IV");
62039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
62139beb93cSSam Leffler 		eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
62239beb93cSSam Leffler 					   EAP_SIM_AT_ENCR_DATA);
62339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", data->counter);
62439beb93cSSam Leffler 		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
62539beb93cSSam Leffler 				NULL, 0);
62639beb93cSSam Leffler 		if (eap_sim_msg_add_encr_end(msg, data->k_encr,
62739beb93cSSam Leffler 					     EAP_SIM_AT_PADDING)) {
62839beb93cSSam Leffler 			wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
62939beb93cSSam Leffler 				   "AT_ENCR_DATA");
63039beb93cSSam Leffler 			eap_sim_msg_free(msg);
63139beb93cSSam Leffler 			return NULL;
63239beb93cSSam Leffler 		}
63339beb93cSSam Leffler 	}
63439beb93cSSam Leffler 	if (k_aut) {
63539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "   AT_MAC");
63639beb93cSSam Leffler 		eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
63739beb93cSSam Leffler 	}
6385b9c547cSRui Paulo 	return eap_sim_msg_finish(msg, EAP_TYPE_SIM, k_aut, (u8 *) "", 0);
63939beb93cSSam Leffler }
64039beb93cSSam Leffler 
64139beb93cSSam Leffler 
64239beb93cSSam Leffler static struct wpabuf * eap_sim_process_start(struct eap_sm *sm,
64339beb93cSSam Leffler 					     struct eap_sim_data *data, u8 id,
64439beb93cSSam Leffler 					     struct eap_sim_attrs *attr)
64539beb93cSSam Leffler {
64639beb93cSSam Leffler 	int selected_version = -1, id_error;
64739beb93cSSam Leffler 	size_t i;
64839beb93cSSam Leffler 	u8 *pos;
64939beb93cSSam Leffler 
65039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Start");
65139beb93cSSam Leffler 	if (attr->version_list == NULL) {
65239beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: No AT_VERSION_LIST in "
65339beb93cSSam Leffler 			   "SIM/Start");
65439beb93cSSam Leffler 		return eap_sim_client_error(data, id,
65539beb93cSSam Leffler 					    EAP_SIM_UNSUPPORTED_VERSION);
65639beb93cSSam Leffler 	}
65739beb93cSSam Leffler 
65839beb93cSSam Leffler 	os_free(data->ver_list);
65985732ac8SCy Schubert 	data->ver_list = os_memdup(attr->version_list, attr->version_list_len);
66039beb93cSSam Leffler 	if (data->ver_list == NULL) {
66139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to allocate "
66239beb93cSSam Leffler 			   "memory for version list");
66339beb93cSSam Leffler 		return eap_sim_client_error(data, id,
66439beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
66539beb93cSSam Leffler 	}
66639beb93cSSam Leffler 	data->ver_list_len = attr->version_list_len;
66739beb93cSSam Leffler 	pos = data->ver_list;
66839beb93cSSam Leffler 	for (i = 0; i < data->ver_list_len / 2; i++) {
66939beb93cSSam Leffler 		int ver = pos[0] * 256 + pos[1];
67039beb93cSSam Leffler 		pos += 2;
67139beb93cSSam Leffler 		if (eap_sim_supported_ver(ver)) {
67239beb93cSSam Leffler 			selected_version = ver;
67339beb93cSSam Leffler 			break;
67439beb93cSSam Leffler 		}
67539beb93cSSam Leffler 	}
67639beb93cSSam Leffler 	if (selected_version < 0) {
67739beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: Could not find a supported "
67839beb93cSSam Leffler 			   "version");
67939beb93cSSam Leffler 		return eap_sim_client_error(data, id,
68039beb93cSSam Leffler 					    EAP_SIM_UNSUPPORTED_VERSION);
68139beb93cSSam Leffler 	}
68239beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: Selected Version %d",
68339beb93cSSam Leffler 		   selected_version);
68439beb93cSSam Leffler 	data->selected_version = selected_version;
68539beb93cSSam Leffler 
68639beb93cSSam Leffler 	id_error = 0;
68739beb93cSSam Leffler 	switch (attr->id_req) {
68839beb93cSSam Leffler 	case NO_ID_REQ:
68939beb93cSSam Leffler 		break;
69039beb93cSSam Leffler 	case ANY_ID:
69139beb93cSSam Leffler 		if (data->num_id_req > 0)
69239beb93cSSam Leffler 			id_error++;
69339beb93cSSam Leffler 		data->num_id_req++;
69439beb93cSSam Leffler 		break;
69539beb93cSSam Leffler 	case FULLAUTH_ID:
69639beb93cSSam Leffler 		if (data->num_id_req > 1)
69739beb93cSSam Leffler 			id_error++;
69839beb93cSSam Leffler 		data->num_id_req++;
69939beb93cSSam Leffler 		break;
70039beb93cSSam Leffler 	case PERMANENT_ID:
70139beb93cSSam Leffler 		if (data->num_id_req > 2)
70239beb93cSSam Leffler 			id_error++;
70339beb93cSSam Leffler 		data->num_id_req++;
70439beb93cSSam Leffler 		break;
70539beb93cSSam Leffler 	}
70639beb93cSSam Leffler 	if (id_error) {
70739beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: Too many ID requests "
70839beb93cSSam Leffler 			   "used within one authentication");
70939beb93cSSam Leffler 		return eap_sim_client_error(data, id,
71039beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
71139beb93cSSam Leffler 	}
71239beb93cSSam Leffler 
71339beb93cSSam Leffler 	return eap_sim_response_start(sm, data, id, attr->id_req);
71439beb93cSSam Leffler }
71539beb93cSSam Leffler 
71639beb93cSSam Leffler 
71739beb93cSSam Leffler static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm,
71839beb93cSSam Leffler 						 struct eap_sim_data *data,
71939beb93cSSam Leffler 						 u8 id,
72039beb93cSSam Leffler 						 const struct wpabuf *reqData,
72139beb93cSSam Leffler 						 struct eap_sim_attrs *attr)
72239beb93cSSam Leffler {
72339beb93cSSam Leffler 	const u8 *identity;
72439beb93cSSam Leffler 	size_t identity_len;
72539beb93cSSam Leffler 	struct eap_sim_attrs eattr;
7265b9c547cSRui Paulo 	int res;
72739beb93cSSam Leffler 
72839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Challenge");
729*c1d255d3SCy Schubert 	if (data->state != START_DONE) {
730*c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
731*c1d255d3SCy Schubert 			   "EAP-SIM: Unexpected Challenge in state %s",
732*c1d255d3SCy Schubert 			   eap_sim_state_txt(data->state));
733*c1d255d3SCy Schubert 		return eap_sim_client_error(data, id,
734*c1d255d3SCy Schubert 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
735*c1d255d3SCy Schubert 	}
73639beb93cSSam Leffler 	data->reauth = 0;
73739beb93cSSam Leffler 	if (!attr->mac || !attr->rand) {
73839beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
73939beb93cSSam Leffler 			   "did not include%s%s",
74039beb93cSSam Leffler 			   !attr->mac ? " AT_MAC" : "",
74139beb93cSSam Leffler 			   !attr->rand ? " AT_RAND" : "");
74239beb93cSSam Leffler 		return eap_sim_client_error(data, id,
74339beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
74439beb93cSSam Leffler 	}
74539beb93cSSam Leffler 
74639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: %lu challenges",
74739beb93cSSam Leffler 		   (unsigned long) attr->num_chal);
74839beb93cSSam Leffler 	if (attr->num_chal < data->min_num_chal) {
74939beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: Insufficient number of "
75039beb93cSSam Leffler 			   "challenges (%lu)", (unsigned long) attr->num_chal);
75139beb93cSSam Leffler 		return eap_sim_client_error(data, id,
75239beb93cSSam Leffler 					    EAP_SIM_INSUFFICIENT_NUM_OF_CHAL);
75339beb93cSSam Leffler 	}
75439beb93cSSam Leffler 	if (attr->num_chal > 3) {
75539beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: Too many challenges "
75639beb93cSSam Leffler 			   "(%lu)", (unsigned long) attr->num_chal);
75739beb93cSSam Leffler 		return eap_sim_client_error(data, id,
75839beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
75939beb93cSSam Leffler 	}
76039beb93cSSam Leffler 
76139beb93cSSam Leffler 	/* Verify that RANDs are different */
76239beb93cSSam Leffler 	if (os_memcmp(attr->rand, attr->rand + GSM_RAND_LEN,
76339beb93cSSam Leffler 		   GSM_RAND_LEN) == 0 ||
76439beb93cSSam Leffler 	    (attr->num_chal > 2 &&
76539beb93cSSam Leffler 	     (os_memcmp(attr->rand, attr->rand + 2 * GSM_RAND_LEN,
76639beb93cSSam Leffler 			GSM_RAND_LEN) == 0 ||
76739beb93cSSam Leffler 	      os_memcmp(attr->rand + GSM_RAND_LEN,
76839beb93cSSam Leffler 			attr->rand + 2 * GSM_RAND_LEN,
76939beb93cSSam Leffler 			GSM_RAND_LEN) == 0))) {
77039beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: Same RAND used multiple times");
77139beb93cSSam Leffler 		return eap_sim_client_error(data, id,
77239beb93cSSam Leffler 					    EAP_SIM_RAND_NOT_FRESH);
77339beb93cSSam Leffler 	}
77439beb93cSSam Leffler 
77539beb93cSSam Leffler 	os_memcpy(data->rand, attr->rand, attr->num_chal * GSM_RAND_LEN);
77639beb93cSSam Leffler 	data->num_chal = attr->num_chal;
77739beb93cSSam Leffler 
7785b9c547cSRui Paulo 	res = eap_sim_gsm_auth(sm, data);
7795b9c547cSRui Paulo 	if (res > 0) {
7805b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-SIM: Wait for external SIM processing");
7815b9c547cSRui Paulo 		return NULL;
7825b9c547cSRui Paulo 	}
7835b9c547cSRui Paulo 	if (res) {
78439beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: GSM authentication failed");
78539beb93cSSam Leffler 		return eap_sim_client_error(data, id,
78639beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
78739beb93cSSam Leffler 	}
78839beb93cSSam Leffler 	if (data->last_eap_identity) {
78939beb93cSSam Leffler 		identity = data->last_eap_identity;
79039beb93cSSam Leffler 		identity_len = data->last_eap_identity_len;
791206b73d0SCy Schubert 	} else if (data->pseudonym &&
792206b73d0SCy Schubert 		   !eap_sim_anonymous_username(data->pseudonym,
793206b73d0SCy Schubert 					       data->pseudonym_len)) {
79439beb93cSSam Leffler 		identity = data->pseudonym;
79539beb93cSSam Leffler 		identity_len = data->pseudonym_len;
79685732ac8SCy Schubert 	} else {
79785732ac8SCy Schubert 		struct eap_peer_config *config;
79885732ac8SCy Schubert 
79985732ac8SCy Schubert 		config = eap_get_config(sm);
80085732ac8SCy Schubert 		if (config && config->imsi_identity) {
80185732ac8SCy Schubert 			identity = config->imsi_identity;
80285732ac8SCy Schubert 			identity_len = config->imsi_identity_len;
80385732ac8SCy Schubert 		} else {
80439beb93cSSam Leffler 			identity = eap_get_config_identity(sm, &identity_len);
80585732ac8SCy Schubert 		}
80685732ac8SCy Schubert 	}
80739beb93cSSam Leffler 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Selected identity for MK "
80839beb93cSSam Leffler 			  "derivation", identity, identity_len);
80939beb93cSSam Leffler 	eap_sim_derive_mk(identity, identity_len, data->nonce_mt,
81039beb93cSSam Leffler 			  data->selected_version, data->ver_list,
81139beb93cSSam Leffler 			  data->ver_list_len, data->num_chal,
81239beb93cSSam Leffler 			  (const u8 *) data->kc, data->mk);
81339beb93cSSam Leffler 	eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
81439beb93cSSam Leffler 			    data->emsk);
81539beb93cSSam Leffler 	if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, data->nonce_mt,
81639beb93cSSam Leffler 			       EAP_SIM_NONCE_MT_LEN)) {
81739beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
81839beb93cSSam Leffler 			   "used invalid AT_MAC");
819206b73d0SCy Schubert #ifdef TEST_FUZZ
820206b73d0SCy Schubert 		wpa_printf(MSG_INFO,
821206b73d0SCy Schubert 			   "TEST: Ignore AT_MAC mismatch for fuzz testing");
822206b73d0SCy Schubert #else /* TEST_FUZZ */
82339beb93cSSam Leffler 		return eap_sim_client_error(data, id,
82439beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
825206b73d0SCy Schubert #endif /* TEST_FUZZ */
82639beb93cSSam Leffler 	}
82739beb93cSSam Leffler 
828f05cddf9SRui Paulo 	/* Old reauthentication identity must not be used anymore. In
829f05cddf9SRui Paulo 	 * other words, if no new reauth identity is received, full
830f05cddf9SRui Paulo 	 * authentication will be used on next reauthentication (using
831f05cddf9SRui Paulo 	 * pseudonym identity or permanent identity). */
832f05cddf9SRui Paulo 	eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
83339beb93cSSam Leffler 
83439beb93cSSam Leffler 	if (attr->encr_data) {
83539beb93cSSam Leffler 		u8 *decrypted;
83639beb93cSSam Leffler 		decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
83739beb93cSSam Leffler 					       attr->encr_data_len, attr->iv,
83839beb93cSSam Leffler 					       &eattr, 0);
83939beb93cSSam Leffler 		if (decrypted == NULL) {
84039beb93cSSam Leffler 			return eap_sim_client_error(
84139beb93cSSam Leffler 				data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET);
84239beb93cSSam Leffler 		}
843f05cddf9SRui Paulo 		eap_sim_learn_ids(sm, data, &eattr);
84439beb93cSSam Leffler 		os_free(decrypted);
84539beb93cSSam Leffler 	}
84639beb93cSSam Leffler 
84739beb93cSSam Leffler 	if (data->result_ind && attr->result_ind)
84839beb93cSSam Leffler 		data->use_result_ind = 1;
84939beb93cSSam Leffler 
8505b9c547cSRui Paulo 	if (data->state != FAILURE) {
85139beb93cSSam Leffler 		eap_sim_state(data, data->use_result_ind ?
85239beb93cSSam Leffler 			      RESULT_SUCCESS : SUCCESS);
85339beb93cSSam Leffler 	}
85439beb93cSSam Leffler 
85539beb93cSSam Leffler 	data->num_id_req = 0;
85639beb93cSSam Leffler 	data->num_notification = 0;
85739beb93cSSam Leffler 	/* RFC 4186 specifies that counter is initialized to one after
85839beb93cSSam Leffler 	 * fullauth, but initializing it to zero makes it easier to implement
85939beb93cSSam Leffler 	 * reauth verification. */
86039beb93cSSam Leffler 	data->counter = 0;
86139beb93cSSam Leffler 	return eap_sim_response_challenge(data, id);
86239beb93cSSam Leffler }
86339beb93cSSam Leffler 
86439beb93cSSam Leffler 
86539beb93cSSam Leffler static int eap_sim_process_notification_reauth(struct eap_sim_data *data,
86639beb93cSSam Leffler 					       struct eap_sim_attrs *attr)
86739beb93cSSam Leffler {
86839beb93cSSam Leffler 	struct eap_sim_attrs eattr;
86939beb93cSSam Leffler 	u8 *decrypted;
87039beb93cSSam Leffler 
87139beb93cSSam Leffler 	if (attr->encr_data == NULL || attr->iv == NULL) {
87239beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Notification message after "
87339beb93cSSam Leffler 			   "reauth did not include encrypted data");
87439beb93cSSam Leffler 		return -1;
87539beb93cSSam Leffler 	}
87639beb93cSSam Leffler 
87739beb93cSSam Leffler 	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
87839beb93cSSam Leffler 				       attr->encr_data_len, attr->iv, &eattr,
87939beb93cSSam Leffler 				       0);
88039beb93cSSam Leffler 	if (decrypted == NULL) {
88139beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
88239beb93cSSam Leffler 			   "data from notification message");
88339beb93cSSam Leffler 		return -1;
88439beb93cSSam Leffler 	}
88539beb93cSSam Leffler 
88639beb93cSSam Leffler 	if (eattr.counter < 0 || (size_t) eattr.counter != data->counter) {
88739beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Counter in notification "
88839beb93cSSam Leffler 			   "message does not match with counter in reauth "
88939beb93cSSam Leffler 			   "message");
89039beb93cSSam Leffler 		os_free(decrypted);
89139beb93cSSam Leffler 		return -1;
89239beb93cSSam Leffler 	}
89339beb93cSSam Leffler 
89439beb93cSSam Leffler 	os_free(decrypted);
89539beb93cSSam Leffler 	return 0;
89639beb93cSSam Leffler }
89739beb93cSSam Leffler 
89839beb93cSSam Leffler 
89939beb93cSSam Leffler static int eap_sim_process_notification_auth(struct eap_sim_data *data,
90039beb93cSSam Leffler 					     const struct wpabuf *reqData,
90139beb93cSSam Leffler 					     struct eap_sim_attrs *attr)
90239beb93cSSam Leffler {
90339beb93cSSam Leffler 	if (attr->mac == NULL) {
90439beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: no AT_MAC in after_auth "
90539beb93cSSam Leffler 			   "Notification message");
90639beb93cSSam Leffler 		return -1;
90739beb93cSSam Leffler 	}
90839beb93cSSam Leffler 
90939beb93cSSam Leffler 	if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0))
91039beb93cSSam Leffler 	{
91139beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Notification message "
91239beb93cSSam Leffler 			   "used invalid AT_MAC");
91339beb93cSSam Leffler 		return -1;
91439beb93cSSam Leffler 	}
91539beb93cSSam Leffler 
91639beb93cSSam Leffler 	if (data->reauth &&
91739beb93cSSam Leffler 	    eap_sim_process_notification_reauth(data, attr)) {
91839beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Invalid notification "
91939beb93cSSam Leffler 			   "message after reauth");
92039beb93cSSam Leffler 		return -1;
92139beb93cSSam Leffler 	}
92239beb93cSSam Leffler 
92339beb93cSSam Leffler 	return 0;
92439beb93cSSam Leffler }
92539beb93cSSam Leffler 
92639beb93cSSam Leffler 
92739beb93cSSam Leffler static struct wpabuf * eap_sim_process_notification(
92839beb93cSSam Leffler 	struct eap_sm *sm, struct eap_sim_data *data, u8 id,
92939beb93cSSam Leffler 	const struct wpabuf *reqData, struct eap_sim_attrs *attr)
93039beb93cSSam Leffler {
93139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Notification");
93239beb93cSSam Leffler 	if (data->num_notification > 0) {
93339beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: too many notification "
93439beb93cSSam Leffler 			   "rounds (only one allowed)");
93539beb93cSSam Leffler 		return eap_sim_client_error(data, id,
93639beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
93739beb93cSSam Leffler 	}
93839beb93cSSam Leffler 	data->num_notification++;
93939beb93cSSam Leffler 	if (attr->notification == -1) {
94039beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: no AT_NOTIFICATION in "
94139beb93cSSam Leffler 			   "Notification message");
94239beb93cSSam Leffler 		return eap_sim_client_error(data, id,
94339beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
94439beb93cSSam Leffler 	}
94539beb93cSSam Leffler 
94639beb93cSSam Leffler 	if ((attr->notification & 0x4000) == 0 &&
94739beb93cSSam Leffler 	    eap_sim_process_notification_auth(data, reqData, attr)) {
94839beb93cSSam Leffler 		return eap_sim_client_error(data, id,
94939beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
95039beb93cSSam Leffler 	}
95139beb93cSSam Leffler 
95239beb93cSSam Leffler 	eap_sim_report_notification(sm->msg_ctx, attr->notification, 0);
95339beb93cSSam Leffler 	if (attr->notification >= 0 && attr->notification < 32768) {
95485732ac8SCy Schubert 		data->error_code = attr->notification;
95539beb93cSSam Leffler 		eap_sim_state(data, FAILURE);
95639beb93cSSam Leffler 	} else if (attr->notification == EAP_SIM_SUCCESS &&
95739beb93cSSam Leffler 		   data->state == RESULT_SUCCESS)
95839beb93cSSam Leffler 		eap_sim_state(data, SUCCESS);
95939beb93cSSam Leffler 	return eap_sim_response_notification(data, id, attr->notification);
96039beb93cSSam Leffler }
96139beb93cSSam Leffler 
96239beb93cSSam Leffler 
96339beb93cSSam Leffler static struct wpabuf * eap_sim_process_reauthentication(
96439beb93cSSam Leffler 	struct eap_sm *sm, struct eap_sim_data *data, u8 id,
96539beb93cSSam Leffler 	const struct wpabuf *reqData, struct eap_sim_attrs *attr)
96639beb93cSSam Leffler {
96739beb93cSSam Leffler 	struct eap_sim_attrs eattr;
96839beb93cSSam Leffler 	u8 *decrypted;
96939beb93cSSam Leffler 
97039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Reauthentication");
97139beb93cSSam Leffler 
97239beb93cSSam Leffler 	if (data->reauth_id == NULL) {
97339beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Server is trying "
97439beb93cSSam Leffler 			   "reauthentication, but no reauth_id available");
97539beb93cSSam Leffler 		return eap_sim_client_error(data, id,
97639beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
97739beb93cSSam Leffler 	}
97839beb93cSSam Leffler 
97939beb93cSSam Leffler 	data->reauth = 1;
98039beb93cSSam Leffler 	if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0))
98139beb93cSSam Leffler 	{
98239beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
98339beb93cSSam Leffler 			   "did not have valid AT_MAC");
984206b73d0SCy Schubert #ifdef TEST_FUZZ
985206b73d0SCy Schubert 		wpa_printf(MSG_INFO,
986206b73d0SCy Schubert 			   "TEST: Ignore AT_MAC mismatch for fuzz testing");
987206b73d0SCy Schubert #else /* TEST_FUZZ */
98839beb93cSSam Leffler 		return eap_sim_client_error(data, id,
98939beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
990206b73d0SCy Schubert #endif /* TEST_FUZZ */
99139beb93cSSam Leffler 	}
99239beb93cSSam Leffler 
993206b73d0SCy Schubert 	/* At this stage the received MAC has been verified. Use this MAC for
994206b73d0SCy Schubert 	 * reauth Session-Id calculation if all other checks pass.
995206b73d0SCy Schubert 	 * The peer does not use the local MAC but the received MAC in deriving
996206b73d0SCy Schubert 	 * Session-Id. */
997206b73d0SCy Schubert #ifdef TEST_FUZZ
998206b73d0SCy Schubert 	if (attr->mac)
999206b73d0SCy Schubert 		os_memcpy(data->reauth_mac, attr->mac, EAP_SIM_MAC_LEN);
1000206b73d0SCy Schubert 	else
1001206b73d0SCy Schubert 		os_memset(data->reauth_mac, 0x12, EAP_SIM_MAC_LEN);
1002206b73d0SCy Schubert #else /* TEST_FUZZ */
1003206b73d0SCy Schubert 	os_memcpy(data->reauth_mac, attr->mac, EAP_SIM_MAC_LEN);
1004206b73d0SCy Schubert #endif /* TEST_FUZZ */
1005206b73d0SCy Schubert 	wpa_hexdump(MSG_DEBUG, "EAP-SIM: Server MAC",
1006206b73d0SCy Schubert 		    data->reauth_mac, EAP_SIM_MAC_LEN);
1007206b73d0SCy Schubert 
100839beb93cSSam Leffler 	if (attr->encr_data == NULL || attr->iv == NULL) {
100939beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
101039beb93cSSam Leffler 			   "message did not include encrypted data");
101139beb93cSSam Leffler 		return eap_sim_client_error(data, id,
101239beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
101339beb93cSSam Leffler 	}
101439beb93cSSam Leffler 
101539beb93cSSam Leffler 	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
101639beb93cSSam Leffler 				       attr->encr_data_len, attr->iv, &eattr,
101739beb93cSSam Leffler 				       0);
101839beb93cSSam Leffler 	if (decrypted == NULL) {
101939beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
102039beb93cSSam Leffler 			   "data from reauthentication message");
102139beb93cSSam Leffler 		return eap_sim_client_error(data, id,
102239beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
102339beb93cSSam Leffler 	}
102439beb93cSSam Leffler 
102539beb93cSSam Leffler 	if (eattr.nonce_s == NULL || eattr.counter < 0) {
102639beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: (encr) No%s%s in reauth packet",
102739beb93cSSam Leffler 			   !eattr.nonce_s ? " AT_NONCE_S" : "",
102839beb93cSSam Leffler 			   eattr.counter < 0 ? " AT_COUNTER" : "");
102939beb93cSSam Leffler 		os_free(decrypted);
103039beb93cSSam Leffler 		return eap_sim_client_error(data, id,
103139beb93cSSam Leffler 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
103239beb93cSSam Leffler 	}
103339beb93cSSam Leffler 
103439beb93cSSam Leffler 	if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) {
10355b9c547cSRui Paulo 		struct wpabuf *res;
103639beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid counter "
103739beb93cSSam Leffler 			   "(%d <= %d)", eattr.counter, data->counter);
103839beb93cSSam Leffler 		data->counter_too_small = eattr.counter;
10395b9c547cSRui Paulo 
104039beb93cSSam Leffler 		/* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
104139beb93cSSam Leffler 		 * reauth_id must not be used to start a new reauthentication.
104239beb93cSSam Leffler 		 * However, since it was used in the last EAP-Response-Identity
104339beb93cSSam Leffler 		 * packet, it has to saved for the following fullauth to be
104439beb93cSSam Leffler 		 * used in MK derivation. */
104539beb93cSSam Leffler 		os_free(data->last_eap_identity);
104639beb93cSSam Leffler 		data->last_eap_identity = data->reauth_id;
104739beb93cSSam Leffler 		data->last_eap_identity_len = data->reauth_id_len;
104839beb93cSSam Leffler 		data->reauth_id = NULL;
104939beb93cSSam Leffler 		data->reauth_id_len = 0;
10505b9c547cSRui Paulo 
10515b9c547cSRui Paulo 		res = eap_sim_response_reauth(data, id, 1, eattr.nonce_s);
105239beb93cSSam Leffler 		os_free(decrypted);
10535b9c547cSRui Paulo 
10545b9c547cSRui Paulo 		return res;
105539beb93cSSam Leffler 	}
105639beb93cSSam Leffler 	data->counter = eattr.counter;
105739beb93cSSam Leffler 
105839beb93cSSam Leffler 	os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN);
105939beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-SIM: (encr) AT_NONCE_S",
106039beb93cSSam Leffler 		    data->nonce_s, EAP_SIM_NONCE_S_LEN);
106139beb93cSSam Leffler 
106239beb93cSSam Leffler 	eap_sim_derive_keys_reauth(data->counter,
106339beb93cSSam Leffler 				   data->reauth_id, data->reauth_id_len,
106439beb93cSSam Leffler 				   data->nonce_s, data->mk, data->msk,
106539beb93cSSam Leffler 				   data->emsk);
1066f05cddf9SRui Paulo 	eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
1067f05cddf9SRui Paulo 	eap_sim_learn_ids(sm, data, &eattr);
106839beb93cSSam Leffler 
106939beb93cSSam Leffler 	if (data->result_ind && attr->result_ind)
107039beb93cSSam Leffler 		data->use_result_ind = 1;
107139beb93cSSam Leffler 
10725b9c547cSRui Paulo 	if (data->state != FAILURE) {
107339beb93cSSam Leffler 		eap_sim_state(data, data->use_result_ind ?
107439beb93cSSam Leffler 			      RESULT_SUCCESS : SUCCESS);
107539beb93cSSam Leffler 	}
107639beb93cSSam Leffler 
107739beb93cSSam Leffler 	data->num_id_req = 0;
107839beb93cSSam Leffler 	data->num_notification = 0;
107939beb93cSSam Leffler 	if (data->counter > EAP_SIM_MAX_FAST_REAUTHS) {
108039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM: Maximum number of "
108139beb93cSSam Leffler 			   "fast reauths performed - force fullauth");
1082f05cddf9SRui Paulo 		eap_sim_clear_identities(sm, data,
1083f05cddf9SRui Paulo 					 CLEAR_REAUTH_ID | CLEAR_EAP_ID);
108439beb93cSSam Leffler 	}
108539beb93cSSam Leffler 	os_free(decrypted);
1086f05cddf9SRui Paulo 	return eap_sim_response_reauth(data, id, 0, data->nonce_s);
108739beb93cSSam Leffler }
108839beb93cSSam Leffler 
108939beb93cSSam Leffler 
109039beb93cSSam Leffler static struct wpabuf * eap_sim_process(struct eap_sm *sm, void *priv,
109139beb93cSSam Leffler 				       struct eap_method_ret *ret,
109239beb93cSSam Leffler 				       const struct wpabuf *reqData)
109339beb93cSSam Leffler {
109439beb93cSSam Leffler 	struct eap_sim_data *data = priv;
109539beb93cSSam Leffler 	const struct eap_hdr *req;
109639beb93cSSam Leffler 	u8 subtype, id;
109739beb93cSSam Leffler 	struct wpabuf *res;
109839beb93cSSam Leffler 	const u8 *pos;
109939beb93cSSam Leffler 	struct eap_sim_attrs attr;
110039beb93cSSam Leffler 	size_t len;
110139beb93cSSam Leffler 
110239beb93cSSam Leffler 	wpa_hexdump_buf(MSG_DEBUG, "EAP-SIM: EAP data", reqData);
110339beb93cSSam Leffler 	if (eap_get_config_identity(sm, &len) == NULL) {
110439beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM: Identity not configured");
110539beb93cSSam Leffler 		eap_sm_request_identity(sm);
1106*c1d255d3SCy Schubert 		ret->ignore = true;
110739beb93cSSam Leffler 		return NULL;
110839beb93cSSam Leffler 	}
110939beb93cSSam Leffler 
111039beb93cSSam Leffler 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, reqData, &len);
1111325151a3SRui Paulo 	if (pos == NULL || len < 3) {
1112*c1d255d3SCy Schubert 		ret->ignore = true;
111339beb93cSSam Leffler 		return NULL;
111439beb93cSSam Leffler 	}
111539beb93cSSam Leffler 	req = wpabuf_head(reqData);
111639beb93cSSam Leffler 	id = req->identifier;
111739beb93cSSam Leffler 	len = be_to_host16(req->length);
111839beb93cSSam Leffler 
1119*c1d255d3SCy Schubert 	ret->ignore = false;
112039beb93cSSam Leffler 	ret->methodState = METHOD_MAY_CONT;
112139beb93cSSam Leffler 	ret->decision = DECISION_FAIL;
1122*c1d255d3SCy Schubert 	ret->allowNotifications = true;
112339beb93cSSam Leffler 
112439beb93cSSam Leffler 	subtype = *pos++;
112539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM: Subtype=%d", subtype);
112639beb93cSSam Leffler 	pos += 2; /* Reserved */
112739beb93cSSam Leffler 
112839beb93cSSam Leffler 	if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr, 0,
112939beb93cSSam Leffler 			       0)) {
113039beb93cSSam Leffler 		res = eap_sim_client_error(data, id,
113139beb93cSSam Leffler 					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
113239beb93cSSam Leffler 		goto done;
113339beb93cSSam Leffler 	}
113439beb93cSSam Leffler 
113539beb93cSSam Leffler 	switch (subtype) {
113639beb93cSSam Leffler 	case EAP_SIM_SUBTYPE_START:
113739beb93cSSam Leffler 		res = eap_sim_process_start(sm, data, id, &attr);
113839beb93cSSam Leffler 		break;
113939beb93cSSam Leffler 	case EAP_SIM_SUBTYPE_CHALLENGE:
114039beb93cSSam Leffler 		res = eap_sim_process_challenge(sm, data, id, reqData, &attr);
114139beb93cSSam Leffler 		break;
114239beb93cSSam Leffler 	case EAP_SIM_SUBTYPE_NOTIFICATION:
114339beb93cSSam Leffler 		res = eap_sim_process_notification(sm, data, id, reqData,
114439beb93cSSam Leffler 						   &attr);
114539beb93cSSam Leffler 		break;
114639beb93cSSam Leffler 	case EAP_SIM_SUBTYPE_REAUTHENTICATION:
114739beb93cSSam Leffler 		res = eap_sim_process_reauthentication(sm, data, id, reqData,
114839beb93cSSam Leffler 						       &attr);
114939beb93cSSam Leffler 		break;
115039beb93cSSam Leffler 	case EAP_SIM_SUBTYPE_CLIENT_ERROR:
115139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Client-Error");
115239beb93cSSam Leffler 		res = eap_sim_client_error(data, id,
115339beb93cSSam Leffler 					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
115439beb93cSSam Leffler 		break;
115539beb93cSSam Leffler 	default:
115639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown subtype=%d", subtype);
115739beb93cSSam Leffler 		res = eap_sim_client_error(data, id,
115839beb93cSSam Leffler 					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
115939beb93cSSam Leffler 		break;
116039beb93cSSam Leffler 	}
116139beb93cSSam Leffler 
116239beb93cSSam Leffler done:
116339beb93cSSam Leffler 	if (data->state == FAILURE) {
116439beb93cSSam Leffler 		ret->decision = DECISION_FAIL;
116539beb93cSSam Leffler 		ret->methodState = METHOD_DONE;
116639beb93cSSam Leffler 	} else if (data->state == SUCCESS) {
116739beb93cSSam Leffler 		ret->decision = data->use_result_ind ?
116839beb93cSSam Leffler 			DECISION_UNCOND_SUCC : DECISION_COND_SUCC;
116939beb93cSSam Leffler 		ret->methodState = data->use_result_ind ?
117039beb93cSSam Leffler 			METHOD_DONE : METHOD_MAY_CONT;
11715b9c547cSRui Paulo 	} else if (data->state == RESULT_SUCCESS)
117239beb93cSSam Leffler 		ret->methodState = METHOD_CONT;
117339beb93cSSam Leffler 
117439beb93cSSam Leffler 	if (ret->methodState == METHOD_DONE) {
1175*c1d255d3SCy Schubert 		ret->allowNotifications = false;
117639beb93cSSam Leffler 	}
117739beb93cSSam Leffler 
117839beb93cSSam Leffler 	return res;
117939beb93cSSam Leffler }
118039beb93cSSam Leffler 
118139beb93cSSam Leffler 
1182*c1d255d3SCy Schubert static bool eap_sim_has_reauth_data(struct eap_sm *sm, void *priv)
118339beb93cSSam Leffler {
118439beb93cSSam Leffler 	struct eap_sim_data *data = priv;
118539beb93cSSam Leffler 	return data->pseudonym || data->reauth_id;
118639beb93cSSam Leffler }
118739beb93cSSam Leffler 
118839beb93cSSam Leffler 
118939beb93cSSam Leffler static void eap_sim_deinit_for_reauth(struct eap_sm *sm, void *priv)
119039beb93cSSam Leffler {
119139beb93cSSam Leffler 	struct eap_sim_data *data = priv;
1192f05cddf9SRui Paulo 	eap_sim_clear_identities(sm, data, CLEAR_EAP_ID);
119339beb93cSSam Leffler 	data->use_result_ind = 0;
11945b9c547cSRui Paulo 	eap_sim_clear_keys(data, 1);
119539beb93cSSam Leffler }
119639beb93cSSam Leffler 
119739beb93cSSam Leffler 
119839beb93cSSam Leffler static void * eap_sim_init_for_reauth(struct eap_sm *sm, void *priv)
119939beb93cSSam Leffler {
120039beb93cSSam Leffler 	struct eap_sim_data *data = priv;
1201f05cddf9SRui Paulo 	if (random_get_bytes(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
120239beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data "
120339beb93cSSam Leffler 			   "for NONCE_MT");
1204780fb4a2SCy Schubert 		eap_sim_deinit(sm, data);
120539beb93cSSam Leffler 		return NULL;
120639beb93cSSam Leffler 	}
120739beb93cSSam Leffler 	data->num_id_req = 0;
120839beb93cSSam Leffler 	data->num_notification = 0;
120939beb93cSSam Leffler 	eap_sim_state(data, CONTINUE);
121039beb93cSSam Leffler 	return priv;
121139beb93cSSam Leffler }
121239beb93cSSam Leffler 
121339beb93cSSam Leffler 
121439beb93cSSam Leffler static const u8 * eap_sim_get_identity(struct eap_sm *sm, void *priv,
121539beb93cSSam Leffler 				       size_t *len)
121639beb93cSSam Leffler {
121739beb93cSSam Leffler 	struct eap_sim_data *data = priv;
121839beb93cSSam Leffler 
121939beb93cSSam Leffler 	if (data->reauth_id) {
122039beb93cSSam Leffler 		*len = data->reauth_id_len;
122139beb93cSSam Leffler 		return data->reauth_id;
122239beb93cSSam Leffler 	}
122339beb93cSSam Leffler 
122439beb93cSSam Leffler 	if (data->pseudonym) {
122539beb93cSSam Leffler 		*len = data->pseudonym_len;
122639beb93cSSam Leffler 		return data->pseudonym;
122739beb93cSSam Leffler 	}
122839beb93cSSam Leffler 
122939beb93cSSam Leffler 	return NULL;
123039beb93cSSam Leffler }
123139beb93cSSam Leffler 
123239beb93cSSam Leffler 
1233*c1d255d3SCy Schubert static bool eap_sim_isKeyAvailable(struct eap_sm *sm, void *priv)
123439beb93cSSam Leffler {
123539beb93cSSam Leffler 	struct eap_sim_data *data = priv;
123639beb93cSSam Leffler 	return data->state == SUCCESS;
123739beb93cSSam Leffler }
123839beb93cSSam Leffler 
123939beb93cSSam Leffler 
124039beb93cSSam Leffler static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
124139beb93cSSam Leffler {
124239beb93cSSam Leffler 	struct eap_sim_data *data = priv;
124339beb93cSSam Leffler 	u8 *key;
124439beb93cSSam Leffler 
124539beb93cSSam Leffler 	if (data->state != SUCCESS)
124639beb93cSSam Leffler 		return NULL;
124739beb93cSSam Leffler 
124885732ac8SCy Schubert 	key = os_memdup(data->msk, EAP_SIM_KEYING_DATA_LEN);
124939beb93cSSam Leffler 	if (key == NULL)
125039beb93cSSam Leffler 		return NULL;
125139beb93cSSam Leffler 
125239beb93cSSam Leffler 	*len = EAP_SIM_KEYING_DATA_LEN;
125339beb93cSSam Leffler 
125439beb93cSSam Leffler 	return key;
125539beb93cSSam Leffler }
125639beb93cSSam Leffler 
125739beb93cSSam Leffler 
12585b9c547cSRui Paulo static u8 * eap_sim_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
12595b9c547cSRui Paulo {
12605b9c547cSRui Paulo 	struct eap_sim_data *data = priv;
12615b9c547cSRui Paulo 	u8 *id;
12625b9c547cSRui Paulo 
12635b9c547cSRui Paulo 	if (data->state != SUCCESS)
12645b9c547cSRui Paulo 		return NULL;
12655b9c547cSRui Paulo 
1266206b73d0SCy Schubert 	if (!data->reauth)
12675b9c547cSRui Paulo 		*len = 1 + data->num_chal * GSM_RAND_LEN + EAP_SIM_NONCE_MT_LEN;
1268206b73d0SCy Schubert 	else
1269206b73d0SCy Schubert 		*len = 1 + EAP_SIM_NONCE_S_LEN + EAP_SIM_MAC_LEN;
12705b9c547cSRui Paulo 	id = os_malloc(*len);
12715b9c547cSRui Paulo 	if (id == NULL)
12725b9c547cSRui Paulo 		return NULL;
12735b9c547cSRui Paulo 
12745b9c547cSRui Paulo 	id[0] = EAP_TYPE_SIM;
1275206b73d0SCy Schubert 	if (!data->reauth) {
12765b9c547cSRui Paulo 		os_memcpy(id + 1, data->rand, data->num_chal * GSM_RAND_LEN);
1277206b73d0SCy Schubert 		os_memcpy(id + 1 + data->num_chal * GSM_RAND_LEN,
1278206b73d0SCy Schubert 			  data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
1279206b73d0SCy Schubert 	} else {
1280206b73d0SCy Schubert 		os_memcpy(id + 1, data->nonce_s, EAP_SIM_NONCE_S_LEN);
1281206b73d0SCy Schubert 		os_memcpy(id + 1 + EAP_SIM_NONCE_S_LEN, data->reauth_mac,
1282206b73d0SCy Schubert 			  EAP_SIM_MAC_LEN);
1283206b73d0SCy Schubert 	}
12845b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "EAP-SIM: Derived Session-Id", id, *len);
12855b9c547cSRui Paulo 
12865b9c547cSRui Paulo 	return id;
12875b9c547cSRui Paulo }
12885b9c547cSRui Paulo 
12895b9c547cSRui Paulo 
129039beb93cSSam Leffler static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
129139beb93cSSam Leffler {
129239beb93cSSam Leffler 	struct eap_sim_data *data = priv;
129339beb93cSSam Leffler 	u8 *key;
129439beb93cSSam Leffler 
129539beb93cSSam Leffler 	if (data->state != SUCCESS)
129639beb93cSSam Leffler 		return NULL;
129739beb93cSSam Leffler 
129885732ac8SCy Schubert 	key = os_memdup(data->emsk, EAP_EMSK_LEN);
129939beb93cSSam Leffler 	if (key == NULL)
130039beb93cSSam Leffler 		return NULL;
130139beb93cSSam Leffler 
130239beb93cSSam Leffler 	*len = EAP_EMSK_LEN;
130339beb93cSSam Leffler 
130439beb93cSSam Leffler 	return key;
130539beb93cSSam Leffler }
130639beb93cSSam Leffler 
130739beb93cSSam Leffler 
130885732ac8SCy Schubert static int eap_sim_get_error_code(void *priv)
130985732ac8SCy Schubert {
131085732ac8SCy Schubert 	struct eap_sim_data *data = priv;
131185732ac8SCy Schubert 	int current_data_error;
131285732ac8SCy Schubert 
131385732ac8SCy Schubert 	if (!data)
131485732ac8SCy Schubert 		return NO_EAP_METHOD_ERROR;
131585732ac8SCy Schubert 
131685732ac8SCy Schubert 	current_data_error = data->error_code;
131785732ac8SCy Schubert 
131885732ac8SCy Schubert 	/* Now reset for next transaction */
131985732ac8SCy Schubert 	data->error_code = NO_EAP_METHOD_ERROR;
132085732ac8SCy Schubert 
132185732ac8SCy Schubert 	return current_data_error;
132285732ac8SCy Schubert }
132385732ac8SCy Schubert 
132485732ac8SCy Schubert 
132539beb93cSSam Leffler int eap_peer_sim_register(void)
132639beb93cSSam Leffler {
132739beb93cSSam Leffler 	struct eap_method *eap;
132839beb93cSSam Leffler 
132939beb93cSSam Leffler 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
133039beb93cSSam Leffler 				    EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM");
133139beb93cSSam Leffler 	if (eap == NULL)
133239beb93cSSam Leffler 		return -1;
133339beb93cSSam Leffler 
133439beb93cSSam Leffler 	eap->init = eap_sim_init;
133539beb93cSSam Leffler 	eap->deinit = eap_sim_deinit;
133639beb93cSSam Leffler 	eap->process = eap_sim_process;
133739beb93cSSam Leffler 	eap->isKeyAvailable = eap_sim_isKeyAvailable;
133839beb93cSSam Leffler 	eap->getKey = eap_sim_getKey;
13395b9c547cSRui Paulo 	eap->getSessionId = eap_sim_get_session_id;
134039beb93cSSam Leffler 	eap->has_reauth_data = eap_sim_has_reauth_data;
134139beb93cSSam Leffler 	eap->deinit_for_reauth = eap_sim_deinit_for_reauth;
134239beb93cSSam Leffler 	eap->init_for_reauth = eap_sim_init_for_reauth;
134339beb93cSSam Leffler 	eap->get_identity = eap_sim_get_identity;
134439beb93cSSam Leffler 	eap->get_emsk = eap_sim_get_emsk;
134585732ac8SCy Schubert 	eap->get_error_code = eap_sim_get_error_code;
134639beb93cSSam Leffler 
1347780fb4a2SCy Schubert 	return eap_peer_method_register(eap);
134839beb93cSSam Leffler }
1349