eap.c
Go to the documentation of this file.
00001 /*
00002  * EAP peer state machines (RFC 4137)
00003  * Copyright (c) 2004-2010, 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  * This file implements the Peer State Machine as defined in RFC 4137. The used
00015  * states and state transitions match mostly with the RFC. However, there are
00016  * couple of additional transitions for working around small issues noticed
00017  * during testing. These exceptions are explained in comments within the
00018  * functions in this file. The method functions, m.func(), are similar to the
00019  * ones used in RFC 4137, but some small changes have used here to optimize
00020  * operations and to add functionality needed for fast re-authentication
00021  * (session resumption).
00022  */
00023 
00024 #include "includes.h"
00025 
00026 #include "common.h"
00027 #include "pcsc_funcs.h"
00028 #include "state_machine.h"
00029 #include "crypto/crypto.h"
00030 #include "crypto/tls.h"
00031 #include "common/wpa_ctrl.h"
00032 #include "eap_common/eap_wsc_common.h"
00033 #include "eap_i.h"
00034 #include "eap_config.h"
00035 
00036 #define STATE_MACHINE_DATA struct eap_sm
00037 #define STATE_MACHINE_DEBUG_PREFIX "EAP"
00038 
00039 #define EAP_MAX_AUTH_ROUNDS 50
00040 
00041 
00042 static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor,
00043                                   EapType method);
00044 static struct wpabuf * eap_sm_buildNak(struct eap_sm *sm, int id);
00045 static void eap_sm_processIdentity(struct eap_sm *sm,
00046                                    const struct wpabuf *req);
00047 static void eap_sm_processNotify(struct eap_sm *sm, const struct wpabuf *req);
00048 static struct wpabuf * eap_sm_buildNotify(int id);
00049 static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req);
00050 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
00051 static const char * eap_sm_method_state_txt(EapMethodState state);
00052 static const char * eap_sm_decision_txt(EapDecision decision);
00053 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
00054 
00055 
00056 
00057 static Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
00058 {
00059         return sm->eapol_cb->get_bool(sm->eapol_ctx, var);
00060 }
00061 
00062 
00063 static void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var,
00064                            Boolean value)
00065 {
00066         sm->eapol_cb->set_bool(sm->eapol_ctx, var, value);
00067 }
00068 
00069 
00070 static unsigned int eapol_get_int(struct eap_sm *sm, enum eapol_int_var var)
00071 {
00072         return sm->eapol_cb->get_int(sm->eapol_ctx, var);
00073 }
00074 
00075 
00076 static void eapol_set_int(struct eap_sm *sm, enum eapol_int_var var,
00077                           unsigned int value)
00078 {
00079         sm->eapol_cb->set_int(sm->eapol_ctx, var, value);
00080 }
00081 
00082 
00083 static struct wpabuf * eapol_get_eapReqData(struct eap_sm *sm)
00084 {
00085         return sm->eapol_cb->get_eapReqData(sm->eapol_ctx);
00086 }
00087 
00088 
00089 static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)
00090 {
00091         if (sm->m == NULL || sm->eap_method_priv == NULL)
00092                 return;
00093 
00094         wpa_printf(MSG_DEBUG, "EAP: deinitialize previously used EAP method "
00095                    "(%d, %s) at %s", sm->selectedMethod, sm->m->name, txt);
00096         sm->m->deinit(sm, sm->eap_method_priv);
00097         sm->eap_method_priv = NULL;
00098         sm->m = NULL;
00099 }
00100 
00101 
00109 int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method)
00110 {
00111         struct eap_peer_config *config = eap_get_config(sm);
00112         int i;
00113         struct eap_method_type *m;
00114 
00115         if (config == NULL || config->eap_methods == NULL)
00116                 return 1;
00117 
00118         m = config->eap_methods;
00119         for (i = 0; m[i].vendor != EAP_VENDOR_IETF ||
00120                      m[i].method != EAP_TYPE_NONE; i++) {
00121                 if (m[i].vendor == vendor && m[i].method == method)
00122                         return 1;
00123         }
00124         return 0;
00125 }
00126 
00127 
00128 /*
00129  * This state initializes state machine variables when the machine is
00130  * activated (portEnabled = TRUE). This is also used when re-starting
00131  * authentication (eapRestart == TRUE).
00132  */
00133 SM_STATE(EAP, INITIALIZE)
00134 {
00135         SM_ENTRY(EAP, INITIALIZE);
00136         if (sm->fast_reauth && sm->m && sm->m->has_reauth_data &&
00137             sm->m->has_reauth_data(sm, sm->eap_method_priv) &&
00138             !sm->prev_failure) {
00139                 wpa_printf(MSG_DEBUG, "EAP: maintaining EAP method data for "
00140                            "fast reauthentication");
00141                 sm->m->deinit_for_reauth(sm, sm->eap_method_priv);
00142         } else {
00143                 eap_deinit_prev_method(sm, "INITIALIZE");
00144         }
00145         sm->selectedMethod = EAP_TYPE_NONE;
00146         sm->methodState = METHOD_NONE;
00147         sm->allowNotifications = TRUE;
00148         sm->decision = DECISION_FAIL;
00149         eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
00150         eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
00151         eapol_set_bool(sm, EAPOL_eapFail, FALSE);
00152         os_free(sm->eapKeyData);
00153         sm->eapKeyData = NULL;
00154         sm->eapKeyAvailable = FALSE;
00155         eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
00156         sm->lastId = -1; /* new session - make sure this does not match with
00157                           * the first EAP-Packet */
00158         /*
00159          * RFC 4137 does not reset eapResp and eapNoResp here. However, this
00160          * seemed to be able to trigger cases where both were set and if EAPOL
00161          * state machine uses eapNoResp first, it may end up not sending a real
00162          * reply correctly. This occurred when the workaround in FAIL state set
00163          * eapNoResp = TRUE.. Maybe that workaround needs to be fixed to do
00164          * something else(?)
00165          */
00166         eapol_set_bool(sm, EAPOL_eapResp, FALSE);
00167         eapol_set_bool(sm, EAPOL_eapNoResp, FALSE);
00168         sm->num_rounds = 0;
00169         sm->prev_failure = 0;
00170 }
00171 
00172 
00173 /*
00174  * This state is reached whenever service from the lower layer is interrupted
00175  * or unavailable (portEnabled == FALSE). Immediate transition to INITIALIZE
00176  * occurs when the port becomes enabled.
00177  */
00178 SM_STATE(EAP, DISABLED)
00179 {
00180         SM_ENTRY(EAP, DISABLED);
00181         sm->num_rounds = 0;
00182 }
00183 
00184 
00185 /*
00186  * The state machine spends most of its time here, waiting for something to
00187  * happen. This state is entered unconditionally from INITIALIZE, DISCARD, and
00188  * SEND_RESPONSE states.
00189  */
00190 SM_STATE(EAP, IDLE)
00191 {
00192         SM_ENTRY(EAP, IDLE);
00193 }
00194 
00195 
00196 /*
00197  * This state is entered when an EAP packet is received (eapReq == TRUE) to
00198  * parse the packet header.
00199  */
00200 SM_STATE(EAP, RECEIVED)
00201 {
00202         const struct wpabuf *eapReqData;
00203 
00204         SM_ENTRY(EAP, RECEIVED);
00205         eapReqData = eapol_get_eapReqData(sm);
00206         /* parse rxReq, rxSuccess, rxFailure, reqId, reqMethod */
00207         eap_sm_parseEapReq(sm, eapReqData);
00208         sm->num_rounds++;
00209 }
00210 
00211 
00212 /*
00213  * This state is entered when a request for a new type comes in. Either the
00214  * correct method is started, or a Nak response is built.
00215  */
00216 SM_STATE(EAP, GET_METHOD)
00217 {
00218         int reinit;
00219         EapType method;
00220 
00221         SM_ENTRY(EAP, GET_METHOD);
00222 
00223         if (sm->reqMethod == EAP_TYPE_EXPANDED)
00224                 method = sm->reqVendorMethod;
00225         else
00226                 method = sm->reqMethod;
00227 
00228         if (!eap_sm_allowMethod(sm, sm->reqVendor, method)) {
00229                 wpa_printf(MSG_DEBUG, "EAP: vendor %u method %u not allowed",
00230                            sm->reqVendor, method);
00231                 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
00232                         "vendor=%u method=%u -> NAK",
00233                         sm->reqVendor, method);
00234                 goto nak;
00235         }
00236 
00237         wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
00238                 "vendor=%u method=%u", sm->reqVendor, method);
00239 
00240         /*
00241          * RFC 4137 does not define specific operation for fast
00242          * re-authentication (session resumption). The design here is to allow
00243          * the previously used method data to be maintained for
00244          * re-authentication if the method support session resumption.
00245          * Otherwise, the previously used method data is freed and a new method
00246          * is allocated here.
00247          */
00248         if (sm->fast_reauth &&
00249             sm->m && sm->m->vendor == sm->reqVendor &&
00250             sm->m->method == method &&
00251             sm->m->has_reauth_data &&
00252             sm->m->has_reauth_data(sm, sm->eap_method_priv)) {
00253                 wpa_printf(MSG_DEBUG, "EAP: Using previous method data"
00254                            " for fast re-authentication");
00255                 reinit = 1;
00256         } else {
00257                 eap_deinit_prev_method(sm, "GET_METHOD");
00258                 reinit = 0;
00259         }
00260 
00261         sm->selectedMethod = sm->reqMethod;
00262         if (sm->m == NULL)
00263                 sm->m = eap_peer_get_eap_method(sm->reqVendor, method);
00264         if (!sm->m) {
00265                 wpa_printf(MSG_DEBUG, "EAP: Could not find selected method: "
00266                            "vendor %d method %d",
00267                            sm->reqVendor, method);
00268                 goto nak;
00269         }
00270 
00271         wpa_printf(MSG_DEBUG, "EAP: Initialize selected EAP method: "
00272                    "vendor %u method %u (%s)",
00273                    sm->reqVendor, method, sm->m->name);
00274         if (reinit)
00275                 sm->eap_method_priv = sm->m->init_for_reauth(
00276                         sm, sm->eap_method_priv);
00277         else
00278                 sm->eap_method_priv = sm->m->init(sm);
00279 
00280         if (sm->eap_method_priv == NULL) {
00281                 struct eap_peer_config *config = eap_get_config(sm);
00282                 wpa_msg(sm->msg_ctx, MSG_INFO,
00283                         "EAP: Failed to initialize EAP method: vendor %u "
00284                         "method %u (%s)",
00285                         sm->reqVendor, method, sm->m->name);
00286                 sm->m = NULL;
00287                 sm->methodState = METHOD_NONE;
00288                 sm->selectedMethod = EAP_TYPE_NONE;
00289                 if (sm->reqMethod == EAP_TYPE_TLS && config &&
00290                     (config->pending_req_pin ||
00291                      config->pending_req_passphrase)) {
00292                         /*
00293                          * Return without generating Nak in order to allow
00294                          * entering of PIN code or passphrase to retry the
00295                          * current EAP packet.
00296                          */
00297                         wpa_printf(MSG_DEBUG, "EAP: Pending PIN/passphrase "
00298                                    "request - skip Nak");
00299                         return;
00300                 }
00301 
00302                 goto nak;
00303         }
00304 
00305         sm->methodState = METHOD_INIT;
00306         wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_METHOD
00307                 "EAP vendor %u method %u (%s) selected",
00308                 sm->reqVendor, method, sm->m->name);
00309         return;
00310 
00311 nak:
00312         wpabuf_free(sm->eapRespData);
00313         sm->eapRespData = NULL;
00314         sm->eapRespData = eap_sm_buildNak(sm, sm->reqId);
00315 }
00316 
00317 
00318 /*
00319  * The method processing happens here. The request from the authenticator is
00320  * processed, and an appropriate response packet is built.
00321  */
00322 SM_STATE(EAP, METHOD)
00323 {
00324         struct wpabuf *eapReqData;
00325         struct eap_method_ret ret;
00326 
00327         SM_ENTRY(EAP, METHOD);
00328         if (sm->m == NULL) {
00329                 wpa_printf(MSG_WARNING, "EAP::METHOD - method not selected");
00330                 return;
00331         }
00332 
00333         eapReqData = eapol_get_eapReqData(sm);
00334 
00335         /*
00336          * Get ignore, methodState, decision, allowNotifications, and
00337          * eapRespData. RFC 4137 uses three separate method procedure (check,
00338          * process, and buildResp) in this state. These have been combined into
00339          * a single function call to m->process() in order to optimize EAP
00340          * method implementation interface a bit. These procedures are only
00341          * used from within this METHOD state, so there is no need to keep
00342          * these as separate C functions.
00343          *
00344          * The RFC 4137 procedures return values as follows:
00345          * ignore = m.check(eapReqData)
00346          * (methodState, decision, allowNotifications) = m.process(eapReqData)
00347          * eapRespData = m.buildResp(reqId)
00348          */
00349         os_memset(&ret, 0, sizeof(ret));
00350         ret.ignore = sm->ignore;
00351         ret.methodState = sm->methodState;
00352         ret.decision = sm->decision;
00353         ret.allowNotifications = sm->allowNotifications;
00354         wpabuf_free(sm->eapRespData);
00355         sm->eapRespData = NULL;
00356         sm->eapRespData = sm->m->process(sm, sm->eap_method_priv, &ret,
00357                                          eapReqData);
00358         wpa_printf(MSG_DEBUG, "EAP: method process -> ignore=%s "
00359                    "methodState=%s decision=%s",
00360                    ret.ignore ? "TRUE" : "FALSE",
00361                    eap_sm_method_state_txt(ret.methodState),
00362                    eap_sm_decision_txt(ret.decision));
00363 
00364         sm->ignore = ret.ignore;
00365         if (sm->ignore)
00366                 return;
00367         sm->methodState = ret.methodState;
00368         sm->decision = ret.decision;
00369         sm->allowNotifications = ret.allowNotifications;
00370 
00371         if (sm->m->isKeyAvailable && sm->m->getKey &&
00372             sm->m->isKeyAvailable(sm, sm->eap_method_priv)) {
00373                 os_free(sm->eapKeyData);
00374                 sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
00375                                                &sm->eapKeyDataLen);
00376         }
00377 }
00378 
00379 
00380 /*
00381  * This state signals the lower layer that a response packet is ready to be
00382  * sent.
00383  */
00384 SM_STATE(EAP, SEND_RESPONSE)
00385 {
00386         SM_ENTRY(EAP, SEND_RESPONSE);
00387         wpabuf_free(sm->lastRespData);
00388         if (sm->eapRespData) {
00389                 if (sm->workaround)
00390                         os_memcpy(sm->last_md5, sm->req_md5, 16);
00391                 sm->lastId = sm->reqId;
00392                 sm->lastRespData = wpabuf_dup(sm->eapRespData);
00393                 eapol_set_bool(sm, EAPOL_eapResp, TRUE);
00394         } else
00395                 sm->lastRespData = NULL;
00396         eapol_set_bool(sm, EAPOL_eapReq, FALSE);
00397         eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
00398 }
00399 
00400 
00401 /*
00402  * This state signals the lower layer that the request was discarded, and no
00403  * response packet will be sent at this time.
00404  */
00405 SM_STATE(EAP, DISCARD)
00406 {
00407         SM_ENTRY(EAP, DISCARD);
00408         eapol_set_bool(sm, EAPOL_eapReq, FALSE);
00409         eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
00410 }
00411 
00412 
00413 /*
00414  * Handles requests for Identity method and builds a response.
00415  */
00416 SM_STATE(EAP, IDENTITY)
00417 {
00418         const struct wpabuf *eapReqData;
00419 
00420         SM_ENTRY(EAP, IDENTITY);
00421         eapReqData = eapol_get_eapReqData(sm);
00422         eap_sm_processIdentity(sm, eapReqData);
00423         wpabuf_free(sm->eapRespData);
00424         sm->eapRespData = NULL;
00425         sm->eapRespData = eap_sm_buildIdentity(sm, sm->reqId, 0);
00426 }
00427 
00428 
00429 /*
00430  * Handles requests for Notification method and builds a response.
00431  */
00432 SM_STATE(EAP, NOTIFICATION)
00433 {
00434         const struct wpabuf *eapReqData;
00435 
00436         SM_ENTRY(EAP, NOTIFICATION);
00437         eapReqData = eapol_get_eapReqData(sm);
00438         eap_sm_processNotify(sm, eapReqData);
00439         wpabuf_free(sm->eapRespData);
00440         sm->eapRespData = NULL;
00441         sm->eapRespData = eap_sm_buildNotify(sm->reqId);
00442 }
00443 
00444 
00445 /*
00446  * This state retransmits the previous response packet.
00447  */
00448 SM_STATE(EAP, RETRANSMIT)
00449 {
00450         SM_ENTRY(EAP, RETRANSMIT);
00451         wpabuf_free(sm->eapRespData);
00452         if (sm->lastRespData)
00453                 sm->eapRespData = wpabuf_dup(sm->lastRespData);
00454         else
00455                 sm->eapRespData = NULL;
00456 }
00457 
00458 
00459 /*
00460  * This state is entered in case of a successful completion of authentication
00461  * and state machine waits here until port is disabled or EAP authentication is
00462  * restarted.
00463  */
00464 SM_STATE(EAP, SUCCESS)
00465 {
00466         SM_ENTRY(EAP, SUCCESS);
00467         if (sm->eapKeyData != NULL)
00468                 sm->eapKeyAvailable = TRUE;
00469         eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
00470 
00471         /*
00472          * RFC 4137 does not clear eapReq here, but this seems to be required
00473          * to avoid processing the same request twice when state machine is
00474          * initialized.
00475          */
00476         eapol_set_bool(sm, EAPOL_eapReq, FALSE);
00477 
00478         /*
00479          * RFC 4137 does not set eapNoResp here, but this seems to be required
00480          * to get EAPOL Supplicant backend state machine into SUCCESS state. In
00481          * addition, either eapResp or eapNoResp is required to be set after
00482          * processing the received EAP frame.
00483          */
00484         eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
00485 
00486         wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
00487                 "EAP authentication completed successfully");
00488 }
00489 
00490 
00491 /*
00492  * This state is entered in case of a failure and state machine waits here
00493  * until port is disabled or EAP authentication is restarted.
00494  */
00495 SM_STATE(EAP, FAILURE)
00496 {
00497         SM_ENTRY(EAP, FAILURE);
00498         eapol_set_bool(sm, EAPOL_eapFail, TRUE);
00499 
00500         /*
00501          * RFC 4137 does not clear eapReq here, but this seems to be required
00502          * to avoid processing the same request twice when state machine is
00503          * initialized.
00504          */
00505         eapol_set_bool(sm, EAPOL_eapReq, FALSE);
00506 
00507         /*
00508          * RFC 4137 does not set eapNoResp here. However, either eapResp or
00509          * eapNoResp is required to be set after processing the received EAP
00510          * frame.
00511          */
00512         eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
00513 
00514         wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
00515                 "EAP authentication failed");
00516 
00517         sm->prev_failure = 1;
00518 }
00519 
00520 
00521 static int eap_success_workaround(struct eap_sm *sm, int reqId, int lastId)
00522 {
00523         /*
00524          * At least Microsoft IAS and Meetinghouse Aegis seem to be sending
00525          * EAP-Success/Failure with lastId + 1 even though RFC 3748 and
00526          * RFC 4137 require that reqId == lastId. In addition, it looks like
00527          * Ringmaster v2.1.2.0 would be using lastId + 2 in EAP-Success.
00528          *
00529          * Accept this kind of Id if EAP workarounds are enabled. These are
00530          * unauthenticated plaintext messages, so this should have minimal
00531          * security implications (bit easier to fake EAP-Success/Failure).
00532          */
00533         if (sm->workaround && (reqId == ((lastId + 1) & 0xff) ||
00534                                reqId == ((lastId + 2) & 0xff))) {
00535                 wpa_printf(MSG_DEBUG, "EAP: Workaround for unexpected "
00536                            "identifier field in EAP Success: "
00537                            "reqId=%d lastId=%d (these are supposed to be "
00538                            "same)", reqId, lastId);
00539                 return 1;
00540         }
00541         wpa_printf(MSG_DEBUG, "EAP: EAP-Success Id mismatch - reqId=%d "
00542                    "lastId=%d", reqId, lastId);
00543         return 0;
00544 }
00545 
00546 
00547 /*
00548  * RFC 4137 - Appendix A.1: EAP Peer State Machine - State transitions
00549  */
00550 
00551 static void eap_peer_sm_step_idle(struct eap_sm *sm)
00552 {
00553         /*
00554          * The first three transitions are from RFC 4137. The last two are
00555          * local additions to handle special cases with LEAP and PEAP server
00556          * not sending EAP-Success in some cases.
00557          */
00558         if (eapol_get_bool(sm, EAPOL_eapReq))
00559                 SM_ENTER(EAP, RECEIVED);
00560         else if ((eapol_get_bool(sm, EAPOL_altAccept) &&
00561                   sm->decision != DECISION_FAIL) ||
00562                  (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
00563                   sm->decision == DECISION_UNCOND_SUCC))
00564                 SM_ENTER(EAP, SUCCESS);
00565         else if (eapol_get_bool(sm, EAPOL_altReject) ||
00566                  (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
00567                   sm->decision != DECISION_UNCOND_SUCC) ||
00568                  (eapol_get_bool(sm, EAPOL_altAccept) &&
00569                   sm->methodState != METHOD_CONT &&
00570                   sm->decision == DECISION_FAIL))
00571                 SM_ENTER(EAP, FAILURE);
00572         else if (sm->selectedMethod == EAP_TYPE_LEAP &&
00573                  sm->leap_done && sm->decision != DECISION_FAIL &&
00574                  sm->methodState == METHOD_DONE)
00575                 SM_ENTER(EAP, SUCCESS);
00576         else if (sm->selectedMethod == EAP_TYPE_PEAP &&
00577                  sm->peap_done && sm->decision != DECISION_FAIL &&
00578                  sm->methodState == METHOD_DONE)
00579                 SM_ENTER(EAP, SUCCESS);
00580 }
00581 
00582 
00583 static int eap_peer_req_is_duplicate(struct eap_sm *sm)
00584 {
00585         int duplicate;
00586 
00587         duplicate = (sm->reqId == sm->lastId) && sm->rxReq;
00588         if (sm->workaround && duplicate &&
00589             os_memcmp(sm->req_md5, sm->last_md5, 16) != 0) {
00590                 /*
00591                  * RFC 4137 uses (reqId == lastId) as the only verification for
00592                  * duplicate EAP requests. However, this misses cases where the
00593                  * AS is incorrectly using the same id again; and
00594                  * unfortunately, such implementations exist. Use MD5 hash as
00595                  * an extra verification for the packets being duplicate to
00596                  * workaround these issues.
00597                  */
00598                 wpa_printf(MSG_DEBUG, "EAP: AS used the same Id again, but "
00599                            "EAP packets were not identical");
00600                 wpa_printf(MSG_DEBUG, "EAP: workaround - assume this is not a "
00601                            "duplicate packet");
00602                 duplicate = 0;
00603         }
00604 
00605         return duplicate;
00606 }
00607 
00608 
00609 static void eap_peer_sm_step_received(struct eap_sm *sm)
00610 {
00611         int duplicate = eap_peer_req_is_duplicate(sm);
00612 
00613         /*
00614          * Two special cases below for LEAP are local additions to work around
00615          * odd LEAP behavior (EAP-Success in the middle of authentication and
00616          * then swapped roles). Other transitions are based on RFC 4137.
00617          */
00618         if (sm->rxSuccess && sm->decision != DECISION_FAIL &&
00619             (sm->reqId == sm->lastId ||
00620              eap_success_workaround(sm, sm->reqId, sm->lastId)))
00621                 SM_ENTER(EAP, SUCCESS);
00622         else if (sm->methodState != METHOD_CONT &&
00623                  ((sm->rxFailure &&
00624                    sm->decision != DECISION_UNCOND_SUCC) ||
00625                   (sm->rxSuccess && sm->decision == DECISION_FAIL &&
00626                    (sm->selectedMethod != EAP_TYPE_LEAP ||
00627                     sm->methodState != METHOD_MAY_CONT))) &&
00628                  (sm->reqId == sm->lastId ||
00629                   eap_success_workaround(sm, sm->reqId, sm->lastId)))
00630                 SM_ENTER(EAP, FAILURE);
00631         else if (sm->rxReq && duplicate)
00632                 SM_ENTER(EAP, RETRANSMIT);
00633         else if (sm->rxReq && !duplicate &&
00634                  sm->reqMethod == EAP_TYPE_NOTIFICATION &&
00635                  sm->allowNotifications)
00636                 SM_ENTER(EAP, NOTIFICATION);
00637         else if (sm->rxReq && !duplicate &&
00638                  sm->selectedMethod == EAP_TYPE_NONE &&
00639                  sm->reqMethod == EAP_TYPE_IDENTITY)
00640                 SM_ENTER(EAP, IDENTITY);
00641         else if (sm->rxReq && !duplicate &&
00642                  sm->selectedMethod == EAP_TYPE_NONE &&
00643                  sm->reqMethod != EAP_TYPE_IDENTITY &&
00644                  sm->reqMethod != EAP_TYPE_NOTIFICATION)
00645                 SM_ENTER(EAP, GET_METHOD);
00646         else if (sm->rxReq && !duplicate &&
00647                  sm->reqMethod == sm->selectedMethod &&
00648                  sm->methodState != METHOD_DONE)
00649                 SM_ENTER(EAP, METHOD);
00650         else if (sm->selectedMethod == EAP_TYPE_LEAP &&
00651                  (sm->rxSuccess || sm->rxResp))
00652                 SM_ENTER(EAP, METHOD);
00653         else
00654                 SM_ENTER(EAP, DISCARD);
00655 }
00656 
00657 
00658 static void eap_peer_sm_step_local(struct eap_sm *sm)
00659 {
00660         switch (sm->EAP_state) {
00661         case EAP_INITIALIZE:
00662                 SM_ENTER(EAP, IDLE);
00663                 break;
00664         case EAP_DISABLED:
00665                 if (eapol_get_bool(sm, EAPOL_portEnabled) &&
00666                     !sm->force_disabled)
00667                         SM_ENTER(EAP, INITIALIZE);
00668                 break;
00669         case EAP_IDLE:
00670                 eap_peer_sm_step_idle(sm);
00671                 break;
00672         case EAP_RECEIVED:
00673                 eap_peer_sm_step_received(sm);
00674                 break;
00675         case EAP_GET_METHOD:
00676                 if (sm->selectedMethod == sm->reqMethod)
00677                         SM_ENTER(EAP, METHOD);
00678                 else
00679                         SM_ENTER(EAP, SEND_RESPONSE);
00680                 break;
00681         case EAP_METHOD:
00682                 if (sm->ignore)
00683                         SM_ENTER(EAP, DISCARD);
00684                 else
00685                         SM_ENTER(EAP, SEND_RESPONSE);
00686                 break;
00687         case EAP_SEND_RESPONSE:
00688                 SM_ENTER(EAP, IDLE);
00689                 break;
00690         case EAP_DISCARD:
00691                 SM_ENTER(EAP, IDLE);
00692                 break;
00693         case EAP_IDENTITY:
00694                 SM_ENTER(EAP, SEND_RESPONSE);
00695                 break;
00696         case EAP_NOTIFICATION:
00697                 SM_ENTER(EAP, SEND_RESPONSE);
00698                 break;
00699         case EAP_RETRANSMIT:
00700                 SM_ENTER(EAP, SEND_RESPONSE);
00701                 break;
00702         case EAP_SUCCESS:
00703                 break;
00704         case EAP_FAILURE:
00705                 break;
00706         }
00707 }
00708 
00709 
00710 SM_STEP(EAP)
00711 {
00712         /* Global transitions */
00713         if (eapol_get_bool(sm, EAPOL_eapRestart) &&
00714             eapol_get_bool(sm, EAPOL_portEnabled))
00715                 SM_ENTER_GLOBAL(EAP, INITIALIZE);
00716         else if (!eapol_get_bool(sm, EAPOL_portEnabled) || sm->force_disabled)
00717                 SM_ENTER_GLOBAL(EAP, DISABLED);
00718         else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
00719                 /* RFC 4137 does not place any limit on number of EAP messages
00720                  * in an authentication session. However, some error cases have
00721                  * ended up in a state were EAP messages were sent between the
00722                  * peer and server in a loop (e.g., TLS ACK frame in both
00723                  * direction). Since this is quite undesired outcome, limit the
00724                  * total number of EAP round-trips and abort authentication if
00725                  * this limit is exceeded.
00726                  */
00727                 if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
00728                         wpa_msg(sm->msg_ctx, MSG_INFO, "EAP: more than %d "
00729                                 "authentication rounds - abort",
00730                                 EAP_MAX_AUTH_ROUNDS);
00731                         sm->num_rounds++;
00732                         SM_ENTER_GLOBAL(EAP, FAILURE);
00733                 }
00734         } else {
00735                 /* Local transitions */
00736                 eap_peer_sm_step_local(sm);
00737         }
00738 }
00739 
00740 
00741 static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor,
00742                                   EapType method)
00743 {
00744         if (!eap_allowed_method(sm, vendor, method)) {
00745                 wpa_printf(MSG_DEBUG, "EAP: configuration does not allow: "
00746                            "vendor %u method %u", vendor, method);
00747                 return FALSE;
00748         }
00749         if (eap_peer_get_eap_method(vendor, method))
00750                 return TRUE;
00751         wpa_printf(MSG_DEBUG, "EAP: not included in build: "
00752                    "vendor %u method %u", vendor, method);
00753         return FALSE;
00754 }
00755 
00756 
00757 static struct wpabuf * eap_sm_build_expanded_nak(
00758         struct eap_sm *sm, int id, const struct eap_method *methods,
00759         size_t count)
00760 {
00761         struct wpabuf *resp;
00762         int found = 0;
00763         const struct eap_method *m;
00764 
00765         wpa_printf(MSG_DEBUG, "EAP: Building expanded EAP-Nak");
00766 
00767         /* RFC 3748 - 5.3.2: Expanded Nak */
00768         resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EXPANDED,
00769                              8 + 8 * (count + 1), EAP_CODE_RESPONSE, id);
00770         if (resp == NULL)
00771                 return NULL;
00772 
00773         wpabuf_put_be24(resp, EAP_VENDOR_IETF);
00774         wpabuf_put_be32(resp, EAP_TYPE_NAK);
00775 
00776         for (m = methods; m; m = m->next) {
00777                 if (sm->reqVendor == m->vendor &&
00778                     sm->reqVendorMethod == m->method)
00779                         continue; /* do not allow the current method again */
00780                 if (eap_allowed_method(sm, m->vendor, m->method)) {
00781                         wpa_printf(MSG_DEBUG, "EAP: allowed type: "
00782                                    "vendor=%u method=%u",
00783                                    m->vendor, m->method);
00784                         wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
00785                         wpabuf_put_be24(resp, m->vendor);
00786                         wpabuf_put_be32(resp, m->method);
00787 
00788                         found++;
00789                 }
00790         }
00791         if (!found) {
00792                 wpa_printf(MSG_DEBUG, "EAP: no more allowed methods");
00793                 wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
00794                 wpabuf_put_be24(resp, EAP_VENDOR_IETF);
00795                 wpabuf_put_be32(resp, EAP_TYPE_NONE);
00796         }
00797 
00798         eap_update_len(resp);
00799 
00800         return resp;
00801 }
00802 
00803 
00804 static struct wpabuf * eap_sm_buildNak(struct eap_sm *sm, int id)
00805 {
00806         struct wpabuf *resp;
00807         u8 *start;
00808         int found = 0, expanded_found = 0;
00809         size_t count;
00810         const struct eap_method *methods, *m;
00811 
00812         wpa_printf(MSG_DEBUG, "EAP: Building EAP-Nak (requested type %u "
00813                    "vendor=%u method=%u not allowed)", sm->reqMethod,
00814                    sm->reqVendor, sm->reqVendorMethod);
00815         methods = eap_peer_get_methods(&count);
00816         if (methods == NULL)
00817                 return NULL;
00818         if (sm->reqMethod == EAP_TYPE_EXPANDED)
00819                 return eap_sm_build_expanded_nak(sm, id, methods, count);
00820 
00821         /* RFC 3748 - 5.3.1: Legacy Nak */
00822         resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NAK,
00823                              sizeof(struct eap_hdr) + 1 + count + 1,
00824                              EAP_CODE_RESPONSE, id);
00825         if (resp == NULL)
00826                 return NULL;
00827 
00828         start = wpabuf_put(resp, 0);
00829         for (m = methods; m; m = m->next) {
00830                 if (m->vendor == EAP_VENDOR_IETF && m->method == sm->reqMethod)
00831                         continue; /* do not allow the current method again */
00832                 if (eap_allowed_method(sm, m->vendor, m->method)) {
00833                         if (m->vendor != EAP_VENDOR_IETF) {
00834                                 if (expanded_found)
00835                                         continue;
00836                                 expanded_found = 1;
00837                                 wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
00838                         } else
00839                                 wpabuf_put_u8(resp, m->method);
00840                         found++;
00841                 }
00842         }
00843         if (!found)
00844                 wpabuf_put_u8(resp, EAP_TYPE_NONE);
00845         wpa_hexdump(MSG_DEBUG, "EAP: allowed methods", start, found);
00846 
00847         eap_update_len(resp);
00848 
00849         return resp;
00850 }
00851 
00852 
00853 static void eap_sm_processIdentity(struct eap_sm *sm, const struct wpabuf *req)
00854 {
00855         const struct eap_hdr *hdr = wpabuf_head(req);
00856         const u8 *pos = (const u8 *) (hdr + 1);
00857         pos++;
00858 
00859         wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
00860                 "EAP authentication started");
00861 
00862         /*
00863          * RFC 3748 - 5.1: Identity
00864          * Data field may contain a displayable message in UTF-8. If this
00865          * includes NUL-character, only the data before that should be
00866          * displayed. Some EAP implementasitons may piggy-back additional
00867          * options after the NUL.
00868          */
00869         /* TODO: could save displayable message so that it can be shown to the
00870          * user in case of interaction is required */
00871         wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Identity data",
00872                           pos, be_to_host16(hdr->length) - 5);
00873 }
00874 
00875 
00876 #ifdef PCSC_FUNCS
00877 static int eap_sm_imsi_identity(struct eap_sm *sm,
00878                                 struct eap_peer_config *conf)
00879 {
00880         int aka = 0;
00881         char imsi[100];
00882         size_t imsi_len;
00883         struct eap_method_type *m = conf->eap_methods;
00884         int i;
00885 
00886         imsi_len = sizeof(imsi);
00887         if (scard_get_imsi(sm->scard_ctx, imsi, &imsi_len)) {
00888                 wpa_printf(MSG_WARNING, "Failed to get IMSI from SIM");
00889                 return -1;
00890         }
00891 
00892         wpa_hexdump_ascii(MSG_DEBUG, "IMSI", (u8 *) imsi, imsi_len);
00893 
00894         for (i = 0; m && (m[i].vendor != EAP_VENDOR_IETF ||
00895                           m[i].method != EAP_TYPE_NONE); i++) {
00896                 if (m[i].vendor == EAP_VENDOR_IETF &&
00897                     m[i].method == EAP_TYPE_AKA) {
00898                         aka = 1;
00899                         break;
00900                 }
00901         }
00902 
00903         os_free(conf->identity);
00904         conf->identity = os_malloc(1 + imsi_len);
00905         if (conf->identity == NULL) {
00906                 wpa_printf(MSG_WARNING, "Failed to allocate buffer for "
00907                            "IMSI-based identity");
00908                 return -1;
00909         }
00910 
00911         conf->identity[0] = aka ? '0' : '1';
00912         os_memcpy(conf->identity + 1, imsi, imsi_len);
00913         conf->identity_len = 1 + imsi_len;
00914 
00915         return 0;
00916 }
00917 #endif /* PCSC_FUNCS */
00918 
00919 
00920 static int eap_sm_set_scard_pin(struct eap_sm *sm,
00921                                 struct eap_peer_config *conf)
00922 {
00923 #ifdef PCSC_FUNCS
00924         if (scard_set_pin(sm->scard_ctx, conf->pin)) {
00925                 /*
00926                  * Make sure the same PIN is not tried again in order to avoid
00927                  * blocking SIM.
00928                  */
00929                 os_free(conf->pin);
00930                 conf->pin = NULL;
00931 
00932                 wpa_printf(MSG_WARNING, "PIN validation failed");
00933                 eap_sm_request_pin(sm);
00934                 return -1;
00935         }
00936         return 0;
00937 #else /* PCSC_FUNCS */
00938         return -1;
00939 #endif /* PCSC_FUNCS */
00940 }
00941 
00942 static int eap_sm_get_scard_identity(struct eap_sm *sm,
00943                                      struct eap_peer_config *conf)
00944 {
00945 #ifdef PCSC_FUNCS
00946         if (eap_sm_set_scard_pin(sm, conf))
00947                 return -1;
00948 
00949         return eap_sm_imsi_identity(sm, conf);
00950 #else /* PCSC_FUNCS */
00951         return -1;
00952 #endif /* PCSC_FUNCS */
00953 }
00954 
00955 
00967 struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted)
00968 {
00969         struct eap_peer_config *config = eap_get_config(sm);
00970         struct wpabuf *resp;
00971         const u8 *identity;
00972         size_t identity_len;
00973 
00974         if (config == NULL) {
00975                 wpa_printf(MSG_WARNING, "EAP: buildIdentity: configuration "
00976                            "was not available");
00977                 return NULL;
00978         }
00979 
00980         if (sm->m && sm->m->get_identity &&
00981             (identity = sm->m->get_identity(sm, sm->eap_method_priv,
00982                                             &identity_len)) != NULL) {
00983                 wpa_hexdump_ascii(MSG_DEBUG, "EAP: using method re-auth "
00984                                   "identity", identity, identity_len);
00985         } else if (!encrypted && config->anonymous_identity) {
00986                 identity = config->anonymous_identity;
00987                 identity_len = config->anonymous_identity_len;
00988                 wpa_hexdump_ascii(MSG_DEBUG, "EAP: using anonymous identity",
00989                                   identity, identity_len);
00990         } else {
00991                 identity = config->identity;
00992                 identity_len = config->identity_len;
00993                 wpa_hexdump_ascii(MSG_DEBUG, "EAP: using real identity",
00994                                   identity, identity_len);
00995         }
00996 
00997         if (identity == NULL) {
00998                 wpa_printf(MSG_WARNING, "EAP: buildIdentity: identity "
00999                            "configuration was not available");
01000                 if (config->pcsc) {
01001                         if (eap_sm_get_scard_identity(sm, config) < 0)
01002                                 return NULL;
01003                         identity = config->identity;
01004                         identity_len = config->identity_len;
01005                         wpa_hexdump_ascii(MSG_DEBUG, "permanent identity from "
01006                                           "IMSI", identity, identity_len);
01007                 } else {
01008                         eap_sm_request_identity(sm);
01009                         return NULL;
01010                 }
01011         } else if (config->pcsc) {
01012                 if (eap_sm_set_scard_pin(sm, config) < 0)
01013                         return NULL;
01014         }
01015 
01016         resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, identity_len,
01017                              EAP_CODE_RESPONSE, id);
01018         if (resp == NULL)
01019                 return NULL;
01020 
01021         wpabuf_put_data(resp, identity, identity_len);
01022 
01023         return resp;
01024 }
01025 
01026 
01027 static void eap_sm_processNotify(struct eap_sm *sm, const struct wpabuf *req)
01028 {
01029         const u8 *pos;
01030         char *msg;
01031         size_t i, msg_len;
01032 
01033         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_NOTIFICATION, req,
01034                                &msg_len);
01035         if (pos == NULL)
01036                 return;
01037         wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Notification data",
01038                           pos, msg_len);
01039 
01040         msg = os_malloc(msg_len + 1);
01041         if (msg == NULL)
01042                 return;
01043         for (i = 0; i < msg_len; i++)
01044                 msg[i] = isprint(pos[i]) ? (char) pos[i] : '_';
01045         msg[msg_len] = '\0';
01046         wpa_msg(sm->msg_ctx, MSG_INFO, "%s%s",
01047                 WPA_EVENT_EAP_NOTIFICATION, msg);
01048         os_free(msg);
01049 }
01050 
01051 
01052 static struct wpabuf * eap_sm_buildNotify(int id)
01053 {
01054         struct wpabuf *resp;
01055 
01056         wpa_printf(MSG_DEBUG, "EAP: Generating EAP-Response Notification");
01057         resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NOTIFICATION, 0,
01058                              EAP_CODE_RESPONSE, id);
01059         if (resp == NULL)
01060                 return NULL;
01061 
01062         return resp;
01063 }
01064 
01065 
01066 static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req)
01067 {
01068         const struct eap_hdr *hdr;
01069         size_t plen;
01070         const u8 *pos;
01071 
01072         sm->rxReq = sm->rxResp = sm->rxSuccess = sm->rxFailure = FALSE;
01073         sm->reqId = 0;
01074         sm->reqMethod = EAP_TYPE_NONE;
01075         sm->reqVendor = EAP_VENDOR_IETF;
01076         sm->reqVendorMethod = EAP_TYPE_NONE;
01077 
01078         if (req == NULL || wpabuf_len(req) < sizeof(*hdr))
01079                 return;
01080 
01081         hdr = wpabuf_head(req);
01082         plen = be_to_host16(hdr->length);
01083         if (plen > wpabuf_len(req)) {
01084                 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
01085                            "(len=%lu plen=%lu)",
01086                            (unsigned long) wpabuf_len(req),
01087                            (unsigned long) plen);
01088                 return;
01089         }
01090 
01091         sm->reqId = hdr->identifier;
01092 
01093         if (sm->workaround) {
01094                 const u8 *addr[1];
01095                 addr[0] = wpabuf_head(req);
01096                 md5_vector(1, addr, &plen, sm->req_md5);
01097         }
01098 
01099         switch (hdr->code) {
01100         case EAP_CODE_REQUEST:
01101                 if (plen < sizeof(*hdr) + 1) {
01102                         wpa_printf(MSG_DEBUG, "EAP: Too short EAP-Request - "
01103                                    "no Type field");
01104                         return;
01105                 }
01106                 sm->rxReq = TRUE;
01107                 pos = (const u8 *) (hdr + 1);
01108                 sm->reqMethod = *pos++;
01109                 if (sm->reqMethod == EAP_TYPE_EXPANDED) {
01110                         if (plen < sizeof(*hdr) + 8) {
01111                                 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated "
01112                                            "expanded EAP-Packet (plen=%lu)",
01113                                            (unsigned long) plen);
01114                                 return;
01115                         }
01116                         sm->reqVendor = WPA_GET_BE24(pos);
01117                         pos += 3;
01118                         sm->reqVendorMethod = WPA_GET_BE32(pos);
01119                 }
01120                 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Request id=%d "
01121                            "method=%u vendor=%u vendorMethod=%u",
01122                            sm->reqId, sm->reqMethod, sm->reqVendor,
01123                            sm->reqVendorMethod);
01124                 break;
01125         case EAP_CODE_RESPONSE:
01126                 if (sm->selectedMethod == EAP_TYPE_LEAP) {
01127                         /*
01128                          * LEAP differs from RFC 4137 by using reversed roles
01129                          * for mutual authentication and because of this, we
01130                          * need to accept EAP-Response frames if LEAP is used.
01131                          */
01132                         if (plen < sizeof(*hdr) + 1) {
01133                                 wpa_printf(MSG_DEBUG, "EAP: Too short "
01134                                            "EAP-Response - no Type field");
01135                                 return;
01136                         }
01137                         sm->rxResp = TRUE;
01138                         pos = (const u8 *) (hdr + 1);
01139                         sm->reqMethod = *pos;
01140                         wpa_printf(MSG_DEBUG, "EAP: Received EAP-Response for "
01141                                    "LEAP method=%d id=%d",
01142                                    sm->reqMethod, sm->reqId);
01143                         break;
01144                 }
01145                 wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Response");
01146                 break;
01147         case EAP_CODE_SUCCESS:
01148                 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Success");
01149                 sm->rxSuccess = TRUE;
01150                 break;
01151         case EAP_CODE_FAILURE:
01152                 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure");
01153                 sm->rxFailure = TRUE;
01154                 break;
01155         default:
01156                 wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Packet with unknown "
01157                            "code %d", hdr->code);
01158                 break;
01159         }
01160 }
01161 
01162 
01163 static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev,
01164                                   union tls_event_data *data)
01165 {
01166         struct eap_sm *sm = ctx;
01167         char *hash_hex = NULL;
01168         char *cert_hex = NULL;
01169 
01170         switch (ev) {
01171         case TLS_CERT_CHAIN_FAILURE:
01172                 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TLS_CERT_ERROR
01173                         "reason=%d depth=%d subject='%s' err='%s'",
01174                         data->cert_fail.reason,
01175                         data->cert_fail.depth,
01176                         data->cert_fail.subject,
01177                         data->cert_fail.reason_txt);
01178                 break;
01179         case TLS_PEER_CERTIFICATE:
01180                 if (data->peer_cert.hash) {
01181                         size_t len = data->peer_cert.hash_len * 2 + 1;
01182                         hash_hex = os_malloc(len);
01183                         if (hash_hex) {
01184                                 wpa_snprintf_hex(hash_hex, len,
01185                                                  data->peer_cert.hash,
01186                                                  data->peer_cert.hash_len);
01187                         }
01188                 }
01189                 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PEER_CERT
01190                         "depth=%d subject='%s'%s%s",
01191                         data->peer_cert.depth, data->peer_cert.subject,
01192                         hash_hex ? " hash=" : "", hash_hex ? hash_hex : "");
01193 
01194                 if (data->peer_cert.cert) {
01195                         size_t len = wpabuf_len(data->peer_cert.cert) * 2 + 1;
01196                         cert_hex = os_malloc(len);
01197                         if (cert_hex == NULL)
01198                                 break;
01199                         wpa_snprintf_hex(cert_hex, len,
01200                                          wpabuf_head(data->peer_cert.cert),
01201                                          wpabuf_len(data->peer_cert.cert));
01202                         wpa_msg_ctrl(sm->msg_ctx, MSG_INFO,
01203                                      WPA_EVENT_EAP_PEER_CERT
01204                                      "depth=%d subject='%s' cert=%s",
01205                                      data->peer_cert.depth,
01206                                      data->peer_cert.subject,
01207                                      cert_hex);
01208                 }
01209                 break;
01210         }
01211 
01212         os_free(hash_hex);
01213         os_free(cert_hex);
01214 }
01215 
01216 
01231 struct eap_sm * eap_peer_sm_init(void *eapol_ctx,
01232                                  struct eapol_callbacks *eapol_cb,
01233                                  void *msg_ctx, struct eap_config *conf)
01234 {
01235         struct eap_sm *sm;
01236         struct tls_config tlsconf;
01237 
01238         sm = os_zalloc(sizeof(*sm));
01239         if (sm == NULL)
01240                 return NULL;
01241         sm->eapol_ctx = eapol_ctx;
01242         sm->eapol_cb = eapol_cb;
01243         sm->msg_ctx = msg_ctx;
01244         sm->ClientTimeout = 60;
01245         sm->wps = conf->wps;
01246 
01247         os_memset(&tlsconf, 0, sizeof(tlsconf));
01248         tlsconf.opensc_engine_path = conf->opensc_engine_path;
01249         tlsconf.pkcs11_engine_path = conf->pkcs11_engine_path;
01250         tlsconf.pkcs11_module_path = conf->pkcs11_module_path;
01251 #ifdef CONFIG_FIPS
01252         tlsconf.fips_mode = 1;
01253 #endif /* CONFIG_FIPS */
01254         tlsconf.event_cb = eap_peer_sm_tls_event;
01255         tlsconf.cb_ctx = sm;
01256         sm->ssl_ctx = tls_init(&tlsconf);
01257         if (sm->ssl_ctx == NULL) {
01258                 wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS "
01259                            "context.");
01260                 os_free(sm);
01261                 return NULL;
01262         }
01263 
01264         return sm;
01265 }
01266 
01267 
01275 void eap_peer_sm_deinit(struct eap_sm *sm)
01276 {
01277         if (sm == NULL)
01278                 return;
01279         eap_deinit_prev_method(sm, "EAP deinit");
01280         eap_sm_abort(sm);
01281         tls_deinit(sm->ssl_ctx);
01282         os_free(sm);
01283 }
01284 
01285 
01295 int eap_peer_sm_step(struct eap_sm *sm)
01296 {
01297         int res = 0;
01298         do {
01299                 sm->changed = FALSE;
01300                 SM_STEP_RUN(EAP);
01301                 if (sm->changed)
01302                         res = 1;
01303         } while (sm->changed);
01304         return res;
01305 }
01306 
01307 
01315 void eap_sm_abort(struct eap_sm *sm)
01316 {
01317         wpabuf_free(sm->lastRespData);
01318         sm->lastRespData = NULL;
01319         wpabuf_free(sm->eapRespData);
01320         sm->eapRespData = NULL;
01321         os_free(sm->eapKeyData);
01322         sm->eapKeyData = NULL;
01323 
01324         /* This is not clearly specified in the EAP statemachines draft, but
01325          * it seems necessary to make sure that some of the EAPOL variables get
01326          * cleared for the next authentication. */
01327         eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
01328 }
01329 
01330 
01331 #ifdef CONFIG_CTRL_IFACE
01332 static const char * eap_sm_state_txt(int state)
01333 {
01334         switch (state) {
01335         case EAP_INITIALIZE:
01336                 return "INITIALIZE";
01337         case EAP_DISABLED:
01338                 return "DISABLED";
01339         case EAP_IDLE:
01340                 return "IDLE";
01341         case EAP_RECEIVED:
01342                 return "RECEIVED";
01343         case EAP_GET_METHOD:
01344                 return "GET_METHOD";
01345         case EAP_METHOD:
01346                 return "METHOD";
01347         case EAP_SEND_RESPONSE:
01348                 return "SEND_RESPONSE";
01349         case EAP_DISCARD:
01350                 return "DISCARD";
01351         case EAP_IDENTITY:
01352                 return "IDENTITY";
01353         case EAP_NOTIFICATION:
01354                 return "NOTIFICATION";
01355         case EAP_RETRANSMIT:
01356                 return "RETRANSMIT";
01357         case EAP_SUCCESS:
01358                 return "SUCCESS";
01359         case EAP_FAILURE:
01360                 return "FAILURE";
01361         default:
01362                 return "UNKNOWN";
01363         }
01364 }
01365 #endif /* CONFIG_CTRL_IFACE */
01366 
01367 
01368 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
01369 static const char * eap_sm_method_state_txt(EapMethodState state)
01370 {
01371         switch (state) {
01372         case METHOD_NONE:
01373                 return "NONE";
01374         case METHOD_INIT:
01375                 return "INIT";
01376         case METHOD_CONT:
01377                 return "CONT";
01378         case METHOD_MAY_CONT:
01379                 return "MAY_CONT";
01380         case METHOD_DONE:
01381                 return "DONE";
01382         default:
01383                 return "UNKNOWN";
01384         }
01385 }
01386 
01387 
01388 static const char * eap_sm_decision_txt(EapDecision decision)
01389 {
01390         switch (decision) {
01391         case DECISION_FAIL:
01392                 return "FAIL";
01393         case DECISION_COND_SUCC:
01394                 return "COND_SUCC";
01395         case DECISION_UNCOND_SUCC:
01396                 return "UNCOND_SUCC";
01397         default:
01398                 return "UNKNOWN";
01399         }
01400 }
01401 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
01402 
01403 
01404 #ifdef CONFIG_CTRL_IFACE
01405 
01419 int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
01420 {
01421         int len, ret;
01422 
01423         if (sm == NULL)
01424                 return 0;
01425 
01426         len = os_snprintf(buf, buflen,
01427                           "EAP state=%s\n",
01428                           eap_sm_state_txt(sm->EAP_state));
01429         if (len < 0 || (size_t) len >= buflen)
01430                 return 0;
01431 
01432         if (sm->selectedMethod != EAP_TYPE_NONE) {
01433                 const char *name;
01434                 if (sm->m) {
01435                         name = sm->m->name;
01436                 } else {
01437                         const struct eap_method *m =
01438                                 eap_peer_get_eap_method(EAP_VENDOR_IETF,
01439                                                         sm->selectedMethod);
01440                         if (m)
01441                                 name = m->name;
01442                         else
01443                                 name = "?";
01444                 }
01445                 ret = os_snprintf(buf + len, buflen - len,
01446                                   "selectedMethod=%d (EAP-%s)\n",
01447                                   sm->selectedMethod, name);
01448                 if (ret < 0 || (size_t) ret >= buflen - len)
01449                         return len;
01450                 len += ret;
01451 
01452                 if (sm->m && sm->m->get_status) {
01453                         len += sm->m->get_status(sm, sm->eap_method_priv,
01454                                                  buf + len, buflen - len,
01455                                                  verbose);
01456                 }
01457         }
01458 
01459         if (verbose) {
01460                 ret = os_snprintf(buf + len, buflen - len,
01461                                   "reqMethod=%d\n"
01462                                   "methodState=%s\n"
01463                                   "decision=%s\n"
01464                                   "ClientTimeout=%d\n",
01465                                   sm->reqMethod,
01466                                   eap_sm_method_state_txt(sm->methodState),
01467                                   eap_sm_decision_txt(sm->decision),
01468                                   sm->ClientTimeout);
01469                 if (ret < 0 || (size_t) ret >= buflen - len)
01470                         return len;
01471                 len += ret;
01472         }
01473 
01474         return len;
01475 }
01476 #endif /* CONFIG_CTRL_IFACE */
01477 
01478 
01479 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
01480 typedef enum {
01481         TYPE_IDENTITY, TYPE_PASSWORD, TYPE_OTP, TYPE_PIN, TYPE_NEW_PASSWORD,
01482         TYPE_PASSPHRASE
01483 } eap_ctrl_req_type;
01484 
01485 static void eap_sm_request(struct eap_sm *sm, eap_ctrl_req_type type,
01486                            const char *msg, size_t msglen)
01487 {
01488         struct eap_peer_config *config;
01489         char *field, *txt, *tmp;
01490 
01491         if (sm == NULL)
01492                 return;
01493         config = eap_get_config(sm);
01494         if (config == NULL)
01495                 return;
01496 
01497         switch (type) {
01498         case TYPE_IDENTITY:
01499                 field = "IDENTITY";
01500                 txt = "Identity";
01501                 config->pending_req_identity++;
01502                 break;
01503         case TYPE_PASSWORD:
01504                 field = "PASSWORD";
01505                 txt = "Password";
01506                 config->pending_req_password++;
01507                 break;
01508         case TYPE_NEW_PASSWORD:
01509                 field = "NEW_PASSWORD";
01510                 txt = "New Password";
01511                 config->pending_req_new_password++;
01512                 break;
01513         case TYPE_PIN:
01514                 field = "PIN";
01515                 txt = "PIN";
01516                 config->pending_req_pin++;
01517                 break;
01518         case TYPE_OTP:
01519                 field = "OTP";
01520                 if (msg) {
01521                         tmp = os_malloc(msglen + 3);
01522                         if (tmp == NULL)
01523                                 return;
01524                         tmp[0] = '[';
01525                         os_memcpy(tmp + 1, msg, msglen);
01526                         tmp[msglen + 1] = ']';
01527                         tmp[msglen + 2] = '\0';
01528                         txt = tmp;
01529                         os_free(config->pending_req_otp);
01530                         config->pending_req_otp = tmp;
01531                         config->pending_req_otp_len = msglen + 3;
01532                 } else {
01533                         if (config->pending_req_otp == NULL)
01534                                 return;
01535                         txt = config->pending_req_otp;
01536                 }
01537                 break;
01538         case TYPE_PASSPHRASE:
01539                 field = "PASSPHRASE";
01540                 txt = "Private key passphrase";
01541                 config->pending_req_passphrase++;
01542                 break;
01543         default:
01544                 return;
01545         }
01546 
01547         if (sm->eapol_cb->eap_param_needed)
01548                 sm->eapol_cb->eap_param_needed(sm->eapol_ctx, field, txt);
01549 }
01550 #else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
01551 #define eap_sm_request(sm, type, msg, msglen) do { } while (0)
01552 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
01553 
01554 
01564 void eap_sm_request_identity(struct eap_sm *sm)
01565 {
01566         eap_sm_request(sm, TYPE_IDENTITY, NULL, 0);
01567 }
01568 
01569 
01579 void eap_sm_request_password(struct eap_sm *sm)
01580 {
01581         eap_sm_request(sm, TYPE_PASSWORD, NULL, 0);
01582 }
01583 
01584 
01594 void eap_sm_request_new_password(struct eap_sm *sm)
01595 {
01596         eap_sm_request(sm, TYPE_NEW_PASSWORD, NULL, 0);
01597 }
01598 
01599 
01609 void eap_sm_request_pin(struct eap_sm *sm)
01610 {
01611         eap_sm_request(sm, TYPE_PIN, NULL, 0);
01612 }
01613 
01614 
01625 void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len)
01626 {
01627         eap_sm_request(sm, TYPE_OTP, msg, msg_len);
01628 }
01629 
01630 
01640 void eap_sm_request_passphrase(struct eap_sm *sm)
01641 {
01642         eap_sm_request(sm, TYPE_PASSPHRASE, NULL, 0);
01643 }
01644 
01645 
01653 void eap_sm_notify_ctrl_attached(struct eap_sm *sm)
01654 {
01655         struct eap_peer_config *config = eap_get_config(sm);
01656 
01657         if (config == NULL)
01658                 return;
01659 
01660         /* Re-send any pending requests for user data since a new control
01661          * interface was added. This handles cases where the EAP authentication
01662          * starts immediately after system startup when the user interface is
01663          * not yet running. */
01664         if (config->pending_req_identity)
01665                 eap_sm_request_identity(sm);
01666         if (config->pending_req_password)
01667                 eap_sm_request_password(sm);
01668         if (config->pending_req_new_password)
01669                 eap_sm_request_new_password(sm);
01670         if (config->pending_req_otp)
01671                 eap_sm_request_otp(sm, NULL, 0);
01672         if (config->pending_req_pin)
01673                 eap_sm_request_pin(sm);
01674         if (config->pending_req_passphrase)
01675                 eap_sm_request_passphrase(sm);
01676 }
01677 
01678 
01679 static int eap_allowed_phase2_type(int vendor, int type)
01680 {
01681         if (vendor != EAP_VENDOR_IETF)
01682                 return 0;
01683         return type != EAP_TYPE_PEAP && type != EAP_TYPE_TTLS &&
01684                 type != EAP_TYPE_FAST;
01685 }
01686 
01687 
01698 u32 eap_get_phase2_type(const char *name, int *vendor)
01699 {
01700         int v;
01701         u8 type = eap_peer_get_type(name, &v);
01702         if (eap_allowed_phase2_type(v, type)) {
01703                 *vendor = v;
01704                 return type;
01705         }
01706         *vendor = EAP_VENDOR_IETF;
01707         return EAP_TYPE_NONE;
01708 }
01709 
01710 
01720 struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config,
01721                                               size_t *count)
01722 {
01723         struct eap_method_type *buf;
01724         u32 method;
01725         int vendor;
01726         size_t mcount;
01727         const struct eap_method *methods, *m;
01728 
01729         methods = eap_peer_get_methods(&mcount);
01730         if (methods == NULL)
01731                 return NULL;
01732         *count = 0;
01733         buf = os_malloc(mcount * sizeof(struct eap_method_type));
01734         if (buf == NULL)
01735                 return NULL;
01736 
01737         for (m = methods; m; m = m->next) {
01738                 vendor = m->vendor;
01739                 method = m->method;
01740                 if (eap_allowed_phase2_type(vendor, method)) {
01741                         if (vendor == EAP_VENDOR_IETF &&
01742                             method == EAP_TYPE_TLS && config &&
01743                             config->private_key2 == NULL)
01744                                 continue;
01745                         buf[*count].vendor = vendor;
01746                         buf[*count].method = method;
01747                         (*count)++;
01748                 }
01749         }
01750 
01751         return buf;
01752 }
01753 
01754 
01760 void eap_set_fast_reauth(struct eap_sm *sm, int enabled)
01761 {
01762         sm->fast_reauth = enabled;
01763 }
01764 
01765 
01771 void eap_set_workaround(struct eap_sm *sm, unsigned int workaround)
01772 {
01773         sm->workaround = workaround;
01774 }
01775 
01776 
01787 struct eap_peer_config * eap_get_config(struct eap_sm *sm)
01788 {
01789         return sm->eapol_cb->get_config(sm->eapol_ctx);
01790 }
01791 
01792 
01799 const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)
01800 {
01801         struct eap_peer_config *config = eap_get_config(sm);
01802         if (config == NULL)
01803                 return NULL;
01804         *len = config->identity_len;
01805         return config->identity;
01806 }
01807 
01808 
01815 const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len)
01816 {
01817         struct eap_peer_config *config = eap_get_config(sm);
01818         if (config == NULL)
01819                 return NULL;
01820         *len = config->password_len;
01821         return config->password;
01822 }
01823 
01824 
01834 const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)
01835 {
01836         struct eap_peer_config *config = eap_get_config(sm);
01837         if (config == NULL)
01838                 return NULL;
01839         *len = config->password_len;
01840         if (hash)
01841                 *hash = !!(config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH);
01842         return config->password;
01843 }
01844 
01845 
01852 const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len)
01853 {
01854         struct eap_peer_config *config = eap_get_config(sm);
01855         if (config == NULL)
01856                 return NULL;
01857         *len = config->new_password_len;
01858         return config->new_password;
01859 }
01860 
01861 
01868 const u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len)
01869 {
01870         struct eap_peer_config *config = eap_get_config(sm);
01871         if (config == NULL)
01872                 return NULL;
01873         *len = config->otp_len;
01874         return config->otp;
01875 }
01876 
01877 
01886 void eap_clear_config_otp(struct eap_sm *sm)
01887 {
01888         struct eap_peer_config *config = eap_get_config(sm);
01889         if (config == NULL)
01890                 return;
01891         os_memset(config->otp, 0, config->otp_len);
01892         os_free(config->otp);
01893         config->otp = NULL;
01894         config->otp_len = 0;
01895 }
01896 
01897 
01903 const char * eap_get_config_phase1(struct eap_sm *sm)
01904 {
01905         struct eap_peer_config *config = eap_get_config(sm);
01906         if (config == NULL)
01907                 return NULL;
01908         return config->phase1;
01909 }
01910 
01911 
01917 const char * eap_get_config_phase2(struct eap_sm *sm)
01918 {
01919         struct eap_peer_config *config = eap_get_config(sm);
01920         if (config == NULL)
01921                 return NULL;
01922         return config->phase2;
01923 }
01924 
01925 
01931 int eap_key_available(struct eap_sm *sm)
01932 {
01933         return sm ? sm->eapKeyAvailable : 0;
01934 }
01935 
01936 
01946 void eap_notify_success(struct eap_sm *sm)
01947 {
01948         if (sm) {
01949                 sm->decision = DECISION_COND_SUCC;
01950                 sm->EAP_state = EAP_SUCCESS;
01951         }
01952 }
01953 
01954 
01962 void eap_notify_lower_layer_success(struct eap_sm *sm)
01963 {
01964         if (sm == NULL)
01965                 return;
01966 
01967         if (eapol_get_bool(sm, EAPOL_eapSuccess) ||
01968             sm->decision == DECISION_FAIL ||
01969             (sm->methodState != METHOD_MAY_CONT &&
01970              sm->methodState != METHOD_DONE))
01971                 return;
01972 
01973         if (sm->eapKeyData != NULL)
01974                 sm->eapKeyAvailable = TRUE;
01975         eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
01976         wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
01977                 "EAP authentication completed successfully (based on lower "
01978                 "layer success)");
01979 }
01980 
01981 
01993 const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len)
01994 {
01995         if (sm == NULL || sm->eapKeyData == NULL) {
01996                 *len = 0;
01997                 return NULL;
01998         }
01999 
02000         *len = sm->eapKeyDataLen;
02001         return sm->eapKeyData;
02002 }
02003 
02004 
02015 struct wpabuf * eap_get_eapRespData(struct eap_sm *sm)
02016 {
02017         struct wpabuf *resp;
02018 
02019         if (sm == NULL || sm->eapRespData == NULL)
02020                 return NULL;
02021 
02022         resp = sm->eapRespData;
02023         sm->eapRespData = NULL;
02024 
02025         return resp;
02026 }
02027 
02028 
02037 void eap_register_scard_ctx(struct eap_sm *sm, void *ctx)
02038 {
02039         if (sm)
02040                 sm->scard_ctx = ctx;
02041 }
02042 
02043 
02052 void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob)
02053 {
02054 #ifndef CONFIG_NO_CONFIG_BLOBS
02055         sm->eapol_cb->set_config_blob(sm->eapol_ctx, blob);
02056 #endif /* CONFIG_NO_CONFIG_BLOBS */
02057 }
02058 
02059 
02066 const struct wpa_config_blob * eap_get_config_blob(struct eap_sm *sm,
02067                                                    const char *name)
02068 {
02069 #ifndef CONFIG_NO_CONFIG_BLOBS
02070         return sm->eapol_cb->get_config_blob(sm->eapol_ctx, name);
02071 #else /* CONFIG_NO_CONFIG_BLOBS */
02072         return NULL;
02073 #endif /* CONFIG_NO_CONFIG_BLOBS */
02074 }
02075 
02076 
02085 void eap_set_force_disabled(struct eap_sm *sm, int disabled)
02086 {
02087         sm->force_disabled = disabled;
02088 }
02089 
02090 
02100 void eap_notify_pending(struct eap_sm *sm)
02101 {
02102         sm->eapol_cb->notify_pending(sm->eapol_ctx);
02103 }
02104 
02105 
02110 void eap_invalidate_cached_session(struct eap_sm *sm)
02111 {
02112         if (sm)
02113                 eap_deinit_prev_method(sm, "invalidate");
02114 }
02115 
02116 
02117 int eap_is_wps_pbc_enrollee(struct eap_peer_config *conf)
02118 {
02119         if (conf->identity_len != WSC_ID_ENROLLEE_LEN ||
02120             os_memcmp(conf->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN))
02121                 return 0; /* Not a WPS Enrollee */
02122 
02123         if (conf->phase1 == NULL || os_strstr(conf->phase1, "pbc=1") == NULL)
02124                 return 0; /* Not using PBC */
02125 
02126         return 1;
02127 }
02128 
02129 
02130 int eap_is_wps_pin_enrollee(struct eap_peer_config *conf)
02131 {
02132         if (conf->identity_len != WSC_ID_ENROLLEE_LEN ||
02133             os_memcmp(conf->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN))
02134                 return 0; /* Not a WPS Enrollee */
02135 
02136         if (conf->phase1 == NULL || os_strstr(conf->phase1, "pin=") == NULL)
02137                 return 0; /* Not using PIN */
02138 
02139         return 1;
02140 }


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