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