eapol_sm.c

Go to the documentation of this file.
00001 
00016 #include <stdlib.h>
00017 #include <stdio.h>
00018 #include <string.h>
00019 
00020 #include "common.h"
00021 #include "eapol_sm.h"
00022 #include "eap.h"
00023 #include "eloop.h"
00024 #include "l2_packet.h"
00025 #include "wpa.h"
00026 #include "md5.h"
00027 #include "rc4.h"
00028 
00029 
00030 /* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
00031 
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 
00043         /* Global variables */
00044         Boolean eapFail;
00045         Boolean eapolEap;
00046         Boolean eapSuccess;
00047         Boolean initialize;
00048         Boolean keyDone;
00049         Boolean keyRun;
00050         PortControl portControl;
00051         Boolean portEnabled;
00052         PortStatus suppPortStatus;  /* dot1xSuppControlledPortStatus */
00053         Boolean portValid;
00054         Boolean suppAbort;
00055         Boolean suppFail;
00056         Boolean suppStart;
00057         Boolean suppSuccess;
00058         Boolean suppTimeout;
00059 
00060         /* Supplicant PAE state machine */
00061         enum {
00062                 SUPP_PAE_UNKNOWN = 0,
00063                 SUPP_PAE_DISCONNECTED = 1,
00064                 SUPP_PAE_LOGOFF = 2,
00065                 SUPP_PAE_CONNECTING = 3,
00066                 SUPP_PAE_AUTHENTICATING = 4,
00067                 SUPP_PAE_AUTHENTICATED = 5,
00068                 /* unused(6) */
00069                 SUPP_PAE_HELD = 7,
00070                 SUPP_PAE_RESTART = 8,
00071                 SUPP_PAE_S_FORCE_AUTH = 9,
00072                 SUPP_PAE_S_FORCE_UNAUTH = 10
00073         } SUPP_PAE_state; /* dot1xSuppPaeState */
00074         /* Variables */
00075         Boolean userLogoff;
00076         Boolean logoffSent;
00077         unsigned int startCount;
00078         Boolean eapRestart;
00079         PortControl sPortMode;
00080         /* Constants */
00081         unsigned int heldPeriod; /* dot1xSuppHeldPeriod */
00082         unsigned int startPeriod; /* dot1xSuppStartPeriod */
00083         unsigned int maxStart; /* dot1xSuppMaxStart */
00084 
00085         /* Key Receive state machine */
00086         enum {
00087                 KEY_RX_UNKNOWN = 0,
00088                 KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
00089         } KEY_RX_state;
00090         /* Variables */
00091         Boolean rxKey;
00092 
00093         /* Supplicant Backend state machine */
00094         enum {
00095                 SUPP_BE_UNKNOWN = 0,
00096                 SUPP_BE_INITIALIZE = 1,
00097                 SUPP_BE_IDLE = 2,
00098                 SUPP_BE_REQUEST = 3,
00099                 SUPP_BE_RECEIVE = 4,
00100                 SUPP_BE_RESPONSE = 5,
00101                 SUPP_BE_FAIL = 6,
00102                 SUPP_BE_TIMEOUT = 7, 
00103                 SUPP_BE_SUCCESS = 8
00104         } SUPP_BE_state; /* dot1xSuppBackendPaeState */
00105         /* Variables */
00106         Boolean eapNoResp;
00107         Boolean eapReq;
00108         Boolean eapResp;
00109         /* Constants */
00110         unsigned int authPeriod; /* dot1xSuppAuthPeriod */
00111 
00112         /* Statistics */
00113         unsigned int dot1xSuppEapolFramesRx;
00114         unsigned int dot1xSuppEapolFramesTx;
00115         unsigned int dot1xSuppEapolStartFramesTx;
00116         unsigned int dot1xSuppEapolLogoffFramesTx;
00117         unsigned int dot1xSuppEapolRespFramesTx;
00118         unsigned int dot1xSuppEapolReqIdFramesRx;
00119         unsigned int dot1xSuppEapolReqFramesRx;
00120         unsigned int dot1xSuppInvalidEapolFramesRx;
00121         unsigned int dot1xSuppEapLengthErrorFramesRx;
00122         unsigned int dot1xSuppLastEapolFrameVersion;
00123         unsigned char dot1xSuppLastEapolFrameSource[6];
00124 
00125         /* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
00126         Boolean changed;
00127         struct eap_sm *eap;
00128         struct wpa_ssid *config;
00129         Boolean initial_req;
00130         u8 *last_rx_key;
00131         size_t last_rx_key_len;
00132         u8 *eapReqData; /* for EAP */
00133         size_t eapReqDataLen; /* 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 struct ieee802_1x_eapol_key {
00156         u8 type;
00157         /* Note: key_length is unaligned */
00158         u8 key_length[2];
00159         /* does not repeat within the life of the keying material used to
00160          * encrypt the Key field; 64-bit NTP timestamp MAY be used here */
00161         u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN];
00162         u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */
00163         u8 key_index; /* key flag in the most significant bit:
00164                        * 0 = broadcast (default key),
00165                        * 1 = unicast (key mapping key); key index is in the
00166                        * 7 least significant bits */
00167         /* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as
00168          * the key */
00169         u8 key_signature[IEEE8021X_KEY_SIGN_LEN];
00170 
00171         /* followed by key: if packet body length = 44 + key length, then the
00172          * key field (of key_length bytes) contains the key in encrypted form;
00173          * if packet body length = 44, key field is absent and key_length
00174          * represents the number of least significant octets from
00175          * MS-MPPE-Send-Key attribute to be used as the keying material;
00176          * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
00177 } __attribute__ ((packed));
00178 
00179 
00180 static void eapol_sm_txLogoff(struct eapol_sm *sm);
00181 static void eapol_sm_txStart(struct eapol_sm *sm);
00182 static void eapol_sm_processKey(struct eapol_sm *sm);
00183 static void eapol_sm_getSuppRsp(struct eapol_sm *sm);
00184 static void eapol_sm_txSuppRsp(struct eapol_sm *sm);
00185 static void eapol_sm_abortSupp(struct eapol_sm *sm);
00186 static void eapol_sm_abort_cached(struct eapol_sm *sm);
00187 static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx);
00188 
00189 
00190 /* Definitions for clarifying state machine implementation */
00191 #define SM_STATE(machine, state) \
00192 static void sm_ ## machine ## _ ## state ## _Enter(struct eapol_sm *sm, \
00193         int global)
00194 
00195 #define SM_ENTRY(machine, state) \
00196 if (!global || sm->machine ## _state != machine ## _ ## state) { \
00197         sm->changed = TRUE; \
00198         wpa_printf(MSG_DEBUG, "EAPOL: " #machine " entering state " #state); \
00199 } \
00200 sm->machine ## _state = machine ## _ ## state;
00201 
00202 #define SM_ENTER(machine, state) \
00203 sm_ ## machine ## _ ## state ## _Enter(sm, 0)
00204 #define SM_ENTER_GLOBAL(machine, state) \
00205 sm_ ## machine ## _ ## state ## _Enter(sm, 1)
00206 
00207 #define SM_STEP(machine) \
00208 static void sm_ ## machine ## _Step(struct eapol_sm *sm)
00209 
00210 #define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
00211 
00212 
00213 /* Port Timers state machine - implemented as a function that will be called
00214  * once a second as a registered event loop timeout */
00215 static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
00216 {
00217         struct eapol_sm *sm = timeout_ctx;
00218 
00219         if (sm->authWhile > 0) {
00220                 sm->authWhile--;
00221                 if (sm->authWhile == 0)
00222                         wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0");
00223         }
00224         if (sm->heldWhile > 0) {
00225                 sm->heldWhile--;
00226                 if (sm->heldWhile == 0)
00227                         wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0");
00228         }
00229         if (sm->startWhen > 0) {
00230                 sm->startWhen--;
00231                 if (sm->startWhen == 0)
00232                         wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0");
00233         }
00234         if (sm->idleWhile > 0) {
00235                 sm->idleWhile--;
00236                 if (sm->idleWhile == 0)
00237                         wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0");
00238         }
00239 
00240         eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, sm);
00241         eapol_sm_step(sm);
00242 }
00243 
00244 
00245 SM_STATE(SUPP_PAE, LOGOFF)
00246 {
00247         SM_ENTRY(SUPP_PAE, LOGOFF);
00248         eapol_sm_txLogoff(sm);
00249         sm->logoffSent = TRUE;
00250         sm->suppPortStatus = Unauthorized;
00251 }
00252 
00253 
00254 SM_STATE(SUPP_PAE, DISCONNECTED)
00255 {
00256         SM_ENTRY(SUPP_PAE, DISCONNECTED);
00257         sm->sPortMode = Auto;
00258         sm->startCount = 0;
00259         sm->logoffSent = FALSE;
00260         sm->suppPortStatus = Unauthorized;
00261         sm->suppAbort = TRUE;
00262 
00263         sm->unicast_key_received = FALSE;
00264         sm->broadcast_key_received = FALSE;
00265 }
00266 
00267 
00268 SM_STATE(SUPP_PAE, CONNECTING)
00269 {
00270         int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING;
00271         SM_ENTRY(SUPP_PAE, CONNECTING);
00272         if (send_start) {
00273                 sm->startWhen = sm->startPeriod;
00274                 sm->startCount++;
00275         } else {
00276                 /*
00277                  * Do not send EAPOL-Start immediately since in most cases,
00278                  * Authenticator is going to start authentication immediately
00279                  * after association and an extra EAPOL-Start is just going to
00280                  * delay authentication. Use a short timeout to send the first
00281                  * EAPOL-Start if Authenticator does not start authentication.
00282                  */
00283                 sm->startWhen = 3;
00284         }
00285         sm->eapolEap = FALSE;
00286         if (send_start)
00287                 eapol_sm_txStart(sm);
00288 }
00289 
00290 
00291 SM_STATE(SUPP_PAE, AUTHENTICATING)
00292 {
00293         SM_ENTRY(SUPP_PAE, AUTHENTICATING);
00294         sm->startCount = 0;
00295         sm->suppSuccess = FALSE;
00296         sm->suppFail = FALSE;
00297         sm->suppTimeout = FALSE;
00298         sm->keyRun = FALSE;
00299         sm->keyDone = FALSE;
00300         sm->suppStart = TRUE;
00301 }
00302 
00303 
00304 SM_STATE(SUPP_PAE, HELD)
00305 {
00306         SM_ENTRY(SUPP_PAE, HELD);
00307         sm->heldWhile = sm->heldPeriod;
00308         sm->suppPortStatus = Unauthorized;
00309         sm->cb_status = EAPOL_CB_FAILURE;
00310 }
00311 
00312 
00313 SM_STATE(SUPP_PAE, AUTHENTICATED)
00314 {
00315         SM_ENTRY(SUPP_PAE, AUTHENTICATED);
00316         sm->suppPortStatus = Authorized;
00317         sm->cb_status = EAPOL_CB_SUCCESS;
00318 }
00319 
00320 
00321 SM_STATE(SUPP_PAE, RESTART)
00322 {
00323         SM_ENTRY(SUPP_PAE, RESTART);
00324         sm->eapRestart = TRUE;
00325 }
00326 
00327 
00328 SM_STATE(SUPP_PAE, S_FORCE_AUTH)
00329 {
00330         SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
00331         sm->suppPortStatus = Authorized;
00332         sm->sPortMode = ForceAuthorized;
00333 }
00334 
00335 
00336 SM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
00337 {
00338         SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
00339         sm->suppPortStatus = Unauthorized;
00340         sm->sPortMode = ForceUnauthorized;
00341         eapol_sm_txLogoff(sm);
00342 }
00343 
00344 
00345 SM_STEP(SUPP_PAE)
00346 {
00347         if ((sm->userLogoff && !sm->logoffSent) &&
00348             !(sm->initialize || !sm->portEnabled))
00349                 SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF);
00350         else if (((sm->portControl == Auto) &&
00351                   (sm->sPortMode != sm->portControl)) ||
00352                  sm->initialize || !sm->portEnabled)
00353                 SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED);
00354         else if ((sm->portControl == ForceAuthorized) &&
00355                  (sm->sPortMode != sm->portControl) &&
00356                  !(sm->initialize || !sm->portEnabled))
00357                 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH);
00358         else if ((sm->portControl == ForceUnauthorized) &&
00359                  (sm->sPortMode != sm->portControl) &&
00360                  !(sm->initialize || !sm->portEnabled))
00361                 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH);
00362         else switch (sm->SUPP_PAE_state) {
00363         case SUPP_PAE_UNKNOWN:
00364                 break;
00365         case SUPP_PAE_LOGOFF:
00366                 if (!sm->userLogoff)
00367                         SM_ENTER(SUPP_PAE, DISCONNECTED);
00368                 break;
00369         case SUPP_PAE_DISCONNECTED:
00370                 SM_ENTER(SUPP_PAE, CONNECTING);
00371                 break;
00372         case SUPP_PAE_CONNECTING:
00373                 if (sm->startWhen == 0 && sm->startCount < sm->maxStart)
00374                         SM_ENTER(SUPP_PAE, CONNECTING);
00375                 else if (sm->startWhen == 0 &&
00376                          sm->startCount >= sm->maxStart &&
00377                          sm->portValid)
00378                         SM_ENTER(SUPP_PAE, AUTHENTICATED);
00379                 else if (sm->eapSuccess || sm->eapFail)
00380                         SM_ENTER(SUPP_PAE, AUTHENTICATING);
00381                 else if (sm->eapolEap)
00382                         SM_ENTER(SUPP_PAE, RESTART);
00383                 else if (sm->startWhen == 0 &&
00384                          sm->startCount >= sm->maxStart &&
00385                          !sm->portValid)
00386                         SM_ENTER(SUPP_PAE, HELD);
00387                 break;
00388         case SUPP_PAE_AUTHENTICATING:
00389                 if (sm->eapSuccess && !sm->portValid &&
00390                     sm->conf.accept_802_1x_keys &&
00391                     sm->conf.required_keys == 0) {
00392                         wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for "
00393                                    "plaintext connection; no EAPOL-Key frames "
00394                                    "required");
00395                         sm->portValid = TRUE;
00396                         if (sm->ctx->eapol_done_cb)
00397                                 sm->ctx->eapol_done_cb(sm->ctx->ctx);
00398                 }
00399                 if (sm->eapSuccess && sm->portValid)
00400                         SM_ENTER(SUPP_PAE, AUTHENTICATED);
00401                 else if (sm->eapFail || (sm->keyDone && !sm->portValid))
00402                         SM_ENTER(SUPP_PAE, HELD);
00403                 else if (sm->suppTimeout)
00404                         SM_ENTER(SUPP_PAE, CONNECTING);
00405                 break;
00406         case SUPP_PAE_HELD:
00407                 if (sm->heldWhile == 0)
00408                         SM_ENTER(SUPP_PAE, CONNECTING);
00409                 else if (sm->eapolEap)
00410                         SM_ENTER(SUPP_PAE, RESTART);
00411                 break;
00412         case SUPP_PAE_AUTHENTICATED:
00413                 if (sm->eapolEap && sm->portValid)
00414                         SM_ENTER(SUPP_PAE, RESTART);
00415                 else if (!sm->portValid)
00416                         SM_ENTER(SUPP_PAE, DISCONNECTED);
00417                 break;
00418         case SUPP_PAE_RESTART:
00419                 if (!sm->eapRestart)
00420                         SM_ENTER(SUPP_PAE, AUTHENTICATING);
00421                 break;
00422         case SUPP_PAE_S_FORCE_AUTH:
00423                 break;
00424         case SUPP_PAE_S_FORCE_UNAUTH:
00425                 break;
00426         }
00427 }
00428 
00429 
00430 SM_STATE(KEY_RX, NO_KEY_RECEIVE)
00431 {
00432         SM_ENTRY(KEY_RX, NO_KEY_RECEIVE);
00433 }
00434 
00435 
00436 SM_STATE(KEY_RX, KEY_RECEIVE)
00437 {
00438         SM_ENTRY(KEY_RX, KEY_RECEIVE);
00439         eapol_sm_processKey(sm);
00440         sm->rxKey = FALSE;
00441 }
00442 
00443 
00444 SM_STEP(KEY_RX)
00445 {
00446         if (sm->initialize || !sm->portEnabled)
00447                 SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
00448         switch (sm->KEY_RX_state) {
00449         case KEY_RX_UNKNOWN:
00450                 break;
00451         case KEY_RX_NO_KEY_RECEIVE:
00452                 if (sm->rxKey)
00453                         SM_ENTER(KEY_RX, KEY_RECEIVE);
00454                 break;
00455         case KEY_RX_KEY_RECEIVE:
00456                 if (sm->rxKey)
00457                         SM_ENTER(KEY_RX, KEY_RECEIVE);
00458                 break;
00459         }
00460 }
00461 
00462 
00463 SM_STATE(SUPP_BE, REQUEST)
00464 {
00465         SM_ENTRY(SUPP_BE, REQUEST);
00466         sm->authWhile = 0;
00467         sm->eapReq = TRUE;
00468         eapol_sm_getSuppRsp(sm);
00469 }
00470 
00471 
00472 SM_STATE(SUPP_BE, RESPONSE)
00473 {
00474         SM_ENTRY(SUPP_BE, RESPONSE);
00475         eapol_sm_txSuppRsp(sm);
00476         sm->eapResp = FALSE;
00477 }
00478 
00479 
00480 SM_STATE(SUPP_BE, SUCCESS)
00481 {
00482         SM_ENTRY(SUPP_BE, SUCCESS);
00483         sm->keyRun = TRUE;
00484         sm->suppSuccess = TRUE;
00485 
00486         if (eap_key_available(sm->eap)) {
00487                 /* New key received - clear IEEE 802.1X EAPOL-Key replay
00488                  * counter */
00489                 sm->replay_counter_valid = FALSE;
00490         }
00491 }
00492 
00493 
00494 SM_STATE(SUPP_BE, FAIL)
00495 {
00496         SM_ENTRY(SUPP_BE, FAIL);
00497         sm->suppFail = TRUE;
00498 }
00499 
00500 
00501 SM_STATE(SUPP_BE, TIMEOUT)
00502 {
00503         SM_ENTRY(SUPP_BE, TIMEOUT);
00504         sm->suppTimeout = TRUE;
00505 }
00506 
00507 
00508 SM_STATE(SUPP_BE, IDLE)
00509 {
00510         SM_ENTRY(SUPP_BE, IDLE);
00511         sm->suppStart = FALSE;
00512         sm->initial_req = TRUE;
00513 }
00514 
00515 
00516 SM_STATE(SUPP_BE, INITIALIZE)
00517 {
00518         SM_ENTRY(SUPP_BE, INITIALIZE);
00519         eapol_sm_abortSupp(sm);
00520         sm->suppAbort = FALSE;
00521 }
00522 
00523 
00524 SM_STATE(SUPP_BE, RECEIVE)
00525 {
00526         SM_ENTRY(SUPP_BE, RECEIVE);
00527         sm->authWhile = sm->authPeriod;
00528         sm->eapolEap = FALSE;
00529         sm->eapNoResp = FALSE;
00530         sm->initial_req = FALSE;
00531 }
00532 
00533 
00534 SM_STEP(SUPP_BE)
00535 {
00536         if (sm->initialize || sm->suppAbort)
00537                 SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE);
00538         else switch (sm->SUPP_BE_state) {
00539         case SUPP_BE_UNKNOWN:
00540                 break;
00541         case SUPP_BE_REQUEST:
00542                 if (sm->eapResp && sm->eapNoResp) {
00543                         wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both "
00544                                    "eapResp and eapNoResp set?!");
00545                 }
00546                 if (sm->eapResp)
00547                         SM_ENTER(SUPP_BE, RESPONSE);
00548                 else if (sm->eapNoResp)
00549                         SM_ENTER(SUPP_BE, RECEIVE);
00550                 break;
00551         case SUPP_BE_RESPONSE:
00552                 SM_ENTER(SUPP_BE, RECEIVE);
00553                 break;
00554         case SUPP_BE_SUCCESS:
00555                 SM_ENTER(SUPP_BE, IDLE);
00556                 break;
00557         case SUPP_BE_FAIL:
00558                 SM_ENTER(SUPP_BE, IDLE);
00559                 break;
00560         case SUPP_BE_TIMEOUT:
00561                 SM_ENTER(SUPP_BE, IDLE);
00562                 break;
00563         case SUPP_BE_IDLE:
00564                 if (sm->eapFail && sm->suppStart)
00565                         SM_ENTER(SUPP_BE, FAIL);
00566                 else if (sm->eapolEap && sm->suppStart)
00567                         SM_ENTER(SUPP_BE, REQUEST);
00568                 else if (sm->eapSuccess && sm->suppStart)
00569                         SM_ENTER(SUPP_BE, SUCCESS);
00570                 break;
00571         case SUPP_BE_INITIALIZE:
00572                 SM_ENTER(SUPP_BE, IDLE);
00573                 break;
00574         case SUPP_BE_RECEIVE:
00575                 if (sm->eapolEap)
00576                         SM_ENTER(SUPP_BE, REQUEST);
00577                 else if (sm->eapFail)
00578                         SM_ENTER(SUPP_BE, FAIL);
00579                 else if (sm->authWhile == 0)
00580                         SM_ENTER(SUPP_BE, TIMEOUT);
00581                 else if (sm->eapSuccess)
00582                         SM_ENTER(SUPP_BE, SUCCESS);
00583                 break;
00584         }
00585 }
00586 
00587 
00588 static void eapol_sm_txLogoff(struct eapol_sm *sm)
00589 {
00590         wpa_printf(MSG_DEBUG, "EAPOL: txLogoff");
00591         sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
00592                             IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0);
00593         sm->dot1xSuppEapolLogoffFramesTx++;
00594         sm->dot1xSuppEapolFramesTx++;
00595 }
00596 
00597 
00598 static void eapol_sm_txStart(struct eapol_sm *sm)
00599 {
00600         wpa_printf(MSG_DEBUG, "EAPOL: txStart");
00601         sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
00602                             IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0);
00603         sm->dot1xSuppEapolStartFramesTx++;
00604         sm->dot1xSuppEapolFramesTx++;
00605 }
00606 
00607 
00608 #define IEEE8021X_ENCR_KEY_LEN 32
00609 #define IEEE8021X_SIGN_KEY_LEN 32
00610 
00611 struct eap_key_data {
00612         u8 encr_key[IEEE8021X_ENCR_KEY_LEN];
00613         u8 sign_key[IEEE8021X_SIGN_KEY_LEN];
00614 };
00615 
00616 
00617 static void eapol_sm_processKey(struct eapol_sm *sm)
00618 {
00619         struct ieee802_1x_hdr *hdr;
00620         struct ieee802_1x_eapol_key *key;
00621         struct eap_key_data keydata;
00622         u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
00623         u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
00624         int key_len, res, sign_key_len, encr_key_len;
00625         u16 rx_key_length;
00626 
00627         wpa_printf(MSG_DEBUG, "EAPOL: processKey");
00628         if (sm->last_rx_key == NULL)
00629                 return;
00630 
00631         if (!sm->conf.accept_802_1x_keys) {
00632                 wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key"
00633                            " even though this was not accepted - "
00634                            "ignoring this packet");
00635                 return;
00636         }
00637 
00638         hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
00639         key = (struct ieee802_1x_eapol_key *) (hdr + 1);
00640         if (sizeof(*hdr) + be_to_host16(hdr->length) > sm->last_rx_key_len) {
00641                 wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
00642                 return;
00643         }
00644         rx_key_length = WPA_GET_BE16(key->key_length);
00645         wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
00646                    "EAPOL-Key: type=%d key_length=%d key_index=0x%x",
00647                    hdr->version, hdr->type, be_to_host16(hdr->length),
00648                    key->type, rx_key_length, key->key_index);
00649 
00650         eapol_sm_notify_lower_layer_success(sm);
00651         sign_key_len = IEEE8021X_SIGN_KEY_LEN;
00652         encr_key_len = IEEE8021X_ENCR_KEY_LEN;
00653         res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata));
00654         if (res < 0) {
00655                 wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for "
00656                            "decrypting EAPOL-Key keys");
00657                 return;
00658         }
00659         if (res == 16) {
00660                 /* LEAP derives only 16 bytes of keying material. */
00661                 res = eapol_sm_get_key(sm, (u8 *) &keydata, 16);
00662                 if (res) {
00663                         wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP "
00664                                    "master key for decrypting EAPOL-Key keys");
00665                         return;
00666                 }
00667                 sign_key_len = 16;
00668                 encr_key_len = 16;
00669                 memcpy(keydata.sign_key, keydata.encr_key, 16);
00670         } else if (res) {
00671                 wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key "
00672                            "data for decrypting EAPOL-Key keys (res=%d)", res);
00673                 return;
00674         }
00675 
00676         /* The key replay_counter must increase when same master key */
00677         if (sm->replay_counter_valid &&
00678             memcmp(sm->last_replay_counter, key->replay_counter,
00679                    IEEE8021X_REPLAY_COUNTER_LEN) >= 0) {
00680                 wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did "
00681                            "not increase - ignoring key");
00682                 wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter",
00683                             sm->last_replay_counter,
00684                             IEEE8021X_REPLAY_COUNTER_LEN);
00685                 wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter",
00686                             key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN);
00687                 return;
00688         }
00689 
00690         /* Verify key signature (HMAC-MD5) */
00691         memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN);
00692         memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN);
00693         hmac_md5(keydata.sign_key, sign_key_len,
00694                  sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
00695                  key->key_signature);
00696         if (memcmp(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN)
00697             != 0) {
00698                 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
00699                            "EAPOL-Key packet");
00700                 memcpy(key->key_signature, orig_key_sign,
00701                        IEEE8021X_KEY_SIGN_LEN);
00702                 return;
00703         }
00704         wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
00705 
00706         key_len = be_to_host16(hdr->length) - sizeof(*key);
00707         if (key_len > 32 || rx_key_length > 32) {
00708                 wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
00709                            key_len ? key_len : rx_key_length);
00710                 return;
00711         }
00712         if (key_len == rx_key_length) {
00713                 memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
00714                 memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
00715                        encr_key_len);
00716                 memcpy(datakey, key + 1, key_len);
00717                 rc4(datakey, key_len, ekey,
00718                     IEEE8021X_KEY_IV_LEN + encr_key_len);
00719                 wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
00720                                 datakey, key_len);
00721         } else if (key_len == 0) {
00722                 /*
00723                  * IEEE 802.1X-2004 specifies that least significant Key Length
00724                  * octets from MS-MPPE-Send-Key are used as the key if the key
00725                  * data is not present. This seems to be meaning the beginning
00726                  * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
00727                  * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
00728                  * Anyway, taking the beginning of the keying material from EAP
00729                  * seems to interoperate with Authenticators.
00730                  */
00731                 key_len = rx_key_length;
00732                 memcpy(datakey, keydata.encr_key, key_len);
00733                 wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying "
00734                                 "material data encryption key",
00735                                 datakey, key_len);
00736         } else {
00737                 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
00738                            "(key_length=%d)", key_len, rx_key_length);
00739                 return;
00740         }
00741 
00742         sm->replay_counter_valid = TRUE;
00743         memcpy(sm->last_replay_counter, key->replay_counter,
00744                IEEE8021X_REPLAY_COUNTER_LEN);
00745 
00746         wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
00747                    "len %d",
00748                    key->key_index & IEEE8021X_KEY_INDEX_FLAG ?
00749                    "unicast" : "broadcast",
00750                    key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len);
00751 
00752         if (sm->ctx->set_wep_key &&
00753             sm->ctx->set_wep_key(sm->ctx->ctx,
00754                                  key->key_index & IEEE8021X_KEY_INDEX_FLAG,
00755                                  key->key_index & IEEE8021X_KEY_INDEX_MASK,
00756                                  datakey, key_len) < 0) {
00757                 wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
00758                            " driver.");
00759         } else {
00760                 if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
00761                         sm->unicast_key_received = TRUE;
00762                 else
00763                         sm->broadcast_key_received = TRUE;
00764 
00765                 if ((sm->unicast_key_received ||
00766                      !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) &&
00767                     (sm->broadcast_key_received ||
00768                      !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST)))
00769                 {
00770                         wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
00771                                    "frames received");
00772                         sm->portValid = TRUE;
00773                         if (sm->ctx->eapol_done_cb)
00774                                 sm->ctx->eapol_done_cb(sm->ctx->ctx);
00775                 }
00776         }
00777 }
00778 
00779 
00780 static void eapol_sm_getSuppRsp(struct eapol_sm *sm)
00781 {
00782         wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp");
00783         /* EAP layer processing; no special code is needed, since Supplicant
00784          * Backend state machine is waiting for eapNoResp or eapResp to be set
00785          * and these are only set in the EAP state machine when the processing
00786          * has finished. */
00787 }
00788 
00789 
00790 static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
00791 {
00792         u8 *resp;
00793         size_t resp_len;
00794 
00795         wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
00796         resp = eap_get_eapRespData(sm->eap, &resp_len);
00797         if (resp == NULL) {
00798                 wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
00799                            "not available");
00800                 return;
00801         }
00802 
00803         /* Send EAP-Packet from the EAP layer to the Authenticator */
00804         sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
00805                             IEEE802_1X_TYPE_EAP_PACKET, resp, resp_len);
00806 
00807         /* eapRespData is not used anymore, so free it here */
00808         free(resp);
00809 
00810         if (sm->initial_req)
00811                 sm->dot1xSuppEapolReqIdFramesRx++;
00812         else
00813                 sm->dot1xSuppEapolReqFramesRx++;
00814         sm->dot1xSuppEapolRespFramesTx++;
00815         sm->dot1xSuppEapolFramesTx++;
00816 }
00817 
00818 
00819 static void eapol_sm_abortSupp(struct eapol_sm *sm)
00820 {
00821         /* release system resources that may have been allocated for the
00822          * authentication session */
00823         free(sm->last_rx_key);
00824         sm->last_rx_key = NULL;
00825         free(sm->eapReqData);
00826         sm->eapReqData = NULL;
00827         eap_sm_abort(sm->eap);
00828 }
00829 
00830 
00831 static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
00832 {
00833         eapol_sm_step(timeout_ctx);
00834 }
00835 
00836 
00846 void eapol_sm_step(struct eapol_sm *sm)
00847 {
00848         int i;
00849 
00850         /* In theory, it should be ok to run this in loop until !changed.
00851          * However, it is better to use a limit on number of iterations to
00852          * allow events (e.g., SIGTERM) to stop the program cleanly if the
00853          * state machine were to generate a busy loop. */
00854         for (i = 0; i < 100; i++) {
00855                 sm->changed = FALSE;
00856                 SM_STEP_RUN(SUPP_PAE);
00857                 SM_STEP_RUN(KEY_RX);
00858                 SM_STEP_RUN(SUPP_BE);
00859                 if (eap_sm_step(sm->eap))
00860                         sm->changed = TRUE;
00861         }
00862 
00863         if (sm->changed) {
00864                 /* restart EAPOL state machine step from timeout call in order
00865                  * to allow other events to be processed. */
00866                 eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
00867                 eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm);
00868         }
00869 
00870         if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
00871                 int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0;
00872                 sm->cb_status = EAPOL_CB_IN_PROGRESS;
00873                 sm->ctx->cb(sm, success, sm->ctx->cb_ctx);
00874         }
00875 }
00876 
00877 
00878 static const char *eapol_supp_pae_state(int state)
00879 {
00880         switch (state) {
00881         case SUPP_PAE_LOGOFF:
00882                 return "LOGOFF";
00883         case SUPP_PAE_DISCONNECTED:
00884                 return "DISCONNECTED";
00885         case SUPP_PAE_CONNECTING:
00886                 return "CONNECTING";
00887         case SUPP_PAE_AUTHENTICATING:
00888                 return "AUTHENTICATING";
00889         case SUPP_PAE_HELD:
00890                 return "HELD";
00891         case SUPP_PAE_AUTHENTICATED:
00892                 return "AUTHENTICATED";
00893         case SUPP_PAE_RESTART:
00894                 return "RESTART";
00895         default:
00896                 return "UNKNOWN";
00897         }
00898 }
00899 
00900 
00901 static const char *eapol_supp_be_state(int state)
00902 {
00903         switch (state) {
00904         case SUPP_BE_REQUEST:
00905                 return "REQUEST";
00906         case SUPP_BE_RESPONSE:
00907                 return "RESPONSE";
00908         case SUPP_BE_SUCCESS:
00909                 return "SUCCESS";
00910         case SUPP_BE_FAIL:
00911                 return "FAIL";
00912         case SUPP_BE_TIMEOUT:
00913                 return "TIMEOUT";
00914         case SUPP_BE_IDLE:
00915                 return "IDLE";
00916         case SUPP_BE_INITIALIZE:
00917                 return "INITIALIZE";
00918         case SUPP_BE_RECEIVE:
00919                 return "RECEIVE";
00920         default:
00921                 return "UNKNOWN";
00922         }
00923 }
00924 
00925 
00926 static const char * eapol_port_status(PortStatus status)
00927 {
00928         if (status == Authorized)
00929                 return "Authorized";
00930         else
00931                 return "Unauthorized";
00932 }
00933 
00934 
00935 static const char * eapol_port_control(PortControl ctrl)
00936 {
00937         switch (ctrl) {
00938         case Auto:
00939                 return "Auto";
00940         case ForceUnauthorized:
00941                 return "ForceUnauthorized";
00942         case ForceAuthorized:
00943                 return "ForceAuthorized";
00944         default:
00945                 return "Unknown";
00946         }
00947 }
00948 
00949 
00962 void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
00963                         int startPeriod, int maxStart)
00964 {
00965         if (sm == NULL)
00966                 return;
00967         if (heldPeriod >= 0)
00968                 sm->heldPeriod = heldPeriod;
00969         if (authPeriod >= 0)
00970                 sm->authPeriod = authPeriod;
00971         if (startPeriod >= 0)
00972                 sm->startPeriod = startPeriod;
00973         if (maxStart >= 0)
00974                 sm->maxStart = maxStart;
00975 }
00976 
00977 
00992 int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
00993                         int verbose)
00994 {
00995         int len;
00996         if (sm == NULL)
00997                 return 0;
00998 
00999         len = snprintf(buf, buflen,
01000                        "Supplicant PAE state=%s\n"
01001                        "suppPortStatus=%s\n",
01002                        eapol_supp_pae_state(sm->SUPP_PAE_state),
01003                        eapol_port_status(sm->suppPortStatus));
01004 
01005         if (verbose) {
01006                 len += snprintf(buf + len, buflen - len,
01007                                 "heldPeriod=%u\n"
01008                                 "authPeriod=%u\n"
01009                                 "startPeriod=%u\n"
01010                                 "maxStart=%u\n"
01011                                 "portControl=%s\n"
01012                                 "Supplicant Backend state=%s\n",
01013                                 sm->heldPeriod,
01014                                 sm->authPeriod,
01015                                 sm->startPeriod,
01016                                 sm->maxStart,
01017                                 eapol_port_control(sm->portControl),
01018                                 eapol_supp_be_state(sm->SUPP_BE_state));
01019         }
01020 
01021         len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
01022 
01023         return len;
01024 }
01025 
01026 
01040 int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
01041 {
01042         int len;
01043         if (sm == NULL)
01044                 return 0;
01045         len = snprintf(buf, buflen,
01046                        "dot1xSuppPaeState=%d\n"
01047                        "dot1xSuppHeldPeriod=%u\n"
01048                        "dot1xSuppAuthPeriod=%u\n"
01049                        "dot1xSuppStartPeriod=%u\n"
01050                        "dot1xSuppMaxStart=%u\n"
01051                        "dot1xSuppSuppControlledPortStatus=%s\n"
01052                        "dot1xSuppBackendPaeState=%d\n"
01053                        "dot1xSuppEapolFramesRx=%u\n"
01054                        "dot1xSuppEapolFramesTx=%u\n"
01055                        "dot1xSuppEapolStartFramesTx=%u\n"
01056                        "dot1xSuppEapolLogoffFramesTx=%u\n"
01057                        "dot1xSuppEapolRespFramesTx=%u\n"
01058                        "dot1xSuppEapolReqIdFramesRx=%u\n"
01059                        "dot1xSuppEapolReqFramesRx=%u\n"
01060                        "dot1xSuppInvalidEapolFramesRx=%u\n"
01061                        "dot1xSuppEapLengthErrorFramesRx=%u\n"
01062                        "dot1xSuppLastEapolFrameVersion=%u\n"
01063                        "dot1xSuppLastEapolFrameSource=" MACSTR "\n",
01064                        sm->SUPP_PAE_state,
01065                        sm->heldPeriod,
01066                        sm->authPeriod,
01067                        sm->startPeriod,
01068                        sm->maxStart,
01069                        sm->suppPortStatus == Authorized ?
01070                        "Authorized" : "Unauthorized",
01071                        sm->SUPP_BE_state,
01072                        sm->dot1xSuppEapolFramesRx,
01073                        sm->dot1xSuppEapolFramesTx,
01074                        sm->dot1xSuppEapolStartFramesTx,
01075                        sm->dot1xSuppEapolLogoffFramesTx,
01076                        sm->dot1xSuppEapolRespFramesTx,
01077                        sm->dot1xSuppEapolReqIdFramesRx,
01078                        sm->dot1xSuppEapolReqFramesRx,
01079                        sm->dot1xSuppInvalidEapolFramesRx,
01080                        sm->dot1xSuppEapLengthErrorFramesRx,
01081                        sm->dot1xSuppLastEapolFrameVersion,
01082                        MAC2STR(sm->dot1xSuppLastEapolFrameSource));
01083         return len;
01084 }
01085 
01086 
01097 int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
01098                       size_t len)
01099 {
01100         const struct ieee802_1x_hdr *hdr;
01101         const struct ieee802_1x_eapol_key *key;
01102         int plen, data_len;
01103         int res = 1;
01104 
01105         if (sm == NULL)
01106                 return 0;
01107         sm->dot1xSuppEapolFramesRx++;
01108         if (len < sizeof(*hdr)) {
01109                 sm->dot1xSuppInvalidEapolFramesRx++;
01110                 return 0;
01111         }
01112         hdr = (const struct ieee802_1x_hdr *) buf;
01113         sm->dot1xSuppLastEapolFrameVersion = hdr->version;
01114         memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
01115         if (hdr->version < EAPOL_VERSION) {
01116                 /* TODO: backwards compatibility */
01117         }
01118         plen = be_to_host16(hdr->length);
01119         if (plen > len - sizeof(*hdr)) {
01120                 sm->dot1xSuppEapLengthErrorFramesRx++;
01121                 return 0;
01122         }
01123         data_len = plen + sizeof(*hdr);
01124 
01125         switch (hdr->type) {
01126         case IEEE802_1X_TYPE_EAP_PACKET:
01127                 if (sm->cached_pmk) {
01128                         /* Trying to use PMKSA caching, but Authenticator did
01129                          * not seem to have a matching entry. Need to restart
01130                          * EAPOL state machines.
01131                          */
01132                         eapol_sm_abort_cached(sm);
01133                 }
01134                 free(sm->eapReqData);
01135                 sm->eapReqDataLen = plen;
01136                 sm->eapReqData = malloc(sm->eapReqDataLen);
01137                 if (sm->eapReqData) {
01138                         wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
01139                                    "frame");
01140                         memcpy(sm->eapReqData, (u8 *) (hdr + 1),
01141                                sm->eapReqDataLen);
01142                         sm->eapolEap = TRUE;
01143                         eapol_sm_step(sm);
01144                 }
01145                 break;
01146         case IEEE802_1X_TYPE_EAPOL_KEY:
01147                 if (plen < sizeof(*key)) {
01148                         wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key "
01149                                    "frame received");
01150                         break;
01151                 }
01152                 key = (const struct ieee802_1x_eapol_key *) (hdr + 1);
01153                 if (key->type == EAPOL_KEY_TYPE_WPA ||
01154                     key->type == EAPOL_KEY_TYPE_RSN) {
01155                         /* WPA Supplicant takes care of this frame. */
01156                         wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
01157                                    "frame in EAPOL state machines");
01158                         res = 0;
01159                         break;
01160                 }
01161                 if (key->type != EAPOL_KEY_TYPE_RC4) {
01162                         wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown "
01163                                    "EAPOL-Key type %d", key->type);
01164                         break;
01165                 }
01166                 free(sm->last_rx_key);
01167                 sm->last_rx_key = malloc(data_len);
01168                 if (sm->last_rx_key) {
01169                         wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key "
01170                                    "frame");
01171                         memcpy(sm->last_rx_key, buf, data_len);
01172                         sm->last_rx_key_len = data_len;
01173                         sm->rxKey = TRUE;
01174                         eapol_sm_step(sm);
01175                 }
01176                 break;
01177         default:
01178                 wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
01179                            hdr->type);
01180                 sm->dot1xSuppInvalidEapolFramesRx++;
01181                 break;
01182         }
01183 
01184         return res;
01185 }
01186 
01187 
01196 void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
01197 {
01198         if (sm)
01199                 sm->dot1xSuppEapolFramesTx++;
01200 }
01201 
01202 
01211 void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
01212 {
01213         if (sm == NULL)
01214                 return;
01215         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
01216                    "portEnabled=%d", enabled);
01217         sm->portEnabled = enabled;
01218         eapol_sm_step(sm);
01219 }
01220 
01221 
01230 void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
01231 {
01232         if (sm == NULL)
01233                 return;
01234         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
01235                    "portValid=%d", valid);
01236         sm->portValid = valid;
01237         eapol_sm_step(sm);
01238 }
01239 
01240 
01253 void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
01254 {
01255         if (sm == NULL)
01256                 return;
01257         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
01258                    "EAP success=%d", success);
01259         sm->eapSuccess = success;
01260         sm->altAccept = success;
01261         if (success)
01262                 eap_notify_success(sm->eap);
01263         eapol_sm_step(sm);
01264 }
01265 
01266 
01276 void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
01277 {
01278         if (sm == NULL)
01279                 return;
01280         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
01281                    "EAP fail=%d", fail);
01282         sm->eapFail = fail;
01283         sm->altReject = fail;
01284         eapol_sm_step(sm);
01285 }
01286 
01287 
01301 void eapol_sm_notify_config(struct eapol_sm *sm, struct wpa_ssid *config,
01302                             const struct eapol_config *conf)
01303 {
01304         if (sm == NULL)
01305                 return;
01306 
01307         sm->config = config;
01308 
01309         if (conf == NULL)
01310                 return;
01311 
01312         sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys;
01313         sm->conf.required_keys = conf->required_keys;
01314         sm->conf.fast_reauth = conf->fast_reauth;
01315         if (sm->eap) {
01316                 eap_set_fast_reauth(sm->eap, conf->fast_reauth);
01317                 eap_set_workaround(sm->eap, conf->workaround);
01318                 eap_set_force_disabled(sm->eap, conf->eap_disabled);
01319         }
01320 }
01321 
01322 
01335 int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
01336 {
01337         const u8 *eap_key;
01338         size_t eap_len;
01339 
01340         if (sm == NULL || !eap_key_available(sm->eap))
01341                 return -1;
01342         eap_key = eap_get_eapKeyData(sm->eap, &eap_len);
01343         if (eap_key == NULL)
01344                 return -1;
01345         if (len > eap_len)
01346                 return eap_len;
01347         memcpy(key, eap_key, len);
01348         return 0;
01349 }
01350 
01351 
01360 void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
01361 {
01362         if (sm) {
01363                 sm->userLogoff = logoff;
01364                 eapol_sm_step(sm);
01365         }
01366 }
01367 
01368 
01377 void eapol_sm_notify_cached(struct eapol_sm *sm)
01378 {
01379         if (sm == NULL)
01380                 return;
01381         sm->SUPP_PAE_state = SUPP_PAE_AUTHENTICATED;
01382         sm->suppPortStatus = Authorized;
01383         eap_notify_success(sm->eap);
01384 }
01385 
01386 
01395 void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt)
01396 {
01397         if (sm == NULL)
01398                 return;
01399         if (attempt) {
01400                 wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
01401                 sm->cached_pmk = TRUE;
01402         } else {
01403                 wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA");
01404                 sm->cached_pmk = FALSE;
01405         }
01406 }
01407 
01408 
01409 static void eapol_sm_abort_cached(struct eapol_sm *sm)
01410 {
01411         wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, "
01412                    "doing full EAP authentication");
01413         if (sm == NULL)
01414                 return;
01415         sm->cached_pmk = FALSE;
01416         sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
01417         sm->suppPortStatus = Unauthorized;
01418 
01419         /* Make sure we do not start sending EAPOL-Start frames first, but
01420          * instead move to RESTART state to start EAPOL authentication. */
01421         sm->startWhen = 3;
01422 
01423         if (sm->ctx->aborted_cached)
01424                 sm->ctx->aborted_cached(sm->ctx->ctx);
01425 }
01426 
01427 
01437 void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
01438 {
01439         if (sm) {
01440                 sm->ctx->scard_ctx = ctx;
01441                 eap_register_scard_ctx(sm->eap, ctx);
01442         }
01443 }
01444 
01445 
01454 void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
01455 {
01456         if (sm == NULL)
01457                 return;
01458         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
01459                    "portControl=%s", eapol_port_control(portControl));
01460         sm->portControl = portControl;
01461         eapol_sm_step(sm);
01462 }
01463 
01464 
01473 void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
01474 {
01475         if (sm == NULL)
01476                 return;
01477         eap_sm_notify_ctrl_attached(sm->eap);
01478 }
01479 
01480 
01489 void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
01490 {
01491         if (sm == NULL)
01492                 return;
01493         if (sm->eapReqData && !sm->eapReq) {
01494                 wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
01495                            "input) notification - retrying pending EAP "
01496                            "Request");
01497                 sm->eapolEap = TRUE;
01498                 sm->eapReq = TRUE;
01499                 eapol_sm_step(sm);
01500         }
01501 }
01502 
01503 
01512 void eapol_sm_request_reauth(struct eapol_sm *sm)
01513 {
01514         if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
01515                 return;
01516         eapol_sm_txStart(sm);
01517 }
01518 
01519 
01529 void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm)
01530 {
01531         if (sm == NULL)
01532                 return;
01533         eap_notify_lower_layer_success(sm->eap);
01534 }
01535 
01536 
01537 static struct wpa_ssid * eapol_sm_get_config(void *ctx)
01538 {
01539         struct eapol_sm *sm = ctx;
01540         return sm ? sm->config : NULL;
01541 }
01542 
01543 
01544 static u8 * eapol_sm_get_eapReqData(void *ctx, size_t *len)
01545 {
01546         struct eapol_sm *sm = ctx;
01547         if (sm == NULL || sm->eapReqData == NULL) {
01548                 *len = 0;
01549                 return NULL;
01550         }
01551 
01552         *len = sm->eapReqDataLen;
01553         return sm->eapReqData;
01554 }
01555 
01556 
01557 static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
01558 {
01559         struct eapol_sm *sm = ctx;
01560         if (sm == NULL)
01561                 return FALSE;
01562         switch (variable) {
01563         case EAPOL_eapSuccess:
01564                 return sm->eapSuccess;
01565         case EAPOL_eapRestart:
01566                 return sm->eapRestart;
01567         case EAPOL_eapFail:
01568                 return sm->eapFail;
01569         case EAPOL_eapResp:
01570                 return sm->eapResp;
01571         case EAPOL_eapNoResp:
01572                 return sm->eapNoResp;
01573         case EAPOL_eapReq:
01574                 return sm->eapReq;
01575         case EAPOL_portEnabled:
01576                 return sm->portEnabled;
01577         case EAPOL_altAccept:
01578                 return sm->altAccept;
01579         case EAPOL_altReject:
01580                 return sm->altReject;
01581         }
01582         return FALSE;
01583 }
01584 
01585 
01586 static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
01587                               Boolean value)
01588 {
01589         struct eapol_sm *sm = ctx;
01590         if (sm == NULL)
01591                 return;
01592         switch (variable) {
01593         case EAPOL_eapSuccess:
01594                 sm->eapSuccess = value;
01595                 break;
01596         case EAPOL_eapRestart:
01597                 sm->eapRestart = value;
01598                 break;
01599         case EAPOL_eapFail:
01600                 sm->eapFail = value;
01601                 break;
01602         case EAPOL_eapResp:
01603                 sm->eapResp = value;
01604                 break;
01605         case EAPOL_eapNoResp:
01606                 sm->eapNoResp = value;
01607                 break;
01608         case EAPOL_eapReq:
01609                 sm->eapReq = value;
01610                 break;
01611         case EAPOL_portEnabled:
01612                 sm->portEnabled = value;
01613                 break;
01614         case EAPOL_altAccept:
01615                 sm->altAccept = value;
01616                 break;
01617         case EAPOL_altReject:
01618                 sm->altReject = value;
01619                 break;
01620         }
01621 }
01622 
01623 
01624 static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable)
01625 {
01626         struct eapol_sm *sm = ctx;
01627         if (sm == NULL)
01628                 return 0;
01629         switch (variable) {
01630         case EAPOL_idleWhile:
01631                 return sm->idleWhile;
01632         }
01633         return 0;
01634 }
01635 
01636 
01637 static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
01638                              unsigned int value)
01639 {
01640         struct eapol_sm *sm = ctx;
01641         if (sm == NULL)
01642                 return;
01643         switch (variable) {
01644         case EAPOL_idleWhile:
01645                 sm->idleWhile = value;
01646                 break;
01647         }
01648 }
01649 
01650 
01651 static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
01652 {
01653         struct eapol_sm *sm = ctx;
01654         if (sm && sm->ctx && sm->ctx->set_config_blob)
01655                 sm->ctx->set_config_blob(sm->ctx->ctx, blob);
01656 }
01657 
01658 
01659 static const struct wpa_config_blob *
01660 eapol_sm_get_config_blob(void *ctx, const char *name)
01661 {
01662         struct eapol_sm *sm = ctx;
01663         if (sm && sm->ctx && sm->ctx->get_config_blob)
01664                 return sm->ctx->get_config_blob(sm->ctx->ctx, name);
01665         else
01666                 return NULL;
01667 }
01668 
01669 
01670 static struct eapol_callbacks eapol_cb =
01671 {
01672         .get_config = eapol_sm_get_config,
01673         .get_bool = eapol_sm_get_bool,
01674         .set_bool = eapol_sm_set_bool,
01675         .get_int = eapol_sm_get_int,
01676         .set_int = eapol_sm_set_int,
01677         .get_eapReqData = eapol_sm_get_eapReqData,
01678         .set_config_blob = eapol_sm_set_config_blob,
01679         .get_config_blob = eapol_sm_get_config_blob,
01680 };
01681 
01682 
01692 struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
01693 {
01694         struct eapol_sm *sm;
01695         struct eap_config conf;
01696         sm = malloc(sizeof(*sm));
01697         if (sm == NULL)
01698                 return NULL;
01699         memset(sm, 0, sizeof(*sm));
01700         sm->ctx = ctx;
01701 
01702         sm->portControl = Auto;
01703 
01704         /* Supplicant PAE state machine */
01705         sm->heldPeriod = 60;
01706         sm->startPeriod = 30;
01707         sm->maxStart = 3;
01708 
01709         /* Supplicant Backend state machine */
01710         sm->authPeriod = 30;
01711 
01712         memset(&conf, 0, sizeof(conf));
01713         conf.opensc_engine_path = ctx->opensc_engine_path;
01714         conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
01715         conf.pkcs11_module_path = ctx->pkcs11_module_path;
01716 
01717         sm->eap = eap_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
01718         if (sm->eap == NULL) {
01719                 free(sm);
01720                 return NULL;
01721         }
01722 
01723         /* Initialize EAPOL state machines */
01724         sm->initialize = TRUE;
01725         eapol_sm_step(sm);
01726         sm->initialize = FALSE;
01727         eapol_sm_step(sm);
01728 
01729         eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
01730 
01731         return sm;
01732 }
01733 
01734 
01742 void eapol_sm_deinit(struct eapol_sm *sm)
01743 {
01744         if (sm == NULL)
01745                 return;
01746         eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
01747         eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
01748         eap_sm_deinit(sm->eap);
01749         free(sm->last_rx_key);
01750         free(sm->eapReqData);
01751         free(sm->ctx);
01752         free(sm);
01753 }
01754 

Generated on Sat May 6 21:13:36 2006 for wpa_supplicant by  doxygen 1.4.2