1/*
2 * EAP-IKEv2 peer (RFC 5106)
3 * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15#include "includes.h"
16
17#include "common.h"
18#include "eap_i.h"
19#include "eap_common/eap_ikev2_common.h"
20#include "ikev2.h"
21
22
23struct eap_ikev2_data {
24	struct ikev2_responder_data ikev2;
25	enum { WAIT_START, PROC_MSG, WAIT_FRAG_ACK, DONE, FAIL } state;
26	struct wpabuf *in_buf;
27	struct wpabuf *out_buf;
28	size_t out_used;
29	size_t fragment_size;
30	int keys_ready;
31	u8 keymat[EAP_MSK_LEN + EAP_EMSK_LEN];
32	int keymat_ok;
33};
34
35
36static const char * eap_ikev2_state_txt(int state)
37{
38	switch (state) {
39	case WAIT_START:
40		return "WAIT_START";
41	case PROC_MSG:
42		return "PROC_MSG";
43	case WAIT_FRAG_ACK:
44		return "WAIT_FRAG_ACK";
45	case DONE:
46		return "DONE";
47	case FAIL:
48		return "FAIL";
49	default:
50		return "?";
51	}
52}
53
54
55static void eap_ikev2_state(struct eap_ikev2_data *data, int state)
56{
57	wpa_printf(MSG_DEBUG, "EAP-IKEV2: %s -> %s",
58		   eap_ikev2_state_txt(data->state),
59		   eap_ikev2_state_txt(state));
60	data->state = state;
61}
62
63
64static void * eap_ikev2_init(struct eap_sm *sm)
65{
66	struct eap_ikev2_data *data;
67	const u8 *identity, *password;
68	size_t identity_len, password_len;
69
70	identity = eap_get_config_identity(sm, &identity_len);
71	if (identity == NULL) {
72		wpa_printf(MSG_INFO, "EAP-IKEV2: No identity available");
73		return NULL;
74	}
75
76	data = os_zalloc(sizeof(*data));
77	if (data == NULL)
78		return NULL;
79	data->state = WAIT_START;
80	data->fragment_size = IKEV2_FRAGMENT_SIZE;
81	data->ikev2.state = SA_INIT;
82	data->ikev2.peer_auth = PEER_AUTH_SECRET;
83	data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2");
84	if (data->ikev2.key_pad == NULL)
85		goto failed;
86	data->ikev2.key_pad_len = 21;
87	data->ikev2.IDr = os_malloc(identity_len);
88	if (data->ikev2.IDr == NULL)
89		goto failed;
90	os_memcpy(data->ikev2.IDr, identity, identity_len);
91	data->ikev2.IDr_len = identity_len;
92
93	password = eap_get_config_password(sm, &password_len);
94	if (password) {
95		data->ikev2.shared_secret = os_malloc(password_len);
96		if (data->ikev2.shared_secret == NULL)
97			goto failed;
98		os_memcpy(data->ikev2.shared_secret, password, password_len);
99		data->ikev2.shared_secret_len = password_len;
100	}
101
102	return data;
103
104failed:
105	ikev2_responder_deinit(&data->ikev2);
106	os_free(data);
107	return NULL;
108}
109
110
111static void eap_ikev2_deinit(struct eap_sm *sm, void *priv)
112{
113	struct eap_ikev2_data *data = priv;
114	wpabuf_free(data->in_buf);
115	wpabuf_free(data->out_buf);
116	ikev2_responder_deinit(&data->ikev2);
117	os_free(data);
118}
119
120
121static int eap_ikev2_peer_keymat(struct eap_ikev2_data *data)
122{
123	if (eap_ikev2_derive_keymat(
124		    data->ikev2.proposal.prf, &data->ikev2.keys,
125		    data->ikev2.i_nonce, data->ikev2.i_nonce_len,
126		    data->ikev2.r_nonce, data->ikev2.r_nonce_len,
127		    data->keymat) < 0) {
128		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to "
129			   "derive key material");
130		return -1;
131	}
132	data->keymat_ok = 1;
133	return 0;
134}
135
136
137static struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data,
138					   struct eap_method_ret *ret, u8 id)
139{
140	struct wpabuf *resp;
141	u8 flags;
142	size_t send_len, plen, icv_len = 0;
143
144	ret->ignore = FALSE;
145	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Generating Response");
146	ret->allowNotifications = TRUE;
147
148	flags = 0;
149	send_len = wpabuf_len(data->out_buf) - data->out_used;
150	if (1 + send_len > data->fragment_size) {
151		send_len = data->fragment_size - 1;
152		flags |= IKEV2_FLAGS_MORE_FRAGMENTS;
153		if (data->out_used == 0) {
154			flags |= IKEV2_FLAGS_LENGTH_INCLUDED;
155			send_len -= 4;
156		}
157	}
158#ifdef CCNS_PL
159	/* Some issues figuring out the length of the message if Message Length
160	 * field not included?! */
161	if (!(flags & IKEV2_FLAGS_LENGTH_INCLUDED))
162		flags |= IKEV2_FLAGS_LENGTH_INCLUDED;
163#endif /* CCNS_PL */
164
165	plen = 1 + send_len;
166	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED)
167		plen += 4;
168	if (data->keys_ready) {
169		const struct ikev2_integ_alg *integ;
170		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Add Integrity Checksum "
171			   "Data");
172		flags |= IKEV2_FLAGS_ICV_INCLUDED;
173		integ = ikev2_get_integ(data->ikev2.proposal.integ);
174		if (integ == NULL) {
175			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG "
176				   "transform / cannot generate ICV");
177			return NULL;
178		}
179		icv_len = integ->hash_len;
180
181		plen += icv_len;
182	}
183	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, plen,
184			     EAP_CODE_RESPONSE, id);
185	if (resp == NULL)
186		return NULL;
187
188	wpabuf_put_u8(resp, flags); /* Flags */
189	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED)
190		wpabuf_put_be32(resp, wpabuf_len(data->out_buf));
191
192	wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used,
193			send_len);
194	data->out_used += send_len;
195
196	if (flags & IKEV2_FLAGS_ICV_INCLUDED) {
197		const u8 *msg = wpabuf_head(resp);
198		size_t len = wpabuf_len(resp);
199		ikev2_integ_hash(data->ikev2.proposal.integ,
200				 data->ikev2.keys.SK_ar,
201				 data->ikev2.keys.SK_integ_len,
202				 msg, len, wpabuf_put(resp, icv_len));
203	}
204
205	ret->methodState = METHOD_MAY_CONT;
206	ret->decision = DECISION_FAIL;
207
208	if (data->out_used == wpabuf_len(data->out_buf)) {
209		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes "
210			   "(message sent completely)",
211			   (unsigned long) send_len);
212		wpabuf_free(data->out_buf);
213		data->out_buf = NULL;
214		data->out_used = 0;
215		switch (data->ikev2.state) {
216		case SA_AUTH:
217			/* SA_INIT was sent out, so message have to be
218			 * integrity protected from now on. */
219			data->keys_ready = 1;
220			break;
221		case IKEV2_DONE:
222			ret->methodState = METHOD_DONE;
223			if (data->state == FAIL)
224				break;
225			ret->decision = DECISION_COND_SUCC;
226			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication "
227				   "completed successfully");
228			if (eap_ikev2_peer_keymat(data))
229				break;
230			eap_ikev2_state(data, DONE);
231			break;
232		case IKEV2_FAILED:
233			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication "
234				   "failed");
235			ret->methodState = METHOD_DONE;
236			ret->decision = DECISION_FAIL;
237			break;
238		default:
239			break;
240		}
241	} else {
242		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes "
243			   "(%lu more to send)", (unsigned long) send_len,
244			   (unsigned long) wpabuf_len(data->out_buf) -
245			   data->out_used);
246		eap_ikev2_state(data, WAIT_FRAG_ACK);
247	}
248
249	return resp;
250}
251
252
253static int eap_ikev2_process_icv(struct eap_ikev2_data *data,
254				 const struct wpabuf *reqData,
255				 u8 flags, const u8 *pos, const u8 **end)
256{
257	if (flags & IKEV2_FLAGS_ICV_INCLUDED) {
258		int icv_len = eap_ikev2_validate_icv(
259			data->ikev2.proposal.integ, &data->ikev2.keys, 1,
260			reqData, pos, *end);
261		if (icv_len < 0)
262			return -1;
263		/* Hide Integrity Checksum Data from further processing */
264		*end -= icv_len;
265	} else if (data->keys_ready) {
266		wpa_printf(MSG_INFO, "EAP-IKEV2: The message should have "
267			   "included integrity checksum");
268		return -1;
269	}
270
271	return 0;
272}
273
274
275static int eap_ikev2_process_cont(struct eap_ikev2_data *data,
276				  const u8 *buf, size_t len)
277{
278	/* Process continuation of a pending message */
279	if (len > wpabuf_tailroom(data->in_buf)) {
280		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment overflow");
281		eap_ikev2_state(data, FAIL);
282		return -1;
283	}
284
285	wpabuf_put_data(data->in_buf, buf, len);
286	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes, waiting "
287		   "for %lu bytes more", (unsigned long) len,
288		   (unsigned long) wpabuf_tailroom(data->in_buf));
289
290	return 0;
291}
292
293
294static struct wpabuf * eap_ikev2_process_fragment(struct eap_ikev2_data *data,
295						  struct eap_method_ret *ret,
296						  u8 id, u8 flags,
297						  u32 message_length,
298						  const u8 *buf, size_t len)
299{
300	/* Process a fragment that is not the last one of the message */
301	if (data->in_buf == NULL && !(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) {
302		wpa_printf(MSG_DEBUG, "EAP-IKEV2: No Message Length field in "
303			   "a fragmented packet");
304		ret->ignore = TRUE;
305		return NULL;
306	}
307
308	if (data->in_buf == NULL) {
309		/* First fragment of the message */
310		data->in_buf = wpabuf_alloc(message_length);
311		if (data->in_buf == NULL) {
312			wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for "
313				   "message");
314			ret->ignore = TRUE;
315			return NULL;
316		}
317		wpabuf_put_data(data->in_buf, buf, len);
318		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes in first "
319			   "fragment, waiting for %lu bytes more",
320			   (unsigned long) len,
321			   (unsigned long) wpabuf_tailroom(data->in_buf));
322	}
323
324	return eap_ikev2_build_frag_ack(id, EAP_CODE_RESPONSE);
325}
326
327
328static struct wpabuf * eap_ikev2_process(struct eap_sm *sm, void *priv,
329					 struct eap_method_ret *ret,
330					 const struct wpabuf *reqData)
331{
332	struct eap_ikev2_data *data = priv;
333	const u8 *start, *pos, *end;
334	size_t len;
335	u8 flags, id;
336	u32 message_length = 0;
337	struct wpabuf tmpbuf;
338
339	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, reqData, &len);
340	if (pos == NULL) {
341		ret->ignore = TRUE;
342		return NULL;
343	}
344
345	id = eap_get_id(reqData);
346
347	start = pos;
348	end = start + len;
349
350	if (len == 0)
351		flags = 0; /* fragment ack */
352	else
353		flags = *pos++;
354
355	if (eap_ikev2_process_icv(data, reqData, flags, pos, &end) < 0) {
356		ret->ignore = TRUE;
357		return NULL;
358	}
359
360	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) {
361		if (end - pos < 4) {
362			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow");
363			ret->ignore = TRUE;
364			return NULL;
365		}
366		message_length = WPA_GET_BE32(pos);
367		pos += 4;
368
369		if (message_length < (u32) (end - pos)) {
370			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message "
371				   "Length (%d; %ld remaining in this msg)",
372				   message_length, (long) (end - pos));
373			ret->ignore = TRUE;
374			return NULL;
375		}
376	}
377
378	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x "
379		   "Message Length %u", flags, message_length);
380
381	if (data->state == WAIT_FRAG_ACK) {
382#ifdef CCNS_PL
383		if (len > 1) /* Empty Flags field included in ACK */
384#else /* CCNS_PL */
385		if (len != 0)
386#endif /* CCNS_PL */
387		{
388			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload "
389				   "in WAIT_FRAG_ACK state");
390			ret->ignore = TRUE;
391			return NULL;
392		}
393		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged");
394		eap_ikev2_state(data, PROC_MSG);
395		return eap_ikev2_build_msg(data, ret, id);
396	}
397
398	if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) {
399		ret->ignore = TRUE;
400		return NULL;
401	}
402
403	if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) {
404		return eap_ikev2_process_fragment(data, ret, id, flags,
405						  message_length, pos,
406						  end - pos);
407	}
408
409	if (data->in_buf == NULL) {
410		/* Wrap unfragmented messages as wpabuf without extra copy */
411		wpabuf_set(&tmpbuf, pos, end - pos);
412		data->in_buf = &tmpbuf;
413	}
414
415	if (ikev2_responder_process(&data->ikev2, data->in_buf) < 0) {
416		if (data->in_buf == &tmpbuf)
417			data->in_buf = NULL;
418		eap_ikev2_state(data, FAIL);
419		return NULL;
420	}
421
422	if (data->in_buf != &tmpbuf)
423		wpabuf_free(data->in_buf);
424	data->in_buf = NULL;
425
426	if (data->out_buf == NULL) {
427		data->out_buf = ikev2_responder_build(&data->ikev2);
428		if (data->out_buf == NULL) {
429			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to generate "
430				   "IKEv2 message");
431			return NULL;
432		}
433		data->out_used = 0;
434	}
435
436	eap_ikev2_state(data, PROC_MSG);
437	return eap_ikev2_build_msg(data, ret, id);
438}
439
440
441static Boolean eap_ikev2_isKeyAvailable(struct eap_sm *sm, void *priv)
442{
443	struct eap_ikev2_data *data = priv;
444	return data->state == DONE && data->keymat_ok;
445}
446
447
448static u8 * eap_ikev2_getKey(struct eap_sm *sm, void *priv, size_t *len)
449{
450	struct eap_ikev2_data *data = priv;
451	u8 *key;
452
453	if (data->state != DONE || !data->keymat_ok)
454		return NULL;
455
456	key = os_malloc(EAP_MSK_LEN);
457	if (key) {
458		os_memcpy(key, data->keymat, EAP_MSK_LEN);
459		*len = EAP_MSK_LEN;
460	}
461
462	return key;
463}
464
465
466static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
467{
468	struct eap_ikev2_data *data = priv;
469	u8 *key;
470
471	if (data->state != DONE || !data->keymat_ok)
472		return NULL;
473
474	key = os_malloc(EAP_EMSK_LEN);
475	if (key) {
476		os_memcpy(key, data->keymat + EAP_MSK_LEN, EAP_EMSK_LEN);
477		*len = EAP_EMSK_LEN;
478	}
479
480	return key;
481}
482
483
484int eap_peer_ikev2_register(void)
485{
486	struct eap_method *eap;
487	int ret;
488
489	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
490				    EAP_VENDOR_IETF, EAP_TYPE_IKEV2,
491				    "IKEV2");
492	if (eap == NULL)
493		return -1;
494
495	eap->init = eap_ikev2_init;
496	eap->deinit = eap_ikev2_deinit;
497	eap->process = eap_ikev2_process;
498	eap->isKeyAvailable = eap_ikev2_isKeyAvailable;
499	eap->getKey = eap_ikev2_getKey;
500	eap->get_emsk = eap_ikev2_get_emsk;
501
502	ret = eap_peer_method_register(eap);
503	if (ret)
504		eap_peer_method_free(eap);
505	return ret;
506}
507