Esempio n. 1
0
static void eap_aka_determine_identity(struct eap_sm *sm,
				       struct eap_aka_data *data,
				       int before_identity, int after_reauth)
{
	const u8 *identity;
	size_t identity_len;
	int res;

	identity = NULL;
	identity_len = 0;

	if (after_reauth && data->reauth) {
		identity = data->reauth->identity;
		identity_len = data->reauth->identity_len;
	} else if (sm->identity && sm->identity_len > 0 &&
		   sm->identity[0] == EAP_AKA_PERMANENT_PREFIX) {
		identity = sm->identity;
		identity_len = sm->identity_len;
	} else {
		identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv,
						    sm->identity,
						    sm->identity_len,
						    &identity_len);
		if (identity == NULL) {
			data->reauth = eap_sim_db_get_reauth_entry(
				sm->eap_sim_db_priv, sm->identity,
				sm->identity_len);
			if (data->reauth &&
			    data->reauth->aka_prime !=
			    (data->eap_method == EAP_TYPE_AKA_PRIME)) {
				wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth data "
					   "was for different AKA version");
				data->reauth = NULL;
			}
			if (data->reauth) {
				wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast "
					   "re-authentication");
				identity = data->reauth->identity;
				identity_len = data->reauth->identity_len;
				data->counter = data->reauth->counter;
				if (data->eap_method == EAP_TYPE_AKA_PRIME) {
					os_memcpy(data->k_encr,
						  data->reauth->k_encr,
						  EAP_SIM_K_ENCR_LEN);
					os_memcpy(data->k_aut,
						  data->reauth->k_aut,
						  EAP_AKA_PRIME_K_AUT_LEN);
					os_memcpy(data->k_re,
						  data->reauth->k_re,
						  EAP_AKA_PRIME_K_RE_LEN);
				} else {
					os_memcpy(data->mk, data->reauth->mk,
						  EAP_SIM_MK_LEN);
				}
			}
		}
	}

	if (identity == NULL ||
	    eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
				      sm->identity_len) < 0) {
		if (before_identity) {
			wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent user name "
				   "not known - send AKA-Identity request");
			eap_aka_state(data, IDENTITY);
			return;
		} else {
			wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown whether the "
				   "permanent user name is known; try to use "
				   "it");
			/* eap_sim_db_get_aka_auth() will report failure, if
			 * this identity is not known. */
		}
	}

	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity",
			  identity, identity_len);

	if (!after_reauth && data->reauth) {
		eap_aka_state(data, REAUTH);
		return;
	}

	res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, identity,
				      identity_len, data->rand, data->autn,
				      data->ik, data->ck, data->res,
				      &data->res_len, sm);
	if (res == EAP_SIM_DB_PENDING) {
		wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
			   "not yet available - pending request");
		sm->method_pending = METHOD_PENDING_WAIT;
		return;
	}

#ifdef EAP_SERVER_AKA_PRIME
	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
		/* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
		 * needed 6-octet SQN ^AK for CK',IK' derivation */
		eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
						 data->autn,
						 data->network_name,
						 data->network_name_len);
	}
#endif /* EAP_SERVER_AKA_PRIME */

	data->reauth = NULL;
	data->counter = 0; /* reset re-auth counter since this is full auth */

	if (res != 0) {
		wpa_printf(MSG_INFO, "EAP-AKA: Failed to get AKA "
			   "authentication data for the peer");
		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
		eap_aka_state(data, NOTIFICATION);
		return;
	}
	if (sm->method_pending == METHOD_PENDING_WAIT) {
		wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
			   "available - abort pending wait");
		sm->method_pending = METHOD_PENDING_NONE;
	}

	identity_len = sm->identity_len;
	while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') {
		wpa_printf(MSG_DEBUG, "EAP-AKA: Workaround - drop last null "
			   "character from identity");
		identity_len--;
	}
	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation",
			  sm->identity, identity_len);

	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
		eap_aka_prime_derive_keys(identity, identity_len, data->ik,
					  data->ck, data->k_encr, data->k_aut,
					  data->k_re, data->msk, data->emsk);
	} else {
		eap_aka_derive_mk(sm->identity, identity_len, data->ik,
				  data->ck, data->mk);
		eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
				    data->msk, data->emsk);
	}

	eap_aka_state(data, CHALLENGE);
}
static void eap_aka_fullauth(struct eap_sm *sm, struct eap_aka_data *data)
{
	size_t identity_len;
	int res;

	res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, data->permanent,
				      data->rand, data->autn, data->ik,
				      data->ck, data->res, &data->res_len, sm);
	if (res == EAP_SIM_DB_PENDING) {
		wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
			   "not yet available - pending request");
		sm->method_pending = METHOD_PENDING_WAIT;
		return;
	}

#ifdef EAP_SERVER_AKA_PRIME
	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
		/* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
		 * needed 6-octet SQN ^AK for CK',IK' derivation */
		eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
						 data->autn,
						 data->network_name,
						 data->network_name_len);
	}
#endif /* EAP_SERVER_AKA_PRIME */

	data->reauth = NULL;
	data->counter = 0; /* reset re-auth counter since this is full auth */

	if (res != 0) {
		wpa_printf(MSG_INFO, "EAP-AKA: Failed to get AKA "
			   "authentication data for the peer");
		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
		eap_aka_state(data, NOTIFICATION);
		return;
	}
	if (sm->method_pending == METHOD_PENDING_WAIT) {
		wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
			   "available - abort pending wait");
		sm->method_pending = METHOD_PENDING_NONE;
	}

	identity_len = sm->identity_len;
	while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') {
		wpa_printf(MSG_DEBUG, "EAP-AKA: Workaround - drop last null "
			   "character from identity");
		identity_len--;
	}
	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation",
			  sm->identity, identity_len);

	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
		eap_aka_prime_derive_keys(sm->identity, identity_len, data->ik,
					  data->ck, data->k_encr, data->k_aut,
					  data->k_re, data->msk, data->emsk);
	} else {
		eap_aka_derive_mk(sm->identity, identity_len, data->ik,
				  data->ck, data->mk);
		eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
				    data->msk, data->emsk);
	}

	eap_aka_state(data, CHALLENGE);
}