Pre-2.0 release: Sync with HAMMER 64 - NFS and cross-device link fixes.
[dragonfly.git] / contrib / wpa_supplicant-0.5.8 / eapol_sm.c
blob899e2ce096a9910ebe2561209637ccbd2ea13018
1 /*
2 * WPA Supplicant / EAPOL state machines
3 * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
12 * See README and COPYING for more details.
15 #include "includes.h"
17 #include "common.h"
18 #include "eapol_sm.h"
19 #include "eap.h"
20 #include "eloop.h"
21 #include "l2_packet.h"
22 #include "wpa.h"
23 #include "md5.h"
24 #include "rc4.h"
25 #include "state_machine.h"
27 #define STATE_MACHINE_DATA struct eapol_sm
28 #define STATE_MACHINE_DEBUG_PREFIX "EAPOL"
31 /* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
33 /**
34 * struct eapol_sm - Internal data for EAPOL state machines
36 struct eapol_sm {
37 /* Timers */
38 unsigned int authWhile;
39 unsigned int heldWhile;
40 unsigned int startWhen;
41 unsigned int idleWhile; /* for EAP state machine */
43 /* Global variables */
44 Boolean eapFail;
45 Boolean eapolEap;
46 Boolean eapSuccess;
47 Boolean initialize;
48 Boolean keyDone;
49 Boolean keyRun;
50 PortControl portControl;
51 Boolean portEnabled;
52 PortStatus suppPortStatus; /* dot1xSuppControlledPortStatus */
53 Boolean portValid;
54 Boolean suppAbort;
55 Boolean suppFail;
56 Boolean suppStart;
57 Boolean suppSuccess;
58 Boolean suppTimeout;
60 /* Supplicant PAE state machine */
61 enum {
62 SUPP_PAE_UNKNOWN = 0,
63 SUPP_PAE_DISCONNECTED = 1,
64 SUPP_PAE_LOGOFF = 2,
65 SUPP_PAE_CONNECTING = 3,
66 SUPP_PAE_AUTHENTICATING = 4,
67 SUPP_PAE_AUTHENTICATED = 5,
68 /* unused(6) */
69 SUPP_PAE_HELD = 7,
70 SUPP_PAE_RESTART = 8,
71 SUPP_PAE_S_FORCE_AUTH = 9,
72 SUPP_PAE_S_FORCE_UNAUTH = 10
73 } SUPP_PAE_state; /* dot1xSuppPaeState */
74 /* Variables */
75 Boolean userLogoff;
76 Boolean logoffSent;
77 unsigned int startCount;
78 Boolean eapRestart;
79 PortControl sPortMode;
80 /* Constants */
81 unsigned int heldPeriod; /* dot1xSuppHeldPeriod */
82 unsigned int startPeriod; /* dot1xSuppStartPeriod */
83 unsigned int maxStart; /* dot1xSuppMaxStart */
85 /* Key Receive state machine */
86 enum {
87 KEY_RX_UNKNOWN = 0,
88 KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
89 } KEY_RX_state;
90 /* Variables */
91 Boolean rxKey;
93 /* Supplicant Backend state machine */
94 enum {
95 SUPP_BE_UNKNOWN = 0,
96 SUPP_BE_INITIALIZE = 1,
97 SUPP_BE_IDLE = 2,
98 SUPP_BE_REQUEST = 3,
99 SUPP_BE_RECEIVE = 4,
100 SUPP_BE_RESPONSE = 5,
101 SUPP_BE_FAIL = 6,
102 SUPP_BE_TIMEOUT = 7,
103 SUPP_BE_SUCCESS = 8
104 } SUPP_BE_state; /* dot1xSuppBackendPaeState */
105 /* Variables */
106 Boolean eapNoResp;
107 Boolean eapReq;
108 Boolean eapResp;
109 /* Constants */
110 unsigned int authPeriod; /* dot1xSuppAuthPeriod */
112 /* Statistics */
113 unsigned int dot1xSuppEapolFramesRx;
114 unsigned int dot1xSuppEapolFramesTx;
115 unsigned int dot1xSuppEapolStartFramesTx;
116 unsigned int dot1xSuppEapolLogoffFramesTx;
117 unsigned int dot1xSuppEapolRespFramesTx;
118 unsigned int dot1xSuppEapolReqIdFramesRx;
119 unsigned int dot1xSuppEapolReqFramesRx;
120 unsigned int dot1xSuppInvalidEapolFramesRx;
121 unsigned int dot1xSuppEapLengthErrorFramesRx;
122 unsigned int dot1xSuppLastEapolFrameVersion;
123 unsigned char dot1xSuppLastEapolFrameSource[6];
125 /* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
126 Boolean changed;
127 struct eap_sm *eap;
128 struct wpa_ssid *config;
129 Boolean initial_req;
130 u8 *last_rx_key;
131 size_t last_rx_key_len;
132 u8 *eapReqData; /* for EAP */
133 size_t eapReqDataLen; /* for EAP */
134 Boolean altAccept; /* for EAP */
135 Boolean altReject; /* for EAP */
136 Boolean replay_counter_valid;
137 u8 last_replay_counter[16];
138 struct eapol_config conf;
139 struct eapol_ctx *ctx;
140 enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE }
141 cb_status;
142 Boolean cached_pmk;
144 Boolean unicast_key_received, broadcast_key_received;
148 #define IEEE8021X_REPLAY_COUNTER_LEN 8
149 #define IEEE8021X_KEY_SIGN_LEN 16
150 #define IEEE8021X_KEY_IV_LEN 16
152 #define IEEE8021X_KEY_INDEX_FLAG 0x80
153 #define IEEE8021X_KEY_INDEX_MASK 0x03
155 #ifdef _MSC_VER
156 #pragma pack(push, 1)
157 #endif /* _MSC_VER */
159 struct ieee802_1x_eapol_key {
160 u8 type;
161 /* Note: key_length is unaligned */
162 u8 key_length[2];
163 /* does not repeat within the life of the keying material used to
164 * encrypt the Key field; 64-bit NTP timestamp MAY be used here */
165 u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN];
166 u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */
167 u8 key_index; /* key flag in the most significant bit:
168 * 0 = broadcast (default key),
169 * 1 = unicast (key mapping key); key index is in the
170 * 7 least significant bits */
171 /* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as
172 * the key */
173 u8 key_signature[IEEE8021X_KEY_SIGN_LEN];
175 /* followed by key: if packet body length = 44 + key length, then the
176 * key field (of key_length bytes) contains the key in encrypted form;
177 * if packet body length = 44, key field is absent and key_length
178 * represents the number of least significant octets from
179 * MS-MPPE-Send-Key attribute to be used as the keying material;
180 * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
181 } STRUCT_PACKED;
183 #ifdef _MSC_VER
184 #pragma pack(pop)
185 #endif /* _MSC_VER */
188 static void eapol_sm_txLogoff(struct eapol_sm *sm);
189 static void eapol_sm_txStart(struct eapol_sm *sm);
190 static void eapol_sm_processKey(struct eapol_sm *sm);
191 static void eapol_sm_getSuppRsp(struct eapol_sm *sm);
192 static void eapol_sm_txSuppRsp(struct eapol_sm *sm);
193 static void eapol_sm_abortSupp(struct eapol_sm *sm);
194 static void eapol_sm_abort_cached(struct eapol_sm *sm);
195 static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx);
198 /* Port Timers state machine - implemented as a function that will be called
199 * once a second as a registered event loop timeout */
200 static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
202 struct eapol_sm *sm = timeout_ctx;
204 if (sm->authWhile > 0) {
205 sm->authWhile--;
206 if (sm->authWhile == 0)
207 wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0");
209 if (sm->heldWhile > 0) {
210 sm->heldWhile--;
211 if (sm->heldWhile == 0)
212 wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0");
214 if (sm->startWhen > 0) {
215 sm->startWhen--;
216 if (sm->startWhen == 0)
217 wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0");
219 if (sm->idleWhile > 0) {
220 sm->idleWhile--;
221 if (sm->idleWhile == 0)
222 wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0");
225 eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, sm);
226 eapol_sm_step(sm);
230 SM_STATE(SUPP_PAE, LOGOFF)
232 SM_ENTRY(SUPP_PAE, LOGOFF);
233 eapol_sm_txLogoff(sm);
234 sm->logoffSent = TRUE;
235 sm->suppPortStatus = Unauthorized;
239 SM_STATE(SUPP_PAE, DISCONNECTED)
241 SM_ENTRY(SUPP_PAE, DISCONNECTED);
242 sm->sPortMode = Auto;
243 sm->startCount = 0;
244 sm->logoffSent = FALSE;
245 sm->suppPortStatus = Unauthorized;
246 sm->suppAbort = TRUE;
248 sm->unicast_key_received = FALSE;
249 sm->broadcast_key_received = FALSE;
253 SM_STATE(SUPP_PAE, CONNECTING)
255 int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING;
256 SM_ENTRY(SUPP_PAE, CONNECTING);
257 if (send_start) {
258 sm->startWhen = sm->startPeriod;
259 sm->startCount++;
260 } else {
262 * Do not send EAPOL-Start immediately since in most cases,
263 * Authenticator is going to start authentication immediately
264 * after association and an extra EAPOL-Start is just going to
265 * delay authentication. Use a short timeout to send the first
266 * EAPOL-Start if Authenticator does not start authentication.
268 sm->startWhen = 3;
270 sm->eapolEap = FALSE;
271 if (send_start)
272 eapol_sm_txStart(sm);
276 SM_STATE(SUPP_PAE, AUTHENTICATING)
278 SM_ENTRY(SUPP_PAE, AUTHENTICATING);
279 sm->startCount = 0;
280 sm->suppSuccess = FALSE;
281 sm->suppFail = FALSE;
282 sm->suppTimeout = FALSE;
283 sm->keyRun = FALSE;
284 sm->keyDone = FALSE;
285 sm->suppStart = TRUE;
289 SM_STATE(SUPP_PAE, HELD)
291 SM_ENTRY(SUPP_PAE, HELD);
292 sm->heldWhile = sm->heldPeriod;
293 sm->suppPortStatus = Unauthorized;
294 sm->cb_status = EAPOL_CB_FAILURE;
298 SM_STATE(SUPP_PAE, AUTHENTICATED)
300 SM_ENTRY(SUPP_PAE, AUTHENTICATED);
301 sm->suppPortStatus = Authorized;
302 sm->cb_status = EAPOL_CB_SUCCESS;
306 SM_STATE(SUPP_PAE, RESTART)
308 SM_ENTRY(SUPP_PAE, RESTART);
309 sm->eapRestart = TRUE;
313 SM_STATE(SUPP_PAE, S_FORCE_AUTH)
315 SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
316 sm->suppPortStatus = Authorized;
317 sm->sPortMode = ForceAuthorized;
321 SM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
323 SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
324 sm->suppPortStatus = Unauthorized;
325 sm->sPortMode = ForceUnauthorized;
326 eapol_sm_txLogoff(sm);
330 SM_STEP(SUPP_PAE)
332 if ((sm->userLogoff && !sm->logoffSent) &&
333 !(sm->initialize || !sm->portEnabled))
334 SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF);
335 else if (((sm->portControl == Auto) &&
336 (sm->sPortMode != sm->portControl)) ||
337 sm->initialize || !sm->portEnabled)
338 SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED);
339 else if ((sm->portControl == ForceAuthorized) &&
340 (sm->sPortMode != sm->portControl) &&
341 !(sm->initialize || !sm->portEnabled))
342 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH);
343 else if ((sm->portControl == ForceUnauthorized) &&
344 (sm->sPortMode != sm->portControl) &&
345 !(sm->initialize || !sm->portEnabled))
346 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH);
347 else switch (sm->SUPP_PAE_state) {
348 case SUPP_PAE_UNKNOWN:
349 break;
350 case SUPP_PAE_LOGOFF:
351 if (!sm->userLogoff)
352 SM_ENTER(SUPP_PAE, DISCONNECTED);
353 break;
354 case SUPP_PAE_DISCONNECTED:
355 SM_ENTER(SUPP_PAE, CONNECTING);
356 break;
357 case SUPP_PAE_CONNECTING:
358 if (sm->startWhen == 0 && sm->startCount < sm->maxStart)
359 SM_ENTER(SUPP_PAE, CONNECTING);
360 else if (sm->startWhen == 0 &&
361 sm->startCount >= sm->maxStart &&
362 sm->portValid)
363 SM_ENTER(SUPP_PAE, AUTHENTICATED);
364 else if (sm->eapSuccess || sm->eapFail)
365 SM_ENTER(SUPP_PAE, AUTHENTICATING);
366 else if (sm->eapolEap)
367 SM_ENTER(SUPP_PAE, RESTART);
368 else if (sm->startWhen == 0 &&
369 sm->startCount >= sm->maxStart &&
370 !sm->portValid)
371 SM_ENTER(SUPP_PAE, HELD);
372 break;
373 case SUPP_PAE_AUTHENTICATING:
374 if (sm->eapSuccess && !sm->portValid &&
375 sm->conf.accept_802_1x_keys &&
376 sm->conf.required_keys == 0) {
377 wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for "
378 "plaintext connection; no EAPOL-Key frames "
379 "required");
380 sm->portValid = TRUE;
381 if (sm->ctx->eapol_done_cb)
382 sm->ctx->eapol_done_cb(sm->ctx->ctx);
384 if (sm->eapSuccess && sm->portValid)
385 SM_ENTER(SUPP_PAE, AUTHENTICATED);
386 else if (sm->eapFail || (sm->keyDone && !sm->portValid))
387 SM_ENTER(SUPP_PAE, HELD);
388 else if (sm->suppTimeout)
389 SM_ENTER(SUPP_PAE, CONNECTING);
390 break;
391 case SUPP_PAE_HELD:
392 if (sm->heldWhile == 0)
393 SM_ENTER(SUPP_PAE, CONNECTING);
394 else if (sm->eapolEap)
395 SM_ENTER(SUPP_PAE, RESTART);
396 break;
397 case SUPP_PAE_AUTHENTICATED:
398 if (sm->eapolEap && sm->portValid)
399 SM_ENTER(SUPP_PAE, RESTART);
400 else if (!sm->portValid)
401 SM_ENTER(SUPP_PAE, DISCONNECTED);
402 break;
403 case SUPP_PAE_RESTART:
404 if (!sm->eapRestart)
405 SM_ENTER(SUPP_PAE, AUTHENTICATING);
406 break;
407 case SUPP_PAE_S_FORCE_AUTH:
408 break;
409 case SUPP_PAE_S_FORCE_UNAUTH:
410 break;
415 SM_STATE(KEY_RX, NO_KEY_RECEIVE)
417 SM_ENTRY(KEY_RX, NO_KEY_RECEIVE);
421 SM_STATE(KEY_RX, KEY_RECEIVE)
423 SM_ENTRY(KEY_RX, KEY_RECEIVE);
424 eapol_sm_processKey(sm);
425 sm->rxKey = FALSE;
429 SM_STEP(KEY_RX)
431 if (sm->initialize || !sm->portEnabled)
432 SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
433 switch (sm->KEY_RX_state) {
434 case KEY_RX_UNKNOWN:
435 break;
436 case KEY_RX_NO_KEY_RECEIVE:
437 if (sm->rxKey)
438 SM_ENTER(KEY_RX, KEY_RECEIVE);
439 break;
440 case KEY_RX_KEY_RECEIVE:
441 if (sm->rxKey)
442 SM_ENTER(KEY_RX, KEY_RECEIVE);
443 break;
448 SM_STATE(SUPP_BE, REQUEST)
450 SM_ENTRY(SUPP_BE, REQUEST);
451 sm->authWhile = 0;
452 sm->eapReq = TRUE;
453 eapol_sm_getSuppRsp(sm);
457 SM_STATE(SUPP_BE, RESPONSE)
459 SM_ENTRY(SUPP_BE, RESPONSE);
460 eapol_sm_txSuppRsp(sm);
461 sm->eapResp = FALSE;
465 SM_STATE(SUPP_BE, SUCCESS)
467 SM_ENTRY(SUPP_BE, SUCCESS);
468 sm->keyRun = TRUE;
469 sm->suppSuccess = TRUE;
471 if (eap_key_available(sm->eap)) {
472 /* New key received - clear IEEE 802.1X EAPOL-Key replay
473 * counter */
474 sm->replay_counter_valid = FALSE;
479 SM_STATE(SUPP_BE, FAIL)
481 SM_ENTRY(SUPP_BE, FAIL);
482 sm->suppFail = TRUE;
486 SM_STATE(SUPP_BE, TIMEOUT)
488 SM_ENTRY(SUPP_BE, TIMEOUT);
489 sm->suppTimeout = TRUE;
493 SM_STATE(SUPP_BE, IDLE)
495 SM_ENTRY(SUPP_BE, IDLE);
496 sm->suppStart = FALSE;
497 sm->initial_req = TRUE;
501 SM_STATE(SUPP_BE, INITIALIZE)
503 SM_ENTRY(SUPP_BE, INITIALIZE);
504 eapol_sm_abortSupp(sm);
505 sm->suppAbort = FALSE;
509 SM_STATE(SUPP_BE, RECEIVE)
511 SM_ENTRY(SUPP_BE, RECEIVE);
512 sm->authWhile = sm->authPeriod;
513 sm->eapolEap = FALSE;
514 sm->eapNoResp = FALSE;
515 sm->initial_req = FALSE;
519 SM_STEP(SUPP_BE)
521 if (sm->initialize || sm->suppAbort)
522 SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE);
523 else switch (sm->SUPP_BE_state) {
524 case SUPP_BE_UNKNOWN:
525 break;
526 case SUPP_BE_REQUEST:
528 * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
529 * and SUCCESS based on eapFail and eapSuccess, respectively.
530 * However, IEEE Std 802.1X-2004 is also specifying that
531 * eapNoResp should be set in conjuction with eapSuccess and
532 * eapFail which would mean that more than one of the
533 * transitions here would be activated at the same time.
534 * Skipping RESPONSE and/or RECEIVE states in these cases can
535 * cause problems and the direct transitions to do not seem
536 * correct. Because of this, the conditions for these
537 * transitions are verified only after eapNoResp. They are
538 * unlikely to be used since eapNoResp should always be set if
539 * either of eapSuccess or eapFail is set.
541 if (sm->eapResp && sm->eapNoResp) {
542 wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both "
543 "eapResp and eapNoResp set?!");
545 if (sm->eapResp)
546 SM_ENTER(SUPP_BE, RESPONSE);
547 else if (sm->eapNoResp)
548 SM_ENTER(SUPP_BE, RECEIVE);
549 else if (sm->eapFail)
550 SM_ENTER(SUPP_BE, FAIL);
551 else if (sm->eapSuccess)
552 SM_ENTER(SUPP_BE, SUCCESS);
553 break;
554 case SUPP_BE_RESPONSE:
555 SM_ENTER(SUPP_BE, RECEIVE);
556 break;
557 case SUPP_BE_SUCCESS:
558 SM_ENTER(SUPP_BE, IDLE);
559 break;
560 case SUPP_BE_FAIL:
561 SM_ENTER(SUPP_BE, IDLE);
562 break;
563 case SUPP_BE_TIMEOUT:
564 SM_ENTER(SUPP_BE, IDLE);
565 break;
566 case SUPP_BE_IDLE:
567 if (sm->eapFail && sm->suppStart)
568 SM_ENTER(SUPP_BE, FAIL);
569 else if (sm->eapolEap && sm->suppStart)
570 SM_ENTER(SUPP_BE, REQUEST);
571 else if (sm->eapSuccess && sm->suppStart)
572 SM_ENTER(SUPP_BE, SUCCESS);
573 break;
574 case SUPP_BE_INITIALIZE:
575 SM_ENTER(SUPP_BE, IDLE);
576 break;
577 case SUPP_BE_RECEIVE:
578 if (sm->eapolEap)
579 SM_ENTER(SUPP_BE, REQUEST);
580 else if (sm->eapFail)
581 SM_ENTER(SUPP_BE, FAIL);
582 else if (sm->authWhile == 0)
583 SM_ENTER(SUPP_BE, TIMEOUT);
584 else if (sm->eapSuccess)
585 SM_ENTER(SUPP_BE, SUCCESS);
586 break;
591 static void eapol_sm_txLogoff(struct eapol_sm *sm)
593 wpa_printf(MSG_DEBUG, "EAPOL: txLogoff");
594 sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
595 IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0);
596 sm->dot1xSuppEapolLogoffFramesTx++;
597 sm->dot1xSuppEapolFramesTx++;
601 static void eapol_sm_txStart(struct eapol_sm *sm)
603 wpa_printf(MSG_DEBUG, "EAPOL: txStart");
604 sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
605 IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0);
606 sm->dot1xSuppEapolStartFramesTx++;
607 sm->dot1xSuppEapolFramesTx++;
611 #define IEEE8021X_ENCR_KEY_LEN 32
612 #define IEEE8021X_SIGN_KEY_LEN 32
614 struct eap_key_data {
615 u8 encr_key[IEEE8021X_ENCR_KEY_LEN];
616 u8 sign_key[IEEE8021X_SIGN_KEY_LEN];
620 static void eapol_sm_processKey(struct eapol_sm *sm)
622 struct ieee802_1x_hdr *hdr;
623 struct ieee802_1x_eapol_key *key;
624 struct eap_key_data keydata;
625 u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
626 u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
627 int key_len, res, sign_key_len, encr_key_len;
628 u16 rx_key_length;
630 wpa_printf(MSG_DEBUG, "EAPOL: processKey");
631 if (sm->last_rx_key == NULL)
632 return;
634 if (!sm->conf.accept_802_1x_keys) {
635 wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key"
636 " even though this was not accepted - "
637 "ignoring this packet");
638 return;
641 hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
642 key = (struct ieee802_1x_eapol_key *) (hdr + 1);
643 if (sizeof(*hdr) + be_to_host16(hdr->length) > sm->last_rx_key_len) {
644 wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
645 return;
647 rx_key_length = WPA_GET_BE16(key->key_length);
648 wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
649 "EAPOL-Key: type=%d key_length=%d key_index=0x%x",
650 hdr->version, hdr->type, be_to_host16(hdr->length),
651 key->type, rx_key_length, key->key_index);
653 eapol_sm_notify_lower_layer_success(sm);
654 sign_key_len = IEEE8021X_SIGN_KEY_LEN;
655 encr_key_len = IEEE8021X_ENCR_KEY_LEN;
656 res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata));
657 if (res < 0) {
658 wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for "
659 "decrypting EAPOL-Key keys");
660 return;
662 if (res == 16) {
663 /* LEAP derives only 16 bytes of keying material. */
664 res = eapol_sm_get_key(sm, (u8 *) &keydata, 16);
665 if (res) {
666 wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP "
667 "master key for decrypting EAPOL-Key keys");
668 return;
670 sign_key_len = 16;
671 encr_key_len = 16;
672 os_memcpy(keydata.sign_key, keydata.encr_key, 16);
673 } else if (res) {
674 wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key "
675 "data for decrypting EAPOL-Key keys (res=%d)", res);
676 return;
679 /* The key replay_counter must increase when same master key */
680 if (sm->replay_counter_valid &&
681 os_memcmp(sm->last_replay_counter, key->replay_counter,
682 IEEE8021X_REPLAY_COUNTER_LEN) >= 0) {
683 wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did "
684 "not increase - ignoring key");
685 wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter",
686 sm->last_replay_counter,
687 IEEE8021X_REPLAY_COUNTER_LEN);
688 wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter",
689 key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN);
690 return;
693 /* Verify key signature (HMAC-MD5) */
694 os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN);
695 os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN);
696 hmac_md5(keydata.sign_key, sign_key_len,
697 sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
698 key->key_signature);
699 if (os_memcmp(orig_key_sign, key->key_signature,
700 IEEE8021X_KEY_SIGN_LEN) != 0) {
701 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
702 "EAPOL-Key packet");
703 os_memcpy(key->key_signature, orig_key_sign,
704 IEEE8021X_KEY_SIGN_LEN);
705 return;
707 wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
709 key_len = be_to_host16(hdr->length) - sizeof(*key);
710 if (key_len > 32 || rx_key_length > 32) {
711 wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
712 key_len ? key_len : rx_key_length);
713 return;
715 if (key_len == rx_key_length) {
716 os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
717 os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
718 encr_key_len);
719 os_memcpy(datakey, key + 1, key_len);
720 rc4(datakey, key_len, ekey,
721 IEEE8021X_KEY_IV_LEN + encr_key_len);
722 wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
723 datakey, key_len);
724 } else if (key_len == 0) {
726 * IEEE 802.1X-2004 specifies that least significant Key Length
727 * octets from MS-MPPE-Send-Key are used as the key if the key
728 * data is not present. This seems to be meaning the beginning
729 * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
730 * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
731 * Anyway, taking the beginning of the keying material from EAP
732 * seems to interoperate with Authenticators.
734 key_len = rx_key_length;
735 os_memcpy(datakey, keydata.encr_key, key_len);
736 wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying "
737 "material data encryption key",
738 datakey, key_len);
739 } else {
740 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
741 "(key_length=%d)", key_len, rx_key_length);
742 return;
745 sm->replay_counter_valid = TRUE;
746 os_memcpy(sm->last_replay_counter, key->replay_counter,
747 IEEE8021X_REPLAY_COUNTER_LEN);
749 wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
750 "len %d",
751 key->key_index & IEEE8021X_KEY_INDEX_FLAG ?
752 "unicast" : "broadcast",
753 key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len);
755 if (sm->ctx->set_wep_key &&
756 sm->ctx->set_wep_key(sm->ctx->ctx,
757 key->key_index & IEEE8021X_KEY_INDEX_FLAG,
758 key->key_index & IEEE8021X_KEY_INDEX_MASK,
759 datakey, key_len) < 0) {
760 wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
761 " driver.");
762 } else {
763 if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
764 sm->unicast_key_received = TRUE;
765 else
766 sm->broadcast_key_received = TRUE;
768 if ((sm->unicast_key_received ||
769 !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) &&
770 (sm->broadcast_key_received ||
771 !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST)))
773 wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
774 "frames received");
775 sm->portValid = TRUE;
776 if (sm->ctx->eapol_done_cb)
777 sm->ctx->eapol_done_cb(sm->ctx->ctx);
783 static void eapol_sm_getSuppRsp(struct eapol_sm *sm)
785 wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp");
786 /* EAP layer processing; no special code is needed, since Supplicant
787 * Backend state machine is waiting for eapNoResp or eapResp to be set
788 * and these are only set in the EAP state machine when the processing
789 * has finished. */
793 static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
795 u8 *resp;
796 size_t resp_len;
798 wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
799 resp = eap_get_eapRespData(sm->eap, &resp_len);
800 if (resp == NULL) {
801 wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
802 "not available");
803 return;
806 /* Send EAP-Packet from the EAP layer to the Authenticator */
807 sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
808 IEEE802_1X_TYPE_EAP_PACKET, resp, resp_len);
810 /* eapRespData is not used anymore, so free it here */
811 os_free(resp);
813 if (sm->initial_req)
814 sm->dot1xSuppEapolReqIdFramesRx++;
815 else
816 sm->dot1xSuppEapolReqFramesRx++;
817 sm->dot1xSuppEapolRespFramesTx++;
818 sm->dot1xSuppEapolFramesTx++;
822 static void eapol_sm_abortSupp(struct eapol_sm *sm)
824 /* release system resources that may have been allocated for the
825 * authentication session */
826 os_free(sm->last_rx_key);
827 sm->last_rx_key = NULL;
828 os_free(sm->eapReqData);
829 sm->eapReqData = NULL;
830 eap_sm_abort(sm->eap);
834 static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
836 eapol_sm_step(timeout_ctx);
841 * eapol_sm_step - EAPOL state machine step function
842 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
844 * This function is called to notify the state machine about changed external
845 * variables. It will step through the EAPOL state machines in loop to process
846 * all triggered state changes.
848 void eapol_sm_step(struct eapol_sm *sm)
850 int i;
852 /* In theory, it should be ok to run this in loop until !changed.
853 * However, it is better to use a limit on number of iterations to
854 * allow events (e.g., SIGTERM) to stop the program cleanly if the
855 * state machine were to generate a busy loop. */
856 for (i = 0; i < 100; i++) {
857 sm->changed = FALSE;
858 SM_STEP_RUN(SUPP_PAE);
859 SM_STEP_RUN(KEY_RX);
860 SM_STEP_RUN(SUPP_BE);
861 if (eap_sm_step(sm->eap))
862 sm->changed = TRUE;
863 if (!sm->changed)
864 break;
867 if (sm->changed) {
868 /* restart EAPOL state machine step from timeout call in order
869 * to allow other events to be processed. */
870 eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
871 eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm);
874 if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
875 int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0;
876 sm->cb_status = EAPOL_CB_IN_PROGRESS;
877 sm->ctx->cb(sm, success, sm->ctx->cb_ctx);
882 #ifdef CONFIG_CTRL_IFACE
883 static const char *eapol_supp_pae_state(int state)
885 switch (state) {
886 case SUPP_PAE_LOGOFF:
887 return "LOGOFF";
888 case SUPP_PAE_DISCONNECTED:
889 return "DISCONNECTED";
890 case SUPP_PAE_CONNECTING:
891 return "CONNECTING";
892 case SUPP_PAE_AUTHENTICATING:
893 return "AUTHENTICATING";
894 case SUPP_PAE_HELD:
895 return "HELD";
896 case SUPP_PAE_AUTHENTICATED:
897 return "AUTHENTICATED";
898 case SUPP_PAE_RESTART:
899 return "RESTART";
900 default:
901 return "UNKNOWN";
906 static const char *eapol_supp_be_state(int state)
908 switch (state) {
909 case SUPP_BE_REQUEST:
910 return "REQUEST";
911 case SUPP_BE_RESPONSE:
912 return "RESPONSE";
913 case SUPP_BE_SUCCESS:
914 return "SUCCESS";
915 case SUPP_BE_FAIL:
916 return "FAIL";
917 case SUPP_BE_TIMEOUT:
918 return "TIMEOUT";
919 case SUPP_BE_IDLE:
920 return "IDLE";
921 case SUPP_BE_INITIALIZE:
922 return "INITIALIZE";
923 case SUPP_BE_RECEIVE:
924 return "RECEIVE";
925 default:
926 return "UNKNOWN";
931 static const char * eapol_port_status(PortStatus status)
933 if (status == Authorized)
934 return "Authorized";
935 else
936 return "Unauthorized";
938 #endif /* CONFIG_CTRL_IFACE */
941 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
942 static const char * eapol_port_control(PortControl ctrl)
944 switch (ctrl) {
945 case Auto:
946 return "Auto";
947 case ForceUnauthorized:
948 return "ForceUnauthorized";
949 case ForceAuthorized:
950 return "ForceAuthorized";
951 default:
952 return "Unknown";
955 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
959 * eapol_sm_configure - Set EAPOL variables
960 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
961 * @heldPeriod: dot1xSuppHeldPeriod
962 * @authPeriod: dot1xSuppAuthPeriod
963 * @startPeriod: dot1xSuppStartPeriod
964 * @maxStart: dot1xSuppMaxStart
966 * Set configurable EAPOL state machine variables. Each variable can be set to
967 * the given value or ignored if set to -1 (to set only some of the variables).
969 void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
970 int startPeriod, int maxStart)
972 if (sm == NULL)
973 return;
974 if (heldPeriod >= 0)
975 sm->heldPeriod = heldPeriod;
976 if (authPeriod >= 0)
977 sm->authPeriod = authPeriod;
978 if (startPeriod >= 0)
979 sm->startPeriod = startPeriod;
980 if (maxStart >= 0)
981 sm->maxStart = maxStart;
985 #ifdef CONFIG_CTRL_IFACE
987 * eapol_sm_get_status - Get EAPOL state machine status
988 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
989 * @buf: Buffer for status information
990 * @buflen: Maximum buffer length
991 * @verbose: Whether to include verbose status information
992 * Returns: Number of bytes written to buf.
994 * Query EAPOL state machine for status information. This function fills in a
995 * text area with current status information from the EAPOL state machine. If
996 * the buffer (buf) is not large enough, status information will be truncated
997 * to fit the buffer.
999 int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
1000 int verbose)
1002 int len, ret;
1003 if (sm == NULL)
1004 return 0;
1006 len = os_snprintf(buf, buflen,
1007 "Supplicant PAE state=%s\n"
1008 "suppPortStatus=%s\n",
1009 eapol_supp_pae_state(sm->SUPP_PAE_state),
1010 eapol_port_status(sm->suppPortStatus));
1011 if (len < 0 || (size_t) len >= buflen)
1012 return 0;
1014 if (verbose) {
1015 ret = os_snprintf(buf + len, buflen - len,
1016 "heldPeriod=%u\n"
1017 "authPeriod=%u\n"
1018 "startPeriod=%u\n"
1019 "maxStart=%u\n"
1020 "portControl=%s\n"
1021 "Supplicant Backend state=%s\n",
1022 sm->heldPeriod,
1023 sm->authPeriod,
1024 sm->startPeriod,
1025 sm->maxStart,
1026 eapol_port_control(sm->portControl),
1027 eapol_supp_be_state(sm->SUPP_BE_state));
1028 if (ret < 0 || (size_t) ret >= buflen - len)
1029 return len;
1030 len += ret;
1033 len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
1035 return len;
1040 * eapol_sm_get_mib - Get EAPOL state machine MIBs
1041 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1042 * @buf: Buffer for MIB information
1043 * @buflen: Maximum buffer length
1044 * Returns: Number of bytes written to buf.
1046 * Query EAPOL state machine for MIB information. This function fills in a
1047 * text area with current MIB information from the EAPOL state machine. If
1048 * the buffer (buf) is not large enough, MIB information will be truncated to
1049 * fit the buffer.
1051 int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
1053 size_t len;
1054 int ret;
1056 if (sm == NULL)
1057 return 0;
1058 ret = os_snprintf(buf, buflen,
1059 "dot1xSuppPaeState=%d\n"
1060 "dot1xSuppHeldPeriod=%u\n"
1061 "dot1xSuppAuthPeriod=%u\n"
1062 "dot1xSuppStartPeriod=%u\n"
1063 "dot1xSuppMaxStart=%u\n"
1064 "dot1xSuppSuppControlledPortStatus=%s\n"
1065 "dot1xSuppBackendPaeState=%d\n",
1066 sm->SUPP_PAE_state,
1067 sm->heldPeriod,
1068 sm->authPeriod,
1069 sm->startPeriod,
1070 sm->maxStart,
1071 sm->suppPortStatus == Authorized ?
1072 "Authorized" : "Unauthorized",
1073 sm->SUPP_BE_state);
1075 if (ret < 0 || (size_t) ret >= buflen)
1076 return 0;
1077 len = ret;
1079 ret = os_snprintf(buf + len, buflen - len,
1080 "dot1xSuppEapolFramesRx=%u\n"
1081 "dot1xSuppEapolFramesTx=%u\n"
1082 "dot1xSuppEapolStartFramesTx=%u\n"
1083 "dot1xSuppEapolLogoffFramesTx=%u\n"
1084 "dot1xSuppEapolRespFramesTx=%u\n"
1085 "dot1xSuppEapolReqIdFramesRx=%u\n"
1086 "dot1xSuppEapolReqFramesRx=%u\n"
1087 "dot1xSuppInvalidEapolFramesRx=%u\n"
1088 "dot1xSuppEapLengthErrorFramesRx=%u\n"
1089 "dot1xSuppLastEapolFrameVersion=%u\n"
1090 "dot1xSuppLastEapolFrameSource=" MACSTR "\n",
1091 sm->dot1xSuppEapolFramesRx,
1092 sm->dot1xSuppEapolFramesTx,
1093 sm->dot1xSuppEapolStartFramesTx,
1094 sm->dot1xSuppEapolLogoffFramesTx,
1095 sm->dot1xSuppEapolRespFramesTx,
1096 sm->dot1xSuppEapolReqIdFramesRx,
1097 sm->dot1xSuppEapolReqFramesRx,
1098 sm->dot1xSuppInvalidEapolFramesRx,
1099 sm->dot1xSuppEapLengthErrorFramesRx,
1100 sm->dot1xSuppLastEapolFrameVersion,
1101 MAC2STR(sm->dot1xSuppLastEapolFrameSource));
1103 if (ret < 0 || (size_t) ret >= buflen - len)
1104 return len;
1105 len += ret;
1107 return len;
1109 #endif /* CONFIG_CTRL_IFACE */
1113 * eapol_sm_rx_eapol - Process received EAPOL frames
1114 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1115 * @src: Source MAC address of the EAPOL packet
1116 * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
1117 * @len: Length of the EAPOL frame
1118 * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
1119 * -1 failure
1121 int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
1122 size_t len)
1124 const struct ieee802_1x_hdr *hdr;
1125 const struct ieee802_1x_eapol_key *key;
1126 int data_len;
1127 int res = 1;
1128 size_t plen;
1130 if (sm == NULL)
1131 return 0;
1132 sm->dot1xSuppEapolFramesRx++;
1133 if (len < sizeof(*hdr)) {
1134 sm->dot1xSuppInvalidEapolFramesRx++;
1135 return 0;
1137 hdr = (const struct ieee802_1x_hdr *) buf;
1138 sm->dot1xSuppLastEapolFrameVersion = hdr->version;
1139 os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
1140 if (hdr->version < EAPOL_VERSION) {
1141 /* TODO: backwards compatibility */
1143 plen = be_to_host16(hdr->length);
1144 if (plen > len - sizeof(*hdr)) {
1145 sm->dot1xSuppEapLengthErrorFramesRx++;
1146 return 0;
1148 data_len = plen + sizeof(*hdr);
1150 switch (hdr->type) {
1151 case IEEE802_1X_TYPE_EAP_PACKET:
1152 if (sm->cached_pmk) {
1153 /* Trying to use PMKSA caching, but Authenticator did
1154 * not seem to have a matching entry. Need to restart
1155 * EAPOL state machines.
1157 eapol_sm_abort_cached(sm);
1159 os_free(sm->eapReqData);
1160 sm->eapReqDataLen = plen;
1161 sm->eapReqData = os_malloc(sm->eapReqDataLen);
1162 if (sm->eapReqData) {
1163 wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
1164 "frame");
1165 os_memcpy(sm->eapReqData, (u8 *) (hdr + 1),
1166 sm->eapReqDataLen);
1167 sm->eapolEap = TRUE;
1168 eapol_sm_step(sm);
1170 break;
1171 case IEEE802_1X_TYPE_EAPOL_KEY:
1172 if (plen < sizeof(*key)) {
1173 wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key "
1174 "frame received");
1175 break;
1177 key = (const struct ieee802_1x_eapol_key *) (hdr + 1);
1178 if (key->type == EAPOL_KEY_TYPE_WPA ||
1179 key->type == EAPOL_KEY_TYPE_RSN) {
1180 /* WPA Supplicant takes care of this frame. */
1181 wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
1182 "frame in EAPOL state machines");
1183 res = 0;
1184 break;
1186 if (key->type != EAPOL_KEY_TYPE_RC4) {
1187 wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown "
1188 "EAPOL-Key type %d", key->type);
1189 break;
1191 os_free(sm->last_rx_key);
1192 sm->last_rx_key = os_malloc(data_len);
1193 if (sm->last_rx_key) {
1194 wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key "
1195 "frame");
1196 os_memcpy(sm->last_rx_key, buf, data_len);
1197 sm->last_rx_key_len = data_len;
1198 sm->rxKey = TRUE;
1199 eapol_sm_step(sm);
1201 break;
1202 default:
1203 wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
1204 hdr->type);
1205 sm->dot1xSuppInvalidEapolFramesRx++;
1206 break;
1209 return res;
1214 * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet
1215 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1217 * Notify EAPOL station machine about transmitted EAPOL packet from an external
1218 * component, e.g., WPA. This will update the statistics.
1220 void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
1222 if (sm)
1223 sm->dot1xSuppEapolFramesTx++;
1228 * eapol_sm_notify_portEnabled - Notification about portEnabled change
1229 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1230 * @enabled: New portEnabled value
1232 * Notify EAPOL station machine about new portEnabled value.
1234 void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
1236 if (sm == NULL)
1237 return;
1238 wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1239 "portEnabled=%d", enabled);
1240 sm->portEnabled = enabled;
1241 eapol_sm_step(sm);
1246 * eapol_sm_notify_portValid - Notification about portValid change
1247 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1248 * @valid: New portValid value
1250 * Notify EAPOL station machine about new portValid value.
1252 void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
1254 if (sm == NULL)
1255 return;
1256 wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1257 "portValid=%d", valid);
1258 sm->portValid = valid;
1259 eapol_sm_step(sm);
1264 * eapol_sm_notify_eap_success - Notification of external EAP success trigger
1265 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1266 * @success: %TRUE = set success, %FALSE = clear success
1268 * Notify EAPOL station machine that external event has forced EAP state to
1269 * success (success = %TRUE). This can be cleared by setting success = %FALSE.
1271 * This function is called to update EAP state when WPA-PSK key handshake has
1272 * been completed successfully since WPA-PSK does not use EAP state machine.
1274 void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
1276 if (sm == NULL)
1277 return;
1278 wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1279 "EAP success=%d", success);
1280 sm->eapSuccess = success;
1281 sm->altAccept = success;
1282 if (success)
1283 eap_notify_success(sm->eap);
1284 eapol_sm_step(sm);
1289 * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
1290 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1291 * @fail: %TRUE = set failure, %FALSE = clear failure
1293 * Notify EAPOL station machine that external event has forced EAP state to
1294 * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE.
1296 void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
1298 if (sm == NULL)
1299 return;
1300 wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1301 "EAP fail=%d", fail);
1302 sm->eapFail = fail;
1303 sm->altReject = fail;
1304 eapol_sm_step(sm);
1309 * eapol_sm_notify_config - Notification of EAPOL configuration change
1310 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1311 * @config: Pointer to current network configuration
1312 * @conf: Pointer to EAPOL configuration data
1314 * Notify EAPOL station machine that configuration has changed. config will be
1315 * stored as a backpointer to network configuration. This can be %NULL to clear
1316 * the stored pointed. conf will be copied to local EAPOL/EAP configuration
1317 * data. If conf is %NULL, this part of the configuration change will be
1318 * skipped.
1320 void eapol_sm_notify_config(struct eapol_sm *sm, struct wpa_ssid *config,
1321 const struct eapol_config *conf)
1323 if (sm == NULL)
1324 return;
1326 sm->config = config;
1328 if (conf == NULL)
1329 return;
1331 sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys;
1332 sm->conf.required_keys = conf->required_keys;
1333 sm->conf.fast_reauth = conf->fast_reauth;
1334 if (sm->eap) {
1335 eap_set_fast_reauth(sm->eap, conf->fast_reauth);
1336 eap_set_workaround(sm->eap, conf->workaround);
1337 eap_set_force_disabled(sm->eap, conf->eap_disabled);
1343 * eapol_sm_get_key - Get master session key (MSK) from EAP
1344 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1345 * @key: Pointer for key buffer
1346 * @len: Number of bytes to copy to key
1347 * Returns: 0 on success (len of key available), maximum available key len
1348 * (>0) if key is available but it is shorter than len, or -1 on failure.
1350 * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key
1351 * is available only after a successful authentication.
1353 int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
1355 const u8 *eap_key;
1356 size_t eap_len;
1358 if (sm == NULL || !eap_key_available(sm->eap))
1359 return -1;
1360 eap_key = eap_get_eapKeyData(sm->eap, &eap_len);
1361 if (eap_key == NULL)
1362 return -1;
1363 if (len > eap_len)
1364 return eap_len;
1365 os_memcpy(key, eap_key, len);
1366 return 0;
1371 * eapol_sm_notify_logoff - Notification of logon/logoff commands
1372 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1373 * @logoff: Whether command was logoff
1375 * Notify EAPOL state machines that user requested logon/logoff.
1377 void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
1379 if (sm) {
1380 sm->userLogoff = logoff;
1381 eapol_sm_step(sm);
1387 * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching
1388 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1390 * Notify EAPOL state machines that PMKSA caching was successful. This is used
1391 * to move EAPOL and EAP state machines into authenticated/successful state.
1393 void eapol_sm_notify_cached(struct eapol_sm *sm)
1395 if (sm == NULL)
1396 return;
1397 sm->SUPP_PAE_state = SUPP_PAE_AUTHENTICATED;
1398 sm->suppPortStatus = Authorized;
1399 eap_notify_success(sm->eap);
1404 * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
1405 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1406 * @attempt: Whether PMKSA caching is tried
1408 * Notify EAPOL state machines whether PMKSA caching is used.
1410 void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt)
1412 if (sm == NULL)
1413 return;
1414 if (attempt) {
1415 wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
1416 sm->cached_pmk = TRUE;
1417 } else {
1418 wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA");
1419 sm->cached_pmk = FALSE;
1424 static void eapol_sm_abort_cached(struct eapol_sm *sm)
1426 wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, "
1427 "doing full EAP authentication");
1428 if (sm == NULL)
1429 return;
1430 sm->cached_pmk = FALSE;
1431 sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
1432 sm->suppPortStatus = Unauthorized;
1434 /* Make sure we do not start sending EAPOL-Start frames first, but
1435 * instead move to RESTART state to start EAPOL authentication. */
1436 sm->startWhen = 3;
1438 if (sm->ctx->aborted_cached)
1439 sm->ctx->aborted_cached(sm->ctx->ctx);
1444 * eapol_sm_register_scard_ctx - Notification of smart card context
1445 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1446 * @ctx: Context data for smart card operations
1448 * Notify EAPOL state machines of context data for smart card operations. This
1449 * context data will be used as a parameter for scard_*() functions.
1451 void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
1453 if (sm) {
1454 sm->ctx->scard_ctx = ctx;
1455 eap_register_scard_ctx(sm->eap, ctx);
1461 * eapol_sm_notify_portControl - Notification of portControl changes
1462 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1463 * @portControl: New value for portControl variable
1465 * Notify EAPOL state machines that portControl variable has changed.
1467 void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
1469 if (sm == NULL)
1470 return;
1471 wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1472 "portControl=%s", eapol_port_control(portControl));
1473 sm->portControl = portControl;
1474 eapol_sm_step(sm);
1479 * eapol_sm_notify_ctrl_attached - Notification of attached monitor
1480 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1482 * Notify EAPOL state machines that a monitor was attached to the control
1483 * interface to trigger re-sending of pending requests for user input.
1485 void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
1487 if (sm == NULL)
1488 return;
1489 eap_sm_notify_ctrl_attached(sm->eap);
1494 * eapol_sm_notify_ctrl_response - Notification of received user input
1495 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1497 * Notify EAPOL state machines that a control response, i.e., user
1498 * input, was received in order to trigger retrying of a pending EAP request.
1500 void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
1502 if (sm == NULL)
1503 return;
1504 if (sm->eapReqData && !sm->eapReq) {
1505 wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
1506 "input) notification - retrying pending EAP "
1507 "Request");
1508 sm->eapolEap = TRUE;
1509 sm->eapReq = TRUE;
1510 eapol_sm_step(sm);
1516 * eapol_sm_request_reauth - Request reauthentication
1517 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1519 * This function can be used to request EAPOL reauthentication, e.g., when the
1520 * current PMKSA entry is nearing expiration.
1522 void eapol_sm_request_reauth(struct eapol_sm *sm)
1524 if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
1525 return;
1526 eapol_sm_txStart(sm);
1531 * eapol_sm_notify_lower_layer_success - Notification of lower layer success
1532 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1534 * Notify EAPOL (and EAP) state machines that a lower layer has detected a
1535 * successful authentication. This is used to recover from dropped EAP-Success
1536 * messages.
1538 void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm)
1540 if (sm == NULL)
1541 return;
1542 eap_notify_lower_layer_success(sm->eap);
1547 * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid
1548 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1550 void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
1552 if (sm)
1553 eap_invalidate_cached_session(sm->eap);
1557 static struct wpa_ssid * eapol_sm_get_config(void *ctx)
1559 struct eapol_sm *sm = ctx;
1560 return sm ? sm->config : NULL;
1564 static u8 * eapol_sm_get_eapReqData(void *ctx, size_t *len)
1566 struct eapol_sm *sm = ctx;
1567 if (sm == NULL || sm->eapReqData == NULL) {
1568 *len = 0;
1569 return NULL;
1572 *len = sm->eapReqDataLen;
1573 return sm->eapReqData;
1577 static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
1579 struct eapol_sm *sm = ctx;
1580 if (sm == NULL)
1581 return FALSE;
1582 switch (variable) {
1583 case EAPOL_eapSuccess:
1584 return sm->eapSuccess;
1585 case EAPOL_eapRestart:
1586 return sm->eapRestart;
1587 case EAPOL_eapFail:
1588 return sm->eapFail;
1589 case EAPOL_eapResp:
1590 return sm->eapResp;
1591 case EAPOL_eapNoResp:
1592 return sm->eapNoResp;
1593 case EAPOL_eapReq:
1594 return sm->eapReq;
1595 case EAPOL_portEnabled:
1596 return sm->portEnabled;
1597 case EAPOL_altAccept:
1598 return sm->altAccept;
1599 case EAPOL_altReject:
1600 return sm->altReject;
1602 return FALSE;
1606 static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
1607 Boolean value)
1609 struct eapol_sm *sm = ctx;
1610 if (sm == NULL)
1611 return;
1612 switch (variable) {
1613 case EAPOL_eapSuccess:
1614 sm->eapSuccess = value;
1615 break;
1616 case EAPOL_eapRestart:
1617 sm->eapRestart = value;
1618 break;
1619 case EAPOL_eapFail:
1620 sm->eapFail = value;
1621 break;
1622 case EAPOL_eapResp:
1623 sm->eapResp = value;
1624 break;
1625 case EAPOL_eapNoResp:
1626 sm->eapNoResp = value;
1627 break;
1628 case EAPOL_eapReq:
1629 sm->eapReq = value;
1630 break;
1631 case EAPOL_portEnabled:
1632 sm->portEnabled = value;
1633 break;
1634 case EAPOL_altAccept:
1635 sm->altAccept = value;
1636 break;
1637 case EAPOL_altReject:
1638 sm->altReject = value;
1639 break;
1644 static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable)
1646 struct eapol_sm *sm = ctx;
1647 if (sm == NULL)
1648 return 0;
1649 switch (variable) {
1650 case EAPOL_idleWhile:
1651 return sm->idleWhile;
1653 return 0;
1657 static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
1658 unsigned int value)
1660 struct eapol_sm *sm = ctx;
1661 if (sm == NULL)
1662 return;
1663 switch (variable) {
1664 case EAPOL_idleWhile:
1665 sm->idleWhile = value;
1666 break;
1671 static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
1673 struct eapol_sm *sm = ctx;
1674 if (sm && sm->ctx && sm->ctx->set_config_blob)
1675 sm->ctx->set_config_blob(sm->ctx->ctx, blob);
1679 static const struct wpa_config_blob *
1680 eapol_sm_get_config_blob(void *ctx, const char *name)
1682 struct eapol_sm *sm = ctx;
1683 if (sm && sm->ctx && sm->ctx->get_config_blob)
1684 return sm->ctx->get_config_blob(sm->ctx->ctx, name);
1685 else
1686 return NULL;
1690 static void eapol_sm_notify_pending(void *ctx)
1692 struct eapol_sm *sm = ctx;
1693 if (sm == NULL)
1694 return;
1695 if (sm->eapReqData && !sm->eapReq) {
1696 wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP "
1697 "state machine - retrying pending EAP Request");
1698 sm->eapolEap = TRUE;
1699 sm->eapReq = TRUE;
1700 eapol_sm_step(sm);
1705 static struct eapol_callbacks eapol_cb =
1707 eapol_sm_get_config,
1708 eapol_sm_get_bool,
1709 eapol_sm_set_bool,
1710 eapol_sm_get_int,
1711 eapol_sm_set_int,
1712 eapol_sm_get_eapReqData,
1713 eapol_sm_set_config_blob,
1714 eapol_sm_get_config_blob,
1715 eapol_sm_notify_pending
1720 * eapol_sm_init - Initialize EAPOL state machine
1721 * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
1722 * and EAPOL state machine will free it in eapol_sm_deinit()
1723 * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
1725 * Allocate and initialize an EAPOL state machine.
1727 struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
1729 struct eapol_sm *sm;
1730 struct eap_config conf;
1731 sm = os_zalloc(sizeof(*sm));
1732 if (sm == NULL)
1733 return NULL;
1734 sm->ctx = ctx;
1736 sm->portControl = Auto;
1738 /* Supplicant PAE state machine */
1739 sm->heldPeriod = 60;
1740 sm->startPeriod = 30;
1741 sm->maxStart = 3;
1743 /* Supplicant Backend state machine */
1744 sm->authPeriod = 30;
1746 os_memset(&conf, 0, sizeof(conf));
1747 conf.opensc_engine_path = ctx->opensc_engine_path;
1748 conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
1749 conf.pkcs11_module_path = ctx->pkcs11_module_path;
1751 sm->eap = eap_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
1752 if (sm->eap == NULL) {
1753 os_free(sm);
1754 return NULL;
1757 /* Initialize EAPOL state machines */
1758 sm->initialize = TRUE;
1759 eapol_sm_step(sm);
1760 sm->initialize = FALSE;
1761 eapol_sm_step(sm);
1763 eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
1765 return sm;
1770 * eapol_sm_deinit - Deinitialize EAPOL state machine
1771 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1773 * Deinitialize and free EAPOL state machine.
1775 void eapol_sm_deinit(struct eapol_sm *sm)
1777 if (sm == NULL)
1778 return;
1779 eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
1780 eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
1781 eap_sm_deinit(sm->eap);
1782 os_free(sm->last_rx_key);
1783 os_free(sm->eapReqData);
1784 os_free(sm->ctx);
1785 os_free(sm);