Re-enable hardware UDP/TCP checksum calculation with pseudo header on
[dragonfly/port-amd64.git] / contrib / wpa_supplicant-0.4.9 / eapol_sm.c
blob7bb88cbab5593901ca3f0cd9bda2cde5544ffa62
1 /*
2 * WPA Supplicant / EAPOL state machines
3 * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
19 #include "common.h"
20 #include "eapol_sm.h"
21 #include "eap.h"
22 #include "eloop.h"
23 #include "l2_packet.h"
24 #include "wpa.h"
25 #include "md5.h"
26 #include "rc4.h"
29 /* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
31 /**
32 * struct eapol_sm - Internal data for EAPOL state machines
34 struct eapol_sm {
35 /* Timers */
36 unsigned int authWhile;
37 unsigned int heldWhile;
38 unsigned int startWhen;
39 unsigned int idleWhile; /* for EAP state machine */
41 /* Global variables */
42 Boolean eapFail;
43 Boolean eapolEap;
44 Boolean eapSuccess;
45 Boolean initialize;
46 Boolean keyDone;
47 Boolean keyRun;
48 PortControl portControl;
49 Boolean portEnabled;
50 PortStatus suppPortStatus; /* dot1xSuppControlledPortStatus */
51 Boolean portValid;
52 Boolean suppAbort;
53 Boolean suppFail;
54 Boolean suppStart;
55 Boolean suppSuccess;
56 Boolean suppTimeout;
58 /* Supplicant PAE state machine */
59 enum {
60 SUPP_PAE_UNKNOWN = 0,
61 SUPP_PAE_DISCONNECTED = 1,
62 SUPP_PAE_LOGOFF = 2,
63 SUPP_PAE_CONNECTING = 3,
64 SUPP_PAE_AUTHENTICATING = 4,
65 SUPP_PAE_AUTHENTICATED = 5,
66 /* unused(6) */
67 SUPP_PAE_HELD = 7,
68 SUPP_PAE_RESTART = 8,
69 SUPP_PAE_S_FORCE_AUTH = 9,
70 SUPP_PAE_S_FORCE_UNAUTH = 10
71 } SUPP_PAE_state; /* dot1xSuppPaeState */
72 /* Variables */
73 Boolean userLogoff;
74 Boolean logoffSent;
75 unsigned int startCount;
76 Boolean eapRestart;
77 PortControl sPortMode;
78 /* Constants */
79 unsigned int heldPeriod; /* dot1xSuppHeldPeriod */
80 unsigned int startPeriod; /* dot1xSuppStartPeriod */
81 unsigned int maxStart; /* dot1xSuppMaxStart */
83 /* Key Receive state machine */
84 enum {
85 KEY_RX_UNKNOWN = 0,
86 KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
87 } KEY_RX_state;
88 /* Variables */
89 Boolean rxKey;
91 /* Supplicant Backend state machine */
92 enum {
93 SUPP_BE_UNKNOWN = 0,
94 SUPP_BE_INITIALIZE = 1,
95 SUPP_BE_IDLE = 2,
96 SUPP_BE_REQUEST = 3,
97 SUPP_BE_RECEIVE = 4,
98 SUPP_BE_RESPONSE = 5,
99 SUPP_BE_FAIL = 6,
100 SUPP_BE_TIMEOUT = 7,
101 SUPP_BE_SUCCESS = 8
102 } SUPP_BE_state; /* dot1xSuppBackendPaeState */
103 /* Variables */
104 Boolean eapNoResp;
105 Boolean eapReq;
106 Boolean eapResp;
107 /* Constants */
108 unsigned int authPeriod; /* dot1xSuppAuthPeriod */
110 /* Statistics */
111 unsigned int dot1xSuppEapolFramesRx;
112 unsigned int dot1xSuppEapolFramesTx;
113 unsigned int dot1xSuppEapolStartFramesTx;
114 unsigned int dot1xSuppEapolLogoffFramesTx;
115 unsigned int dot1xSuppEapolRespFramesTx;
116 unsigned int dot1xSuppEapolReqIdFramesRx;
117 unsigned int dot1xSuppEapolReqFramesRx;
118 unsigned int dot1xSuppInvalidEapolFramesRx;
119 unsigned int dot1xSuppEapLengthErrorFramesRx;
120 unsigned int dot1xSuppLastEapolFrameVersion;
121 unsigned char dot1xSuppLastEapolFrameSource[6];
123 /* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
124 Boolean changed;
125 struct eap_sm *eap;
126 struct wpa_ssid *config;
127 Boolean initial_req;
128 u8 *last_rx_key;
129 size_t last_rx_key_len;
130 u8 *eapReqData; /* for EAP */
131 size_t eapReqDataLen; /* for EAP */
132 Boolean altAccept; /* for EAP */
133 Boolean altReject; /* for EAP */
134 Boolean replay_counter_valid;
135 u8 last_replay_counter[16];
136 struct eapol_config conf;
137 struct eapol_ctx *ctx;
138 enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE }
139 cb_status;
140 Boolean cached_pmk;
142 Boolean unicast_key_received, broadcast_key_received;
146 #define IEEE8021X_REPLAY_COUNTER_LEN 8
147 #define IEEE8021X_KEY_SIGN_LEN 16
148 #define IEEE8021X_KEY_IV_LEN 16
150 #define IEEE8021X_KEY_INDEX_FLAG 0x80
151 #define IEEE8021X_KEY_INDEX_MASK 0x03
153 struct ieee802_1x_eapol_key {
154 u8 type;
155 /* Note: key_length is unaligned */
156 u8 key_length[2];
157 /* does not repeat within the life of the keying material used to
158 * encrypt the Key field; 64-bit NTP timestamp MAY be used here */
159 u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN];
160 u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */
161 u8 key_index; /* key flag in the most significant bit:
162 * 0 = broadcast (default key),
163 * 1 = unicast (key mapping key); key index is in the
164 * 7 least significant bits */
165 /* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as
166 * the key */
167 u8 key_signature[IEEE8021X_KEY_SIGN_LEN];
169 /* followed by key: if packet body length = 44 + key length, then the
170 * key field (of key_length bytes) contains the key in encrypted form;
171 * if packet body length = 44, key field is absent and key_length
172 * represents the number of least significant octets from
173 * MS-MPPE-Send-Key attribute to be used as the keying material;
174 * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
175 } __attribute__ ((packed));
178 static void eapol_sm_txLogoff(struct eapol_sm *sm);
179 static void eapol_sm_txStart(struct eapol_sm *sm);
180 static void eapol_sm_processKey(struct eapol_sm *sm);
181 static void eapol_sm_getSuppRsp(struct eapol_sm *sm);
182 static void eapol_sm_txSuppRsp(struct eapol_sm *sm);
183 static void eapol_sm_abortSupp(struct eapol_sm *sm);
184 static void eapol_sm_abort_cached(struct eapol_sm *sm);
185 static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx);
188 /* Definitions for clarifying state machine implementation */
189 #define SM_STATE(machine, state) \
190 static void sm_ ## machine ## _ ## state ## _Enter(struct eapol_sm *sm, \
191 int global)
193 #define SM_ENTRY(machine, state) \
194 if (!global || sm->machine ## _state != machine ## _ ## state) { \
195 sm->changed = TRUE; \
196 wpa_printf(MSG_DEBUG, "EAPOL: " #machine " entering state " #state); \
198 sm->machine ## _state = machine ## _ ## state;
200 #define SM_ENTER(machine, state) \
201 sm_ ## machine ## _ ## state ## _Enter(sm, 0)
202 #define SM_ENTER_GLOBAL(machine, state) \
203 sm_ ## machine ## _ ## state ## _Enter(sm, 1)
205 #define SM_STEP(machine) \
206 static void sm_ ## machine ## _Step(struct eapol_sm *sm)
208 #define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
211 /* Port Timers state machine - implemented as a function that will be called
212 * once a second as a registered event loop timeout */
213 static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
215 struct eapol_sm *sm = timeout_ctx;
217 if (sm->authWhile > 0) {
218 sm->authWhile--;
219 if (sm->authWhile == 0)
220 wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0");
222 if (sm->heldWhile > 0) {
223 sm->heldWhile--;
224 if (sm->heldWhile == 0)
225 wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0");
227 if (sm->startWhen > 0) {
228 sm->startWhen--;
229 if (sm->startWhen == 0)
230 wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0");
232 if (sm->idleWhile > 0) {
233 sm->idleWhile--;
234 if (sm->idleWhile == 0)
235 wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0");
238 eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, sm);
239 eapol_sm_step(sm);
243 SM_STATE(SUPP_PAE, LOGOFF)
245 SM_ENTRY(SUPP_PAE, LOGOFF);
246 eapol_sm_txLogoff(sm);
247 sm->logoffSent = TRUE;
248 sm->suppPortStatus = Unauthorized;
252 SM_STATE(SUPP_PAE, DISCONNECTED)
254 SM_ENTRY(SUPP_PAE, DISCONNECTED);
255 sm->sPortMode = Auto;
256 sm->startCount = 0;
257 sm->logoffSent = FALSE;
258 sm->suppPortStatus = Unauthorized;
259 sm->suppAbort = TRUE;
261 sm->unicast_key_received = FALSE;
262 sm->broadcast_key_received = FALSE;
266 SM_STATE(SUPP_PAE, CONNECTING)
268 int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING;
269 SM_ENTRY(SUPP_PAE, CONNECTING);
270 if (send_start) {
271 sm->startWhen = sm->startPeriod;
272 sm->startCount++;
273 } else {
275 * Do not send EAPOL-Start immediately since in most cases,
276 * Authenticator is going to start authentication immediately
277 * after association and an extra EAPOL-Start is just going to
278 * delay authentication. Use a short timeout to send the first
279 * EAPOL-Start if Authenticator does not start authentication.
281 sm->startWhen = 3;
283 sm->eapolEap = FALSE;
284 if (send_start)
285 eapol_sm_txStart(sm);
289 SM_STATE(SUPP_PAE, AUTHENTICATING)
291 SM_ENTRY(SUPP_PAE, AUTHENTICATING);
292 sm->startCount = 0;
293 sm->suppSuccess = FALSE;
294 sm->suppFail = FALSE;
295 sm->suppTimeout = FALSE;
296 sm->keyRun = FALSE;
297 sm->keyDone = FALSE;
298 sm->suppStart = TRUE;
302 SM_STATE(SUPP_PAE, HELD)
304 SM_ENTRY(SUPP_PAE, HELD);
305 sm->heldWhile = sm->heldPeriod;
306 sm->suppPortStatus = Unauthorized;
307 sm->cb_status = EAPOL_CB_FAILURE;
311 SM_STATE(SUPP_PAE, AUTHENTICATED)
313 SM_ENTRY(SUPP_PAE, AUTHENTICATED);
314 sm->suppPortStatus = Authorized;
315 sm->cb_status = EAPOL_CB_SUCCESS;
319 SM_STATE(SUPP_PAE, RESTART)
321 SM_ENTRY(SUPP_PAE, RESTART);
322 sm->eapRestart = TRUE;
326 SM_STATE(SUPP_PAE, S_FORCE_AUTH)
328 SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
329 sm->suppPortStatus = Authorized;
330 sm->sPortMode = ForceAuthorized;
334 SM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
336 SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
337 sm->suppPortStatus = Unauthorized;
338 sm->sPortMode = ForceUnauthorized;
339 eapol_sm_txLogoff(sm);
343 SM_STEP(SUPP_PAE)
345 if ((sm->userLogoff && !sm->logoffSent) &&
346 !(sm->initialize || !sm->portEnabled))
347 SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF);
348 else if (((sm->portControl == Auto) &&
349 (sm->sPortMode != sm->portControl)) ||
350 sm->initialize || !sm->portEnabled)
351 SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED);
352 else if ((sm->portControl == ForceAuthorized) &&
353 (sm->sPortMode != sm->portControl) &&
354 !(sm->initialize || !sm->portEnabled))
355 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH);
356 else if ((sm->portControl == ForceUnauthorized) &&
357 (sm->sPortMode != sm->portControl) &&
358 !(sm->initialize || !sm->portEnabled))
359 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH);
360 else switch (sm->SUPP_PAE_state) {
361 case SUPP_PAE_UNKNOWN:
362 break;
363 case SUPP_PAE_LOGOFF:
364 if (!sm->userLogoff)
365 SM_ENTER(SUPP_PAE, DISCONNECTED);
366 break;
367 case SUPP_PAE_DISCONNECTED:
368 SM_ENTER(SUPP_PAE, CONNECTING);
369 break;
370 case SUPP_PAE_CONNECTING:
371 if (sm->startWhen == 0 && sm->startCount < sm->maxStart)
372 SM_ENTER(SUPP_PAE, CONNECTING);
373 else if (sm->startWhen == 0 &&
374 sm->startCount >= sm->maxStart &&
375 sm->portValid)
376 SM_ENTER(SUPP_PAE, AUTHENTICATED);
377 else if (sm->eapSuccess || sm->eapFail)
378 SM_ENTER(SUPP_PAE, AUTHENTICATING);
379 else if (sm->eapolEap)
380 SM_ENTER(SUPP_PAE, RESTART);
381 else if (sm->startWhen == 0 &&
382 sm->startCount >= sm->maxStart &&
383 !sm->portValid)
384 SM_ENTER(SUPP_PAE, HELD);
385 break;
386 case SUPP_PAE_AUTHENTICATING:
387 if (sm->eapSuccess && !sm->portValid &&
388 sm->conf.accept_802_1x_keys &&
389 sm->conf.required_keys == 0) {
390 wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for "
391 "plaintext connection; no EAPOL-Key frames "
392 "required");
393 sm->portValid = TRUE;
394 if (sm->ctx->eapol_done_cb)
395 sm->ctx->eapol_done_cb(sm->ctx->ctx);
397 if (sm->eapSuccess && sm->portValid)
398 SM_ENTER(SUPP_PAE, AUTHENTICATED);
399 else if (sm->eapFail || (sm->keyDone && !sm->portValid))
400 SM_ENTER(SUPP_PAE, HELD);
401 else if (sm->suppTimeout)
402 SM_ENTER(SUPP_PAE, CONNECTING);
403 break;
404 case SUPP_PAE_HELD:
405 if (sm->heldWhile == 0)
406 SM_ENTER(SUPP_PAE, CONNECTING);
407 else if (sm->eapolEap)
408 SM_ENTER(SUPP_PAE, RESTART);
409 break;
410 case SUPP_PAE_AUTHENTICATED:
411 if (sm->eapolEap && sm->portValid)
412 SM_ENTER(SUPP_PAE, RESTART);
413 else if (!sm->portValid)
414 SM_ENTER(SUPP_PAE, DISCONNECTED);
415 break;
416 case SUPP_PAE_RESTART:
417 if (!sm->eapRestart)
418 SM_ENTER(SUPP_PAE, AUTHENTICATING);
419 break;
420 case SUPP_PAE_S_FORCE_AUTH:
421 break;
422 case SUPP_PAE_S_FORCE_UNAUTH:
423 break;
428 SM_STATE(KEY_RX, NO_KEY_RECEIVE)
430 SM_ENTRY(KEY_RX, NO_KEY_RECEIVE);
434 SM_STATE(KEY_RX, KEY_RECEIVE)
436 SM_ENTRY(KEY_RX, KEY_RECEIVE);
437 eapol_sm_processKey(sm);
438 sm->rxKey = FALSE;
442 SM_STEP(KEY_RX)
444 if (sm->initialize || !sm->portEnabled)
445 SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
446 switch (sm->KEY_RX_state) {
447 case KEY_RX_UNKNOWN:
448 break;
449 case KEY_RX_NO_KEY_RECEIVE:
450 if (sm->rxKey)
451 SM_ENTER(KEY_RX, KEY_RECEIVE);
452 break;
453 case KEY_RX_KEY_RECEIVE:
454 if (sm->rxKey)
455 SM_ENTER(KEY_RX, KEY_RECEIVE);
456 break;
461 SM_STATE(SUPP_BE, REQUEST)
463 SM_ENTRY(SUPP_BE, REQUEST);
464 sm->authWhile = 0;
465 sm->eapReq = TRUE;
466 eapol_sm_getSuppRsp(sm);
470 SM_STATE(SUPP_BE, RESPONSE)
472 SM_ENTRY(SUPP_BE, RESPONSE);
473 eapol_sm_txSuppRsp(sm);
474 sm->eapResp = FALSE;
478 SM_STATE(SUPP_BE, SUCCESS)
480 SM_ENTRY(SUPP_BE, SUCCESS);
481 sm->keyRun = TRUE;
482 sm->suppSuccess = TRUE;
484 if (eap_key_available(sm->eap)) {
485 /* New key received - clear IEEE 802.1X EAPOL-Key replay
486 * counter */
487 sm->replay_counter_valid = FALSE;
492 SM_STATE(SUPP_BE, FAIL)
494 SM_ENTRY(SUPP_BE, FAIL);
495 sm->suppFail = TRUE;
499 SM_STATE(SUPP_BE, TIMEOUT)
501 SM_ENTRY(SUPP_BE, TIMEOUT);
502 sm->suppTimeout = TRUE;
506 SM_STATE(SUPP_BE, IDLE)
508 SM_ENTRY(SUPP_BE, IDLE);
509 sm->suppStart = FALSE;
510 sm->initial_req = TRUE;
514 SM_STATE(SUPP_BE, INITIALIZE)
516 SM_ENTRY(SUPP_BE, INITIALIZE);
517 eapol_sm_abortSupp(sm);
518 sm->suppAbort = FALSE;
522 SM_STATE(SUPP_BE, RECEIVE)
524 SM_ENTRY(SUPP_BE, RECEIVE);
525 sm->authWhile = sm->authPeriod;
526 sm->eapolEap = FALSE;
527 sm->eapNoResp = FALSE;
528 sm->initial_req = FALSE;
532 SM_STEP(SUPP_BE)
534 if (sm->initialize || sm->suppAbort)
535 SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE);
536 else switch (sm->SUPP_BE_state) {
537 case SUPP_BE_UNKNOWN:
538 break;
539 case SUPP_BE_REQUEST:
540 if (sm->eapResp && sm->eapNoResp) {
541 wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both "
542 "eapResp and eapNoResp set?!");
544 if (sm->eapResp)
545 SM_ENTER(SUPP_BE, RESPONSE);
546 else if (sm->eapNoResp)
547 SM_ENTER(SUPP_BE, RECEIVE);
548 break;
549 case SUPP_BE_RESPONSE:
550 SM_ENTER(SUPP_BE, RECEIVE);
551 break;
552 case SUPP_BE_SUCCESS:
553 SM_ENTER(SUPP_BE, IDLE);
554 break;
555 case SUPP_BE_FAIL:
556 SM_ENTER(SUPP_BE, IDLE);
557 break;
558 case SUPP_BE_TIMEOUT:
559 SM_ENTER(SUPP_BE, IDLE);
560 break;
561 case SUPP_BE_IDLE:
562 if (sm->eapFail && sm->suppStart)
563 SM_ENTER(SUPP_BE, FAIL);
564 else if (sm->eapolEap && sm->suppStart)
565 SM_ENTER(SUPP_BE, REQUEST);
566 else if (sm->eapSuccess && sm->suppStart)
567 SM_ENTER(SUPP_BE, SUCCESS);
568 break;
569 case SUPP_BE_INITIALIZE:
570 SM_ENTER(SUPP_BE, IDLE);
571 break;
572 case SUPP_BE_RECEIVE:
573 if (sm->eapolEap)
574 SM_ENTER(SUPP_BE, REQUEST);
575 else if (sm->eapFail)
576 SM_ENTER(SUPP_BE, FAIL);
577 else if (sm->authWhile == 0)
578 SM_ENTER(SUPP_BE, TIMEOUT);
579 else if (sm->eapSuccess)
580 SM_ENTER(SUPP_BE, SUCCESS);
581 break;
586 static void eapol_sm_txLogoff(struct eapol_sm *sm)
588 wpa_printf(MSG_DEBUG, "EAPOL: txLogoff");
589 sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
590 IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0);
591 sm->dot1xSuppEapolLogoffFramesTx++;
592 sm->dot1xSuppEapolFramesTx++;
596 static void eapol_sm_txStart(struct eapol_sm *sm)
598 wpa_printf(MSG_DEBUG, "EAPOL: txStart");
599 sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
600 IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0);
601 sm->dot1xSuppEapolStartFramesTx++;
602 sm->dot1xSuppEapolFramesTx++;
606 #define IEEE8021X_ENCR_KEY_LEN 32
607 #define IEEE8021X_SIGN_KEY_LEN 32
609 struct eap_key_data {
610 u8 encr_key[IEEE8021X_ENCR_KEY_LEN];
611 u8 sign_key[IEEE8021X_SIGN_KEY_LEN];
615 static void eapol_sm_processKey(struct eapol_sm *sm)
617 struct ieee802_1x_hdr *hdr;
618 struct ieee802_1x_eapol_key *key;
619 struct eap_key_data keydata;
620 u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
621 u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
622 int key_len, res, sign_key_len, encr_key_len;
623 u16 rx_key_length;
625 wpa_printf(MSG_DEBUG, "EAPOL: processKey");
626 if (sm->last_rx_key == NULL)
627 return;
629 if (!sm->conf.accept_802_1x_keys) {
630 wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key"
631 " even though this was not accepted - "
632 "ignoring this packet");
633 return;
636 hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
637 key = (struct ieee802_1x_eapol_key *) (hdr + 1);
638 if (sizeof(*hdr) + be_to_host16(hdr->length) > sm->last_rx_key_len) {
639 wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
640 return;
642 rx_key_length = WPA_GET_BE16(key->key_length);
643 wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
644 "EAPOL-Key: type=%d key_length=%d key_index=0x%x",
645 hdr->version, hdr->type, be_to_host16(hdr->length),
646 key->type, rx_key_length, key->key_index);
648 eapol_sm_notify_lower_layer_success(sm);
649 sign_key_len = IEEE8021X_SIGN_KEY_LEN;
650 encr_key_len = IEEE8021X_ENCR_KEY_LEN;
651 res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata));
652 if (res < 0) {
653 wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for "
654 "decrypting EAPOL-Key keys");
655 return;
657 if (res == 16) {
658 /* LEAP derives only 16 bytes of keying material. */
659 res = eapol_sm_get_key(sm, (u8 *) &keydata, 16);
660 if (res) {
661 wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP "
662 "master key for decrypting EAPOL-Key keys");
663 return;
665 sign_key_len = 16;
666 encr_key_len = 16;
667 memcpy(keydata.sign_key, keydata.encr_key, 16);
668 } else if (res) {
669 wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key "
670 "data for decrypting EAPOL-Key keys (res=%d)", res);
671 return;
674 /* The key replay_counter must increase when same master key */
675 if (sm->replay_counter_valid &&
676 memcmp(sm->last_replay_counter, key->replay_counter,
677 IEEE8021X_REPLAY_COUNTER_LEN) >= 0) {
678 wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did "
679 "not increase - ignoring key");
680 wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter",
681 sm->last_replay_counter,
682 IEEE8021X_REPLAY_COUNTER_LEN);
683 wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter",
684 key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN);
685 return;
688 /* Verify key signature (HMAC-MD5) */
689 memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN);
690 memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN);
691 hmac_md5(keydata.sign_key, sign_key_len,
692 sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
693 key->key_signature);
694 if (memcmp(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN)
695 != 0) {
696 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
697 "EAPOL-Key packet");
698 memcpy(key->key_signature, orig_key_sign,
699 IEEE8021X_KEY_SIGN_LEN);
700 return;
702 wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
704 key_len = be_to_host16(hdr->length) - sizeof(*key);
705 if (key_len > 32 || rx_key_length > 32) {
706 wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
707 key_len ? key_len : rx_key_length);
708 return;
710 if (key_len == rx_key_length) {
711 memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
712 memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
713 encr_key_len);
714 memcpy(datakey, key + 1, key_len);
715 rc4(datakey, key_len, ekey,
716 IEEE8021X_KEY_IV_LEN + encr_key_len);
717 wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
718 datakey, key_len);
719 } else if (key_len == 0) {
721 * IEEE 802.1X-2004 specifies that least significant Key Length
722 * octets from MS-MPPE-Send-Key are used as the key if the key
723 * data is not present. This seems to be meaning the beginning
724 * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
725 * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
726 * Anyway, taking the beginning of the keying material from EAP
727 * seems to interoperate with Authenticators.
729 key_len = rx_key_length;
730 memcpy(datakey, keydata.encr_key, key_len);
731 wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying "
732 "material data encryption key",
733 datakey, key_len);
734 } else {
735 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
736 "(key_length=%d)", key_len, rx_key_length);
737 return;
740 sm->replay_counter_valid = TRUE;
741 memcpy(sm->last_replay_counter, key->replay_counter,
742 IEEE8021X_REPLAY_COUNTER_LEN);
744 wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
745 "len %d",
746 key->key_index & IEEE8021X_KEY_INDEX_FLAG ?
747 "unicast" : "broadcast",
748 key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len);
750 if (sm->ctx->set_wep_key &&
751 sm->ctx->set_wep_key(sm->ctx->ctx,
752 key->key_index & IEEE8021X_KEY_INDEX_FLAG,
753 key->key_index & IEEE8021X_KEY_INDEX_MASK,
754 datakey, key_len) < 0) {
755 wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
756 " driver.");
757 } else {
758 if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
759 sm->unicast_key_received = TRUE;
760 else
761 sm->broadcast_key_received = TRUE;
763 if ((sm->unicast_key_received ||
764 !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) &&
765 (sm->broadcast_key_received ||
766 !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST)))
768 wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
769 "frames received");
770 sm->portValid = TRUE;
771 if (sm->ctx->eapol_done_cb)
772 sm->ctx->eapol_done_cb(sm->ctx->ctx);
778 static void eapol_sm_getSuppRsp(struct eapol_sm *sm)
780 wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp");
781 /* EAP layer processing; no special code is needed, since Supplicant
782 * Backend state machine is waiting for eapNoResp or eapResp to be set
783 * and these are only set in the EAP state machine when the processing
784 * has finished. */
788 static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
790 u8 *resp;
791 size_t resp_len;
793 wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
794 resp = eap_get_eapRespData(sm->eap, &resp_len);
795 if (resp == NULL) {
796 wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
797 "not available");
798 return;
801 /* Send EAP-Packet from the EAP layer to the Authenticator */
802 sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
803 IEEE802_1X_TYPE_EAP_PACKET, resp, resp_len);
805 /* eapRespData is not used anymore, so free it here */
806 free(resp);
808 if (sm->initial_req)
809 sm->dot1xSuppEapolReqIdFramesRx++;
810 else
811 sm->dot1xSuppEapolReqFramesRx++;
812 sm->dot1xSuppEapolRespFramesTx++;
813 sm->dot1xSuppEapolFramesTx++;
817 static void eapol_sm_abortSupp(struct eapol_sm *sm)
819 /* release system resources that may have been allocated for the
820 * authentication session */
821 free(sm->last_rx_key);
822 sm->last_rx_key = NULL;
823 free(sm->eapReqData);
824 sm->eapReqData = NULL;
825 eap_sm_abort(sm->eap);
829 static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
831 eapol_sm_step(timeout_ctx);
836 * eapol_sm_step - EAPOL state machine step function
837 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
839 * This function is called to notify the state machine about changed external
840 * variables. It will step through the EAPOL state machines in loop to process
841 * all triggered state changes.
843 void eapol_sm_step(struct eapol_sm *sm)
845 int i;
847 /* In theory, it should be ok to run this in loop until !changed.
848 * However, it is better to use a limit on number of iterations to
849 * allow events (e.g., SIGTERM) to stop the program cleanly if the
850 * state machine were to generate a busy loop. */
851 for (i = 0; i < 100; i++) {
852 sm->changed = FALSE;
853 SM_STEP_RUN(SUPP_PAE);
854 SM_STEP_RUN(KEY_RX);
855 SM_STEP_RUN(SUPP_BE);
856 if (eap_sm_step(sm->eap))
857 sm->changed = TRUE;
860 if (sm->changed) {
861 /* restart EAPOL state machine step from timeout call in order
862 * to allow other events to be processed. */
863 eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
864 eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm);
867 if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
868 int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0;
869 sm->cb_status = EAPOL_CB_IN_PROGRESS;
870 sm->ctx->cb(sm, success, sm->ctx->cb_ctx);
875 static const char *eapol_supp_pae_state(int state)
877 switch (state) {
878 case SUPP_PAE_LOGOFF:
879 return "LOGOFF";
880 case SUPP_PAE_DISCONNECTED:
881 return "DISCONNECTED";
882 case SUPP_PAE_CONNECTING:
883 return "CONNECTING";
884 case SUPP_PAE_AUTHENTICATING:
885 return "AUTHENTICATING";
886 case SUPP_PAE_HELD:
887 return "HELD";
888 case SUPP_PAE_AUTHENTICATED:
889 return "AUTHENTICATED";
890 case SUPP_PAE_RESTART:
891 return "RESTART";
892 default:
893 return "UNKNOWN";
898 static const char *eapol_supp_be_state(int state)
900 switch (state) {
901 case SUPP_BE_REQUEST:
902 return "REQUEST";
903 case SUPP_BE_RESPONSE:
904 return "RESPONSE";
905 case SUPP_BE_SUCCESS:
906 return "SUCCESS";
907 case SUPP_BE_FAIL:
908 return "FAIL";
909 case SUPP_BE_TIMEOUT:
910 return "TIMEOUT";
911 case SUPP_BE_IDLE:
912 return "IDLE";
913 case SUPP_BE_INITIALIZE:
914 return "INITIALIZE";
915 case SUPP_BE_RECEIVE:
916 return "RECEIVE";
917 default:
918 return "UNKNOWN";
923 static const char * eapol_port_status(PortStatus status)
925 if (status == Authorized)
926 return "Authorized";
927 else
928 return "Unauthorized";
932 static const char * eapol_port_control(PortControl ctrl)
934 switch (ctrl) {
935 case Auto:
936 return "Auto";
937 case ForceUnauthorized:
938 return "ForceUnauthorized";
939 case ForceAuthorized:
940 return "ForceAuthorized";
941 default:
942 return "Unknown";
948 * eapol_sm_configure - Set EAPOL variables
949 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
950 * @heldPeriod: dot1xSuppHeldPeriod
951 * @authPeriod: dot1xSuppAuthPeriod
952 * @startPeriod: dot1xSuppStartPeriod
953 * @maxStart: dot1xSuppMaxStart
955 * Set configurable EAPOL state machine variables. Each variable can be set to
956 * the given value or ignored if set to -1 (to set only some of the variables).
958 void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
959 int startPeriod, int maxStart)
961 if (sm == NULL)
962 return;
963 if (heldPeriod >= 0)
964 sm->heldPeriod = heldPeriod;
965 if (authPeriod >= 0)
966 sm->authPeriod = authPeriod;
967 if (startPeriod >= 0)
968 sm->startPeriod = startPeriod;
969 if (maxStart >= 0)
970 sm->maxStart = maxStart;
975 * eapol_sm_get_status - Get EAPOL state machine status
976 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
977 * @buf: Buffer for status information
978 * @buflen: Maximum buffer length
979 * @verbose: Whether to include verbose status information
980 * Returns: Number of bytes written to buf.
982 * Query EAPOL state machine for status information. This function fills in a
983 * text area with current status information from the EAPOL state machine. If
984 * the buffer (buf) is not large enough, status information will be truncated
985 * to fit the buffer.
987 int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
988 int verbose)
990 int len;
991 if (sm == NULL)
992 return 0;
994 len = snprintf(buf, buflen,
995 "Supplicant PAE state=%s\n"
996 "suppPortStatus=%s\n",
997 eapol_supp_pae_state(sm->SUPP_PAE_state),
998 eapol_port_status(sm->suppPortStatus));
1000 if (verbose) {
1001 len += snprintf(buf + len, buflen - len,
1002 "heldPeriod=%u\n"
1003 "authPeriod=%u\n"
1004 "startPeriod=%u\n"
1005 "maxStart=%u\n"
1006 "portControl=%s\n"
1007 "Supplicant Backend state=%s\n",
1008 sm->heldPeriod,
1009 sm->authPeriod,
1010 sm->startPeriod,
1011 sm->maxStart,
1012 eapol_port_control(sm->portControl),
1013 eapol_supp_be_state(sm->SUPP_BE_state));
1016 len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
1018 return len;
1023 * eapol_sm_get_mib - Get EAPOL state machine MIBs
1024 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1025 * @buf: Buffer for MIB information
1026 * @buflen: Maximum buffer length
1027 * Returns: Number of bytes written to buf.
1029 * Query EAPOL state machine for MIB information. This function fills in a
1030 * text area with current MIB information from the EAPOL state machine. If
1031 * the buffer (buf) is not large enough, MIB information will be truncated to
1032 * fit the buffer.
1034 int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
1036 int len;
1037 if (sm == NULL)
1038 return 0;
1039 len = snprintf(buf, buflen,
1040 "dot1xSuppPaeState=%d\n"
1041 "dot1xSuppHeldPeriod=%u\n"
1042 "dot1xSuppAuthPeriod=%u\n"
1043 "dot1xSuppStartPeriod=%u\n"
1044 "dot1xSuppMaxStart=%u\n"
1045 "dot1xSuppSuppControlledPortStatus=%s\n"
1046 "dot1xSuppBackendPaeState=%d\n"
1047 "dot1xSuppEapolFramesRx=%u\n"
1048 "dot1xSuppEapolFramesTx=%u\n"
1049 "dot1xSuppEapolStartFramesTx=%u\n"
1050 "dot1xSuppEapolLogoffFramesTx=%u\n"
1051 "dot1xSuppEapolRespFramesTx=%u\n"
1052 "dot1xSuppEapolReqIdFramesRx=%u\n"
1053 "dot1xSuppEapolReqFramesRx=%u\n"
1054 "dot1xSuppInvalidEapolFramesRx=%u\n"
1055 "dot1xSuppEapLengthErrorFramesRx=%u\n"
1056 "dot1xSuppLastEapolFrameVersion=%u\n"
1057 "dot1xSuppLastEapolFrameSource=" MACSTR "\n",
1058 sm->SUPP_PAE_state,
1059 sm->heldPeriod,
1060 sm->authPeriod,
1061 sm->startPeriod,
1062 sm->maxStart,
1063 sm->suppPortStatus == Authorized ?
1064 "Authorized" : "Unauthorized",
1065 sm->SUPP_BE_state,
1066 sm->dot1xSuppEapolFramesRx,
1067 sm->dot1xSuppEapolFramesTx,
1068 sm->dot1xSuppEapolStartFramesTx,
1069 sm->dot1xSuppEapolLogoffFramesTx,
1070 sm->dot1xSuppEapolRespFramesTx,
1071 sm->dot1xSuppEapolReqIdFramesRx,
1072 sm->dot1xSuppEapolReqFramesRx,
1073 sm->dot1xSuppInvalidEapolFramesRx,
1074 sm->dot1xSuppEapLengthErrorFramesRx,
1075 sm->dot1xSuppLastEapolFrameVersion,
1076 MAC2STR(sm->dot1xSuppLastEapolFrameSource));
1077 return len;
1082 * eapol_sm_rx_eapol - Process received EAPOL frames
1083 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1084 * @src: Source MAC address of the EAPOL packet
1085 * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
1086 * @len: Length of the EAPOL frame
1087 * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
1088 * -1 failure
1090 int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
1091 size_t len)
1093 const struct ieee802_1x_hdr *hdr;
1094 const struct ieee802_1x_eapol_key *key;
1095 int plen, data_len;
1096 int res = 1;
1098 if (sm == NULL)
1099 return 0;
1100 sm->dot1xSuppEapolFramesRx++;
1101 if (len < sizeof(*hdr)) {
1102 sm->dot1xSuppInvalidEapolFramesRx++;
1103 return 0;
1105 hdr = (const struct ieee802_1x_hdr *) buf;
1106 sm->dot1xSuppLastEapolFrameVersion = hdr->version;
1107 memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
1108 if (hdr->version < EAPOL_VERSION) {
1109 /* TODO: backwards compatibility */
1111 plen = be_to_host16(hdr->length);
1112 if (plen > len - sizeof(*hdr)) {
1113 sm->dot1xSuppEapLengthErrorFramesRx++;
1114 return 0;
1116 data_len = plen + sizeof(*hdr);
1118 switch (hdr->type) {
1119 case IEEE802_1X_TYPE_EAP_PACKET:
1120 if (sm->cached_pmk) {
1121 /* Trying to use PMKSA caching, but Authenticator did
1122 * not seem to have a matching entry. Need to restart
1123 * EAPOL state machines.
1125 eapol_sm_abort_cached(sm);
1127 free(sm->eapReqData);
1128 sm->eapReqDataLen = plen;
1129 sm->eapReqData = malloc(sm->eapReqDataLen);
1130 if (sm->eapReqData) {
1131 wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
1132 "frame");
1133 memcpy(sm->eapReqData, (u8 *) (hdr + 1),
1134 sm->eapReqDataLen);
1135 sm->eapolEap = TRUE;
1136 eapol_sm_step(sm);
1138 break;
1139 case IEEE802_1X_TYPE_EAPOL_KEY:
1140 if (plen < sizeof(*key)) {
1141 wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key "
1142 "frame received");
1143 break;
1145 key = (const struct ieee802_1x_eapol_key *) (hdr + 1);
1146 if (key->type == EAPOL_KEY_TYPE_WPA ||
1147 key->type == EAPOL_KEY_TYPE_RSN) {
1148 /* WPA Supplicant takes care of this frame. */
1149 wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
1150 "frame in EAPOL state machines");
1151 res = 0;
1152 break;
1154 if (key->type != EAPOL_KEY_TYPE_RC4) {
1155 wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown "
1156 "EAPOL-Key type %d", key->type);
1157 break;
1159 free(sm->last_rx_key);
1160 sm->last_rx_key = malloc(data_len);
1161 if (sm->last_rx_key) {
1162 wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key "
1163 "frame");
1164 memcpy(sm->last_rx_key, buf, data_len);
1165 sm->last_rx_key_len = data_len;
1166 sm->rxKey = TRUE;
1167 eapol_sm_step(sm);
1169 break;
1170 default:
1171 wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
1172 hdr->type);
1173 sm->dot1xSuppInvalidEapolFramesRx++;
1174 break;
1177 return res;
1182 * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet
1183 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1185 * Notify EAPOL station machine about transmitted EAPOL packet from an external
1186 * component, e.g., WPA. This will update the statistics.
1188 void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
1190 if (sm)
1191 sm->dot1xSuppEapolFramesTx++;
1196 * eapol_sm_notify_portEnabled - Notification about portEnabled change
1197 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1198 * @enabled: New portEnabled value
1200 * Notify EAPOL station machine about new portEnabled value.
1202 void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
1204 if (sm == NULL)
1205 return;
1206 wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1207 "portEnabled=%d", enabled);
1208 sm->portEnabled = enabled;
1209 eapol_sm_step(sm);
1214 * eapol_sm_notify_portValid - Notification about portValid change
1215 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1216 * @valid: New portValid value
1218 * Notify EAPOL station machine about new portValid value.
1220 void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
1222 if (sm == NULL)
1223 return;
1224 wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1225 "portValid=%d", valid);
1226 sm->portValid = valid;
1227 eapol_sm_step(sm);
1232 * eapol_sm_notify_eap_success - Notification of external EAP success trigger
1233 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1234 * @success: %TRUE = set success, %FALSE = clear success
1236 * Notify EAPOL station machine that external event has forced EAP state to
1237 * success (success = %TRUE). This can be cleared by setting success = %FALSE.
1239 * This function is called to update EAP state when WPA-PSK key handshake has
1240 * been completed successfully since WPA-PSK does not use EAP state machine.
1242 void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
1244 if (sm == NULL)
1245 return;
1246 wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1247 "EAP success=%d", success);
1248 sm->eapSuccess = success;
1249 sm->altAccept = success;
1250 if (success)
1251 eap_notify_success(sm->eap);
1252 eapol_sm_step(sm);
1257 * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
1258 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1259 * @fail: %TRUE = set failure, %FALSE = clear failure
1261 * Notify EAPOL station machine that external event has forced EAP state to
1262 * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE.
1264 void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
1266 if (sm == NULL)
1267 return;
1268 wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1269 "EAP fail=%d", fail);
1270 sm->eapFail = fail;
1271 sm->altReject = fail;
1272 eapol_sm_step(sm);
1277 * eapol_sm_notify_config - Notification of EAPOL configuration change
1278 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1279 * @config: Pointer to current network configuration
1280 * @conf: Pointer to EAPOL configuration data
1282 * Notify EAPOL station machine that configuration has changed. config will be
1283 * stored as a backpointer to network configuration. This can be %NULL to clear
1284 * the stored pointed. conf will be copied to local EAPOL/EAP configuration
1285 * data. If conf is %NULL, this part of the configuration change will be
1286 * skipped.
1288 void eapol_sm_notify_config(struct eapol_sm *sm, struct wpa_ssid *config,
1289 const struct eapol_config *conf)
1291 if (sm == NULL)
1292 return;
1294 sm->config = config;
1296 if (conf == NULL)
1297 return;
1299 sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys;
1300 sm->conf.required_keys = conf->required_keys;
1301 sm->conf.fast_reauth = conf->fast_reauth;
1302 if (sm->eap) {
1303 eap_set_fast_reauth(sm->eap, conf->fast_reauth);
1304 eap_set_workaround(sm->eap, conf->workaround);
1305 eap_set_force_disabled(sm->eap, conf->eap_disabled);
1311 * eapol_sm_get_key - Get master session key (MSK) from EAP
1312 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1313 * @key: Pointer for key buffer
1314 * @len: Number of bytes to copy to key
1315 * Returns: 0 on success (len of key available), maximum available key len
1316 * (>0) if key is available but it is shorter than len, or -1 on failure.
1318 * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key
1319 * is available only after a successful authentication.
1321 int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
1323 const u8 *eap_key;
1324 size_t eap_len;
1326 if (sm == NULL || !eap_key_available(sm->eap))
1327 return -1;
1328 eap_key = eap_get_eapKeyData(sm->eap, &eap_len);
1329 if (eap_key == NULL)
1330 return -1;
1331 if (len > eap_len)
1332 return eap_len;
1333 memcpy(key, eap_key, len);
1334 return 0;
1339 * eapol_sm_notify_logoff - Notification of logon/logoff commands
1340 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1341 * @logoff: Whether command was logoff
1343 * Notify EAPOL state machines that user requested logon/logoff.
1345 void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
1347 if (sm) {
1348 sm->userLogoff = logoff;
1349 eapol_sm_step(sm);
1355 * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching
1356 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1358 * Notify EAPOL state machines that PMKSA caching was successful. This is used
1359 * to move EAPOL and EAP state machines into authenticated/successful state.
1361 void eapol_sm_notify_cached(struct eapol_sm *sm)
1363 if (sm == NULL)
1364 return;
1365 sm->SUPP_PAE_state = SUPP_PAE_AUTHENTICATED;
1366 sm->suppPortStatus = Authorized;
1367 eap_notify_success(sm->eap);
1372 * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
1373 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1374 * @attempt: Whether PMKSA caching is tried
1376 * Notify EAPOL state machines whether PMKSA caching is used.
1378 void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt)
1380 if (sm == NULL)
1381 return;
1382 if (attempt) {
1383 wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
1384 sm->cached_pmk = TRUE;
1385 } else {
1386 wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA");
1387 sm->cached_pmk = FALSE;
1392 static void eapol_sm_abort_cached(struct eapol_sm *sm)
1394 wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, "
1395 "doing full EAP authentication");
1396 if (sm == NULL)
1397 return;
1398 sm->cached_pmk = FALSE;
1399 sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
1400 sm->suppPortStatus = Unauthorized;
1402 /* Make sure we do not start sending EAPOL-Start frames first, but
1403 * instead move to RESTART state to start EAPOL authentication. */
1404 sm->startWhen = 3;
1406 if (sm->ctx->aborted_cached)
1407 sm->ctx->aborted_cached(sm->ctx->ctx);
1412 * eapol_sm_register_scard_ctx - Notification of smart card context
1413 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1414 * @ctx: Context data for smart card operations
1416 * Notify EAPOL state machines of context data for smart card operations. This
1417 * context data will be used as a parameter for scard_*() functions.
1419 void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
1421 if (sm) {
1422 sm->ctx->scard_ctx = ctx;
1423 eap_register_scard_ctx(sm->eap, ctx);
1429 * eapol_sm_notify_portControl - Notification of portControl changes
1430 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1431 * @portControl: New value for portControl variable
1433 * Notify EAPOL state machines that portControl variable has changed.
1435 void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
1437 if (sm == NULL)
1438 return;
1439 wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1440 "portControl=%s", eapol_port_control(portControl));
1441 sm->portControl = portControl;
1442 eapol_sm_step(sm);
1447 * eapol_sm_notify_ctrl_attached - Notification of attached monitor
1448 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1450 * Notify EAPOL state machines that a monitor was attached to the control
1451 * interface to trigger re-sending of pending requests for user input.
1453 void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
1455 if (sm == NULL)
1456 return;
1457 eap_sm_notify_ctrl_attached(sm->eap);
1462 * eapol_sm_notify_ctrl_response - Notification of received user input
1463 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1465 * Notify EAPOL state machines that a control response, i.e., user
1466 * input, was received in order to trigger retrying of a pending EAP request.
1468 void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
1470 if (sm == NULL)
1471 return;
1472 if (sm->eapReqData && !sm->eapReq) {
1473 wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
1474 "input) notification - retrying pending EAP "
1475 "Request");
1476 sm->eapolEap = TRUE;
1477 sm->eapReq = TRUE;
1478 eapol_sm_step(sm);
1484 * eapol_sm_request_reauth - Request reauthentication
1485 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1487 * This function can be used to request EAPOL reauthentication, e.g., when the
1488 * current PMKSA entry is nearing expiration.
1490 void eapol_sm_request_reauth(struct eapol_sm *sm)
1492 if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
1493 return;
1494 eapol_sm_txStart(sm);
1499 * eapol_sm_notify_lower_layer_success - Notification of lower layer success
1500 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1502 * Notify EAPOL (and EAP) state machines that a lower layer has detected a
1503 * successful authentication. This is used to recover from dropped EAP-Success
1504 * messages.
1506 void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm)
1508 if (sm == NULL)
1509 return;
1510 eap_notify_lower_layer_success(sm->eap);
1514 static struct wpa_ssid * eapol_sm_get_config(void *ctx)
1516 struct eapol_sm *sm = ctx;
1517 return sm ? sm->config : NULL;
1521 static u8 * eapol_sm_get_eapReqData(void *ctx, size_t *len)
1523 struct eapol_sm *sm = ctx;
1524 if (sm == NULL || sm->eapReqData == NULL) {
1525 *len = 0;
1526 return NULL;
1529 *len = sm->eapReqDataLen;
1530 return sm->eapReqData;
1534 static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
1536 struct eapol_sm *sm = ctx;
1537 if (sm == NULL)
1538 return FALSE;
1539 switch (variable) {
1540 case EAPOL_eapSuccess:
1541 return sm->eapSuccess;
1542 case EAPOL_eapRestart:
1543 return sm->eapRestart;
1544 case EAPOL_eapFail:
1545 return sm->eapFail;
1546 case EAPOL_eapResp:
1547 return sm->eapResp;
1548 case EAPOL_eapNoResp:
1549 return sm->eapNoResp;
1550 case EAPOL_eapReq:
1551 return sm->eapReq;
1552 case EAPOL_portEnabled:
1553 return sm->portEnabled;
1554 case EAPOL_altAccept:
1555 return sm->altAccept;
1556 case EAPOL_altReject:
1557 return sm->altReject;
1559 return FALSE;
1563 static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
1564 Boolean value)
1566 struct eapol_sm *sm = ctx;
1567 if (sm == NULL)
1568 return;
1569 switch (variable) {
1570 case EAPOL_eapSuccess:
1571 sm->eapSuccess = value;
1572 break;
1573 case EAPOL_eapRestart:
1574 sm->eapRestart = value;
1575 break;
1576 case EAPOL_eapFail:
1577 sm->eapFail = value;
1578 break;
1579 case EAPOL_eapResp:
1580 sm->eapResp = value;
1581 break;
1582 case EAPOL_eapNoResp:
1583 sm->eapNoResp = value;
1584 break;
1585 case EAPOL_eapReq:
1586 sm->eapReq = value;
1587 break;
1588 case EAPOL_portEnabled:
1589 sm->portEnabled = value;
1590 break;
1591 case EAPOL_altAccept:
1592 sm->altAccept = value;
1593 break;
1594 case EAPOL_altReject:
1595 sm->altReject = value;
1596 break;
1601 static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable)
1603 struct eapol_sm *sm = ctx;
1604 if (sm == NULL)
1605 return 0;
1606 switch (variable) {
1607 case EAPOL_idleWhile:
1608 return sm->idleWhile;
1610 return 0;
1614 static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
1615 unsigned int value)
1617 struct eapol_sm *sm = ctx;
1618 if (sm == NULL)
1619 return;
1620 switch (variable) {
1621 case EAPOL_idleWhile:
1622 sm->idleWhile = value;
1623 break;
1628 static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
1630 struct eapol_sm *sm = ctx;
1631 if (sm && sm->ctx && sm->ctx->set_config_blob)
1632 sm->ctx->set_config_blob(sm->ctx->ctx, blob);
1636 static const struct wpa_config_blob *
1637 eapol_sm_get_config_blob(void *ctx, const char *name)
1639 struct eapol_sm *sm = ctx;
1640 if (sm && sm->ctx && sm->ctx->get_config_blob)
1641 return sm->ctx->get_config_blob(sm->ctx->ctx, name);
1642 else
1643 return NULL;
1647 static struct eapol_callbacks eapol_cb =
1649 .get_config = eapol_sm_get_config,
1650 .get_bool = eapol_sm_get_bool,
1651 .set_bool = eapol_sm_set_bool,
1652 .get_int = eapol_sm_get_int,
1653 .set_int = eapol_sm_set_int,
1654 .get_eapReqData = eapol_sm_get_eapReqData,
1655 .set_config_blob = eapol_sm_set_config_blob,
1656 .get_config_blob = eapol_sm_get_config_blob,
1661 * eapol_sm_init - Initialize EAPOL state machine
1662 * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
1663 * and EAPOL state machine will free it in eapol_sm_deinit()
1664 * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
1666 * Allocate and initialize an EAPOL state machine.
1668 struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
1670 struct eapol_sm *sm;
1671 struct eap_config conf;
1672 sm = malloc(sizeof(*sm));
1673 if (sm == NULL)
1674 return NULL;
1675 memset(sm, 0, sizeof(*sm));
1676 sm->ctx = ctx;
1678 sm->portControl = Auto;
1680 /* Supplicant PAE state machine */
1681 sm->heldPeriod = 60;
1682 sm->startPeriod = 30;
1683 sm->maxStart = 3;
1685 /* Supplicant Backend state machine */
1686 sm->authPeriod = 30;
1688 memset(&conf, 0, sizeof(conf));
1689 conf.opensc_engine_path = ctx->opensc_engine_path;
1690 conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
1691 conf.pkcs11_module_path = ctx->pkcs11_module_path;
1693 sm->eap = eap_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
1694 if (sm->eap == NULL) {
1695 free(sm);
1696 return NULL;
1699 /* Initialize EAPOL state machines */
1700 sm->initialize = TRUE;
1701 eapol_sm_step(sm);
1702 sm->initialize = FALSE;
1703 eapol_sm_step(sm);
1705 eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
1707 return sm;
1712 * eapol_sm_deinit - Deinitialize EAPOL state machine
1713 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1715 * Deinitialize and free EAPOL state machine.
1717 void eapol_sm_deinit(struct eapol_sm *sm)
1719 if (sm == NULL)
1720 return;
1721 eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
1722 eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
1723 eap_sm_deinit(sm->eap);
1724 free(sm->last_rx_key);
1725 free(sm->eapReqData);
1726 free(sm->ctx);
1727 free(sm);