eap_aka.c
Go to the documentation of this file.
00001 /*
00002  * EAP peer method: EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf)
00003  * Copyright (c) 2004-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 "pcsc_funcs.h"
00019 #include "crypto/crypto.h"
00020 #include "crypto/sha1.h"
00021 #include "crypto/sha256.h"
00022 #include "crypto/milenage.h"
00023 #include "eap_common/eap_sim_common.h"
00024 #include "eap_config.h"
00025 #include "eap_i.h"
00026 
00027 
00028 struct eap_aka_data {
00029         u8 ik[EAP_AKA_IK_LEN], ck[EAP_AKA_CK_LEN], res[EAP_AKA_RES_MAX_LEN];
00030         size_t res_len;
00031         u8 nonce_s[EAP_SIM_NONCE_S_LEN];
00032         u8 mk[EAP_SIM_MK_LEN];
00033         u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
00034         u8 k_encr[EAP_SIM_K_ENCR_LEN];
00035         u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */
00036         u8 msk[EAP_SIM_KEYING_DATA_LEN];
00037         u8 emsk[EAP_EMSK_LEN];
00038         u8 rand[EAP_AKA_RAND_LEN], autn[EAP_AKA_AUTN_LEN];
00039         u8 auts[EAP_AKA_AUTS_LEN];
00040 
00041         int num_id_req, num_notification;
00042         u8 *pseudonym;
00043         size_t pseudonym_len;
00044         u8 *reauth_id;
00045         size_t reauth_id_len;
00046         int reauth;
00047         unsigned int counter, counter_too_small;
00048         u8 *last_eap_identity;
00049         size_t last_eap_identity_len;
00050         enum {
00051                 CONTINUE, RESULT_SUCCESS, RESULT_FAILURE, SUCCESS, FAILURE
00052         } state;
00053 
00054         struct wpabuf *id_msgs;
00055         int prev_id;
00056         int result_ind, use_result_ind;
00057         u8 eap_method;
00058         u8 *network_name;
00059         size_t network_name_len;
00060         u16 kdf;
00061         int kdf_negotiation;
00062 };
00063 
00064 
00065 #ifndef CONFIG_NO_STDOUT_DEBUG
00066 static const char * eap_aka_state_txt(int state)
00067 {
00068         switch (state) {
00069         case CONTINUE:
00070                 return "CONTINUE";
00071         case RESULT_SUCCESS:
00072                 return "RESULT_SUCCESS";
00073         case RESULT_FAILURE:
00074                 return "RESULT_FAILURE";
00075         case SUCCESS:
00076                 return "SUCCESS";
00077         case FAILURE:
00078                 return "FAILURE";
00079         default:
00080                 return "?";
00081         }
00082 }
00083 #endif /* CONFIG_NO_STDOUT_DEBUG */
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         const char *phase1 = eap_get_config_phase1(sm);
00099 
00100         data = os_zalloc(sizeof(*data));
00101         if (data == NULL)
00102                 return NULL;
00103 
00104         data->eap_method = EAP_TYPE_AKA;
00105 
00106         eap_aka_state(data, CONTINUE);
00107         data->prev_id = -1;
00108 
00109         data->result_ind = phase1 && os_strstr(phase1, "result_ind=1") != NULL;
00110 
00111         return data;
00112 }
00113 
00114 
00115 #ifdef EAP_AKA_PRIME
00116 static void * eap_aka_prime_init(struct eap_sm *sm)
00117 {
00118         struct eap_aka_data *data = eap_aka_init(sm);
00119         if (data == NULL)
00120                 return NULL;
00121         data->eap_method = EAP_TYPE_AKA_PRIME;
00122         return data;
00123 }
00124 #endif /* EAP_AKA_PRIME */
00125 
00126 
00127 static void eap_aka_deinit(struct eap_sm *sm, void *priv)
00128 {
00129         struct eap_aka_data *data = priv;
00130         if (data) {
00131                 os_free(data->pseudonym);
00132                 os_free(data->reauth_id);
00133                 os_free(data->last_eap_identity);
00134                 wpabuf_free(data->id_msgs);
00135                 os_free(data->network_name);
00136                 os_free(data);
00137         }
00138 }
00139 
00140 
00141 static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data)
00142 {
00143         struct eap_peer_config *conf;
00144 
00145         wpa_printf(MSG_DEBUG, "EAP-AKA: UMTS authentication algorithm");
00146 
00147         conf = eap_get_config(sm);
00148         if (conf == NULL)
00149                 return -1;
00150         if (conf->pcsc) {
00151                 return scard_umts_auth(sm->scard_ctx, data->rand,
00152                                        data->autn, data->res, &data->res_len,
00153                                        data->ik, data->ck, data->auts);
00154         }
00155 
00156 #ifdef CONFIG_USIM_SIMULATOR
00157         if (conf->password) {
00158                 u8 opc[16], k[16], sqn[6];
00159                 const char *pos;
00160                 wpa_printf(MSG_DEBUG, "EAP-AKA: Use internal Milenage "
00161                            "implementation for UMTS authentication");
00162                 if (conf->password_len < 78) {
00163                         wpa_printf(MSG_DEBUG, "EAP-AKA: invalid Milenage "
00164                                    "password");
00165                         return -1;
00166                 }
00167                 pos = (const char *) conf->password;
00168                 if (hexstr2bin(pos, k, 16))
00169                         return -1;
00170                 pos += 32;
00171                 if (*pos != ':')
00172                         return -1;
00173                 pos++;
00174 
00175                 if (hexstr2bin(pos, opc, 16))
00176                         return -1;
00177                 pos += 32;
00178                 if (*pos != ':')
00179                         return -1;
00180                 pos++;
00181 
00182                 if (hexstr2bin(pos, sqn, 6))
00183                         return -1;
00184 
00185                 return milenage_check(opc, k, sqn, data->rand, data->autn,
00186                                       data->ik, data->ck,
00187                                       data->res, &data->res_len, data->auts);
00188         }
00189 #endif /* CONFIG_USIM_SIMULATOR */
00190 
00191 #ifdef CONFIG_USIM_HARDCODED
00192         wpa_printf(MSG_DEBUG, "EAP-AKA: Use hardcoded Kc and SRES values for "
00193                    "testing");
00194 
00195         /* These hardcoded Kc and SRES values are used for testing.
00196          * Could consider making them configurable. */
00197         os_memset(data->res, '2', EAP_AKA_RES_MAX_LEN);
00198         data->res_len = EAP_AKA_RES_MAX_LEN;
00199         os_memset(data->ik, '3', EAP_AKA_IK_LEN);
00200         os_memset(data->ck, '4', EAP_AKA_CK_LEN);
00201         {
00202                 u8 autn[EAP_AKA_AUTN_LEN];
00203                 os_memset(autn, '1', EAP_AKA_AUTN_LEN);
00204                 if (os_memcmp(autn, data->autn, EAP_AKA_AUTN_LEN) != 0) {
00205                         wpa_printf(MSG_WARNING, "EAP-AKA: AUTN did not match "
00206                                    "with expected value");
00207                         return -1;
00208                 }
00209         }
00210 #if 0
00211         {
00212                 static int test_resync = 1;
00213                 if (test_resync) {
00214                         /* Test Resynchronization */
00215                         test_resync = 0;
00216                         return -2;
00217                 }
00218         }
00219 #endif
00220         return 0;
00221 
00222 #else /* CONFIG_USIM_HARDCODED */
00223 
00224         wpa_printf(MSG_DEBUG, "EAP-AKA: No UMTS authentication algorith "
00225                    "enabled");
00226         return -1;
00227 
00228 #endif /* CONFIG_USIM_HARDCODED */
00229 }
00230 
00231 
00232 #define CLEAR_PSEUDONYM 0x01
00233 #define CLEAR_REAUTH_ID 0x02
00234 #define CLEAR_EAP_ID    0x04
00235 
00236 static void eap_aka_clear_identities(struct eap_aka_data *data, int id)
00237 {
00238         wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old%s%s%s",
00239                    id & CLEAR_PSEUDONYM ? " pseudonym" : "",
00240                    id & CLEAR_REAUTH_ID ? " reauth_id" : "",
00241                    id & CLEAR_EAP_ID ? " eap_id" : "");
00242         if (id & CLEAR_PSEUDONYM) {
00243                 os_free(data->pseudonym);
00244                 data->pseudonym = NULL;
00245                 data->pseudonym_len = 0;
00246         }
00247         if (id & CLEAR_REAUTH_ID) {
00248                 os_free(data->reauth_id);
00249                 data->reauth_id = NULL;
00250                 data->reauth_id_len = 0;
00251         }
00252         if (id & CLEAR_EAP_ID) {
00253                 os_free(data->last_eap_identity);
00254                 data->last_eap_identity = NULL;
00255                 data->last_eap_identity_len = 0;
00256         }
00257 }
00258 
00259 
00260 static int eap_aka_learn_ids(struct eap_aka_data *data,
00261                              struct eap_sim_attrs *attr)
00262 {
00263         if (attr->next_pseudonym) {
00264                 os_free(data->pseudonym);
00265                 data->pseudonym = os_malloc(attr->next_pseudonym_len);
00266                 if (data->pseudonym == NULL) {
00267                         wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for "
00268                                    "next pseudonym");
00269                         return -1;
00270                 }
00271                 os_memcpy(data->pseudonym, attr->next_pseudonym,
00272                           attr->next_pseudonym_len);
00273                 data->pseudonym_len = attr->next_pseudonym_len;
00274                 wpa_hexdump_ascii(MSG_DEBUG,
00275                                   "EAP-AKA: (encr) AT_NEXT_PSEUDONYM",
00276                                   data->pseudonym,
00277                                   data->pseudonym_len);
00278         }
00279 
00280         if (attr->next_reauth_id) {
00281                 os_free(data->reauth_id);
00282                 data->reauth_id = os_malloc(attr->next_reauth_id_len);
00283                 if (data->reauth_id == NULL) {
00284                         wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for "
00285                                    "next reauth_id");
00286                         return -1;
00287                 }
00288                 os_memcpy(data->reauth_id, attr->next_reauth_id,
00289                           attr->next_reauth_id_len);
00290                 data->reauth_id_len = attr->next_reauth_id_len;
00291                 wpa_hexdump_ascii(MSG_DEBUG,
00292                                   "EAP-AKA: (encr) AT_NEXT_REAUTH_ID",
00293                                   data->reauth_id,
00294                                   data->reauth_id_len);
00295         }
00296 
00297         return 0;
00298 }
00299 
00300 
00301 static int eap_aka_add_id_msg(struct eap_aka_data *data,
00302                               const struct wpabuf *msg)
00303 {
00304         if (msg == NULL)
00305                 return -1;
00306 
00307         if (data->id_msgs == NULL) {
00308                 data->id_msgs = wpabuf_dup(msg);
00309                 return data->id_msgs == NULL ? -1 : 0;
00310         }
00311 
00312         if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0)
00313                 return -1;
00314         wpabuf_put_buf(data->id_msgs, msg);
00315 
00316         return 0;
00317 }
00318 
00319 
00320 static void eap_aka_add_checkcode(struct eap_aka_data *data,
00321                                   struct eap_sim_msg *msg)
00322 {
00323         const u8 *addr;
00324         size_t len;
00325         u8 hash[SHA256_MAC_LEN];
00326 
00327         wpa_printf(MSG_DEBUG, "   AT_CHECKCODE");
00328 
00329         if (data->id_msgs == NULL) {
00330                 /*
00331                  * No EAP-AKA/Identity packets were exchanged - send empty
00332                  * checkcode.
00333                  */
00334                 eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0);
00335                 return;
00336         }
00337 
00338         /* Checkcode is SHA1/SHA256 hash over all EAP-AKA/Identity packets. */
00339         addr = wpabuf_head(data->id_msgs);
00340         len = wpabuf_len(data->id_msgs);
00341         wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len);
00342 #ifdef EAP_AKA_PRIME
00343         if (data->eap_method == EAP_TYPE_AKA_PRIME)
00344                 sha256_vector(1, &addr, &len, hash);
00345         else
00346 #endif /* EAP_AKA_PRIME */
00347                 sha1_vector(1, &addr, &len, hash);
00348 
00349         eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash,
00350                         data->eap_method == EAP_TYPE_AKA_PRIME ?
00351                         EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN);
00352 }
00353 
00354 
00355 static int eap_aka_verify_checkcode(struct eap_aka_data *data,
00356                                     const u8 *checkcode, size_t checkcode_len)
00357 {
00358         const u8 *addr;
00359         size_t len;
00360         u8 hash[SHA256_MAC_LEN];
00361         size_t hash_len;
00362 
00363         if (checkcode == NULL)
00364                 return -1;
00365 
00366         if (data->id_msgs == NULL) {
00367                 if (checkcode_len != 0) {
00368                         wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from server "
00369                                    "indicates that AKA/Identity messages were "
00370                                    "used, but they were not");
00371                         return -1;
00372                 }
00373                 return 0;
00374         }
00375 
00376         hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ?
00377                 EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN;
00378 
00379         if (checkcode_len != hash_len) {
00380                 wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from server "
00381                            "indicates that AKA/Identity message were not "
00382                            "used, but they were");
00383                 return -1;
00384         }
00385 
00386         /* Checkcode is SHA1/SHA256 hash over all EAP-AKA/Identity packets. */
00387         addr = wpabuf_head(data->id_msgs);
00388         len = wpabuf_len(data->id_msgs);
00389 #ifdef EAP_AKA_PRIME
00390         if (data->eap_method == EAP_TYPE_AKA_PRIME)
00391                 sha256_vector(1, &addr, &len, hash);
00392         else
00393 #endif /* EAP_AKA_PRIME */
00394                 sha1_vector(1, &addr, &len, hash);
00395 
00396         if (os_memcmp(hash, checkcode, hash_len) != 0) {
00397                 wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
00398                 return -1;
00399         }
00400 
00401         return 0;
00402 }
00403 
00404 
00405 static struct wpabuf * eap_aka_client_error(struct eap_aka_data *data, u8 id,
00406                                             int err)
00407 {
00408         struct eap_sim_msg *msg;
00409 
00410         eap_aka_state(data, FAILURE);
00411         data->num_id_req = 0;
00412         data->num_notification = 0;
00413 
00414         msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
00415                                EAP_AKA_SUBTYPE_CLIENT_ERROR);
00416         eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
00417         return eap_sim_msg_finish(msg, NULL, NULL, 0);
00418 }
00419 
00420 
00421 static struct wpabuf * eap_aka_authentication_reject(struct eap_aka_data *data,
00422                                                      u8 id)
00423 {
00424         struct eap_sim_msg *msg;
00425 
00426         eap_aka_state(data, FAILURE);
00427         data->num_id_req = 0;
00428         data->num_notification = 0;
00429 
00430         wpa_printf(MSG_DEBUG, "Generating EAP-AKA Authentication-Reject "
00431                    "(id=%d)", id);
00432         msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
00433                                EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT);
00434         return eap_sim_msg_finish(msg, NULL, NULL, 0);
00435 }
00436 
00437 
00438 static struct wpabuf * eap_aka_synchronization_failure(
00439         struct eap_aka_data *data, u8 id)
00440 {
00441         struct eap_sim_msg *msg;
00442 
00443         data->num_id_req = 0;
00444         data->num_notification = 0;
00445 
00446         wpa_printf(MSG_DEBUG, "Generating EAP-AKA Synchronization-Failure "
00447                    "(id=%d)", id);
00448         msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
00449                                EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE);
00450         wpa_printf(MSG_DEBUG, "   AT_AUTS");
00451         eap_sim_msg_add_full(msg, EAP_SIM_AT_AUTS, data->auts,
00452                              EAP_AKA_AUTS_LEN);
00453         return eap_sim_msg_finish(msg, NULL, NULL, 0);
00454 }
00455 
00456 
00457 static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm,
00458                                                  struct eap_aka_data *data,
00459                                                  u8 id,
00460                                                  enum eap_sim_id_req id_req)
00461 {
00462         const u8 *identity = NULL;
00463         size_t identity_len = 0;
00464         struct eap_sim_msg *msg;
00465 
00466         data->reauth = 0;
00467         if (id_req == ANY_ID && data->reauth_id) {
00468                 identity = data->reauth_id;
00469                 identity_len = data->reauth_id_len;
00470                 data->reauth = 1;
00471         } else if ((id_req == ANY_ID || id_req == FULLAUTH_ID) &&
00472                    data->pseudonym) {
00473                 identity = data->pseudonym;
00474                 identity_len = data->pseudonym_len;
00475                 eap_aka_clear_identities(data, CLEAR_REAUTH_ID);
00476         } else if (id_req != NO_ID_REQ) {
00477                 identity = eap_get_config_identity(sm, &identity_len);
00478                 if (identity) {
00479                         eap_aka_clear_identities(data, CLEAR_PSEUDONYM |
00480                                                  CLEAR_REAUTH_ID);
00481                 }
00482         }
00483         if (id_req != NO_ID_REQ)
00484                 eap_aka_clear_identities(data, CLEAR_EAP_ID);
00485 
00486         wpa_printf(MSG_DEBUG, "Generating EAP-AKA Identity (id=%d)", id);
00487         msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
00488                                EAP_AKA_SUBTYPE_IDENTITY);
00489 
00490         if (identity) {
00491                 wpa_hexdump_ascii(MSG_DEBUG, "   AT_IDENTITY",
00492                                   identity, identity_len);
00493                 eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
00494                                 identity, identity_len);
00495         }
00496 
00497         return eap_sim_msg_finish(msg, NULL, NULL, 0);
00498 }
00499 
00500 
00501 static struct wpabuf * eap_aka_response_challenge(struct eap_aka_data *data,
00502                                                   u8 id)
00503 {
00504         struct eap_sim_msg *msg;
00505 
00506         wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d)", id);
00507         msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
00508                                EAP_AKA_SUBTYPE_CHALLENGE);
00509         wpa_printf(MSG_DEBUG, "   AT_RES");
00510         eap_sim_msg_add(msg, EAP_SIM_AT_RES, data->res_len * 8,
00511                         data->res, data->res_len);
00512         eap_aka_add_checkcode(data, msg);
00513         if (data->use_result_ind) {
00514                 wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
00515                 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
00516         }
00517         wpa_printf(MSG_DEBUG, "   AT_MAC");
00518         eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
00519         return eap_sim_msg_finish(msg, data->k_aut, (u8 *) "", 0);
00520 }
00521 
00522 
00523 static struct wpabuf * eap_aka_response_reauth(struct eap_aka_data *data,
00524                                                u8 id, int counter_too_small,
00525                                                const u8 *nonce_s)
00526 {
00527         struct eap_sim_msg *msg;
00528         unsigned int counter;
00529 
00530         wpa_printf(MSG_DEBUG, "Generating EAP-AKA Reauthentication (id=%d)",
00531                    id);
00532         msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
00533                                EAP_AKA_SUBTYPE_REAUTHENTICATION);
00534         wpa_printf(MSG_DEBUG, "   AT_IV");
00535         wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
00536         eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
00537 
00538         if (counter_too_small) {
00539                 wpa_printf(MSG_DEBUG, "   *AT_COUNTER_TOO_SMALL");
00540                 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER_TOO_SMALL, 0, NULL, 0);
00541                 counter = data->counter_too_small;
00542         } else
00543                 counter = data->counter;
00544 
00545         wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", counter);
00546         eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
00547 
00548         if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
00549                 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
00550                            "AT_ENCR_DATA");
00551                 eap_sim_msg_free(msg);
00552                 return NULL;
00553         }
00554         eap_aka_add_checkcode(data, msg);
00555         if (data->use_result_ind) {
00556                 wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
00557                 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
00558         }
00559         wpa_printf(MSG_DEBUG, "   AT_MAC");
00560         eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
00561         return eap_sim_msg_finish(msg, data->k_aut, nonce_s,
00562                                   EAP_SIM_NONCE_S_LEN);
00563 }
00564 
00565 
00566 static struct wpabuf * eap_aka_response_notification(struct eap_aka_data *data,
00567                                                      u8 id, u16 notification)
00568 {
00569         struct eap_sim_msg *msg;
00570         u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL;
00571 
00572         wpa_printf(MSG_DEBUG, "Generating EAP-AKA Notification (id=%d)", id);
00573         msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
00574                                EAP_AKA_SUBTYPE_NOTIFICATION);
00575         if (k_aut && data->reauth) {
00576                 wpa_printf(MSG_DEBUG, "   AT_IV");
00577                 wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
00578                 eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
00579                                            EAP_SIM_AT_ENCR_DATA);
00580                 wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", data->counter);
00581                 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
00582                                 NULL, 0);
00583                 if (eap_sim_msg_add_encr_end(msg, data->k_encr,
00584                                              EAP_SIM_AT_PADDING)) {
00585                         wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
00586                                    "AT_ENCR_DATA");
00587                         eap_sim_msg_free(msg);
00588                         return NULL;
00589                 }
00590         }
00591         if (k_aut) {
00592                 wpa_printf(MSG_DEBUG, "   AT_MAC");
00593                 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
00594         }
00595         return eap_sim_msg_finish(msg, k_aut, (u8 *) "", 0);
00596 }
00597 
00598 
00599 static struct wpabuf * eap_aka_process_identity(struct eap_sm *sm,
00600                                                 struct eap_aka_data *data,
00601                                                 u8 id,
00602                                                 const struct wpabuf *reqData,
00603                                                 struct eap_sim_attrs *attr)
00604 {
00605         int id_error;
00606         struct wpabuf *buf;
00607 
00608         wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Identity");
00609 
00610         id_error = 0;
00611         switch (attr->id_req) {
00612         case NO_ID_REQ:
00613                 break;
00614         case ANY_ID:
00615                 if (data->num_id_req > 0)
00616                         id_error++;
00617                 data->num_id_req++;
00618                 break;
00619         case FULLAUTH_ID:
00620                 if (data->num_id_req > 1)
00621                         id_error++;
00622                 data->num_id_req++;
00623                 break;
00624         case PERMANENT_ID:
00625                 if (data->num_id_req > 2)
00626                         id_error++;
00627                 data->num_id_req++;
00628                 break;
00629         }
00630         if (id_error) {
00631                 wpa_printf(MSG_INFO, "EAP-AKA: Too many ID requests "
00632                            "used within one authentication");
00633                 return eap_aka_client_error(data, id,
00634                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
00635         }
00636 
00637         buf = eap_aka_response_identity(sm, data, id, attr->id_req);
00638 
00639         if (data->prev_id != id) {
00640                 eap_aka_add_id_msg(data, reqData);
00641                 eap_aka_add_id_msg(data, buf);
00642                 data->prev_id = id;
00643         }
00644 
00645         return buf;
00646 }
00647 
00648 
00649 static int eap_aka_verify_mac(struct eap_aka_data *data,
00650                               const struct wpabuf *req,
00651                               const u8 *mac, const u8 *extra,
00652                               size_t extra_len)
00653 {
00654         if (data->eap_method == EAP_TYPE_AKA_PRIME)
00655                 return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra,
00656                                                  extra_len);
00657         return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len);
00658 }
00659 
00660 
00661 #ifdef EAP_AKA_PRIME
00662 static struct wpabuf * eap_aka_prime_kdf_select(struct eap_aka_data *data,
00663                                                 u8 id, u16 kdf)
00664 {
00665         struct eap_sim_msg *msg;
00666 
00667         data->kdf_negotiation = 1;
00668         data->kdf = kdf;
00669         wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d) (KDF "
00670                    "select)", id);
00671         msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
00672                                EAP_AKA_SUBTYPE_CHALLENGE);
00673         wpa_printf(MSG_DEBUG, "   AT_KDF");
00674         eap_sim_msg_add(msg, EAP_SIM_AT_KDF, kdf, NULL, 0);
00675         return eap_sim_msg_finish(msg, NULL, NULL, 0);
00676 }
00677 
00678 
00679 static struct wpabuf * eap_aka_prime_kdf_neg(struct eap_aka_data *data,
00680                                              u8 id, struct eap_sim_attrs *attr)
00681 {
00682         size_t i;
00683 
00684         for (i = 0; i < attr->kdf_count; i++) {
00685                 if (attr->kdf[i] == EAP_AKA_PRIME_KDF)
00686                         return eap_aka_prime_kdf_select(data, id,
00687                                                         EAP_AKA_PRIME_KDF);
00688         }
00689 
00690         /* No matching KDF found - fail authentication as if AUTN had been
00691          * incorrect */
00692         return eap_aka_authentication_reject(data, id);
00693 }
00694 
00695 
00696 static int eap_aka_prime_kdf_valid(struct eap_aka_data *data,
00697                                    struct eap_sim_attrs *attr)
00698 {
00699         size_t i, j;
00700 
00701         if (attr->kdf_count == 0)
00702                 return 0;
00703 
00704         /* The only allowed (and required) duplication of a KDF is the addition
00705          * of the selected KDF into the beginning of the list. */
00706 
00707         if (data->kdf_negotiation) {
00708                 if (attr->kdf[0] != data->kdf) {
00709                         wpa_printf(MSG_WARNING, "EAP-AKA': The server did not "
00710                                    "accept the selected KDF");
00711                         return 0;
00712                 }
00713 
00714                 for (i = 1; i < attr->kdf_count; i++) {
00715                         if (attr->kdf[i] == data->kdf)
00716                                 break;
00717                 }
00718                 if (i == attr->kdf_count &&
00719                     attr->kdf_count < EAP_AKA_PRIME_KDF_MAX) {
00720                         wpa_printf(MSG_WARNING, "EAP-AKA': The server did not "
00721                                    "duplicate the selected KDF");
00722                         return 0;
00723                 }
00724 
00725                 /* TODO: should check that the list is identical to the one
00726                  * used in the previous Challenge message apart from the added
00727                  * entry in the beginning. */
00728         }
00729 
00730         for (i = data->kdf ? 1 : 0; i < attr->kdf_count; i++) {
00731                 for (j = i + 1; j < attr->kdf_count; j++) {
00732                         if (attr->kdf[i] == attr->kdf[j]) {
00733                                 wpa_printf(MSG_WARNING, "EAP-AKA': The server "
00734                                            "included a duplicated KDF");
00735                                 return 0;
00736                         }
00737                 }
00738         }
00739 
00740         return 1;
00741 }
00742 #endif /* EAP_AKA_PRIME */
00743 
00744 
00745 static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
00746                                                  struct eap_aka_data *data,
00747                                                  u8 id,
00748                                                  const struct wpabuf *reqData,
00749                                                  struct eap_sim_attrs *attr)
00750 {
00751         const u8 *identity;
00752         size_t identity_len;
00753         int res;
00754         struct eap_sim_attrs eattr;
00755 
00756         wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Challenge");
00757 
00758         if (attr->checkcode &&
00759             eap_aka_verify_checkcode(data, attr->checkcode,
00760                                      attr->checkcode_len)) {
00761                 wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
00762                            "message");
00763                 return eap_aka_client_error(data, id,
00764                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
00765         }
00766 
00767 #ifdef EAP_AKA_PRIME
00768         if (data->eap_method == EAP_TYPE_AKA_PRIME) {
00769                 if (!attr->kdf_input || attr->kdf_input_len == 0) {
00770                         wpa_printf(MSG_WARNING, "EAP-AKA': Challenge message "
00771                                    "did not include non-empty AT_KDF_INPUT");
00772                         /* Fail authentication as if AUTN had been incorrect */
00773                         return eap_aka_authentication_reject(data, id);
00774                 }
00775                 os_free(data->network_name);
00776                 data->network_name = os_malloc(attr->kdf_input_len);
00777                 if (data->network_name == NULL) {
00778                         wpa_printf(MSG_WARNING, "EAP-AKA': No memory for "
00779                                    "storing Network Name");
00780                         return eap_aka_authentication_reject(data, id);
00781                 }
00782                 os_memcpy(data->network_name, attr->kdf_input,
00783                           attr->kdf_input_len);
00784                 data->network_name_len = attr->kdf_input_len;
00785                 wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA': Network Name "
00786                                   "(AT_KDF_INPUT)",
00787                                   data->network_name, data->network_name_len);
00788                 /* TODO: check Network Name per 3GPP.33.402 */
00789 
00790                 if (!eap_aka_prime_kdf_valid(data, attr))
00791                         return eap_aka_authentication_reject(data, id);
00792 
00793                 if (attr->kdf[0] != EAP_AKA_PRIME_KDF)
00794                         return eap_aka_prime_kdf_neg(data, id, attr);
00795 
00796                 data->kdf = EAP_AKA_PRIME_KDF;
00797                 wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf);
00798         }
00799 
00800         if (data->eap_method == EAP_TYPE_AKA && attr->bidding) {
00801                 u16 flags = WPA_GET_BE16(attr->bidding);
00802                 if ((flags & EAP_AKA_BIDDING_FLAG_D) &&
00803                     eap_allowed_method(sm, EAP_VENDOR_IETF,
00804                                        EAP_TYPE_AKA_PRIME)) {
00805                         wpa_printf(MSG_WARNING, "EAP-AKA: Bidding down from "
00806                                    "AKA' to AKA detected");
00807                         /* Fail authentication as if AUTN had been incorrect */
00808                         return eap_aka_authentication_reject(data, id);
00809                 }
00810         }
00811 #endif /* EAP_AKA_PRIME */
00812 
00813         data->reauth = 0;
00814         if (!attr->mac || !attr->rand || !attr->autn) {
00815                 wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
00816                            "did not include%s%s%s",
00817                            !attr->mac ? " AT_MAC" : "",
00818                            !attr->rand ? " AT_RAND" : "",
00819                            !attr->autn ? " AT_AUTN" : "");
00820                 return eap_aka_client_error(data, id,
00821                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
00822         }
00823         os_memcpy(data->rand, attr->rand, EAP_AKA_RAND_LEN);
00824         os_memcpy(data->autn, attr->autn, EAP_AKA_AUTN_LEN);
00825 
00826         res = eap_aka_umts_auth(sm, data);
00827         if (res == -1) {
00828                 wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
00829                            "failed (AUTN)");
00830                 return eap_aka_authentication_reject(data, id);
00831         } else if (res == -2) {
00832                 wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
00833                            "failed (AUTN seq# -> AUTS)");
00834                 return eap_aka_synchronization_failure(data, id);
00835         } else if (res) {
00836                 wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication failed");
00837                 return eap_aka_client_error(data, id,
00838                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
00839         }
00840 #ifdef EAP_AKA_PRIME
00841         if (data->eap_method == EAP_TYPE_AKA_PRIME) {
00842                 /* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
00843                  * needed 6-octet SQN ^ AK for CK',IK' derivation */
00844                 u16 amf = WPA_GET_BE16(data->autn + 6);
00845                 if (!(amf & 0x8000)) {
00846                         wpa_printf(MSG_WARNING, "EAP-AKA': AMF separation bit "
00847                                    "not set (AMF=0x%4x)", amf);
00848                         return eap_aka_authentication_reject(data, id);
00849                 }
00850                 eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
00851                                                  data->autn,
00852                                                  data->network_name,
00853                                                  data->network_name_len);
00854         }
00855 #endif /* EAP_AKA_PRIME */
00856         if (data->last_eap_identity) {
00857                 identity = data->last_eap_identity;
00858                 identity_len = data->last_eap_identity_len;
00859         } else if (data->pseudonym) {
00860                 identity = data->pseudonym;
00861                 identity_len = data->pseudonym_len;
00862         } else
00863                 identity = eap_get_config_identity(sm, &identity_len);
00864         wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Selected identity for MK "
00865                           "derivation", identity, identity_len);
00866         if (data->eap_method == EAP_TYPE_AKA_PRIME) {
00867                 eap_aka_prime_derive_keys(identity, identity_len, data->ik,
00868                                           data->ck, data->k_encr, data->k_aut,
00869                                           data->k_re, data->msk, data->emsk);
00870         } else {
00871                 eap_aka_derive_mk(identity, identity_len, data->ik, data->ck,
00872                                   data->mk);
00873                 eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
00874                                     data->msk, data->emsk);
00875         }
00876         if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
00877                 wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
00878                            "used invalid AT_MAC");
00879                 return eap_aka_client_error(data, id,
00880                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
00881         }
00882 
00883         /* Old reauthentication and pseudonym identities must not be used
00884          * anymore. In other words, if no new identities are received, full
00885          * authentication will be used on next reauthentication. */
00886         eap_aka_clear_identities(data, CLEAR_PSEUDONYM | CLEAR_REAUTH_ID |
00887                                  CLEAR_EAP_ID);
00888 
00889         if (attr->encr_data) {
00890                 u8 *decrypted;
00891                 decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
00892                                                attr->encr_data_len, attr->iv,
00893                                                &eattr, 0);
00894                 if (decrypted == NULL) {
00895                         return eap_aka_client_error(
00896                                 data, id, EAP_AKA_UNABLE_TO_PROCESS_PACKET);
00897                 }
00898                 eap_aka_learn_ids(data, &eattr);
00899                 os_free(decrypted);
00900         }
00901 
00902         if (data->result_ind && attr->result_ind)
00903                 data->use_result_ind = 1;
00904 
00905         if (data->state != FAILURE && data->state != RESULT_FAILURE) {
00906                 eap_aka_state(data, data->use_result_ind ?
00907                               RESULT_SUCCESS : SUCCESS);
00908         }
00909 
00910         data->num_id_req = 0;
00911         data->num_notification = 0;
00912         /* RFC 4187 specifies that counter is initialized to one after
00913          * fullauth, but initializing it to zero makes it easier to implement
00914          * reauth verification. */
00915         data->counter = 0;
00916         return eap_aka_response_challenge(data, id);
00917 }
00918 
00919 
00920 static int eap_aka_process_notification_reauth(struct eap_aka_data *data,
00921                                                struct eap_sim_attrs *attr)
00922 {
00923         struct eap_sim_attrs eattr;
00924         u8 *decrypted;
00925 
00926         if (attr->encr_data == NULL || attr->iv == NULL) {
00927                 wpa_printf(MSG_WARNING, "EAP-AKA: Notification message after "
00928                            "reauth did not include encrypted data");
00929                 return -1;
00930         }
00931 
00932         decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
00933                                        attr->encr_data_len, attr->iv, &eattr,
00934                                        0);
00935         if (decrypted == NULL) {
00936                 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
00937                            "data from notification message");
00938                 return -1;
00939         }
00940 
00941         if (eattr.counter < 0 || (size_t) eattr.counter != data->counter) {
00942                 wpa_printf(MSG_WARNING, "EAP-AKA: Counter in notification "
00943                            "message does not match with counter in reauth "
00944                            "message");
00945                 os_free(decrypted);
00946                 return -1;
00947         }
00948 
00949         os_free(decrypted);
00950         return 0;
00951 }
00952 
00953 
00954 static int eap_aka_process_notification_auth(struct eap_aka_data *data,
00955                                              const struct wpabuf *reqData,
00956                                              struct eap_sim_attrs *attr)
00957 {
00958         if (attr->mac == NULL) {
00959                 wpa_printf(MSG_INFO, "EAP-AKA: no AT_MAC in after_auth "
00960                            "Notification message");
00961                 return -1;
00962         }
00963 
00964         if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
00965                 wpa_printf(MSG_WARNING, "EAP-AKA: Notification message "
00966                            "used invalid AT_MAC");
00967                 return -1;
00968         }
00969 
00970         if (data->reauth &&
00971             eap_aka_process_notification_reauth(data, attr)) {
00972                 wpa_printf(MSG_WARNING, "EAP-AKA: Invalid notification "
00973                            "message after reauth");
00974                 return -1;
00975         }
00976 
00977         return 0;
00978 }
00979 
00980 
00981 static struct wpabuf * eap_aka_process_notification(
00982         struct eap_sm *sm, struct eap_aka_data *data, u8 id,
00983         const struct wpabuf *reqData, struct eap_sim_attrs *attr)
00984 {
00985         wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Notification");
00986         if (data->num_notification > 0) {
00987                 wpa_printf(MSG_INFO, "EAP-AKA: too many notification "
00988                            "rounds (only one allowed)");
00989                 return eap_aka_client_error(data, id,
00990                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
00991         }
00992         data->num_notification++;
00993         if (attr->notification == -1) {
00994                 wpa_printf(MSG_INFO, "EAP-AKA: no AT_NOTIFICATION in "
00995                            "Notification message");
00996                 return eap_aka_client_error(data, id,
00997                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
00998         }
00999 
01000         if ((attr->notification & 0x4000) == 0 &&
01001             eap_aka_process_notification_auth(data, reqData, attr)) {
01002                 return eap_aka_client_error(data, id,
01003                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
01004         }
01005 
01006         eap_sim_report_notification(sm->msg_ctx, attr->notification, 1);
01007         if (attr->notification >= 0 && attr->notification < 32768) {
01008                 eap_aka_state(data, FAILURE);
01009         } else if (attr->notification == EAP_SIM_SUCCESS &&
01010                    data->state == RESULT_SUCCESS)
01011                 eap_aka_state(data, SUCCESS);
01012         return eap_aka_response_notification(data, id, attr->notification);
01013 }
01014 
01015 
01016 static struct wpabuf * eap_aka_process_reauthentication(
01017         struct eap_sm *sm, struct eap_aka_data *data, u8 id,
01018         const struct wpabuf *reqData, struct eap_sim_attrs *attr)
01019 {
01020         struct eap_sim_attrs eattr;
01021         u8 *decrypted;
01022 
01023         wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Reauthentication");
01024 
01025         if (attr->checkcode &&
01026             eap_aka_verify_checkcode(data, attr->checkcode,
01027                                      attr->checkcode_len)) {
01028                 wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
01029                            "message");
01030                 return eap_aka_client_error(data, id,
01031                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
01032         }
01033 
01034         if (data->reauth_id == NULL) {
01035                 wpa_printf(MSG_WARNING, "EAP-AKA: Server is trying "
01036                            "reauthentication, but no reauth_id available");
01037                 return eap_aka_client_error(data, id,
01038                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
01039         }
01040 
01041         data->reauth = 1;
01042         if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
01043                 wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
01044                            "did not have valid AT_MAC");
01045                 return eap_aka_client_error(data, id,
01046                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
01047         }
01048 
01049         if (attr->encr_data == NULL || attr->iv == NULL) {
01050                 wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
01051                            "message did not include encrypted data");
01052                 return eap_aka_client_error(data, id,
01053                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
01054         }
01055 
01056         decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
01057                                        attr->encr_data_len, attr->iv, &eattr,
01058                                        0);
01059         if (decrypted == NULL) {
01060                 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
01061                            "data from reauthentication message");
01062                 return eap_aka_client_error(data, id,
01063                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
01064         }
01065 
01066         if (eattr.nonce_s == NULL || eattr.counter < 0) {
01067                 wpa_printf(MSG_INFO, "EAP-AKA: (encr) No%s%s in reauth packet",
01068                            !eattr.nonce_s ? " AT_NONCE_S" : "",
01069                            eattr.counter < 0 ? " AT_COUNTER" : "");
01070                 os_free(decrypted);
01071                 return eap_aka_client_error(data, id,
01072                                             EAP_AKA_UNABLE_TO_PROCESS_PACKET);
01073         }
01074 
01075         if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) {
01076                 struct wpabuf *res;
01077                 wpa_printf(MSG_INFO, "EAP-AKA: (encr) Invalid counter "
01078                            "(%d <= %d)", eattr.counter, data->counter);
01079                 data->counter_too_small = eattr.counter;
01080 
01081                 /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
01082                  * reauth_id must not be used to start a new reauthentication.
01083                  * However, since it was used in the last EAP-Response-Identity
01084                  * packet, it has to saved for the following fullauth to be
01085                  * used in MK derivation. */
01086                 os_free(data->last_eap_identity);
01087                 data->last_eap_identity = data->reauth_id;
01088                 data->last_eap_identity_len = data->reauth_id_len;
01089                 data->reauth_id = NULL;
01090                 data->reauth_id_len = 0;
01091 
01092                 res = eap_aka_response_reauth(data, id, 1, eattr.nonce_s);
01093                 os_free(decrypted);
01094 
01095                 return res;
01096         }
01097         data->counter = eattr.counter;
01098 
01099         os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN);
01100         wpa_hexdump(MSG_DEBUG, "EAP-AKA: (encr) AT_NONCE_S",
01101                     data->nonce_s, EAP_SIM_NONCE_S_LEN);
01102 
01103         if (data->eap_method == EAP_TYPE_AKA_PRIME) {
01104                 eap_aka_prime_derive_keys_reauth(data->k_re, data->counter,
01105                                                  data->reauth_id,
01106                                                  data->reauth_id_len,
01107                                                  data->nonce_s,
01108                                                  data->msk, data->emsk);
01109         } else {
01110                 eap_sim_derive_keys_reauth(data->counter, data->reauth_id,
01111                                            data->reauth_id_len,
01112                                            data->nonce_s, data->mk,
01113                                            data->msk, data->emsk);
01114         }
01115         eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
01116         eap_aka_learn_ids(data, &eattr);
01117 
01118         if (data->result_ind && attr->result_ind)
01119                 data->use_result_ind = 1;
01120 
01121         if (data->state != FAILURE && data->state != RESULT_FAILURE) {
01122                 eap_aka_state(data, data->use_result_ind ?
01123                               RESULT_SUCCESS : SUCCESS);
01124         }
01125 
01126         data->num_id_req = 0;
01127         data->num_notification = 0;
01128         if (data->counter > EAP_AKA_MAX_FAST_REAUTHS) {
01129                 wpa_printf(MSG_DEBUG, "EAP-AKA: Maximum number of "
01130                            "fast reauths performed - force fullauth");
01131                 eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
01132         }
01133         os_free(decrypted);
01134         return eap_aka_response_reauth(data, id, 0, data->nonce_s);
01135 }
01136 
01137 
01138 static struct wpabuf * eap_aka_process(struct eap_sm *sm, void *priv,
01139                                        struct eap_method_ret *ret,
01140                                        const struct wpabuf *reqData)
01141 {
01142         struct eap_aka_data *data = priv;
01143         const struct eap_hdr *req;
01144         u8 subtype, id;
01145         struct wpabuf *res;
01146         const u8 *pos;
01147         struct eap_sim_attrs attr;
01148         size_t len;
01149 
01150         wpa_hexdump_buf(MSG_DEBUG, "EAP-AKA: EAP data", reqData);
01151         if (eap_get_config_identity(sm, &len) == NULL) {
01152                 wpa_printf(MSG_INFO, "EAP-AKA: Identity not configured");
01153                 eap_sm_request_identity(sm);
01154                 ret->ignore = TRUE;
01155                 return NULL;
01156         }
01157 
01158         pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, reqData,
01159                                &len);
01160         if (pos == NULL || len < 1) {
01161                 ret->ignore = TRUE;
01162                 return NULL;
01163         }
01164         req = wpabuf_head(reqData);
01165         id = req->identifier;
01166         len = be_to_host16(req->length);
01167 
01168         ret->ignore = FALSE;
01169         ret->methodState = METHOD_MAY_CONT;
01170         ret->decision = DECISION_FAIL;
01171         ret->allowNotifications = TRUE;
01172 
01173         subtype = *pos++;
01174         wpa_printf(MSG_DEBUG, "EAP-AKA: Subtype=%d", subtype);
01175         pos += 2; /* Reserved */
01176 
01177         if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr,
01178                                data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1,
01179                                0)) {
01180                 res = eap_aka_client_error(data, id,
01181                                            EAP_AKA_UNABLE_TO_PROCESS_PACKET);
01182                 goto done;
01183         }
01184 
01185         switch (subtype) {
01186         case EAP_AKA_SUBTYPE_IDENTITY:
01187                 res = eap_aka_process_identity(sm, data, id, reqData, &attr);
01188                 break;
01189         case EAP_AKA_SUBTYPE_CHALLENGE:
01190                 res = eap_aka_process_challenge(sm, data, id, reqData, &attr);
01191                 break;
01192         case EAP_AKA_SUBTYPE_NOTIFICATION:
01193                 res = eap_aka_process_notification(sm, data, id, reqData,
01194                                                    &attr);
01195                 break;
01196         case EAP_AKA_SUBTYPE_REAUTHENTICATION:
01197                 res = eap_aka_process_reauthentication(sm, data, id, reqData,
01198                                                        &attr);
01199                 break;
01200         case EAP_AKA_SUBTYPE_CLIENT_ERROR:
01201                 wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Client-Error");
01202                 res = eap_aka_client_error(data, id,
01203                                            EAP_AKA_UNABLE_TO_PROCESS_PACKET);
01204                 break;
01205         default:
01206                 wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown subtype=%d", subtype);
01207                 res = eap_aka_client_error(data, id,
01208                                            EAP_AKA_UNABLE_TO_PROCESS_PACKET);
01209                 break;
01210         }
01211 
01212 done:
01213         if (data->state == FAILURE) {
01214                 ret->decision = DECISION_FAIL;
01215                 ret->methodState = METHOD_DONE;
01216         } else if (data->state == SUCCESS) {
01217                 ret->decision = data->use_result_ind ?
01218                         DECISION_UNCOND_SUCC : DECISION_COND_SUCC;
01219                 /*
01220                  * It is possible for the server to reply with AKA
01221                  * Notification, so we must allow the method to continue and
01222                  * not only accept EAP-Success at this point.
01223                  */
01224                 ret->methodState = data->use_result_ind ?
01225                         METHOD_DONE : METHOD_MAY_CONT;
01226         } else if (data->state == RESULT_FAILURE)
01227                 ret->methodState = METHOD_CONT;
01228         else if (data->state == RESULT_SUCCESS)
01229                 ret->methodState = METHOD_CONT;
01230 
01231         if (ret->methodState == METHOD_DONE) {
01232                 ret->allowNotifications = FALSE;
01233         }
01234 
01235         return res;
01236 }
01237 
01238 
01239 static Boolean eap_aka_has_reauth_data(struct eap_sm *sm, void *priv)
01240 {
01241         struct eap_aka_data *data = priv;
01242         return data->pseudonym || data->reauth_id;
01243 }
01244 
01245 
01246 static void eap_aka_deinit_for_reauth(struct eap_sm *sm, void *priv)
01247 {
01248         struct eap_aka_data *data = priv;
01249         eap_aka_clear_identities(data, CLEAR_EAP_ID);
01250         data->prev_id = -1;
01251         wpabuf_free(data->id_msgs);
01252         data->id_msgs = NULL;
01253         data->use_result_ind = 0;
01254         data->kdf_negotiation = 0;
01255 }
01256 
01257 
01258 static void * eap_aka_init_for_reauth(struct eap_sm *sm, void *priv)
01259 {
01260         struct eap_aka_data *data = priv;
01261         data->num_id_req = 0;
01262         data->num_notification = 0;
01263         eap_aka_state(data, CONTINUE);
01264         return priv;
01265 }
01266 
01267 
01268 static const u8 * eap_aka_get_identity(struct eap_sm *sm, void *priv,
01269                                        size_t *len)
01270 {
01271         struct eap_aka_data *data = priv;
01272 
01273         if (data->reauth_id) {
01274                 *len = data->reauth_id_len;
01275                 return data->reauth_id;
01276         }
01277 
01278         if (data->pseudonym) {
01279                 *len = data->pseudonym_len;
01280                 return data->pseudonym;
01281         }
01282 
01283         return NULL;
01284 }
01285 
01286 
01287 static Boolean eap_aka_isKeyAvailable(struct eap_sm *sm, void *priv)
01288 {
01289         struct eap_aka_data *data = priv;
01290         return data->state == SUCCESS;
01291 }
01292 
01293 
01294 static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
01295 {
01296         struct eap_aka_data *data = priv;
01297         u8 *key;
01298 
01299         if (data->state != SUCCESS)
01300                 return NULL;
01301 
01302         key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
01303         if (key == NULL)
01304                 return NULL;
01305 
01306         *len = EAP_SIM_KEYING_DATA_LEN;
01307         os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
01308 
01309         return key;
01310 }
01311 
01312 
01313 static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
01314 {
01315         struct eap_aka_data *data = priv;
01316         u8 *key;
01317 
01318         if (data->state != SUCCESS)
01319                 return NULL;
01320 
01321         key = os_malloc(EAP_EMSK_LEN);
01322         if (key == NULL)
01323                 return NULL;
01324 
01325         *len = EAP_EMSK_LEN;
01326         os_memcpy(key, data->emsk, EAP_EMSK_LEN);
01327 
01328         return key;
01329 }
01330 
01331 
01332 int eap_peer_aka_register(void)
01333 {
01334         struct eap_method *eap;
01335         int ret;
01336 
01337         eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
01338                                     EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
01339         if (eap == NULL)
01340                 return -1;
01341 
01342         eap->init = eap_aka_init;
01343         eap->deinit = eap_aka_deinit;
01344         eap->process = eap_aka_process;
01345         eap->isKeyAvailable = eap_aka_isKeyAvailable;
01346         eap->getKey = eap_aka_getKey;
01347         eap->has_reauth_data = eap_aka_has_reauth_data;
01348         eap->deinit_for_reauth = eap_aka_deinit_for_reauth;
01349         eap->init_for_reauth = eap_aka_init_for_reauth;
01350         eap->get_identity = eap_aka_get_identity;
01351         eap->get_emsk = eap_aka_get_emsk;
01352 
01353         ret = eap_peer_method_register(eap);
01354         if (ret)
01355                 eap_peer_method_free(eap);
01356         return ret;
01357 }
01358 
01359 
01360 #ifdef EAP_AKA_PRIME
01361 int eap_peer_aka_prime_register(void)
01362 {
01363         struct eap_method *eap;
01364         int ret;
01365 
01366         eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
01367                                     EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
01368                                     "AKA'");
01369         if (eap == NULL)
01370                 return -1;
01371 
01372         eap->init = eap_aka_prime_init;
01373         eap->deinit = eap_aka_deinit;
01374         eap->process = eap_aka_process;
01375         eap->isKeyAvailable = eap_aka_isKeyAvailable;
01376         eap->getKey = eap_aka_getKey;
01377         eap->has_reauth_data = eap_aka_has_reauth_data;
01378         eap->deinit_for_reauth = eap_aka_deinit_for_reauth;
01379         eap->init_for_reauth = eap_aka_init_for_reauth;
01380         eap->get_identity = eap_aka_get_identity;
01381         eap->get_emsk = eap_aka_get_emsk;
01382 
01383         ret = eap_peer_method_register(eap);
01384         if (ret)
01385                 eap_peer_method_free(eap);
01386 
01387         return ret;
01388 }
01389 #endif /* EAP_AKA_PRIME */


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Jan 2 2014 11:26:37