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
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define NUM_INTEG_ALGS (sizeof(ikev2_integ_algs) / sizeof(ikev2_integ_algs[0]))
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
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define NUM_PRF_ALGS (sizeof(ikev2_prf_algs) / sizeof(ikev2_prf_algs[0]))
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
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define NUM_ENCR_ALGS (sizeof(ikev2_encr_algs) / sizeof(ikev2_encr_algs[0]))
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 Shmidt#ifdef CCNS_PL
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* from des.c */
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct des3_key_s {
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 ek[3][32];
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 dk[3][32];
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid des3_key_setup(const u8 *key, struct des3_key_s *dkey);
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt);
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain);
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CCNS_PL */
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_encr_encrypt(int alg, const u8 *key, size_t key_len, const u8 *iv,
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       const u8 *plain, u8 *crypt, size_t len)
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct crypto_cipher *cipher;
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int encr_alg;
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CCNS_PL
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (alg == ENCR_3DES) {
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct des3_key_s des3key;
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		size_t i, blocks;
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		u8 *pos;
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* ECB mode is used incorrectly for 3DES!? */
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (key_len != 24) {
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "IKEV2: Invalid encr key length");
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		des3_key_setup(key, &des3key);
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		blocks = len / 8;
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos = crypt;
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		for (i = 0; i < blocks; i++) {
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			des3_encrypt(pos, &des3key, pos);
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			pos += 8;
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CCNS_PL */
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (alg) {
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case ENCR_3DES:
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		encr_alg = CRYPTO_CIPHER_ALG_3DES;
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case ENCR_AES_CBC:
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		encr_alg = CRYPTO_CIPHER_ALG_AES;
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "IKEV2: Unsupported encr alg %d", alg);
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cipher = crypto_cipher_init(encr_alg, iv, key, key_len);
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cipher == NULL) {
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Failed to initialize cipher");
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (crypto_cipher_encrypt(cipher, plain, crypt, len) < 0) {
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Encryption failed");
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		crypto_cipher_deinit(cipher);
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	crypto_cipher_deinit(cipher);
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CCNS_PL
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CCNS_PL */
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_encr_decrypt(int alg, const u8 *key, size_t key_len, const u8 *iv,
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       const u8 *crypt, u8 *plain, size_t len)
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct crypto_cipher *cipher;
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int encr_alg;
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CCNS_PL
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (alg == ENCR_3DES) {
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct des3_key_s des3key;
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		size_t i, blocks;
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* ECB mode is used incorrectly for 3DES!? */
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (key_len != 24) {
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "IKEV2: Invalid encr key length");
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		des3_key_setup(key, &des3key);
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (len % 8) {
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "IKEV2: Invalid encrypted "
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "length");
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		blocks = len / 8;
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		for (i = 0; i < blocks; i++) {
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			des3_decrypt(crypt, &des3key, plain);
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			plain += 8;
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			crypt += 8;
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CCNS_PL */
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (alg) {
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case ENCR_3DES:
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		encr_alg = CRYPTO_CIPHER_ALG_3DES;
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case ENCR_AES_CBC:
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		encr_alg = CRYPTO_CIPHER_ALG_AES;
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "IKEV2: Unsupported encr alg %d", alg);
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cipher = crypto_cipher_init(encr_alg, iv, key, key_len);
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cipher == NULL) {
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Failed to initialize cipher");
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (crypto_cipher_decrypt(cipher, crypt, plain, len) < 0) {
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Decryption failed");
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		crypto_cipher_deinit(cipher);
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	crypto_cipher_deinit(cipher);
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CCNS_PL
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CCNS_PL */
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_parse_payloads(struct ikev2_payloads *payloads,
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 u8 next_payload, const u8 *pos, const u8 *end)
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ikev2_payload_hdr *phdr;
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(payloads, 0, sizeof(*payloads));
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (next_payload != IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) {
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int plen, pdatalen;
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		const u8 *pdata;
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "IKEV2: Processing payload %u",
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   next_payload);
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (end - pos < (int) sizeof(*phdr)) {
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "IKEV2:   Too short message for "
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "payload header (left=%ld)",
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   (long) (end - pos));
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		phdr = (const struct ikev2_payload_hdr *) pos;
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		plen = WPA_GET_BE16(phdr->payload_length);
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (plen < (int) sizeof(*phdr) || pos + plen > end) {
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "IKEV2:   Invalid payload header "
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "length %d", plen);
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "IKEV2:   Next Payload: %u  Flags: 0x%x"
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "  Payload Length: %d",
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   phdr->next_payload, phdr->flags, plen);
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pdata = (const u8 *) (phdr + 1);
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pdatalen = plen - sizeof(*phdr);
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (next_payload) {
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_SA:
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Security "
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Association");
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->sa = pdata;
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->sa_len = pdatalen;
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_KEY_EXCHANGE:
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Key "
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Exchange");
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->ke = pdata;
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->ke_len = pdatalen;
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_IDi:
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: IDi");
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->idi = pdata;
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->idi_len = pdatalen;
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_IDr:
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: IDr");
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->idr = pdata;
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->idr_len = pdatalen;
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_CERTIFICATE:
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Certificate");
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->cert = pdata;
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->cert_len = pdatalen;
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_AUTHENTICATION:
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: "
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Authentication");
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->auth = pdata;
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->auth_len = pdatalen;
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_NONCE:
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Nonce");
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->nonce = pdata;
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->nonce_len = pdatalen;
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_ENCRYPTED:
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Encrypted");
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->encrypted = pdata;
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->encrypted_len = pdatalen;
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IKEV2_PAYLOAD_NOTIFICATION:
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: "
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Notification");
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->notification = pdata;
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->notification_len = pdatalen;
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (phdr->flags & IKEV2_PAYLOAD_FLAGS_CRITICAL) {
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_INFO, "IKEV2:   Unsupported "
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "critical payload %u - reject the "
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "entire message", next_payload);
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return -1;
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			} else {
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "IKEV2:   Skipped "
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "unsupported payload %u",
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   next_payload);
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (next_payload == IKEV2_PAYLOAD_ENCRYPTED &&
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    pos + plen == end) {
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/*
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * Next Payload in the case of Encrypted Payload is
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * actually the payload type for the first embedded
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * payload.
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 */
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			payloads->encr_next_payload = phdr->next_payload;
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			next_payload = IKEV2_PAYLOAD_NO_NEXT_PAYLOAD;
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			next_payload = phdr->next_payload;
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += plen;
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pos != end) {
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unexpected extra data after "
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "payloads");
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_derive_auth_data(int prf_alg, const struct wpabuf *sign_msg,
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   const u8 *ID, size_t ID_len, u8 ID_type,
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   struct ikev2_keys *keys, int initiator,
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   const u8 *shared_secret, size_t shared_secret_len,
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   const u8 *nonce, size_t nonce_len,
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   const u8 *key_pad, size_t key_pad_len,
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   u8 *auth_data)
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t sign_len, buf_len;
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *sign_data, *pos, *buf, hash[IKEV2_MAX_HASH_LEN];
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ikev2_prf_alg *prf;
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *SK_p = initiator ? keys->SK_pi : keys->SK_pr;
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	prf = ikev2_get_prf(prf_alg);
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sign_msg == NULL || ID == NULL || SK_p == NULL ||
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    shared_secret == NULL || nonce == NULL || prf == NULL)
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* prf(SK_pi/r,IDi/r') */
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf_len = 4 + ID_len;
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf = os_zalloc(buf_len);
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL)
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf[0] = ID_type;
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(buf + 4, ID, ID_len);
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ikev2_prf_hash(prf->id, SK_p, keys->SK_prf_len,
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   1, (const u8 **) &buf, &buf_len, hash) < 0) {
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(buf);
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(buf);
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* sign_data = msg | Nr/i | prf(SK_pi/r,IDi/r') */
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sign_len = wpabuf_len(sign_msg) + nonce_len + prf->hash_len;
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sign_data = os_malloc(sign_len);
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sign_data == NULL)
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = sign_data;
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, wpabuf_head(sign_msg), wpabuf_len(sign_msg));
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += wpabuf_len(sign_msg);
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, nonce, nonce_len);
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += nonce_len;
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, hash, prf->hash_len);
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* AUTH = prf(prf(Shared Secret, key pad, sign_data) */
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ikev2_prf_hash(prf->id, shared_secret, shared_secret_len, 1,
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   &key_pad, &key_pad_len, hash) < 0 ||
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    ikev2_prf_hash(prf->id, hash, prf->hash_len, 1,
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (const u8 **) &sign_data, &sign_len, auth_data) < 0)
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(sign_data);
4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(sign_data);
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtu8 * ikev2_decrypt_payload(int encr_id, int integ_id,
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   struct ikev2_keys *keys, int initiator,
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   const struct ikev2_hdr *hdr,
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   const u8 *encrypted, size_t encrypted_len,
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   size_t *res_len)
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t iv_len;
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos, *end, *iv, *integ;
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 hash[IKEV2_MAX_HASH_LEN], *decrypted;
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t decrypted_len, pad_len;
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ikev2_integ_alg *integ_alg;
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ikev2_encr_alg *encr_alg;
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *SK_e = initiator ? keys->SK_ei : keys->SK_er;
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar;
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (encrypted == NULL) {
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No Encrypted payload in SA_AUTH");
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	encr_alg = ikev2_get_encr(encr_id);
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (encr_alg == NULL) {
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unsupported encryption type");
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iv_len = encr_alg->block_size;
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	integ_alg = ikev2_get_integ(integ_id);
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (integ_alg == NULL) {
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unsupported intergrity type");
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (encrypted_len < iv_len + 1 + integ_alg->hash_len) {
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No room for IV or Integrity "
5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "Checksum");
5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iv = encrypted;
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = iv + iv_len;
5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = encrypted + encrypted_len;
5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	integ = end - integ_alg->hash_len;
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (SK_a == NULL) {
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No SK_a available");
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ikev2_integ_hash(integ_id, SK_a, keys->SK_integ_len,
5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     (const u8 *) hdr,
5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     integ - (const u8 *) hdr, hash) < 0) {
5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Failed to calculate integrity "
5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "hash");
5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_memcmp(integ, hash, integ_alg->hash_len) != 0) {
5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Incorrect Integrity Checksum "
5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Data");
5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (SK_e == NULL) {
5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No SK_e available");
5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	decrypted_len = integ - pos;
5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	decrypted = os_malloc(decrypted_len);
5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (decrypted == NULL)
5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ikev2_encr_decrypt(encr_alg->id, SK_e, keys->SK_encr_len, iv, pos,
5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       decrypted, decrypted_len) < 0) {
5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(decrypted);
5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pad_len = decrypted[decrypted_len - 1];
5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (decrypted_len < pad_len + 1) {
5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Invalid padding in encrypted "
5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "payload");
5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(decrypted);
5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	decrypted_len -= pad_len + 1;
5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*res_len = decrypted_len;
5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return decrypted;
5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ikev2_update_hdr(struct wpabuf *msg)
5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ikev2_hdr *hdr;
5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Update lenth field in HDR */
5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr = wpabuf_mhead(msg);
5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_PUT_BE32(hdr->length, wpabuf_len(msg));
5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_build_encrypted(int encr_id, int integ_id, struct ikev2_keys *keys,
5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  int initiator, struct wpabuf *msg,
5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  struct wpabuf *plain, u8 next_payload)
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ikev2_payload_hdr *phdr;
5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t plen;
5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t iv_len, pad_len;
5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *icv, *iv;
6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ikev2_integ_alg *integ_alg;
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ikev2_encr_alg *encr_alg;
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *SK_e = initiator ? keys->SK_ei : keys->SK_er;
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar;
6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "IKEV2: Adding Encrypted payload");
6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Encr - RFC 4306, Sect. 3.14 */
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	encr_alg = ikev2_get_encr(encr_id);
6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (encr_alg == NULL) {
6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unsupported encryption type");
6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iv_len = encr_alg->block_size;
6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	integ_alg = ikev2_get_integ(integ_id);
6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (integ_alg == NULL) {
6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unsupported intergrity type");
6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (SK_e == NULL) {
6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No SK_e available");
6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (SK_a == NULL) {
6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No SK_a available");
6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	phdr = wpabuf_put(msg, sizeof(*phdr));
6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	phdr->next_payload = next_payload;
6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	phdr->flags = 0;
6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iv = wpabuf_put(msg, iv_len);
6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (random_get_bytes(iv, iv_len)) {
6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Could not generate IV");
6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pad_len = iv_len - (wpabuf_len(plain) + 1) % iv_len;
6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pad_len == iv_len)
6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pad_len = 0;
6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put(plain, pad_len);
6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_u8(plain, pad_len);
6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ikev2_encr_encrypt(encr_alg->id, SK_e, keys->SK_encr_len, iv,
6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       wpabuf_head(plain), wpabuf_mhead(plain),
6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       wpabuf_len(plain)) < 0)
6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_buf(msg, plain);
6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Need to update all headers (Length fields) prior to hash func */
6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	icv = wpabuf_put(msg, integ_alg->hash_len);
6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_PUT_BE16(phdr->payload_length, plen);
6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ikev2_update_hdr(msg);
6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ikev2_integ_hash(integ_id, SK_a, keys->SK_integ_len,
6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpabuf_head(msg),
6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpabuf_len(msg) - integ_alg->hash_len, icv);
6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_keys_set(struct ikev2_keys *keys)
6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return keys->SK_d && keys->SK_ai && keys->SK_ar && keys->SK_ei &&
6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		keys->SK_er && keys->SK_pi && keys->SK_pr;
6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ikev2_free_keys(struct ikev2_keys *keys)
6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(keys->SK_d);
6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(keys->SK_ai);
6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(keys->SK_ar);
6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(keys->SK_ei);
6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(keys->SK_er);
6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(keys->SK_pi);
6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(keys->SK_pr);
6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_d = keys->SK_ai = keys->SK_ar = keys->SK_ei = keys->SK_er =
6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		keys->SK_pi = keys->SK_pr = NULL;
6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_derive_sk_keys(const struct ikev2_prf_alg *prf,
6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 const struct ikev2_integ_alg *integ,
6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 const struct ikev2_encr_alg *encr,
6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 const u8 *skeyseed, const u8 *data, size_t data_len,
6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 struct ikev2_keys *keys)
6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *keybuf, *pos;
6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t keybuf_len;
6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * {SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr } =
7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *	prf+(SKEYSEED, Ni | Nr | SPIi | SPIr )
7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ikev2_free_keys(keys);
7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_d_len = prf->key_len;
7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_integ_len = integ->key_len;
7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_encr_len = encr->key_len;
7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_prf_len = prf->key_len;
7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CCNS_PL
7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Uses encryption key length for SK_d; should be PRF length */
7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_d_len = keys->SK_encr_len;
7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CCNS_PL */
7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keybuf_len = keys->SK_d_len + 2 * keys->SK_integ_len +
7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		2 * keys->SK_encr_len + 2 * keys->SK_prf_len;
7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keybuf = os_malloc(keybuf_len);
7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (keybuf == NULL)
7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ikev2_prf_plus(prf->id, skeyseed, prf->hash_len,
7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   data, data_len, keybuf, keybuf_len)) {
7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(keybuf);
7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = keybuf;
7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_d = os_malloc(keys->SK_d_len);
7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (keys->SK_d) {
7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(keys->SK_d, pos, keys->SK_d_len);
7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_d",
7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				keys->SK_d, keys->SK_d_len);
7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += keys->SK_d_len;
7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_ai = os_malloc(keys->SK_integ_len);
7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (keys->SK_ai) {
7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(keys->SK_ai, pos, keys->SK_integ_len);
7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ai",
7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				keys->SK_ai, keys->SK_integ_len);
7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += keys->SK_integ_len;
7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_ar = os_malloc(keys->SK_integ_len);
7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (keys->SK_ar) {
7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(keys->SK_ar, pos, keys->SK_integ_len);
7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ar",
7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				keys->SK_ar, keys->SK_integ_len);
7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += keys->SK_integ_len;
7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_ei = os_malloc(keys->SK_encr_len);
7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (keys->SK_ei) {
7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(keys->SK_ei, pos, keys->SK_encr_len);
7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ei",
7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				keys->SK_ei, keys->SK_encr_len);
7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += keys->SK_encr_len;
7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_er = os_malloc(keys->SK_encr_len);
7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (keys->SK_er) {
7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(keys->SK_er, pos, keys->SK_encr_len);
7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_er",
7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				keys->SK_er, keys->SK_encr_len);
7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += keys->SK_encr_len;
7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_pi = os_malloc(keys->SK_prf_len);
7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (keys->SK_pi) {
7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(keys->SK_pi, pos, keys->SK_prf_len);
7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_pi",
7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				keys->SK_pi, keys->SK_prf_len);
7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += keys->SK_prf_len;
7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->SK_pr = os_malloc(keys->SK_prf_len);
7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (keys->SK_pr) {
7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(keys->SK_pr, pos, keys->SK_prf_len);
7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_pr",
7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				keys->SK_pr, keys->SK_prf_len);
7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(keybuf);
7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!ikev2_keys_set(keys)) {
7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ikev2_free_keys(keys);
7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
792