2 * hostapd / EAP Standalone Authenticator state machine (RFC 4137)
3 * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
22 #include "state_machine.h"
24 #define STATE_MACHINE_DATA struct eap_sm
25 #define STATE_MACHINE_DEBUG_PREFIX "EAP"
27 #define EAP_MAX_AUTH_ROUNDS 50
29 static void eap_user_free(struct eap_user *user);
32 /* EAP state machines are described in RFC 4137 */
34 static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
35 int eapSRTT, int eapRTTVAR,
37 static void eap_sm_parseEapResp(struct eap_sm *sm, u8 *resp, size_t len);
38 static u8 * eap_sm_buildSuccess(struct eap_sm *sm, int id, size_t *len);
39 static u8 * eap_sm_buildFailure(struct eap_sm *sm, int id, size_t *len);
40 static int eap_sm_nextId(struct eap_sm *sm, int id);
41 static void eap_sm_Policy_update(struct eap_sm *sm, u8 *nak_list, size_t len);
42 static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor);
43 static int eap_sm_Policy_getDecision(struct eap_sm *sm);
44 static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method);
47 static Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
49 return sm->eapol_cb->get_bool(sm->eapol_ctx, var);
53 static void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var,
56 sm->eapol_cb->set_bool(sm->eapol_ctx, var, value);
60 static void eapol_set_eapReqData(struct eap_sm *sm,
61 const u8 *eapReqData, size_t eapReqDataLen)
63 wpa_hexdump(MSG_MSGDUMP, "EAP: eapReqData -> EAPOL",
64 sm->eapReqData, sm->eapReqDataLen);
65 sm->eapol_cb->set_eapReqData(sm->eapol_ctx, eapReqData, eapReqDataLen);
69 static void eapol_set_eapKeyData(struct eap_sm *sm,
70 const u8 *eapKeyData, size_t eapKeyDataLen)
72 wpa_hexdump(MSG_MSGDUMP, "EAP: eapKeyData -> EAPOL",
73 sm->eapKeyData, sm->eapKeyDataLen);
74 sm->eapol_cb->set_eapKeyData(sm->eapol_ctx, eapKeyData, eapKeyDataLen);
79 * eap_user_get - Fetch user information from the database
80 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
81 * @identity: Identity (User-Name) of the user
82 * @identity_len: Length of identity in bytes
83 * @phase2: 0 = EAP phase1 user, 1 = EAP phase2 (tunneled) user
84 * Returns: 0 on success, or -1 on failure
86 * This function is used to fetch user information for EAP. The user will be
87 * selected based on the specified identity. sm->user and
88 * sm->user_eap_method_index are updated for the new user when a matching user
89 * is found. sm->user can be used to get user information (e.g., password).
91 int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
94 struct eap_user *user;
96 if (sm == NULL || sm->eapol_cb == NULL ||
97 sm->eapol_cb->get_eap_user == NULL)
100 eap_user_free(sm->user);
103 user = wpa_zalloc(sizeof(*user));
107 if (sm->eapol_cb->get_eap_user(sm->eapol_ctx, identity,
108 identity_len, phase2, user) != 0) {
114 sm->user_eap_method_index = 0;
120 SM_STATE(EAP, DISABLED)
122 SM_ENTRY(EAP, DISABLED);
127 SM_STATE(EAP, INITIALIZE)
129 SM_ENTRY(EAP, INITIALIZE);
132 eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
133 eapol_set_bool(sm, EAPOL_eapFail, FALSE);
134 eapol_set_bool(sm, EAPOL_eapTimeout, FALSE);
135 free(sm->eapKeyData);
136 sm->eapKeyData = NULL;
137 sm->eapKeyDataLen = 0;
138 /* eapKeyAvailable = FALSE */
139 eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
142 * This is not defined in RFC 4137, but method state needs to be
143 * reseted here so that it does not remain in success state when
144 * re-authentication starts.
146 if (sm->m && sm->eap_method_priv) {
147 sm->m->reset(sm, sm->eap_method_priv);
148 sm->eap_method_priv = NULL;
151 sm->user_eap_method_index = 0;
153 if (sm->backend_auth) {
154 sm->currentMethod = EAP_TYPE_NONE;
155 /* parse rxResp, respId, respMethod */
156 eap_sm_parseEapResp(sm, sm->eapRespData, sm->eapRespDataLen);
158 sm->currentId = sm->respId;
162 sm->method_pending = METHOD_PENDING_NONE;
166 SM_STATE(EAP, PICK_UP_METHOD)
168 SM_ENTRY(EAP, PICK_UP_METHOD);
170 if (eap_sm_Policy_doPickUp(sm, sm->respMethod)) {
171 sm->currentMethod = sm->respMethod;
172 if (sm->m && sm->eap_method_priv) {
173 sm->m->reset(sm, sm->eap_method_priv);
174 sm->eap_method_priv = NULL;
176 sm->m = eap_sm_get_eap_methods(EAP_VENDOR_IETF,
178 if (sm->m && sm->m->initPickUp) {
179 sm->eap_method_priv = sm->m->initPickUp(sm);
180 if (sm->eap_method_priv == NULL) {
181 wpa_printf(MSG_DEBUG, "EAP: Failed to "
182 "initialize EAP method %d",
185 sm->currentMethod = EAP_TYPE_NONE;
189 sm->currentMethod = EAP_TYPE_NONE;
199 sm->retransWhile = eap_sm_calculateTimeout(sm, sm->retransCount,
200 sm->eapSRTT, sm->eapRTTVAR,
205 SM_STATE(EAP, RETRANSMIT)
207 SM_ENTRY(EAP, RETRANSMIT);
209 /* TODO: Is this needed since EAPOL state machines take care of
214 SM_STATE(EAP, RECEIVED)
216 SM_ENTRY(EAP, RECEIVED);
218 /* parse rxResp, respId, respMethod */
219 eap_sm_parseEapResp(sm, sm->eapRespData, sm->eapRespDataLen);
224 SM_STATE(EAP, DISCARD)
226 SM_ENTRY(EAP, DISCARD);
227 eapol_set_bool(sm, EAPOL_eapResp, FALSE);
228 eapol_set_bool(sm, EAPOL_eapNoReq, TRUE);
232 SM_STATE(EAP, SEND_REQUEST)
234 SM_ENTRY(EAP, SEND_REQUEST);
236 sm->retransCount = 0;
237 if (sm->eapReqData) {
238 eapol_set_eapReqData(sm, sm->eapReqData, sm->eapReqDataLen);
239 free(sm->lastReqData);
240 sm->lastReqData = sm->eapReqData;
241 sm->lastReqDataLen = sm->eapReqDataLen;
242 sm->eapReqData = NULL;
243 sm->eapReqDataLen = 0;
244 eapol_set_bool(sm, EAPOL_eapResp, FALSE);
245 eapol_set_bool(sm, EAPOL_eapReq, TRUE);
247 wpa_printf(MSG_INFO, "EAP: SEND_REQUEST - no eapReqData");
248 eapol_set_bool(sm, EAPOL_eapResp, FALSE);
249 eapol_set_bool(sm, EAPOL_eapReq, FALSE);
250 eapol_set_bool(sm, EAPOL_eapNoReq, TRUE);
255 SM_STATE(EAP, INTEGRITY_CHECK)
257 SM_ENTRY(EAP, INTEGRITY_CHECK);
260 sm->ignore = sm->m->check(sm, sm->eap_method_priv,
261 sm->eapRespData, sm->eapRespDataLen);
266 SM_STATE(EAP, METHOD_REQUEST)
268 SM_ENTRY(EAP, METHOD_REQUEST);
271 wpa_printf(MSG_DEBUG, "EAP: method not initialized");
275 sm->currentId = eap_sm_nextId(sm, sm->currentId);
276 wpa_printf(MSG_DEBUG, "EAP: building EAP-Request: Identifier %d",
278 sm->lastId = sm->currentId;
279 free(sm->eapReqData);
280 sm->eapReqData = sm->m->buildReq(sm, sm->eap_method_priv,
281 sm->currentId, &sm->eapReqDataLen);
282 if (sm->m->getTimeout)
283 sm->methodTimeout = sm->m->getTimeout(sm, sm->eap_method_priv);
285 sm->methodTimeout = 0;
289 SM_STATE(EAP, METHOD_RESPONSE)
291 SM_ENTRY(EAP, METHOD_RESPONSE);
293 sm->m->process(sm, sm->eap_method_priv, sm->eapRespData,
295 if (sm->m->isDone(sm, sm->eap_method_priv)) {
296 eap_sm_Policy_update(sm, NULL, 0);
297 free(sm->eapKeyData);
299 sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
302 sm->eapKeyData = NULL;
303 sm->eapKeyDataLen = 0;
305 sm->methodState = METHOD_END;
307 sm->methodState = METHOD_CONTINUE;
312 SM_STATE(EAP, PROPOSE_METHOD)
317 SM_ENTRY(EAP, PROPOSE_METHOD);
319 type = eap_sm_Policy_getNextMethod(sm, &vendor);
320 if (vendor == EAP_VENDOR_IETF)
321 sm->currentMethod = type;
323 sm->currentMethod = EAP_TYPE_EXPANDED;
324 if (sm->m && sm->eap_method_priv) {
325 sm->m->reset(sm, sm->eap_method_priv);
326 sm->eap_method_priv = NULL;
328 sm->m = eap_sm_get_eap_methods(vendor, type);
330 sm->eap_method_priv = sm->m->init(sm);
331 if (sm->eap_method_priv == NULL) {
332 wpa_printf(MSG_DEBUG, "EAP: Failed to initialize EAP "
333 "method %d", sm->currentMethod);
335 sm->currentMethod = EAP_TYPE_NONE;
338 if (sm->currentMethod == EAP_TYPE_IDENTITY ||
339 sm->currentMethod == EAP_TYPE_NOTIFICATION)
340 sm->methodState = METHOD_CONTINUE;
342 sm->methodState = METHOD_PROPOSED;
350 u8 *pos, *nak_list = NULL;
354 if (sm->eap_method_priv) {
355 sm->m->reset(sm, sm->eap_method_priv);
356 sm->eap_method_priv = NULL;
360 nak = (struct eap_hdr *) sm->eapRespData;
361 if (nak && sm->eapRespDataLen > sizeof(*nak)) {
362 len = ntohs(nak->length);
363 if (len > sm->eapRespDataLen)
364 len = sm->eapRespDataLen;
365 pos = (u8 *) (nak + 1);
367 if (*pos == EAP_TYPE_NAK) {
373 eap_sm_Policy_update(sm, nak_list, len);
377 SM_STATE(EAP, SELECT_ACTION)
379 SM_ENTRY(EAP, SELECT_ACTION);
381 sm->decision = eap_sm_Policy_getDecision(sm);
385 SM_STATE(EAP, TIMEOUT_FAILURE)
387 SM_ENTRY(EAP, TIMEOUT_FAILURE);
389 eapol_set_bool(sm, EAPOL_eapTimeout, TRUE);
393 SM_STATE(EAP, FAILURE)
395 SM_ENTRY(EAP, FAILURE);
397 free(sm->eapReqData);
398 sm->eapReqData = eap_sm_buildFailure(sm, sm->currentId,
400 if (sm->eapReqData) {
401 eapol_set_eapReqData(sm, sm->eapReqData, sm->eapReqDataLen);
402 free(sm->eapReqData);
403 sm->eapReqData = NULL;
404 sm->eapReqDataLen = 0;
406 free(sm->lastReqData);
407 sm->lastReqData = NULL;
408 sm->lastReqDataLen = 0;
409 eapol_set_bool(sm, EAPOL_eapFail, TRUE);
413 SM_STATE(EAP, SUCCESS)
415 SM_ENTRY(EAP, SUCCESS);
417 free(sm->eapReqData);
418 sm->eapReqData = eap_sm_buildSuccess(sm, sm->currentId,
420 if (sm->eapReqData) {
421 eapol_set_eapReqData(sm, sm->eapReqData, sm->eapReqDataLen);
422 free(sm->eapReqData);
423 sm->eapReqData = NULL;
424 sm->eapReqDataLen = 0;
426 free(sm->lastReqData);
427 sm->lastReqData = NULL;
428 sm->lastReqDataLen = 0;
429 if (sm->eapKeyData) {
430 eapol_set_eapKeyData(sm, sm->eapKeyData, sm->eapKeyDataLen);
432 eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
438 if (eapol_get_bool(sm, EAPOL_eapRestart) &&
439 eapol_get_bool(sm, EAPOL_portEnabled))
440 SM_ENTER_GLOBAL(EAP, INITIALIZE);
441 else if (!eapol_get_bool(sm, EAPOL_portEnabled))
442 SM_ENTER_GLOBAL(EAP, DISABLED);
443 else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
444 if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
445 wpa_printf(MSG_DEBUG, "EAP: more than %d "
446 "authentication rounds - abort",
447 EAP_MAX_AUTH_ROUNDS);
449 SM_ENTER_GLOBAL(EAP, FAILURE);
451 } else switch (sm->EAP_state) {
453 if (sm->backend_auth) {
455 SM_ENTER(EAP, SELECT_ACTION);
456 else if (sm->rxResp &&
457 (sm->respMethod == EAP_TYPE_NAK ||
458 (sm->respMethod == EAP_TYPE_EXPANDED &&
459 sm->respVendor == EAP_VENDOR_IETF &&
460 sm->respVendorMethod == EAP_TYPE_NAK)))
463 SM_ENTER(EAP, PICK_UP_METHOD);
465 SM_ENTER(EAP, SELECT_ACTION);
468 case EAP_PICK_UP_METHOD:
469 if (sm->currentMethod == EAP_TYPE_NONE) {
470 SM_ENTER(EAP, SELECT_ACTION);
472 SM_ENTER(EAP, METHOD_RESPONSE);
476 if (eapol_get_bool(sm, EAPOL_portEnabled))
477 SM_ENTER(EAP, INITIALIZE);
480 if (sm->retransWhile == 0)
481 SM_ENTER(EAP, RETRANSMIT);
482 else if (eapol_get_bool(sm, EAPOL_eapResp))
483 SM_ENTER(EAP, RECEIVED);
486 if (sm->retransCount > sm->MaxRetrans)
487 SM_ENTER(EAP, TIMEOUT_FAILURE);
492 if (sm->rxResp && (sm->respId == sm->currentId) &&
493 (sm->respMethod == EAP_TYPE_NAK ||
494 (sm->respMethod == EAP_TYPE_EXPANDED &&
495 sm->respVendor == EAP_VENDOR_IETF &&
496 sm->respVendorMethod == EAP_TYPE_NAK))
497 && (sm->methodState == METHOD_PROPOSED))
499 else if (sm->rxResp && (sm->respId == sm->currentId) &&
500 ((sm->respMethod == sm->currentMethod) ||
501 (sm->respMethod == EAP_TYPE_EXPANDED &&
502 sm->respVendor == EAP_VENDOR_IETF &&
503 sm->respVendorMethod == sm->currentMethod)))
504 SM_ENTER(EAP, INTEGRITY_CHECK);
506 wpa_printf(MSG_DEBUG, "EAP: RECEIVED->DISCARD: "
507 "rxResp=%d respId=%d currentId=%d "
508 "respMethod=%d currentMethod=%d",
509 sm->rxResp, sm->respId, sm->currentId,
510 sm->respMethod, sm->currentMethod);
511 SM_ENTER(EAP, DISCARD);
517 case EAP_SEND_REQUEST:
520 case EAP_INTEGRITY_CHECK:
522 SM_ENTER(EAP, DISCARD);
524 SM_ENTER(EAP, METHOD_RESPONSE);
526 case EAP_METHOD_REQUEST:
527 SM_ENTER(EAP, SEND_REQUEST);
529 case EAP_METHOD_RESPONSE:
531 * Note: Mechanism to allow EAP methods to wait while going
532 * through pending processing is an extension to RFC 4137
533 * which only defines the transits to SELECT_ACTION and
534 * METHOD_REQUEST from this METHOD_RESPONSE state.
536 if (sm->methodState == METHOD_END)
537 SM_ENTER(EAP, SELECT_ACTION);
538 else if (sm->method_pending == METHOD_PENDING_WAIT) {
539 wpa_printf(MSG_DEBUG, "EAP: Method has pending "
540 "processing - wait before proceeding to "
541 "METHOD_REQUEST state");
542 } else if (sm->method_pending == METHOD_PENDING_CONT) {
543 wpa_printf(MSG_DEBUG, "EAP: Method has completed "
544 "pending processing - reprocess pending "
546 sm->method_pending = METHOD_PENDING_NONE;
547 SM_ENTER(EAP, METHOD_RESPONSE);
549 SM_ENTER(EAP, METHOD_REQUEST);
551 case EAP_PROPOSE_METHOD:
553 * Note: Mechanism to allow EAP methods to wait while going
554 * through pending processing is an extension to RFC 4137
555 * which only defines the transit to METHOD_REQUEST from this
556 * PROPOSE_METHOD state.
558 if (sm->method_pending == METHOD_PENDING_WAIT) {
559 wpa_printf(MSG_DEBUG, "EAP: Method has pending "
560 "processing - wait before proceeding to "
561 "METHOD_REQUEST state");
562 if (sm->user_eap_method_index > 0)
563 sm->user_eap_method_index--;
564 } else if (sm->method_pending == METHOD_PENDING_CONT) {
565 wpa_printf(MSG_DEBUG, "EAP: Method has completed "
566 "pending processing - reprocess pending "
568 sm->method_pending = METHOD_PENDING_NONE;
569 SM_ENTER(EAP, PROPOSE_METHOD);
571 SM_ENTER(EAP, METHOD_REQUEST);
574 SM_ENTER(EAP, SELECT_ACTION);
576 case EAP_SELECT_ACTION:
577 if (sm->decision == DECISION_FAILURE)
578 SM_ENTER(EAP, FAILURE);
579 else if (sm->decision == DECISION_SUCCESS)
580 SM_ENTER(EAP, SUCCESS);
582 SM_ENTER(EAP, PROPOSE_METHOD);
584 case EAP_TIMEOUT_FAILURE:
594 static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
595 int eapSRTT, int eapRTTVAR,
598 /* For now, retransmission is done in EAPOL state machines, so make
599 * sure EAP state machine does not end up trying to retransmit packets.
605 static void eap_sm_parseEapResp(struct eap_sm *sm, u8 *resp, size_t len)
610 /* parse rxResp, respId, respMethod */
613 sm->respMethod = EAP_TYPE_NONE;
614 sm->respVendor = EAP_VENDOR_IETF;
615 sm->respVendorMethod = EAP_TYPE_NONE;
617 if (resp == NULL || len < sizeof(*hdr))
620 hdr = (struct eap_hdr *) resp;
621 plen = ntohs(hdr->length);
623 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
624 "(len=%lu plen=%lu)", (unsigned long) len,
625 (unsigned long) plen);
629 sm->respId = hdr->identifier;
631 if (hdr->code == EAP_CODE_RESPONSE)
634 if (plen > sizeof(*hdr)) {
635 u8 *pos = (u8 *) (hdr + 1);
636 sm->respMethod = *pos++;
637 if (sm->respMethod == EAP_TYPE_EXPANDED) {
638 if (plen < sizeof(*hdr) + 8) {
639 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated "
640 "expanded EAP-Packet (plen=%lu)",
641 (unsigned long) plen);
644 sm->respVendor = WPA_GET_BE24(pos);
646 sm->respVendorMethod = WPA_GET_BE32(pos);
650 wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d "
651 "respMethod=%u respVendor=%u respVendorMethod=%u",
652 sm->rxResp, sm->respId, sm->respMethod, sm->respVendor,
653 sm->respVendorMethod);
657 static u8 * eap_sm_buildSuccess(struct eap_sm *sm, int id, size_t *len)
659 struct eap_hdr *resp;
660 wpa_printf(MSG_DEBUG, "EAP: Building EAP-Success (id=%d)", id);
662 *len = sizeof(*resp);
666 resp->code = EAP_CODE_SUCCESS;
667 resp->identifier = id;
668 resp->length = htons(*len);
674 static u8 * eap_sm_buildFailure(struct eap_sm *sm, int id, size_t *len)
676 struct eap_hdr *resp;
677 wpa_printf(MSG_DEBUG, "EAP: Building EAP-Failure (id=%d)", id);
679 *len = sizeof(*resp);
683 resp->code = EAP_CODE_FAILURE;
684 resp->identifier = id;
685 resp->length = htons(*len);
691 static int eap_sm_nextId(struct eap_sm *sm, int id)
694 /* RFC 3748 Ch 4.1: recommended to initialize Identifier with a
697 if (id != sm->lastId)
700 return (id + 1) & 0xff;
705 * eap_sm_process_nak - Process EAP-Response/Nak
706 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
707 * @nak_list: Nak list (allowed methods) from the supplicant
708 * @len: Length of nak_list in bytes
710 * This function is called when EAP-Response/Nak is received from the
711 * supplicant. This can happen for both phase 1 and phase 2 authentications.
713 void eap_sm_process_nak(struct eap_sm *sm, u8 *nak_list, size_t len)
718 if (sm->user == NULL)
721 wpa_printf(MSG_MSGDUMP, "EAP: processing NAK (current EAP method "
722 "index %d)", sm->user_eap_method_index);
724 wpa_hexdump(MSG_MSGDUMP, "EAP: configured methods",
725 (u8 *) sm->user->methods,
726 EAP_MAX_METHODS * sizeof(sm->user->methods[0]));
727 wpa_hexdump(MSG_MSGDUMP, "EAP: list of methods supported by the peer",
730 i = sm->user_eap_method_index;
731 while (i < EAP_MAX_METHODS &&
732 (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
733 sm->user->methods[i].method != EAP_TYPE_NONE)) {
734 if (sm->user->methods[i].vendor != EAP_VENDOR_IETF)
736 for (j = 0; j < len; j++) {
737 if (nak_list[j] == sm->user->methods[i].method) {
749 /* not found - remove from the list */
750 memmove(&sm->user->methods[i], &sm->user->methods[i + 1],
751 (EAP_MAX_METHODS - i - 1) *
752 sizeof(sm->user->methods[0]));
753 sm->user->methods[EAP_MAX_METHODS - 1].vendor =
755 sm->user->methods[EAP_MAX_METHODS - 1].method = EAP_TYPE_NONE;
758 wpa_hexdump(MSG_MSGDUMP, "EAP: new list of configured methods",
759 (u8 *) sm->user->methods, EAP_MAX_METHODS *
760 sizeof(sm->user->methods[0]));
764 static void eap_sm_Policy_update(struct eap_sm *sm, u8 *nak_list, size_t len)
766 if (nak_list == NULL || sm == NULL || sm->user == NULL)
769 if (sm->user->phase2) {
770 wpa_printf(MSG_DEBUG, "EAP: EAP-Nak received after Phase2 user"
771 " info was selected - reject");
772 sm->decision = DECISION_FAILURE;
776 eap_sm_process_nak(sm, nak_list, len);
780 static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor)
783 int idx = sm->user_eap_method_index;
785 /* In theory, there should be no problems with starting
786 * re-authentication with something else than EAP-Request/Identity and
787 * this does indeed work with wpa_supplicant. However, at least Funk
788 * Supplicant seemed to ignore re-auth if it skipped
789 * EAP-Request/Identity.
790 * Re-auth sets currentId == -1, so that can be used here to select
791 * whether Identity needs to be requested again. */
792 if (sm->identity == NULL || sm->currentId == -1) {
793 *vendor = EAP_VENDOR_IETF;
794 next = EAP_TYPE_IDENTITY;
795 sm->update_user = TRUE;
796 } else if (sm->user && idx < EAP_MAX_METHODS &&
797 (sm->user->methods[idx].vendor != EAP_VENDOR_IETF ||
798 sm->user->methods[idx].method != EAP_TYPE_NONE)) {
799 *vendor = sm->user->methods[idx].vendor;
800 next = sm->user->methods[idx].method;
801 sm->user_eap_method_index++;
803 *vendor = EAP_VENDOR_IETF;
804 next = EAP_TYPE_NONE;
806 wpa_printf(MSG_DEBUG, "EAP: getNextMethod: vendor %d type %d",
812 static int eap_sm_Policy_getDecision(struct eap_sm *sm)
814 if (sm->m && sm->currentMethod != EAP_TYPE_IDENTITY &&
815 sm->m->isSuccess(sm, sm->eap_method_priv)) {
816 wpa_printf(MSG_DEBUG, "EAP: getDecision: method succeeded -> "
818 sm->update_user = TRUE;
819 return DECISION_SUCCESS;
822 if (sm->m && sm->m->isDone(sm, sm->eap_method_priv) &&
823 !sm->m->isSuccess(sm, sm->eap_method_priv)) {
824 wpa_printf(MSG_DEBUG, "EAP: getDecision: method failed -> "
826 sm->update_user = TRUE;
827 return DECISION_FAILURE;
830 if ((sm->user == NULL || sm->update_user) && sm->identity) {
831 if (eap_user_get(sm, sm->identity, sm->identity_len, 0) != 0) {
832 wpa_printf(MSG_DEBUG, "EAP: getDecision: user not "
833 "found from database -> FAILURE");
834 return DECISION_FAILURE;
836 sm->update_user = FALSE;
839 if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
840 (sm->user->methods[sm->user_eap_method_index].vendor !=
842 sm->user->methods[sm->user_eap_method_index].method !=
844 wpa_printf(MSG_DEBUG, "EAP: getDecision: another method "
845 "available -> CONTINUE");
846 return DECISION_CONTINUE;
849 if (sm->identity == NULL || sm->currentId == -1) {
850 wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known "
852 return DECISION_CONTINUE;
855 wpa_printf(MSG_DEBUG, "EAP: getDecision: no more methods available -> "
857 return DECISION_FAILURE;
861 static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method)
863 return method == EAP_TYPE_IDENTITY ? TRUE : FALSE;
868 * eap_sm_step - Step EAP state machine
869 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
870 * Returns: 1 if EAP state was changed or 0 if not
872 * This function advances EAP state machine to a new state to match with the
873 * current variables. This should be called whenever variables used by the EAP
874 * state machine have changed.
876 int eap_sm_step(struct eap_sm *sm)
884 } while (sm->changed);
890 * eap_set_eapRespData - Set EAP response (eapRespData)
891 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
892 * @eapRespData: EAP-Response payload from the supplicant
893 * @eapRespDataLen: Length of eapRespData in bytes
895 * This function is called when an EAP-Response is received from a supplicant.
897 void eap_set_eapRespData(struct eap_sm *sm, const u8 *eapRespData,
898 size_t eapRespDataLen)
902 free(sm->eapRespData);
903 sm->eapRespData = malloc(eapRespDataLen);
904 if (sm->eapRespData == NULL)
906 memcpy(sm->eapRespData, eapRespData, eapRespDataLen);
907 sm->eapRespDataLen = eapRespDataLen;
908 wpa_hexdump(MSG_MSGDUMP, "EAP: EAP-Response received",
909 eapRespData, eapRespDataLen);
913 static void eap_user_free(struct eap_user *user)
917 free(user->password);
918 user->password = NULL;
924 * eap_sm_init - Allocate and initialize EAP state machine
925 * @eapol_ctx: Context data to be used with eapol_cb calls
926 * @eapol_cb: Pointer to EAPOL callback functions
927 * @conf: EAP configuration
928 * Returns: Pointer to the allocated EAP state machine or %NULL on failure
930 * This function allocates and initializes an EAP state machine.
932 struct eap_sm * eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
933 struct eap_config *conf)
937 sm = wpa_zalloc(sizeof(*sm));
940 sm->eapol_ctx = eapol_ctx;
941 sm->eapol_cb = eapol_cb;
943 sm->ssl_ctx = conf->ssl_ctx;
944 sm->eap_sim_db_priv = conf->eap_sim_db_priv;
945 sm->backend_auth = conf->backend_auth;
947 wpa_printf(MSG_DEBUG, "EAP: State machine created");
954 * eap_sm_deinit - Deinitialize and free an EAP state machine
955 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
957 * This function deinitializes EAP state machine and frees all allocated
960 void eap_sm_deinit(struct eap_sm *sm)
964 wpa_printf(MSG_DEBUG, "EAP: State machine removed");
965 if (sm->m && sm->eap_method_priv)
966 sm->m->reset(sm, sm->eap_method_priv);
967 free(sm->eapReqData);
968 free(sm->eapKeyData);
969 free(sm->lastReqData);
970 free(sm->eapRespData);
972 eap_user_free(sm->user);
978 * eap_sm_notify_cached - Notify EAP state machine of cached PMK
979 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
981 * This function is called when PMKSA caching is used to skip EAP
984 void eap_sm_notify_cached(struct eap_sm *sm)
989 sm->EAP_state = EAP_SUCCESS;
994 * eap_sm_pending_cb - EAP state machine callback for a pending EAP request
995 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
997 * This function is called when data for a pending EAP-Request is received.
999 void eap_sm_pending_cb(struct eap_sm *sm)
1003 wpa_printf(MSG_DEBUG, "EAP: Callback for pending request received");
1004 if (sm->method_pending == METHOD_PENDING_WAIT)
1005 sm->method_pending = METHOD_PENDING_CONT;
1010 * eap_sm_method_pending - Query whether EAP method is waiting for pending data
1011 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
1012 * Returns: 1 if method is waiting for pending data or 0 if not
1014 int eap_sm_method_pending(struct eap_sm *sm)
1018 return sm->method_pending == METHOD_PENDING_WAIT;
1023 * eap_hdr_validate - Validate EAP header
1024 * @vendor: Expected EAP Vendor-Id (0 = IETF)
1025 * @eap_type: Expected EAP type number
1026 * @msg: EAP frame (starting with EAP header)
1027 * @msglen: Length of msg
1028 * @plen: Pointer to variable to contain the returned payload length
1029 * Returns: Pointer to EAP payload (after type field), or %NULL on failure
1031 * This is a helper function for EAP method implementations. This is usually
1032 * called in the beginning of struct eap_method::process() function to verify
1033 * that the received EAP request packet has a valid header. This function is
1034 * able to process both legacy and expanded EAP headers and in most cases, the
1035 * caller can just use the returned payload pointer (into *plen) for processing
1036 * the payload regardless of whether the packet used the expanded EAP header or
1039 const u8 * eap_hdr_validate(int vendor, EapType eap_type,
1040 const u8 *msg, size_t msglen, size_t *plen)
1042 const struct eap_hdr *hdr;
1046 hdr = (const struct eap_hdr *) msg;
1048 if (msglen < sizeof(*hdr)) {
1049 wpa_printf(MSG_INFO, "EAP: Too short EAP frame");
1053 len = be_to_host16(hdr->length);
1054 if (len < sizeof(*hdr) + 1 || len > msglen) {
1055 wpa_printf(MSG_INFO, "EAP: Invalid EAP length");
1059 pos = (const u8 *) (hdr + 1);
1061 if (*pos == EAP_TYPE_EXPANDED) {
1064 if (len < sizeof(*hdr) + 8) {
1065 wpa_printf(MSG_INFO, "EAP: Invalid expanded EAP "
1070 exp_vendor = WPA_GET_BE24(pos);
1072 exp_type = WPA_GET_BE32(pos);
1074 if (exp_vendor != vendor || exp_type != (u32) eap_type) {
1075 wpa_printf(MSG_INFO, "EAP: Invalid expanded frame "
1080 *plen = len - sizeof(*hdr) - 8;
1083 if (vendor != EAP_VENDOR_IETF || *pos != eap_type) {
1084 wpa_printf(MSG_INFO, "EAP: Invalid frame type");
1087 *plen = len - sizeof(*hdr) - 1;
1094 * eap_msg_alloc - Allocate a buffer for an EAP message
1095 * @vendor: Vendor-Id (0 = IETF)
1097 * @len: Buffer for returning message length
1098 * @payload_len: Payload length in bytes (data after Type)
1099 * @code: Message Code (EAP_CODE_*)
1100 * @identifier: Identifier
1101 * @payload: Pointer to payload pointer that will be set to point to the
1102 * beginning of the payload or %NULL if payload pointer is not needed
1103 * Returns: Pointer to the allocated message buffer or %NULL on error
1105 * This function can be used to allocate a buffer for an EAP message and fill
1106 * in the EAP header. This function is automatically using expanded EAP header
1107 * if the selected Vendor-Id is not IETF. In other words, most EAP methods do
1108 * not need to separately select which header type to use when using this
1109 * function to allocate the message buffers.
1111 struct eap_hdr * eap_msg_alloc(int vendor, EapType type, size_t *len,
1112 size_t payload_len, u8 code, u8 identifier,
1115 struct eap_hdr *hdr;
1118 *len = sizeof(struct eap_hdr) + (vendor == EAP_VENDOR_IETF ? 1 : 8) +
1123 hdr->identifier = identifier;
1124 hdr->length = host_to_be16(*len);
1125 pos = (u8 *) (hdr + 1);
1126 if (vendor == EAP_VENDOR_IETF) {
1129 *pos++ = EAP_TYPE_EXPANDED;
1130 WPA_PUT_BE24(pos, vendor);
1132 WPA_PUT_BE32(pos, type);