1e5b75505Sopenharmony_ci/*
2e5b75505Sopenharmony_ci * IKEv2 responder (RFC 4306) for EAP-IKEV2
3e5b75505Sopenharmony_ci * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
4e5b75505Sopenharmony_ci *
5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license.
6e5b75505Sopenharmony_ci * See README for more details.
7e5b75505Sopenharmony_ci */
8e5b75505Sopenharmony_ci
9e5b75505Sopenharmony_ci#include "includes.h"
10e5b75505Sopenharmony_ci
11e5b75505Sopenharmony_ci#include "common.h"
12e5b75505Sopenharmony_ci#include "crypto/dh_groups.h"
13e5b75505Sopenharmony_ci#include "crypto/random.h"
14e5b75505Sopenharmony_ci#include "ikev2.h"
15e5b75505Sopenharmony_ci
16e5b75505Sopenharmony_ci
17e5b75505Sopenharmony_civoid ikev2_responder_deinit(struct ikev2_responder_data *data)
18e5b75505Sopenharmony_ci{
19e5b75505Sopenharmony_ci	ikev2_free_keys(&data->keys);
20e5b75505Sopenharmony_ci	wpabuf_free(data->i_dh_public);
21e5b75505Sopenharmony_ci	wpabuf_free(data->r_dh_private);
22e5b75505Sopenharmony_ci	os_free(data->IDi);
23e5b75505Sopenharmony_ci	os_free(data->IDr);
24e5b75505Sopenharmony_ci	os_free(data->shared_secret);
25e5b75505Sopenharmony_ci	wpabuf_free(data->i_sign_msg);
26e5b75505Sopenharmony_ci	wpabuf_free(data->r_sign_msg);
27e5b75505Sopenharmony_ci	os_free(data->key_pad);
28e5b75505Sopenharmony_ci}
29e5b75505Sopenharmony_ci
30e5b75505Sopenharmony_ci
31e5b75505Sopenharmony_cistatic int ikev2_derive_keys(struct ikev2_responder_data *data)
32e5b75505Sopenharmony_ci{
33e5b75505Sopenharmony_ci	u8 *buf, *pos, *pad, skeyseed[IKEV2_MAX_HASH_LEN];
34e5b75505Sopenharmony_ci	size_t buf_len, pad_len;
35e5b75505Sopenharmony_ci	struct wpabuf *shared;
36e5b75505Sopenharmony_ci	const struct ikev2_integ_alg *integ;
37e5b75505Sopenharmony_ci	const struct ikev2_prf_alg *prf;
38e5b75505Sopenharmony_ci	const struct ikev2_encr_alg *encr;
39e5b75505Sopenharmony_ci	int ret;
40e5b75505Sopenharmony_ci	const u8 *addr[2];
41e5b75505Sopenharmony_ci	size_t len[2];
42e5b75505Sopenharmony_ci
43e5b75505Sopenharmony_ci	/* RFC 4306, Sect. 2.14 */
44e5b75505Sopenharmony_ci
45e5b75505Sopenharmony_ci	integ = ikev2_get_integ(data->proposal.integ);
46e5b75505Sopenharmony_ci	prf = ikev2_get_prf(data->proposal.prf);
47e5b75505Sopenharmony_ci	encr = ikev2_get_encr(data->proposal.encr);
48e5b75505Sopenharmony_ci	if (integ == NULL || prf == NULL || encr == NULL) {
49e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Unsupported proposal");
50e5b75505Sopenharmony_ci		return -1;
51e5b75505Sopenharmony_ci	}
52e5b75505Sopenharmony_ci
53e5b75505Sopenharmony_ci	shared = dh_derive_shared(data->i_dh_public, data->r_dh_private,
54e5b75505Sopenharmony_ci				  data->dh);
55e5b75505Sopenharmony_ci	if (shared == NULL)
56e5b75505Sopenharmony_ci		return -1;
57e5b75505Sopenharmony_ci
58e5b75505Sopenharmony_ci	/* Construct Ni | Nr | SPIi | SPIr */
59e5b75505Sopenharmony_ci
60e5b75505Sopenharmony_ci	buf_len = data->i_nonce_len + data->r_nonce_len + 2 * IKEV2_SPI_LEN;
61e5b75505Sopenharmony_ci	buf = os_malloc(buf_len);
62e5b75505Sopenharmony_ci	if (buf == NULL) {
63e5b75505Sopenharmony_ci		wpabuf_free(shared);
64e5b75505Sopenharmony_ci		return -1;
65e5b75505Sopenharmony_ci	}
66e5b75505Sopenharmony_ci
67e5b75505Sopenharmony_ci	pos = buf;
68e5b75505Sopenharmony_ci	os_memcpy(pos, data->i_nonce, data->i_nonce_len);
69e5b75505Sopenharmony_ci	pos += data->i_nonce_len;
70e5b75505Sopenharmony_ci	os_memcpy(pos, data->r_nonce, data->r_nonce_len);
71e5b75505Sopenharmony_ci	pos += data->r_nonce_len;
72e5b75505Sopenharmony_ci	os_memcpy(pos, data->i_spi, IKEV2_SPI_LEN);
73e5b75505Sopenharmony_ci	pos += IKEV2_SPI_LEN;
74e5b75505Sopenharmony_ci	os_memcpy(pos, data->r_spi, IKEV2_SPI_LEN);
75e5b75505Sopenharmony_ci
76e5b75505Sopenharmony_ci	/* SKEYSEED = prf(Ni | Nr, g^ir) */
77e5b75505Sopenharmony_ci	/* Use zero-padding per RFC 4306, Sect. 2.14 */
78e5b75505Sopenharmony_ci	pad_len = data->dh->prime_len - wpabuf_len(shared);
79e5b75505Sopenharmony_ci	pad = os_zalloc(pad_len ? pad_len : 1);
80e5b75505Sopenharmony_ci	if (pad == NULL) {
81e5b75505Sopenharmony_ci		wpabuf_free(shared);
82e5b75505Sopenharmony_ci		os_free(buf);
83e5b75505Sopenharmony_ci		return -1;
84e5b75505Sopenharmony_ci	}
85e5b75505Sopenharmony_ci
86e5b75505Sopenharmony_ci	addr[0] = pad;
87e5b75505Sopenharmony_ci	len[0] = pad_len;
88e5b75505Sopenharmony_ci	addr[1] = wpabuf_head(shared);
89e5b75505Sopenharmony_ci	len[1] = wpabuf_len(shared);
90e5b75505Sopenharmony_ci	if (ikev2_prf_hash(prf->id, buf, data->i_nonce_len + data->r_nonce_len,
91e5b75505Sopenharmony_ci			   2, addr, len, skeyseed) < 0) {
92e5b75505Sopenharmony_ci		wpabuf_free(shared);
93e5b75505Sopenharmony_ci		os_free(buf);
94e5b75505Sopenharmony_ci		os_free(pad);
95e5b75505Sopenharmony_ci		return -1;
96e5b75505Sopenharmony_ci	}
97e5b75505Sopenharmony_ci	os_free(pad);
98e5b75505Sopenharmony_ci	wpabuf_free(shared);
99e5b75505Sopenharmony_ci
100e5b75505Sopenharmony_ci	/* DH parameters are not needed anymore, so free them */
101e5b75505Sopenharmony_ci	wpabuf_free(data->i_dh_public);
102e5b75505Sopenharmony_ci	data->i_dh_public = NULL;
103e5b75505Sopenharmony_ci	wpabuf_free(data->r_dh_private);
104e5b75505Sopenharmony_ci	data->r_dh_private = NULL;
105e5b75505Sopenharmony_ci
106e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG, "IKEV2: SKEYSEED",
107e5b75505Sopenharmony_ci			skeyseed, prf->hash_len);
108e5b75505Sopenharmony_ci
109e5b75505Sopenharmony_ci	ret = ikev2_derive_sk_keys(prf, integ, encr, skeyseed, buf, buf_len,
110e5b75505Sopenharmony_ci				   &data->keys);
111e5b75505Sopenharmony_ci	os_free(buf);
112e5b75505Sopenharmony_ci	return ret;
113e5b75505Sopenharmony_ci}
114e5b75505Sopenharmony_ci
115e5b75505Sopenharmony_ci
116e5b75505Sopenharmony_cistatic int ikev2_parse_transform(struct ikev2_proposal_data *prop,
117e5b75505Sopenharmony_ci				 const u8 *pos, const u8 *end)
118e5b75505Sopenharmony_ci{
119e5b75505Sopenharmony_ci	int transform_len;
120e5b75505Sopenharmony_ci	const struct ikev2_transform *t;
121e5b75505Sopenharmony_ci	u16 transform_id;
122e5b75505Sopenharmony_ci	const u8 *tend;
123e5b75505Sopenharmony_ci
124e5b75505Sopenharmony_ci	if (end - pos < (int) sizeof(*t)) {
125e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Too short transform");
126e5b75505Sopenharmony_ci		return -1;
127e5b75505Sopenharmony_ci	}
128e5b75505Sopenharmony_ci
129e5b75505Sopenharmony_ci	t = (const struct ikev2_transform *) pos;
130e5b75505Sopenharmony_ci	transform_len = WPA_GET_BE16(t->transform_length);
131e5b75505Sopenharmony_ci	if (transform_len < (int) sizeof(*t) || transform_len > end - pos) {
132e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Invalid transform length %d",
133e5b75505Sopenharmony_ci			   transform_len);
134e5b75505Sopenharmony_ci		return -1;
135e5b75505Sopenharmony_ci	}
136e5b75505Sopenharmony_ci	tend = pos + transform_len;
137e5b75505Sopenharmony_ci
138e5b75505Sopenharmony_ci	transform_id = WPA_GET_BE16(t->transform_id);
139e5b75505Sopenharmony_ci
140e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "IKEV2:   Transform:");
141e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "IKEV2:     Type: %d  Transform Length: %d  "
142e5b75505Sopenharmony_ci		   "Transform Type: %d  Transform ID: %d",
143e5b75505Sopenharmony_ci		   t->type, transform_len, t->transform_type, transform_id);
144e5b75505Sopenharmony_ci
145e5b75505Sopenharmony_ci	if (t->type != 0 && t->type != 3) {
146e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Unexpected Transform type");
147e5b75505Sopenharmony_ci		return -1;
148e5b75505Sopenharmony_ci	}
149e5b75505Sopenharmony_ci
150e5b75505Sopenharmony_ci	pos = (const u8 *) (t + 1);
151e5b75505Sopenharmony_ci	if (pos < tend) {
152e5b75505Sopenharmony_ci		wpa_hexdump(MSG_DEBUG, "IKEV2:     Transform Attributes",
153e5b75505Sopenharmony_ci			    pos, tend - pos);
154e5b75505Sopenharmony_ci	}
155e5b75505Sopenharmony_ci
156e5b75505Sopenharmony_ci	switch (t->transform_type) {
157e5b75505Sopenharmony_ci	case IKEV2_TRANSFORM_ENCR:
158e5b75505Sopenharmony_ci		if (ikev2_get_encr(transform_id)) {
159e5b75505Sopenharmony_ci			if (transform_id == ENCR_AES_CBC) {
160e5b75505Sopenharmony_ci				if (tend - pos != 4) {
161e5b75505Sopenharmony_ci					wpa_printf(MSG_DEBUG, "IKEV2: No "
162e5b75505Sopenharmony_ci						   "Transform Attr for AES");
163e5b75505Sopenharmony_ci					break;
164e5b75505Sopenharmony_ci				}
165e5b75505Sopenharmony_ci				if (WPA_GET_BE16(pos) != 0x800e) {
166e5b75505Sopenharmony_ci					wpa_printf(MSG_DEBUG, "IKEV2: Not a "
167e5b75505Sopenharmony_ci						   "Key Size attribute for "
168e5b75505Sopenharmony_ci						   "AES");
169e5b75505Sopenharmony_ci					break;
170e5b75505Sopenharmony_ci				}
171e5b75505Sopenharmony_ci				if (WPA_GET_BE16(pos + 2) != 128) {
172e5b75505Sopenharmony_ci					wpa_printf(MSG_DEBUG, "IKEV2: "
173e5b75505Sopenharmony_ci						   "Unsupported AES key size "
174e5b75505Sopenharmony_ci						   "%d bits",
175e5b75505Sopenharmony_ci						   WPA_GET_BE16(pos + 2));
176e5b75505Sopenharmony_ci					break;
177e5b75505Sopenharmony_ci				}
178e5b75505Sopenharmony_ci			}
179e5b75505Sopenharmony_ci			prop->encr = transform_id;
180e5b75505Sopenharmony_ci		}
181e5b75505Sopenharmony_ci		break;
182e5b75505Sopenharmony_ci	case IKEV2_TRANSFORM_PRF:
183e5b75505Sopenharmony_ci		if (ikev2_get_prf(transform_id))
184e5b75505Sopenharmony_ci			prop->prf = transform_id;
185e5b75505Sopenharmony_ci		break;
186e5b75505Sopenharmony_ci	case IKEV2_TRANSFORM_INTEG:
187e5b75505Sopenharmony_ci		if (ikev2_get_integ(transform_id))
188e5b75505Sopenharmony_ci			prop->integ = transform_id;
189e5b75505Sopenharmony_ci		break;
190e5b75505Sopenharmony_ci	case IKEV2_TRANSFORM_DH:
191e5b75505Sopenharmony_ci		if (dh_groups_get(transform_id))
192e5b75505Sopenharmony_ci			prop->dh = transform_id;
193e5b75505Sopenharmony_ci		break;
194e5b75505Sopenharmony_ci	}
195e5b75505Sopenharmony_ci
196e5b75505Sopenharmony_ci	return transform_len;
197e5b75505Sopenharmony_ci}
198e5b75505Sopenharmony_ci
199e5b75505Sopenharmony_ci
200e5b75505Sopenharmony_cistatic int ikev2_parse_proposal(struct ikev2_proposal_data *prop,
201e5b75505Sopenharmony_ci				const u8 *pos, const u8 *end)
202e5b75505Sopenharmony_ci{
203e5b75505Sopenharmony_ci	const u8 *pend, *ppos;
204e5b75505Sopenharmony_ci	int proposal_len, i;
205e5b75505Sopenharmony_ci	const struct ikev2_proposal *p;
206e5b75505Sopenharmony_ci
207e5b75505Sopenharmony_ci	if (end - pos < (int) sizeof(*p)) {
208e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Too short proposal");
209e5b75505Sopenharmony_ci		return -1;
210e5b75505Sopenharmony_ci	}
211e5b75505Sopenharmony_ci
212e5b75505Sopenharmony_ci	/* FIX: AND processing if multiple proposals use the same # */
213e5b75505Sopenharmony_ci
214e5b75505Sopenharmony_ci	p = (const struct ikev2_proposal *) pos;
215e5b75505Sopenharmony_ci	proposal_len = WPA_GET_BE16(p->proposal_length);
216e5b75505Sopenharmony_ci	if (proposal_len < (int) sizeof(*p) || proposal_len > end - pos) {
217e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Invalid proposal length %d",
218e5b75505Sopenharmony_ci			   proposal_len);
219e5b75505Sopenharmony_ci		return -1;
220e5b75505Sopenharmony_ci	}
221e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "IKEV2: SAi1 Proposal # %d",
222e5b75505Sopenharmony_ci		   p->proposal_num);
223e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "IKEV2:   Type: %d  Proposal Length: %d "
224e5b75505Sopenharmony_ci		   " Protocol ID: %d",
225e5b75505Sopenharmony_ci		   p->type, proposal_len, p->protocol_id);
226e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "IKEV2:   SPI Size: %d  Transforms: %d",
227e5b75505Sopenharmony_ci		   p->spi_size, p->num_transforms);
228e5b75505Sopenharmony_ci
229e5b75505Sopenharmony_ci	if (p->type != 0 && p->type != 2) {
230e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal type");
231e5b75505Sopenharmony_ci		return -1;
232e5b75505Sopenharmony_ci	}
233e5b75505Sopenharmony_ci
234e5b75505Sopenharmony_ci	if (p->protocol_id != IKEV2_PROTOCOL_IKE) {
235e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "IKEV2: Unexpected Protocol ID "
236e5b75505Sopenharmony_ci			   "(only IKE allowed for EAP-IKEv2)");
237e5b75505Sopenharmony_ci		return -1;
238e5b75505Sopenharmony_ci	}
239e5b75505Sopenharmony_ci
240e5b75505Sopenharmony_ci	if (p->proposal_num != prop->proposal_num) {
241e5b75505Sopenharmony_ci		if (p->proposal_num == prop->proposal_num + 1)
242e5b75505Sopenharmony_ci			prop->proposal_num = p->proposal_num;
243e5b75505Sopenharmony_ci		else {
244e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal #");
245e5b75505Sopenharmony_ci			return -1;
246e5b75505Sopenharmony_ci		}
247e5b75505Sopenharmony_ci	}
248e5b75505Sopenharmony_ci
249e5b75505Sopenharmony_ci	ppos = (const u8 *) (p + 1);
250e5b75505Sopenharmony_ci	pend = pos + proposal_len;
251e5b75505Sopenharmony_ci	if (p->spi_size > pend - ppos) {
252e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Not enough room for SPI "
253e5b75505Sopenharmony_ci			   "in proposal");
254e5b75505Sopenharmony_ci		return -1;
255e5b75505Sopenharmony_ci	}
256e5b75505Sopenharmony_ci	if (p->spi_size) {
257e5b75505Sopenharmony_ci		wpa_hexdump(MSG_DEBUG, "IKEV2:    SPI",
258e5b75505Sopenharmony_ci			    ppos, p->spi_size);
259e5b75505Sopenharmony_ci		ppos += p->spi_size;
260e5b75505Sopenharmony_ci	}
261e5b75505Sopenharmony_ci
262e5b75505Sopenharmony_ci	/*
263e5b75505Sopenharmony_ci	 * For initial IKE_SA negotiation, SPI Size MUST be zero; for
264e5b75505Sopenharmony_ci	 * subsequent negotiations, it must be 8 for IKE. We only support
265e5b75505Sopenharmony_ci	 * initial case for now.
266e5b75505Sopenharmony_ci	 */
267e5b75505Sopenharmony_ci	if (p->spi_size != 0) {
268e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Unexpected SPI Size");
269e5b75505Sopenharmony_ci		return -1;
270e5b75505Sopenharmony_ci	}
271e5b75505Sopenharmony_ci
272e5b75505Sopenharmony_ci	if (p->num_transforms == 0) {
273e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: At least one transform required");
274e5b75505Sopenharmony_ci		return -1;
275e5b75505Sopenharmony_ci	}
276e5b75505Sopenharmony_ci
277e5b75505Sopenharmony_ci	for (i = 0; i < (int) p->num_transforms; i++) {
278e5b75505Sopenharmony_ci		int tlen = ikev2_parse_transform(prop, ppos, pend);
279e5b75505Sopenharmony_ci		if (tlen < 0)
280e5b75505Sopenharmony_ci			return -1;
281e5b75505Sopenharmony_ci		ppos += tlen;
282e5b75505Sopenharmony_ci	}
283e5b75505Sopenharmony_ci
284e5b75505Sopenharmony_ci	if (ppos != pend) {
285e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Unexpected data after "
286e5b75505Sopenharmony_ci			   "transforms");
287e5b75505Sopenharmony_ci		return -1;
288e5b75505Sopenharmony_ci	}
289e5b75505Sopenharmony_ci
290e5b75505Sopenharmony_ci	return proposal_len;
291e5b75505Sopenharmony_ci}
292e5b75505Sopenharmony_ci
293e5b75505Sopenharmony_ci
294e5b75505Sopenharmony_cistatic int ikev2_process_sai1(struct ikev2_responder_data *data,
295e5b75505Sopenharmony_ci			      const u8 *sai1, size_t sai1_len)
296e5b75505Sopenharmony_ci{
297e5b75505Sopenharmony_ci	struct ikev2_proposal_data prop;
298e5b75505Sopenharmony_ci	const u8 *pos, *end;
299e5b75505Sopenharmony_ci	int found = 0;
300e5b75505Sopenharmony_ci
301e5b75505Sopenharmony_ci	/* Security Association Payloads: <Proposals> */
302e5b75505Sopenharmony_ci
303e5b75505Sopenharmony_ci	if (sai1 == NULL) {
304e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: SAi1 not received");
305e5b75505Sopenharmony_ci		return -1;
306e5b75505Sopenharmony_ci	}
307e5b75505Sopenharmony_ci
308e5b75505Sopenharmony_ci	os_memset(&prop, 0, sizeof(prop));
309e5b75505Sopenharmony_ci	prop.proposal_num = 1;
310e5b75505Sopenharmony_ci
311e5b75505Sopenharmony_ci	pos = sai1;
312e5b75505Sopenharmony_ci	end = sai1 + sai1_len;
313e5b75505Sopenharmony_ci
314e5b75505Sopenharmony_ci	while (pos < end) {
315e5b75505Sopenharmony_ci		int plen;
316e5b75505Sopenharmony_ci
317e5b75505Sopenharmony_ci		prop.integ = -1;
318e5b75505Sopenharmony_ci		prop.prf = -1;
319e5b75505Sopenharmony_ci		prop.encr = -1;
320e5b75505Sopenharmony_ci		prop.dh = -1;
321e5b75505Sopenharmony_ci		plen = ikev2_parse_proposal(&prop, pos, end);
322e5b75505Sopenharmony_ci		if (plen < 0)
323e5b75505Sopenharmony_ci			return -1;
324e5b75505Sopenharmony_ci
325e5b75505Sopenharmony_ci		if (!found && prop.integ != -1 && prop.prf != -1 &&
326e5b75505Sopenharmony_ci		    prop.encr != -1 && prop.dh != -1) {
327e5b75505Sopenharmony_ci			os_memcpy(&data->proposal, &prop, sizeof(prop));
328e5b75505Sopenharmony_ci			data->dh = dh_groups_get(prop.dh);
329e5b75505Sopenharmony_ci			found = 1;
330e5b75505Sopenharmony_ci		}
331e5b75505Sopenharmony_ci
332e5b75505Sopenharmony_ci		pos += plen;
333e5b75505Sopenharmony_ci	}
334e5b75505Sopenharmony_ci
335e5b75505Sopenharmony_ci	if (pos != end) {
336e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Unexpected data after proposals");
337e5b75505Sopenharmony_ci		return -1;
338e5b75505Sopenharmony_ci	}
339e5b75505Sopenharmony_ci
340e5b75505Sopenharmony_ci	if (!found) {
341e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: No acceptable proposal found");
342e5b75505Sopenharmony_ci		return -1;
343e5b75505Sopenharmony_ci	}
344e5b75505Sopenharmony_ci
345e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "IKEV2: Accepted proposal #%d: ENCR:%d PRF:%d "
346e5b75505Sopenharmony_ci		   "INTEG:%d D-H:%d", data->proposal.proposal_num,
347e5b75505Sopenharmony_ci		   data->proposal.encr, data->proposal.prf,
348e5b75505Sopenharmony_ci		   data->proposal.integ, data->proposal.dh);
349e5b75505Sopenharmony_ci
350e5b75505Sopenharmony_ci	return 0;
351e5b75505Sopenharmony_ci}
352e5b75505Sopenharmony_ci
353e5b75505Sopenharmony_ci
354e5b75505Sopenharmony_cistatic int ikev2_process_kei(struct ikev2_responder_data *data,
355e5b75505Sopenharmony_ci			     const u8 *kei, size_t kei_len)
356e5b75505Sopenharmony_ci{
357e5b75505Sopenharmony_ci	u16 group;
358e5b75505Sopenharmony_ci
359e5b75505Sopenharmony_ci	/*
360e5b75505Sopenharmony_ci	 * Key Exchange Payload:
361e5b75505Sopenharmony_ci	 * DH Group # (16 bits)
362e5b75505Sopenharmony_ci	 * RESERVED (16 bits)
363e5b75505Sopenharmony_ci	 * Key Exchange Data (Diffie-Hellman public value)
364e5b75505Sopenharmony_ci	 */
365e5b75505Sopenharmony_ci
366e5b75505Sopenharmony_ci	if (kei == NULL) {
367e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: KEi not received");
368e5b75505Sopenharmony_ci		return -1;
369e5b75505Sopenharmony_ci	}
370e5b75505Sopenharmony_ci
371e5b75505Sopenharmony_ci	if (kei_len < 4 + 96) {
372e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Too short Key Exchange Payload");
373e5b75505Sopenharmony_ci		return -1;
374e5b75505Sopenharmony_ci	}
375e5b75505Sopenharmony_ci
376e5b75505Sopenharmony_ci	group = WPA_GET_BE16(kei);
377e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "IKEV2: KEi DH Group #%u", group);
378e5b75505Sopenharmony_ci
379e5b75505Sopenharmony_ci	if (group != data->proposal.dh) {
380e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "IKEV2: KEi DH Group #%u does not match "
381e5b75505Sopenharmony_ci			   "with the selected proposal (%u)",
382e5b75505Sopenharmony_ci			   group, data->proposal.dh);
383e5b75505Sopenharmony_ci		/* Reject message with Notify payload of type
384e5b75505Sopenharmony_ci		 * INVALID_KE_PAYLOAD (RFC 4306, Sect. 3.4) */
385e5b75505Sopenharmony_ci		data->error_type = INVALID_KE_PAYLOAD;
386e5b75505Sopenharmony_ci		data->state = NOTIFY;
387e5b75505Sopenharmony_ci		return -1;
388e5b75505Sopenharmony_ci	}
389e5b75505Sopenharmony_ci
390e5b75505Sopenharmony_ci	if (data->dh == NULL) {
391e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Unsupported DH group");
392e5b75505Sopenharmony_ci		return -1;
393e5b75505Sopenharmony_ci	}
394e5b75505Sopenharmony_ci
395e5b75505Sopenharmony_ci	/* RFC 4306, Section 3.4:
396e5b75505Sopenharmony_ci	 * The length of DH public value MUST be equal to the length of the
397e5b75505Sopenharmony_ci	 * prime modulus.
398e5b75505Sopenharmony_ci	 */
399e5b75505Sopenharmony_ci	if (kei_len - 4 != data->dh->prime_len) {
400e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Invalid DH public value length "
401e5b75505Sopenharmony_ci			   "%ld (expected %ld)",
402e5b75505Sopenharmony_ci			   (long) (kei_len - 4), (long) data->dh->prime_len);
403e5b75505Sopenharmony_ci		return -1;
404e5b75505Sopenharmony_ci	}
405e5b75505Sopenharmony_ci
406e5b75505Sopenharmony_ci	wpabuf_free(data->i_dh_public);
407e5b75505Sopenharmony_ci	data->i_dh_public = wpabuf_alloc(kei_len - 4);
408e5b75505Sopenharmony_ci	if (data->i_dh_public == NULL)
409e5b75505Sopenharmony_ci		return -1;
410e5b75505Sopenharmony_ci	wpabuf_put_data(data->i_dh_public, kei + 4, kei_len - 4);
411e5b75505Sopenharmony_ci
412e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_DEBUG, "IKEV2: KEi Diffie-Hellman Public Value",
413e5b75505Sopenharmony_ci			data->i_dh_public);
414e5b75505Sopenharmony_ci
415e5b75505Sopenharmony_ci	return 0;
416e5b75505Sopenharmony_ci}
417e5b75505Sopenharmony_ci
418e5b75505Sopenharmony_ci
419e5b75505Sopenharmony_cistatic int ikev2_process_ni(struct ikev2_responder_data *data,
420e5b75505Sopenharmony_ci			    const u8 *ni, size_t ni_len)
421e5b75505Sopenharmony_ci{
422e5b75505Sopenharmony_ci	if (ni == NULL) {
423e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Ni not received");
424e5b75505Sopenharmony_ci		return -1;
425e5b75505Sopenharmony_ci	}
426e5b75505Sopenharmony_ci
427e5b75505Sopenharmony_ci	if (ni_len < IKEV2_NONCE_MIN_LEN || ni_len > IKEV2_NONCE_MAX_LEN) {
428e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Invalid Ni length %ld",
429e5b75505Sopenharmony_ci		           (long) ni_len);
430e5b75505Sopenharmony_ci		return -1;
431e5b75505Sopenharmony_ci	}
432e5b75505Sopenharmony_ci
433e5b75505Sopenharmony_ci	data->i_nonce_len = ni_len;
434e5b75505Sopenharmony_ci	os_memcpy(data->i_nonce, ni, ni_len);
435e5b75505Sopenharmony_ci	wpa_hexdump(MSG_MSGDUMP, "IKEV2: Ni",
436e5b75505Sopenharmony_ci		    data->i_nonce, data->i_nonce_len);
437e5b75505Sopenharmony_ci
438e5b75505Sopenharmony_ci	return 0;
439e5b75505Sopenharmony_ci}
440e5b75505Sopenharmony_ci
441e5b75505Sopenharmony_ci
442e5b75505Sopenharmony_cistatic int ikev2_process_sa_init(struct ikev2_responder_data *data,
443e5b75505Sopenharmony_ci				 const struct ikev2_hdr *hdr,
444e5b75505Sopenharmony_ci				 struct ikev2_payloads *pl)
445e5b75505Sopenharmony_ci{
446e5b75505Sopenharmony_ci	if (ikev2_process_sai1(data, pl->sa, pl->sa_len) < 0 ||
447e5b75505Sopenharmony_ci	    ikev2_process_kei(data, pl->ke, pl->ke_len) < 0 ||
448e5b75505Sopenharmony_ci	    ikev2_process_ni(data, pl->nonce, pl->nonce_len) < 0)
449e5b75505Sopenharmony_ci		return -1;
450e5b75505Sopenharmony_ci
451e5b75505Sopenharmony_ci	os_memcpy(data->i_spi, hdr->i_spi, IKEV2_SPI_LEN);
452e5b75505Sopenharmony_ci
453e5b75505Sopenharmony_ci	return 0;
454e5b75505Sopenharmony_ci}
455e5b75505Sopenharmony_ci
456e5b75505Sopenharmony_ci
457e5b75505Sopenharmony_cistatic int ikev2_process_idi(struct ikev2_responder_data *data,
458e5b75505Sopenharmony_ci			     const u8 *idi, size_t idi_len)
459e5b75505Sopenharmony_ci{
460e5b75505Sopenharmony_ci	u8 id_type;
461e5b75505Sopenharmony_ci
462e5b75505Sopenharmony_ci	if (idi == NULL) {
463e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: No IDi received");
464e5b75505Sopenharmony_ci		return -1;
465e5b75505Sopenharmony_ci	}
466e5b75505Sopenharmony_ci
467e5b75505Sopenharmony_ci	if (idi_len < 4) {
468e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Too short IDi payload");
469e5b75505Sopenharmony_ci		return -1;
470e5b75505Sopenharmony_ci	}
471e5b75505Sopenharmony_ci
472e5b75505Sopenharmony_ci	id_type = idi[0];
473e5b75505Sopenharmony_ci	idi += 4;
474e5b75505Sopenharmony_ci	idi_len -= 4;
475e5b75505Sopenharmony_ci
476e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "IKEV2: IDi ID Type %d", id_type);
477e5b75505Sopenharmony_ci	wpa_hexdump_ascii(MSG_DEBUG, "IKEV2: IDi", idi, idi_len);
478e5b75505Sopenharmony_ci	os_free(data->IDi);
479e5b75505Sopenharmony_ci	data->IDi = os_memdup(idi, idi_len);
480e5b75505Sopenharmony_ci	if (data->IDi == NULL)
481e5b75505Sopenharmony_ci		return -1;
482e5b75505Sopenharmony_ci	data->IDi_len = idi_len;
483e5b75505Sopenharmony_ci	data->IDi_type = id_type;
484e5b75505Sopenharmony_ci
485e5b75505Sopenharmony_ci	return 0;
486e5b75505Sopenharmony_ci}
487e5b75505Sopenharmony_ci
488e5b75505Sopenharmony_ci
489e5b75505Sopenharmony_cistatic int ikev2_process_cert(struct ikev2_responder_data *data,
490e5b75505Sopenharmony_ci			      const u8 *cert, size_t cert_len)
491e5b75505Sopenharmony_ci{
492e5b75505Sopenharmony_ci	u8 cert_encoding;
493e5b75505Sopenharmony_ci
494e5b75505Sopenharmony_ci	if (cert == NULL) {
495e5b75505Sopenharmony_ci		if (data->peer_auth == PEER_AUTH_CERT) {
496e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "IKEV2: No Certificate received");
497e5b75505Sopenharmony_ci			return -1;
498e5b75505Sopenharmony_ci		}
499e5b75505Sopenharmony_ci		return 0;
500e5b75505Sopenharmony_ci	}
501e5b75505Sopenharmony_ci
502e5b75505Sopenharmony_ci	if (cert_len < 1) {
503e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: No Cert Encoding field");
504e5b75505Sopenharmony_ci		return -1;
505e5b75505Sopenharmony_ci	}
506e5b75505Sopenharmony_ci
507e5b75505Sopenharmony_ci	cert_encoding = cert[0];
508e5b75505Sopenharmony_ci	cert++;
509e5b75505Sopenharmony_ci	cert_len--;
510e5b75505Sopenharmony_ci
511e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "IKEV2: Cert Encoding %d", cert_encoding);
512e5b75505Sopenharmony_ci	wpa_hexdump(MSG_MSGDUMP, "IKEV2: Certificate Data", cert, cert_len);
513e5b75505Sopenharmony_ci
514e5b75505Sopenharmony_ci	/* TODO: validate certificate */
515e5b75505Sopenharmony_ci
516e5b75505Sopenharmony_ci	return 0;
517e5b75505Sopenharmony_ci}
518e5b75505Sopenharmony_ci
519e5b75505Sopenharmony_ci
520e5b75505Sopenharmony_cistatic int ikev2_process_auth_cert(struct ikev2_responder_data *data,
521e5b75505Sopenharmony_ci				   u8 method, const u8 *auth, size_t auth_len)
522e5b75505Sopenharmony_ci{
523e5b75505Sopenharmony_ci	if (method != AUTH_RSA_SIGN) {
524e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication "
525e5b75505Sopenharmony_ci			   "method %d", method);
526e5b75505Sopenharmony_ci		return -1;
527e5b75505Sopenharmony_ci	}
528e5b75505Sopenharmony_ci
529e5b75505Sopenharmony_ci	/* TODO: validate AUTH */
530e5b75505Sopenharmony_ci	return 0;
531e5b75505Sopenharmony_ci}
532e5b75505Sopenharmony_ci
533e5b75505Sopenharmony_ci
534e5b75505Sopenharmony_cistatic int ikev2_process_auth_secret(struct ikev2_responder_data *data,
535e5b75505Sopenharmony_ci				     u8 method, const u8 *auth,
536e5b75505Sopenharmony_ci				     size_t auth_len)
537e5b75505Sopenharmony_ci{
538e5b75505Sopenharmony_ci	u8 auth_data[IKEV2_MAX_HASH_LEN];
539e5b75505Sopenharmony_ci	const struct ikev2_prf_alg *prf;
540e5b75505Sopenharmony_ci
541e5b75505Sopenharmony_ci	if (method != AUTH_SHARED_KEY_MIC) {
542e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication "
543e5b75505Sopenharmony_ci			   "method %d", method);
544e5b75505Sopenharmony_ci		return -1;
545e5b75505Sopenharmony_ci	}
546e5b75505Sopenharmony_ci
547e5b75505Sopenharmony_ci	/* msg | Nr | prf(SK_pi,IDi') */
548e5b75505Sopenharmony_ci	if (ikev2_derive_auth_data(data->proposal.prf, data->i_sign_msg,
549e5b75505Sopenharmony_ci				   data->IDi, data->IDi_len, data->IDi_type,
550e5b75505Sopenharmony_ci				   &data->keys, 1, data->shared_secret,
551e5b75505Sopenharmony_ci				   data->shared_secret_len,
552e5b75505Sopenharmony_ci				   data->r_nonce, data->r_nonce_len,
553e5b75505Sopenharmony_ci				   data->key_pad, data->key_pad_len,
554e5b75505Sopenharmony_ci				   auth_data) < 0) {
555e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data");
556e5b75505Sopenharmony_ci		return -1;
557e5b75505Sopenharmony_ci	}
558e5b75505Sopenharmony_ci
559e5b75505Sopenharmony_ci	wpabuf_free(data->i_sign_msg);
560e5b75505Sopenharmony_ci	data->i_sign_msg = NULL;
561e5b75505Sopenharmony_ci
562e5b75505Sopenharmony_ci	prf = ikev2_get_prf(data->proposal.prf);
563e5b75505Sopenharmony_ci	if (prf == NULL)
564e5b75505Sopenharmony_ci		return -1;
565e5b75505Sopenharmony_ci
566e5b75505Sopenharmony_ci	if (auth_len != prf->hash_len ||
567e5b75505Sopenharmony_ci	    os_memcmp_const(auth, auth_data, auth_len) != 0) {
568e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Invalid Authentication Data");
569e5b75505Sopenharmony_ci		wpa_hexdump(MSG_DEBUG, "IKEV2: Received Authentication Data",
570e5b75505Sopenharmony_ci			    auth, auth_len);
571e5b75505Sopenharmony_ci		wpa_hexdump(MSG_DEBUG, "IKEV2: Expected Authentication Data",
572e5b75505Sopenharmony_ci			    auth_data, prf->hash_len);
573e5b75505Sopenharmony_ci		data->error_type = AUTHENTICATION_FAILED;
574e5b75505Sopenharmony_ci		data->state = NOTIFY;
575e5b75505Sopenharmony_ci		return -1;
576e5b75505Sopenharmony_ci	}
577e5b75505Sopenharmony_ci
578e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "IKEV2: Server authenticated successfully "
579e5b75505Sopenharmony_ci		   "using shared keys");
580e5b75505Sopenharmony_ci
581e5b75505Sopenharmony_ci	return 0;
582e5b75505Sopenharmony_ci}
583e5b75505Sopenharmony_ci
584e5b75505Sopenharmony_ci
585e5b75505Sopenharmony_cistatic int ikev2_process_auth(struct ikev2_responder_data *data,
586e5b75505Sopenharmony_ci			      const u8 *auth, size_t auth_len)
587e5b75505Sopenharmony_ci{
588e5b75505Sopenharmony_ci	u8 auth_method;
589e5b75505Sopenharmony_ci
590e5b75505Sopenharmony_ci	if (auth == NULL) {
591e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: No Authentication Payload");
592e5b75505Sopenharmony_ci		return -1;
593e5b75505Sopenharmony_ci	}
594e5b75505Sopenharmony_ci
595e5b75505Sopenharmony_ci	if (auth_len < 4) {
596e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Too short Authentication "
597e5b75505Sopenharmony_ci			   "Payload");
598e5b75505Sopenharmony_ci		return -1;
599e5b75505Sopenharmony_ci	}
600e5b75505Sopenharmony_ci
601e5b75505Sopenharmony_ci	auth_method = auth[0];
602e5b75505Sopenharmony_ci	auth += 4;
603e5b75505Sopenharmony_ci	auth_len -= 4;
604e5b75505Sopenharmony_ci
605e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "IKEV2: Auth Method %d", auth_method);
606e5b75505Sopenharmony_ci	wpa_hexdump(MSG_MSGDUMP, "IKEV2: Authentication Data", auth, auth_len);
607e5b75505Sopenharmony_ci
608e5b75505Sopenharmony_ci	switch (data->peer_auth) {
609e5b75505Sopenharmony_ci	case PEER_AUTH_CERT:
610e5b75505Sopenharmony_ci		return ikev2_process_auth_cert(data, auth_method, auth,
611e5b75505Sopenharmony_ci					       auth_len);
612e5b75505Sopenharmony_ci	case PEER_AUTH_SECRET:
613e5b75505Sopenharmony_ci		return ikev2_process_auth_secret(data, auth_method, auth,
614e5b75505Sopenharmony_ci						 auth_len);
615e5b75505Sopenharmony_ci	}
616e5b75505Sopenharmony_ci
617e5b75505Sopenharmony_ci	return -1;
618e5b75505Sopenharmony_ci}
619e5b75505Sopenharmony_ci
620e5b75505Sopenharmony_ci
621e5b75505Sopenharmony_cistatic int ikev2_process_sa_auth_decrypted(struct ikev2_responder_data *data,
622e5b75505Sopenharmony_ci					   u8 next_payload,
623e5b75505Sopenharmony_ci					   u8 *payload, size_t payload_len)
624e5b75505Sopenharmony_ci{
625e5b75505Sopenharmony_ci	struct ikev2_payloads pl;
626e5b75505Sopenharmony_ci
627e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "IKEV2: Processing decrypted payloads");
628e5b75505Sopenharmony_ci
629e5b75505Sopenharmony_ci	if (ikev2_parse_payloads(&pl, next_payload, payload, payload +
630e5b75505Sopenharmony_ci				 payload_len) < 0) {
631e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Failed to parse decrypted "
632e5b75505Sopenharmony_ci			   "payloads");
633e5b75505Sopenharmony_ci		return -1;
634e5b75505Sopenharmony_ci	}
635e5b75505Sopenharmony_ci
636e5b75505Sopenharmony_ci	if (ikev2_process_idi(data, pl.idi, pl.idi_len) < 0 ||
637e5b75505Sopenharmony_ci	    ikev2_process_cert(data, pl.cert, pl.cert_len) < 0 ||
638e5b75505Sopenharmony_ci	    ikev2_process_auth(data, pl.auth, pl.auth_len) < 0)
639e5b75505Sopenharmony_ci		return -1;
640e5b75505Sopenharmony_ci
641e5b75505Sopenharmony_ci	return 0;
642e5b75505Sopenharmony_ci}
643e5b75505Sopenharmony_ci
644e5b75505Sopenharmony_ci
645e5b75505Sopenharmony_cistatic int ikev2_process_sa_auth(struct ikev2_responder_data *data,
646e5b75505Sopenharmony_ci				 const struct ikev2_hdr *hdr,
647e5b75505Sopenharmony_ci				 struct ikev2_payloads *pl)
648e5b75505Sopenharmony_ci{
649e5b75505Sopenharmony_ci	u8 *decrypted;
650e5b75505Sopenharmony_ci	size_t decrypted_len;
651e5b75505Sopenharmony_ci	int ret;
652e5b75505Sopenharmony_ci
653e5b75505Sopenharmony_ci	decrypted = ikev2_decrypt_payload(data->proposal.encr,
654e5b75505Sopenharmony_ci					  data->proposal.integ,
655e5b75505Sopenharmony_ci					  &data->keys, 1, hdr, pl->encrypted,
656e5b75505Sopenharmony_ci					  pl->encrypted_len, &decrypted_len);
657e5b75505Sopenharmony_ci	if (decrypted == NULL)
658e5b75505Sopenharmony_ci		return -1;
659e5b75505Sopenharmony_ci
660e5b75505Sopenharmony_ci	ret = ikev2_process_sa_auth_decrypted(data, pl->encr_next_payload,
661e5b75505Sopenharmony_ci					      decrypted, decrypted_len);
662e5b75505Sopenharmony_ci	os_free(decrypted);
663e5b75505Sopenharmony_ci
664e5b75505Sopenharmony_ci	return ret;
665e5b75505Sopenharmony_ci}
666e5b75505Sopenharmony_ci
667e5b75505Sopenharmony_ci
668e5b75505Sopenharmony_cistatic int ikev2_validate_rx_state(struct ikev2_responder_data *data,
669e5b75505Sopenharmony_ci				   u8 exchange_type, u32 message_id)
670e5b75505Sopenharmony_ci{
671e5b75505Sopenharmony_ci	switch (data->state) {
672e5b75505Sopenharmony_ci	case SA_INIT:
673e5b75505Sopenharmony_ci		/* Expect to receive IKE_SA_INIT: HDR, SAi1, KEi, Ni */
674e5b75505Sopenharmony_ci		if (exchange_type != IKE_SA_INIT) {
675e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type "
676e5b75505Sopenharmony_ci				   "%u in SA_INIT state", exchange_type);
677e5b75505Sopenharmony_ci			return -1;
678e5b75505Sopenharmony_ci		}
679e5b75505Sopenharmony_ci		if (message_id != 0) {
680e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u "
681e5b75505Sopenharmony_ci				   "in SA_INIT state", message_id);
682e5b75505Sopenharmony_ci			return -1;
683e5b75505Sopenharmony_ci		}
684e5b75505Sopenharmony_ci		break;
685e5b75505Sopenharmony_ci	case SA_AUTH:
686e5b75505Sopenharmony_ci		/* Expect to receive IKE_SA_AUTH:
687e5b75505Sopenharmony_ci		 * HDR, SK {IDi, [CERT,] [CERTREQ,] [IDr,]
688e5b75505Sopenharmony_ci		 *	AUTH, SAi2, TSi, TSr}
689e5b75505Sopenharmony_ci		 */
690e5b75505Sopenharmony_ci		if (exchange_type != IKE_SA_AUTH) {
691e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type "
692e5b75505Sopenharmony_ci				   "%u in SA_AUTH state", exchange_type);
693e5b75505Sopenharmony_ci			return -1;
694e5b75505Sopenharmony_ci		}
695e5b75505Sopenharmony_ci		if (message_id != 1) {
696e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u "
697e5b75505Sopenharmony_ci				   "in SA_AUTH state", message_id);
698e5b75505Sopenharmony_ci			return -1;
699e5b75505Sopenharmony_ci		}
700e5b75505Sopenharmony_ci		break;
701e5b75505Sopenharmony_ci	case CHILD_SA:
702e5b75505Sopenharmony_ci		if (exchange_type != CREATE_CHILD_SA) {
703e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type "
704e5b75505Sopenharmony_ci				   "%u in CHILD_SA state", exchange_type);
705e5b75505Sopenharmony_ci			return -1;
706e5b75505Sopenharmony_ci		}
707e5b75505Sopenharmony_ci		if (message_id != 2) {
708e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u "
709e5b75505Sopenharmony_ci				   "in CHILD_SA state", message_id);
710e5b75505Sopenharmony_ci			return -1;
711e5b75505Sopenharmony_ci		}
712e5b75505Sopenharmony_ci		break;
713e5b75505Sopenharmony_ci	case NOTIFY:
714e5b75505Sopenharmony_ci	case IKEV2_DONE:
715e5b75505Sopenharmony_ci	case IKEV2_FAILED:
716e5b75505Sopenharmony_ci		return -1;
717e5b75505Sopenharmony_ci	}
718e5b75505Sopenharmony_ci
719e5b75505Sopenharmony_ci	return 0;
720e5b75505Sopenharmony_ci}
721e5b75505Sopenharmony_ci
722e5b75505Sopenharmony_ci
723e5b75505Sopenharmony_ciint ikev2_responder_process(struct ikev2_responder_data *data,
724e5b75505Sopenharmony_ci			    const struct wpabuf *buf)
725e5b75505Sopenharmony_ci{
726e5b75505Sopenharmony_ci	const struct ikev2_hdr *hdr;
727e5b75505Sopenharmony_ci	u32 length, message_id;
728e5b75505Sopenharmony_ci	const u8 *pos, *end;
729e5b75505Sopenharmony_ci	struct ikev2_payloads pl;
730e5b75505Sopenharmony_ci
731e5b75505Sopenharmony_ci	wpa_printf(MSG_MSGDUMP, "IKEV2: Received message (len %lu)",
732e5b75505Sopenharmony_ci		   (unsigned long) wpabuf_len(buf));
733e5b75505Sopenharmony_ci
734e5b75505Sopenharmony_ci	if (wpabuf_len(buf) < sizeof(*hdr)) {
735e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Too short frame to include HDR");
736e5b75505Sopenharmony_ci		return -1;
737e5b75505Sopenharmony_ci	}
738e5b75505Sopenharmony_ci
739e5b75505Sopenharmony_ci	data->error_type = 0;
740e5b75505Sopenharmony_ci	hdr = (const struct ikev2_hdr *) wpabuf_head(buf);
741e5b75505Sopenharmony_ci	end = wpabuf_head_u8(buf) + wpabuf_len(buf);
742e5b75505Sopenharmony_ci	message_id = WPA_GET_BE32(hdr->message_id);
743e5b75505Sopenharmony_ci	length = WPA_GET_BE32(hdr->length);
744e5b75505Sopenharmony_ci
745e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "IKEV2:   IKE_SA Initiator's SPI",
746e5b75505Sopenharmony_ci		    hdr->i_spi, IKEV2_SPI_LEN);
747e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "IKEV2:   IKE_SA Responder's SPI",
748e5b75505Sopenharmony_ci		    hdr->r_spi, IKEV2_SPI_LEN);
749e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "IKEV2:   Next Payload: %u  Version: 0x%x  "
750e5b75505Sopenharmony_ci		   "Exchange Type: %u",
751e5b75505Sopenharmony_ci		   hdr->next_payload, hdr->version, hdr->exchange_type);
752e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "IKEV2:   Message ID: %u  Length: %u",
753e5b75505Sopenharmony_ci		   message_id, length);
754e5b75505Sopenharmony_ci
755e5b75505Sopenharmony_ci	if (hdr->version != IKEV2_VERSION) {
756e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Unsupported HDR version 0x%x "
757e5b75505Sopenharmony_ci			   "(expected 0x%x)", hdr->version, IKEV2_VERSION);
758e5b75505Sopenharmony_ci		return -1;
759e5b75505Sopenharmony_ci	}
760e5b75505Sopenharmony_ci
761e5b75505Sopenharmony_ci	if (length != wpabuf_len(buf)) {
762e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Invalid length (HDR: %lu != "
763e5b75505Sopenharmony_ci			   "RX: %lu)", (unsigned long) length,
764e5b75505Sopenharmony_ci			   (unsigned long) wpabuf_len(buf));
765e5b75505Sopenharmony_ci		return -1;
766e5b75505Sopenharmony_ci	}
767e5b75505Sopenharmony_ci
768e5b75505Sopenharmony_ci	if (ikev2_validate_rx_state(data, hdr->exchange_type, message_id) < 0)
769e5b75505Sopenharmony_ci		return -1;
770e5b75505Sopenharmony_ci
771e5b75505Sopenharmony_ci	if ((hdr->flags & (IKEV2_HDR_INITIATOR | IKEV2_HDR_RESPONSE)) !=
772e5b75505Sopenharmony_ci	    IKEV2_HDR_INITIATOR) {
773e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Unexpected Flags value 0x%x",
774e5b75505Sopenharmony_ci			   hdr->flags);
775e5b75505Sopenharmony_ci		return -1;
776e5b75505Sopenharmony_ci	}
777e5b75505Sopenharmony_ci
778e5b75505Sopenharmony_ci	if (data->state != SA_INIT) {
779e5b75505Sopenharmony_ci		if (os_memcmp(data->i_spi, hdr->i_spi, IKEV2_SPI_LEN) != 0) {
780e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA "
781e5b75505Sopenharmony_ci				   "Initiator's SPI");
782e5b75505Sopenharmony_ci			return -1;
783e5b75505Sopenharmony_ci		}
784e5b75505Sopenharmony_ci		if (os_memcmp(data->r_spi, hdr->r_spi, IKEV2_SPI_LEN) != 0) {
785e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA "
786e5b75505Sopenharmony_ci				   "Responder's SPI");
787e5b75505Sopenharmony_ci			return -1;
788e5b75505Sopenharmony_ci		}
789e5b75505Sopenharmony_ci	}
790e5b75505Sopenharmony_ci
791e5b75505Sopenharmony_ci	pos = (const u8 *) (hdr + 1);
792e5b75505Sopenharmony_ci	if (ikev2_parse_payloads(&pl, hdr->next_payload, pos, end) < 0)
793e5b75505Sopenharmony_ci		return -1;
794e5b75505Sopenharmony_ci
795e5b75505Sopenharmony_ci	if (data->state == SA_INIT) {
796e5b75505Sopenharmony_ci		data->last_msg = LAST_MSG_SA_INIT;
797e5b75505Sopenharmony_ci		if (ikev2_process_sa_init(data, hdr, &pl) < 0) {
798e5b75505Sopenharmony_ci			if (data->state == NOTIFY)
799e5b75505Sopenharmony_ci				return 0;
800e5b75505Sopenharmony_ci			return -1;
801e5b75505Sopenharmony_ci		}
802e5b75505Sopenharmony_ci		wpabuf_free(data->i_sign_msg);
803e5b75505Sopenharmony_ci		data->i_sign_msg = wpabuf_dup(buf);
804e5b75505Sopenharmony_ci	}
805e5b75505Sopenharmony_ci
806e5b75505Sopenharmony_ci	if (data->state == SA_AUTH) {
807e5b75505Sopenharmony_ci		data->last_msg = LAST_MSG_SA_AUTH;
808e5b75505Sopenharmony_ci		if (ikev2_process_sa_auth(data, hdr, &pl) < 0) {
809e5b75505Sopenharmony_ci			if (data->state == NOTIFY)
810e5b75505Sopenharmony_ci				return 0;
811e5b75505Sopenharmony_ci			return -1;
812e5b75505Sopenharmony_ci		}
813e5b75505Sopenharmony_ci	}
814e5b75505Sopenharmony_ci
815e5b75505Sopenharmony_ci	return 0;
816e5b75505Sopenharmony_ci}
817e5b75505Sopenharmony_ci
818e5b75505Sopenharmony_ci
819e5b75505Sopenharmony_cistatic void ikev2_build_hdr(struct ikev2_responder_data *data,
820e5b75505Sopenharmony_ci			    struct wpabuf *msg, u8 exchange_type,
821e5b75505Sopenharmony_ci			    u8 next_payload, u32 message_id)
822e5b75505Sopenharmony_ci{
823e5b75505Sopenharmony_ci	struct ikev2_hdr *hdr;
824e5b75505Sopenharmony_ci
825e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "IKEV2: Adding HDR");
826e5b75505Sopenharmony_ci
827e5b75505Sopenharmony_ci	/* HDR - RFC 4306, Sect. 3.1 */
828e5b75505Sopenharmony_ci	hdr = wpabuf_put(msg, sizeof(*hdr));
829e5b75505Sopenharmony_ci	os_memcpy(hdr->i_spi, data->i_spi, IKEV2_SPI_LEN);
830e5b75505Sopenharmony_ci	os_memcpy(hdr->r_spi, data->r_spi, IKEV2_SPI_LEN);
831e5b75505Sopenharmony_ci	hdr->next_payload = next_payload;
832e5b75505Sopenharmony_ci	hdr->version = IKEV2_VERSION;
833e5b75505Sopenharmony_ci	hdr->exchange_type = exchange_type;
834e5b75505Sopenharmony_ci	hdr->flags = IKEV2_HDR_RESPONSE;
835e5b75505Sopenharmony_ci	WPA_PUT_BE32(hdr->message_id, message_id);
836e5b75505Sopenharmony_ci}
837e5b75505Sopenharmony_ci
838e5b75505Sopenharmony_ci
839e5b75505Sopenharmony_cistatic int ikev2_build_sar1(struct ikev2_responder_data *data,
840e5b75505Sopenharmony_ci			    struct wpabuf *msg, u8 next_payload)
841e5b75505Sopenharmony_ci{
842e5b75505Sopenharmony_ci	struct ikev2_payload_hdr *phdr;
843e5b75505Sopenharmony_ci	size_t plen;
844e5b75505Sopenharmony_ci	struct ikev2_proposal *p;
845e5b75505Sopenharmony_ci	struct ikev2_transform *t;
846e5b75505Sopenharmony_ci
847e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "IKEV2: Adding SAr1 payload");
848e5b75505Sopenharmony_ci
849e5b75505Sopenharmony_ci	/* SAr1 - RFC 4306, Sect. 2.7 and 3.3 */
850e5b75505Sopenharmony_ci	phdr = wpabuf_put(msg, sizeof(*phdr));
851e5b75505Sopenharmony_ci	phdr->next_payload = next_payload;
852e5b75505Sopenharmony_ci	phdr->flags = 0;
853e5b75505Sopenharmony_ci
854e5b75505Sopenharmony_ci	p = wpabuf_put(msg, sizeof(*p));
855e5b75505Sopenharmony_ci	p->proposal_num = data->proposal.proposal_num;
856e5b75505Sopenharmony_ci	p->protocol_id = IKEV2_PROTOCOL_IKE;
857e5b75505Sopenharmony_ci	p->num_transforms = 4;
858e5b75505Sopenharmony_ci
859e5b75505Sopenharmony_ci	t = wpabuf_put(msg, sizeof(*t));
860e5b75505Sopenharmony_ci	t->type = 3;
861e5b75505Sopenharmony_ci	t->transform_type = IKEV2_TRANSFORM_ENCR;
862e5b75505Sopenharmony_ci	WPA_PUT_BE16(t->transform_id, data->proposal.encr);
863e5b75505Sopenharmony_ci	if (data->proposal.encr == ENCR_AES_CBC) {
864e5b75505Sopenharmony_ci		/* Transform Attribute: Key Len = 128 bits */
865e5b75505Sopenharmony_ci		wpabuf_put_be16(msg, 0x800e); /* AF=1, AttrType=14 */
866e5b75505Sopenharmony_ci		wpabuf_put_be16(msg, 128); /* 128-bit key */
867e5b75505Sopenharmony_ci	}
868e5b75505Sopenharmony_ci	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) t;
869e5b75505Sopenharmony_ci	WPA_PUT_BE16(t->transform_length, plen);
870e5b75505Sopenharmony_ci
871e5b75505Sopenharmony_ci	t = wpabuf_put(msg, sizeof(*t));
872e5b75505Sopenharmony_ci	t->type = 3;
873e5b75505Sopenharmony_ci	WPA_PUT_BE16(t->transform_length, sizeof(*t));
874e5b75505Sopenharmony_ci	t->transform_type = IKEV2_TRANSFORM_PRF;
875e5b75505Sopenharmony_ci	WPA_PUT_BE16(t->transform_id, data->proposal.prf);
876e5b75505Sopenharmony_ci
877e5b75505Sopenharmony_ci	t = wpabuf_put(msg, sizeof(*t));
878e5b75505Sopenharmony_ci	t->type = 3;
879e5b75505Sopenharmony_ci	WPA_PUT_BE16(t->transform_length, sizeof(*t));
880e5b75505Sopenharmony_ci	t->transform_type = IKEV2_TRANSFORM_INTEG;
881e5b75505Sopenharmony_ci	WPA_PUT_BE16(t->transform_id, data->proposal.integ);
882e5b75505Sopenharmony_ci
883e5b75505Sopenharmony_ci	t = wpabuf_put(msg, sizeof(*t));
884e5b75505Sopenharmony_ci	WPA_PUT_BE16(t->transform_length, sizeof(*t));
885e5b75505Sopenharmony_ci	t->transform_type = IKEV2_TRANSFORM_DH;
886e5b75505Sopenharmony_ci	WPA_PUT_BE16(t->transform_id, data->proposal.dh);
887e5b75505Sopenharmony_ci
888e5b75505Sopenharmony_ci	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) p;
889e5b75505Sopenharmony_ci	WPA_PUT_BE16(p->proposal_length, plen);
890e5b75505Sopenharmony_ci
891e5b75505Sopenharmony_ci	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
892e5b75505Sopenharmony_ci	WPA_PUT_BE16(phdr->payload_length, plen);
893e5b75505Sopenharmony_ci
894e5b75505Sopenharmony_ci	return 0;
895e5b75505Sopenharmony_ci}
896e5b75505Sopenharmony_ci
897e5b75505Sopenharmony_ci
898e5b75505Sopenharmony_cistatic int ikev2_build_ker(struct ikev2_responder_data *data,
899e5b75505Sopenharmony_ci			   struct wpabuf *msg, u8 next_payload)
900e5b75505Sopenharmony_ci{
901e5b75505Sopenharmony_ci	struct ikev2_payload_hdr *phdr;
902e5b75505Sopenharmony_ci	size_t plen;
903e5b75505Sopenharmony_ci	struct wpabuf *pv;
904e5b75505Sopenharmony_ci
905e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "IKEV2: Adding KEr payload");
906e5b75505Sopenharmony_ci
907e5b75505Sopenharmony_ci	pv = dh_init(data->dh, &data->r_dh_private);
908e5b75505Sopenharmony_ci	if (pv == NULL) {
909e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "IKEV2: Failed to initialize DH");
910e5b75505Sopenharmony_ci		return -1;
911e5b75505Sopenharmony_ci	}
912e5b75505Sopenharmony_ci
913e5b75505Sopenharmony_ci	/* KEr - RFC 4306, Sect. 3.4 */
914e5b75505Sopenharmony_ci	phdr = wpabuf_put(msg, sizeof(*phdr));
915e5b75505Sopenharmony_ci	phdr->next_payload = next_payload;
916e5b75505Sopenharmony_ci	phdr->flags = 0;
917e5b75505Sopenharmony_ci
918e5b75505Sopenharmony_ci	wpabuf_put_be16(msg, data->proposal.dh); /* DH Group # */
919e5b75505Sopenharmony_ci	wpabuf_put(msg, 2); /* RESERVED */
920e5b75505Sopenharmony_ci	/*
921e5b75505Sopenharmony_ci	 * RFC 4306, Sect. 3.4: possible zero padding for public value to
922e5b75505Sopenharmony_ci	 * match the length of the prime.
923e5b75505Sopenharmony_ci	 */
924e5b75505Sopenharmony_ci	wpabuf_put(msg, data->dh->prime_len - wpabuf_len(pv));
925e5b75505Sopenharmony_ci	wpabuf_put_buf(msg, pv);
926e5b75505Sopenharmony_ci	wpabuf_free(pv);
927e5b75505Sopenharmony_ci
928e5b75505Sopenharmony_ci	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
929e5b75505Sopenharmony_ci	WPA_PUT_BE16(phdr->payload_length, plen);
930e5b75505Sopenharmony_ci	return 0;
931e5b75505Sopenharmony_ci}
932e5b75505Sopenharmony_ci
933e5b75505Sopenharmony_ci
934e5b75505Sopenharmony_cistatic int ikev2_build_nr(struct ikev2_responder_data *data,
935e5b75505Sopenharmony_ci			  struct wpabuf *msg, u8 next_payload)
936e5b75505Sopenharmony_ci{
937e5b75505Sopenharmony_ci	struct ikev2_payload_hdr *phdr;
938e5b75505Sopenharmony_ci	size_t plen;
939e5b75505Sopenharmony_ci
940e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "IKEV2: Adding Nr payload");
941e5b75505Sopenharmony_ci
942e5b75505Sopenharmony_ci	/* Nr - RFC 4306, Sect. 3.9 */
943e5b75505Sopenharmony_ci	phdr = wpabuf_put(msg, sizeof(*phdr));
944e5b75505Sopenharmony_ci	phdr->next_payload = next_payload;
945e5b75505Sopenharmony_ci	phdr->flags = 0;
946e5b75505Sopenharmony_ci	wpabuf_put_data(msg, data->r_nonce, data->r_nonce_len);
947e5b75505Sopenharmony_ci	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
948e5b75505Sopenharmony_ci	WPA_PUT_BE16(phdr->payload_length, plen);
949e5b75505Sopenharmony_ci	return 0;
950e5b75505Sopenharmony_ci}
951e5b75505Sopenharmony_ci
952e5b75505Sopenharmony_ci
953e5b75505Sopenharmony_cistatic int ikev2_build_idr(struct ikev2_responder_data *data,
954e5b75505Sopenharmony_ci			   struct wpabuf *msg, u8 next_payload)
955e5b75505Sopenharmony_ci{
956e5b75505Sopenharmony_ci	struct ikev2_payload_hdr *phdr;
957e5b75505Sopenharmony_ci	size_t plen;
958e5b75505Sopenharmony_ci
959e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "IKEV2: Adding IDr payload");
960e5b75505Sopenharmony_ci
961e5b75505Sopenharmony_ci	if (data->IDr == NULL) {
962e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: No IDr available");
963e5b75505Sopenharmony_ci		return -1;
964e5b75505Sopenharmony_ci	}
965e5b75505Sopenharmony_ci
966e5b75505Sopenharmony_ci	/* IDr - RFC 4306, Sect. 3.5 */
967e5b75505Sopenharmony_ci	phdr = wpabuf_put(msg, sizeof(*phdr));
968e5b75505Sopenharmony_ci	phdr->next_payload = next_payload;
969e5b75505Sopenharmony_ci	phdr->flags = 0;
970e5b75505Sopenharmony_ci	wpabuf_put_u8(msg, ID_KEY_ID);
971e5b75505Sopenharmony_ci	wpabuf_put(msg, 3); /* RESERVED */
972e5b75505Sopenharmony_ci	wpabuf_put_data(msg, data->IDr, data->IDr_len);
973e5b75505Sopenharmony_ci	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
974e5b75505Sopenharmony_ci	WPA_PUT_BE16(phdr->payload_length, plen);
975e5b75505Sopenharmony_ci	return 0;
976e5b75505Sopenharmony_ci}
977e5b75505Sopenharmony_ci
978e5b75505Sopenharmony_ci
979e5b75505Sopenharmony_cistatic int ikev2_build_auth(struct ikev2_responder_data *data,
980e5b75505Sopenharmony_ci			    struct wpabuf *msg, u8 next_payload)
981e5b75505Sopenharmony_ci{
982e5b75505Sopenharmony_ci	struct ikev2_payload_hdr *phdr;
983e5b75505Sopenharmony_ci	size_t plen;
984e5b75505Sopenharmony_ci	const struct ikev2_prf_alg *prf;
985e5b75505Sopenharmony_ci
986e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "IKEV2: Adding AUTH payload");
987e5b75505Sopenharmony_ci
988e5b75505Sopenharmony_ci	prf = ikev2_get_prf(data->proposal.prf);
989e5b75505Sopenharmony_ci	if (prf == NULL)
990e5b75505Sopenharmony_ci		return -1;
991e5b75505Sopenharmony_ci
992e5b75505Sopenharmony_ci	/* Authentication - RFC 4306, Sect. 3.8 */
993e5b75505Sopenharmony_ci	phdr = wpabuf_put(msg, sizeof(*phdr));
994e5b75505Sopenharmony_ci	phdr->next_payload = next_payload;
995e5b75505Sopenharmony_ci	phdr->flags = 0;
996e5b75505Sopenharmony_ci	wpabuf_put_u8(msg, AUTH_SHARED_KEY_MIC);
997e5b75505Sopenharmony_ci	wpabuf_put(msg, 3); /* RESERVED */
998e5b75505Sopenharmony_ci
999e5b75505Sopenharmony_ci	/* msg | Ni | prf(SK_pr,IDr') */
1000e5b75505Sopenharmony_ci	if (ikev2_derive_auth_data(data->proposal.prf, data->r_sign_msg,
1001e5b75505Sopenharmony_ci				   data->IDr, data->IDr_len, ID_KEY_ID,
1002e5b75505Sopenharmony_ci				   &data->keys, 0, data->shared_secret,
1003e5b75505Sopenharmony_ci				   data->shared_secret_len,
1004e5b75505Sopenharmony_ci				   data->i_nonce, data->i_nonce_len,
1005e5b75505Sopenharmony_ci				   data->key_pad, data->key_pad_len,
1006e5b75505Sopenharmony_ci				   wpabuf_put(msg, prf->hash_len)) < 0) {
1007e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data");
1008e5b75505Sopenharmony_ci		return -1;
1009e5b75505Sopenharmony_ci	}
1010e5b75505Sopenharmony_ci	wpabuf_free(data->r_sign_msg);
1011e5b75505Sopenharmony_ci	data->r_sign_msg = NULL;
1012e5b75505Sopenharmony_ci
1013e5b75505Sopenharmony_ci	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
1014e5b75505Sopenharmony_ci	WPA_PUT_BE16(phdr->payload_length, plen);
1015e5b75505Sopenharmony_ci	return 0;
1016e5b75505Sopenharmony_ci}
1017e5b75505Sopenharmony_ci
1018e5b75505Sopenharmony_ci
1019e5b75505Sopenharmony_cistatic int ikev2_build_notification(struct ikev2_responder_data *data,
1020e5b75505Sopenharmony_ci				    struct wpabuf *msg, u8 next_payload)
1021e5b75505Sopenharmony_ci{
1022e5b75505Sopenharmony_ci	struct ikev2_payload_hdr *phdr;
1023e5b75505Sopenharmony_ci	size_t plen;
1024e5b75505Sopenharmony_ci
1025e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "IKEV2: Adding Notification payload");
1026e5b75505Sopenharmony_ci
1027e5b75505Sopenharmony_ci	if (data->error_type == 0) {
1028e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: No Notify Message Type "
1029e5b75505Sopenharmony_ci			   "available");
1030e5b75505Sopenharmony_ci		return -1;
1031e5b75505Sopenharmony_ci	}
1032e5b75505Sopenharmony_ci
1033e5b75505Sopenharmony_ci	/* Notify - RFC 4306, Sect. 3.10 */
1034e5b75505Sopenharmony_ci	phdr = wpabuf_put(msg, sizeof(*phdr));
1035e5b75505Sopenharmony_ci	phdr->next_payload = next_payload;
1036e5b75505Sopenharmony_ci	phdr->flags = 0;
1037e5b75505Sopenharmony_ci	wpabuf_put_u8(msg, 0); /* Protocol ID: no existing SA */
1038e5b75505Sopenharmony_ci	wpabuf_put_u8(msg, 0); /* SPI Size */
1039e5b75505Sopenharmony_ci	wpabuf_put_be16(msg, data->error_type);
1040e5b75505Sopenharmony_ci
1041e5b75505Sopenharmony_ci	switch (data->error_type) {
1042e5b75505Sopenharmony_ci	case INVALID_KE_PAYLOAD:
1043e5b75505Sopenharmony_ci		if (data->proposal.dh == -1) {
1044e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "IKEV2: No DH Group selected for "
1045e5b75505Sopenharmony_ci				   "INVALID_KE_PAYLOAD notifications");
1046e5b75505Sopenharmony_ci			return -1;
1047e5b75505Sopenharmony_ci		}
1048e5b75505Sopenharmony_ci		wpabuf_put_be16(msg, data->proposal.dh);
1049e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "IKEV2: INVALID_KE_PAYLOAD - request "
1050e5b75505Sopenharmony_ci			   "DH Group #%d", data->proposal.dh);
1051e5b75505Sopenharmony_ci		break;
1052e5b75505Sopenharmony_ci	case AUTHENTICATION_FAILED:
1053e5b75505Sopenharmony_ci		/* no associated data */
1054e5b75505Sopenharmony_ci		break;
1055e5b75505Sopenharmony_ci	default:
1056e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "IKEV2: Unsupported Notify Message Type "
1057e5b75505Sopenharmony_ci			   "%d", data->error_type);
1058e5b75505Sopenharmony_ci		return -1;
1059e5b75505Sopenharmony_ci	}
1060e5b75505Sopenharmony_ci
1061e5b75505Sopenharmony_ci	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
1062e5b75505Sopenharmony_ci	WPA_PUT_BE16(phdr->payload_length, plen);
1063e5b75505Sopenharmony_ci	return 0;
1064e5b75505Sopenharmony_ci}
1065e5b75505Sopenharmony_ci
1066e5b75505Sopenharmony_ci
1067e5b75505Sopenharmony_cistatic struct wpabuf * ikev2_build_sa_init(struct ikev2_responder_data *data)
1068e5b75505Sopenharmony_ci{
1069e5b75505Sopenharmony_ci	struct wpabuf *msg;
1070e5b75505Sopenharmony_ci
1071e5b75505Sopenharmony_ci	/* build IKE_SA_INIT: HDR, SAr1, KEr, Nr, [CERTREQ], [SK{IDr}] */
1072e5b75505Sopenharmony_ci
1073e5b75505Sopenharmony_ci	if (os_get_random(data->r_spi, IKEV2_SPI_LEN))
1074e5b75505Sopenharmony_ci		return NULL;
1075e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Responder's SPI",
1076e5b75505Sopenharmony_ci		    data->r_spi, IKEV2_SPI_LEN);
1077e5b75505Sopenharmony_ci
1078e5b75505Sopenharmony_ci	data->r_nonce_len = IKEV2_NONCE_MIN_LEN;
1079e5b75505Sopenharmony_ci	if (random_get_bytes(data->r_nonce, data->r_nonce_len))
1080e5b75505Sopenharmony_ci		return NULL;
1081e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "IKEV2: Nr", data->r_nonce, data->r_nonce_len);
1082e5b75505Sopenharmony_ci
1083e5b75505Sopenharmony_ci	msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1500);
1084e5b75505Sopenharmony_ci	if (msg == NULL)
1085e5b75505Sopenharmony_ci		return NULL;
1086e5b75505Sopenharmony_ci
1087e5b75505Sopenharmony_ci	ikev2_build_hdr(data, msg, IKE_SA_INIT, IKEV2_PAYLOAD_SA, 0);
1088e5b75505Sopenharmony_ci	if (ikev2_build_sar1(data, msg, IKEV2_PAYLOAD_KEY_EXCHANGE) ||
1089e5b75505Sopenharmony_ci	    ikev2_build_ker(data, msg, IKEV2_PAYLOAD_NONCE) ||
1090e5b75505Sopenharmony_ci	    ikev2_build_nr(data, msg, data->peer_auth == PEER_AUTH_SECRET ?
1091e5b75505Sopenharmony_ci			   IKEV2_PAYLOAD_ENCRYPTED :
1092e5b75505Sopenharmony_ci			   IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) {
1093e5b75505Sopenharmony_ci		wpabuf_free(msg);
1094e5b75505Sopenharmony_ci		return NULL;
1095e5b75505Sopenharmony_ci	}
1096e5b75505Sopenharmony_ci
1097e5b75505Sopenharmony_ci	if (ikev2_derive_keys(data)) {
1098e5b75505Sopenharmony_ci		wpabuf_free(msg);
1099e5b75505Sopenharmony_ci		return NULL;
1100e5b75505Sopenharmony_ci	}
1101e5b75505Sopenharmony_ci
1102e5b75505Sopenharmony_ci	if (data->peer_auth == PEER_AUTH_CERT) {
1103e5b75505Sopenharmony_ci		/* TODO: CERTREQ with SHA-1 hashes of Subject Public Key Info
1104e5b75505Sopenharmony_ci		 * for trust agents */
1105e5b75505Sopenharmony_ci	}
1106e5b75505Sopenharmony_ci
1107e5b75505Sopenharmony_ci	if (data->peer_auth == PEER_AUTH_SECRET) {
1108e5b75505Sopenharmony_ci		struct wpabuf *plain = wpabuf_alloc(data->IDr_len + 1000);
1109e5b75505Sopenharmony_ci		if (plain == NULL) {
1110e5b75505Sopenharmony_ci			wpabuf_free(msg);
1111e5b75505Sopenharmony_ci			return NULL;
1112e5b75505Sopenharmony_ci		}
1113e5b75505Sopenharmony_ci		if (ikev2_build_idr(data, plain,
1114e5b75505Sopenharmony_ci				    IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) ||
1115e5b75505Sopenharmony_ci		    ikev2_build_encrypted(data->proposal.encr,
1116e5b75505Sopenharmony_ci					  data->proposal.integ,
1117e5b75505Sopenharmony_ci					  &data->keys, 0, msg, plain,
1118e5b75505Sopenharmony_ci					  IKEV2_PAYLOAD_IDr)) {
1119e5b75505Sopenharmony_ci			wpabuf_free(plain);
1120e5b75505Sopenharmony_ci			wpabuf_free(msg);
1121e5b75505Sopenharmony_ci			return NULL;
1122e5b75505Sopenharmony_ci		}
1123e5b75505Sopenharmony_ci		wpabuf_free(plain);
1124e5b75505Sopenharmony_ci	}
1125e5b75505Sopenharmony_ci
1126e5b75505Sopenharmony_ci	ikev2_update_hdr(msg);
1127e5b75505Sopenharmony_ci
1128e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_INIT)", msg);
1129e5b75505Sopenharmony_ci
1130e5b75505Sopenharmony_ci	data->state = SA_AUTH;
1131e5b75505Sopenharmony_ci
1132e5b75505Sopenharmony_ci	wpabuf_free(data->r_sign_msg);
1133e5b75505Sopenharmony_ci	data->r_sign_msg = wpabuf_dup(msg);
1134e5b75505Sopenharmony_ci
1135e5b75505Sopenharmony_ci	return msg;
1136e5b75505Sopenharmony_ci}
1137e5b75505Sopenharmony_ci
1138e5b75505Sopenharmony_ci
1139e5b75505Sopenharmony_cistatic struct wpabuf * ikev2_build_sa_auth(struct ikev2_responder_data *data)
1140e5b75505Sopenharmony_ci{
1141e5b75505Sopenharmony_ci	struct wpabuf *msg, *plain;
1142e5b75505Sopenharmony_ci
1143e5b75505Sopenharmony_ci	/* build IKE_SA_AUTH: HDR, SK {IDr, [CERT,] AUTH} */
1144e5b75505Sopenharmony_ci
1145e5b75505Sopenharmony_ci	msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1000);
1146e5b75505Sopenharmony_ci	if (msg == NULL)
1147e5b75505Sopenharmony_ci		return NULL;
1148e5b75505Sopenharmony_ci	ikev2_build_hdr(data, msg, IKE_SA_AUTH, IKEV2_PAYLOAD_ENCRYPTED, 1);
1149e5b75505Sopenharmony_ci
1150e5b75505Sopenharmony_ci	plain = wpabuf_alloc(data->IDr_len + 1000);
1151e5b75505Sopenharmony_ci	if (plain == NULL) {
1152e5b75505Sopenharmony_ci		wpabuf_free(msg);
1153e5b75505Sopenharmony_ci		return NULL;
1154e5b75505Sopenharmony_ci	}
1155e5b75505Sopenharmony_ci
1156e5b75505Sopenharmony_ci	if (ikev2_build_idr(data, plain, IKEV2_PAYLOAD_AUTHENTICATION) ||
1157e5b75505Sopenharmony_ci	    ikev2_build_auth(data, plain, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) ||
1158e5b75505Sopenharmony_ci	    ikev2_build_encrypted(data->proposal.encr, data->proposal.integ,
1159e5b75505Sopenharmony_ci				  &data->keys, 0, msg, plain,
1160e5b75505Sopenharmony_ci				  IKEV2_PAYLOAD_IDr)) {
1161e5b75505Sopenharmony_ci		wpabuf_free(plain);
1162e5b75505Sopenharmony_ci		wpabuf_free(msg);
1163e5b75505Sopenharmony_ci		return NULL;
1164e5b75505Sopenharmony_ci	}
1165e5b75505Sopenharmony_ci	wpabuf_free(plain);
1166e5b75505Sopenharmony_ci
1167e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_AUTH)", msg);
1168e5b75505Sopenharmony_ci
1169e5b75505Sopenharmony_ci	data->state = IKEV2_DONE;
1170e5b75505Sopenharmony_ci
1171e5b75505Sopenharmony_ci	return msg;
1172e5b75505Sopenharmony_ci}
1173e5b75505Sopenharmony_ci
1174e5b75505Sopenharmony_ci
1175e5b75505Sopenharmony_cistatic struct wpabuf * ikev2_build_notify(struct ikev2_responder_data *data)
1176e5b75505Sopenharmony_ci{
1177e5b75505Sopenharmony_ci	struct wpabuf *msg;
1178e5b75505Sopenharmony_ci
1179e5b75505Sopenharmony_ci	msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + 1000);
1180e5b75505Sopenharmony_ci	if (msg == NULL)
1181e5b75505Sopenharmony_ci		return NULL;
1182e5b75505Sopenharmony_ci	if (data->last_msg == LAST_MSG_SA_AUTH) {
1183e5b75505Sopenharmony_ci		/* HDR, SK{N} */
1184e5b75505Sopenharmony_ci		struct wpabuf *plain = wpabuf_alloc(100);
1185e5b75505Sopenharmony_ci		if (plain == NULL) {
1186e5b75505Sopenharmony_ci			wpabuf_free(msg);
1187e5b75505Sopenharmony_ci			return NULL;
1188e5b75505Sopenharmony_ci		}
1189e5b75505Sopenharmony_ci		ikev2_build_hdr(data, msg, IKE_SA_AUTH,
1190e5b75505Sopenharmony_ci				IKEV2_PAYLOAD_ENCRYPTED, 1);
1191e5b75505Sopenharmony_ci		if (ikev2_build_notification(data, plain,
1192e5b75505Sopenharmony_ci					     IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) ||
1193e5b75505Sopenharmony_ci		    ikev2_build_encrypted(data->proposal.encr,
1194e5b75505Sopenharmony_ci					  data->proposal.integ,
1195e5b75505Sopenharmony_ci					  &data->keys, 0, msg, plain,
1196e5b75505Sopenharmony_ci					  IKEV2_PAYLOAD_NOTIFICATION)) {
1197e5b75505Sopenharmony_ci			wpabuf_free(plain);
1198e5b75505Sopenharmony_ci			wpabuf_free(msg);
1199e5b75505Sopenharmony_ci			return NULL;
1200e5b75505Sopenharmony_ci		}
1201e5b75505Sopenharmony_ci		wpabuf_free(plain);
1202e5b75505Sopenharmony_ci		data->state = IKEV2_FAILED;
1203e5b75505Sopenharmony_ci	} else {
1204e5b75505Sopenharmony_ci		/* HDR, N */
1205e5b75505Sopenharmony_ci		ikev2_build_hdr(data, msg, IKE_SA_INIT,
1206e5b75505Sopenharmony_ci				IKEV2_PAYLOAD_NOTIFICATION, 0);
1207e5b75505Sopenharmony_ci		if (ikev2_build_notification(data, msg,
1208e5b75505Sopenharmony_ci					     IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) {
1209e5b75505Sopenharmony_ci			wpabuf_free(msg);
1210e5b75505Sopenharmony_ci			return NULL;
1211e5b75505Sopenharmony_ci		}
1212e5b75505Sopenharmony_ci		data->state = SA_INIT;
1213e5b75505Sopenharmony_ci	}
1214e5b75505Sopenharmony_ci
1215e5b75505Sopenharmony_ci	ikev2_update_hdr(msg);
1216e5b75505Sopenharmony_ci
1217e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (Notification)",
1218e5b75505Sopenharmony_ci			msg);
1219e5b75505Sopenharmony_ci
1220e5b75505Sopenharmony_ci	return msg;
1221e5b75505Sopenharmony_ci}
1222e5b75505Sopenharmony_ci
1223e5b75505Sopenharmony_ci
1224e5b75505Sopenharmony_cistruct wpabuf * ikev2_responder_build(struct ikev2_responder_data *data)
1225e5b75505Sopenharmony_ci{
1226e5b75505Sopenharmony_ci	switch (data->state) {
1227e5b75505Sopenharmony_ci	case SA_INIT:
1228e5b75505Sopenharmony_ci		return ikev2_build_sa_init(data);
1229e5b75505Sopenharmony_ci	case SA_AUTH:
1230e5b75505Sopenharmony_ci		return ikev2_build_sa_auth(data);
1231e5b75505Sopenharmony_ci	case CHILD_SA:
1232e5b75505Sopenharmony_ci		return NULL;
1233e5b75505Sopenharmony_ci	case NOTIFY:
1234e5b75505Sopenharmony_ci		return ikev2_build_notify(data);
1235e5b75505Sopenharmony_ci	case IKEV2_DONE:
1236e5b75505Sopenharmony_ci	case IKEV2_FAILED:
1237e5b75505Sopenharmony_ci		return NULL;
1238e5b75505Sopenharmony_ci	}
1239e5b75505Sopenharmony_ci	return NULL;
1240e5b75505Sopenharmony_ci}
1241