Home | History | Annotate | Download | only in eap_server
      1 /*
      2  * hostapd / EAP-SIM (RFC 4186)
      3  * Copyright (c) 2005-2012, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This software may be distributed under the terms of the BSD license.
      6  * See README for more details.
      7  */
      8 
      9 #include "includes.h"
     10 
     11 #include "common.h"
     12 #include "crypto/random.h"
     13 #include "eap_server/eap_i.h"
     14 #include "eap_common/eap_sim_common.h"
     15 #include "eap_server/eap_sim_db.h"
     16 
     17 
     18 struct eap_sim_data {
     19 	u8 mk[EAP_SIM_MK_LEN];
     20 	u8 nonce_mt[EAP_SIM_NONCE_MT_LEN];
     21 	u8 nonce_s[EAP_SIM_NONCE_S_LEN];
     22 	u8 k_aut[EAP_SIM_K_AUT_LEN];
     23 	u8 k_encr[EAP_SIM_K_ENCR_LEN];
     24 	u8 msk[EAP_SIM_KEYING_DATA_LEN];
     25 	u8 emsk[EAP_EMSK_LEN];
     26 	u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
     27 	u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
     28 	u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
     29 	int num_chal;
     30 	enum {
     31 		START, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE
     32 	} state;
     33 	char *next_pseudonym;
     34 	char *next_reauth_id;
     35 	u16 counter;
     36 	struct eap_sim_reauth *reauth;
     37 	u16 notification;
     38 	int use_result_ind;
     39 	int start_round;
     40 	char permanent[20]; /* Permanent username */
     41 };
     42 
     43 
     44 static const char * eap_sim_state_txt(int state)
     45 {
     46 	switch (state) {
     47 	case START:
     48 		return "START";
     49 	case CHALLENGE:
     50 		return "CHALLENGE";
     51 	case REAUTH:
     52 		return "REAUTH";
     53 	case SUCCESS:
     54 		return "SUCCESS";
     55 	case FAILURE:
     56 		return "FAILURE";
     57 	case NOTIFICATION:
     58 		return "NOTIFICATION";
     59 	default:
     60 		return "Unknown?!";
     61 	}
     62 }
     63 
     64 
     65 static void eap_sim_state(struct eap_sim_data *data, int state)
     66 {
     67 	wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s",
     68 		   eap_sim_state_txt(data->state),
     69 		   eap_sim_state_txt(state));
     70 	data->state = state;
     71 }
     72 
     73 
     74 static void * eap_sim_init(struct eap_sm *sm)
     75 {
     76 	struct eap_sim_data *data;
     77 
     78 	if (sm->eap_sim_db_priv == NULL) {
     79 		wpa_printf(MSG_WARNING, "EAP-SIM: eap_sim_db not configured");
     80 		return NULL;
     81 	}
     82 
     83 	data = os_zalloc(sizeof(*data));
     84 	if (data == NULL)
     85 		return NULL;
     86 	data->state = START;
     87 
     88 	return data;
     89 }
     90 
     91 
     92 static void eap_sim_reset(struct eap_sm *sm, void *priv)
     93 {
     94 	struct eap_sim_data *data = priv;
     95 	os_free(data->next_pseudonym);
     96 	os_free(data->next_reauth_id);
     97 	bin_clear_free(data, sizeof(*data));
     98 }
     99 
    100 
    101 static struct wpabuf * eap_sim_build_start(struct eap_sm *sm,
    102 					   struct eap_sim_data *data, u8 id)
    103 {
    104 	struct eap_sim_msg *msg;
    105 	u8 ver[2];
    106 
    107 	wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Start");
    108 	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
    109 			       EAP_SIM_SUBTYPE_START);
    110 	data->start_round++;
    111 	if (data->start_round == 1) {
    112 		/*
    113 		 * RFC 4186, Chap. 4.2.4 recommends that identity from EAP is
    114 		 * ignored and the SIM/Start is used to request the identity.
    115 		 */
    116 		wpa_printf(MSG_DEBUG, "   AT_ANY_ID_REQ");
    117 		eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
    118 	} else if (data->start_round > 3) {
    119 		/* Cannot use more than three rounds of Start messages */
    120 		eap_sim_msg_free(msg);
    121 		return NULL;
    122 	} else if (data->start_round == 0) {
    123 		/*
    124 		 * This is a special case that is used to recover from
    125 		 * AT_COUNTER_TOO_SMALL during re-authentication. Since we
    126 		 * already know the identity of the peer, there is no need to
    127 		 * request any identity in this case.
    128 		 */
    129 	} else if (sm->identity && sm->identity_len > 0 &&
    130 		   sm->identity[0] == EAP_SIM_REAUTH_ID_PREFIX) {
    131 		/* Reauth id may have expired - try fullauth */
    132 		wpa_printf(MSG_DEBUG, "   AT_FULLAUTH_ID_REQ");
    133 		eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0, NULL, 0);
    134 	} else {
    135 		wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
    136 		eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
    137 	}
    138 	wpa_printf(MSG_DEBUG, "   AT_VERSION_LIST");
    139 	ver[0] = 0;
    140 	ver[1] = EAP_SIM_VERSION;
    141 	eap_sim_msg_add(msg, EAP_SIM_AT_VERSION_LIST, sizeof(ver),
    142 			ver, sizeof(ver));
    143 	return eap_sim_msg_finish(msg, EAP_TYPE_SIM, NULL, NULL, 0);
    144 }
    145 
    146 
    147 static int eap_sim_build_encr(struct eap_sm *sm, struct eap_sim_data *data,
    148 			      struct eap_sim_msg *msg, u16 counter,
    149 			      const u8 *nonce_s)
    150 {
    151 	os_free(data->next_pseudonym);
    152 	if (nonce_s == NULL) {
    153 		data->next_pseudonym =
    154 			eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv,
    155 						      EAP_SIM_DB_SIM);
    156 	} else {
    157 		/* Do not update pseudonym during re-authentication */
    158 		data->next_pseudonym = NULL;
    159 	}
    160 	os_free(data->next_reauth_id);
    161 	if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) {
    162 		data->next_reauth_id =
    163 			eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv,
    164 						      EAP_SIM_DB_SIM);
    165 	} else {
    166 		wpa_printf(MSG_DEBUG, "EAP-SIM: Max fast re-authentication "
    167 			   "count exceeded - force full authentication");
    168 		data->next_reauth_id = NULL;
    169 	}
    170 
    171 	if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
    172 	    counter == 0 && nonce_s == NULL)
    173 		return 0;
    174 
    175 	wpa_printf(MSG_DEBUG, "   AT_IV");
    176 	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
    177 	eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
    178 
    179 	if (counter > 0) {
    180 		wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)", counter);
    181 		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
    182 	}
    183 
    184 	if (nonce_s) {
    185 		wpa_printf(MSG_DEBUG, "   *AT_NONCE_S");
    186 		eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
    187 				EAP_SIM_NONCE_S_LEN);
    188 	}
    189 
    190 	if (data->next_pseudonym) {
    191 		wpa_printf(MSG_DEBUG, "   *AT_NEXT_PSEUDONYM (%s)",
    192 			   data->next_pseudonym);
    193 		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
    194 				os_strlen(data->next_pseudonym),
    195 				(u8 *) data->next_pseudonym,
    196 				os_strlen(data->next_pseudonym));
    197 	}
    198 
    199 	if (data->next_reauth_id) {
    200 		wpa_printf(MSG_DEBUG, "   *AT_NEXT_REAUTH_ID (%s)",
    201 			   data->next_reauth_id);
    202 		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
    203 				os_strlen(data->next_reauth_id),
    204 				(u8 *) data->next_reauth_id,
    205 				os_strlen(data->next_reauth_id));
    206 	}
    207 
    208 	if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
    209 		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
    210 			   "AT_ENCR_DATA");
    211 		return -1;
    212 	}
    213 
    214 	return 0;
    215 }
    216 
    217 
    218 static struct wpabuf * eap_sim_build_challenge(struct eap_sm *sm,
    219 					       struct eap_sim_data *data,
    220 					       u8 id)
    221 {
    222 	struct eap_sim_msg *msg;
    223 
    224 	wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Challenge");
    225 	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
    226 			       EAP_SIM_SUBTYPE_CHALLENGE);
    227 	wpa_printf(MSG_DEBUG, "   AT_RAND");
    228 	eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, (u8 *) data->rand,
    229 			data->num_chal * GSM_RAND_LEN);
    230 
    231 	if (eap_sim_build_encr(sm, data, msg, 0, NULL)) {
    232 		eap_sim_msg_free(msg);
    233 		return NULL;
    234 	}
    235 
    236 	if (sm->eap_sim_aka_result_ind) {
    237 		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
    238 		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
    239 	}
    240 
    241 	wpa_printf(MSG_DEBUG, "   AT_MAC");
    242 	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
    243 	return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut,
    244 				  data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
    245 }
    246 
    247 
    248 static struct wpabuf * eap_sim_build_reauth(struct eap_sm *sm,
    249 					    struct eap_sim_data *data, u8 id)
    250 {
    251 	struct eap_sim_msg *msg;
    252 
    253 	wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Re-authentication");
    254 
    255 	if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN))
    256 		return NULL;
    257 	wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: NONCE_S",
    258 			data->nonce_s, EAP_SIM_NONCE_S_LEN);
    259 
    260 	eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
    261 			    data->emsk);
    262 	eap_sim_derive_keys_reauth(data->counter, sm->identity,
    263 				   sm->identity_len, data->nonce_s, data->mk,
    264 				   data->msk, data->emsk);
    265 
    266 	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
    267 			       EAP_SIM_SUBTYPE_REAUTHENTICATION);
    268 
    269 	if (eap_sim_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
    270 		eap_sim_msg_free(msg);
    271 		return NULL;
    272 	}
    273 
    274 	if (sm->eap_sim_aka_result_ind) {
    275 		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
    276 		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
    277 	}
    278 
    279 	wpa_printf(MSG_DEBUG, "   AT_MAC");
    280 	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
    281 	return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut, NULL, 0);
    282 }
    283 
    284 
    285 static struct wpabuf * eap_sim_build_notification(struct eap_sm *sm,
    286 						  struct eap_sim_data *data,
    287 						  u8 id)
    288 {
    289 	struct eap_sim_msg *msg;
    290 
    291 	wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Notification");
    292 	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
    293 			       EAP_SIM_SUBTYPE_NOTIFICATION);
    294 	wpa_printf(MSG_DEBUG, "   AT_NOTIFICATION (%d)", data->notification);
    295 	eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification,
    296 			NULL, 0);
    297 	if (data->use_result_ind) {
    298 		if (data->reauth) {
    299 			wpa_printf(MSG_DEBUG, "   AT_IV");
    300 			wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
    301 			eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
    302 						   EAP_SIM_AT_ENCR_DATA);
    303 			wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)",
    304 				   data->counter);
    305 			eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
    306 					NULL, 0);
    307 
    308 			if (eap_sim_msg_add_encr_end(msg, data->k_encr,
    309 						     EAP_SIM_AT_PADDING)) {
    310 				wpa_printf(MSG_WARNING, "EAP-SIM: Failed to "
    311 					   "encrypt AT_ENCR_DATA");
    312 				eap_sim_msg_free(msg);
    313 				return NULL;
    314 			}
    315 		}
    316 
    317 		wpa_printf(MSG_DEBUG, "   AT_MAC");
    318 		eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
    319 	}
    320 	return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut, NULL, 0);
    321 }
    322 
    323 
    324 static struct wpabuf * eap_sim_buildReq(struct eap_sm *sm, void *priv, u8 id)
    325 {
    326 	struct eap_sim_data *data = priv;
    327 
    328 	switch (data->state) {
    329 	case START:
    330 		return eap_sim_build_start(sm, data, id);
    331 	case CHALLENGE:
    332 		return eap_sim_build_challenge(sm, data, id);
    333 	case REAUTH:
    334 		return eap_sim_build_reauth(sm, data, id);
    335 	case NOTIFICATION:
    336 		return eap_sim_build_notification(sm, data, id);
    337 	default:
    338 		wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
    339 			   "buildReq", data->state);
    340 		break;
    341 	}
    342 	return NULL;
    343 }
    344 
    345 
    346 static Boolean eap_sim_check(struct eap_sm *sm, void *priv,
    347 			     struct wpabuf *respData)
    348 {
    349 	const u8 *pos;
    350 	size_t len;
    351 
    352 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len);
    353 	if (pos == NULL || len < 3) {
    354 		wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame");
    355 		return TRUE;
    356 	}
    357 
    358 	return FALSE;
    359 }
    360 
    361 
    362 static Boolean eap_sim_unexpected_subtype(struct eap_sim_data *data,
    363 					  u8 subtype)
    364 {
    365 	if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR)
    366 		return FALSE;
    367 
    368 	switch (data->state) {
    369 	case START:
    370 		if (subtype != EAP_SIM_SUBTYPE_START) {
    371 			wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
    372 				   "subtype %d", subtype);
    373 			return TRUE;
    374 		}
    375 		break;
    376 	case CHALLENGE:
    377 		if (subtype != EAP_SIM_SUBTYPE_CHALLENGE) {
    378 			wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
    379 				   "subtype %d", subtype);
    380 			return TRUE;
    381 		}
    382 		break;
    383 	case REAUTH:
    384 		if (subtype != EAP_SIM_SUBTYPE_REAUTHENTICATION) {
    385 			wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
    386 				   "subtype %d", subtype);
    387 			return TRUE;
    388 		}
    389 		break;
    390 	case NOTIFICATION:
    391 		if (subtype != EAP_SIM_SUBTYPE_NOTIFICATION) {
    392 			wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
    393 				   "subtype %d", subtype);
    394 			return TRUE;
    395 		}
    396 		break;
    397 	default:
    398 		wpa_printf(MSG_INFO, "EAP-SIM: Unexpected state (%d) for "
    399 			   "processing a response", data->state);
    400 		return TRUE;
    401 	}
    402 
    403 	return FALSE;
    404 }
    405 
    406 
    407 static int eap_sim_supported_ver(struct eap_sim_data *data, int version)
    408 {
    409 	return version == EAP_SIM_VERSION;
    410 }
    411 
    412 
    413 static void eap_sim_process_start(struct eap_sm *sm,
    414 				  struct eap_sim_data *data,
    415 				  struct wpabuf *respData,
    416 				  struct eap_sim_attrs *attr)
    417 {
    418 	size_t identity_len;
    419 	u8 ver_list[2];
    420 	u8 *new_identity;
    421 	char *username;
    422 
    423 	wpa_printf(MSG_DEBUG, "EAP-SIM: Receive start response");
    424 
    425 	if (data->start_round == 0) {
    426 		/*
    427 		 * Special case for AT_COUNTER_TOO_SMALL recovery - no identity
    428 		 * was requested since we already know it.
    429 		 */
    430 		goto skip_id_update;
    431 	}
    432 
    433 	/*
    434 	 * We always request identity in SIM/Start, so the peer is required to
    435 	 * have replied with one.
    436 	 */
    437 	if (!attr->identity || attr->identity_len == 0) {
    438 		wpa_printf(MSG_DEBUG, "EAP-SIM: Peer did not provide any "
    439 			   "identity");
    440 		goto failed;
    441 	}
    442 
    443 	new_identity = os_malloc(attr->identity_len);
    444 	if (new_identity == NULL)
    445 		goto failed;
    446 	os_free(sm->identity);
    447 	sm->identity = new_identity;
    448 	os_memcpy(sm->identity, attr->identity, attr->identity_len);
    449 	sm->identity_len = attr->identity_len;
    450 
    451 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
    452 			  sm->identity, sm->identity_len);
    453 	username = sim_get_username(sm->identity, sm->identity_len);
    454 	if (username == NULL)
    455 		goto failed;
    456 
    457 	if (username[0] == EAP_SIM_REAUTH_ID_PREFIX) {
    458 		wpa_printf(MSG_DEBUG, "EAP-SIM: Reauth username '%s'",
    459 			   username);
    460 		data->reauth = eap_sim_db_get_reauth_entry(
    461 			sm->eap_sim_db_priv, username);
    462 		os_free(username);
    463 		if (data->reauth == NULL) {
    464 			wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown reauth "
    465 				   "identity - request full auth identity");
    466 			/* Remain in START state for another round */
    467 			return;
    468 		}
    469 		wpa_printf(MSG_DEBUG, "EAP-SIM: Using fast re-authentication");
    470 		os_strlcpy(data->permanent, data->reauth->permanent,
    471 			   sizeof(data->permanent));
    472 		data->counter = data->reauth->counter;
    473 		os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN);
    474 		eap_sim_state(data, REAUTH);
    475 		return;
    476 	}
    477 
    478 	if (username[0] == EAP_SIM_PSEUDONYM_PREFIX) {
    479 		const char *permanent;
    480 		wpa_printf(MSG_DEBUG, "EAP-SIM: Pseudonym username '%s'",
    481 			   username);
    482 		permanent = eap_sim_db_get_permanent(
    483 			sm->eap_sim_db_priv, username);
    484 		os_free(username);
    485 		if (permanent == NULL) {
    486 			wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown pseudonym "
    487 				   "identity - request permanent identity");
    488 			/* Remain in START state for another round */
    489 			return;
    490 		}
    491 		os_strlcpy(data->permanent, permanent,
    492 			   sizeof(data->permanent));
    493 	} else if (username[0] == EAP_SIM_PERMANENT_PREFIX) {
    494 		wpa_printf(MSG_DEBUG, "EAP-SIM: Permanent username '%s'",
    495 			   username);
    496 		os_strlcpy(data->permanent, username, sizeof(data->permanent));
    497 		os_free(username);
    498 	} else {
    499 		wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized username '%s'",
    500 			   username);
    501 		os_free(username);
    502 		goto failed;
    503 	}
    504 
    505 skip_id_update:
    506 	/* Full authentication */
    507 
    508 	if (attr->nonce_mt == NULL || attr->selected_version < 0) {
    509 		wpa_printf(MSG_DEBUG, "EAP-SIM: Start/Response missing "
    510 			   "required attributes");
    511 		goto failed;
    512 	}
    513 
    514 	if (!eap_sim_supported_ver(data, attr->selected_version)) {
    515 		wpa_printf(MSG_DEBUG, "EAP-SIM: Peer selected unsupported "
    516 			   "version %d", attr->selected_version);
    517 		goto failed;
    518 	}
    519 
    520 	data->counter = 0; /* reset re-auth counter since this is full auth */
    521 	data->reauth = NULL;
    522 
    523 	data->num_chal = eap_sim_db_get_gsm_triplets(
    524 		sm->eap_sim_db_priv, data->permanent, EAP_SIM_MAX_CHAL,
    525 		(u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm);
    526 	if (data->num_chal == EAP_SIM_DB_PENDING) {
    527 		wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets "
    528 			   "not yet available - pending request");
    529 		sm->method_pending = METHOD_PENDING_WAIT;
    530 		return;
    531 	}
    532 	if (data->num_chal < 2) {
    533 		wpa_printf(MSG_INFO, "EAP-SIM: Failed to get GSM "
    534 			   "authentication triplets for the peer");
    535 		goto failed;
    536 	}
    537 
    538 	identity_len = sm->identity_len;
    539 	while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') {
    540 		wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop last null "
    541 			   "character from identity");
    542 		identity_len--;
    543 	}
    544 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity for MK derivation",
    545 			  sm->identity, identity_len);
    546 
    547 	os_memcpy(data->nonce_mt, attr->nonce_mt, EAP_SIM_NONCE_MT_LEN);
    548 	WPA_PUT_BE16(ver_list, EAP_SIM_VERSION);
    549 	eap_sim_derive_mk(sm->identity, identity_len, attr->nonce_mt,
    550 			  attr->selected_version, ver_list, sizeof(ver_list),
    551 			  data->num_chal, (const u8 *) data->kc, data->mk);
    552 	eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
    553 			    data->emsk);
    554 
    555 	eap_sim_state(data, CHALLENGE);
    556 	return;
    557 
    558 failed:
    559 	data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
    560 	eap_sim_state(data, NOTIFICATION);
    561 }
    562 
    563 
    564 static void eap_sim_process_challenge(struct eap_sm *sm,
    565 				      struct eap_sim_data *data,
    566 				      struct wpabuf *respData,
    567 				      struct eap_sim_attrs *attr)
    568 {
    569 	if (attr->mac == NULL ||
    570 	    eap_sim_verify_mac(data->k_aut, respData, attr->mac,
    571 			       (u8 *) data->sres,
    572 			       data->num_chal * EAP_SIM_SRES_LEN)) {
    573 		wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
    574 			   "did not include valid AT_MAC");
    575 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
    576 		eap_sim_state(data, NOTIFICATION);
    577 		return;
    578 	}
    579 
    580 	wpa_printf(MSG_DEBUG, "EAP-SIM: Challenge response includes the "
    581 		   "correct AT_MAC");
    582 	if (sm->eap_sim_aka_result_ind && attr->result_ind) {
    583 		data->use_result_ind = 1;
    584 		data->notification = EAP_SIM_SUCCESS;
    585 		eap_sim_state(data, NOTIFICATION);
    586 	} else
    587 		eap_sim_state(data, SUCCESS);
    588 
    589 	if (data->next_pseudonym) {
    590 		eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent,
    591 					 data->next_pseudonym);
    592 		data->next_pseudonym = NULL;
    593 	}
    594 	if (data->next_reauth_id) {
    595 		eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent,
    596 				      data->next_reauth_id, data->counter + 1,
    597 				      data->mk);
    598 		data->next_reauth_id = NULL;
    599 	}
    600 }
    601 
    602 
    603 static void eap_sim_process_reauth(struct eap_sm *sm,
    604 				   struct eap_sim_data *data,
    605 				   struct wpabuf *respData,
    606 				   struct eap_sim_attrs *attr)
    607 {
    608 	struct eap_sim_attrs eattr;
    609 	u8 *decrypted = NULL;
    610 
    611 	if (attr->mac == NULL ||
    612 	    eap_sim_verify_mac(data->k_aut, respData, attr->mac, data->nonce_s,
    613 			       EAP_SIM_NONCE_S_LEN)) {
    614 		wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message "
    615 			   "did not include valid AT_MAC");
    616 		goto fail;
    617 	}
    618 
    619 	if (attr->encr_data == NULL || attr->iv == NULL) {
    620 		wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
    621 			   "message did not include encrypted data");
    622 		goto fail;
    623 	}
    624 
    625 	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
    626 				       attr->encr_data_len, attr->iv, &eattr,
    627 				       0);
    628 	if (decrypted == NULL) {
    629 		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
    630 			   "data from reauthentication message");
    631 		goto fail;
    632 	}
    633 
    634 	if (eattr.counter != data->counter) {
    635 		wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message "
    636 			   "used incorrect counter %u, expected %u",
    637 			   eattr.counter, data->counter);
    638 		goto fail;
    639 	}
    640 	os_free(decrypted);
    641 	decrypted = NULL;
    642 
    643 	wpa_printf(MSG_DEBUG, "EAP-SIM: Re-authentication response includes "
    644 		   "the correct AT_MAC");
    645 
    646 	if (eattr.counter_too_small) {
    647 		wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response "
    648 			   "included AT_COUNTER_TOO_SMALL - starting full "
    649 			   "authentication");
    650 		data->start_round = -1;
    651 		eap_sim_state(data, START);
    652 		return;
    653 	}
    654 
    655 	if (sm->eap_sim_aka_result_ind && attr->result_ind) {
    656 		data->use_result_ind = 1;
    657 		data->notification = EAP_SIM_SUCCESS;
    658 		eap_sim_state(data, NOTIFICATION);
    659 	} else
    660 		eap_sim_state(data, SUCCESS);
    661 
    662 	if (data->next_reauth_id) {
    663 		eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent,
    664 				      data->next_reauth_id,
    665 				      data->counter + 1, data->mk);
    666 		data->next_reauth_id = NULL;
    667 	} else {
    668 		eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
    669 		data->reauth = NULL;
    670 	}
    671 
    672 	return;
    673 
    674 fail:
    675 	data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
    676 	eap_sim_state(data, NOTIFICATION);
    677 	eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
    678 	data->reauth = NULL;
    679 	os_free(decrypted);
    680 }
    681 
    682 
    683 static void eap_sim_process_client_error(struct eap_sm *sm,
    684 					 struct eap_sim_data *data,
    685 					 struct wpabuf *respData,
    686 					 struct eap_sim_attrs *attr)
    687 {
    688 	wpa_printf(MSG_DEBUG, "EAP-SIM: Client reported error %d",
    689 		   attr->client_error_code);
    690 	if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
    691 		eap_sim_state(data, SUCCESS);
    692 	else
    693 		eap_sim_state(data, FAILURE);
    694 }
    695 
    696 
    697 static void eap_sim_process_notification(struct eap_sm *sm,
    698 					 struct eap_sim_data *data,
    699 					 struct wpabuf *respData,
    700 					 struct eap_sim_attrs *attr)
    701 {
    702 	wpa_printf(MSG_DEBUG, "EAP-SIM: Client replied to notification");
    703 	if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
    704 		eap_sim_state(data, SUCCESS);
    705 	else
    706 		eap_sim_state(data, FAILURE);
    707 }
    708 
    709 
    710 static void eap_sim_process(struct eap_sm *sm, void *priv,
    711 			    struct wpabuf *respData)
    712 {
    713 	struct eap_sim_data *data = priv;
    714 	const u8 *pos, *end;
    715 	u8 subtype;
    716 	size_t len;
    717 	struct eap_sim_attrs attr;
    718 
    719 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len);
    720 	if (pos == NULL || len < 3)
    721 		return;
    722 
    723 	end = pos + len;
    724 	subtype = *pos;
    725 	pos += 3;
    726 
    727 	if (eap_sim_unexpected_subtype(data, subtype)) {
    728 		wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized or unexpected "
    729 			   "EAP-SIM Subtype in EAP Response");
    730 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
    731 		eap_sim_state(data, NOTIFICATION);
    732 		return;
    733 	}
    734 
    735 	if (eap_sim_parse_attr(pos, end, &attr, 0, 0)) {
    736 		wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to parse attributes");
    737 		if (subtype != EAP_SIM_SUBTYPE_CLIENT_ERROR &&
    738 		    (data->state == START || data->state == CHALLENGE ||
    739 		     data->state == REAUTH)) {
    740 			data->notification =
    741 				EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
    742 			eap_sim_state(data, NOTIFICATION);
    743 			return;
    744 		}
    745 		eap_sim_state(data, FAILURE);
    746 		return;
    747 	}
    748 
    749 	if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) {
    750 		eap_sim_process_client_error(sm, data, respData, &attr);
    751 		return;
    752 	}
    753 
    754 	switch (data->state) {
    755 	case START:
    756 		eap_sim_process_start(sm, data, respData, &attr);
    757 		break;
    758 	case CHALLENGE:
    759 		eap_sim_process_challenge(sm, data, respData, &attr);
    760 		break;
    761 	case REAUTH:
    762 		eap_sim_process_reauth(sm, data, respData, &attr);
    763 		break;
    764 	case NOTIFICATION:
    765 		eap_sim_process_notification(sm, data, respData, &attr);
    766 		break;
    767 	default:
    768 		wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
    769 			   "process", data->state);
    770 		break;
    771 	}
    772 }
    773 
    774 
    775 static Boolean eap_sim_isDone(struct eap_sm *sm, void *priv)
    776 {
    777 	struct eap_sim_data *data = priv;
    778 	return data->state == SUCCESS || data->state == FAILURE;
    779 }
    780 
    781 
    782 static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
    783 {
    784 	struct eap_sim_data *data = priv;
    785 	u8 *key;
    786 
    787 	if (data->state != SUCCESS)
    788 		return NULL;
    789 
    790 	key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
    791 	if (key == NULL)
    792 		return NULL;
    793 	os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
    794 	*len = EAP_SIM_KEYING_DATA_LEN;
    795 	return key;
    796 }
    797 
    798 
    799 static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
    800 {
    801 	struct eap_sim_data *data = priv;
    802 	u8 *key;
    803 
    804 	if (data->state != SUCCESS)
    805 		return NULL;
    806 
    807 	key = os_malloc(EAP_EMSK_LEN);
    808 	if (key == NULL)
    809 		return NULL;
    810 	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
    811 	*len = EAP_EMSK_LEN;
    812 	return key;
    813 }
    814 
    815 
    816 static Boolean eap_sim_isSuccess(struct eap_sm *sm, void *priv)
    817 {
    818 	struct eap_sim_data *data = priv;
    819 	return data->state == SUCCESS;
    820 }
    821 
    822 
    823 static u8 * eap_sim_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
    824 {
    825 	struct eap_sim_data *data = priv;
    826 	u8 *id;
    827 
    828 	if (data->state != SUCCESS)
    829 		return NULL;
    830 
    831 	*len = 1 + data->num_chal * GSM_RAND_LEN + EAP_SIM_NONCE_MT_LEN;
    832 	id = os_malloc(*len);
    833 	if (id == NULL)
    834 		return NULL;
    835 
    836 	id[0] = EAP_TYPE_SIM;
    837 	os_memcpy(id + 1, data->rand, data->num_chal * GSM_RAND_LEN);
    838 	os_memcpy(id + 1 + data->num_chal * GSM_RAND_LEN, data->nonce_mt,
    839 		  EAP_SIM_NONCE_MT_LEN);
    840 	wpa_hexdump(MSG_DEBUG, "EAP-SIM: Derived Session-Id", id, *len);
    841 
    842 	return id;
    843 }
    844 
    845 
    846 int eap_server_sim_register(void)
    847 {
    848 	struct eap_method *eap;
    849 
    850 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
    851 				      EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM");
    852 	if (eap == NULL)
    853 		return -1;
    854 
    855 	eap->init = eap_sim_init;
    856 	eap->reset = eap_sim_reset;
    857 	eap->buildReq = eap_sim_buildReq;
    858 	eap->check = eap_sim_check;
    859 	eap->process = eap_sim_process;
    860 	eap->isDone = eap_sim_isDone;
    861 	eap->getKey = eap_sim_getKey;
    862 	eap->isSuccess = eap_sim_isSuccess;
    863 	eap->get_emsk = eap_sim_get_emsk;
    864 	eap->getSessionId = eap_sim_get_session_id;
    865 
    866 	return eap_server_method_register(eap);
    867 }
    868