eap_server_aka.c
Go to the documentation of this file.
00001 /*
00002  * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf)
00003  * Copyright (c) 2005-2008, 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 "crypto/sha256.h"
00019 #include "crypto/crypto.h"
00020 #include "eap_common/eap_sim_common.h"
00021 #include "eap_server/eap_i.h"
00022 #include "eap_server/eap_sim_db.h"
00023 
00024 
00025 struct eap_aka_data {
00026         u8 mk[EAP_SIM_MK_LEN];
00027         u8 nonce_s[EAP_SIM_NONCE_S_LEN];
00028         u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
00029         u8 k_encr[EAP_SIM_K_ENCR_LEN];
00030         u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */
00031         u8 msk[EAP_SIM_KEYING_DATA_LEN];
00032         u8 emsk[EAP_EMSK_LEN];
00033         u8 rand[EAP_AKA_RAND_LEN];
00034         u8 autn[EAP_AKA_AUTN_LEN];
00035         u8 ck[EAP_AKA_CK_LEN];
00036         u8 ik[EAP_AKA_IK_LEN];
00037         u8 res[EAP_AKA_RES_MAX_LEN];
00038         size_t res_len;
00039         enum {
00040                 IDENTITY, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE
00041         } state;
00042         char *next_pseudonym;
00043         char *next_reauth_id;
00044         u16 counter;
00045         struct eap_sim_reauth *reauth;
00046         int auts_reported; /* whether the current AUTS has been reported to the
00047                             * eap_sim_db */
00048         u16 notification;
00049         int use_result_ind;
00050 
00051         struct wpabuf *id_msgs;
00052         int pending_id;
00053         u8 eap_method;
00054         u8 *network_name;
00055         size_t network_name_len;
00056         u16 kdf;
00057 };
00058 
00059 
00060 static void eap_aka_determine_identity(struct eap_sm *sm,
00061                                        struct eap_aka_data *data,
00062                                        int before_identity, int after_reauth);
00063 
00064 
00065 static const char * eap_aka_state_txt(int state)
00066 {
00067         switch (state) {
00068         case IDENTITY:
00069                 return "IDENTITY";
00070         case CHALLENGE:
00071                 return "CHALLENGE";
00072         case REAUTH:
00073                 return "REAUTH";
00074         case SUCCESS:
00075                 return "SUCCESS";
00076         case FAILURE:
00077                 return "FAILURE";
00078         case NOTIFICATION:
00079                 return "NOTIFICATION";
00080         default:
00081                 return "Unknown?!";
00082         }
00083 }
00084 
00085 
00086 static void eap_aka_state(struct eap_aka_data *data, int state)
00087 {
00088         wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s",
00089                    eap_aka_state_txt(data->state),
00090                    eap_aka_state_txt(state));
00091         data->state = state;
00092 }
00093 
00094 
00095 static void * eap_aka_init(struct eap_sm *sm)
00096 {
00097         struct eap_aka_data *data;
00098 
00099         if (sm->eap_sim_db_priv == NULL) {
00100                 wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
00101                 return NULL;
00102         }
00103 
00104         data = os_zalloc(sizeof(*data));
00105         if (data == NULL)
00106                 return NULL;
00107 
00108         data->eap_method = EAP_TYPE_AKA;
00109 
00110         data->state = IDENTITY;
00111         eap_aka_determine_identity(sm, data, 1, 0);
00112         data->pending_id = -1;
00113 
00114         return data;
00115 }
00116 
00117 
00118 #ifdef EAP_SERVER_AKA_PRIME
00119 static void * eap_aka_prime_init(struct eap_sm *sm)
00120 {
00121         struct eap_aka_data *data;
00122         /* TODO: make ANID configurable; see 3GPP TS 24.302 */
00123         char *network_name = "WLAN";
00124 
00125         if (sm->eap_sim_db_priv == NULL) {
00126                 wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
00127                 return NULL;
00128         }
00129 
00130         data = os_zalloc(sizeof(*data));
00131         if (data == NULL)
00132                 return NULL;
00133 
00134         data->eap_method = EAP_TYPE_AKA_PRIME;
00135         data->network_name = os_malloc(os_strlen(network_name));
00136         if (data->network_name == NULL) {
00137                 os_free(data);
00138                 return NULL;
00139         }
00140 
00141         data->network_name_len = os_strlen(network_name);
00142         os_memcpy(data->network_name, network_name, data->network_name_len);
00143 
00144         data->state = IDENTITY;
00145         eap_aka_determine_identity(sm, data, 1, 0);
00146         data->pending_id = -1;
00147 
00148         return data;
00149 }
00150 #endif /* EAP_SERVER_AKA_PRIME */
00151 
00152 
00153 static void eap_aka_reset(struct eap_sm *sm, void *priv)
00154 {
00155         struct eap_aka_data *data = priv;
00156         os_free(data->next_pseudonym);
00157         os_free(data->next_reauth_id);
00158         wpabuf_free(data->id_msgs);
00159         os_free(data->network_name);
00160         os_free(data);
00161 }
00162 
00163 
00164 static int eap_aka_add_id_msg(struct eap_aka_data *data,
00165                               const struct wpabuf *msg)
00166 {
00167         if (msg == NULL)
00168                 return -1;
00169 
00170         if (data->id_msgs == NULL) {
00171                 data->id_msgs = wpabuf_dup(msg);
00172                 return data->id_msgs == NULL ? -1 : 0;
00173         }
00174 
00175         if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0)
00176                 return -1;
00177         wpabuf_put_buf(data->id_msgs, msg);
00178 
00179         return 0;
00180 }
00181 
00182 
00183 static void eap_aka_add_checkcode(struct eap_aka_data *data,
00184                                   struct eap_sim_msg *msg)
00185 {
00186         const u8 *addr;
00187         size_t len;
00188         u8 hash[SHA256_MAC_LEN];
00189 
00190         wpa_printf(MSG_DEBUG, "   AT_CHECKCODE");
00191 
00192         if (data->id_msgs == NULL) {
00193                 /*
00194                  * No EAP-AKA/Identity packets were exchanged - send empty
00195                  * checkcode.
00196                  */
00197                 eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0);
00198                 return;
00199         }
00200 
00201         /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
00202         addr = wpabuf_head(data->id_msgs);
00203         len = wpabuf_len(data->id_msgs);
00204         wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len);
00205         if (data->eap_method == EAP_TYPE_AKA_PRIME)
00206                 sha256_vector(1, &addr, &len, hash);
00207         else
00208                 sha1_vector(1, &addr, &len, hash);
00209 
00210         eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash,
00211                         data->eap_method == EAP_TYPE_AKA_PRIME ?
00212                         EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN);
00213 }
00214 
00215 
00216 static int eap_aka_verify_checkcode(struct eap_aka_data *data,
00217                                     const u8 *checkcode, size_t checkcode_len)
00218 {
00219         const u8 *addr;
00220         size_t len;
00221         u8 hash[SHA256_MAC_LEN];
00222         size_t hash_len;
00223 
00224         if (checkcode == NULL)
00225                 return -1;
00226 
00227         if (data->id_msgs == NULL) {
00228                 if (checkcode_len != 0) {
00229                         wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer "
00230                                    "indicates that AKA/Identity messages were "
00231                                    "used, but they were not");
00232                         return -1;
00233                 }
00234                 return 0;
00235         }
00236 
00237         hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ?
00238                 EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN;
00239 
00240         if (checkcode_len != hash_len) {
00241                 wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer indicates "
00242                            "that AKA/Identity message were not used, but they "
00243                            "were");
00244                 return -1;
00245         }
00246 
00247         /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
00248         addr = wpabuf_head(data->id_msgs);
00249         len = wpabuf_len(data->id_msgs);
00250         if (data->eap_method == EAP_TYPE_AKA_PRIME)
00251                 sha256_vector(1, &addr, &len, hash);
00252         else
00253                 sha1_vector(1, &addr, &len, hash);
00254 
00255         if (os_memcmp(hash, checkcode, hash_len) != 0) {
00256                 wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
00257                 return -1;
00258         }
00259 
00260         return 0;
00261 }
00262 
00263 
00264 static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm,
00265                                               struct eap_aka_data *data, u8 id)
00266 {
00267         struct eap_sim_msg *msg;
00268         struct wpabuf *buf;
00269 
00270         wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity");
00271         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
00272                                EAP_AKA_SUBTYPE_IDENTITY);
00273         if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
00274                                       sm->identity_len)) {
00275                 wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
00276                 eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
00277         } else {
00278                 /*
00279                  * RFC 4187, Chap. 4.1.4 recommends that identity from EAP is
00280                  * ignored and the AKA/Identity is used to request the
00281                  * identity.
00282                  */
00283                 wpa_printf(MSG_DEBUG, "   AT_ANY_ID_REQ");
00284                 eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
00285         }
00286         buf = eap_sim_msg_finish(msg, NULL, NULL, 0);
00287         if (eap_aka_add_id_msg(data, buf) < 0) {
00288                 wpabuf_free(buf);
00289                 return NULL;
00290         }
00291         data->pending_id = id;
00292         return buf;
00293 }
00294 
00295 
00296 static int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data,
00297                               struct eap_sim_msg *msg, u16 counter,
00298                               const u8 *nonce_s)
00299 {
00300         os_free(data->next_pseudonym);
00301         data->next_pseudonym =
00302                 eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 1);
00303         os_free(data->next_reauth_id);
00304         if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) {
00305                 data->next_reauth_id =
00306                         eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 1);
00307         } else {
00308                 wpa_printf(MSG_DEBUG, "EAP-AKA: Max fast re-authentication "
00309                            "count exceeded - force full authentication");
00310                 data->next_reauth_id = NULL;
00311         }
00312 
00313         if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
00314             counter == 0 && nonce_s == NULL)
00315                 return 0;
00316 
00317         wpa_printf(MSG_DEBUG, "   AT_IV");
00318         wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
00319         eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
00320 
00321         if (counter > 0) {
00322                 wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)", counter);
00323                 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
00324         }
00325 
00326         if (nonce_s) {
00327                 wpa_printf(MSG_DEBUG, "   *AT_NONCE_S");
00328                 eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
00329                                 EAP_SIM_NONCE_S_LEN);
00330         }
00331 
00332         if (data->next_pseudonym) {
00333                 wpa_printf(MSG_DEBUG, "   *AT_NEXT_PSEUDONYM (%s)",
00334                            data->next_pseudonym);
00335                 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
00336                                 os_strlen(data->next_pseudonym),
00337                                 (u8 *) data->next_pseudonym,
00338                                 os_strlen(data->next_pseudonym));
00339         }
00340 
00341         if (data->next_reauth_id) {
00342                 wpa_printf(MSG_DEBUG, "   *AT_NEXT_REAUTH_ID (%s)",
00343                            data->next_reauth_id);
00344                 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
00345                                 os_strlen(data->next_reauth_id),
00346                                 (u8 *) data->next_reauth_id,
00347                                 os_strlen(data->next_reauth_id));
00348         }
00349 
00350         if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
00351                 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
00352                            "AT_ENCR_DATA");
00353                 return -1;
00354         }
00355 
00356         return 0;
00357 }
00358 
00359 
00360 static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm,
00361                                                struct eap_aka_data *data,
00362                                                u8 id)
00363 {
00364         struct eap_sim_msg *msg;
00365 
00366         wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Challenge");
00367         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
00368                                EAP_AKA_SUBTYPE_CHALLENGE);
00369         wpa_printf(MSG_DEBUG, "   AT_RAND");
00370         eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, data->rand, EAP_AKA_RAND_LEN);
00371         wpa_printf(MSG_DEBUG, "   AT_AUTN");
00372         eap_sim_msg_add(msg, EAP_SIM_AT_AUTN, 0, data->autn, EAP_AKA_AUTN_LEN);
00373         if (data->eap_method == EAP_TYPE_AKA_PRIME) {
00374                 if (data->kdf) {
00375                         /* Add the selected KDF into the beginning */
00376                         wpa_printf(MSG_DEBUG, "   AT_KDF");
00377                         eap_sim_msg_add(msg, EAP_SIM_AT_KDF, data->kdf,
00378                                         NULL, 0);
00379                 }
00380                 wpa_printf(MSG_DEBUG, "   AT_KDF");
00381                 eap_sim_msg_add(msg, EAP_SIM_AT_KDF, EAP_AKA_PRIME_KDF,
00382                                 NULL, 0);
00383                 wpa_printf(MSG_DEBUG, "   AT_KDF_INPUT");
00384                 eap_sim_msg_add(msg, EAP_SIM_AT_KDF_INPUT,
00385                                 data->network_name_len,
00386                                 data->network_name, data->network_name_len);
00387         }
00388 
00389         if (eap_aka_build_encr(sm, data, msg, 0, NULL)) {
00390                 eap_sim_msg_free(msg);
00391                 return NULL;
00392         }
00393 
00394         eap_aka_add_checkcode(data, msg);
00395 
00396         if (sm->eap_sim_aka_result_ind) {
00397                 wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
00398                 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
00399         }
00400 
00401 #ifdef EAP_SERVER_AKA_PRIME
00402         if (data->eap_method == EAP_TYPE_AKA) {
00403                 u16 flags = 0;
00404                 int i;
00405                 int aka_prime_preferred = 0;
00406 
00407                 i = 0;
00408                 while (sm->user && i < EAP_MAX_METHODS &&
00409                        (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
00410                         sm->user->methods[i].method != EAP_TYPE_NONE)) {
00411                         if (sm->user->methods[i].vendor == EAP_VENDOR_IETF) {
00412                                 if (sm->user->methods[i].method ==
00413                                     EAP_TYPE_AKA)
00414                                         break;
00415                                 if (sm->user->methods[i].method ==
00416                                     EAP_TYPE_AKA_PRIME) {
00417                                         aka_prime_preferred = 1;
00418                                         break;
00419                                 }
00420                         }
00421                         i++;
00422                 }
00423 
00424                 if (aka_prime_preferred)
00425                         flags |= EAP_AKA_BIDDING_FLAG_D;
00426                 eap_sim_msg_add(msg, EAP_SIM_AT_BIDDING, flags, NULL, 0);
00427         }
00428 #endif /* EAP_SERVER_AKA_PRIME */
00429 
00430         wpa_printf(MSG_DEBUG, "   AT_MAC");
00431         eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
00432         return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
00433 }
00434 
00435 
00436 static struct wpabuf * eap_aka_build_reauth(struct eap_sm *sm,
00437                                             struct eap_aka_data *data, u8 id)
00438 {
00439         struct eap_sim_msg *msg;
00440 
00441         wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Re-authentication");
00442 
00443         if (os_get_random(data->nonce_s, EAP_SIM_NONCE_S_LEN))
00444                 return NULL;
00445         wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA: NONCE_S",
00446                         data->nonce_s, EAP_SIM_NONCE_S_LEN);
00447 
00448         if (data->eap_method == EAP_TYPE_AKA_PRIME) {
00449                 eap_aka_prime_derive_keys_reauth(data->k_re, data->counter,
00450                                                  sm->identity,
00451                                                  sm->identity_len,
00452                                                  data->nonce_s,
00453                                                  data->msk, data->emsk);
00454         } else {
00455                 eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
00456                                     data->msk, data->emsk);
00457                 eap_sim_derive_keys_reauth(data->counter, sm->identity,
00458                                            sm->identity_len, data->nonce_s,
00459                                            data->mk, data->msk, data->emsk);
00460         }
00461 
00462         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
00463                                EAP_AKA_SUBTYPE_REAUTHENTICATION);
00464 
00465         if (eap_aka_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
00466                 eap_sim_msg_free(msg);
00467                 return NULL;
00468         }
00469 
00470         eap_aka_add_checkcode(data, msg);
00471 
00472         if (sm->eap_sim_aka_result_ind) {
00473                 wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
00474                 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
00475         }
00476 
00477         wpa_printf(MSG_DEBUG, "   AT_MAC");
00478         eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
00479         return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
00480 }
00481 
00482 
00483 static struct wpabuf * eap_aka_build_notification(struct eap_sm *sm,
00484                                                   struct eap_aka_data *data,
00485                                                   u8 id)
00486 {
00487         struct eap_sim_msg *msg;
00488 
00489         wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Notification");
00490         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
00491                                EAP_AKA_SUBTYPE_NOTIFICATION);
00492         wpa_printf(MSG_DEBUG, "   AT_NOTIFICATION (%d)", data->notification);
00493         eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification,
00494                         NULL, 0);
00495         if (data->use_result_ind) {
00496                 if (data->reauth) {
00497                         wpa_printf(MSG_DEBUG, "   AT_IV");
00498                         wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
00499                         eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
00500                                                    EAP_SIM_AT_ENCR_DATA);
00501                         wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)",
00502                                    data->counter);
00503                         eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
00504                                         NULL, 0);
00505 
00506                         if (eap_sim_msg_add_encr_end(msg, data->k_encr,
00507                                                      EAP_SIM_AT_PADDING)) {
00508                                 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to "
00509                                            "encrypt AT_ENCR_DATA");
00510                                 eap_sim_msg_free(msg);
00511                                 return NULL;
00512                         }
00513                 }
00514 
00515                 wpa_printf(MSG_DEBUG, "   AT_MAC");
00516                 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
00517         }
00518         return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
00519 }
00520 
00521 
00522 static struct wpabuf * eap_aka_buildReq(struct eap_sm *sm, void *priv, u8 id)
00523 {
00524         struct eap_aka_data *data = priv;
00525 
00526         data->auts_reported = 0;
00527         switch (data->state) {
00528         case IDENTITY:
00529                 return eap_aka_build_identity(sm, data, id);
00530         case CHALLENGE:
00531                 return eap_aka_build_challenge(sm, data, id);
00532         case REAUTH:
00533                 return eap_aka_build_reauth(sm, data, id);
00534         case NOTIFICATION:
00535                 return eap_aka_build_notification(sm, data, id);
00536         default:
00537                 wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
00538                            "buildReq", data->state);
00539                 break;
00540         }
00541         return NULL;
00542 }
00543 
00544 
00545 static Boolean eap_aka_check(struct eap_sm *sm, void *priv,
00546                              struct wpabuf *respData)
00547 {
00548         struct eap_aka_data *data = priv;
00549         const u8 *pos;
00550         size_t len;
00551 
00552         pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
00553                                &len);
00554         if (pos == NULL || len < 3) {
00555                 wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame");
00556                 return TRUE;
00557         }
00558 
00559         return FALSE;
00560 }
00561 
00562 
00563 static Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype)
00564 {
00565         if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR ||
00566             subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT)
00567                 return FALSE;
00568 
00569         switch (data->state) {
00570         case IDENTITY:
00571                 if (subtype != EAP_AKA_SUBTYPE_IDENTITY) {
00572                         wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
00573                                    "subtype %d", subtype);
00574                         return TRUE;
00575                 }
00576                 break;
00577         case CHALLENGE:
00578                 if (subtype != EAP_AKA_SUBTYPE_CHALLENGE &&
00579                     subtype != EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
00580                         wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
00581                                    "subtype %d", subtype);
00582                         return TRUE;
00583                 }
00584                 break;
00585         case REAUTH:
00586                 if (subtype != EAP_AKA_SUBTYPE_REAUTHENTICATION) {
00587                         wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
00588                                    "subtype %d", subtype);
00589                         return TRUE;
00590                 }
00591                 break;
00592         case NOTIFICATION:
00593                 if (subtype != EAP_AKA_SUBTYPE_NOTIFICATION) {
00594                         wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
00595                                    "subtype %d", subtype);
00596                         return TRUE;
00597                 }
00598                 break;
00599         default:
00600                 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected state (%d) for "
00601                            "processing a response", data->state);
00602                 return TRUE;
00603         }
00604 
00605         return FALSE;
00606 }
00607 
00608 
00609 static void eap_aka_determine_identity(struct eap_sm *sm,
00610                                        struct eap_aka_data *data,
00611                                        int before_identity, int after_reauth)
00612 {
00613         const u8 *identity;
00614         size_t identity_len;
00615         int res;
00616 
00617         identity = NULL;
00618         identity_len = 0;
00619 
00620         if (after_reauth && data->reauth) {
00621                 identity = data->reauth->identity;
00622                 identity_len = data->reauth->identity_len;
00623         } else if (sm->identity && sm->identity_len > 0 &&
00624                    sm->identity[0] == EAP_AKA_PERMANENT_PREFIX) {
00625                 identity = sm->identity;
00626                 identity_len = sm->identity_len;
00627         } else {
00628                 identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv,
00629                                                     sm->identity,
00630                                                     sm->identity_len,
00631                                                     &identity_len);
00632                 if (identity == NULL) {
00633                         data->reauth = eap_sim_db_get_reauth_entry(
00634                                 sm->eap_sim_db_priv, sm->identity,
00635                                 sm->identity_len);
00636                         if (data->reauth &&
00637                             data->reauth->aka_prime !=
00638                             (data->eap_method == EAP_TYPE_AKA_PRIME)) {
00639                                 wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth data "
00640                                            "was for different AKA version");
00641                                 data->reauth = NULL;
00642                         }
00643                         if (data->reauth) {
00644                                 wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast "
00645                                            "re-authentication");
00646                                 identity = data->reauth->identity;
00647                                 identity_len = data->reauth->identity_len;
00648                                 data->counter = data->reauth->counter;
00649                                 if (data->eap_method == EAP_TYPE_AKA_PRIME) {
00650                                         os_memcpy(data->k_encr,
00651                                                   data->reauth->k_encr,
00652                                                   EAP_SIM_K_ENCR_LEN);
00653                                         os_memcpy(data->k_aut,
00654                                                   data->reauth->k_aut,
00655                                                   EAP_AKA_PRIME_K_AUT_LEN);
00656                                         os_memcpy(data->k_re,
00657                                                   data->reauth->k_re,
00658                                                   EAP_AKA_PRIME_K_RE_LEN);
00659                                 } else {
00660                                         os_memcpy(data->mk, data->reauth->mk,
00661                                                   EAP_SIM_MK_LEN);
00662                                 }
00663                         }
00664                 }
00665         }
00666 
00667         if (identity == NULL ||
00668             eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
00669                                       sm->identity_len) < 0) {
00670                 if (before_identity) {
00671                         wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent user name "
00672                                    "not known - send AKA-Identity request");
00673                         eap_aka_state(data, IDENTITY);
00674                         return;
00675                 } else {
00676                         wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown whether the "
00677                                    "permanent user name is known; try to use "
00678                                    "it");
00679                         /* eap_sim_db_get_aka_auth() will report failure, if
00680                          * this identity is not known. */
00681                 }
00682         }
00683 
00684         wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity",
00685                           identity, identity_len);
00686 
00687         if (!after_reauth && data->reauth) {
00688                 eap_aka_state(data, REAUTH);
00689                 return;
00690         }
00691 
00692         res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, identity,
00693                                       identity_len, data->rand, data->autn,
00694                                       data->ik, data->ck, data->res,
00695                                       &data->res_len, sm);
00696         if (res == EAP_SIM_DB_PENDING) {
00697                 wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
00698                            "not yet available - pending request");
00699                 sm->method_pending = METHOD_PENDING_WAIT;
00700                 return;
00701         }
00702 
00703 #ifdef EAP_SERVER_AKA_PRIME
00704         if (data->eap_method == EAP_TYPE_AKA_PRIME) {
00705                 /* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
00706                  * needed 6-octet SQN ^AK for CK',IK' derivation */
00707                 eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
00708                                                  data->autn,
00709                                                  data->network_name,
00710                                                  data->network_name_len);
00711         }
00712 #endif /* EAP_SERVER_AKA_PRIME */
00713 
00714         data->reauth = NULL;
00715         data->counter = 0; /* reset re-auth counter since this is full auth */
00716 
00717         if (res != 0) {
00718                 wpa_printf(MSG_INFO, "EAP-AKA: Failed to get AKA "
00719                            "authentication data for the peer");
00720                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
00721                 eap_aka_state(data, NOTIFICATION);
00722                 return;
00723         }
00724         if (sm->method_pending == METHOD_PENDING_WAIT) {
00725                 wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
00726                            "available - abort pending wait");
00727                 sm->method_pending = METHOD_PENDING_NONE;
00728         }
00729 
00730         identity_len = sm->identity_len;
00731         while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') {
00732                 wpa_printf(MSG_DEBUG, "EAP-AKA: Workaround - drop last null "
00733                            "character from identity");
00734                 identity_len--;
00735         }
00736         wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation",
00737                           sm->identity, identity_len);
00738 
00739         if (data->eap_method == EAP_TYPE_AKA_PRIME) {
00740                 eap_aka_prime_derive_keys(identity, identity_len, data->ik,
00741                                           data->ck, data->k_encr, data->k_aut,
00742                                           data->k_re, data->msk, data->emsk);
00743         } else {
00744                 eap_aka_derive_mk(sm->identity, identity_len, data->ik,
00745                                   data->ck, data->mk);
00746                 eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
00747                                     data->msk, data->emsk);
00748         }
00749 
00750         eap_aka_state(data, CHALLENGE);
00751 }
00752 
00753 
00754 static void eap_aka_process_identity(struct eap_sm *sm,
00755                                      struct eap_aka_data *data,
00756                                      struct wpabuf *respData,
00757                                      struct eap_sim_attrs *attr)
00758 {
00759         wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Identity");
00760 
00761         if (attr->mac || attr->iv || attr->encr_data) {
00762                 wpa_printf(MSG_WARNING, "EAP-AKA: Unexpected attribute "
00763                            "received in EAP-Response/AKA-Identity");
00764                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
00765                 eap_aka_state(data, NOTIFICATION);
00766                 return;
00767         }
00768 
00769         if (attr->identity) {
00770                 os_free(sm->identity);
00771                 sm->identity = os_malloc(attr->identity_len);
00772                 if (sm->identity) {
00773                         os_memcpy(sm->identity, attr->identity,
00774                                   attr->identity_len);
00775                         sm->identity_len = attr->identity_len;
00776                 }
00777         }
00778 
00779         eap_aka_determine_identity(sm, data, 0, 0);
00780         if (eap_get_id(respData) == data->pending_id) {
00781                 data->pending_id = -1;
00782                 eap_aka_add_id_msg(data, respData);
00783         }
00784 }
00785 
00786 
00787 static int eap_aka_verify_mac(struct eap_aka_data *data,
00788                               const struct wpabuf *req,
00789                               const u8 *mac, const u8 *extra,
00790                               size_t extra_len)
00791 {
00792         if (data->eap_method == EAP_TYPE_AKA_PRIME)
00793                 return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra,
00794                                                  extra_len);
00795         return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len);
00796 }
00797 
00798 
00799 static void eap_aka_process_challenge(struct eap_sm *sm,
00800                                       struct eap_aka_data *data,
00801                                       struct wpabuf *respData,
00802                                       struct eap_sim_attrs *attr)
00803 {
00804         const u8 *identity;
00805         size_t identity_len;
00806 
00807         wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge");
00808 
00809 #ifdef EAP_SERVER_AKA_PRIME
00810 #if 0
00811         /* KDF negotiation; to be enabled only after more than one KDF is
00812          * supported */
00813         if (data->eap_method == EAP_TYPE_AKA_PRIME &&
00814             attr->kdf_count == 1 && attr->mac == NULL) {
00815                 if (attr->kdf[0] != EAP_AKA_PRIME_KDF) {
00816                         wpa_printf(MSG_WARNING, "EAP-AKA': Peer selected "
00817                                    "unknown KDF");
00818                         data->notification =
00819                                 EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
00820                         eap_aka_state(data, NOTIFICATION);
00821                         return;
00822                 }
00823 
00824                 data->kdf = attr->kdf[0];
00825 
00826                 /* Allow negotiation to continue with the selected KDF by
00827                  * sending another Challenge message */
00828                 wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf);
00829                 return;
00830         }
00831 #endif
00832 #endif /* EAP_SERVER_AKA_PRIME */
00833 
00834         if (attr->checkcode &&
00835             eap_aka_verify_checkcode(data, attr->checkcode,
00836                                      attr->checkcode_len)) {
00837                 wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
00838                            "message");
00839                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
00840                 eap_aka_state(data, NOTIFICATION);
00841                 return;
00842         }
00843         if (attr->mac == NULL ||
00844             eap_aka_verify_mac(data, respData, attr->mac, NULL, 0)) {
00845                 wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
00846                            "did not include valid AT_MAC");
00847                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
00848                 eap_aka_state(data, NOTIFICATION);
00849                 return;
00850         }
00851 
00852         /*
00853          * AT_RES is padded, so verify that there is enough room for RES and
00854          * that the RES length in bits matches with the expected RES.
00855          */
00856         if (attr->res == NULL || attr->res_len < data->res_len ||
00857             attr->res_len_bits != data->res_len * 8 ||
00858             os_memcmp(attr->res, data->res, data->res_len) != 0) {
00859                 wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message did not "
00860                            "include valid AT_RES (attr len=%lu, res len=%lu "
00861                            "bits, expected %lu bits)",
00862                            (unsigned long) attr->res_len,
00863                            (unsigned long) attr->res_len_bits,
00864                            (unsigned long) data->res_len * 8);
00865                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
00866                 eap_aka_state(data, NOTIFICATION);
00867                 return;
00868         }
00869 
00870         wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the "
00871                    "correct AT_MAC");
00872         if (sm->eap_sim_aka_result_ind && attr->result_ind) {
00873                 data->use_result_ind = 1;
00874                 data->notification = EAP_SIM_SUCCESS;
00875                 eap_aka_state(data, NOTIFICATION);
00876         } else
00877                 eap_aka_state(data, SUCCESS);
00878 
00879         identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity,
00880                                             sm->identity_len, &identity_len);
00881         if (identity == NULL) {
00882                 identity = sm->identity;
00883                 identity_len = sm->identity_len;
00884         }
00885 
00886         if (data->next_pseudonym) {
00887                 eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
00888                                          identity_len,
00889                                          data->next_pseudonym);
00890                 data->next_pseudonym = NULL;
00891         }
00892         if (data->next_reauth_id) {
00893                 if (data->eap_method == EAP_TYPE_AKA_PRIME) {
00894 #ifdef EAP_SERVER_AKA_PRIME
00895                         eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
00896                                                     identity,
00897                                                     identity_len,
00898                                                     data->next_reauth_id,
00899                                                     data->counter + 1,
00900                                                     data->k_encr, data->k_aut,
00901                                                     data->k_re);
00902 #endif /* EAP_SERVER_AKA_PRIME */
00903                 } else {
00904                         eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
00905                                               identity_len,
00906                                               data->next_reauth_id,
00907                                               data->counter + 1,
00908                                               data->mk);
00909                 }
00910                 data->next_reauth_id = NULL;
00911         }
00912 }
00913 
00914 
00915 static void eap_aka_process_sync_failure(struct eap_sm *sm,
00916                                          struct eap_aka_data *data,
00917                                          struct wpabuf *respData,
00918                                          struct eap_sim_attrs *attr)
00919 {
00920         wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Synchronization-Failure");
00921 
00922         if (attr->auts == NULL) {
00923                 wpa_printf(MSG_WARNING, "EAP-AKA: Synchronization-Failure "
00924                            "message did not include valid AT_AUTS");
00925                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
00926                 eap_aka_state(data, NOTIFICATION);
00927                 return;
00928         }
00929 
00930         /* Avoid re-reporting AUTS when processing pending EAP packet by
00931          * maintaining a local flag stating whether this AUTS has already been
00932          * reported. */
00933         if (!data->auts_reported &&
00934             eap_sim_db_resynchronize(sm->eap_sim_db_priv, sm->identity,
00935                                      sm->identity_len, attr->auts,
00936                                      data->rand)) {
00937                 wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed");
00938                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
00939                 eap_aka_state(data, NOTIFICATION);
00940                 return;
00941         }
00942         data->auts_reported = 1;
00943 
00944         /* Try again after resynchronization */
00945         eap_aka_determine_identity(sm, data, 0, 0);
00946 }
00947 
00948 
00949 static void eap_aka_process_reauth(struct eap_sm *sm,
00950                                    struct eap_aka_data *data,
00951                                    struct wpabuf *respData,
00952                                    struct eap_sim_attrs *attr)
00953 {
00954         struct eap_sim_attrs eattr;
00955         u8 *decrypted = NULL;
00956         const u8 *identity, *id2;
00957         size_t identity_len, id2_len;
00958 
00959         wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication");
00960 
00961         if (attr->mac == NULL ||
00962             eap_aka_verify_mac(data, respData, attr->mac, data->nonce_s,
00963                                EAP_SIM_NONCE_S_LEN)) {
00964                 wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
00965                            "did not include valid AT_MAC");
00966                 goto fail;
00967         }
00968 
00969         if (attr->encr_data == NULL || attr->iv == NULL) {
00970                 wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
00971                            "message did not include encrypted data");
00972                 goto fail;
00973         }
00974 
00975         decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
00976                                        attr->encr_data_len, attr->iv, &eattr,
00977                                        0);
00978         if (decrypted == NULL) {
00979                 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
00980                            "data from reauthentication message");
00981                 goto fail;
00982         }
00983 
00984         if (eattr.counter != data->counter) {
00985                 wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
00986                            "used incorrect counter %u, expected %u",
00987                            eattr.counter, data->counter);
00988                 goto fail;
00989         }
00990         os_free(decrypted);
00991         decrypted = NULL;
00992 
00993         wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response includes "
00994                    "the correct AT_MAC");
00995 
00996         if (eattr.counter_too_small) {
00997                 wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response "
00998                            "included AT_COUNTER_TOO_SMALL - starting full "
00999                            "authentication");
01000                 eap_aka_determine_identity(sm, data, 0, 1);
01001                 return;
01002         }
01003 
01004         if (sm->eap_sim_aka_result_ind && attr->result_ind) {
01005                 data->use_result_ind = 1;
01006                 data->notification = EAP_SIM_SUCCESS;
01007                 eap_aka_state(data, NOTIFICATION);
01008         } else
01009                 eap_aka_state(data, SUCCESS);
01010 
01011         if (data->reauth) {
01012                 identity = data->reauth->identity;
01013                 identity_len = data->reauth->identity_len;
01014         } else {
01015                 identity = sm->identity;
01016                 identity_len = sm->identity_len;
01017         }
01018 
01019         id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity,
01020                                        identity_len, &id2_len);
01021         if (id2) {
01022                 identity = id2;
01023                 identity_len = id2_len;
01024         }
01025 
01026         if (data->next_pseudonym) {
01027                 eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
01028                                          identity_len, data->next_pseudonym);
01029                 data->next_pseudonym = NULL;
01030         }
01031         if (data->next_reauth_id) {
01032                 if (data->eap_method == EAP_TYPE_AKA_PRIME) {
01033 #ifdef EAP_SERVER_AKA_PRIME
01034                         eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
01035                                                     identity,
01036                                                     identity_len,
01037                                                     data->next_reauth_id,
01038                                                     data->counter + 1,
01039                                                     data->k_encr, data->k_aut,
01040                                                     data->k_re);
01041 #endif /* EAP_SERVER_AKA_PRIME */
01042                 } else {
01043                         eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
01044                                               identity_len,
01045                                               data->next_reauth_id,
01046                                               data->counter + 1,
01047                                               data->mk);
01048                 }
01049                 data->next_reauth_id = NULL;
01050         } else {
01051                 eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
01052                 data->reauth = NULL;
01053         }
01054 
01055         return;
01056 
01057 fail:
01058         data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
01059         eap_aka_state(data, NOTIFICATION);
01060         eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
01061         data->reauth = NULL;
01062         os_free(decrypted);
01063 }
01064 
01065 
01066 static void eap_aka_process_client_error(struct eap_sm *sm,
01067                                          struct eap_aka_data *data,
01068                                          struct wpabuf *respData,
01069                                          struct eap_sim_attrs *attr)
01070 {
01071         wpa_printf(MSG_DEBUG, "EAP-AKA: Client reported error %d",
01072                    attr->client_error_code);
01073         if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
01074                 eap_aka_state(data, SUCCESS);
01075         else
01076                 eap_aka_state(data, FAILURE);
01077 }
01078 
01079 
01080 static void eap_aka_process_authentication_reject(
01081         struct eap_sm *sm, struct eap_aka_data *data,
01082         struct wpabuf *respData, struct eap_sim_attrs *attr)
01083 {
01084         wpa_printf(MSG_DEBUG, "EAP-AKA: Client rejected authentication");
01085         eap_aka_state(data, FAILURE);
01086 }
01087 
01088 
01089 static void eap_aka_process_notification(struct eap_sm *sm,
01090                                          struct eap_aka_data *data,
01091                                          struct wpabuf *respData,
01092                                          struct eap_sim_attrs *attr)
01093 {
01094         wpa_printf(MSG_DEBUG, "EAP-AKA: Client replied to notification");
01095         if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
01096                 eap_aka_state(data, SUCCESS);
01097         else
01098                 eap_aka_state(data, FAILURE);
01099 }
01100 
01101 
01102 static void eap_aka_process(struct eap_sm *sm, void *priv,
01103                             struct wpabuf *respData)
01104 {
01105         struct eap_aka_data *data = priv;
01106         const u8 *pos, *end;
01107         u8 subtype;
01108         size_t len;
01109         struct eap_sim_attrs attr;
01110 
01111         pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
01112                                &len);
01113         if (pos == NULL || len < 3)
01114                 return;
01115 
01116         end = pos + len;
01117         subtype = *pos;
01118         pos += 3;
01119 
01120         if (eap_aka_subtype_ok(data, subtype)) {
01121                 wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized or unexpected "
01122                            "EAP-AKA Subtype in EAP Response");
01123                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
01124                 eap_aka_state(data, NOTIFICATION);
01125                 return;
01126         }
01127 
01128         if (eap_sim_parse_attr(pos, end, &attr,
01129                                data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1,
01130                                0)) {
01131                 wpa_printf(MSG_DEBUG, "EAP-AKA: Failed to parse attributes");
01132                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
01133                 eap_aka_state(data, NOTIFICATION);
01134                 return;
01135         }
01136 
01137         if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR) {
01138                 eap_aka_process_client_error(sm, data, respData, &attr);
01139                 return;
01140         }
01141 
01142         if (subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) {
01143                 eap_aka_process_authentication_reject(sm, data, respData,
01144                                                       &attr);
01145                 return;
01146         }
01147 
01148         switch (data->state) {
01149         case IDENTITY:
01150                 eap_aka_process_identity(sm, data, respData, &attr);
01151                 break;
01152         case CHALLENGE:
01153                 if (subtype == EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
01154                         eap_aka_process_sync_failure(sm, data, respData,
01155                                                      &attr);
01156                 } else {
01157                         eap_aka_process_challenge(sm, data, respData, &attr);
01158                 }
01159                 break;
01160         case REAUTH:
01161                 eap_aka_process_reauth(sm, data, respData, &attr);
01162                 break;
01163         case NOTIFICATION:
01164                 eap_aka_process_notification(sm, data, respData, &attr);
01165                 break;
01166         default:
01167                 wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
01168                            "process", data->state);
01169                 break;
01170         }
01171 }
01172 
01173 
01174 static Boolean eap_aka_isDone(struct eap_sm *sm, void *priv)
01175 {
01176         struct eap_aka_data *data = priv;
01177         return data->state == SUCCESS || data->state == FAILURE;
01178 }
01179 
01180 
01181 static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
01182 {
01183         struct eap_aka_data *data = priv;
01184         u8 *key;
01185 
01186         if (data->state != SUCCESS)
01187                 return NULL;
01188 
01189         key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
01190         if (key == NULL)
01191                 return NULL;
01192         os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
01193         *len = EAP_SIM_KEYING_DATA_LEN;
01194         return key;
01195 }
01196 
01197 
01198 static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
01199 {
01200         struct eap_aka_data *data = priv;
01201         u8 *key;
01202 
01203         if (data->state != SUCCESS)
01204                 return NULL;
01205 
01206         key = os_malloc(EAP_EMSK_LEN);
01207         if (key == NULL)
01208                 return NULL;
01209         os_memcpy(key, data->emsk, EAP_EMSK_LEN);
01210         *len = EAP_EMSK_LEN;
01211         return key;
01212 }
01213 
01214 
01215 static Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv)
01216 {
01217         struct eap_aka_data *data = priv;
01218         return data->state == SUCCESS;
01219 }
01220 
01221 
01222 int eap_server_aka_register(void)
01223 {
01224         struct eap_method *eap;
01225         int ret;
01226 
01227         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
01228                                       EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
01229         if (eap == NULL)
01230                 return -1;
01231 
01232         eap->init = eap_aka_init;
01233         eap->reset = eap_aka_reset;
01234         eap->buildReq = eap_aka_buildReq;
01235         eap->check = eap_aka_check;
01236         eap->process = eap_aka_process;
01237         eap->isDone = eap_aka_isDone;
01238         eap->getKey = eap_aka_getKey;
01239         eap->isSuccess = eap_aka_isSuccess;
01240         eap->get_emsk = eap_aka_get_emsk;
01241 
01242         ret = eap_server_method_register(eap);
01243         if (ret)
01244                 eap_server_method_free(eap);
01245         return ret;
01246 }
01247 
01248 
01249 #ifdef EAP_SERVER_AKA_PRIME
01250 int eap_server_aka_prime_register(void)
01251 {
01252         struct eap_method *eap;
01253         int ret;
01254 
01255         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
01256                                       EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
01257                                       "AKA'");
01258         if (eap == NULL)
01259                 return -1;
01260 
01261         eap->init = eap_aka_prime_init;
01262         eap->reset = eap_aka_reset;
01263         eap->buildReq = eap_aka_buildReq;
01264         eap->check = eap_aka_check;
01265         eap->process = eap_aka_process;
01266         eap->isDone = eap_aka_isDone;
01267         eap->getKey = eap_aka_getKey;
01268         eap->isSuccess = eap_aka_isSuccess;
01269         eap->get_emsk = eap_aka_get_emsk;
01270 
01271         ret = eap_server_method_register(eap);
01272         if (ret)
01273                 eap_server_method_free(eap);
01274 
01275         return ret;
01276 }
01277 #endif /* EAP_SERVER_AKA_PRIME */


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Apr 24 2014 15:34:34