Merge from vendor branch GDB:
[dragonfly.git] / contrib / wpa_supplicant-0.4.9 / 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
1402         /* Make sure we do not start sending EAPOL-Start frames first, but
1403          * instead move to RESTART state to start EAPOL authentication. */
1404         sm->startWhen = 3;
1405
1406         if (sm->ctx->aborted_cached)
1407                 sm->ctx->aborted_cached(sm->ctx->ctx);
1408 }
1409
1410
1411 /**
1412  * eapol_sm_register_scard_ctx - Notification of smart card context
1413  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1414  * @ctx: Context data for smart card operations
1415  *
1416  * Notify EAPOL state machines of context data for smart card operations. This
1417  * context data will be used as a parameter for scard_*() functions.
1418  */
1419 void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
1420 {
1421         if (sm) {
1422                 sm->ctx->scard_ctx = ctx;
1423                 eap_register_scard_ctx(sm->eap, ctx);
1424         }
1425 }
1426
1427
1428 /**
1429  * eapol_sm_notify_portControl - Notification of portControl changes
1430  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1431  * @portControl: New value for portControl variable
1432  *
1433  * Notify EAPOL state machines that portControl variable has changed.
1434  */
1435 void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
1436 {
1437         if (sm == NULL)
1438                 return;
1439         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1440                    "portControl=%s", eapol_port_control(portControl));
1441         sm->portControl = portControl;
1442         eapol_sm_step(sm);
1443 }
1444
1445
1446 /**
1447  * eapol_sm_notify_ctrl_attached - Notification of attached monitor
1448  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1449  *
1450  * Notify EAPOL state machines that a monitor was attached to the control
1451  * interface to trigger re-sending of pending requests for user input.
1452  */
1453 void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
1454 {
1455         if (sm == NULL)
1456                 return;
1457         eap_sm_notify_ctrl_attached(sm->eap);
1458 }
1459
1460
1461 /**
1462  * eapol_sm_notify_ctrl_response - Notification of received user input
1463  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1464  *
1465  * Notify EAPOL state machines that a control response, i.e., user
1466  * input, was received in order to trigger retrying of a pending EAP request.
1467  */
1468 void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
1469 {
1470         if (sm == NULL)
1471                 return;
1472         if (sm->eapReqData && !sm->eapReq) {
1473                 wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
1474                            "input) notification - retrying pending EAP "
1475                            "Request");
1476                 sm->eapolEap = TRUE;
1477                 sm->eapReq = TRUE;
1478                 eapol_sm_step(sm);
1479         }
1480 }
1481
1482
1483 /**
1484  * eapol_sm_request_reauth - Request reauthentication
1485  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1486  *
1487  * This function can be used to request EAPOL reauthentication, e.g., when the
1488  * current PMKSA entry is nearing expiration.
1489  */
1490 void eapol_sm_request_reauth(struct eapol_sm *sm)
1491 {
1492         if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
1493                 return;
1494         eapol_sm_txStart(sm);
1495 }
1496
1497
1498 /**
1499  * eapol_sm_notify_lower_layer_success - Notification of lower layer success
1500  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1501  *
1502  * Notify EAPOL (and EAP) state machines that a lower layer has detected a
1503  * successful authentication. This is used to recover from dropped EAP-Success
1504  * messages.
1505  */
1506 void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm)
1507 {
1508         if (sm == NULL)
1509                 return;
1510         eap_notify_lower_layer_success(sm->eap);
1511 }
1512
1513
1514 static struct wpa_ssid * eapol_sm_get_config(void *ctx)
1515 {
1516         struct eapol_sm *sm = ctx;
1517         return sm ? sm->config : NULL;
1518 }
1519
1520
1521 static u8 * eapol_sm_get_eapReqData(void *ctx, size_t *len)
1522 {
1523         struct eapol_sm *sm = ctx;
1524         if (sm == NULL || sm->eapReqData == NULL) {
1525                 *len = 0;
1526                 return NULL;
1527         }
1528
1529         *len = sm->eapReqDataLen;
1530         return sm->eapReqData;
1531 }
1532
1533
1534 static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
1535 {
1536         struct eapol_sm *sm = ctx;
1537         if (sm == NULL)
1538                 return FALSE;
1539         switch (variable) {
1540         case EAPOL_eapSuccess:
1541                 return sm->eapSuccess;
1542         case EAPOL_eapRestart:
1543                 return sm->eapRestart;
1544         case EAPOL_eapFail:
1545                 return sm->eapFail;
1546         case EAPOL_eapResp:
1547                 return sm->eapResp;
1548         case EAPOL_eapNoResp:
1549                 return sm->eapNoResp;
1550         case EAPOL_eapReq:
1551                 return sm->eapReq;
1552         case EAPOL_portEnabled:
1553                 return sm->portEnabled;
1554         case EAPOL_altAccept:
1555                 return sm->altAccept;
1556         case EAPOL_altReject:
1557                 return sm->altReject;
1558         }
1559         return FALSE;
1560 }
1561
1562
1563 static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
1564                               Boolean value)
1565 {
1566         struct eapol_sm *sm = ctx;
1567         if (sm == NULL)
1568                 return;
1569         switch (variable) {
1570         case EAPOL_eapSuccess:
1571                 sm->eapSuccess = value;
1572                 break;
1573         case EAPOL_eapRestart:
1574                 sm->eapRestart = value;
1575                 break;
1576         case EAPOL_eapFail:
1577                 sm->eapFail = value;
1578                 break;
1579         case EAPOL_eapResp:
1580                 sm->eapResp = value;
1581                 break;
1582         case EAPOL_eapNoResp:
1583                 sm->eapNoResp = value;
1584                 break;
1585         case EAPOL_eapReq:
1586                 sm->eapReq = value;
1587                 break;
1588         case EAPOL_portEnabled:
1589                 sm->portEnabled = value;
1590                 break;
1591         case EAPOL_altAccept:
1592                 sm->altAccept = value;
1593                 break;
1594         case EAPOL_altReject:
1595                 sm->altReject = value;
1596                 break;
1597         }
1598 }
1599
1600
1601 static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable)
1602 {
1603         struct eapol_sm *sm = ctx;
1604         if (sm == NULL)
1605                 return 0;
1606         switch (variable) {
1607         case EAPOL_idleWhile:
1608                 return sm->idleWhile;
1609         }
1610         return 0;
1611 }
1612
1613
1614 static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
1615                              unsigned int value)
1616 {
1617         struct eapol_sm *sm = ctx;
1618         if (sm == NULL)
1619                 return;
1620         switch (variable) {
1621         case EAPOL_idleWhile:
1622                 sm->idleWhile = value;
1623                 break;
1624         }
1625 }
1626
1627
1628 static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
1629 {
1630         struct eapol_sm *sm = ctx;
1631         if (sm && sm->ctx && sm->ctx->set_config_blob)
1632                 sm->ctx->set_config_blob(sm->ctx->ctx, blob);
1633 }
1634
1635
1636 static const struct wpa_config_blob *
1637 eapol_sm_get_config_blob(void *ctx, const char *name)
1638 {
1639         struct eapol_sm *sm = ctx;
1640         if (sm && sm->ctx && sm->ctx->get_config_blob)
1641                 return sm->ctx->get_config_blob(sm->ctx->ctx, name);
1642         else
1643                 return NULL;
1644 }
1645
1646
1647 static struct eapol_callbacks eapol_cb =
1648 {
1649         .get_config = eapol_sm_get_config,
1650         .get_bool = eapol_sm_get_bool,
1651         .set_bool = eapol_sm_set_bool,
1652         .get_int = eapol_sm_get_int,
1653         .set_int = eapol_sm_set_int,
1654         .get_eapReqData = eapol_sm_get_eapReqData,
1655         .set_config_blob = eapol_sm_set_config_blob,
1656         .get_config_blob = eapol_sm_get_config_blob,
1657 };
1658
1659
1660 /**
1661  * eapol_sm_init - Initialize EAPOL state machine
1662  * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
1663  * and EAPOL state machine will free it in eapol_sm_deinit()
1664  * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
1665  *
1666  * Allocate and initialize an EAPOL state machine.
1667  */
1668 struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
1669 {
1670         struct eapol_sm *sm;
1671         struct eap_config conf;
1672         sm = malloc(sizeof(*sm));
1673         if (sm == NULL)
1674                 return NULL;
1675         memset(sm, 0, sizeof(*sm));
1676         sm->ctx = ctx;
1677
1678         sm->portControl = Auto;
1679
1680         /* Supplicant PAE state machine */
1681         sm->heldPeriod = 60;
1682         sm->startPeriod = 30;
1683         sm->maxStart = 3;
1684
1685         /* Supplicant Backend state machine */
1686         sm->authPeriod = 30;
1687
1688         memset(&conf, 0, sizeof(conf));
1689         conf.opensc_engine_path = ctx->opensc_engine_path;
1690         conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
1691         conf.pkcs11_module_path = ctx->pkcs11_module_path;
1692
1693         sm->eap = eap_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
1694         if (sm->eap == NULL) {
1695                 free(sm);
1696                 return NULL;
1697         }
1698
1699         /* Initialize EAPOL state machines */
1700         sm->initialize = TRUE;
1701         eapol_sm_step(sm);
1702         sm->initialize = FALSE;
1703         eapol_sm_step(sm);
1704
1705         eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
1706
1707         return sm;
1708 }
1709
1710
1711 /**
1712  * eapol_sm_deinit - Deinitialize EAPOL state machine
1713  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1714  *
1715  * Deinitialize and free EAPOL state machine.
1716  */
1717 void eapol_sm_deinit(struct eapol_sm *sm)
1718 {
1719         if (sm == NULL)
1720                 return;
1721         eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
1722         eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
1723         eap_sm_deinit(sm->eap);
1724         free(sm->last_rx_key);
1725         free(sm->eapReqData);
1726         free(sm->ctx);
1727         free(sm);
1728 }