1526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/*
2526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * IKEv2 responder (RFC 4306) for EAP-IKEV2
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 "dh_groups.h"
19526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "ikev2.h"
20526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
21526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
22526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid ikev2_responder_deinit(struct ikev2_responder_data *data)
23526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
24526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ikev2_free_keys(&data->keys);
25526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_free(data->i_dh_public);
26526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_free(data->r_dh_private);
27526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(data->IDi);
28526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(data->IDr);
29526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(data->shared_secret);
30526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_free(data->i_sign_msg);
31526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_free(data->r_sign_msg);
32526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(data->key_pad);
33526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
34526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
35526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
36526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int ikev2_derive_keys(struct ikev2_responder_data *data)
37526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
38526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *buf, *pos, *pad, skeyseed[IKEV2_MAX_HASH_LEN];
39526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t buf_len, pad_len;
40526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wpabuf *shared;
41526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const struct ikev2_integ_alg *integ;
42526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const struct ikev2_prf_alg *prf;
43526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const struct ikev2_encr_alg *encr;
44526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int ret;
45526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *addr[2];
46526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t len[2];
47526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
48526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* RFC 4306, Sect. 2.14 */
49526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
50526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	integ = ikev2_get_integ(data->proposal.integ);
51526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	prf = ikev2_get_prf(data->proposal.prf);
52526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	encr = ikev2_get_encr(data->proposal.encr);
53526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (integ == NULL || prf == NULL || encr == NULL) {
54526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unsupported proposal");
55526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
56526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
57526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
58526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	shared = dh_derive_shared(data->i_dh_public, data->r_dh_private,
59526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  data->dh);
60526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (shared == NULL)
61526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
62526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
63526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Construct Ni | Nr | SPIi | SPIr */
64526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
65526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	buf_len = data->i_nonce_len + data->r_nonce_len + 2 * IKEV2_SPI_LEN;
66526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	buf = os_malloc(buf_len);
67526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (buf == NULL) {
68526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpabuf_free(shared);
69526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
70526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
71526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
72526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos = buf;
73526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(pos, data->i_nonce, data->i_nonce_len);
74526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += data->i_nonce_len;
75526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(pos, data->r_nonce, data->r_nonce_len);
76526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += data->r_nonce_len;
77526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(pos, data->i_spi, IKEV2_SPI_LEN);
78526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += IKEV2_SPI_LEN;
79526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(pos, data->r_spi, IKEV2_SPI_LEN);
80526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CCNS_PL
81526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#if __BYTE_ORDER == __LITTLE_ENDIAN
82526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	{
83526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		int i;
84526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		u8 *tmp = pos - IKEV2_SPI_LEN;
85526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		/* Incorrect byte re-ordering on little endian hosts.. */
86526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		for (i = 0; i < IKEV2_SPI_LEN; i++)
87526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			*tmp++ = data->i_spi[IKEV2_SPI_LEN - 1 - i];
88526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		for (i = 0; i < IKEV2_SPI_LEN; i++)
89526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			*tmp++ = data->r_spi[IKEV2_SPI_LEN - 1 - i];
90526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
91526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif
92526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CCNS_PL */
93526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
94526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* SKEYSEED = prf(Ni | Nr, g^ir) */
95526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Use zero-padding per RFC 4306, Sect. 2.14 */
96526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pad_len = data->dh->prime_len - wpabuf_len(shared);
97526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CCNS_PL
98526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Shared secret is not zero-padded correctly */
99526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pad_len = 0;
100526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CCNS_PL */
101526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pad = os_zalloc(pad_len ? pad_len : 1);
102526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (pad == NULL) {
103526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpabuf_free(shared);
104526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(buf);
105526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
106526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
107526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
108526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	addr[0] = pad;
109526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	len[0] = pad_len;
110526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	addr[1] = wpabuf_head(shared);
111526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	len[1] = wpabuf_len(shared);
112526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ikev2_prf_hash(prf->id, buf, data->i_nonce_len + data->r_nonce_len,
113526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   2, addr, len, skeyseed) < 0) {
114526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpabuf_free(shared);
115526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(buf);
116526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(pad);
117526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
118526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
119526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(pad);
120526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_free(shared);
121526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
122526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* DH parameters are not needed anymore, so free them */
123526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_free(data->i_dh_public);
124526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->i_dh_public = NULL;
125526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_free(data->r_dh_private);
126526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->r_dh_private = NULL;
127526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
128526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "IKEV2: SKEYSEED",
129526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			skeyseed, prf->hash_len);
130526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
131526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret = ikev2_derive_sk_keys(prf, integ, encr, skeyseed, buf, buf_len,
132526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   &data->keys);
133526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(buf);
134526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return ret;
135526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
136526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
137526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
138526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int ikev2_parse_transform(struct ikev2_proposal_data *prop,
139526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				 const u8 *pos, const u8 *end)
140526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
141526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int transform_len;
142526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const struct ikev2_transform *t;
143526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u16 transform_id;
144526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *tend;
145526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
146526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (end - pos < (int) sizeof(*t)) {
147526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Too short transform");
148526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
149526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
150526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
151526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	t = (const struct ikev2_transform *) pos;
152526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	transform_len = WPA_GET_BE16(t->transform_length);
153526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (transform_len < (int) sizeof(*t) || pos + transform_len > end) {
154526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Invalid transform length %d",
155526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   transform_len);
156526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
157526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
158526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	tend = pos + transform_len;
159526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
160526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	transform_id = WPA_GET_BE16(t->transform_id);
161526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
162526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "IKEV2:   Transform:");
163526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "IKEV2:     Type: %d  Transform Length: %d  "
164526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   "Transform Type: %d  Transform ID: %d",
165526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   t->type, transform_len, t->transform_type, transform_id);
166526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
167526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (t->type != 0 && t->type != 3) {
168526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unexpected Transform type");
169526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
170526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
171526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
172526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos = (const u8 *) (t + 1);
173526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (pos < tend) {
174526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_hexdump(MSG_DEBUG, "IKEV2:     Transform Attributes",
175526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			    pos, tend - pos);
176526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
177526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
178526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	switch (t->transform_type) {
179526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case IKEV2_TRANSFORM_ENCR:
180526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (ikev2_get_encr(transform_id)) {
181526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			if (transform_id == ENCR_AES_CBC) {
182526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				if (tend - pos != 4) {
183526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					wpa_printf(MSG_DEBUG, "IKEV2: No "
184526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						   "Transform Attr for AES");
185526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					break;
186526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				}
187526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CCNS_PL
188526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				if (WPA_GET_BE16(pos) != 0x001d /* ?? */) {
189526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					wpa_printf(MSG_DEBUG, "IKEV2: Not a "
190526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						   "Key Size attribute for "
191526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						   "AES");
192526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					break;
193526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				}
194526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#else /* CCNS_PL */
195526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				if (WPA_GET_BE16(pos) != 0x800e) {
196526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					wpa_printf(MSG_DEBUG, "IKEV2: Not a "
197526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						   "Key Size attribute for "
198526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						   "AES");
199526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					break;
200526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				}
201526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CCNS_PL */
202526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				if (WPA_GET_BE16(pos + 2) != 128) {
203526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					wpa_printf(MSG_DEBUG, "IKEV2: "
204526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						   "Unsupported AES key size "
205526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						   "%d bits",
206526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						   WPA_GET_BE16(pos + 2));
207526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					break;
208526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				}
209526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			}
210526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			prop->encr = transform_id;
211526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
212526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
213526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case IKEV2_TRANSFORM_PRF:
214526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (ikev2_get_prf(transform_id))
215526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			prop->prf = transform_id;
216526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
217526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case IKEV2_TRANSFORM_INTEG:
218526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (ikev2_get_integ(transform_id))
219526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			prop->integ = transform_id;
220526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
221526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case IKEV2_TRANSFORM_DH:
222526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (dh_groups_get(transform_id))
223526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			prop->dh = transform_id;
224526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
225526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
226526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
227526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return transform_len;
228526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
229526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
230526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
231526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int ikev2_parse_proposal(struct ikev2_proposal_data *prop,
232526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				const u8 *pos, const u8 *end)
233526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
234526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *pend, *ppos;
235526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int proposal_len, i;
236526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const struct ikev2_proposal *p;
237526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
238526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (end - pos < (int) sizeof(*p)) {
239526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Too short proposal");
240526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
241526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
242526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
243526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* FIX: AND processing if multiple proposals use the same # */
244526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
245526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	p = (const struct ikev2_proposal *) pos;
246526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	proposal_len = WPA_GET_BE16(p->proposal_length);
247526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (proposal_len < (int) sizeof(*p) || pos + proposal_len > end) {
248526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Invalid proposal length %d",
249526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   proposal_len);
250526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
251526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
252526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "IKEV2: SAi1 Proposal # %d",
253526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   p->proposal_num);
254526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "IKEV2:   Type: %d  Proposal Length: %d "
255526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   " Protocol ID: %d",
256526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   p->type, proposal_len, p->protocol_id);
257526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "IKEV2:   SPI Size: %d  Transforms: %d",
258526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   p->spi_size, p->num_transforms);
259526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
260526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (p->type != 0 && p->type != 2) {
261526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal type");
262526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
263526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
264526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
265526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (p->protocol_id != IKEV2_PROTOCOL_IKE) {
266526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "IKEV2: Unexpected Protocol ID "
267526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "(only IKE allowed for EAP-IKEv2)");
268526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
269526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
270526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
271526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (p->proposal_num != prop->proposal_num) {
272526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (p->proposal_num == prop->proposal_num + 1)
273526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			prop->proposal_num = p->proposal_num;
274526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		else {
275526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal #");
276526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
277526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
278526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
279526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
280526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ppos = (const u8 *) (p + 1);
281526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pend = pos + proposal_len;
282526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ppos + p->spi_size > pend) {
283526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Not enough room for SPI "
284526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "in proposal");
285526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
286526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
287526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (p->spi_size) {
288526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_hexdump(MSG_DEBUG, "IKEV2:    SPI",
289526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			    ppos, p->spi_size);
290526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ppos += p->spi_size;
291526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
292526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
293526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/*
294526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * For initial IKE_SA negotiation, SPI Size MUST be zero; for
295526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * subsequent negotiations, it must be 8 for IKE. We only support
296526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * initial case for now.
297526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 */
298526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (p->spi_size != 0) {
299526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unexpected SPI Size");
300526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
301526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
302526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
303526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (p->num_transforms == 0) {
304526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: At least one transform required");
305526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
306526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
307526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
308526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	for (i = 0; i < (int) p->num_transforms; i++) {
309526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		int tlen = ikev2_parse_transform(prop, ppos, pend);
310526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (tlen < 0)
311526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
312526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ppos += tlen;
313526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
314526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
315526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ppos != pend) {
316526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unexpected data after "
317526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "transforms");
318526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
319526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
320526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
321526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return proposal_len;
322526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
323526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
324526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
325526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int ikev2_process_sai1(struct ikev2_responder_data *data,
326526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			      const u8 *sai1, size_t sai1_len)
327526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
328526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct ikev2_proposal_data prop;
329526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *pos, *end;
330526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int found = 0;
331526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
332526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Security Association Payloads: <Proposals> */
333526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
334526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (sai1 == NULL) {
335526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: SAi1 not received");
336526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
337526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
338526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
339526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memset(&prop, 0, sizeof(prop));
340526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	prop.proposal_num = 1;
341526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
342526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos = sai1;
343526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	end = sai1 + sai1_len;
344526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
345526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	while (pos < end) {
346526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		int plen;
347526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
348526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		prop.integ = -1;
349526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		prop.prf = -1;
350526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		prop.encr = -1;
351526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		prop.dh = -1;
352526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		plen = ikev2_parse_proposal(&prop, pos, end);
353526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (plen < 0)
354526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
355526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
356526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (!found && prop.integ != -1 && prop.prf != -1 &&
357526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    prop.encr != -1 && prop.dh != -1) {
358526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			os_memcpy(&data->proposal, &prop, sizeof(prop));
359526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			data->dh = dh_groups_get(prop.dh);
360526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			found = 1;
361526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
362526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
363526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos += plen;
364526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
365526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
366526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (pos != end) {
367526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unexpected data after proposals");
368526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
369526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
370526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
371526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (!found) {
372526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No acceptable proposal found");
373526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
374526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
375526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
376526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "IKEV2: Accepted proposal #%d: ENCR:%d PRF:%d "
377526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   "INTEG:%d D-H:%d", data->proposal.proposal_num,
378526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   data->proposal.encr, data->proposal.prf,
379526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   data->proposal.integ, data->proposal.dh);
380526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
381526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
382526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
383526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
384526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
385526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int ikev2_process_kei(struct ikev2_responder_data *data,
386526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     const u8 *kei, size_t kei_len)
387526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
388526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u16 group;
389526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
390526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/*
391526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * Key Exchange Payload:
392526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * DH Group # (16 bits)
393526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * RESERVED (16 bits)
394526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * Key Exchange Data (Diffie-Hellman public value)
395526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 */
396526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
397526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (kei == NULL) {
398526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: KEi not received");
399526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
400526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
401526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
402526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (kei_len < 4 + 96) {
403526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Too show Key Exchange Payload");
404526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
405526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
406526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
407526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	group = WPA_GET_BE16(kei);
408526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "IKEV2: KEi DH Group #%u", group);
409526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
410526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (group != data->proposal.dh) {
411526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "IKEV2: KEi DH Group #%u does not match "
412526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "with the selected proposal (%u)",
413526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   group, data->proposal.dh);
414526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		/* Reject message with Notify payload of type
415526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * INVALID_KE_PAYLOAD (RFC 4306, Sect. 3.4) */
416526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->error_type = INVALID_KE_PAYLOAD;
417526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->state = NOTIFY;
418526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
419526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
420526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
421526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->dh == NULL) {
422526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unsupported DH group");
423526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
424526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
425526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
426526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* RFC 4306, Section 3.4:
427526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * The length of DH public value MUST be equal to the lenght of the
428526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * prime modulus.
429526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 */
430526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (kei_len - 4 != data->dh->prime_len) {
431526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Invalid DH public value length "
432526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "%ld (expected %ld)",
433526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   (long) (kei_len - 4), (long) data->dh->prime_len);
434526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
435526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
436526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
437526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_free(data->i_dh_public);
438526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->i_dh_public = wpabuf_alloc(kei_len - 4);
439526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->i_dh_public == NULL)
440526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
441526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_put_data(data->i_dh_public, kei + 4, kei_len - 4);
442526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
443526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump_buf(MSG_DEBUG, "IKEV2: KEi Diffie-Hellman Public Value",
444526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			data->i_dh_public);
445526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
446526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
447526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
448526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
449526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
450526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int ikev2_process_ni(struct ikev2_responder_data *data,
451526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			    const u8 *ni, size_t ni_len)
452526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
453526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ni == NULL) {
454526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Ni not received");
455526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
456526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
457526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
458526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ni_len < IKEV2_NONCE_MIN_LEN || ni_len > IKEV2_NONCE_MAX_LEN) {
459526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Invalid Ni length %ld",
460526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		           (long) ni_len);
461526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
462526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
463526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
464526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CCNS_PL
465526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Zeros are removed incorrectly from the beginning of the nonces */
466526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	while (ni_len > 1 && *ni == 0) {
467526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ni_len--;
468526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ni++;
469526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
470526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CCNS_PL */
471526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
472526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->i_nonce_len = ni_len;
473526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(data->i_nonce, ni, ni_len);
474526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump(MSG_MSGDUMP, "IKEV2: Ni",
475526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    data->i_nonce, data->i_nonce_len);
476526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
477526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
478526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
479526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
480526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
481526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int ikev2_process_sa_init(struct ikev2_responder_data *data,
482526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				 const struct ikev2_hdr *hdr,
483526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				 struct ikev2_payloads *pl)
484526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
485526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ikev2_process_sai1(data, pl->sa, pl->sa_len) < 0 ||
486526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    ikev2_process_kei(data, pl->ke, pl->ke_len) < 0 ||
487526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    ikev2_process_ni(data, pl->nonce, pl->nonce_len) < 0)
488526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
489526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
490526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(data->i_spi, hdr->i_spi, IKEV2_SPI_LEN);
491526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
492526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
493526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
494526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
495526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
496526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int ikev2_process_idi(struct ikev2_responder_data *data,
497526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			     const u8 *idi, size_t idi_len)
498526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
499526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 id_type;
500526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
501526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (idi == NULL) {
502526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No IDi received");
503526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
504526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
505526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
506526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (idi_len < 4) {
507526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Too short IDi payload");
508526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
509526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
510526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
511526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	id_type = idi[0];
512526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	idi += 4;
513526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	idi_len -= 4;
514526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
515526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "IKEV2: IDi ID Type %d", id_type);
516526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "IKEV2: IDi", idi, idi_len);
517526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(data->IDi);
518526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->IDi = os_malloc(idi_len);
519526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->IDi == NULL)
520526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
521526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(data->IDi, idi, idi_len);
522526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->IDi_len = idi_len;
523526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->IDi_type = id_type;
524526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
525526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
526526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
527526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
528526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
529526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int ikev2_process_cert(struct ikev2_responder_data *data,
530526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			      const u8 *cert, size_t cert_len)
531526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
532526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 cert_encoding;
533526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
534526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (cert == NULL) {
535526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (data->peer_auth == PEER_AUTH_CERT) {
536526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_INFO, "IKEV2: No Certificate received");
537526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
538526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
539526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return 0;
540526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
541526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
542526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (cert_len < 1) {
543526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No Cert Encoding field");
544526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
545526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
546526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
547526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	cert_encoding = cert[0];
548526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	cert++;
549526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	cert_len--;
550526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
551526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "IKEV2: Cert Encoding %d", cert_encoding);
552526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump(MSG_MSGDUMP, "IKEV2: Certificate Data", cert, cert_len);
553526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
554526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* TODO: validate certificate */
555526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
556526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
557526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
558526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
559526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
560526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int ikev2_process_auth_cert(struct ikev2_responder_data *data,
561526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   u8 method, const u8 *auth, size_t auth_len)
562526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
563526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (method != AUTH_RSA_SIGN) {
564526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication "
565526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "method %d", method);
566526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
567526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
568526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
569526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* TODO: validate AUTH */
570526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
571526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
572526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
573526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
574526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int ikev2_process_auth_secret(struct ikev2_responder_data *data,
575526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				     u8 method, const u8 *auth,
576526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				     size_t auth_len)
577526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
578526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 auth_data[IKEV2_MAX_HASH_LEN];
579526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const struct ikev2_prf_alg *prf;
580526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
581526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (method != AUTH_SHARED_KEY_MIC) {
582526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication "
583526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "method %d", method);
584526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
585526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
586526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
587526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* msg | Nr | prf(SK_pi,IDi') */
588526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ikev2_derive_auth_data(data->proposal.prf, data->i_sign_msg,
589526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   data->IDi, data->IDi_len, data->IDi_type,
590526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   &data->keys, 1, data->shared_secret,
591526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   data->shared_secret_len,
592526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   data->r_nonce, data->r_nonce_len,
593526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   data->key_pad, data->key_pad_len,
594526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   auth_data) < 0) {
595526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data");
596526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
597526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
598526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
599526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_free(data->i_sign_msg);
600526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->i_sign_msg = NULL;
601526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
602526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	prf = ikev2_get_prf(data->proposal.prf);
603526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (prf == NULL)
604526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
605526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
606526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (auth_len != prf->hash_len ||
607526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    os_memcmp(auth, auth_data, auth_len) != 0) {
608526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Invalid Authentication Data");
609526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_hexdump(MSG_DEBUG, "IKEV2: Received Authentication Data",
610526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			    auth, auth_len);
611526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_hexdump(MSG_DEBUG, "IKEV2: Expected Authentication Data",
612526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			    auth_data, prf->hash_len);
613526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->error_type = AUTHENTICATION_FAILED;
614526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->state = NOTIFY;
615526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
616526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
617526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
618526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "IKEV2: Server authenticated successfully "
619526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   "using shared keys");
620526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
621526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
622526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
623526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
624526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
625526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int ikev2_process_auth(struct ikev2_responder_data *data,
626526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			      const u8 *auth, size_t auth_len)
627526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
628526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 auth_method;
629526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
630526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (auth == NULL) {
631526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No Authentication Payload");
632526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
633526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
634526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
635526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (auth_len < 4) {
636526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Too short Authentication "
637526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "Payload");
638526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
639526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
640526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
641526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	auth_method = auth[0];
642526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	auth += 4;
643526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	auth_len -= 4;
644526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
645526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "IKEV2: Auth Method %d", auth_method);
646526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump(MSG_MSGDUMP, "IKEV2: Authentication Data", auth, auth_len);
647526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
648526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	switch (data->peer_auth) {
649526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case PEER_AUTH_CERT:
650526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return ikev2_process_auth_cert(data, auth_method, auth,
651526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					       auth_len);
652526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case PEER_AUTH_SECRET:
653526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return ikev2_process_auth_secret(data, auth_method, auth,
654526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt						 auth_len);
655526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
656526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
657526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return -1;
658526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
659526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
660526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
661526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int ikev2_process_sa_auth_decrypted(struct ikev2_responder_data *data,
662526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					   u8 next_payload,
663526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					   u8 *payload, size_t payload_len)
664526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
665526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct ikev2_payloads pl;
666526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
667526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "IKEV2: Processing decrypted payloads");
668526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
669526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ikev2_parse_payloads(&pl, next_payload, payload, payload +
670526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				 payload_len) < 0) {
671526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Failed to parse decrypted "
672526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "payloads");
673526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
674526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
675526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
676526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ikev2_process_idi(data, pl.idi, pl.idi_len) < 0 ||
677526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    ikev2_process_cert(data, pl.cert, pl.cert_len) < 0 ||
678526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    ikev2_process_auth(data, pl.auth, pl.auth_len) < 0)
679526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
680526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
681526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
682526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
683526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
684526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
685526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int ikev2_process_sa_auth(struct ikev2_responder_data *data,
686526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				 const struct ikev2_hdr *hdr,
687526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				 struct ikev2_payloads *pl)
688526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
689526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *decrypted;
690526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t decrypted_len;
691526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int ret;
692526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
693526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	decrypted = ikev2_decrypt_payload(data->proposal.encr,
694526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					  data->proposal.integ,
695526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					  &data->keys, 1, hdr, pl->encrypted,
696526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					  pl->encrypted_len, &decrypted_len);
697526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (decrypted == NULL)
698526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
699526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
700526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ret = ikev2_process_sa_auth_decrypted(data, pl->encr_next_payload,
701526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					      decrypted, decrypted_len);
702526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(decrypted);
703526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
704526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return ret;
705526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
706526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
707526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
708526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int ikev2_validate_rx_state(struct ikev2_responder_data *data,
709526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   u8 exchange_type, u32 message_id)
710526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
711526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	switch (data->state) {
712526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case SA_INIT:
713526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		/* Expect to receive IKE_SA_INIT: HDR, SAi1, KEi, Ni */
714526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (exchange_type != IKE_SA_INIT) {
715526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type "
716526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "%u in SA_INIT state", exchange_type);
717526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
718526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
719526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (message_id != 0) {
720526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u "
721526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "in SA_INIT state", message_id);
722526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
723526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
724526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
725526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case SA_AUTH:
726526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		/* Expect to receive IKE_SA_AUTH:
727526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * HDR, SK {IDi, [CERT,] [CERTREQ,] [IDr,]
728526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 *	AUTH, SAi2, TSi, TSr}
729526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 */
730526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (exchange_type != IKE_SA_AUTH) {
731526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type "
732526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "%u in SA_AUTH state", exchange_type);
733526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
734526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
735526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (message_id != 1) {
736526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u "
737526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "in SA_AUTH state", message_id);
738526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
739526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
740526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
741526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case CHILD_SA:
742526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (exchange_type != CREATE_CHILD_SA) {
743526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type "
744526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "%u in CHILD_SA state", exchange_type);
745526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
746526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
747526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (message_id != 2) {
748526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u "
749526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "in CHILD_SA state", message_id);
750526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
751526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
752526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
753526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case NOTIFY:
754526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case IKEV2_DONE:
755526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case IKEV2_FAILED:
756526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
757526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
758526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
759526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
760526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
761526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
762526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
763526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint ikev2_responder_process(struct ikev2_responder_data *data,
764526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			    const struct wpabuf *buf)
765526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
766526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const struct ikev2_hdr *hdr;
767526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u32 length, message_id;
768526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *pos, *end;
769526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct ikev2_payloads pl;
770526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
771526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_MSGDUMP, "IKEV2: Received message (len %lu)",
772526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   (unsigned long) wpabuf_len(buf));
773526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
774526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (wpabuf_len(buf) < sizeof(*hdr)) {
775526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Too short frame to include HDR");
776526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
777526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
778526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
779526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->error_type = 0;
780526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	hdr = (const struct ikev2_hdr *) wpabuf_head(buf);
781526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	end = wpabuf_head_u8(buf) + wpabuf_len(buf);
782526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	message_id = WPA_GET_BE32(hdr->message_id);
783526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	length = WPA_GET_BE32(hdr->length);
784526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
785526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "IKEV2:   IKE_SA Initiator's SPI",
786526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    hdr->i_spi, IKEV2_SPI_LEN);
787526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "IKEV2:   IKE_SA Responder's SPI",
788526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    hdr->r_spi, IKEV2_SPI_LEN);
789526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "IKEV2:   Next Payload: %u  Version: 0x%x  "
790526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   "Exchange Type: %u",
791526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   hdr->next_payload, hdr->version, hdr->exchange_type);
792526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "IKEV2:   Message ID: %u  Length: %u",
793526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   message_id, length);
794526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
795526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (hdr->version != IKEV2_VERSION) {
796526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unsupported HDR version 0x%x "
797526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "(expected 0x%x)", hdr->version, IKEV2_VERSION);
798526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
799526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
800526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
801526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (length != wpabuf_len(buf)) {
802526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Invalid length (HDR: %lu != "
803526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "RX: %lu)", (unsigned long) length,
804526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   (unsigned long) wpabuf_len(buf));
805526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
806526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
807526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
808526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ikev2_validate_rx_state(data, hdr->exchange_type, message_id) < 0)
809526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
810526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
811526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if ((hdr->flags & (IKEV2_HDR_INITIATOR | IKEV2_HDR_RESPONSE)) !=
812526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    IKEV2_HDR_INITIATOR) {
813526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unexpected Flags value 0x%x",
814526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   hdr->flags);
815526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
816526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
817526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
818526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->state != SA_INIT) {
819526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (os_memcmp(data->i_spi, hdr->i_spi, IKEV2_SPI_LEN) != 0) {
820526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA "
821526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "Initiator's SPI");
822526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
823526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
824526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (os_memcmp(data->r_spi, hdr->r_spi, IKEV2_SPI_LEN) != 0) {
825526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA "
826526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "Responder's SPI");
827526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
828526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
829526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
830526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
831526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos = (const u8 *) (hdr + 1);
832526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ikev2_parse_payloads(&pl, hdr->next_payload, pos, end) < 0)
833526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
834526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
835526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->state == SA_INIT) {
836526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->last_msg = LAST_MSG_SA_INIT;
837526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (ikev2_process_sa_init(data, hdr, &pl) < 0) {
838526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			if (data->state == NOTIFY)
839526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				return 0;
840526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
841526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
842526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpabuf_free(data->i_sign_msg);
843526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->i_sign_msg = wpabuf_dup(buf);
844526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
845526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
846526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->state == SA_AUTH) {
847526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->last_msg = LAST_MSG_SA_AUTH;
848526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (ikev2_process_sa_auth(data, hdr, &pl) < 0) {
849526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			if (data->state == NOTIFY)
850526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				return 0;
851526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
852526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
853526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
854526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
855526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
856526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
857526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
858526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
859526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void ikev2_build_hdr(struct ikev2_responder_data *data,
860526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			    struct wpabuf *msg, u8 exchange_type,
861526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			    u8 next_payload, u32 message_id)
862526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
863526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct ikev2_hdr *hdr;
864526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
865526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "IKEV2: Adding HDR");
866526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
867526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* HDR - RFC 4306, Sect. 3.1 */
868526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	hdr = wpabuf_put(msg, sizeof(*hdr));
869526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(hdr->i_spi, data->i_spi, IKEV2_SPI_LEN);
870526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(hdr->r_spi, data->r_spi, IKEV2_SPI_LEN);
871526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	hdr->next_payload = next_payload;
872526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	hdr->version = IKEV2_VERSION;
873526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	hdr->exchange_type = exchange_type;
874526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	hdr->flags = IKEV2_HDR_RESPONSE;
875526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	WPA_PUT_BE32(hdr->message_id, message_id);
876526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
877526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
878526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
879526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int ikev2_build_sar1(struct ikev2_responder_data *data,
880526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			    struct wpabuf *msg, u8 next_payload)
881526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
882526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct ikev2_payload_hdr *phdr;
883526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t plen;
884526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct ikev2_proposal *p;
885526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct ikev2_transform *t;
886526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
887526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "IKEV2: Adding SAr1 payload");
888526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
889526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* SAr1 - RFC 4306, Sect. 2.7 and 3.3 */
890526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	phdr = wpabuf_put(msg, sizeof(*phdr));
891526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	phdr->next_payload = next_payload;
892526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	phdr->flags = 0;
893526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
894526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	p = wpabuf_put(msg, sizeof(*p));
895526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CCNS_PL
896526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Seems to require that the Proposal # is 1 even though RFC 4306
897526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * Sect 3.3.1 has following requirement "When a proposal is accepted,
898526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * all of the proposal numbers in the SA payload MUST be the same and
899526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * MUST match the number on the proposal sent that was accepted.".
900526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 */
901526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	p->proposal_num = 1;
902526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#else /* CCNS_PL */
903526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	p->proposal_num = data->proposal.proposal_num;
904526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CCNS_PL */
905526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	p->protocol_id = IKEV2_PROTOCOL_IKE;
906526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	p->num_transforms = 4;
907526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
908526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	t = wpabuf_put(msg, sizeof(*t));
909526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	t->type = 3;
910526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	t->transform_type = IKEV2_TRANSFORM_ENCR;
911526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	WPA_PUT_BE16(t->transform_id, data->proposal.encr);
912526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->proposal.encr == ENCR_AES_CBC) {
913526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		/* Transform Attribute: Key Len = 128 bits */
914526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CCNS_PL
915526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpabuf_put_be16(msg, 0x001d); /* ?? */
916526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#else /* CCNS_PL */
917526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpabuf_put_be16(msg, 0x800e); /* AF=1, AttrType=14 */
918526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CCNS_PL */
919526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpabuf_put_be16(msg, 128); /* 128-bit key */
920526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
921526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) t;
922526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	WPA_PUT_BE16(t->transform_length, plen);
923526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
924526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	t = wpabuf_put(msg, sizeof(*t));
925526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	t->type = 3;
926526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	WPA_PUT_BE16(t->transform_length, sizeof(*t));
927526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	t->transform_type = IKEV2_TRANSFORM_PRF;
928526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	WPA_PUT_BE16(t->transform_id, data->proposal.prf);
929526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
930526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	t = wpabuf_put(msg, sizeof(*t));
931526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	t->type = 3;
932526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	WPA_PUT_BE16(t->transform_length, sizeof(*t));
933526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	t->transform_type = IKEV2_TRANSFORM_INTEG;
934526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	WPA_PUT_BE16(t->transform_id, data->proposal.integ);
935526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
936526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	t = wpabuf_put(msg, sizeof(*t));
937526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	WPA_PUT_BE16(t->transform_length, sizeof(*t));
938526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	t->transform_type = IKEV2_TRANSFORM_DH;
939526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	WPA_PUT_BE16(t->transform_id, data->proposal.dh);
940526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
941526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) p;
942526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	WPA_PUT_BE16(p->proposal_length, plen);
943526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
944526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
945526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	WPA_PUT_BE16(phdr->payload_length, plen);
946526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
947526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
948526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
949526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
950526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
951526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int ikev2_build_ker(struct ikev2_responder_data *data,
952526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   struct wpabuf *msg, u8 next_payload)
953526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
954526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct ikev2_payload_hdr *phdr;
955526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t plen;
956526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wpabuf *pv;
957526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
958526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "IKEV2: Adding KEr payload");
959526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
960526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pv = dh_init(data->dh, &data->r_dh_private);
961526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (pv == NULL) {
962526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "IKEV2: Failed to initialize DH");
963526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
964526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
965526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
966526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* KEr - RFC 4306, Sect. 3.4 */
967526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	phdr = wpabuf_put(msg, sizeof(*phdr));
968526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	phdr->next_payload = next_payload;
969526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	phdr->flags = 0;
970526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
971526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_put_be16(msg, data->proposal.dh); /* DH Group # */
972526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_put(msg, 2); /* RESERVED */
973526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/*
974526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * RFC 4306, Sect. 3.4: possible zero padding for public value to
975526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * match the length of the prime.
976526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 */
977526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_put(msg, data->dh->prime_len - wpabuf_len(pv));
978526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_put_buf(msg, pv);
979526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_free(pv);
980526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
981526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
982526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	WPA_PUT_BE16(phdr->payload_length, plen);
983526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
984526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
985526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
986526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
987526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int ikev2_build_nr(struct ikev2_responder_data *data,
988526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  struct wpabuf *msg, u8 next_payload)
989526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
990526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct ikev2_payload_hdr *phdr;
991526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t plen;
992526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
993526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "IKEV2: Adding Nr payload");
994526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
995526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Nr - RFC 4306, Sect. 3.9 */
996526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	phdr = wpabuf_put(msg, sizeof(*phdr));
997526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	phdr->next_payload = next_payload;
998526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	phdr->flags = 0;
999526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_put_data(msg, data->r_nonce, data->r_nonce_len);
1000526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
1001526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	WPA_PUT_BE16(phdr->payload_length, plen);
1002526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
1003526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1004526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1005526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1006526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int ikev2_build_idr(struct ikev2_responder_data *data,
1007526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   struct wpabuf *msg, u8 next_payload)
1008526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
1009526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct ikev2_payload_hdr *phdr;
1010526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t plen;
1011526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1012526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "IKEV2: Adding IDr payload");
1013526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1014526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->IDr == NULL) {
1015526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No IDr available");
1016526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
1017526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1018526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1019526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* IDr - RFC 4306, Sect. 3.5 */
1020526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	phdr = wpabuf_put(msg, sizeof(*phdr));
1021526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	phdr->next_payload = next_payload;
1022526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	phdr->flags = 0;
1023526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_put_u8(msg, ID_KEY_ID);
1024526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_put(msg, 3); /* RESERVED */
1025526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_put_data(msg, data->IDr, data->IDr_len);
1026526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
1027526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	WPA_PUT_BE16(phdr->payload_length, plen);
1028526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
1029526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1030526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1031526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1032526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int ikev2_build_auth(struct ikev2_responder_data *data,
1033526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			    struct wpabuf *msg, u8 next_payload)
1034526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
1035526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct ikev2_payload_hdr *phdr;
1036526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t plen;
1037526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const struct ikev2_prf_alg *prf;
1038526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1039526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "IKEV2: Adding AUTH payload");
1040526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1041526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	prf = ikev2_get_prf(data->proposal.prf);
1042526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (prf == NULL)
1043526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
1044526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1045526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Authentication - RFC 4306, Sect. 3.8 */
1046526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	phdr = wpabuf_put(msg, sizeof(*phdr));
1047526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	phdr->next_payload = next_payload;
1048526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	phdr->flags = 0;
1049526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_put_u8(msg, AUTH_SHARED_KEY_MIC);
1050526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_put(msg, 3); /* RESERVED */
1051526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1052526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* msg | Ni | prf(SK_pr,IDr') */
1053526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ikev2_derive_auth_data(data->proposal.prf, data->r_sign_msg,
1054526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   data->IDr, data->IDr_len, ID_KEY_ID,
1055526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   &data->keys, 0, data->shared_secret,
1056526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   data->shared_secret_len,
1057526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   data->i_nonce, data->i_nonce_len,
1058526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   data->key_pad, data->key_pad_len,
1059526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   wpabuf_put(msg, prf->hash_len)) < 0) {
1060526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data");
1061526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
1062526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1063526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_free(data->r_sign_msg);
1064526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->r_sign_msg = NULL;
1065526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1066526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
1067526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	WPA_PUT_BE16(phdr->payload_length, plen);
1068526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
1069526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1070526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1071526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1072526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int ikev2_build_notification(struct ikev2_responder_data *data,
1073526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				    struct wpabuf *msg, u8 next_payload)
1074526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
1075526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct ikev2_payload_hdr *phdr;
1076526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t plen;
1077526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1078526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "IKEV2: Adding Notification payload");
1079526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1080526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->error_type == 0) {
1081526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: No Notify Message Type "
1082526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "available");
1083526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
1084526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1085526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1086526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Notify - RFC 4306, Sect. 3.10 */
1087526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	phdr = wpabuf_put(msg, sizeof(*phdr));
1088526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	phdr->next_payload = next_payload;
1089526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	phdr->flags = 0;
1090526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CCNS_PL
1091526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_put_u8(msg, 1); /* Protocol ID: IKE_SA notification */
1092526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#else /* CCNS_PL */
1093526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_put_u8(msg, 0); /* Protocol ID: no existing SA */
1094526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CCNS_PL */
1095526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_put_u8(msg, 0); /* SPI Size */
1096526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_put_be16(msg, data->error_type);
1097526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1098526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	switch (data->error_type) {
1099526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case INVALID_KE_PAYLOAD:
1100526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (data->proposal.dh == -1) {
1101526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_INFO, "IKEV2: No DH Group selected for "
1102526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "INVALID_KE_PAYLOAD notifications");
1103526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
1104526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
1105526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpabuf_put_be16(msg, data->proposal.dh);
1106526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "IKEV2: INVALID_KE_PAYLOAD - request "
1107526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "DH Group #%d", data->proposal.dh);
1108526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
1109526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case AUTHENTICATION_FAILED:
1110526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		/* no associated data */
1111526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
1112526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	default:
1113526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_INFO, "IKEV2: Unsupported Notify Message Type "
1114526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   "%d", data->error_type);
1115526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
1116526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1117526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1118526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
1119526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	WPA_PUT_BE16(phdr->payload_length, plen);
1120526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
1121526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1122526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1123526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1124526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * ikev2_build_sa_init(struct ikev2_responder_data *data)
1125526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
1126526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wpabuf *msg;
1127526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1128526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* build IKE_SA_INIT: HDR, SAr1, KEr, Nr, [CERTREQ], [SK{IDr}] */
1129526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1130526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (os_get_random(data->r_spi, IKEV2_SPI_LEN))
1131526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
1132526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Responder's SPI",
1133526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    data->r_spi, IKEV2_SPI_LEN);
1134526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1135526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->r_nonce_len = IKEV2_NONCE_MIN_LEN;
1136526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (os_get_random(data->r_nonce, data->r_nonce_len))
1137526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
1138526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CCNS_PL
1139526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* Zeros are removed incorrectly from the beginning of the nonces in
1140526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * key derivation; as a workaround, make sure Nr does not start with
1141526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * zero.. */
1142526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->r_nonce[0] == 0)
1143526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->r_nonce[0] = 1;
1144526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CCNS_PL */
1145526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "IKEV2: Nr", data->r_nonce, data->r_nonce_len);
1146526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1147526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1500);
1148526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (msg == NULL)
1149526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
1150526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1151526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ikev2_build_hdr(data, msg, IKE_SA_INIT, IKEV2_PAYLOAD_SA, 0);
1152526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ikev2_build_sar1(data, msg, IKEV2_PAYLOAD_KEY_EXCHANGE) ||
1153526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    ikev2_build_ker(data, msg, IKEV2_PAYLOAD_NONCE) ||
1154526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    ikev2_build_nr(data, msg, data->peer_auth == PEER_AUTH_SECRET ?
1155526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   IKEV2_PAYLOAD_ENCRYPTED :
1156526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) {
1157526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpabuf_free(msg);
1158526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
1159526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1160526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1161526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ikev2_derive_keys(data)) {
1162526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpabuf_free(msg);
1163526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
1164526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1165526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1166526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->peer_auth == PEER_AUTH_CERT) {
1167526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		/* TODO: CERTREQ with SHA-1 hashes of Subject Public Key Info
1168526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		 * for trust agents */
1169526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1170526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1171526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->peer_auth == PEER_AUTH_SECRET) {
1172526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		struct wpabuf *plain = wpabuf_alloc(data->IDr_len + 1000);
1173526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (plain == NULL) {
1174526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpabuf_free(msg);
1175526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return NULL;
1176526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
1177526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (ikev2_build_idr(data, plain,
1178526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				    IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) ||
1179526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    ikev2_build_encrypted(data->proposal.encr,
1180526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					  data->proposal.integ,
1181526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					  &data->keys, 0, msg, plain,
1182526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					  IKEV2_PAYLOAD_IDr)) {
1183526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpabuf_free(plain);
1184526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpabuf_free(msg);
1185526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return NULL;
1186526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
1187526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpabuf_free(plain);
1188526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1189526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1190526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ikev2_update_hdr(msg);
1191526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1192526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_INIT)", msg);
1193526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1194526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->state = SA_AUTH;
1195526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1196526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_free(data->r_sign_msg);
1197526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->r_sign_msg = wpabuf_dup(msg);
1198526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1199526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return msg;
1200526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1201526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1202526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1203526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * ikev2_build_sa_auth(struct ikev2_responder_data *data)
1204526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
1205526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wpabuf *msg, *plain;
1206526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1207526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* build IKE_SA_AUTH: HDR, SK {IDr, [CERT,] AUTH} */
1208526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1209526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1000);
1210526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (msg == NULL)
1211526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
1212526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ikev2_build_hdr(data, msg, IKE_SA_AUTH, IKEV2_PAYLOAD_ENCRYPTED, 1);
1213526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1214526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	plain = wpabuf_alloc(data->IDr_len + 1000);
1215526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (plain == NULL) {
1216526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpabuf_free(msg);
1217526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
1218526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1219526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1220526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ikev2_build_idr(data, plain, IKEV2_PAYLOAD_AUTHENTICATION) ||
1221526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    ikev2_build_auth(data, plain, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) ||
1222526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    ikev2_build_encrypted(data->proposal.encr, data->proposal.integ,
1223526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  &data->keys, 0, msg, plain,
1224526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				  IKEV2_PAYLOAD_IDr)) {
1225526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpabuf_free(plain);
1226526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpabuf_free(msg);
1227526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
1228526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1229526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpabuf_free(plain);
1230526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1231526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_AUTH)", msg);
1232526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1233526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->state = IKEV2_DONE;
1234526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1235526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return msg;
1236526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1237526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1238526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1239526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct wpabuf * ikev2_build_notify(struct ikev2_responder_data *data)
1240526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
1241526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	struct wpabuf *msg;
1242526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1243526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + 1000);
1244526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (msg == NULL)
1245526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
1246526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (data->last_msg == LAST_MSG_SA_AUTH) {
1247526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		/* HDR, SK{N} */
1248526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		struct wpabuf *plain = wpabuf_alloc(100);
1249526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (plain == NULL) {
1250526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpabuf_free(msg);
1251526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return NULL;
1252526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
1253526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ikev2_build_hdr(data, msg, IKE_SA_AUTH,
1254526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				IKEV2_PAYLOAD_ENCRYPTED, 1);
1255526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (ikev2_build_notification(data, plain,
1256526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					     IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) ||
1257526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    ikev2_build_encrypted(data->proposal.encr,
1258526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					  data->proposal.integ,
1259526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					  &data->keys, 0, msg, plain,
1260526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					  IKEV2_PAYLOAD_NOTIFICATION)) {
1261526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpabuf_free(plain);
1262526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpabuf_free(msg);
1263526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return NULL;
1264526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
1265526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->state = IKEV2_FAILED;
1266526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else {
1267526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		/* HDR, N */
1268526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		ikev2_build_hdr(data, msg, IKE_SA_INIT,
1269526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				IKEV2_PAYLOAD_NOTIFICATION, 0);
1270526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (ikev2_build_notification(data, msg,
1271526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt					     IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) {
1272526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpabuf_free(msg);
1273526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return NULL;
1274526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
1275526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->state = SA_INIT;
1276526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1277526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1278526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	ikev2_update_hdr(msg);
1279526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1280526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (Notification)",
1281526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			msg);
1282526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1283526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return msg;
1284526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1285526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1286526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
1287526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct wpabuf * ikev2_responder_build(struct ikev2_responder_data *data)
1288526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
1289526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	switch (data->state) {
1290526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case SA_INIT:
1291526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return ikev2_build_sa_init(data);
1292526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case SA_AUTH:
1293526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return ikev2_build_sa_auth(data);
1294526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case CHILD_SA:
1295526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
1296526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case NOTIFY:
1297526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return ikev2_build_notify(data);
1298526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case IKEV2_DONE:
1299526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case IKEV2_FAILED:
1300526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return NULL;
1301526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
1302526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return NULL;
1303526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
1304