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,
799 * EAP method (either internal or through AAA server, provided
800 * timeout hint. Use that as-is as a timeout for retransmitting
801 * the EAP request if no response is received.
803 wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds "
804 "(from EAP method hint)", methodTimeout);
805 return methodTimeout;
809 * RFC 3748 recommends algorithms described in RFC 2988 for estimation
810 * of the retransmission timeout. This should be implemented once
811 * round-trip time measurements are available. For nowm a simple
812 * backoff mechanism is used instead if there are no EAP method
815 * SRTT = smoothed round-trip time
816 * RTTVAR = round-trip time variation
817 * RTO = retransmission timeout
821 * RFC 2988, 2.1: before RTT measurement, set RTO to 3 seconds for
822 * initial retransmission and then double the RTO to provide back off
823 * per 5.5. Limit the maximum RTO to 20 seconds per RFC 3748, 4.3
827 for (i = 0; i < retransCount; i++) {
835 wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds "
836 "(from dynamic back off; retransCount=%d)",
843 static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp)
845 const struct eap_hdr *hdr;
848 /* parse rxResp, respId, respMethod */
851 sm->respMethod = EAP_TYPE_NONE;
852 sm->respVendor = EAP_VENDOR_IETF;
853 sm->respVendorMethod = EAP_TYPE_NONE;
855 if (resp == NULL || wpabuf_len(resp) < sizeof(*hdr)) {
856 wpa_printf(MSG_DEBUG, "EAP: parseEapResp: invalid resp=%p "
858 resp ? (unsigned long) wpabuf_len(resp) : 0);
862 hdr = wpabuf_head(resp);
863 plen = be_to_host16(hdr->length);
864 if (plen > wpabuf_len(resp)) {
865 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
866 "(len=%lu plen=%lu)",
867 (unsigned long) wpabuf_len(resp),
868 (unsigned long) plen);
872 sm->respId = hdr->identifier;
874 if (hdr->code == EAP_CODE_RESPONSE)
877 if (plen > sizeof(*hdr)) {
878 u8 *pos = (u8 *) (hdr + 1);
879 sm->respMethod = *pos++;
880 if (sm->respMethod == EAP_TYPE_EXPANDED) {
881 if (plen < sizeof(*hdr) + 8) {
882 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated "
883 "expanded EAP-Packet (plen=%lu)",
884 (unsigned long) plen);
887 sm->respVendor = WPA_GET_BE24(pos);
889 sm->respVendorMethod = WPA_GET_BE32(pos);
893 wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d "
894 "respMethod=%u respVendor=%u respVendorMethod=%u",
895 sm->rxResp, sm->respId, sm->respMethod, sm->respVendor,
896 sm->respVendorMethod);
900 static int eap_sm_getId(const struct wpabuf *data)
902 const struct eap_hdr *hdr;
904 if (data == NULL || wpabuf_len(data) < sizeof(*hdr))
907 hdr = wpabuf_head(data);
908 wpa_printf(MSG_DEBUG, "EAP: getId: id=%d", hdr->identifier);
909 return hdr->identifier;
913 static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id)
916 struct eap_hdr *resp;
917 wpa_printf(MSG_DEBUG, "EAP: Building EAP-Success (id=%d)", id);
919 msg = wpabuf_alloc(sizeof(*resp));
922 resp = wpabuf_put(msg, sizeof(*resp));
923 resp->code = EAP_CODE_SUCCESS;
924 resp->identifier = id;
925 resp->length = host_to_be16(sizeof(*resp));
931 static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id)
934 struct eap_hdr *resp;
935 wpa_printf(MSG_DEBUG, "EAP: Building EAP-Failure (id=%d)", id);
937 msg = wpabuf_alloc(sizeof(*resp));
940 resp = wpabuf_put(msg, sizeof(*resp));
941 resp->code = EAP_CODE_FAILURE;
942 resp->identifier = id;
943 resp->length = host_to_be16(sizeof(*resp));
949 static int eap_sm_nextId(struct eap_sm *sm, int id)
952 /* RFC 3748 Ch 4.1: recommended to initialize Identifier with a
955 if (id != sm->lastId)
958 return (id + 1) & 0xff;
963 * eap_sm_process_nak - Process EAP-Response/Nak
964 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
965 * @nak_list: Nak list (allowed methods) from the supplicant
966 * @len: Length of nak_list in bytes
968 * This function is called when EAP-Response/Nak is received from the
969 * supplicant. This can happen for both phase 1 and phase 2 authentications.
971 void eap_sm_process_nak(struct eap_sm *sm, const u8 *nak_list, size_t len)
976 if (sm->user == NULL)
979 wpa_printf(MSG_MSGDUMP, "EAP: processing NAK (current EAP method "
980 "index %d)", sm->user_eap_method_index);
982 wpa_hexdump(MSG_MSGDUMP, "EAP: configured methods",
983 (u8 *) sm->user->methods,
984 EAP_MAX_METHODS * sizeof(sm->user->methods[0]));
985 wpa_hexdump(MSG_MSGDUMP, "EAP: list of methods supported by the peer",
988 i = sm->user_eap_method_index;
989 while (i < EAP_MAX_METHODS &&
990 (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
991 sm->user->methods[i].method != EAP_TYPE_NONE)) {
992 if (sm->user->methods[i].vendor != EAP_VENDOR_IETF)
994 for (j = 0; j < len; j++) {
995 if (nak_list[j] == sm->user->methods[i].method) {
1007 /* not found - remove from the list */
1008 os_memmove(&sm->user->methods[i], &sm->user->methods[i + 1],
1009 (EAP_MAX_METHODS - i - 1) *
1010 sizeof(sm->user->methods[0]));
1011 sm->user->methods[EAP_MAX_METHODS - 1].vendor =
1013 sm->user->methods[EAP_MAX_METHODS - 1].method = EAP_TYPE_NONE;
1016 wpa_hexdump(MSG_MSGDUMP, "EAP: new list of configured methods",
1017 (u8 *) sm->user->methods, EAP_MAX_METHODS *
1018 sizeof(sm->user->methods[0]));
1022 static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list,
1025 if (nak_list == NULL || sm == NULL || sm->user == NULL)
1028 if (sm->user->phase2) {
1029 wpa_printf(MSG_DEBUG, "EAP: EAP-Nak received after Phase2 user"
1030 " info was selected - reject");
1031 sm->decision = DECISION_FAILURE;
1035 eap_sm_process_nak(sm, nak_list, len);
1039 static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor)
1042 int idx = sm->user_eap_method_index;
1044 /* In theory, there should be no problems with starting
1045 * re-authentication with something else than EAP-Request/Identity and
1046 * this does indeed work with wpa_supplicant. However, at least Funk
1047 * Supplicant seemed to ignore re-auth if it skipped
1048 * EAP-Request/Identity.
1049 * Re-auth sets currentId == -1, so that can be used here to select
1050 * whether Identity needs to be requested again. */
1051 if (sm->identity == NULL || sm->currentId == -1) {
1052 *vendor = EAP_VENDOR_IETF;
1053 next = EAP_TYPE_IDENTITY;
1054 sm->update_user = TRUE;
1055 } else if (sm->user && idx < EAP_MAX_METHODS &&
1056 (sm->user->methods[idx].vendor != EAP_VENDOR_IETF ||
1057 sm->user->methods[idx].method != EAP_TYPE_NONE)) {
1058 *vendor = sm->user->methods[idx].vendor;
1059 next = sm->user->methods[idx].method;
1060 sm->user_eap_method_index++;
1062 *vendor = EAP_VENDOR_IETF;
1063 next = EAP_TYPE_NONE;
1065 wpa_printf(MSG_DEBUG, "EAP: getNextMethod: vendor %d type %d",
1071 static int eap_sm_Policy_getDecision(struct eap_sm *sm)
1073 if (!sm->eap_server && sm->identity) {
1074 wpa_printf(MSG_DEBUG, "EAP: getDecision: -> PASSTHROUGH");
1075 return DECISION_PASSTHROUGH;
1078 if (sm->m && sm->currentMethod != EAP_TYPE_IDENTITY &&
1079 sm->m->isSuccess(sm, sm->eap_method_priv)) {
1080 wpa_printf(MSG_DEBUG, "EAP: getDecision: method succeeded -> "
1082 sm->update_user = TRUE;
1083 return DECISION_SUCCESS;
1086 if (sm->m && sm->m->isDone(sm, sm->eap_method_priv) &&
1087 !sm->m->isSuccess(sm, sm->eap_method_priv)) {
1088 wpa_printf(MSG_DEBUG, "EAP: getDecision: method failed -> "
1090 sm->update_user = TRUE;
1091 return DECISION_FAILURE;
1094 if ((sm->user == NULL || sm->update_user) && sm->identity) {
1096 * Allow Identity method to be started once to allow identity
1097 * selection hint to be sent from the authentication server,
1098 * but prevent a loop of Identity requests by only allowing
1099 * this to happen once.
1102 if (sm->user && sm->currentMethod == EAP_TYPE_IDENTITY &&
1103 sm->user->methods[0].vendor == EAP_VENDOR_IETF &&
1104 sm->user->methods[0].method == EAP_TYPE_IDENTITY)
1106 if (eap_user_get(sm, sm->identity, sm->identity_len, 0) != 0) {
1107 wpa_printf(MSG_DEBUG, "EAP: getDecision: user not "
1108 "found from database -> FAILURE");
1109 return DECISION_FAILURE;
1111 if (id_req && sm->user &&
1112 sm->user->methods[0].vendor == EAP_VENDOR_IETF &&
1113 sm->user->methods[0].method == EAP_TYPE_IDENTITY) {
1114 wpa_printf(MSG_DEBUG, "EAP: getDecision: stop "
1115 "identity request loop -> FAILURE");
1116 sm->update_user = TRUE;
1117 return DECISION_FAILURE;
1119 sm->update_user = FALSE;
1122 if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
1123 (sm->user->methods[sm->user_eap_method_index].vendor !=
1125 sm->user->methods[sm->user_eap_method_index].method !=
1127 wpa_printf(MSG_DEBUG, "EAP: getDecision: another method "
1128 "available -> CONTINUE");
1129 return DECISION_CONTINUE;
1132 if (sm->identity == NULL || sm->currentId == -1) {
1133 wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known "
1135 return DECISION_CONTINUE;
1138 wpa_printf(MSG_DEBUG, "EAP: getDecision: no more methods available -> "
1140 return DECISION_FAILURE;
1144 static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method)
1146 return method == EAP_TYPE_IDENTITY ? TRUE : FALSE;
1151 * eap_server_sm_step - Step EAP server state machine
1152 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1153 * Returns: 1 if EAP state was changed or 0 if not
1155 * This function advances EAP state machine to a new state to match with the
1156 * current variables. This should be called whenever variables used by the EAP
1157 * state machine have changed.
1159 int eap_server_sm_step(struct eap_sm *sm)
1163 sm->changed = FALSE;
1167 } while (sm->changed);
1172 static void eap_user_free(struct eap_user *user)
1176 os_free(user->password);
1177 user->password = NULL;
1183 * eap_server_sm_init - Allocate and initialize EAP server state machine
1184 * @eapol_ctx: Context data to be used with eapol_cb calls
1185 * @eapol_cb: Pointer to EAPOL callback functions
1186 * @conf: EAP configuration
1187 * Returns: Pointer to the allocated EAP state machine or %NULL on failure
1189 * This function allocates and initializes an EAP state machine.
1191 struct eap_sm * eap_server_sm_init(void *eapol_ctx,
1192 struct eapol_callbacks *eapol_cb,
1193 struct eap_config *conf)
1197 sm = os_zalloc(sizeof(*sm));
1200 sm->eapol_ctx = eapol_ctx;
1201 sm->eapol_cb = eapol_cb;
1202 sm->MaxRetrans = 5; /* RFC 3748: max 3-5 retransmissions suggested */
1203 sm->ssl_ctx = conf->ssl_ctx;
1204 sm->eap_sim_db_priv = conf->eap_sim_db_priv;
1205 sm->backend_auth = conf->backend_auth;
1206 sm->eap_server = conf->eap_server;
1207 if (conf->pac_opaque_encr_key) {
1208 sm->pac_opaque_encr_key = os_malloc(16);
1209 if (sm->pac_opaque_encr_key) {
1210 os_memcpy(sm->pac_opaque_encr_key,
1211 conf->pac_opaque_encr_key, 16);
1214 if (conf->eap_fast_a_id) {
1215 sm->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len);
1216 if (sm->eap_fast_a_id) {
1217 os_memcpy(sm->eap_fast_a_id, conf->eap_fast_a_id,
1218 conf->eap_fast_a_id_len);
1219 sm->eap_fast_a_id_len = conf->eap_fast_a_id_len;
1222 if (conf->eap_fast_a_id_info)
1223 sm->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info);
1224 sm->eap_fast_prov = conf->eap_fast_prov;
1225 sm->pac_key_lifetime = conf->pac_key_lifetime;
1226 sm->pac_key_refresh_time = conf->pac_key_refresh_time;
1227 sm->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
1228 sm->tnc = conf->tnc;
1229 sm->wps = conf->wps;
1230 if (conf->assoc_wps_ie)
1231 sm->assoc_wps_ie = wpabuf_dup(conf->assoc_wps_ie);
1233 wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
1240 * eap_server_sm_deinit - Deinitialize and free an EAP server state machine
1241 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1243 * This function deinitializes EAP state machine and frees all allocated
1246 void eap_server_sm_deinit(struct eap_sm *sm)
1250 wpa_printf(MSG_DEBUG, "EAP: Server state machine removed");
1251 if (sm->m && sm->eap_method_priv)
1252 sm->m->reset(sm, sm->eap_method_priv);
1253 wpabuf_free(sm->eap_if.eapReqData);
1254 os_free(sm->eap_if.eapKeyData);
1255 os_free(sm->lastReqData);
1256 wpabuf_free(sm->eap_if.eapRespData);
1257 os_free(sm->identity);
1258 os_free(sm->pac_opaque_encr_key);
1259 os_free(sm->eap_fast_a_id);
1260 os_free(sm->eap_fast_a_id_info);
1261 wpabuf_free(sm->eap_if.aaaEapReqData);
1262 wpabuf_free(sm->eap_if.aaaEapRespData);
1263 os_free(sm->eap_if.aaaEapKeyData);
1264 eap_user_free(sm->user);
1265 wpabuf_free(sm->assoc_wps_ie);
1271 * eap_sm_notify_cached - Notify EAP state machine of cached PMK
1272 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1274 * This function is called when PMKSA caching is used to skip EAP
1277 void eap_sm_notify_cached(struct eap_sm *sm)
1282 sm->EAP_state = EAP_SUCCESS;
1287 * eap_sm_pending_cb - EAP state machine callback for a pending EAP request
1288 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1290 * This function is called when data for a pending EAP-Request is received.
1292 void eap_sm_pending_cb(struct eap_sm *sm)
1296 wpa_printf(MSG_DEBUG, "EAP: Callback for pending request received");
1297 if (sm->method_pending == METHOD_PENDING_WAIT)
1298 sm->method_pending = METHOD_PENDING_CONT;
1303 * eap_sm_method_pending - Query whether EAP method is waiting for pending data
1304 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1305 * Returns: 1 if method is waiting for pending data or 0 if not
1307 int eap_sm_method_pending(struct eap_sm *sm)
1311 return sm->method_pending == METHOD_PENDING_WAIT;
1316 * eap_get_identity - Get the user identity (from EAP-Response/Identity)
1317 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1318 * @len: Buffer for returning identity length
1319 * Returns: Pointer to the user identity or %NULL if not available
1321 const u8 * eap_get_identity(struct eap_sm *sm, size_t *len)
1323 *len = sm->identity_len;
1324 return sm->identity;
1329 * eap_get_interface - Get pointer to EAP-EAPOL interface data
1330 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1331 * Returns: Pointer to the EAP-EAPOL interface data
1333 struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm)