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.
20 #include "state_machine.h"
22 #define STATE_MACHINE_DATA struct eap_sm
23 #define STATE_MACHINE_DEBUG_PREFIX "EAP"
25 #define EAP_MAX_AUTH_ROUNDS 50
27 static void eap_user_free(struct eap_user
*user
);
30 /* EAP state machines are described in RFC 4137 */
32 static int eap_sm_calculateTimeout(struct eap_sm
*sm
, int retransCount
,
33 int eapSRTT
, int eapRTTVAR
,
35 static void eap_sm_parseEapResp(struct eap_sm
*sm
, u8
*resp
, size_t len
);
36 static u8
* eap_sm_buildSuccess(struct eap_sm
*sm
, int id
, size_t *len
);
37 static u8
* eap_sm_buildFailure(struct eap_sm
*sm
, int id
, size_t *len
);
38 static int eap_sm_nextId(struct eap_sm
*sm
, int id
);
39 static void eap_sm_Policy_update(struct eap_sm
*sm
, u8
*nak_list
, size_t len
);
40 static EapType
eap_sm_Policy_getNextMethod(struct eap_sm
*sm
, int *vendor
);
41 static int eap_sm_Policy_getDecision(struct eap_sm
*sm
);
42 static Boolean
eap_sm_Policy_doPickUp(struct eap_sm
*sm
, EapType method
);
45 static Boolean
eapol_get_bool(struct eap_sm
*sm
, enum eapol_bool_var var
)
47 return sm
->eapol_cb
->get_bool(sm
->eapol_ctx
, var
);
51 static void eapol_set_bool(struct eap_sm
*sm
, enum eapol_bool_var var
,
54 sm
->eapol_cb
->set_bool(sm
->eapol_ctx
, var
, value
);
58 static void eapol_set_eapReqData(struct eap_sm
*sm
,
59 const u8
*eapReqData
, size_t eapReqDataLen
)
61 wpa_hexdump(MSG_MSGDUMP
, "EAP: eapReqData -> EAPOL",
62 sm
->eapReqData
, sm
->eapReqDataLen
);
63 sm
->eapol_cb
->set_eapReqData(sm
->eapol_ctx
, eapReqData
, eapReqDataLen
);
67 static void eapol_set_eapKeyData(struct eap_sm
*sm
,
68 const u8
*eapKeyData
, size_t eapKeyDataLen
)
70 wpa_hexdump(MSG_MSGDUMP
, "EAP: eapKeyData -> EAPOL",
71 sm
->eapKeyData
, sm
->eapKeyDataLen
);
72 sm
->eapol_cb
->set_eapKeyData(sm
->eapol_ctx
, eapKeyData
, eapKeyDataLen
);
77 * eap_user_get - Fetch user information from the database
78 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
79 * @identity: Identity (User-Name) of the user
80 * @identity_len: Length of identity in bytes
81 * @phase2: 0 = EAP phase1 user, 1 = EAP phase2 (tunneled) user
82 * Returns: 0 on success, or -1 on failure
84 * This function is used to fetch user information for EAP. The user will be
85 * selected based on the specified identity. sm->user and
86 * sm->user_eap_method_index are updated for the new user when a matching user
87 * is found. sm->user can be used to get user information (e.g., password).
89 int eap_user_get(struct eap_sm
*sm
, const u8
*identity
, size_t identity_len
,
92 struct eap_user
*user
;
94 if (sm
== NULL
|| sm
->eapol_cb
== NULL
||
95 sm
->eapol_cb
->get_eap_user
== NULL
)
98 eap_user_free(sm
->user
);
101 user
= wpa_zalloc(sizeof(*user
));
105 if (sm
->eapol_cb
->get_eap_user(sm
->eapol_ctx
, identity
,
106 identity_len
, phase2
, user
) != 0) {
112 sm
->user_eap_method_index
= 0;
118 SM_STATE(EAP
, DISABLED
)
120 SM_ENTRY(EAP
, DISABLED
);
125 SM_STATE(EAP
, INITIALIZE
)
127 SM_ENTRY(EAP
, INITIALIZE
);
130 eapol_set_bool(sm
, EAPOL_eapSuccess
, FALSE
);
131 eapol_set_bool(sm
, EAPOL_eapFail
, FALSE
);
132 eapol_set_bool(sm
, EAPOL_eapTimeout
, FALSE
);
133 free(sm
->eapKeyData
);
134 sm
->eapKeyData
= NULL
;
135 sm
->eapKeyDataLen
= 0;
136 /* eapKeyAvailable = FALSE */
137 eapol_set_bool(sm
, EAPOL_eapRestart
, FALSE
);
140 * This is not defined in RFC 4137, but method state needs to be
141 * reseted here so that it does not remain in success state when
142 * re-authentication starts.
144 if (sm
->m
&& sm
->eap_method_priv
) {
145 sm
->m
->reset(sm
, sm
->eap_method_priv
);
146 sm
->eap_method_priv
= NULL
;
149 sm
->user_eap_method_index
= 0;
151 if (sm
->backend_auth
) {
152 sm
->currentMethod
= EAP_TYPE_NONE
;
153 /* parse rxResp, respId, respMethod */
154 eap_sm_parseEapResp(sm
, sm
->eapRespData
, sm
->eapRespDataLen
);
156 sm
->currentId
= sm
->respId
;
160 sm
->method_pending
= METHOD_PENDING_NONE
;
164 SM_STATE(EAP
, PICK_UP_METHOD
)
166 SM_ENTRY(EAP
, PICK_UP_METHOD
);
168 if (eap_sm_Policy_doPickUp(sm
, sm
->respMethod
)) {
169 sm
->currentMethod
= sm
->respMethod
;
170 if (sm
->m
&& sm
->eap_method_priv
) {
171 sm
->m
->reset(sm
, sm
->eap_method_priv
);
172 sm
->eap_method_priv
= NULL
;
174 sm
->m
= eap_sm_get_eap_methods(EAP_VENDOR_IETF
,
176 if (sm
->m
&& sm
->m
->initPickUp
) {
177 sm
->eap_method_priv
= sm
->m
->initPickUp(sm
);
178 if (sm
->eap_method_priv
== NULL
) {
179 wpa_printf(MSG_DEBUG
, "EAP: Failed to "
180 "initialize EAP method %d",
183 sm
->currentMethod
= EAP_TYPE_NONE
;
187 sm
->currentMethod
= EAP_TYPE_NONE
;
197 sm
->retransWhile
= eap_sm_calculateTimeout(sm
, sm
->retransCount
,
198 sm
->eapSRTT
, sm
->eapRTTVAR
,
203 SM_STATE(EAP
, RETRANSMIT
)
205 SM_ENTRY(EAP
, RETRANSMIT
);
207 /* TODO: Is this needed since EAPOL state machines take care of
212 SM_STATE(EAP
, RECEIVED
)
214 SM_ENTRY(EAP
, RECEIVED
);
216 /* parse rxResp, respId, respMethod */
217 eap_sm_parseEapResp(sm
, sm
->eapRespData
, sm
->eapRespDataLen
);
222 SM_STATE(EAP
, DISCARD
)
224 SM_ENTRY(EAP
, DISCARD
);
225 eapol_set_bool(sm
, EAPOL_eapResp
, FALSE
);
226 eapol_set_bool(sm
, EAPOL_eapNoReq
, TRUE
);
230 SM_STATE(EAP
, SEND_REQUEST
)
232 SM_ENTRY(EAP
, SEND_REQUEST
);
234 sm
->retransCount
= 0;
235 if (sm
->eapReqData
) {
236 eapol_set_eapReqData(sm
, sm
->eapReqData
, sm
->eapReqDataLen
);
237 free(sm
->lastReqData
);
238 sm
->lastReqData
= sm
->eapReqData
;
239 sm
->lastReqDataLen
= sm
->eapReqDataLen
;
240 sm
->eapReqData
= NULL
;
241 sm
->eapReqDataLen
= 0;
242 eapol_set_bool(sm
, EAPOL_eapResp
, FALSE
);
243 eapol_set_bool(sm
, EAPOL_eapReq
, TRUE
);
245 wpa_printf(MSG_INFO
, "EAP: SEND_REQUEST - no eapReqData");
246 eapol_set_bool(sm
, EAPOL_eapResp
, FALSE
);
247 eapol_set_bool(sm
, EAPOL_eapReq
, FALSE
);
248 eapol_set_bool(sm
, EAPOL_eapNoReq
, TRUE
);
253 SM_STATE(EAP
, INTEGRITY_CHECK
)
255 SM_ENTRY(EAP
, INTEGRITY_CHECK
);
258 sm
->ignore
= sm
->m
->check(sm
, sm
->eap_method_priv
,
259 sm
->eapRespData
, sm
->eapRespDataLen
);
264 SM_STATE(EAP
, METHOD_REQUEST
)
266 SM_ENTRY(EAP
, METHOD_REQUEST
);
269 wpa_printf(MSG_DEBUG
, "EAP: method not initialized");
273 sm
->currentId
= eap_sm_nextId(sm
, sm
->currentId
);
274 wpa_printf(MSG_DEBUG
, "EAP: building EAP-Request: Identifier %d",
276 sm
->lastId
= sm
->currentId
;
277 free(sm
->eapReqData
);
278 sm
->eapReqData
= sm
->m
->buildReq(sm
, sm
->eap_method_priv
,
279 sm
->currentId
, &sm
->eapReqDataLen
);
280 if (sm
->m
->getTimeout
)
281 sm
->methodTimeout
= sm
->m
->getTimeout(sm
, sm
->eap_method_priv
);
283 sm
->methodTimeout
= 0;
287 SM_STATE(EAP
, METHOD_RESPONSE
)
289 SM_ENTRY(EAP
, METHOD_RESPONSE
);
291 sm
->m
->process(sm
, sm
->eap_method_priv
, sm
->eapRespData
,
293 if (sm
->m
->isDone(sm
, sm
->eap_method_priv
)) {
294 eap_sm_Policy_update(sm
, NULL
, 0);
295 free(sm
->eapKeyData
);
297 sm
->eapKeyData
= sm
->m
->getKey(sm
, sm
->eap_method_priv
,
300 sm
->eapKeyData
= NULL
;
301 sm
->eapKeyDataLen
= 0;
303 sm
->methodState
= METHOD_END
;
305 sm
->methodState
= METHOD_CONTINUE
;
310 SM_STATE(EAP
, PROPOSE_METHOD
)
315 SM_ENTRY(EAP
, PROPOSE_METHOD
);
317 type
= eap_sm_Policy_getNextMethod(sm
, &vendor
);
318 if (vendor
== EAP_VENDOR_IETF
)
319 sm
->currentMethod
= type
;
321 sm
->currentMethod
= EAP_TYPE_EXPANDED
;
322 if (sm
->m
&& sm
->eap_method_priv
) {
323 sm
->m
->reset(sm
, sm
->eap_method_priv
);
324 sm
->eap_method_priv
= NULL
;
326 sm
->m
= eap_sm_get_eap_methods(vendor
, type
);
328 sm
->eap_method_priv
= sm
->m
->init(sm
);
329 if (sm
->eap_method_priv
== NULL
) {
330 wpa_printf(MSG_DEBUG
, "EAP: Failed to initialize EAP "
331 "method %d", sm
->currentMethod
);
333 sm
->currentMethod
= EAP_TYPE_NONE
;
336 if (sm
->currentMethod
== EAP_TYPE_IDENTITY
||
337 sm
->currentMethod
== EAP_TYPE_NOTIFICATION
)
338 sm
->methodState
= METHOD_CONTINUE
;
340 sm
->methodState
= METHOD_PROPOSED
;
348 u8
*pos
, *nak_list
= NULL
;
352 if (sm
->eap_method_priv
) {
353 sm
->m
->reset(sm
, sm
->eap_method_priv
);
354 sm
->eap_method_priv
= NULL
;
358 nak
= (struct eap_hdr
*) sm
->eapRespData
;
359 if (nak
&& sm
->eapRespDataLen
> sizeof(*nak
)) {
360 len
= ntohs(nak
->length
);
361 if (len
> sm
->eapRespDataLen
)
362 len
= sm
->eapRespDataLen
;
363 pos
= (u8
*) (nak
+ 1);
365 if (*pos
== EAP_TYPE_NAK
) {
371 eap_sm_Policy_update(sm
, nak_list
, len
);
375 SM_STATE(EAP
, SELECT_ACTION
)
377 SM_ENTRY(EAP
, SELECT_ACTION
);
379 sm
->decision
= eap_sm_Policy_getDecision(sm
);
383 SM_STATE(EAP
, TIMEOUT_FAILURE
)
385 SM_ENTRY(EAP
, TIMEOUT_FAILURE
);
387 eapol_set_bool(sm
, EAPOL_eapTimeout
, TRUE
);
391 SM_STATE(EAP
, FAILURE
)
393 SM_ENTRY(EAP
, FAILURE
);
395 free(sm
->eapReqData
);
396 sm
->eapReqData
= eap_sm_buildFailure(sm
, sm
->currentId
,
398 if (sm
->eapReqData
) {
399 eapol_set_eapReqData(sm
, sm
->eapReqData
, sm
->eapReqDataLen
);
400 free(sm
->eapReqData
);
401 sm
->eapReqData
= NULL
;
402 sm
->eapReqDataLen
= 0;
404 free(sm
->lastReqData
);
405 sm
->lastReqData
= NULL
;
406 sm
->lastReqDataLen
= 0;
407 eapol_set_bool(sm
, EAPOL_eapFail
, TRUE
);
411 SM_STATE(EAP
, SUCCESS
)
413 SM_ENTRY(EAP
, SUCCESS
);
415 free(sm
->eapReqData
);
416 sm
->eapReqData
= eap_sm_buildSuccess(sm
, sm
->currentId
,
418 if (sm
->eapReqData
) {
419 eapol_set_eapReqData(sm
, sm
->eapReqData
, sm
->eapReqDataLen
);
420 free(sm
->eapReqData
);
421 sm
->eapReqData
= NULL
;
422 sm
->eapReqDataLen
= 0;
424 free(sm
->lastReqData
);
425 sm
->lastReqData
= NULL
;
426 sm
->lastReqDataLen
= 0;
427 if (sm
->eapKeyData
) {
428 eapol_set_eapKeyData(sm
, sm
->eapKeyData
, sm
->eapKeyDataLen
);
430 eapol_set_bool(sm
, EAPOL_eapSuccess
, TRUE
);
436 if (eapol_get_bool(sm
, EAPOL_eapRestart
) &&
437 eapol_get_bool(sm
, EAPOL_portEnabled
))
438 SM_ENTER_GLOBAL(EAP
, INITIALIZE
);
439 else if (!eapol_get_bool(sm
, EAPOL_portEnabled
))
440 SM_ENTER_GLOBAL(EAP
, DISABLED
);
441 else if (sm
->num_rounds
> EAP_MAX_AUTH_ROUNDS
) {
442 if (sm
->num_rounds
== EAP_MAX_AUTH_ROUNDS
+ 1) {
443 wpa_printf(MSG_DEBUG
, "EAP: more than %d "
444 "authentication rounds - abort",
445 EAP_MAX_AUTH_ROUNDS
);
447 SM_ENTER_GLOBAL(EAP
, FAILURE
);
449 } else switch (sm
->EAP_state
) {
451 if (sm
->backend_auth
) {
453 SM_ENTER(EAP
, SELECT_ACTION
);
454 else if (sm
->rxResp
&&
455 (sm
->respMethod
== EAP_TYPE_NAK
||
456 (sm
->respMethod
== EAP_TYPE_EXPANDED
&&
457 sm
->respVendor
== EAP_VENDOR_IETF
&&
458 sm
->respVendorMethod
== EAP_TYPE_NAK
)))
461 SM_ENTER(EAP
, PICK_UP_METHOD
);
463 SM_ENTER(EAP
, SELECT_ACTION
);
466 case EAP_PICK_UP_METHOD
:
467 if (sm
->currentMethod
== EAP_TYPE_NONE
) {
468 SM_ENTER(EAP
, SELECT_ACTION
);
470 SM_ENTER(EAP
, METHOD_RESPONSE
);
474 if (eapol_get_bool(sm
, EAPOL_portEnabled
))
475 SM_ENTER(EAP
, INITIALIZE
);
478 if (sm
->retransWhile
== 0)
479 SM_ENTER(EAP
, RETRANSMIT
);
480 else if (eapol_get_bool(sm
, EAPOL_eapResp
))
481 SM_ENTER(EAP
, RECEIVED
);
484 if (sm
->retransCount
> sm
->MaxRetrans
)
485 SM_ENTER(EAP
, TIMEOUT_FAILURE
);
490 if (sm
->rxResp
&& (sm
->respId
== sm
->currentId
) &&
491 (sm
->respMethod
== EAP_TYPE_NAK
||
492 (sm
->respMethod
== EAP_TYPE_EXPANDED
&&
493 sm
->respVendor
== EAP_VENDOR_IETF
&&
494 sm
->respVendorMethod
== EAP_TYPE_NAK
))
495 && (sm
->methodState
== METHOD_PROPOSED
))
497 else if (sm
->rxResp
&& (sm
->respId
== sm
->currentId
) &&
498 ((sm
->respMethod
== sm
->currentMethod
) ||
499 (sm
->respMethod
== EAP_TYPE_EXPANDED
&&
500 sm
->respVendor
== EAP_VENDOR_IETF
&&
501 sm
->respVendorMethod
== sm
->currentMethod
)))
502 SM_ENTER(EAP
, INTEGRITY_CHECK
);
504 wpa_printf(MSG_DEBUG
, "EAP: RECEIVED->DISCARD: "
505 "rxResp=%d respId=%d currentId=%d "
506 "respMethod=%d currentMethod=%d",
507 sm
->rxResp
, sm
->respId
, sm
->currentId
,
508 sm
->respMethod
, sm
->currentMethod
);
509 SM_ENTER(EAP
, DISCARD
);
515 case EAP_SEND_REQUEST
:
518 case EAP_INTEGRITY_CHECK
:
520 SM_ENTER(EAP
, DISCARD
);
522 SM_ENTER(EAP
, METHOD_RESPONSE
);
524 case EAP_METHOD_REQUEST
:
525 SM_ENTER(EAP
, SEND_REQUEST
);
527 case EAP_METHOD_RESPONSE
:
529 * Note: Mechanism to allow EAP methods to wait while going
530 * through pending processing is an extension to RFC 4137
531 * which only defines the transits to SELECT_ACTION and
532 * METHOD_REQUEST from this METHOD_RESPONSE state.
534 if (sm
->methodState
== METHOD_END
)
535 SM_ENTER(EAP
, SELECT_ACTION
);
536 else if (sm
->method_pending
== METHOD_PENDING_WAIT
) {
537 wpa_printf(MSG_DEBUG
, "EAP: Method has pending "
538 "processing - wait before proceeding to "
539 "METHOD_REQUEST state");
540 } else if (sm
->method_pending
== METHOD_PENDING_CONT
) {
541 wpa_printf(MSG_DEBUG
, "EAP: Method has completed "
542 "pending processing - reprocess pending "
544 sm
->method_pending
= METHOD_PENDING_NONE
;
545 SM_ENTER(EAP
, METHOD_RESPONSE
);
547 SM_ENTER(EAP
, METHOD_REQUEST
);
549 case EAP_PROPOSE_METHOD
:
551 * Note: Mechanism to allow EAP methods to wait while going
552 * through pending processing is an extension to RFC 4137
553 * which only defines the transit to METHOD_REQUEST from this
554 * PROPOSE_METHOD state.
556 if (sm
->method_pending
== METHOD_PENDING_WAIT
) {
557 wpa_printf(MSG_DEBUG
, "EAP: Method has pending "
558 "processing - wait before proceeding to "
559 "METHOD_REQUEST state");
560 if (sm
->user_eap_method_index
> 0)
561 sm
->user_eap_method_index
--;
562 } else if (sm
->method_pending
== METHOD_PENDING_CONT
) {
563 wpa_printf(MSG_DEBUG
, "EAP: Method has completed "
564 "pending processing - reprocess pending "
566 sm
->method_pending
= METHOD_PENDING_NONE
;
567 SM_ENTER(EAP
, PROPOSE_METHOD
);
569 SM_ENTER(EAP
, METHOD_REQUEST
);
572 SM_ENTER(EAP
, SELECT_ACTION
);
574 case EAP_SELECT_ACTION
:
575 if (sm
->decision
== DECISION_FAILURE
)
576 SM_ENTER(EAP
, FAILURE
);
577 else if (sm
->decision
== DECISION_SUCCESS
)
578 SM_ENTER(EAP
, SUCCESS
);
580 SM_ENTER(EAP
, PROPOSE_METHOD
);
582 case EAP_TIMEOUT_FAILURE
:
592 static int eap_sm_calculateTimeout(struct eap_sm
*sm
, int retransCount
,
593 int eapSRTT
, int eapRTTVAR
,
596 /* For now, retransmission is done in EAPOL state machines, so make
597 * sure EAP state machine does not end up trying to retransmit packets.
603 static void eap_sm_parseEapResp(struct eap_sm
*sm
, u8
*resp
, size_t len
)
608 /* parse rxResp, respId, respMethod */
611 sm
->respMethod
= EAP_TYPE_NONE
;
612 sm
->respVendor
= EAP_VENDOR_IETF
;
613 sm
->respVendorMethod
= EAP_TYPE_NONE
;
615 if (resp
== NULL
|| len
< sizeof(*hdr
))
618 hdr
= (struct eap_hdr
*) resp
;
619 plen
= ntohs(hdr
->length
);
621 wpa_printf(MSG_DEBUG
, "EAP: Ignored truncated EAP-Packet "
622 "(len=%lu plen=%lu)", (unsigned long) len
,
623 (unsigned long) plen
);
627 sm
->respId
= hdr
->identifier
;
629 if (hdr
->code
== EAP_CODE_RESPONSE
)
632 if (plen
> sizeof(*hdr
)) {
633 u8
*pos
= (u8
*) (hdr
+ 1);
634 sm
->respMethod
= *pos
++;
635 if (sm
->respMethod
== EAP_TYPE_EXPANDED
) {
636 if (plen
< sizeof(*hdr
) + 8) {
637 wpa_printf(MSG_DEBUG
, "EAP: Ignored truncated "
638 "expanded EAP-Packet (plen=%lu)",
639 (unsigned long) plen
);
642 sm
->respVendor
= WPA_GET_BE24(pos
);
644 sm
->respVendorMethod
= WPA_GET_BE32(pos
);
648 wpa_printf(MSG_DEBUG
, "EAP: parseEapResp: rxResp=%d respId=%d "
649 "respMethod=%u respVendor=%u respVendorMethod=%u",
650 sm
->rxResp
, sm
->respId
, sm
->respMethod
, sm
->respVendor
,
651 sm
->respVendorMethod
);
655 static u8
* eap_sm_buildSuccess(struct eap_sm
*sm
, int id
, size_t *len
)
657 struct eap_hdr
*resp
;
658 wpa_printf(MSG_DEBUG
, "EAP: Building EAP-Success (id=%d)", id
);
660 *len
= sizeof(*resp
);
664 resp
->code
= EAP_CODE_SUCCESS
;
665 resp
->identifier
= id
;
666 resp
->length
= htons(*len
);
672 static u8
* eap_sm_buildFailure(struct eap_sm
*sm
, int id
, size_t *len
)
674 struct eap_hdr
*resp
;
675 wpa_printf(MSG_DEBUG
, "EAP: Building EAP-Failure (id=%d)", id
);
677 *len
= sizeof(*resp
);
681 resp
->code
= EAP_CODE_FAILURE
;
682 resp
->identifier
= id
;
683 resp
->length
= htons(*len
);
689 static int eap_sm_nextId(struct eap_sm
*sm
, int id
)
692 /* RFC 3748 Ch 4.1: recommended to initialize Identifier with a
695 if (id
!= sm
->lastId
)
698 return (id
+ 1) & 0xff;
703 * eap_sm_process_nak - Process EAP-Response/Nak
704 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
705 * @nak_list: Nak list (allowed methods) from the supplicant
706 * @len: Length of nak_list in bytes
708 * This function is called when EAP-Response/Nak is received from the
709 * supplicant. This can happen for both phase 1 and phase 2 authentications.
711 void eap_sm_process_nak(struct eap_sm
*sm
, u8
*nak_list
, size_t len
)
716 if (sm
->user
== NULL
)
719 wpa_printf(MSG_MSGDUMP
, "EAP: processing NAK (current EAP method "
720 "index %d)", sm
->user_eap_method_index
);
722 wpa_hexdump(MSG_MSGDUMP
, "EAP: configured methods",
723 (u8
*) sm
->user
->methods
,
724 EAP_MAX_METHODS
* sizeof(sm
->user
->methods
[0]));
725 wpa_hexdump(MSG_MSGDUMP
, "EAP: list of methods supported by the peer",
728 i
= sm
->user_eap_method_index
;
729 while (i
< EAP_MAX_METHODS
&&
730 (sm
->user
->methods
[i
].vendor
!= EAP_VENDOR_IETF
||
731 sm
->user
->methods
[i
].method
!= EAP_TYPE_NONE
)) {
732 if (sm
->user
->methods
[i
].vendor
!= EAP_VENDOR_IETF
)
734 for (j
= 0; j
< len
; j
++) {
735 if (nak_list
[j
] == sm
->user
->methods
[i
].method
) {
747 /* not found - remove from the list */
748 memmove(&sm
->user
->methods
[i
], &sm
->user
->methods
[i
+ 1],
749 (EAP_MAX_METHODS
- i
- 1) *
750 sizeof(sm
->user
->methods
[0]));
751 sm
->user
->methods
[EAP_MAX_METHODS
- 1].vendor
=
753 sm
->user
->methods
[EAP_MAX_METHODS
- 1].method
= EAP_TYPE_NONE
;
756 wpa_hexdump(MSG_MSGDUMP
, "EAP: new list of configured methods",
757 (u8
*) sm
->user
->methods
, EAP_MAX_METHODS
*
758 sizeof(sm
->user
->methods
[0]));
762 static void eap_sm_Policy_update(struct eap_sm
*sm
, u8
*nak_list
, size_t len
)
764 if (nak_list
== NULL
|| sm
== NULL
|| sm
->user
== NULL
)
767 if (sm
->user
->phase2
) {
768 wpa_printf(MSG_DEBUG
, "EAP: EAP-Nak received after Phase2 user"
769 " info was selected - reject");
770 sm
->decision
= DECISION_FAILURE
;
774 eap_sm_process_nak(sm
, nak_list
, len
);
778 static EapType
eap_sm_Policy_getNextMethod(struct eap_sm
*sm
, int *vendor
)
781 int idx
= sm
->user_eap_method_index
;
783 /* In theory, there should be no problems with starting
784 * re-authentication with something else than EAP-Request/Identity and
785 * this does indeed work with wpa_supplicant. However, at least Funk
786 * Supplicant seemed to ignore re-auth if it skipped
787 * EAP-Request/Identity.
788 * Re-auth sets currentId == -1, so that can be used here to select
789 * whether Identity needs to be requested again. */
790 if (sm
->identity
== NULL
|| sm
->currentId
== -1) {
791 *vendor
= EAP_VENDOR_IETF
;
792 next
= EAP_TYPE_IDENTITY
;
793 sm
->update_user
= TRUE
;
794 } else if (sm
->user
&& idx
< EAP_MAX_METHODS
&&
795 (sm
->user
->methods
[idx
].vendor
!= EAP_VENDOR_IETF
||
796 sm
->user
->methods
[idx
].method
!= EAP_TYPE_NONE
)) {
797 *vendor
= sm
->user
->methods
[idx
].vendor
;
798 next
= sm
->user
->methods
[idx
].method
;
799 sm
->user_eap_method_index
++;
801 *vendor
= EAP_VENDOR_IETF
;
802 next
= EAP_TYPE_NONE
;
804 wpa_printf(MSG_DEBUG
, "EAP: getNextMethod: vendor %d type %d",
810 static int eap_sm_Policy_getDecision(struct eap_sm
*sm
)
812 if (sm
->m
&& sm
->currentMethod
!= EAP_TYPE_IDENTITY
&&
813 sm
->m
->isSuccess(sm
, sm
->eap_method_priv
)) {
814 wpa_printf(MSG_DEBUG
, "EAP: getDecision: method succeeded -> "
816 sm
->update_user
= TRUE
;
817 return DECISION_SUCCESS
;
820 if (sm
->m
&& sm
->m
->isDone(sm
, sm
->eap_method_priv
) &&
821 !sm
->m
->isSuccess(sm
, sm
->eap_method_priv
)) {
822 wpa_printf(MSG_DEBUG
, "EAP: getDecision: method failed -> "
824 sm
->update_user
= TRUE
;
825 return DECISION_FAILURE
;
828 if ((sm
->user
== NULL
|| sm
->update_user
) && sm
->identity
) {
829 if (eap_user_get(sm
, sm
->identity
, sm
->identity_len
, 0) != 0) {
830 wpa_printf(MSG_DEBUG
, "EAP: getDecision: user not "
831 "found from database -> FAILURE");
832 return DECISION_FAILURE
;
834 sm
->update_user
= FALSE
;
837 if (sm
->user
&& sm
->user_eap_method_index
< EAP_MAX_METHODS
&&
838 (sm
->user
->methods
[sm
->user_eap_method_index
].vendor
!=
840 sm
->user
->methods
[sm
->user_eap_method_index
].method
!=
842 wpa_printf(MSG_DEBUG
, "EAP: getDecision: another method "
843 "available -> CONTINUE");
844 return DECISION_CONTINUE
;
847 if (sm
->identity
== NULL
|| sm
->currentId
== -1) {
848 wpa_printf(MSG_DEBUG
, "EAP: getDecision: no identity known "
850 return DECISION_CONTINUE
;
853 wpa_printf(MSG_DEBUG
, "EAP: getDecision: no more methods available -> "
855 return DECISION_FAILURE
;
859 static Boolean
eap_sm_Policy_doPickUp(struct eap_sm
*sm
, EapType method
)
861 return method
== EAP_TYPE_IDENTITY
? TRUE
: FALSE
;
866 * eap_sm_step - Step EAP state machine
867 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
868 * Returns: 1 if EAP state was changed or 0 if not
870 * This function advances EAP state machine to a new state to match with the
871 * current variables. This should be called whenever variables used by the EAP
872 * state machine have changed.
874 int eap_sm_step(struct eap_sm
*sm
)
882 } while (sm
->changed
);
888 * eap_set_eapRespData - Set EAP response (eapRespData)
889 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
890 * @eapRespData: EAP-Response payload from the supplicant
891 * @eapRespDataLen: Length of eapRespData in bytes
893 * This function is called when an EAP-Response is received from a supplicant.
895 void eap_set_eapRespData(struct eap_sm
*sm
, const u8
*eapRespData
,
896 size_t eapRespDataLen
)
900 free(sm
->eapRespData
);
901 sm
->eapRespData
= malloc(eapRespDataLen
);
902 if (sm
->eapRespData
== NULL
)
904 memcpy(sm
->eapRespData
, eapRespData
, eapRespDataLen
);
905 sm
->eapRespDataLen
= eapRespDataLen
;
906 wpa_hexdump(MSG_MSGDUMP
, "EAP: EAP-Response received",
907 eapRespData
, eapRespDataLen
);
911 static void eap_user_free(struct eap_user
*user
)
915 free(user
->password
);
916 user
->password
= NULL
;
922 * eap_sm_init - Allocate and initialize EAP state machine
923 * @eapol_ctx: Context data to be used with eapol_cb calls
924 * @eapol_cb: Pointer to EAPOL callback functions
925 * @conf: EAP configuration
926 * Returns: Pointer to the allocated EAP state machine or %NULL on failure
928 * This function allocates and initializes an EAP state machine.
930 struct eap_sm
* eap_sm_init(void *eapol_ctx
, struct eapol_callbacks
*eapol_cb
,
931 struct eap_config
*conf
)
935 sm
= wpa_zalloc(sizeof(*sm
));
938 sm
->eapol_ctx
= eapol_ctx
;
939 sm
->eapol_cb
= eapol_cb
;
941 sm
->ssl_ctx
= conf
->ssl_ctx
;
942 sm
->eap_sim_db_priv
= conf
->eap_sim_db_priv
;
943 sm
->backend_auth
= conf
->backend_auth
;
945 wpa_printf(MSG_DEBUG
, "EAP: State machine created");
952 * eap_sm_deinit - Deinitialize and free an EAP state machine
953 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
955 * This function deinitializes EAP state machine and frees all allocated
958 void eap_sm_deinit(struct eap_sm
*sm
)
962 wpa_printf(MSG_DEBUG
, "EAP: State machine removed");
963 if (sm
->m
&& sm
->eap_method_priv
)
964 sm
->m
->reset(sm
, sm
->eap_method_priv
);
965 free(sm
->eapReqData
);
966 free(sm
->eapKeyData
);
967 free(sm
->lastReqData
);
968 free(sm
->eapRespData
);
970 eap_user_free(sm
->user
);
976 * eap_sm_notify_cached - Notify EAP state machine of cached PMK
977 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
979 * This function is called when PMKSA caching is used to skip EAP
982 void eap_sm_notify_cached(struct eap_sm
*sm
)
987 sm
->EAP_state
= EAP_SUCCESS
;
992 * eap_sm_pending_cb - EAP state machine callback for a pending EAP request
993 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
995 * This function is called when data for a pending EAP-Request is received.
997 void eap_sm_pending_cb(struct eap_sm
*sm
)
1001 wpa_printf(MSG_DEBUG
, "EAP: Callback for pending request received");
1002 if (sm
->method_pending
== METHOD_PENDING_WAIT
)
1003 sm
->method_pending
= METHOD_PENDING_CONT
;
1008 * eap_sm_method_pending - Query whether EAP method is waiting for pending data
1009 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
1010 * Returns: 1 if method is waiting for pending data or 0 if not
1012 int eap_sm_method_pending(struct eap_sm
*sm
)
1016 return sm
->method_pending
== METHOD_PENDING_WAIT
;
1021 * eap_hdr_validate - Validate EAP header
1022 * @vendor: Expected EAP Vendor-Id (0 = IETF)
1023 * @eap_type: Expected EAP type number
1024 * @msg: EAP frame (starting with EAP header)
1025 * @msglen: Length of msg
1026 * @plen: Pointer to variable to contain the returned payload length
1027 * Returns: Pointer to EAP payload (after type field), or %NULL on failure
1029 * This is a helper function for EAP method implementations. This is usually
1030 * called in the beginning of struct eap_method::process() function to verify
1031 * that the received EAP request packet has a valid header. This function is
1032 * able to process both legacy and expanded EAP headers and in most cases, the
1033 * caller can just use the returned payload pointer (into *plen) for processing
1034 * the payload regardless of whether the packet used the expanded EAP header or
1037 const u8
* eap_hdr_validate(int vendor
, EapType eap_type
,
1038 const u8
*msg
, size_t msglen
, size_t *plen
)
1040 const struct eap_hdr
*hdr
;
1044 hdr
= (const struct eap_hdr
*) msg
;
1046 if (msglen
< sizeof(*hdr
)) {
1047 wpa_printf(MSG_INFO
, "EAP: Too short EAP frame");
1051 len
= be_to_host16(hdr
->length
);
1052 if (len
< sizeof(*hdr
) + 1 || len
> msglen
) {
1053 wpa_printf(MSG_INFO
, "EAP: Invalid EAP length");
1057 pos
= (const u8
*) (hdr
+ 1);
1059 if (*pos
== EAP_TYPE_EXPANDED
) {
1062 if (len
< sizeof(*hdr
) + 8) {
1063 wpa_printf(MSG_INFO
, "EAP: Invalid expanded EAP "
1068 exp_vendor
= WPA_GET_BE24(pos
);
1070 exp_type
= WPA_GET_BE32(pos
);
1072 if (exp_vendor
!= vendor
|| exp_type
!= (u32
) eap_type
) {
1073 wpa_printf(MSG_INFO
, "EAP: Invalid expanded frame "
1078 *plen
= len
- sizeof(*hdr
) - 8;
1081 if (vendor
!= EAP_VENDOR_IETF
|| *pos
!= eap_type
) {
1082 wpa_printf(MSG_INFO
, "EAP: Invalid frame type");
1085 *plen
= len
- sizeof(*hdr
) - 1;
1092 * eap_msg_alloc - Allocate a buffer for an EAP message
1093 * @vendor: Vendor-Id (0 = IETF)
1095 * @len: Buffer for returning message length
1096 * @payload_len: Payload length in bytes (data after Type)
1097 * @code: Message Code (EAP_CODE_*)
1098 * @identifier: Identifier
1099 * @payload: Pointer to payload pointer that will be set to point to the
1100 * beginning of the payload or %NULL if payload pointer is not needed
1101 * Returns: Pointer to the allocated message buffer or %NULL on error
1103 * This function can be used to allocate a buffer for an EAP message and fill
1104 * in the EAP header. This function is automatically using expanded EAP header
1105 * if the selected Vendor-Id is not IETF. In other words, most EAP methods do
1106 * not need to separately select which header type to use when using this
1107 * function to allocate the message buffers.
1109 struct eap_hdr
* eap_msg_alloc(int vendor
, EapType type
, size_t *len
,
1110 size_t payload_len
, u8 code
, u8 identifier
,
1113 struct eap_hdr
*hdr
;
1116 *len
= sizeof(struct eap_hdr
) + (vendor
== EAP_VENDOR_IETF
? 1 : 8) +
1121 hdr
->identifier
= identifier
;
1122 hdr
->length
= host_to_be16(*len
);
1123 pos
= (u8
*) (hdr
+ 1);
1124 if (vendor
== EAP_VENDOR_IETF
) {
1127 *pos
++ = EAP_TYPE_EXPANDED
;
1128 WPA_PUT_BE24(pos
, vendor
);
1130 WPA_PUT_BE32(pos
, type
);