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