~ubuntu-branches/ubuntu/vivid/wpasupplicant/vivid

« back to all changes in this revision

Viewing changes to src/eapol_supp/eapol_supp_sm.c

  • Committer: Bazaar Package Importer
  • Author(s): Kel Modderman
  • Date: 2008-03-12 20:03:04 UTC
  • mfrom: (1.1.10 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20080312200304-4331y9wj46pdd34z
Tags: 0.6.3-1
* New upstream release.
* Drop patches applied upstream:
  - debian/patches/30_wpa_gui_qt4_eventhistoryui_rework.patch
  - debian/patches/31_wpa_gui_qt4_eventhistory_always_scrollbar.patch
  - debian/patches/32_wpa_gui_qt4_eventhistory_scroll_with_events.patch
  - debian/patches/40_dbus_ssid_data.patch
* Tidy up the clean target of debian/rules. Now that the madwifi headers are
  handled differently we no longer need to do any cleanup.
* Fix formatting error in debian/ifupdown/wpa_action.8 to make lintian
  quieter.
* Add patch to fix formatting errors in manpages build from sgml source. Use
  <emphasis> tags to hightlight keywords instead of surrounding them in
  strong quotes.
  - debian/patches/41_manpage_format_fixes.patch
* wpasupplicant binary package no longer suggests pcscd, guessnet, iproute
  or wireless-tools, nor does it recommend dhcp3-client. These are not
  needed.
* Add debian/patches/10_silence_siocsiwauth_icotl_failure.patch to disable
  ioctl failure messages that occur under normal conditions.
* Cherry pick two upstream git commits concerning the dbus interface:
  - debian/patches/11_avoid_dbus_version_namespace.patch
  - debian/patches/12_fix_potential_use_after_free.patch
* Add debian/patches/42_manpage_explain_available_drivers.patch to explain
  that not all of the driver backends are available in the provided
  wpa_supplicant binary, and that the canonical list of supported driver
  backends can be retrieved from the wpa_supplicant -h (help) output.
  (Closes: #466910)
* Add debian/patches/20_wpa_gui_qt4_disable_link_prl.patch to remove
  link_prl CONFIG compile flag added by qmake-qt4 >= 4.3.4-2 to avoid excess
  linking.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * EAPOL supplicant state machines
 
3
 * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
 
4
 *
 
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.
 
8
 *
 
9
 * Alternatively, this software may be distributed under the terms of BSD
 
10
 * license.
 
11
 *
 
12
 * See README and COPYING for more details.
 
13
 */
 
14
 
 
15
#include "includes.h"
 
16
 
 
17
#include "common.h"
 
18
#include "eapol_supp_sm.h"
 
19
#include "eap_peer/eap.h"
 
20
#include "eloop.h"
 
21
#include "eapol_common.h"
 
22
#include "md5.h"
 
23
#include "rc4.h"
 
24
#include "state_machine.h"
 
25
#include "wpabuf.h"
 
26
 
 
27
#define STATE_MACHINE_DATA struct eapol_sm
 
28
#define STATE_MACHINE_DEBUG_PREFIX "EAPOL"
 
29
 
 
30
 
 
31
/* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
 
32
 
 
33
/**
 
34
 * struct eapol_sm - Internal data for EAPOL state machines
 
35
 */
 
36
struct eapol_sm {
 
37
        /* Timers */
 
38
        unsigned int authWhile;
 
39
        unsigned int heldWhile;
 
40
        unsigned int startWhen;
 
41
        unsigned int idleWhile; /* for EAP state machine */
 
42
        int timer_tick_enabled;
 
43
 
 
44
        /* Global variables */
 
45
        Boolean eapFail;
 
46
        Boolean eapolEap;
 
47
        Boolean eapSuccess;
 
48
        Boolean initialize;
 
49
        Boolean keyDone;
 
50
        Boolean keyRun;
 
51
        PortControl portControl;
 
52
        Boolean portEnabled;
 
53
        PortStatus suppPortStatus;  /* dot1xSuppControlledPortStatus */
 
54
        Boolean portValid;
 
55
        Boolean suppAbort;
 
56
        Boolean suppFail;
 
57
        Boolean suppStart;
 
58
        Boolean suppSuccess;
 
59
        Boolean suppTimeout;
 
60
 
 
61
        /* Supplicant PAE state machine */
 
62
        enum {
 
63
                SUPP_PAE_UNKNOWN = 0,
 
64
                SUPP_PAE_DISCONNECTED = 1,
 
65
                SUPP_PAE_LOGOFF = 2,
 
66
                SUPP_PAE_CONNECTING = 3,
 
67
                SUPP_PAE_AUTHENTICATING = 4,
 
68
                SUPP_PAE_AUTHENTICATED = 5,
 
69
                /* unused(6) */
 
70
                SUPP_PAE_HELD = 7,
 
71
                SUPP_PAE_RESTART = 8,
 
72
                SUPP_PAE_S_FORCE_AUTH = 9,
 
73
                SUPP_PAE_S_FORCE_UNAUTH = 10
 
74
        } SUPP_PAE_state; /* dot1xSuppPaeState */
 
75
        /* Variables */
 
76
        Boolean userLogoff;
 
77
        Boolean logoffSent;
 
78
        unsigned int startCount;
 
79
        Boolean eapRestart;
 
80
        PortControl sPortMode;
 
81
        /* Constants */
 
82
        unsigned int heldPeriod; /* dot1xSuppHeldPeriod */
 
83
        unsigned int startPeriod; /* dot1xSuppStartPeriod */
 
84
        unsigned int maxStart; /* dot1xSuppMaxStart */
 
85
 
 
86
        /* Key Receive state machine */
 
87
        enum {
 
88
                KEY_RX_UNKNOWN = 0,
 
89
                KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
 
90
        } KEY_RX_state;
 
91
        /* Variables */
 
92
        Boolean rxKey;
 
93
 
 
94
        /* Supplicant Backend state machine */
 
95
        enum {
 
96
                SUPP_BE_UNKNOWN = 0,
 
97
                SUPP_BE_INITIALIZE = 1,
 
98
                SUPP_BE_IDLE = 2,
 
99
                SUPP_BE_REQUEST = 3,
 
100
                SUPP_BE_RECEIVE = 4,
 
101
                SUPP_BE_RESPONSE = 5,
 
102
                SUPP_BE_FAIL = 6,
 
103
                SUPP_BE_TIMEOUT = 7, 
 
104
                SUPP_BE_SUCCESS = 8
 
105
        } SUPP_BE_state; /* dot1xSuppBackendPaeState */
 
106
        /* Variables */
 
107
        Boolean eapNoResp;
 
108
        Boolean eapReq;
 
109
        Boolean eapResp;
 
110
        /* Constants */
 
111
        unsigned int authPeriod; /* dot1xSuppAuthPeriod */
 
112
 
 
113
        /* Statistics */
 
114
        unsigned int dot1xSuppEapolFramesRx;
 
115
        unsigned int dot1xSuppEapolFramesTx;
 
116
        unsigned int dot1xSuppEapolStartFramesTx;
 
117
        unsigned int dot1xSuppEapolLogoffFramesTx;
 
118
        unsigned int dot1xSuppEapolRespFramesTx;
 
119
        unsigned int dot1xSuppEapolReqIdFramesRx;
 
120
        unsigned int dot1xSuppEapolReqFramesRx;
 
121
        unsigned int dot1xSuppInvalidEapolFramesRx;
 
122
        unsigned int dot1xSuppEapLengthErrorFramesRx;
 
123
        unsigned int dot1xSuppLastEapolFrameVersion;
 
124
        unsigned char dot1xSuppLastEapolFrameSource[6];
 
125
 
 
126
        /* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
 
127
        Boolean changed;
 
128
        struct eap_sm *eap;
 
129
        struct eap_peer_config *config;
 
130
        Boolean initial_req;
 
131
        u8 *last_rx_key;
 
132
        size_t last_rx_key_len;
 
133
        struct wpabuf *eapReqData; /* for EAP */
 
134
        Boolean altAccept; /* for EAP */
 
135
        Boolean altReject; /* for EAP */
 
136
        Boolean replay_counter_valid;
 
137
        u8 last_replay_counter[16];
 
138
        struct eapol_config conf;
 
139
        struct eapol_ctx *ctx;
 
140
        enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE }
 
141
                cb_status;
 
142
        Boolean cached_pmk;
 
143
 
 
144
        Boolean unicast_key_received, broadcast_key_received;
 
145
};
 
146
 
 
147
 
 
148
#define IEEE8021X_REPLAY_COUNTER_LEN 8
 
149
#define IEEE8021X_KEY_SIGN_LEN 16
 
150
#define IEEE8021X_KEY_IV_LEN 16
 
151
 
 
152
#define IEEE8021X_KEY_INDEX_FLAG 0x80
 
153
#define IEEE8021X_KEY_INDEX_MASK 0x03
 
154
 
 
155
#ifdef _MSC_VER
 
156
#pragma pack(push, 1)
 
157
#endif /* _MSC_VER */
 
158
 
 
159
struct ieee802_1x_eapol_key {
 
160
        u8 type;
 
161
        /* Note: key_length is unaligned */
 
162
        u8 key_length[2];
 
163
        /* does not repeat within the life of the keying material used to
 
164
         * encrypt the Key field; 64-bit NTP timestamp MAY be used here */
 
165
        u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN];
 
166
        u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */
 
167
        u8 key_index; /* key flag in the most significant bit:
 
168
                       * 0 = broadcast (default key),
 
169
                       * 1 = unicast (key mapping key); key index is in the
 
170
                       * 7 least significant bits */
 
171
        /* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as
 
172
         * the key */
 
173
        u8 key_signature[IEEE8021X_KEY_SIGN_LEN];
 
174
 
 
175
        /* followed by key: if packet body length = 44 + key length, then the
 
176
         * key field (of key_length bytes) contains the key in encrypted form;
 
177
         * if packet body length = 44, key field is absent and key_length
 
178
         * represents the number of least significant octets from
 
179
         * MS-MPPE-Send-Key attribute to be used as the keying material;
 
180
         * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
 
181
} STRUCT_PACKED;
 
182
 
 
183
#ifdef _MSC_VER
 
184
#pragma pack(pop)
 
185
#endif /* _MSC_VER */
 
186
 
 
187
 
 
188
static void eapol_sm_txLogoff(struct eapol_sm *sm);
 
189
static void eapol_sm_txStart(struct eapol_sm *sm);
 
190
static void eapol_sm_processKey(struct eapol_sm *sm);
 
191
static void eapol_sm_getSuppRsp(struct eapol_sm *sm);
 
192
static void eapol_sm_txSuppRsp(struct eapol_sm *sm);
 
193
static void eapol_sm_abortSupp(struct eapol_sm *sm);
 
194
static void eapol_sm_abort_cached(struct eapol_sm *sm);
 
195
static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx);
 
