List.mui: Update entries count prior to range change
[AROS.git] / workbench / network / WirelessManager / src / eapol_supp / eapol_supp_sm.c
blob77cd564b0d43be397f22982bd7e2fa6273179f05
1 /*
2 * EAPOL supplicant state machines
3 * Copyright (c) 2004-2008, 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 "state_machine.h"
19 #include "wpabuf.h"
20 #include "eloop.h"
21 #include "crypto/crypto.h"
22 #include "crypto/md5.h"
23 #include "common/eapol_common.h"
24 #include "eap_peer/eap.h"
25 #include "eapol_supp_sm.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 */
42 int timer_tick_enabled;
44 /* Global variables */
45 Boolean eapFail;
46 Boolean eapolEap;
47 Boolean eapSuccess;
48 Boolean initialize;
49 Boolean keyDone;
50 Boolean keyRun;
51 PortControl portControl;
52 Boolean portEnabled;
53 PortStatus suppPortStatus; /* dot1xSuppControlledPortStatus */
54 Boolean portValid;
55 Boolean suppAbort;
56 Boolean suppFail;
57 Boolean suppStart;
58 Boolean suppSuccess;
59 Boolean suppTimeout;
61 /* Supplicant PAE state machine */
62 enum {
63 SUPP_PAE_UNKNOWN = 0,
64 SUPP_PAE_DISCONNECTED = 1,
65 SUPP_PAE_LOGOFF = 2,
66 SUPP_PAE_CONNECTING = 3,
67 SUPP_PAE_AUTHENTICATING = 4,
68 SUPP_PAE_AUTHENTICATED = 5,
69 /* unused(6) */
70 SUPP_PAE_HELD = 7,
71 SUPP_PAE_RESTART = 8,
72 SUPP_PAE_S_FORCE_AUTH = 9,
73 SUPP_PAE_S_FORCE_UNAUTH = 10
74 } SUPP_PAE_state; /* dot1xSuppPaeState */
75 /* Variables */
76 Boolean userLogoff;
77 Boolean logoffSent;
78 unsigned int startCount;
79 Boolean eapRestart;
80 PortControl sPortMode;
81 /* Constants */
82 unsigned int heldPeriod; /* dot1xSuppHeldPeriod */
83 unsigned int startPeriod; /* dot1xSuppStartPeriod */
84 unsigned int maxStart; /* dot1xSuppMaxStart */
86 /* Key Receive state machine */
87 enum {
88 KEY_RX_UNKNOWN = 0,
89 KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
90 } KEY_RX_state;
91 /* Variables */
92 Boolean rxKey;
94 /* Supplicant Backend state machine */
95 enum {
96 SUPP_BE_UNKNOWN = 0,
97 SUPP_BE_INITIALIZE = 1,
98 SUPP_BE_IDLE = 2,
99 SUPP_BE_REQUEST = 3,
100 SUPP_BE_RECEIVE = 4,
101 SUPP_BE_RESPONSE = 5,
102 SUPP_BE_FAIL = 6,
103 SUPP_BE_TIMEOUT = 7,
104 SUPP_BE_SUCCESS = 8
105 } SUPP_BE_state; /* dot1xSuppBackendPaeState */
106 /* Variables */
107 Boolean eapNoResp;
108 Boolean eapReq;
109 Boolean eapResp;
110 /* Constants */
111 unsigned int authPeriod; /* dot1xSuppAuthPeriod */
113 /* Statistics */
114 unsigned int dot1xSuppEapolFramesRx;
115 unsigned int dot1xSuppEapolFramesTx;
116 unsigned int dot1xSuppEapolStartFramesTx;
117 unsigned int dot1xSuppEapolLogoffFramesTx;
118 unsigned int dot1xSuppEapolRespFramesTx;
119 unsigned int dot1xSuppEapolReqIdFramesRx;
120 unsigned int dot1xSuppEapolReqFramesRx;
121 unsigned int dot1xSuppInvalidEapolFramesRx;
122 unsigned int dot1xSuppEapLengthErrorFramesRx;
123 unsigned int dot1xSuppLastEapolFrameVersion;
124 unsigned char dot1xSuppLastEapolFrameSource[6];
126 /* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
127 Boolean changed;
128 struct eap_sm *eap;
129 struct eap_peer_config *config;
130 Boolean initial_req;
131 u8 *last_rx_key;
132 size_t last_rx_key_len;
133 struct wpabuf *eapReqData; /* 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);
196 static void eapol_sm_set_port_authorized(struct eapol_sm *sm);
197 static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm);
200 /* Port Timers state machine - implemented as a function that will be called
201 * once a second as a registered event loop timeout */
202 static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
204 struct eapol_sm *sm = timeout_ctx;
206 if (sm->authWhile > 0) {
207 sm->authWhile--;
208 if (sm->authWhile == 0)
209 wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0");
211 if (sm->heldWhile > 0) {
212 sm->heldWhile--;
213 if (sm->heldWhile == 0)
214 wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0");
216 if (sm->startWhen > 0) {
217 sm->startWhen--;
218 if (sm->startWhen == 0)
219 wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0");
221 if (sm->idleWhile > 0) {
222 sm->idleWhile--;
223 if (sm->idleWhile == 0)
224 wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0");
227 if (sm->authWhile | sm->heldWhile | sm->startWhen | sm->idleWhile) {
228 eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx,
229 sm);
230 } else {
231 wpa_printf(MSG_DEBUG, "EAPOL: disable timer tick");
232 sm->timer_tick_enabled = 0;
234 eapol_sm_step(sm);
238 static void eapol_enable_timer_tick(struct eapol_sm *sm)
240 if (sm->timer_tick_enabled)
241 return;
242 wpa_printf(MSG_DEBUG, "EAPOL: enable timer tick");
243 sm->timer_tick_enabled = 1;
244 eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
245 eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
249 SM_STATE(SUPP_PAE, LOGOFF)
251 SM_ENTRY(SUPP_PAE, LOGOFF);
252 eapol_sm_txLogoff(sm);
253 sm->logoffSent = TRUE;
254 sm->suppPortStatus = Unauthorized;
255 eapol_sm_set_port_unauthorized(sm);
259 SM_STATE(SUPP_PAE, DISCONNECTED)
261 SM_ENTRY(SUPP_PAE, DISCONNECTED);
262 sm->sPortMode = Auto;
263 sm->startCount = 0;
264 sm->logoffSent = FALSE;
265 sm->suppPortStatus = Unauthorized;
266 eapol_sm_set_port_unauthorized(sm);
267 sm->suppAbort = TRUE;
269 sm->unicast_key_received = FALSE;
270 sm->broadcast_key_received = FALSE;
274 SM_STATE(SUPP_PAE, CONNECTING)
276 int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING;
277 SM_ENTRY(SUPP_PAE, CONNECTING);
278 if (send_start) {
279 sm->startWhen = sm->startPeriod;
280 sm->startCount++;
281 } else {
283 * Do not send EAPOL-Start immediately since in most cases,
284 * Authenticator is going to start authentication immediately
285 * after association and an extra EAPOL-Start is just going to
286 * delay authentication. Use a short timeout to send the first
287 * EAPOL-Start if Authenticator does not start authentication.
289 #ifdef CONFIG_WPS
290 /* Reduce latency on starting WPS negotiation. */
291 sm->startWhen = 1;
292 #else /* CONFIG_WPS */
293 sm->startWhen = 3;
294 #endif /* CONFIG_WPS */
296 eapol_enable_timer_tick(sm);
297 sm->eapolEap = FALSE;
298 if (send_start)
299 eapol_sm_txStart(sm);
303 SM_STATE(SUPP_PAE, AUTHENTICATING)
305 SM_ENTRY(SUPP_PAE, AUTHENTICATING);
306 sm->startCount = 0;
307 sm->suppSuccess = FALSE;
308 sm->suppFail = FALSE;
309 sm->suppTimeout = FALSE;
310 sm->keyRun = FALSE;
311 sm->keyDone = FALSE;
312 sm->suppStart = TRUE;
316 SM_STATE(SUPP_PAE, HELD)
318 SM_ENTRY(SUPP_PAE, HELD);
319 sm->heldWhile = sm->heldPeriod;
320 eapol_enable_timer_tick(sm);
321 sm->suppPortStatus = Unauthorized;
322 eapol_sm_set_port_unauthorized(sm);
323 sm->cb_status = EAPOL_CB_FAILURE;
327 SM_STATE(SUPP_PAE, AUTHENTICATED)
329 SM_ENTRY(SUPP_PAE, AUTHENTICATED);
330 sm->suppPortStatus = Authorized;
331 eapol_sm_set_port_authorized(sm);
332 sm->cb_status = EAPOL_CB_SUCCESS;
336 SM_STATE(SUPP_PAE, RESTART)
338 SM_ENTRY(SUPP_PAE, RESTART);
339 sm->eapRestart = TRUE;
343 SM_STATE(SUPP_PAE, S_FORCE_AUTH)
345 SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
346 sm->suppPortStatus = Authorized;
347 eapol_sm_set_port_authorized(sm);
348 sm->sPortMode = ForceAuthorized;
352 SM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
354 SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
355 sm->suppPortStatus = Unauthorized;
356 eapol_sm_set_port_unauthorized(sm);
357 sm->sPortMode = ForceUnauthorized;
358 eapol_sm_txLogoff(sm);
362 SM_STEP(SUPP_PAE)
364 if ((sm->userLogoff && !sm->logoffSent) &&
365 !(sm->initialize || !sm->portEnabled))
366 SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF);
367 else if (((sm->portControl == Auto) &&
368 (sm->sPortMode != sm->portControl)) ||
369 sm->initialize || !sm->portEnabled)
370 SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED);
371 else if ((sm->portControl == ForceAuthorized) &&
372 (sm->sPortMode != sm->portControl) &&
373 !(sm->initialize || !sm->portEnabled))
374 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH);
375 else if ((sm->portControl == ForceUnauthorized) &&
376 (sm->sPortMode != sm->portControl) &&
377 !(sm->initialize || !sm->portEnabled))
378 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH);
379 else switch (sm->SUPP_PAE_state) {
380 case SUPP_PAE_UNKNOWN:
381 break;
382 case SUPP_PAE_LOGOFF:
383 if (!sm->userLogoff)
384 SM_ENTER(SUPP_PAE, DISCONNECTED);
385 break;
386 case SUPP_PAE_DISCONNECTED:
387 SM_ENTER(SUPP_PAE, CONNECTING);
388 break;
389 case SUPP_PAE_CONNECTING:
390 if (sm->startWhen == 0 && sm->startCount < sm->maxStart)
391 SM_ENTER(SUPP_PAE, CONNECTING);
392 else if (sm->startWhen == 0 &&
393 sm->startCount >= sm->maxStart &&
394 sm->portValid)
395 SM_ENTER(SUPP_PAE, AUTHENTICATED);
396 else if (sm->eapSuccess || sm->eapFail)
397 SM_ENTER(SUPP_PAE, AUTHENTICATING);
398 else if (sm->eapolEap)
399 SM_ENTER(SUPP_PAE, RESTART);
400 else if (sm->startWhen == 0 &&
401 sm->startCount >= sm->maxStart &&
402 !sm->portValid)
403 SM_ENTER(SUPP_PAE, HELD);
404 break;
405 case SUPP_PAE_AUTHENTICATING:
406 if (sm->eapSuccess && !sm->portValid &&
407 sm->conf.accept_802_1x_keys &&
408 sm->conf.required_keys == 0) {
409 wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for "
410 "plaintext connection; no EAPOL-Key frames "
411 "required");
412 sm->portValid = TRUE;
413 if (sm->ctx->eapol_done_cb)
414 sm->ctx->eapol_done_cb(sm->ctx->ctx);
416 if (sm->eapSuccess && sm->portValid)
417 SM_ENTER(SUPP_PAE, AUTHENTICATED);
418 else if (sm->eapFail || (sm->keyDone && !sm->portValid))
419 SM_ENTER(SUPP_PAE, HELD);
420 else if (sm->suppTimeout)
421 SM_ENTER(SUPP_PAE, CONNECTING);
422 break;
423 case SUPP_PAE_HELD:
424 if (sm->heldWhile == 0)
425 SM_ENTER(SUPP_PAE, CONNECTING);
426 else if (sm->eapolEap)
427 SM_ENTER(SUPP_PAE, RESTART);
428 break;
429 case SUPP_PAE_AUTHENTICATED:
430 if (sm->eapolEap && sm->portValid)
431 SM_ENTER(SUPP_PAE, RESTART);
432 else if (!sm->portValid)
433 SM_ENTER(SUPP_PAE, DISCONNECTED);
434 break;
435 case SUPP_PAE_RESTART:
436 if (!sm->eapRestart)
437 SM_ENTER(SUPP_PAE, AUTHENTICATING);
438 break;
439 case SUPP_PAE_S_FORCE_AUTH:
440 break;
441 case SUPP_PAE_S_FORCE_UNAUTH:
442 break;
447 SM_STATE(KEY_RX, NO_KEY_RECEIVE)
449 SM_ENTRY(KEY_RX, NO_KEY_RECEIVE);
453 SM_STATE(KEY_RX, KEY_RECEIVE)
455 SM_ENTRY(KEY_RX, KEY_RECEIVE);
456 eapol_sm_processKey(sm);
457 sm->rxKey = FALSE;
461 SM_STEP(KEY_RX)
463 if (sm->initialize || !sm->portEnabled)
464 SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
465 switch (sm->KEY_RX_state) {
466 case KEY_RX_UNKNOWN:
467 break;
468 case KEY_RX_NO_KEY_RECEIVE:
469 if (sm->rxKey)
470 SM_ENTER(KEY_RX, KEY_RECEIVE);
471 break;
472 case KEY_RX_KEY_RECEIVE:
473 if (sm->rxKey)
474 SM_ENTER(KEY_RX, KEY_RECEIVE);
475 break;
480 SM_STATE(SUPP_BE, REQUEST)
482 SM_ENTRY(SUPP_BE, REQUEST);
483 sm->authWhile = 0;
484 sm->eapReq = TRUE;
485 eapol_sm_getSuppRsp(sm);
489 SM_STATE(SUPP_BE, RESPONSE)
491 SM_ENTRY(SUPP_BE, RESPONSE);
492 eapol_sm_txSuppRsp(sm);
493 sm->eapResp = FALSE;
497 SM_STATE(SUPP_BE, SUCCESS)
499 SM_ENTRY(SUPP_BE, SUCCESS);
500 sm->keyRun = TRUE;
501 sm->suppSuccess = TRUE;
503 if (eap_key_available(sm->eap)) {
504 /* New key received - clear IEEE 802.1X EAPOL-Key replay
505 * counter */
506 sm->replay_counter_valid = FALSE;
511 SM_STATE(SUPP_BE, FAIL)
513 SM_ENTRY(SUPP_BE, FAIL);
514 sm->suppFail = TRUE;
518 SM_STATE(SUPP_BE, TIMEOUT)
520 SM_ENTRY(SUPP_BE, TIMEOUT);
521 sm->suppTimeout = TRUE;
525 SM_STATE(SUPP_BE, IDLE)
527 SM_ENTRY(SUPP_BE, IDLE);
528 sm->suppStart = FALSE;
529 sm->initial_req = TRUE;
533 SM_STATE(SUPP_BE, INITIALIZE)
535 SM_ENTRY(SUPP_BE, INITIALIZE);
536 eapol_sm_abortSupp(sm);
537 sm->suppAbort = FALSE;
541 SM_STATE(SUPP_BE, RECEIVE)
543 SM_ENTRY(SUPP_BE, RECEIVE);
544 sm->authWhile = sm->authPeriod;
545 eapol_enable_timer_tick(sm);
546 sm->eapolEap = FALSE;
547 sm->eapNoResp = FALSE;
548 sm->initial_req = FALSE;
552 SM_STEP(SUPP_BE)
554 if (sm->initialize || sm->suppAbort)
555 SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE);
556 else switch (sm->SUPP_BE_state) {
557 case SUPP_BE_UNKNOWN:
558 break;
559 case SUPP_BE_REQUEST:
561 * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
562 * and SUCCESS based on eapFail and eapSuccess, respectively.
563 * However, IEEE Std 802.1X-2004 is also specifying that
564 * eapNoResp should be set in conjuction with eapSuccess and
565 * eapFail which would mean that more than one of the
566 * transitions here would be activated at the same time.
567 * Skipping RESPONSE and/or RECEIVE states in these cases can
568 * cause problems and the direct transitions to do not seem
569 * correct. Because of this, the conditions for these
570 * transitions are verified only after eapNoResp. They are
571 * unlikely to be used since eapNoResp should always be set if
572 * either of eapSuccess or eapFail is set.
574 if (sm->eapResp && sm->eapNoResp) {
575 wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both "
576 "eapResp and eapNoResp set?!");
578 if (sm->eapResp)
579 SM_ENTER(SUPP_BE, RESPONSE);
580 else if (sm->eapNoResp)
581 SM_ENTER(SUPP_BE, RECEIVE);
582 else if (sm->eapFail)
583 SM_ENTER(SUPP_BE, FAIL);
584 else if (sm->eapSuccess)
585 SM_ENTER(SUPP_BE, SUCCESS);
586 break;
587 case SUPP_BE_RESPONSE:
588 SM_ENTER(SUPP_BE, RECEIVE);
589 break;
590 case SUPP_BE_SUCCESS:
591 SM_ENTER(SUPP_BE, IDLE);
592 break;
593 case SUPP_BE_FAIL:
594 SM_ENTER(SUPP_BE, IDLE);
595 break;
596 case SUPP_BE_TIMEOUT:
597 SM_ENTER(SUPP_BE, IDLE);
598 break;
599 case SUPP_BE_IDLE:
600 if (sm->eapFail && sm->suppStart)
601 SM_ENTER(SUPP_BE, FAIL);
602 else if (sm->eapolEap && sm->suppStart)
603 SM_ENTER(SUPP_BE, REQUEST);
604 else if (sm->eapSuccess && sm->suppStart)
605 SM_ENTER(SUPP_BE, SUCCESS);
606 break;
607 case SUPP_BE_INITIALIZE:
608 SM_ENTER(SUPP_BE, IDLE);
609 break;
610 case SUPP_BE_RECEIVE:
611 if (sm->eapolEap)
612 SM_ENTER(SUPP_BE, REQUEST);
613 else if (sm->eapFail)
614 SM_ENTER(SUPP_BE, FAIL);
615 else if (sm->authWhile == 0)
616 SM_ENTER(SUPP_BE, TIMEOUT);
617 else if (sm->eapSuccess)
618 SM_ENTER(SUPP_BE, SUCCESS);
619 break;
624 static void eapol_sm_txLogoff(struct eapol_sm *sm)
626 wpa_printf(MSG_DEBUG, "EAPOL: txLogoff");
627 sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
628 IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0);
629 sm->dot1xSuppEapolLogoffFramesTx++;
630 sm->dot1xSuppEapolFramesTx++;
634 static void eapol_sm_txStart(struct eapol_sm *sm)
636 wpa_printf(MSG_DEBUG, "EAPOL: txStart");
637 sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
638 IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0);
639 sm->dot1xSuppEapolStartFramesTx++;
640 sm->dot1xSuppEapolFramesTx++;
644 #define IEEE8021X_ENCR_KEY_LEN 32
645 #define IEEE8021X_SIGN_KEY_LEN 32
647 struct eap_key_data {
648 u8 encr_key[IEEE8021X_ENCR_KEY_LEN];
649 u8 sign_key[IEEE8021X_SIGN_KEY_LEN];
653 static void eapol_sm_processKey(struct eapol_sm *sm)
655 struct ieee802_1x_hdr *hdr;
656 struct ieee802_1x_eapol_key *key;
657 struct eap_key_data keydata;
658 u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
659 u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
660 int key_len, res, sign_key_len, encr_key_len;
661 u16 rx_key_length;
663 wpa_printf(MSG_DEBUG, "EAPOL: processKey");
664 if (sm->last_rx_key == NULL)
665 return;
667 if (!sm->conf.accept_802_1x_keys) {
668 wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key"
669 " even though this was not accepted - "
670 "ignoring this packet");
671 return;
674 hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
675 key = (struct ieee802_1x_eapol_key *) (hdr + 1);
676 if (sizeof(*hdr) + be_to_host16(hdr->length) > sm->last_rx_key_len) {
677 wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
678 return;
680 rx_key_length = WPA_GET_BE16(key->key_length);
681 wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
682 "EAPOL-Key: type=%d key_length=%d key_index=0x%x",
683 hdr->version, hdr->type, be_to_host16(hdr->length),
684 key->type, rx_key_length, key->key_index);
686 eapol_sm_notify_lower_layer_success(sm, 1);
687 sign_key_len = IEEE8021X_SIGN_KEY_LEN;
688 encr_key_len = IEEE8021X_ENCR_KEY_LEN;
689 res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata));
690 if (res < 0) {
691 wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for "
692 "decrypting EAPOL-Key keys");
693 return;
695 if (res == 16) {
696 /* LEAP derives only 16 bytes of keying material. */
697 res = eapol_sm_get_key(sm, (u8 *) &keydata, 16);
698 if (res) {
699 wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP "
700 "master key for decrypting EAPOL-Key keys");
701 return;
703 sign_key_len = 16;
704 encr_key_len = 16;
705 os_memcpy(keydata.sign_key, keydata.encr_key, 16);
706 } else if (res) {
707 wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key "
708 "data for decrypting EAPOL-Key keys (res=%d)", res);
709 return;
712 /* The key replay_counter must increase when same master key */
713 if (sm->replay_counter_valid &&
714 os_memcmp(sm->last_replay_counter, key->replay_counter,
715 IEEE8021X_REPLAY_COUNTER_LEN) >= 0) {
716 wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did "
717 "not increase - ignoring key");
718 wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter",
719 sm->last_replay_counter,
720 IEEE8021X_REPLAY_COUNTER_LEN);
721 wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter",
722 key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN);
723 return;
726 /* Verify key signature (HMAC-MD5) */
727 os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN);
728 os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN);
729 hmac_md5(keydata.sign_key, sign_key_len,
730 sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
731 key->key_signature);
732 if (os_memcmp(orig_key_sign, key->key_signature,
733 IEEE8021X_KEY_SIGN_LEN) != 0) {
734 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
735 "EAPOL-Key packet");
736 os_memcpy(key->key_signature, orig_key_sign,
737 IEEE8021X_KEY_SIGN_LEN);
738 return;
740 wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
742 key_len = be_to_host16(hdr->length) - sizeof(*key);
743 if (key_len > 32 || rx_key_length > 32) {
744 wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
745 key_len ? key_len : rx_key_length);
746 return;
748 if (key_len == rx_key_length) {
749 os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
750 os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
751 encr_key_len);
752 os_memcpy(datakey, key + 1, key_len);
753 rc4_skip(ekey, IEEE8021X_KEY_IV_LEN + encr_key_len, 0,
754 datakey, key_len);
755 wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
756 datakey, key_len);
757 } else if (key_len == 0) {
759 * IEEE 802.1X-2004 specifies that least significant Key Length
760 * octets from MS-MPPE-Send-Key are used as the key if the key
761 * data is not present. This seems to be meaning the beginning
762 * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
763 * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
764 * Anyway, taking the beginning of the keying material from EAP
765 * seems to interoperate with Authenticators.
767 key_len = rx_key_length;
768 os_memcpy(datakey, keydata.encr_key, key_len);
769 wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying "
770 "material data encryption key",
771 datakey, key_len);
772 } else {
773 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
774 "(key_length=%d)", key_len, rx_key_length);
775 return;
778 sm->replay_counter_valid = TRUE;
779 os_memcpy(sm->last_replay_counter, key->replay_counter,
780 IEEE8021X_REPLAY_COUNTER_LEN);
782 wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
783 "len %d",
784 key->key_index & IEEE8021X_KEY_INDEX_FLAG ?
785 "unicast" : "broadcast",
786 key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len);
788 if (sm->ctx->set_wep_key &&
789 sm->ctx->set_wep_key(sm->ctx->ctx,
790 key->key_index & IEEE8021X_KEY_INDEX_FLAG,
791 key->key_index & IEEE8021X_KEY_INDEX_MASK,
792 datakey, key_len) < 0) {
793 wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
794 " driver.");
795 } else {
796 if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
797 sm->unicast_key_received = TRUE;
798 else
799 sm->broadcast_key_received = TRUE;
801 if ((sm->unicast_key_received ||
802 !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) &&
803 (sm->broadcast_key_received ||
804 !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST)))
806 wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
807 "frames received");
808 sm->portValid = TRUE;
809 if (sm->ctx->eapol_done_cb)
810 sm->ctx->eapol_done_cb(sm->ctx->ctx);
816 static void eapol_sm_getSuppRsp(struct eapol_sm *sm)
818 wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp");
819 /* EAP layer processing; no special code is needed, since Supplicant
820 * Backend state machine is waiting for eapNoResp or eapResp to be set
821 * and these are only set in the EAP state machine when the processing
822 * has finished. */
826 static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
828 struct wpabuf *resp;
830 wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
831 resp = eap_get_eapRespData(sm->eap);
832 if (resp == NULL) {
833 wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
834 "not available");
835 return;
838 /* Send EAP-Packet from the EAP layer to the Authenticator */
839 sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
840 IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head(resp),
841 wpabuf_len(resp));
843 /* eapRespData is not used anymore, so free it here */
844 wpabuf_free(resp);
846 if (sm->initial_req)
847 sm->dot1xSuppEapolReqIdFramesRx++;
848 else
849 sm->dot1xSuppEapolReqFramesRx++;
850 sm->dot1xSuppEapolRespFramesTx++;
851 sm->dot1xSuppEapolFramesTx++;
855 static void eapol_sm_abortSupp(struct eapol_sm *sm)
857 /* release system resources that may have been allocated for the
858 * authentication session */
859 os_free(sm->last_rx_key);
860 sm->last_rx_key = NULL;
861 wpabuf_free(sm->eapReqData);
862 sm->eapReqData = NULL;
863 eap_sm_abort(sm->eap);
867 static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
869 eapol_sm_step(timeout_ctx);
873 static void eapol_sm_set_port_authorized(struct eapol_sm *sm)
875 if (sm->ctx->port_cb)
876 sm->ctx->port_cb(sm->ctx->ctx, 1);
880 static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm)
882 if (sm->ctx->port_cb)
883 sm->ctx->port_cb(sm->ctx->ctx, 0);
888 * eapol_sm_step - EAPOL state machine step function
889 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
891 * This function is called to notify the state machine about changed external
892 * variables. It will step through the EAPOL state machines in loop to process
893 * all triggered state changes.
895 void eapol_sm_step(struct eapol_sm *sm)
897 int i;
899 /* In theory, it should be ok to run this in loop until !changed.
900 * However, it is better to use a limit on number of iterations to
901 * allow events (e.g., SIGTERM) to stop the program cleanly if the
902 * state machine were to generate a busy loop. */
903 for (i = 0; i < 100; i++) {
904 sm->changed = FALSE;
905 SM_STEP_RUN(SUPP_PAE);
906 SM_STEP_RUN(KEY_RX);
907 SM_STEP_RUN(SUPP_BE);
908 if (eap_peer_sm_step(sm->eap))
909 sm->changed = TRUE;
910 if (!sm->changed)
911 break;
914 if (sm->changed) {
915 /* restart EAPOL state machine step from timeout call in order
916 * to allow other events to be processed. */
917 eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
918 eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm);
921 if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
922 int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0;
923 sm->cb_status = EAPOL_CB_IN_PROGRESS;
924 sm->ctx->cb(sm, success, sm->ctx->cb_ctx);
929 #ifdef CONFIG_CTRL_IFACE
930 static const char *eapol_supp_pae_state(int state)
932 switch (state) {
933 case SUPP_PAE_LOGOFF:
934 return "LOGOFF";
935 case SUPP_PAE_DISCONNECTED:
936 return "DISCONNECTED";
937 case SUPP_PAE_CONNECTING:
938 return "CONNECTING";
939 case SUPP_PAE_AUTHENTICATING:
940 return "AUTHENTICATING";
941 case SUPP_PAE_HELD:
942 return "HELD";
943 case SUPP_PAE_AUTHENTICATED:
944 return "AUTHENTICATED";
945 case SUPP_PAE_RESTART:
946 return "RESTART";
947 default:
948 return "UNKNOWN";
953 static const char *eapol_supp_be_state(int state)
955 switch (state) {
956 case SUPP_BE_REQUEST:
957 return "REQUEST";
958 case SUPP_BE_RESPONSE:
959 return "RESPONSE";
960 case SUPP_BE_SUCCESS:
961 return "SUCCESS";
962 case SUPP_BE_FAIL:
963 return "FAIL";
964 case SUPP_BE_TIMEOUT:
965 return "TIMEOUT";
966 case SUPP_BE_IDLE:
967 return "IDLE";
968 case SUPP_BE_INITIALIZE:
969 return "INITIALIZE";
970 case SUPP_BE_RECEIVE:
971 return "RECEIVE";
972 default:
973 return "UNKNOWN";
978 static const char * eapol_port_status(PortStatus status)
980 if (status == Authorized)
981 return "Authorized";
982 else
983 return "Unauthorized";
985 #endif /* CONFIG_CTRL_IFACE */
988 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
989 static const char * eapol_port_control(PortControl ctrl)
991 switch (ctrl) {
992 case Auto:
993 return "Auto";
994 case ForceUnauthorized:
995 return "ForceUnauthorized";
996 case ForceAuthorized:
997 return "ForceAuthorized";
998 default:
999 return "Unknown";
1002 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1006 * eapol_sm_configure - Set EAPOL variables
1007 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1008 * @heldPeriod: dot1xSuppHeldPeriod
1009 * @authPeriod: dot1xSuppAuthPeriod
1010 * @startPeriod: dot1xSuppStartPeriod
1011 * @maxStart: dot1xSuppMaxStart
1013 * Set configurable EAPOL state machine variables. Each variable can be set to
1014 * the given value or ignored if set to -1 (to set only some of the variables).
1016 void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
1017 int startPeriod, int maxStart)
1019 if (sm == NULL)
1020 return;
1021 if (heldPeriod >= 0)
1022 sm->heldPeriod = heldPeriod;
1023 if (authPeriod >= 0)
1024 sm->authPeriod = authPeriod;
1025 if (startPeriod >= 0)
1026 sm->startPeriod = startPeriod;
1027 if (maxStart >= 0)
1028 sm->maxStart = maxStart;
1032 #ifdef CONFIG_CTRL_IFACE
1034 * eapol_sm_get_status - Get EAPOL state machine status
1035 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1036 * @buf: Buffer for status information
1037 * @buflen: Maximum buffer length
1038 * @verbose: Whether to include verbose status information
1039 * Returns: Number of bytes written to buf.
1041 * Query EAPOL state machine for status information. This function fills in a
1042 * text area with current status information from the EAPOL state machine. If
1043 * the buffer (buf) is not large enough, status information will be truncated
1044 * to fit the buffer.
1046 int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
1047 int verbose)
1049 int len, ret;
1050 if (sm == NULL)
1051 return 0;
1053 len = os_snprintf(buf, buflen,
1054 "Supplicant PAE state=%s\n"
1055 "suppPortStatus=%s\n",
1056 eapol_supp_pae_state(sm->SUPP_PAE_state),
1057 eapol_port_status(sm->suppPortStatus));
1058 if (len < 0 || (size_t) len >= buflen)
1059 return 0;
1061 if (verbose) {
1062 ret = os_snprintf(buf + len, buflen - len,
1063 "heldPeriod=%u\n"
1064 "authPeriod=%u\n"
1065 "startPeriod=%u\n"
1066 "maxStart=%u\n"
1067 "portControl=%s\n"
1068 "Supplicant Backend state=%s\n",
1069 sm->heldPeriod,
1070 sm->authPeriod,
1071 sm->startPeriod,
1072 sm->maxStart,
1073 eapol_port_control(sm->portControl),
1074 eapol_supp_be_state(sm->SUPP_BE_state));
1075 if (ret < 0 || (size_t) ret >= buflen - len)
1076 return len;
1077 len += ret;
1080 len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
1082 return len;
1087 * eapol_sm_get_mib - Get EAPOL state machine MIBs
1088 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1089 * @buf: Buffer for MIB information
1090 * @buflen: Maximum buffer length
1091 * Returns: Number of bytes written to buf.
1093 * Query EAPOL state machine for MIB information. This function fills in a
1094 * text area with current MIB information from the EAPOL state machine. If
1095 * the buffer (buf) is not large enough, MIB information will be truncated to
1096 * fit the buffer.
1098 int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
1100 size_t len;
1101 int ret;
1103 if (sm == NULL)
1104 return 0;
1105 ret = os_snprintf(buf, buflen,
1106 "dot1xSuppPaeState=%d\n"
1107 "dot1xSuppHeldPeriod=%u\n"
1108 "dot1xSuppAuthPeriod=%u\n"
1109 "dot1xSuppStartPeriod=%u\n"
1110 "dot1xSuppMaxStart=%u\n"
1111 "dot1xSuppSuppControlledPortStatus=%s\n"
1112 "dot1xSuppBackendPaeState=%d\n",
1113 sm->SUPP_PAE_state,
1114 sm->heldPeriod,
1115 sm->authPeriod,
1116 sm->startPeriod,
1117 sm->maxStart,
1118 sm->suppPortStatus == Authorized ?
1119 "Authorized" : "Unauthorized",
1120 sm->SUPP_BE_state);
1122 if (ret < 0 || (size_t) ret >= buflen)
1123 return 0;
1124 len = ret;
1126 ret = os_snprintf(buf + len, buflen - len,
1127 "dot1xSuppEapolFramesRx=%u\n"
1128 "dot1xSuppEapolFramesTx=%u\n"
1129 "dot1xSuppEapolStartFramesTx=%u\n"
1130 "dot1xSuppEapolLogoffFramesTx=%u\n"
1131 "dot1xSuppEapolRespFramesTx=%u\n"
1132 "dot1xSuppEapolReqIdFramesRx=%u\n"
1133 "dot1xSuppEapolReqFramesRx=%u\n"
1134 "dot1xSuppInvalidEapolFramesRx=%u\n"
1135 "dot1xSuppEapLengthErrorFramesRx=%u\n"
1136 "dot1xSuppLastEapolFrameVersion=%u\n"
1137 "dot1xSuppLastEapolFrameSource=" MACSTR "\n",
1138 sm->dot1xSuppEapolFramesRx,
1139 sm->dot1xSuppEapolFramesTx,
1140 sm->dot1xSuppEapolStartFramesTx,
1141 sm->dot1xSuppEapolLogoffFramesTx,
1142 sm->dot1xSuppEapolRespFramesTx,
1143 sm->dot1xSuppEapolReqIdFramesRx,
1144 sm->dot1xSuppEapolReqFramesRx,
1145 sm->dot1xSuppInvalidEapolFramesRx,
1146 sm->dot1xSuppEapLengthErrorFramesRx,
1147 sm->dot1xSuppLastEapolFrameVersion,
1148 MAC2STR(sm->dot1xSuppLastEapolFrameSource));
1150 if (ret < 0 || (size_t) ret >= buflen - len)
1151 return len;
1152 len += ret;
1154 return len;
1156 #endif /* CONFIG_CTRL_IFACE */
1160 * eapol_sm_rx_eapol - Process received EAPOL frames
1161 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1162 * @src: Source MAC address of the EAPOL packet
1163 * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
1164 * @len: Length of the EAPOL frame
1165 * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
1166 * -1 failure
1168 int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
1169 size_t len)
1171 const struct ieee802_1x_hdr *hdr;
1172 const struct ieee802_1x_eapol_key *key;
1173 int data_len;
1174 int res = 1;
1175 size_t plen;
1177 if (sm == NULL)
1178 return 0;
1179 sm->dot1xSuppEapolFramesRx++;
1180 if (len < sizeof(*hdr)) {
1181 sm->dot1xSuppInvalidEapolFramesRx++;
1182 return 0;
1184 hdr = (const struct ieee802_1x_hdr *) buf;
1185 sm->dot1xSuppLastEapolFrameVersion = hdr->version;
1186 os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
1187 if (hdr->version < EAPOL_VERSION) {
1188 /* TODO: backwards compatibility */
1190 plen = be_to_host16(hdr->length);
1191 if (plen > len - sizeof(*hdr)) {
1192 sm->dot1xSuppEapLengthErrorFramesRx++;
1193 return 0;
1195 #ifdef CONFIG_WPS
1196 if (sm->conf.workaround &&
1197 plen < len - sizeof(*hdr) &&
1198 hdr->type == IEEE802_1X_TYPE_EAP_PACKET &&
1199 len - sizeof(*hdr) > sizeof(struct eap_hdr)) {
1200 const struct eap_hdr *ehdr =
1201 (const struct eap_hdr *) (hdr + 1);
1202 u16 elen;
1204 elen = be_to_host16(ehdr->length);
1205 if (elen > plen && elen <= len - sizeof(*hdr)) {
1207 * Buffalo WHR-G125 Ver.1.47 seems to send EAP-WPS
1208 * packets with too short EAPOL header length field
1209 * (14 octets). This is fixed in firmware Ver.1.49.
1210 * As a workaround, fix the EAPOL header based on the
1211 * correct length in the EAP packet.
1213 wpa_printf(MSG_DEBUG, "EAPOL: Workaround - fix EAPOL "
1214 "payload length based on EAP header: "
1215 "%d -> %d", (int) plen, elen);
1216 plen = elen;
1219 #endif /* CONFIG_WPS */
1220 data_len = plen + sizeof(*hdr);
1222 switch (hdr->type) {
1223 case IEEE802_1X_TYPE_EAP_PACKET:
1224 if (sm->cached_pmk) {
1225 /* Trying to use PMKSA caching, but Authenticator did
1226 * not seem to have a matching entry. Need to restart
1227 * EAPOL state machines.
1229 eapol_sm_abort_cached(sm);
1231 wpabuf_free(sm->eapReqData);
1232 sm->eapReqData = wpabuf_alloc_copy(hdr + 1, plen);
1233 if (sm->eapReqData) {
1234 wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
1235 "frame");
1236 sm->eapolEap = TRUE;
1237 eapol_sm_step(sm);
1239 break;
1240 case IEEE802_1X_TYPE_EAPOL_KEY:
1241 if (plen < sizeof(*key)) {
1242 wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key "
1243 "frame received");
1244 break;
1246 key = (const struct ieee802_1x_eapol_key *) (hdr + 1);
1247 if (key->type == EAPOL_KEY_TYPE_WPA ||
1248 key->type == EAPOL_KEY_TYPE_RSN) {
1249 /* WPA Supplicant takes care of this frame. */
1250 wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
1251 "frame in EAPOL state machines");
1252 res = 0;
1253 break;
1255 if (key->type != EAPOL_KEY_TYPE_RC4) {
1256 wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown "
1257 "EAPOL-Key type %d", key->type);
1258 break;
1260 os_free(sm->last_rx_key);
1261 sm->last_rx_key = os_malloc(data_len);
1262 if (sm->last_rx_key) {
1263 wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key "
1264 "frame");
1265 os_memcpy(sm->last_rx_key, buf, data_len);
1266 sm->last_rx_key_len = data_len;
1267 sm->rxKey = TRUE;
1268 eapol_sm_step(sm);
1270 break;
1271 default:
1272 wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
1273 hdr->type);
1274 sm->dot1xSuppInvalidEapolFramesRx++;
1275 break;
1278 return res;
1283 * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet
1284 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1286 * Notify EAPOL state machine about transmitted EAPOL packet from an external
1287 * component, e.g., WPA. This will update the statistics.
1289 void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
1291 if (sm)
1292 sm->dot1xSuppEapolFramesTx++;
1297 * eapol_sm_notify_portEnabled - Notification about portEnabled change
1298 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1299 * @enabled: New portEnabled value
1301 * Notify EAPOL state machine about new portEnabled value.
1303 void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
1305 if (sm == NULL)
1306 return;
1307 wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1308 "portEnabled=%d", enabled);
1309 sm->portEnabled = enabled;
1310 eapol_sm_step(sm);
1315 * eapol_sm_notify_portValid - Notification about portValid change
1316 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1317 * @valid: New portValid value
1319 * Notify EAPOL state machine about new portValid value.
1321 void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
1323 if (sm == NULL)
1324 return;
1325 wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1326 "portValid=%d", valid);
1327 sm->portValid = valid;
1328 eapol_sm_step(sm);
1333 * eapol_sm_notify_eap_success - Notification of external EAP success trigger
1334 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1335 * @success: %TRUE = set success, %FALSE = clear success
1337 * Notify the EAPOL state machine that external event has forced EAP state to
1338 * success (success = %TRUE). This can be cleared by setting success = %FALSE.
1340 * This function is called to update EAP state when WPA-PSK key handshake has
1341 * been completed successfully since WPA-PSK does not use EAP state machine.
1343 void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
1345 if (sm == NULL)
1346 return;
1347 wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1348 "EAP success=%d", success);
1349 sm->eapSuccess = success;
1350 sm->altAccept = success;
1351 if (success)
1352 eap_notify_success(sm->eap);
1353 eapol_sm_step(sm);
1358 * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
1359 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1360 * @fail: %TRUE = set failure, %FALSE = clear failure
1362 * Notify EAPOL state machine that external event has forced EAP state to
1363 * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE.
1365 void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
1367 if (sm == NULL)
1368 return;
1369 wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1370 "EAP fail=%d", fail);
1371 sm->eapFail = fail;
1372 sm->altReject = fail;
1373 eapol_sm_step(sm);
1378 * eapol_sm_notify_config - Notification of EAPOL configuration change
1379 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1380 * @config: Pointer to current network EAP configuration
1381 * @conf: Pointer to EAPOL configuration data
1383 * Notify EAPOL state machine that configuration has changed. config will be
1384 * stored as a backpointer to network configuration. This can be %NULL to clear
1385 * the stored pointed. conf will be copied to local EAPOL/EAP configuration
1386 * data. If conf is %NULL, this part of the configuration change will be
1387 * skipped.
1389 void eapol_sm_notify_config(struct eapol_sm *sm,
1390 struct eap_peer_config *config,
1391 const struct eapol_config *conf)
1393 if (sm == NULL)
1394 return;
1396 sm->config = config;
1398 if (conf == NULL)
1399 return;
1401 sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys;
1402 sm->conf.required_keys = conf->required_keys;
1403 sm->conf.fast_reauth = conf->fast_reauth;
1404 sm->conf.workaround = conf->workaround;
1405 if (sm->eap) {
1406 eap_set_fast_reauth(sm->eap, conf->fast_reauth);
1407 eap_set_workaround(sm->eap, conf->workaround);
1408 eap_set_force_disabled(sm->eap, conf->eap_disabled);
1414 * eapol_sm_get_key - Get master session key (MSK) from EAP
1415 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1416 * @key: Pointer for key buffer
1417 * @len: Number of bytes to copy to key
1418 * Returns: 0 on success (len of key available), maximum available key len
1419 * (>0) if key is available but it is shorter than len, or -1 on failure.
1421 * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key
1422 * is available only after a successful authentication.
1424 int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
1426 const u8 *eap_key;
1427 size_t eap_len;
1429 if (sm == NULL || !eap_key_available(sm->eap)) {
1430 wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
1431 return -1;
1433 eap_key = eap_get_eapKeyData(sm->eap, &eap_len);
1434 if (eap_key == NULL) {
1435 wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData");
1436 return -1;
1438 if (len > eap_len) {
1439 wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not "
1440 "available (len=%lu)",
1441 (unsigned long) len, (unsigned long) eap_len);
1442 return eap_len;
1444 os_memcpy(key, eap_key, len);
1445 wpa_printf(MSG_DEBUG, "EAPOL: Successfully fetched key (len=%lu)",
1446 (unsigned long) len);
1447 return 0;
1452 * eapol_sm_notify_logoff - Notification of logon/logoff commands
1453 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1454 * @logoff: Whether command was logoff
1456 * Notify EAPOL state machines that user requested logon/logoff.
1458 void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
1460 if (sm) {
1461 sm->userLogoff = logoff;
1462 eapol_sm_step(sm);
1468 * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching
1469 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1471 * Notify EAPOL state machines that PMKSA caching was successful. This is used
1472 * to move EAPOL and EAP state machines into authenticated/successful state.
1474 void eapol_sm_notify_cached(struct eapol_sm *sm)
1476 if (sm == NULL)
1477 return;
1478 wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL");
1479 sm->SUPP_PAE_state = SUPP_PAE_AUTHENTICATED;
1480 sm->suppPortStatus = Authorized;
1481 eapol_sm_set_port_authorized(sm);
1482 sm->portValid = TRUE;
1483 eap_notify_success(sm->eap);
1484 eapol_sm_step(sm);
1489 * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
1490 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1491 * @attempt: Whether PMKSA caching is tried
1493 * Notify EAPOL state machines whether PMKSA caching is used.
1495 void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt)
1497 if (sm == NULL)
1498 return;
1499 if (attempt) {
1500 wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
1501 sm->cached_pmk = TRUE;
1502 } else {
1503 wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA");
1504 sm->cached_pmk = FALSE;
1509 static void eapol_sm_abort_cached(struct eapol_sm *sm)
1511 wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, "
1512 "doing full EAP authentication");
1513 if (sm == NULL)
1514 return;
1515 sm->cached_pmk = FALSE;
1516 sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
1517 sm->suppPortStatus = Unauthorized;
1518 eapol_sm_set_port_unauthorized(sm);
1520 /* Make sure we do not start sending EAPOL-Start frames first, but
1521 * instead move to RESTART state to start EAPOL authentication. */
1522 sm->startWhen = 3;
1523 eapol_enable_timer_tick(sm);
1525 if (sm->ctx->aborted_cached)
1526 sm->ctx->aborted_cached(sm->ctx->ctx);
1531 * eapol_sm_register_scard_ctx - Notification of smart card context
1532 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1533 * @ctx: Context data for smart card operations
1535 * Notify EAPOL state machines of context data for smart card operations. This
1536 * context data will be used as a parameter for scard_*() functions.
1538 void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
1540 if (sm) {
1541 sm->ctx->scard_ctx = ctx;
1542 eap_register_scard_ctx(sm->eap, ctx);
1548 * eapol_sm_notify_portControl - Notification of portControl changes
1549 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1550 * @portControl: New value for portControl variable
1552 * Notify EAPOL state machines that portControl variable has changed.
1554 void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
1556 if (sm == NULL)
1557 return;
1558 wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1559 "portControl=%s", eapol_port_control(portControl));
1560 sm->portControl = portControl;
1561 eapol_sm_step(sm);
1566 * eapol_sm_notify_ctrl_attached - Notification of attached monitor
1567 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1569 * Notify EAPOL state machines that a monitor was attached to the control
1570 * interface to trigger re-sending of pending requests for user input.
1572 void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
1574 if (sm == NULL)
1575 return;
1576 eap_sm_notify_ctrl_attached(sm->eap);
1581 * eapol_sm_notify_ctrl_response - Notification of received user input
1582 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1584 * Notify EAPOL state machines that a control response, i.e., user
1585 * input, was received in order to trigger retrying of a pending EAP request.
1587 void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
1589 if (sm == NULL)
1590 return;
1591 if (sm->eapReqData && !sm->eapReq) {
1592 wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
1593 "input) notification - retrying pending EAP "
1594 "Request");
1595 sm->eapolEap = TRUE;
1596 sm->eapReq = TRUE;
1597 eapol_sm_step(sm);
1603 * eapol_sm_request_reauth - Request reauthentication
1604 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1606 * This function can be used to request EAPOL reauthentication, e.g., when the
1607 * current PMKSA entry is nearing expiration.
1609 void eapol_sm_request_reauth(struct eapol_sm *sm)
1611 if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
1612 return;
1613 eapol_sm_txStart(sm);
1618 * eapol_sm_notify_lower_layer_success - Notification of lower layer success
1619 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1620 * @in_eapol_sm: Whether the caller is already running inside EAPOL state
1621 * machine loop (eapol_sm_step())
1623 * Notify EAPOL (and EAP) state machines that a lower layer has detected a
1624 * successful authentication. This is used to recover from dropped EAP-Success
1625 * messages.
1627 void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm)
1629 if (sm == NULL)
1630 return;
1631 eap_notify_lower_layer_success(sm->eap);
1632 if (!in_eapol_sm)
1633 eapol_sm_step(sm);
1638 * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid
1639 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1641 void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
1643 if (sm)
1644 eap_invalidate_cached_session(sm->eap);
1648 static struct eap_peer_config * eapol_sm_get_config(void *ctx)
1650 struct eapol_sm *sm = ctx;
1651 return sm ? sm->config : NULL;
1655 static struct wpabuf * eapol_sm_get_eapReqData(void *ctx)
1657 struct eapol_sm *sm = ctx;
1658 if (sm == NULL || sm->eapReqData == NULL)
1659 return NULL;
1661 return sm->eapReqData;
1665 static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
1667 struct eapol_sm *sm = ctx;
1668 if (sm == NULL)
1669 return FALSE;
1670 switch (variable) {
1671 case EAPOL_eapSuccess:
1672 return sm->eapSuccess;
1673 case EAPOL_eapRestart:
1674 return sm->eapRestart;
1675 case EAPOL_eapFail:
1676 return sm->eapFail;
1677 case EAPOL_eapResp:
1678 return sm->eapResp;
1679 case EAPOL_eapNoResp:
1680 return sm->eapNoResp;
1681 case EAPOL_eapReq:
1682 return sm->eapReq;
1683 case EAPOL_portEnabled:
1684 return sm->portEnabled;
1685 case EAPOL_altAccept:
1686 return sm->altAccept;
1687 case EAPOL_altReject:
1688 return sm->altReject;
1690 return FALSE;
1694 static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
1695 Boolean value)
1697 struct eapol_sm *sm = ctx;
1698 if (sm == NULL)
1699 return;
1700 switch (variable) {
1701 case EAPOL_eapSuccess:
1702 sm->eapSuccess = value;
1703 break;
1704 case EAPOL_eapRestart:
1705 sm->eapRestart = value;
1706 break;
1707 case EAPOL_eapFail:
1708 sm->eapFail = value;
1709 break;
1710 case EAPOL_eapResp:
1711 sm->eapResp = value;
1712 break;
1713 case EAPOL_eapNoResp:
1714 sm->eapNoResp = value;
1715 break;
1716 case EAPOL_eapReq:
1717 sm->eapReq = value;
1718 break;
1719 case EAPOL_portEnabled:
1720 sm->portEnabled = value;
1721 break;
1722 case EAPOL_altAccept:
1723 sm->altAccept = value;
1724 break;
1725 case EAPOL_altReject:
1726 sm->altReject = value;
1727 break;
1732 static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable)
1734 struct eapol_sm *sm = ctx;
1735 if (sm == NULL)
1736 return 0;
1737 switch (variable) {
1738 case EAPOL_idleWhile:
1739 return sm->idleWhile;
1741 return 0;
1745 static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
1746 unsigned int value)
1748 struct eapol_sm *sm = ctx;
1749 if (sm == NULL)
1750 return;
1751 switch (variable) {
1752 case EAPOL_idleWhile:
1753 sm->idleWhile = value;
1754 eapol_enable_timer_tick(sm);
1755 break;
1760 static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
1762 #ifndef CONFIG_NO_CONFIG_BLOBS
1763 struct eapol_sm *sm = ctx;
1764 if (sm && sm->ctx && sm->ctx->set_config_blob)
1765 sm->ctx->set_config_blob(sm->ctx->ctx, blob);
1766 #endif /* CONFIG_NO_CONFIG_BLOBS */
1770 static const struct wpa_config_blob *
1771 eapol_sm_get_config_blob(void *ctx, const char *name)
1773 #ifndef CONFIG_NO_CONFIG_BLOBS
1774 struct eapol_sm *sm = ctx;
1775 if (sm && sm->ctx && sm->ctx->get_config_blob)
1776 return sm->ctx->get_config_blob(sm->ctx->ctx, name);
1777 else
1778 return NULL;
1779 #else /* CONFIG_NO_CONFIG_BLOBS */
1780 return NULL;
1781 #endif /* CONFIG_NO_CONFIG_BLOBS */
1785 static void eapol_sm_notify_pending(void *ctx)
1787 struct eapol_sm *sm = ctx;
1788 if (sm == NULL)
1789 return;
1790 if (sm->eapReqData && !sm->eapReq) {
1791 wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP "
1792 "state machine - retrying pending EAP Request");
1793 sm->eapolEap = TRUE;
1794 sm->eapReq = TRUE;
1795 eapol_sm_step(sm);
1800 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
1801 static void eapol_sm_eap_param_needed(void *ctx, const char *field,
1802 const char *txt)
1804 struct eapol_sm *sm = ctx;
1805 wpa_printf(MSG_DEBUG, "EAPOL: EAP parameter needed");
1806 if (sm->ctx->eap_param_needed)
1807 sm->ctx->eap_param_needed(sm->ctx->ctx, field, txt);
1809 #else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1810 #define eapol_sm_eap_param_needed NULL
1811 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1814 static struct eapol_callbacks eapol_cb =
1816 eapol_sm_get_config,
1817 eapol_sm_get_bool,
1818 eapol_sm_set_bool,
1819 eapol_sm_get_int,
1820 eapol_sm_set_int,
1821 eapol_sm_get_eapReqData,
1822 eapol_sm_set_config_blob,
1823 eapol_sm_get_config_blob,
1824 eapol_sm_notify_pending,
1825 eapol_sm_eap_param_needed
1830 * eapol_sm_init - Initialize EAPOL state machine
1831 * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
1832 * and EAPOL state machine will free it in eapol_sm_deinit()
1833 * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
1835 * Allocate and initialize an EAPOL state machine.
1837 struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
1839 struct eapol_sm *sm;
1840 struct eap_config conf;
1841 sm = os_zalloc(sizeof(*sm));
1842 if (sm == NULL)
1843 return NULL;
1844 sm->ctx = ctx;
1846 sm->portControl = Auto;
1848 /* Supplicant PAE state machine */
1849 sm->heldPeriod = 60;
1850 sm->startPeriod = 30;
1851 sm->maxStart = 3;
1853 /* Supplicant Backend state machine */
1854 sm->authPeriod = 30;
1856 os_memset(&conf, 0, sizeof(conf));
1857 conf.opensc_engine_path = ctx->opensc_engine_path;
1858 conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
1859 conf.pkcs11_module_path = ctx->pkcs11_module_path;
1860 conf.wps = ctx->wps;
1862 sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
1863 if (sm->eap == NULL) {
1864 os_free(sm);
1865 return NULL;
1868 /* Initialize EAPOL state machines */
1869 sm->initialize = TRUE;
1870 eapol_sm_step(sm);
1871 sm->initialize = FALSE;
1872 eapol_sm_step(sm);
1874 sm->timer_tick_enabled = 1;
1875 eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
1877 return sm;
1882 * eapol_sm_deinit - Deinitialize EAPOL state machine
1883 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1885 * Deinitialize and free EAPOL state machine.
1887 void eapol_sm_deinit(struct eapol_sm *sm)
1889 if (sm == NULL)
1890 return;
1891 eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
1892 eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
1893 eap_peer_sm_deinit(sm->eap);
1894 os_free(sm->last_rx_key);
1895 wpabuf_free(sm->eapReqData);
1896 os_free(sm->ctx);
1897 os_free(sm);