eap_ikev2.c
Go to the documentation of this file.
00001 /*
00002  * EAP-IKEv2 peer (RFC 5106)
00003  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 2 as
00007  * published by the Free Software Foundation.
00008  *
00009  * Alternatively, this software may be distributed under the terms of BSD
00010  * license.
00011  *
00012  * See README and COPYING for more details.
00013  */
00014 
00015 #include "includes.h"
00016 
00017 #include "common.h"
00018 #include "eap_i.h"
00019 #include "eap_common/eap_ikev2_common.h"
00020 #include "ikev2.h"
00021 
00022 
00023 struct eap_ikev2_data {
00024         struct ikev2_responder_data ikev2;
00025         enum { WAIT_START, PROC_MSG, WAIT_FRAG_ACK, DONE, FAIL } state;
00026         struct wpabuf *in_buf;
00027         struct wpabuf *out_buf;
00028         size_t out_used;
00029         size_t fragment_size;
00030         int keys_ready;
00031         u8 keymat[EAP_MSK_LEN + EAP_EMSK_LEN];
00032         int keymat_ok;
00033 };
00034 
00035 
00036 static const char * eap_ikev2_state_txt(int state)
00037 {
00038         switch (state) {
00039         case WAIT_START:
00040                 return "WAIT_START";
00041         case PROC_MSG:
00042                 return "PROC_MSG";
00043         case WAIT_FRAG_ACK:
00044                 return "WAIT_FRAG_ACK";
00045         case DONE:
00046                 return "DONE";
00047         case FAIL:
00048                 return "FAIL";
00049         default:
00050                 return "?";
00051         }
00052 }
00053 
00054 
00055 static void eap_ikev2_state(struct eap_ikev2_data *data, int state)
00056 {
00057         wpa_printf(MSG_DEBUG, "EAP-IKEV2: %s -> %s",
00058                    eap_ikev2_state_txt(data->state),
00059                    eap_ikev2_state_txt(state));
00060         data->state = state;
00061 }
00062 
00063 
00064 static void * eap_ikev2_init(struct eap_sm *sm)
00065 {
00066         struct eap_ikev2_data *data;
00067         const u8 *identity, *password;
00068         size_t identity_len, password_len;
00069 
00070         identity = eap_get_config_identity(sm, &identity_len);
00071         if (identity == NULL) {
00072                 wpa_printf(MSG_INFO, "EAP-IKEV2: No identity available");
00073                 return NULL;
00074         }
00075 
00076         data = os_zalloc(sizeof(*data));
00077         if (data == NULL)
00078                 return NULL;
00079         data->state = WAIT_START;
00080         data->fragment_size = IKEV2_FRAGMENT_SIZE;
00081         data->ikev2.state = SA_INIT;
00082         data->ikev2.peer_auth = PEER_AUTH_SECRET;
00083         data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2");
00084         if (data->ikev2.key_pad == NULL)
00085                 goto failed;
00086         data->ikev2.key_pad_len = 21;
00087         data->ikev2.IDr = os_malloc(identity_len);
00088         if (data->ikev2.IDr == NULL)
00089                 goto failed;
00090         os_memcpy(data->ikev2.IDr, identity, identity_len);
00091         data->ikev2.IDr_len = identity_len;
00092 
00093         password = eap_get_config_password(sm, &password_len);
00094         if (password) {
00095                 data->ikev2.shared_secret = os_malloc(password_len);
00096                 if (data->ikev2.shared_secret == NULL)
00097                         goto failed;
00098                 os_memcpy(data->ikev2.shared_secret, password, password_len);
00099                 data->ikev2.shared_secret_len = password_len;
00100         }
00101 
00102         return data;
00103 
00104 failed:
00105         ikev2_responder_deinit(&data->ikev2);
00106         os_free(data);
00107         return NULL;
00108 }
00109 
00110 
00111 static void eap_ikev2_deinit(struct eap_sm *sm, void *priv)
00112 {
00113         struct eap_ikev2_data *data = priv;
00114         wpabuf_free(data->in_buf);
00115         wpabuf_free(data->out_buf);
00116         ikev2_responder_deinit(&data->ikev2);
00117         os_free(data);
00118 }
00119 
00120 
00121 static int eap_ikev2_peer_keymat(struct eap_ikev2_data *data)
00122 {
00123         if (eap_ikev2_derive_keymat(
00124                     data->ikev2.proposal.prf, &data->ikev2.keys,
00125                     data->ikev2.i_nonce, data->ikev2.i_nonce_len,
00126                     data->ikev2.r_nonce, data->ikev2.r_nonce_len,
00127                     data->keymat) < 0) {
00128                 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to "
00129                            "derive key material");
00130                 return -1;
00131         }
00132         data->keymat_ok = 1;
00133         return 0;
00134 }
00135 
00136 
00137 static struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data,
00138                                            struct eap_method_ret *ret, u8 id)
00139 {
00140         struct wpabuf *resp;
00141         u8 flags;
00142         size_t send_len, plen, icv_len = 0;
00143 
00144         ret->ignore = FALSE;
00145         wpa_printf(MSG_DEBUG, "EAP-IKEV2: Generating Response");
00146         ret->allowNotifications = TRUE;
00147 
00148         flags = 0;
00149         send_len = wpabuf_len(data->out_buf) - data->out_used;
00150         if (1 + send_len > data->fragment_size) {
00151                 send_len = data->fragment_size - 1;
00152                 flags |= IKEV2_FLAGS_MORE_FRAGMENTS;
00153                 if (data->out_used == 0) {
00154                         flags |= IKEV2_FLAGS_LENGTH_INCLUDED;
00155                         send_len -= 4;
00156                 }
00157         }
00158 #ifdef CCNS_PL
00159         /* Some issues figuring out the length of the message if Message Length
00160          * field not included?! */
00161         if (!(flags & IKEV2_FLAGS_LENGTH_INCLUDED))
00162                 flags |= IKEV2_FLAGS_LENGTH_INCLUDED;
00163 #endif /* CCNS_PL */
00164 
00165         plen = 1 + send_len;
00166         if (flags & IKEV2_FLAGS_LENGTH_INCLUDED)
00167                 plen += 4;
00168         if (data->keys_ready) {
00169                 const struct ikev2_integ_alg *integ;
00170                 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Add Integrity Checksum "
00171                            "Data");
00172                 flags |= IKEV2_FLAGS_ICV_INCLUDED;
00173                 integ = ikev2_get_integ(data->ikev2.proposal.integ);
00174                 if (integ == NULL) {
00175                         wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG "
00176                                    "transform / cannot generate ICV");
00177                         return NULL;
00178                 }
00179                 icv_len = integ->hash_len;
00180 
00181                 plen += icv_len;
00182         }
00183         resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, plen,
00184                              EAP_CODE_RESPONSE, id);
00185         if (resp == NULL)
00186                 return NULL;
00187 
00188         wpabuf_put_u8(resp, flags); /* Flags */
00189         if (flags & IKEV2_FLAGS_LENGTH_INCLUDED)
00190                 wpabuf_put_be32(resp, wpabuf_len(data->out_buf));
00191 
00192         wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used,
00193                         send_len);
00194         data->out_used += send_len;
00195 
00196         if (flags & IKEV2_FLAGS_ICV_INCLUDED) {
00197                 const u8 *msg = wpabuf_head(resp);
00198                 size_t len = wpabuf_len(resp);
00199                 ikev2_integ_hash(data->ikev2.proposal.integ,
00200                                  data->ikev2.keys.SK_ar,
00201                                  data->ikev2.keys.SK_integ_len,
00202                                  msg, len, wpabuf_put(resp, icv_len));
00203         }
00204 
00205         ret->methodState = METHOD_MAY_CONT;
00206         ret->decision = DECISION_FAIL;
00207 
00208         if (data->out_used == wpabuf_len(data->out_buf)) {
00209                 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes "
00210                            "(message sent completely)",
00211                            (unsigned long) send_len);
00212                 wpabuf_free(data->out_buf);
00213                 data->out_buf = NULL;
00214                 data->out_used = 0;
00215                 switch (data->ikev2.state) {
00216                 case SA_AUTH:
00217                         /* SA_INIT was sent out, so message have to be
00218                          * integrity protected from now on. */
00219                         data->keys_ready = 1;
00220                         break;
00221                 case IKEV2_DONE:
00222                         ret->methodState = METHOD_DONE;
00223                         if (data->state == FAIL)
00224                                 break;
00225                         ret->decision = DECISION_COND_SUCC;
00226                         wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication "
00227                                    "completed successfully");
00228                         if (eap_ikev2_peer_keymat(data))
00229                                 break;
00230                         eap_ikev2_state(data, DONE);
00231                         break;
00232                 case IKEV2_FAILED:
00233                         wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication "
00234                                    "failed");
00235                         ret->methodState = METHOD_DONE;
00236                         ret->decision = DECISION_FAIL;
00237                         break;
00238                 default:
00239                         break;
00240                 }
00241         } else {
00242                 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes "
00243                            "(%lu more to send)", (unsigned long) send_len,
00244                            (unsigned long) wpabuf_len(data->out_buf) -
00245                            data->out_used);
00246                 eap_ikev2_state(data, WAIT_FRAG_ACK);
00247         }
00248 
00249         return resp;
00250 }
00251 
00252 
00253 static int eap_ikev2_process_icv(struct eap_ikev2_data *data,
00254                                  const struct wpabuf *reqData,
00255                                  u8 flags, const u8 *pos, const u8 **end)
00256 {
00257         if (flags & IKEV2_FLAGS_ICV_INCLUDED) {
00258                 int icv_len = eap_ikev2_validate_icv(
00259                         data->ikev2.proposal.integ, &data->ikev2.keys, 1,
00260                         reqData, pos, *end);
00261                 if (icv_len < 0)
00262                         return -1;
00263                 /* Hide Integrity Checksum Data from further processing */
00264                 *end -= icv_len;
00265         } else if (data->keys_ready) {
00266                 wpa_printf(MSG_INFO, "EAP-IKEV2: The message should have "
00267                            "included integrity checksum");
00268                 return -1;
00269         }
00270 
00271         return 0;
00272 }
00273 
00274 
00275 static int eap_ikev2_process_cont(struct eap_ikev2_data *data,
00276                                   const u8 *buf, size_t len)
00277 {
00278         /* Process continuation of a pending message */
00279         if (len > wpabuf_tailroom(data->in_buf)) {
00280                 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment overflow");
00281                 eap_ikev2_state(data, FAIL);
00282                 return -1;
00283         }
00284 
00285         wpabuf_put_data(data->in_buf, buf, len);
00286         wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes, waiting "
00287                    "for %lu bytes more", (unsigned long) len,
00288                    (unsigned long) wpabuf_tailroom(data->in_buf));
00289 
00290         return 0;
00291 }
00292 
00293 
00294 static struct wpabuf * eap_ikev2_process_fragment(struct eap_ikev2_data *data,
00295                                                   struct eap_method_ret *ret,
00296                                                   u8 id, u8 flags,
00297                                                   u32 message_length,
00298                                                   const u8 *buf, size_t len)
00299 {
00300         /* Process a fragment that is not the last one of the message */
00301         if (data->in_buf == NULL && !(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) {
00302                 wpa_printf(MSG_DEBUG, "EAP-IKEV2: No Message Length field in "
00303                            "a fragmented packet");
00304                 ret->ignore = TRUE;
00305                 return NULL;
00306         }
00307 
00308         if (data->in_buf == NULL) {
00309                 /* First fragment of the message */
00310                 data->in_buf = wpabuf_alloc(message_length);
00311                 if (data->in_buf == NULL) {
00312                         wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for "
00313                                    "message");
00314                         ret->ignore = TRUE;
00315                         return NULL;
00316                 }
00317                 wpabuf_put_data(data->in_buf, buf, len);
00318                 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes in first "
00319                            "fragment, waiting for %lu bytes more",
00320                            (unsigned long) len,
00321                            (unsigned long) wpabuf_tailroom(data->in_buf));
00322         }
00323 
00324         return eap_ikev2_build_frag_ack(id, EAP_CODE_RESPONSE);
00325 }
00326 
00327 
00328 static struct wpabuf * eap_ikev2_process(struct eap_sm *sm, void *priv,
00329                                          struct eap_method_ret *ret,
00330                                          const struct wpabuf *reqData)
00331 {
00332         struct eap_ikev2_data *data = priv;
00333         const u8 *start, *pos, *end;
00334         size_t len;
00335         u8 flags, id;
00336         u32 message_length = 0;
00337         struct wpabuf tmpbuf;
00338 
00339         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, reqData, &len);
00340         if (pos == NULL) {
00341                 ret->ignore = TRUE;
00342                 return NULL;
00343         }
00344 
00345         id = eap_get_id(reqData);
00346 
00347         start = pos;
00348         end = start + len;
00349 
00350         if (len == 0)
00351                 flags = 0; /* fragment ack */
00352         else
00353                 flags = *pos++;
00354 
00355         if (eap_ikev2_process_icv(data, reqData, flags, pos, &end) < 0) {
00356                 ret->ignore = TRUE;
00357                 return NULL;
00358         }
00359 
00360         if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) {
00361                 if (end - pos < 4) {
00362                         wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow");
00363                         ret->ignore = TRUE;
00364                         return NULL;
00365                 }
00366                 message_length = WPA_GET_BE32(pos);
00367                 pos += 4;
00368 
00369                 if (message_length < (u32) (end - pos)) {
00370                         wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message "
00371                                    "Length (%d; %ld remaining in this msg)",
00372                                    message_length, (long) (end - pos));
00373                         ret->ignore = TRUE;
00374                         return NULL;
00375                 }
00376         }
00377 
00378         wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x "
00379                    "Message Length %u", flags, message_length);
00380 
00381         if (data->state == WAIT_FRAG_ACK) {
00382 #ifdef CCNS_PL
00383                 if (len > 1) /* Empty Flags field included in ACK */
00384 #else /* CCNS_PL */
00385                 if (len != 0)
00386 #endif /* CCNS_PL */
00387                 {
00388                         wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload "
00389                                    "in WAIT_FRAG_ACK state");
00390                         ret->ignore = TRUE;
00391                         return NULL;
00392                 }
00393                 wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged");
00394                 eap_ikev2_state(data, PROC_MSG);
00395                 return eap_ikev2_build_msg(data, ret, id);
00396         }
00397 
00398         if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) {
00399                 ret->ignore = TRUE;
00400                 return NULL;
00401         }
00402                 
00403         if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) {
00404                 return eap_ikev2_process_fragment(data, ret, id, flags,
00405                                                   message_length, pos,
00406                                                   end - pos);
00407         }
00408 
00409         if (data->in_buf == NULL) {
00410                 /* Wrap unfragmented messages as wpabuf without extra copy */
00411                 wpabuf_set(&tmpbuf, pos, end - pos);
00412                 data->in_buf = &tmpbuf;
00413         }
00414 
00415         if (ikev2_responder_process(&data->ikev2, data->in_buf) < 0) {
00416                 if (data->in_buf == &tmpbuf)
00417                         data->in_buf = NULL;
00418                 eap_ikev2_state(data, FAIL);
00419                 return NULL;
00420         }
00421 
00422         if (data->in_buf != &tmpbuf)
00423                 wpabuf_free(data->in_buf);
00424         data->in_buf = NULL;
00425 
00426         if (data->out_buf == NULL) {
00427                 data->out_buf = ikev2_responder_build(&data->ikev2);
00428                 if (data->out_buf == NULL) {
00429                         wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to generate "
00430                                    "IKEv2 message");
00431                         return NULL;
00432                 }
00433                 data->out_used = 0;
00434         }
00435 
00436         eap_ikev2_state(data, PROC_MSG);
00437         return eap_ikev2_build_msg(data, ret, id);
00438 }
00439 
00440 
00441 static Boolean eap_ikev2_isKeyAvailable(struct eap_sm *sm, void *priv)
00442 {
00443         struct eap_ikev2_data *data = priv;
00444         return data->state == DONE && data->keymat_ok;
00445 }
00446 
00447 
00448 static u8 * eap_ikev2_getKey(struct eap_sm *sm, void *priv, size_t *len)
00449 {
00450         struct eap_ikev2_data *data = priv;
00451         u8 *key;
00452 
00453         if (data->state != DONE || !data->keymat_ok)
00454                 return NULL;
00455 
00456         key = os_malloc(EAP_MSK_LEN);
00457         if (key) {
00458                 os_memcpy(key, data->keymat, EAP_MSK_LEN);
00459                 *len = EAP_MSK_LEN;
00460         }
00461 
00462         return key;
00463 }
00464 
00465 
00466 static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
00467 {
00468         struct eap_ikev2_data *data = priv;
00469         u8 *key;
00470 
00471         if (data->state != DONE || !data->keymat_ok)
00472                 return NULL;
00473 
00474         key = os_malloc(EAP_EMSK_LEN);
00475         if (key) {
00476                 os_memcpy(key, data->keymat + EAP_MSK_LEN, EAP_EMSK_LEN);
00477                 *len = EAP_EMSK_LEN;
00478         }
00479 
00480         return key;
00481 }
00482 
00483 
00484 int eap_peer_ikev2_register(void)
00485 {
00486         struct eap_method *eap;
00487         int ret;
00488 
00489         eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
00490                                     EAP_VENDOR_IETF, EAP_TYPE_IKEV2,
00491                                     "IKEV2");
00492         if (eap == NULL)
00493                 return -1;
00494 
00495         eap->init = eap_ikev2_init;
00496         eap->deinit = eap_ikev2_deinit;
00497         eap->process = eap_ikev2_process;
00498         eap->isKeyAvailable = eap_ikev2_isKeyAvailable;
00499         eap->getKey = eap_ikev2_getKey;
00500         eap->get_emsk = eap_ikev2_get_emsk;
00501 
00502         ret = eap_peer_method_register(eap);
00503         if (ret)
00504                 eap_peer_method_free(eap);
00505         return ret;
00506 }


wpa_supplicant_node
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Jan 2 2014 11:25:13