196
 
 
197
 
 
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)
 
201
{
 
202
        struct eapol_sm *sm = timeout_ctx;
 
203
 
 
204
        if (sm->authWhile > 0) {
 
205
                sm->authWhile--;
 
206
                if (sm->authWhile == 0)
 
207
                        wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0");
 
208
        }
 
209
        if (sm->heldWhile > 0) {
 
210
                sm->heldWhile--;
 
211
                if (sm->heldWhile == 0)
 
212
                        wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0");
 
213
        }
 
214
        if (sm->startWhen > 0) {
 
215
                sm->startWhen--;
 
216
                if (sm->startWhen == 0)
 
217
                        wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0");
 
218
        }
 
219
        if (sm->idleWhile > 0) {
 
220
                sm->idleWhile--;
 
221
                if (sm->idleWhile == 0)
 
222
                        wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0");
 
223
        }
 
224
 
 
225
        if (sm->authWhile | sm->heldWhile | sm->startWhen | sm->idleWhile) {
 
226
                eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx,
 
227
                                       sm);
 
228
        } else {
 
229
                wpa_printf(MSG_DEBUG, "EAPOL: disable timer tick");
 
230
                sm->timer_tick_enabled = 0;
 
231
        }
 
232
        eapol_sm_step(sm);
 
233
}
 
234
 
 
235
 
 
236
static void eapol_enable_timer_tick(struct eapol_sm *sm)
 
237
{
 
238
        if (sm->timer_tick_enabled)
 
239
                return;
 
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);
 
244
}
 
245
 
 
246
 
 
247
SM_STATE(SUPP_PAE, LOGOFF)
 
248
{
 
249
        SM_ENTRY(SUPP_PAE, LOGOFF);
 
250
        eapol_sm_txLogoff(sm);
 
251
        sm->logoffSent = TRUE;
 
252
        sm->suppPortStatus = Unauthorized;
 
253
}
 
254
 
 
255
 
 
256
SM_STATE(SUPP_PAE, DISCONNECTED)
 
257
{
 
258
        SM_ENTRY(SUPP_PAE, DISCONNECTED);
 
259
        sm->sPortMode = Auto;
 
260
        sm->startCount = 0;
 
261
        sm->logoffSent = FALSE;
 
262
        sm->suppPortStatus = Unauthorized;
 
263
        sm->suppAbort = TRUE;
 
264
 
 
265
        sm->unicast_key_received = FALSE;
 
266
        sm->broadcast_key_received = FALSE;
 
267
}
 
268
 
 
269
 
 
270
SM_STATE(SUPP_PAE, CONNECTING)
 
