2 * hostapd / EAP Full Authenticator state machine (RFC 4137)
3 * Copyright (c) 2004-2007, 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.
14 * This state machine is based on the full authenticator state machine defined
15 * in RFC 4137. However, to support backend authentication in RADIUS
16 * authentication server functionality, parts of backend authenticator (also
17 * from RFC 4137) are mixed in. This functionality is enabled by setting
18 * backend_auth configuration variable to TRUE.
25 #include "state_machine.h"
26 #include "common/wpa_ctrl.h"
28 #define STATE_MACHINE_DATA struct eap_sm
29 #define STATE_MACHINE_DEBUG_PREFIX "EAP"
31 #define EAP_MAX_AUTH_ROUNDS 50
33 static void eap_user_free(struct eap_user
*user
);
36 /* EAP state machines are described in RFC 4137 */
38 static int eap_sm_calculateTimeout(struct eap_sm
*sm
, int retransCount
,
39 int eapSRTT
, int eapRTTVAR
,
41 static void eap_sm_parseEapResp(struct eap_sm
*sm
, const struct wpabuf
*resp
);
42 static int eap_sm_getId(const struct wpabuf
*data
);
43 static struct wpabuf
* eap_sm_buildSuccess(struct eap_sm
*sm
, u8 id
);
44 static struct wpabuf
* eap_sm_buildFailure(struct eap_sm
*sm
, u8 id
);
45 static int eap_sm_nextId(struct eap_sm
*sm
, int id
);
46 static void eap_sm_Policy_update(struct eap_sm
*sm
, const u8
*nak_list
,
48 static EapType
eap_sm_Policy_getNextMethod(struct eap_sm
*sm
, int *vendor
);
49 static int eap_sm_Policy_getDecision(struct eap_sm
*sm
);
50 static Boolean
eap_sm_Policy_doPickUp(struct eap_sm
*sm
, EapType method
);
53 static int eap_copy_buf(struct wpabuf
**dst
, const struct wpabuf
*src
)
59 *dst
= wpabuf_dup(src
);
64 static int eap_copy_data(u8
**dst
, size_t *dst_len
,
65 const u8
*src
, size_t src_len
)
71 *dst
= os_malloc(src_len
);
73 os_memcpy(*dst
, src
, src_len
);
82 #define EAP_COPY(dst, src) \
83 eap_copy_data((dst), (dst ## Len), (src), (src ## Len))
87 * eap_user_get - Fetch user information from the database
88 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
89 * @identity: Identity (User-Name) of the user
90 * @identity_len: Length of identity in bytes
91 * @phase2: 0 = EAP phase1 user, 1 = EAP phase2 (tunneled) user
92 * Returns: 0 on success, or -1 on failure
94 * This function is used to fetch user information for EAP. The user will be
95 * selected based on the specified identity. sm->user and
96 * sm->user_eap_method_index are updated for the new user when a matching user
97 * is found. sm->user can be used to get user information (e.g., password).
99 int eap_user_get(struct eap_sm
*sm
, const u8
*identity
, size_t identity_len
,
102 struct eap_user
*user
;
104 if (sm
== NULL
|| sm
->eapol_cb
== NULL
||
105 sm
->eapol_cb
->get_eap_user
== NULL
)
108 eap_user_free(sm
->user
);
111 user
= os_zalloc(sizeof(*user
));
115 if (sm
->eapol_cb
->get_eap_user(sm
->eapol_ctx
, identity
,
116 identity_len
, phase2
, user
) != 0) {
122 sm
->user_eap_method_index
= 0;
128 SM_STATE(EAP
, DISABLED
)
130 SM_ENTRY(EAP
, DISABLED
);
135 SM_STATE(EAP
, INITIALIZE
)
137 SM_ENTRY(EAP
, INITIALIZE
);
140 sm
->eap_if
.eapSuccess
= FALSE
;
141 sm
->eap_if
.eapFail
= FALSE
;
142 sm
->eap_if
.eapTimeout
= FALSE
;
143 os_free(sm
->eap_if
.eapKeyData
);
144 sm
->eap_if
.eapKeyData
= NULL
;
145 sm
->eap_if
.eapKeyDataLen
= 0;
146 sm
->eap_if
.eapKeyAvailable
= FALSE
;
147 sm
->eap_if
.eapRestart
= FALSE
;
150 * This is not defined in RFC 4137, but method state needs to be
151 * reseted here so that it does not remain in success state when
152 * re-authentication starts.
154 if (sm
->m
&& sm
->eap_method_priv
) {
155 sm
->m
->reset(sm
, sm
->eap_method_priv
);
156 sm
->eap_method_priv
= NULL
;
159 sm
->user_eap_method_index
= 0;
161 if (sm
->backend_auth
) {
162 sm
->currentMethod
= EAP_TYPE_NONE
;
163 /* parse rxResp, respId, respMethod */
164 eap_sm_parseEapResp(sm
, sm
->eap_if
.eapRespData
);
166 sm
->currentId
= sm
->respId
;
170 sm
->method_pending
= METHOD_PENDING_NONE
;
172 wpa_msg(sm
->msg_ctx
, MSG_INFO
, WPA_EVENT_EAP_STARTED
173 MACSTR
, MAC2STR(sm
->peer_addr
));
177 SM_STATE(EAP
, PICK_UP_METHOD
)
179 SM_ENTRY(EAP
, PICK_UP_METHOD
);
181 if (eap_sm_Policy_doPickUp(sm
, sm
->respMethod
)) {
182 sm
->currentMethod
= sm
->respMethod
;
183 if (sm
->m
&& sm
->eap_method_priv
) {
184 sm
->m
->reset(sm
, sm
->eap_method_priv
);
185 sm
->eap_method_priv
= NULL
;
187 sm
->m
= eap_server_get_eap_method(EAP_VENDOR_IETF
,
189 if (sm
->m
&& sm
->m
->initPickUp
) {
190 sm
->eap_method_priv
= sm
->m
->initPickUp(sm
);
191 if (sm
->eap_method_priv
== NULL
) {
192 wpa_printf(MSG_DEBUG
, "EAP: Failed to "
193 "initialize EAP method %d",
196 sm
->currentMethod
= EAP_TYPE_NONE
;
200 sm
->currentMethod
= EAP_TYPE_NONE
;
204 wpa_msg(sm
->msg_ctx
, MSG_INFO
, WPA_EVENT_EAP_PROPOSED_METHOD
205 "method=%u", sm
->currentMethod
);
213 sm
->eap_if
.retransWhile
= eap_sm_calculateTimeout(
214 sm
, sm
->retransCount
, sm
->eap_if
.eapSRTT
, sm
->eap_if
.eapRTTVAR
,
219 SM_STATE(EAP
, RETRANSMIT
)
221 SM_ENTRY(EAP
, RETRANSMIT
);
224 if (sm
->retransCount
<= sm
->MaxRetrans
&& sm
->lastReqData
) {
225 if (eap_copy_buf(&sm
->eap_if
.eapReqData
, sm
->lastReqData
) == 0)
226 sm
->eap_if
.eapReq
= TRUE
;
231 SM_STATE(EAP
, RECEIVED
)
233 SM_ENTRY(EAP
, RECEIVED
);
235 /* parse rxResp, respId, respMethod */
236 eap_sm_parseEapResp(sm
, sm
->eap_if
.eapRespData
);
241 SM_STATE(EAP
, DISCARD
)
243 SM_ENTRY(EAP
, DISCARD
);
244 sm
->eap_if
.eapResp
= FALSE
;
245 sm
->eap_if
.eapNoReq
= TRUE
;
249 SM_STATE(EAP
, SEND_REQUEST
)
251 SM_ENTRY(EAP
, SEND_REQUEST
);
253 sm
->retransCount
= 0;
254 if (sm
->eap_if
.eapReqData
) {
255 if (eap_copy_buf(&sm
->lastReqData
, sm
->eap_if
.eapReqData
) == 0)
257 sm
->eap_if
.eapResp
= FALSE
;
258 sm
->eap_if
.eapReq
= TRUE
;
260 sm
->eap_if
.eapResp
= FALSE
;
261 sm
->eap_if
.eapReq
= FALSE
;
264 wpa_printf(MSG_INFO
, "EAP: SEND_REQUEST - no eapReqData");
265 sm
->eap_if
.eapResp
= FALSE
;
266 sm
->eap_if
.eapReq
= FALSE
;
267 sm
->eap_if
.eapNoReq
= TRUE
;
272 SM_STATE(EAP
, INTEGRITY_CHECK
)
274 SM_ENTRY(EAP
, INTEGRITY_CHECK
);
277 sm
->ignore
= sm
->m
->check(sm
, sm
->eap_method_priv
,
278 sm
->eap_if
.eapRespData
);
283 SM_STATE(EAP
, METHOD_REQUEST
)
285 SM_ENTRY(EAP
, METHOD_REQUEST
);
288 wpa_printf(MSG_DEBUG
, "EAP: method not initialized");
292 sm
->currentId
= eap_sm_nextId(sm
, sm
->currentId
);
293 wpa_printf(MSG_DEBUG
, "EAP: building EAP-Request: Identifier %d",
295 sm
->lastId
= sm
->currentId
;
296 wpabuf_free(sm
->eap_if
.eapReqData
);
297 sm
->eap_if
.eapReqData
= sm
->m
->buildReq(sm
, sm
->eap_method_priv
,
299 if (sm
->m
->getTimeout
)
300 sm
->methodTimeout
= sm
->m
->getTimeout(sm
, sm
->eap_method_priv
);
302 sm
->methodTimeout
= 0;
306 SM_STATE(EAP
, METHOD_RESPONSE
)
308 SM_ENTRY(EAP
, METHOD_RESPONSE
);
310 sm
->m
->process(sm
, sm
->eap_method_priv
, sm
->eap_if
.eapRespData
);
311 if (sm
->m
->isDone(sm
, sm
->eap_method_priv
)) {
312 eap_sm_Policy_update(sm
, NULL
, 0);
313 os_free(sm
->eap_if
.eapKeyData
);
315 sm
->eap_if
.eapKeyData
= sm
->m
->getKey(
316 sm
, sm
->eap_method_priv
,
317 &sm
->eap_if
.eapKeyDataLen
);
319 sm
->eap_if
.eapKeyData
= NULL
;
320 sm
->eap_if
.eapKeyDataLen
= 0;
322 sm
->methodState
= METHOD_END
;
324 sm
->methodState
= METHOD_CONTINUE
;
329 SM_STATE(EAP
, PROPOSE_METHOD
)
334 SM_ENTRY(EAP
, PROPOSE_METHOD
);
336 type
= eap_sm_Policy_getNextMethod(sm
, &vendor
);
337 if (vendor
== EAP_VENDOR_IETF
)
338 sm
->currentMethod
= type
;
340 sm
->currentMethod
= EAP_TYPE_EXPANDED
;
341 if (sm
->m
&& sm
->eap_method_priv
) {
342 sm
->m
->reset(sm
, sm
->eap_method_priv
);
343 sm
->eap_method_priv
= NULL
;
345 sm
->m
= eap_server_get_eap_method(vendor
, type
);
347 sm
->eap_method_priv
= sm
->m
->init(sm
);
348 if (sm
->eap_method_priv
== NULL
) {
349 wpa_printf(MSG_DEBUG
, "EAP: Failed to initialize EAP "
350 "method %d", sm
->currentMethod
);
352 sm
->currentMethod
= EAP_TYPE_NONE
;
355 if (sm
->currentMethod
== EAP_TYPE_IDENTITY
||
356 sm
->currentMethod
== EAP_TYPE_NOTIFICATION
)
357 sm
->methodState
= METHOD_CONTINUE
;
359 sm
->methodState
= METHOD_PROPOSED
;
361 wpa_msg(sm
->msg_ctx
, MSG_INFO
, WPA_EVENT_EAP_PROPOSED_METHOD
362 "vendor=%u method=%u", vendor
, sm
->currentMethod
);
368 const struct eap_hdr
*nak
;
371 const u8
*nak_list
= NULL
;
375 if (sm
->eap_method_priv
) {
376 sm
->m
->reset(sm
, sm
->eap_method_priv
);
377 sm
->eap_method_priv
= NULL
;
381 nak
= wpabuf_head(sm
->eap_if
.eapRespData
);
382 if (nak
&& wpabuf_len(sm
->eap_if
.eapRespData
) > sizeof(*nak
)) {
383 len
= be_to_host16(nak
->length
);
384 if (len
> wpabuf_len(sm
->eap_if
.eapRespData
))
385 len
= wpabuf_len(sm
->eap_if
.eapRespData
);
386 pos
= (const u8
*) (nak
+ 1);
388 if (*pos
== EAP_TYPE_NAK
) {
394 eap_sm_Policy_update(sm
, nak_list
, len
);
398 SM_STATE(EAP
, SELECT_ACTION
)
400 SM_ENTRY(EAP
, SELECT_ACTION
);
402 sm
->decision
= eap_sm_Policy_getDecision(sm
);
406 SM_STATE(EAP
, TIMEOUT_FAILURE
)
408 SM_ENTRY(EAP
, TIMEOUT_FAILURE
);
410 sm
->eap_if
.eapTimeout
= TRUE
;
414 SM_STATE(EAP
, FAILURE
)
416 SM_ENTRY(EAP
, FAILURE
);
418 wpabuf_free(sm
->eap_if
.eapReqData
);
419 sm
->eap_if
.eapReqData
= eap_sm_buildFailure(sm
, sm
->currentId
);
420 wpabuf_free(sm
->lastReqData
);
421 sm
->lastReqData
= NULL
;
422 sm
->eap_if
.eapFail
= TRUE
;
424 wpa_msg(sm
->msg_ctx
, MSG_INFO
, WPA_EVENT_EAP_FAILURE
425 MACSTR
, MAC2STR(sm
->peer_addr
));
429 SM_STATE(EAP
, SUCCESS
)
431 SM_ENTRY(EAP
, SUCCESS
);
433 wpabuf_free(sm
->eap_if
.eapReqData
);
434 sm
->eap_if
.eapReqData
= eap_sm_buildSuccess(sm
, sm
->currentId
);
435 wpabuf_free(sm
->lastReqData
);
436 sm
->lastReqData
= NULL
;
437 if (sm
->eap_if
.eapKeyData
)
438 sm
->eap_if
.eapKeyAvailable
= TRUE
;
439 sm
->eap_if
.eapSuccess
= TRUE
;
441 wpa_msg(sm
->msg_ctx
, MSG_INFO
, WPA_EVENT_EAP_SUCCESS
442 MACSTR
, MAC2STR(sm
->peer_addr
));
446 SM_STATE(EAP
, INITIALIZE_PASSTHROUGH
)
448 SM_ENTRY(EAP
, INITIALIZE_PASSTHROUGH
);
450 wpabuf_free(sm
->eap_if
.aaaEapRespData
);
451 sm
->eap_if
.aaaEapRespData
= NULL
;
457 SM_ENTRY(EAP
, IDLE2
);
459 sm
->eap_if
.retransWhile
= eap_sm_calculateTimeout(
460 sm
, sm
->retransCount
, sm
->eap_if
.eapSRTT
, sm
->eap_if
.eapRTTVAR
,
465 SM_STATE(EAP
, RETRANSMIT2
)
467 SM_ENTRY(EAP
, RETRANSMIT2
);
470 if (sm
->retransCount
<= sm
->MaxRetrans
&& sm
->lastReqData
) {
471 if (eap_copy_buf(&sm
->eap_if
.eapReqData
, sm
->lastReqData
) == 0)
472 sm
->eap_if
.eapReq
= TRUE
;
477 SM_STATE(EAP
, RECEIVED2
)
479 SM_ENTRY(EAP
, RECEIVED2
);
481 /* parse rxResp, respId, respMethod */
482 eap_sm_parseEapResp(sm
, sm
->eap_if
.eapRespData
);
486 SM_STATE(EAP
, DISCARD2
)
488 SM_ENTRY(EAP
, DISCARD2
);
489 sm
->eap_if
.eapResp
= FALSE
;
490 sm
->eap_if
.eapNoReq
= TRUE
;
494 SM_STATE(EAP
, SEND_REQUEST2
)
496 SM_ENTRY(EAP
, SEND_REQUEST2
);
498 sm
->retransCount
= 0;
499 if (sm
->eap_if
.eapReqData
) {
500 if (eap_copy_buf(&sm
->lastReqData
, sm
->eap_if
.eapReqData
) == 0)
502 sm
->eap_if
.eapResp
= FALSE
;
503 sm
->eap_if
.eapReq
= TRUE
;
505 sm
->eap_if
.eapResp
= FALSE
;
506 sm
->eap_if
.eapReq
= FALSE
;
509 wpa_printf(MSG_INFO
, "EAP: SEND_REQUEST2 - no eapReqData");
510 sm
->eap_if
.eapResp
= FALSE
;
511 sm
->eap_if
.eapReq
= FALSE
;
512 sm
->eap_if
.eapNoReq
= TRUE
;
517 SM_STATE(EAP
, AAA_REQUEST
)
519 SM_ENTRY(EAP
, AAA_REQUEST
);
521 if (sm
->eap_if
.eapRespData
== NULL
) {
522 wpa_printf(MSG_INFO
, "EAP: AAA_REQUEST - no eapRespData");
527 * if (respMethod == IDENTITY)
528 * aaaIdentity = eapRespData
529 * This is already taken care of by the EAP-Identity method which
530 * stores the identity into sm->identity.
533 eap_copy_buf(&sm
->eap_if
.aaaEapRespData
, sm
->eap_if
.eapRespData
);
537 SM_STATE(EAP
, AAA_RESPONSE
)
539 SM_ENTRY(EAP
, AAA_RESPONSE
);
541 eap_copy_buf(&sm
->eap_if
.eapReqData
, sm
->eap_if
.aaaEapReqData
);
542 sm
->currentId
= eap_sm_getId(sm
->eap_if
.eapReqData
);
543 sm
->methodTimeout
= sm
->eap_if
.aaaMethodTimeout
;
547 SM_STATE(EAP
, AAA_IDLE
)
549 SM_ENTRY(EAP
, AAA_IDLE
);
551 sm
->eap_if
.aaaFail
= FALSE
;
552 sm
->eap_if
.aaaSuccess
= FALSE
;
553 sm
->eap_if
.aaaEapReq
= FALSE
;
554 sm
->eap_if
.aaaEapNoReq
= FALSE
;
555 sm
->eap_if
.aaaEapResp
= TRUE
;
559 SM_STATE(EAP
, TIMEOUT_FAILURE2
)
561 SM_ENTRY(EAP
, TIMEOUT_FAILURE2
);
563 sm
->eap_if
.eapTimeout
= TRUE
;
567 SM_STATE(EAP
, FAILURE2
)
569 SM_ENTRY(EAP
, FAILURE2
);
571 eap_copy_buf(&sm
->eap_if
.eapReqData
, sm
->eap_if
.aaaEapReqData
);
572 sm
->eap_if
.eapFail
= TRUE
;
576 SM_STATE(EAP
, SUCCESS2
)
578 SM_ENTRY(EAP
, SUCCESS2
);
580 eap_copy_buf(&sm
->eap_if
.eapReqData
, sm
->eap_if
.aaaEapReqData
);
582 sm
->eap_if
.eapKeyAvailable
= sm
->eap_if
.aaaEapKeyAvailable
;
583 if (sm
->eap_if
.aaaEapKeyAvailable
) {
584 EAP_COPY(&sm
->eap_if
.eapKeyData
, sm
->eap_if
.aaaEapKeyData
);
586 os_free(sm
->eap_if
.eapKeyData
);
587 sm
->eap_if
.eapKeyData
= NULL
;
588 sm
->eap_if
.eapKeyDataLen
= 0;
591 sm
->eap_if
.eapSuccess
= TRUE
;
594 * Start reauthentication with identity request even though we know the
595 * previously used identity. This is needed to get reauthentication
598 sm
->start_reauth
= TRUE
;
604 if (sm
->eap_if
.eapRestart
&& sm
->eap_if
.portEnabled
)
605 SM_ENTER_GLOBAL(EAP
, INITIALIZE
);
606 else if (!sm
->eap_if
.portEnabled
)
607 SM_ENTER_GLOBAL(EAP
, DISABLED
);
608 else if (sm
->num_rounds
> EAP_MAX_AUTH_ROUNDS
) {
609 if (sm
->num_rounds
== EAP_MAX_AUTH_ROUNDS
+ 1) {
610 wpa_printf(MSG_DEBUG
, "EAP: more than %d "
611 "authentication rounds - abort",
612 EAP_MAX_AUTH_ROUNDS
);
614 SM_ENTER_GLOBAL(EAP
, FAILURE
);
616 } else switch (sm
->EAP_state
) {
618 if (sm
->backend_auth
) {
620 SM_ENTER(EAP
, SELECT_ACTION
);
621 else if (sm
->rxResp
&&
622 (sm
->respMethod
== EAP_TYPE_NAK
||
623 (sm
->respMethod
== EAP_TYPE_EXPANDED
&&
624 sm
->respVendor
== EAP_VENDOR_IETF
&&
625 sm
->respVendorMethod
== EAP_TYPE_NAK
)))
628 SM_ENTER(EAP
, PICK_UP_METHOD
);
630 SM_ENTER(EAP
, SELECT_ACTION
);
633 case EAP_PICK_UP_METHOD
:
634 if (sm
->currentMethod
== EAP_TYPE_NONE
) {
635 SM_ENTER(EAP
, SELECT_ACTION
);
637 SM_ENTER(EAP
, METHOD_RESPONSE
);
641 if (sm
->eap_if
.portEnabled
)
642 SM_ENTER(EAP
, INITIALIZE
);
645 if (sm
->eap_if
.retransWhile
== 0)
646 SM_ENTER(EAP
, RETRANSMIT
);
647 else if (sm
->eap_if
.eapResp
)
648 SM_ENTER(EAP
, RECEIVED
);
651 if (sm
->retransCount
> sm
->MaxRetrans
)
652 SM_ENTER(EAP
, TIMEOUT_FAILURE
);
657 if (sm
->rxResp
&& (sm
->respId
== sm
->currentId
) &&
658 (sm
->respMethod
== EAP_TYPE_NAK
||
659 (sm
->respMethod
== EAP_TYPE_EXPANDED
&&
660 sm
->respVendor
== EAP_VENDOR_IETF
&&
661 sm
->respVendorMethod
== EAP_TYPE_NAK
))
662 && (sm
->methodState
== METHOD_PROPOSED
))
664 else if (sm
->rxResp
&& (sm
->respId
== sm
->currentId
) &&
665 ((sm
->respMethod
== sm
->currentMethod
) ||
666 (sm
->respMethod
== EAP_TYPE_EXPANDED
&&
667 sm
->respVendor
== EAP_VENDOR_IETF
&&
668 sm
->respVendorMethod
== sm
->currentMethod
)))
669 SM_ENTER(EAP
, INTEGRITY_CHECK
);
671 wpa_printf(MSG_DEBUG
, "EAP: RECEIVED->DISCARD: "
672 "rxResp=%d respId=%d currentId=%d "
673 "respMethod=%d currentMethod=%d",
674 sm
->rxResp
, sm
->respId
, sm
->currentId
,
675 sm
->respMethod
, sm
->currentMethod
);
676 SM_ENTER(EAP
, DISCARD
);
682 case EAP_SEND_REQUEST
:
685 case EAP_INTEGRITY_CHECK
:
687 SM_ENTER(EAP
, DISCARD
);
689 SM_ENTER(EAP
, METHOD_RESPONSE
);
691 case EAP_METHOD_REQUEST
:
692 SM_ENTER(EAP
, SEND_REQUEST
);
694 case EAP_METHOD_RESPONSE
:
696 * Note: Mechanism to allow EAP methods to wait while going
697 * through pending processing is an extension to RFC 4137
698 * which only defines the transits to SELECT_ACTION and
699 * METHOD_REQUEST from this METHOD_RESPONSE state.
701 if (sm
->methodState
== METHOD_END
)
702 SM_ENTER(EAP
, SELECT_ACTION
);
703 else if (sm
->method_pending
== METHOD_PENDING_WAIT
) {
704 wpa_printf(MSG_DEBUG
, "EAP: Method has pending "
705 "processing - wait before proceeding to "
706 "METHOD_REQUEST state");
707 } else if (sm
->method_pending
== METHOD_PENDING_CONT
) {
708 wpa_printf(MSG_DEBUG
, "EAP: Method has completed "
709 "pending processing - reprocess pending "
711 sm
->method_pending
= METHOD_PENDING_NONE
;
712 SM_ENTER(EAP
, METHOD_RESPONSE
);
714 SM_ENTER(EAP
, METHOD_REQUEST
);
716 case EAP_PROPOSE_METHOD
:
718 * Note: Mechanism to allow EAP methods to wait while going
719 * through pending processing is an extension to RFC 4137
720 * which only defines the transit to METHOD_REQUEST from this
721 * PROPOSE_METHOD state.
723 if (sm
->method_pending
== METHOD_PENDING_WAIT
) {
724 wpa_printf(MSG_DEBUG
, "EAP: Method has pending "
725 "processing - wait before proceeding to "
726 "METHOD_REQUEST state");
727 if (sm
->user_eap_method_index
> 0)
728 sm
->user_eap_method_index
--;
729 } else if (sm
->method_pending
== METHOD_PENDING_CONT
) {
730 wpa_printf(MSG_DEBUG
, "EAP: Method has completed "
731 "pending processing - reprocess pending "
733 sm
->method_pending
= METHOD_PENDING_NONE
;
734 SM_ENTER(EAP
, PROPOSE_METHOD
);
736 SM_ENTER(EAP
, METHOD_REQUEST
);
739 SM_ENTER(EAP
, SELECT_ACTION
);
741 case EAP_SELECT_ACTION
:
742 if (sm
->decision
== DECISION_FAILURE
)
743 SM_ENTER(EAP
, FAILURE
);
744 else if (sm
->decision
== DECISION_SUCCESS
)
745 SM_ENTER(EAP
, SUCCESS
);
746 else if (sm
->decision
== DECISION_PASSTHROUGH
)
747 SM_ENTER(EAP
, INITIALIZE_PASSTHROUGH
);
749 SM_ENTER(EAP
, PROPOSE_METHOD
);
751 case EAP_TIMEOUT_FAILURE
:
758 case EAP_INITIALIZE_PASSTHROUGH
:
759 if (sm
->currentId
== -1)
760 SM_ENTER(EAP
, AAA_IDLE
);
762 SM_ENTER(EAP
, AAA_REQUEST
);
765 if (sm
->eap_if
.eapResp
)
766 SM_ENTER(EAP
, RECEIVED2
);
767 else if (sm
->eap_if
.retransWhile
== 0)
768 SM_ENTER(EAP
, RETRANSMIT2
);
770 case EAP_RETRANSMIT2
:
771 if (sm
->retransCount
> sm
->MaxRetrans
)
772 SM_ENTER(EAP
, TIMEOUT_FAILURE2
);
774 SM_ENTER(EAP
, IDLE2
);
777 if (sm
->rxResp
&& (sm
->respId
== sm
->currentId
))
778 SM_ENTER(EAP
, AAA_REQUEST
);
780 SM_ENTER(EAP
, DISCARD2
);
783 SM_ENTER(EAP
, IDLE2
);
785 case EAP_SEND_REQUEST2
:
786 SM_ENTER(EAP
, IDLE2
);
788 case EAP_AAA_REQUEST
:
789 SM_ENTER(EAP
, AAA_IDLE
);
791 case EAP_AAA_RESPONSE
:
792 SM_ENTER(EAP
, SEND_REQUEST2
);
795 if (sm
->eap_if
.aaaFail
)
796 SM_ENTER(EAP
, FAILURE2
);
797 else if (sm
->eap_if
.aaaSuccess
)
798 SM_ENTER(EAP
, SUCCESS2
);
799 else if (sm
->eap_if
.aaaEapReq
)
800 SM_ENTER(EAP
, AAA_RESPONSE
);
801 else if (sm
->eap_if
.aaaTimeout
)
802 SM_ENTER(EAP
, TIMEOUT_FAILURE2
);
804 case EAP_TIMEOUT_FAILURE2
:
814 static int eap_sm_calculateTimeout(struct eap_sm
*sm
, int retransCount
,
815 int eapSRTT
, int eapRTTVAR
,
822 * EAP method (either internal or through AAA server, provided
823 * timeout hint. Use that as-is as a timeout for retransmitting
824 * the EAP request if no response is received.
826 wpa_printf(MSG_DEBUG
, "EAP: retransmit timeout %d seconds "
827 "(from EAP method hint)", methodTimeout
);
828 return methodTimeout
;
832 * RFC 3748 recommends algorithms described in RFC 2988 for estimation
833 * of the retransmission timeout. This should be implemented once
834 * round-trip time measurements are available. For nowm a simple
835 * backoff mechanism is used instead if there are no EAP method
838 * SRTT = smoothed round-trip time
839 * RTTVAR = round-trip time variation
840 * RTO = retransmission timeout
844 * RFC 2988, 2.1: before RTT measurement, set RTO to 3 seconds for
845 * initial retransmission and then double the RTO to provide back off
846 * per 5.5. Limit the maximum RTO to 20 seconds per RFC 3748, 4.3
850 for (i
= 0; i
< retransCount
; i
++) {
858 wpa_printf(MSG_DEBUG
, "EAP: retransmit timeout %d seconds "
859 "(from dynamic back off; retransCount=%d)",
866 static void eap_sm_parseEapResp(struct eap_sm
*sm
, const struct wpabuf
*resp
)
868 const struct eap_hdr
*hdr
;
871 /* parse rxResp, respId, respMethod */
874 sm
->respMethod
= EAP_TYPE_NONE
;
875 sm
->respVendor
= EAP_VENDOR_IETF
;
876 sm
->respVendorMethod
= EAP_TYPE_NONE
;
878 if (resp
== NULL
|| wpabuf_len(resp
) < sizeof(*hdr
)) {
879 wpa_printf(MSG_DEBUG
, "EAP: parseEapResp: invalid resp=%p "
881 resp
? (unsigned long) wpabuf_len(resp
) : 0);
885 hdr
= wpabuf_head(resp
);
886 plen
= be_to_host16(hdr
->length
);
887 if (plen
> wpabuf_len(resp
)) {
888 wpa_printf(MSG_DEBUG
, "EAP: Ignored truncated EAP-Packet "
889 "(len=%lu plen=%lu)",
890 (unsigned long) wpabuf_len(resp
),
891 (unsigned long) plen
);
895 sm
->respId
= hdr
->identifier
;
897 if (hdr
->code
== EAP_CODE_RESPONSE
)
900 if (plen
> sizeof(*hdr
)) {
901 u8
*pos
= (u8
*) (hdr
+ 1);
902 sm
->respMethod
= *pos
++;
903 if (sm
->respMethod
== EAP_TYPE_EXPANDED
) {
904 if (plen
< sizeof(*hdr
) + 8) {
905 wpa_printf(MSG_DEBUG
, "EAP: Ignored truncated "
906 "expanded EAP-Packet (plen=%lu)",
907 (unsigned long) plen
);
910 sm
->respVendor
= WPA_GET_BE24(pos
);
912 sm
->respVendorMethod
= WPA_GET_BE32(pos
);
916 wpa_printf(MSG_DEBUG
, "EAP: parseEapResp: rxResp=%d respId=%d "
917 "respMethod=%u respVendor=%u respVendorMethod=%u",
918 sm
->rxResp
, sm
->respId
, sm
->respMethod
, sm
->respVendor
,
919 sm
->respVendorMethod
);
923 static int eap_sm_getId(const struct wpabuf
*data
)
925 const struct eap_hdr
*hdr
;
927 if (data
== NULL
|| wpabuf_len(data
) < sizeof(*hdr
))
930 hdr
= wpabuf_head(data
);
931 wpa_printf(MSG_DEBUG
, "EAP: getId: id=%d", hdr
->identifier
);
932 return hdr
->identifier
;
936 static struct wpabuf
* eap_sm_buildSuccess(struct eap_sm
*sm
, u8 id
)
939 struct eap_hdr
*resp
;
940 wpa_printf(MSG_DEBUG
, "EAP: Building EAP-Success (id=%d)", id
);
942 msg
= wpabuf_alloc(sizeof(*resp
));
945 resp
= wpabuf_put(msg
, sizeof(*resp
));
946 resp
->code
= EAP_CODE_SUCCESS
;
947 resp
->identifier
= id
;
948 resp
->length
= host_to_be16(sizeof(*resp
));
954 static struct wpabuf
* eap_sm_buildFailure(struct eap_sm
*sm
, u8 id
)
957 struct eap_hdr
*resp
;
958 wpa_printf(MSG_DEBUG
, "EAP: Building EAP-Failure (id=%d)", id
);
960 msg
= wpabuf_alloc(sizeof(*resp
));
963 resp
= wpabuf_put(msg
, sizeof(*resp
));
964 resp
->code
= EAP_CODE_FAILURE
;
965 resp
->identifier
= id
;
966 resp
->length
= host_to_be16(sizeof(*resp
));
972 static int eap_sm_nextId(struct eap_sm
*sm
, int id
)
975 /* RFC 3748 Ch 4.1: recommended to initialize Identifier with a
978 if (id
!= sm
->lastId
)
981 return (id
+ 1) & 0xff;
986 * eap_sm_process_nak - Process EAP-Response/Nak
987 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
988 * @nak_list: Nak list (allowed methods) from the supplicant
989 * @len: Length of nak_list in bytes
991 * This function is called when EAP-Response/Nak is received from the
992 * supplicant. This can happen for both phase 1 and phase 2 authentications.
994 void eap_sm_process_nak(struct eap_sm
*sm
, const u8
*nak_list
, size_t len
)
999 if (sm
->user
== NULL
)
1002 wpa_printf(MSG_MSGDUMP
, "EAP: processing NAK (current EAP method "
1003 "index %d)", sm
->user_eap_method_index
);
1005 wpa_hexdump(MSG_MSGDUMP
, "EAP: configured methods",
1006 (u8
*) sm
->user
->methods
,
1007 EAP_MAX_METHODS
* sizeof(sm
->user
->methods
[0]));
1008 wpa_hexdump(MSG_MSGDUMP
, "EAP: list of methods supported by the peer",
1011 i
= sm
->user_eap_method_index
;
1012 while (i
< EAP_MAX_METHODS
&&
1013 (sm
->user
->methods
[i
].vendor
!= EAP_VENDOR_IETF
||
1014 sm
->user
->methods
[i
].method
!= EAP_TYPE_NONE
)) {
1015 if (sm
->user
->methods
[i
].vendor
!= EAP_VENDOR_IETF
)
1017 for (j
= 0; j
< len
; j
++) {
1018 if (nak_list
[j
] == sm
->user
->methods
[i
].method
) {
1030 /* not found - remove from the list */
1031 os_memmove(&sm
->user
->methods
[i
], &sm
->user
->methods
[i
+ 1],
1032 (EAP_MAX_METHODS
- i
- 1) *
1033 sizeof(sm
->user
->methods
[0]));
1034 sm
->user
->methods
[EAP_MAX_METHODS
- 1].vendor
=
1036 sm
->user
->methods
[EAP_MAX_METHODS
- 1].method
= EAP_TYPE_NONE
;
1039 wpa_hexdump(MSG_MSGDUMP
, "EAP: new list of configured methods",
1040 (u8
*) sm
->user
->methods
, EAP_MAX_METHODS
*
1041 sizeof(sm
->user
->methods
[0]));
1045 static void eap_sm_Policy_update(struct eap_sm
*sm
, const u8
*nak_list
,
1048 if (nak_list
== NULL
|| sm
== NULL
|| sm
->user
== NULL
)
1051 if (sm
->user
->phase2
) {
1052 wpa_printf(MSG_DEBUG
, "EAP: EAP-Nak received after Phase2 user"
1053 " info was selected - reject");
1054 sm
->decision
= DECISION_FAILURE
;
1058 eap_sm_process_nak(sm
, nak_list
, len
);
1062 static EapType
eap_sm_Policy_getNextMethod(struct eap_sm
*sm
, int *vendor
)
1065 int idx
= sm
->user_eap_method_index
;
1067 /* In theory, there should be no problems with starting
1068 * re-authentication with something else than EAP-Request/Identity and
1069 * this does indeed work with wpa_supplicant. However, at least Funk
1070 * Supplicant seemed to ignore re-auth if it skipped
1071 * EAP-Request/Identity.
1072 * Re-auth sets currentId == -1, so that can be used here to select
1073 * whether Identity needs to be requested again. */
1074 if (sm
->identity
== NULL
|| sm
->currentId
== -1) {
1075 *vendor
= EAP_VENDOR_IETF
;
1076 next
= EAP_TYPE_IDENTITY
;
1077 sm
->update_user
= TRUE
;
1078 } else if (sm
->user
&& idx
< EAP_MAX_METHODS
&&
1079 (sm
->user
->methods
[idx
].vendor
!= EAP_VENDOR_IETF
||
1080 sm
->user
->methods
[idx
].method
!= EAP_TYPE_NONE
)) {
1081 *vendor
= sm
->user
->methods
[idx
].vendor
;
1082 next
= sm
->user
->methods
[idx
].method
;
1083 sm
->user_eap_method_index
++;
1085 *vendor
= EAP_VENDOR_IETF
;
1086 next
= EAP_TYPE_NONE
;
1088 wpa_printf(MSG_DEBUG
, "EAP: getNextMethod: vendor %d type %d",
1094 static int eap_sm_Policy_getDecision(struct eap_sm
*sm
)
1096 if (!sm
->eap_server
&& sm
->identity
&& !sm
->start_reauth
) {
1097 wpa_printf(MSG_DEBUG
, "EAP: getDecision: -> PASSTHROUGH");
1098 return DECISION_PASSTHROUGH
;
1101 if (sm
->m
&& sm
->currentMethod
!= EAP_TYPE_IDENTITY
&&
1102 sm
->m
->isSuccess(sm
, sm
->eap_method_priv
)) {
1103 wpa_printf(MSG_DEBUG
, "EAP: getDecision: method succeeded -> "
1105 sm
->update_user
= TRUE
;
1106 return DECISION_SUCCESS
;
1109 if (sm
->m
&& sm
->m
->isDone(sm
, sm
->eap_method_priv
) &&
1110 !sm
->m
->isSuccess(sm
, sm
->eap_method_priv
)) {
1111 wpa_printf(MSG_DEBUG
, "EAP: getDecision: method failed -> "
1113 sm
->update_user
= TRUE
;
1114 return DECISION_FAILURE
;
1117 if ((sm
->user
== NULL
|| sm
->update_user
) && sm
->identity
&&
1118 !sm
->start_reauth
) {
1120 * Allow Identity method to be started once to allow identity
1121 * selection hint to be sent from the authentication server,
1122 * but prevent a loop of Identity requests by only allowing
1123 * this to happen once.
1126 if (sm
->user
&& sm
->currentMethod
== EAP_TYPE_IDENTITY
&&
1127 sm
->user
->methods
[0].vendor
== EAP_VENDOR_IETF
&&
1128 sm
->user
->methods
[0].method
== EAP_TYPE_IDENTITY
)
1130 if (eap_user_get(sm
, sm
->identity
, sm
->identity_len
, 0) != 0) {
1131 wpa_printf(MSG_DEBUG
, "EAP: getDecision: user not "
1132 "found from database -> FAILURE");
1133 return DECISION_FAILURE
;
1135 if (id_req
&& sm
->user
&&
1136 sm
->user
->methods
[0].vendor
== EAP_VENDOR_IETF
&&
1137 sm
->user
->methods
[0].method
== EAP_TYPE_IDENTITY
) {
1138 wpa_printf(MSG_DEBUG
, "EAP: getDecision: stop "
1139 "identity request loop -> FAILURE");
1140 sm
->update_user
= TRUE
;
1141 return DECISION_FAILURE
;
1143 sm
->update_user
= FALSE
;
1145 sm
->start_reauth
= FALSE
;
1147 if (sm
->user
&& sm
->user_eap_method_index
< EAP_MAX_METHODS
&&
1148 (sm
->user
->methods
[sm
->user_eap_method_index
].vendor
!=
1150 sm
->user
->methods
[sm
->user_eap_method_index
].method
!=
1152 wpa_printf(MSG_DEBUG
, "EAP: getDecision: another method "
1153 "available -> CONTINUE");
1154 return DECISION_CONTINUE
;
1157 if (sm
->identity
== NULL
|| sm
->currentId
== -1) {
1158 wpa_printf(MSG_DEBUG
, "EAP: getDecision: no identity known "
1160 return DECISION_CONTINUE
;
1163 wpa_printf(MSG_DEBUG
, "EAP: getDecision: no more methods available -> "
1165 return DECISION_FAILURE
;
1169 static Boolean
eap_sm_Policy_doPickUp(struct eap_sm
*sm
, EapType method
)
1171 return method
== EAP_TYPE_IDENTITY
? TRUE
: FALSE
;
1176 * eap_server_sm_step - Step EAP server state machine
1177 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1178 * Returns: 1 if EAP state was changed or 0 if not
1180 * This function advances EAP state machine to a new state to match with the
1181 * current variables. This should be called whenever variables used by the EAP
1182 * state machine have changed.
1184 int eap_server_sm_step(struct eap_sm
*sm
)
1188 sm
->changed
= FALSE
;
1192 } while (sm
->changed
);
1197 static void eap_user_free(struct eap_user
*user
)
1201 os_free(user
->password
);
1202 user
->password
= NULL
;
1208 * eap_server_sm_init - Allocate and initialize EAP server state machine
1209 * @eapol_ctx: Context data to be used with eapol_cb calls
1210 * @eapol_cb: Pointer to EAPOL callback functions
1211 * @conf: EAP configuration
1212 * Returns: Pointer to the allocated EAP state machine or %NULL on failure
1214 * This function allocates and initializes an EAP state machine.
1216 struct eap_sm
* eap_server_sm_init(void *eapol_ctx
,
1217 struct eapol_callbacks
*eapol_cb
,
1218 struct eap_config
*conf
)
1222 sm
= os_zalloc(sizeof(*sm
));
1225 sm
->eapol_ctx
= eapol_ctx
;
1226 sm
->eapol_cb
= eapol_cb
;
1227 sm
->MaxRetrans
= 5; /* RFC 3748: max 3-5 retransmissions suggested */
1228 sm
->ssl_ctx
= conf
->ssl_ctx
;
1229 sm
->msg_ctx
= conf
->msg_ctx
;
1230 sm
->eap_sim_db_priv
= conf
->eap_sim_db_priv
;
1231 sm
->backend_auth
= conf
->backend_auth
;
1232 sm
->eap_server
= conf
->eap_server
;
1233 if (conf
->pac_opaque_encr_key
) {
1234 sm
->pac_opaque_encr_key
= os_malloc(16);
1235 if (sm
->pac_opaque_encr_key
) {
1236 os_memcpy(sm
->pac_opaque_encr_key
,
1237 conf
->pac_opaque_encr_key
, 16);
1240 if (conf
->eap_fast_a_id
) {
1241 sm
->eap_fast_a_id
= os_malloc(conf
->eap_fast_a_id_len
);
1242 if (sm
->eap_fast_a_id
) {
1243 os_memcpy(sm
->eap_fast_a_id
, conf
->eap_fast_a_id
,
1244 conf
->eap_fast_a_id_len
);
1245 sm
->eap_fast_a_id_len
= conf
->eap_fast_a_id_len
;
1248 if (conf
->eap_fast_a_id_info
)
1249 sm
->eap_fast_a_id_info
= os_strdup(conf
->eap_fast_a_id_info
);
1250 sm
->eap_fast_prov
= conf
->eap_fast_prov
;
1251 sm
->pac_key_lifetime
= conf
->pac_key_lifetime
;
1252 sm
->pac_key_refresh_time
= conf
->pac_key_refresh_time
;
1253 sm
->eap_sim_aka_result_ind
= conf
->eap_sim_aka_result_ind
;
1254 sm
->tnc
= conf
->tnc
;
1255 sm
->wps
= conf
->wps
;
1256 if (conf
->assoc_wps_ie
)
1257 sm
->assoc_wps_ie
= wpabuf_dup(conf
->assoc_wps_ie
);
1258 if (conf
->peer_addr
)
1259 os_memcpy(sm
->peer_addr
, conf
->peer_addr
, ETH_ALEN
);
1261 wpa_printf(MSG_DEBUG
, "EAP: Server state machine created");
1268 * eap_server_sm_deinit - Deinitialize and free an EAP server state machine
1269 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1271 * This function deinitializes EAP state machine and frees all allocated
1274 void eap_server_sm_deinit(struct eap_sm
*sm
)
1278 wpa_printf(MSG_DEBUG
, "EAP: Server state machine removed");
1279 if (sm
->m
&& sm
->eap_method_priv
)
1280 sm
->m
->reset(sm
, sm
->eap_method_priv
);
1281 wpabuf_free(sm
->eap_if
.eapReqData
);
1282 os_free(sm
->eap_if
.eapKeyData
);
1283 wpabuf_free(sm
->lastReqData
);
1284 wpabuf_free(sm
->eap_if
.eapRespData
);
1285 os_free(sm
->identity
);
1286 os_free(sm
->pac_opaque_encr_key
);
1287 os_free(sm
->eap_fast_a_id
);
1288 os_free(sm
->eap_fast_a_id_info
);
1289 wpabuf_free(sm
->eap_if
.aaaEapReqData
);
1290 wpabuf_free(sm
->eap_if
.aaaEapRespData
);
1291 os_free(sm
->eap_if
.aaaEapKeyData
);
1292 eap_user_free(sm
->user
);
1293 wpabuf_free(sm
->assoc_wps_ie
);
1299 * eap_sm_notify_cached - Notify EAP state machine of cached PMK
1300 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1302 * This function is called when PMKSA caching is used to skip EAP
1305 void eap_sm_notify_cached(struct eap_sm
*sm
)
1310 sm
->EAP_state
= EAP_SUCCESS
;
1315 * eap_sm_pending_cb - EAP state machine callback for a pending EAP request
1316 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1318 * This function is called when data for a pending EAP-Request is received.
1320 void eap_sm_pending_cb(struct eap_sm
*sm
)
1324 wpa_printf(MSG_DEBUG
, "EAP: Callback for pending request received");
1325 if (sm
->method_pending
== METHOD_PENDING_WAIT
)
1326 sm
->method_pending
= METHOD_PENDING_CONT
;
1331 * eap_sm_method_pending - Query whether EAP method is waiting for pending data
1332 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1333 * Returns: 1 if method is waiting for pending data or 0 if not
1335 int eap_sm_method_pending(struct eap_sm
*sm
)
1339 return sm
->method_pending
== METHOD_PENDING_WAIT
;
1344 * eap_get_identity - Get the user identity (from EAP-Response/Identity)
1345 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1346 * @len: Buffer for returning identity length
1347 * Returns: Pointer to the user identity or %NULL if not available
1349 const u8
* eap_get_identity(struct eap_sm
*sm
, size_t *len
)
1351 *len
= sm
->identity_len
;
1352 return sm
->identity
;
1357 * eap_get_interface - Get pointer to EAP-EAPOL interface data
1358 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1359 * Returns: Pointer to the EAP-EAPOL interface data
1361 struct eap_eapol_interface
* eap_get_interface(struct eap_sm
*sm
)