1526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/*
2526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * IKEv2 common routines for initiator and responder
3526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
4526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
5526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * This program is free software; you can redistribute it and/or modify
6526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * it under the terms of the GNU General Public License version 2 as
7526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * published by the Free Software Foundation.
8526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
9526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD
10526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * license.
11526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
12526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * See README and COPYING for more details.
13526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */
14526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
15526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "includes.h"
16526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
17526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "common.h"
18526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "sha1.h"
19526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "md5.h"
20526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "crypto.h"
21526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "ikev2_common.h"
22526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
23526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
24526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct ikev2_integ_alg ikev2_integ_algs[] = {
25526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	{ AUTH_HMAC_SHA1_96, 20, 12 },
26526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	{ AUTH_HMAC_MD5_96, 16, 12 }
27526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt};
28526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
29526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define NUM_INTEG_ALGS (sizeof(ikev2_integ_algs) / sizeof(ikev2_integ_algs[0]))
30526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
31526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
32526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct ikev2_prf_alg ikev2_prf_algs[] = {
33526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	{ PRF_HMAC_SHA1, 20, 20 },
34526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	{ PRF_HMAC_MD5, 16, 16 }
35526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt};
36526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
37526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define NUM_PRF_ALGS (sizeof(ikev2_prf_algs) / sizeof(ikev2_prf_algs[0]))
38526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
39526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
40526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct ikev2_encr_alg ikev2_encr_algs[] = {
41526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	{ ENCR_AES_CBC, 16, 16 }, /* only 128-bit keys supported for now */
42526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	{ ENCR_3DES, 24, 8 }
43526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt};
44526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
45526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#define NUM_ENCR_ALGS (sizeof(ikev2_encr_algs) / sizeof(ikev2_encr_algs[0]))
46526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
47526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
48526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtconst struct ikev2_integ_alg * ikev2_get_integ(int id)
49526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
50526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t i;
51526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
52526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	for (i = 0; i < NUM_INTEG_ALGS; i++) {
53526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (ikev2_integ_algs[i].id == id)
54526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return &ikev2_integ_algs[i];
55526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
56526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
57526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return NULL;
58526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
59526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
60526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
61526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint ikev2_integ_hash(int alg, const u8 *key, size_t key_len, const u8 *data,
62526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		     size_t data_len, u8 *hash)
63526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
64526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 tmphash[IKEV2_MAX_HASH_LEN];
65526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
66526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	switch (alg) {
67526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case AUTH_HMAC_SHA1_96:
68526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (key_len != 20)
69526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
70526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		hmac_sha1(key, key_len, data, data_len, tmphash);
71526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(hash, tmphash, 12);
72526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
73526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case AUTH_HMAC_MD5_96:
74526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (key_len != 16)
75526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
76526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		hmac_md5(key, key_len, data, data_len, tmphash);
77526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(hash, tmphash, 12);
78526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
79526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	default:
80526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
81526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
82526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
83526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
84526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
85526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
86526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
87526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtconst struct ikev2_prf_alg * ikev2_get_prf(int id)
88526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
89526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t i;
90526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
91526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	for (i = 0; i < NUM_PRF_ALGS; i++) {
92526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (ikev2_prf_algs[i].id == id)
93526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return &ikev2_prf_algs[i];
94526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
95526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
96526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return NULL;
97526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
98526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
99526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
100526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint ikev2_prf_hash(int alg, const u8 *key, size_t key_len,
101526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   size_t num_elem, const u8 *addr[], const size_t *len,
102526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   u8 *hash)
103526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
104526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	switch (alg) {
105526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case PRF_HMAC_SHA1:
106526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		hmac_sha1_vector(key, key_len, num_elem, addr, len, hash);
107526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
108526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case PRF_HMAC_MD5:
109526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		hmac_md5_vector(key, key_len, num_elem, addr, len, hash);
110526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
111526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	default:
112526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
113526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
114526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
115526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
116526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
117526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
118526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
119526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint ikev2_prf_plus(int alg, const u8 *key, size_t key_len,
120526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   const u8 *data, size_t data_len,
121526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   u8 *out, size_t out_len)
122526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
123526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 hash[IKEV2_MAX_HASH_LEN];
124526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t hash_len;
125526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 iter, *pos, *end;
126526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *addr[3];
127526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t len[3];
128526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const struct ikev2_prf_alg *prf;
129526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int res;
130526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
131526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	prf = ikev2_get_prf(alg);
132526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (prf == NULL)
133526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
134526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	hash_len = prf->hash_len;
135526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
136526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	addr[0] = hash;
137526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	len[0] = hash_len;
138526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	addr[1] = data;
139526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	len[1] = data_len;
140526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	addr[2] = &iter;
141526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	len[2] = 1;
142526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
143526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos = out;
144526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	end = out + out_len;
145526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	iter = 1;
146526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	while (pos < end) {
147526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		size_t clen;
148526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (iter == 1)
149526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			res = ikev2_prf_hash(alg, key, key_len, 2, &addr[1],
150526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					     &len[1], hash);
151526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		else
152526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			res = ikev2_prf_hash(alg, key, key_len, 3, addr, len,
153526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					     hash);
154526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (res < 0)
155526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
156526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		clen = hash_len;
157526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if ((int) clen > end - pos)
158526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			clen = end - pos;
159526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(pos, hash, clen);
160526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos += clen;
161526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		iter++;
162526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
163526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
164526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
165526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
166526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
167526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
168526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtconst struct ikev2_encr_alg * ikev2_get_encr(int id)
169526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
170526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t i;
171526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
172526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	for (i = 0; i < NUM_ENCR_ALGS; i++) {
173526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (ikev2_encr_algs[i].id == id)
174526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return &ikev2_encr_algs[i];
175526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
176526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
177526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return NULL;
178526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
179526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
180526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
181526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CCNS_PL
182526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/* from des.c */
183526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct des3_key_s {
184526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u32 ek[3][32];
185526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u32 dk[3][32];
186526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt};
187526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
188526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid des3_key_setup(const u8 *key, struct des3_key_s *dkey);
189526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt);
190526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain);
191526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CCNS_PL */
192526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
193526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
194526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint ikev2_encr_encrypt(int alg, const u8 *key, size_t key_len, const u8 *iv,
195526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		       const u8 *plain, u8 *crypt, size_t len)
196526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
197526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct crypto_cipher *cipher;
198526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int encr_alg;
199526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
200526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CCNS_PL
201526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (alg == ENCR_3DES) {
202526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		struct des3_key_s des3key;
203526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		size_t i, blocks;
204526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		u8 *pos;
205526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
206526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		/* ECB mode is used incorrectly for 3DES!? */
207526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (key_len != 24) {
208526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_INFO, "IKEV2: Invalid encr key length");
209526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
210526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
211526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		des3_key_setup(key, &des3key);
212526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
213526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		blocks = len / 8;
214526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos = crypt;
215526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		for (i = 0; i < blocks; i++) {
216526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			des3_encrypt(pos, &des3key, pos);
217526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			pos += 8;
218526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
219526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else {
220526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CCNS_PL */
221526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	switch (alg) {
222526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case ENCR_3DES:
223526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		encr_alg = CRYPTO_CIPHER_ALG_3DES;
224526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
225526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case ENCR_AES_CBC:
226526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		encr_alg = CRYPTO_CIPHER_ALG_AES;
227526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
228526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	default:
229526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "IKEV2: Unsupported encr alg %d", alg);
230526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
231526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
232526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
233526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	cipher = crypto_cipher_init(encr_alg, iv, key, key_len);
234526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (cipher == NULL) {
235526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Failed to initialize cipher");
236526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
237526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
238526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
239526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (crypto_cipher_encrypt(cipher, plain, crypt, len) < 0) {
240526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Encryption failed");
241526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		crypto_cipher_deinit(cipher);
242526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
243526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
244526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	crypto_cipher_deinit(cipher);
245526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CCNS_PL
246526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
247526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CCNS_PL */
248526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
249526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
250526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
251526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
252526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
253526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint ikev2_encr_decrypt(int alg, const u8 *key, size_t key_len, const u8 *iv,
254526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		       const u8 *crypt, u8 *plain, size_t len)
255526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
256526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct crypto_cipher *cipher;
257526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int encr_alg;
258526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
259526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CCNS_PL
260526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (alg == ENCR_3DES) {
261526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		struct des3_key_s des3key;
262526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		size_t i, blocks;
263526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
264526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		/* ECB mode is used incorrectly for 3DES!? */
265526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (key_len != 24) {
266526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_INFO, "IKEV2: Invalid encr key length");
267526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
268526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
269526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		des3_key_setup(key, &des3key);
270526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
271526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (len % 8) {
272526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_INFO, "IKEV2: Invalid encrypted "
273526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "length");
274526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
275526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
276526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		blocks = len / 8;
277526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		for (i = 0; i < blocks; i++) {
278526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			des3_decrypt(crypt, &des3key, plain);
279526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			plain += 8;
280526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			crypt += 8;
281526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
282526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else {
283526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CCNS_PL */
284526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	switch (alg) {
285526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case ENCR_3DES:
286526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		encr_alg = CRYPTO_CIPHER_ALG_3DES;
287526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
288526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case ENCR_AES_CBC:
289526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		encr_alg = CRYPTO_CIPHER_ALG_AES;
290526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
291526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	default:
292526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "IKEV2: Unsupported encr alg %d", alg);
293526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
294526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
295526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
296526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	cipher = crypto_cipher_init(encr_alg, iv, key, key_len);
297526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (cipher == NULL) {
298526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Failed to initialize cipher");
299526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
300526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
301526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
302526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (crypto_cipher_decrypt(cipher, crypt, plain, len) < 0) {
303526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Decryption failed");
304526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		crypto_cipher_deinit(cipher);
305526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
306526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
307526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	crypto_cipher_deinit(cipher);
308526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CCNS_PL
309526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
310526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CCNS_PL */
311526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
312526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
313526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
314526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
315526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
316526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint ikev2_parse_payloads(struct ikev2_payloads *payloads,
317526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			 u8 next_payload, const u8 *pos, const u8 *end)
318526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
319526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const struct ikev2_payload_hdr *phdr;
320526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
321526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memset(payloads, 0, sizeof(*payloads));
322526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
323526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	while (next_payload != IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) {
324526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		int plen, pdatalen;
325526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		const u8 *pdata;
326526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "IKEV2: Processing payload %u",
327526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   next_payload);
328526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (end - pos < (int) sizeof(*phdr)) {
329526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_INFO, "IKEV2:   Too short message for "
330526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "payload header (left=%ld)",
331526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   (long) (end - pos));
332526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
333526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		phdr = (const struct ikev2_payload_hdr *) pos;
334526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		plen = WPA_GET_BE16(phdr->payload_length);
335526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (plen < (int) sizeof(*phdr) || pos + plen > end) {
336526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_INFO, "IKEV2:   Invalid payload header "
337526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "length %d", plen);
338526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
339526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
340526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
341526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "IKEV2:   Next Payload: %u  Flags: 0x%x"
342526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "  Payload Length: %d",
343526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   phdr->next_payload, phdr->flags, plen);
344526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
345526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pdata = (const u8 *) (phdr + 1);
346526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pdatalen = plen - sizeof(*phdr);
347526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
348526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		switch (next_payload) {
349526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		case IKEV2_PAYLOAD_SA:
350526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Security "
351526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "Association");
352526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			payloads->sa = pdata;
353526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			payloads->sa_len = pdatalen;
354526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			break;
355526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		case IKEV2_PAYLOAD_KEY_EXCHANGE:
356526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Key "
357526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "Exchange");
358526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			payloads->ke = pdata;
359526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			payloads->ke_len = pdatalen;
360526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			break;
361526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		case IKEV2_PAYLOAD_IDi:
362526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: IDi");
363526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			payloads->idi = pdata;
364526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			payloads->idi_len = pdatalen;
365526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			break;
366526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		case IKEV2_PAYLOAD_IDr:
367526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: IDr");
368526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			payloads->idr = pdata;
369526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			payloads->idr_len = pdatalen;
370526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			break;
371526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		case IKEV2_PAYLOAD_CERTIFICATE:
372526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Certificate");
373526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			payloads->cert = pdata;
374526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			payloads->cert_len = pdatalen;
375526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			break;
376526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		case IKEV2_PAYLOAD_AUTHENTICATION:
377526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: "
378526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "Authentication");
379526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			payloads->auth = pdata;
380526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			payloads->auth_len = pdatalen;
381526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			break;
382526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		case IKEV2_PAYLOAD_NONCE:
383526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Nonce");
384526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			payloads->nonce = pdata;
385526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			payloads->nonce_len = pdatalen;
386526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			break;
387526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		case IKEV2_PAYLOAD_ENCRYPTED:
388526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Encrypted");
389526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			payloads->encrypted = pdata;
390526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			payloads->encrypted_len = pdatalen;
391526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			break;
392526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		case IKEV2_PAYLOAD_NOTIFICATION:
393526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: "
394526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "Notification");
395526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			payloads->notification = pdata;
396526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			payloads->notification_len = pdatalen;
397526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			break;
398526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		default:
399526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			if (phdr->flags & IKEV2_PAYLOAD_FLAGS_CRITICAL) {
400526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				wpa_printf(MSG_INFO, "IKEV2:   Unsupported "
401526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					   "critical payload %u - reject the "
402526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					   "entire message", next_payload);
403526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				return -1;
404526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			} else {
405526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				wpa_printf(MSG_DEBUG, "IKEV2:   Skipped "
406526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					   "unsupported payload %u",
407526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					   next_payload);
408526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			}
409526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
410526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
411526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (next_payload == IKEV2_PAYLOAD_ENCRYPTED &&
412526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    pos + plen == end) {
413526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			/*
414526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			 * Next Payload in the case of Encrypted Payload is
415526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			 * actually the payload type for the first embedded
416526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			 * payload.
417526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			 */
418526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			payloads->encr_next_payload = phdr->next_payload;
419526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			next_payload = IKEV2_PAYLOAD_NO_NEXT_PAYLOAD;
420526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		} else
421526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			next_payload = phdr->next_payload;
422526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
423526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos += plen;
424526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
425526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
426526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (pos != end) {
427526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unexpected extra data after "
428526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "payloads");
429526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
430526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
431526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
432526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
433526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
434526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
435526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
436526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint ikev2_derive_auth_data(int prf_alg, const struct wpabuf *sign_msg,
437526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   const u8 *ID, size_t ID_len, u8 ID_type,
438526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   struct ikev2_keys *keys, int initiator,
439526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   const u8 *shared_secret, size_t shared_secret_len,
440526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   const u8 *nonce, size_t nonce_len,
441526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   const u8 *key_pad, size_t key_pad_len,
442526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   u8 *auth_data)
443526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
444526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t sign_len, buf_len;
445526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *sign_data, *pos, *buf, hash[IKEV2_MAX_HASH_LEN];
446526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const struct ikev2_prf_alg *prf;
447526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *SK_p = initiator ? keys->SK_pi : keys->SK_pr;
448526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
449526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	prf = ikev2_get_prf(prf_alg);
450526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (sign_msg == NULL || ID == NULL || SK_p == NULL ||
451526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    shared_secret == NULL || nonce == NULL || prf == NULL)
452526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
453526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
454526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* prf(SK_pi/r,IDi/r') */
455526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	buf_len = 4 + ID_len;
456526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	buf = os_zalloc(buf_len);
457526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (buf == NULL)
458526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
459526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	buf[0] = ID_type;
460526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(buf + 4, ID, ID_len);
461526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ikev2_prf_hash(prf->id, SK_p, keys->SK_prf_len,
462526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   1, (const u8 **) &buf, &buf_len, hash) < 0) {
463526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(buf);
464526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
465526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
466526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(buf);
467526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
468526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* sign_data = msg | Nr/i | prf(SK_pi/r,IDi/r') */
469526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	sign_len = wpabuf_len(sign_msg) + nonce_len + prf->hash_len;
470526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	sign_data = os_malloc(sign_len);
471526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (sign_data == NULL)
472526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
473526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos = sign_data;
474526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(pos, wpabuf_head(sign_msg), wpabuf_len(sign_msg));
475526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += wpabuf_len(sign_msg);
476526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(pos, nonce, nonce_len);
477526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += nonce_len;
478526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(pos, hash, prf->hash_len);
479526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
480526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* AUTH = prf(prf(Shared Secret, key pad, sign_data) */
481526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ikev2_prf_hash(prf->id, shared_secret, shared_secret_len, 1,
482526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   &key_pad, &key_pad_len, hash) < 0 ||
483526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    ikev2_prf_hash(prf->id, hash, prf->hash_len, 1,
484526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   (const u8 **) &sign_data, &sign_len, auth_data) < 0)
485526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	{
486526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(sign_data);
487526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
488526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
489526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(sign_data);
490526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
491526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
492526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
493526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
494526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
495526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtu8 * ikev2_decrypt_payload(int encr_id, int integ_id,
496526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   struct ikev2_keys *keys, int initiator,
497526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   const struct ikev2_hdr *hdr,
498526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   const u8 *encrypted, size_t encrypted_len,
499526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   size_t *res_len)
500526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
501526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t iv_len;
502526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *pos, *end, *iv, *integ;
503526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 hash[IKEV2_MAX_HASH_LEN], *decrypted;
504526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t decrypted_len, pad_len;
505526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const struct ikev2_integ_alg *integ_alg;
506526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const struct ikev2_encr_alg *encr_alg;
507526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *SK_e = initiator ? keys->SK_ei : keys->SK_er;
508526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar;
509526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
510526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (encrypted == NULL) {
511526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No Encrypted payload in SA_AUTH");
512526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
513526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
514526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
515526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	encr_alg = ikev2_get_encr(encr_id);
516526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (encr_alg == NULL) {
517526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unsupported encryption type");
518526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
519526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
520526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	iv_len = encr_alg->block_size;
521526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
522526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	integ_alg = ikev2_get_integ(integ_id);
523526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (integ_alg == NULL) {
524526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unsupported intergrity type");
525526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
526526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
527526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
528526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (encrypted_len < iv_len + 1 + integ_alg->hash_len) {
529526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No room for IV or Integrity "
530526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  "Checksum");
531526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
532526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
533526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
534526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	iv = encrypted;
535526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos = iv + iv_len;
536526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	end = encrypted + encrypted_len;
537526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	integ = end - integ_alg->hash_len;
538526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
539526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (SK_a == NULL) {
540526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No SK_a available");
541526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
542526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
543526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ikev2_integ_hash(integ_id, SK_a, keys->SK_integ_len,
544526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     (const u8 *) hdr,
545526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     integ - (const u8 *) hdr, hash) < 0) {
546526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Failed to calculate integrity "
547526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "hash");
548526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
549526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
550526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (os_memcmp(integ, hash, integ_alg->hash_len) != 0) {
551526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Incorrect Integrity Checksum "
552526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "Data");
553526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
554526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
555526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
556526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (SK_e == NULL) {
557526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No SK_e available");
558526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
559526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
560526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
561526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	decrypted_len = integ - pos;
562526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	decrypted = os_malloc(decrypted_len);
563526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (decrypted == NULL)
564526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
565526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
566526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ikev2_encr_decrypt(encr_alg->id, SK_e, keys->SK_encr_len, iv, pos,
567526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			       decrypted, decrypted_len) < 0) {
568526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(decrypted);
569526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
570526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
571526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
572526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pad_len = decrypted[decrypted_len - 1];
573526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (decrypted_len < pad_len + 1) {
574526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Invalid padding in encrypted "
575526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "payload");
576526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(decrypted);
577526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
578526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
579526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
580526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	decrypted_len -= pad_len + 1;
581526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
582526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	*res_len = decrypted_len;
583526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return decrypted;
584526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
585526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
586526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
587526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid ikev2_update_hdr(struct wpabuf *msg)
588526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
589526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct ikev2_hdr *hdr;
590526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
591526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Update lenth field in HDR */
592526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	hdr = wpabuf_mhead(msg);
593526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	WPA_PUT_BE32(hdr->length, wpabuf_len(msg));
594526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
595526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
596526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
597526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint ikev2_build_encrypted(int encr_id, int integ_id, struct ikev2_keys *keys,
598526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  int initiator, struct wpabuf *msg,
599526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  struct wpabuf *plain, u8 next_payload)
600526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
601526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct ikev2_payload_hdr *phdr;
602526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t plen;
603526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t iv_len, pad_len;
604526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *icv, *iv;
605526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const struct ikev2_integ_alg *integ_alg;
606526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const struct ikev2_encr_alg *encr_alg;
607526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *SK_e = initiator ? keys->SK_ei : keys->SK_er;
608526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar;
609526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
610526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "IKEV2: Adding Encrypted payload");
611526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
612526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Encr - RFC 4306, Sect. 3.14 */
613526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
614526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	encr_alg = ikev2_get_encr(encr_id);
615526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (encr_alg == NULL) {
616526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unsupported encryption type");
617526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
618526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
619526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	iv_len = encr_alg->block_size;
620526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
621526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	integ_alg = ikev2_get_integ(integ_id);
622526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (integ_alg == NULL) {
623526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unsupported intergrity type");
624526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
625526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
626526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
627526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (SK_e == NULL) {
628526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No SK_e available");
629526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
630526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
631526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
632526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (SK_a == NULL) {
633526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No SK_a available");
634526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
635526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
636526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
637526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	phdr = wpabuf_put(msg, sizeof(*phdr));
638526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	phdr->next_payload = next_payload;
639526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	phdr->flags = 0;
640526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
641526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	iv = wpabuf_put(msg, iv_len);
642526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (os_get_random(iv, iv_len)) {
643526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Could not generate IV");
644526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
645526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
646526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
647526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pad_len = iv_len - (wpabuf_len(plain) + 1) % iv_len;
648526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (pad_len == iv_len)
649526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pad_len = 0;
650526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_put(plain, pad_len);
651526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_put_u8(plain, pad_len);
652526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
653526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ikev2_encr_encrypt(encr_alg->id, SK_e, keys->SK_encr_len, iv,
654526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			       wpabuf_head(plain), wpabuf_mhead(plain),
655526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			       wpabuf_len(plain)) < 0)
656526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
657526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
658526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_put_buf(msg, plain);
659526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
660526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Need to update all headers (Length fields) prior to hash func */
661526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	icv = wpabuf_put(msg, integ_alg->hash_len);
662526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
663526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	WPA_PUT_BE16(phdr->payload_length, plen);
664526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
665526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ikev2_update_hdr(msg);
666526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
667526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return ikev2_integ_hash(integ_id, SK_a, keys->SK_integ_len,
668526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				wpabuf_head(msg),
669526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				wpabuf_len(msg) - integ_alg->hash_len, icv);
670526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
671526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
672526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
673526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
674526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
675526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint ikev2_keys_set(struct ikev2_keys *keys)
676526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
677526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return keys->SK_d && keys->SK_ai && keys->SK_ar && keys->SK_ei &&
678526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		keys->SK_er && keys->SK_pi && keys->SK_pr;
679526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
680526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
681526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
682526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid ikev2_free_keys(struct ikev2_keys *keys)
683526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
684526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(keys->SK_d);
685526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(keys->SK_ai);
686526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(keys->SK_ar);
687526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(keys->SK_ei);
688526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(keys->SK_er);
689526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(keys->SK_pi);
690526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(keys->SK_pr);
691526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	keys->SK_d = keys->SK_ai = keys->SK_ar = keys->SK_ei = keys->SK_er =
692526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		keys->SK_pi = keys->SK_pr = NULL;
693526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
694526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
695526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
696526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint ikev2_derive_sk_keys(const struct ikev2_prf_alg *prf,
697526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			 const struct ikev2_integ_alg *integ,
698526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			 const struct ikev2_encr_alg *encr,
699526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			 const u8 *skeyseed, const u8 *data, size_t data_len,
700526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			 struct ikev2_keys *keys)
701526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
702526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *keybuf, *pos;
703526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t keybuf_len;
704526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
705526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/*
706526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * {SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr } =
707526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 *	prf+(SKEYSEED, Ni | Nr | SPIi | SPIr )
708526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 */
709526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ikev2_free_keys(keys);
710526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	keys->SK_d_len = prf->key_len;
711526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	keys->SK_integ_len = integ->key_len;
712526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	keys->SK_encr_len = encr->key_len;
713526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	keys->SK_prf_len = prf->key_len;
714526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CCNS_PL
715526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Uses encryption key length for SK_d; should be PRF length */
716526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	keys->SK_d_len = keys->SK_encr_len;
717526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CCNS_PL */
718526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
719526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	keybuf_len = keys->SK_d_len + 2 * keys->SK_integ_len +
720526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		2 * keys->SK_encr_len + 2 * keys->SK_prf_len;
721526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	keybuf = os_malloc(keybuf_len);
722526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (keybuf == NULL)
723526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
724526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
725526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ikev2_prf_plus(prf->id, skeyseed, prf->hash_len,
726526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   data, data_len, keybuf, keybuf_len)) {
727526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(keybuf);
728526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
729526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
730526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
731526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos = keybuf;
732526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
733526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	keys->SK_d = os_malloc(keys->SK_d_len);
734526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (keys->SK_d) {
735526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(keys->SK_d, pos, keys->SK_d_len);
736526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_d",
737526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				keys->SK_d, keys->SK_d_len);
738526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
739526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += keys->SK_d_len;
740526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
741526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	keys->SK_ai = os_malloc(keys->SK_integ_len);
742526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (keys->SK_ai) {
743526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(keys->SK_ai, pos, keys->SK_integ_len);
744526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ai",
745526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				keys->SK_ai, keys->SK_integ_len);
746526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
747526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += keys->SK_integ_len;
748526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
749526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	keys->SK_ar = os_malloc(keys->SK_integ_len);
750526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (keys->SK_ar) {
751526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(keys->SK_ar, pos, keys->SK_integ_len);
752526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ar",
753526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				keys->SK_ar, keys->SK_integ_len);
754526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
755526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += keys->SK_integ_len;
756526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
757526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	keys->SK_ei = os_malloc(keys->SK_encr_len);
758526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (keys->SK_ei) {
759526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(keys->SK_ei, pos, keys->SK_encr_len);
760526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ei",
761526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				keys->SK_ei, keys->SK_encr_len);
762526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
763526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += keys->SK_encr_len;
764526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
765526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	keys->SK_er = os_malloc(keys->SK_encr_len);
766526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (keys->SK_er) {
767526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(keys->SK_er, pos, keys->SK_encr_len);
768526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_er",
769526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				keys->SK_er, keys->SK_encr_len);
770526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
771526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += keys->SK_encr_len;
772526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
773526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	keys->SK_pi = os_malloc(keys->SK_prf_len);
774526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (keys->SK_pi) {
775526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(keys->SK_pi, pos, keys->SK_prf_len);
776526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_pi",
777526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				keys->SK_pi, keys->SK_prf_len);
778526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
779526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += keys->SK_prf_len;
780526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
781526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	keys->SK_pr = os_malloc(keys->SK_prf_len);
782526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (keys->SK_pr) {
783526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(keys->SK_pr, pos, keys->SK_prf_len);
784526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_pr",
785526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				keys->SK_pr, keys->SK_prf_len);
786526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
787526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
788526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(keybuf);
789526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
790526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (!ikev2_keys_set(keys)) {
791526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ikev2_free_keys(keys);
792526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
793526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
794526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
795526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
796526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
797