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
12
* See README and COPYING for more details.
18
#include "eapol_supp_sm.h"
19
#include "eap_peer/eap.h"
21
#include "eapol_common.h"
24
#include "state_machine.h"
27
#define STATE_MACHINE_DATA struct eapol_sm
28
#define STATE_MACHINE_DEBUG_PREFIX "EAPOL"
31
/* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
34
* struct eapol_sm - Internal data for EAPOL state machines
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 */
51
PortControl portControl;
53
PortStatus suppPortStatus; /* dot1xSuppControlledPortStatus */
61
/* Supplicant PAE state machine */
64
SUPP_PAE_DISCONNECTED = 1,
66
SUPP_PAE_CONNECTING = 3,
67
SUPP_PAE_AUTHENTICATING = 4,
68
SUPP_PAE_AUTHENTICATED = 5,
72
SUPP_PAE_S_FORCE_AUTH = 9,
73
SUPP_PAE_S_FORCE_UNAUTH = 10
74
} SUPP_PAE_state; /* dot1xSuppPaeState */
78
unsigned int startCount;
80
PortControl sPortMode;
82
unsigned int heldPeriod; /* dot1xSuppHeldPeriod */
83
unsigned int startPeriod; /* dot1xSuppStartPeriod */
84
unsigned int maxStart; /* dot1xSuppMaxStart */
86
/* Key Receive state machine */
89
KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
94
/* Supplicant Backend state machine */
97
SUPP_BE_INITIALIZE = 1,
101
SUPP_BE_RESPONSE = 5,
105
} SUPP_BE_state; /* dot1xSuppBackendPaeState */
111
unsigned int authPeriod; /* dot1xSuppAuthPeriod */
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) */
129
struct eap_peer_config *config;
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 }
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
156
#pragma pack(push, 1)
157
#endif /* _MSC_VER */
159
struct ieee802_1x_eapol_key {
161
/* Note: key_length is unaligned */
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
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 */
185
#endif /* _MSC_VER */
188
static void eapol_sm_txLogoff(struct eapol_sm *sm);
189
static void eapol_sm_txStart(struct eapol_sm *sm);
190
static void eapol_sm_processKey(struct eapol_sm *sm);
191
static void eapol_sm_getSuppRsp(struct eapol_sm *sm);
192
static void eapol_sm_txSuppRsp(struct eapol_sm *sm);
193
static void eapol_sm_abortSupp(struct eapol_sm *sm);
194
static void eapol_sm_abort_cached(struct eapol_sm *sm);
195
static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx);
198
/* Port Timers state machine - implemented as a function that will be called
199
* once a second as a registered event loop timeout */
200
static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
202
struct eapol_sm *sm = timeout_ctx;
204
if (sm->authWhile > 0) {
206
if (sm->authWhile == 0)
207
wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0");
209
if (sm->heldWhile > 0) {
211
if (sm->heldWhile == 0)
212
wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0");
214
if (sm->startWhen > 0) {
216
if (sm->startWhen == 0)
217
wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0");
219
if (sm->idleWhile > 0) {
221
if (sm->idleWhile == 0)
222
wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0");
225
if (sm->authWhile | sm->heldWhile | sm->startWhen | sm->idleWhile) {
226
eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx,
229
wpa_printf(MSG_DEBUG, "EAPOL: disable timer tick");
230
sm->timer_tick_enabled = 0;
236
static void eapol_enable_timer_tick(struct eapol_sm *sm)
238
if (sm->timer_tick_enabled)
240
wpa_printf(MSG_DEBUG, "EAPOL: enable timer tick");
241
sm->timer_tick_enabled = 1;
242
eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
243
eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
247
SM_STATE(SUPP_PAE, LOGOFF)
249
SM_ENTRY(SUPP_PAE, LOGOFF);
250
eapol_sm_txLogoff(sm);
251
sm->logoffSent = TRUE;
252
sm->suppPortStatus = Unauthorized;
256
SM_STATE(SUPP_PAE, DISCONNECTED)
258
SM_ENTRY(SUPP_PAE, DISCONNECTED);
259
sm->sPortMode = Auto;
261
sm->logoffSent = FALSE;
262
sm->suppPortStatus = Unauthorized;
263
sm->suppAbort = TRUE;
265
sm->unicast_key_received = FALSE;
266
sm->broadcast_key_received = FALSE;
270
SM_STATE(SUPP_PAE, CONNECTING)
272
int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING;
273
SM_ENTRY(SUPP_PAE, CONNECTING);
275
sm->startWhen = sm->startPeriod;
279
* Do not send EAPOL-Start immediately since in most cases,
280
* Authenticator is going to start authentication immediately
281
* after association and an extra EAPOL-Start is just going to
282
* delay authentication. Use a short timeout to send the first
283
* EAPOL-Start if Authenticator does not start authentication.
287
eapol_enable_timer_tick(sm);
288
sm->eapolEap = FALSE;
290
eapol_sm_txStart(sm);
294
SM_STATE(SUPP_PAE, AUTHENTICATING)
296
SM_ENTRY(SUPP_PAE, AUTHENTICATING);
298
sm->suppSuccess = FALSE;
299
sm->suppFail = FALSE;
300
sm->suppTimeout = FALSE;
303
sm->suppStart = TRUE;
307
SM_STATE(SUPP_PAE, HELD)
309
SM_ENTRY(SUPP_PAE, HELD);
310
sm->heldWhile = sm->heldPeriod;
311
eapol_enable_timer_tick(sm);
312
sm->suppPortStatus = Unauthorized;
313
sm->cb_status = EAPOL_CB_FAILURE;
317
SM_STATE(SUPP_PAE, AUTHENTICATED)
319
SM_ENTRY(SUPP_PAE, AUTHENTICATED);
320
sm->suppPortStatus = Authorized;
321
sm->cb_status = EAPOL_CB_SUCCESS;
325
SM_STATE(SUPP_PAE, RESTART)
327
SM_ENTRY(SUPP_PAE, RESTART);
328
sm->eapRestart = TRUE;
332
SM_STATE(SUPP_PAE, S_FORCE_AUTH)
334
SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
335
sm->suppPortStatus = Authorized;
336
sm->sPortMode = ForceAuthorized;
340
SM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
342
SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
343
sm->suppPortStatus = Unauthorized;
344
sm->sPortMode = ForceUnauthorized;
345
eapol_sm_txLogoff(sm);
351
if ((sm->userLogoff && !sm->logoffSent) &&
352
!(sm->initialize || !sm->portEnabled))
353
SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF);
354
else if (((sm->portControl == Auto) &&
355
(sm->sPortMode != sm->portControl)) ||
356
sm->initialize || !sm->portEnabled)
357
SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED);
358
else if ((sm->portControl == ForceAuthorized) &&
359
(sm->sPortMode != sm->portControl) &&
360
!(sm->initialize || !sm->portEnabled))
361
SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH);
362
else if ((sm->portControl == ForceUnauthorized) &&
363
(sm->sPortMode != sm->portControl) &&
364
!(sm->initialize || !sm->portEnabled))
365
SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH);
366
else switch (sm->SUPP_PAE_state) {
367
case SUPP_PAE_UNKNOWN:
369
case SUPP_PAE_LOGOFF:
371
SM_ENTER(SUPP_PAE, DISCONNECTED);
373
case SUPP_PAE_DISCONNECTED:
374
SM_ENTER(SUPP_PAE, CONNECTING);
376
case SUPP_PAE_CONNECTING:
377
if (sm->startWhen == 0 && sm->startCount < sm->maxStart)
378
SM_ENTER(SUPP_PAE, CONNECTING);
379
else if (sm->startWhen == 0 &&
380
sm->startCount >= sm->maxStart &&
382
SM_ENTER(SUPP_PAE, AUTHENTICATED);
383
else if (sm->eapSuccess || sm->eapFail)
384
SM_ENTER(SUPP_PAE, AUTHENTICATING);
385
else if (sm->eapolEap)
386
SM_ENTER(SUPP_PAE, RESTART);
387
else if (sm->startWhen == 0 &&
388
sm->startCount >= sm->maxStart &&
390
SM_ENTER(SUPP_PAE, HELD);
392
case SUPP_PAE_AUTHENTICATING:
393
if (sm->eapSuccess && !sm->portValid &&
394
sm->conf.accept_802_1x_keys &&
395
sm->conf.required_keys == 0) {
396
wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for "
397
"plaintext connection; no EAPOL-Key frames "
399
sm->portValid = TRUE;
400
if (sm->ctx->eapol_done_cb)
401
sm->ctx->eapol_done_cb(sm->ctx->ctx);
403
if (sm->eapSuccess && sm->portValid)
404
SM_ENTER(SUPP_PAE, AUTHENTICATED);
405
else if (sm->eapFail || (sm->keyDone && !sm->portValid))
406
SM_ENTER(SUPP_PAE, HELD);
407
else if (sm->suppTimeout)
408
SM_ENTER(SUPP_PAE, CONNECTING);
411
if (sm->heldWhile == 0)
412
SM_ENTER(SUPP_PAE, CONNECTING);
413
else if (sm->eapolEap)
414
SM_ENTER(SUPP_PAE, RESTART);
416
case SUPP_PAE_AUTHENTICATED:
417
if (sm->eapolEap && sm->portValid)
418
SM_ENTER(SUPP_PAE, RESTART);
419
else if (!sm->portValid)
420
SM_ENTER(SUPP_PAE, DISCONNECTED);
422
case SUPP_PAE_RESTART:
424
SM_ENTER(SUPP_PAE, AUTHENTICATING);
426
case SUPP_PAE_S_FORCE_AUTH:
428
case SUPP_PAE_S_FORCE_UNAUTH:
434
SM_STATE(KEY_RX, NO_KEY_RECEIVE)
436
SM_ENTRY(KEY_RX, NO_KEY_RECEIVE);
440
SM_STATE(KEY_RX, KEY_RECEIVE)
442
SM_ENTRY(KEY_RX, KEY_RECEIVE);
443
eapol_sm_processKey(sm);
450
if (sm->initialize || !sm->portEnabled)
451
SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
452
switch (sm->KEY_RX_state) {
455
case KEY_RX_NO_KEY_RECEIVE:
457
SM_ENTER(KEY_RX, KEY_RECEIVE);
459
case KEY_RX_KEY_RECEIVE:
461
SM_ENTER(KEY_RX, KEY_RECEIVE);
467
SM_STATE(SUPP_BE, REQUEST)
469
SM_ENTRY(SUPP_BE, REQUEST);
472
eapol_sm_getSuppRsp(sm);
476
SM_STATE(SUPP_BE, RESPONSE)
478
SM_ENTRY(SUPP_BE, RESPONSE);
479
eapol_sm_txSuppRsp(sm);
484
SM_STATE(SUPP_BE, SUCCESS)
486
SM_ENTRY(SUPP_BE, SUCCESS);
488
sm->suppSuccess = TRUE;
490
if (eap_key_available(sm->eap)) {
491
/* New key received - clear IEEE 802.1X EAPOL-Key replay
493
sm->replay_counter_valid = FALSE;
498
SM_STATE(SUPP_BE, FAIL)
500
SM_ENTRY(SUPP_BE, FAIL);
505
SM_STATE(SUPP_BE, TIMEOUT)
507
SM_ENTRY(SUPP_BE, TIMEOUT);
508
sm->suppTimeout = TRUE;
512
SM_STATE(SUPP_BE, IDLE)
514
SM_ENTRY(SUPP_BE, IDLE);
515
sm->suppStart = FALSE;
516
sm->initial_req = TRUE;
520
SM_STATE(SUPP_BE, INITIALIZE)
522
SM_ENTRY(SUPP_BE, INITIALIZE);
523
eapol_sm_abortSupp(sm);
524
sm->suppAbort = FALSE;
528
SM_STATE(SUPP_BE, RECEIVE)
530
SM_ENTRY(SUPP_BE, RECEIVE);
531
sm->authWhile = sm->authPeriod;
532
eapol_enable_timer_tick(sm);
533
sm->eapolEap = FALSE;
534
sm->eapNoResp = FALSE;
535
sm->initial_req = FALSE;
541
if (sm->initialize || sm->suppAbort)
542
SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE);
543
else switch (sm->SUPP_BE_state) {
544
case SUPP_BE_UNKNOWN:
546
case SUPP_BE_REQUEST:
548
* IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
549
* and SUCCESS based on eapFail and eapSuccess, respectively.
550
* However, IEEE Std 802.1X-2004 is also specifying that
551
* eapNoResp should be set in conjuction with eapSuccess and
552
* eapFail which would mean that more than one of the
553
* transitions here would be activated at the same time.
554
* Skipping RESPONSE and/or RECEIVE states in these cases can
555
* cause problems and the direct transitions to do not seem
556
* correct. Because of this, the conditions for these
557
* transitions are verified only after eapNoResp. They are
558
* unlikely to be used since eapNoResp should always be set if
559
* either of eapSuccess or eapFail is set.
561
if (sm->eapResp && sm->eapNoResp) {
562
wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both "
563
"eapResp and eapNoResp set?!");
566
SM_ENTER(SUPP_BE, RESPONSE);
567
else if (sm->eapNoResp)
568
SM_ENTER(SUPP_BE, RECEIVE);
569
else if (sm->eapFail)
570
SM_ENTER(SUPP_BE, FAIL);
571
else if (sm->eapSuccess)
572
SM_ENTER(SUPP_BE, SUCCESS);
574
case SUPP_BE_RESPONSE:
575
SM_ENTER(SUPP_BE, RECEIVE);
577
case SUPP_BE_SUCCESS:
578
SM_ENTER(SUPP_BE, IDLE);
581
SM_ENTER(SUPP_BE, IDLE);
583
case SUPP_BE_TIMEOUT:
584
SM_ENTER(SUPP_BE, IDLE);
587
if (sm->eapFail && sm->suppStart)
588
SM_ENTER(SUPP_BE, FAIL);
589
else if (sm->eapolEap && sm->suppStart)
590
SM_ENTER(SUPP_BE, REQUEST);
591
else if (sm->eapSuccess && sm->suppStart)
592
SM_ENTER(SUPP_BE, SUCCESS);
594
case SUPP_BE_INITIALIZE:
595
SM_ENTER(SUPP_BE, IDLE);
597
case SUPP_BE_RECEIVE:
599
SM_ENTER(SUPP_BE, REQUEST);
600
else if (sm->eapFail)
601
SM_ENTER(SUPP_BE, FAIL);
602
else if (sm->authWhile == 0)
603
SM_ENTER(SUPP_BE, TIMEOUT);
604
else if (sm->eapSuccess)
605
SM_ENTER(SUPP_BE, SUCCESS);
611
static void eapol_sm_txLogoff(struct eapol_sm *sm)
613
wpa_printf(MSG_DEBUG, "EAPOL: txLogoff");
614
sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
615
IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0);
616
sm->dot1xSuppEapolLogoffFramesTx++;
617
sm->dot1xSuppEapolFramesTx++;
621
static void eapol_sm_txStart(struct eapol_sm *sm)
623
wpa_printf(MSG_DEBUG, "EAPOL: txStart");
624
sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
625
IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0);
626
sm->dot1xSuppEapolStartFramesTx++;
627
sm->dot1xSuppEapolFramesTx++;
631
#define IEEE8021X_ENCR_KEY_LEN 32
632
#define IEEE8021X_SIGN_KEY_LEN 32
634
struct eap_key_data {
635
u8 encr_key[IEEE8021X_ENCR_KEY_LEN];
636
u8 sign_key[IEEE8021X_SIGN_KEY_LEN];
640
static void eapol_sm_processKey(struct eapol_sm *sm)
642
struct ieee802_1x_hdr *hdr;
643
struct ieee802_1x_eapol_key *key;
644
struct eap_key_data keydata;
645
u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
646
u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
647
int key_len, res, sign_key_len, encr_key_len;
650
wpa_printf(MSG_DEBUG, "EAPOL: processKey");
651
if (sm->last_rx_key == NULL)
654
if (!sm->conf.accept_802_1x_keys) {
655
wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key"
656
" even though this was not accepted - "
657
"ignoring this packet");
661
hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
662
key = (struct ieee802_1x_eapol_key *) (hdr + 1);
663
if (sizeof(*hdr) + be_to_host16(hdr->length) > sm->last_rx_key_len) {
664
wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
667
rx_key_length = WPA_GET_BE16(key->key_length);
668
wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
669
"EAPOL-Key: type=%d key_length=%d key_index=0x%x",
670
hdr->version, hdr->type, be_to_host16(hdr->length),
671
key->type, rx_key_length, key->key_index);
673
eapol_sm_notify_lower_layer_success(sm, 1);
674
sign_key_len = IEEE8021X_SIGN_KEY_LEN;
675
encr_key_len = IEEE8021X_ENCR_KEY_LEN;
676
res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata));
678
wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for "
679
"decrypting EAPOL-Key keys");
683
/* LEAP derives only 16 bytes of keying material. */
684
res = eapol_sm_get_key(sm, (u8 *) &keydata, 16);
686
wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP "
687
"master key for decrypting EAPOL-Key keys");
692
os_memcpy(keydata.sign_key, keydata.encr_key, 16);
694
wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key "
695
"data for decrypting EAPOL-Key keys (res=%d)", res);
699
/* The key replay_counter must increase when same master key */
700
if (sm->replay_counter_valid &&
701
os_memcmp(sm->last_replay_counter, key->replay_counter,
702
IEEE8021X_REPLAY_COUNTER_LEN) >= 0) {
703
wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did "
704
"not increase - ignoring key");
705
wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter",
706
sm->last_replay_counter,
707
IEEE8021X_REPLAY_COUNTER_LEN);
708
wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter",
709
key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN);
713
/* Verify key signature (HMAC-MD5) */
714
os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN);
715
os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN);
716
hmac_md5(keydata.sign_key, sign_key_len,
717
sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
719
if (os_memcmp(orig_key_sign, key->key_signature,
720
IEEE8021X_KEY_SIGN_LEN) != 0) {
721
wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
723
os_memcpy(key->key_signature, orig_key_sign,
724
IEEE8021X_KEY_SIGN_LEN);
727
wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
729
key_len = be_to_host16(hdr->length) - sizeof(*key);
730
if (key_len > 32 || rx_key_length > 32) {
731
wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
732
key_len ? key_len : rx_key_length);
735
if (key_len == rx_key_length) {
736
os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
737
os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
739
os_memcpy(datakey, key + 1, key_len);
740
rc4(datakey, key_len, ekey,
741
IEEE8021X_KEY_IV_LEN + encr_key_len);
742
wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
744
} else if (key_len == 0) {
746
* IEEE 802.1X-2004 specifies that least significant Key Length
747
* octets from MS-MPPE-Send-Key are used as the key if the key
748
* data is not present. This seems to be meaning the beginning
749
* of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
750
* Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
751
* Anyway, taking the beginning of the keying material from EAP
752
* seems to interoperate with Authenticators.
754
key_len = rx_key_length;
755
os_memcpy(datakey, keydata.encr_key, key_len);
756
wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying "
757
"material data encryption key",
760
wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
761
"(key_length=%d)", key_len, rx_key_length);
765
sm->replay_counter_valid = TRUE;
766
os_memcpy(sm->last_replay_counter, key->replay_counter,
767
IEEE8021X_REPLAY_COUNTER_LEN);
769
wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
771
key->key_index & IEEE8021X_KEY_INDEX_FLAG ?
772
"unicast" : "broadcast",
773
key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len);
775
if (sm->ctx->set_wep_key &&
776
sm->ctx->set_wep_key(sm->ctx->ctx,
777
key->key_index & IEEE8021X_KEY_INDEX_FLAG,
778
key->key_index & IEEE8021X_KEY_INDEX_MASK,
779
datakey, key_len) < 0) {
780
wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
783
if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
784
sm->unicast_key_received = TRUE;
786
sm->broadcast_key_received = TRUE;
788
if ((sm->unicast_key_received ||
789
!(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) &&
790
(sm->broadcast_key_received ||
791
!(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST)))
793
wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
795
sm->portValid = TRUE;
796
if (sm->ctx->eapol_done_cb)
797
sm->ctx->eapol_done_cb(sm->ctx->ctx);
803
static void eapol_sm_getSuppRsp(struct eapol_sm *sm)
805
wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp");
806
/* EAP layer processing; no special code is needed, since Supplicant
807
* Backend state machine is waiting for eapNoResp or eapResp to be set
808
* and these are only set in the EAP state machine when the processing
813
static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
817
wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
818
resp = eap_get_eapRespData(sm->eap);
820
wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
825
/* Send EAP-Packet from the EAP layer to the Authenticator */
826
sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
827
IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head(resp),
830
/* eapRespData is not used anymore, so free it here */
834
sm->dot1xSuppEapolReqIdFramesRx++;
836
sm->dot1xSuppEapolReqFramesRx++;
837
sm->dot1xSuppEapolRespFramesTx++;
838
sm->dot1xSuppEapolFramesTx++;
842
static void eapol_sm_abortSupp(struct eapol_sm *sm)
844
/* release system resources that may have been allocated for the
845
* authentication session */
846
os_free(sm->last_rx_key);
847
sm->last_rx_key = NULL;
848
wpabuf_free(sm->eapReqData);
849
sm->eapReqData = NULL;
850
eap_sm_abort(sm->eap);
854
static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
856
eapol_sm_step(timeout_ctx);
861
* eapol_sm_step - EAPOL state machine step function
862
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
864
* This function is called to notify the state machine about changed external
865
* variables. It will step through the EAPOL state machines in loop to process
866
* all triggered state changes.
868
void eapol_sm_step(struct eapol_sm *sm)
872
/* In theory, it should be ok to run this in loop until !changed.
873
* However, it is better to use a limit on number of iterations to
874
* allow events (e.g., SIGTERM) to stop the program cleanly if the
875
* state machine were to generate a busy loop. */
876
for (i = 0; i < 100; i++) {
878
SM_STEP_RUN(SUPP_PAE);
880
SM_STEP_RUN(SUPP_BE);
881
if (eap_peer_sm_step(sm->eap))
888
/* restart EAPOL state machine step from timeout call in order
889
* to allow other events to be processed. */
890
eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
891
eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm);
894
if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
895
int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0;
896
sm->cb_status = EAPOL_CB_IN_PROGRESS;
897
sm->ctx->cb(sm, success, sm->ctx->cb_ctx);
902
#ifdef CONFIG_CTRL_IFACE
903
static const char *eapol_supp_pae_state(int state)
906
case SUPP_PAE_LOGOFF:
908
case SUPP_PAE_DISCONNECTED:
909
return "DISCONNECTED";
910
case SUPP_PAE_CONNECTING:
912
case SUPP_PAE_AUTHENTICATING:
913
return "AUTHENTICATING";
916
case SUPP_PAE_AUTHENTICATED:
917
return "AUTHENTICATED";
918
case SUPP_PAE_RESTART:
926
static const char *eapol_supp_be_state(int state)
929
case SUPP_BE_REQUEST:
931
case SUPP_BE_RESPONSE:
933
case SUPP_BE_SUCCESS:
937
case SUPP_BE_TIMEOUT:
941
case SUPP_BE_INITIALIZE:
943
case SUPP_BE_RECEIVE:
951
static const char * eapol_port_status(PortStatus status)
953
if (status == Authorized)
956
return "Unauthorized";
958
#endif /* CONFIG_CTRL_IFACE */
961
#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
962
static const char * eapol_port_control(PortControl ctrl)
967
case ForceUnauthorized:
968
return "ForceUnauthorized";
969
case ForceAuthorized:
970
return "ForceAuthorized";
975
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
979
* eapol_sm_configure - Set EAPOL variables
980
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
981
* @heldPeriod: dot1xSuppHeldPeriod
982
* @authPeriod: dot1xSuppAuthPeriod
983
* @startPeriod: dot1xSuppStartPeriod
984
* @maxStart: dot1xSuppMaxStart
986
* Set configurable EAPOL state machine variables. Each variable can be set to
987
* the given value or ignored if set to -1 (to set only some of the variables).
989
void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
990
int startPeriod, int maxStart)
995
sm->heldPeriod = heldPeriod;
997
sm->authPeriod = authPeriod;
998
if (startPeriod >= 0)
999
sm->startPeriod = startPeriod;
1001
sm->maxStart = maxStart;
1005
#ifdef CONFIG_CTRL_IFACE
1007
* eapol_sm_get_status - Get EAPOL state machine status
1008
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1009
* @buf: Buffer for status information
1010
* @buflen: Maximum buffer length
1011
* @verbose: Whether to include verbose status information
1012
* Returns: Number of bytes written to buf.
1014
* Query EAPOL state machine for status information. This function fills in a
1015
* text area with current status information from the EAPOL state machine. If
1016
* the buffer (buf) is not large enough, status information will be truncated
1017
* to fit the buffer.
1019
int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
1026
len = os_snprintf(buf, buflen,
1027
"Supplicant PAE state=%s\n"
1028
"suppPortStatus=%s\n",
1029
eapol_supp_pae_state(sm->SUPP_PAE_state),
1030
eapol_port_status(sm->suppPortStatus));
1031
if (len < 0 || (size_t) len >= buflen)
1035
ret = os_snprintf(buf + len, buflen - len,
1041
"Supplicant Backend state=%s\n",
1046
eapol_port_control(sm->portControl),
1047
eapol_supp_be_state(sm->SUPP_BE_state));
1048
if (ret < 0 || (size_t) ret >= buflen - len)
1053
len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
1060
* eapol_sm_get_mib - Get EAPOL state machine MIBs
1061
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1062
* @buf: Buffer for MIB information
1063
* @buflen: Maximum buffer length
1064
* Returns: Number of bytes written to buf.
1066
* Query EAPOL state machine for MIB information. This function fills in a
1067
* text area with current MIB information from the EAPOL state machine. If
1068
* the buffer (buf) is not large enough, MIB information will be truncated to
1071
int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
1078
ret = os_snprintf(buf, buflen,
1079
"dot1xSuppPaeState=%d\n"
1080
"dot1xSuppHeldPeriod=%u\n"
1081
"dot1xSuppAuthPeriod=%u\n"
1082
"dot1xSuppStartPeriod=%u\n"
1083
"dot1xSuppMaxStart=%u\n"
1084
"dot1xSuppSuppControlledPortStatus=%s\n"
1085
"dot1xSuppBackendPaeState=%d\n",
1091
sm->suppPortStatus == Authorized ?
1092
"Authorized" : "Unauthorized",
1095
if (ret < 0 || (size_t) ret >= buflen)
1099
ret = os_snprintf(buf + len, buflen - len,
1100
"dot1xSuppEapolFramesRx=%u\n"
1101
"dot1xSuppEapolFramesTx=%u\n"
1102
"dot1xSuppEapolStartFramesTx=%u\n"
1103
"dot1xSuppEapolLogoffFramesTx=%u\n"
1104
"dot1xSuppEapolRespFramesTx=%u\n"
1105
"dot1xSuppEapolReqIdFramesRx=%u\n"
1106
"dot1xSuppEapolReqFramesRx=%u\n"
1107
"dot1xSuppInvalidEapolFramesRx=%u\n"
1108
"dot1xSuppEapLengthErrorFramesRx=%u\n"
1109
"dot1xSuppLastEapolFrameVersion=%u\n"
1110
"dot1xSuppLastEapolFrameSource=" MACSTR "\n",
1111
sm->dot1xSuppEapolFramesRx,
1112
sm->dot1xSuppEapolFramesTx,
1113
sm->dot1xSuppEapolStartFramesTx,
1114
sm->dot1xSuppEapolLogoffFramesTx,
1115
sm->dot1xSuppEapolRespFramesTx,
1116
sm->dot1xSuppEapolReqIdFramesRx,
1117
sm->dot1xSuppEapolReqFramesRx,
1118
sm->dot1xSuppInvalidEapolFramesRx,
1119
sm->dot1xSuppEapLengthErrorFramesRx,
1120
sm->dot1xSuppLastEapolFrameVersion,
1121
MAC2STR(sm->dot1xSuppLastEapolFrameSource));
1123
if (ret < 0 || (size_t) ret >= buflen - len)
1129
#endif /* CONFIG_CTRL_IFACE */
1133
* eapol_sm_rx_eapol - Process received EAPOL frames
1134
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1135
* @src: Source MAC address of the EAPOL packet
1136
* @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
1137
* @len: Length of the EAPOL frame
1138
* Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
1141
int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
1144
const struct ieee802_1x_hdr *hdr;
1145
const struct ieee802_1x_eapol_key *key;
1152
sm->dot1xSuppEapolFramesRx++;
1153
if (len < sizeof(*hdr)) {
1154
sm->dot1xSuppInvalidEapolFramesRx++;
1157
hdr = (const struct ieee802_1x_hdr *) buf;
1158
sm->dot1xSuppLastEapolFrameVersion = hdr->version;
1159
os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
1160
if (hdr->version < EAPOL_VERSION) {
1161
/* TODO: backwards compatibility */
1163
plen = be_to_host16(hdr->length);
1164
if (plen > len - sizeof(*hdr)) {
1165
sm->dot1xSuppEapLengthErrorFramesRx++;
1168
data_len = plen + sizeof(*hdr);
1170
switch (hdr->type) {
1171
case IEEE802_1X_TYPE_EAP_PACKET:
1172
if (sm->cached_pmk) {
1173
/* Trying to use PMKSA caching, but Authenticator did
1174
* not seem to have a matching entry. Need to restart
1175
* EAPOL state machines.
1177
eapol_sm_abort_cached(sm);
1179
wpabuf_free(sm->eapReqData);
1180
sm->eapReqData = wpabuf_alloc_copy(hdr + 1, plen);
1181
if (sm->eapReqData) {
1182
wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
1184
sm->eapolEap = TRUE;
1188
case IEEE802_1X_TYPE_EAPOL_KEY:
1189
if (plen < sizeof(*key)) {
1190
wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key "
1194
key = (const struct ieee802_1x_eapol_key *) (hdr + 1);
1195
if (key->type == EAPOL_KEY_TYPE_WPA ||
1196
key->type == EAPOL_KEY_TYPE_RSN) {
1197
/* WPA Supplicant takes care of this frame. */
1198
wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
1199
"frame in EAPOL state machines");
1203
if (key->type != EAPOL_KEY_TYPE_RC4) {
1204
wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown "
1205
"EAPOL-Key type %d", key->type);
1208
os_free(sm->last_rx_key);
1209
sm->last_rx_key = os_malloc(data_len);
1210
if (sm->last_rx_key) {
1211
wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key "
1213
os_memcpy(sm->last_rx_key, buf, data_len);
1214
sm->last_rx_key_len = data_len;
1220
wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
1222
sm->dot1xSuppInvalidEapolFramesRx++;
1231
* eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet
1232
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1234
* Notify EAPOL state machine about transmitted EAPOL packet from an external
1235
* component, e.g., WPA. This will update the statistics.
1237
void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
1240
sm->dot1xSuppEapolFramesTx++;
1245
* eapol_sm_notify_portEnabled - Notification about portEnabled change
1246
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1247
* @enabled: New portEnabled value
1249
* Notify EAPOL state machine about new portEnabled value.
1251
void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
1255
wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1256
"portEnabled=%d", enabled);
1257
sm->portEnabled = enabled;
1263
* eapol_sm_notify_portValid - Notification about portValid change
1264
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1265
* @valid: New portValid value
1267
* Notify EAPOL state machine about new portValid value.
1269
void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
1273
wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1274
"portValid=%d", valid);
1275
sm->portValid = valid;
1281
* eapol_sm_notify_eap_success - Notification of external EAP success trigger
1282
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1283
* @success: %TRUE = set success, %FALSE = clear success
1285
* Notify the EAPOL state machine that external event has forced EAP state to
1286
* success (success = %TRUE). This can be cleared by setting success = %FALSE.
1288
* This function is called to update EAP state when WPA-PSK key handshake has
1289
* been completed successfully since WPA-PSK does not use EAP state machine.
1291
void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
1295
wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1296
"EAP success=%d", success);
1297
sm->eapSuccess = success;
1298
sm->altAccept = success;
1300
eap_notify_success(sm->eap);
1306
* eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
1307
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1308
* @fail: %TRUE = set failure, %FALSE = clear failure
1310
* Notify EAPOL state machine that external event has forced EAP state to
1311
* failure (fail = %TRUE). This can be cleared by setting fail = %FALSE.
1313
void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
1317
wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1318
"EAP fail=%d", fail);
1320
sm->altReject = fail;
1326
* eapol_sm_notify_config - Notification of EAPOL configuration change
1327
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1328
* @config: Pointer to current network EAP configuration
1329
* @conf: Pointer to EAPOL configuration data
1331
* Notify EAPOL state machine that configuration has changed. config will be
1332
* stored as a backpointer to network configuration. This can be %NULL to clear
1333
* the stored pointed. conf will be copied to local EAPOL/EAP configuration
1334
* data. If conf is %NULL, this part of the configuration change will be
1337
void eapol_sm_notify_config(struct eapol_sm *sm,
1338
struct eap_peer_config *config,
1339
const struct eapol_config *conf)
1344
sm->config = config;
1349
sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys;
1350
sm->conf.required_keys = conf->required_keys;
1351
sm->conf.fast_reauth = conf->fast_reauth;
1353
eap_set_fast_reauth(sm->eap, conf->fast_reauth);
1354
eap_set_workaround(sm->eap, conf->workaround);
1355
eap_set_force_disabled(sm->eap, conf->eap_disabled);
1361
* eapol_sm_get_key - Get master session key (MSK) from EAP
1362
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1363
* @key: Pointer for key buffer
1364
* @len: Number of bytes to copy to key
1365
* Returns: 0 on success (len of key available), maximum available key len
1366
* (>0) if key is available but it is shorter than len, or -1 on failure.
1368
* Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key
1369
* is available only after a successful authentication.
1371
int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
1376
if (sm == NULL || !eap_key_available(sm->eap)) {
1377
wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
1380
eap_key = eap_get_eapKeyData(sm->eap, &eap_len);
1381
if (eap_key == NULL) {
1382
wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData");
1385
if (len > eap_len) {
1386
wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not "
1387
"available (len=%lu)",
1388
(unsigned long) len, (unsigned long) eap_len);
1391
os_memcpy(key, eap_key, len);
1392
wpa_printf(MSG_DEBUG, "EAPOL: Successfully fetched key (len=%lu)",
1393
(unsigned long) len);
1399
* eapol_sm_notify_logoff - Notification of logon/logoff commands
1400
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1401
* @logoff: Whether command was logoff
1403
* Notify EAPOL state machines that user requested logon/logoff.
1405
void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
1408
sm->userLogoff = logoff;
1415
* eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching
1416
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1418
* Notify EAPOL state machines that PMKSA caching was successful. This is used
1419
* to move EAPOL and EAP state machines into authenticated/successful state.
1421
void eapol_sm_notify_cached(struct eapol_sm *sm)
1425
sm->SUPP_PAE_state = SUPP_PAE_AUTHENTICATED;
1426
sm->suppPortStatus = Authorized;
1427
eap_notify_success(sm->eap);
1433
* eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
1434
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1435
* @attempt: Whether PMKSA caching is tried
1437
* Notify EAPOL state machines whether PMKSA caching is used.
1439
void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt)
1444
wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
1445
sm->cached_pmk = TRUE;
1447
wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA");
1448
sm->cached_pmk = FALSE;
1453
static void eapol_sm_abort_cached(struct eapol_sm *sm)
1455
wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, "
1456
"doing full EAP authentication");
1459
sm->cached_pmk = FALSE;
1460
sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
1461
sm->suppPortStatus = Unauthorized;
1463
/* Make sure we do not start sending EAPOL-Start frames first, but
1464
* instead move to RESTART state to start EAPOL authentication. */
1466
eapol_enable_timer_tick(sm);
1468
if (sm->ctx->aborted_cached)
1469
sm->ctx->aborted_cached(sm->ctx->ctx);
1474
* eapol_sm_register_scard_ctx - Notification of smart card context
1475
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1476
* @ctx: Context data for smart card operations
1478
* Notify EAPOL state machines of context data for smart card operations. This
1479
* context data will be used as a parameter for scard_*() functions.
1481
void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
1484
sm->ctx->scard_ctx = ctx;
1485
eap_register_scard_ctx(sm->eap, ctx);
1491
* eapol_sm_notify_portControl - Notification of portControl changes
1492
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1493
* @portControl: New value for portControl variable
1495
* Notify EAPOL state machines that portControl variable has changed.
1497
void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
1501
wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1502
"portControl=%s", eapol_port_control(portControl));
1503
sm->portControl = portControl;
1509
* eapol_sm_notify_ctrl_attached - Notification of attached monitor
1510
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1512
* Notify EAPOL state machines that a monitor was attached to the control
1513
* interface to trigger re-sending of pending requests for user input.
1515
void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
1519
eap_sm_notify_ctrl_attached(sm->eap);
1524
* eapol_sm_notify_ctrl_response - Notification of received user input
1525
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1527
* Notify EAPOL state machines that a control response, i.e., user
1528
* input, was received in order to trigger retrying of a pending EAP request.
1530
void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
1534
if (sm->eapReqData && !sm->eapReq) {
1535
wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
1536
"input) notification - retrying pending EAP "
1538
sm->eapolEap = TRUE;
1546
* eapol_sm_request_reauth - Request reauthentication
1547
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1549
* This function can be used to request EAPOL reauthentication, e.g., when the
1550
* current PMKSA entry is nearing expiration.
1552
void eapol_sm_request_reauth(struct eapol_sm *sm)
1554
if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
1556
eapol_sm_txStart(sm);
1561
* eapol_sm_notify_lower_layer_success - Notification of lower layer success
1562
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1563
* @in_eapol_sm: Whether the caller is already running inside EAPOL state
1564
* machine loop (eapol_sm_step())
1566
* Notify EAPOL (and EAP) state machines that a lower layer has detected a
1567
* successful authentication. This is used to recover from dropped EAP-Success
1570
void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm)
1574
eap_notify_lower_layer_success(sm->eap);
1581
* eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid
1582
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1584
void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
1587
eap_invalidate_cached_session(sm->eap);
1591
static struct eap_peer_config * eapol_sm_get_config(void *ctx)
1593
struct eapol_sm *sm = ctx;
1594
return sm ? sm->config : NULL;
1598
static struct wpabuf * eapol_sm_get_eapReqData(void *ctx)
1600
struct eapol_sm *sm = ctx;
1601
if (sm == NULL || sm->eapReqData == NULL)
1604
return sm->eapReqData;
1608
static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
1610
struct eapol_sm *sm = ctx;
1614
case EAPOL_eapSuccess:
1615
return sm->eapSuccess;
1616
case EAPOL_eapRestart:
1617
return sm->eapRestart;
1622
case EAPOL_eapNoResp:
1623
return sm->eapNoResp;
1626
case EAPOL_portEnabled:
1627
return sm->portEnabled;
1628
case EAPOL_altAccept:
1629
return sm->altAccept;
1630
case EAPOL_altReject:
1631
return sm->altReject;
1637
static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
1640
struct eapol_sm *sm = ctx;
1644
case EAPOL_eapSuccess:
1645
sm->eapSuccess = value;
1647
case EAPOL_eapRestart:
1648
sm->eapRestart = value;
1651
sm->eapFail = value;
1654
sm->eapResp = value;
1656
case EAPOL_eapNoResp:
1657
sm->eapNoResp = value;
1662
case EAPOL_portEnabled:
1663
sm->portEnabled = value;
1665
case EAPOL_altAccept:
1666
sm->altAccept = value;
1668
case EAPOL_altReject:
1669
sm->altReject = value;
1675
static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable)
1677
struct eapol_sm *sm = ctx;
1681
case EAPOL_idleWhile:
1682
return sm->idleWhile;
1688
static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
1691
struct eapol_sm *sm = ctx;
1695
case EAPOL_idleWhile:
1696
sm->idleWhile = value;
1697
eapol_enable_timer_tick(sm);
1703
static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
1705
#ifndef CONFIG_NO_CONFIG_BLOBS
1706
struct eapol_sm *sm = ctx;
1707
if (sm && sm->ctx && sm->ctx->set_config_blob)
1708
sm->ctx->set_config_blob(sm->ctx->ctx, blob);
1709
#endif /* CONFIG_NO_CONFIG_BLOBS */
1713
static const struct wpa_config_blob *
1714
eapol_sm_get_config_blob(void *ctx, const char *name)
1716
#ifndef CONFIG_NO_CONFIG_BLOBS
1717
struct eapol_sm *sm = ctx;
1718
if (sm && sm->ctx && sm->ctx->get_config_blob)
1719
return sm->ctx->get_config_blob(sm->ctx->ctx, name);
1722
#else /* CONFIG_NO_CONFIG_BLOBS */
1724
#endif /* CONFIG_NO_CONFIG_BLOBS */
1728
static void eapol_sm_notify_pending(void *ctx)
1730
struct eapol_sm *sm = ctx;
1733
if (sm->eapReqData && !sm->eapReq) {
1734
wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP "
1735
"state machine - retrying pending EAP Request");
1736
sm->eapolEap = TRUE;
1743
#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
1744
static void eapol_sm_eap_param_needed(void *ctx, const char *field,
1747
struct eapol_sm *sm = ctx;
1748
wpa_printf(MSG_DEBUG, "EAPOL: EAP parameter needed");
1749
if (sm->ctx->eap_param_needed)
1750
sm->ctx->eap_param_needed(sm->ctx->ctx, field, txt);
1752
#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1753
#define eapol_sm_eap_param_needed NULL
1754
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1757
static struct eapol_callbacks eapol_cb =
1759
eapol_sm_get_config,
1764
eapol_sm_get_eapReqData,
1765
eapol_sm_set_config_blob,
1766
eapol_sm_get_config_blob,
1767
eapol_sm_notify_pending,
1768
eapol_sm_eap_param_needed
1773
* eapol_sm_init - Initialize EAPOL state machine
1774
* @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
1775
* and EAPOL state machine will free it in eapol_sm_deinit()
1776
* Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
1778
* Allocate and initialize an EAPOL state machine.
1780
struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
1782
struct eapol_sm *sm;
1783
struct eap_config conf;
1784
sm = os_zalloc(sizeof(*sm));
1789
sm->portControl = Auto;
1791
/* Supplicant PAE state machine */
1792
sm->heldPeriod = 60;
1793
sm->startPeriod = 30;
1796
/* Supplicant Backend state machine */
1797
sm->authPeriod = 30;
1799
os_memset(&conf, 0, sizeof(conf));
1800
#ifdef EAP_TLS_OPENSSL
1801
conf.opensc_engine_path = ctx->opensc_engine_path;
1802
conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
1803
conf.pkcs11_module_path = ctx->pkcs11_module_path;
1804
#endif /* EAP_TLS_OPENSSL */
1806
sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
1807
if (sm->eap == NULL) {
1812
/* Initialize EAPOL state machines */
1813
sm->initialize = TRUE;
1815
sm->initialize = FALSE;
1818
sm->timer_tick_enabled = 1;
1819
eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
1826
* eapol_sm_deinit - Deinitialize EAPOL state machine
1827
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1829
* Deinitialize and free EAPOL state machine.
1831
void eapol_sm_deinit(struct eapol_sm *sm)
1835
eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
1836
eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
1837
eap_peer_sm_deinit(sm->eap);
1838
os_free(sm->last_rx_key);
1839
wpabuf_free(sm->eapReqData);