271
{
 
272
        int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING;
 
273
        SM_ENTRY(SUPP_PAE, CONNECTING);
 
274
        if (send_start) {
 
275
                sm->startWhen = sm->startPeriod;
 
276
                sm->startCount++;
 
277
        } else {
 
278
                /*
 
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.
 
284
                 */
 
285
                sm->startWhen = 3;
 
286
        }
 
287
        eapol_enable_timer_tick(sm);
 
288
        sm->eapolEap = FALSE;
 
289
        if (send_start)
 
290
                eapol_sm_txStart(sm);
 
291
}
 
292
 
 
293
 
 
294
SM_STATE(SUPP_PAE, AUTHENTICATING)
 
295
{
 
296
        SM_ENTRY(SUPP_PAE, AUTHENTICATING);
 
297
        sm->startCount = 0;
 
298
        sm->suppSuccess = FALSE;
 
299
        sm->suppFail = FALSE;
 
300
        sm->suppTimeout = FALSE;
 
301
        sm->keyRun = FALSE;
 
302
        sm->keyDone = FALSE;
 
303
        sm->suppStart = TRUE;
 
304
}
 
305
 
 
306
 
 
307
SM_STATE(SUPP_PAE, HELD)
 
308
{
 
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;
 
314
}
 
315
 
 
316
 
 
317
SM_STATE(SUPP_PAE, AUTHENTICATED)
 
318
{
 
319
        SM_ENTRY(SUPP_PAE, AUTHENTICATED);
 
320
        sm->suppPortStatus = Authorized;
 
321
        sm->cb_status = EAPOL_CB_SUCCESS;
 
322
}
 
323
 
 
324
 
 
325
SM_STATE(SUPP_PAE, RESTART)
 
326
{
 
327
        SM_ENTRY(SUPP_PAE, RESTART);
 
328
        sm->eapRestart = TRUE;
 
329
}
 
330
 
 
331
 
 
332
SM_STATE(SUPP_PAE, S_FORCE_AUTH)
 
333
{
 
334
        SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
 
335
        sm->suppPortStatus = Authorized;
 
336
        sm->sPortMode = ForceAuthorized;
 
337
}
 
338
 
 
339
 
 
340
SM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
 
341
{
 
342
        SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
 
343
        sm->suppPortStatus = Unauthorized;
 
344
        sm->sPortMode = ForceUnauthorized;
 
345
        eapol_sm_txLogoff(sm);
 
346
}
 
347
 
 
348
 
 
349
SM_STEP(SUPP_PAE)
 
350
{
 
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:
 
368
                break;
 
369
        case SUPP_PAE_LOGOFF:
 
370
                if (!sm->userLogoff)
 
371
                        SM_ENTER(SUPP_PAE, DISCONNECTED);
 
372
                break;
 
373
        case SUPP_PAE_DISCONNECTED:
 
374
                SM_ENTER(SUPP_PAE, CONNECTING);
 
375
                break;
 
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 &&
 
381
                         sm->portValid)
 
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 &&
 
389
                         !sm->portValid)
 
390
                        SM_ENTER(SUPP_PAE, HELD);
 
391
                break;
 
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 "
 
398
                                   "required");
 
399
                        sm->portValid = TRUE;
 
400
                        if (sm->ctx->eapol_done_cb)
 
401
                                sm->ctx->eapol_done_cb(sm->ctx->ctx);
 
402
                }
 
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);
 
409
                break;
 
410
        case SUPP_PAE_HELD:
 
411
                if (sm->heldWhile == 0)
 
412
                        SM_ENTER(SUPP_PAE, CONNECTING);
 
413
                else if (sm->eapolEap)
 
414
                        SM_ENTER(SUPP_PAE, RESTART);
 
415
                break;
 
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);
 
421
                break;
 
422
        case SUPP_PAE_RESTART:
 
423
                if (!sm->eapRestart)
 
424
                        SM_ENTER(SUPP_PAE, AUTHENTICATING);
 
425
                break;
 
426
        case SUPP_PAE_S_FORCE_AUTH:
 
427
                break;
 
428
        case SUPP_PAE_S_FORCE_UNAUTH:
 
429
                break;
 
430
        }
 
431
}
 
432
 
 
433
 
 
434
SM_STATE(KEY_RX, NO_KEY_RECEIVE)
 
435
{
 
436
        SM_ENTRY(KEY_RX, NO_KEY_RECEIVE);
 
437
}
 
438
 
 
439
 
 
440
SM_STATE(KEY_RX, KEY_RECEIVE)
 
441
{
 
442
        SM_ENTRY(KEY_RX, KEY_RECEIVE);
 
443
        eapol_sm_processKey(sm);
 
444
        sm->rxKey = FALSE;
 
445
}
 
446
 
 
447
 
 
448
SM_STEP(KEY_RX)
 
449
{
 
450
        if (sm->initialize || !sm->portEnabled)
 
451
                SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
 
452
        switch (sm->KEY_RX_state) {
 
453
        case KEY_RX_UNKNOWN:
 
454
                break;
 
455
        case KEY_RX_NO_KEY_RECEIVE:
 
456
                if (sm->rxKey)
 
457
                        SM_ENTER(KEY_RX, KEY_RECEIVE);
 
458
                break;
 
459
        case KEY_RX_KEY_RECEIVE:
 
460
                if (sm->rxKey)
 
461
                        SM_ENTER(KEY_RX, KEY_RECEIVE);
 
462
                break;
 
463
        }
 
464
}
 
465
 
 
466
 
 
467
SM_STATE(SUPP_BE, REQUEST)
 
468
{
 
469
        SM_ENTRY(SUPP_BE, REQUEST);
 
470
        sm->authWhile = 0;
 
471
        sm->eapReq = TRUE;
 
472
        eapol_sm_getSuppRsp(sm);
 
473
}
 
474
 
 
475
 
 
476
SM_STATE(SUPP_BE, RESPONSE)
 
477
{
 
478
        SM_ENTRY(SUPP_BE, RESPONSE);
 
479
        eapol_sm_txSuppRsp(sm);
 
480
        sm->eapResp = FALSE;
 
481
}
 
482
 
 
483
 
 
484
SM_STATE(SUPP_BE, SUCCESS)
 
485
{
 
486
        SM_ENTRY(SUPP_BE, SUCCESS);
 
487
        sm->keyRun = TRUE;
 
488
        sm->suppSuccess = TRUE;
 
489
 
 
490
        if (eap_key_available(sm->eap)) {
 
491
                /* New key received - clear IEEE 802.1X EAPOL-Key replay
 
492
                 * counter */
 
493
                sm->replay_counter_valid = FALSE;
 
494
        }
 
495
}
 
496
 
 
497
 
 
498
SM_STATE(SUPP_BE, FAIL)
 
499
{
 
500
        SM_ENTRY(SUPP_BE, FAIL);
 
501
        sm->suppFail = TRUE;
 
502
}
 
