eapol_sm.c

Go to the documentation of this file.
00001 
00016 #include "includes.h"
00017 
00018 #include "common.h"
00019 #include "eapol_sm.h"
00020 #include "eap.h"
00021 #include "eloop.h"
00022 #include "l2_packet.h"
00023 #include "wpa.h"
00024 #include "md5.h"
00025 #include "rc4.h"
00026 #include "state_machine.h"
00027 
00028 #define STATE_MACHINE_DATA struct eapol_sm
00029 #define STATE_MACHINE_DEBUG_PREFIX "EAPOL"
00030 
00031 
00032 /* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
00033 
00038 struct eapol_sm {
00039         /* Timers */
00040         unsigned int authWhile;
00041         unsigned int heldWhile;
00042         unsigned int startWhen;
00043         unsigned int idleWhile; /* for EAP state machine */
00044 
00045         /* Global variables */
00046         Boolean eapFail;
00047         Boolean eapolEap;
00048         Boolean eapSuccess;
00049         Boolean initialize;
00050         Boolean keyDone;
00051         Boolean keyRun;
00052         PortControl portControl;
00053         Boolean portEnabled;
00054         PortStatus suppPortStatus;  /* dot1xSuppControlledPortStatus */
00055         Boolean portValid;
00056         Boolean suppAbort;
00057         Boolean suppFail;
00058         Boolean suppStart;
00059         Boolean suppSuccess;
00060         Boolean suppTimeout;
00061 
00062         /* Supplicant PAE state machine */
00063         enum {
00064                 SUPP_PAE_UNKNOWN = 0,
00065                 SUPP_PAE_DISCONNECTED = 1,
00066                 SUPP_PAE_LOGOFF = 2,
00067                 SUPP_PAE_CONNECTING = 3,
00068                 SUPP_PAE_AUTHENTICATING = 4,
00069                 SUPP_PAE_AUTHENTICATED = 5,
00070                 /* unused(6) */
00071                 SUPP_PAE_HELD = 7,
00072                 SUPP_PAE_RESTART = 8,
00073                 SUPP_PAE_S_FORCE_AUTH = 9,
00074                 SUPP_PAE_S_FORCE_UNAUTH = 10
00075         } SUPP_PAE_state; /* dot1xSuppPaeState */
00076         /* Variables */
00077         Boolean userLogoff;
00078         Boolean logoffSent;
00079         unsigned int startCount;
00080         Boolean eapRestart;
00081         PortControl sPortMode;
00082         /* Constants */
00083         unsigned int heldPeriod; /* dot1xSuppHeldPeriod */
00084         unsigned int startPeriod; /* dot1xSuppStartPeriod */
00085         unsigned int maxStart; /* dot1xSuppMaxStart */
00086 
00087         /* Key Receive state machine */
00088         enum {
00089                 KEY_RX_UNKNOWN = 0,
00090                 KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
00091         } KEY_RX_state;
00092         /* Variables */
00093         Boolean rxKey;
00094 
00095         /* Supplicant Backend state machine */
00096         enum {
00097                 SUPP_BE_UNKNOWN = 0,
00098                 SUPP_BE_INITIALIZE = 1,
00099                 SUPP_BE_IDLE = 2,
00100                 SUPP_BE_REQUEST = 3,
00101                 SUPP_BE_RECEIVE = 4,
00102                 SUPP_BE_RESPONSE = 5,
00103                 SUPP_BE_FAIL = 6,
00104                 SUPP_BE_TIMEOUT = 7, 
00105                 SUPP_BE_SUCCESS = 8
00106         } SUPP_BE_state; /* dot1xSuppBackendPaeState */
00107         /* Variables */
00108         Boolean eapNoResp;
00109         Boolean eapReq;
00110         Boolean eapResp;
00111         /* Constants */
00112         unsigned int authPeriod; /* dot1xSuppAuthPeriod */
00113 
00114         /* Statistics */
00115         unsigned int dot1xSuppEapolFramesRx;
00116         unsigned int dot1xSuppEapolFramesTx;
00117         unsigned int dot1xSuppEapolStartFramesTx;
00118         unsigned int dot1xSuppEapolLogoffFramesTx;
00119         unsigned int dot1xSuppEapolRespFramesTx;
00120         unsigned int dot1xSuppEapolReqIdFramesRx;
00121         unsigned int dot1xSuppEapolReqFramesRx;
00122         unsigned int dot1xSuppInvalidEapolFramesRx;
00123         unsigned int dot1xSuppEapLengthErrorFramesRx;
00124         unsigned int dot1xSuppLastEapolFrameVersion;
00125         unsigned char dot1xSuppLastEapolFrameSource[6];
00126 
00127         /* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
00128         Boolean changed;
00129         struct eap_sm *eap;
00130         struct wpa_ssid *config;
00131         Boolean initial_req;
00132         u8 *last_rx_key;
00133         size_t last_rx_key_len;
00134         u8 *eapReqData; /* for EAP */
00135         size_t eapReqDataLen; /* for EAP */
00136         Boolean altAccept; /* for EAP */
00137         Boolean altReject; /* for EAP */
00138         Boolean replay_counter_valid;
00139         u8 last_replay_counter[16];
00140         struct eapol_config conf;
00141         struct eapol_ctx *ctx;
00142         enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE }
00143                 cb_status;
00144         Boolean cached_pmk;
00145 
00146         Boolean unicast_key_received, broadcast_key_received;
00147 };
00148 
00149 
00150 #define IEEE8021X_REPLAY_COUNTER_LEN 8
00151 #define IEEE8021X_KEY_SIGN_LEN 16
00152 #define IEEE8021X_KEY_IV_LEN 16
00153 
00154 #define IEEE8021X_KEY_INDEX_FLAG 0x80
00155 #define IEEE8021X_KEY_INDEX_MASK 0x03
00156 
00157 #ifdef _MSC_VER
00158 #pragma pack(push, 1)
00159 #endif /* _MSC_VER */
00160 
00161 struct ieee802_1x_eapol_key {
00162         u8 type;
00163         /* Note: key_length is unaligned */
00164         u8 key_length[2];
00165         /* does not repeat within the life of the keying material used to
00166          * encrypt the Key field; 64-bit NTP timestamp MAY be used here */
00167         u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN];
00168         u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */
00169         u8 key_index; /* key flag in the most significant bit:
00170                        * 0 = broadcast (default key),
00171                        * 1 = unicast (key mapping key); key index is in the
00172                        * 7 least significant bits */
00173         /* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as
00174          * the key */
00175         u8 key_signature[IEEE8021X_KEY_SIGN_LEN];
00176 
00177         /* followed by key: if packet body length = 44 + key length, then the
00178          * key field (of key_length bytes) contains the key in encrypted form;
00179          * if packet body length = 44, key field is absent and key_length
00180          * represents the number of least significant octets from
00181          * MS-MPPE-Send-Key attribute to be used as the keying material;
00182          * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
00183 } STRUCT_PACKED;
00184 
00185 #ifdef _MSC_VER
00186 #pragma pack(pop)
00187 #endif /* _MSC_VER */
00188 
00189 
00190 static void eapol_sm_txLogoff(struct eapol_sm *sm);
00191 static void eapol_sm_txStart(struct eapol_sm *sm);
00192 static void eapol_sm_processKey(struct eapol_sm *sm);
00193 static void eapol_sm_getSuppRsp(struct eapol_sm *sm);
00194 static void eapol_sm_txSuppRsp(struct eapol_sm *sm);
00195 static void eapol_sm_abortSupp(struct eapol_sm *sm);
00196 static void eapol_sm_abort_cached(struct eapol_sm *sm);
00197 static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx);
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         eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, sm);
00228         eapol_sm_step(sm);
00229 }
00230 
00231 
00232 SM_STATE(SUPP_PAE, LOGOFF)
00233 {
00234         SM_ENTRY(SUPP_PAE, LOGOFF);
00235         eapol_sm_txLogoff(sm);
00236         sm->logoffSent = TRUE;
00237         sm->suppPortStatus = Unauthorized;
00238 }
00239 
00240 
00241 SM_STATE(SUPP_PAE, DISCONNECTED)
00242 {
00243         SM_ENTRY(SUPP_PAE, DISCONNECTED);
00244         sm->sPortMode = Auto;
00245         sm->startCount = 0;
00246         sm->logoffSent = FALSE;
00247         sm->suppPortStatus = Unauthorized;
00248         sm->suppAbort = TRUE;
00249 
00250         sm->unicast_key_received = FALSE;
00251         sm->broadcast_key_received = FALSE;
00252 }
00253 
00254 
00255 SM_STATE(SUPP_PAE, CONNECTING)
00256 {
00257         int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING;
00258         SM_ENTRY(SUPP_PAE, CONNECTING);
00259         if (send_start) {
00260                 sm->startWhen = sm->startPeriod;
00261                 sm->startCount++;
00262         } else {
00263                 /*
00264                  * Do not send EAPOL-Start immediately since in most cases,
00265                  * Authenticator is going to start authentication immediately
00266                  * after association and an extra EAPOL-Start is just going to
00267                  * delay authentication. Use a short timeout to send the first
00268                  * EAPOL-Start if Authenticator does not start authentication.
00269                  */
00270                 sm->startWhen = 3;
00271         }
00272         sm->eapolEap = FALSE;
00273         if (send_start)
00274                 eapol_sm_txStart(sm);
00275 }
00276 
00277 
00278 SM_STATE(SUPP_PAE, AUTHENTICATING)
00279 {
00280         SM_ENTRY(SUPP_PAE, AUTHENTICATING);
00281         sm->startCount = 0;
00282         sm->suppSuccess = FALSE;
00283         sm->suppFail = FALSE;
00284         sm->suppTimeout = FALSE;
00285         sm->keyRun = FALSE;
00286         sm->keyDone = FALSE;
00287         sm->suppStart = TRUE;
00288 }
00289 
00290 
00291 SM_STATE(SUPP_PAE, HELD)
00292 {
00293         SM_ENTRY(SUPP_PAE, HELD);
00294         sm->heldWhile = sm->heldPeriod;
00295         sm->suppPortStatus = Unauthorized;
00296         sm->cb_status = EAPOL_CB_FAILURE;
00297 }
00298 
00299 
00300 SM_STATE(SUPP_PAE, AUTHENTICATED)
00301 {
00302         SM_ENTRY(SUPP_PAE, AUTHENTICATED);
00303         sm->suppPortStatus = Authorized;
00304         sm->cb_status = EAPOL_CB_SUCCESS;
00305 }
00306 
00307 
00308 SM_STATE(SUPP_PAE, RESTART)
00309 {
00310         SM_ENTRY(SUPP_PAE, RESTART);
00311         sm->eapRestart = TRUE;
00312 }
00313 
00314 
00315 SM_STATE(SUPP_PAE, S_FORCE_AUTH)
00316 {
00317         SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
00318         sm->suppPortStatus = Authorized;
00319         sm->sPortMode = ForceAuthorized;
00320 }
00321 
00322 
00323 SM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
00324 {
00325         SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
00326         sm->suppPortStatus = Unauthorized;
00327         sm->sPortMode = ForceUnauthorized;
00328         eapol_sm_txLogoff(sm);
00329 }
00330 
00331 
00332 SM_STEP(SUPP_PAE)
00333 {
00334         if ((sm->userLogoff && !sm->logoffSent) &&
00335             !(sm->initialize || !sm->portEnabled))
00336                 SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF);
00337         else if (((sm->portControl == Auto) &&
00338                   (sm->sPortMode != sm->portControl)) ||
00339                  sm->initialize || !sm->portEnabled)
00340                 SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED);
00341         else if ((sm->portControl == ForceAuthorized) &&
00342                  (sm->sPortMode != sm->portControl) &&
00343                  !(sm->initialize || !sm->portEnabled))
00344                 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH);
00345         else if ((sm->portControl == ForceUnauthorized) &&
00346                  (sm->sPortMode != sm->portControl) &&
00347                  !(sm->initialize || !sm->portEnabled))
00348                 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH);
00349         else switch (sm->SUPP_PAE_state) {
00350         case SUPP_PAE_UNKNOWN:
00351                 break;
00352         case SUPP_PAE_LOGOFF:
00353                 if (!sm->userLogoff)
00354                         SM_ENTER(SUPP_PAE, DISCONNECTED);
00355                 break;
00356         case SUPP_PAE_DISCONNECTED:
00357                 SM_ENTER(SUPP_PAE, CONNECTING);
00358                 break;
00359         case SUPP_PAE_CONNECTING:
00360                 if (sm->startWhen == 0 && sm->startCount < sm->maxStart)
00361                         SM_ENTER(SUPP_PAE, CONNECTING);
00362                 else if (sm->startWhen == 0 &&
00363                          sm->startCount >= sm->maxStart &&
00364                          sm->portValid)
00365                         SM_ENTER(SUPP_PAE, AUTHENTICATED);
00366                 else if (sm->eapSuccess || sm->eapFail)
00367                         SM_ENTER(SUPP_PAE, AUTHENTICATING);
00368                 else if (sm->eapolEap)
00369                         SM_ENTER(SUPP_PAE, RESTART);
00370                 else if (sm->startWhen == 0 &&
00371                          sm->startCount >= sm->maxStart &&
00372                          !sm->portValid)
00373                         SM_ENTER(SUPP_PAE, HELD);
00374                 break;
00375         case SUPP_PAE_AUTHENTICATING:
00376                 if (sm->eapSuccess && !sm->portValid &&
00377                     sm->conf.accept_802_1x_keys &&
00378                     sm->conf.required_keys == 0) {
00379                         wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for "
00380                                    "plaintext connection; no EAPOL-Key frames "
00381                                    "required");
00382                         sm->portValid = TRUE;
00383                         if (sm->ctx->eapol_done_cb)
00384                                 sm->ctx->eapol_done_cb(sm->ctx->ctx);
00385                 }
00386                 if (sm->eapSuccess && sm->portValid)
00387                         SM_ENTER(SUPP_PAE, AUTHENTICATED);
00388                 else if (sm->eapFail || (sm->keyDone && !sm->portValid))
00389                         SM_ENTER(SUPP_PAE, HELD);
00390                 else if (sm->suppTimeout)
00391                         SM_ENTER(SUPP_PAE, CONNECTING);
00392                 break;
00393         case SUPP_PAE_HELD:
00394                 if (sm->heldWhile == 0)
00395                         SM_ENTER(SUPP_PAE, CONNECTING);
00396                 else if (sm->eapolEap)
00397                         SM_ENTER(SUPP_PAE, RESTART);
00398                 break;
00399         case SUPP_PAE_AUTHENTICATED:
00400                 if (sm->eapolEap && sm->portValid)
00401                         SM_ENTER(SUPP_PAE, RESTART);
00402                 else if (!sm->portValid)
00403                         SM_ENTER(SUPP_PAE, DISCONNECTED);
00404                 break;
00405         case SUPP_PAE_RESTART:
00406                 if (!sm->eapRestart)
00407                         SM_ENTER(SUPP_PAE, AUTHENTICATING);
00408                 break;
00409         case SUPP_PAE_S_FORCE_AUTH:
00410                 break;
00411         case SUPP_PAE_S_FORCE_UNAUTH:
00412                 break;
00413         }
00414 }
00415 
00416 
00417 SM_STATE(KEY_RX, NO_KEY_RECEIVE)
00418 {
00419         SM_ENTRY(KEY_RX, NO_KEY_RECEIVE);
00420 }
00421 
00422 
00423 SM_STATE(KEY_RX, KEY_RECEIVE)
00424 {
00425         SM_ENTRY(KEY_RX, KEY_RECEIVE);
00426         eapol_sm_processKey(sm);
00427         sm->rxKey = FALSE;
00428 }
00429 
00430 
00431 SM_STEP(KEY_RX)
00432 {
00433         if (sm->initialize || !sm->portEnabled)
00434                 SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
00435         switch (sm->KEY_RX_state) {
00436         case KEY_RX_UNKNOWN:
00437                 break;
00438         case KEY_RX_NO_KEY_RECEIVE:
00439                 if (sm->rxKey)
00440                         SM_ENTER(KEY_RX, KEY_RECEIVE);
00441                 break;
00442         case KEY_RX_KEY_RECEIVE:
00443                 if (sm->rxKey)
00444                         SM_ENTER(KEY_RX, KEY_RECEIVE);
00445                 break;
00446         }
00447 }
00448 
00449 
00450 SM_STATE(SUPP_BE, REQUEST)
00451 {
00452         SM_ENTRY(SUPP_BE, REQUEST);
00453         sm->authWhile = 0;
00454         sm->eapReq = TRUE;
00455         eapol_sm_getSuppRsp(sm);
00456 }
00457 
00458 
00459 SM_STATE(SUPP_BE, RESPONSE)
00460 {
00461         SM_ENTRY(SUPP_BE, RESPONSE);
00462         eapol_sm_txSuppRsp(sm);
00463         sm->eapResp = FALSE;
00464 }
00465 
00466 
00467 SM_STATE(SUPP_BE, SUCCESS)
00468 {
00469         SM_ENTRY(SUPP_BE, SUCCESS);
00470         sm->keyRun = TRUE;
00471         sm->suppSuccess = TRUE;
00472 
00473         if (eap_key_available(sm->eap)) {
00474                 /* New key received - clear IEEE 802.1X EAPOL-Key replay
00475                  * counter */
00476                 sm->replay_counter_valid = FALSE;
00477         }
00478 }
00479 
00480 
00481 SM_STATE(SUPP_BE, FAIL)
00482 {
00483         SM_ENTRY(SUPP_BE, FAIL);
00484         sm->suppFail = TRUE;
00485 }
00486 
00487 
00488 SM_STATE(SUPP_BE, TIMEOUT)
00489 {
00490         SM_ENTRY(SUPP_BE, TIMEOUT);
00491         sm->suppTimeout = TRUE;
00492 }
00493 
00494 
00495 SM_STATE(SUPP_BE, IDLE)
00496 {
00497         SM_ENTRY(SUPP_BE, IDLE);
00498         sm->suppStart = FALSE;
00499         sm->initial_req = TRUE;
00500 }
00501 
00502 
00503 SM_STATE(SUPP_BE, INITIALIZE)
00504 {
00505         SM_ENTRY(SUPP_BE, INITIALIZE);
00506         eapol_sm_abortSupp(sm);
00507         sm->suppAbort = FALSE;
00508 }
00509 
00510 
00511 SM_STATE(SUPP_BE, RECEIVE)
00512 {
00513         SM_ENTRY(SUPP_BE, RECEIVE);
00514         sm->authWhile = sm->authPeriod;
00515         sm->eapolEap = FALSE;
00516         sm->eapNoResp = FALSE;
00517         sm->initial_req = FALSE;
00518 }
00519 
00520 
00521 SM_STEP(SUPP_BE)
00522 {
00523         if (sm->initialize || sm->suppAbort)
00524                 SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE);
00525         else switch (sm->SUPP_BE_state) {
00526         case SUPP_BE_UNKNOWN:
00527                 break;
00528         case SUPP_BE_REQUEST:
00529                 /*
00530                  * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
00531                  * and SUCCESS based on eapFail and eapSuccess, respectively.
00532                  * However, IEEE Std 802.1X-2004 is also specifying that
00533                  * eapNoResp should be set in conjuction with eapSuccess and
00534                  * eapFail which would mean that more than one of the
00535                  * transitions here would be activated at the same time.
00536                  * Skipping RESPONSE and/or RECEIVE states in these cases can
00537                  * cause problems and the direct transitions to do not seem
00538                  * correct. Because of this, the conditions for these
00539                  * transitions are verified only after eapNoResp. They are
00540                  * unlikely to be used since eapNoResp should always be set if
00541                  * either of eapSuccess or eapFail is set.
00542                  */
00543                 if (sm->eapResp && sm->eapNoResp) {
00544                         wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both "
00545                                    "eapResp and eapNoResp set?!");
00546                 }
00547                 if (sm->eapResp)
00548                         SM_ENTER(SUPP_BE, RESPONSE);
00549                 else if (sm->eapNoResp)
00550                         SM_ENTER(SUPP_BE, RECEIVE);
00551                 else if (sm->eapFail)
00552                         SM_ENTER(SUPP_BE, FAIL);
00553                 else if (sm->eapSuccess)
00554                         SM_ENTER(SUPP_BE, SUCCESS);
00555                 break;
00556         case SUPP_BE_RESPONSE:
00557                 SM_ENTER(SUPP_BE, RECEIVE);
00558                 break;
00559         case SUPP_BE_SUCCESS:
00560                 SM_ENTER(SUPP_BE, IDLE);
00561                 break;
00562         case SUPP_BE_FAIL:
00563                 SM_ENTER(SUPP_BE, IDLE);
00564                 break;
00565         case SUPP_BE_TIMEOUT:
00566                 SM_ENTER(SUPP_BE, IDLE);
00567                 break;
00568         case SUPP_BE_IDLE:
00569                 if (sm->eapFail && sm->suppStart)
00570                         SM_ENTER(SUPP_BE, FAIL);
00571                 else if (sm->eapolEap && sm->suppStart)
00572                         SM_ENTER(SUPP_BE, REQUEST);
00573                 else if (sm->eapSuccess && sm->suppStart)
00574                         SM_ENTER(SUPP_BE, SUCCESS);
00575                 break;
00576         case SUPP_BE_INITIALIZE:
00577                 SM_ENTER(SUPP_BE, IDLE);
00578                 break;
00579         case SUPP_BE_RECEIVE:
00580                 if (sm->eapolEap)
00581                         SM_ENTER(SUPP_BE, REQUEST);
00582                 else if (sm->eapFail)
00583                         SM_ENTER(SUPP_BE, FAIL);
00584                 else if (sm->authWhile == 0)
00585                         SM_ENTER(SUPP_BE, TIMEOUT);
00586                 else if (sm->eapSuccess)
00587                         SM_ENTER(SUPP_BE, SUCCESS);
00588                 break;
00589         }
00590 }
00591 
00592 
00593 static void eapol_sm_txLogoff(struct eapol_sm *sm)
00594 {
00595         wpa_printf(MSG_DEBUG, "EAPOL: txLogoff");
00596         sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
00597                             IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0);
00598         sm->dot1xSuppEapolLogoffFramesTx++;
00599         sm->dot1xSuppEapolFramesTx++;
00600 }
00601 
00602 
00603 static void eapol_sm_txStart(struct eapol_sm *sm)
00604 {
00605         wpa_printf(MSG_DEBUG, "EAPOL: txStart");
00606         sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
00607                             IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0);
00608         sm->dot1xSuppEapolStartFramesTx++;
00609         sm->dot1xSuppEapolFramesTx++;
00610 }
00611 
00612 
00613 #define IEEE8021X_ENCR_KEY_LEN 32
00614 #define IEEE8021X_SIGN_KEY_LEN 32
00615 
00616 struct eap_key_data {
00617         u8 encr_key[IEEE8021X_ENCR_KEY_LEN];
00618         u8 sign_key[IEEE8021X_SIGN_KEY_LEN];
00619 };
00620 
00621 
00622 static void eapol_sm_processKey(struct eapol_sm *sm)
00623 {
00624         struct ieee802_1x_hdr *hdr;
00625         struct ieee802_1x_eapol_key *key;
00626         struct eap_key_data keydata;
00627         u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
00628         u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
00629         int key_len, res, sign_key_len, encr_key_len;
00630         u16 rx_key_length;
00631 
00632         wpa_printf(MSG_DEBUG, "EAPOL: processKey");
00633         if (sm->last_rx_key == NULL)
00634                 return;
00635 
00636         if (!sm->conf.accept_802_1x_keys) {
00637                 wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key"
00638                            " even though this was not accepted - "
00639                            "ignoring this packet");
00640                 return;
00641         }
00642 
00643         hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
00644         key = (struct ieee802_1x_eapol_key *) (hdr + 1);
00645         if (sizeof(*hdr) + be_to_host16(hdr->length) > sm->last_rx_key_len) {
00646                 wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
00647                 return;
00648         }
00649         rx_key_length = WPA_GET_BE16(key->key_length);
00650         wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
00651                    "EAPOL-Key: type=%d key_length=%d key_index=0x%x",
00652                    hdr->version, hdr->type, be_to_host16(hdr->length),
00653                    key->type, rx_key_length, key->key_index);
00654 
00655         eapol_sm_notify_lower_layer_success(sm);
00656         sign_key_len = IEEE8021X_SIGN_KEY_LEN;
00657         encr_key_len = IEEE8021X_ENCR_KEY_LEN;
00658         res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata));
00659         if (res < 0) {
00660                 wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for "
00661                            "decrypting EAPOL-Key keys");
00662                 return;
00663         }
00664         if (res == 16) {
00665                 /* LEAP derives only 16 bytes of keying material. */
00666                 res = eapol_sm_get_key(sm, (u8 *) &keydata, 16);
00667                 if (res) {
00668                         wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP "
00669                                    "master key for decrypting EAPOL-Key keys");
00670                         return;
00671                 }
00672                 sign_key_len = 16;
00673                 encr_key_len = 16;
00674                 os_memcpy(keydata.sign_key, keydata.encr_key, 16);
00675         } else if (res) {
00676                 wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key "
00677                            "data for decrypting EAPOL-Key keys (res=%d)", res);
00678                 return;
00679         }
00680 
00681         /* The key replay_counter must increase when same master key */
00682         if (sm->replay_counter_valid &&
00683             os_memcmp(sm->last_replay_counter, key->replay_counter,
00684                       IEEE8021X_REPLAY_COUNTER_LEN) >= 0) {
00685                 wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did "
00686                            "not increase - ignoring key");
00687                 wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter",
00688                             sm->last_replay_counter,
00689                             IEEE8021X_REPLAY_COUNTER_LEN);
00690                 wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter",
00691                             key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN);
00692                 return;
00693         }
00694 
00695         /* Verify key signature (HMAC-MD5) */
00696         os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN);
00697         os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN);
00698         hmac_md5(keydata.sign_key, sign_key_len,
00699                  sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
00700                  key->key_signature);
00701         if (os_memcmp(orig_key_sign, key->key_signature,
00702                       IEEE8021X_KEY_SIGN_LEN) != 0) {
00703                 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
00704                            "EAPOL-Key packet");
00705                 os_memcpy(key->key_signature, orig_key_sign,
00706                           IEEE8021X_KEY_SIGN_LEN);
00707                 return;
00708         }
00709         wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
00710 
00711         key_len = be_to_host16(hdr->length) - sizeof(*key);
00712         if (key_len > 32 || rx_key_length > 32) {
00713                 wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
00714                            key_len ? key_len : rx_key_length);
00715                 return;
00716         }
00717         if (key_len == rx_key_length) {
00718                 os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
00719                 os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
00720                           encr_key_len);
00721                 os_memcpy(datakey, key + 1, key_len);
00722                 rc4(datakey, key_len, ekey,
00723                     IEEE8021X_KEY_IV_LEN + encr_key_len);
00724                 wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
00725                                 datakey, key_len);
00726         } else if (key_len == 0) {
00727                 /*
00728                  * IEEE 802.1X-2004 specifies that least significant Key Length
00729                  * octets from MS-MPPE-Send-Key are used as the key if the key
00730                  * data is not present. This seems to be meaning the beginning
00731                  * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
00732                  * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
00733                  * Anyway, taking the beginning of the keying material from EAP
00734                  * seems to interoperate with Authenticators.
00735                  */
00736                 key_len = rx_key_length;
00737                 os_memcpy(datakey, keydata.encr_key, key_len);
00738                 wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying "
00739                                 "material data encryption key",
00740                                 datakey, key_len);
00741         } else {
00742                 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
00743                            "(key_length=%d)", key_len, rx_key_length);
00744                 return;
00745         }
00746 
00747         sm->replay_counter_valid = TRUE;
00748         os_memcpy(sm->last_replay_counter, key->replay_counter,
00749                   IEEE8021X_REPLAY_COUNTER_LEN);
00750 
00751         wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
00752                    "len %d",
00753                    key->key_index & IEEE8021X_KEY_INDEX_FLAG ?
00754                    "unicast" : "broadcast",
00755                    key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len);
00756 
00757         if (sm->ctx->set_wep_key &&
00758             sm->ctx->set_wep_key(sm->ctx->ctx,
00759                                  key->key_index & IEEE8021X_KEY_INDEX_FLAG,
00760                                  key->key_index & IEEE8021X_KEY_INDEX_MASK,
00761                                  datakey, key_len) < 0) {
00762                 wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
00763                            " driver.");
00764         } else {
00765                 if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
00766                         sm->unicast_key_received = TRUE;
00767                 else
00768                         sm->broadcast_key_received = TRUE;
00769 
00770                 if ((sm->unicast_key_received ||
00771                      !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) &&
00772                     (sm->broadcast_key_received ||
00773                      !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST)))
00774                 {
00775                         wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
00776                                    "frames received");
00777                         sm->portValid = TRUE;
00778                         if (sm->ctx->eapol_done_cb)
00779                                 sm->ctx->eapol_done_cb(sm->ctx->ctx);
00780                 }
00781         }
00782 }
00783 
00784 
00785 static void eapol_sm_getSuppRsp(struct eapol_sm *sm)
00786 {
00787         wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp");
00788         /* EAP layer processing; no special code is needed, since Supplicant
00789          * Backend state machine is waiting for eapNoResp or eapResp to be set
00790          * and these are only set in the EAP state machine when the processing
00791          * has finished. */
00792 }
00793 
00794 
00795 static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
00796 {
00797         u8 *resp;
00798         size_t resp_len;
00799 
00800         wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
00801         resp = eap_get_eapRespData(sm->eap, &resp_len);
00802         if (resp == NULL) {
00803                 wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
00804                            "not available");
00805                 return;
00806         }
00807 
00808         /* Send EAP-Packet from the EAP layer to the Authenticator */
00809         sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
00810                             IEEE802_1X_TYPE_EAP_PACKET, resp, resp_len);
00811 
00812         /* eapRespData is not used anymore, so free it here */
00813         os_free(resp);
00814 
00815         if (sm->initial_req)
00816                 sm->dot1xSuppEapolReqIdFramesRx++;
00817         else
00818                 sm->dot1xSuppEapolReqFramesRx++;
00819         sm->dot1xSuppEapolRespFramesTx++;
00820         sm->dot1xSuppEapolFramesTx++;
00821 }
00822 
00823 
00824 static void eapol_sm_abortSupp(struct eapol_sm *sm)
00825 {
00826         /* release system resources that may have been allocated for the
00827          * authentication session */
00828         os_free(sm->last_rx_key);
00829         sm->last_rx_key = NULL;
00830         os_free(sm->eapReqData);
00831         sm->eapReqData = NULL;
00832         eap_sm_abort(sm->eap);
00833 }
00834 
00835 
00836 static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
00837 {
00838         eapol_sm_step(timeout_ctx);
00839 }
00840 
00841 
00851 void eapol_sm_step(struct eapol_sm *sm)
00852 {
00853         int i;
00854 
00855         /* In theory, it should be ok to run this in loop until !changed.
00856          * However, it is better to use a limit on number of iterations to
00857          * allow events (e.g., SIGTERM) to stop the program cleanly if the
00858          * state machine were to generate a busy loop. */
00859         for (i = 0; i < 100; i++) {
00860                 sm->changed = FALSE;
00861                 SM_STEP_RUN(SUPP_PAE);
00862                 SM_STEP_RUN(KEY_RX);
00863                 SM_STEP_RUN(SUPP_BE);
00864                 if (eap_sm_step(sm->eap))
00865                         sm->changed = TRUE;
00866                 if (!sm->changed)
00867                         break;
00868         }
00869 
00870         if (sm->changed) {
00871                 /* restart EAPOL state machine step from timeout call in order
00872                  * to allow other events to be processed. */
00873                 eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
00874                 eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm);
00875         }
00876 
00877         if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
00878                 int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0;
00879                 sm->cb_status = EAPOL_CB_IN_PROGRESS;
00880                 sm->ctx->cb(sm, success, sm->ctx->cb_ctx);
00881         }
00882 }
00883 
00884 
00885 #ifdef CONFIG_CTRL_IFACE
00886 static const char *eapol_supp_pae_state(int state)
00887 {
00888         switch (state) {
00889         case SUPP_PAE_LOGOFF:
00890                 return "LOGOFF";
00891         case SUPP_PAE_DISCONNECTED:
00892                 return "DISCONNECTED";
00893         case SUPP_PAE_CONNECTING:
00894                 return "CONNECTING";
00895         case SUPP_PAE_AUTHENTICATING:
00896                 return "AUTHENTICATING";
00897         case SUPP_PAE_HELD:
00898                 return "HELD";
00899         case SUPP_PAE_AUTHENTICATED:
00900                 return "AUTHENTICATED";
00901         case SUPP_PAE_RESTART:
00902                 return "RESTART";
00903         default:
00904                 return "UNKNOWN";
00905         }
00906 }
00907 
00908 
00909 static const char *eapol_supp_be_state(int state)
00910 {
00911         switch (state) {
00912         case SUPP_BE_REQUEST:
00913                 return "REQUEST";
00914         case SUPP_BE_RESPONSE:
00915                 return "RESPONSE";
00916         case SUPP_BE_SUCCESS:
00917                 return "SUCCESS";
00918         case SUPP_BE_FAIL:
00919                 return "FAIL";
00920         case SUPP_BE_TIMEOUT:
00921                 return "TIMEOUT";
00922         case SUPP_BE_IDLE:
00923                 return "IDLE";
00924         case SUPP_BE_INITIALIZE:
00925                 return "INITIALIZE";
00926         case SUPP_BE_RECEIVE:
00927                 return "RECEIVE";
00928         default:
00929                 return "UNKNOWN";
00930         }
00931 }
00932 
00933 
00934 static const char * eapol_port_status(PortStatus status)
00935 {
00936         if (status == Authorized)
00937                 return "Authorized";
00938         else
00939                 return "Unauthorized";
00940 }
00941 #endif /* CONFIG_CTRL_IFACE */
00942 
00943 
00944 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
00945 static const char * eapol_port_control(PortControl ctrl)
00946 {
00947         switch (ctrl) {
00948         case Auto:
00949                 return "Auto";
00950         case ForceUnauthorized:
00951                 return "ForceUnauthorized";
00952         case ForceAuthorized:
00953                 return "ForceAuthorized";
00954         default:
00955                 return "Unknown";
00956         }
00957 }
00958 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
00959 
00960 
00973 void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
00974                         int startPeriod, int maxStart)
00975 {
00976         if (sm == NULL)
00977                 return;
00978         if (heldPeriod >= 0)
00979                 sm->heldPeriod = heldPeriod;
00980         if (authPeriod >= 0)
00981                 sm->authPeriod = authPeriod;
00982         if (startPeriod >= 0)
00983                 sm->startPeriod = startPeriod;
00984         if (maxStart >= 0)
00985                 sm->maxStart = maxStart;
00986 }
00987 
00988 
00989 #ifdef CONFIG_CTRL_IFACE
00990 
01004 int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
01005                         int verbose)
01006 {
01007         int len, ret;
01008         if (sm == NULL)
01009                 return 0;
01010 
01011         len = os_snprintf(buf, buflen,
01012                           "Supplicant PAE state=%s\n"
01013                           "suppPortStatus=%s\n",
01014                           eapol_supp_pae_state(sm->SUPP_PAE_state),
01015                           eapol_port_status(sm->suppPortStatus));
01016         if (len < 0 || (size_t) len >= buflen)
01017                 return 0;
01018 
01019         if (verbose) {
01020                 ret = os_snprintf(buf + len, buflen - len,
01021                                   "heldPeriod=%u\n"
01022                                   "authPeriod=%u\n"
01023                                   "startPeriod=%u\n"
01024                                   "maxStart=%u\n"
01025                                   "portControl=%s\n"
01026                                   "Supplicant Backend state=%s\n",
01027                                   sm->heldPeriod,
01028                                   sm->authPeriod,
01029                                   sm->startPeriod,
01030                                   sm->maxStart,
01031                                   eapol_port_control(sm->portControl),
01032                                   eapol_supp_be_state(sm->SUPP_BE_state));
01033                 if (ret < 0 || (size_t) ret >= buflen - len)
01034                         return len;
01035                 len += ret;
01036         }
01037 
01038         len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
01039 
01040         return len;
01041 }
01042 
01043 
01057 int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
01058 {
01059         size_t len;
01060         int ret;
01061 
01062         if (sm == NULL)
01063                 return 0;
01064         ret = os_snprintf(buf, buflen,
01065                           "dot1xSuppPaeState=%d\n"
01066                           "dot1xSuppHeldPeriod=%u\n"
01067                           "dot1xSuppAuthPeriod=%u\n"
01068                           "dot1xSuppStartPeriod=%u\n"
01069                           "dot1xSuppMaxStart=%u\n"
01070                           "dot1xSuppSuppControlledPortStatus=%s\n"
01071                           "dot1xSuppBackendPaeState=%d\n",
01072                           sm->SUPP_PAE_state,
01073                           sm->heldPeriod,
01074                           sm->authPeriod,
01075                           sm->startPeriod,
01076                           sm->maxStart,
01077                           sm->suppPortStatus == Authorized ?
01078                           "Authorized" : "Unauthorized",
01079                           sm->SUPP_BE_state);
01080 
01081         if (ret < 0 || (size_t) ret >= buflen)
01082                 return 0;
01083         len = ret;
01084 
01085         ret = os_snprintf(buf + len, buflen - len,
01086                           "dot1xSuppEapolFramesRx=%u\n"
01087                           "dot1xSuppEapolFramesTx=%u\n"
01088                           "dot1xSuppEapolStartFramesTx=%u\n"
01089                           "dot1xSuppEapolLogoffFramesTx=%u\n"
01090                           "dot1xSuppEapolRespFramesTx=%u\n"
01091                           "dot1xSuppEapolReqIdFramesRx=%u\n"
01092                           "dot1xSuppEapolReqFramesRx=%u\n"
01093                           "dot1xSuppInvalidEapolFramesRx=%u\n"
01094                           "dot1xSuppEapLengthErrorFramesRx=%u\n"
01095                           "dot1xSuppLastEapolFrameVersion=%u\n"
01096                           "dot1xSuppLastEapolFrameSource=" MACSTR "\n",
01097                           sm->dot1xSuppEapolFramesRx,
01098                           sm->dot1xSuppEapolFramesTx,
01099                           sm->dot1xSuppEapolStartFramesTx,
01100                           sm->dot1xSuppEapolLogoffFramesTx,
01101                           sm->dot1xSuppEapolRespFramesTx,
01102                           sm->dot1xSuppEapolReqIdFramesRx,
01103                           sm->dot1xSuppEapolReqFramesRx,
01104                           sm->dot1xSuppInvalidEapolFramesRx,
01105                           sm->dot1xSuppEapLengthErrorFramesRx,
01106                           sm->dot1xSuppLastEapolFrameVersion,
01107                           MAC2STR(sm->dot1xSuppLastEapolFrameSource));
01108 
01109         if (ret < 0 || (size_t) ret >= buflen - len)
01110                 return len;
01111         len += ret;
01112 
01113         return len;
01114 }
01115 #endif /* CONFIG_CTRL_IFACE */
01116 
01117 
01128 int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
01129                       size_t len)
01130 {
01131         const struct ieee802_1x_hdr *hdr;
01132         const struct ieee802_1x_eapol_key *key;
01133         int data_len;
01134         int res = 1;
01135         size_t plen;
01136 
01137         if (sm == NULL)
01138                 return 0;
01139         sm->dot1xSuppEapolFramesRx++;
01140         if (len < sizeof(*hdr)) {
01141                 sm->dot1xSuppInvalidEapolFramesRx++;
01142                 return 0;
01143         }
01144         hdr = (const struct ieee802_1x_hdr *) buf;
01145         sm->dot1xSuppLastEapolFrameVersion = hdr->version;
01146         os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
01147         if (hdr->version < EAPOL_VERSION) {
01148                 /* TODO: backwards compatibility */
01149         }
01150         plen = be_to_host16(hdr->length);
01151         if (plen > len - sizeof(*hdr)) {
01152                 sm->dot1xSuppEapLengthErrorFramesRx++;
01153                 return 0;
01154         }
01155         data_len = plen + sizeof(*hdr);
01156 
01157         switch (hdr->type) {
01158         case IEEE802_1X_TYPE_EAP_PACKET:
01159                 if (sm->cached_pmk) {
01160                         /* Trying to use PMKSA caching, but Authenticator did
01161                          * not seem to have a matching entry. Need to restart
01162                          * EAPOL state machines.
01163                          */
01164                         eapol_sm_abort_cached(sm);
01165                 }
01166                 os_free(sm->eapReqData);
01167                 sm->eapReqDataLen = plen;
01168                 sm->eapReqData = os_malloc(sm->eapReqDataLen);
01169                 if (sm->eapReqData) {
01170                         wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
01171                                    "frame");
01172                         os_memcpy(sm->eapReqData, (u8 *) (hdr + 1),
01173                                   sm->eapReqDataLen);
01174                         sm->eapolEap = TRUE;
01175                         eapol_sm_step(sm);
01176                 }
01177                 break;
01178         case IEEE802_1X_TYPE_EAPOL_KEY:
01179                 if (plen < sizeof(*key)) {
01180                         wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key "
01181                                    "frame received");
01182                         break;
01183                 }
01184                 key = (const struct ieee802_1x_eapol_key *) (hdr + 1);
01185                 if (key->type == EAPOL_KEY_TYPE_WPA ||
01186                     key->type == EAPOL_KEY_TYPE_RSN) {
01187                         /* WPA Supplicant takes care of this frame. */
01188                         wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
01189                                    "frame in EAPOL state machines");
01190                         res = 0;
01191                         break;
01192                 }
01193                 if (key->type != EAPOL_KEY_TYPE_RC4) {
01194                         wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown "
01195                                    "EAPOL-Key type %d", key->type);
01196                         break;
01197                 }
01198                 os_free(sm->last_rx_key);
01199                 sm->last_rx_key = os_malloc(data_len);
01200                 if (sm->last_rx_key) {
01201                         wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key "
01202                                    "frame");
01203                         os_memcpy(sm->last_rx_key, buf, data_len);
01204                         sm->last_rx_key_len = data_len;
01205                         sm->rxKey = TRUE;
01206                         eapol_sm_step(sm);
01207                 }
01208                 break;
01209         default:
01210                 wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
01211                            hdr->type);
01212                 sm->dot1xSuppInvalidEapolFramesRx++;
01213                 break;
01214         }
01215 
01216         return res;
01217 }
01218 
01219 
01228 void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
01229 {
01230         if (sm)
01231                 sm->dot1xSuppEapolFramesTx++;
01232 }
01233 
01234 
01243 void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
01244 {
01245         if (sm == NULL)
01246                 return;
01247         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
01248                    "portEnabled=%d", enabled);
01249         sm->portEnabled = enabled;
01250         eapol_sm_step(sm);
01251 }
01252 
01253 
01262 void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
01263 {
01264         if (sm == NULL)
01265                 return;
01266         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
01267                    "portValid=%d", valid);
01268         sm->portValid = valid;
01269         eapol_sm_step(sm);
01270 }
01271 
01272 
01285 void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
01286 {
01287         if (sm == NULL)
01288                 return;
01289         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
01290                    "EAP success=%d", success);
01291         sm->eapSuccess = success;
01292         sm->altAccept = success;
01293         if (success)
01294                 eap_notify_success(sm->eap);
01295         eapol_sm_step(sm);
01296 }
01297 
01298 
01308 void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
01309 {
01310         if (sm == NULL)
01311                 return;
01312         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
01313                    "EAP fail=%d", fail);
01314         sm->eapFail = fail;
01315         sm->altReject = fail;
01316         eapol_sm_step(sm);
01317 }
01318 
01319 
01333 void eapol_sm_notify_config(struct eapol_sm *sm, struct wpa_ssid *config,
01334                             const struct eapol_config *conf)
01335 {
01336         if (sm == NULL)
01337                 return;
01338 
01339         sm->config = config;
01340 
01341         if (conf == NULL)
01342                 return;
01343 
01344         sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys;
01345         sm->conf.required_keys = conf->required_keys;
01346         sm->conf.fast_reauth = conf->fast_reauth;
01347         if (sm->eap) {
01348                 eap_set_fast_reauth(sm->eap, conf->fast_reauth);
01349                 eap_set_workaround(sm->eap, conf->workaround);
01350                 eap_set_force_disabled(sm->eap, conf->eap_disabled);
01351         }
01352 }
01353 
01354 
01367 int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
01368 {
01369         const u8 *eap_key;
01370         size_t eap_len;
01371 
01372         if (sm == NULL || !eap_key_available(sm->eap))
01373                 return -1;
01374         eap_key = eap_get_eapKeyData(sm->eap, &eap_len);
01375         if (eap_key == NULL)
01376                 return -1;
01377         if (len > eap_len)
01378                 return eap_len;
01379         os_memcpy(key, eap_key, len);
01380         return 0;
01381 }
01382 
01383 
01392 void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
01393 {
01394         if (sm) {
01395                 sm->userLogoff = logoff;
01396                 eapol_sm_step(sm);
01397         }
01398 }
01399 
01400 
01409 void eapol_sm_notify_cached(struct eapol_sm *sm)
01410 {
01411         if (sm == NULL)
01412                 return;
01413         sm->SUPP_PAE_state = SUPP_PAE_AUTHENTICATED;
01414         sm->suppPortStatus = Authorized;
01415         eap_notify_success(sm->eap);
01416 }
01417 
01418 
01427 void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt)
01428 {
01429         if (sm == NULL)
01430                 return;
01431         if (attempt) {
01432                 wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
01433                 sm->cached_pmk = TRUE;
01434         } else {
01435                 wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA");
01436                 sm->cached_pmk = FALSE;
01437         }
01438 }
01439 
01440 
01441 static void eapol_sm_abort_cached(struct eapol_sm *sm)
01442 {
01443         wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, "
01444                    "doing full EAP authentication");
01445         if (sm == NULL)
01446                 return;
01447         sm->cached_pmk = FALSE;
01448         sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
01449         sm->suppPortStatus = Unauthorized;
01450 
01451         /* Make sure we do not start sending EAPOL-Start frames first, but
01452          * instead move to RESTART state to start EAPOL authentication. */
01453         sm->startWhen = 3;
01454 
01455         if (sm->ctx->aborted_cached)
01456                 sm->ctx->aborted_cached(sm->ctx->ctx);
01457 }
01458 
01459 
01469 void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
01470 {
01471         if (sm) {
01472                 sm->ctx->scard_ctx = ctx;
01473                 eap_register_scard_ctx(sm->eap, ctx);
01474         }
01475 }
01476 
01477 
01486 void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
01487 {
01488         if (sm == NULL)
01489                 return;
01490         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
01491                    "portControl=%s", eapol_port_control(portControl));
01492         sm->portControl = portControl;
01493         eapol_sm_step(sm);
01494 }
01495 
01496 
01505 void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
01506 {
01507         if (sm == NULL)
01508                 return;
01509         eap_sm_notify_ctrl_attached(sm->eap);
01510 }
01511 
01512 
01521 void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
01522 {
01523         if (sm == NULL)
01524                 return;
01525         if (sm->eapReqData && !sm->eapReq) {
01526                 wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
01527                            "input) notification - retrying pending EAP "
01528                            "Request");
01529                 sm->eapolEap = TRUE;
01530                 sm->eapReq = TRUE;
01531                 eapol_sm_step(sm);
01532         }
01533 }
01534 
01535 
01544 void eapol_sm_request_reauth(struct eapol_sm *sm)
01545 {
01546         if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
01547                 return;
01548         eapol_sm_txStart(sm);
01549 }
01550 
01551 
01561 void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm)
01562 {
01563         if (sm == NULL)
01564                 return;
01565         eap_notify_lower_layer_success(sm->eap);
01566 }
01567 
01568 
01574 void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
01575 {
01576         if (sm)
01577                 eap_invalidate_cached_session(sm->eap);
01578 }
01579 
01580 
01581 static struct wpa_ssid * eapol_sm_get_config(void *ctx)
01582 {
01583         struct eapol_sm *sm = ctx;
01584         return sm ? sm->config : NULL;
01585 }
01586 
01587 
01588 static u8 * eapol_sm_get_eapReqData(void *ctx, size_t *len)
01589 {
01590         struct eapol_sm *sm = ctx;
01591         if (sm == NULL || sm->eapReqData == NULL) {
01592                 *len = 0;
01593                 return NULL;
01594         }
01595 
01596         *len = sm->eapReqDataLen;
01597         return sm->eapReqData;
01598 }
01599 
01600 
01601 static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
01602 {
01603         struct eapol_sm *sm = ctx;
01604         if (sm == NULL)
01605                 return FALSE;
01606         switch (variable) {
01607         case EAPOL_eapSuccess:
01608                 return sm->eapSuccess;
01609         case EAPOL_eapRestart:
01610                 return sm->eapRestart;
01611         case EAPOL_eapFail:
01612                 return sm->eapFail;
01613         case EAPOL_eapResp:
01614                 return sm->eapResp;
01615         case EAPOL_eapNoResp:
01616                 return sm->eapNoResp;
01617         case EAPOL_eapReq:
01618                 return sm->eapReq;
01619         case EAPOL_portEnabled:
01620                 return sm->portEnabled;
01621         case EAPOL_altAccept:
01622                 return sm->altAccept;
01623         case EAPOL_altReject:
01624                 return sm->altReject;
01625         }
01626         return FALSE;
01627 }
01628 
01629 
01630 static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
01631                               Boolean value)
01632 {
01633         struct eapol_sm *sm = ctx;
01634         if (sm == NULL)
01635                 return;
01636         switch (variable) {
01637         case EAPOL_eapSuccess:
01638                 sm->eapSuccess = value;
01639                 break;
01640         case EAPOL_eapRestart:
01641                 sm->eapRestart = value;
01642                 break;
01643         case EAPOL_eapFail:
01644                 sm->eapFail = value;
01645                 break;
01646         case EAPOL_eapResp:
01647                 sm->eapResp = value;
01648                 break;
01649         case EAPOL_eapNoResp:
01650                 sm->eapNoResp = value;
01651                 break;
01652         case EAPOL_eapReq:
01653                 sm->eapReq = value;
01654                 break;
01655         case EAPOL_portEnabled:
01656                 sm->portEnabled = value;
01657                 break;
01658         case EAPOL_altAccept:
01659                 sm->altAccept = value;
01660                 break;
01661         case EAPOL_altReject:
01662                 sm->altReject = value;
01663                 break;
01664         }
01665 }
01666 
01667 
01668 static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable)
01669 {
01670         struct eapol_sm *sm = ctx;
01671         if (sm == NULL)
01672                 return 0;
01673         switch (variable) {
01674         case EAPOL_idleWhile:
01675                 return sm->idleWhile;
01676         }
01677         return 0;
01678 }
01679 
01680 
01681 static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
01682                              unsigned int value)
01683 {
01684         struct eapol_sm *sm = ctx;
01685         if (sm == NULL)
01686                 return;
01687         switch (variable) {
01688         case EAPOL_idleWhile:
01689                 sm->idleWhile = value;
01690                 break;
01691         }
01692 }
01693 
01694 
01695 static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
01696 {
01697         struct eapol_sm *sm = ctx;
01698         if (sm && sm->ctx && sm->ctx->set_config_blob)
01699                 sm->ctx->set_config_blob(sm->ctx->ctx, blob);
01700 }
01701 
01702 
01703 static const struct wpa_config_blob *
01704 eapol_sm_get_config_blob(void *ctx, const char *name)
01705 {
01706         struct eapol_sm *sm = ctx;
01707         if (sm && sm->ctx && sm->ctx->get_config_blob)
01708                 return sm->ctx->get_config_blob(sm->ctx->ctx, name);
01709         else
01710                 return NULL;
01711 }
01712 
01713 
01714 static void eapol_sm_notify_pending(void *ctx)
01715 {
01716         struct eapol_sm *sm = ctx;
01717         if (sm == NULL)
01718                 return;
01719         if (sm->eapReqData && !sm->eapReq) {
01720                 wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP "
01721                            "state machine - retrying pending EAP Request");
01722                 sm->eapolEap = TRUE;
01723                 sm->eapReq = TRUE;
01724                 eapol_sm_step(sm);
01725         }
01726 }
01727 
01728 
01729 static struct eapol_callbacks eapol_cb =
01730 {
01731         eapol_sm_get_config,
01732         eapol_sm_get_bool,
01733         eapol_sm_set_bool,
01734         eapol_sm_get_int,
01735         eapol_sm_set_int,
01736         eapol_sm_get_eapReqData,
01737         eapol_sm_set_config_blob,
01738         eapol_sm_get_config_blob,
01739         eapol_sm_notify_pending
01740 };
01741 
01742 
01752 struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
01753 {
01754         struct eapol_sm *sm;
01755         struct eap_config conf;
01756         sm = os_zalloc(sizeof(*sm));
01757         if (sm == NULL)
01758                 return NULL;
01759         sm->ctx = ctx;
01760 
01761         sm->portControl = Auto;
01762 
01763         /* Supplicant PAE state machine */
01764         sm->heldPeriod = 60;
01765         sm->startPeriod = 30;
01766         sm->maxStart = 3;
01767 
01768         /* Supplicant Backend state machine */
01769         sm->authPeriod = 30;
01770 
01771         os_memset(&conf, 0, sizeof(conf));
01772         conf.opensc_engine_path = ctx->opensc_engine_path;
01773         conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
01774         conf.pkcs11_module_path = ctx->pkcs11_module_path;
01775 
01776         sm->eap = eap_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
01777         if (sm->eap == NULL) {
01778                 os_free(sm);
01779                 return NULL;
01780         }
01781 
01782         /* Initialize EAPOL state machines */
01783         sm->initialize = TRUE;
01784         eapol_sm_step(sm);
01785         sm->initialize = FALSE;
01786         eapol_sm_step(sm);
01787 
01788         eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
01789 
01790         return sm;
01791 }
01792 
01793 
01801 void eapol_sm_deinit(struct eapol_sm *sm)
01802 {
01803         if (sm == NULL)
01804                 return;
01805         eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
01806         eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
01807         eap_sm_deinit(sm->eap);
01808         os_free(sm->last_rx_key);
01809         os_free(sm->eapReqData);
01810         os_free(sm->ctx);
01811         os_free(sm);
01812 }
01813 

Generated on Sun Dec 31 13:48:54 2006 for wpa_supplicant by  doxygen 1.4.2