eapol_supp_sm.c
Go to the documentation of this file.
00001 /*
00002  * EAPOL supplicant state machines
00003  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 2 as
00007  * published by the Free Software Foundation.
00008  *
00009  * Alternatively, this software may be distributed under the terms of BSD
00010  * license.
00011  *
00012  * See README and COPYING for more details.
00013  */
00014 
00015 #include "includes.h"
00016 
00017 #include "common.h"
00018 #include "state_machine.h"
00019 #include "wpabuf.h"
00020 #include "eloop.h"
00021 #include "crypto/crypto.h"
00022 #include "crypto/md5.h"
00023 #include "common/eapol_common.h"
00024 #include "eap_peer/eap.h"
00025 #include "eapol_supp_sm.h"
00026 
00027 #define STATE_MACHINE_DATA struct eapol_sm
00028 #define STATE_MACHINE_DEBUG_PREFIX "EAPOL"
00029 
00030 
00031 /* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
00032 
00036 struct eapol_sm {
00037         /* Timers */
00038         unsigned int authWhile;
00039         unsigned int heldWhile;
00040         unsigned int startWhen;
00041         unsigned int idleWhile; /* for EAP state machine */
00042         int timer_tick_enabled;
00043 
00044         /* Global variables */
00045         Boolean eapFail;
00046         Boolean eapolEap;
00047         Boolean eapSuccess;
00048         Boolean initialize;
00049         Boolean keyDone;
00050         Boolean keyRun;
00051         PortControl portControl;
00052         Boolean portEnabled;
00053         PortStatus suppPortStatus;  /* dot1xSuppControlledPortStatus */
00054         Boolean portValid;
00055         Boolean suppAbort;
00056         Boolean suppFail;
00057         Boolean suppStart;
00058         Boolean suppSuccess;
00059         Boolean suppTimeout;
00060 
00061         /* Supplicant PAE state machine */
00062         enum {
00063                 SUPP_PAE_UNKNOWN = 0,
00064                 SUPP_PAE_DISCONNECTED = 1,
00065                 SUPP_PAE_LOGOFF = 2,
00066                 SUPP_PAE_CONNECTING = 3,
00067                 SUPP_PAE_AUTHENTICATING = 4,
00068                 SUPP_PAE_AUTHENTICATED = 5,
00069                 /* unused(6) */
00070                 SUPP_PAE_HELD = 7,
00071                 SUPP_PAE_RESTART = 8,
00072                 SUPP_PAE_S_FORCE_AUTH = 9,
00073                 SUPP_PAE_S_FORCE_UNAUTH = 10
00074         } SUPP_PAE_state; /* dot1xSuppPaeState */
00075         /* Variables */
00076         Boolean userLogoff;
00077         Boolean logoffSent;
00078         unsigned int startCount;
00079         Boolean eapRestart;
00080         PortControl sPortMode;
00081         /* Constants */
00082         unsigned int heldPeriod; /* dot1xSuppHeldPeriod */
00083         unsigned int startPeriod; /* dot1xSuppStartPeriod */
00084         unsigned int maxStart; /* dot1xSuppMaxStart */
00085 
00086         /* Key Receive state machine */
00087         enum {
00088                 KEY_RX_UNKNOWN = 0,
00089                 KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
00090         } KEY_RX_state;
00091         /* Variables */
00092         Boolean rxKey;
00093 
00094         /* Supplicant Backend state machine */
00095         enum {
00096                 SUPP_BE_UNKNOWN = 0,
00097                 SUPP_BE_INITIALIZE = 1,
00098                 SUPP_BE_IDLE = 2,
00099                 SUPP_BE_REQUEST = 3,
00100                 SUPP_BE_RECEIVE = 4,
00101                 SUPP_BE_RESPONSE = 5,
00102                 SUPP_BE_FAIL = 6,
00103                 SUPP_BE_TIMEOUT = 7, 
00104                 SUPP_BE_SUCCESS = 8
00105         } SUPP_BE_state; /* dot1xSuppBackendPaeState */
00106         /* Variables */
00107         Boolean eapNoResp;
00108         Boolean eapReq;
00109         Boolean eapResp;
00110         /* Constants */
00111         unsigned int authPeriod; /* dot1xSuppAuthPeriod */
00112 
00113         /* Statistics */
00114         unsigned int dot1xSuppEapolFramesRx;
00115         unsigned int dot1xSuppEapolFramesTx;
00116         unsigned int dot1xSuppEapolStartFramesTx;
00117         unsigned int dot1xSuppEapolLogoffFramesTx;
00118         unsigned int dot1xSuppEapolRespFramesTx;
00119         unsigned int dot1xSuppEapolReqIdFramesRx;
00120         unsigned int dot1xSuppEapolReqFramesRx;
00121         unsigned int dot1xSuppInvalidEapolFramesRx;
00122         unsigned int dot1xSuppEapLengthErrorFramesRx;
00123         unsigned int dot1xSuppLastEapolFrameVersion;
00124         unsigned char dot1xSuppLastEapolFrameSource[6];
00125 
00126         /* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
00127         Boolean changed;
00128         struct eap_sm *eap;
00129         struct eap_peer_config *config;
00130         Boolean initial_req;
00131         u8 *last_rx_key;
00132         size_t last_rx_key_len;
00133         struct wpabuf *eapReqData; /* for EAP */
00134         Boolean altAccept; /* for EAP */
00135         Boolean altReject; /* for EAP */
00136         Boolean replay_counter_valid;
00137         u8 last_replay_counter[16];
00138         struct eapol_config conf;
00139         struct eapol_ctx *ctx;
00140         enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE }
00141                 cb_status;
00142         Boolean cached_pmk;
00143 
00144         Boolean unicast_key_received, broadcast_key_received;
00145 };
00146 
00147 
00148 #define IEEE8021X_REPLAY_COUNTER_LEN 8
00149 #define IEEE8021X_KEY_SIGN_LEN 16
00150 #define IEEE8021X_KEY_IV_LEN 16
00151 
00152 #define IEEE8021X_KEY_INDEX_FLAG 0x80
00153 #define IEEE8021X_KEY_INDEX_MASK 0x03
00154 
00155 #ifdef _MSC_VER
00156 #pragma pack(push, 1)
00157 #endif /* _MSC_VER */
00158 
00159 struct ieee802_1x_eapol_key {
00160         u8 type;
00161         /* Note: key_length is unaligned */
00162         u8 key_length[2];
00163         /* does not repeat within the life of the keying material used to
00164          * encrypt the Key field; 64-bit NTP timestamp MAY be used here */
00165         u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN];
00166         u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */
00167         u8 key_index; /* key flag in the most significant bit:
00168                        * 0 = broadcast (default key),
00169                        * 1 = unicast (key mapping key); key index is in the
00170                        * 7 least significant bits */
00171         /* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as
00172          * the key */
00173         u8 key_signature[IEEE8021X_KEY_SIGN_LEN];
00174 
00175         /* followed by key: if packet body length = 44 + key length, then the
00176          * key field (of key_length bytes) contains the key in encrypted form;
00177          * if packet body length = 44, key field is absent and key_length
00178          * represents the number of least significant octets from
00179          * MS-MPPE-Send-Key attribute to be used as the keying material;
00180          * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
00181 } STRUCT_PACKED;
00182 
00183 #ifdef _MSC_VER
00184 #pragma pack(pop)
00185 #endif /* _MSC_VER */
00186 
00187 
00188 static void eapol_sm_txLogoff(struct eapol_sm *sm);
00189 static void eapol_sm_txStart(struct eapol_sm *sm);
00190 static void eapol_sm_processKey(struct eapol_sm *sm);
00191 static void eapol_sm_getSuppRsp(struct eapol_sm *sm);
00192 static void eapol_sm_txSuppRsp(struct eapol_sm *sm);
00193 static void eapol_sm_abortSupp(struct eapol_sm *sm);
00194 static void eapol_sm_abort_cached(struct eapol_sm *sm);
00195 static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx);
00196 static void eapol_sm_set_port_authorized(struct eapol_sm *sm);
00197 static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm);
00198 
00199 
00200 /* Port Timers state machine - implemented as a function that will be called
00201  * once a second as a registered event loop timeout */
00202 static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
00203 {
00204         struct eapol_sm *sm = timeout_ctx;
00205 
00206         if (sm->authWhile > 0) {
00207                 sm->authWhile--;
00208                 if (sm->authWhile == 0)
00209                         wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0");
00210         }
00211         if (sm->heldWhile > 0) {
00212                 sm->heldWhile--;
00213                 if (sm->heldWhile == 0)
00214                         wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0");
00215         }
00216         if (sm->startWhen > 0) {
00217                 sm->startWhen--;
00218                 if (sm->startWhen == 0)
00219                         wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0");
00220         }
00221         if (sm->idleWhile > 0) {
00222                 sm->idleWhile--;
00223                 if (sm->idleWhile == 0)
00224                         wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0");
00225         }
00226 
00227         if (sm->authWhile | sm->heldWhile | sm->startWhen | sm->idleWhile) {
00228                 eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx,
00229                                        sm);
00230         } else {
00231                 wpa_printf(MSG_DEBUG, "EAPOL: disable timer tick");
00232                 sm->timer_tick_enabled = 0;
00233         }
00234         eapol_sm_step(sm);
00235 }
00236 
00237 
00238 static void eapol_enable_timer_tick(struct eapol_sm *sm)
00239 {
00240         if (sm->timer_tick_enabled)
00241                 return;
00242         wpa_printf(MSG_DEBUG, "EAPOL: enable timer tick");
00243         sm->timer_tick_enabled = 1;
00244         eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
00245         eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
00246 }
00247 
00248 
00249 SM_STATE(SUPP_PAE, LOGOFF)
00250 {
00251         SM_ENTRY(SUPP_PAE, LOGOFF);
00252         eapol_sm_txLogoff(sm);
00253         sm->logoffSent = TRUE;
00254         sm->suppPortStatus = Unauthorized;
00255         eapol_sm_set_port_unauthorized(sm);
00256 }
00257 
00258 
00259 SM_STATE(SUPP_PAE, DISCONNECTED)
00260 {
00261         SM_ENTRY(SUPP_PAE, DISCONNECTED);
00262         sm->sPortMode = Auto;
00263         sm->startCount = 0;
00264         sm->logoffSent = FALSE;
00265         sm->suppPortStatus = Unauthorized;
00266         eapol_sm_set_port_unauthorized(sm);
00267         sm->suppAbort = TRUE;
00268 
00269         sm->unicast_key_received = FALSE;
00270         sm->broadcast_key_received = FALSE;
00271 }
00272 
00273 
00274 SM_STATE(SUPP_PAE, CONNECTING)
00275 {
00276         int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING;
00277         SM_ENTRY(SUPP_PAE, CONNECTING);
00278         if (send_start) {
00279                 sm->startWhen = sm->startPeriod;
00280                 sm->startCount++;
00281         } else {
00282                 /*
00283                  * Do not send EAPOL-Start immediately since in most cases,
00284                  * Authenticator is going to start authentication immediately
00285                  * after association and an extra EAPOL-Start is just going to
00286                  * delay authentication. Use a short timeout to send the first
00287                  * EAPOL-Start if Authenticator does not start authentication.
00288                  */
00289 #ifdef CONFIG_WPS
00290                 /* Reduce latency on starting WPS negotiation. */
00291                 sm->startWhen = 1;
00292 #else /* CONFIG_WPS */
00293                 sm->startWhen = 3;
00294 #endif /* CONFIG_WPS */
00295         }
00296         eapol_enable_timer_tick(sm);
00297         sm->eapolEap = FALSE;
00298         if (send_start)
00299                 eapol_sm_txStart(sm);
00300 }
00301 
00302 
00303 SM_STATE(SUPP_PAE, AUTHENTICATING)
00304 {
00305         SM_ENTRY(SUPP_PAE, AUTHENTICATING);
00306         sm->startCount = 0;
00307         sm->suppSuccess = FALSE;
00308         sm->suppFail = FALSE;
00309         sm->suppTimeout = FALSE;
00310         sm->keyRun = FALSE;
00311         sm->keyDone = FALSE;
00312         sm->suppStart = TRUE;
00313 }
00314 
00315 
00316 SM_STATE(SUPP_PAE, HELD)
00317 {
00318         SM_ENTRY(SUPP_PAE, HELD);
00319         sm->heldWhile = sm->heldPeriod;
00320         eapol_enable_timer_tick(sm);
00321         sm->suppPortStatus = Unauthorized;
00322         eapol_sm_set_port_unauthorized(sm);
00323         sm->cb_status = EAPOL_CB_FAILURE;
00324 }
00325 
00326 
00327 SM_STATE(SUPP_PAE, AUTHENTICATED)
00328 {
00329         SM_ENTRY(SUPP_PAE, AUTHENTICATED);
00330         sm->suppPortStatus = Authorized;
00331         eapol_sm_set_port_authorized(sm);
00332         sm->cb_status = EAPOL_CB_SUCCESS;
00333 }
00334 
00335 
00336 SM_STATE(SUPP_PAE, RESTART)
00337 {
00338         SM_ENTRY(SUPP_PAE, RESTART);
00339         sm->eapRestart = TRUE;
00340 }
00341 
00342 
00343 SM_STATE(SUPP_PAE, S_FORCE_AUTH)
00344 {
00345         SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
00346         sm->suppPortStatus = Authorized;
00347         eapol_sm_set_port_authorized(sm);
00348         sm->sPortMode = ForceAuthorized;
00349 }
00350 
00351 
00352 SM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
00353 {
00354         SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
00355         sm->suppPortStatus = Unauthorized;
00356         eapol_sm_set_port_unauthorized(sm);
00357         sm->sPortMode = ForceUnauthorized;
00358         eapol_sm_txLogoff(sm);
00359 }
00360 
00361 
00362 SM_STEP(SUPP_PAE)
00363 {
00364         if ((sm->userLogoff && !sm->logoffSent) &&
00365             !(sm->initialize || !sm->portEnabled))
00366                 SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF);
00367         else if (((sm->portControl == Auto) &&
00368                   (sm->sPortMode != sm->portControl)) ||
00369                  sm->initialize || !sm->portEnabled)
00370                 SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED);
00371         else if ((sm->portControl == ForceAuthorized) &&
00372                  (sm->sPortMode != sm->portControl) &&
00373                  !(sm->initialize || !sm->portEnabled))
00374                 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH);
00375         else if ((sm->portControl == ForceUnauthorized) &&
00376                  (sm->sPortMode != sm->portControl) &&
00377                  !(sm->initialize || !sm->portEnabled))
00378                 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH);
00379         else switch (sm->SUPP_PAE_state) {
00380         case SUPP_PAE_UNKNOWN:
00381                 break;
00382         case SUPP_PAE_LOGOFF:
00383                 if (!sm->userLogoff)
00384                         SM_ENTER(SUPP_PAE, DISCONNECTED);
00385                 break;
00386         case SUPP_PAE_DISCONNECTED:
00387                 SM_ENTER(SUPP_PAE, CONNECTING);
00388                 break;
00389         case SUPP_PAE_CONNECTING:
00390                 if (sm->startWhen == 0 && sm->startCount < sm->maxStart)
00391                         SM_ENTER(SUPP_PAE, CONNECTING);
00392                 else if (sm->startWhen == 0 &&
00393                          sm->startCount >= sm->maxStart &&
00394                          sm->portValid)
00395                         SM_ENTER(SUPP_PAE, AUTHENTICATED);
00396                 else if (sm->eapSuccess || sm->eapFail)
00397                         SM_ENTER(SUPP_PAE, AUTHENTICATING);
00398                 else if (sm->eapolEap)
00399                         SM_ENTER(SUPP_PAE, RESTART);
00400                 else if (sm->startWhen == 0 &&
00401                          sm->startCount >= sm->maxStart &&
00402                          !sm->portValid)
00403                         SM_ENTER(SUPP_PAE, HELD);
00404                 break;
00405         case SUPP_PAE_AUTHENTICATING:
00406                 if (sm->eapSuccess && !sm->portValid &&
00407                     sm->conf.accept_802_1x_keys &&
00408                     sm->conf.required_keys == 0) {
00409                         wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for "
00410                                    "plaintext connection; no EAPOL-Key frames "
00411                                    "required");
00412                         sm->portValid = TRUE;
00413                         if (sm->ctx->eapol_done_cb)
00414                                 sm->ctx->eapol_done_cb(sm->ctx->ctx);
00415                 }
00416                 if (sm->eapSuccess && sm->portValid)
00417                         SM_ENTER(SUPP_PAE, AUTHENTICATED);
00418                 else if (sm->eapFail || (sm->keyDone && !sm->portValid))
00419                         SM_ENTER(SUPP_PAE, HELD);
00420                 else if (sm->suppTimeout)
00421                         SM_ENTER(SUPP_PAE, CONNECTING);
00422                 break;
00423         case SUPP_PAE_HELD:
00424                 if (sm->heldWhile == 0)
00425                         SM_ENTER(SUPP_PAE, CONNECTING);
00426                 else if (sm->eapolEap)
00427                         SM_ENTER(SUPP_PAE, RESTART);
00428                 break;
00429         case SUPP_PAE_AUTHENTICATED:
00430                 if (sm->eapolEap && sm->portValid)
00431                         SM_ENTER(SUPP_PAE, RESTART);
00432                 else if (!sm->portValid)
00433                         SM_ENTER(SUPP_PAE, DISCONNECTED);
00434                 break;
00435         case SUPP_PAE_RESTART:
00436                 if (!sm->eapRestart)
00437                         SM_ENTER(SUPP_PAE, AUTHENTICATING);
00438                 break;
00439         case SUPP_PAE_S_FORCE_AUTH:
00440                 break;
00441         case SUPP_PAE_S_FORCE_UNAUTH:
00442                 break;
00443         }
00444 }
00445 
00446 
00447 SM_STATE(KEY_RX, NO_KEY_RECEIVE)
00448 {
00449         SM_ENTRY(KEY_RX, NO_KEY_RECEIVE);
00450 }
00451 
00452 
00453 SM_STATE(KEY_RX, KEY_RECEIVE)
00454 {
00455         SM_ENTRY(KEY_RX, KEY_RECEIVE);
00456         eapol_sm_processKey(sm);
00457         sm->rxKey = FALSE;
00458 }
00459 
00460 
00461 SM_STEP(KEY_RX)
00462 {
00463         if (sm->initialize || !sm->portEnabled)
00464                 SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
00465         switch (sm->KEY_RX_state) {
00466         case KEY_RX_UNKNOWN:
00467                 break;
00468         case KEY_RX_NO_KEY_RECEIVE:
00469                 if (sm->rxKey)
00470                         SM_ENTER(KEY_RX, KEY_RECEIVE);
00471                 break;
00472         case KEY_RX_KEY_RECEIVE:
00473                 if (sm->rxKey)
00474                         SM_ENTER(KEY_RX, KEY_RECEIVE);
00475                 break;
00476         }
00477 }
00478 
00479 
00480 SM_STATE(SUPP_BE, REQUEST)
00481 {
00482         SM_ENTRY(SUPP_BE, REQUEST);
00483         sm->authWhile = 0;
00484         sm->eapReq = TRUE;
00485         eapol_sm_getSuppRsp(sm);
00486 }
00487 
00488 
00489 SM_STATE(SUPP_BE, RESPONSE)
00490 {
00491         SM_ENTRY(SUPP_BE, RESPONSE);
00492         eapol_sm_txSuppRsp(sm);
00493         sm->eapResp = FALSE;
00494 }
00495 
00496 
00497 SM_STATE(SUPP_BE, SUCCESS)
00498 {
00499         SM_ENTRY(SUPP_BE, SUCCESS);
00500         sm->keyRun = TRUE;
00501         sm->suppSuccess = TRUE;
00502 
00503         if (eap_key_available(sm->eap)) {
00504                 /* New key received - clear IEEE 802.1X EAPOL-Key replay
00505                  * counter */
00506                 sm->replay_counter_valid = FALSE;
00507         }
00508 }
00509 
00510 
00511 SM_STATE(SUPP_BE, FAIL)
00512 {
00513         SM_ENTRY(SUPP_BE, FAIL);
00514         sm->suppFail = TRUE;
00515 }
00516 
00517 
00518 SM_STATE(SUPP_BE, TIMEOUT)
00519 {
00520         SM_ENTRY(SUPP_BE, TIMEOUT);
00521         sm->suppTimeout = TRUE;
00522 }
00523 
00524 
00525 SM_STATE(SUPP_BE, IDLE)
00526 {
00527         SM_ENTRY(SUPP_BE, IDLE);
00528         sm->suppStart = FALSE;
00529         sm->initial_req = TRUE;
00530 }
00531 
00532 
00533 SM_STATE(SUPP_BE, INITIALIZE)
00534 {
00535         SM_ENTRY(SUPP_BE, INITIALIZE);
00536         eapol_sm_abortSupp(sm);
00537         sm->suppAbort = FALSE;
00538 }
00539 
00540 
00541 SM_STATE(SUPP_BE, RECEIVE)
00542 {
00543         SM_ENTRY(SUPP_BE, RECEIVE);
00544         sm->authWhile = sm->authPeriod;
00545         eapol_enable_timer_tick(sm);
00546         sm->eapolEap = FALSE;
00547         sm->eapNoResp = FALSE;
00548         sm->initial_req = FALSE;
00549 }
00550 
00551 
00552 SM_STEP(SUPP_BE)
00553 {
00554         if (sm->initialize || sm->suppAbort)
00555                 SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE);
00556         else switch (sm->SUPP_BE_state) {
00557         case SUPP_BE_UNKNOWN:
00558                 break;
00559         case SUPP_BE_REQUEST:
00560                 /*
00561                  * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
00562                  * and SUCCESS based on eapFail and eapSuccess, respectively.
00563                  * However, IEEE Std 802.1X-2004 is also specifying that
00564                  * eapNoResp should be set in conjuction with eapSuccess and
00565                  * eapFail which would mean that more than one of the
00566                  * transitions here would be activated at the same time.
00567                  * Skipping RESPONSE and/or RECEIVE states in these cases can
00568                  * cause problems and the direct transitions to do not seem
00569                  * correct. Because of this, the conditions for these
00570                  * transitions are verified only after eapNoResp. They are
00571                  * unlikely to be used since eapNoResp should always be set if
00572                  * either of eapSuccess or eapFail is set.
00573                  */
00574                 if (sm->eapResp && sm->eapNoResp) {
00575                         wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both "
00576                                    "eapResp and eapNoResp set?!");
00577                 }
00578                 if (sm->eapResp)
00579                         SM_ENTER(SUPP_BE, RESPONSE);
00580                 else if (sm->eapNoResp)
00581                         SM_ENTER(SUPP_BE, RECEIVE);
00582                 else if (sm->eapFail)
00583                         SM_ENTER(SUPP_BE, FAIL);
00584                 else if (sm->eapSuccess)
00585                         SM_ENTER(SUPP_BE, SUCCESS);
00586                 break;
00587         case SUPP_BE_RESPONSE:
00588                 SM_ENTER(SUPP_BE, RECEIVE);
00589                 break;
00590         case SUPP_BE_SUCCESS:
00591                 SM_ENTER(SUPP_BE, IDLE);
00592                 break;
00593         case SUPP_BE_FAIL:
00594                 SM_ENTER(SUPP_BE, IDLE);
00595                 break;
00596         case SUPP_BE_TIMEOUT:
00597                 SM_ENTER(SUPP_BE, IDLE);
00598                 break;
00599         case SUPP_BE_IDLE:
00600                 if (sm->eapFail && sm->suppStart)
00601                         SM_ENTER(SUPP_BE, FAIL);
00602                 else if (sm->eapolEap && sm->suppStart)
00603                         SM_ENTER(SUPP_BE, REQUEST);
00604                 else if (sm->eapSuccess && sm->suppStart)
00605                         SM_ENTER(SUPP_BE, SUCCESS);
00606                 break;
00607         case SUPP_BE_INITIALIZE:
00608                 SM_ENTER(SUPP_BE, IDLE);
00609                 break;
00610         case SUPP_BE_RECEIVE:
00611                 if (sm->eapolEap)
00612                         SM_ENTER(SUPP_BE, REQUEST);
00613                 else if (sm->eapFail)
00614                         SM_ENTER(SUPP_BE, FAIL);
00615                 else if (sm->authWhile == 0)
00616                         SM_ENTER(SUPP_BE, TIMEOUT);
00617                 else if (sm->eapSuccess)
00618                         SM_ENTER(SUPP_BE, SUCCESS);
00619                 break;
00620         }
00621 }
00622 
00623 
00624 static void eapol_sm_txLogoff(struct eapol_sm *sm)
00625 {
00626         wpa_printf(MSG_DEBUG, "EAPOL: txLogoff");
00627         sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
00628                             IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0);
00629         sm->dot1xSuppEapolLogoffFramesTx++;
00630         sm->dot1xSuppEapolFramesTx++;
00631 }
00632 
00633 
00634 static void eapol_sm_txStart(struct eapol_sm *sm)
00635 {
00636         wpa_printf(MSG_DEBUG, "EAPOL: txStart");
00637         sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
00638                             IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0);
00639         sm->dot1xSuppEapolStartFramesTx++;
00640         sm->dot1xSuppEapolFramesTx++;
00641 }
00642 
00643 
00644 #define IEEE8021X_ENCR_KEY_LEN 32
00645 #define IEEE8021X_SIGN_KEY_LEN 32
00646 
00647 struct eap_key_data {
00648         u8 encr_key[IEEE8021X_ENCR_KEY_LEN];
00649         u8 sign_key[IEEE8021X_SIGN_KEY_LEN];
00650 };
00651 
00652 
00653 static void eapol_sm_processKey(struct eapol_sm *sm)
00654 {
00655         struct ieee802_1x_hdr *hdr;
00656         struct ieee802_1x_eapol_key *key;
00657         struct eap_key_data keydata;
00658         u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
00659         u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
00660         int key_len, res, sign_key_len, encr_key_len;
00661         u16 rx_key_length;
00662 
00663         wpa_printf(MSG_DEBUG, "EAPOL: processKey");
00664         if (sm->last_rx_key == NULL)
00665                 return;
00666 
00667         if (!sm->conf.accept_802_1x_keys) {
00668                 wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key"
00669                            " even though this was not accepted - "
00670                            "ignoring this packet");
00671                 return;
00672         }
00673 
00674         hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
00675         key = (struct ieee802_1x_eapol_key *) (hdr + 1);
00676         if (sizeof(*hdr) + be_to_host16(hdr->length) > sm->last_rx_key_len) {
00677                 wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
00678                 return;
00679         }
00680         rx_key_length = WPA_GET_BE16(key->key_length);
00681         wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
00682                    "EAPOL-Key: type=%d key_length=%d key_index=0x%x",
00683                    hdr->version, hdr->type, be_to_host16(hdr->length),
00684                    key->type, rx_key_length, key->key_index);
00685 
00686         eapol_sm_notify_lower_layer_success(sm, 1);
00687         sign_key_len = IEEE8021X_SIGN_KEY_LEN;
00688         encr_key_len = IEEE8021X_ENCR_KEY_LEN;
00689         res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata));
00690         if (res < 0) {
00691                 wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for "
00692                            "decrypting EAPOL-Key keys");
00693                 return;
00694         }
00695         if (res == 16) {
00696                 /* LEAP derives only 16 bytes of keying material. */
00697                 res = eapol_sm_get_key(sm, (u8 *) &keydata, 16);
00698                 if (res) {
00699                         wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP "
00700                                    "master key for decrypting EAPOL-Key keys");
00701                         return;
00702                 }
00703                 sign_key_len = 16;
00704                 encr_key_len = 16;
00705                 os_memcpy(keydata.sign_key, keydata.encr_key, 16);
00706         } else if (res) {
00707                 wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key "
00708                            "data for decrypting EAPOL-Key keys (res=%d)", res);
00709                 return;
00710         }
00711 
00712         /* The key replay_counter must increase when same master key */
00713         if (sm->replay_counter_valid &&
00714             os_memcmp(sm->last_replay_counter, key->replay_counter,
00715                       IEEE8021X_REPLAY_COUNTER_LEN) >= 0) {
00716                 wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did "
00717                            "not increase - ignoring key");
00718                 wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter",
00719                             sm->last_replay_counter,
00720                             IEEE8021X_REPLAY_COUNTER_LEN);
00721                 wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter",
00722                             key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN);
00723                 return;
00724         }
00725 
00726         /* Verify key signature (HMAC-MD5) */
00727         os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN);
00728         os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN);
00729         hmac_md5(keydata.sign_key, sign_key_len,
00730                  sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
00731                  key->key_signature);
00732         if (os_memcmp(orig_key_sign, key->key_signature,
00733                       IEEE8021X_KEY_SIGN_LEN) != 0) {
00734                 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
00735                            "EAPOL-Key packet");
00736                 os_memcpy(key->key_signature, orig_key_sign,
00737                           IEEE8021X_KEY_SIGN_LEN);
00738                 return;
00739         }
00740         wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
00741 
00742         key_len = be_to_host16(hdr->length) - sizeof(*key);
00743         if (key_len > 32 || rx_key_length > 32) {
00744                 wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
00745                            key_len ? key_len : rx_key_length);
00746                 return;
00747         }
00748         if (key_len == rx_key_length) {
00749                 os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
00750                 os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
00751                           encr_key_len);
00752                 os_memcpy(datakey, key + 1, key_len);
00753                 rc4_skip(ekey, IEEE8021X_KEY_IV_LEN + encr_key_len, 0,
00754                          datakey, key_len);
00755                 wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
00756                                 datakey, key_len);
00757         } else if (key_len == 0) {
00758                 /*
00759                  * IEEE 802.1X-2004 specifies that least significant Key Length
00760                  * octets from MS-MPPE-Send-Key are used as the key if the key
00761                  * data is not present. This seems to be meaning the beginning
00762                  * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
00763                  * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
00764                  * Anyway, taking the beginning of the keying material from EAP
00765                  * seems to interoperate with Authenticators.
00766                  */
00767                 key_len = rx_key_length;
00768                 os_memcpy(datakey, keydata.encr_key, key_len);
00769                 wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying "
00770                                 "material data encryption key",
00771                                 datakey, key_len);
00772         } else {
00773                 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
00774                            "(key_length=%d)", key_len, rx_key_length);
00775                 return;
00776         }
00777 
00778         sm->replay_counter_valid = TRUE;
00779         os_memcpy(sm->last_replay_counter, key->replay_counter,
00780                   IEEE8021X_REPLAY_COUNTER_LEN);
00781 
00782         wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
00783                    "len %d",
00784                    key->key_index & IEEE8021X_KEY_INDEX_FLAG ?
00785                    "unicast" : "broadcast",
00786                    key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len);
00787 
00788         if (sm->ctx->set_wep_key &&
00789             sm->ctx->set_wep_key(sm->ctx->ctx,
00790                                  key->key_index & IEEE8021X_KEY_INDEX_FLAG,
00791                                  key->key_index & IEEE8021X_KEY_INDEX_MASK,
00792                                  datakey, key_len) < 0) {
00793                 wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
00794                            " driver.");
00795         } else {
00796                 if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
00797                         sm->unicast_key_received = TRUE;
00798                 else
00799                         sm->broadcast_key_received = TRUE;
00800 
00801                 if ((sm->unicast_key_received ||
00802                      !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) &&
00803                     (sm->broadcast_key_received ||
00804                      !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST)))
00805                 {
00806                         wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
00807                                    "frames received");
00808                         sm->portValid = TRUE;
00809                         if (sm->ctx->eapol_done_cb)
00810                                 sm->ctx->eapol_done_cb(sm->ctx->ctx);
00811                 }
00812         }
00813 }
00814 
00815 
00816 static void eapol_sm_getSuppRsp(struct eapol_sm *sm)
00817 {
00818         wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp");
00819         /* EAP layer processing; no special code is needed, since Supplicant
00820          * Backend state machine is waiting for eapNoResp or eapResp to be set
00821          * and these are only set in the EAP state machine when the processing
00822          * has finished. */
00823 }
00824 
00825 
00826 static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
00827 {
00828         struct wpabuf *resp;
00829 
00830         wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
00831         resp = eap_get_eapRespData(sm->eap);
00832         if (resp == NULL) {
00833                 wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
00834                            "not available");
00835                 return;
00836         }
00837 
00838         /* Send EAP-Packet from the EAP layer to the Authenticator */
00839         sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
00840                             IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head(resp),
00841                             wpabuf_len(resp));
00842 
00843         /* eapRespData is not used anymore, so free it here */
00844         wpabuf_free(resp);
00845 
00846         if (sm->initial_req)
00847                 sm->dot1xSuppEapolReqIdFramesRx++;
00848         else
00849                 sm->dot1xSuppEapolReqFramesRx++;
00850         sm->dot1xSuppEapolRespFramesTx++;
00851         sm->dot1xSuppEapolFramesTx++;
00852 }
00853 
00854 
00855 static void eapol_sm_abortSupp(struct eapol_sm *sm)
00856 {
00857         /* release system resources that may have been allocated for the
00858          * authentication session */
00859         os_free(sm->last_rx_key);
00860         sm->last_rx_key = NULL;
00861         wpabuf_free(sm->eapReqData);
00862         sm->eapReqData = NULL;
00863         eap_sm_abort(sm->eap);
00864 }
00865 
00866 
00867 static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
00868 {
00869         eapol_sm_step(timeout_ctx);
00870 }
00871 
00872 
00873 static void eapol_sm_set_port_authorized(struct eapol_sm *sm)
00874 {
00875         if (sm->ctx->port_cb)
00876                 sm->ctx->port_cb(sm->ctx->ctx, 1);
00877 }
00878 
00879 
00880 static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm)
00881 {
00882         if (sm->ctx->port_cb)
00883                 sm->ctx->port_cb(sm->ctx->ctx, 0);
00884 }
00885 
00886 
00895 void eapol_sm_step(struct eapol_sm *sm)
00896 {
00897         int i;
00898 
00899         /* In theory, it should be ok to run this in loop until !changed.
00900          * However, it is better to use a limit on number of iterations to
00901          * allow events (e.g., SIGTERM) to stop the program cleanly if the
00902          * state machine were to generate a busy loop. */
00903         for (i = 0; i < 100; i++) {
00904                 sm->changed = FALSE;
00905                 SM_STEP_RUN(SUPP_PAE);
00906                 SM_STEP_RUN(KEY_RX);
00907                 SM_STEP_RUN(SUPP_BE);
00908                 if (eap_peer_sm_step(sm->eap))
00909                         sm->changed = TRUE;
00910                 if (!sm->changed)
00911                         break;
00912         }
00913 
00914         if (sm->changed) {
00915                 /* restart EAPOL state machine step from timeout call in order
00916                  * to allow other events to be processed. */
00917                 eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
00918                 eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm);
00919         }
00920 
00921         if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
00922                 int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0;
00923                 sm->cb_status = EAPOL_CB_IN_PROGRESS;
00924                 sm->ctx->cb(sm, success, sm->ctx->cb_ctx);
00925         }
00926 }
00927 
00928 
00929 #ifdef CONFIG_CTRL_IFACE
00930 static const char *eapol_supp_pae_state(int state)
00931 {
00932         switch (state) {
00933         case SUPP_PAE_LOGOFF:
00934                 return "LOGOFF";
00935         case SUPP_PAE_DISCONNECTED:
00936                 return "DISCONNECTED";
00937         case SUPP_PAE_CONNECTING:
00938                 return "CONNECTING";
00939         case SUPP_PAE_AUTHENTICATING:
00940                 return "AUTHENTICATING";
00941         case SUPP_PAE_HELD:
00942                 return "HELD";
00943         case SUPP_PAE_AUTHENTICATED:
00944                 return "AUTHENTICATED";
00945         case SUPP_PAE_RESTART:
00946                 return "RESTART";
00947         default:
00948                 return "UNKNOWN";
00949         }
00950 }
00951 
00952 
00953 static const char *eapol_supp_be_state(int state)
00954 {
00955         switch (state) {
00956         case SUPP_BE_REQUEST:
00957                 return "REQUEST";
00958         case SUPP_BE_RESPONSE:
00959                 return "RESPONSE";
00960         case SUPP_BE_SUCCESS:
00961                 return "SUCCESS";
00962         case SUPP_BE_FAIL:
00963                 return "FAIL";
00964         case SUPP_BE_TIMEOUT:
00965                 return "TIMEOUT";
00966         case SUPP_BE_IDLE:
00967                 return "IDLE";
00968         case SUPP_BE_INITIALIZE:
00969                 return "INITIALIZE";
00970         case SUPP_BE_RECEIVE:
00971                 return "RECEIVE";
00972         default:
00973                 return "UNKNOWN";
00974         }
00975 }
00976 
00977 
00978 static const char * eapol_port_status(PortStatus status)
00979 {
00980         if (status == Authorized)
00981                 return "Authorized";
00982         else
00983                 return "Unauthorized";
00984 }
00985 #endif /* CONFIG_CTRL_IFACE */
00986 
00987 
00988 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
00989 static const char * eapol_port_control(PortControl ctrl)
00990 {
00991         switch (ctrl) {
00992         case Auto:
00993                 return "Auto";
00994         case ForceUnauthorized:
00995                 return "ForceUnauthorized";
00996         case ForceAuthorized:
00997                 return "ForceAuthorized";
00998         default:
00999                 return "Unknown";
01000         }
01001 }
01002 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
01003 
01004 
01016 void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
01017                         int startPeriod, int maxStart)
01018 {
01019         if (sm == NULL)
01020                 return;
01021         if (heldPeriod >= 0)
01022                 sm->heldPeriod = heldPeriod;
01023         if (authPeriod >= 0)
01024                 sm->authPeriod = authPeriod;
01025         if (startPeriod >= 0)
01026                 sm->startPeriod = startPeriod;
01027         if (maxStart >= 0)
01028                 sm->maxStart = maxStart;
01029 }
01030 
01031 
01032 #ifdef CONFIG_CTRL_IFACE
01033 
01046 int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
01047                         int verbose)
01048 {
01049         int len, ret;
01050         if (sm == NULL)
01051                 return 0;
01052 
01053         len = os_snprintf(buf, buflen,
01054                           "Supplicant PAE state=%s\n"
01055                           "suppPortStatus=%s\n",
01056                           eapol_supp_pae_state(sm->SUPP_PAE_state),
01057                           eapol_port_status(sm->suppPortStatus));
01058         if (len < 0 || (size_t) len >= buflen)
01059                 return 0;
01060 
01061         if (verbose) {
01062                 ret = os_snprintf(buf + len, buflen - len,
01063                                   "heldPeriod=%u\n"
01064                                   "authPeriod=%u\n"
01065                                   "startPeriod=%u\n"
01066                                   "maxStart=%u\n"
01067                                   "portControl=%s\n"
01068                                   "Supplicant Backend state=%s\n",
01069                                   sm->heldPeriod,
01070                                   sm->authPeriod,
01071                                   sm->startPeriod,
01072                                   sm->maxStart,
01073                                   eapol_port_control(sm->portControl),
01074                                   eapol_supp_be_state(sm->SUPP_BE_state));
01075                 if (ret < 0 || (size_t) ret >= buflen - len)
01076                         return len;
01077                 len += ret;
01078         }
01079 
01080         len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
01081 
01082         return len;
01083 }
01084 
01085 
01098 int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
01099 {
01100         size_t len;
01101         int ret;
01102 
01103         if (sm == NULL)
01104                 return 0;
01105         ret = os_snprintf(buf, buflen,
01106                           "dot1xSuppPaeState=%d\n"
01107                           "dot1xSuppHeldPeriod=%u\n"
01108                           "dot1xSuppAuthPeriod=%u\n"
01109                           "dot1xSuppStartPeriod=%u\n"
01110                           "dot1xSuppMaxStart=%u\n"
01111                           "dot1xSuppSuppControlledPortStatus=%s\n"
01112                           "dot1xSuppBackendPaeState=%d\n",
01113                           sm->SUPP_PAE_state,
01114                           sm->heldPeriod,
01115                           sm->authPeriod,
01116                           sm->startPeriod,
01117                           sm->maxStart,
01118                           sm->suppPortStatus == Authorized ?
01119                           "Authorized" : "Unauthorized",
01120                           sm->SUPP_BE_state);
01121 
01122         if (ret < 0 || (size_t) ret >= buflen)
01123                 return 0;
01124         len = ret;
01125 
01126         ret = os_snprintf(buf + len, buflen - len,
01127                           "dot1xSuppEapolFramesRx=%u\n"
01128                           "dot1xSuppEapolFramesTx=%u\n"
01129                           "dot1xSuppEapolStartFramesTx=%u\n"
01130                           "dot1xSuppEapolLogoffFramesTx=%u\n"
01131                           "dot1xSuppEapolRespFramesTx=%u\n"
01132                           "dot1xSuppEapolReqIdFramesRx=%u\n"
01133                           "dot1xSuppEapolReqFramesRx=%u\n"
01134                           "dot1xSuppInvalidEapolFramesRx=%u\n"
01135                           "dot1xSuppEapLengthErrorFramesRx=%u\n"
01136                           "dot1xSuppLastEapolFrameVersion=%u\n"
01137                           "dot1xSuppLastEapolFrameSource=" MACSTR "\n",
01138                           sm->dot1xSuppEapolFramesRx,
01139                           sm->dot1xSuppEapolFramesTx,
01140                           sm->dot1xSuppEapolStartFramesTx,
01141                           sm->dot1xSuppEapolLogoffFramesTx,
01142                           sm->dot1xSuppEapolRespFramesTx,
01143                           sm->dot1xSuppEapolReqIdFramesRx,
01144                           sm->dot1xSuppEapolReqFramesRx,
01145                           sm->dot1xSuppInvalidEapolFramesRx,
01146                           sm->dot1xSuppEapLengthErrorFramesRx,
01147                           sm->dot1xSuppLastEapolFrameVersion,
01148                           MAC2STR(sm->dot1xSuppLastEapolFrameSource));
01149 
01150         if (ret < 0 || (size_t) ret >= buflen - len)
01151                 return len;
01152         len += ret;
01153 
01154         return len;
01155 }
01156 #endif /* CONFIG_CTRL_IFACE */
01157 
01158 
01168 int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
01169                       size_t len)
01170 {
01171         const struct ieee802_1x_hdr *hdr;
01172         const struct ieee802_1x_eapol_key *key;
01173         int data_len;
01174         int res = 1;
01175         size_t plen;
01176 
01177         if (sm == NULL)
01178                 return 0;
01179         sm->dot1xSuppEapolFramesRx++;
01180         if (len < sizeof(*hdr)) {
01181                 sm->dot1xSuppInvalidEapolFramesRx++;
01182                 return 0;
01183         }
01184         hdr = (const struct ieee802_1x_hdr *) buf;
01185         sm->dot1xSuppLastEapolFrameVersion = hdr->version;
01186         os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
01187         if (hdr->version < EAPOL_VERSION) {
01188                 /* TODO: backwards compatibility */
01189         }
01190         plen = be_to_host16(hdr->length);
01191         if (plen > len - sizeof(*hdr)) {
01192                 sm->dot1xSuppEapLengthErrorFramesRx++;
01193                 return 0;
01194         }
01195 #ifdef CONFIG_WPS
01196         if (sm->conf.workaround &&
01197             plen < len - sizeof(*hdr) &&
01198             hdr->type == IEEE802_1X_TYPE_EAP_PACKET &&
01199             len - sizeof(*hdr) > sizeof(struct eap_hdr)) {
01200                 const struct eap_hdr *ehdr =
01201                         (const struct eap_hdr *) (hdr + 1);
01202                 u16 elen;
01203 
01204                 elen = be_to_host16(ehdr->length);
01205                 if (elen > plen && elen <= len - sizeof(*hdr)) {
01206                         /*
01207                          * Buffalo WHR-G125 Ver.1.47 seems to send EAP-WPS
01208                          * packets with too short EAPOL header length field
01209                          * (14 octets). This is fixed in firmware Ver.1.49.
01210                          * As a workaround, fix the EAPOL header based on the
01211                          * correct length in the EAP packet.
01212                          */
01213                         wpa_printf(MSG_DEBUG, "EAPOL: Workaround - fix EAPOL "
01214                                    "payload length based on EAP header: "
01215                                    "%d -> %d", (int) plen, elen);
01216                         plen = elen;
01217                 }
01218         }
01219 #endif /* CONFIG_WPS */
01220         data_len = plen + sizeof(*hdr);
01221 
01222         switch (hdr->type) {
01223         case IEEE802_1X_TYPE_EAP_PACKET:
01224                 if (sm->cached_pmk) {
01225                         /* Trying to use PMKSA caching, but Authenticator did
01226                          * not seem to have a matching entry. Need to restart
01227                          * EAPOL state machines.
01228                          */
01229                         eapol_sm_abort_cached(sm);
01230                 }
01231                 wpabuf_free(sm->eapReqData);
01232                 sm->eapReqData = wpabuf_alloc_copy(hdr + 1, plen);
01233                 if (sm->eapReqData) {
01234                         wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
01235                                    "frame");
01236                         sm->eapolEap = TRUE;
01237                         eapol_sm_step(sm);
01238                 }
01239                 break;
01240         case IEEE802_1X_TYPE_EAPOL_KEY:
01241                 if (plen < sizeof(*key)) {
01242                         wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key "
01243                                    "frame received");
01244                         break;
01245                 }
01246                 key = (const struct ieee802_1x_eapol_key *) (hdr + 1);
01247                 if (key->type == EAPOL_KEY_TYPE_WPA ||
01248                     key->type == EAPOL_KEY_TYPE_RSN) {
01249                         /* WPA Supplicant takes care of this frame. */
01250                         wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
01251                                    "frame in EAPOL state machines");
01252                         res = 0;
01253                         break;
01254                 }
01255                 if (key->type != EAPOL_KEY_TYPE_RC4) {
01256                         wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown "
01257                                    "EAPOL-Key type %d", key->type);
01258                         break;
01259                 }
01260                 os_free(sm->last_rx_key);
01261                 sm->last_rx_key = os_malloc(data_len);
01262                 if (sm->last_rx_key) {
01263                         wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key "
01264                                    "frame");
01265                         os_memcpy(sm->last_rx_key, buf, data_len);
01266                         sm->last_rx_key_len = data_len;
01267                         sm->rxKey = TRUE;
01268                         eapol_sm_step(sm);
01269                 }
01270                 break;
01271         default:
01272                 wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
01273                            hdr->type);
01274                 sm->dot1xSuppInvalidEapolFramesRx++;
01275                 break;
01276         }
01277 
01278         return res;
01279 }
01280 
01281 
01289 void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
01290 {
01291         if (sm)
01292                 sm->dot1xSuppEapolFramesTx++;
01293 }
01294 
01295 
01303 void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
01304 {
01305         if (sm == NULL)
01306                 return;
01307         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
01308                    "portEnabled=%d", enabled);
01309         sm->portEnabled = enabled;
01310         eapol_sm_step(sm);
01311 }
01312 
01313 
01321 void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
01322 {
01323         if (sm == NULL)
01324                 return;
01325         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
01326                    "portValid=%d", valid);
01327         sm->portValid = valid;
01328         eapol_sm_step(sm);
01329 }
01330 
01331 
01343 void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
01344 {
01345         if (sm == NULL)
01346                 return;
01347         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
01348                    "EAP success=%d", success);
01349         sm->eapSuccess = success;
01350         sm->altAccept = success;
01351         if (success)
01352                 eap_notify_success(sm->eap);
01353         eapol_sm_step(sm);
01354 }
01355 
01356 
01365 void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
01366 {
01367         if (sm == NULL)
01368                 return;
01369         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
01370                    "EAP fail=%d", fail);
01371         sm->eapFail = fail;
01372         sm->altReject = fail;
01373         eapol_sm_step(sm);
01374 }
01375 
01376 
01389 void eapol_sm_notify_config(struct eapol_sm *sm,
01390                             struct eap_peer_config *config,
01391                             const struct eapol_config *conf)
01392 {
01393         if (sm == NULL)
01394                 return;
01395 
01396         sm->config = config;
01397 
01398         if (conf == NULL)
01399                 return;
01400 
01401         sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys;
01402         sm->conf.required_keys = conf->required_keys;
01403         sm->conf.fast_reauth = conf->fast_reauth;
01404         sm->conf.workaround = conf->workaround;
01405         if (sm->eap) {
01406                 eap_set_fast_reauth(sm->eap, conf->fast_reauth);
01407                 eap_set_workaround(sm->eap, conf->workaround);
01408                 eap_set_force_disabled(sm->eap, conf->eap_disabled);
01409         }
01410 }
01411 
01412 
01424 int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
01425 {
01426         const u8 *eap_key;
01427         size_t eap_len;
01428 
01429         if (sm == NULL || !eap_key_available(sm->eap)) {
01430                 wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
01431                 return -1;
01432         }
01433         eap_key = eap_get_eapKeyData(sm->eap, &eap_len);
01434         if (eap_key == NULL) {
01435                 wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData");
01436                 return -1;
01437         }
01438         if (len > eap_len) {
01439                 wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not "
01440                            "available (len=%lu)",
01441                            (unsigned long) len, (unsigned long) eap_len);
01442                 return eap_len;
01443         }
01444         os_memcpy(key, eap_key, len);
01445         wpa_printf(MSG_DEBUG, "EAPOL: Successfully fetched key (len=%lu)",
01446                    (unsigned long) len);
01447         return 0;
01448 }
01449 
01450 
01458 void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
01459 {
01460         if (sm) {
01461                 sm->userLogoff = logoff;
01462                 eapol_sm_step(sm);
01463         }
01464 }
01465 
01466 
01474 void eapol_sm_notify_cached(struct eapol_sm *sm)
01475 {
01476         if (sm == NULL)
01477                 return;
01478         wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL");
01479         sm->SUPP_PAE_state = SUPP_PAE_AUTHENTICATED;
01480         sm->suppPortStatus = Authorized;
01481         eapol_sm_set_port_authorized(sm);
01482         sm->portValid = TRUE;
01483         eap_notify_success(sm->eap);
01484         eapol_sm_step(sm);
01485 }
01486 
01487 
01495 void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt)
01496 {
01497         if (sm == NULL)
01498                 return;
01499         if (attempt) {
01500                 wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
01501                 sm->cached_pmk = TRUE;
01502         } else {
01503                 wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA");
01504                 sm->cached_pmk = FALSE;
01505         }
01506 }
01507 
01508 
01509 static void eapol_sm_abort_cached(struct eapol_sm *sm)
01510 {
01511         wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, "
01512                    "doing full EAP authentication");
01513         if (sm == NULL)
01514                 return;
01515         sm->cached_pmk = FALSE;
01516         sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
01517         sm->suppPortStatus = Unauthorized;
01518         eapol_sm_set_port_unauthorized(sm);
01519 
01520         /* Make sure we do not start sending EAPOL-Start frames first, but
01521          * instead move to RESTART state to start EAPOL authentication. */
01522         sm->startWhen = 3;
01523         eapol_enable_timer_tick(sm);
01524 
01525         if (sm->ctx->aborted_cached)
01526                 sm->ctx->aborted_cached(sm->ctx->ctx);
01527 }
01528 
01529 
01538 void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
01539 {
01540         if (sm) {
01541                 sm->ctx->scard_ctx = ctx;
01542                 eap_register_scard_ctx(sm->eap, ctx);
01543         }
01544 }
01545 
01546 
01554 void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
01555 {
01556         if (sm == NULL)
01557                 return;
01558         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
01559                    "portControl=%s", eapol_port_control(portControl));
01560         sm->portControl = portControl;
01561         eapol_sm_step(sm);
01562 }
01563 
01564 
01572 void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
01573 {
01574         if (sm == NULL)
01575                 return;
01576         eap_sm_notify_ctrl_attached(sm->eap);
01577 }
01578 
01579 
01587 void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
01588 {
01589         if (sm == NULL)
01590                 return;
01591         if (sm->eapReqData && !sm->eapReq) {
01592                 wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
01593                            "input) notification - retrying pending EAP "
01594                            "Request");
01595                 sm->eapolEap = TRUE;
01596                 sm->eapReq = TRUE;
01597                 eapol_sm_step(sm);
01598         }
01599 }
01600 
01601 
01609 void eapol_sm_request_reauth(struct eapol_sm *sm)
01610 {
01611         if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
01612                 return;
01613         eapol_sm_txStart(sm);
01614 }
01615 
01616 
01627 void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm)
01628 {
01629         if (sm == NULL)
01630                 return;
01631         eap_notify_lower_layer_success(sm->eap);
01632         if (!in_eapol_sm)
01633                 eapol_sm_step(sm);
01634 }
01635 
01636 
01641 void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
01642 {
01643         if (sm)
01644                 eap_invalidate_cached_session(sm->eap);
01645 }
01646 
01647 
01648 static struct eap_peer_config * eapol_sm_get_config(void *ctx)
01649 {
01650         struct eapol_sm *sm = ctx;
01651         return sm ? sm->config : NULL;
01652 }
01653 
01654 
01655 static struct wpabuf * eapol_sm_get_eapReqData(void *ctx)
01656 {
01657         struct eapol_sm *sm = ctx;
01658         if (sm == NULL || sm->eapReqData == NULL)
01659                 return NULL;
01660 
01661         return sm->eapReqData;
01662 }
01663 
01664 
01665 static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
01666 {
01667         struct eapol_sm *sm = ctx;
01668         if (sm == NULL)
01669                 return FALSE;
01670         switch (variable) {
01671         case EAPOL_eapSuccess:
01672                 return sm->eapSuccess;
01673         case EAPOL_eapRestart:
01674                 return sm->eapRestart;
01675         case EAPOL_eapFail:
01676                 return sm->eapFail;
01677         case EAPOL_eapResp:
01678                 return sm->eapResp;
01679         case EAPOL_eapNoResp:
01680                 return sm->eapNoResp;
01681         case EAPOL_eapReq:
01682                 return sm->eapReq;
01683         case EAPOL_portEnabled:
01684                 return sm->portEnabled;
01685         case EAPOL_altAccept:
01686                 return sm->altAccept;
01687         case EAPOL_altReject:
01688                 return sm->altReject;
01689         }
01690         return FALSE;
01691 }
01692 
01693 
01694 static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
01695                               Boolean value)
01696 {
01697         struct eapol_sm *sm = ctx;
01698         if (sm == NULL)
01699                 return;
01700         switch (variable) {
01701         case EAPOL_eapSuccess:
01702                 sm->eapSuccess = value;
01703                 break;
01704         case EAPOL_eapRestart:
01705                 sm->eapRestart = value;
01706                 break;
01707         case EAPOL_eapFail:
01708                 sm->eapFail = value;
01709                 break;
01710         case EAPOL_eapResp:
01711                 sm->eapResp = value;
01712                 break;
01713         case EAPOL_eapNoResp:
01714                 sm->eapNoResp = value;
01715                 break;
01716         case EAPOL_eapReq:
01717                 sm->eapReq = value;
01718                 break;
01719         case EAPOL_portEnabled:
01720                 sm->portEnabled = value;
01721                 break;
01722         case EAPOL_altAccept:
01723                 sm->altAccept = value;
01724                 break;
01725         case EAPOL_altReject:
01726                 sm->altReject = value;
01727                 break;
01728         }
01729 }
01730 
01731 
01732 static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable)
01733 {
01734         struct eapol_sm *sm = ctx;
01735         if (sm == NULL)
01736                 return 0;
01737         switch (variable) {
01738         case EAPOL_idleWhile:
01739                 return sm->idleWhile;
01740         }
01741         return 0;
01742 }
01743 
01744 
01745 static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
01746                              unsigned int value)
01747 {
01748         struct eapol_sm *sm = ctx;
01749         if (sm == NULL)
01750                 return;
01751         switch (variable) {
01752         case EAPOL_idleWhile:
01753                 sm->idleWhile = value;
01754                 eapol_enable_timer_tick(sm);
01755                 break;
01756         }
01757 }
01758 
01759 
01760 static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
01761 {
01762 #ifndef CONFIG_NO_CONFIG_BLOBS
01763         struct eapol_sm *sm = ctx;
01764         if (sm && sm->ctx && sm->ctx->set_config_blob)
01765                 sm->ctx->set_config_blob(sm->ctx->ctx, blob);
01766 #endif /* CONFIG_NO_CONFIG_BLOBS */
01767 }
01768 
01769 
01770 static const struct wpa_config_blob *
01771 eapol_sm_get_config_blob(void *ctx, const char *name)
01772 {
01773 #ifndef CONFIG_NO_CONFIG_BLOBS
01774         struct eapol_sm *sm = ctx;
01775         if (sm && sm->ctx && sm->ctx->get_config_blob)
01776                 return sm->ctx->get_config_blob(sm->ctx->ctx, name);
01777         else
01778                 return NULL;
01779 #else /* CONFIG_NO_CONFIG_BLOBS */
01780         return NULL;
01781 #endif /* CONFIG_NO_CONFIG_BLOBS */
01782 }
01783 
01784 
01785 static void eapol_sm_notify_pending(void *ctx)
01786 {
01787         struct eapol_sm *sm = ctx;
01788         if (sm == NULL)
01789                 return;
01790         if (sm->eapReqData && !sm->eapReq) {
01791                 wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP "
01792                            "state machine - retrying pending EAP Request");
01793                 sm->eapolEap = TRUE;
01794                 sm->eapReq = TRUE;
01795                 eapol_sm_step(sm);
01796         }
01797 }
01798 
01799 
01800 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
01801 static void eapol_sm_eap_param_needed(void *ctx, const char *field,
01802                                       const char *txt)
01803 {
01804         struct eapol_sm *sm = ctx;
01805         wpa_printf(MSG_DEBUG, "EAPOL: EAP parameter needed");
01806         if (sm->ctx->eap_param_needed)
01807                 sm->ctx->eap_param_needed(sm->ctx->ctx, field, txt);
01808 }
01809 #else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
01810 #define eapol_sm_eap_param_needed NULL
01811 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
01812 
01813 
01814 static struct eapol_callbacks eapol_cb =
01815 {
01816         eapol_sm_get_config,
01817         eapol_sm_get_bool,
01818         eapol_sm_set_bool,
01819         eapol_sm_get_int,
01820         eapol_sm_set_int,
01821         eapol_sm_get_eapReqData,
01822         eapol_sm_set_config_blob,
01823         eapol_sm_get_config_blob,
01824         eapol_sm_notify_pending,
01825         eapol_sm_eap_param_needed
01826 };
01827 
01828 
01837 struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
01838 {
01839         struct eapol_sm *sm;
01840         struct eap_config conf;
01841         sm = os_zalloc(sizeof(*sm));
01842         if (sm == NULL)
01843                 return NULL;
01844         sm->ctx = ctx;
01845 
01846         sm->portControl = Auto;
01847 
01848         /* Supplicant PAE state machine */
01849         sm->heldPeriod = 60;
01850         sm->startPeriod = 30;
01851         sm->maxStart = 3;
01852 
01853         /* Supplicant Backend state machine */
01854         sm->authPeriod = 30;
01855 
01856         os_memset(&conf, 0, sizeof(conf));
01857         conf.opensc_engine_path = ctx->opensc_engine_path;
01858         conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
01859         conf.pkcs11_module_path = ctx->pkcs11_module_path;
01860         conf.wps = ctx->wps;
01861 
01862         sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
01863         if (sm->eap == NULL) {
01864                 os_free(sm);
01865                 return NULL;
01866         }
01867 
01868         /* Initialize EAPOL state machines */
01869         sm->initialize = TRUE;
01870         eapol_sm_step(sm);
01871         sm->initialize = FALSE;
01872         eapol_sm_step(sm);
01873 
01874         sm->timer_tick_enabled = 1;
01875         eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
01876 
01877         return sm;
01878 }
01879 
01880 
01887 void eapol_sm_deinit(struct eapol_sm *sm)
01888 {
01889         if (sm == NULL)
01890                 return;
01891         eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
01892         eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
01893         eap_peer_sm_deinit(sm->eap);
01894         os_free(sm->last_rx_key);
01895         wpabuf_free(sm->eapReqData);
01896         os_free(sm->ctx);
01897         os_free(sm);
01898 }


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