503
 
 
504
 
 
505
SM_STATE(SUPP_BE, TIMEOUT)
 
506
{
 
507
        SM_ENTRY(SUPP_BE, TIMEOUT);
 
508
        sm->suppTimeout = TRUE;
 
509
}
 
510
 
 
511
 
 
512
SM_STATE(SUPP_BE, IDLE)
 
513
{
 
514
        SM_ENTRY(SUPP_BE, IDLE);
 
515
        sm->suppStart = FALSE;
 
516
        sm->initial_req = TRUE;
 
517
}
 
518
 
 
519
 
 
520
SM_STATE(SUPP_BE, INITIALIZE)
 
521
{
 
522
        SM_ENTRY(SUPP_BE, INITIALIZE);
 
523
        eapol_sm_abortSupp(sm);
 
524
        sm->suppAbort = FALSE;
 
525
}
 
526
 
 
527
 
 
528
SM_STATE(SUPP_BE, RECEIVE)
 
529
{
 
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;
 
536
}
 
537
 
 
538
 
 
539
SM_STEP(SUPP_BE)
 
540
{
 
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:
 
545
                break;
 
546
        case SUPP_BE_REQUEST:
 
547
                /*
 
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.
 
560
                 */
 
561
                if (sm->eapResp && sm->eapNoResp) {
 
562
                        wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both "
 
563
                                   "eapResp and eapNoResp set?!");
 
564
                }
 
565
                if (sm->eapResp)
 
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);
 
573
                break;
 
574
        case SUPP_BE_RESPONSE:
 
575
                SM_ENTER(SUPP_BE, RECEIVE);
 
576
                break;
 
577
        case SUPP_BE_SUCCESS:
 
578
                SM_ENTER(SUPP_BE, IDLE);
 
579
                break;
 
580
        case SUPP_BE_FAIL:
 
581
                SM_ENTER(SUPP_BE, IDLE);
 
582
                break;
 
583
        case SUPP_BE_TIMEOUT:
 
584
                SM_ENTER(SUPP_BE, IDLE);
 
585
                break;
 
586
        case 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);
 
593
                break;
 
594
        case SUPP_BE_INITIALIZE:
 
595
                SM_ENTER(SUPP_BE, IDLE);
 
596
                break;
 
597
        case SUPP_BE_RECEIVE:
 
598
                if (sm->eapolEap)
 
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);
 
606
                break;
 
607
        }
 
608
}
 
609
 
 
610
 
 
611
static void eapol_sm_txLogoff(struct eapol_sm *sm)
 
612
{
 
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++;
 
618
}
 
619
 
 
620
 
 
621
static void eapol_sm_txStart(struct eapol_sm *sm)
 
622
{
 
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++;
 
628
}
 
629
 
 
630
 
 
631
#define IEEE8021X_ENCR_KEY_LEN 32
 
632
#define IEEE8021X_SIGN_KEY_LEN 32
 
633
 
 
634
struct eap_key_data {
 
635
        u8 encr_key[IEEE8021X_ENCR_KEY_LEN];
 
636
        u8 sign_key[IEEE8021X_SIGN_KEY_LEN];
 
637
};
 
638
 
 
639
 
 
640
static void eapol_sm_processKey(struct eapol_sm *sm)
 
641
{
 
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;
 
648
        u16 rx_key_length;
 
649
 
 
650
        wpa_printf(MSG_DEBUG, "EAPOL: processKey");
 
651
        if (sm->last_rx_key == NULL)
 
652
                return;
 
653
 
 
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");
 
658
                return;
 
659
        }
 
660
 
 
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");
 
665
                return;
 
666
        }
 
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);
 
672
 
 
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));
 
677
        if (res < 0) {
 
678
                wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for "
 
679
                           "decrypting EAPOL-Key keys");
 
680
                return;
 
681
        }
 
682
        if (res == 16) {
 
683
                /* LEAP derives only 16 bytes of keying material. */
 
684
                res = eapol_sm_get_key(sm, (u8 *) &keydata, 16);
 
685
                if (res) {
 
686
                        wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP "
 
687
                                   "master key for decrypting EAPOL-Key keys");
 
688
                        return;
 
689
                }
 
690
                sign_key_len = 16;
 
691
                encr_key_len = 16;
 
692
                os_memcpy(keydata.sign_key, keydata.encr_key, 16);
 
693
        } else if (res) {
 
694
                wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key "
 
695
                           "data for decrypting EAPOL-Key keys (res=%d)", res);
 
696
                return;
 
697
        }
 
698
 
 
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);
 
710
                return;
 
711
        }
 
712
 
 
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),
 
718
                 key->key_signature);
 
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 "
 
722
                           "EAPOL-Key packet");
 
723
                os_memcpy(key->key_signature, orig_key_sign,
 
724
                          IEEE8021X_KEY_SIGN_LEN);
 
725
                return;
 
726
        }
 
727
        wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
 
728
 
 
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);
 
733
                return;
 
734
        }
 
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,
 
738
                          encr_key_len);
 
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",
 
743
                                datakey, key_len);
 
744
        } else if (key_len == 0) {
 
745
                /*
 
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.
 
753
                 */
 
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",
 
758
                                datakey, key_len);
 
759
        } else {
 
760
                wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
 
761
                           "(key_length=%d)", key_len, rx_key_length);
 
762
                return;
 
763
        }
 
764
 
 
765
        sm->replay_counter_valid = TRUE;
 
766
        os_memcpy(sm->last_replay_counter, key->replay_counter,
 
767
                  IEEE8021X_REPLAY_COUNTER_LEN);
 
768
 
 
769
        wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
 
770
                   "len %d",
 
771
                   key->key_index & IEEE8021X_KEY_INDEX_FLAG ?
 
772
                   "unicast" : "broadcast",
 
773
                   key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len);
 
774
 
 
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 "
 
781
                           " driver.");
 
782
        } else {
 
783
                if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
 
784
                        sm->unicast_key_received = TRUE;
 
785
                else
 
786
                        sm->broadcast_key_received = TRUE;
 
787
 
 
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)))
 
792
                {
 
793
                        wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
 
794
                                   "frames received");
 
795
                        sm->portValid = TRUE;
 
796
                        if (sm->ctx->eapol_done_cb)
 
797
                                sm->ctx->eapol_done_cb(sm->ctx->ctx);
 
798
                }
 
799
        }
 
800
}
 
801
 
 
802
 
 
803
static void eapol_sm_getSuppRsp(struct eapol_sm *sm)
 
804
{
 
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
 
809
         * has finished. */
 
810
}
 
811
 
 
812
 
 
813
static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
 
814
{
 
815
        struct wpabuf *resp;
 
816
 
 
817
        wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
 
818
        resp = eap_get_eapRespData(sm->eap);
 
819
        if (resp == NULL) {
 
820
                wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
 
821
                           "not available");
 
822
                return;
 
823
        }
 
