Branch data Line data Source code
1 : : /*
2 : : * EAPOL supplicant state machines
3 : : * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
4 : : *
5 : : * This software may be distributed under the terms of the BSD license.
6 : : * See README for more details.
7 : : */
8 : :
9 : : #include "includes.h"
10 : :
11 : : #include "common.h"
12 : : #include "state_machine.h"
13 : : #include "wpabuf.h"
14 : : #include "eloop.h"
15 : : #include "crypto/crypto.h"
16 : : #include "crypto/md5.h"
17 : : #include "common/eapol_common.h"
18 : : #include "eap_peer/eap.h"
19 : : #include "eap_peer/eap_proxy.h"
20 : : #include "eapol_supp_sm.h"
21 : :
22 : : #define STATE_MACHINE_DATA struct eapol_sm
23 : : #define STATE_MACHINE_DEBUG_PREFIX "EAPOL"
24 : :
25 : :
26 : : /* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
27 : :
28 : : /**
29 : : * struct eapol_sm - Internal data for EAPOL state machines
30 : : */
31 : : struct eapol_sm {
32 : : /* Timers */
33 : : unsigned int authWhile;
34 : : unsigned int heldWhile;
35 : : unsigned int startWhen;
36 : : unsigned int idleWhile; /* for EAP state machine */
37 : : int timer_tick_enabled;
38 : :
39 : : /* Global variables */
40 : : Boolean eapFail;
41 : : Boolean eapolEap;
42 : : Boolean eapSuccess;
43 : : Boolean initialize;
44 : : Boolean keyDone;
45 : : Boolean keyRun;
46 : : PortControl portControl;
47 : : Boolean portEnabled;
48 : : PortStatus suppPortStatus; /* dot1xSuppControlledPortStatus */
49 : : Boolean portValid;
50 : : Boolean suppAbort;
51 : : Boolean suppFail;
52 : : Boolean suppStart;
53 : : Boolean suppSuccess;
54 : : Boolean suppTimeout;
55 : :
56 : : /* Supplicant PAE state machine */
57 : : enum {
58 : : SUPP_PAE_UNKNOWN = 0,
59 : : SUPP_PAE_DISCONNECTED = 1,
60 : : SUPP_PAE_LOGOFF = 2,
61 : : SUPP_PAE_CONNECTING = 3,
62 : : SUPP_PAE_AUTHENTICATING = 4,
63 : : SUPP_PAE_AUTHENTICATED = 5,
64 : : /* unused(6) */
65 : : SUPP_PAE_HELD = 7,
66 : : SUPP_PAE_RESTART = 8,
67 : : SUPP_PAE_S_FORCE_AUTH = 9,
68 : : SUPP_PAE_S_FORCE_UNAUTH = 10
69 : : } SUPP_PAE_state; /* dot1xSuppPaeState */
70 : : /* Variables */
71 : : Boolean userLogoff;
72 : : Boolean logoffSent;
73 : : unsigned int startCount;
74 : : Boolean eapRestart;
75 : : PortControl sPortMode;
76 : : /* Constants */
77 : : unsigned int heldPeriod; /* dot1xSuppHeldPeriod */
78 : : unsigned int startPeriod; /* dot1xSuppStartPeriod */
79 : : unsigned int maxStart; /* dot1xSuppMaxStart */
80 : :
81 : : /* Key Receive state machine */
82 : : enum {
83 : : KEY_RX_UNKNOWN = 0,
84 : : KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
85 : : } KEY_RX_state;
86 : : /* Variables */
87 : : Boolean rxKey;
88 : :
89 : : /* Supplicant Backend state machine */
90 : : enum {
91 : : SUPP_BE_UNKNOWN = 0,
92 : : SUPP_BE_INITIALIZE = 1,
93 : : SUPP_BE_IDLE = 2,
94 : : SUPP_BE_REQUEST = 3,
95 : : SUPP_BE_RECEIVE = 4,
96 : : SUPP_BE_RESPONSE = 5,
97 : : SUPP_BE_FAIL = 6,
98 : : SUPP_BE_TIMEOUT = 7,
99 : : SUPP_BE_SUCCESS = 8
100 : : } SUPP_BE_state; /* dot1xSuppBackendPaeState */
101 : : /* Variables */
102 : : Boolean eapNoResp;
103 : : Boolean eapReq;
104 : : Boolean eapResp;
105 : : /* Constants */
106 : : unsigned int authPeriod; /* dot1xSuppAuthPeriod */
107 : :
108 : : /* Statistics */
109 : : unsigned int dot1xSuppEapolFramesRx;
110 : : unsigned int dot1xSuppEapolFramesTx;
111 : : unsigned int dot1xSuppEapolStartFramesTx;
112 : : unsigned int dot1xSuppEapolLogoffFramesTx;
113 : : unsigned int dot1xSuppEapolRespFramesTx;
114 : : unsigned int dot1xSuppEapolReqIdFramesRx;
115 : : unsigned int dot1xSuppEapolReqFramesRx;
116 : : unsigned int dot1xSuppInvalidEapolFramesRx;
117 : : unsigned int dot1xSuppEapLengthErrorFramesRx;
118 : : unsigned int dot1xSuppLastEapolFrameVersion;
119 : : unsigned char dot1xSuppLastEapolFrameSource[6];
120 : :
121 : : /* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
122 : : Boolean changed;
123 : : struct eap_sm *eap;
124 : : struct eap_peer_config *config;
125 : : Boolean initial_req;
126 : : u8 *last_rx_key;
127 : : size_t last_rx_key_len;
128 : : struct wpabuf *eapReqData; /* for EAP */
129 : : Boolean altAccept; /* for EAP */
130 : : Boolean altReject; /* for EAP */
131 : : Boolean replay_counter_valid;
132 : : u8 last_replay_counter[16];
133 : : struct eapol_config conf;
134 : : struct eapol_ctx *ctx;
135 : : enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE }
136 : : cb_status;
137 : : Boolean cached_pmk;
138 : :
139 : : Boolean unicast_key_received, broadcast_key_received;
140 : : #ifdef CONFIG_EAP_PROXY
141 : : Boolean use_eap_proxy;
142 : : struct eap_proxy_sm *eap_proxy;
143 : : #endif /* CONFIG_EAP_PROXY */
144 : : };
145 : :
146 : :
147 : : static void eapol_sm_txLogoff(struct eapol_sm *sm);
148 : : static void eapol_sm_txStart(struct eapol_sm *sm);
149 : : static void eapol_sm_processKey(struct eapol_sm *sm);
150 : : static void eapol_sm_getSuppRsp(struct eapol_sm *sm);
151 : : static void eapol_sm_txSuppRsp(struct eapol_sm *sm);
152 : : static void eapol_sm_abortSupp(struct eapol_sm *sm);
153 : : static void eapol_sm_abort_cached(struct eapol_sm *sm);
154 : : static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx);
155 : : static void eapol_sm_set_port_authorized(struct eapol_sm *sm);
156 : : static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm);
157 : :
158 : :
159 : : /* Port Timers state machine - implemented as a function that will be called
160 : : * once a second as a registered event loop timeout */
161 : 297 : static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
162 : : {
163 : 297 : struct eapol_sm *sm = timeout_ctx;
164 : :
165 [ + + ]: 297 : if (sm->authWhile > 0) {
166 : 21 : sm->authWhile--;
167 [ - + ]: 21 : if (sm->authWhile == 0)
168 : 0 : wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0");
169 : : }
170 [ - + ]: 297 : if (sm->heldWhile > 0) {
171 : 0 : sm->heldWhile--;
172 [ # # ]: 0 : if (sm->heldWhile == 0)
173 : 0 : wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0");
174 : : }
175 [ + + ]: 297 : if (sm->startWhen > 0) {
176 : 107 : sm->startWhen--;
177 [ + + ]: 107 : if (sm->startWhen == 0)
178 : 105 : wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0");
179 : : }
180 [ + + ]: 297 : if (sm->idleWhile > 0) {
181 : 50 : sm->idleWhile--;
182 [ - + ]: 50 : if (sm->idleWhile == 0)
183 : 0 : wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0");
184 : : }
185 : :
186 [ + + ]: 297 : if (sm->authWhile | sm->heldWhile | sm->startWhen | sm->idleWhile) {
187 : 50 : eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx,
188 : : sm);
189 : : } else {
190 : 247 : wpa_printf(MSG_DEBUG, "EAPOL: disable timer tick");
191 : 247 : sm->timer_tick_enabled = 0;
192 : : }
193 : 297 : eapol_sm_step(sm);
194 : 297 : }
195 : :
196 : :
197 : 3010 : static void eapol_enable_timer_tick(struct eapol_sm *sm)
198 : : {
199 [ + + ]: 3010 : if (sm->timer_tick_enabled)
200 : 3010 : return;
201 : 229 : wpa_printf(MSG_DEBUG, "EAPOL: enable timer tick");
202 : 229 : sm->timer_tick_enabled = 1;
203 : 229 : eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
204 : 229 : eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
205 : : }
206 : :
207 : :
208 : 1 : SM_STATE(SUPP_PAE, LOGOFF)
209 : : {
210 [ + - ][ + - ]: 1 : SM_ENTRY(SUPP_PAE, LOGOFF);
211 : 1 : eapol_sm_txLogoff(sm);
212 : 1 : sm->logoffSent = TRUE;
213 : 1 : sm->suppPortStatus = Unauthorized;
214 : 1 : eapol_sm_set_port_unauthorized(sm);
215 : 1 : }
216 : :
217 : :
218 : 6507 : SM_STATE(SUPP_PAE, DISCONNECTED)
219 : : {
220 [ + + ][ + + ]: 6507 : SM_ENTRY(SUPP_PAE, DISCONNECTED);
221 : 6507 : sm->sPortMode = Auto;
222 : 6507 : sm->startCount = 0;
223 : 6507 : sm->logoffSent = FALSE;
224 : 6507 : sm->suppPortStatus = Unauthorized;
225 : 6507 : eapol_sm_set_port_unauthorized(sm);
226 : 6507 : sm->suppAbort = TRUE;
227 : :
228 : 6507 : sm->unicast_key_received = FALSE;
229 : 6507 : sm->broadcast_key_received = FALSE;
230 : :
231 : : /*
232 : : * IEEE Std 802.1X-2004 does not clear heldWhile here, but doing so
233 : : * allows the timer tick to be stopped more quickly when the port is
234 : : * not enabled. Since this variable is used only within HELD state,
235 : : * clearing it on initialization does not change actual state machine
236 : : * behavior.
237 : : */
238 : 6507 : sm->heldWhile = 0;
239 : 6507 : }
240 : :
241 : :
242 : 364 : SM_STATE(SUPP_PAE, CONNECTING)
243 : : {
244 : 364 : int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING;
245 [ - + ][ # # ]: 364 : SM_ENTRY(SUPP_PAE, CONNECTING);
246 [ + + ]: 364 : if (send_start) {
247 : 9 : sm->startWhen = sm->startPeriod;
248 : 9 : sm->startCount++;
249 : : } else {
250 : : /*
251 : : * Do not send EAPOL-Start immediately since in most cases,
252 : : * Authenticator is going to start authentication immediately
253 : : * after association and an extra EAPOL-Start is just going to
254 : : * delay authentication. Use a short timeout to send the first
255 : : * EAPOL-Start if Authenticator does not start authentication.
256 : : */
257 : : #ifdef CONFIG_WPS
258 : : /* Reduce latency on starting WPS negotiation. */
259 : 355 : sm->startWhen = 1;
260 : : #else /* CONFIG_WPS */
261 : : sm->startWhen = 3;
262 : : #endif /* CONFIG_WPS */
263 : : }
264 : 364 : eapol_enable_timer_tick(sm);
265 : 364 : sm->eapolEap = FALSE;
266 [ + + ]: 364 : if (send_start)
267 : 9 : eapol_sm_txStart(sm);
268 : 364 : }
269 : :
270 : :
271 : 376 : SM_STATE(SUPP_PAE, AUTHENTICATING)
272 : : {
273 [ - + ][ # # ]: 376 : SM_ENTRY(SUPP_PAE, AUTHENTICATING);
274 : 376 : sm->startCount = 0;
275 : 376 : sm->suppSuccess = FALSE;
276 : 376 : sm->suppFail = FALSE;
277 : 376 : sm->suppTimeout = FALSE;
278 : 376 : sm->keyRun = FALSE;
279 : 376 : sm->keyDone = FALSE;
280 : 376 : sm->suppStart = TRUE;
281 : 376 : }
282 : :
283 : :
284 : 95 : SM_STATE(SUPP_PAE, HELD)
285 : : {
286 [ - + ][ # # ]: 95 : SM_ENTRY(SUPP_PAE, HELD);
287 : 95 : sm->heldWhile = sm->heldPeriod;
288 : 95 : eapol_enable_timer_tick(sm);
289 : 95 : sm->suppPortStatus = Unauthorized;
290 : 95 : eapol_sm_set_port_unauthorized(sm);
291 : 95 : sm->cb_status = EAPOL_CB_FAILURE;
292 : 95 : }
293 : :
294 : :
295 : 274 : SM_STATE(SUPP_PAE, AUTHENTICATED)
296 : : {
297 [ - + ][ # # ]: 274 : SM_ENTRY(SUPP_PAE, AUTHENTICATED);
298 : 274 : sm->suppPortStatus = Authorized;
299 : 274 : eapol_sm_set_port_authorized(sm);
300 : 274 : sm->cb_status = EAPOL_CB_SUCCESS;
301 : 274 : }
302 : :
303 : :
304 : 183 : SM_STATE(SUPP_PAE, RESTART)
305 : : {
306 [ - + ][ # # ]: 183 : SM_ENTRY(SUPP_PAE, RESTART);
307 : 183 : sm->eapRestart = TRUE;
308 : 183 : }
309 : :
310 : :
311 : 90 : SM_STATE(SUPP_PAE, S_FORCE_AUTH)
312 : : {
313 [ + - ][ + - ]: 90 : SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
314 : 90 : sm->suppPortStatus = Authorized;
315 : 90 : eapol_sm_set_port_authorized(sm);
316 : 90 : sm->sPortMode = ForceAuthorized;
317 : 90 : }
318 : :
319 : :
320 : 0 : SM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
321 : : {
322 [ # # ][ # # ]: 0 : SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
323 : 0 : sm->suppPortStatus = Unauthorized;
324 : 0 : eapol_sm_set_port_unauthorized(sm);
325 : 0 : sm->sPortMode = ForceUnauthorized;
326 : 0 : eapol_sm_txLogoff(sm);
327 : 0 : }
328 : :
329 : :
330 : 14606 : SM_STEP(SUPP_PAE)
331 : : {
332 [ + + ][ + + ]: 14606 : if ((sm->userLogoff && !sm->logoffSent) &&
[ + - ]
333 [ + + ]: 3 : !(sm->initialize || !sm->portEnabled))
334 : 1 : SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF);
335 [ + + ][ + - ]: 14605 : else if (((sm->portControl == Auto) &&
336 [ + + ]: 14605 : (sm->sPortMode != sm->portControl)) ||
337 [ + + ]: 14543 : sm->initialize || !sm->portEnabled)
338 : 6491 : SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED);
339 [ + + ][ + + ]: 8114 : else if ((sm->portControl == ForceAuthorized) &&
340 [ + - ]: 90 : (sm->sPortMode != sm->portControl) &&
341 [ + - ]: 90 : !(sm->initialize || !sm->portEnabled))
342 : 90 : SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH);
343 [ - + ][ # # ]: 8024 : else if ((sm->portControl == ForceUnauthorized) &&
344 [ # # ]: 0 : (sm->sPortMode != sm->portControl) &&
345 [ # # ]: 0 : !(sm->initialize || !sm->portEnabled))
346 : 0 : SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH);
347 [ - + + + : 8024 : else switch (sm->SUPP_PAE_state) {
+ + + + +
- - ]
348 : : case SUPP_PAE_UNKNOWN:
349 : 0 : break;
350 : : case SUPP_PAE_LOGOFF:
351 [ - + ]: 1 : if (!sm->userLogoff)
352 : 0 : SM_ENTER(SUPP_PAE, DISCONNECTED);
353 : 1 : break;
354 : : case SUPP_PAE_DISCONNECTED:
355 : 355 : SM_ENTER(SUPP_PAE, CONNECTING);
356 : 355 : break;
357 : : case SUPP_PAE_CONNECTING:
358 [ + + ][ + - ]: 1162 : if (sm->startWhen == 0 && sm->startCount < sm->maxStart)
359 : 9 : SM_ENTER(SUPP_PAE, CONNECTING);
360 [ - + ][ # # ]: 1153 : else if (sm->startWhen == 0 &&
361 [ # # ]: 0 : sm->startCount >= sm->maxStart &&
362 : 0 : sm->portValid)
363 : 0 : SM_ENTER(SUPP_PAE, AUTHENTICATED);
364 [ + + ][ - + ]: 1153 : else if (sm->eapSuccess || sm->eapFail)
365 : 193 : SM_ENTER(SUPP_PAE, AUTHENTICATING);
366 [ + + ]: 960 : else if (sm->eapolEap)
367 : 161 : SM_ENTER(SUPP_PAE, RESTART);
368 [ - + ][ # # ]: 799 : else if (sm->startWhen == 0 &&
369 [ # # ]: 0 : sm->startCount >= sm->maxStart &&
370 : 0 : !sm->portValid)
371 : 0 : SM_ENTER(SUPP_PAE, HELD);
372 : 1162 : break;
373 : : case SUPP_PAE_AUTHENTICATING:
374 [ + + ][ + + ]: 5023 : if (sm->eapSuccess && !sm->portValid &&
[ + + ]
375 [ + + ]: 16 : sm->conf.accept_802_1x_keys &&
376 : 16 : sm->conf.required_keys == 0) {
377 : 2 : wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for "
378 : : "plaintext connection; no EAPOL-Key frames "
379 : : "required");
380 : 2 : sm->portValid = TRUE;
381 [ + - ]: 2 : if (sm->ctx->eapol_done_cb)
382 : 2 : sm->ctx->eapol_done_cb(sm->ctx->ctx);
383 : : }
384 [ + + ][ + + ]: 5023 : if (sm->eapSuccess && sm->portValid)
385 : 274 : SM_ENTER(SUPP_PAE, AUTHENTICATED);
386 [ + + ][ - + ]: 4749 : else if (sm->eapFail || (sm->keyDone && !sm->portValid))
[ # # ]
387 : 95 : SM_ENTER(SUPP_PAE, HELD);
388 [ - + ]: 4654 : else if (sm->suppTimeout)
389 : 0 : SM_ENTER(SUPP_PAE, CONNECTING);
390 : 5023 : break;
391 : : case SUPP_PAE_HELD:
392 [ - + ]: 285 : if (sm->heldWhile == 0)
393 : 0 : SM_ENTER(SUPP_PAE, CONNECTING);
394 [ - + ]: 285 : else if (sm->eapolEap)
395 : 0 : SM_ENTER(SUPP_PAE, RESTART);
396 : 285 : break;
397 : : case SUPP_PAE_AUTHENTICATED:
398 [ + + ][ + - ]: 901 : if (sm->eapolEap && sm->portValid)
399 : 22 : SM_ENTER(SUPP_PAE, RESTART);
400 [ + + ]: 879 : else if (!sm->portValid)
401 : 16 : SM_ENTER(SUPP_PAE, DISCONNECTED);
402 : 901 : break;
403 : : case SUPP_PAE_RESTART:
404 [ + - ]: 183 : if (!sm->eapRestart)
405 : 183 : SM_ENTER(SUPP_PAE, AUTHENTICATING);
406 : 183 : break;
407 : : case SUPP_PAE_S_FORCE_AUTH:
408 : 114 : break;
409 : : case SUPP_PAE_S_FORCE_UNAUTH:
410 : 0 : break;
411 : : }
412 : 14606 : }
413 : :
414 : :
415 : 6491 : SM_STATE(KEY_RX, NO_KEY_RECEIVE)
416 : : {
417 [ + - ][ + + ]: 6491 : SM_ENTRY(KEY_RX, NO_KEY_RECEIVE);
418 : 6491 : }
419 : :
420 : :
421 : 4 : SM_STATE(KEY_RX, KEY_RECEIVE)
422 : : {
423 [ - + ][ # # ]: 4 : SM_ENTRY(KEY_RX, KEY_RECEIVE);
424 : 4 : eapol_sm_processKey(sm);
425 : 4 : sm->rxKey = FALSE;
426 : 4 : }
427 : :
428 : :
429 : 14606 : SM_STEP(KEY_RX)
430 : : {
431 [ + + ][ + + ]: 14606 : if (sm->initialize || !sm->portEnabled)
432 : 6491 : SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
433 [ - + + - ]: 14606 : switch (sm->KEY_RX_state) {
434 : : case KEY_RX_UNKNOWN:
435 : 0 : break;
436 : : case KEY_RX_NO_KEY_RECEIVE:
437 [ + + ]: 14598 : if (sm->rxKey)
438 : 2 : SM_ENTER(KEY_RX, KEY_RECEIVE);
439 : 14598 : break;
440 : : case KEY_RX_KEY_RECEIVE:
441 [ + + ]: 8 : if (sm->rxKey)
442 : 2 : SM_ENTER(KEY_RX, KEY_RECEIVE);
443 : 8 : break;
444 : : }
445 : 14606 : }
446 : :
447 : :
448 : 1187 : SM_STATE(SUPP_BE, REQUEST)
449 : : {
450 [ - + ][ # # ]: 1187 : SM_ENTRY(SUPP_BE, REQUEST);
451 : 1187 : sm->authWhile = 0;
452 : 1187 : sm->eapReq = TRUE;
453 : 1187 : eapol_sm_getSuppRsp(sm);
454 : 1187 : }
455 : :
456 : :
457 : 1005 : SM_STATE(SUPP_BE, RESPONSE)
458 : : {
459 [ - + ][ # # ]: 1005 : SM_ENTRY(SUPP_BE, RESPONSE);
460 : 1005 : eapol_sm_txSuppRsp(sm);
461 : 1005 : sm->eapResp = FALSE;
462 : 1005 : }
463 : :
464 : :
465 : 280 : SM_STATE(SUPP_BE, SUCCESS)
466 : : {
467 [ - + ][ # # ]: 280 : SM_ENTRY(SUPP_BE, SUCCESS);
468 : 280 : sm->keyRun = TRUE;
469 : 280 : sm->suppSuccess = TRUE;
470 : :
471 : : #ifdef CONFIG_EAP_PROXY
472 : : if (sm->use_eap_proxy) {
473 : : if (eap_proxy_key_available(sm->eap_proxy)) {
474 : : /* New key received - clear IEEE 802.1X EAPOL-Key replay
475 : : * counter */
476 : : sm->replay_counter_valid = FALSE;
477 : : }
478 : : return;
479 : : }
480 : : #endif /* CONFIG_EAP_PROXY */
481 : :
482 [ + + ]: 280 : if (eap_key_available(sm->eap)) {
483 : : /* New key received - clear IEEE 802.1X EAPOL-Key replay
484 : : * counter */
485 : 125 : sm->replay_counter_valid = FALSE;
486 : : }
487 : 280 : }
488 : :
489 : :
490 : 95 : SM_STATE(SUPP_BE, FAIL)
491 : : {
492 [ - + ][ # # ]: 95 : SM_ENTRY(SUPP_BE, FAIL);
493 : 95 : sm->suppFail = TRUE;
494 : 95 : }
495 : :
496 : :
497 : 0 : SM_STATE(SUPP_BE, TIMEOUT)
498 : : {
499 [ # # ][ # # ]: 0 : SM_ENTRY(SUPP_BE, TIMEOUT);
500 : 0 : sm->suppTimeout = TRUE;
501 : 0 : }
502 : :
503 : :
504 : 820 : SM_STATE(SUPP_BE, IDLE)
505 : : {
506 [ - + ][ # # ]: 820 : SM_ENTRY(SUPP_BE, IDLE);
507 : 820 : sm->suppStart = FALSE;
508 : 820 : sm->initial_req = TRUE;
509 : 820 : }
510 : :
511 : :
512 : 6507 : SM_STATE(SUPP_BE, INITIALIZE)
513 : : {
514 [ + - ][ + + ]: 6507 : SM_ENTRY(SUPP_BE, INITIALIZE);
515 : 6507 : eapol_sm_abortSupp(sm);
516 : 6507 : sm->suppAbort = FALSE;
517 : :
518 : : /*
519 : : * IEEE Std 802.1X-2004 does not clear authWhile here, but doing so
520 : : * allows the timer tick to be stopped more quickly when the port is
521 : : * not enabled. Since this variable is used only within RECEIVE state,
522 : : * clearing it on initialization does not change actual state machine
523 : : * behavior.
524 : : */
525 : 6507 : sm->authWhile = 0;
526 : 6507 : }
527 : :
528 : :
529 : 1187 : SM_STATE(SUPP_BE, RECEIVE)
530 : : {
531 [ - + ][ # # ]: 1187 : SM_ENTRY(SUPP_BE, RECEIVE);
532 : 1187 : sm->authWhile = sm->authPeriod;
533 : 1187 : eapol_enable_timer_tick(sm);
534 : 1187 : sm->eapolEap = FALSE;
535 : 1187 : sm->eapNoResp = FALSE;
536 : 1187 : sm->initial_req = FALSE;
537 : 1187 : }
538 : :
539 : :
540 : 14606 : SM_STEP(SUPP_BE)
541 : : {
542 [ + + ][ + + ]: 14606 : if (sm->initialize || sm->suppAbort)
543 : 6507 : SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE);
544 [ - + + + : 8099 : else switch (sm->SUPP_BE_state) {
+ - + + +
- ]
545 : : case SUPP_BE_UNKNOWN:
546 : 0 : break;
547 : : case SUPP_BE_REQUEST:
548 : : /*
549 : : * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
550 : : * and SUCCESS based on eapFail and eapSuccess, respectively.
551 : : * However, IEEE Std 802.1X-2004 is also specifying that
552 : : * eapNoResp should be set in conjunction with eapSuccess and
553 : : * eapFail which would mean that more than one of the
554 : : * transitions here would be activated at the same time.
555 : : * Skipping RESPONSE and/or RECEIVE states in these cases can
556 : : * cause problems and the direct transitions to do not seem
557 : : * correct. Because of this, the conditions for these
558 : : * transitions are verified only after eapNoResp. They are
559 : : * unlikely to be used since eapNoResp should always be set if
560 : : * either of eapSuccess or eapFail is set.
561 : : */
562 [ + + ][ - + ]: 1191 : if (sm->eapResp && sm->eapNoResp) {
563 : 0 : wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both "
564 : : "eapResp and eapNoResp set?!");
565 : : }
566 [ + + ]: 1191 : if (sm->eapResp)
567 : 1005 : SM_ENTER(SUPP_BE, RESPONSE);
568 [ + + ]: 186 : else if (sm->eapNoResp)
569 : 182 : SM_ENTER(SUPP_BE, RECEIVE);
570 [ - + ]: 4 : else if (sm->eapFail)
571 : 0 : SM_ENTER(SUPP_BE, FAIL);
572 [ - + ]: 4 : else if (sm->eapSuccess)
573 : 0 : SM_ENTER(SUPP_BE, SUCCESS);
574 : 1191 : break;
575 : : case SUPP_BE_RESPONSE:
576 : 1005 : SM_ENTER(SUPP_BE, RECEIVE);
577 : 1005 : break;
578 : : case SUPP_BE_SUCCESS:
579 : 280 : SM_ENTER(SUPP_BE, IDLE);
580 : 280 : break;
581 : : case SUPP_BE_FAIL:
582 : 95 : SM_ENTER(SUPP_BE, IDLE);
583 : 95 : break;
584 : : case SUPP_BE_TIMEOUT:
585 : 0 : SM_ENTER(SUPP_BE, IDLE);
586 : 0 : break;
587 : : case SUPP_BE_IDLE:
588 [ + + ][ - + ]: 2887 : if (sm->eapFail && sm->suppStart)
589 : 0 : SM_ENTER(SUPP_BE, FAIL);
590 [ + + ][ + + ]: 2887 : else if (sm->eapolEap && sm->suppStart)
591 : 183 : SM_ENTER(SUPP_BE, REQUEST);
592 [ + + ][ + + ]: 2704 : else if (sm->eapSuccess && sm->suppStart)
593 : 193 : SM_ENTER(SUPP_BE, SUCCESS);
594 : 2887 : break;
595 : : case SUPP_BE_INITIALIZE:
596 : 445 : SM_ENTER(SUPP_BE, IDLE);
597 : 445 : break;
598 : : case SUPP_BE_RECEIVE:
599 [ + + ]: 2196 : if (sm->eapolEap)
600 : 1004 : SM_ENTER(SUPP_BE, REQUEST);
601 [ + + ]: 1192 : else if (sm->eapFail)
602 : 95 : SM_ENTER(SUPP_BE, FAIL);
603 [ - + ]: 1097 : else if (sm->authWhile == 0)
604 : 0 : SM_ENTER(SUPP_BE, TIMEOUT);
605 [ + + ]: 1097 : else if (sm->eapSuccess)
606 : 87 : SM_ENTER(SUPP_BE, SUCCESS);
607 : 2196 : break;
608 : : }
609 : 14606 : }
610 : :
611 : :
612 : 1 : static void eapol_sm_txLogoff(struct eapol_sm *sm)
613 : : {
614 : 1 : wpa_printf(MSG_DEBUG, "EAPOL: txLogoff");
615 : 1 : sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
616 : : IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0);
617 : 1 : sm->dot1xSuppEapolLogoffFramesTx++;
618 : 1 : sm->dot1xSuppEapolFramesTx++;
619 : 1 : }
620 : :
621 : :
622 : 31 : static void eapol_sm_txStart(struct eapol_sm *sm)
623 : : {
624 : 31 : wpa_printf(MSG_DEBUG, "EAPOL: txStart");
625 : 31 : sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
626 : : IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0);
627 : 31 : sm->dot1xSuppEapolStartFramesTx++;
628 : 31 : sm->dot1xSuppEapolFramesTx++;
629 : 31 : }
630 : :
631 : :
632 : : #define IEEE8021X_ENCR_KEY_LEN 32
633 : : #define IEEE8021X_SIGN_KEY_LEN 32
634 : :
635 : : struct eap_key_data {
636 : : u8 encr_key[IEEE8021X_ENCR_KEY_LEN];
637 : : u8 sign_key[IEEE8021X_SIGN_KEY_LEN];
638 : : };
639 : :
640 : :
641 : 4 : static void eapol_sm_processKey(struct eapol_sm *sm)
642 : : {
643 : : #ifndef CONFIG_FIPS
644 : : struct ieee802_1x_hdr *hdr;
645 : : struct ieee802_1x_eapol_key *key;
646 : : struct eap_key_data keydata;
647 : : u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
648 : : u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
649 : : int key_len, res, sign_key_len, encr_key_len;
650 : : u16 rx_key_length;
651 : : size_t plen;
652 : :
653 : 4 : wpa_printf(MSG_DEBUG, "EAPOL: processKey");
654 [ - + ]: 4 : if (sm->last_rx_key == NULL)
655 : 0 : return;
656 : :
657 [ - + ]: 4 : if (!sm->conf.accept_802_1x_keys) {
658 : 0 : wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key"
659 : : " even though this was not accepted - "
660 : : "ignoring this packet");
661 : 0 : return;
662 : : }
663 : :
664 [ - + ]: 4 : if (sm->last_rx_key_len < sizeof(*hdr) + sizeof(*key))
665 : 0 : return;
666 : 4 : hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
667 : 4 : key = (struct ieee802_1x_eapol_key *) (hdr + 1);
668 : 4 : plen = be_to_host16(hdr->length);
669 [ + - ][ - + ]: 4 : if (sizeof(*hdr) + plen > sm->last_rx_key_len || plen < sizeof(*key)) {
670 : 0 : wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
671 : 0 : return;
672 : : }
673 : 4 : rx_key_length = WPA_GET_BE16(key->key_length);
674 : 4 : wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
675 : : "EAPOL-Key: type=%d key_length=%d key_index=0x%x",
676 : 12 : hdr->version, hdr->type, be_to_host16(hdr->length),
677 : 8 : key->type, rx_key_length, key->key_index);
678 : :
679 : 4 : eapol_sm_notify_lower_layer_success(sm, 1);
680 : 4 : sign_key_len = IEEE8021X_SIGN_KEY_LEN;
681 : 4 : encr_key_len = IEEE8021X_ENCR_KEY_LEN;
682 : 4 : res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata));
683 [ - + ]: 4 : if (res < 0) {
684 : 0 : wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for "
685 : : "decrypting EAPOL-Key keys");
686 : 0 : return;
687 : : }
688 [ - + ]: 4 : if (res == 16) {
689 : : /* LEAP derives only 16 bytes of keying material. */
690 : 0 : res = eapol_sm_get_key(sm, (u8 *) &keydata, 16);
691 [ # # ]: 0 : if (res) {
692 : 0 : wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP "
693 : : "master key for decrypting EAPOL-Key keys");
694 : 0 : return;
695 : : }
696 : 0 : sign_key_len = 16;
697 : 0 : encr_key_len = 16;
698 : 0 : os_memcpy(keydata.sign_key, keydata.encr_key, 16);
699 [ - + ]: 4 : } else if (res) {
700 : 0 : wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key "
701 : : "data for decrypting EAPOL-Key keys (res=%d)", res);
702 : 0 : return;
703 : : }
704 : :
705 : : /* The key replay_counter must increase when same master key */
706 [ + + ][ - + ]: 4 : if (sm->replay_counter_valid &&
707 : 2 : os_memcmp(sm->last_replay_counter, key->replay_counter,
708 : : IEEE8021X_REPLAY_COUNTER_LEN) >= 0) {
709 : 0 : wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did "
710 : : "not increase - ignoring key");
711 : 0 : wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter",
712 : 0 : sm->last_replay_counter,
713 : : IEEE8021X_REPLAY_COUNTER_LEN);
714 : 0 : wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter",
715 : 0 : key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN);
716 : 0 : return;
717 : : }
718 : :
719 : : /* Verify key signature (HMAC-MD5) */
720 : 4 : os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN);
721 : 4 : os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN);
722 : 4 : hmac_md5(keydata.sign_key, sign_key_len,
723 : 8 : sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
724 : 4 : key->key_signature);
725 [ - + ]: 4 : if (os_memcmp(orig_key_sign, key->key_signature,
726 : : IEEE8021X_KEY_SIGN_LEN) != 0) {
727 : 0 : wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
728 : : "EAPOL-Key packet");
729 : 0 : os_memcpy(key->key_signature, orig_key_sign,
730 : : IEEE8021X_KEY_SIGN_LEN);
731 : 0 : return;
732 : : }
733 : 4 : wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
734 : :
735 : 4 : key_len = plen - sizeof(*key);
736 [ + - ][ - + ]: 4 : if (key_len > 32 || rx_key_length > 32) {
737 [ # # ]: 0 : wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
738 : : key_len ? key_len : rx_key_length);
739 : 0 : return;
740 : : }
741 [ + - ]: 4 : if (key_len == rx_key_length) {
742 : 4 : os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
743 : 4 : os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
744 : : encr_key_len);
745 : 4 : os_memcpy(datakey, key + 1, key_len);
746 : 4 : rc4_skip(ekey, IEEE8021X_KEY_IV_LEN + encr_key_len, 0,
747 : : datakey, key_len);
748 : 4 : wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
749 : : datakey, key_len);
750 [ # # ]: 0 : } else if (key_len == 0) {
751 : : /*
752 : : * IEEE 802.1X-2004 specifies that least significant Key Length
753 : : * octets from MS-MPPE-Send-Key are used as the key if the key
754 : : * data is not present. This seems to be meaning the beginning
755 : : * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
756 : : * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
757 : : * Anyway, taking the beginning of the keying material from EAP
758 : : * seems to interoperate with Authenticators.
759 : : */
760 : 0 : key_len = rx_key_length;
761 : 0 : os_memcpy(datakey, keydata.encr_key, key_len);
762 : 0 : wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying "
763 : : "material data encryption key",
764 : : datakey, key_len);
765 : : } else {
766 : 0 : wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
767 : : "(key_length=%d)", key_len, rx_key_length);
768 : 0 : return;
769 : : }
770 : :
771 : 4 : sm->replay_counter_valid = TRUE;
772 : 4 : os_memcpy(sm->last_replay_counter, key->replay_counter,
773 : : IEEE8021X_REPLAY_COUNTER_LEN);
774 : :
775 [ + + ]: 4 : wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
776 : : "len %d",
777 : 4 : key->key_index & IEEE8021X_KEY_INDEX_FLAG ?
778 : : "unicast" : "broadcast",
779 : 4 : key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len);
780 : :
781 [ + - - + ]: 8 : if (sm->ctx->set_wep_key &&
782 : 4 : sm->ctx->set_wep_key(sm->ctx->ctx,
783 : 4 : key->key_index & IEEE8021X_KEY_INDEX_FLAG,
784 : 4 : key->key_index & IEEE8021X_KEY_INDEX_MASK,
785 : : datakey, key_len) < 0) {
786 : 0 : wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
787 : : " driver.");
788 : : } else {
789 [ + + ]: 4 : if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
790 : 2 : sm->unicast_key_received = TRUE;
791 : : else
792 : 2 : sm->broadcast_key_received = TRUE;
793 : :
794 [ + + ][ - + ]: 4 : if ((sm->unicast_key_received ||
795 [ - + ]: 2 : !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) &&
796 [ # # ]: 0 : (sm->broadcast_key_received ||
797 : 0 : !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST)))
798 : : {
799 : 2 : wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
800 : : "frames received");
801 : 2 : sm->portValid = TRUE;
802 [ + - ]: 2 : if (sm->ctx->eapol_done_cb)
803 : 4 : sm->ctx->eapol_done_cb(sm->ctx->ctx);
804 : : }
805 : : }
806 : : #endif /* CONFIG_FIPS */
807 : : }
808 : :
809 : :
810 : 1187 : static void eapol_sm_getSuppRsp(struct eapol_sm *sm)
811 : : {
812 : 1187 : wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp");
813 : : /* EAP layer processing; no special code is needed, since Supplicant
814 : : * Backend state machine is waiting for eapNoResp or eapResp to be set
815 : : * and these are only set in the EAP state machine when the processing
816 : : * has finished. */
817 : 1187 : }
818 : :
819 : :
820 : 1005 : static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
821 : : {
822 : : struct wpabuf *resp;
823 : :
824 : 1005 : wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
825 : :
826 : : #ifdef CONFIG_EAP_PROXY
827 : : if (sm->use_eap_proxy) {
828 : : /* Get EAP Response from EAP Proxy */
829 : : resp = eap_proxy_get_eapRespData(sm->eap_proxy);
830 : : if (resp == NULL) {
831 : : wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP Proxy "
832 : : "response data not available");
833 : : return;
834 : : }
835 : : } else
836 : : #endif /* CONFIG_EAP_PROXY */
837 : :
838 : 1005 : resp = eap_get_eapRespData(sm->eap);
839 [ - + ]: 1005 : if (resp == NULL) {
840 : 0 : wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
841 : : "not available");
842 : 1005 : return;
843 : : }
844 : :
845 : : /* Send EAP-Packet from the EAP layer to the Authenticator */
846 : 2010 : sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
847 : 1005 : IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head(resp),
848 : : wpabuf_len(resp));
849 : :
850 : : /* eapRespData is not used anymore, so free it here */
851 : 1005 : wpabuf_free(resp);
852 : :
853 [ + + ]: 1005 : if (sm->initial_req)
854 : 183 : sm->dot1xSuppEapolReqIdFramesRx++;
855 : : else
856 : 822 : sm->dot1xSuppEapolReqFramesRx++;
857 : 1005 : sm->dot1xSuppEapolRespFramesTx++;
858 : 1005 : sm->dot1xSuppEapolFramesTx++;
859 : : }
860 : :
861 : :
862 : 6507 : static void eapol_sm_abortSupp(struct eapol_sm *sm)
863 : : {
864 : : /* release system resources that may have been allocated for the
865 : : * authentication session */
866 : 6507 : os_free(sm->last_rx_key);
867 : 6507 : sm->last_rx_key = NULL;
868 : 6507 : wpabuf_free(sm->eapReqData);
869 : 6507 : sm->eapReqData = NULL;
870 : 6507 : eap_sm_abort(sm->eap);
871 : 6507 : }
872 : :
873 : :
874 : 0 : static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
875 : : {
876 : 0 : eapol_sm_step(timeout_ctx);
877 : 0 : }
878 : :
879 : :
880 : 364 : static void eapol_sm_set_port_authorized(struct eapol_sm *sm)
881 : : {
882 [ + - ]: 364 : if (sm->ctx->port_cb)
883 : 364 : sm->ctx->port_cb(sm->ctx->ctx, 1);
884 : 364 : }
885 : :
886 : :
887 : 6608 : static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm)
888 : : {
889 [ + - ]: 6608 : if (sm->ctx->port_cb)
890 : 6608 : sm->ctx->port_cb(sm->ctx->ctx, 0);
891 : 6608 : }
892 : :
893 : :
894 : : /**
895 : : * eapol_sm_step - EAPOL state machine step function
896 : : * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
897 : : *
898 : : * This function is called to notify the state machine about changed external
899 : : * variables. It will step through the EAPOL state machines in loop to process
900 : : * all triggered state changes.
901 : : */
902 : 9144 : void eapol_sm_step(struct eapol_sm *sm)
903 : : {
904 : : int i;
905 : :
906 : : /* In theory, it should be ok to run this in loop until !changed.
907 : : * However, it is better to use a limit on number of iterations to
908 : : * allow events (e.g., SIGTERM) to stop the program cleanly if the
909 : : * state machine were to generate a busy loop. */
910 [ + - ]: 14606 : for (i = 0; i < 100; i++) {
911 : 14606 : sm->changed = FALSE;
912 : 14606 : SM_STEP_RUN(SUPP_PAE);
913 : 14606 : SM_STEP_RUN(KEY_RX);
914 : 14606 : SM_STEP_RUN(SUPP_BE);
915 : : #ifdef CONFIG_EAP_PROXY
916 : : if (sm->use_eap_proxy) {
917 : : /* Drive the EAP proxy state machine */
918 : : if (eap_proxy_sm_step(sm->eap_proxy, sm->eap))
919 : : sm->changed = TRUE;
920 : : } else
921 : : #endif /* CONFIG_EAP_PROXY */
922 [ + + ]: 14606 : if (eap_peer_sm_step(sm->eap))
923 : 1938 : sm->changed = TRUE;
924 [ + + ]: 14606 : if (!sm->changed)
925 : 9144 : break;
926 : : }
927 : :
928 [ - + ]: 9144 : if (sm->changed) {
929 : : /* restart EAPOL state machine step from timeout call in order
930 : : * to allow other events to be processed. */
931 : 0 : eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
932 : 0 : eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm);
933 : : }
934 : :
935 [ + - ][ + + ]: 9144 : if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
936 : 369 : int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0;
937 : 369 : sm->cb_status = EAPOL_CB_IN_PROGRESS;
938 : 369 : sm->ctx->cb(sm, success, sm->ctx->cb_ctx);
939 : : }
940 : 9144 : }
941 : :
942 : :
943 : : #ifdef CONFIG_CTRL_IFACE
944 : 60 : static const char *eapol_supp_pae_state(int state)
945 : : {
946 [ - - - - : 60 : switch (state) {
- + - - ]
947 : : case SUPP_PAE_LOGOFF:
948 : 0 : return "LOGOFF";
949 : : case SUPP_PAE_DISCONNECTED:
950 : 0 : return "DISCONNECTED";
951 : : case SUPP_PAE_CONNECTING:
952 : 0 : return "CONNECTING";
953 : : case SUPP_PAE_AUTHENTICATING:
954 : 0 : return "AUTHENTICATING";
955 : : case SUPP_PAE_HELD:
956 : 0 : return "HELD";
957 : : case SUPP_PAE_AUTHENTICATED:
958 : 60 : return "AUTHENTICATED";
959 : : case SUPP_PAE_RESTART:
960 : 0 : return "RESTART";
961 : : default:
962 : 60 : return "UNKNOWN";
963 : : }
964 : : }
965 : :
966 : :
967 : 0 : static const char *eapol_supp_be_state(int state)
968 : : {
969 [ # # # # : 0 : switch (state) {
# # # #
# ]
970 : : case SUPP_BE_REQUEST:
971 : 0 : return "REQUEST";
972 : : case SUPP_BE_RESPONSE:
973 : 0 : return "RESPONSE";
974 : : case SUPP_BE_SUCCESS:
975 : 0 : return "SUCCESS";
976 : : case SUPP_BE_FAIL:
977 : 0 : return "FAIL";
978 : : case SUPP_BE_TIMEOUT:
979 : 0 : return "TIMEOUT";
980 : : case SUPP_BE_IDLE:
981 : 0 : return "IDLE";
982 : : case SUPP_BE_INITIALIZE:
983 : 0 : return "INITIALIZE";
984 : : case SUPP_BE_RECEIVE:
985 : 0 : return "RECEIVE";
986 : : default:
987 : 0 : return "UNKNOWN";
988 : : }
989 : : }
990 : :
991 : :
992 : 60 : static const char * eapol_port_status(PortStatus status)
993 : : {
994 [ + - ]: 60 : if (status == Authorized)
995 : 60 : return "Authorized";
996 : : else
997 : 60 : return "Unauthorized";
998 : : }
999 : : #endif /* CONFIG_CTRL_IFACE */
1000 : :
1001 : :
1002 : : #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
1003 : 460 : static const char * eapol_port_control(PortControl ctrl)
1004 : : {
1005 [ + - + - ]: 460 : switch (ctrl) {
1006 : : case Auto:
1007 : 371 : return "Auto";
1008 : : case ForceUnauthorized:
1009 : 0 : return "ForceUnauthorized";
1010 : : case ForceAuthorized:
1011 : 89 : return "ForceAuthorized";
1012 : : default:
1013 : 460 : return "Unknown";
1014 : : }
1015 : : }
1016 : : #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1017 : :
1018 : :
1019 : : /**
1020 : : * eapol_sm_configure - Set EAPOL variables
1021 : : * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1022 : : * @heldPeriod: dot1xSuppHeldPeriod
1023 : : * @authPeriod: dot1xSuppAuthPeriod
1024 : : * @startPeriod: dot1xSuppStartPeriod
1025 : : * @maxStart: dot1xSuppMaxStart
1026 : : *
1027 : : * Set configurable EAPOL state machine variables. Each variable can be set to
1028 : : * the given value or ignored if set to -1 (to set only some of the variables).
1029 : : */
1030 : 0 : void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
1031 : : int startPeriod, int maxStart)
1032 : : {
1033 [ # # ]: 0 : if (sm == NULL)
1034 : 0 : return;
1035 [ # # ]: 0 : if (heldPeriod >= 0)
1036 : 0 : sm->heldPeriod = heldPeriod;
1037 [ # # ]: 0 : if (authPeriod >= 0)
1038 : 0 : sm->authPeriod = authPeriod;
1039 [ # # ]: 0 : if (startPeriod >= 0)
1040 : 0 : sm->startPeriod = startPeriod;
1041 [ # # ]: 0 : if (maxStart >= 0)
1042 : 0 : sm->maxStart = maxStart;
1043 : : }
1044 : :
1045 : :
1046 : : /**
1047 : : * eapol_sm_get_method_name - Get EAPOL method name
1048 : : * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1049 : : * Returns: Static string containing name of current eap method or NULL
1050 : : */
1051 : 0 : const char * eapol_sm_get_method_name(struct eapol_sm *sm)
1052 : : {
1053 [ # # ][ # # ]: 0 : if (sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED ||
1054 : 0 : sm->suppPortStatus != Authorized)
1055 : 0 : return NULL;
1056 : :
1057 : 0 : return eap_sm_get_method_name(sm->eap);
1058 : : }
1059 : :
1060 : :
1061 : : #ifdef CONFIG_CTRL_IFACE
1062 : : /**
1063 : : * eapol_sm_get_status - Get EAPOL state machine status
1064 : : * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1065 : : * @buf: Buffer for status information
1066 : : * @buflen: Maximum buffer length
1067 : : * @verbose: Whether to include verbose status information
1068 : : * Returns: Number of bytes written to buf.
1069 : : *
1070 : : * Query EAPOL state machine for status information. This function fills in a
1071 : : * text area with current status information from the EAPOL state machine. If
1072 : : * the buffer (buf) is not large enough, status information will be truncated
1073 : : * to fit the buffer.
1074 : : */
1075 : 60 : int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
1076 : : int verbose)
1077 : : {
1078 : : int len, ret;
1079 [ - + ]: 60 : if (sm == NULL)
1080 : 0 : return 0;
1081 : :
1082 : 60 : len = os_snprintf(buf, buflen,
1083 : : "Supplicant PAE state=%s\n"
1084 : : "suppPortStatus=%s\n",
1085 : 60 : eapol_supp_pae_state(sm->SUPP_PAE_state),
1086 : : eapol_port_status(sm->suppPortStatus));
1087 [ + - ][ - + ]: 60 : if (len < 0 || (size_t) len >= buflen)
1088 : 0 : return 0;
1089 : :
1090 [ - + ]: 60 : if (verbose) {
1091 : 0 : ret = os_snprintf(buf + len, buflen - len,
1092 : : "heldPeriod=%u\n"
1093 : : "authPeriod=%u\n"
1094 : : "startPeriod=%u\n"
1095 : : "maxStart=%u\n"
1096 : : "portControl=%s\n"
1097 : : "Supplicant Backend state=%s\n",
1098 : : sm->heldPeriod,
1099 : : sm->authPeriod,
1100 : : sm->startPeriod,
1101 : : sm->maxStart,
1102 : : eapol_port_control(sm->portControl),
1103 : 0 : eapol_supp_be_state(sm->SUPP_BE_state));
1104 [ # # ][ # # ]: 0 : if (ret < 0 || (size_t) ret >= buflen - len)
1105 : 0 : return len;
1106 : 0 : len += ret;
1107 : : }
1108 : :
1109 : : #ifdef CONFIG_EAP_PROXY
1110 : : if (sm->use_eap_proxy)
1111 : : len += eap_proxy_sm_get_status(sm->eap_proxy,
1112 : : buf + len, buflen - len,
1113 : : verbose);
1114 : : else
1115 : : #endif /* CONFIG_EAP_PROXY */
1116 : 60 : len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
1117 : :
1118 : 60 : return len;
1119 : : }
1120 : :
1121 : :
1122 : : /**
1123 : : * eapol_sm_get_mib - Get EAPOL state machine MIBs
1124 : : * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1125 : : * @buf: Buffer for MIB information
1126 : : * @buflen: Maximum buffer length
1127 : : * Returns: Number of bytes written to buf.
1128 : : *
1129 : : * Query EAPOL state machine for MIB information. This function fills in a
1130 : : * text area with current MIB information from the EAPOL state machine. If
1131 : : * the buffer (buf) is not large enough, MIB information will be truncated to
1132 : : * fit the buffer.
1133 : : */
1134 : 0 : int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
1135 : : {
1136 : : size_t len;
1137 : : int ret;
1138 : :
1139 [ # # ]: 0 : if (sm == NULL)
1140 : 0 : return 0;
1141 [ # # ]: 0 : ret = os_snprintf(buf, buflen,
1142 : : "dot1xSuppPaeState=%d\n"
1143 : : "dot1xSuppHeldPeriod=%u\n"
1144 : : "dot1xSuppAuthPeriod=%u\n"
1145 : : "dot1xSuppStartPeriod=%u\n"
1146 : : "dot1xSuppMaxStart=%u\n"
1147 : : "dot1xSuppSuppControlledPortStatus=%s\n"
1148 : : "dot1xSuppBackendPaeState=%d\n",
1149 : 0 : sm->SUPP_PAE_state,
1150 : : sm->heldPeriod,
1151 : : sm->authPeriod,
1152 : : sm->startPeriod,
1153 : : sm->maxStart,
1154 : 0 : sm->suppPortStatus == Authorized ?
1155 : : "Authorized" : "Unauthorized",
1156 : 0 : sm->SUPP_BE_state);
1157 : :
1158 [ # # ][ # # ]: 0 : if (ret < 0 || (size_t) ret >= buflen)
1159 : 0 : return 0;
1160 : 0 : len = ret;
1161 : :
1162 : 0 : ret = os_snprintf(buf + len, buflen - len,
1163 : : "dot1xSuppEapolFramesRx=%u\n"
1164 : : "dot1xSuppEapolFramesTx=%u\n"
1165 : : "dot1xSuppEapolStartFramesTx=%u\n"
1166 : : "dot1xSuppEapolLogoffFramesTx=%u\n"
1167 : : "dot1xSuppEapolRespFramesTx=%u\n"
1168 : : "dot1xSuppEapolReqIdFramesRx=%u\n"
1169 : : "dot1xSuppEapolReqFramesRx=%u\n"
1170 : : "dot1xSuppInvalidEapolFramesRx=%u\n"
1171 : : "dot1xSuppEapLengthErrorFramesRx=%u\n"
1172 : : "dot1xSuppLastEapolFrameVersion=%u\n"
1173 : : "dot1xSuppLastEapolFrameSource=" MACSTR "\n",
1174 : : sm->dot1xSuppEapolFramesRx,
1175 : : sm->dot1xSuppEapolFramesTx,
1176 : : sm->dot1xSuppEapolStartFramesTx,
1177 : : sm->dot1xSuppEapolLogoffFramesTx,
1178 : : sm->dot1xSuppEapolRespFramesTx,
1179 : : sm->dot1xSuppEapolReqIdFramesRx,
1180 : : sm->dot1xSuppEapolReqFramesRx,
1181 : : sm->dot1xSuppInvalidEapolFramesRx,
1182 : : sm->dot1xSuppEapLengthErrorFramesRx,
1183 : : sm->dot1xSuppLastEapolFrameVersion,
1184 : 0 : MAC2STR(sm->dot1xSuppLastEapolFrameSource));
1185 : :
1186 [ # # ][ # # ]: 0 : if (ret < 0 || (size_t) ret >= buflen - len)
1187 : 0 : return len;
1188 : 0 : len += ret;
1189 : :
1190 : 0 : return len;
1191 : : }
1192 : : #endif /* CONFIG_CTRL_IFACE */
1193 : :
1194 : :
1195 : : /**
1196 : : * eapol_sm_rx_eapol - Process received EAPOL frames
1197 : : * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1198 : : * @src: Source MAC address of the EAPOL packet
1199 : : * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
1200 : : * @len: Length of the EAPOL frame
1201 : : * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
1202 : : * -1 failure
1203 : : */
1204 : 1513 : int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
1205 : : size_t len)
1206 : : {
1207 : : const struct ieee802_1x_hdr *hdr;
1208 : : const struct ieee802_1x_eapol_key *key;
1209 : : int data_len;
1210 : 1513 : int res = 1;
1211 : : size_t plen;
1212 : :
1213 [ - + ]: 1513 : if (sm == NULL)
1214 : 0 : return 0;
1215 : 1513 : sm->dot1xSuppEapolFramesRx++;
1216 [ - + ]: 1513 : if (len < sizeof(*hdr)) {
1217 : 0 : sm->dot1xSuppInvalidEapolFramesRx++;
1218 : 0 : return 0;
1219 : : }
1220 : 1513 : hdr = (const struct ieee802_1x_hdr *) buf;
1221 : 1513 : sm->dot1xSuppLastEapolFrameVersion = hdr->version;
1222 : 1513 : os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
1223 : 1513 : if (hdr->version < EAPOL_VERSION) {
1224 : : /* TODO: backwards compatibility */
1225 : : }
1226 : 1513 : plen = be_to_host16(hdr->length);
1227 [ - + ]: 1513 : if (plen > len - sizeof(*hdr)) {
1228 : 0 : sm->dot1xSuppEapLengthErrorFramesRx++;
1229 : 0 : return 0;
1230 : : }
1231 : : #ifdef CONFIG_WPS
1232 [ + - ][ - + ]: 1513 : if (sm->conf.workaround &&
1233 [ # # ]: 0 : plen < len - sizeof(*hdr) &&
1234 [ # # ]: 0 : hdr->type == IEEE802_1X_TYPE_EAP_PACKET &&
1235 : 0 : len - sizeof(*hdr) > sizeof(struct eap_hdr)) {
1236 : 0 : const struct eap_hdr *ehdr =
1237 : : (const struct eap_hdr *) (hdr + 1);
1238 : : u16 elen;
1239 : :
1240 : 0 : elen = be_to_host16(ehdr->length);
1241 [ # # ][ # # ]: 0 : if (elen > plen && elen <= len - sizeof(*hdr)) {
1242 : : /*
1243 : : * Buffalo WHR-G125 Ver.1.47 seems to send EAP-WPS
1244 : : * packets with too short EAPOL header length field
1245 : : * (14 octets). This is fixed in firmware Ver.1.49.
1246 : : * As a workaround, fix the EAPOL header based on the
1247 : : * correct length in the EAP packet.
1248 : : */
1249 : 0 : wpa_printf(MSG_DEBUG, "EAPOL: Workaround - fix EAPOL "
1250 : : "payload length based on EAP header: "
1251 : : "%d -> %d", (int) plen, elen);
1252 : 0 : plen = elen;
1253 : : }
1254 : : }
1255 : : #endif /* CONFIG_WPS */
1256 : 1513 : data_len = plen + sizeof(*hdr);
1257 : :
1258 [ + + - ]: 1513 : switch (hdr->type) {
1259 : : case IEEE802_1X_TYPE_EAP_PACKET:
1260 [ + - ]: 1187 : if (sm->conf.workaround) {
1261 : : /*
1262 : : * An AP has been reported to send out EAP message with
1263 : : * undocumented code 10 at some point near the
1264 : : * completion of EAP authentication. This can result in
1265 : : * issues with the unexpected EAP message triggering
1266 : : * restart of EAPOL authentication. Avoid this by
1267 : : * skipping the message without advancing the state
1268 : : * machine.
1269 : : */
1270 : 1187 : const struct eap_hdr *ehdr =
1271 : : (const struct eap_hdr *) (hdr + 1);
1272 [ + - ][ - + ]: 1187 : if (plen >= sizeof(*ehdr) && ehdr->code == 10) {
1273 : 0 : wpa_printf(MSG_DEBUG, "EAPOL: Ignore EAP packet with unknown code 10");
1274 : 0 : break;
1275 : : }
1276 : : }
1277 : :
1278 [ + + ]: 1187 : if (sm->cached_pmk) {
1279 : : /* Trying to use PMKSA caching, but Authenticator did
1280 : : * not seem to have a matching entry. Need to restart
1281 : : * EAPOL state machines.
1282 : : */
1283 : 5 : eapol_sm_abort_cached(sm);
1284 : : }
1285 : 1187 : wpabuf_free(sm->eapReqData);
1286 : 1187 : sm->eapReqData = wpabuf_alloc_copy(hdr + 1, plen);
1287 [ + - ]: 1187 : if (sm->eapReqData) {
1288 : 1187 : wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
1289 : : "frame");
1290 : 1187 : sm->eapolEap = TRUE;
1291 : : #ifdef CONFIG_EAP_PROXY
1292 : : if (sm->use_eap_proxy) {
1293 : : eap_proxy_packet_update(
1294 : : sm->eap_proxy,
1295 : : wpabuf_mhead_u8(sm->eapReqData),
1296 : : wpabuf_len(sm->eapReqData));
1297 : : wpa_printf(MSG_DEBUG, "EAPOL: eap_proxy "
1298 : : "EAP Req updated");
1299 : : }
1300 : : #endif /* CONFIG_EAP_PROXY */
1301 : 1187 : eapol_sm_step(sm);
1302 : : }
1303 : 1187 : break;
1304 : : case IEEE802_1X_TYPE_EAPOL_KEY:
1305 [ - + ]: 326 : if (plen < sizeof(*key)) {
1306 : 0 : wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key "
1307 : : "frame received");
1308 : 0 : break;
1309 : : }
1310 : 326 : key = (const struct ieee802_1x_eapol_key *) (hdr + 1);
1311 [ + + ][ + + ]: 326 : if (key->type == EAPOL_KEY_TYPE_WPA ||
1312 : 320 : key->type == EAPOL_KEY_TYPE_RSN) {
1313 : : /* WPA Supplicant takes care of this frame. */
1314 : 322 : wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
1315 : : "frame in EAPOL state machines");
1316 : 322 : res = 0;
1317 : 322 : break;
1318 : : }
1319 [ - + ]: 4 : if (key->type != EAPOL_KEY_TYPE_RC4) {
1320 : 0 : wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown "
1321 : 0 : "EAPOL-Key type %d", key->type);
1322 : 0 : break;
1323 : : }
1324 : 4 : os_free(sm->last_rx_key);
1325 : 4 : sm->last_rx_key = os_malloc(data_len);
1326 [ + - ]: 4 : if (sm->last_rx_key) {
1327 : 4 : wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key "
1328 : : "frame");
1329 : 4 : os_memcpy(sm->last_rx_key, buf, data_len);
1330 : 4 : sm->last_rx_key_len = data_len;
1331 : 4 : sm->rxKey = TRUE;
1332 : 4 : eapol_sm_step(sm);
1333 : : }
1334 : 4 : break;
1335 : : default:
1336 : 0 : wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
1337 : 0 : hdr->type);
1338 : 0 : sm->dot1xSuppInvalidEapolFramesRx++;
1339 : 0 : break;
1340 : : }
1341 : :
1342 : 1513 : return res;
1343 : : }
1344 : :
1345 : :
1346 : : /**
1347 : : * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet
1348 : : * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1349 : : *
1350 : : * Notify EAPOL state machine about transmitted EAPOL packet from an external
1351 : : * component, e.g., WPA. This will update the statistics.
1352 : : */
1353 : 559 : void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
1354 : : {
1355 [ + + ]: 559 : if (sm)
1356 : 547 : sm->dot1xSuppEapolFramesTx++;
1357 : 559 : }
1358 : :
1359 : :
1360 : : /**
1361 : : * eapol_sm_notify_portEnabled - Notification about portEnabled change
1362 : : * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1363 : : * @enabled: New portEnabled value
1364 : : *
1365 : : * Notify EAPOL state machine about new portEnabled value.
1366 : : */
1367 : 2194 : void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
1368 : : {
1369 [ + + ]: 2194 : if (sm == NULL)
1370 : 2194 : return;
1371 : 2163 : wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1372 : : "portEnabled=%d", enabled);
1373 : 2163 : sm->portEnabled = enabled;
1374 : 2163 : eapol_sm_step(sm);
1375 : : }
1376 : :
1377 : :
1378 : : /**
1379 : : * eapol_sm_notify_portValid - Notification about portValid change
1380 : : * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1381 : : * @valid: New portValid value
1382 : : *
1383 : : * Notify EAPOL state machine about new portValid value.
1384 : : */
1385 : 2309 : void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
1386 : : {
1387 [ + + ]: 2309 : if (sm == NULL)
1388 : 2309 : return;
1389 : 2266 : wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1390 : : "portValid=%d", valid);
1391 : 2266 : sm->portValid = valid;
1392 : 2266 : eapol_sm_step(sm);
1393 : : }
1394 : :
1395 : :
1396 : : /**
1397 : : * eapol_sm_notify_eap_success - Notification of external EAP success trigger
1398 : : * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1399 : : * @success: %TRUE = set success, %FALSE = clear success
1400 : : *
1401 : : * Notify the EAPOL state machine that external event has forced EAP state to
1402 : : * success (success = %TRUE). This can be cleared by setting success = %FALSE.
1403 : : *
1404 : : * This function is called to update EAP state when WPA-PSK key handshake has
1405 : : * been completed successfully since WPA-PSK does not use EAP state machine.
1406 : : */
1407 : 970 : void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
1408 : : {
1409 [ + + ]: 970 : if (sm == NULL)
1410 : 970 : return;
1411 : 964 : wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1412 : : "EAP success=%d", success);
1413 : 964 : sm->eapSuccess = success;
1414 : 964 : sm->altAccept = success;
1415 [ + + ]: 964 : if (success)
1416 : 199 : eap_notify_success(sm->eap);
1417 : 964 : eapol_sm_step(sm);
1418 : : }
1419 : :
1420 : :
1421 : : /**
1422 : : * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
1423 : : * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1424 : : * @fail: %TRUE = set failure, %FALSE = clear failure
1425 : : *
1426 : : * Notify EAPOL state machine that external event has forced EAP state to
1427 : : * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE.
1428 : : */
1429 : 460 : void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
1430 : : {
1431 [ - + ]: 460 : if (sm == NULL)
1432 : 460 : return;
1433 : 460 : wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1434 : : "EAP fail=%d", fail);
1435 : 460 : sm->eapFail = fail;
1436 : 460 : sm->altReject = fail;
1437 : 460 : eapol_sm_step(sm);
1438 : : }
1439 : :
1440 : :
1441 : : /**
1442 : : * eapol_sm_notify_config - Notification of EAPOL configuration change
1443 : : * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1444 : : * @config: Pointer to current network EAP configuration
1445 : : * @conf: Pointer to EAPOL configuration data
1446 : : *
1447 : : * Notify EAPOL state machine that configuration has changed. config will be
1448 : : * stored as a backpointer to network configuration. This can be %NULL to clear
1449 : : * the stored pointed. conf will be copied to local EAPOL/EAP configuration
1450 : : * data. If conf is %NULL, this part of the configuration change will be
1451 : : * skipped.
1452 : : */
1453 : 2737 : void eapol_sm_notify_config(struct eapol_sm *sm,
1454 : : struct eap_peer_config *config,
1455 : : const struct eapol_config *conf)
1456 : : {
1457 [ - + ]: 2737 : if (sm == NULL)
1458 : 0 : return;
1459 : :
1460 : 2737 : sm->config = config;
1461 : : #ifdef CONFIG_EAP_PROXY
1462 : : sm->use_eap_proxy = eap_proxy_notify_config(sm->eap_proxy, config) > 0;
1463 : : #endif /* CONFIG_EAP_PROXY */
1464 : :
1465 [ + + ]: 2737 : if (conf == NULL)
1466 : 2280 : return;
1467 : :
1468 : 457 : sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys;
1469 : 457 : sm->conf.required_keys = conf->required_keys;
1470 : 457 : sm->conf.fast_reauth = conf->fast_reauth;
1471 : 457 : sm->conf.workaround = conf->workaround;
1472 : : #ifdef CONFIG_EAP_PROXY
1473 : : if (sm->use_eap_proxy) {
1474 : : /* Using EAP Proxy, so skip EAP state machine update */
1475 : : return;
1476 : : }
1477 : : #endif /* CONFIG_EAP_PROXY */
1478 [ + - ]: 457 : if (sm->eap) {
1479 : 457 : eap_set_fast_reauth(sm->eap, conf->fast_reauth);
1480 : 457 : eap_set_workaround(sm->eap, conf->workaround);
1481 : 457 : eap_set_force_disabled(sm->eap, conf->eap_disabled);
1482 : 2737 : eap_set_external_sim(sm->eap, conf->external_sim);
1483 : : }
1484 : : }
1485 : :
1486 : :
1487 : : /**
1488 : : * eapol_sm_get_key - Get master session key (MSK) from EAP
1489 : : * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1490 : : * @key: Pointer for key buffer
1491 : : * @len: Number of bytes to copy to key
1492 : : * Returns: 0 on success (len of key available), maximum available key len
1493 : : * (>0) if key is available but it is shorter than len, or -1 on failure.
1494 : : *
1495 : : * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key
1496 : : * is available only after a successful authentication.
1497 : : */
1498 : 170 : int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
1499 : : {
1500 : : const u8 *eap_key;
1501 : : size_t eap_len;
1502 : :
1503 : : #ifdef CONFIG_EAP_PROXY
1504 : : if (sm->use_eap_proxy) {
1505 : : /* Get key from EAP proxy */
1506 : : if (sm == NULL || !eap_proxy_key_available(sm->eap_proxy)) {
1507 : : wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
1508 : : return -1;
1509 : : }
1510 : : eap_key = eap_proxy_get_eapKeyData(sm->eap_proxy, &eap_len);
1511 : : if (eap_key == NULL) {
1512 : : wpa_printf(MSG_DEBUG, "EAPOL: Failed to get "
1513 : : "eapKeyData");
1514 : : return -1;
1515 : : }
1516 : : goto key_fetched;
1517 : : }
1518 : : #endif /* CONFIG_EAP_PROXY */
1519 [ + - ][ - + ]: 170 : if (sm == NULL || !eap_key_available(sm->eap)) {
1520 : 0 : wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
1521 : 0 : return -1;
1522 : : }
1523 : 170 : eap_key = eap_get_eapKeyData(sm->eap, &eap_len);
1524 [ - + ]: 170 : if (eap_key == NULL) {
1525 : 0 : wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData");
1526 : 0 : return -1;
1527 : : }
1528 : : #ifdef CONFIG_EAP_PROXY
1529 : : key_fetched:
1530 : : #endif /* CONFIG_EAP_PROXY */
1531 [ - + ]: 170 : if (len > eap_len) {
1532 : 0 : wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not "
1533 : : "available (len=%lu)",
1534 : : (unsigned long) len, (unsigned long) eap_len);
1535 : 0 : return eap_len;
1536 : : }
1537 : 170 : os_memcpy(key, eap_key, len);
1538 : 170 : wpa_printf(MSG_DEBUG, "EAPOL: Successfully fetched key (len=%lu)",
1539 : : (unsigned long) len);
1540 : 170 : return 0;
1541 : : }
1542 : :
1543 : :
1544 : : /**
1545 : : * eapol_sm_notify_logoff - Notification of logon/logoff commands
1546 : : * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1547 : : * @logoff: Whether command was logoff
1548 : : *
1549 : : * Notify EAPOL state machines that user requested logon/logoff.
1550 : : */
1551 : 726 : void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
1552 : : {
1553 [ + - ]: 726 : if (sm) {
1554 : 726 : sm->userLogoff = logoff;
1555 [ + + ]: 726 : if (!logoff) {
1556 : : /* If there is a delayed txStart queued, start now. */
1557 : 725 : sm->startWhen = 0;
1558 : : }
1559 : 726 : eapol_sm_step(sm);
1560 : : }
1561 : 726 : }
1562 : :
1563 : :
1564 : : /**
1565 : : * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching
1566 : : * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1567 : : *
1568 : : * Notify EAPOL state machines that PMKSA caching was successful. This is used
1569 : : * to move EAPOL and EAP state machines into authenticated/successful state.
1570 : : */
1571 : 5 : void eapol_sm_notify_cached(struct eapol_sm *sm)
1572 : : {
1573 [ - + ]: 5 : if (sm == NULL)
1574 : 5 : return;
1575 : 5 : wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL");
1576 : 5 : sm->eapSuccess = TRUE;
1577 : 5 : eap_notify_success(sm->eap);
1578 : 5 : eapol_sm_step(sm);
1579 : : }
1580 : :
1581 : :
1582 : : /**
1583 : : * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
1584 : : * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1585 : : * @attempt: Whether PMKSA caching is tried
1586 : : *
1587 : : * Notify EAPOL state machines whether PMKSA caching is used.
1588 : : */
1589 : 6 : void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt)
1590 : : {
1591 [ - + ]: 6 : if (sm == NULL)
1592 : 6 : return;
1593 [ + - ]: 6 : if (attempt) {
1594 : 6 : wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
1595 : 6 : sm->cached_pmk = TRUE;
1596 : : } else {
1597 : 0 : wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA");
1598 : 0 : sm->cached_pmk = FALSE;
1599 : : }
1600 : : }
1601 : :
1602 : :
1603 : 5 : static void eapol_sm_abort_cached(struct eapol_sm *sm)
1604 : : {
1605 : 5 : wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, "
1606 : : "doing full EAP authentication");
1607 [ - + ]: 5 : if (sm == NULL)
1608 : 5 : return;
1609 : 5 : sm->cached_pmk = FALSE;
1610 : 5 : sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
1611 : 5 : sm->suppPortStatus = Unauthorized;
1612 : 5 : eapol_sm_set_port_unauthorized(sm);
1613 : :
1614 : : /* Make sure we do not start sending EAPOL-Start frames first, but
1615 : : * instead move to RESTART state to start EAPOL authentication. */
1616 : 5 : sm->startWhen = 3;
1617 : 5 : eapol_enable_timer_tick(sm);
1618 : :
1619 [ + - ]: 5 : if (sm->ctx->aborted_cached)
1620 : 5 : sm->ctx->aborted_cached(sm->ctx->ctx);
1621 : : }
1622 : :
1623 : :
1624 : : /**
1625 : : * eapol_sm_register_scard_ctx - Notification of smart card context
1626 : : * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1627 : : * @ctx: Context data for smart card operations
1628 : : *
1629 : : * Notify EAPOL state machines of context data for smart card operations. This
1630 : : * context data will be used as a parameter for scard_*() functions.
1631 : : */
1632 : 31 : void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
1633 : : {
1634 [ + - ]: 31 : if (sm) {
1635 : 31 : sm->ctx->scard_ctx = ctx;
1636 : 31 : eap_register_scard_ctx(sm->eap, ctx);
1637 : : }
1638 : 31 : }
1639 : :
1640 : :
1641 : : /**
1642 : : * eapol_sm_notify_portControl - Notification of portControl changes
1643 : : * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1644 : : * @portControl: New value for portControl variable
1645 : : *
1646 : : * Notify EAPOL state machines that portControl variable has changed.
1647 : : */
1648 : 460 : void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
1649 : : {
1650 [ - + ]: 460 : if (sm == NULL)
1651 : 460 : return;
1652 : 460 : wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1653 : : "portControl=%s", eapol_port_control(portControl));
1654 : 460 : sm->portControl = portControl;
1655 : 460 : eapol_sm_step(sm);
1656 : : }
1657 : :
1658 : :
1659 : : /**
1660 : : * eapol_sm_notify_ctrl_attached - Notification of attached monitor
1661 : : * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1662 : : *
1663 : : * Notify EAPOL state machines that a monitor was attached to the control
1664 : : * interface to trigger re-sending of pending requests for user input.
1665 : : */
1666 : 17 : void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
1667 : : {
1668 [ - + ]: 17 : if (sm == NULL)
1669 : 17 : return;
1670 : 17 : eap_sm_notify_ctrl_attached(sm->eap);
1671 : : }
1672 : :
1673 : :
1674 : : /**
1675 : : * eapol_sm_notify_ctrl_response - Notification of received user input
1676 : : * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1677 : : *
1678 : : * Notify EAPOL state machines that a control response, i.e., user
1679 : : * input, was received in order to trigger retrying of a pending EAP request.
1680 : : */
1681 : 2 : void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
1682 : : {
1683 [ - + ]: 2 : if (sm == NULL)
1684 : 2 : return;
1685 [ + - ][ + - ]: 2 : if (sm->eapReqData && !sm->eapReq) {
1686 : 2 : wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
1687 : : "input) notification - retrying pending EAP "
1688 : : "Request");
1689 : 2 : sm->eapolEap = TRUE;
1690 : 2 : sm->eapReq = TRUE;
1691 : 2 : eapol_sm_step(sm);
1692 : : }
1693 : : }
1694 : :
1695 : :
1696 : : /**
1697 : : * eapol_sm_request_reauth - Request reauthentication
1698 : : * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1699 : : *
1700 : : * This function can be used to request EAPOL reauthentication, e.g., when the
1701 : : * current PMKSA entry is nearing expiration.
1702 : : */
1703 : 22 : void eapol_sm_request_reauth(struct eapol_sm *sm)
1704 : : {
1705 [ + - ][ - + ]: 22 : if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
1706 : 22 : return;
1707 : 22 : eapol_sm_txStart(sm);
1708 : : }
1709 : :
1710 : :
1711 : : /**
1712 : : * eapol_sm_notify_lower_layer_success - Notification of lower layer success
1713 : : * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1714 : : * @in_eapol_sm: Whether the caller is already running inside EAPOL state
1715 : : * machine loop (eapol_sm_step())
1716 : : *
1717 : : * Notify EAPOL (and EAP) state machines that a lower layer has detected a
1718 : : * successful authentication. This is used to recover from dropped EAP-Success
1719 : : * messages.
1720 : : */
1721 : 564 : void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm)
1722 : : {
1723 [ + + ]: 564 : if (sm == NULL)
1724 : 564 : return;
1725 : 552 : eap_notify_lower_layer_success(sm->eap);
1726 [ + + ]: 552 : if (!in_eapol_sm)
1727 : 548 : eapol_sm_step(sm);
1728 : : }
1729 : :
1730 : :
1731 : : /**
1732 : : * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid
1733 : : * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1734 : : */
1735 : 1796 : void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
1736 : : {
1737 [ + - ]: 1796 : if (sm)
1738 : 1796 : eap_invalidate_cached_session(sm->eap);
1739 : 1796 : }
1740 : :
1741 : :
1742 : 1515 : static struct eap_peer_config * eapol_sm_get_config(void *ctx)
1743 : : {
1744 : 1515 : struct eapol_sm *sm = ctx;
1745 [ + - ]: 1515 : return sm ? sm->config : NULL;
1746 : : }
1747 : :
1748 : :
1749 : 2182 : static struct wpabuf * eapol_sm_get_eapReqData(void *ctx)
1750 : : {
1751 : 2182 : struct eapol_sm *sm = ctx;
1752 [ + - ][ - + ]: 2182 : if (sm == NULL || sm->eapReqData == NULL)
1753 : 0 : return NULL;
1754 : :
1755 : 2182 : return sm->eapReqData;
1756 : : }
1757 : :
1758 : :
1759 : 60828 : static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
1760 : : {
1761 : 60828 : struct eapol_sm *sm = ctx;
1762 [ - + ]: 60828 : if (sm == NULL)
1763 : 0 : return FALSE;
1764 [ + + - - : 60828 : switch (variable) {
- + + + +
- ]
1765 : : case EAPOL_eapSuccess:
1766 : 552 : return sm->eapSuccess;
1767 : : case EAPOL_eapRestart:
1768 : 20281 : return sm->eapRestart;
1769 : : case EAPOL_eapFail:
1770 : 0 : return sm->eapFail;
1771 : : case EAPOL_eapResp:
1772 : 0 : return sm->eapResp;
1773 : : case EAPOL_eapNoResp:
1774 : 0 : return sm->eapNoResp;
1775 : : case EAPOL_eapReq:
1776 : 5778 : return sm->eapReq;
1777 : : case EAPOL_portEnabled:
1778 : 20450 : return sm->portEnabled;
1779 : : case EAPOL_altAccept:
1780 : 9178 : return sm->altAccept;
1781 : : case EAPOL_altReject:
1782 : 4589 : return sm->altReject;
1783 : : }
1784 : 60828 : return FALSE;
1785 : : }
1786 : :
1787 : :
1788 : 10926 : static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
1789 : : Boolean value)
1790 : : {
1791 : 10926 : struct eapol_sm *sm = ctx;
1792 [ - + ]: 10926 : if (sm == NULL)
1793 : 10926 : return;
1794 [ + + + + : 10926 : switch (variable) {
+ + - - -
- ]
1795 : : case EAPOL_eapSuccess:
1796 : 7047 : sm->eapSuccess = value;
1797 : 7047 : break;
1798 : : case EAPOL_eapRestart:
1799 : 352 : sm->eapRestart = value;
1800 : 352 : break;
1801 : : case EAPOL_eapFail:
1802 : 447 : sm->eapFail = value;
1803 : 447 : break;
1804 : : case EAPOL_eapResp:
1805 : 1357 : sm->eapResp = value;
1806 : 1357 : break;
1807 : : case EAPOL_eapNoResp:
1808 : 534 : sm->eapNoResp = value;
1809 : 534 : break;
1810 : : case EAPOL_eapReq:
1811 : 1189 : sm->eapReq = value;
1812 : 1189 : break;
1813 : : case EAPOL_portEnabled:
1814 : 0 : sm->portEnabled = value;
1815 : 0 : break;
1816 : : case EAPOL_altAccept:
1817 : 0 : sm->altAccept = value;
1818 : 0 : break;
1819 : : case EAPOL_altReject:
1820 : 0 : sm->altReject = value;
1821 : 0 : break;
1822 : : }
1823 : : }
1824 : :
1825 : :
1826 : 9178 : static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable)
1827 : : {
1828 : 9178 : struct eapol_sm *sm = ctx;
1829 [ - + ]: 9178 : if (sm == NULL)
1830 : 0 : return 0;
1831 [ + - ]: 9178 : switch (variable) {
1832 : : case EAPOL_idleWhile:
1833 : 9178 : return sm->idleWhile;
1834 : : }
1835 : 9178 : return 0;
1836 : : }
1837 : :
1838 : :
1839 : 10360 : static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
1840 : : unsigned int value)
1841 : : {
1842 : 10360 : struct eapol_sm *sm = ctx;
1843 [ - + ]: 10360 : if (sm == NULL)
1844 : 10360 : return;
1845 [ + - ]: 10360 : switch (variable) {
1846 : : case EAPOL_idleWhile:
1847 : 10360 : sm->idleWhile = value;
1848 [ + + ]: 10360 : if (sm->idleWhile > 0)
1849 : 1359 : eapol_enable_timer_tick(sm);
1850 : 10360 : break;
1851 : : }
1852 : : }
1853 : :
1854 : :
1855 : 1 : static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
1856 : : {
1857 : : #ifndef CONFIG_NO_CONFIG_BLOBS
1858 : 1 : struct eapol_sm *sm = ctx;
1859 [ + - ][ + - ]: 1 : if (sm && sm->ctx && sm->ctx->set_config_blob)
[ + - ]
1860 : 1 : sm->ctx->set_config_blob(sm->ctx->ctx, blob);
1861 : : #endif /* CONFIG_NO_CONFIG_BLOBS */
1862 : 1 : }
1863 : :
1864 : :
1865 : : static const struct wpa_config_blob *
1866 : 2 : eapol_sm_get_config_blob(void *ctx, const char *name)
1867 : : {
1868 : : #ifndef CONFIG_NO_CONFIG_BLOBS
1869 : 2 : struct eapol_sm *sm = ctx;
1870 [ + - ][ + - ]: 2 : if (sm && sm->ctx && sm->ctx->get_config_blob)
[ + - ]
1871 : 2 : return sm->ctx->get_config_blob(sm->ctx->ctx, name);
1872 : : else
1873 : 2 : return NULL;
1874 : : #else /* CONFIG_NO_CONFIG_BLOBS */
1875 : : return NULL;
1876 : : #endif /* CONFIG_NO_CONFIG_BLOBS */
1877 : : }
1878 : :
1879 : :
1880 : 0 : static void eapol_sm_notify_pending(void *ctx)
1881 : : {
1882 : 0 : struct eapol_sm *sm = ctx;
1883 [ # # ]: 0 : if (sm == NULL)
1884 : 0 : return;
1885 [ # # ][ # # ]: 0 : if (sm->eapReqData && !sm->eapReq) {
1886 : 0 : wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP "
1887 : : "state machine - retrying pending EAP Request");
1888 : 0 : sm->eapolEap = TRUE;
1889 : 0 : sm->eapReq = TRUE;
1890 : 0 : eapol_sm_step(sm);
1891 : : }
1892 : : }
1893 : :
1894 : :
1895 : : #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
1896 : 2 : static void eapol_sm_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field,
1897 : : const char *txt)
1898 : : {
1899 : 2 : struct eapol_sm *sm = ctx;
1900 : 2 : wpa_printf(MSG_DEBUG, "EAPOL: EAP parameter needed");
1901 [ + - ]: 2 : if (sm->ctx->eap_param_needed)
1902 : 2 : sm->ctx->eap_param_needed(sm->ctx->ctx, field, txt);
1903 : 2 : }
1904 : : #else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1905 : : #define eapol_sm_eap_param_needed NULL
1906 : : #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1907 : :
1908 : 109 : static void eapol_sm_notify_cert(void *ctx, int depth, const char *subject,
1909 : : const char *cert_hash,
1910 : : const struct wpabuf *cert)
1911 : : {
1912 : 109 : struct eapol_sm *sm = ctx;
1913 [ + - ]: 109 : if (sm->ctx->cert_cb)
1914 : 109 : sm->ctx->cert_cb(sm->ctx->ctx, depth, subject,
1915 : : cert_hash, cert);
1916 : 109 : }
1917 : :
1918 : :
1919 : 674 : static void eapol_sm_notify_status(void *ctx, const char *status,
1920 : : const char *parameter)
1921 : : {
1922 : 674 : struct eapol_sm *sm = ctx;
1923 : :
1924 [ + - ]: 674 : if (sm->ctx->status_cb)
1925 : 674 : sm->ctx->status_cb(sm->ctx->ctx, status, parameter);
1926 : 674 : }
1927 : :
1928 : :
1929 : 8 : static void eapol_sm_set_anon_id(void *ctx, const u8 *id, size_t len)
1930 : : {
1931 : 8 : struct eapol_sm *sm = ctx;
1932 : :
1933 [ + - ]: 8 : if (sm->ctx->set_anon_id)
1934 : 8 : sm->ctx->set_anon_id(sm->ctx->ctx, id, len);
1935 : 8 : }
1936 : :
1937 : :
1938 : : static struct eapol_callbacks eapol_cb =
1939 : : {
1940 : : eapol_sm_get_config,
1941 : : eapol_sm_get_bool,
1942 : : eapol_sm_set_bool,
1943 : : eapol_sm_get_int,
1944 : : eapol_sm_set_int,
1945 : : eapol_sm_get_eapReqData,
1946 : : eapol_sm_set_config_blob,
1947 : : eapol_sm_get_config_blob,
1948 : : eapol_sm_notify_pending,
1949 : : eapol_sm_eap_param_needed,
1950 : : eapol_sm_notify_cert,
1951 : : eapol_sm_notify_status,
1952 : : eapol_sm_set_anon_id
1953 : : };
1954 : :
1955 : :
1956 : : /**
1957 : : * eapol_sm_init - Initialize EAPOL state machine
1958 : : * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
1959 : : * and EAPOL state machine will free it in eapol_sm_deinit()
1960 : : * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
1961 : : *
1962 : : * Allocate and initialize an EAPOL state machine.
1963 : : */
1964 : 31 : struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
1965 : : {
1966 : : struct eapol_sm *sm;
1967 : : struct eap_config conf;
1968 : 31 : sm = os_zalloc(sizeof(*sm));
1969 [ - + ]: 31 : if (sm == NULL)
1970 : 0 : return NULL;
1971 : 31 : sm->ctx = ctx;
1972 : :
1973 : 31 : sm->portControl = Auto;
1974 : :
1975 : : /* Supplicant PAE state machine */
1976 : 31 : sm->heldPeriod = 60;
1977 : 31 : sm->startPeriod = 30;
1978 : 31 : sm->maxStart = 3;
1979 : :
1980 : : /* Supplicant Backend state machine */
1981 : 31 : sm->authPeriod = 30;
1982 : :
1983 : 31 : os_memset(&conf, 0, sizeof(conf));
1984 : 31 : conf.opensc_engine_path = ctx->opensc_engine_path;
1985 : 31 : conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
1986 : 31 : conf.pkcs11_module_path = ctx->pkcs11_module_path;
1987 : 31 : conf.wps = ctx->wps;
1988 : 31 : conf.cert_in_cb = ctx->cert_in_cb;
1989 : :
1990 : 31 : sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
1991 [ - + ]: 31 : if (sm->eap == NULL) {
1992 : 0 : os_free(sm);
1993 : 0 : return NULL;
1994 : : }
1995 : :
1996 : : #ifdef CONFIG_EAP_PROXY
1997 : : sm->use_eap_proxy = FALSE;
1998 : : sm->eap_proxy = eap_proxy_init(sm, &eapol_cb, sm->ctx->msg_ctx);
1999 : : if (sm->eap_proxy == NULL) {
2000 : : wpa_printf(MSG_ERROR, "Unable to initialize EAP Proxy");
2001 : : }
2002 : : #endif /* CONFIG_EAP_PROXY */
2003 : :
2004 : : /* Initialize EAPOL state machines */
2005 : 31 : sm->initialize = TRUE;
2006 : 31 : eapol_sm_step(sm);
2007 : 31 : sm->initialize = FALSE;
2008 : 31 : eapol_sm_step(sm);
2009 : :
2010 : 31 : sm->timer_tick_enabled = 1;
2011 : 31 : eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
2012 : :
2013 : 31 : return sm;
2014 : : }
2015 : :
2016 : :
2017 : : /**
2018 : : * eapol_sm_deinit - Deinitialize EAPOL state machine
2019 : : * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
2020 : : *
2021 : : * Deinitialize and free EAPOL state machine.
2022 : : */
2023 : 31 : void eapol_sm_deinit(struct eapol_sm *sm)
2024 : : {
2025 [ - + ]: 31 : if (sm == NULL)
2026 : 31 : return;
2027 : 31 : eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
2028 : 31 : eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
2029 : 31 : eap_peer_sm_deinit(sm->eap);
2030 : : #ifdef CONFIG_EAP_PROXY
2031 : : eap_proxy_deinit(sm->eap_proxy);
2032 : : #endif /* CONFIG_EAP_PROXY */
2033 : 31 : os_free(sm->last_rx_key);
2034 : 31 : wpabuf_free(sm->eapReqData);
2035 : 31 : os_free(sm->ctx);
2036 : 31 : os_free(sm);
2037 : : }
2038 : :
2039 : :
2040 : 31 : void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
2041 : : struct ext_password_data *ext)
2042 : : {
2043 [ + - ][ + - ]: 31 : if (sm && sm->eap)
2044 : 31 : eap_sm_set_ext_pw_ctx(sm->eap, ext);
2045 : 31 : }
2046 : :
2047 : :
2048 : 64 : int eapol_sm_failed(struct eapol_sm *sm)
2049 : : {
2050 [ - + ]: 64 : if (sm == NULL)
2051 : 0 : return 0;
2052 [ + + ][ - + ]: 64 : return !sm->eapSuccess && sm->eapFail;
2053 : : }
2054 : :
2055 : :
2056 : 0 : int eapol_sm_get_eap_proxy_imsi(struct eapol_sm *sm, char *imsi, size_t *len)
2057 : : {
2058 : : #ifdef CONFIG_EAP_PROXY
2059 : : if (sm->eap_proxy == NULL)
2060 : : return -1;
2061 : : return eap_proxy_get_imsi(sm->eap_proxy, imsi, len);
2062 : : #else /* CONFIG_EAP_PROXY */
2063 : 0 : return -1;
2064 : : #endif /* CONFIG_EAP_PROXY */
2065 : : }
|