1214501Srpaulo/*
2214501Srpaulo * EAP-IKEv2 server (RFC 5106)
3214501Srpaulo * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
4214501Srpaulo *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7214501Srpaulo */
8214501Srpaulo
9214501Srpaulo#include "includes.h"
10214501Srpaulo
11214501Srpaulo#include "common.h"
12214501Srpaulo#include "eap_i.h"
13214501Srpaulo#include "eap_common/eap_ikev2_common.h"
14214501Srpaulo#include "ikev2.h"
15214501Srpaulo
16214501Srpaulo
17214501Srpaulostruct eap_ikev2_data {
18214501Srpaulo	struct ikev2_initiator_data ikev2;
19214501Srpaulo	enum { MSG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state;
20214501Srpaulo	struct wpabuf *in_buf;
21214501Srpaulo	struct wpabuf *out_buf;
22214501Srpaulo	size_t out_used;
23214501Srpaulo	size_t fragment_size;
24214501Srpaulo	int keys_ready;
25214501Srpaulo	u8 keymat[EAP_MSK_LEN + EAP_EMSK_LEN];
26214501Srpaulo	int keymat_ok;
27214501Srpaulo};
28214501Srpaulo
29214501Srpaulo
30214501Srpaulostatic const u8 * eap_ikev2_get_shared_secret(void *ctx, const u8 *IDr,
31214501Srpaulo					      size_t IDr_len,
32214501Srpaulo					      size_t *secret_len)
33214501Srpaulo{
34214501Srpaulo	struct eap_sm *sm = ctx;
35214501Srpaulo
36214501Srpaulo	if (IDr == NULL) {
37214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-IKEV2: No IDr received - default "
38214501Srpaulo			   "to user identity from EAP-Identity");
39214501Srpaulo		IDr = sm->identity;
40214501Srpaulo		IDr_len = sm->identity_len;
41214501Srpaulo	}
42214501Srpaulo
43214501Srpaulo	if (eap_user_get(sm, IDr, IDr_len, 0) < 0 || sm->user == NULL ||
44214501Srpaulo	    sm->user->password == NULL) {
45214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-IKEV2: No user entry found");
46214501Srpaulo		return NULL;
47214501Srpaulo	}
48214501Srpaulo
49214501Srpaulo	*secret_len = sm->user->password_len;
50214501Srpaulo	return sm->user->password;
51214501Srpaulo}
52214501Srpaulo
53214501Srpaulo
54214501Srpaulostatic const char * eap_ikev2_state_txt(int state)
55214501Srpaulo{
56214501Srpaulo	switch (state) {
57214501Srpaulo	case MSG:
58214501Srpaulo		return "MSG";
59214501Srpaulo	case FRAG_ACK:
60214501Srpaulo		return "FRAG_ACK";
61214501Srpaulo	case WAIT_FRAG_ACK:
62214501Srpaulo		return "WAIT_FRAG_ACK";
63214501Srpaulo	case DONE:
64214501Srpaulo		return "DONE";
65214501Srpaulo	case FAIL:
66214501Srpaulo		return "FAIL";
67214501Srpaulo	default:
68214501Srpaulo		return "?";
69214501Srpaulo	}
70214501Srpaulo}
71214501Srpaulo
72214501Srpaulo
73214501Srpaulostatic void eap_ikev2_state(struct eap_ikev2_data *data, int state)
74214501Srpaulo{
75214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-IKEV2: %s -> %s",
76214501Srpaulo		   eap_ikev2_state_txt(data->state),
77214501Srpaulo		   eap_ikev2_state_txt(state));
78214501Srpaulo	data->state = state;
79214501Srpaulo}
80214501Srpaulo
81214501Srpaulo
82214501Srpaulostatic void * eap_ikev2_init(struct eap_sm *sm)
83214501Srpaulo{
84214501Srpaulo	struct eap_ikev2_data *data;
85214501Srpaulo
86214501Srpaulo	data = os_zalloc(sizeof(*data));
87214501Srpaulo	if (data == NULL)
88214501Srpaulo		return NULL;
89214501Srpaulo	data->state = MSG;
90252726Srpaulo	data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size :
91252726Srpaulo		IKEV2_FRAGMENT_SIZE;
92214501Srpaulo	data->ikev2.state = SA_INIT;
93214501Srpaulo	data->ikev2.peer_auth = PEER_AUTH_SECRET;
94214501Srpaulo	data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2");
95214501Srpaulo	if (data->ikev2.key_pad == NULL)
96214501Srpaulo		goto failed;
97214501Srpaulo	data->ikev2.key_pad_len = 21;
98214501Srpaulo
99214501Srpaulo	/* TODO: make proposals configurable */
100214501Srpaulo	data->ikev2.proposal.proposal_num = 1;
101214501Srpaulo	data->ikev2.proposal.integ = AUTH_HMAC_SHA1_96;
102214501Srpaulo	data->ikev2.proposal.prf = PRF_HMAC_SHA1;
103214501Srpaulo	data->ikev2.proposal.encr = ENCR_AES_CBC;
104214501Srpaulo	data->ikev2.proposal.dh = DH_GROUP2_1024BIT_MODP;
105214501Srpaulo
106214501Srpaulo	data->ikev2.IDi = (u8 *) os_strdup("hostapd");
107214501Srpaulo	data->ikev2.IDi_len = 7;
108214501Srpaulo
109214501Srpaulo	data->ikev2.get_shared_secret = eap_ikev2_get_shared_secret;
110214501Srpaulo	data->ikev2.cb_ctx = sm;
111214501Srpaulo
112214501Srpaulo	return data;
113214501Srpaulo
114214501Srpaulofailed:
115214501Srpaulo	ikev2_initiator_deinit(&data->ikev2);
116214501Srpaulo	os_free(data);
117214501Srpaulo	return NULL;
118214501Srpaulo}
119214501Srpaulo
120214501Srpaulo
121214501Srpaulostatic void eap_ikev2_reset(struct eap_sm *sm, void *priv)
122214501Srpaulo{
123214501Srpaulo	struct eap_ikev2_data *data = priv;
124214501Srpaulo	wpabuf_free(data->in_buf);
125214501Srpaulo	wpabuf_free(data->out_buf);
126214501Srpaulo	ikev2_initiator_deinit(&data->ikev2);
127214501Srpaulo	os_free(data);
128214501Srpaulo}
129214501Srpaulo
130214501Srpaulo
131214501Srpaulostatic struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data, u8 id)
132214501Srpaulo{
133214501Srpaulo	struct wpabuf *req;
134214501Srpaulo	u8 flags;
135214501Srpaulo	size_t send_len, plen, icv_len = 0;
136214501Srpaulo
137214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Generating Request");
138214501Srpaulo
139214501Srpaulo	flags = 0;
140214501Srpaulo	send_len = wpabuf_len(data->out_buf) - data->out_used;
141214501Srpaulo	if (1 + send_len > data->fragment_size) {
142214501Srpaulo		send_len = data->fragment_size - 1;
143214501Srpaulo		flags |= IKEV2_FLAGS_MORE_FRAGMENTS;
144214501Srpaulo		if (data->out_used == 0) {
145214501Srpaulo			flags |= IKEV2_FLAGS_LENGTH_INCLUDED;
146214501Srpaulo			send_len -= 4;
147214501Srpaulo		}
148214501Srpaulo	}
149214501Srpaulo
150214501Srpaulo	plen = 1 + send_len;
151214501Srpaulo	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED)
152214501Srpaulo		plen += 4;
153214501Srpaulo	if (data->keys_ready) {
154214501Srpaulo		const struct ikev2_integ_alg *integ;
155214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Add Integrity Checksum "
156214501Srpaulo			   "Data");
157214501Srpaulo		flags |= IKEV2_FLAGS_ICV_INCLUDED;
158214501Srpaulo		integ = ikev2_get_integ(data->ikev2.proposal.integ);
159214501Srpaulo		if (integ == NULL) {
160214501Srpaulo			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG "
161214501Srpaulo				   "transform / cannot generate ICV");
162214501Srpaulo			return NULL;
163214501Srpaulo		}
164214501Srpaulo		icv_len = integ->hash_len;
165214501Srpaulo
166214501Srpaulo		plen += icv_len;
167214501Srpaulo	}
168214501Srpaulo	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, plen,
169214501Srpaulo			    EAP_CODE_REQUEST, id);
170214501Srpaulo	if (req == NULL)
171214501Srpaulo		return NULL;
172214501Srpaulo
173214501Srpaulo	wpabuf_put_u8(req, flags); /* Flags */
174214501Srpaulo	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED)
175214501Srpaulo		wpabuf_put_be32(req, wpabuf_len(data->out_buf));
176214501Srpaulo
177214501Srpaulo	wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used,
178214501Srpaulo			send_len);
179214501Srpaulo	data->out_used += send_len;
180214501Srpaulo
181214501Srpaulo	if (flags & IKEV2_FLAGS_ICV_INCLUDED) {
182214501Srpaulo		const u8 *msg = wpabuf_head(req);
183214501Srpaulo		size_t len = wpabuf_len(req);
184214501Srpaulo		ikev2_integ_hash(data->ikev2.proposal.integ,
185214501Srpaulo				 data->ikev2.keys.SK_ai,
186214501Srpaulo				 data->ikev2.keys.SK_integ_len,
187214501Srpaulo				 msg, len, wpabuf_put(req, icv_len));
188214501Srpaulo	}
189214501Srpaulo
190214501Srpaulo	if (data->out_used == wpabuf_len(data->out_buf)) {
191214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes "
192214501Srpaulo			   "(message sent completely)",
193214501Srpaulo			   (unsigned long) send_len);
194214501Srpaulo		wpabuf_free(data->out_buf);
195214501Srpaulo		data->out_buf = NULL;
196214501Srpaulo		data->out_used = 0;
197214501Srpaulo	} else {
198214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes "
199214501Srpaulo			   "(%lu more to send)", (unsigned long) send_len,
200214501Srpaulo			   (unsigned long) wpabuf_len(data->out_buf) -
201214501Srpaulo			   data->out_used);
202214501Srpaulo		eap_ikev2_state(data, WAIT_FRAG_ACK);
203214501Srpaulo	}
204214501Srpaulo
205214501Srpaulo	return req;
206214501Srpaulo}
207214501Srpaulo
208214501Srpaulo
209214501Srpaulostatic struct wpabuf * eap_ikev2_buildReq(struct eap_sm *sm, void *priv, u8 id)
210214501Srpaulo{
211214501Srpaulo	struct eap_ikev2_data *data = priv;
212214501Srpaulo
213214501Srpaulo	switch (data->state) {
214214501Srpaulo	case MSG:
215214501Srpaulo		if (data->out_buf == NULL) {
216214501Srpaulo			data->out_buf = ikev2_initiator_build(&data->ikev2);
217214501Srpaulo			if (data->out_buf == NULL) {
218214501Srpaulo				wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to "
219214501Srpaulo					   "generate IKEv2 message");
220214501Srpaulo				return NULL;
221214501Srpaulo			}
222214501Srpaulo			data->out_used = 0;
223214501Srpaulo		}
224214501Srpaulo		/* pass through */
225214501Srpaulo	case WAIT_FRAG_ACK:
226214501Srpaulo		return eap_ikev2_build_msg(data, id);
227214501Srpaulo	case FRAG_ACK:
228214501Srpaulo		return eap_ikev2_build_frag_ack(id, EAP_CODE_REQUEST);
229214501Srpaulo	default:
230214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected state %d in "
231214501Srpaulo			   "buildReq", data->state);
232214501Srpaulo		return NULL;
233214501Srpaulo	}
234214501Srpaulo}
235214501Srpaulo
236214501Srpaulo
237214501Srpaulostatic Boolean eap_ikev2_check(struct eap_sm *sm, void *priv,
238214501Srpaulo			       struct wpabuf *respData)
239214501Srpaulo{
240214501Srpaulo	const u8 *pos;
241214501Srpaulo	size_t len;
242214501Srpaulo
243214501Srpaulo	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, respData,
244214501Srpaulo			       &len);
245214501Srpaulo	if (pos == NULL) {
246214501Srpaulo		wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid frame");
247214501Srpaulo		return TRUE;
248214501Srpaulo	}
249214501Srpaulo
250214501Srpaulo	return FALSE;
251214501Srpaulo}
252214501Srpaulo
253214501Srpaulo
254214501Srpaulostatic int eap_ikev2_process_icv(struct eap_ikev2_data *data,
255214501Srpaulo				 const struct wpabuf *respData,
256214501Srpaulo				 u8 flags, const u8 *pos, const u8 **end)
257214501Srpaulo{
258214501Srpaulo	if (flags & IKEV2_FLAGS_ICV_INCLUDED) {
259214501Srpaulo		int icv_len = eap_ikev2_validate_icv(
260214501Srpaulo			data->ikev2.proposal.integ, &data->ikev2.keys, 0,
261214501Srpaulo			respData, pos, *end);
262214501Srpaulo		if (icv_len < 0)
263214501Srpaulo			return -1;
264214501Srpaulo		/* Hide Integrity Checksum Data from further processing */
265214501Srpaulo		*end -= icv_len;
266214501Srpaulo	} else if (data->keys_ready) {
267214501Srpaulo		wpa_printf(MSG_INFO, "EAP-IKEV2: The message should have "
268214501Srpaulo			   "included integrity checksum");
269214501Srpaulo		return -1;
270214501Srpaulo	}
271214501Srpaulo
272214501Srpaulo	return 0;
273214501Srpaulo}
274214501Srpaulo
275214501Srpaulo
276214501Srpaulostatic int eap_ikev2_process_cont(struct eap_ikev2_data *data,
277214501Srpaulo				  const u8 *buf, size_t len)
278214501Srpaulo{
279214501Srpaulo	/* Process continuation of a pending message */
280214501Srpaulo	if (len > wpabuf_tailroom(data->in_buf)) {
281214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment overflow");
282214501Srpaulo		eap_ikev2_state(data, FAIL);
283214501Srpaulo		return -1;
284214501Srpaulo	}
285214501Srpaulo
286214501Srpaulo	wpabuf_put_data(data->in_buf, buf, len);
287214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes, waiting for %lu "
288214501Srpaulo		   "bytes more", (unsigned long) len,
289214501Srpaulo		   (unsigned long) wpabuf_tailroom(data->in_buf));
290214501Srpaulo
291214501Srpaulo	return 0;
292214501Srpaulo}
293214501Srpaulo
294214501Srpaulo
295214501Srpaulostatic int eap_ikev2_process_fragment(struct eap_ikev2_data *data,
296214501Srpaulo				      u8 flags, u32 message_length,
297214501Srpaulo				      const u8 *buf, size_t len)
298214501Srpaulo{
299214501Srpaulo	/* Process a fragment that is not the last one of the message */
300214501Srpaulo	if (data->in_buf == NULL && !(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) {
301214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-IKEV2: No Message Length field in "
302214501Srpaulo			   "a fragmented packet");
303214501Srpaulo		return -1;
304214501Srpaulo	}
305214501Srpaulo
306214501Srpaulo	if (data->in_buf == NULL) {
307214501Srpaulo		/* First fragment of the message */
308214501Srpaulo		data->in_buf = wpabuf_alloc(message_length);
309214501Srpaulo		if (data->in_buf == NULL) {
310214501Srpaulo			wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for "
311214501Srpaulo				   "message");
312214501Srpaulo			return -1;
313214501Srpaulo		}
314214501Srpaulo		wpabuf_put_data(data->in_buf, buf, len);
315214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes in first "
316214501Srpaulo			   "fragment, waiting for %lu bytes more",
317214501Srpaulo			   (unsigned long) len,
318214501Srpaulo			   (unsigned long) wpabuf_tailroom(data->in_buf));
319214501Srpaulo	}
320214501Srpaulo
321214501Srpaulo	return 0;
322214501Srpaulo}
323214501Srpaulo
324214501Srpaulo
325214501Srpaulostatic int eap_ikev2_server_keymat(struct eap_ikev2_data *data)
326214501Srpaulo{
327214501Srpaulo	if (eap_ikev2_derive_keymat(
328214501Srpaulo		    data->ikev2.proposal.prf, &data->ikev2.keys,
329214501Srpaulo		    data->ikev2.i_nonce, data->ikev2.i_nonce_len,
330214501Srpaulo		    data->ikev2.r_nonce, data->ikev2.r_nonce_len,
331214501Srpaulo		    data->keymat) < 0) {
332214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to derive "
333214501Srpaulo			   "key material");
334214501Srpaulo		return -1;
335214501Srpaulo	}
336214501Srpaulo	data->keymat_ok = 1;
337214501Srpaulo	return 0;
338214501Srpaulo}
339214501Srpaulo
340214501Srpaulo
341214501Srpaulostatic void eap_ikev2_process(struct eap_sm *sm, void *priv,
342214501Srpaulo			      struct wpabuf *respData)
343214501Srpaulo{
344214501Srpaulo	struct eap_ikev2_data *data = priv;
345214501Srpaulo	const u8 *start, *pos, *end;
346214501Srpaulo	size_t len;
347214501Srpaulo	u8 flags;
348214501Srpaulo	u32 message_length = 0;
349214501Srpaulo	struct wpabuf tmpbuf;
350214501Srpaulo
351214501Srpaulo	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, respData,
352214501Srpaulo			       &len);
353214501Srpaulo	if (pos == NULL)
354214501Srpaulo		return; /* Should not happen; message already verified */
355214501Srpaulo
356214501Srpaulo	start = pos;
357214501Srpaulo	end = start + len;
358214501Srpaulo
359214501Srpaulo	if (len == 0) {
360214501Srpaulo		/* fragment ack */
361214501Srpaulo		flags = 0;
362214501Srpaulo	} else
363214501Srpaulo		flags = *pos++;
364214501Srpaulo
365214501Srpaulo	if (eap_ikev2_process_icv(data, respData, flags, pos, &end) < 0) {
366214501Srpaulo		eap_ikev2_state(data, FAIL);
367214501Srpaulo		return;
368214501Srpaulo	}
369214501Srpaulo
370214501Srpaulo	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) {
371214501Srpaulo		if (end - pos < 4) {
372214501Srpaulo			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow");
373214501Srpaulo			eap_ikev2_state(data, FAIL);
374214501Srpaulo			return;
375214501Srpaulo		}
376214501Srpaulo		message_length = WPA_GET_BE32(pos);
377214501Srpaulo		pos += 4;
378214501Srpaulo
379214501Srpaulo		if (message_length < (u32) (end - pos)) {
380214501Srpaulo			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message "
381214501Srpaulo				   "Length (%d; %ld remaining in this msg)",
382214501Srpaulo				   message_length, (long) (end - pos));
383214501Srpaulo			eap_ikev2_state(data, FAIL);
384214501Srpaulo			return;
385214501Srpaulo		}
386214501Srpaulo	}
387214501Srpaulo	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x "
388214501Srpaulo		   "Message Length %u", flags, message_length);
389214501Srpaulo
390214501Srpaulo	if (data->state == WAIT_FRAG_ACK) {
391214501Srpaulo		if (len != 0) {
392214501Srpaulo			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload "
393214501Srpaulo				   "in WAIT_FRAG_ACK state");
394214501Srpaulo			eap_ikev2_state(data, FAIL);
395214501Srpaulo			return;
396214501Srpaulo		}
397214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged");
398214501Srpaulo		eap_ikev2_state(data, MSG);
399214501Srpaulo		return;
400214501Srpaulo	}
401214501Srpaulo
402214501Srpaulo	if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) {
403214501Srpaulo		eap_ikev2_state(data, FAIL);
404214501Srpaulo		return;
405214501Srpaulo	}
406214501Srpaulo
407214501Srpaulo	if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) {
408214501Srpaulo		if (eap_ikev2_process_fragment(data, flags, message_length,
409214501Srpaulo					       pos, end - pos) < 0)
410214501Srpaulo			eap_ikev2_state(data, FAIL);
411214501Srpaulo		else
412214501Srpaulo			eap_ikev2_state(data, FRAG_ACK);
413214501Srpaulo		return;
414214501Srpaulo	} else if (data->state == FRAG_ACK) {
415214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received");
416214501Srpaulo		data->state = MSG;
417214501Srpaulo	}
418214501Srpaulo
419214501Srpaulo	if (data->in_buf == NULL) {
420214501Srpaulo		/* Wrap unfragmented messages as wpabuf without extra copy */
421214501Srpaulo		wpabuf_set(&tmpbuf, pos, end - pos);
422214501Srpaulo		data->in_buf = &tmpbuf;
423214501Srpaulo	}
424214501Srpaulo
425214501Srpaulo	if (ikev2_initiator_process(&data->ikev2, data->in_buf) < 0) {
426214501Srpaulo		if (data->in_buf == &tmpbuf)
427214501Srpaulo			data->in_buf = NULL;
428214501Srpaulo		eap_ikev2_state(data, FAIL);
429214501Srpaulo		return;
430214501Srpaulo	}
431214501Srpaulo
432214501Srpaulo	switch (data->ikev2.state) {
433214501Srpaulo	case SA_AUTH:
434214501Srpaulo		/* SA_INIT was sent out, so message have to be
435214501Srpaulo		 * integrity protected from now on. */
436214501Srpaulo		data->keys_ready = 1;
437214501Srpaulo		break;
438214501Srpaulo	case IKEV2_DONE:
439214501Srpaulo		if (data->state == FAIL)
440214501Srpaulo			break;
441214501Srpaulo		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication completed "
442214501Srpaulo			   "successfully");
443214501Srpaulo		if (eap_ikev2_server_keymat(data))
444214501Srpaulo			break;
445214501Srpaulo		eap_ikev2_state(data, DONE);
446214501Srpaulo		break;
447214501Srpaulo	default:
448214501Srpaulo		break;
449214501Srpaulo	}
450214501Srpaulo
451214501Srpaulo	if (data->in_buf != &tmpbuf)
452214501Srpaulo		wpabuf_free(data->in_buf);
453214501Srpaulo	data->in_buf = NULL;
454214501Srpaulo}
455214501Srpaulo
456214501Srpaulo
457214501Srpaulostatic Boolean eap_ikev2_isDone(struct eap_sm *sm, void *priv)
458214501Srpaulo{
459214501Srpaulo	struct eap_ikev2_data *data = priv;
460214501Srpaulo	return data->state == DONE || data->state == FAIL;
461214501Srpaulo}
462214501Srpaulo
463214501Srpaulo
464214501Srpaulostatic Boolean eap_ikev2_isSuccess(struct eap_sm *sm, void *priv)
465214501Srpaulo{
466214501Srpaulo	struct eap_ikev2_data *data = priv;
467214501Srpaulo	return data->state == DONE && data->ikev2.state == IKEV2_DONE &&
468214501Srpaulo		data->keymat_ok;
469214501Srpaulo}
470214501Srpaulo
471214501Srpaulo
472214501Srpaulostatic u8 * eap_ikev2_getKey(struct eap_sm *sm, void *priv, size_t *len)
473214501Srpaulo{
474214501Srpaulo	struct eap_ikev2_data *data = priv;
475214501Srpaulo	u8 *key;
476214501Srpaulo
477214501Srpaulo	if (data->state != DONE || !data->keymat_ok)
478214501Srpaulo		return NULL;
479214501Srpaulo
480214501Srpaulo	key = os_malloc(EAP_MSK_LEN);
481214501Srpaulo	if (key) {
482214501Srpaulo		os_memcpy(key, data->keymat, EAP_MSK_LEN);
483214501Srpaulo		*len = EAP_MSK_LEN;
484214501Srpaulo	}
485214501Srpaulo
486214501Srpaulo	return key;
487214501Srpaulo}
488214501Srpaulo
489214501Srpaulo
490214501Srpaulostatic u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
491214501Srpaulo{
492214501Srpaulo	struct eap_ikev2_data *data = priv;
493214501Srpaulo	u8 *key;
494214501Srpaulo
495214501Srpaulo	if (data->state != DONE || !data->keymat_ok)
496214501Srpaulo		return NULL;
497214501Srpaulo
498214501Srpaulo	key = os_malloc(EAP_EMSK_LEN);
499214501Srpaulo	if (key) {
500214501Srpaulo		os_memcpy(key, data->keymat + EAP_MSK_LEN, EAP_EMSK_LEN);
501214501Srpaulo		*len = EAP_EMSK_LEN;
502214501Srpaulo	}
503214501Srpaulo
504214501Srpaulo	return key;
505214501Srpaulo}
506214501Srpaulo
507214501Srpaulo
508214501Srpauloint eap_server_ikev2_register(void)
509214501Srpaulo{
510214501Srpaulo	struct eap_method *eap;
511214501Srpaulo	int ret;
512214501Srpaulo
513214501Srpaulo	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
514214501Srpaulo				      EAP_VENDOR_IETF, EAP_TYPE_IKEV2,
515214501Srpaulo				      "IKEV2");
516214501Srpaulo	if (eap == NULL)
517214501Srpaulo		return -1;
518214501Srpaulo
519214501Srpaulo	eap->init = eap_ikev2_init;
520214501Srpaulo	eap->reset = eap_ikev2_reset;
521214501Srpaulo	eap->buildReq = eap_ikev2_buildReq;
522214501Srpaulo	eap->check = eap_ikev2_check;
523214501Srpaulo	eap->process = eap_ikev2_process;
524214501Srpaulo	eap->isDone = eap_ikev2_isDone;
525214501Srpaulo	eap->getKey = eap_ikev2_getKey;
526214501Srpaulo	eap->isSuccess = eap_ikev2_isSuccess;
527214501Srpaulo	eap->get_emsk = eap_ikev2_get_emsk;
528214501Srpaulo
529214501Srpaulo	ret = eap_server_method_register(eap);
530214501Srpaulo	if (ret)
531214501Srpaulo		eap_server_method_free(eap);
532214501Srpaulo	return ret;
533214501Srpaulo}
534