示例#1
0
int ikev2_derive_auth_data(int prf_alg, const struct wpabuf *sign_msg,
			   const u8 *ID, size_t ID_len, u8 ID_type,
			   struct ikev2_keys *keys, int initiator,
			   const u8 *shared_secret, size_t shared_secret_len,
			   const u8 *nonce, size_t nonce_len,
			   const u8 *key_pad, size_t key_pad_len,
			   u8 *auth_data)
{
	size_t sign_len, buf_len;
	u8 *sign_data, *pos, *buf, hash[IKEV2_MAX_HASH_LEN];
	const struct ikev2_prf_alg *prf;
	const u8 *SK_p = initiator ? keys->SK_pi : keys->SK_pr;

	prf = ikev2_get_prf(prf_alg);
	if (sign_msg == NULL || ID == NULL || SK_p == NULL ||
	    shared_secret == NULL || nonce == NULL || prf == NULL)
		return -1;

	/* prf(SK_pi/r,IDi/r') */
	buf_len = 4 + ID_len;
	buf = os_zalloc(buf_len);
	if (buf == NULL)
		return -1;
	buf[0] = ID_type;
	os_memcpy(buf + 4, ID, ID_len);
	if (ikev2_prf_hash(prf->id, SK_p, keys->SK_prf_len,
			   1, (const u8 **) &buf, &buf_len, hash) < 0) {
		os_free(buf);
		return -1;
	}
	os_free(buf);

	/* sign_data = msg | Nr/i | prf(SK_pi/r,IDi/r') */
	sign_len = wpabuf_len(sign_msg) + nonce_len + prf->hash_len;
	sign_data = os_malloc(sign_len);
	if (sign_data == NULL)
		return -1;
	pos = sign_data;
	os_memcpy(pos, wpabuf_head(sign_msg), wpabuf_len(sign_msg));
	pos += wpabuf_len(sign_msg);
	os_memcpy(pos, nonce, nonce_len);
	pos += nonce_len;
	os_memcpy(pos, hash, prf->hash_len);

	/* AUTH = prf(prf(Shared Secret, key pad, sign_data) */
	if (ikev2_prf_hash(prf->id, shared_secret, shared_secret_len, 1,
			   &key_pad, &key_pad_len, hash) < 0 ||
	    ikev2_prf_hash(prf->id, hash, prf->hash_len, 1,
			   (const u8 **) &sign_data, &sign_len, auth_data) < 0)
	{
		os_free(sign_data);
		return -1;
	}
	os_free(sign_data);

	return 0;
}
示例#2
0
int ikev2_prf_plus(int alg, const u8 *key, size_t key_len,
		   const u8 *data, size_t data_len,
		   u8 *out, size_t out_len)
{
	u8 hash[IKEV2_MAX_HASH_LEN];
	size_t hash_len;
	u8 iter, *pos, *end;
	const u8 *addr[3];
	size_t len[3];
	const struct ikev2_prf_alg *prf;
	int res;

	prf = ikev2_get_prf(alg);
	if (prf == NULL)
		return -1;
	hash_len = prf->hash_len;

	addr[0] = hash;
	len[0] = hash_len;
	addr[1] = data;
	len[1] = data_len;
	addr[2] = &iter;
	len[2] = 1;

	pos = out;
	end = out + out_len;
	iter = 1;
	while (pos < end) {
		size_t clen;
		if (iter == 1)
			res = ikev2_prf_hash(alg, key, key_len, 2, &addr[1],
					     &len[1], hash);
		else
			res = ikev2_prf_hash(alg, key, key_len, 3, addr, len,
					     hash);
		if (res < 0)
			return -1;
		clen = hash_len;
		if ((int) clen > end - pos)
			clen = end - pos;
		os_memcpy(pos, hash, clen);
		pos += clen;
		iter++;
	}

	return 0;
}
示例#3
0
static int ikev2_derive_keys(struct ikev2_responder_data *data)
{
	u8 *buf, *pos, *pad, skeyseed[IKEV2_MAX_HASH_LEN];
	size_t buf_len, pad_len;
	struct wpabuf *shared;
	const struct ikev2_integ_alg *integ;
	const struct ikev2_prf_alg *prf;
	const struct ikev2_encr_alg *encr;
	int ret;
	const u8 *addr[2];
	size_t len[2];

	/* RFC 4306, Sect. 2.14 */

	integ = ikev2_get_integ(data->proposal.integ);
	prf = ikev2_get_prf(data->proposal.prf);
	encr = ikev2_get_encr(data->proposal.encr);
	if (integ == NULL || prf == NULL || encr == NULL) {
		wpa_printf(MSG_INFO, "IKEV2: Unsupported proposal");
		return -1;
	}

	shared = dh_derive_shared(data->i_dh_public, data->r_dh_private,
				  data->dh);
	if (shared == NULL)
		return -1;

	/* Construct Ni | Nr | SPIi | SPIr */

	buf_len = data->i_nonce_len + data->r_nonce_len + 2 * IKEV2_SPI_LEN;
	buf = os_malloc(buf_len);
	if (buf == NULL) {
		wpabuf_free(shared);
		return -1;
	}

	pos = buf;
	os_memcpy(pos, data->i_nonce, data->i_nonce_len);
	pos += data->i_nonce_len;
	os_memcpy(pos, data->r_nonce, data->r_nonce_len);
	pos += data->r_nonce_len;
	os_memcpy(pos, data->i_spi, IKEV2_SPI_LEN);
	pos += IKEV2_SPI_LEN;
	os_memcpy(pos, data->r_spi, IKEV2_SPI_LEN);
#ifdef CCNS_PL
#if __BYTE_ORDER == __LITTLE_ENDIAN
	{
		int i;
		u8 *tmp = pos - IKEV2_SPI_LEN;
		/* Incorrect byte re-ordering on little endian hosts.. */
		for (i = 0; i < IKEV2_SPI_LEN; i++)
			*tmp++ = data->i_spi[IKEV2_SPI_LEN - 1 - i];
		for (i = 0; i < IKEV2_SPI_LEN; i++)
			*tmp++ = data->r_spi[IKEV2_SPI_LEN - 1 - i];
	}
#endif
#endif /* CCNS_PL */

	/* SKEYSEED = prf(Ni | Nr, g^ir) */
	/* Use zero-padding per RFC 4306, Sect. 2.14 */
	pad_len = data->dh->prime_len - wpabuf_len(shared);
#ifdef CCNS_PL
	/* Shared secret is not zero-padded correctly */
	pad_len = 0;
#endif /* CCNS_PL */
	pad = os_zalloc(pad_len ? pad_len : 1);
	if (pad == NULL) {
		wpabuf_free(shared);
		os_free(buf);
		return -1;
	}

	addr[0] = pad;
	len[0] = pad_len;
	addr[1] = wpabuf_head(shared);
	len[1] = wpabuf_len(shared);
	if (ikev2_prf_hash(prf->id, buf, data->i_nonce_len + data->r_nonce_len,
			   2, addr, len, skeyseed) < 0) {
		wpabuf_free(shared);
		os_free(buf);
		os_free(pad);
		return -1;
	}
	os_free(pad);
	wpabuf_free(shared);

	/* DH parameters are not needed anymore, so free them */
	wpabuf_free(data->i_dh_public);
	data->i_dh_public = NULL;
	wpabuf_free(data->r_dh_private);
	data->r_dh_private = NULL;

	wpa_hexdump_key(MSG_DEBUG, "IKEV2: SKEYSEED",
			skeyseed, prf->hash_len);

	ret = ikev2_derive_sk_keys(prf, integ, encr, skeyseed, buf, buf_len,
				   &data->keys);
	os_free(buf);
	return ret;
}
示例#4
0
static int ikev2_derive_keys(struct ikev2_initiator_data *data)
{
	u8 *buf, *pos, *pad, skeyseed[IKEV2_MAX_HASH_LEN];
	size_t buf_len, pad_len;
	struct wpabuf *shared;
	const struct ikev2_integ_alg *integ;
	const struct ikev2_prf_alg *prf;
	const struct ikev2_encr_alg *encr;
	int ret;
	const u8 *addr[2];
	size_t len[2];

	/* RFC 4306, Sect. 2.14 */

	integ = ikev2_get_integ(data->proposal.integ);
	prf = ikev2_get_prf(data->proposal.prf);
	encr = ikev2_get_encr(data->proposal.encr);
	if (integ == NULL || prf == NULL || encr == NULL) {
		asd_printf(ASD_DEFAULT,MSG_DEBUG, "IKEV2: Unsupported proposal");
		return -1;
	}

	shared = dh_derive_shared(data->r_dh_public, data->i_dh_private,
				  data->dh);
	if (shared == NULL)
		return -1;

	/* Construct Ni | Nr | SPIi | SPIr */

	buf_len = data->i_nonce_len + data->r_nonce_len + 2 * IKEV2_SPI_LEN;
	buf = os_zalloc(buf_len);
	if (buf == NULL) {
		wpabuf_free(shared);
		return -1;
	}

	pos = buf;
	os_memcpy(pos, data->i_nonce, data->i_nonce_len);
	pos += data->i_nonce_len;
	os_memcpy(pos, data->r_nonce, data->r_nonce_len);
	pos += data->r_nonce_len;
	os_memcpy(pos, data->i_spi, IKEV2_SPI_LEN);
	pos += IKEV2_SPI_LEN;
	os_memcpy(pos, data->r_spi, IKEV2_SPI_LEN);

	/* SKEYSEED = prf(Ni | Nr, g^ir) */

	/* Use zero-padding per RFC 4306, Sect. 2.14 */
	pad_len = data->dh->prime_len - wpabuf_len(shared);
	pad = os_zalloc(pad_len ? pad_len : 1);
	if (pad == NULL) {
		wpabuf_free(shared);
		os_free(buf);
		return -1;
	}
	addr[0] = pad;
	len[0] = pad_len;
	addr[1] = wpabuf_head(shared);
	len[1] = wpabuf_len(shared);
	if (ikev2_prf_hash(prf->id, buf, data->i_nonce_len + data->r_nonce_len,
			   2, addr, len, skeyseed) < 0) {
		wpabuf_free(shared);
		os_free(buf);
		os_free(pad);
		return -1;
	}
	os_free(pad);
	wpabuf_free(shared);

	/* DH parameters are not needed anymore, so free them */
	wpabuf_free(data->r_dh_public);
	data->r_dh_public = NULL;
	wpabuf_free(data->i_dh_private);
	data->i_dh_private = NULL;

	wpa_hexdump_key(MSG_DEBUG, "IKEV2: SKEYSEED",
			skeyseed, prf->hash_len);

	ret = ikev2_derive_sk_keys(prf, integ, encr, skeyseed, buf, buf_len,
				   &data->keys);
	os_free(buf);
	return ret;
}