824
 
 
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),
 
828
                            wpabuf_len(resp));
 
829
 
 
830
        /* eapRespData is not used anymore, so free it here */
 
831
        wpabuf_free(resp);
 
832
 
 
833
        if (sm->initial_req)
 
834
                sm->dot1xSuppEapolReqIdFramesRx++;
 
835
        else
 
836
                sm->dot1xSuppEapolReqFramesRx++;
 
837
        sm->dot1xSuppEapolRespFramesTx++;
 
838
        sm->dot1xSuppEapolFramesTx++;
 
839
}
 
840
 
 
841
 
 
842
static void eapol_sm_abortSupp(struct eapol_sm *sm)
 
843
{
 
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);
 
851
}
 
852
 
 
853
 
 
854
static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
 
855
{
 
856
        eapol_sm_step(timeout_ctx);
 
857
}
 
858
 
 
859
 
 
860
/**
 
861
 * eapol_sm_step - EAPOL state machine step function
 
862
 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
 
863
 *
 
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.
 
867
 */
 
868
void eapol_sm_step(struct eapol_sm *sm)
 
869
{
 
870
        int i;
 
871
 
 
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++) {
 
877
                sm->changed = FALSE;
 
878
                SM_STEP_RUN(SUPP_PAE);
 
879
                SM_STEP_RUN(KEY_RX);
 
880
                SM_STEP_RUN(SUPP_BE);
 
881
                if (eap_peer_sm_step(sm->eap))
 
882
                        sm->changed = TRUE;
 
883
                if (!sm->changed)
 
884
                        break;
 
885
        }
 
886
 
 
887
        if (sm->changed) {
 
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);
 
892
        }
 
893
 
 
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);
 
898
        }
 
899
}
 
900
 
 
901
 
 
902
#ifdef CONFIG_CTRL_IFACE
 
903
static const char *eapol_supp_pae_state(int state)
 
904
{
 
905
        switch (state) {
 
906
        case SUPP_PAE_LOGOFF:
 
907
                return "LOGOFF";
 
908
        case SUPP_PAE_DISCONNECTED:
 
909
                return "DISCONNECTED";
 
910
        case SUPP_PAE_CONNECTING:
 
911
                return "CONNECTING";
 
912
        case SUPP_PAE_AUTHENTICATING:
 
913
                return "AUTHENTICATING";
 
914
        case SUPP_PAE_HELD:
 
915
                return "HELD";
 
916
        case SUPP_PAE_AUTHENTICATED:
 
917
                return "AUTHENTICATED";
 
918
        case SUPP_PAE_RESTART:
 
919
                return "RESTART";
 
920
        default:
 
921
                return "UNKNOWN";
 
922
        }
 
923
}
 
924
 
 
925
 
 
926
static const char *eapol_supp_be_state(int state)
 
927
{
 
928
        switch (state) {
 
929
        case SUPP_BE_REQUEST:
 
930
                return "REQUEST";
 
931
        case SUPP_BE_RESPONSE:
 
932
                return "RESPONSE";
 
933
        case SUPP_BE_SUCCESS:
 
934
                return "SUCCESS";
 
935
        case SUPP_BE_FAIL:
 
936
                return "FAIL";
 
937
        case SUPP_BE_TIMEOUT:
 
938
                return "TIMEOUT";
 
939
        case SUPP_BE_IDLE:
 
940
                return "IDLE";
 
941
        case SUPP_BE_INITIALIZE:
 
942
                return "INITIALIZE";
 
943
        case SUPP_BE_RECEIVE:
 
944
                return "RECEIVE";
 
945
        default:
 
946
                return "UNKNOWN";
 
947
        }
 
948
}
 
949
 
 
950
 
 
951
static const char * eapol_port_status(PortStatus status)
 
952
{
 
953
        if (status == Authorized)
 
954
                return "Authorized";
 
955
        else
 
956
                return "Unauthorized";
 
957
}
 
958
#endif /* CONFIG_CTRL_IFACE */
 
959
 
 
960
 
 
961
#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
 
962
static const char * eapol_port_control(PortControl ctrl)
 
963
{
 
964
        switch (ctrl) {
 
965
        case Auto:
 
966
                return "Auto";
 
967
        case ForceUnauthorized:
 
968
                return "ForceUnauthorized";
 
969
        case ForceAuthorized:
 
970
                return "ForceAuthorized";
 
971
        default:
 
972
                return "Unknown";
 
973
        }
 
974
}
 
975
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
 
976
 
 
977
 
 
978
/**
 
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
 
985
 *
 
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).
 
988
 */
 
989
void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
 
990
                        int startPeriod, int maxStart)
 
991
{
 
992
        if (sm == NULL)
 
993
                return;
 
994
        if (heldPeriod >= 0)
 
995
                sm->heldPeriod = heldPeriod;
 
996
        if (authPeriod >= 0)
 
997
                sm->authPeriod = authPeriod;
 
998
        if (startPeriod >= 0)
 
999
                sm->startPeriod = startPeriod;
 
1000
        if (maxStart >= 0)
 
1001
                sm->maxStart = maxStart;
 
1002
}
 
1003
 
 
1004
 
 
1005
#ifdef CONFIG_CTRL_IFACE
 
1006
/**
 
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.
 
1013
 *
 
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.
 
1018
 */
 
1019
int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
 
1020
                        int verbose)
 
1021
{
 
1022
        int len, ret;
 
1023
        if (sm == NULL)
 
1024
                return 0;
 
1025
 
 
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)
 
1032
                return 0;
 
1033
 
 
1034
        if (verbose) {
 
1035
                ret = os_snprintf(buf + len, buflen - len,
 
1036
                                  "heldPeriod=%u\n"
 
1037
                                  "authPeriod=%u\n"
 
1038
                                  "startPeriod=%u\n"
 
1039
                                  "maxStart=%u\n"
 
1040
                                  "portControl=%s\n"
 
1041
                                  "Supplicant Backend state=%s\n",
 
1042
                                  sm->heldPeriod,
 
1043
                                  sm->authPeriod,
 
1044
                                  sm->startPeriod,
 
1045
                                  sm->maxStart,
 
1046
                                  eapol_port_control(sm->portControl),
 
1047
                                  eapol_supp_be_state(sm->SUPP_BE_state));
 
1048
                if (ret < 0 || (size_t) ret >= buflen - len)
 
1049
                        return len;
 
1050
                len += ret;
 
1051
        }
 
1052
 
 
1053
        len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
 
1054
 
 
1055
        return len;
 
1056
}
 
1057
 
 
1058
 
 
1059
/**
 
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.
 
1065
 *
 
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
 
1069
 * fit the buffer.
 
1070
 */
 
1071
int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
 
