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"
27 #define STATE_MACHINE_DATA struct eap_sm
28 #define STATE_MACHINE_DEBUG_PREFIX "EAP"
30 #define EAP_MAX_AUTH_ROUNDS 50
32 static void eap_user_free(struct eap_user
*user
);
35 /* EAP state machines are described in RFC 4137 */
37 static int eap_sm_calculateTimeout(struct eap_sm
*sm
, int retransCount
,
38 int eapSRTT
, int eapRTTVAR
,
40 static void eap_sm_parseEapResp(struct eap_sm
*sm
, const struct wpabuf
*resp
);
41 static int eap_sm_getId(const struct wpabuf
*data
);
42 static struct wpabuf
* eap_sm_buildSuccess(struct eap_sm
*sm
, u8 id
);
43 static struct wpabuf
* eap_sm_buildFailure(struct eap_sm
*sm
, u8 id
);
44 static int eap_sm_nextId(struct eap_sm
*sm
, int id
);
45 static void eap_sm_Policy_update(struct eap_sm
*sm
, const u8
*nak_list
,
47 static EapType
eap_sm_Policy_getNextMethod(struct eap_sm
*sm
, int *vendor
);
48 static int eap_sm_Policy_getDecision(struct eap_sm
*sm
);
49 static Boolean
eap_sm_Policy_doPickUp(struct eap_sm
*sm
, EapType method
);
52 static int eap_copy_buf(struct wpabuf
**dst
, const struct wpabuf
*src
)
58 *dst
= wpabuf_dup(src
);
63 static int eap_copy_data(u8
**dst
, size_t *dst_len
,
64 const u8
*src
, size_t src_len
)
70 *dst
= os_malloc(src_len
);
72 os_memcpy(*dst
, src
, src_len
);
81 #define EAP_COPY(dst, src) \
82 eap_copy_data((dst), (dst ## Len), (src), (src ## Len))
86 * eap_user_get - Fetch user information from the database
87 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
88 * @identity: Identity (User-Name) of the user
89 * @identity_len: Length of identity in bytes
90 * @phase2: 0 = EAP phase1 user, 1 = EAP phase2 (tunneled) user
91 * Returns: 0 on success, or -1 on failure
93 * This function is used to fetch user information for EAP. The user will be
94 * selected based on the specified identity. sm->user and
95 * sm->user_eap_method_index are updated for the new user when a matching user
96 * is found. sm->user can be used to get user information (e.g., password).
98 int eap_user_get(struct eap_sm
*sm
, const u8
*identity
, size_t identity_len
,
101 struct eap_user
*user
;
103 if (sm
== NULL
|| sm
->eapol_cb
== NULL
||
104 sm
->eapol_cb
->get_eap_user
== NULL
)
107 eap_user_free(sm
->user
);
110 user
= os_zalloc(sizeof(*user
));
114 if (sm
->eapol_cb
->get_eap_user(sm
->eapol_ctx
, identity
,
115 identity_len
, phase2
, user
) != 0) {
121 sm
->user_eap_method_index
= 0;
127 SM_STATE(EAP
, DISABLED
)
129 SM_ENTRY(EAP
, DISABLED
);
134 SM_STATE(EAP
, INITIALIZE
)
136 SM_ENTRY(EAP
, INITIALIZE
);
139 sm
->eap_if
.eapSuccess
= FALSE
;
140 sm
->eap_if
.eapFail
= FALSE
;
141 sm
->eap_if
.eapTimeout
= FALSE
;
142 os_free(sm
->eap_if
.eapKeyData
);
143 sm
->eap_if
.eapKeyData
= NULL
;
144 sm
->eap_if
.eapKeyDataLen
= 0;
145 sm
->eap_if
.eapKeyAvailable
= FALSE
;
146 sm
->eap_if
.eapRestart
= FALSE
;
149 * This is not defined in RFC 4137, but method state needs to be
150 * reseted here so that it does not remain in success state when
151 * re-authentication starts.
153 if (sm
->m
&& sm
->eap_method_priv
) {
154 sm
->m
->reset(sm
, sm
->eap_method_priv
);
155 sm
->eap_method_priv
= NULL
;
158 sm
->user_eap_method_index
= 0;
160 if (sm
->backend_auth
) {
161 sm
->currentMethod
= EAP_TYPE_NONE
;
162 /* parse rxResp, respId, respMethod */
163 eap_sm_parseEapResp(sm
, sm
->eap_if
.eapRespData
);
165 sm
->currentId
= sm
->respId
;
169 sm
->method_pending
= METHOD_PENDING_NONE
;
173 SM_STATE(EAP
, PICK_UP_METHOD
)
175 SM_ENTRY(EAP
, PICK_UP_METHOD
);
177 if (eap_sm_Policy_doPickUp(sm
, sm
->respMethod
)) {
178 sm
->currentMethod
= sm
->respMethod
;
179 if (sm
->m
&& sm
->eap_method_priv
) {
180 sm
->m
->reset(sm
, sm
->eap_method_priv
);
181 sm
->eap_method_priv
= NULL
;
183 sm
->m
= eap_server_get_eap_method(EAP_VENDOR_IETF
,
185 if (sm
->m
&& sm
->m
->initPickUp
) {
186 sm
->eap_method_priv
= sm
->m
->initPickUp(sm
);
187 if (sm
->eap_method_priv
== NULL
) {
188 wpa_printf(MSG_DEBUG
, "EAP: Failed to "
189 "initialize EAP method %d",
192 sm
->currentMethod
= EAP_TYPE_NONE
;
196 sm
->currentMethod
= EAP_TYPE_NONE
;
206 sm
->eap_if
.retransWhile
= eap_sm_calculateTimeout(
207 sm
, sm
->retransCount
, sm
->eap_if
.eapSRTT
, sm
->eap_if
.eapRTTVAR
,
212 SM_STATE(EAP
, RETRANSMIT
)
214 SM_ENTRY(EAP
, RETRANSMIT
);
217 if (sm
->retransCount
<= sm
->MaxRetrans
&& sm
->lastReqData
) {
218 if (eap_copy_buf(&sm
->eap_if
.eapReqData
, sm
->lastReqData
) == 0)
219 sm
->eap_if
.eapReq
= TRUE
;
224 SM_STATE(EAP
, RECEIVED
)
226 SM_ENTRY(EAP
, RECEIVED
);
228 /* parse rxResp, respId, respMethod */
229 eap_sm_parseEapResp(sm
, sm
->eap_if
.eapRespData
);
234 SM_STATE(EAP
, DISCARD
)
236 SM_ENTRY(EAP
, DISCARD
);
237 sm
->eap_if
.eapResp
= FALSE
;
238 sm
->eap_if
.eapNoReq
= TRUE
;
242 SM_STATE(EAP
, SEND_REQUEST
)
244 SM_ENTRY(EAP
, SEND_REQUEST
);
246 sm
->retransCount
= 0;
247 if (sm
->eap_if
.eapReqData
) {
248 if (eap_copy_buf(&sm
->lastReqData
, sm
->eap_if
.eapReqData
) == 0)
250 sm
->eap_if
.eapResp
= FALSE
;
251 sm
->eap_if
.eapReq
= TRUE
;
253 sm
->eap_if
.eapResp
= FALSE
;
254 sm
->eap_if
.eapReq
= FALSE
;
257 wpa_printf(MSG_INFO
, "EAP: SEND_REQUEST - no eapReqData");
258 sm
->eap_if
.eapResp
= FALSE
;
259 sm
->eap_if
.eapReq
= FALSE
;
260 sm
->eap_if
.eapNoReq
= TRUE
;
265 SM_STATE(EAP
, INTEGRITY_CHECK
)
267 SM_ENTRY(EAP
, INTEGRITY_CHECK
);
270 sm
->ignore
= sm
->m
->check(sm
, sm
->eap_method_priv
,
271 sm
->eap_if
.eapRespData
);
276 SM_STATE(EAP
, METHOD_REQUEST
)
278 SM_ENTRY(EAP
, METHOD_REQUEST
);
281 wpa_printf(MSG_DEBUG
, "EAP: method not initialized");
285 sm
->currentId
= eap_sm_nextId(sm
, sm
->currentId
);
286 wpa_printf(MSG_DEBUG
, "EAP: building EAP-Request: Identifier %d",
288 sm
->lastId
= sm
->currentId
;
289 wpabuf_free(sm
->eap_if
.eapReqData
);
290 sm
->eap_if
.eapReqData
= sm
->m
->buildReq(sm
, sm
->eap_method_priv
,
292 if (sm
->m
->getTimeout
)
293 sm
->methodTimeout
= sm
->m
->getTimeout(sm
, sm
->eap_method_priv
);
295 sm
->methodTimeout
= 0;
299 SM_STATE(EAP
, METHOD_RESPONSE
)
301 SM_ENTRY(EAP
, METHOD_RESPONSE
);
303 sm
->m
->process(sm
, sm
->eap_method_priv
, sm
->eap_if
.eapRespData
);
304 if (sm
->m
->isDone(sm
, sm
->eap_method_priv
)) {
305 eap_sm_Policy_update(sm
, NULL
, 0);
306 os_free(sm
->eap_if
.eapKeyData
);
308 sm
->eap_if
.eapKeyData
= sm
->m
->getKey(
309 sm
, sm
->eap_method_priv
,
310 &sm
->eap_if
.eapKeyDataLen
);
312 sm
->eap_if
.eapKeyData
= NULL
;
313 sm
->eap_if
.eapKeyDataLen
= 0;
315 sm
->methodState
= METHOD_END
;
317 sm
->methodState
= METHOD_CONTINUE
;
322 SM_STATE(EAP
, PROPOSE_METHOD
)
327 SM_ENTRY(EAP
, PROPOSE_METHOD
);
329 type
= eap_sm_Policy_getNextMethod(sm
, &vendor
);
330 if (vendor
== EAP_VENDOR_IETF
)
331 sm
->currentMethod
= type
;
333 sm
->currentMethod
= EAP_TYPE_EXPANDED
;
334 if (sm
->m
&& sm
->eap_method_priv
) {
335 sm
->m
->reset(sm
, sm
->eap_method_priv
);
336 sm
->eap_method_priv
= NULL
;
338 sm
->m
= eap_server_get_eap_method(vendor
, type
);
340 sm
->eap_method_priv
= sm
->m
->init(sm
);
341 if (sm
->eap_method_priv
== NULL
) {
342 wpa_printf(MSG_DEBUG
, "EAP: Failed to initialize EAP "
343 "method %d", sm
->currentMethod
);
345 sm
->currentMethod
= EAP_TYPE_NONE
;
348 if (sm
->currentMethod
== EAP_TYPE_IDENTITY
||
349 sm
->currentMethod
== EAP_TYPE_NOTIFICATION
)
350 sm
->methodState
= METHOD_CONTINUE
;
352 sm
->methodState
= METHOD_PROPOSED
;
358 const struct eap_hdr
*nak
;
361 const u8
*nak_list
= NULL
;
365 if (sm
->eap_method_priv
) {
366 sm
->m
->reset(sm
, sm
->eap_method_priv
);
367 sm
->eap_method_priv
= NULL
;
371 nak
= wpabuf_head(sm
->eap_if
.eapRespData
);
372 if (nak
&& wpabuf_len(sm
->eap_if
.eapRespData
) > sizeof(*nak
)) {
373 len
= be_to_host16(nak
->length
);
374 if (len
> wpabuf_len(sm
->eap_if
.eapRespData
))
375 len
= wpabuf_len(sm
->eap_if
.eapRespData
);
376 pos
= (const u8
*) (nak
+ 1);
378 if (*pos
== EAP_TYPE_NAK
) {
384 eap_sm_Policy_update(sm
, nak_list
, len
);
388 SM_STATE(EAP
, SELECT_ACTION
)
390 SM_ENTRY(EAP
, SELECT_ACTION
);
392 sm
->decision
= eap_sm_Policy_getDecision(sm
);
396 SM_STATE(EAP
, TIMEOUT_FAILURE
)
398 SM_ENTRY(EAP
, TIMEOUT_FAILURE
);
400 sm
->eap_if
.eapTimeout
= TRUE
;
404 SM_STATE(EAP
, FAILURE
)
406 SM_ENTRY(EAP
, FAILURE
);
408 wpabuf_free(sm
->eap_if
.eapReqData
);
409 sm
->eap_if
.eapReqData
= eap_sm_buildFailure(sm
, sm
->currentId
);
410 wpabuf_free(sm
->lastReqData
);
411 sm
->lastReqData
= NULL
;
412 sm
->eap_if
.eapFail
= TRUE
;
416 SM_STATE(EAP
, SUCCESS
)
418 SM_ENTRY(EAP
, SUCCESS
);
420 wpabuf_free(sm
->eap_if
.eapReqData
);
421 sm
->eap_if
.eapReqData
= eap_sm_buildSuccess(sm
, sm
->currentId
);
422 wpabuf_free(sm
->lastReqData
);
423 sm
->lastReqData
= NULL
;
424 if (sm
->eap_if
.eapKeyData
)
425 sm
->eap_if
.eapKeyAvailable
= TRUE
;
426 sm
->eap_if
.eapSuccess
= TRUE
;
430 SM_STATE(EAP
, INITIALIZE_PASSTHROUGH
)
432 SM_ENTRY(EAP
, INITIALIZE_PASSTHROUGH
);
434 wpabuf_free(sm
->eap_if
.aaaEapRespData
);
435 sm
->eap_if
.aaaEapRespData
= NULL
;
441 SM_ENTRY(EAP
, IDLE2
);
443 sm
->eap_if
.retransWhile
= eap_sm_calculateTimeout(
444 sm
, sm
->retransCount
, sm
->eap_if
.eapSRTT
, sm
->eap_if
.eapRTTVAR
,
449 SM_STATE(EAP
, RETRANSMIT2
)
451 SM_ENTRY(EAP
, RETRANSMIT2
);
454 if (sm
->retransCount
<= sm
->MaxRetrans
&& sm
->lastReqData
) {
455 if (eap_copy_buf(&sm
->eap_if
.eapReqData
, sm
->lastReqData
) == 0)
456 sm
->eap_if
.eapReq
= TRUE
;
461 SM_STATE(EAP
, RECEIVED2
)
463 SM_ENTRY(EAP
, RECEIVED2
);
465 /* parse rxResp, respId, respMethod */
466 eap_sm_parseEapResp(sm
, sm
->eap_if
.eapRespData
);
470 SM_STATE(EAP
, DISCARD2
)
472 SM_ENTRY(EAP
, DISCARD2
);
473 sm
->eap_if
.eapResp
= FALSE
;
474 sm
->eap_if
.eapNoReq
= TRUE
;
478 SM_STATE(EAP
, SEND_REQUEST2
)
480 SM_ENTRY(EAP
, SEND_REQUEST2
);
482 sm
->retransCount
= 0;
483 if (sm
->eap_if
.eapReqData
) {
484 if (eap_copy_buf(&sm
->lastReqData
, sm
->eap_if
.eapReqData
) == 0)
486 sm
->eap_if
.eapResp
= FALSE
;
487 sm
->eap_if
.eapReq
= TRUE
;
489 sm
->eap_if
.eapResp
= FALSE
;
490 sm
->eap_if
.eapReq
= FALSE
;
493 wpa_printf(MSG_INFO
, "EAP: SEND_REQUEST2 - no eapReqData");
494 sm
->eap_if
.eapResp
= FALSE
;
495 sm
->eap_if
.eapReq
= FALSE
;
496 sm
->eap_if
.eapNoReq
= TRUE
;
501 SM_STATE(EAP
, AAA_REQUEST
)
503 SM_ENTRY(EAP
, AAA_REQUEST
);
505 if (sm
->eap_if
.eapRespData
== NULL
) {
506 wpa_printf(MSG_INFO
, "EAP: AAA_REQUEST - no eapRespData");
511 * if (respMethod == IDENTITY)
512 * aaaIdentity = eapRespData
513 * This is already taken care of by the EAP-Identity method which
514 * stores the identity into sm->identity.
517 eap_copy_buf(&sm
->eap_if
.aaaEapRespData
, sm
->eap_if
.eapRespData
);
521 SM_STATE(EAP
, AAA_RESPONSE
)
523 SM_ENTRY(EAP
, AAA_RESPONSE
);
525 eap_copy_buf(&sm
->eap_if
.eapReqData
, sm
->eap_if
.aaaEapReqData
);
526 sm
->currentId
= eap_sm_getId(sm
->eap_if
.eapReqData
);
527 sm
->methodTimeout
= sm
->eap_if
.aaaMethodTimeout
;
531 SM_STATE(EAP
, AAA_IDLE
)
533 SM_ENTRY(EAP
, AAA_IDLE
);
535 sm
->eap_if
.aaaFail
= FALSE
;
536 sm
->eap_if
.aaaSuccess
= FALSE
;
537 sm
->eap_if
.aaaEapReq
= FALSE
;
538 sm
->eap_if
.aaaEapNoReq
= FALSE
;
539 sm
->eap_if
.aaaEapResp
= TRUE
;
543 SM_STATE(EAP
, TIMEOUT_FAILURE2
)
545 SM_ENTRY(EAP
, TIMEOUT_FAILURE2
);
547 sm
->eap_if
.eapTimeout
= TRUE
;
551 SM_STATE(EAP
, FAILURE2
)
553 SM_ENTRY(EAP
, FAILURE2
);
555 eap_copy_buf(&sm
->eap_if
.eapReqData
, sm
->eap_if
.aaaEapReqData
);
556 sm
->eap_if
.eapFail
= TRUE
;
560 SM_STATE(EAP
, SUCCESS2
)
562 SM_ENTRY(EAP
, SUCCESS2
);
564 eap_copy_buf(&sm
->eap_if
.eapReqData
, sm
->eap_if
.aaaEapReqData
);
566 sm
->eap_if
.eapKeyAvailable
= sm
->eap_if
.aaaEapKeyAvailable
;
567 if (sm
->eap_if
.aaaEapKeyAvailable
) {
568 EAP_COPY(&sm
->eap_if
.eapKeyData
, sm
->eap_if
.aaaEapKeyData
);
570 os_free(sm
->eap_if
.eapKeyData
);
571 sm
->eap_if
.eapKeyData
= NULL
;
572 sm
->eap_if
.eapKeyDataLen
= 0;
575 sm
->eap_if
.eapSuccess
= TRUE
;
581 if (sm
->eap_if
.eapRestart
&& sm
->eap_if
.portEnabled
)
582 SM_ENTER_GLOBAL(EAP
, INITIALIZE
);
583 else if (!sm
->eap_if
.portEnabled
)
584 SM_ENTER_GLOBAL(EAP
, DISABLED
);
585 else if (sm
->num_rounds
> EAP_MAX_AUTH_ROUNDS
) {
586 if (sm
->num_rounds
== EAP_MAX_AUTH_ROUNDS
+ 1) {
587 wpa_printf(MSG_DEBUG
, "EAP: more than %d "
588 "authentication rounds - abort",
589 EAP_MAX_AUTH_ROUNDS
);
591 SM_ENTER_GLOBAL(EAP
, FAILURE
);
593 } else switch (sm
->EAP_state
) {
595 if (sm
->backend_auth
) {
597 SM_ENTER(EAP
, SELECT_ACTION
);
598 else if (sm
->rxResp
&&
599 (sm
->respMethod
== EAP_TYPE_NAK
||
600 (sm
->respMethod
== EAP_TYPE_EXPANDED
&&
601 sm
->respVendor
== EAP_VENDOR_IETF
&&
602 sm
->respVendorMethod
== EAP_TYPE_NAK
)))
605 SM_ENTER(EAP
, PICK_UP_METHOD
);
607 SM_ENTER(EAP
, SELECT_ACTION
);
610 case EAP_PICK_UP_METHOD
:
611 if (sm
->currentMethod
== EAP_TYPE_NONE
) {
612 SM_ENTER(EAP
, SELECT_ACTION
);
614 SM_ENTER(EAP
, METHOD_RESPONSE
);
618 if (sm
->eap_if
.portEnabled
)
619 SM_ENTER(EAP
, INITIALIZE
);
622 if (sm
->eap_if
.retransWhile
== 0)
623 SM_ENTER(EAP
, RETRANSMIT
);
624 else if (sm
->eap_if
.eapResp
)
625 SM_ENTER(EAP
, RECEIVED
);
628 if (sm
->retransCount
> sm
->MaxRetrans
)
629 SM_ENTER(EAP
, TIMEOUT_FAILURE
);
634 if (sm
->rxResp
&& (sm
->respId
== sm
->currentId
) &&
635 (sm
->respMethod
== EAP_TYPE_NAK
||
636 (sm
->respMethod
== EAP_TYPE_EXPANDED
&&
637 sm
->respVendor
== EAP_VENDOR_IETF
&&
638 sm
->respVendorMethod
== EAP_TYPE_NAK
))
639 && (sm
->methodState
== METHOD_PROPOSED
))
641 else if (sm
->rxResp
&& (sm
->respId
== sm
->currentId
) &&
642 ((sm
->respMethod
== sm
->currentMethod
) ||
643 (sm
->respMethod
== EAP_TYPE_EXPANDED
&&
644 sm
->respVendor
== EAP_VENDOR_IETF
&&
645 sm
->respVendorMethod
== sm
->currentMethod
)))
646 SM_ENTER(EAP
, INTEGRITY_CHECK
);
648 wpa_printf(MSG_DEBUG
, "EAP: RECEIVED->DISCARD: "
649 "rxResp=%d respId=%d currentId=%d "
650 "respMethod=%d currentMethod=%d",
651 sm
->rxResp
, sm
->respId
, sm
->currentId
,
652 sm
->respMethod
, sm
->currentMethod
);
653 SM_ENTER(EAP
, DISCARD
);
659 case EAP_SEND_REQUEST
:
662 case EAP_INTEGRITY_CHECK
:
664 SM_ENTER(EAP
, DISCARD
);
666 SM_ENTER(EAP
, METHOD_RESPONSE
);
668 case EAP_METHOD_REQUEST
:
669 SM_ENTER(EAP
, SEND_REQUEST
);
671 case EAP_METHOD_RESPONSE
:
673 * Note: Mechanism to allow EAP methods to wait while going
674 * through pending processing is an extension to RFC 4137
675 * which only defines the transits to SELECT_ACTION and
676 * METHOD_REQUEST from this METHOD_RESPONSE state.
678 if (sm
->methodState
== METHOD_END
)
679 SM_ENTER(EAP
, SELECT_ACTION
);
680 else if (sm
->method_pending
== METHOD_PENDING_WAIT
) {
681 wpa_printf(MSG_DEBUG
, "EAP: Method has pending "
682 "processing - wait before proceeding to "
683 "METHOD_REQUEST state");
684 } else if (sm
->method_pending
== METHOD_PENDING_CONT
) {
685 wpa_printf(MSG_DEBUG
, "EAP: Method has completed "
686 "pending processing - reprocess pending "
688 sm
->method_pending
= METHOD_PENDING_NONE
;
689 SM_ENTER(EAP
, METHOD_RESPONSE
);
691 SM_ENTER(EAP
, METHOD_REQUEST
);
693 case EAP_PROPOSE_METHOD
:
695 * Note: Mechanism to allow EAP methods to wait while going
696 * through pending processing is an extension to RFC 4137
697 * which only defines the transit to METHOD_REQUEST from this
698 * PROPOSE_METHOD state.
700 if (sm
->method_pending
== METHOD_PENDING_WAIT
) {
701 wpa_printf(MSG_DEBUG
, "EAP: Method has pending "
702 "processing - wait before proceeding to "
703 "METHOD_REQUEST state");
704 if (sm
->user_eap_method_index
> 0)
705 sm
->user_eap_method_index
--;
706 } else if (sm
->method_pending
== METHOD_PENDING_CONT
) {
707 wpa_printf(MSG_DEBUG
, "EAP: Method has completed "
708 "pending processing - reprocess pending "
710 sm
->method_pending
= METHOD_PENDING_NONE
;
711 SM_ENTER(EAP
, PROPOSE_METHOD
);
713 SM_ENTER(EAP
, METHOD_REQUEST
);
716 SM_ENTER(EAP
, SELECT_ACTION
);
718 case EAP_SELECT_ACTION
:
719 if (sm
->decision
== DECISION_FAILURE
)
720 SM_ENTER(EAP
, FAILURE
);
721 else if (sm
->decision
== DECISION_SUCCESS
)
722 SM_ENTER(EAP
, SUCCESS
);
723 else if (sm
->decision
== DECISION_PASSTHROUGH
)
724 SM_ENTER(EAP
, INITIALIZE_PASSTHROUGH
);
726 SM_ENTER(EAP
, PROPOSE_METHOD
);
728 case EAP_TIMEOUT_FAILURE
:
735 case EAP_INITIALIZE_PASSTHROUGH
:
736 if (sm
->currentId
== -1)
737 SM_ENTER(EAP
, AAA_IDLE
);
739 SM_ENTER(EAP
, AAA_REQUEST
);
742 if (sm
->eap_if
.eapResp
)
743 SM_ENTER(EAP
, RECEIVED2
);
744 else if (sm
->eap_if
.retransWhile
== 0)
745 SM_ENTER(EAP
, RETRANSMIT2
);
747 case EAP_RETRANSMIT2
:
748 if (sm
->retransCount
> sm
->MaxRetrans
)
749 SM_ENTER(EAP
, TIMEOUT_FAILURE2
);
751 SM_ENTER(EAP
, IDLE2
);
754 if (sm
->rxResp
&& (sm
->respId
== sm
->currentId
))
755 SM_ENTER(EAP
, AAA_REQUEST
);
757 SM_ENTER(EAP
, DISCARD2
);
760 SM_ENTER(EAP
, IDLE2
);
762 case EAP_SEND_REQUEST2
:
763 SM_ENTER(EAP
, IDLE2
);
765 case EAP_AAA_REQUEST
:
766 SM_ENTER(EAP
, AAA_IDLE
);
768 case EAP_AAA_RESPONSE
:
769 SM_ENTER(EAP
, SEND_REQUEST2
);
772 if (sm
->eap_if
.aaaFail
)
773 SM_ENTER(EAP
, FAILURE2
);
774 else if (sm
->eap_if
.aaaSuccess
)
775 SM_ENTER(EAP
, SUCCESS2
);
776 else if (sm
->eap_if
.aaaEapReq
)
777 SM_ENTER(EAP
, AAA_RESPONSE
);
778 else if (sm
->eap_if
.aaaTimeout
)
779 SM_ENTER(EAP
, TIMEOUT_FAILURE2
);
781 case EAP_TIMEOUT_FAILURE2
:
791 static int eap_sm_calculateTimeout(struct eap_sm
*sm
, int retransCount
,
792 int eapSRTT
, int eapRTTVAR
,
795 /* For now, retransmission is done in EAPOL state machines, so make
796 * sure EAP state machine does not end up trying to retransmit packets.
802 static void eap_sm_parseEapResp(struct eap_sm
*sm
, const struct wpabuf
*resp
)
804 const struct eap_hdr
*hdr
;
807 /* parse rxResp, respId, respMethod */
810 sm
->respMethod
= EAP_TYPE_NONE
;
811 sm
->respVendor
= EAP_VENDOR_IETF
;
812 sm
->respVendorMethod
= EAP_TYPE_NONE
;
814 if (resp
== NULL
|| wpabuf_len(resp
) < sizeof(*hdr
)) {
815 wpa_printf(MSG_DEBUG
, "EAP: parseEapResp: invalid resp=%p "
817 resp
? (unsigned long) wpabuf_len(resp
) : 0);
821 hdr
= wpabuf_head(resp
);
822 plen
= be_to_host16(hdr
->length
);
823 if (plen
> wpabuf_len(resp
)) {
824 wpa_printf(MSG_DEBUG
, "EAP: Ignored truncated EAP-Packet "
825 "(len=%lu plen=%lu)",
826 (unsigned long) wpabuf_len(resp
),
827 (unsigned long) plen
);
831 sm
->respId
= hdr
->identifier
;
833 if (hdr
->code
== EAP_CODE_RESPONSE
)
836 if (plen
> sizeof(*hdr
)) {
837 u8
*pos
= (u8
*) (hdr
+ 1);
838 sm
->respMethod
= *pos
++;
839 if (sm
->respMethod
== EAP_TYPE_EXPANDED
) {
840 if (plen
< sizeof(*hdr
) + 8) {
841 wpa_printf(MSG_DEBUG
, "EAP: Ignored truncated "
842 "expanded EAP-Packet (plen=%lu)",
843 (unsigned long) plen
);
846 sm
->respVendor
= WPA_GET_BE24(pos
);
848 sm
->respVendorMethod
= WPA_GET_BE32(pos
);
852 wpa_printf(MSG_DEBUG
, "EAP: parseEapResp: rxResp=%d respId=%d "
853 "respMethod=%u respVendor=%u respVendorMethod=%u",
854 sm
->rxResp
, sm
->respId
, sm
->respMethod
, sm
->respVendor
,
855 sm
->respVendorMethod
);
859 static int eap_sm_getId(const struct wpabuf
*data
)
861 const struct eap_hdr
*hdr
;
863 if (data
== NULL
|| wpabuf_len(data
) < sizeof(*hdr
))
866 hdr
= wpabuf_head(data
);
867 wpa_printf(MSG_DEBUG
, "EAP: getId: id=%d", hdr
->identifier
);
868 return hdr
->identifier
;
872 static struct wpabuf
* eap_sm_buildSuccess(struct eap_sm
*sm
, u8 id
)
875 struct eap_hdr
*resp
;
876 wpa_printf(MSG_DEBUG
, "EAP: Building EAP-Success (id=%d)", id
);
878 msg
= wpabuf_alloc(sizeof(*resp
));
881 resp
= wpabuf_put(msg
, sizeof(*resp
));
882 resp
->code
= EAP_CODE_SUCCESS
;
883 resp
->identifier
= id
;
884 resp
->length
= host_to_be16(sizeof(*resp
));
890 static struct wpabuf
* eap_sm_buildFailure(struct eap_sm
*sm
, u8 id
)
893 struct eap_hdr
*resp
;
894 wpa_printf(MSG_DEBUG
, "EAP: Building EAP-Failure (id=%d)", id
);
896 msg
= wpabuf_alloc(sizeof(*resp
));
899 resp
= wpabuf_put(msg
, sizeof(*resp
));
900 resp
->code
= EAP_CODE_FAILURE
;
901 resp
->identifier
= id
;
902 resp
->length
= host_to_be16(sizeof(*resp
));
908 static int eap_sm_nextId(struct eap_sm
*sm
, int id
)
911 /* RFC 3748 Ch 4.1: recommended to initialize Identifier with a
914 if (id
!= sm
->lastId
)
917 return (id
+ 1) & 0xff;
922 * eap_sm_process_nak - Process EAP-Response/Nak
923 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
924 * @nak_list: Nak list (allowed methods) from the supplicant
925 * @len: Length of nak_list in bytes
927 * This function is called when EAP-Response/Nak is received from the
928 * supplicant. This can happen for both phase 1 and phase 2 authentications.
930 void eap_sm_process_nak(struct eap_sm
*sm
, const u8
*nak_list
, size_t len
)
935 if (sm
->user
== NULL
)
938 wpa_printf(MSG_MSGDUMP
, "EAP: processing NAK (current EAP method "
939 "index %d)", sm
->user_eap_method_index
);
941 wpa_hexdump(MSG_MSGDUMP
, "EAP: configured methods",
942 (u8
*) sm
->user
->methods
,
943 EAP_MAX_METHODS
* sizeof(sm
->user
->methods
[0]));
944 wpa_hexdump(MSG_MSGDUMP
, "EAP: list of methods supported by the peer",
947 i
= sm
->user_eap_method_index
;
948 while (i
< EAP_MAX_METHODS
&&
949 (sm
->user
->methods
[i
].vendor
!= EAP_VENDOR_IETF
||
950 sm
->user
->methods
[i
].method
!= EAP_TYPE_NONE
)) {
951 if (sm
->user
->methods
[i
].vendor
!= EAP_VENDOR_IETF
)
953 for (j
= 0; j
< len
; j
++) {
954 if (nak_list
[j
] == sm
->user
->methods
[i
].method
) {
966 /* not found - remove from the list */
967 os_memmove(&sm
->user
->methods
[i
], &sm
->user
->methods
[i
+ 1],
968 (EAP_MAX_METHODS
- i
- 1) *
969 sizeof(sm
->user
->methods
[0]));
970 sm
->user
->methods
[EAP_MAX_METHODS
- 1].vendor
=
972 sm
->user
->methods
[EAP_MAX_METHODS
- 1].method
= EAP_TYPE_NONE
;
975 wpa_hexdump(MSG_MSGDUMP
, "EAP: new list of configured methods",
976 (u8
*) sm
->user
->methods
, EAP_MAX_METHODS
*
977 sizeof(sm
->user
->methods
[0]));
981 static void eap_sm_Policy_update(struct eap_sm
*sm
, const u8
*nak_list
,
984 if (nak_list
== NULL
|| sm
== NULL
|| sm
->user
== NULL
)
987 if (sm
->user
->phase2
) {
988 wpa_printf(MSG_DEBUG
, "EAP: EAP-Nak received after Phase2 user"
989 " info was selected - reject");
990 sm
->decision
= DECISION_FAILURE
;
994 eap_sm_process_nak(sm
, nak_list
, len
);
998 static EapType
eap_sm_Policy_getNextMethod(struct eap_sm
*sm
, int *vendor
)
1001 int idx
= sm
->user_eap_method_index
;
1003 /* In theory, there should be no problems with starting
1004 * re-authentication with something else than EAP-Request/Identity and
1005 * this does indeed work with wpa_supplicant. However, at least Funk
1006 * Supplicant seemed to ignore re-auth if it skipped
1007 * EAP-Request/Identity.
1008 * Re-auth sets currentId == -1, so that can be used here to select
1009 * whether Identity needs to be requested again. */
1010 if (sm
->identity
== NULL
|| sm
->currentId
== -1) {
1011 *vendor
= EAP_VENDOR_IETF
;
1012 next
= EAP_TYPE_IDENTITY
;
1013 sm
->update_user
= TRUE
;
1014 } else if (sm
->user
&& idx
< EAP_MAX_METHODS
&&
1015 (sm
->user
->methods
[idx
].vendor
!= EAP_VENDOR_IETF
||
1016 sm
->user
->methods
[idx
].method
!= EAP_TYPE_NONE
)) {
1017 *vendor
= sm
->user
->methods
[idx
].vendor
;
1018 next
= sm
->user
->methods
[idx
].method
;
1019 sm
->user_eap_method_index
++;
1021 *vendor
= EAP_VENDOR_IETF
;
1022 next
= EAP_TYPE_NONE
;
1024 wpa_printf(MSG_DEBUG
, "EAP: getNextMethod: vendor %d type %d",
1030 static int eap_sm_Policy_getDecision(struct eap_sm
*sm
)
1032 if (!sm
->eap_server
&& sm
->identity
) {
1033 wpa_printf(MSG_DEBUG
, "EAP: getDecision: -> PASSTHROUGH");
1034 return DECISION_PASSTHROUGH
;
1037 if (sm
->m
&& sm
->currentMethod
!= EAP_TYPE_IDENTITY
&&
1038 sm
->m
->isSuccess(sm
, sm
->eap_method_priv
)) {
1039 wpa_printf(MSG_DEBUG
, "EAP: getDecision: method succeeded -> "
1041 sm
->update_user
= TRUE
;
1042 return DECISION_SUCCESS
;
1045 if (sm
->m
&& sm
->m
->isDone(sm
, sm
->eap_method_priv
) &&
1046 !sm
->m
->isSuccess(sm
, sm
->eap_method_priv
)) {
1047 wpa_printf(MSG_DEBUG
, "EAP: getDecision: method failed -> "
1049 sm
->update_user
= TRUE
;
1050 return DECISION_FAILURE
;
1053 if ((sm
->user
== NULL
|| sm
->update_user
) && sm
->identity
) {
1054 if (eap_user_get(sm
, sm
->identity
, sm
->identity_len
, 0) != 0) {
1055 wpa_printf(MSG_DEBUG
, "EAP: getDecision: user not "
1056 "found from database -> FAILURE");
1057 return DECISION_FAILURE
;
1059 sm
->update_user
= FALSE
;
1062 if (sm
->user
&& sm
->user_eap_method_index
< EAP_MAX_METHODS
&&
1063 (sm
->user
->methods
[sm
->user_eap_method_index
].vendor
!=
1065 sm
->user
->methods
[sm
->user_eap_method_index
].method
!=
1067 wpa_printf(MSG_DEBUG
, "EAP: getDecision: another method "
1068 "available -> CONTINUE");
1069 return DECISION_CONTINUE
;
1072 if (sm
->identity
== NULL
|| sm
->currentId
== -1) {
1073 wpa_printf(MSG_DEBUG
, "EAP: getDecision: no identity known "
1075 return DECISION_CONTINUE
;
1078 wpa_printf(MSG_DEBUG
, "EAP: getDecision: no more methods available -> "
1080 return DECISION_FAILURE
;
1084 static Boolean
eap_sm_Policy_doPickUp(struct eap_sm
*sm
, EapType method
)
1086 return method
== EAP_TYPE_IDENTITY
? TRUE
: FALSE
;
1091 * eap_server_sm_step - Step EAP server state machine
1092 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1093 * Returns: 1 if EAP state was changed or 0 if not
1095 * This function advances EAP state machine to a new state to match with the
1096 * current variables. This should be called whenever variables used by the EAP
1097 * state machine have changed.
1099 int eap_server_sm_step(struct eap_sm
*sm
)
1103 sm
->changed
= FALSE
;
1107 } while (sm
->changed
);
1112 static void eap_user_free(struct eap_user
*user
)
1116 os_free(user
->password
);
1117 user
->password
= NULL
;
1123 * eap_server_sm_init - Allocate and initialize EAP server state machine
1124 * @eapol_ctx: Context data to be used with eapol_cb calls
1125 * @eapol_cb: Pointer to EAPOL callback functions
1126 * @conf: EAP configuration
1127 * Returns: Pointer to the allocated EAP state machine or %NULL on failure
1129 * This function allocates and initializes an EAP state machine.
1131 struct eap_sm
* eap_server_sm_init(void *eapol_ctx
,
1132 struct eapol_callbacks
*eapol_cb
,
1133 struct eap_config
*conf
)
1137 sm
= os_zalloc(sizeof(*sm
));
1140 sm
->eapol_ctx
= eapol_ctx
;
1141 sm
->eapol_cb
= eapol_cb
;
1142 sm
->MaxRetrans
= 10;
1143 sm
->ssl_ctx
= conf
->ssl_ctx
;
1144 sm
->eap_sim_db_priv
= conf
->eap_sim_db_priv
;
1145 sm
->backend_auth
= conf
->backend_auth
;
1146 sm
->eap_server
= conf
->eap_server
;
1147 if (conf
->pac_opaque_encr_key
) {
1148 sm
->pac_opaque_encr_key
= os_malloc(16);
1149 if (sm
->pac_opaque_encr_key
) {
1150 os_memcpy(sm
->pac_opaque_encr_key
,
1151 conf
->pac_opaque_encr_key
, 16);
1154 if (conf
->eap_fast_a_id
)
1155 sm
->eap_fast_a_id
= os_strdup(conf
->eap_fast_a_id
);
1156 sm
->eap_sim_aka_result_ind
= conf
->eap_sim_aka_result_ind
;
1157 sm
->tnc
= conf
->tnc
;
1159 wpa_printf(MSG_DEBUG
, "EAP: Server state machine created");
1166 * eap_server_sm_deinit - Deinitialize and free an EAP server state machine
1167 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1169 * This function deinitializes EAP state machine and frees all allocated
1172 void eap_server_sm_deinit(struct eap_sm
*sm
)
1176 wpa_printf(MSG_DEBUG
, "EAP: Server state machine removed");
1177 if (sm
->m
&& sm
->eap_method_priv
)
1178 sm
->m
->reset(sm
, sm
->eap_method_priv
);
1179 wpabuf_free(sm
->eap_if
.eapReqData
);
1180 os_free(sm
->eap_if
.eapKeyData
);
1181 os_free(sm
->lastReqData
);
1182 wpabuf_free(sm
->eap_if
.eapRespData
);
1183 os_free(sm
->identity
);
1184 os_free(sm
->pac_opaque_encr_key
);
1185 os_free(sm
->eap_fast_a_id
);
1186 wpabuf_free(sm
->eap_if
.aaaEapReqData
);
1187 wpabuf_free(sm
->eap_if
.aaaEapRespData
);
1188 os_free(sm
->eap_if
.aaaEapKeyData
);
1189 eap_user_free(sm
->user
);
1195 * eap_sm_notify_cached - Notify EAP state machine of cached PMK
1196 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1198 * This function is called when PMKSA caching is used to skip EAP
1201 void eap_sm_notify_cached(struct eap_sm
*sm
)
1206 sm
->EAP_state
= EAP_SUCCESS
;
1211 * eap_sm_pending_cb - EAP state machine callback for a pending EAP request
1212 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1214 * This function is called when data for a pending EAP-Request is received.
1216 void eap_sm_pending_cb(struct eap_sm
*sm
)
1220 wpa_printf(MSG_DEBUG
, "EAP: Callback for pending request received");
1221 if (sm
->method_pending
== METHOD_PENDING_WAIT
)
1222 sm
->method_pending
= METHOD_PENDING_CONT
;
1227 * eap_sm_method_pending - Query whether EAP method is waiting for pending data
1228 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1229 * Returns: 1 if method is waiting for pending data or 0 if not
1231 int eap_sm_method_pending(struct eap_sm
*sm
)
1235 return sm
->method_pending
== METHOD_PENDING_WAIT
;
1240 * eap_get_identity - Get the user identity (from EAP-Response/Identity)
1241 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1242 * @len: Buffer for returning identity length
1243 * Returns: Pointer to the user identity or %NULL if not available
1245 const u8
* eap_get_identity(struct eap_sm
*sm
, size_t *len
)
1247 *len
= sm
->identity_len
;
1248 return sm
->identity
;
1253 * eap_get_interface - Get pointer to EAP-EAPOL interface data
1254 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1255 * Returns: Pointer to the EAP-EAPOL interface data
1257 struct eap_eapol_interface
* eap_get_interface(struct eap_sm
*sm
)