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
00033
00038 struct eapol_sm {
00039
00040 unsigned int authWhile;
00041 unsigned int heldWhile;
00042 unsigned int startWhen;
00043 unsigned int idleWhile;
00044
00045
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;
00055 Boolean portValid;
00056 Boolean suppAbort;
00057 Boolean suppFail;
00058 Boolean suppStart;
00059 Boolean suppSuccess;
00060 Boolean suppTimeout;
00061
00062
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
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;
00076
00077 Boolean userLogoff;
00078 Boolean logoffSent;
00079 unsigned int startCount;
00080 Boolean eapRestart;
00081 PortControl sPortMode;
00082
00083 unsigned int heldPeriod;
00084 unsigned int startPeriod;
00085 unsigned int maxStart;
00086
00087
00088 enum {
00089 KEY_RX_UNKNOWN = 0,
00090 KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
00091 } KEY_RX_state;
00092
00093 Boolean rxKey;
00094
00095
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;
00107
00108 Boolean eapNoResp;
00109 Boolean eapReq;
00110 Boolean eapResp;
00111
00112 unsigned int authPeriod;
00113
00114
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
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;
00135 size_t eapReqDataLen;
00136 Boolean altAccept;
00137 Boolean altReject;
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
00160
00161 struct ieee802_1x_eapol_key {
00162 u8 type;
00163
00164 u8 key_length[2];
00165
00166
00167 u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN];
00168 u8 key_iv[IEEE8021X_KEY_IV_LEN];
00169 u8 key_index;
00170
00171
00172
00173
00174
00175 u8 key_signature[IEEE8021X_KEY_SIGN_LEN];
00176
00177
00178
00179
00180
00181
00182
00183 } STRUCT_PACKED;
00184
00185 #ifdef _MSC_VER
00186 #pragma pack(pop)
00187 #endif
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
00201
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
00265
00266
00267
00268
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
00475
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
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
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
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
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
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
00729
00730
00731
00732
00733
00734
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
00789
00790
00791
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
00809 sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
00810 IEEE802_1X_TYPE_EAP_PACKET, resp, resp_len);
00811
00812
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
00827
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
00856
00857
00858
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
00872
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
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
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
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
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
01161
01162
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
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
01452
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
01764 sm->heldPeriod = 60;
01765 sm->startPeriod = 30;
01766 sm->maxStart = 3;
01767
01768
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
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