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