18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * IKEv2 common routines for initiator and responder
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/crypto.h"
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/md5.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/sha1.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/random.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ikev2_common.h"
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct ikev2_integ_alg ikev2_integ_algs[] = {
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{ AUTH_HMAC_SHA1_96, 20, 12 },
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{ AUTH_HMAC_MD5_96, 16, 12 }
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#define NUM_INTEG_ALGS ARRAY_SIZE(ikev2_integ_algs)
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct ikev2_prf_alg ikev2_prf_algs[] = {
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{ PRF_HMAC_SHA1, 20, 20 },
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{ PRF_HMAC_MD5, 16, 16 }
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#define NUM_PRF_ALGS ARRAY_SIZE(ikev2_prf_algs)
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct ikev2_encr_alg ikev2_encr_algs[] = {
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{ ENCR_AES_CBC, 16, 16 }, /* only 128-bit keys supported for now */
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{ ENCR_3DES, 24, 8 }
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#define NUM_ENCR_ALGS ARRAY_SIZE(ikev2_encr_algs)
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst struct ikev2_integ_alg * ikev2_get_integ(int id)
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < NUM_INTEG_ALGS; i++) {
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ikev2_integ_algs[i].id == id)
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return &ikev2_integ_algs[i];
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_integ_hash(int alg, const u8 *key, size_t key_len, const u8 *data,
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		     size_t data_len, u8 *hash)
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 tmphash[IKEV2_MAX_HASH_LEN];
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (alg) {
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case AUTH_HMAC_SHA1_96:
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (key_len != 20)
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hmac_sha1(key, key_len, data, data_len, tmphash);
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(hash, tmphash, 12);
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case AUTH_HMAC_MD5_96:
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (key_len != 16)
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hmac_md5(key, key_len, data, data_len, tmphash);
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(hash, tmphash, 12);
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst struct ikev2_prf_alg * ikev2_get_prf(int id)
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < NUM_PRF_ALGS; i++) {
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ikev2_prf_algs[i].id == id)
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return &ikev2_prf_algs[i];
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_prf_hash(int alg, const u8 *key, size_t key_len,
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   size_t num_elem, const u8 *addr[], const size_t *len,
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   u8 *hash)
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (alg) {
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case PRF_HMAC_SHA1:
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hmac_sha1_vector(key, key_len, num_elem, addr, len, hash);
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case PRF_HMAC_MD5:
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hmac_md5_vector(key, key_len, num_elem, addr, len, hash);
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_prf_plus(int alg, const u8 *key, size_t key_len,
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   const u8 *data, size_t data_len,
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   u8 *out, size_t out_len)
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 hash[IKEV2_MAX_HASH_LEN];
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t hash_len;
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 iter, *pos, *end;
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[3];
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len[3];
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ikev2_prf_alg *prf;
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int res;
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	prf = ikev2_get_prf(alg);
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (prf == NULL)
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hash_len = prf->hash_len;
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = hash;
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = hash_len;
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = data;
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[1] = data_len;
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[2] = &iter;
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[2] = 1;
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = out;
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = out + out_len;
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iter = 1;
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pos < end) {
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		size_t clen;
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (iter == 1)
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			res = ikev2_prf_hash(alg, key, key_len, 2, &addr[1],
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     &len[1], hash);
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			res = ikev2_prf_hash(alg, key, key_len, 3, addr, len,
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     hash);
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (res < 0)
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		clen = hash_len;
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if ((int) clen > end - pos)
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			clen = end - pos;
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(pos, hash, clen);
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += clen;
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		iter++;
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst struct ikev2_encr_alg * ikev2_get_encr(int id)
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < NUM_ENCR_ALGS; i++) {
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ikev2_encr_algs[i].id == id)
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return &ikev2_encr_algs[i];
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_encr_encrypt(int alg, const u8 *key, size_t key_len, const u8 *iv,
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       const u8 *plain, u8 *crypt, size_t len)
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct crypto_cipher *cipher;
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int encr_alg;
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (alg) {
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case ENCR_3DES:
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		encr_alg = CRYPTO_CIPHER_ALG_3DES;
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case ENCR_AES_CBC:
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		encr_alg = CRYPTO_CIPHER_ALG_AES;
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "IKEV2: Unsupported encr alg %d", alg);
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cipher = crypto_cipher_init(encr_alg, iv, key, key_len);
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cipher == NULL) {
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Failed to initialize cipher");
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (crypto_cipher_encrypt(cipher, plain, crypt, len) < 0) {
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Encryption failed");
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		crypto_cipher_deinit(cipher);
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	crypto_cipher_deinit(cipher);
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_encr_decrypt(int alg, const u8 *key, size_t key_len, const u8 *iv,
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       const u8 *crypt, u8 *plain, size_t len)
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct crypto_cipher *cipher;
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int encr_alg;
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (alg) {
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case ENCR_3DES:
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		encr_alg = CRYPTO_CIPHER_ALG_3DES;
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case ENCR_AES_CBC:
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		encr_alg = CRYPTO_CIPHER_ALG_AES;
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "IKEV2: Unsupported encr alg %d", alg);
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cipher = crypto_cipher_init(encr_alg, iv, key, key_len);
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cipher == NULL) {
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Failed to initialize cipher");
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (crypto_cipher_decrypt(cipher, crypt, plain, len) < 0) {
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Decryption failed");
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		crypto_cipher_deinit(cipher);
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	crypto_cipher_deinit(cipher);
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_parse_payloads(struct ikev2_payloads *payloads,
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 u8 next_payload, const u8 *pos, const u8 *end)
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ikev2_payload_hdr *phdr;
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(payloads, 0, sizeof(*payloads));
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (next_payload != IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) {
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int plen, pdatalen;
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		const u8 *pdata;
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "IKEV2: Processing payload %u",
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   next_payload);
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (end - pos < (int) sizeof(*phdr)) {
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "IKEV2:   Too short message for "
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "payload header (left=%ld)",
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   (long) (end - pos));
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		phdr = (const struct ikev2_payload_hdr *) pos;
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		plen = WPA_GET_BE16(phdr->payload_length);
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (plen < (int) sizeof(*phdr) || pos + plen > end) {
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "IKEV2:   Invalid payload header "
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "length %d", plen);
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "IKEV2:   Next Payload: %u  Flags: 0x%x"
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "  Payload Length: %d",
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   phdr->next_payload, phdr->flags, plen);
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pdata = (const u8 *) (phdr + 1);
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pdatalen = plen - sizeof(*phdr);
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (next_payload) {
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_SA:
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Security "
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Association");
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->sa = pdata;
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->sa_len = pdatalen;
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_KEY_EXCHANGE:
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Key "
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Exchange");
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->ke = pdata;
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->ke_len = pdatalen;
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_IDi:
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: IDi");
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->idi = pdata;
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->idi_len = pdatalen;
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_IDr:
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: IDr");
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->idr = pdata;
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->idr_len = pdatalen;
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_CERTIFICATE:
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Certificate");
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->cert = pdata;
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->cert_len = pdatalen;
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_AUTHENTICATION:
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: "
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Authentication");
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->auth = pdata;
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->auth_len = pdatalen;
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_NONCE:
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Nonce");
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->nonce = pdata;
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->nonce_len = pdatalen;
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_ENCRYPTED:
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Encrypted");
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->encrypted = pdata;
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->encrypted_len = pdatalen;
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_NOTIFICATION:
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: "
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Notification");
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->notification = pdata;
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->notification_len = pdatalen;
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (phdr->flags & IKEV2_PAYLOAD_FLAGS_CRITICAL) {
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_INFO, "IKEV2:   Unsupported "
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "critical payload %u - reject the "
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "entire message", next_payload);
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return -1;
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			} else {
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "IKEV2:   Skipped "
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "unsupported payload %u",
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   next_payload);
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (next_payload == IKEV2_PAYLOAD_ENCRYPTED &&
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    pos + plen == end) {
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/*
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * Next Payload in the case of Encrypted Payload is
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * actually the payload type for the first embedded
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * payload.
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 */
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->encr_next_payload = phdr->next_payload;
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			next_payload = IKEV2_PAYLOAD_NO_NEXT_PAYLOAD;
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			next_payload = phdr->next_payload;
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += plen;
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pos != end) {
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unexpected extra data after "
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "payloads");
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_derive_auth_data(int prf_alg, const struct wpabuf *sign_msg,
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   const u8 *ID, size_t ID_len, u8 ID_type,
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   struct ikev2_keys *keys, int initiator,
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   const u8 *shared_secret, size_t shared_secret_len,
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   const u8 *nonce, size_t nonce_len,
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   const u8 *key_pad, size_t key_pad_len,
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   u8 *auth_data)
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t sign_len, buf_len;
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *sign_data, *pos, *buf, hash[IKEV2_MAX_HASH_LEN];
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ikev2_prf_alg *prf;
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *SK_p = initiator ? keys->SK_pi : keys->SK_pr;
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	prf = ikev2_get_prf(prf_alg);
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sign_msg == NULL || ID == NULL || SK_p == NULL ||
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    shared_secret == NULL || nonce == NULL || prf == NULL)
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* prf(SK_pi/r,IDi/r') */
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf_len = 4 + ID_len;
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf = os_zalloc(buf_len);
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL)
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf[0] = ID_type;
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(buf + 4, ID, ID_len);
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ikev2_prf_hash(prf->id, SK_p, keys->SK_prf_len,
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   1, (const u8 **) &buf, &buf_len, hash) < 0) {
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(buf);
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(buf);
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* sign_data = msg | Nr/i | prf(SK_pi/r,IDi/r') */
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sign_len = wpabuf_len(sign_msg) + nonce_len + prf->hash_len;
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sign_data = os_malloc(sign_len);
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sign_data == NULL)
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = sign_data;
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, wpabuf_head(sign_msg), wpabuf_len(sign_msg));
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += wpabuf_len(sign_msg);
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, nonce, nonce_len);
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += nonce_len;
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, hash, prf->hash_len);
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* AUTH = prf(prf(Shared Secret, key pad, sign_data) */
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ikev2_prf_hash(prf->id, shared_secret, shared_secret_len, 1,
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   &key_pad, &key_pad_len, hash) < 0 ||
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    ikev2_prf_hash(prf->id, hash, prf->hash_len, 1,
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (const u8 **) &sign_data, &sign_len, auth_data) < 0)
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(sign_data);
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(sign_data);
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtu8 * ikev2_decrypt_payload(int encr_id, int integ_id,
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   struct ikev2_keys *keys, int initiator,
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   const struct ikev2_hdr *hdr,
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   const u8 *encrypted, size_t encrypted_len,
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   size_t *res_len)
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t iv_len;
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos, *end, *iv, *integ;
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 hash[IKEV2_MAX_HASH_LEN], *decrypted;
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t decrypted_len, pad_len;
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ikev2_integ_alg *integ_alg;
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ikev2_encr_alg *encr_alg;
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *SK_e = initiator ? keys->SK_ei : keys->SK_er;
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar;
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (encrypted == NULL) {
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No Encrypted payload in SA_AUTH");
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	encr_alg = ikev2_get_encr(encr_id);
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (encr_alg == NULL) {
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unsupported encryption type");
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iv_len = encr_alg->block_size;
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	integ_alg = ikev2_get_integ(integ_id);
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (integ_alg == NULL) {
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unsupported intergrity type");
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (encrypted_len < iv_len + 1 + integ_alg->hash_len) {
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No room for IV or Integrity "
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "Checksum");
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iv = encrypted;
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = iv + iv_len;
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = encrypted + encrypted_len;
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	integ = end - integ_alg->hash_len;
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (SK_a == NULL) {
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No SK_a available");
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ikev2_integ_hash(integ_id, SK_a, keys->SK_integ_len,
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     (const u8 *) hdr,
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     integ - (const u8 *) hdr, hash) < 0) {
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Failed to calculate integrity "
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "hash");
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
480c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt	if (os_memcmp_const(integ, hash, integ_alg->hash_len) != 0) {
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Incorrect Integrity Checksum "
4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Data");
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (SK_e == NULL) {
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No SK_e available");
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	decrypted_len = integ - pos;
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	decrypted = os_malloc(decrypted_len);
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (decrypted == NULL)
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ikev2_encr_decrypt(encr_alg->id, SK_e, keys->SK_encr_len, iv, pos,
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       decrypted, decrypted_len) < 0) {
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(decrypted);
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pad_len = decrypted[decrypted_len - 1];
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (decrypted_len < pad_len + 1) {
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Invalid padding in encrypted "
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "payload");
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(decrypted);
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	decrypted_len -= pad_len + 1;
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*res_len = decrypted_len;
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return decrypted;
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ikev2_update_hdr(struct wpabuf *msg)
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ikev2_hdr *hdr;
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Update lenth field in HDR */
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr = wpabuf_mhead(msg);
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_PUT_BE32(hdr->length, wpabuf_len(msg));
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_build_encrypted(int encr_id, int integ_id, struct ikev2_keys *keys,
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  int initiator, struct wpabuf *msg,
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  struct wpabuf *plain, u8 next_payload)
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ikev2_payload_hdr *phdr;
5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t plen;
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t iv_len, pad_len;
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *icv, *iv;
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ikev2_integ_alg *integ_alg;
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ikev2_encr_alg *encr_alg;
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *SK_e = initiator ? keys->SK_ei : keys->SK_er;
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar;
5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "IKEV2: Adding Encrypted payload");
5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Encr - RFC 4306, Sect. 3.14 */
5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	encr_alg = ikev2_get_encr(encr_id);
5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (encr_alg == NULL) {
5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unsupported encryption type");
5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iv_len = encr_alg->block_size;
5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	integ_alg = ikev2_get_integ(integ_id);
5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (integ_alg == NULL) {
5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unsupported intergrity type");
5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (SK_e == NULL) {
5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No SK_e available");
5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (SK_a == NULL) {
5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No SK_a available");
5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	phdr = wpabuf_put(msg, sizeof(*phdr));
5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	phdr->next_payload = next_payload;
5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	phdr->flags = 0;
5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iv = wpabuf_put(msg, iv_len);
5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (random_get_bytes(iv, iv_len)) {
5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Could not generate IV");
5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pad_len = iv_len - (wpabuf_len(plain) + 1) % iv_len;
5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pad_len == iv_len)
5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pad_len = 0;
5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put(plain, pad_len);
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_u8(plain, pad_len);
5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ikev2_encr_encrypt(encr_alg->id, SK_e, keys->SK_encr_len, iv,
5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       wpabuf_head(plain), wpabuf_mhead(plain),
5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       wpabuf_len(plain)) < 0)
5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_buf(msg, plain);
5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Need to update all headers (Length fields) prior to hash func */
5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	icv = wpabuf_put(msg, integ_alg->hash_len);
5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_PUT_BE16(phdr->payload_length, plen);
5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ikev2_update_hdr(msg);
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ikev2_integ_hash(integ_id, SK_a, keys->SK_integ_len,
5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpabuf_head(msg),
5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpabuf_len(msg) - integ_alg->hash_len, icv);
6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_keys_set(struct ikev2_keys *keys)
6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return keys->SK_d && keys->SK_ai && keys->SK_ar && keys->SK_ei &&
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		keys->SK_er && keys->SK_pi && keys->SK_pr;
6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ikev2_free_keys(struct ikev2_keys *keys)
6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(keys->SK_d);
6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(keys->SK_ai);
6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(keys->SK_ar);
6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(keys->SK_ei);
6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(keys->SK_er);
6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(keys->SK_pi);
6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(keys->SK_pr);
6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_d = keys->SK_ai = keys->SK_ar = keys->SK_ei = keys->SK_er =
6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		keys->SK_pi = keys->SK_pr = NULL;
6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_derive_sk_keys(const struct ikev2_prf_alg *prf,
6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 const struct ikev2_integ_alg *integ,
6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 const struct ikev2_encr_alg *encr,
6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 const u8 *skeyseed, const u8 *data, size_t data_len,
6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 struct ikev2_keys *keys)
6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *keybuf, *pos;
6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t keybuf_len;
6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * {SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr } =
6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *	prf+(SKEYSEED, Ni | Nr | SPIi | SPIr )
6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ikev2_free_keys(keys);
6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_d_len = prf->key_len;
6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_integ_len = integ->key_len;
6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_encr_len = encr->key_len;
6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_prf_len = prf->key_len;
6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keybuf_len = keys->SK_d_len + 2 * keys->SK_integ_len +
6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		2 * keys->SK_encr_len + 2 * keys->SK_prf_len;
6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keybuf = os_malloc(keybuf_len);
6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (keybuf == NULL)
6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ikev2_prf_plus(prf->id, skeyseed, prf->hash_len,
6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   data, data_len, keybuf, keybuf_len)) {
6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(keybuf);
6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = keybuf;
6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_d = os_malloc(keys->SK_d_len);
6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (keys->SK_d) {
6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(keys->SK_d, pos, keys->SK_d_len);
6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_d",
6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				keys->SK_d, keys->SK_d_len);
6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += keys->SK_d_len;
6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_ai = os_malloc(keys->SK_integ_len);
6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (keys->SK_ai) {
6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(keys->SK_ai, pos, keys->SK_integ_len);
6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ai",
6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				keys->SK_ai, keys->SK_integ_len);
6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += keys->SK_integ_len;
6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_ar = os_malloc(keys->SK_integ_len);
6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (keys->SK_ar) {
6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(keys->SK_ar, pos, keys->SK_integ_len);
6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ar",
6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				keys->SK_ar, keys->SK_integ_len);
6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += keys->SK_integ_len;
6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_ei = os_malloc(keys->SK_encr_len);
6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (keys->SK_ei) {
6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(keys->SK_ei, pos, keys->SK_encr_len);
6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ei",
6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				keys->SK_ei, keys->SK_encr_len);
6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += keys->SK_encr_len;
6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_er = os_malloc(keys->SK_encr_len);
6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (keys->SK_er) {
6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(keys->SK_er, pos, keys->SK_encr_len);
6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_er",
6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				keys->SK_er, keys->SK_encr_len);
6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += keys->SK_encr_len;
6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_pi = os_malloc(keys->SK_prf_len);
7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (keys->SK_pi) {
7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(keys->SK_pi, pos, keys->SK_prf_len);
7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_pi",
7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				keys->SK_pi, keys->SK_prf_len);
7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += keys->SK_prf_len;
7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_pr = os_malloc(keys->SK_prf_len);
7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (keys->SK_pr) {
7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(keys->SK_pr, pos, keys->SK_prf_len);
7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_pr",
7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				keys->SK_pr, keys->SK_prf_len);
7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(keybuf);
7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!ikev2_keys_set(keys)) {
7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ikev2_free_keys(keys);
7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
723