eap_sim.c

Go to the documentation of this file.
00001 
00016 #include "includes.h"
00017 
00018 #include "common.h"
00019 #include "eap_server/eap_i.h"
00020 #include "eap_common/eap_sim_common.h"
00021 #include "eap_server/eap_sim_db.h"
00022 
00023 
00024 struct eap_sim_data {
00025         u8 mk[EAP_SIM_MK_LEN];
00026         u8 nonce_mt[EAP_SIM_NONCE_MT_LEN];
00027         u8 nonce_s[EAP_SIM_NONCE_S_LEN];
00028         u8 k_aut[EAP_SIM_K_AUT_LEN];
00029         u8 k_encr[EAP_SIM_K_ENCR_LEN];
00030         u8 msk[EAP_SIM_KEYING_DATA_LEN];
00031         u8 emsk[EAP_EMSK_LEN];
00032         u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
00033         u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
00034         u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
00035         int num_chal;
00036         enum {
00037                 START, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE
00038         } state;
00039         char *next_pseudonym;
00040         char *next_reauth_id;
00041         u16 counter;
00042         struct eap_sim_reauth *reauth;
00043         u16 notification;
00044         int use_result_ind;
00045 };
00046 
00047 
00048 static const char * eap_sim_state_txt(int state)
00049 {
00050         switch (state) {
00051         case START:
00052                 return "START";
00053         case CHALLENGE:
00054                 return "CHALLENGE";
00055         case REAUTH:
00056                 return "REAUTH";
00057         case SUCCESS:
00058                 return "SUCCESS";
00059         case FAILURE:
00060                 return "FAILURE";
00061         case NOTIFICATION:
00062                 return "NOTIFICATION";
00063         default:
00064                 return "Unknown?!";
00065         }
00066 }
00067 
00068 
00069 static void eap_sim_state(struct eap_sim_data *data, int state)
00070 {
00071         wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s",
00072                    eap_sim_state_txt(data->state),
00073                    eap_sim_state_txt(state));
00074         data->state = state;
00075 }
00076 
00077 
00078 static void * eap_sim_init(struct eap_sm *sm)
00079 {
00080         struct eap_sim_data *data;
00081 
00082         if (sm->eap_sim_db_priv == NULL) {
00083                 wpa_printf(MSG_WARNING, "EAP-SIM: eap_sim_db not configured");
00084                 return NULL;
00085         }
00086 
00087         data = os_zalloc(sizeof(*data));
00088         if (data == NULL)
00089                 return NULL;
00090         data->state = START;
00091 
00092         return data;
00093 }
00094 
00095 
00096 static void eap_sim_reset(struct eap_sm *sm, void *priv)
00097 {
00098         struct eap_sim_data *data = priv;
00099         os_free(data->next_pseudonym);
00100         os_free(data->next_reauth_id);
00101         os_free(data);
00102 }
00103 
00104 
00105 static struct wpabuf * eap_sim_build_start(struct eap_sm *sm,
00106                                            struct eap_sim_data *data, u8 id)
00107 {
00108         struct eap_sim_msg *msg;
00109         u8 ver[2];
00110 
00111         wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Start");
00112         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
00113                                EAP_SIM_SUBTYPE_START);
00114         if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
00115                                       sm->identity_len)) {
00116                 wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
00117                 eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
00118         } else {
00119                 /*
00120                  * RFC 4186, Chap. 4.2.4 recommends that identity from EAP is
00121                  * ignored and the SIM/Start is used to request the identity.
00122                  */
00123                 wpa_printf(MSG_DEBUG, "   AT_ANY_ID_REQ");
00124                 eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
00125         }
00126         wpa_printf(MSG_DEBUG, "   AT_VERSION_LIST");
00127         ver[0] = 0;
00128         ver[1] = EAP_SIM_VERSION;
00129         eap_sim_msg_add(msg, EAP_SIM_AT_VERSION_LIST, sizeof(ver),
00130                         ver, sizeof(ver));
00131         return eap_sim_msg_finish(msg, NULL, NULL, 0);
00132 }
00133 
00134 
00135 static int eap_sim_build_encr(struct eap_sm *sm, struct eap_sim_data *data,
00136                               struct eap_sim_msg *msg, u16 counter,
00137                               const u8 *nonce_s)
00138 {
00139         os_free(data->next_pseudonym);
00140         data->next_pseudonym =
00141                 eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 0);
00142         os_free(data->next_reauth_id);
00143         if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) {
00144                 data->next_reauth_id =
00145                         eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 0);
00146         } else {
00147                 wpa_printf(MSG_DEBUG, "EAP-SIM: Max fast re-authentication "
00148                            "count exceeded - force full authentication");
00149                 data->next_reauth_id = NULL;
00150         }
00151 
00152         if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
00153             counter == 0 && nonce_s == NULL)
00154                 return 0;
00155 
00156         wpa_printf(MSG_DEBUG, "   AT_IV");
00157         wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
00158         eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
00159 
00160         if (counter > 0) {
00161                 wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)", counter);
00162                 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
00163         }
00164 
00165         if (nonce_s) {
00166                 wpa_printf(MSG_DEBUG, "   *AT_NONCE_S");
00167                 eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
00168                                 EAP_SIM_NONCE_S_LEN);
00169         }
00170 
00171         if (data->next_pseudonym) {
00172                 wpa_printf(MSG_DEBUG, "   *AT_NEXT_PSEUDONYM (%s)",
00173                            data->next_pseudonym);
00174                 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
00175                                 os_strlen(data->next_pseudonym),
00176                                 (u8 *) data->next_pseudonym,
00177                                 os_strlen(data->next_pseudonym));
00178         }
00179 
00180         if (data->next_reauth_id) {
00181                 wpa_printf(MSG_DEBUG, "   *AT_NEXT_REAUTH_ID (%s)",
00182                            data->next_reauth_id);
00183                 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
00184                                 os_strlen(data->next_reauth_id),
00185                                 (u8 *) data->next_reauth_id,
00186                                 os_strlen(data->next_reauth_id));
00187         }
00188 
00189         if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
00190                 wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
00191                            "AT_ENCR_DATA");
00192                 return -1;
00193         }
00194 
00195         return 0;
00196 }
00197 
00198 
00199 static struct wpabuf * eap_sim_build_challenge(struct eap_sm *sm,
00200                                                struct eap_sim_data *data,
00201                                                u8 id)
00202 {
00203         struct eap_sim_msg *msg;
00204 
00205         wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Challenge");
00206         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
00207                                EAP_SIM_SUBTYPE_CHALLENGE);
00208         wpa_printf(MSG_DEBUG, "   AT_RAND");
00209         eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, (u8 *) data->rand,
00210                         data->num_chal * GSM_RAND_LEN);
00211 
00212         if (eap_sim_build_encr(sm, data, msg, 0, NULL)) {
00213                 eap_sim_msg_free(msg);
00214                 return NULL;
00215         }
00216 
00217         if (sm->eap_sim_aka_result_ind) {
00218                 wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
00219                 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
00220         }
00221 
00222         wpa_printf(MSG_DEBUG, "   AT_MAC");
00223         eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
00224         return eap_sim_msg_finish(msg, data->k_aut, data->nonce_mt,
00225                                   EAP_SIM_NONCE_MT_LEN);
00226 }
00227 
00228 
00229 static struct wpabuf * eap_sim_build_reauth(struct eap_sm *sm,
00230                                             struct eap_sim_data *data, u8 id)
00231 {
00232         struct eap_sim_msg *msg;
00233 
00234         wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Re-authentication");
00235 
00236         if (os_get_random(data->nonce_s, EAP_SIM_NONCE_S_LEN))
00237                 return NULL;
00238         wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: NONCE_S",
00239                         data->nonce_s, EAP_SIM_NONCE_S_LEN);
00240 
00241         eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
00242                             data->emsk);
00243         eap_sim_derive_keys_reauth(data->counter, sm->identity,
00244                                    sm->identity_len, data->nonce_s, data->mk,
00245                                    data->msk, data->emsk);
00246 
00247         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
00248                                EAP_SIM_SUBTYPE_REAUTHENTICATION);
00249 
00250         if (eap_sim_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
00251                 eap_sim_msg_free(msg);
00252                 return NULL;
00253         }
00254 
00255         if (sm->eap_sim_aka_result_ind) {
00256                 wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
00257                 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
00258         }
00259 
00260         wpa_printf(MSG_DEBUG, "   AT_MAC");
00261         eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
00262         return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
00263 }
00264 
00265 
00266 static struct wpabuf * eap_sim_build_notification(struct eap_sm *sm,
00267                                                   struct eap_sim_data *data,
00268                                                   u8 id)
00269 {
00270         struct eap_sim_msg *msg;
00271 
00272         wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Notification");
00273         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
00274                                EAP_SIM_SUBTYPE_NOTIFICATION);
00275         wpa_printf(MSG_DEBUG, "   AT_NOTIFICATION (%d)", data->notification);
00276         eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification,
00277                         NULL, 0);
00278         if (data->use_result_ind) {
00279                 if (data->reauth) {
00280                         wpa_printf(MSG_DEBUG, "   AT_IV");
00281                         wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
00282                         eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
00283                                                    EAP_SIM_AT_ENCR_DATA);
00284                         wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)",
00285                                    data->counter);
00286                         eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
00287                                         NULL, 0);
00288 
00289                         if (eap_sim_msg_add_encr_end(msg, data->k_encr,
00290                                                      EAP_SIM_AT_PADDING)) {
00291                                 wpa_printf(MSG_WARNING, "EAP-SIM: Failed to "
00292                                            "encrypt AT_ENCR_DATA");
00293                                 eap_sim_msg_free(msg);
00294                                 return NULL;
00295                         }
00296                 }
00297 
00298                 wpa_printf(MSG_DEBUG, "   AT_MAC");
00299                 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
00300         }
00301         return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
00302 }
00303 
00304 
00305 static struct wpabuf * eap_sim_buildReq(struct eap_sm *sm, void *priv, u8 id)
00306 {
00307         struct eap_sim_data *data = priv;
00308 
00309         switch (data->state) {
00310         case START:
00311                 return eap_sim_build_start(sm, data, id);
00312         case CHALLENGE:
00313                 return eap_sim_build_challenge(sm, data, id);
00314         case REAUTH:
00315                 return eap_sim_build_reauth(sm, data, id);
00316         case NOTIFICATION:
00317                 return eap_sim_build_notification(sm, data, id);
00318         default:
00319                 wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
00320                            "buildReq", data->state);
00321                 break;
00322         }
00323         return NULL;
00324 }
00325 
00326 
00327 static Boolean eap_sim_check(struct eap_sm *sm, void *priv,
00328                              struct wpabuf *respData)
00329 {
00330         struct eap_sim_data *data = priv;
00331         const u8 *pos;
00332         size_t len;
00333         u8 subtype;
00334 
00335         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len);
00336         if (pos == NULL || len < 3) {
00337                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame");
00338                 return TRUE;
00339         }
00340         subtype = *pos;
00341 
00342         if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR)
00343                 return FALSE;
00344 
00345         switch (data->state) {
00346         case START:
00347                 if (subtype != EAP_SIM_SUBTYPE_START) {
00348                         wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
00349                                    "subtype %d", subtype);
00350                         return TRUE;
00351                 }
00352                 break;
00353         case CHALLENGE:
00354                 if (subtype != EAP_SIM_SUBTYPE_CHALLENGE) {
00355                         wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
00356                                    "subtype %d", subtype);
00357                         return TRUE;
00358                 }
00359                 break;
00360         case REAUTH:
00361                 if (subtype != EAP_SIM_SUBTYPE_REAUTHENTICATION) {
00362                         wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
00363                                    "subtype %d", subtype);
00364                         return TRUE;
00365                 }
00366                 break;
00367         case NOTIFICATION:
00368                 if (subtype != EAP_SIM_SUBTYPE_NOTIFICATION) {
00369                         wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
00370                                    "subtype %d", subtype);
00371                         return TRUE;
00372                 }
00373                 break;
00374         default:
00375                 wpa_printf(MSG_INFO, "EAP-SIM: Unexpected state (%d) for "
00376                            "processing a response", data->state);
00377                 return TRUE;
00378         }
00379 
00380         return FALSE;
00381 }
00382 
00383 
00384 static int eap_sim_supported_ver(struct eap_sim_data *data, int version)
00385 {
00386         return version == EAP_SIM_VERSION;
00387 }
00388 
00389 
00390 static void eap_sim_process_start(struct eap_sm *sm,
00391                                   struct eap_sim_data *data,
00392                                   struct wpabuf *respData,
00393                                   struct eap_sim_attrs *attr)
00394 {
00395         const u8 *identity;
00396         size_t identity_len;
00397         u8 ver_list[2];
00398 
00399         wpa_printf(MSG_DEBUG, "EAP-SIM: Receive start response");
00400 
00401         if (attr->identity) {
00402                 os_free(sm->identity);
00403                 sm->identity = os_malloc(attr->identity_len);
00404                 if (sm->identity) {
00405                         os_memcpy(sm->identity, attr->identity,
00406                                   attr->identity_len);
00407                         sm->identity_len = attr->identity_len;
00408                 }
00409         }
00410 
00411         identity = NULL;
00412         identity_len = 0;
00413 
00414         if (sm->identity && sm->identity_len > 0 &&
00415             sm->identity[0] == EAP_SIM_PERMANENT_PREFIX) {
00416                 identity = sm->identity;
00417                 identity_len = sm->identity_len;
00418         } else {
00419                 identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv,
00420                                                     sm->identity,
00421                                                     sm->identity_len,
00422                                                     &identity_len);
00423                 if (identity == NULL) {
00424                         data->reauth = eap_sim_db_get_reauth_entry(
00425                                 sm->eap_sim_db_priv, sm->identity,
00426                                 sm->identity_len);
00427                         if (data->reauth) {
00428                                 wpa_printf(MSG_DEBUG, "EAP-SIM: Using fast "
00429                                            "re-authentication");
00430                                 identity = data->reauth->identity;
00431                                 identity_len = data->reauth->identity_len;
00432                                 data->counter = data->reauth->counter;
00433                                 os_memcpy(data->mk, data->reauth->mk,
00434                                           EAP_SIM_MK_LEN);
00435                         }
00436                 }
00437         }
00438 
00439         if (identity == NULL) {
00440                 wpa_printf(MSG_DEBUG, "EAP-SIM: Could not get proper permanent"
00441                            " user name");
00442                 eap_sim_state(data, FAILURE);
00443                 return;
00444         }
00445 
00446         wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
00447                           identity, identity_len);
00448 
00449         if (data->reauth) {
00450                 eap_sim_state(data, REAUTH);
00451                 return;
00452         }
00453 
00454         if (attr->nonce_mt == NULL || attr->selected_version < 0) {
00455                 wpa_printf(MSG_DEBUG, "EAP-SIM: Start/Response missing "
00456                            "required attributes");
00457                 eap_sim_state(data, FAILURE);
00458                 return;
00459         }
00460 
00461         if (!eap_sim_supported_ver(data, attr->selected_version)) {
00462                 wpa_printf(MSG_DEBUG, "EAP-SIM: Peer selected unsupported "
00463                            "version %d", attr->selected_version);
00464                 eap_sim_state(data, FAILURE);
00465                 return;
00466         }
00467 
00468         data->counter = 0; /* reset re-auth counter since this is full auth */
00469         data->reauth = NULL;
00470 
00471         data->num_chal = eap_sim_db_get_gsm_triplets(
00472                 sm->eap_sim_db_priv, identity, identity_len,
00473                 EAP_SIM_MAX_CHAL,
00474                 (u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm);
00475         if (data->num_chal == EAP_SIM_DB_PENDING) {
00476                 wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets "
00477                            "not yet available - pending request");
00478                 sm->method_pending = METHOD_PENDING_WAIT;
00479                 return;
00480         }
00481         if (data->num_chal < 2) {
00482                 wpa_printf(MSG_INFO, "EAP-SIM: Failed to get GSM "
00483                            "authentication triplets for the peer");
00484                 eap_sim_state(data, FAILURE);
00485                 return;
00486         }
00487 
00488         identity_len = sm->identity_len;
00489         while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') {
00490                 wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop last null "
00491                            "character from identity");
00492                 identity_len--;
00493         }
00494         wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity for MK derivation",
00495                           sm->identity, identity_len);
00496 
00497         os_memcpy(data->nonce_mt, attr->nonce_mt, EAP_SIM_NONCE_MT_LEN);
00498         WPA_PUT_BE16(ver_list, EAP_SIM_VERSION);
00499         eap_sim_derive_mk(sm->identity, identity_len, attr->nonce_mt,
00500                           attr->selected_version, ver_list, sizeof(ver_list),
00501                           data->num_chal, (const u8 *) data->kc, data->mk);
00502         eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
00503                             data->emsk);
00504 
00505         eap_sim_state(data, CHALLENGE);
00506 }
00507 
00508 
00509 static void eap_sim_process_challenge(struct eap_sm *sm,
00510                                       struct eap_sim_data *data,
00511                                       struct wpabuf *respData,
00512                                       struct eap_sim_attrs *attr)
00513 {
00514         const u8 *identity;
00515         size_t identity_len;
00516 
00517         if (attr->mac == NULL ||
00518             eap_sim_verify_mac(data->k_aut, respData, attr->mac,
00519                                (u8 *) data->sres,
00520                                data->num_chal * EAP_SIM_SRES_LEN)) {
00521                 wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
00522                            "did not include valid AT_MAC");
00523                 eap_sim_state(data, FAILURE);
00524                 return;
00525         }
00526 
00527         wpa_printf(MSG_DEBUG, "EAP-SIM: Challenge response includes the "
00528                    "correct AT_MAC");
00529         if (sm->eap_sim_aka_result_ind && attr->result_ind) {
00530                 data->use_result_ind = 1;
00531                 data->notification = EAP_SIM_SUCCESS;
00532                 eap_sim_state(data, NOTIFICATION);
00533         } else
00534                 eap_sim_state(data, SUCCESS);
00535 
00536         identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity,
00537                                             sm->identity_len, &identity_len);
00538         if (identity == NULL) {
00539                 identity = sm->identity;
00540                 identity_len = sm->identity_len;
00541         }
00542 
00543         if (data->next_pseudonym) {
00544                 eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
00545                                          identity_len,
00546                                          data->next_pseudonym);
00547                 data->next_pseudonym = NULL;
00548         }
00549         if (data->next_reauth_id) {
00550                 eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
00551                                       identity_len,
00552                                       data->next_reauth_id, data->counter + 1,
00553                                       data->mk);
00554                 data->next_reauth_id = NULL;
00555         }
00556 }
00557 
00558 
00559 static void eap_sim_process_reauth(struct eap_sm *sm,
00560                                    struct eap_sim_data *data,
00561                                    struct wpabuf *respData,
00562                                    struct eap_sim_attrs *attr)
00563 {
00564         struct eap_sim_attrs eattr;
00565         u8 *decrypted = NULL;
00566         const u8 *identity, *id2;
00567         size_t identity_len, id2_len;
00568 
00569         if (attr->mac == NULL ||
00570             eap_sim_verify_mac(data->k_aut, respData, attr->mac, data->nonce_s,
00571                                EAP_SIM_NONCE_S_LEN)) {
00572                 wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message "
00573                            "did not include valid AT_MAC");
00574                 goto fail;
00575         }
00576 
00577         if (attr->encr_data == NULL || attr->iv == NULL) {
00578                 wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
00579                            "message did not include encrypted data");
00580                 goto fail;
00581         }
00582 
00583         decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
00584                                        attr->encr_data_len, attr->iv, &eattr,
00585                                        0);
00586         if (decrypted == NULL) {
00587                 wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
00588                            "data from reauthentication message");
00589                 goto fail;
00590         }
00591 
00592         if (eattr.counter != data->counter) {
00593                 wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message "
00594                            "used incorrect counter %u, expected %u",
00595                            eattr.counter, data->counter);
00596                 goto fail;
00597         }
00598         os_free(decrypted);
00599         decrypted = NULL;
00600 
00601         wpa_printf(MSG_DEBUG, "EAP-SIM: Re-authentication response includes "
00602                    "the correct AT_MAC");
00603         if (sm->eap_sim_aka_result_ind && attr->result_ind) {
00604                 data->use_result_ind = 1;
00605                 data->notification = EAP_SIM_SUCCESS;
00606                 eap_sim_state(data, NOTIFICATION);
00607         } else
00608                 eap_sim_state(data, SUCCESS);
00609 
00610         if (data->reauth) {
00611                 identity = data->reauth->identity;
00612                 identity_len = data->reauth->identity_len;
00613         } else {
00614                 identity = sm->identity;
00615                 identity_len = sm->identity_len;
00616         }
00617 
00618         id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity,
00619                                        identity_len, &id2_len);
00620         if (id2) {
00621                 identity = id2;
00622                 identity_len = id2_len;
00623         }
00624 
00625         if (data->next_pseudonym) {
00626                 eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
00627                                          identity_len, data->next_pseudonym);
00628                 data->next_pseudonym = NULL;
00629         }
00630         if (data->next_reauth_id) {
00631                 eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
00632                                       identity_len, data->next_reauth_id,
00633                                       data->counter + 1, data->mk);
00634                 data->next_reauth_id = NULL;
00635         } else {
00636                 eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
00637                 data->reauth = NULL;
00638         }
00639 
00640         return;
00641 
00642 fail:
00643         eap_sim_state(data, FAILURE);
00644         eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
00645         data->reauth = NULL;
00646         os_free(decrypted);
00647 }
00648 
00649 
00650 static void eap_sim_process_client_error(struct eap_sm *sm,
00651                                          struct eap_sim_data *data,
00652                                          struct wpabuf *respData,
00653                                          struct eap_sim_attrs *attr)
00654 {
00655         wpa_printf(MSG_DEBUG, "EAP-SIM: Client reported error %d",
00656                    attr->client_error_code);
00657         if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
00658                 eap_sim_state(data, SUCCESS);
00659         else
00660                 eap_sim_state(data, FAILURE);
00661 }
00662 
00663 
00664 static void eap_sim_process_notification(struct eap_sm *sm,
00665                                          struct eap_sim_data *data,
00666                                          struct wpabuf *respData,
00667                                          struct eap_sim_attrs *attr)
00668 {
00669         wpa_printf(MSG_DEBUG, "EAP-SIM: Client replied to notification");
00670         if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
00671                 eap_sim_state(data, SUCCESS);
00672         else
00673                 eap_sim_state(data, FAILURE);
00674 }
00675 
00676 
00677 static void eap_sim_process(struct eap_sm *sm, void *priv,
00678                             struct wpabuf *respData)
00679 {
00680         struct eap_sim_data *data = priv;
00681         const u8 *pos, *end;
00682         u8 subtype;
00683         size_t len;
00684         struct eap_sim_attrs attr;
00685 
00686         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len);
00687         if (pos == NULL || len < 3)
00688                 return;
00689 
00690         end = pos + len;
00691         subtype = *pos;
00692         pos += 3;
00693 
00694         if (eap_sim_parse_attr(pos, end, &attr, 0, 0)) {
00695                 wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to parse attributes");
00696                 eap_sim_state(data, FAILURE);
00697                 return;
00698         }
00699 
00700         if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) {
00701                 eap_sim_process_client_error(sm, data, respData, &attr);
00702                 return;
00703         }
00704 
00705         switch (data->state) {
00706         case START:
00707                 eap_sim_process_start(sm, data, respData, &attr);
00708                 break;
00709         case CHALLENGE:
00710                 eap_sim_process_challenge(sm, data, respData, &attr);
00711                 break;
00712         case REAUTH:
00713                 eap_sim_process_reauth(sm, data, respData, &attr);
00714                 break;
00715         case NOTIFICATION:
00716                 eap_sim_process_notification(sm, data, respData, &attr);
00717                 break;
00718         default:
00719                 wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
00720                            "process", data->state);
00721                 break;
00722         }
00723 }
00724 
00725 
00726 static Boolean eap_sim_isDone(struct eap_sm *sm, void *priv)
00727 {
00728         struct eap_sim_data *data = priv;
00729         return data->state == SUCCESS || data->state == FAILURE;
00730 }
00731 
00732 
00733 static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
00734 {
00735         struct eap_sim_data *data = priv;
00736         u8 *key;
00737 
00738         if (data->state != SUCCESS)
00739                 return NULL;
00740 
00741         key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
00742         if (key == NULL)
00743                 return NULL;
00744         os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
00745         *len = EAP_SIM_KEYING_DATA_LEN;
00746         return key;
00747 }
00748 
00749 
00750 static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
00751 {
00752         struct eap_sim_data *data = priv;
00753         u8 *key;
00754 
00755         if (data->state != SUCCESS)
00756                 return NULL;
00757 
00758         key = os_malloc(EAP_EMSK_LEN);
00759         if (key == NULL)
00760                 return NULL;
00761         os_memcpy(key, data->emsk, EAP_EMSK_LEN);
00762         *len = EAP_EMSK_LEN;
00763         return key;
00764 }
00765 
00766 
00767 static Boolean eap_sim_isSuccess(struct eap_sm *sm, void *priv)
00768 {
00769         struct eap_sim_data *data = priv;
00770         return data->state == SUCCESS;
00771 }
00772 
00773 
00774 int eap_server_sim_register(void)
00775 {
00776         struct eap_method *eap;
00777         int ret;
00778 
00779         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
00780                                       EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM");
00781         if (eap == NULL)
00782                 return -1;
00783 
00784         eap->init = eap_sim_init;
00785         eap->reset = eap_sim_reset;
00786         eap->buildReq = eap_sim_buildReq;
00787         eap->check = eap_sim_check;
00788         eap->process = eap_sim_process;
00789         eap->isDone = eap_sim_isDone;
00790         eap->getKey = eap_sim_getKey;
00791         eap->isSuccess = eap_sim_isSuccess;
00792         eap->get_emsk = eap_sim_get_emsk;
00793 
00794         ret = eap_server_method_register(eap);
00795         if (ret)
00796                 eap_server_method_free(eap);
00797         return ret;
00798 }
00799 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines

Generated on Sat Nov 21 23:16:52 2009 for hostapd by  doxygen 1.6.1