1/* 2 * EAPOL supplicant state machines 3 * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9#include "includes.h" 10 11#include "common.h" 12#include "state_machine.h" 13#include "wpabuf.h" 14#include "eloop.h" 15#include "crypto/crypto.h" 16#include "crypto/md5.h" 17#include "common/eapol_common.h" 18#include "eap_peer/eap.h" 19#include "eapol_supp_sm.h" 20 21#define STATE_MACHINE_DATA struct eapol_sm 22#define STATE_MACHINE_DEBUG_PREFIX "EAPOL" 23 24 25/* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */ 26 27/** 28 * struct eapol_sm - Internal data for EAPOL state machines 29 */ 30struct eapol_sm { 31 /* Timers */ 32 unsigned int authWhile; 33 unsigned int heldWhile; 34 unsigned int startWhen; 35 unsigned int idleWhile; /* for EAP state machine */ 36 int timer_tick_enabled; 37 38 /* Global variables */ 39 Boolean eapFail; 40 Boolean eapolEap; 41 Boolean eapSuccess; 42 Boolean initialize; 43 Boolean keyDone; 44 Boolean keyRun; 45 PortControl portControl; 46 Boolean portEnabled; 47 PortStatus suppPortStatus; /* dot1xSuppControlledPortStatus */ 48 Boolean portValid; 49 Boolean suppAbort; 50 Boolean suppFail; 51 Boolean suppStart; 52 Boolean suppSuccess; 53 Boolean suppTimeout; 54 55 /* Supplicant PAE state machine */ 56 enum { 57 SUPP_PAE_UNKNOWN = 0, 58 SUPP_PAE_DISCONNECTED = 1, 59 SUPP_PAE_LOGOFF = 2, 60 SUPP_PAE_CONNECTING = 3, 61 SUPP_PAE_AUTHENTICATING = 4, 62 SUPP_PAE_AUTHENTICATED = 5, 63 /* unused(6) */ 64 SUPP_PAE_HELD = 7, 65 SUPP_PAE_RESTART = 8, 66 SUPP_PAE_S_FORCE_AUTH = 9, 67 SUPP_PAE_S_FORCE_UNAUTH = 10 68 } SUPP_PAE_state; /* dot1xSuppPaeState */ 69 /* Variables */ 70 Boolean userLogoff; 71 Boolean logoffSent; 72 unsigned int startCount; 73 Boolean eapRestart; 74 PortControl sPortMode; 75 /* Constants */ 76 unsigned int heldPeriod; /* dot1xSuppHeldPeriod */ 77 unsigned int startPeriod; /* dot1xSuppStartPeriod */ 78 unsigned int maxStart; /* dot1xSuppMaxStart */ 79 80 /* Key Receive state machine */ 81 enum { 82 KEY_RX_UNKNOWN = 0, 83 KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE 84 } KEY_RX_state; 85 /* Variables */ 86 Boolean rxKey; 87 88 /* Supplicant Backend state machine */ 89 enum { 90 SUPP_BE_UNKNOWN = 0, 91 SUPP_BE_INITIALIZE = 1, 92 SUPP_BE_IDLE = 2, 93 SUPP_BE_REQUEST = 3, 94 SUPP_BE_RECEIVE = 4, 95 SUPP_BE_RESPONSE = 5, 96 SUPP_BE_FAIL = 6, 97 SUPP_BE_TIMEOUT = 7, 98 SUPP_BE_SUCCESS = 8 99 } SUPP_BE_state; /* dot1xSuppBackendPaeState */ 100 /* Variables */ 101 Boolean eapNoResp; 102 Boolean eapReq; 103 Boolean eapResp; 104 /* Constants */ 105 unsigned int authPeriod; /* dot1xSuppAuthPeriod */ 106 107 /* Statistics */ 108 unsigned int dot1xSuppEapolFramesRx; 109 unsigned int dot1xSuppEapolFramesTx; 110 unsigned int dot1xSuppEapolStartFramesTx; 111 unsigned int dot1xSuppEapolLogoffFramesTx; 112 unsigned int dot1xSuppEapolRespFramesTx; 113 unsigned int dot1xSuppEapolReqIdFramesRx; 114 unsigned int dot1xSuppEapolReqFramesRx; 115 unsigned int dot1xSuppInvalidEapolFramesRx; 116 unsigned int dot1xSuppEapLengthErrorFramesRx; 117 unsigned int dot1xSuppLastEapolFrameVersion; 118 unsigned char dot1xSuppLastEapolFrameSource[6]; 119 120 /* Miscellaneous variables (not defined in IEEE 802.1X-2004) */ 121 Boolean changed; 122 struct eap_sm *eap; 123 struct eap_peer_config *config; 124 Boolean initial_req; 125 u8 *last_rx_key; 126 size_t last_rx_key_len; 127 struct wpabuf *eapReqData; /* for EAP */ 128 Boolean altAccept; /* for EAP */ 129 Boolean altReject; /* for EAP */ 130 Boolean replay_counter_valid; 131 u8 last_replay_counter[16]; 132 struct eapol_config conf; 133 struct eapol_ctx *ctx; 134 enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE } 135 cb_status; 136 Boolean cached_pmk; 137 138 Boolean unicast_key_received, broadcast_key_received; 139}; 140 141 142static void eapol_sm_txLogoff(struct eapol_sm *sm); 143static void eapol_sm_txStart(struct eapol_sm *sm); 144static void eapol_sm_processKey(struct eapol_sm *sm); 145static void eapol_sm_getSuppRsp(struct eapol_sm *sm); 146static void eapol_sm_txSuppRsp(struct eapol_sm *sm); 147static void eapol_sm_abortSupp(struct eapol_sm *sm); 148static void eapol_sm_abort_cached(struct eapol_sm *sm); 149static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx); 150static void eapol_sm_set_port_authorized(struct eapol_sm *sm); 151static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm); 152 153 154/* Port Timers state machine - implemented as a function that will be called 155 * once a second as a registered event loop timeout */ 156static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx) 157{ 158 struct eapol_sm *sm = timeout_ctx; 159 160 if (sm->authWhile > 0) { 161 sm->authWhile--; 162 if (sm->authWhile == 0) 163 wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0"); 164 } 165 if (sm->heldWhile > 0) { 166 sm->heldWhile--; 167 if (sm->heldWhile == 0) 168 wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0"); 169 } 170 if (sm->startWhen > 0) { 171 sm->startWhen--; 172 if (sm->startWhen == 0) 173 wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0"); 174 } 175 if (sm->idleWhile > 0) { 176 sm->idleWhile--; 177 if (sm->idleWhile == 0) 178 wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0"); 179 } 180 181 if (sm->authWhile | sm->heldWhile | sm->startWhen | sm->idleWhile) { 182 eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, 183 sm); 184 } else { 185 wpa_printf(MSG_DEBUG, "EAPOL: disable timer tick"); 186 sm->timer_tick_enabled = 0; 187 } 188 eapol_sm_step(sm); 189} 190 191 192static void eapol_enable_timer_tick(struct eapol_sm *sm) 193{ 194 if (sm->timer_tick_enabled) 195 return; 196 wpa_printf(MSG_DEBUG, "EAPOL: enable timer tick"); 197 sm->timer_tick_enabled = 1; 198 eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm); 199 eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm); 200} 201 202 203SM_STATE(SUPP_PAE, LOGOFF) 204{ 205 SM_ENTRY(SUPP_PAE, LOGOFF); 206 eapol_sm_txLogoff(sm); 207 sm->logoffSent = TRUE; 208 sm->suppPortStatus = Unauthorized; 209 eapol_sm_set_port_unauthorized(sm); 210} 211 212 213SM_STATE(SUPP_PAE, DISCONNECTED) 214{ 215 SM_ENTRY(SUPP_PAE, DISCONNECTED); 216 sm->sPortMode = Auto; 217 sm->startCount = 0; 218 sm->logoffSent = FALSE; 219 sm->suppPortStatus = Unauthorized; 220 eapol_sm_set_port_unauthorized(sm); 221 sm->suppAbort = TRUE; 222 223 sm->unicast_key_received = FALSE; 224 sm->broadcast_key_received = FALSE; 225 226 /* 227 * IEEE Std 802.1X-2004 does not clear heldWhile here, but doing so 228 * allows the timer tick to be stopped more quickly when the port is 229 * not enabled. Since this variable is used only within HELD state, 230 * clearing it on initialization does not change actual state machine 231 * behavior. 232 */ 233 sm->heldWhile = 0; 234} 235 236 237SM_STATE(SUPP_PAE, CONNECTING) 238{ 239 int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING; 240 SM_ENTRY(SUPP_PAE, CONNECTING); 241 if (send_start) { 242 sm->startWhen = sm->startPeriod; 243 sm->startCount++; 244 } else { 245 /* 246 * Do not send EAPOL-Start immediately since in most cases, 247 * Authenticator is going to start authentication immediately 248 * after association and an extra EAPOL-Start is just going to 249 * delay authentication. Use a short timeout to send the first 250 * EAPOL-Start if Authenticator does not start authentication. 251 */ 252#ifdef CONFIG_WPS 253 /* Reduce latency on starting WPS negotiation. */ 254 sm->startWhen = 1; 255#else /* CONFIG_WPS */ 256 sm->startWhen = 3; 257#endif /* CONFIG_WPS */ 258 } 259 eapol_enable_timer_tick(sm); 260 sm->eapolEap = FALSE; 261 if (send_start) 262 eapol_sm_txStart(sm); 263} 264 265 266SM_STATE(SUPP_PAE, AUTHENTICATING) 267{ 268 SM_ENTRY(SUPP_PAE, AUTHENTICATING); 269 sm->startCount = 0; 270 sm->suppSuccess = FALSE; 271 sm->suppFail = FALSE; 272 sm->suppTimeout = FALSE; 273 sm->keyRun = FALSE; 274 sm->keyDone = FALSE; 275 sm->suppStart = TRUE; 276} 277 278 279SM_STATE(SUPP_PAE, HELD) 280{ 281 SM_ENTRY(SUPP_PAE, HELD); 282 sm->heldWhile = sm->heldPeriod; 283 eapol_enable_timer_tick(sm); 284 sm->suppPortStatus = Unauthorized; 285 eapol_sm_set_port_unauthorized(sm); 286 sm->cb_status = EAPOL_CB_FAILURE; 287} 288 289 290SM_STATE(SUPP_PAE, AUTHENTICATED) 291{ 292 SM_ENTRY(SUPP_PAE, AUTHENTICATED); 293 sm->suppPortStatus = Authorized; 294 eapol_sm_set_port_authorized(sm); 295 sm->cb_status = EAPOL_CB_SUCCESS; 296} 297 298 299SM_STATE(SUPP_PAE, RESTART) 300{ 301 SM_ENTRY(SUPP_PAE, RESTART); 302 sm->eapRestart = TRUE; 303} 304 305 306SM_STATE(SUPP_PAE, S_FORCE_AUTH) 307{ 308 SM_ENTRY(SUPP_PAE, S_FORCE_AUTH); 309 sm->suppPortStatus = Authorized; 310 eapol_sm_set_port_authorized(sm); 311 sm->sPortMode = ForceAuthorized; 312} 313 314 315SM_STATE(SUPP_PAE, S_FORCE_UNAUTH) 316{ 317 SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH); 318 sm->suppPortStatus = Unauthorized; 319 eapol_sm_set_port_unauthorized(sm); 320 sm->sPortMode = ForceUnauthorized; 321 eapol_sm_txLogoff(sm); 322} 323 324 325SM_STEP(SUPP_PAE) 326{ 327 if ((sm->userLogoff && !sm->logoffSent) && 328 !(sm->initialize || !sm->portEnabled)) 329 SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF); 330 else if (((sm->portControl == Auto) && 331 (sm->sPortMode != sm->portControl)) || 332 sm->initialize || !sm->portEnabled) 333 SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED); 334 else if ((sm->portControl == ForceAuthorized) && 335 (sm->sPortMode != sm->portControl) && 336 !(sm->initialize || !sm->portEnabled)) 337 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH); 338 else if ((sm->portControl == ForceUnauthorized) && 339 (sm->sPortMode != sm->portControl) && 340 !(sm->initialize || !sm->portEnabled)) 341 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH); 342 else switch (sm->SUPP_PAE_state) { 343 case SUPP_PAE_UNKNOWN: 344 break; 345 case SUPP_PAE_LOGOFF: 346 if (!sm->userLogoff) 347 SM_ENTER(SUPP_PAE, DISCONNECTED); 348 break; 349 case SUPP_PAE_DISCONNECTED: 350 SM_ENTER(SUPP_PAE, CONNECTING); 351 break; 352 case SUPP_PAE_CONNECTING: 353 if (sm->startWhen == 0 && sm->startCount < sm->maxStart) 354 SM_ENTER(SUPP_PAE, CONNECTING); 355 else if (sm->startWhen == 0 && 356 sm->startCount >= sm->maxStart && 357 sm->portValid) 358 SM_ENTER(SUPP_PAE, AUTHENTICATED); 359 else if (sm->eapSuccess || sm->eapFail) 360 SM_ENTER(SUPP_PAE, AUTHENTICATING); 361 else if (sm->eapolEap) 362 SM_ENTER(SUPP_PAE, RESTART); 363 else if (sm->startWhen == 0 && 364 sm->startCount >= sm->maxStart && 365 !sm->portValid) 366 SM_ENTER(SUPP_PAE, HELD); 367 break; 368 case SUPP_PAE_AUTHENTICATING: 369 if (sm->eapSuccess && !sm->portValid && 370 sm->conf.accept_802_1x_keys && 371 sm->conf.required_keys == 0) { 372 wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for " 373 "plaintext connection; no EAPOL-Key frames " 374 "required"); 375 sm->portValid = TRUE; 376 if (sm->ctx->eapol_done_cb) 377 sm->ctx->eapol_done_cb(sm->ctx->ctx); 378 } 379 if (sm->eapSuccess && sm->portValid) 380 SM_ENTER(SUPP_PAE, AUTHENTICATED); 381 else if (sm->eapFail || (sm->keyDone && !sm->portValid)) 382 SM_ENTER(SUPP_PAE, HELD); 383 else if (sm->suppTimeout) 384 SM_ENTER(SUPP_PAE, CONNECTING); 385 break; 386 case SUPP_PAE_HELD: 387 if (sm->heldWhile == 0) 388 SM_ENTER(SUPP_PAE, CONNECTING); 389 else if (sm->eapolEap) 390 SM_ENTER(SUPP_PAE, RESTART); 391 break; 392 case SUPP_PAE_AUTHENTICATED: 393 if (sm->eapolEap && sm->portValid) 394 SM_ENTER(SUPP_PAE, RESTART); 395 else if (!sm->portValid) 396 SM_ENTER(SUPP_PAE, DISCONNECTED); 397 break; 398 case SUPP_PAE_RESTART: 399 if (!sm->eapRestart) 400 SM_ENTER(SUPP_PAE, AUTHENTICATING); 401 break; 402 case SUPP_PAE_S_FORCE_AUTH: 403 break; 404 case SUPP_PAE_S_FORCE_UNAUTH: 405 break; 406 } 407} 408 409 410SM_STATE(KEY_RX, NO_KEY_RECEIVE) 411{ 412 SM_ENTRY(KEY_RX, NO_KEY_RECEIVE); 413} 414 415 416SM_STATE(KEY_RX, KEY_RECEIVE) 417{ 418 SM_ENTRY(KEY_RX, KEY_RECEIVE); 419 eapol_sm_processKey(sm); 420 sm->rxKey = FALSE; 421} 422 423 424SM_STEP(KEY_RX) 425{ 426 if (sm->initialize || !sm->portEnabled) 427 SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE); 428 switch (sm->KEY_RX_state) { 429 case KEY_RX_UNKNOWN: 430 break; 431 case KEY_RX_NO_KEY_RECEIVE: 432 if (sm->rxKey) 433 SM_ENTER(KEY_RX, KEY_RECEIVE); 434 break; 435 case KEY_RX_KEY_RECEIVE: 436 if (sm->rxKey) 437 SM_ENTER(KEY_RX, KEY_RECEIVE); 438 break; 439 } 440} 441 442 443SM_STATE(SUPP_BE, REQUEST) 444{ 445 SM_ENTRY(SUPP_BE, REQUEST); 446 sm->authWhile = 0; 447 sm->eapReq = TRUE; 448 eapol_sm_getSuppRsp(sm); 449} 450 451 452SM_STATE(SUPP_BE, RESPONSE) 453{ 454 SM_ENTRY(SUPP_BE, RESPONSE); 455 eapol_sm_txSuppRsp(sm); 456 sm->eapResp = FALSE; 457} 458 459 460SM_STATE(SUPP_BE, SUCCESS) 461{ 462 SM_ENTRY(SUPP_BE, SUCCESS); 463 sm->keyRun = TRUE; 464 sm->suppSuccess = TRUE; 465 466 if (eap_key_available(sm->eap)) { 467 /* New key received - clear IEEE 802.1X EAPOL-Key replay 468 * counter */ 469 sm->replay_counter_valid = FALSE; 470 } 471} 472 473 474SM_STATE(SUPP_BE, FAIL) 475{ 476 SM_ENTRY(SUPP_BE, FAIL); 477 sm->suppFail = TRUE; 478} 479 480 481SM_STATE(SUPP_BE, TIMEOUT) 482{ 483 SM_ENTRY(SUPP_BE, TIMEOUT); 484 sm->suppTimeout = TRUE; 485} 486 487 488SM_STATE(SUPP_BE, IDLE) 489{ 490 SM_ENTRY(SUPP_BE, IDLE); 491 sm->suppStart = FALSE; 492 sm->initial_req = TRUE; 493} 494 495 496SM_STATE(SUPP_BE, INITIALIZE) 497{ 498 SM_ENTRY(SUPP_BE, INITIALIZE); 499 eapol_sm_abortSupp(sm); 500 sm->suppAbort = FALSE; 501 502 /* 503 * IEEE Std 802.1X-2004 does not clear authWhile here, but doing so 504 * allows the timer tick to be stopped more quickly when the port is 505 * not enabled. Since this variable is used only within RECEIVE state, 506 * clearing it on initialization does not change actual state machine 507 * behavior. 508 */ 509 sm->authWhile = 0; 510} 511 512 513SM_STATE(SUPP_BE, RECEIVE) 514{ 515 SM_ENTRY(SUPP_BE, RECEIVE); 516 sm->authWhile = sm->authPeriod; 517 eapol_enable_timer_tick(sm); 518 sm->eapolEap = FALSE; 519 sm->eapNoResp = FALSE; 520 sm->initial_req = FALSE; 521} 522 523 524SM_STEP(SUPP_BE) 525{ 526 if (sm->initialize || sm->suppAbort) 527 SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE); 528 else switch (sm->SUPP_BE_state) { 529 case SUPP_BE_UNKNOWN: 530 break; 531 case SUPP_BE_REQUEST: 532 /* 533 * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL 534 * and SUCCESS based on eapFail and eapSuccess, respectively. 535 * However, IEEE Std 802.1X-2004 is also specifying that 536 * eapNoResp should be set in conjunction with eapSuccess and 537 * eapFail which would mean that more than one of the 538 * transitions here would be activated at the same time. 539 * Skipping RESPONSE and/or RECEIVE states in these cases can 540 * cause problems and the direct transitions to do not seem 541 * correct. Because of this, the conditions for these 542 * transitions are verified only after eapNoResp. They are 543 * unlikely to be used since eapNoResp should always be set if 544 * either of eapSuccess or eapFail is set. 545 */ 546 if (sm->eapResp && sm->eapNoResp) { 547 wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both " 548 "eapResp and eapNoResp set?!"); 549 } 550 if (sm->eapResp) 551 SM_ENTER(SUPP_BE, RESPONSE); 552 else if (sm->eapNoResp) 553 SM_ENTER(SUPP_BE, RECEIVE); 554 else if (sm->eapFail) 555 SM_ENTER(SUPP_BE, FAIL); 556 else if (sm->eapSuccess) 557 SM_ENTER(SUPP_BE, SUCCESS); 558 break; 559 case SUPP_BE_RESPONSE: 560 SM_ENTER(SUPP_BE, RECEIVE); 561 break; 562 case SUPP_BE_SUCCESS: 563 SM_ENTER(SUPP_BE, IDLE); 564 break; 565 case SUPP_BE_FAIL: 566 SM_ENTER(SUPP_BE, IDLE); 567 break; 568 case SUPP_BE_TIMEOUT: 569 SM_ENTER(SUPP_BE, IDLE); 570 break; 571 case SUPP_BE_IDLE: 572 if (sm->eapFail && sm->suppStart) 573 SM_ENTER(SUPP_BE, FAIL); 574 else if (sm->eapolEap && sm->suppStart) 575 SM_ENTER(SUPP_BE, REQUEST); 576 else if (sm->eapSuccess && sm->suppStart) 577 SM_ENTER(SUPP_BE, SUCCESS); 578 break; 579 case SUPP_BE_INITIALIZE: 580 SM_ENTER(SUPP_BE, IDLE); 581 break; 582 case SUPP_BE_RECEIVE: 583 if (sm->eapolEap) 584 SM_ENTER(SUPP_BE, REQUEST); 585 else if (sm->eapFail) 586 SM_ENTER(SUPP_BE, FAIL); 587 else if (sm->authWhile == 0) 588 SM_ENTER(SUPP_BE, TIMEOUT); 589 else if (sm->eapSuccess) 590 SM_ENTER(SUPP_BE, SUCCESS); 591 break; 592 } 593} 594 595 596static void eapol_sm_txLogoff(struct eapol_sm *sm) 597{ 598 wpa_printf(MSG_DEBUG, "EAPOL: txLogoff"); 599 sm->ctx->eapol_send(sm->ctx->eapol_send_ctx, 600 IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0); 601 sm->dot1xSuppEapolLogoffFramesTx++; 602 sm->dot1xSuppEapolFramesTx++; 603} 604 605 606static void eapol_sm_txStart(struct eapol_sm *sm) 607{ 608 wpa_printf(MSG_DEBUG, "EAPOL: txStart"); 609 sm->ctx->eapol_send(sm->ctx->eapol_send_ctx, 610 IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0); 611 sm->dot1xSuppEapolStartFramesTx++; 612 sm->dot1xSuppEapolFramesTx++; 613} 614 615 616#define IEEE8021X_ENCR_KEY_LEN 32 617#define IEEE8021X_SIGN_KEY_LEN 32 618 619struct eap_key_data { 620 u8 encr_key[IEEE8021X_ENCR_KEY_LEN]; 621 u8 sign_key[IEEE8021X_SIGN_KEY_LEN]; 622}; 623 624 625static void eapol_sm_processKey(struct eapol_sm *sm) 626{ 627#ifndef CONFIG_FIPS 628 struct ieee802_1x_hdr *hdr; 629 struct ieee802_1x_eapol_key *key; 630 struct eap_key_data keydata; 631 u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32]; 632 u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN]; 633 int key_len, res, sign_key_len, encr_key_len; 634 u16 rx_key_length; 635 size_t plen; 636 637 wpa_printf(MSG_DEBUG, "EAPOL: processKey"); 638 if (sm->last_rx_key == NULL) 639 return; 640 641 if (!sm->conf.accept_802_1x_keys) { 642 wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key" 643 " even though this was not accepted - " 644 "ignoring this packet"); 645 return; 646 } 647 648 if (sm->last_rx_key_len < sizeof(*hdr) + sizeof(*key)) 649 return; 650 hdr = (struct ieee802_1x_hdr *) sm->last_rx_key; 651 key = (struct ieee802_1x_eapol_key *) (hdr + 1); 652 plen = be_to_host16(hdr->length); 653 if (sizeof(*hdr) + plen > sm->last_rx_key_len || plen < sizeof(*key)) { 654 wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame"); 655 return; 656 } 657 rx_key_length = WPA_GET_BE16(key->key_length); 658 wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d " 659 "EAPOL-Key: type=%d key_length=%d key_index=0x%x", 660 hdr->version, hdr->type, be_to_host16(hdr->length), 661 key->type, rx_key_length, key->key_index); 662 663 eapol_sm_notify_lower_layer_success(sm, 1); 664 sign_key_len = IEEE8021X_SIGN_KEY_LEN; 665 encr_key_len = IEEE8021X_ENCR_KEY_LEN; 666 res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata)); 667 if (res < 0) { 668 wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for " 669 "decrypting EAPOL-Key keys"); 670 return; 671 } 672 if (res == 16) { 673 /* LEAP derives only 16 bytes of keying material. */ 674 res = eapol_sm_get_key(sm, (u8 *) &keydata, 16); 675 if (res) { 676 wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP " 677 "master key for decrypting EAPOL-Key keys"); 678 return; 679 } 680 sign_key_len = 16; 681 encr_key_len = 16; 682 os_memcpy(keydata.sign_key, keydata.encr_key, 16); 683 } else if (res) { 684 wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key " 685 "data for decrypting EAPOL-Key keys (res=%d)", res); 686 return; 687 } 688 689 /* The key replay_counter must increase when same master key */ 690 if (sm->replay_counter_valid && 691 os_memcmp(sm->last_replay_counter, key->replay_counter, 692 IEEE8021X_REPLAY_COUNTER_LEN) >= 0) { 693 wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did " 694 "not increase - ignoring key"); 695 wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter", 696 sm->last_replay_counter, 697 IEEE8021X_REPLAY_COUNTER_LEN); 698 wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter", 699 key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN); 700 return; 701 } 702 703 /* Verify key signature (HMAC-MD5) */ 704 os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN); 705 os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN); 706 hmac_md5(keydata.sign_key, sign_key_len, 707 sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length), 708 key->key_signature); 709 if (os_memcmp(orig_key_sign, key->key_signature, 710 IEEE8021X_KEY_SIGN_LEN) != 0) { 711 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in " 712 "EAPOL-Key packet"); 713 os_memcpy(key->key_signature, orig_key_sign, 714 IEEE8021X_KEY_SIGN_LEN); 715 return; 716 } 717 wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified"); 718 719 key_len = plen - sizeof(*key); 720 if (key_len > 32 || rx_key_length > 32) { 721 wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d", 722 key_len ? key_len : rx_key_length); 723 return; 724 } 725 if (key_len == rx_key_length) { 726 os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN); 727 os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key, 728 encr_key_len); 729 os_memcpy(datakey, key + 1, key_len); 730 rc4_skip(ekey, IEEE8021X_KEY_IV_LEN + encr_key_len, 0, 731 datakey, key_len); 732 wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key", 733 datakey, key_len); 734 } else if (key_len == 0) { 735 /* 736 * IEEE 802.1X-2004 specifies that least significant Key Length 737 * octets from MS-MPPE-Send-Key are used as the key if the key 738 * data is not present. This seems to be meaning the beginning 739 * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in 740 * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator. 741 * Anyway, taking the beginning of the keying material from EAP 742 * seems to interoperate with Authenticators. 743 */ 744 key_len = rx_key_length; 745 os_memcpy(datakey, keydata.encr_key, key_len); 746 wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying " 747 "material data encryption key", 748 datakey, key_len); 749 } else { 750 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d " 751 "(key_length=%d)", key_len, rx_key_length); 752 return; 753 } 754 755 sm->replay_counter_valid = TRUE; 756 os_memcpy(sm->last_replay_counter, key->replay_counter, 757 IEEE8021X_REPLAY_COUNTER_LEN); 758 759 wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d " 760 "len %d", 761 key->key_index & IEEE8021X_KEY_INDEX_FLAG ? 762 "unicast" : "broadcast", 763 key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len); 764 765 if (sm->ctx->set_wep_key && 766 sm->ctx->set_wep_key(sm->ctx->ctx, 767 key->key_index & IEEE8021X_KEY_INDEX_FLAG, 768 key->key_index & IEEE8021X_KEY_INDEX_MASK, 769 datakey, key_len) < 0) { 770 wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the " 771 " driver."); 772 } else { 773 if (key->key_index & IEEE8021X_KEY_INDEX_FLAG) 774 sm->unicast_key_received = TRUE; 775 else 776 sm->broadcast_key_received = TRUE; 777 778 if ((sm->unicast_key_received || 779 !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) && 780 (sm->broadcast_key_received || 781 !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST))) 782 { 783 wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key " 784 "frames received"); 785 sm->portValid = TRUE; 786 if (sm->ctx->eapol_done_cb) 787 sm->ctx->eapol_done_cb(sm->ctx->ctx); 788 } 789 } 790#endif /* CONFIG_FIPS */ 791} 792 793 794static void eapol_sm_getSuppRsp(struct eapol_sm *sm) 795{ 796 wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp"); 797 /* EAP layer processing; no special code is needed, since Supplicant 798 * Backend state machine is waiting for eapNoResp or eapResp to be set 799 * and these are only set in the EAP state machine when the processing 800 * has finished. */ 801} 802 803 804static void eapol_sm_txSuppRsp(struct eapol_sm *sm) 805{ 806 struct wpabuf *resp; 807 808 wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp"); 809 resp = eap_get_eapRespData(sm->eap); 810 if (resp == NULL) { 811 wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data " 812 "not available"); 813 return; 814 } 815 816 /* Send EAP-Packet from the EAP layer to the Authenticator */ 817 sm->ctx->eapol_send(sm->ctx->eapol_send_ctx, 818 IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head(resp), 819 wpabuf_len(resp)); 820 821 /* eapRespData is not used anymore, so free it here */ 822 wpabuf_free(resp); 823 824 if (sm->initial_req) 825 sm->dot1xSuppEapolReqIdFramesRx++; 826 else 827 sm->dot1xSuppEapolReqFramesRx++; 828 sm->dot1xSuppEapolRespFramesTx++; 829 sm->dot1xSuppEapolFramesTx++; 830} 831 832 833static void eapol_sm_abortSupp(struct eapol_sm *sm) 834{ 835 /* release system resources that may have been allocated for the 836 * authentication session */ 837 os_free(sm->last_rx_key); 838 sm->last_rx_key = NULL; 839 wpabuf_free(sm->eapReqData); 840 sm->eapReqData = NULL; 841 eap_sm_abort(sm->eap); 842} 843 844 845static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx) 846{ 847 eapol_sm_step(timeout_ctx); 848} 849 850 851static void eapol_sm_set_port_authorized(struct eapol_sm *sm) 852{ 853 if (sm->ctx->port_cb) 854 sm->ctx->port_cb(sm->ctx->ctx, 1); 855} 856 857 858static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm) 859{ 860 if (sm->ctx->port_cb) 861 sm->ctx->port_cb(sm->ctx->ctx, 0); 862} 863 864 865/** 866 * eapol_sm_step - EAPOL state machine step function 867 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 868 * 869 * This function is called to notify the state machine about changed external 870 * variables. It will step through the EAPOL state machines in loop to process 871 * all triggered state changes. 872 */ 873void eapol_sm_step(struct eapol_sm *sm) 874{ 875 int i; 876 877 /* In theory, it should be ok to run this in loop until !changed. 878 * However, it is better to use a limit on number of iterations to 879 * allow events (e.g., SIGTERM) to stop the program cleanly if the 880 * state machine were to generate a busy loop. */ 881 for (i = 0; i < 100; i++) { 882 sm->changed = FALSE; 883 SM_STEP_RUN(SUPP_PAE); 884 SM_STEP_RUN(KEY_RX); 885 SM_STEP_RUN(SUPP_BE); 886 if (eap_peer_sm_step(sm->eap)) 887 sm->changed = TRUE; 888 if (!sm->changed) 889 break; 890 } 891 892 if (sm->changed) { 893 /* restart EAPOL state machine step from timeout call in order 894 * to allow other events to be processed. */ 895 eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm); 896 eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm); 897 } 898 899 if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) { 900 int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0; 901 sm->cb_status = EAPOL_CB_IN_PROGRESS; 902 sm->ctx->cb(sm, success, sm->ctx->cb_ctx); 903 } 904} 905 906 907#ifdef CONFIG_CTRL_IFACE 908static const char *eapol_supp_pae_state(int state) 909{ 910 switch (state) { 911 case SUPP_PAE_LOGOFF: 912 return "LOGOFF"; 913 case SUPP_PAE_DISCONNECTED: 914 return "DISCONNECTED"; 915 case SUPP_PAE_CONNECTING: 916 return "CONNECTING"; 917 case SUPP_PAE_AUTHENTICATING: 918 return "AUTHENTICATING"; 919 case SUPP_PAE_HELD: 920 return "HELD"; 921 case SUPP_PAE_AUTHENTICATED: 922 return "AUTHENTICATED"; 923 case SUPP_PAE_RESTART: 924 return "RESTART"; 925 default: 926 return "UNKNOWN"; 927 } 928} 929 930 931static const char *eapol_supp_be_state(int state) 932{ 933 switch (state) { 934 case SUPP_BE_REQUEST: 935 return "REQUEST"; 936 case SUPP_BE_RESPONSE: 937 return "RESPONSE"; 938 case SUPP_BE_SUCCESS: 939 return "SUCCESS"; 940 case SUPP_BE_FAIL: 941 return "FAIL"; 942 case SUPP_BE_TIMEOUT: 943 return "TIMEOUT"; 944 case SUPP_BE_IDLE: 945 return "IDLE"; 946 case SUPP_BE_INITIALIZE: 947 return "INITIALIZE"; 948 case SUPP_BE_RECEIVE: 949 return "RECEIVE"; 950 default: 951 return "UNKNOWN"; 952 } 953} 954 955 956static const char * eapol_port_status(PortStatus status) 957{ 958 if (status == Authorized) 959 return "Authorized"; 960 else 961 return "Unauthorized"; 962} 963#endif /* CONFIG_CTRL_IFACE */ 964 965 966#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) 967static const char * eapol_port_control(PortControl ctrl) 968{ 969 switch (ctrl) { 970 case Auto: 971 return "Auto"; 972 case ForceUnauthorized: 973 return "ForceUnauthorized"; 974 case ForceAuthorized: 975 return "ForceAuthorized"; 976 default: 977 return "Unknown"; 978 } 979} 980#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ 981 982 983/** 984 * eapol_sm_configure - Set EAPOL variables 985 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 986 * @heldPeriod: dot1xSuppHeldPeriod 987 * @authPeriod: dot1xSuppAuthPeriod 988 * @startPeriod: dot1xSuppStartPeriod 989 * @maxStart: dot1xSuppMaxStart 990 * 991 * Set configurable EAPOL state machine variables. Each variable can be set to 992 * the given value or ignored if set to -1 (to set only some of the variables). 993 */ 994void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod, 995 int startPeriod, int maxStart) 996{ 997 if (sm == NULL) 998 return; 999 if (heldPeriod >= 0) 1000 sm->heldPeriod = heldPeriod; 1001 if (authPeriod >= 0) 1002 sm->authPeriod = authPeriod; 1003 if (startPeriod >= 0) 1004 sm->startPeriod = startPeriod; 1005 if (maxStart >= 0) 1006 sm->maxStart = maxStart; 1007} 1008 1009 1010/** 1011 * eapol_sm_get_method_name - Get EAPOL method name 1012 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1013 * Returns: Static string containing name of current eap method or NULL 1014 */ 1015const char * eapol_sm_get_method_name(struct eapol_sm *sm) 1016{ 1017 if (sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED || 1018 sm->suppPortStatus != Authorized) 1019 return NULL; 1020 1021 return eap_sm_get_method_name(sm->eap); 1022} 1023 1024 1025#ifdef CONFIG_CTRL_IFACE 1026/** 1027 * eapol_sm_get_status - Get EAPOL state machine status 1028 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1029 * @buf: Buffer for status information 1030 * @buflen: Maximum buffer length 1031 * @verbose: Whether to include verbose status information 1032 * Returns: Number of bytes written to buf. 1033 * 1034 * Query EAPOL state machine for status information. This function fills in a 1035 * text area with current status information from the EAPOL state machine. If 1036 * the buffer (buf) is not large enough, status information will be truncated 1037 * to fit the buffer. 1038 */ 1039int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen, 1040 int verbose) 1041{ 1042 int len, ret; 1043 if (sm == NULL) 1044 return 0; 1045 1046 len = os_snprintf(buf, buflen, 1047 "Supplicant PAE state=%s\n" 1048 "suppPortStatus=%s\n", 1049 eapol_supp_pae_state(sm->SUPP_PAE_state), 1050 eapol_port_status(sm->suppPortStatus)); 1051 if (len < 0 || (size_t) len >= buflen) 1052 return 0; 1053 1054 if (verbose) { 1055 ret = os_snprintf(buf + len, buflen - len, 1056 "heldPeriod=%u\n" 1057 "authPeriod=%u\n" 1058 "startPeriod=%u\n" 1059 "maxStart=%u\n" 1060 "portControl=%s\n" 1061 "Supplicant Backend state=%s\n", 1062 sm->heldPeriod, 1063 sm->authPeriod, 1064 sm->startPeriod, 1065 sm->maxStart, 1066 eapol_port_control(sm->portControl), 1067 eapol_supp_be_state(sm->SUPP_BE_state)); 1068 if (ret < 0 || (size_t) ret >= buflen - len) 1069 return len; 1070 len += ret; 1071 } 1072 1073 len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose); 1074 1075 return len; 1076} 1077 1078 1079/** 1080 * eapol_sm_get_mib - Get EAPOL state machine MIBs 1081 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1082 * @buf: Buffer for MIB information 1083 * @buflen: Maximum buffer length 1084 * Returns: Number of bytes written to buf. 1085 * 1086 * Query EAPOL state machine for MIB information. This function fills in a 1087 * text area with current MIB information from the EAPOL state machine. If 1088 * the buffer (buf) is not large enough, MIB information will be truncated to 1089 * fit the buffer. 1090 */ 1091int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen) 1092{ 1093 size_t len; 1094 int ret; 1095 1096 if (sm == NULL) 1097 return 0; 1098 ret = os_snprintf(buf, buflen, 1099 "dot1xSuppPaeState=%d\n" 1100 "dot1xSuppHeldPeriod=%u\n" 1101 "dot1xSuppAuthPeriod=%u\n" 1102 "dot1xSuppStartPeriod=%u\n" 1103 "dot1xSuppMaxStart=%u\n" 1104 "dot1xSuppSuppControlledPortStatus=%s\n" 1105 "dot1xSuppBackendPaeState=%d\n", 1106 sm->SUPP_PAE_state, 1107 sm->heldPeriod, 1108 sm->authPeriod, 1109 sm->startPeriod, 1110 sm->maxStart, 1111 sm->suppPortStatus == Authorized ? 1112 "Authorized" : "Unauthorized", 1113 sm->SUPP_BE_state); 1114 1115 if (ret < 0 || (size_t) ret >= buflen) 1116 return 0; 1117 len = ret; 1118 1119 ret = os_snprintf(buf + len, buflen - len, 1120 "dot1xSuppEapolFramesRx=%u\n" 1121 "dot1xSuppEapolFramesTx=%u\n" 1122 "dot1xSuppEapolStartFramesTx=%u\n" 1123 "dot1xSuppEapolLogoffFramesTx=%u\n" 1124 "dot1xSuppEapolRespFramesTx=%u\n" 1125 "dot1xSuppEapolReqIdFramesRx=%u\n" 1126 "dot1xSuppEapolReqFramesRx=%u\n" 1127 "dot1xSuppInvalidEapolFramesRx=%u\n" 1128 "dot1xSuppEapLengthErrorFramesRx=%u\n" 1129 "dot1xSuppLastEapolFrameVersion=%u\n" 1130 "dot1xSuppLastEapolFrameSource=" MACSTR "\n", 1131 sm->dot1xSuppEapolFramesRx, 1132 sm->dot1xSuppEapolFramesTx, 1133 sm->dot1xSuppEapolStartFramesTx, 1134 sm->dot1xSuppEapolLogoffFramesTx, 1135 sm->dot1xSuppEapolRespFramesTx, 1136 sm->dot1xSuppEapolReqIdFramesRx, 1137 sm->dot1xSuppEapolReqFramesRx, 1138 sm->dot1xSuppInvalidEapolFramesRx, 1139 sm->dot1xSuppEapLengthErrorFramesRx, 1140 sm->dot1xSuppLastEapolFrameVersion, 1141 MAC2STR(sm->dot1xSuppLastEapolFrameSource)); 1142 1143 if (ret < 0 || (size_t) ret >= buflen - len) 1144 return len; 1145 len += ret; 1146 1147 return len; 1148} 1149#endif /* CONFIG_CTRL_IFACE */ 1150 1151 1152/** 1153 * eapol_sm_rx_eapol - Process received EAPOL frames 1154 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1155 * @src: Source MAC address of the EAPOL packet 1156 * @buf: Pointer to the beginning of the EAPOL data (EAPOL header) 1157 * @len: Length of the EAPOL frame 1158 * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine, 1159 * -1 failure 1160 */ 1161int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf, 1162 size_t len) 1163{ 1164 const struct ieee802_1x_hdr *hdr; 1165 const struct ieee802_1x_eapol_key *key; 1166 int data_len; 1167 int res = 1; 1168 size_t plen; 1169 1170 if (sm == NULL) 1171 return 0; 1172 sm->dot1xSuppEapolFramesRx++; 1173 if (len < sizeof(*hdr)) { 1174 sm->dot1xSuppInvalidEapolFramesRx++; 1175 return 0; 1176 } 1177 hdr = (const struct ieee802_1x_hdr *) buf; 1178 sm->dot1xSuppLastEapolFrameVersion = hdr->version; 1179 os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN); 1180 if (hdr->version < EAPOL_VERSION) { 1181 /* TODO: backwards compatibility */ 1182 } 1183 plen = be_to_host16(hdr->length); 1184 if (plen > len - sizeof(*hdr)) { 1185 sm->dot1xSuppEapLengthErrorFramesRx++; 1186 return 0; 1187 } 1188#ifdef CONFIG_WPS 1189 if (sm->conf.workaround && 1190 plen < len - sizeof(*hdr) && 1191 hdr->type == IEEE802_1X_TYPE_EAP_PACKET && 1192 len - sizeof(*hdr) > sizeof(struct eap_hdr)) { 1193 const struct eap_hdr *ehdr = 1194 (const struct eap_hdr *) (hdr + 1); 1195 u16 elen; 1196 1197 elen = be_to_host16(ehdr->length); 1198 if (elen > plen && elen <= len - sizeof(*hdr)) { 1199 /* 1200 * Buffalo WHR-G125 Ver.1.47 seems to send EAP-WPS 1201 * packets with too short EAPOL header length field 1202 * (14 octets). This is fixed in firmware Ver.1.49. 1203 * As a workaround, fix the EAPOL header based on the 1204 * correct length in the EAP packet. 1205 */ 1206 wpa_printf(MSG_DEBUG, "EAPOL: Workaround - fix EAPOL " 1207 "payload length based on EAP header: " 1208 "%d -> %d", (int) plen, elen); 1209 plen = elen; 1210 } 1211 } 1212#endif /* CONFIG_WPS */ 1213 data_len = plen + sizeof(*hdr); 1214 1215 switch (hdr->type) { 1216 case IEEE802_1X_TYPE_EAP_PACKET: 1217 if (sm->cached_pmk) { 1218 /* Trying to use PMKSA caching, but Authenticator did 1219 * not seem to have a matching entry. Need to restart 1220 * EAPOL state machines. 1221 */ 1222 eapol_sm_abort_cached(sm); 1223 } 1224 wpabuf_free(sm->eapReqData); 1225 sm->eapReqData = wpabuf_alloc_copy(hdr + 1, plen); 1226 if (sm->eapReqData) { 1227 wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet " 1228 "frame"); 1229 sm->eapolEap = TRUE; 1230 eapol_sm_step(sm); 1231 } 1232 break; 1233 case IEEE802_1X_TYPE_EAPOL_KEY: 1234 if (plen < sizeof(*key)) { 1235 wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key " 1236 "frame received"); 1237 break; 1238 } 1239 key = (const struct ieee802_1x_eapol_key *) (hdr + 1); 1240 if (key->type == EAPOL_KEY_TYPE_WPA || 1241 key->type == EAPOL_KEY_TYPE_RSN) { 1242 /* WPA Supplicant takes care of this frame. */ 1243 wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key " 1244 "frame in EAPOL state machines"); 1245 res = 0; 1246 break; 1247 } 1248 if (key->type != EAPOL_KEY_TYPE_RC4) { 1249 wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown " 1250 "EAPOL-Key type %d", key->type); 1251 break; 1252 } 1253 os_free(sm->last_rx_key); 1254 sm->last_rx_key = os_malloc(data_len); 1255 if (sm->last_rx_key) { 1256 wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key " 1257 "frame"); 1258 os_memcpy(sm->last_rx_key, buf, data_len); 1259 sm->last_rx_key_len = data_len; 1260 sm->rxKey = TRUE; 1261 eapol_sm_step(sm); 1262 } 1263 break; 1264 default: 1265 wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d", 1266 hdr->type); 1267 sm->dot1xSuppInvalidEapolFramesRx++; 1268 break; 1269 } 1270 1271 return res; 1272} 1273 1274 1275/** 1276 * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet 1277 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1278 * 1279 * Notify EAPOL state machine about transmitted EAPOL packet from an external 1280 * component, e.g., WPA. This will update the statistics. 1281 */ 1282void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm) 1283{ 1284 if (sm) 1285 sm->dot1xSuppEapolFramesTx++; 1286} 1287 1288 1289/** 1290 * eapol_sm_notify_portEnabled - Notification about portEnabled change 1291 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1292 * @enabled: New portEnabled value 1293 * 1294 * Notify EAPOL state machine about new portEnabled value. 1295 */ 1296void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled) 1297{ 1298 if (sm == NULL) 1299 return; 1300 wpa_printf(MSG_DEBUG, "EAPOL: External notification - " 1301 "portEnabled=%d", enabled); 1302 sm->portEnabled = enabled; 1303 eapol_sm_step(sm); 1304} 1305 1306 1307/** 1308 * eapol_sm_notify_portValid - Notification about portValid change 1309 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1310 * @valid: New portValid value 1311 * 1312 * Notify EAPOL state machine about new portValid value. 1313 */ 1314void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid) 1315{ 1316 if (sm == NULL) 1317 return; 1318 wpa_printf(MSG_DEBUG, "EAPOL: External notification - " 1319 "portValid=%d", valid); 1320 sm->portValid = valid; 1321 eapol_sm_step(sm); 1322} 1323 1324 1325/** 1326 * eapol_sm_notify_eap_success - Notification of external EAP success trigger 1327 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1328 * @success: %TRUE = set success, %FALSE = clear success 1329 * 1330 * Notify the EAPOL state machine that external event has forced EAP state to 1331 * success (success = %TRUE). This can be cleared by setting success = %FALSE. 1332 * 1333 * This function is called to update EAP state when WPA-PSK key handshake has 1334 * been completed successfully since WPA-PSK does not use EAP state machine. 1335 */ 1336void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success) 1337{ 1338 if (sm == NULL) 1339 return; 1340 wpa_printf(MSG_DEBUG, "EAPOL: External notification - " 1341 "EAP success=%d", success); 1342 sm->eapSuccess = success; 1343 sm->altAccept = success; 1344 if (success) 1345 eap_notify_success(sm->eap); 1346 eapol_sm_step(sm); 1347} 1348 1349 1350/** 1351 * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger 1352 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1353 * @fail: %TRUE = set failure, %FALSE = clear failure 1354 * 1355 * Notify EAPOL state machine that external event has forced EAP state to 1356 * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE. 1357 */ 1358void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail) 1359{ 1360 if (sm == NULL) 1361 return; 1362 wpa_printf(MSG_DEBUG, "EAPOL: External notification - " 1363 "EAP fail=%d", fail); 1364 sm->eapFail = fail; 1365 sm->altReject = fail; 1366 eapol_sm_step(sm); 1367} 1368 1369 1370/** 1371 * eapol_sm_notify_config - Notification of EAPOL configuration change 1372 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1373 * @config: Pointer to current network EAP configuration 1374 * @conf: Pointer to EAPOL configuration data 1375 * 1376 * Notify EAPOL state machine that configuration has changed. config will be 1377 * stored as a backpointer to network configuration. This can be %NULL to clear 1378 * the stored pointed. conf will be copied to local EAPOL/EAP configuration 1379 * data. If conf is %NULL, this part of the configuration change will be 1380 * skipped. 1381 */ 1382void eapol_sm_notify_config(struct eapol_sm *sm, 1383 struct eap_peer_config *config, 1384 const struct eapol_config *conf) 1385{ 1386 if (sm == NULL) 1387 return; 1388 1389 sm->config = config; 1390 1391 if (conf == NULL) 1392 return; 1393 1394 sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys; 1395 sm->conf.required_keys = conf->required_keys; 1396 sm->conf.fast_reauth = conf->fast_reauth; 1397 sm->conf.workaround = conf->workaround; 1398 if (sm->eap) { 1399 eap_set_fast_reauth(sm->eap, conf->fast_reauth); 1400 eap_set_workaround(sm->eap, conf->workaround); 1401 eap_set_force_disabled(sm->eap, conf->eap_disabled); 1402 } 1403} 1404 1405 1406/** 1407 * eapol_sm_get_key - Get master session key (MSK) from EAP 1408 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1409 * @key: Pointer for key buffer 1410 * @len: Number of bytes to copy to key 1411 * Returns: 0 on success (len of key available), maximum available key len 1412 * (>0) if key is available but it is shorter than len, or -1 on failure. 1413 * 1414 * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key 1415 * is available only after a successful authentication. 1416 */ 1417int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len) 1418{ 1419 const u8 *eap_key; 1420 size_t eap_len; 1421 1422 if (sm == NULL || !eap_key_available(sm->eap)) { 1423 wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available"); 1424 return -1; 1425 } 1426 eap_key = eap_get_eapKeyData(sm->eap, &eap_len); 1427 if (eap_key == NULL) { 1428 wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData"); 1429 return -1; 1430 } 1431 if (len > eap_len) { 1432 wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not " 1433 "available (len=%lu)", 1434 (unsigned long) len, (unsigned long) eap_len); 1435 return eap_len; 1436 } 1437 os_memcpy(key, eap_key, len); 1438 wpa_printf(MSG_DEBUG, "EAPOL: Successfully fetched key (len=%lu)", 1439 (unsigned long) len); 1440 return 0; 1441} 1442 1443 1444/** 1445 * eapol_sm_notify_logoff - Notification of logon/logoff commands 1446 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1447 * @logoff: Whether command was logoff 1448 * 1449 * Notify EAPOL state machines that user requested logon/logoff. 1450 */ 1451void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff) 1452{ 1453 if (sm) { 1454 sm->userLogoff = logoff; 1455 eapol_sm_step(sm); 1456 } 1457} 1458 1459 1460/** 1461 * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching 1462 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1463 * 1464 * Notify EAPOL state machines that PMKSA caching was successful. This is used 1465 * to move EAPOL and EAP state machines into authenticated/successful state. 1466 */ 1467void eapol_sm_notify_cached(struct eapol_sm *sm) 1468{ 1469 if (sm == NULL) 1470 return; 1471 wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL"); 1472 sm->SUPP_PAE_state = SUPP_PAE_AUTHENTICATED; 1473 sm->suppPortStatus = Authorized; 1474 eapol_sm_set_port_authorized(sm); 1475 sm->portValid = TRUE; 1476 eap_notify_success(sm->eap); 1477 eapol_sm_step(sm); 1478} 1479 1480 1481/** 1482 * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching 1483 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1484 * @attempt: Whether PMKSA caching is tried 1485 * 1486 * Notify EAPOL state machines whether PMKSA caching is used. 1487 */ 1488void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt) 1489{ 1490 if (sm == NULL) 1491 return; 1492 if (attempt) { 1493 wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA"); 1494 sm->cached_pmk = TRUE; 1495 } else { 1496 wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA"); 1497 sm->cached_pmk = FALSE; 1498 } 1499} 1500 1501 1502static void eapol_sm_abort_cached(struct eapol_sm *sm) 1503{ 1504 wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, " 1505 "doing full EAP authentication"); 1506 if (sm == NULL) 1507 return; 1508 sm->cached_pmk = FALSE; 1509 sm->SUPP_PAE_state = SUPP_PAE_CONNECTING; 1510 sm->suppPortStatus = Unauthorized; 1511 eapol_sm_set_port_unauthorized(sm); 1512 1513 /* Make sure we do not start sending EAPOL-Start frames first, but 1514 * instead move to RESTART state to start EAPOL authentication. */ 1515 sm->startWhen = 3; 1516 eapol_enable_timer_tick(sm); 1517 1518 if (sm->ctx->aborted_cached) 1519 sm->ctx->aborted_cached(sm->ctx->ctx); 1520} 1521 1522 1523/** 1524 * eapol_sm_register_scard_ctx - Notification of smart card context 1525 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1526 * @ctx: Context data for smart card operations 1527 * 1528 * Notify EAPOL state machines of context data for smart card operations. This 1529 * context data will be used as a parameter for scard_*() functions. 1530 */ 1531void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx) 1532{ 1533 if (sm) { 1534 sm->ctx->scard_ctx = ctx; 1535 eap_register_scard_ctx(sm->eap, ctx); 1536 } 1537} 1538 1539 1540/** 1541 * eapol_sm_notify_portControl - Notification of portControl changes 1542 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1543 * @portControl: New value for portControl variable 1544 * 1545 * Notify EAPOL state machines that portControl variable has changed. 1546 */ 1547void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl) 1548{ 1549 if (sm == NULL) 1550 return; 1551 wpa_printf(MSG_DEBUG, "EAPOL: External notification - " 1552 "portControl=%s", eapol_port_control(portControl)); 1553 sm->portControl = portControl; 1554 eapol_sm_step(sm); 1555} 1556 1557 1558/** 1559 * eapol_sm_notify_ctrl_attached - Notification of attached monitor 1560 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1561 * 1562 * Notify EAPOL state machines that a monitor was attached to the control 1563 * interface to trigger re-sending of pending requests for user input. 1564 */ 1565void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm) 1566{ 1567 if (sm == NULL) 1568 return; 1569 eap_sm_notify_ctrl_attached(sm->eap); 1570} 1571 1572 1573/** 1574 * eapol_sm_notify_ctrl_response - Notification of received user input 1575 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1576 * 1577 * Notify EAPOL state machines that a control response, i.e., user 1578 * input, was received in order to trigger retrying of a pending EAP request. 1579 */ 1580void eapol_sm_notify_ctrl_response(struct eapol_sm *sm) 1581{ 1582 if (sm == NULL) 1583 return; 1584 if (sm->eapReqData && !sm->eapReq) { 1585 wpa_printf(MSG_DEBUG, "EAPOL: received control response (user " 1586 "input) notification - retrying pending EAP " 1587 "Request"); 1588 sm->eapolEap = TRUE; 1589 sm->eapReq = TRUE; 1590 eapol_sm_step(sm); 1591 } 1592} 1593 1594 1595/** 1596 * eapol_sm_request_reauth - Request reauthentication 1597 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1598 * 1599 * This function can be used to request EAPOL reauthentication, e.g., when the 1600 * current PMKSA entry is nearing expiration. 1601 */ 1602void eapol_sm_request_reauth(struct eapol_sm *sm) 1603{ 1604 if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED) 1605 return; 1606 eapol_sm_txStart(sm); 1607} 1608 1609 1610/** 1611 * eapol_sm_notify_lower_layer_success - Notification of lower layer success 1612 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1613 * @in_eapol_sm: Whether the caller is already running inside EAPOL state 1614 * machine loop (eapol_sm_step()) 1615 * 1616 * Notify EAPOL (and EAP) state machines that a lower layer has detected a 1617 * successful authentication. This is used to recover from dropped EAP-Success 1618 * messages. 1619 */ 1620void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm) 1621{ 1622 if (sm == NULL) 1623 return; 1624 eap_notify_lower_layer_success(sm->eap); 1625 if (!in_eapol_sm) 1626 eapol_sm_step(sm); 1627} 1628 1629 1630/** 1631 * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid 1632 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1633 */ 1634void eapol_sm_invalidate_cached_session(struct eapol_sm *sm) 1635{ 1636 if (sm) 1637 eap_invalidate_cached_session(sm->eap); 1638} 1639 1640 1641static struct eap_peer_config * eapol_sm_get_config(void *ctx) 1642{ 1643 struct eapol_sm *sm = ctx; 1644 return sm ? sm->config : NULL; 1645} 1646 1647 1648static struct wpabuf * eapol_sm_get_eapReqData(void *ctx) 1649{ 1650 struct eapol_sm *sm = ctx; 1651 if (sm == NULL || sm->eapReqData == NULL) 1652 return NULL; 1653 1654 return sm->eapReqData; 1655} 1656 1657 1658static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable) 1659{ 1660 struct eapol_sm *sm = ctx; 1661 if (sm == NULL) 1662 return FALSE; 1663 switch (variable) { 1664 case EAPOL_eapSuccess: 1665 return sm->eapSuccess; 1666 case EAPOL_eapRestart: 1667 return sm->eapRestart; 1668 case EAPOL_eapFail: 1669 return sm->eapFail; 1670 case EAPOL_eapResp: 1671 return sm->eapResp; 1672 case EAPOL_eapNoResp: 1673 return sm->eapNoResp; 1674 case EAPOL_eapReq: 1675 return sm->eapReq; 1676 case EAPOL_portEnabled: 1677 return sm->portEnabled; 1678 case EAPOL_altAccept: 1679 return sm->altAccept; 1680 case EAPOL_altReject: 1681 return sm->altReject; 1682 } 1683 return FALSE; 1684} 1685 1686 1687static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable, 1688 Boolean value) 1689{ 1690 struct eapol_sm *sm = ctx; 1691 if (sm == NULL) 1692 return; 1693 switch (variable) { 1694 case EAPOL_eapSuccess: 1695 sm->eapSuccess = value; 1696 break; 1697 case EAPOL_eapRestart: 1698 sm->eapRestart = value; 1699 break; 1700 case EAPOL_eapFail: 1701 sm->eapFail = value; 1702 break; 1703 case EAPOL_eapResp: 1704 sm->eapResp = value; 1705 break; 1706 case EAPOL_eapNoResp: 1707 sm->eapNoResp = value; 1708 break; 1709 case EAPOL_eapReq: 1710 sm->eapReq = value; 1711 break; 1712 case EAPOL_portEnabled: 1713 sm->portEnabled = value; 1714 break; 1715 case EAPOL_altAccept: 1716 sm->altAccept = value; 1717 break; 1718 case EAPOL_altReject: 1719 sm->altReject = value; 1720 break; 1721 } 1722} 1723 1724 1725static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable) 1726{ 1727 struct eapol_sm *sm = ctx; 1728 if (sm == NULL) 1729 return 0; 1730 switch (variable) { 1731 case EAPOL_idleWhile: 1732 return sm->idleWhile; 1733 } 1734 return 0; 1735} 1736 1737 1738static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable, 1739 unsigned int value) 1740{ 1741 struct eapol_sm *sm = ctx; 1742 if (sm == NULL) 1743 return; 1744 switch (variable) { 1745 case EAPOL_idleWhile: 1746 sm->idleWhile = value; 1747 if (sm->idleWhile > 0) 1748 eapol_enable_timer_tick(sm); 1749 break; 1750 } 1751} 1752 1753 1754static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob) 1755{ 1756#ifndef CONFIG_NO_CONFIG_BLOBS 1757 struct eapol_sm *sm = ctx; 1758 if (sm && sm->ctx && sm->ctx->set_config_blob) 1759 sm->ctx->set_config_blob(sm->ctx->ctx, blob); 1760#endif /* CONFIG_NO_CONFIG_BLOBS */ 1761} 1762 1763 1764static const struct wpa_config_blob * 1765eapol_sm_get_config_blob(void *ctx, const char *name) 1766{ 1767#ifndef CONFIG_NO_CONFIG_BLOBS 1768 struct eapol_sm *sm = ctx; 1769 if (sm && sm->ctx && sm->ctx->get_config_blob) 1770 return sm->ctx->get_config_blob(sm->ctx->ctx, name); 1771 else 1772 return NULL; 1773#else /* CONFIG_NO_CONFIG_BLOBS */ 1774 return NULL; 1775#endif /* CONFIG_NO_CONFIG_BLOBS */ 1776} 1777 1778 1779static void eapol_sm_notify_pending(void *ctx) 1780{ 1781 struct eapol_sm *sm = ctx; 1782 if (sm == NULL) 1783 return; 1784 if (sm->eapReqData && !sm->eapReq) { 1785 wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP " 1786 "state machine - retrying pending EAP Request"); 1787 sm->eapolEap = TRUE; 1788 sm->eapReq = TRUE; 1789 eapol_sm_step(sm); 1790 } 1791} 1792 1793 1794#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) 1795static void eapol_sm_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field, 1796 const char *txt) 1797{ 1798 struct eapol_sm *sm = ctx; 1799 wpa_printf(MSG_DEBUG, "EAPOL: EAP parameter needed"); 1800 if (sm->ctx->eap_param_needed) 1801 sm->ctx->eap_param_needed(sm->ctx->ctx, field, txt); 1802} 1803#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ 1804#define eapol_sm_eap_param_needed NULL 1805#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ 1806 1807static void eapol_sm_notify_cert(void *ctx, int depth, const char *subject, 1808 const char *cert_hash, 1809 const struct wpabuf *cert) 1810{ 1811 struct eapol_sm *sm = ctx; 1812 if (sm->ctx->cert_cb) 1813 sm->ctx->cert_cb(sm->ctx->ctx, depth, subject, 1814 cert_hash, cert); 1815} 1816 1817 1818static void eapol_sm_notify_status(void *ctx, const char *status, 1819 const char *parameter) 1820{ 1821 struct eapol_sm *sm = ctx; 1822 1823 if (sm->ctx->status_cb) 1824 sm->ctx->status_cb(sm->ctx->ctx, status, parameter); 1825} 1826 1827 1828static void eapol_sm_set_anon_id(void *ctx, const u8 *id, size_t len) 1829{ 1830 struct eapol_sm *sm = ctx; 1831 1832 if (sm->ctx->set_anon_id) 1833 sm->ctx->set_anon_id(sm->ctx->ctx, id, len); 1834} 1835 1836 1837static struct eapol_callbacks eapol_cb = 1838{ 1839 eapol_sm_get_config, 1840 eapol_sm_get_bool, 1841 eapol_sm_set_bool, 1842 eapol_sm_get_int, 1843 eapol_sm_set_int, 1844 eapol_sm_get_eapReqData, 1845 eapol_sm_set_config_blob, 1846 eapol_sm_get_config_blob, 1847 eapol_sm_notify_pending, 1848 eapol_sm_eap_param_needed, 1849 eapol_sm_notify_cert, 1850 eapol_sm_notify_status, 1851 eapol_sm_set_anon_id 1852}; 1853 1854 1855/** 1856 * eapol_sm_init - Initialize EAPOL state machine 1857 * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer 1858 * and EAPOL state machine will free it in eapol_sm_deinit() 1859 * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure 1860 * 1861 * Allocate and initialize an EAPOL state machine. 1862 */ 1863struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx) 1864{ 1865 struct eapol_sm *sm; 1866 struct eap_config conf; 1867 sm = os_zalloc(sizeof(*sm)); 1868 if (sm == NULL) 1869 return NULL; 1870 sm->ctx = ctx; 1871 1872 sm->portControl = Auto; 1873 1874 /* Supplicant PAE state machine */ 1875 sm->heldPeriod = 60; 1876 sm->startPeriod = 30; 1877 sm->maxStart = 3; 1878 1879 /* Supplicant Backend state machine */ 1880 sm->authPeriod = 30; 1881 1882 os_memset(&conf, 0, sizeof(conf)); 1883 conf.opensc_engine_path = ctx->opensc_engine_path; 1884 conf.pkcs11_engine_path = ctx->pkcs11_engine_path; 1885 conf.pkcs11_module_path = ctx->pkcs11_module_path; 1886 conf.wps = ctx->wps; 1887 conf.cert_in_cb = ctx->cert_in_cb; 1888 1889 sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf); 1890 if (sm->eap == NULL) { 1891 os_free(sm); 1892 return NULL; 1893 } 1894 1895 /* Initialize EAPOL state machines */ 1896 sm->initialize = TRUE; 1897 eapol_sm_step(sm); 1898 sm->initialize = FALSE; 1899 eapol_sm_step(sm); 1900 1901 sm->timer_tick_enabled = 1; 1902 eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm); 1903 1904 return sm; 1905} 1906 1907 1908/** 1909 * eapol_sm_deinit - Deinitialize EAPOL state machine 1910 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1911 * 1912 * Deinitialize and free EAPOL state machine. 1913 */ 1914void eapol_sm_deinit(struct eapol_sm *sm) 1915{ 1916 if (sm == NULL) 1917 return; 1918 eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm); 1919 eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm); 1920 eap_peer_sm_deinit(sm->eap); 1921 os_free(sm->last_rx_key); 1922 wpabuf_free(sm->eapReqData); 1923 os_free(sm->ctx); 1924 os_free(sm); 1925} 1926 1927 1928void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm, 1929 struct ext_password_data *ext) 1930{ 1931 if (sm && sm->eap) 1932 eap_sm_set_ext_pw_ctx(sm->eap, ext); 1933} 1934 1935 1936int eapol_sm_failed(struct eapol_sm *sm) 1937{ 1938 if (sm == NULL) 1939 return 0; 1940 return !sm->eapSuccess && sm->eapFail; 1941} 1942