Home | History | Annotate | Download | only in eap_peer
      1 /*
      2  * EAP peer method: EAP-SIM (RFC 4186)
      3  * Copyright (c) 2004-2008, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License version 2 as
      7  * published by the Free Software Foundation.
      8  *
      9  * Alternatively, this software may be distributed under the terms of BSD
     10  * license.
     11  *
     12  * See README and COPYING for more details.
     13  */
     14 
     15 #include "includes.h"
     16 
     17 #include "common.h"
     18 #include "eap_peer/eap_i.h"
     19 #include "eap_config.h"
     20 #include "pcsc_funcs.h"
     21 #include "eap_common/eap_sim_common.h"
     22 #ifdef CONFIG_SIM_SIMULATOR
     23 #include "hlr_auc_gw/milenage.h"
     24 #endif /* CONFIG_SIM_SIMULATOR */
     25 
     26 
     27 struct eap_sim_data {
     28 	u8 *ver_list;
     29 	size_t ver_list_len;
     30 	int selected_version;
     31 	size_t min_num_chal, num_chal;
     32 
     33 	u8 kc[3][EAP_SIM_KC_LEN];
     34 	u8 sres[3][EAP_SIM_SRES_LEN];
     35 	u8 nonce_mt[EAP_SIM_NONCE_MT_LEN], nonce_s[EAP_SIM_NONCE_S_LEN];
     36 	u8 mk[EAP_SIM_MK_LEN];
     37 	u8 k_aut[EAP_SIM_K_AUT_LEN];
     38 	u8 k_encr[EAP_SIM_K_ENCR_LEN];
     39 	u8 msk[EAP_SIM_KEYING_DATA_LEN];
     40 	u8 emsk[EAP_EMSK_LEN];
     41 	u8 rand[3][GSM_RAND_LEN];
     42 
     43 	int num_id_req, num_notification;
     44 	u8 *pseudonym;
     45 	size_t pseudonym_len;
     46 	u8 *reauth_id;
     47 	size_t reauth_id_len;
     48 	int reauth;
     49 	unsigned int counter, counter_too_small;
     50 	u8 *last_eap_identity;
     51 	size_t last_eap_identity_len;
     52 	enum {
     53 		CONTINUE, RESULT_SUCCESS, RESULT_FAILURE, SUCCESS, FAILURE
     54 	} state;
     55 	int result_ind, use_result_ind;
     56 };
     57 
     58 
     59 #ifndef CONFIG_NO_STDOUT_DEBUG
     60 static const char * eap_sim_state_txt(int state)
     61 {
     62 	switch (state) {
     63 	case CONTINUE:
     64 		return "CONTINUE";
     65 	case RESULT_SUCCESS:
     66 		return "RESULT_SUCCESS";
     67 	case RESULT_FAILURE:
     68 		return "RESULT_FAILURE";
     69 	case SUCCESS:
     70 		return "SUCCESS";
     71 	case FAILURE:
     72 		return "FAILURE";
     73 	default:
     74 		return "?";
     75 	}
     76 }
     77 #endif /* CONFIG_NO_STDOUT_DEBUG */
     78 
     79 
     80 static void eap_sim_state(struct eap_sim_data *data, int state)
     81 {
     82 	wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s",
     83 		   eap_sim_state_txt(data->state),
     84 		   eap_sim_state_txt(state));
     85 	data->state = state;
     86 }
     87 
     88 
     89 static void * eap_sim_init(struct eap_sm *sm)
     90 {
     91 	struct eap_sim_data *data;
     92 	struct eap_peer_config *config = eap_get_config(sm);
     93 
     94 	data = os_zalloc(sizeof(*data));
     95 	if (data == NULL)
     96 		return NULL;
     97 
     98 	if (os_get_random(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
     99 		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data "
    100 			   "for NONCE_MT");
    101 		os_free(data);
    102 		return NULL;
    103 	}
    104 
    105 	data->min_num_chal = 2;
    106 	if (config && config->phase1) {
    107 		char *pos = os_strstr(config->phase1, "sim_min_num_chal=");
    108 		if (pos) {
    109 			data->min_num_chal = atoi(pos + 17);
    110 			if (data->min_num_chal < 2 || data->min_num_chal > 3) {
    111 				wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
    112 					   "sim_min_num_chal configuration "
    113 					   "(%lu, expected 2 or 3)",
    114 					   (unsigned long) data->min_num_chal);
    115 				os_free(data);
    116 				return NULL;
    117 			}
    118 			wpa_printf(MSG_DEBUG, "EAP-SIM: Set minimum number of "
    119 				   "challenges to %lu",
    120 				   (unsigned long) data->min_num_chal);
    121 		}
    122 
    123 		data->result_ind = os_strstr(config->phase1, "result_ind=1") !=
    124 			NULL;
    125 	}
    126 
    127 	eap_sim_state(data, CONTINUE);
    128 
    129 	return data;
    130 }
    131 
    132 
    133 static void eap_sim_deinit(struct eap_sm *sm, void *priv)
    134 {
    135 	struct eap_sim_data *data = priv;
    136 	if (data) {
    137 		os_free(data->ver_list);
    138 		os_free(data->pseudonym);
    139 		os_free(data->reauth_id);
    140 		os_free(data->last_eap_identity);
    141 		os_free(data);
    142 	}
    143 }
    144 
    145 
    146 static int eap_sim_gsm_auth(struct eap_sm *sm, struct eap_sim_data *data)
    147 {
    148 	struct eap_peer_config *conf;
    149 
    150 	wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication algorithm");
    151 
    152 	conf = eap_get_config(sm);
    153 	if (conf == NULL)
    154 		return -1;
    155 	if (conf->pcsc) {
    156 		if (scard_gsm_auth(sm->scard_ctx, data->rand[0],
    157 				   data->sres[0], data->kc[0]) ||
    158 		    scard_gsm_auth(sm->scard_ctx, data->rand[1],
    159 				   data->sres[1], data->kc[1]) ||
    160 		    (data->num_chal > 2 &&
    161 		     scard_gsm_auth(sm->scard_ctx, data->rand[2],
    162 				    data->sres[2], data->kc[2]))) {
    163 			wpa_printf(MSG_DEBUG, "EAP-SIM: GSM SIM "
    164 				   "authentication could not be completed");
    165 			return -1;
    166 		}
    167 		return 0;
    168 	}
    169 
    170 #ifdef CONFIG_SIM_SIMULATOR
    171 	if (conf->password) {
    172 		u8 opc[16], k[16];
    173 		const char *pos;
    174 		size_t i;
    175 		wpa_printf(MSG_DEBUG, "EAP-SIM: Use internal GSM-Milenage "
    176 			   "implementation for authentication");
    177 		if (conf->password_len < 65) {
    178 			wpa_printf(MSG_DEBUG, "EAP-SIM: invalid GSM-Milenage "
    179 				   "password");
    180 			return -1;
    181 		}
    182 		pos = (const char *) conf->password;
    183 		if (hexstr2bin(pos, k, 16))
    184 			return -1;
    185 		pos += 32;
    186 		if (*pos != ':')
    187 			return -1;
    188 		pos++;
    189 
    190 		if (hexstr2bin(pos, opc, 16))
    191 			return -1;
    192 
    193 		for (i = 0; i < data->num_chal; i++) {
    194 			if (gsm_milenage(opc, k, data->rand[i],
    195 					 data->sres[i], data->kc[i])) {
    196 				wpa_printf(MSG_DEBUG, "EAP-SIM: "
    197 					   "GSM-Milenage authentication "
    198 					   "could not be completed");
    199 				return -1;
    200 			}
    201 			wpa_hexdump(MSG_DEBUG, "EAP-SIM: RAND",
    202 				    data->rand[i], GSM_RAND_LEN);
    203 			wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: SRES",
    204 					data->sres[i], EAP_SIM_SRES_LEN);
    205 			wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: Kc",
    206 					data->kc[i], EAP_SIM_KC_LEN);
    207 		}
    208 		return 0;
    209 	}
    210 #endif /* CONFIG_SIM_SIMULATOR */
    211 
    212 #ifdef CONFIG_SIM_HARDCODED
    213 	/* These hardcoded Kc and SRES values are used for testing. RAND to
    214 	 * KC/SREC mapping is very bogus as far as real authentication is
    215 	 * concerned, but it is quite useful for cases where the AS is rotating
    216 	 * the order of pre-configured values. */
    217 	{
    218 		size_t i;
    219 
    220 		wpa_printf(MSG_DEBUG, "EAP-SIM: Use hardcoded Kc and SRES "
    221 			   "values for testing");
    222 
    223 		for (i = 0; i < data->num_chal; i++) {
    224 			if (data->rand[i][0] == 0xaa) {
    225 				os_memcpy(data->kc[i],
    226 					  "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7",
    227 					  EAP_SIM_KC_LEN);
    228 				os_memcpy(data->sres[i], "\xd1\xd2\xd3\xd4",
    229 					  EAP_SIM_SRES_LEN);
    230 			} else if (data->rand[i][0] == 0xbb) {
    231 				os_memcpy(data->kc[i],
    232 					  "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7",
    233 					  EAP_SIM_KC_LEN);
    234 				os_memcpy(data->sres[i], "\xe1\xe2\xe3\xe4",
    235 					  EAP_SIM_SRES_LEN);
    236 			} else {
    237 				os_memcpy(data->kc[i],
    238 					  "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7",
    239 					  EAP_SIM_KC_LEN);
    240 				os_memcpy(data->sres[i], "\xf1\xf2\xf3\xf4",
    241 					  EAP_SIM_SRES_LEN);
    242 			}
    243 		}
    244 	}
    245 
    246 	return 0;
    247 
    248 #else /* CONFIG_SIM_HARDCODED */
    249 
    250 	wpa_printf(MSG_DEBUG, "EAP-SIM: No GSM authentication algorithm "
    251 		   "enabled");
    252 	return -1;
    253 
    254 #endif /* CONFIG_SIM_HARDCODED */
    255 }
    256 
    257 
    258 static int eap_sim_supported_ver(int version)
    259 {
    260 	return version == EAP_SIM_VERSION;
    261 }
    262 
    263 
    264 #define CLEAR_PSEUDONYM	0x01
    265 #define CLEAR_REAUTH_ID	0x02
    266 #define CLEAR_EAP_ID	0x04
    267 
    268 static void eap_sim_clear_identities(struct eap_sim_data *data, int id)
    269 {
    270 	wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old%s%s%s",
    271 		   id & CLEAR_PSEUDONYM ? " pseudonym" : "",
    272 		   id & CLEAR_REAUTH_ID ? " reauth_id" : "",
    273 		   id & CLEAR_EAP_ID ? " eap_id" : "");
    274 	if (id & CLEAR_PSEUDONYM) {
    275 		os_free(data->pseudonym);
    276 		data->pseudonym = NULL;
    277 		data->pseudonym_len = 0;
    278 	}
    279 	if (id & CLEAR_REAUTH_ID) {
    280 		os_free(data->reauth_id);
    281 		data->reauth_id = NULL;
    282 		data->reauth_id_len = 0;
    283 	}
    284 	if (id & CLEAR_EAP_ID) {
    285 		os_free(data->last_eap_identity);
    286 		data->last_eap_identity = NULL;
    287 		data->last_eap_identity_len = 0;
    288 	}
    289 }
    290 
    291 
    292 static int eap_sim_learn_ids(struct eap_sim_data *data,
    293 			     struct eap_sim_attrs *attr)
    294 {
    295 	if (attr->next_pseudonym) {
    296 		os_free(data->pseudonym);
    297 		data->pseudonym = os_malloc(attr->next_pseudonym_len);
    298 		if (data->pseudonym == NULL) {
    299 			wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for "
    300 				   "next pseudonym");
    301 			return -1;
    302 		}
    303 		os_memcpy(data->pseudonym, attr->next_pseudonym,
    304 			  attr->next_pseudonym_len);
    305 		data->pseudonym_len = attr->next_pseudonym_len;
    306 		wpa_hexdump_ascii(MSG_DEBUG,
    307 				  "EAP-SIM: (encr) AT_NEXT_PSEUDONYM",
    308 				  data->pseudonym,
    309 				  data->pseudonym_len);
    310 	}
    311 
    312 	if (attr->next_reauth_id) {
    313 		os_free(data->reauth_id);
    314 		data->reauth_id = os_malloc(attr->next_reauth_id_len);
    315 		if (data->reauth_id == NULL) {
    316 			wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for "
    317 				   "next reauth_id");
    318 			return -1;
    319 		}
    320 		os_memcpy(data->reauth_id, attr->next_reauth_id,
    321 			  attr->next_reauth_id_len);
    322 		data->reauth_id_len = attr->next_reauth_id_len;
    323 		wpa_hexdump_ascii(MSG_DEBUG,
    324 				  "EAP-SIM: (encr) AT_NEXT_REAUTH_ID",
    325 				  data->reauth_id,
    326 				  data->reauth_id_len);
    327 	}
    328 
    329 	return 0;
    330 }
    331 
    332 
    333 static struct wpabuf * eap_sim_client_error(struct eap_sim_data *data, u8 id,
    334 					    int err)
    335 {
    336 	struct eap_sim_msg *msg;
    337 
    338 	eap_sim_state(data, FAILURE);
    339 	data->num_id_req = 0;
    340 	data->num_notification = 0;
    341 
    342 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
    343 			       EAP_SIM_SUBTYPE_CLIENT_ERROR);
    344 	eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
    345 	return eap_sim_msg_finish(msg, NULL, NULL, 0);
    346 }
    347 
    348 
    349 static struct wpabuf * eap_sim_response_start(struct eap_sm *sm,
    350 					      struct eap_sim_data *data, u8 id,
    351 					      enum eap_sim_id_req id_req)
    352 {
    353 	const u8 *identity = NULL;
    354 	size_t identity_len = 0;
    355 	struct eap_sim_msg *msg;
    356 
    357 	data->reauth = 0;
    358 	if (id_req == ANY_ID && data->reauth_id) {
    359 		identity = data->reauth_id;
    360 		identity_len = data->reauth_id_len;
    361 		data->reauth = 1;
    362 	} else if ((id_req == ANY_ID || id_req == FULLAUTH_ID) &&
    363 		   data->pseudonym) {
    364 		identity = data->pseudonym;
    365 		identity_len = data->pseudonym_len;
    366 		eap_sim_clear_identities(data, CLEAR_REAUTH_ID);
    367 	} else if (id_req != NO_ID_REQ) {
    368 		identity = eap_get_config_identity(sm, &identity_len);
    369 		if (identity) {
    370 			eap_sim_clear_identities(data, CLEAR_PSEUDONYM |
    371 						 CLEAR_REAUTH_ID);
    372 		}
    373 	}
    374 	if (id_req != NO_ID_REQ)
    375 		eap_sim_clear_identities(data, CLEAR_EAP_ID);
    376 
    377 	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Start (id=%d)", id);
    378 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id,
    379 			       EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START);
    380 	if (!data->reauth) {
    381 		wpa_hexdump(MSG_DEBUG, "   AT_NONCE_MT",
    382 			    data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
    383 		eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_MT, 0,
    384 				data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
    385 		wpa_printf(MSG_DEBUG, "   AT_SELECTED_VERSION %d",
    386 			   data->selected_version);
    387 		eap_sim_msg_add(msg, EAP_SIM_AT_SELECTED_VERSION,
    388 				data->selected_version, NULL, 0);
    389 	}
    390 
    391 	if (identity) {
    392 		wpa_hexdump_ascii(MSG_DEBUG, "   AT_IDENTITY",
    393 				  identity, identity_len);
    394 		eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
    395 				identity, identity_len);
    396 	}
    397 
    398 	return eap_sim_msg_finish(msg, NULL, NULL, 0);
    399 }
    400 
    401 
    402 static struct wpabuf * eap_sim_response_challenge(struct eap_sim_data *data,
    403 						  u8 id)
    404 {
    405 	struct eap_sim_msg *msg;
    406 
    407 	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Challenge (id=%d)", id);
    408 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
    409 			       EAP_SIM_SUBTYPE_CHALLENGE);
    410 	if (data->use_result_ind) {
    411 		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
    412 		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
    413 	}
    414 	wpa_printf(MSG_DEBUG, "   AT_MAC");
    415 	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
    416 	return eap_sim_msg_finish(msg, data->k_aut, (u8 *) data->sres,
    417 				  data->num_chal * EAP_SIM_SRES_LEN);
    418 }
    419 
    420 
    421 static struct wpabuf * eap_sim_response_reauth(struct eap_sim_data *data,
    422 					       u8 id, int counter_too_small)
    423 {
    424 	struct eap_sim_msg *msg;
    425 	unsigned int counter;
    426 
    427 	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Reauthentication (id=%d)",
    428 		   id);
    429 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
    430 			       EAP_SIM_SUBTYPE_REAUTHENTICATION);
    431 	wpa_printf(MSG_DEBUG, "   AT_IV");
    432 	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
    433 	eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
    434 
    435 	if (counter_too_small) {
    436 		wpa_printf(MSG_DEBUG, "   *AT_COUNTER_TOO_SMALL");
    437 		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER_TOO_SMALL, 0, NULL, 0);
    438 		counter = data->counter_too_small;
    439 	} else
    440 		counter = data->counter;
    441 
    442 	wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", counter);
    443 	eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
    444 
    445 	if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
    446 		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
    447 			   "AT_ENCR_DATA");
    448 		eap_sim_msg_free(msg);
    449 		return NULL;
    450 	}
    451 	if (data->use_result_ind) {
    452 		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
    453 		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
    454 	}
    455 	wpa_printf(MSG_DEBUG, "   AT_MAC");
    456 	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
    457 	return eap_sim_msg_finish(msg, data->k_aut, data->nonce_s,
    458 				  EAP_SIM_NONCE_S_LEN);
    459 }
    460 
    461 
    462 static struct wpabuf * eap_sim_response_notification(struct eap_sim_data *data,
    463 						     u8 id, u16 notification)
    464 {
    465 	struct eap_sim_msg *msg;
    466 	u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL;
    467 
    468 	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Notification (id=%d)", id);
    469 	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id,
    470 			       EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION);
    471 	if (k_aut && data->reauth) {
    472 		wpa_printf(MSG_DEBUG, "   AT_IV");
    473 		wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
    474 		eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
    475 					   EAP_SIM_AT_ENCR_DATA);
    476 		wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", data->counter);
    477 		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
    478 				NULL, 0);
    479 		if (eap_sim_msg_add_encr_end(msg, data->k_encr,
    480 					     EAP_SIM_AT_PADDING)) {
    481 			wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
    482 				   "AT_ENCR_DATA");
    483 			eap_sim_msg_free(msg);
    484 			return NULL;
    485 		}
    486 	}
    487 	if (k_aut) {
    488 		wpa_printf(MSG_DEBUG, "   AT_MAC");
    489 		eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
    490 	}
    491 	return eap_sim_msg_finish(msg, k_aut, (u8 *) "", 0);
    492 }
    493 
    494 
    495 static struct wpabuf * eap_sim_process_start(struct eap_sm *sm,
    496 					     struct eap_sim_data *data, u8 id,
    497 					     struct eap_sim_attrs *attr)
    498 {
    499 	int selected_version = -1, id_error;
    500 	size_t i;
    501 	u8 *pos;
    502 
    503 	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Start");
    504 	if (attr->version_list == NULL) {
    505 		wpa_printf(MSG_INFO, "EAP-SIM: No AT_VERSION_LIST in "
    506 			   "SIM/Start");
    507 		return eap_sim_client_error(data, id,
    508 					    EAP_SIM_UNSUPPORTED_VERSION);
    509 	}
    510 
    511 	os_free(data->ver_list);
    512 	data->ver_list = os_malloc(attr->version_list_len);
    513 	if (data->ver_list == NULL) {
    514 		wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to allocate "
    515 			   "memory for version list");
    516 		return eap_sim_client_error(data, id,
    517 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
    518 	}
    519 	os_memcpy(data->ver_list, attr->version_list, attr->version_list_len);
    520 	data->ver_list_len = attr->version_list_len;
    521 	pos = data->ver_list;
    522 	for (i = 0; i < data->ver_list_len / 2; i++) {
    523 		int ver = pos[0] * 256 + pos[1];
    524 		pos += 2;
    525 		if (eap_sim_supported_ver(ver)) {
    526 			selected_version = ver;
    527 			break;
    528 		}
    529 	}
    530 	if (selected_version < 0) {
    531 		wpa_printf(MSG_INFO, "EAP-SIM: Could not find a supported "
    532 			   "version");
    533 		return eap_sim_client_error(data, id,
    534 					    EAP_SIM_UNSUPPORTED_VERSION);
    535 	}
    536 	wpa_printf(MSG_DEBUG, "EAP-SIM: Selected Version %d",
    537 		   selected_version);
    538 	data->selected_version = selected_version;
    539 
    540 	id_error = 0;
    541 	switch (attr->id_req) {
    542 	case NO_ID_REQ:
    543 		break;
    544 	case ANY_ID:
    545 		if (data->num_id_req > 0)
    546 			id_error++;
    547 		data->num_id_req++;
    548 		break;
    549 	case FULLAUTH_ID:
    550 		if (data->num_id_req > 1)
    551 			id_error++;
    552 		data->num_id_req++;
    553 		break;
    554 	case PERMANENT_ID:
    555 		if (data->num_id_req > 2)
    556 			id_error++;
    557 		data->num_id_req++;
    558 		break;
    559 	}
    560 	if (id_error) {
    561 		wpa_printf(MSG_INFO, "EAP-SIM: Too many ID requests "
    562 			   "used within one authentication");
    563 		return eap_sim_client_error(data, id,
    564 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
    565 	}
    566 
    567 	return eap_sim_response_start(sm, data, id, attr->id_req);
    568 }
    569 
    570 
    571 static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm,
    572 						 struct eap_sim_data *data,
    573 						 u8 id,
    574 						 const struct wpabuf *reqData,
    575 						 struct eap_sim_attrs *attr)
    576 {
    577 	const u8 *identity;
    578 	size_t identity_len;
    579 	struct eap_sim_attrs eattr;
    580 
    581 	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Challenge");
    582 	data->reauth = 0;
    583 	if (!attr->mac || !attr->rand) {
    584 		wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
    585 			   "did not include%s%s",
    586 			   !attr->mac ? " AT_MAC" : "",
    587 			   !attr->rand ? " AT_RAND" : "");
    588 		return eap_sim_client_error(data, id,
    589 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
    590 	}
    591 
    592 	wpa_printf(MSG_DEBUG, "EAP-SIM: %lu challenges",
    593 		   (unsigned long) attr->num_chal);
    594 	if (attr->num_chal < data->min_num_chal) {
    595 		wpa_printf(MSG_INFO, "EAP-SIM: Insufficient number of "
    596 			   "challenges (%lu)", (unsigned long) attr->num_chal);
    597 		return eap_sim_client_error(data, id,
    598 					    EAP_SIM_INSUFFICIENT_NUM_OF_CHAL);
    599 	}
    600 	if (attr->num_chal > 3) {
    601 		wpa_printf(MSG_INFO, "EAP-SIM: Too many challenges "
    602 			   "(%lu)", (unsigned long) attr->num_chal);
    603 		return eap_sim_client_error(data, id,
    604 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
    605 	}
    606 
    607 	/* Verify that RANDs are different */
    608 	if (os_memcmp(attr->rand, attr->rand + GSM_RAND_LEN,
    609 		   GSM_RAND_LEN) == 0 ||
    610 	    (attr->num_chal > 2 &&
    611 	     (os_memcmp(attr->rand, attr->rand + 2 * GSM_RAND_LEN,
    612 			GSM_RAND_LEN) == 0 ||
    613 	      os_memcmp(attr->rand + GSM_RAND_LEN,
    614 			attr->rand + 2 * GSM_RAND_LEN,
    615 			GSM_RAND_LEN) == 0))) {
    616 		wpa_printf(MSG_INFO, "EAP-SIM: Same RAND used multiple times");
    617 		return eap_sim_client_error(data, id,
    618 					    EAP_SIM_RAND_NOT_FRESH);
    619 	}
    620 
    621 	os_memcpy(data->rand, attr->rand, attr->num_chal * GSM_RAND_LEN);
    622 	data->num_chal = attr->num_chal;
    623 
    624 	if (eap_sim_gsm_auth(sm, data)) {
    625 		wpa_printf(MSG_WARNING, "EAP-SIM: GSM authentication failed");
    626 		return eap_sim_client_error(data, id,
    627 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
    628 	}
    629 	if (data->last_eap_identity) {
    630 		identity = data->last_eap_identity;
    631 		identity_len = data->last_eap_identity_len;
    632 	} else if (data->pseudonym) {
    633 		identity = data->pseudonym;
    634 		identity_len = data->pseudonym_len;
    635 	} else
    636 		identity = eap_get_config_identity(sm, &identity_len);
    637 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Selected identity for MK "
    638 			  "derivation", identity, identity_len);
    639 	eap_sim_derive_mk(identity, identity_len, data->nonce_mt,
    640 			  data->selected_version, data->ver_list,
    641 			  data->ver_list_len, data->num_chal,
    642 			  (const u8 *) data->kc, data->mk);
    643 	eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
    644 			    data->emsk);
    645 	if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, data->nonce_mt,
    646 			       EAP_SIM_NONCE_MT_LEN)) {
    647 		wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
    648 			   "used invalid AT_MAC");
    649 		return eap_sim_client_error(data, id,
    650 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
    651 	}
    652 
    653 	/* Old reauthentication and pseudonym identities must not be used
    654 	 * anymore. In other words, if no new identities are received, full
    655 	 * authentication will be used on next reauthentication. */
    656 	eap_sim_clear_identities(data, CLEAR_PSEUDONYM | CLEAR_REAUTH_ID |
    657 				 CLEAR_EAP_ID);
    658 
    659 	if (attr->encr_data) {
    660 		u8 *decrypted;
    661 		decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
    662 					       attr->encr_data_len, attr->iv,
    663 					       &eattr, 0);
    664 		if (decrypted == NULL) {
    665 			return eap_sim_client_error(
    666 				data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET);
    667 		}
    668 		eap_sim_learn_ids(data, &eattr);
    669 		os_free(decrypted);
    670 	}
    671 
    672 	if (data->result_ind && attr->result_ind)
    673 		data->use_result_ind = 1;
    674 
    675 	if (data->state != FAILURE && data->state != RESULT_FAILURE) {
    676 		eap_sim_state(data, data->use_result_ind ?
    677 			      RESULT_SUCCESS : SUCCESS);
    678 	}
    679 
    680 	data->num_id_req = 0;
    681 	data->num_notification = 0;
    682 	/* RFC 4186 specifies that counter is initialized to one after
    683 	 * fullauth, but initializing it to zero makes it easier to implement
    684 	 * reauth verification. */
    685 	data->counter = 0;
    686 	return eap_sim_response_challenge(data, id);
    687 }
    688 
    689 
    690 static int eap_sim_process_notification_reauth(struct eap_sim_data *data,
    691 					       struct eap_sim_attrs *attr)
    692 {
    693 	struct eap_sim_attrs eattr;
    694 	u8 *decrypted;
    695 
    696 	if (attr->encr_data == NULL || attr->iv == NULL) {
    697 		wpa_printf(MSG_WARNING, "EAP-SIM: Notification message after "
    698 			   "reauth did not include encrypted data");
    699 		return -1;
    700 	}
    701 
    702 	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
    703 				       attr->encr_data_len, attr->iv, &eattr,
    704 				       0);
    705 	if (decrypted == NULL) {
    706 		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
    707 			   "data from notification message");
    708 		return -1;
    709 	}
    710 
    711 	if (eattr.counter < 0 || (size_t) eattr.counter != data->counter) {
    712 		wpa_printf(MSG_WARNING, "EAP-SIM: Counter in notification "
    713 			   "message does not match with counter in reauth "
    714 			   "message");
    715 		os_free(decrypted);
    716 		return -1;
    717 	}
    718 
    719 	os_free(decrypted);
    720 	return 0;
    721 }
    722 
    723 
    724 static int eap_sim_process_notification_auth(struct eap_sim_data *data,
    725 					     const struct wpabuf *reqData,
    726 					     struct eap_sim_attrs *attr)
    727 {
    728 	if (attr->mac == NULL) {
    729 		wpa_printf(MSG_INFO, "EAP-SIM: no AT_MAC in after_auth "
    730 			   "Notification message");
    731 		return -1;
    732 	}
    733 
    734 	if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0))
    735 	{
    736 		wpa_printf(MSG_WARNING, "EAP-SIM: Notification message "
    737 			   "used invalid AT_MAC");
    738 		return -1;
    739 	}
    740 
    741 	if (data->reauth &&
    742 	    eap_sim_process_notification_reauth(data, attr)) {
    743 		wpa_printf(MSG_WARNING, "EAP-SIM: Invalid notification "
    744 			   "message after reauth");
    745 		return -1;
    746 	}
    747 
    748 	return 0;
    749 }
    750 
    751 
    752 static struct wpabuf * eap_sim_process_notification(
    753 	struct eap_sm *sm, struct eap_sim_data *data, u8 id,
    754 	const struct wpabuf *reqData, struct eap_sim_attrs *attr)
    755 {
    756 	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Notification");
    757 	if (data->num_notification > 0) {
    758 		wpa_printf(MSG_INFO, "EAP-SIM: too many notification "
    759 			   "rounds (only one allowed)");
    760 		return eap_sim_client_error(data, id,
    761 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
    762 	}
    763 	data->num_notification++;
    764 	if (attr->notification == -1) {
    765 		wpa_printf(MSG_INFO, "EAP-SIM: no AT_NOTIFICATION in "
    766 			   "Notification message");
    767 		return eap_sim_client_error(data, id,
    768 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
    769 	}
    770 
    771 	if ((attr->notification & 0x4000) == 0 &&
    772 	    eap_sim_process_notification_auth(data, reqData, attr)) {
    773 		return eap_sim_client_error(data, id,
    774 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
    775 	}
    776 
    777 	eap_sim_report_notification(sm->msg_ctx, attr->notification, 0);
    778 	if (attr->notification >= 0 && attr->notification < 32768) {
    779 		eap_sim_state(data, FAILURE);
    780 	} else if (attr->notification == EAP_SIM_SUCCESS &&
    781 		   data->state == RESULT_SUCCESS)
    782 		eap_sim_state(data, SUCCESS);
    783 	return eap_sim_response_notification(data, id, attr->notification);
    784 }
    785 
    786 
    787 static struct wpabuf * eap_sim_process_reauthentication(
    788 	struct eap_sm *sm, struct eap_sim_data *data, u8 id,
    789 	const struct wpabuf *reqData, struct eap_sim_attrs *attr)
    790 {
    791 	struct eap_sim_attrs eattr;
    792 	u8 *decrypted;
    793 
    794 	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Reauthentication");
    795 
    796 	if (data->reauth_id == NULL) {
    797 		wpa_printf(MSG_WARNING, "EAP-SIM: Server is trying "
    798 			   "reauthentication, but no reauth_id available");
    799 		return eap_sim_client_error(data, id,
    800 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
    801 	}
    802 
    803 	data->reauth = 1;
    804 	if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0))
    805 	{
    806 		wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
    807 			   "did not have valid AT_MAC");
    808 		return eap_sim_client_error(data, id,
    809 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
    810 	}
    811 
    812 	if (attr->encr_data == NULL || attr->iv == NULL) {
    813 		wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
    814 			   "message did not include encrypted data");
    815 		return eap_sim_client_error(data, id,
    816 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
    817 	}
    818 
    819 	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
    820 				       attr->encr_data_len, attr->iv, &eattr,
    821 				       0);
    822 	if (decrypted == NULL) {
    823 		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
    824 			   "data from reauthentication message");
    825 		return eap_sim_client_error(data, id,
    826 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
    827 	}
    828 
    829 	if (eattr.nonce_s == NULL || eattr.counter < 0) {
    830 		wpa_printf(MSG_INFO, "EAP-SIM: (encr) No%s%s in reauth packet",
    831 			   !eattr.nonce_s ? " AT_NONCE_S" : "",
    832 			   eattr.counter < 0 ? " AT_COUNTER" : "");
    833 		os_free(decrypted);
    834 		return eap_sim_client_error(data, id,
    835 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
    836 	}
    837 
    838 	if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) {
    839 		wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid counter "
    840 			   "(%d <= %d)", eattr.counter, data->counter);
    841 		data->counter_too_small = eattr.counter;
    842 		/* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
    843 		 * reauth_id must not be used to start a new reauthentication.
    844 		 * However, since it was used in the last EAP-Response-Identity
    845 		 * packet, it has to saved for the following fullauth to be
    846 		 * used in MK derivation. */
    847 		os_free(data->last_eap_identity);
    848 		data->last_eap_identity = data->reauth_id;
    849 		data->last_eap_identity_len = data->reauth_id_len;
    850 		data->reauth_id = NULL;
    851 		data->reauth_id_len = 0;
    852 		os_free(decrypted);
    853 		return eap_sim_response_reauth(data, id, 1);
    854 	}
    855 	data->counter = eattr.counter;
    856 
    857 	os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN);
    858 	wpa_hexdump(MSG_DEBUG, "EAP-SIM: (encr) AT_NONCE_S",
    859 		    data->nonce_s, EAP_SIM_NONCE_S_LEN);
    860 
    861 	eap_sim_derive_keys_reauth(data->counter,
    862 				   data->reauth_id, data->reauth_id_len,
    863 				   data->nonce_s, data->mk, data->msk,
    864 				   data->emsk);
    865 	eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
    866 	eap_sim_learn_ids(data, &eattr);
    867 
    868 	if (data->result_ind && attr->result_ind)
    869 		data->use_result_ind = 1;
    870 
    871 	if (data->state != FAILURE && data->state != RESULT_FAILURE) {
    872 		eap_sim_state(data, data->use_result_ind ?
    873 			      RESULT_SUCCESS : SUCCESS);
    874 	}
    875 
    876 	data->num_id_req = 0;
    877 	data->num_notification = 0;
    878 	if (data->counter > EAP_SIM_MAX_FAST_REAUTHS) {
    879 		wpa_printf(MSG_DEBUG, "EAP-SIM: Maximum number of "
    880 			   "fast reauths performed - force fullauth");
    881 		eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
    882 	}
    883 	os_free(decrypted);
    884 	return eap_sim_response_reauth(data, id, 0);
    885 }
    886 
    887 
    888 static struct wpabuf * eap_sim_process(struct eap_sm *sm, void *priv,
    889 				       struct eap_method_ret *ret,
    890 				       const struct wpabuf *reqData)
    891 {
    892 	struct eap_sim_data *data = priv;
    893 	const struct eap_hdr *req;
    894 	u8 subtype, id;
    895 	struct wpabuf *res;
    896 	const u8 *pos;
    897 	struct eap_sim_attrs attr;
    898 	size_t len;
    899 
    900 	wpa_hexdump_buf(MSG_DEBUG, "EAP-SIM: EAP data", reqData);
    901 	if (eap_get_config_identity(sm, &len) == NULL) {
    902 		wpa_printf(MSG_INFO, "EAP-SIM: Identity not configured");
    903 		eap_sm_request_identity(sm);
    904 		ret->ignore = TRUE;
    905 		return NULL;
    906 	}
    907 
    908 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, reqData, &len);
    909 	if (pos == NULL || len < 1) {
    910 		ret->ignore = TRUE;
    911 		return NULL;
    912 	}
    913 	req = wpabuf_head(reqData);
    914 	id = req->identifier;
    915 	len = be_to_host16(req->length);
    916 
    917 	ret->ignore = FALSE;
    918 	ret->methodState = METHOD_MAY_CONT;
    919 	ret->decision = DECISION_FAIL;
    920 	ret->allowNotifications = TRUE;
    921 
    922 	subtype = *pos++;
    923 	wpa_printf(MSG_DEBUG, "EAP-SIM: Subtype=%d", subtype);
    924 	pos += 2; /* Reserved */
    925 
    926 	if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr, 0,
    927 			       0)) {
    928 		res = eap_sim_client_error(data, id,
    929 					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
    930 		goto done;
    931 	}
    932 
    933 	switch (subtype) {
    934 	case EAP_SIM_SUBTYPE_START:
    935 		res = eap_sim_process_start(sm, data, id, &attr);
    936 		break;
    937 	case EAP_SIM_SUBTYPE_CHALLENGE:
    938 		res = eap_sim_process_challenge(sm, data, id, reqData, &attr);
    939 		break;
    940 	case EAP_SIM_SUBTYPE_NOTIFICATION:
    941 		res = eap_sim_process_notification(sm, data, id, reqData,
    942 						   &attr);
    943 		break;
    944 	case EAP_SIM_SUBTYPE_REAUTHENTICATION:
    945 		res = eap_sim_process_reauthentication(sm, data, id, reqData,
    946 						       &attr);
    947 		break;
    948 	case EAP_SIM_SUBTYPE_CLIENT_ERROR:
    949 		wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Client-Error");
    950 		res = eap_sim_client_error(data, id,
    951 					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
    952 		break;
    953 	default:
    954 		wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown subtype=%d", subtype);
    955 		res = eap_sim_client_error(data, id,
    956 					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
    957 		break;
    958 	}
    959 
    960 done:
    961 	if (data->state == FAILURE) {
    962 		ret->decision = DECISION_FAIL;
    963 		ret->methodState = METHOD_DONE;
    964 	} else if (data->state == SUCCESS) {
    965 		ret->decision = data->use_result_ind ?
    966 			DECISION_UNCOND_SUCC : DECISION_COND_SUCC;
    967 		ret->methodState = data->use_result_ind ?
    968 			METHOD_DONE : METHOD_MAY_CONT;
    969 	} else if (data->state == RESULT_FAILURE)
    970 		ret->methodState = METHOD_CONT;
    971 	else if (data->state == RESULT_SUCCESS)
    972 		ret->methodState = METHOD_CONT;
    973 
    974 	if (ret->methodState == METHOD_DONE) {
    975 		ret->allowNotifications = FALSE;
    976 	}
    977 
    978 	return res;
    979 }
    980 
    981 
    982 static Boolean eap_sim_has_reauth_data(struct eap_sm *sm, void *priv)
    983 {
    984 	struct eap_sim_data *data = priv;
    985 	return data->pseudonym || data->reauth_id;
    986 }
    987 
    988 
    989 static void eap_sim_deinit_for_reauth(struct eap_sm *sm, void *priv)
    990 {
    991 	struct eap_sim_data *data = priv;
    992 	eap_sim_clear_identities(data, CLEAR_EAP_ID);
    993 	data->use_result_ind = 0;
    994 }
    995 
    996 
    997 static void * eap_sim_init_for_reauth(struct eap_sm *sm, void *priv)
    998 {
    999 	struct eap_sim_data *data = priv;
   1000 	if (os_get_random(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
   1001 		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data "
   1002 			   "for NONCE_MT");
   1003 		os_free(data);
   1004 		return NULL;
   1005 	}
   1006 	data->num_id_req = 0;
   1007 	data->num_notification = 0;
   1008 	eap_sim_state(data, CONTINUE);
   1009 	return priv;
   1010 }
   1011 
   1012 
   1013 static const u8 * eap_sim_get_identity(struct eap_sm *sm, void *priv,
   1014 				       size_t *len)
   1015 {
   1016 	struct eap_sim_data *data = priv;
   1017 
   1018 	if (data->reauth_id) {
   1019 		*len = data->reauth_id_len;
   1020 		return data->reauth_id;
   1021 	}
   1022 
   1023 	if (data->pseudonym) {
   1024 		*len = data->pseudonym_len;
   1025 		return data->pseudonym;
   1026 	}
   1027 
   1028 	return NULL;
   1029 }
   1030 
   1031 
   1032 static Boolean eap_sim_isKeyAvailable(struct eap_sm *sm, void *priv)
   1033 {
   1034 	struct eap_sim_data *data = priv;
   1035 	return data->state == SUCCESS;
   1036 }
   1037 
   1038 
   1039 static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
   1040 {
   1041 	struct eap_sim_data *data = priv;
   1042 	u8 *key;
   1043 
   1044 	if (data->state != SUCCESS)
   1045 		return NULL;
   1046 
   1047 	key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
   1048 	if (key == NULL)
   1049 		return NULL;
   1050 
   1051 	*len = EAP_SIM_KEYING_DATA_LEN;
   1052 	os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
   1053 
   1054 	return key;
   1055 }
   1056 
   1057 
   1058 static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
   1059 {
   1060 	struct eap_sim_data *data = priv;
   1061 	u8 *key;
   1062 
   1063 	if (data->state != SUCCESS)
   1064 		return NULL;
   1065 
   1066 	key = os_malloc(EAP_EMSK_LEN);
   1067 	if (key == NULL)
   1068 		return NULL;
   1069 
   1070 	*len = EAP_EMSK_LEN;
   1071 	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
   1072 
   1073 	return key;
   1074 }
   1075 
   1076 
   1077 int eap_peer_sim_register(void)
   1078 {
   1079 	struct eap_method *eap;
   1080 	int ret;
   1081 
   1082 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
   1083 				    EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM");
   1084 	if (eap == NULL)
   1085 		return -1;
   1086 
   1087 	eap->init = eap_sim_init;
   1088 	eap->deinit = eap_sim_deinit;
   1089 	eap->process = eap_sim_process;
   1090 	eap->isKeyAvailable = eap_sim_isKeyAvailable;
   1091 	eap->getKey = eap_sim_getKey;
   1092 	eap->has_reauth_data = eap_sim_has_reauth_data;
   1093 	eap->deinit_for_reauth = eap_sim_deinit_for_reauth;
   1094 	eap->init_for_reauth = eap_sim_init_for_reauth;
   1095 	eap->get_identity = eap_sim_get_identity;
   1096 	eap->get_emsk = eap_sim_get_emsk;
   1097 
   1098 	ret = eap_peer_method_register(eap);
   1099 	if (ret)
   1100 		eap_peer_method_free(eap);
   1101 	return ret;
   1102 }
   1103