eap_server_ikev2.c revision 302408
11558Srgrimes/*
298542Smckusick * EAP-IKEv2 server (RFC 5106)
398542Smckusick * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
498542Smckusick *
598542Smckusick * This software may be distributed under the terms of the BSD license.
698542Smckusick * See README for more details.
798542Smckusick */
898542Smckusick
9110884Smckusick#include "includes.h"
1098542Smckusick
11136721Srwatson#include "common.h"
12136721Srwatson#include "eap_i.h"
13136721Srwatson#include "eap_common/eap_ikev2_common.h"
14136721Srwatson#include "ikev2.h"
15136721Srwatson
16136721Srwatson
17136721Srwatsonstruct eap_ikev2_data {
18136721Srwatson	struct ikev2_initiator_data ikev2;
19136721Srwatson	enum { MSG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state;
20136721Srwatson	struct wpabuf *in_buf;
21136721Srwatson	struct wpabuf *out_buf;
22136721Srwatson	size_t out_used;
23136721Srwatson	size_t fragment_size;
24136721Srwatson	int keys_ready;
25136721Srwatson	u8 keymat[EAP_MSK_LEN + EAP_EMSK_LEN];
26136721Srwatson	int keymat_ok;
27136721Srwatson};
28136721Srwatson
29136721Srwatson
30136721Srwatsonstatic const u8 * eap_ikev2_get_shared_secret(void *ctx, const u8 *IDr,
31136721Srwatson					      size_t IDr_len,
321558Srgrimes					      size_t *secret_len)
331558Srgrimes{
341558Srgrimes	struct eap_sm *sm = ctx;
351558Srgrimes
361558Srgrimes	if (IDr == NULL) {
371558Srgrimes		wpa_printf(MSG_DEBUG, "EAP-IKEV2: No IDr received - default "
381558Srgrimes			   "to user identity from EAP-Identity");
391558Srgrimes		IDr = sm->identity;
401558Srgrimes		IDr_len = sm->identity_len;
411558Srgrimes	}
421558Srgrimes
431558Srgrimes	if (eap_user_get(sm, IDr, IDr_len, 0) < 0 || sm->user == NULL ||
441558Srgrimes	    sm->user->password == NULL) {
451558Srgrimes		wpa_printf(MSG_DEBUG, "EAP-IKEV2: No user entry found");
461558Srgrimes		return NULL;
471558Srgrimes	}
481558Srgrimes
491558Srgrimes	*secret_len = sm->user->password_len;
501558Srgrimes	return sm->user->password;
511558Srgrimes}
521558Srgrimes
531558Srgrimes
541558Srgrimesstatic const char * eap_ikev2_state_txt(int state)
551558Srgrimes{
561558Srgrimes	switch (state) {
571558Srgrimes	case MSG:
581558Srgrimes		return "MSG";
5923675Speter	case FRAG_ACK:
6055724Speter		return "FRAG_ACK";
611558Srgrimes	case WAIT_FRAG_ACK:
621558Srgrimes		return "WAIT_FRAG_ACK";
63207143Spjd	case DONE:
64207143Spjd		return "DONE";
65207143Spjd	case FAIL:
6623675Speter		return "FAIL";
6723675Speter	default:
6823675Speter		return "?";
6923675Speter	}
70246812Smckusick}
71246812Smckusick
721558Srgrimes
731558Srgrimesstatic void eap_ikev2_state(struct eap_ikev2_data *data, int state)
74246812Smckusick{
75246812Smckusick	wpa_printf(MSG_DEBUG, "EAP-IKEV2: %s -> %s",
76246812Smckusick		   eap_ikev2_state_txt(data->state),
77250056Sdes		   eap_ikev2_state_txt(state));
781558Srgrimes	data->state = state;
7998542Smckusick}
8098542Smckusick
8198542Smckusick
8298542Smckusickstatic void * eap_ikev2_init(struct eap_sm *sm)
8398542Smckusick{
8498542Smckusick	struct eap_ikev2_data *data;
8598542Smckusick
8698542Smckusick	data = os_zalloc(sizeof(*data));
87134589Sscottl	if (data == NULL)
88134589Sscottl		return NULL;
89134589Sscottl	data->state = MSG;
90134589Sscottl	data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size :
91134589Sscottl		IKEV2_FRAGMENT_SIZE;
92134589Sscottl	data->ikev2.state = SA_INIT;
93134589Sscottl	data->ikev2.peer_auth = PEER_AUTH_SECRET;
9441474Sjulian	data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2");
95102231Strhodes	if (data->ikev2.key_pad == NULL)
9641474Sjulian		goto failed;
9741474Sjulian	data->ikev2.key_pad_len = 21;
9841474Sjulian
9941474Sjulian	/* TODO: make proposals configurable */
10041474Sjulian	data->ikev2.proposal.proposal_num = 1;
10141474Sjulian	data->ikev2.proposal.integ = AUTH_HMAC_SHA1_96;
10241474Sjulian	data->ikev2.proposal.prf = PRF_HMAC_SHA1;
10341474Sjulian	data->ikev2.proposal.encr = ENCR_AES_CBC;
10441474Sjulian	data->ikev2.proposal.dh = DH_GROUP2_1024BIT_MODP;
10541474Sjulian
10641474Sjulian	data->ikev2.IDi = os_malloc(sm->server_id_len);
10741474Sjulian	if (data->ikev2.IDi == NULL)
10841474Sjulian		goto failed;
109136281Struckman	os_memcpy(data->ikev2.IDi, sm->server_id, sm->server_id_len);
110136281Struckman	data->ikev2.IDi_len = sm->server_id_len;
111136281Struckman
112136281Struckman	data->ikev2.get_shared_secret = eap_ikev2_get_shared_secret;
113136281Struckman	data->ikev2.cb_ctx = sm;
114136281Struckman
115136281Struckman	return data;
116136281Struckman
117136281Struckmanfailed:
118136281Struckman	ikev2_initiator_deinit(&data->ikev2);
119136281Struckman	os_free(data);
120136281Struckman	return NULL;
121136281Struckman}
122136281Struckman
123136281Struckman
12441474Sjulianstatic void eap_ikev2_reset(struct eap_sm *sm, void *priv)
12541474Sjulian{
12641474Sjulian	struct eap_ikev2_data *data = priv;
12741474Sjulian	wpabuf_free(data->in_buf);
12841474Sjulian	wpabuf_free(data->out_buf);
12941474Sjulian	ikev2_initiator_deinit(&data->ikev2);
13041474Sjulian	bin_clear_free(data, sizeof(*data));
13141474Sjulian}
1321558Srgrimes
1331558Srgrimes
1341558Srgrimesstatic struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data, u8 id)
1351558Srgrimes{
1361558Srgrimes	struct wpabuf *req;
137246812Smckusick	u8 flags;
13898542Smckusick	size_t send_len, plen, icv_len = 0;
13923675Speter
14023675Speter	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Generating Request");
14123675Speter
142247212Smckusick	flags = 0;
1431558Srgrimes	send_len = wpabuf_len(data->out_buf) - data->out_used;
14423675Speter	if (1 + send_len > data->fragment_size) {
14598542Smckusick		send_len = data->fragment_size - 1;
14698542Smckusick		flags |= IKEV2_FLAGS_MORE_FRAGMENTS;
14723675Speter		if (data->out_used == 0) {
14823675Speter			flags |= IKEV2_FLAGS_LENGTH_INCLUDED;
14998542Smckusick			send_len -= 4;
15098542Smckusick		}
1511558Srgrimes	}
15223675Speter
1531558Srgrimes	plen = 1 + send_len;
154134589Sscottl	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED)
15598542Smckusick		plen += 4;
15698542Smckusick	if (data->keys_ready) {
15798542Smckusick		const struct ikev2_integ_alg *integ;
1581558Srgrimes		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Add Integrity Checksum "
159134589Sscottl			   "Data");
160134589Sscottl		flags |= IKEV2_FLAGS_ICV_INCLUDED;
161134589Sscottl		integ = ikev2_get_integ(data->ikev2.proposal.integ);
162134589Sscottl		if (integ == NULL) {
163134589Sscottl			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG "
164134589Sscottl				   "transform / cannot generate ICV");
165134589Sscottl			return NULL;
166246812Smckusick		}
167246812Smckusick		icv_len = integ->hash_len;
168246812Smckusick
169246812Smckusick		plen += icv_len;
170247212Smckusick	}
171247212Smckusick	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, plen,
172247212Smckusick			    EAP_CODE_REQUEST, id);
173247212Smckusick	if (req == NULL)
174247212Smckusick		return NULL;
175247212Smckusick
176247212Smckusick	wpabuf_put_u8(req, flags); /* Flags */
177247212Smckusick	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED)
178247212Smckusick		wpabuf_put_be32(req, wpabuf_len(data->out_buf));
179247212Smckusick
180247212Smckusick	wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used,
181247212Smckusick			send_len);
182247212Smckusick	data->out_used += send_len;
183247212Smckusick
184247212Smckusick	if (flags & IKEV2_FLAGS_ICV_INCLUDED) {
185247212Smckusick		const u8 *msg = wpabuf_head(req);
186247212Smckusick		size_t len = wpabuf_len(req);
187247212Smckusick		ikev2_integ_hash(data->ikev2.proposal.integ,
188247212Smckusick				 data->ikev2.keys.SK_ai,
189247212Smckusick				 data->ikev2.keys.SK_integ_len,
190247212Smckusick				 msg, len, wpabuf_put(req, icv_len));
191247212Smckusick	}
192247212Smckusick
193247212Smckusick	if (data->out_used == wpabuf_len(data->out_buf)) {
194247212Smckusick		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes "
195260178Sscottl			   "(message sent completely)",
196260178Sscottl			   (unsigned long) send_len);
197260178Sscottl		wpabuf_free(data->out_buf);
198260178Sscottl		data->out_buf = NULL;
199260178Sscottl		data->out_used = 0;
2001558Srgrimes	} else {
201260178Sscottl		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes "
202260178Sscottl			   "(%lu more to send)", (unsigned long) send_len,
203260178Sscottl			   (unsigned long) wpabuf_len(data->out_buf) -
2041558Srgrimes			   data->out_used);
20586514Siedowse		eap_ikev2_state(data, WAIT_FRAG_ACK);
20674556Smckusick	}
20774556Smckusick
20874556Smckusick	return req;
20986514Siedowse}
21086514Siedowse
211247212Smckusick
2121558Srgrimesstatic struct wpabuf * eap_ikev2_buildReq(struct eap_sm *sm, void *priv, u8 id)
21398542Smckusick{
21486514Siedowse	struct eap_ikev2_data *data = priv;
215247212Smckusick
21686514Siedowse	switch (data->state) {
2171558Srgrimes	case MSG:
21874556Smckusick		if (data->out_buf == NULL) {
2191558Srgrimes			data->out_buf = ikev2_initiator_build(&data->ikev2);
2201558Srgrimes			if (data->out_buf == NULL) {
2211558Srgrimes				wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to "
222260178Sscottl					   "generate IKEv2 message");
2231558Srgrimes				return NULL;
2241558Srgrimes			}
2251558Srgrimes			data->out_used = 0;
226100935Sphk		}
227100935Sphk		/* pass through */
2281558Srgrimes	case WAIT_FRAG_ACK:
2291558Srgrimes		return eap_ikev2_build_msg(data, id);
23098542Smckusick	case FRAG_ACK:
23198542Smckusick		return eap_ikev2_build_frag_ack(id, EAP_CODE_REQUEST);
2321558Srgrimes	default:
23398542Smckusick		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected state %d in "
23498542Smckusick			   "buildReq", data->state);
2351558Srgrimes		return NULL;
2361558Srgrimes	}
2371558Srgrimes}
2381558Srgrimes
2391558Srgrimes
2401558Srgrimesstatic Boolean eap_ikev2_check(struct eap_sm *sm, void *priv,
24162668Smckusick			       struct wpabuf *respData)
24262668Smckusick{
24362668Smckusick	const u8 *pos;
2441558Srgrimes	size_t len;
2451558Srgrimes
2461558Srgrimes	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, respData,
2478871Srgrimes			       &len);
2481558Srgrimes	if (pos == NULL) {
2491558Srgrimes		wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid frame");
2508871Srgrimes		return TRUE;
2511558Srgrimes	}
2521558Srgrimes
2531558Srgrimes	return FALSE;
2548871Srgrimes}
2551558Srgrimes
256229778Suqs
2571558Srgrimesstatic int eap_ikev2_process_icv(struct eap_ikev2_data *data,
2581558Srgrimes				 const struct wpabuf *respData,
2591558Srgrimes				 u8 flags, const u8 *pos, const u8 **end,
2601558Srgrimes				 int frag_ack)
2611558Srgrimes{
2621558Srgrimes	if (flags & IKEV2_FLAGS_ICV_INCLUDED) {
2631558Srgrimes		int icv_len = eap_ikev2_validate_icv(
2641558Srgrimes			data->ikev2.proposal.integ, &data->ikev2.keys, 0,
2651558Srgrimes			respData, pos, *end);
2661558Srgrimes		if (icv_len < 0)
2671558Srgrimes			return -1;
26898542Smckusick		/* Hide Integrity Checksum Data from further processing */
2691558Srgrimes		*end -= icv_len;
2701558Srgrimes	} else if (data->keys_ready && !frag_ack) {
2711558Srgrimes		wpa_printf(MSG_INFO, "EAP-IKEV2: The message should have "
2721558Srgrimes			   "included integrity checksum");
2731558Srgrimes		return -1;
2741558Srgrimes	}
2751558Srgrimes
2761558Srgrimes	return 0;
2771558Srgrimes}
2781558Srgrimes
2791558Srgrimes
2801558Srgrimesstatic int eap_ikev2_process_cont(struct eap_ikev2_data *data,
2811558Srgrimes				  const u8 *buf, size_t len)
2821558Srgrimes{
28398542Smckusick	/* Process continuation of a pending message */
2841558Srgrimes	if (len > wpabuf_tailroom(data->in_buf)) {
285260178Sscottl		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment overflow");
286260178Sscottl		eap_ikev2_state(data, FAIL);
2871558Srgrimes		return -1;
28874556Smckusick	}
289260178Sscottl
290260178Sscottl	wpabuf_put_data(data->in_buf, buf, len);
291260178Sscottl	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes, waiting for %lu "
292260178Sscottl		   "bytes more", (unsigned long) len,
293260178Sscottl		   (unsigned long) wpabuf_tailroom(data->in_buf));
294260178Sscottl
295260178Sscottl	return 0;
296260178Sscottl}
297260178Sscottl
298260178Sscottl
299260178Sscottlstatic int eap_ikev2_process_fragment(struct eap_ikev2_data *data,
300260178Sscottl				      u8 flags, u32 message_length,
301260178Sscottl				      const u8 *buf, size_t len)
302260178Sscottl{
303260178Sscottl	/* Process a fragment that is not the last one of the message */
304260178Sscottl	if (data->in_buf == NULL && !(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) {
305260178Sscottl		wpa_printf(MSG_DEBUG, "EAP-IKEV2: No Message Length field in "
306260178Sscottl			   "a fragmented packet");
307260178Sscottl		return -1;
308260178Sscottl	}
309260178Sscottl
310260178Sscottl	if (data->in_buf == NULL) {
311260178Sscottl		/* First fragment of the message */
312260178Sscottl		if (message_length > 50000) {
313260178Sscottl			/* Limit maximum memory allocation */
314260178Sscottl			wpa_printf(MSG_DEBUG,
315260178Sscottl				   "EAP-IKEV2: Ignore too long message");
316260178Sscottl			return -1;
317260178Sscottl		}
318260178Sscottl		data->in_buf = wpabuf_alloc(message_length);
319260178Sscottl		if (data->in_buf == NULL) {
320260178Sscottl			wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for "
321260178Sscottl				   "message");
322260178Sscottl			return -1;
323260178Sscottl		}
324260178Sscottl		wpabuf_put_data(data->in_buf, buf, len);
325260178Sscottl		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes in first "
326260178Sscottl			   "fragment, waiting for %lu bytes more",
327260178Sscottl			   (unsigned long) len,
328260178Sscottl			   (unsigned long) wpabuf_tailroom(data->in_buf));
3291558Srgrimes	}
330260178Sscottl
331260178Sscottl	return 0;
332260178Sscottl}
3331558Srgrimes
334260178Sscottl
335260178Sscottlstatic int eap_ikev2_server_keymat(struct eap_ikev2_data *data)
336260178Sscottl{
3371558Srgrimes	if (eap_ikev2_derive_keymat(
338260178Sscottl		    data->ikev2.proposal.prf, &data->ikev2.keys,
339260178Sscottl		    data->ikev2.i_nonce, data->ikev2.i_nonce_len,
3401558Srgrimes		    data->ikev2.r_nonce, data->ikev2.r_nonce_len,
341260178Sscottl		    data->keymat) < 0) {
342260178Sscottl		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to derive "
34370050Siedowse			   "key material");
34498542Smckusick		return -1;
34598542Smckusick	}
34698542Smckusick	data->keymat_ok = 1;
34798542Smckusick	return 0;
34898542Smckusick}
34998542Smckusick
350260178Sscottl
351260178Sscottlstatic void eap_ikev2_process(struct eap_sm *sm, void *priv,
3521558Srgrimes			      struct wpabuf *respData)
3531558Srgrimes{
3541558Srgrimes	struct eap_ikev2_data *data = priv;
3551558Srgrimes	const u8 *start, *pos, *end;
3561558Srgrimes	size_t len;
3571558Srgrimes	u8 flags;
3581558Srgrimes	u32 message_length = 0;
3591558Srgrimes	struct wpabuf tmpbuf;
3601558Srgrimes
3611558Srgrimes	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, respData,
3621558Srgrimes			       &len);
36323675Speter	if (pos == NULL)
364260178Sscottl		return; /* Should not happen; message already verified */
3657585Sbde
366248658Smckusick	start = pos;
367248658Smckusick	end = start + len;
368248658Smckusick
369248658Smckusick	if (len == 0) {
370248658Smckusick		/* fragment ack */
371248658Smckusick		flags = 0;
372263629Smckusick	} else
373248658Smckusick		flags = *pos++;
374248658Smckusick
375248658Smckusick	if (eap_ikev2_process_icv(data, respData, flags, pos, &end,
376248658Smckusick				  data->state == WAIT_FRAG_ACK && len == 0) < 0)
377248658Smckusick	{
378248658Smckusick		eap_ikev2_state(data, FAIL);
379248658Smckusick		return;
380248658Smckusick	}
381248658Smckusick
382248658Smckusick	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) {
383248658Smckusick		if (end - pos < 4) {
384248658Smckusick			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow");
385248658Smckusick			eap_ikev2_state(data, FAIL);
386248658Smckusick			return;
387263629Smckusick		}
388248658Smckusick		message_length = WPA_GET_BE32(pos);
389248658Smckusick		pos += 4;
390248658Smckusick
391248658Smckusick		if (message_length < (u32) (end - pos)) {
392248658Smckusick			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message "
393248658Smckusick				   "Length (%d; %ld remaining in this msg)",
394248658Smckusick				   message_length, (long) (end - pos));
395248658Smckusick			eap_ikev2_state(data, FAIL);
396248658Smckusick			return;
39723675Speter		}
3987585Sbde	}
39941474Sjulian	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x "
40092839Simp		   "Message Length %u", flags, message_length);
40198542Smckusick
40292839Simp	if (data->state == WAIT_FRAG_ACK) {
40392839Simp		if (len != 0) {
404100935Sphk			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload "
40592839Simp				   "in WAIT_FRAG_ACK state");
406163845Spjd			eap_ikev2_state(data, FAIL);
40792839Simp			return;
408240406Sobrien		}
409221233Sdes		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged");
410250056Sdes		eap_ikev2_state(data, MSG);
41198542Smckusick		return;
41292839Simp	}
41392839Simp
414100935Sphk	if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) {
415248658Smckusick		eap_ikev2_state(data, FAIL);
41698542Smckusick		return;
41792839Simp	}
41898542Smckusick
419100935Sphk	if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) {
42092839Simp		if (eap_ikev2_process_fragment(data, flags, message_length,
421100935Sphk					       pos, end - pos) < 0)
42292839Simp			eap_ikev2_state(data, FAIL);
423100935Sphk		else
424103398Sphk			eap_ikev2_state(data, FRAG_ACK);
425100935Sphk		return;
426247212Smckusick	} else if (data->state == FRAG_ACK) {
42792839Simp		wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received");
42892839Simp		data->state = MSG;
42992839Simp	}
43098542Smckusick
43192839Simp	if (data->in_buf == NULL) {
43292839Simp		/* Wrap unfragmented messages as wpabuf without extra copy */
433260178Sscottl		wpabuf_set(&tmpbuf, pos, end - pos);
43498542Smckusick		data->in_buf = &tmpbuf;
43598542Smckusick	}
436248658Smckusick
437247212Smckusick	if (ikev2_initiator_process(&data->ikev2, data->in_buf) < 0) {
43892839Simp		if (data->in_buf == &tmpbuf)
439188110Smckusick			data->in_buf = NULL;
44092839Simp		eap_ikev2_state(data, FAIL);
44198542Smckusick		return;
44292839Simp	}
443126345Sscottl
44492839Simp	switch (data->ikev2.state) {
44592839Simp	case SA_AUTH:
44692839Simp		/* SA_INIT was sent out, so message have to be
447247212Smckusick		 * integrity protected from now on. */
44892839Simp		data->keys_ready = 1;
449100935Sphk		break;
45092839Simp	case IKEV2_DONE:
45192839Simp		if (data->state == FAIL)
45292839Simp			break;
45392839Simp		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication completed "
45492839Simp			   "successfully");
45592839Simp		if (eap_ikev2_server_keymat(data))
45692839Simp			break;
45792839Simp		eap_ikev2_state(data, DONE);
45892839Simp		break;
45992839Simp	default:
46092839Simp		break;
46192839Simp	}
46292839Simp
46392839Simp	if (data->in_buf != &tmpbuf)
464100935Sphk		wpabuf_free(data->in_buf);
465100935Sphk	data->in_buf = NULL;
46692839Simp}
46792839Simp
46892839Simp
469163845Spjdstatic Boolean eap_ikev2_isDone(struct eap_sm *sm, void *priv)
470207141Sjeff{
471224059Smckusick	struct eap_ikev2_data *data = priv;
472260178Sscottl	return data->state == DONE || data->state == FAIL;
473207143Spjd}
474207143Spjd
475
476static Boolean eap_ikev2_isSuccess(struct eap_sm *sm, void *priv)
477{
478	struct eap_ikev2_data *data = priv;
479	return data->state == DONE && data->ikev2.state == IKEV2_DONE &&
480		data->keymat_ok;
481}
482
483
484static u8 * eap_ikev2_getKey(struct eap_sm *sm, void *priv, size_t *len)
485{
486	struct eap_ikev2_data *data = priv;
487	u8 *key;
488
489	if (data->state != DONE || !data->keymat_ok)
490		return NULL;
491
492	key = os_malloc(EAP_MSK_LEN);
493	if (key) {
494		os_memcpy(key, data->keymat, EAP_MSK_LEN);
495		*len = EAP_MSK_LEN;
496	}
497
498	return key;
499}
500
501
502static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
503{
504	struct eap_ikev2_data *data = priv;
505	u8 *key;
506
507	if (data->state != DONE || !data->keymat_ok)
508		return NULL;
509
510	key = os_malloc(EAP_EMSK_LEN);
511	if (key) {
512		os_memcpy(key, data->keymat + EAP_MSK_LEN, EAP_EMSK_LEN);
513		*len = EAP_EMSK_LEN;
514	}
515
516	return key;
517}
518
519
520static u8 * eap_ikev2_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
521{
522	struct eap_ikev2_data *data = priv;
523	u8 *sid;
524	size_t sid_len;
525	size_t offset;
526
527	if (data->state != DONE || !data->keymat_ok)
528		return NULL;
529
530	sid_len = 1 + data->ikev2.i_nonce_len + data->ikev2.r_nonce_len;
531	sid = os_malloc(sid_len);
532	if (sid) {
533		offset = 0;
534		sid[offset] = EAP_TYPE_IKEV2;
535		offset++;
536		os_memcpy(sid + offset, data->ikev2.i_nonce,
537			  data->ikev2.i_nonce_len);
538		offset += data->ikev2.i_nonce_len;
539		os_memcpy(sid + offset, data->ikev2.r_nonce,
540			  data->ikev2.r_nonce_len);
541		*len = sid_len;
542		wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Derived Session-Id",
543			    sid, sid_len);
544	}
545
546	return sid;
547}
548
549
550int eap_server_ikev2_register(void)
551{
552	struct eap_method *eap;
553	int ret;
554
555	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
556				      EAP_VENDOR_IETF, EAP_TYPE_IKEV2,
557				      "IKEV2");
558	if (eap == NULL)
559		return -1;
560
561	eap->init = eap_ikev2_init;
562	eap->reset = eap_ikev2_reset;
563	eap->buildReq = eap_ikev2_buildReq;
564	eap->check = eap_ikev2_check;
565	eap->process = eap_ikev2_process;
566	eap->isDone = eap_ikev2_isDone;
567	eap->getKey = eap_ikev2_getKey;
568	eap->isSuccess = eap_ikev2_isSuccess;
569	eap->get_emsk = eap_ikev2_get_emsk;
570	eap->getSessionId = eap_ikev2_get_session_id;
571
572	ret = eap_server_method_register(eap);
573	if (ret)
574		eap_server_method_free(eap);
575	return ret;
576}
577