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