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
191d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidtstatic const 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
271d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidtstatic const 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
351d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidtstatic const 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) {
2546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		unsigned int plen, pdatalen, left;
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		const u8 *pdata;
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "IKEV2: Processing payload %u",
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   next_payload);
2586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (end < pos)
2596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return -1;
2606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		left = end - pos;
2616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (left < sizeof(*phdr)) {
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "IKEV2:   Too short message for "
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "payload header (left=%ld)",
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   (long) (end - pos));
2656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return -1;
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		phdr = (const struct ikev2_payload_hdr *) pos;
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		plen = WPA_GET_BE16(phdr->payload_length);
2696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (plen < sizeof(*phdr) || plen > left) {
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "IKEV2:   Invalid payload header "
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "length %d", plen);
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "IKEV2:   Next Payload: %u  Flags: 0x%x"
2766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "  Payload Length: %u",
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   phdr->next_payload, phdr->flags, plen);
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pdata = (const u8 *) (phdr + 1);
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pdatalen = plen - sizeof(*phdr);
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (next_payload) {
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_SA:
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Security "
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Association");
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->sa = pdata;
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->sa_len = pdatalen;
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_KEY_EXCHANGE:
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Key "
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Exchange");
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->ke = pdata;
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->ke_len = pdatalen;
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_IDi:
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: IDi");
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->idi = pdata;
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->idi_len = pdatalen;
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_IDr:
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: IDr");
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->idr = pdata;
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->idr_len = pdatalen;
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_CERTIFICATE:
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Certificate");
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->cert = pdata;
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->cert_len = pdatalen;
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_AUTHENTICATION:
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: "
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Authentication");
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->auth = pdata;
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->auth_len = pdatalen;
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_NONCE:
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Nonce");
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->nonce = pdata;
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->nonce_len = pdatalen;
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_ENCRYPTED:
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Encrypted");
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->encrypted = pdata;
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->encrypted_len = pdatalen;
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_NOTIFICATION:
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: "
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Notification");
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->notification = pdata;
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->notification_len = pdatalen;
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (phdr->flags & IKEV2_PAYLOAD_FLAGS_CRITICAL) {
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_INFO, "IKEV2:   Unsupported "
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "critical payload %u - reject the "
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "entire message", next_payload);
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return -1;
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			} else {
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "IKEV2:   Skipped "
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "unsupported payload %u",
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   next_payload);
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (next_payload == IKEV2_PAYLOAD_ENCRYPTED &&
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    pos + plen == end) {
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/*
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * Next Payload in the case of Encrypted Payload is
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * actually the payload type for the first embedded
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * payload.
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 */
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->encr_next_payload = phdr->next_payload;
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			next_payload = IKEV2_PAYLOAD_NO_NEXT_PAYLOAD;
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			next_payload = phdr->next_payload;
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += plen;
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pos != end) {
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unexpected extra data after "
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "payloads");
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_derive_auth_data(int prf_alg, const struct wpabuf *sign_msg,
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   const u8 *ID, size_t ID_len, u8 ID_type,
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   struct ikev2_keys *keys, int initiator,
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   const u8 *shared_secret, size_t shared_secret_len,
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   const u8 *nonce, size_t nonce_len,
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   const u8 *key_pad, size_t key_pad_len,
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   u8 *auth_data)
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t sign_len, buf_len;
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *sign_data, *pos, *buf, hash[IKEV2_MAX_HASH_LEN];
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ikev2_prf_alg *prf;
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *SK_p = initiator ? keys->SK_pi : keys->SK_pr;
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	prf = ikev2_get_prf(prf_alg);
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sign_msg == NULL || ID == NULL || SK_p == NULL ||
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    shared_secret == NULL || nonce == NULL || prf == NULL)
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* prf(SK_pi/r,IDi/r') */
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf_len = 4 + ID_len;
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf = os_zalloc(buf_len);
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL)
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf[0] = ID_type;
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(buf + 4, ID, ID_len);
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ikev2_prf_hash(prf->id, SK_p, keys->SK_prf_len,
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   1, (const u8 **) &buf, &buf_len, hash) < 0) {
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(buf);
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(buf);
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* sign_data = msg | Nr/i | prf(SK_pi/r,IDi/r') */
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sign_len = wpabuf_len(sign_msg) + nonce_len + prf->hash_len;
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sign_data = os_malloc(sign_len);
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sign_data == NULL)
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = sign_data;
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, wpabuf_head(sign_msg), wpabuf_len(sign_msg));
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += wpabuf_len(sign_msg);
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, nonce, nonce_len);
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += nonce_len;
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, hash, prf->hash_len);
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* AUTH = prf(prf(Shared Secret, key pad, sign_data) */
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ikev2_prf_hash(prf->id, shared_secret, shared_secret_len, 1,
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   &key_pad, &key_pad_len, hash) < 0 ||
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    ikev2_prf_hash(prf->id, hash, prf->hash_len, 1,
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (const u8 **) &sign_data, &sign_len, auth_data) < 0)
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(sign_data);
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(sign_data);
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtu8 * ikev2_decrypt_payload(int encr_id, int integ_id,
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   struct ikev2_keys *keys, int initiator,
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   const struct ikev2_hdr *hdr,
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   const u8 *encrypted, size_t encrypted_len,
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   size_t *res_len)
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t iv_len;
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos, *end, *iv, *integ;
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 hash[IKEV2_MAX_HASH_LEN], *decrypted;
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t decrypted_len, pad_len;
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ikev2_integ_alg *integ_alg;
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ikev2_encr_alg *encr_alg;
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *SK_e = initiator ? keys->SK_ei : keys->SK_er;
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar;
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (encrypted == NULL) {
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No Encrypted payload in SA_AUTH");
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	encr_alg = ikev2_get_encr(encr_id);
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (encr_alg == NULL) {
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unsupported encryption type");
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iv_len = encr_alg->block_size;
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	integ_alg = ikev2_get_integ(integ_id);
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (integ_alg == NULL) {
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unsupported intergrity type");
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (encrypted_len < iv_len + 1 + integ_alg->hash_len) {
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No room for IV or Integrity "
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "Checksum");
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iv = encrypted;
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = iv + iv_len;
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = encrypted + encrypted_len;
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	integ = end - integ_alg->hash_len;
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (SK_a == NULL) {
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No SK_a available");
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ikev2_integ_hash(integ_id, SK_a, keys->SK_integ_len,
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     (const u8 *) hdr,
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     integ - (const u8 *) hdr, hash) < 0) {
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Failed to calculate integrity "
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "hash");
4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
484c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt	if (os_memcmp_const(integ, hash, integ_alg->hash_len) != 0) {
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Incorrect Integrity Checksum "
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Data");
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (SK_e == NULL) {
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No SK_e available");
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	decrypted_len = integ - pos;
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	decrypted = os_malloc(decrypted_len);
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (decrypted == NULL)
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ikev2_encr_decrypt(encr_alg->id, SK_e, keys->SK_encr_len, iv, pos,
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       decrypted, decrypted_len) < 0) {
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(decrypted);
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pad_len = decrypted[decrypted_len - 1];
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (decrypted_len < pad_len + 1) {
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Invalid padding in encrypted "
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "payload");
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(decrypted);
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	decrypted_len -= pad_len + 1;
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*res_len = decrypted_len;
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return decrypted;
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ikev2_update_hdr(struct wpabuf *msg)
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ikev2_hdr *hdr;
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Update lenth field in HDR */
5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr = wpabuf_mhead(msg);
5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_PUT_BE32(hdr->length, wpabuf_len(msg));
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_build_encrypted(int encr_id, int integ_id, struct ikev2_keys *keys,
5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  int initiator, struct wpabuf *msg,
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  struct wpabuf *plain, u8 next_payload)
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ikev2_payload_hdr *phdr;
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t plen;
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t iv_len, pad_len;
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *icv, *iv;
5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ikev2_integ_alg *integ_alg;
5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ikev2_encr_alg *encr_alg;
5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *SK_e = initiator ? keys->SK_ei : keys->SK_er;
5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar;
5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "IKEV2: Adding Encrypted payload");
5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Encr - RFC 4306, Sect. 3.14 */
5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	encr_alg = ikev2_get_encr(encr_id);
5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (encr_alg == NULL) {
5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unsupported encryption type");
5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iv_len = encr_alg->block_size;
5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	integ_alg = ikev2_get_integ(integ_id);
5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (integ_alg == NULL) {
5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unsupported intergrity type");
5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (SK_e == NULL) {
5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No SK_e available");
5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (SK_a == NULL) {
5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No SK_a available");
5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	phdr = wpabuf_put(msg, sizeof(*phdr));
5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	phdr->next_payload = next_payload;
5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	phdr->flags = 0;
5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iv = wpabuf_put(msg, iv_len);
5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (random_get_bytes(iv, iv_len)) {
5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Could not generate IV");
5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pad_len = iv_len - (wpabuf_len(plain) + 1) % iv_len;
5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pad_len == iv_len)
5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pad_len = 0;
5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put(plain, pad_len);
5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_u8(plain, pad_len);
5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ikev2_encr_encrypt(encr_alg->id, SK_e, keys->SK_encr_len, iv,
5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       wpabuf_head(plain), wpabuf_mhead(plain),
5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       wpabuf_len(plain)) < 0)
5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_buf(msg, plain);
5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Need to update all headers (Length fields) prior to hash func */
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	icv = wpabuf_put(msg, integ_alg->hash_len);
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_PUT_BE16(phdr->payload_length, plen);
5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ikev2_update_hdr(msg);
6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ikev2_integ_hash(integ_id, SK_a, keys->SK_integ_len,
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpabuf_head(msg),
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpabuf_len(msg) - integ_alg->hash_len, icv);
6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_keys_set(struct ikev2_keys *keys)
6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return keys->SK_d && keys->SK_ai && keys->SK_ar && keys->SK_ei &&
6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		keys->SK_er && keys->SK_pi && keys->SK_pr;
6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ikev2_free_keys(struct ikev2_keys *keys)
6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(keys->SK_d);
6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(keys->SK_ai);
6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(keys->SK_ar);
6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(keys->SK_ei);
6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(keys->SK_er);
6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(keys->SK_pi);
6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(keys->SK_pr);
6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_d = keys->SK_ai = keys->SK_ar = keys->SK_ei = keys->SK_er =
6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		keys->SK_pi = keys->SK_pr = NULL;
6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_derive_sk_keys(const struct ikev2_prf_alg *prf,
6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 const struct ikev2_integ_alg *integ,
6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 const struct ikev2_encr_alg *encr,
6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 const u8 *skeyseed, const u8 *data, size_t data_len,
6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 struct ikev2_keys *keys)
6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *keybuf, *pos;
6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t keybuf_len;
6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * {SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr } =
6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *	prf+(SKEYSEED, Ni | Nr | SPIi | SPIr )
6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ikev2_free_keys(keys);
6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_d_len = prf->key_len;
6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_integ_len = integ->key_len;
6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_encr_len = encr->key_len;
6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_prf_len = prf->key_len;
6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keybuf_len = keys->SK_d_len + 2 * keys->SK_integ_len +
6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		2 * keys->SK_encr_len + 2 * keys->SK_prf_len;
6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keybuf = os_malloc(keybuf_len);
6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (keybuf == NULL)
6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ikev2_prf_plus(prf->id, skeyseed, prf->hash_len,
6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   data, data_len, keybuf, keybuf_len)) {
6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(keybuf);
6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = keybuf;
6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_d = os_malloc(keys->SK_d_len);
6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (keys->SK_d) {
6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(keys->SK_d, pos, keys->SK_d_len);
6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_d",
6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				keys->SK_d, keys->SK_d_len);
6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += keys->SK_d_len;
6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_ai = os_malloc(keys->SK_integ_len);
6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (keys->SK_ai) {
6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(keys->SK_ai, pos, keys->SK_integ_len);
6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ai",
6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				keys->SK_ai, keys->SK_integ_len);
6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += keys->SK_integ_len;
6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_ar = os_malloc(keys->SK_integ_len);
6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (keys->SK_ar) {
6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(keys->SK_ar, pos, keys->SK_integ_len);
6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ar",
6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				keys->SK_ar, keys->SK_integ_len);
6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += keys->SK_integ_len;
6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_ei = os_malloc(keys->SK_encr_len);
6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (keys->SK_ei) {
6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(keys->SK_ei, pos, keys->SK_encr_len);
6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ei",
6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				keys->SK_ei, keys->SK_encr_len);
6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += keys->SK_encr_len;
6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_er = os_malloc(keys->SK_encr_len);
6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (keys->SK_er) {
6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(keys->SK_er, pos, keys->SK_encr_len);
6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_er",
6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				keys->SK_er, keys->SK_encr_len);
7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += keys->SK_encr_len;
7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_pi = os_malloc(keys->SK_prf_len);
7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (keys->SK_pi) {
7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(keys->SK_pi, pos, keys->SK_prf_len);
7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_pi",
7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				keys->SK_pi, keys->SK_prf_len);
7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += keys->SK_prf_len;
7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_pr = os_malloc(keys->SK_prf_len);
7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (keys->SK_pr) {
7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(keys->SK_pr, pos, keys->SK_prf_len);
7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_pr",
7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				keys->SK_pr, keys->SK_prf_len);
7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(keybuf);
7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!ikev2_keys_set(keys)) {
7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ikev2_free_keys(keys);
7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
727