1072
{
 
1073
        size_t len;
 
1074
        int ret;
 
1075
 
 
1076
        if (sm == NULL)
 
1077
                return 0;
 
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",
 
1086
                          sm->SUPP_PAE_state,
 
1087
                          sm->heldPeriod,
 
1088
                          sm->authPeriod,
 
1089
                          sm->startPeriod,
 
1090
                          sm->maxStart,
 
1091
                          sm->suppPortStatus == Authorized ?
 
1092
                          "Authorized" : "Unauthorized",
 
1093
                          sm->SUPP_BE_state);
 
1094
 
 
1095
        if (ret < 0 || (size_t) ret >= buflen)
 
1096
                return 0;
 
1097
        len = ret;
 
1098
 
 
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));
 
1122
 
 
1123
        if (ret < 0 || (size_t) ret >= buflen - len)
 
1124
                return len;
 
1125
        len += ret;
 
1126
 
 
1127
        return len;
 
1128
}
 
1129
#endif /* CONFIG_CTRL_IFACE */
 
1130
 
 
1131
 
 
1132
/**
 
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,
 
1139
 * -1 failure
 
1140
 */
 
1141
int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
 
1142
                      size_t len)
 
1143
{
 
1144
        const struct ieee802_1x_hdr *hdr;
 
1145
        const struct ieee802_1x_eapol_key *key;
 
1146
        int data_len;
 
1147
        int res = 1;
 
1148
        size_t plen;
 
1149
 
 
1150
        if (sm == NULL)
 
1151
                return 0;
 
1152
        sm->dot1xSuppEapolFramesRx++;
 
1153
        if (len < sizeof(*hdr)) {
 
1154
                sm->dot1xSuppInvalidEapolFramesRx++;
 
1155
                return 0;
 
1156
        }
 
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 */
 
1162
        }
 
1163
        plen = be_to_host16(hdr->length);
 
1164
        if (plen > len - sizeof(*hdr)) {
 
1165
                sm->dot1xSuppEapLengthErrorFramesRx++;
 
1166
                return 0;
 
1167
        }
 
1168
        data_len = plen + sizeof(*hdr);
 
1169
 
 
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.
 
1176
                         */
 
1177
                        eapol_sm_abort_cached(sm);
 
1178
                }
 
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 "
 
1183
                                   "frame");
 
1184
                        sm->eapolEap = TRUE;
 
1185
                        eapol_sm_step(sm);
 
1186
                }
 
1187
                break;
 
1188
        case IEEE802_1X_TYPE_EAPOL_KEY:
 
1189
                if (plen < sizeof(*key)) {
 
1190
                        wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key "
 
1191
                                   "frame received");
 
1192
                        break;
 
1193
                }
 
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");
 
1200
                        res = 0;
 
1201
                        break;
 
1202
                }
 
1203
                if (key->type != EAPOL_KEY_TYPE_RC4) {
 
1204
                        wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown "
 
1205
                                   "EAPOL-Key type %d", key->type);
 
1206
                        break;
 
1207
                }
 
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 "
 
1212
                                   "frame");
 
1213
                        os_memcpy(sm->last_rx_key, buf, data_len);
 
1214
                        sm->last_rx_key_len = data_len;
 
1215
                        sm->rxKey = TRUE;
 
1216
                        eapol_sm_step(sm);
 
1217
                }
 
1218
                break;
 
1219
        default:
 
1220
                wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
 
1221
                           hdr->type);
 
1222
                sm->dot1xSuppInvalidEapolFramesRx++;
 
1223
                break;
 
1224
        }
 
1225
 
 
1226
        return res;
 
1227
}
 
1228
 
 
1229
 
 
1230
/**
 
1231
 * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet
 
1232
 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
 
1233
 *
 
1234
 * Notify EAPOL state machine about transmitted EAPOL packet from an external
 
1235
 * component, e.g., WPA. This will update the statistics.
 
1236
 */
 
1237
void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
 
1238
{
 
1239
        if (sm)
 
1240
                sm->dot1xSuppEapolFramesTx++;
 
1241
}
 
1242
 
 
1243
 
 
1244
/**
 
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
 
1248
 *
 
1249
 * Notify EAPOL state machine about new portEnabled value.
 
1250
 */
 
1251
void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
 
1252
{
 
1253
        if (sm == NULL)
 
1254
                return;
 
1255
        wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
 
1256
                   "portEnabled=%d", enabled);
 
1257
        sm->portEnabled = enabled;
 
1258
        eapol_sm_step(sm);
 
1259
}
 
1260
 
 
1261
 
 
1262
/**
 
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
 
1266
 *
 
1267
 * Notify EAPOL state machine about new portValid value.
 
1268
 */
 
1269
void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
 
1270
{
 
1271
        if (sm == NULL)
 
1272
                return;
 
1273
        wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
 
1274
                   "portValid=%d", valid);
 
1275
        sm->portValid = valid;
 
1276
        eapol_sm_step(sm);
 
1277
}
 
1278
 
 
1279
 
 
1280
/**
 
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
 
1284
 *
 
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.
 
1287
 *
 
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.
 
1290
 */
 
1291
void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
 
1292
{
 
1293
        if (sm == NULL)
 
1294
                return;
 
1295
        wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
 
1296
                   "EAP success=%d", success);
 
1297
        sm->eapSuccess = success;
 
1298
        sm->altAccept = success;
 
1299
        if (success)
 
1300
                eap_notify_success(sm->eap);
 
1301
        eapol_sm_step(sm);
 
1302
}
 
1303
 
 
1304
 
 
1305
/**
 
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
 
1309
 *
 
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.
 
1312
 */
 
1313
void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
 
1314
{
 
1315
        if (sm == NULL)
 
1316
                return;
 
1317
        wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
 
1318
                   "EAP fail=%d", fail);
 
1319
        sm->eapFail = fail;
 
1320
        sm->altReject = fail;
 
1321
        eapol_sm_step(sm);
 
1322
}
 
1323
 
 
1324
 
 
1325
/**
 
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
 
1330
 *
 
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
 
1335
 * skipped.
 
1336
 */
 
1337
void eapol_sm_notify_config(struct eapol_sm *sm,
 
1338
                            struct eap_peer_config *config,
 
1339
                            const struct eapol_config *conf)
 
1340
{
 
1341
        if (sm == NULL)
 
1342
                return;
 
1343
 
 
1344
        sm->config = config;
 
1345
 
 
1346
        if (conf == NULL)
 
1347
                return;
 
1348
 
 
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;
 
1352
        if (sm->eap) {
 
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);
 
1356
        }
 
1357
}
 
1358
 
 
1359
 
 
1360
/**
 
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.
 
1367
 *
 
1368
 * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key
 
1369
 * is available only after a successful authentication.
 
1370
 */
 
1371
int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
 
