• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
23 struct 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 
eap_ikev2_state_txt(int state)36 static 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 
eap_ikev2_state(struct eap_ikev2_data * data,int state)55 static 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 
eap_ikev2_init(struct eap_sm * sm)64 static 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 
104 failed:
105 	ikev2_responder_deinit(&data->ikev2);
106 	os_free(data);
107 	return NULL;
108 }
109 
110 
eap_ikev2_deinit(struct eap_sm * sm,void * priv)111 static 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 
eap_ikev2_peer_keymat(struct eap_ikev2_data * data)121 static 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 
eap_ikev2_build_msg(struct eap_ikev2_data * data,struct eap_method_ret * ret,u8 id)137 static 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 
eap_ikev2_process_icv(struct eap_ikev2_data * data,const struct wpabuf * reqData,u8 flags,const u8 * pos,const u8 ** end)253 static 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 
eap_ikev2_process_cont(struct eap_ikev2_data * data,const u8 * buf,size_t len)275 static 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 
eap_ikev2_process_fragment(struct eap_ikev2_data * data,struct eap_method_ret * ret,u8 id,u8 flags,u32 message_length,const u8 * buf,size_t len)294 static 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 
eap_ikev2_process(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)328 static 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 
eap_ikev2_isKeyAvailable(struct eap_sm * sm,void * priv)441 static 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 
eap_ikev2_getKey(struct eap_sm * sm,void * priv,size_t * len)448 static 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 
eap_ikev2_get_emsk(struct eap_sm * sm,void * priv,size_t * len)466 static 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 
eap_peer_ikev2_register(void)484 int 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