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