1372
{
 
1373
        const u8 *eap_key;
 
1374
        size_t eap_len;
 
1375
 
 
1376
        if (sm == NULL || !eap_key_available(sm->eap)) {
 
1377
                wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
 
1378
                return -1;
 
1379
        }
 
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");
 
1383
                return -1;
 
1384
        }
 
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);
 
1389
                return eap_len;
 
1390
        }
 
1391
        os_memcpy(key, eap_key, len);
 
1392
        wpa_printf(MSG_DEBUG, "EAPOL: Successfully fetched key (len=%lu)",
 
1393
                   (unsigned long) len);
 
1394
        return 0;
 
1395
}
 
1396
 
 
1397
 
 
1398
/**
 
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
 
1402
 *
 
1403
 * Notify EAPOL state machines that user requested logon/logoff.
 
1404
 */
 
1405
void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
 
1406
{
 
1407
        if (sm) {
 
1408
                sm->userLogoff = logoff;
 
1409
                eapol_sm_step(sm);
 
1410
        }
 
1411
}
 
1412
 
 
1413
 
 
1414
/**
 
1415
 * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching
 
1416
 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
 
1417
 *
 
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.
 
1420
 */
 
1421
void eapol_sm_notify_cached(struct eapol_sm *sm)
 
1422
{
 
1423
        if (sm == NULL)
 
1424
                return;
 
1425
        sm->SUPP_PAE_state = SUPP_PAE_AUTHENTICATED;
 
1426
        sm->suppPortStatus = Authorized;
 
1427
        eap_notify_success(sm->eap);
 
1428
        eapol_sm_step(sm);
 
1429
}
 
1430
 
 
1431
 
 
1432
/**
 
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
 
1436
 *
 
1437
 * Notify EAPOL state machines whether PMKSA caching is used.
 
1438
 */
 
1439
void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt)
 
1440
{
 
1441
        if (sm == NULL)
 
1442
                return;
 
1443
        if (attempt) {
 
1444
                wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
 
1445
                sm->cached_pmk = TRUE;
 
1446
        } else {
 
1447
                wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA");
 
1448
                sm->cached_pmk = FALSE;
 
1449
        }
 
1450
}
 
1451
 
 
1452
 
 
1453
static void eapol_sm_abort_cached(struct eapol_sm *sm)
 
1454
{
 
1455
        wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, "
 
1456
                   "doing full EAP authentication");
 
1457
        if (sm == NULL)
 
1458
                return;
 
1459
        sm->cached_pmk = FALSE;
 
1460
        sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
 
1461
        sm->suppPortStatus = Unauthorized;
 
1462
 
 
1463
        /* Make sure we do not start sending EAPOL-Start frames first, but
 
1464
         * instead move to RESTART state to start EAPOL authentication. */
 
1465
        sm->startWhen = 3;
 
1466
        eapol_enable_timer_tick(sm);
 
1467
 
 
1468
        if (sm->ctx->aborted_cached)
 
1469
                sm->ctx->aborted_cached(sm->ctx->ctx);
 
1470
}
 
1471
 
 
1472
 
 
1473
/**
 
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
 
1477
 *
 
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.
 
1480
 */
 
1481
void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
 
1482
{
 
1483
        if (sm) {
 
1484
                sm->ctx->scard_ctx = ctx;
 
1485
                eap_register_scard_ctx(sm->eap, ctx);
 
1486
        }
 
1487
}
 
1488
 
 
1489
 
 
1490
/**
 
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
 
1494
 *
 
1495
 * Notify EAPOL state machines that portControl variable has changed.
 
1496
 */
 
1497
void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
 
1498
{
 
1499
        if (sm == NULL)
 
1500
                return;
 
1501
        wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
 
1502
                   "portControl=%s", eapol_port_control(portControl));
 
1503
        sm->portControl = portControl;
 
1504
        eapol_sm_step(sm);
 
1505
}
 
1506
 
 
1507
 
 
1508
/**
 
1509
 * eapol_sm_notify_ctrl_attached - Notification of attached monitor
 
1510
 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
 
1511
 *
 
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.
 
1514
 */
 
1515
void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
 
1516
{
 
1517
        if (sm == NULL)
 
1518
                return;
 
1519
        eap_sm_notify_ctrl_attached(sm->eap);
 
1520
}
 
1521
 
 
1522
 
 
1523
/**
 
1524
 * eapol_sm_notify_ctrl_response - Notification of received user input
 
1525
 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
 
1526
 *
 
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.
 
1529
 */
 
1530
void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
 
1531
{
 
1532
        if (sm == NULL)
 
1533
                return;
 
1534
        if (sm->eapReqData && !sm->eapReq) {
 
1535
                wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
 
1536
                           "input) notification - retrying pending EAP "
 
1537
                           "Request");
 
1538
                sm->eapolEap = TRUE;
 
1539
                sm->eapReq = TRUE;
 
1540
                eapol_sm_step(sm);
 
1541
        }
 
1542
}
 
1543
 
 
1544
 
 
1545
/**
 
1546
 * eapol_sm_request_reauth - Request reauthentication
 
1547
 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
 
1548
 *
 
1549
 * This function can be used to request EAPOL reauthentication, e.g., when the
 
1550
 * current PMKSA entry is nearing expiration.
 
1551
 */
 
1552
void eapol_sm_request_reauth(struct eapol_sm *sm)
 
1553
{
 
1554
        if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
 
1555
                return;
 
1556
        eapol_sm_txStart(sm);
 
1557
}
 
1558
 
 
1559
 
 
1560
/**
 
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())
 
1565
 *
 
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
 
1568
 * messages.
 
1569
 */
 
1570
void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm)
 
1571
{
 
1572
        if (sm == NULL)
 
1573
                return;
 
1574
        eap_notify_lower_layer_success(sm->eap);
 
1575
        if (!in_eapol_sm)
 
1576
                eapol_sm_step(sm);
 
1577
}
 
1578
 
 
1579
 
 
1580
/**
 
1581
 * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid
 
1582
 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
 
1583
 */
 
1584
void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
 
1585
{
 
1586
        if (sm)
 
1587
                eap_invalidate_cached_session(sm->eap);
 
1588
}
 
1589
 
 
1590
 
 
1591
static struct eap_peer_config * eapol_sm_get_config(void *ctx)
 
1592
{
 
1593
        struct eapol_sm *sm = ctx;
 
1594
        return sm ? sm->config : NULL;
 
1595
}
 
1596
 
 
1597
 
 
1598
static struct wpabuf * eapol_sm_get_eapReqData(void *ctx)
 
1599
{
 
1600
        struct eapol_sm *sm = ctx;
 
1601
        if (sm == NULL || sm->eapReqData == NULL)
 
1602
                return NULL;
 
1603
 
 
1604
        return sm->eapReqData;
 
1605
}
 
1606
 
 
1607
 
 
1608
static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
 
