]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/wpa_supplicant/eap.c
This commit was generated by cvs2svn to compensate for changes in r147013,
[FreeBSD/FreeBSD.git] / contrib / wpa_supplicant / eap.c
1 /*
2  * WPA Supplicant / EAP 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 "eap_i.h"
21 #include "wpa_supplicant.h"
22 #include "config_ssid.h"
23 #include "tls.h"
24 #include "md5.h"
25
26
27 #define EAP_MAX_AUTH_ROUNDS 50
28
29
30 #ifdef EAP_MD5
31 extern const struct eap_method eap_method_md5;
32 #endif
33 #ifdef EAP_TLS
34 extern const struct eap_method eap_method_tls;
35 #endif
36 #ifdef EAP_MSCHAPv2
37 extern const struct eap_method eap_method_mschapv2;
38 #endif
39 #ifdef EAP_PEAP
40 extern const struct eap_method eap_method_peap;
41 #endif
42 #ifdef EAP_TTLS
43 extern const struct eap_method eap_method_ttls;
44 #endif
45 #ifdef EAP_GTC
46 extern const struct eap_method eap_method_gtc;
47 #endif
48 #ifdef EAP_OTP
49 extern const struct eap_method eap_method_otp;
50 #endif
51 #ifdef EAP_SIM
52 extern const struct eap_method eap_method_sim;
53 #endif
54 #ifdef EAP_LEAP
55 extern const struct eap_method eap_method_leap;
56 #endif
57 #ifdef EAP_PSK
58 extern const struct eap_method eap_method_psk;
59 #endif
60 #ifdef EAP_AKA
61 extern const struct eap_method eap_method_aka;
62 #endif
63 #ifdef EAP_FAST
64 extern const struct eap_method eap_method_fast;
65 #endif
66
67 static const struct eap_method *eap_methods[] =
68 {
69 #ifdef EAP_MD5
70         &eap_method_md5,
71 #endif
72 #ifdef EAP_TLS
73         &eap_method_tls,
74 #endif
75 #ifdef EAP_MSCHAPv2
76         &eap_method_mschapv2,
77 #endif
78 #ifdef EAP_PEAP
79         &eap_method_peap,
80 #endif
81 #ifdef EAP_TTLS
82         &eap_method_ttls,
83 #endif
84 #ifdef EAP_GTC
85         &eap_method_gtc,
86 #endif
87 #ifdef EAP_OTP
88         &eap_method_otp,
89 #endif
90 #ifdef EAP_SIM
91         &eap_method_sim,
92 #endif
93 #ifdef EAP_LEAP
94         &eap_method_leap,
95 #endif
96 #ifdef EAP_PSK
97         &eap_method_psk,
98 #endif
99 #ifdef EAP_AKA
100         &eap_method_aka,
101 #endif
102 #ifdef EAP_FAST
103         &eap_method_fast,
104 #endif
105 };
106 #define NUM_EAP_METHODS (sizeof(eap_methods) / sizeof(eap_methods[0]))
107
108
109 const struct eap_method * eap_sm_get_eap_methods(int method)
110 {
111         int i;
112         for (i = 0; i < NUM_EAP_METHODS; i++) {
113                 if (eap_methods[i]->method == method)
114                         return eap_methods[i];
115         }
116         return NULL;
117 }
118
119
120 static Boolean eap_sm_allowMethod(struct eap_sm *sm, EapType method);
121 static u8 * eap_sm_buildNak(struct eap_sm *sm, int id, size_t *len);
122 static void eap_sm_processIdentity(struct eap_sm *sm, u8 *req, size_t len);
123 static void eap_sm_processNotify(struct eap_sm *sm, u8 *req, size_t len);
124 static u8 * eap_sm_buildNotify(struct eap_sm *sm, int id, size_t *len);
125 static void eap_sm_parseEapReq(struct eap_sm *sm, u8 *req, size_t len);
126 static const char * eap_sm_method_state_txt(int state);
127 static const char * eap_sm_decision_txt(int decision);
128
129
130 /* Definitions for clarifying state machine implementation */
131 #define SM_STATE(machine, state) \
132 static void sm_ ## machine ## _ ## state ## _Enter(struct eap_sm *sm, \
133         int global)
134
135 #define SM_ENTRY(machine, state) \
136 if (!global || sm->machine ## _state != machine ## _ ## state) { \
137         sm->changed = TRUE; \
138         wpa_printf(MSG_DEBUG, "EAP: " #machine " entering state " #state); \
139 } \
140 sm->machine ## _state = machine ## _ ## state;
141
142 #define SM_ENTER(machine, state) \
143 sm_ ## machine ## _ ## state ## _Enter(sm, 0)
144 #define SM_ENTER_GLOBAL(machine, state) \
145 sm_ ## machine ## _ ## state ## _Enter(sm, 1)
146
147 #define SM_STEP(machine) \
148 static void sm_ ## machine ## _Step(struct eap_sm *sm)
149
150 #define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
151
152
153 static Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
154 {
155         return sm->eapol_cb->get_bool(sm->eapol_ctx, var);
156 }
157
158
159 static void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var,
160                            Boolean value)
161 {
162         sm->eapol_cb->set_bool(sm->eapol_ctx, var, value);
163 }
164
165
166 static unsigned int eapol_get_int(struct eap_sm *sm, enum eapol_int_var var)
167 {
168         return sm->eapol_cb->get_int(sm->eapol_ctx, var);
169 }
170
171
172 static void eapol_set_int(struct eap_sm *sm, enum eapol_int_var var,
173                           unsigned int value)
174 {
175         sm->eapol_cb->set_int(sm->eapol_ctx, var, value);
176 }
177
178
179 static u8 * eapol_get_eapReqData(struct eap_sm *sm, size_t *len)
180 {
181         return sm->eapol_cb->get_eapReqData(sm->eapol_ctx, len);
182 }
183
184
185 static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)
186 {
187         if (sm->m == NULL || sm->eap_method_priv == NULL)
188                 return;
189
190         wpa_printf(MSG_DEBUG, "EAP: deinitialize previously used EAP method "
191                    "(%d, %s) at %s", sm->selectedMethod, sm->m->name, txt);
192         sm->m->deinit(sm, sm->eap_method_priv);
193         sm->eap_method_priv = NULL;
194         sm->m = NULL;
195 }
196
197
198 SM_STATE(EAP, INITIALIZE)
199 {
200         SM_ENTRY(EAP, INITIALIZE);
201         if (sm->fast_reauth && sm->m && sm->m->has_reauth_data &&
202             sm->m->has_reauth_data(sm, sm->eap_method_priv)) {
203                 wpa_printf(MSG_DEBUG, "EAP: maintaining EAP method data for "
204                            "fast reauthentication");
205                 sm->m->deinit_for_reauth(sm, sm->eap_method_priv);
206         } else {
207                 eap_deinit_prev_method(sm, "INITIALIZE");
208         }
209         sm->selectedMethod = EAP_TYPE_NONE;
210         sm->methodState = METHOD_NONE;
211         sm->allowNotifications = TRUE;
212         sm->decision = DECISION_FAIL;
213         eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
214         eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
215         eapol_set_bool(sm, EAPOL_eapFail, FALSE);
216         free(sm->eapKeyData);
217         sm->eapKeyData = NULL;
218         sm->eapKeyAvailable = FALSE;
219         eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
220         sm->lastId = -1; /* new session - make sure this does not match with
221                           * the first EAP-Packet */
222         /* draft-ietf-eap-statemachine-02.pdf does not reset eapResp and
223          * eapNoResp here. However, this seemed to be able to trigger cases
224          * where both were set and if EAPOL state machine uses eapNoResp first,
225          * it may end up not sending a real reply correctly. This occurred
226          * when the workaround in FAIL state set eapNoResp = TRUE.. Maybe that
227          * workaround needs to be fixed to do something else(?) */
228         eapol_set_bool(sm, EAPOL_eapResp, FALSE);
229         eapol_set_bool(sm, EAPOL_eapNoResp, FALSE);
230         sm->num_rounds = 0;
231 }
232
233
234 SM_STATE(EAP, DISABLED)
235 {
236         SM_ENTRY(EAP, DISABLED);
237         sm->num_rounds = 0;
238 }
239
240
241 SM_STATE(EAP, IDLE)
242 {
243         SM_ENTRY(EAP, IDLE);
244 }
245
246
247 SM_STATE(EAP, RECEIVED)
248 {
249         u8 *eapReqData;
250         size_t eapReqDataLen;
251
252         SM_ENTRY(EAP, RECEIVED);
253         eapReqData = eapol_get_eapReqData(sm, &eapReqDataLen);
254         /* parse rxReq, rxSuccess, rxFailure, reqId, reqMethod */
255         eap_sm_parseEapReq(sm, eapReqData, eapReqDataLen);
256         sm->num_rounds++;
257 }
258
259
260 SM_STATE(EAP, GET_METHOD)
261 {
262         SM_ENTRY(EAP, GET_METHOD);
263         if (eap_sm_allowMethod(sm, sm->reqMethod)) {
264                 int reinit = 0;
265                 if (sm->fast_reauth &&
266                     sm->m && sm->m->method == sm->reqMethod &&
267                     sm->m->has_reauth_data &&
268                     sm->m->has_reauth_data(sm, sm->eap_method_priv)) {
269                         wpa_printf(MSG_DEBUG, "EAP: using previous method data"
270                                    " for fast re-authentication");
271                         reinit = 1;
272                 } else
273                         eap_deinit_prev_method(sm, "GET_METHOD");
274                 sm->selectedMethod = sm->reqMethod;
275                 if (sm->m == NULL)
276                         sm->m = eap_sm_get_eap_methods(sm->selectedMethod);
277                 if (sm->m) {
278                         wpa_printf(MSG_DEBUG, "EAP: initialize selected EAP "
279                                    "method (%d, %s)",
280                                    sm->selectedMethod, sm->m->name);
281                         if (reinit)
282                                 sm->eap_method_priv = sm->m->init_for_reauth(
283                                         sm, sm->eap_method_priv);
284                         else
285                                 sm->eap_method_priv = sm->m->init(sm);
286                         if (sm->eap_method_priv == NULL) {
287                                 wpa_printf(MSG_DEBUG, "EAP: Failed to "
288                                            "initialize EAP method %d",
289                                            sm->selectedMethod);
290                                 sm->m = NULL;
291                                 sm->methodState = METHOD_NONE;
292                                 sm->selectedMethod = EAP_TYPE_NONE;
293                         } else {
294                                 sm->methodState = METHOD_INIT;
295                                 return;
296                         }
297                 }
298         }
299
300         free(sm->eapRespData);
301         sm->eapRespData = eap_sm_buildNak(sm, sm->reqId, &sm->eapRespDataLen);
302 }
303
304
305 SM_STATE(EAP, METHOD)
306 {
307         u8 *eapReqData;
308         size_t eapReqDataLen;
309         struct eap_method_ret ret;
310
311         SM_ENTRY(EAP, METHOD);
312         if (sm->m == NULL) {
313                 wpa_printf(MSG_WARNING, "EAP::METHOD - method not selected");
314                 return;
315         }
316
317         eapReqData = eapol_get_eapReqData(sm, &eapReqDataLen);
318
319         /* Get ignore, methodState, decision, allowNotifications, and
320          * eapRespData. */
321         memset(&ret, 0, sizeof(ret));
322         ret.ignore = sm->ignore;
323         ret.methodState = sm->methodState;
324         ret.decision = sm->decision;
325         ret.allowNotifications = sm->allowNotifications;
326         free(sm->eapRespData);
327         sm->eapRespData = sm->m->process(sm, sm->eap_method_priv, &ret,
328                                          eapReqData, eapReqDataLen,
329                                          &sm->eapRespDataLen);
330         wpa_printf(MSG_DEBUG, "EAP: method process -> ignore=%s "
331                    "methodState=%s decision=%s",
332                    ret.ignore ? "TRUE" : "FALSE",
333                    eap_sm_method_state_txt(ret.methodState),
334                    eap_sm_decision_txt(ret.decision));
335
336         sm->ignore = ret.ignore;
337         if (sm->ignore)
338                 return;
339         sm->methodState = ret.methodState;
340         sm->decision = ret.decision;
341         sm->allowNotifications = ret.allowNotifications;
342
343         if (sm->m->isKeyAvailable && sm->m->getKey &&
344             sm->m->isKeyAvailable(sm, sm->eap_method_priv)) {
345                 free(sm->eapKeyData);
346                 sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
347                                                &sm->eapKeyDataLen);
348         }
349 }
350
351
352 SM_STATE(EAP, SEND_RESPONSE)
353 {
354         SM_ENTRY(EAP, SEND_RESPONSE);
355         free(sm->lastRespData);
356         if (sm->eapRespData) {
357                 if (sm->workaround)
358                         memcpy(sm->last_md5, sm->req_md5, 16);
359                 sm->lastId = sm->reqId;
360                 sm->lastRespData = malloc(sm->eapRespDataLen);
361                 if (sm->lastRespData) {
362                         memcpy(sm->lastRespData, sm->eapRespData,
363                                sm->eapRespDataLen);
364                         sm->lastRespDataLen = sm->eapRespDataLen;
365                 }
366                 eapol_set_bool(sm, EAPOL_eapResp, TRUE);
367         } else
368                 sm->lastRespData = NULL;
369         eapol_set_bool(sm, EAPOL_eapReq, FALSE);
370         eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
371 }
372
373
374 SM_STATE(EAP, DISCARD)
375 {
376         SM_ENTRY(EAP, DISCARD);
377         eapol_set_bool(sm, EAPOL_eapReq, FALSE);
378         eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
379 }
380
381
382 SM_STATE(EAP, IDENTITY)
383 {
384         u8 *eapReqData;
385         size_t eapReqDataLen;
386
387         SM_ENTRY(EAP, IDENTITY);
388         eapReqData = eapol_get_eapReqData(sm, &eapReqDataLen);
389         eap_sm_processIdentity(sm, eapReqData, eapReqDataLen);
390         free(sm->eapRespData);
391         sm->eapRespData = eap_sm_buildIdentity(sm, sm->reqId,
392                                                &sm->eapRespDataLen, 0);
393 }
394
395
396 SM_STATE(EAP, NOTIFICATION)
397 {
398         u8 *eapReqData;
399         size_t eapReqDataLen;
400
401         SM_ENTRY(EAP, NOTIFICATION);
402         eapReqData = eapol_get_eapReqData(sm, &eapReqDataLen);
403         eap_sm_processNotify(sm, eapReqData, eapReqDataLen);
404         free(sm->eapRespData);
405         sm->eapRespData = eap_sm_buildNotify(sm, sm->reqId,
406                                              &sm->eapRespDataLen);
407 }
408
409
410 SM_STATE(EAP, RETRANSMIT)
411 {
412         SM_ENTRY(EAP, RETRANSMIT);
413         free(sm->eapRespData);
414         if (sm->lastRespData) {
415                 sm->eapRespData = malloc(sm->lastRespDataLen);
416                 if (sm->eapRespData) {
417                         memcpy(sm->eapRespData, sm->lastRespData,
418                                sm->lastRespDataLen);
419                         sm->eapRespDataLen = sm->lastRespDataLen;
420                 }
421         } else
422                 sm->eapRespData = NULL;
423 }
424
425
426 SM_STATE(EAP, SUCCESS)
427 {
428         SM_ENTRY(EAP, SUCCESS);
429         if (sm->eapKeyData != NULL)
430                 sm->eapKeyAvailable = TRUE;
431         eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
432         /* draft-ietf-eap-statemachine-02.pdf does not clear eapReq here, but
433          * this seems to be required to avoid processing the same request
434          * twice when state machine is initialized. */
435         eapol_set_bool(sm, EAPOL_eapReq, FALSE);
436         /* draft-ietf-eap-statemachine-02.pdf does not set eapNoResp here, but
437          * this seems to be required to get EAPOL Supplicant backend state
438          * machine into SUCCESS state. In addition, either eapResp or eapNoResp
439          * is required to be set after processing the received EAP frame. */
440         eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
441 }
442
443
444 SM_STATE(EAP, FAILURE)
445 {
446         SM_ENTRY(EAP, FAILURE);
447         eapol_set_bool(sm, EAPOL_eapFail, TRUE);
448         /* draft-ietf-eap-statemachine-02.pdf does not clear eapReq here, but
449          * this seems to be required to avoid processing the same request
450          * twice when state machine is initialized. */
451         eapol_set_bool(sm, EAPOL_eapReq, FALSE);
452         /* draft-ietf-eap-statemachine-02.pdf does not set eapNoResp here.
453          * However, either eapResp or eapNoResp is required to be set after
454          * processing the received EAP frame. */
455         eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
456 }
457
458
459 static int eap_success_workaround(struct eap_sm *sm, int reqId, int lastId)
460 {
461         /* At least Microsoft IAS and Meetinghouse Aegis seem to be sending
462          * EAP-Success/Failure with lastId + 1 even though RFC 3748 and
463          * draft-ietf-eap-statemachine-05.pdf require that reqId == lastId.
464          * Accept this kind of Id if EAP workarounds are enabled. These are
465          * unauthenticated plaintext messages, so this should have minimal
466          * security implications (bit easier to fake EAP-Success/Failure). */
467         if (sm->workaround && reqId == ((lastId + 1) & 0xff)) {
468                 wpa_printf(MSG_DEBUG, "EAP: Workaround for unexpected "
469                            "identifier field in EAP Success: "
470                            "reqId=%d lastId=%d (these are supposed to be "
471                            "same)", reqId, lastId);
472                 return 1;
473         }
474         return 0;
475 }
476
477
478 SM_STEP(EAP)
479 {
480         int duplicate;
481
482         if (eapol_get_bool(sm, EAPOL_eapRestart) &&
483             eapol_get_bool(sm, EAPOL_portEnabled))
484                 SM_ENTER_GLOBAL(EAP, INITIALIZE);
485         else if (!eapol_get_bool(sm, EAPOL_portEnabled))
486                 SM_ENTER_GLOBAL(EAP, DISABLED);
487         else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
488                 if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
489                         wpa_printf(MSG_DEBUG, "EAP: more than %d "
490                                    "authentication rounds - abort",
491                                    EAP_MAX_AUTH_ROUNDS);
492                         sm->num_rounds++;
493                         SM_ENTER_GLOBAL(EAP, FAILURE);
494                 }
495         } else switch (sm->EAP_state) {
496         case EAP_INITIALIZE:
497                 SM_ENTER(EAP, IDLE);
498                 break;
499         case EAP_DISABLED:
500                 if (eapol_get_bool(sm, EAPOL_portEnabled))
501                         SM_ENTER(EAP, INITIALIZE);
502                 break;
503         case EAP_IDLE:
504                 if (eapol_get_bool(sm, EAPOL_eapReq))
505                         SM_ENTER(EAP, RECEIVED);
506                 else if ((eapol_get_bool(sm, EAPOL_altAccept) &&
507                           sm->decision != DECISION_FAIL) ||
508                          (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
509                           sm->decision == DECISION_UNCOND_SUCC))
510                         SM_ENTER(EAP, SUCCESS);
511                 else if (eapol_get_bool(sm, EAPOL_altReject) ||
512                          (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
513                           sm->decision != DECISION_UNCOND_SUCC) ||
514                          (eapol_get_bool(sm, EAPOL_altAccept) &&
515                           sm->methodState != METHOD_CONT &&
516                           sm->decision == DECISION_FAIL))
517                         SM_ENTER(EAP, FAILURE);
518                 else if (sm->selectedMethod == EAP_TYPE_LEAP &&
519                          sm->leap_done && sm->decision != DECISION_FAIL &&
520                          sm->methodState == METHOD_DONE)
521                         SM_ENTER(EAP, SUCCESS);
522                 else if (sm->selectedMethod == EAP_TYPE_PEAP &&
523                          sm->peap_done && sm->decision != DECISION_FAIL &&
524                          sm->methodState == METHOD_DONE)
525                         SM_ENTER(EAP, SUCCESS);
526                 break;
527         case EAP_RECEIVED:
528                 duplicate = sm->reqId == sm->lastId;
529                 if (sm->workaround && duplicate &&
530                     memcmp(sm->req_md5, sm->last_md5, 16) != 0) {
531                         /* draft-ietf-eap-statemachine-05.txt uses
532                          * (reqId == lastId) as the only verification for
533                          * duplicate EAP requests. However, this misses cases
534                          * where the AS is incorrectly using the same id again;
535                          * and unfortunately, such implementations exist. Use
536                          * MD5 hash as an extra verification for the packets
537                          * being duplicate to workaround these issues. */
538                         wpa_printf(MSG_DEBUG, "EAP: AS used the same Id again,"
539                                    " but EAP packets were not identical");
540                         wpa_printf(MSG_DEBUG, "EAP: workaround - assume this "
541                                    "is not a duplicate packet");
542                         duplicate = 0;
543                 }
544
545                 if (sm->rxSuccess &&
546                     (sm->reqId == sm->lastId ||
547                      eap_success_workaround(sm, sm->reqId, sm->lastId)) &&
548                     sm->decision != DECISION_FAIL)
549                         SM_ENTER(EAP, SUCCESS);
550                 else if (sm->methodState != METHOD_CONT &&
551                          ((sm->rxFailure &&
552                            sm->decision != DECISION_UNCOND_SUCC) ||
553                           (sm->rxSuccess && sm->decision == DECISION_FAIL)) &&
554                          (sm->reqId == sm->lastId ||
555                           eap_success_workaround(sm, sm->reqId, sm->lastId)))
556                         SM_ENTER(EAP, FAILURE);
557                 else if (sm->rxReq && duplicate)
558                         SM_ENTER(EAP, RETRANSMIT);
559                 else if (sm->rxReq && !duplicate &&
560                          sm->reqMethod == EAP_TYPE_NOTIFICATION &&
561                          sm->allowNotifications)
562                         SM_ENTER(EAP, NOTIFICATION);
563                 else if (sm->rxReq && !duplicate &&
564                          sm->selectedMethod == EAP_TYPE_NONE &&
565                          sm->reqMethod == EAP_TYPE_IDENTITY)
566                         SM_ENTER(EAP, IDENTITY);
567                 else if (sm->rxReq && !duplicate &&
568                          sm->selectedMethod == EAP_TYPE_NONE &&
569                          sm->reqMethod != EAP_TYPE_IDENTITY &&
570                          sm->reqMethod != EAP_TYPE_NOTIFICATION)
571                         SM_ENTER(EAP, GET_METHOD);
572                 else if (sm->rxReq && !duplicate &&
573                          sm->reqMethod == sm->selectedMethod &&
574                          sm->methodState != METHOD_DONE)
575                         SM_ENTER(EAP, METHOD);
576                 else if (sm->selectedMethod == EAP_TYPE_LEAP &&
577                          (sm->rxSuccess || sm->rxResp))
578                         SM_ENTER(EAP, METHOD);
579                 else
580                         SM_ENTER(EAP, DISCARD);
581                 break;
582         case EAP_GET_METHOD:
583                 if (sm->selectedMethod == sm->reqMethod)
584                         SM_ENTER(EAP, METHOD);
585                 else
586                         SM_ENTER(EAP, SEND_RESPONSE);
587                 break;
588         case EAP_METHOD:
589                 if (sm->ignore)
590                         SM_ENTER(EAP, DISCARD);
591                 else
592                         SM_ENTER(EAP, SEND_RESPONSE);
593                 break;
594         case EAP_SEND_RESPONSE:
595                 SM_ENTER(EAP, IDLE);
596                 break;
597         case EAP_DISCARD:
598                 SM_ENTER(EAP, IDLE);
599                 break;
600         case EAP_IDENTITY:
601                 SM_ENTER(EAP, SEND_RESPONSE);
602                 break;
603         case EAP_NOTIFICATION:
604                 SM_ENTER(EAP, SEND_RESPONSE);
605                 break;
606         case EAP_RETRANSMIT:
607                 SM_ENTER(EAP, SEND_RESPONSE);
608                 break;
609         case EAP_SUCCESS:
610                 break;
611         case EAP_FAILURE:
612                 break;
613         }
614 }
615
616
617 static Boolean eap_sm_allowMethod(struct eap_sm *sm, EapType method)
618 {
619         struct wpa_ssid *config = eap_get_config(sm);
620         int i;
621
622         if (!wpa_config_allowed_eap_method(config, method))
623                 return FALSE;
624         for (i = 0; i < NUM_EAP_METHODS; i++) {
625                 if (eap_methods[i]->method == method)
626                         return TRUE;
627         }
628         return FALSE;
629 }
630
631
632 static u8 *eap_sm_buildNak(struct eap_sm *sm, int id, size_t *len)
633 {
634         struct wpa_ssid *config = eap_get_config(sm);
635         struct eap_hdr *resp;
636         u8 *pos;
637         int i, found = 0;
638
639         wpa_printf(MSG_DEBUG, "EAP: Building EAP-Nak (requested type %d not "
640                    "allowed)", sm->reqMethod);
641         *len = sizeof(struct eap_hdr) + 1;
642         resp = malloc(*len + NUM_EAP_METHODS);
643         if (resp == NULL)
644                 return NULL;
645
646         resp->code = EAP_CODE_RESPONSE;
647         resp->identifier = id;
648         pos = (u8 *) (resp + 1);
649         *pos++ = EAP_TYPE_NAK;
650
651         for (i = 0; i < NUM_EAP_METHODS; i++) {
652                 if (wpa_config_allowed_eap_method(config,
653                                                   eap_methods[i]->method)) {
654                         *pos++ = eap_methods[i]->method;
655                         (*len)++;
656                         found++;
657                 }
658         }
659         if (!found) {
660                 *pos = EAP_TYPE_NONE;
661                 (*len)++;
662         }
663         wpa_hexdump(MSG_DEBUG, "EAP: allowed methods",
664                     ((u8 *) (resp + 1)) + 1, found);
665
666         resp->length = host_to_be16(*len);
667
668         return (u8 *) resp;
669 }
670
671
672 static void eap_sm_processIdentity(struct eap_sm *sm, u8 *req, size_t len)
673 {
674         struct eap_hdr *hdr = (struct eap_hdr *) req;
675         u8 *pos = (u8 *) (hdr + 1);
676         pos++;
677         /* TODO: could save displayable message so that it can be shown to the
678          * user in case of interaction is required */
679         wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Identity data",
680                           pos, be_to_host16(hdr->length) - 5);
681 }
682
683
684 u8 *eap_sm_buildIdentity(struct eap_sm *sm, int id, size_t *len,
685                          int encrypted)
686 {
687         struct wpa_ssid *config = eap_get_config(sm);
688         struct eap_hdr *resp;
689         u8 *pos;
690         const u8 *identity;
691         size_t identity_len;
692
693         if (config == NULL) {
694                 wpa_printf(MSG_WARNING, "EAP: buildIdentity: configuration "
695                            "was not available");
696                 return NULL;
697         }
698
699         if (sm->m && sm->m->get_identity &&
700             (identity = sm->m->get_identity(sm, sm->eap_method_priv,
701                                             &identity_len)) != NULL) {
702                 wpa_hexdump_ascii(MSG_DEBUG, "EAP: using method re-auth "
703                                   "identity", identity, identity_len);
704         } else if (!encrypted && config->anonymous_identity) {
705                 identity = config->anonymous_identity;
706                 identity_len = config->anonymous_identity_len;
707                 wpa_hexdump_ascii(MSG_DEBUG, "EAP: using anonymous identity",
708                                   identity, identity_len);
709         } else {
710                 identity = config->identity;
711                 identity_len = config->identity_len;
712                 wpa_hexdump_ascii(MSG_DEBUG, "EAP: using real identity",
713                                   identity, identity_len);
714         }
715
716         if (identity == NULL) {
717                 wpa_printf(MSG_WARNING, "EAP: buildIdentity: identity "
718                            "configuration was not available");
719                 eap_sm_request_identity(sm, config);
720                 return NULL;
721         }
722
723
724         *len = sizeof(struct eap_hdr) + 1 + identity_len;
725         resp = malloc(*len);
726         if (resp == NULL)
727                 return NULL;
728
729         resp->code = EAP_CODE_RESPONSE;
730         resp->identifier = id;
731         resp->length = host_to_be16(*len);
732         pos = (u8 *) (resp + 1);
733         *pos++ = EAP_TYPE_IDENTITY;
734         memcpy(pos, identity, identity_len);
735
736         return (u8 *) resp;
737 }
738
739
740 static void eap_sm_processNotify(struct eap_sm *sm, u8 *req, size_t len)
741 {
742         struct eap_hdr *hdr = (struct eap_hdr *) req;
743         u8 *pos = (u8 *) (hdr + 1);
744         pos++;
745         /* TODO: log the Notification Request and make it available for UI */
746         wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Notification data",
747                           pos, be_to_host16(hdr->length) - 5);
748 }
749
750
751 static u8 *eap_sm_buildNotify(struct eap_sm *sm, int id, size_t *len)
752 {
753         struct eap_hdr *resp;
754         u8 *pos;
755
756         wpa_printf(MSG_DEBUG, "EAP: Generating EAP-Response Notification");
757         *len = sizeof(struct eap_hdr) + 1;
758         resp = malloc(*len);
759         if (resp == NULL)
760                 return NULL;
761
762         resp->code = EAP_CODE_RESPONSE;
763         resp->identifier = id;
764         resp->length = host_to_be16(*len);
765         pos = (u8 *) (resp + 1);
766         *pos = EAP_TYPE_NOTIFICATION;
767
768         return (u8 *) resp;
769 }
770
771
772 static void eap_sm_parseEapReq(struct eap_sm *sm, u8 *req, size_t len)
773 {
774         struct eap_hdr *hdr;
775         size_t plen;
776         MD5_CTX context;
777
778         sm->rxReq = sm->rxSuccess = sm->rxFailure = FALSE;
779         sm->reqId = 0;
780         sm->reqMethod = EAP_TYPE_NONE;
781
782         if (req == NULL || len < sizeof(*hdr))
783                 return;
784
785         hdr = (struct eap_hdr *) req;
786         plen = be_to_host16(hdr->length);
787         if (plen > len) {
788                 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
789                            "(len=%lu plen=%lu)",
790                            (unsigned long) len, (unsigned long) plen);
791                 return;
792         }
793
794         sm->reqId = hdr->identifier;
795
796         if (sm->workaround) {
797                 MD5Init(&context);
798                 MD5Update(&context, req, len);
799                 MD5Final(sm->req_md5, &context);
800         }
801
802         switch (hdr->code) {
803         case EAP_CODE_REQUEST:
804                 sm->rxReq = TRUE;
805                 if (plen > sizeof(*hdr))
806                         sm->reqMethod = *((u8 *) (hdr + 1));
807                 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Request method=%d "
808                            "id=%d", sm->reqMethod, sm->reqId);
809                 break;
810         case EAP_CODE_RESPONSE:
811                 if (sm->selectedMethod == EAP_TYPE_LEAP) {
812                         sm->rxResp = TRUE;
813                         if (plen > sizeof(*hdr))
814                                 sm->reqMethod = *((u8 *) (hdr + 1));
815                         wpa_printf(MSG_DEBUG, "EAP: Received EAP-Response for "
816                                    "LEAP method=%d id=%d",
817                                    sm->reqMethod, sm->reqId);
818                         break;
819                 }
820                 wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Response");
821                 break;
822         case EAP_CODE_SUCCESS:
823                 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Success");
824                 sm->rxSuccess = TRUE;
825                 break;
826         case EAP_CODE_FAILURE:
827                 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure");
828                 sm->rxFailure = TRUE;
829                 break;
830         default:
831                 wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Packet with unknown "
832                            "code %d", hdr->code);
833                 break;
834         }
835 }
836
837
838 struct eap_sm *eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
839                            void *msg_ctx)
840 {
841         struct eap_sm *sm;
842
843         sm = malloc(sizeof(*sm));
844         if (sm == NULL)
845                 return NULL;
846         memset(sm, 0, sizeof(*sm));
847         sm->eapol_ctx = eapol_ctx;
848         sm->eapol_cb = eapol_cb;
849         sm->msg_ctx = msg_ctx;
850         sm->ClientTimeout = 60;
851
852         sm->ssl_ctx = tls_init();
853         if (sm->ssl_ctx == NULL) {
854                 wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS "
855                            "context.");
856                 free(sm);
857                 return NULL;
858         }
859
860         return sm;
861 }
862
863
864 void eap_sm_deinit(struct eap_sm *sm)
865 {
866         if (sm == NULL)
867                 return;
868         eap_deinit_prev_method(sm, "EAP deinit");
869         free(sm->lastRespData);
870         free(sm->eapRespData);
871         free(sm->eapKeyData);
872         tls_deinit(sm->ssl_ctx);
873         free(sm);
874 }
875
876
877 int eap_sm_step(struct eap_sm *sm)
878 {
879         int res = 0;
880         do {
881                 sm->changed = FALSE;
882                 SM_STEP_RUN(EAP);
883                 if (sm->changed)
884                         res = 1;
885         } while (sm->changed);
886         return res;
887 }
888
889
890 void eap_sm_abort(struct eap_sm *sm)
891 {
892         /* release system resources that may have been allocated for the
893          * authentication session */
894         free(sm->eapRespData);
895         sm->eapRespData = NULL;
896         free(sm->eapKeyData);
897         sm->eapKeyData = NULL;
898 }
899
900
901 static const char * eap_sm_state_txt(int state)
902 {
903         switch (state) {
904         case EAP_INITIALIZE:
905                 return "INITIALIZE";
906         case EAP_DISABLED:
907                 return "DISABLED";
908         case EAP_IDLE:
909                 return "IDLE";
910         case EAP_RECEIVED:
911                 return "RECEIVED";
912         case EAP_GET_METHOD:
913                 return "GET_METHOD";
914         case EAP_METHOD:
915                 return "METHOD";
916         case EAP_SEND_RESPONSE:
917                 return "SEND_RESPONSE";
918         case EAP_DISCARD:
919                 return "DISCARD";
920         case EAP_IDENTITY:
921                 return "IDENTITY";
922         case EAP_NOTIFICATION:
923                 return "NOTIFICATION";
924         case EAP_RETRANSMIT:
925                 return "RETRANSMIT";
926         case EAP_SUCCESS:
927                 return "SUCCESS";
928         case EAP_FAILURE:
929                 return "FAILURE";
930         default:
931                 return "UNKNOWN";
932         }
933 }
934
935
936 static const char * eap_sm_method_state_txt(int state)
937 {
938         switch (state) {
939         case METHOD_NONE:
940                 return "NONE";
941         case METHOD_INIT:
942                 return "INIT";
943         case METHOD_CONT:
944                 return "CONT";
945         case METHOD_MAY_CONT:
946                 return "MAY_CONT";
947         case METHOD_DONE:
948                 return "DONE";
949         default:
950                 return "UNKNOWN";
951         }
952 }
953
954
955 static const char * eap_sm_decision_txt(int decision)
956 {
957         switch (decision) {
958         case DECISION_FAIL:
959                 return "FAIL";
960         case DECISION_COND_SUCC:
961                 return "COND_SUCC";
962         case DECISION_UNCOND_SUCC:
963                 return "UNCOND_SUCC";
964         default:
965                 return "UNKNOWN";
966         }
967 }
968
969
970 int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
971 {
972         int len;
973
974         if (sm == NULL)
975                 return 0;
976
977         len = snprintf(buf, buflen,
978                        "EAP state=%s\n",
979                        eap_sm_state_txt(sm->EAP_state));
980
981         if (sm->selectedMethod != EAP_TYPE_NONE) {
982                 const char *name;
983                 if (sm->m) {
984                         name = sm->m->name;
985                 } else {
986                         const struct eap_method *m =
987                                 eap_sm_get_eap_methods(sm->selectedMethod);
988                         if (m)
989                                 name = m->name;
990                         else
991                                 name = "?";
992                 }
993                 len += snprintf(buf + len, buflen - len,
994                                 "selectedMethod=%d (EAP-%s)\n",
995                                 sm->selectedMethod, name);
996
997                 if (sm->m && sm->m->get_status) {
998                         len += sm->m->get_status(sm, sm->eap_method_priv,
999                                                  buf + len, buflen - len,
1000                                                  verbose);
1001                 }
1002         }
1003
1004         if (verbose) {
1005                 len += snprintf(buf + len, buflen - len,
1006                                 "reqMethod=%d\n"
1007                                 "methodState=%s\n"
1008                                 "decision=%s\n"
1009                                 "ClientTimeout=%d\n",
1010                                 sm->reqMethod,
1011                                 eap_sm_method_state_txt(sm->methodState),
1012                                 eap_sm_decision_txt(sm->decision),
1013                                 sm->ClientTimeout);
1014         }
1015
1016         return len;
1017 }
1018
1019
1020 typedef enum { TYPE_IDENTITY, TYPE_PASSWORD, TYPE_OTP } eap_ctrl_req_type;
1021
1022 static void eap_sm_request(struct eap_sm *sm, struct wpa_ssid *config,
1023                            eap_ctrl_req_type type, char *msg, size_t msglen)
1024 {
1025         char *buf;
1026         size_t buflen;
1027         int len;
1028         char *field;
1029         char *txt, *tmp;
1030
1031         if (config == NULL || sm == NULL)
1032                 return;
1033
1034         switch (type) {
1035         case TYPE_IDENTITY:
1036                 field = "IDENTITY";
1037                 txt = "Identity";
1038                 config->pending_req_identity++;
1039                 break;
1040         case TYPE_PASSWORD:
1041                 field = "PASSWORD";
1042                 txt = "Password";
1043                 config->pending_req_password++;
1044                 break;
1045         case TYPE_OTP:
1046                 field = "OTP";
1047                 if (msg) {
1048                         tmp = malloc(msglen + 3);
1049                         if (tmp == NULL)
1050                                 return;
1051                         tmp[0] = '[';
1052                         memcpy(tmp + 1, msg, msglen);
1053                         tmp[msglen + 1] = ']';
1054                         tmp[msglen + 2] = '\0';
1055                         txt = tmp;
1056                         free(config->pending_req_otp);
1057                         config->pending_req_otp = tmp;
1058                         config->pending_req_otp_len = msglen + 3;
1059                 } else {
1060                         if (config->pending_req_otp == NULL)
1061                                 return;
1062                         txt = config->pending_req_otp;
1063                 }
1064                 break;
1065         default:
1066                 return;
1067         }
1068
1069         buflen = 100 + strlen(txt) + config->ssid_len;
1070         buf = malloc(buflen);
1071         if (buf == NULL)
1072                 return;
1073         len = snprintf(buf, buflen, "CTRL-REQ-%s-%d:%s needed for SSID ",
1074                        field, config->id, txt);
1075         if (config->ssid && buflen > len + config->ssid_len) {
1076                 memcpy(buf + len, config->ssid, config->ssid_len);
1077                 len += config->ssid_len;
1078                 buf[len] = '\0';
1079         }
1080         wpa_msg(sm->msg_ctx, MSG_INFO, buf);
1081         free(buf);
1082 }
1083
1084
1085 void eap_sm_request_identity(struct eap_sm *sm, struct wpa_ssid *config)
1086 {
1087         eap_sm_request(sm, config, TYPE_IDENTITY, NULL, 0);
1088 }
1089
1090
1091 void eap_sm_request_password(struct eap_sm *sm, struct wpa_ssid *config)
1092 {
1093         eap_sm_request(sm, config, TYPE_PASSWORD, NULL, 0);
1094 }
1095
1096
1097 void eap_sm_request_otp(struct eap_sm *sm, struct wpa_ssid *config,
1098                         char *msg, size_t msg_len)
1099 {
1100         eap_sm_request(sm, config, TYPE_OTP, msg, msg_len);
1101 }
1102
1103
1104 void eap_sm_notify_ctrl_attached(struct eap_sm *sm)
1105 {
1106         struct wpa_ssid *config = eap_get_config(sm);
1107
1108         if (config == NULL)
1109                 return;
1110
1111         /* Re-send any pending requests for user data since a new control
1112          * interface was added. This handles cases where the EAP authentication
1113          * starts immediately after system startup when the user interface is
1114          * not yet running. */
1115         if (config->pending_req_identity)
1116                 eap_sm_request_identity(sm, config);
1117         if (config->pending_req_password)
1118                 eap_sm_request_password(sm, config);
1119         if (config->pending_req_otp)
1120                 eap_sm_request_otp(sm, config, NULL, 0);
1121 }
1122
1123
1124 u8 eap_get_type(const char *name)
1125 {
1126         int i;
1127         for (i = 0; i < NUM_EAP_METHODS; i++) {
1128                 if (strcmp(eap_methods[i]->name, name) == 0)
1129                         return eap_methods[i]->method;
1130         }
1131         return EAP_TYPE_NONE;
1132 }
1133
1134
1135 static int eap_allowed_phase2_type(int type)
1136 {
1137         return type != EAP_TYPE_PEAP && type != EAP_TYPE_TTLS &&
1138                 type != EAP_TYPE_FAST;
1139 }
1140
1141
1142 u8 eap_get_phase2_type(const char *name)
1143 {
1144         u8 type = eap_get_type(name);
1145         if (eap_allowed_phase2_type(type))
1146                 return type;
1147         return EAP_TYPE_NONE;
1148 }
1149
1150
1151 u8 *eap_get_phase2_types(struct wpa_ssid *config, size_t *count)
1152 {
1153         u8 *buf, method;
1154         int i;
1155
1156         *count = 0;
1157         buf = malloc(NUM_EAP_METHODS);
1158         if (buf == NULL)
1159                 return NULL;
1160
1161         for (i = 0; i < NUM_EAP_METHODS; i++) {
1162                 method = eap_methods[i]->method;
1163                 if (eap_allowed_phase2_type(method)) {
1164                         if (method == EAP_TYPE_TLS && config &&
1165                             config->private_key2 == NULL)
1166                                 continue;
1167                         buf[*count] = method;
1168                         (*count)++;
1169                 }
1170         }
1171
1172         return buf;
1173 }
1174
1175
1176 void eap_set_fast_reauth(struct eap_sm *sm, int enabled)
1177 {
1178         sm->fast_reauth = enabled;
1179 }
1180
1181
1182 void eap_set_workaround(struct eap_sm *sm, unsigned int workaround)
1183 {
1184         sm->workaround = workaround;
1185 }
1186
1187
1188 struct wpa_ssid * eap_get_config(struct eap_sm *sm)
1189 {
1190         return sm->eapol_cb->get_config(sm->eapol_ctx);
1191 }
1192
1193
1194 int eap_key_available(struct eap_sm *sm)
1195 {
1196         return sm ? sm->eapKeyAvailable : 0;
1197 }
1198
1199
1200 void eap_notify_success(struct eap_sm *sm)
1201 {
1202         if (sm) {
1203                 sm->decision = DECISION_COND_SUCC;
1204                 sm->EAP_state = EAP_SUCCESS;
1205         }
1206 }
1207
1208
1209 u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len)
1210 {
1211         if (sm == NULL || sm->eapKeyData == NULL) {
1212                 *len = 0;
1213                 return NULL;
1214         }
1215
1216         *len = sm->eapKeyDataLen;
1217         return sm->eapKeyData;
1218 }
1219
1220
1221 u8 * eap_get_eapRespData(struct eap_sm *sm, size_t *len)
1222 {
1223         u8 *resp;
1224
1225         if (sm == NULL || sm->eapRespData == NULL) {
1226                 *len = 0;
1227                 return NULL;
1228         }
1229
1230         resp = sm->eapRespData;
1231         *len = sm->eapRespDataLen;
1232         sm->eapRespData = NULL;
1233         sm->eapRespDataLen = 0;
1234
1235         return resp;
1236 }
1237
1238
1239 void eap_register_scard_ctx(struct eap_sm *sm, void *ctx)
1240 {
1241         if (sm)
1242                 sm->scard_ctx = ctx;
1243 }