static int eap_sim_get_challenge(eap_handler_t *handler, VALUE_PAIR *vps, int idx, eap_sim_state_t *ess)
{
	REQUEST *request = handler->request;
	VALUE_PAIR *vp, *ki, *algo_version;

	rad_assert(idx >= 0 && idx < 3);

	/*
	 *	Generate a new RAND value, and derive Kc and SRES from Ki
	 */
	ki = pairfind(vps, PW_EAP_SIM_KI, 0, TAG_ANY);
	if (ki) {
		int i;

		/*
		 *	Check to see if have a Ki for the IMSI, this allows us to generate the rest
		 *	of the triplets.
		 */
		algo_version = pairfind(vps, PW_EAP_SIM_ALGO_VERSION, 0, TAG_ANY);
		if (!algo_version) {
			REDEBUG("Found Ki, but missing EAP-Sim-Algo-Version");
			return 0;
		}

		for (i = 0; i < EAPSIM_RAND_SIZE; i++) {
			ess->keys.rand[idx][i] = fr_rand();
		}

		switch (algo_version->vp_integer) {
		case 1:
			comp128v1(ess->keys.sres[idx], ess->keys.Kc[idx], ki->vp_octets, ess->keys.rand[idx]);
			break;

		case 2:
			comp128v23(ess->keys.sres[idx], ess->keys.Kc[idx], ki->vp_octets, ess->keys.rand[idx],
				   true);
			break;

		case 3:
			comp128v23(ess->keys.sres[idx], ess->keys.Kc[idx], ki->vp_octets, ess->keys.rand[idx],
				   false);
			break;

		case 4:
			REDEBUG("Comp128-4 algorithm is not supported as details have not yet been published. "
				"If you have details of this algorithm please contact the FreeRADIUS "
				"maintainers");
			return 0;

		default:
			REDEBUG("Unknown/unsupported algorithm Comp128-%i", algo_version->vp_integer);
		}

		if (RDEBUG_ENABLED2) {
			char buffer[33];	/* 32 hexits (16 bytes) + 1 */
			char *p;

			RDEBUG2("Generated following triplets for round %i:", idx);

			p = buffer;
			for (i = 0; i < EAPSIM_RAND_SIZE; i++) {
				p += sprintf(p, "%02x", ess->keys.rand[idx][i]);
			}
			RDEBUG2("\tRAND : 0x%s", buffer);

			p = buffer;
			for (i = 0; i < EAPSIM_SRES_SIZE; i++) {
				p += sprintf(p, "%02x", ess->keys.sres[idx][i]);
			}
			RDEBUG2("\tSRES : 0x%s", buffer);

			p = buffer;
			for (i = 0; i < EAPSIM_KC_SIZE; i++) {
				p += sprintf(p, "%02x", ess->keys.Kc[idx][i]);
			}
			RDEBUG2("\tKc   : 0x%s", buffer);
		}
		return 1;
	}

	/*
	 *	Use known RAND, SRES, and Kc values, these may of been pulled in from an AuC,
	 *	or created by sending challenges to the SIM directly.
	 */
	vp = pairfind(vps, PW_EAP_SIM_RAND1 + idx, 0, TAG_ANY);
	if (!vp) {
		/* bad, we can't find stuff! */
		REDEBUG("control:EAP-SIM-RAND%i not found", idx + 1);
		return 0;
	}
	if (vp->length != EAPSIM_RAND_SIZE) {
		REDEBUG("control:EAP-SIM-RAND%i is not " STRINGIFY(EAPSIM_RAND_SIZE) " bytes, got %zu bytes",
			idx + 1, vp->length);
		return 0;
	}
	memcpy(ess->keys.rand[idx], vp->vp_octets, EAPSIM_RAND_SIZE);

	vp = pairfind(vps, PW_EAP_SIM_SRES1 + idx, 0, TAG_ANY);
	if (!vp) {
		/* bad, we can't find stuff! */
		REDEBUG("control:EAP-SIM-SRES%i not found", idx + 1);
		return 0;
	}
	if (vp->length != EAPSIM_SRES_SIZE) {
		REDEBUG("control:EAP-SIM-SRES%i is not " STRINGIFY(EAPSIM_SRES_SIZE) " bytes, got %zu bytes",
			idx + 1, vp->length);
		return 0;
	}
	memcpy(ess->keys.sres[idx], vp->vp_octets, EAPSIM_SRES_SIZE);

	vp = pairfind(vps, PW_EAP_SIM_KC1 + idx, 0, TAG_ANY);
	if (!vp) {
		/* bad, we can't find stuff! */
		REDEBUG("control:EAP-SIM-Kc%i not found", idx + 1);
		return 0;
	}
	if (vp->length != EAPSIM_KC_SIZE) {
		REDEBUG("control:EAP-SIM-Kc%i is not 8 bytes, got %zu bytes", idx + 1, vp->length);
		return 0;
	}
	memcpy(ess->keys.Kc[idx], vp->vp_octets, EAPSIM_KC_SIZE);
	if (vp->length != EAPSIM_KC_SIZE) {
		REDEBUG("control:EAP-SIM-Kc%i is not " STRINGIFY(EAPSIM_KC_SIZE) " bytes, got %zu bytes",
			idx + 1, vp->length);
		return 0;
	}
	memcpy(ess->keys.Kc[idx], vp->vp_strvalue, EAPSIM_KC_SIZE);

	return 1;
}
Example #2
0
static int vector_gsm_from_ki(eap_session_t *eap_session, VALUE_PAIR *vps, int idx, fr_sim_keys_t *keys)
{
	REQUEST		*request = eap_session->request;
	VALUE_PAIR	*ki_vp, *version_vp;
	uint8_t		opc_buff[MILENAGE_OPC_SIZE];
	uint8_t	const	*opc_p;
	uint32_t	version;
	int		i;

	/*
	 *	Generate a new RAND value, and derive Kc and SRES from Ki
	 */
	ki_vp = fr_pair_find_by_da(vps, attr_sim_ki, TAG_ANY);
	if (!ki_vp) {
		RDEBUG3("No &control:%sfound, not generating triplets locally", attr_sim_ki->name);
		return 1;
	} else if (ki_vp->vp_length != MILENAGE_KI_SIZE) {
		REDEBUG("&control:%s has incorrect length, expected 16 bytes got %zu bytes",
			attr_sim_ki->name, ki_vp->vp_length);
		return -1;
	}

	/*
	 *	Check to see if have a Ki for the IMSI, this allows us to generate the rest
	 *	of the triplets.
	 */
	version_vp = fr_pair_find_by_da(vps, attr_sim_algo_version, TAG_ANY);
	if (!version_vp) {
		if (vector_opc_from_op(request, &opc_p, opc_buff, vps, ki_vp->vp_octets) < 0) return -1;
		version = opc_p ? 4 : 3;
	/*
	 *	Version we explicitly specified, see if we can find the prerequisite
	 *	attributes.
	 */
	} else {
		version = version_vp->vp_uint32;
		if (version == 4) {
			if (vector_opc_from_op(request, &opc_p, opc_buff, vps, ki_vp->vp_octets) < 0) return -1;
			if (!opc_p) {
				RPEDEBUG2("No &control:%s or &control:%s found, "
					  "can't run Milenage (COMP128-4)", attr_sim_op->name, attr_sim_opc->name);
				return -1;
			}
		}
	}

	for (i = 0; i < SIM_VECTOR_GSM_RAND_SIZE; i += sizeof(uint32_t)) {
		uint32_t rand = fr_rand();
		memcpy(&keys->gsm.vector[idx].rand[i], &rand, sizeof(rand));
	}

	switch (version) {
	case 1:
		comp128v1(keys->gsm.vector[idx].sres,
			  keys->gsm.vector[idx].kc,
			  ki_vp->vp_octets,
			  keys->gsm.vector[idx].rand);
		break;

	case 2:
		comp128v23(keys->gsm.vector[idx].sres,
			   keys->gsm.vector[idx].kc,
			   ki_vp->vp_octets,
			   keys->gsm.vector[idx].rand, true);
		break;

	case 3:
		comp128v23(keys->gsm.vector[idx].sres,
			   keys->gsm.vector[idx].kc,
			   ki_vp->vp_octets,
			   keys->gsm.vector[idx].rand, false);
		break;

	case 4:
		if (milenage_gsm_generate(keys->gsm.vector[idx].sres,
					  keys->gsm.vector[idx].kc,
					  opc_p,
					  ki_vp->vp_octets,
					  keys->gsm.vector[idx].rand) < 0) {
			RPEDEBUG2("Failed deriving GSM triplet");
			return -1;
		}
		return 0;

	default:
		REDEBUG("Unknown/unsupported algorithm %i", version);
		return -1;
	}
	return 0;
}