1609
{
 
1610
        struct eapol_sm *sm = ctx;
 
1611
        if (sm == NULL)
 
1612
                return FALSE;
 
1613
        switch (variable) {
 
1614
        case EAPOL_eapSuccess:
 
1615
                return sm->eapSuccess;
 
1616
        case EAPOL_eapRestart:
 
1617
                return sm->eapRestart;
 
1618
        case EAPOL_eapFail:
 
1619
                return sm->eapFail;
 
1620
        case EAPOL_eapResp:
 
1621
                return sm->eapResp;
 
1622
        case EAPOL_eapNoResp:
 
1623
                return sm->eapNoResp;
 
1624
        case EAPOL_eapReq:
 
1625
                return sm->eapReq;
 
1626
        case EAPOL_portEnabled:
 
1627
                return sm->portEnabled;
 
1628
        case EAPOL_altAccept:
 
1629
                return sm->altAccept;
 
1630
        case EAPOL_altReject:
 
1631
                return sm->altReject;
 
1632
        }
 
1633
        return FALSE;
 
1634
}
 
1635
 
 
1636
 
 
1637
static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
 
1638
                              Boolean value)
 
1639
{
 
1640
        struct eapol_sm *sm = ctx;
 
1641
        if (sm == NULL)
 
1642
                return;
 
1643
        switch (variable) {
 
1644
        case EAPOL_eapSuccess:
 
1645
                sm->eapSuccess = value;
 
1646
                break;
 
1647
        case EAPOL_eapRestart:
 
1648
                sm->eapRestart = value;
 
1649
                break;
 
1650
        case EAPOL_eapFail:
 
1651
                sm->eapFail = value;
 
1652
                break;
 
1653
        case EAPOL_eapResp:
 
1654
                sm->eapResp = value;
 
1655
                break;
 
1656
        case EAPOL_eapNoResp:
 
1657
                sm->eapNoResp = value;
 
1658
                break;
 
1659
        case EAPOL_eapReq:
 
1660
                sm->eapReq = value;
 
1661
                break;
 
1662
        case EAPOL_portEnabled:
 
1663
                sm->portEnabled = value;
 
1664
                break;
 
1665
        case EAPOL_altAccept:
 
1666
                sm->altAccept = value;
 
1667
                break;
 
1668
        case EAPOL_altReject:
 
1669
                sm->altReject = value;
 
1670
                break;
 
1671
        }
 
1672
}
 
1673
 
 
1674
 
 
1675
static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable)
 
1676
{
 
1677
        struct eapol_sm *sm = ctx;
 
1678
        if (sm == NULL)
 
1679
                return 0;
 
1680
        switch (variable) {
 
1681
        case EAPOL_idleWhile:
 
1682
                return sm->idleWhile;
 
1683
        }
 
1684
        return 0;
 
1685
}
 
1686
 
 
1687
 
 
1688
static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
 
1689
                             unsigned int value)
 
1690
{
 
1691
        struct eapol_sm *sm = ctx;
 
1692
        if (sm == NULL)
 
1693
                return;
 
1694
        switch (variable) {
 
1695
        case EAPOL_idleWhile:
 
1696
                sm->idleWhile = value;
 
1697
                eapol_enable_timer_tick(sm);
 
1698
                break;
 
1699
        }
 
1700
}
 
1701
 
 
1702
 
 
1703
static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
 
1704
{
 
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 */
 
1710
}
 
1711
 
 
1712
 
 
1713
static const struct wpa_config_blob *
 
1714
eapol_sm_get_config_blob(void *ctx, const char *name)
 
1715
{
 
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);
 
1720
        else
 
1721
                return NULL;
 
1722
#else /* CONFIG_NO_CONFIG_BLOBS */
 
1723
        return NULL;
 
1724
#endif /* CONFIG_NO_CONFIG_BLOBS */
 
1725
}
 
1726
 
 
1727
 
 
1728
static void eapol_sm_notify_pending(void *ctx)
 
1729
{
 
1730
        struct eapol_sm *sm = ctx;
 
1731
        if (sm == NULL)
 
1732
                return;
 
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;
 
1737
                sm->eapReq = TRUE;
 
1738
                eapol_sm_step(sm);
 
1739
        }
 
1740
}
 
1741
 
 
1742
 
 
1743
#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
 
1744
static void eapol_sm_eap_param_needed(void *ctx, const char *field,
 
1745
                                      const char *txt)
 
1746
{
 
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);
 
1751
}
 
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 */
 
1755
 
 
1756
 
 
1757
static struct eapol_callbacks eapol_cb =
 
1758
{
 
1759
        eapol_sm_get_config,
 
1760
        eapol_sm_get_bool,
 
1761
        eapol_sm_set_bool,
 
1762
        eapol_sm_get_int,
 
1763
        eapol_sm_set_int,
 
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
 
1769
};
 
1770
 
 
1771
 
 
1772
/**
 
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
 
1777
 *
 
1778
 * Allocate and initialize an EAPOL state machine.
 
1779
 */
 
1780
struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
 
1781
{
 
1782
        struct eapol_sm *sm;
 
1783
        struct eap_config conf;
 
1784
        sm = os_zalloc(sizeof(*sm));
 
1785
        if (sm == NULL)
 
1786
                return NULL;
 
1787
        sm->ctx = ctx;
 
1788
 
 
1789
        sm->portControl = Auto;
 
1790
 
 
1791
        /* Supplicant PAE state machine */
 
1792
        sm->heldPeriod = 60;
 
1793
        sm->startPeriod = 30;
 
1794
        sm->maxStart = 3;
 
1795
 
 
1796
        /* Supplicant Backend state machine */
 
1797
        sm->authPeriod = 30;
 
1798
 
 
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 */
 
1805
 
 
1806
        sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
 
1807
        if (sm->eap == NULL) {
 
1808
                os_free(sm);
 
1809
                return NULL;
 
1810
        }
 
1811
 
 
1812
        /* Initialize EAPOL state machines */
 
1813
        sm->initialize = TRUE;
 
1814
        eapol_sm_step(sm);
 
1815
        sm->initialize = FALSE;
 
1816
        eapol_sm_step(sm);
 
1817
 
 
1818
        sm->timer_tick_enabled = 1;
 
1819
        eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
 
1820
 
 
1821
        return sm;
 
1822
}
 
1823
 
 
1824
 
 
1825
/**
 
1826
 * eapol_sm_deinit - Deinitialize EAPOL state machine
 
1827
 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
 
1828
 *
 
1829
 * Deinitialize and free EAPOL state machine.
 
1830
 */
 
1831
void eapol_sm_deinit(struct eapol_sm *sm)
 
1832
{
 
1833
        if (sm == NULL)
 
1834
                return;
 
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);
 
1840
        os_free(sm->ctx);
 
1841
        os_free(sm);
 
1842
}