2 * hostapd / EAP Full Authenticator state machine (RFC 4137)
3 * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
8 * This state machine is based on the full authenticator state machine defined
9 * in RFC 4137. However, to support backend authentication in RADIUS
10 * authentication server functionality, parts of backend authenticator (also
11 * from RFC 4137) are mixed in. This functionality is enabled by setting
12 * backend_auth configuration variable to TRUE.
18 #include "crypto/sha256.h"
20 #include "state_machine.h"
21 #include "common/wpa_ctrl.h"
23 #define STATE_MACHINE_DATA struct eap_sm
24 #define STATE_MACHINE_DEBUG_PREFIX "EAP"
26 /* EAP state machines are described in RFC 4137 */
28 static int eap_sm_calculateTimeout(struct eap_sm
*sm
, int retransCount
,
29 int eapSRTT
, int eapRTTVAR
,
31 static void eap_sm_parseEapResp(struct eap_sm
*sm
, const struct wpabuf
*resp
);
32 static int eap_sm_getId(const struct wpabuf
*data
);
33 static struct wpabuf
* eap_sm_buildSuccess(struct eap_sm
*sm
, u8 id
);
34 static struct wpabuf
* eap_sm_buildFailure(struct eap_sm
*sm
, u8 id
);
35 static int eap_sm_nextId(struct eap_sm
*sm
, int id
);
36 static void eap_sm_Policy_update(struct eap_sm
*sm
, const u8
*nak_list
,
38 static enum eap_type
eap_sm_Policy_getNextMethod(struct eap_sm
*sm
,
40 static int eap_sm_Policy_getDecision(struct eap_sm
*sm
);
41 static Boolean
eap_sm_Policy_doPickUp(struct eap_sm
*sm
, enum eap_type method
);
44 static int eap_get_erp_send_reauth_start(struct eap_sm
*sm
)
46 if (sm
->eapol_cb
->get_erp_send_reauth_start
)
47 return sm
->eapol_cb
->get_erp_send_reauth_start(sm
->eapol_ctx
);
52 static const char * eap_get_erp_domain(struct eap_sm
*sm
)
54 if (sm
->eapol_cb
->get_erp_domain
)
55 return sm
->eapol_cb
->get_erp_domain(sm
->eapol_ctx
);
62 static struct eap_server_erp_key
* eap_erp_get_key(struct eap_sm
*sm
,
65 if (sm
->eapol_cb
->erp_get_key
)
66 return sm
->eapol_cb
->erp_get_key(sm
->eapol_ctx
, keyname
);
71 static int eap_erp_add_key(struct eap_sm
*sm
, struct eap_server_erp_key
*erp
)
73 if (sm
->eapol_cb
->erp_add_key
)
74 return sm
->eapol_cb
->erp_add_key(sm
->eapol_ctx
, erp
);
78 #endif /* CONFIG_ERP */
81 static struct wpabuf
* eap_sm_buildInitiateReauthStart(struct eap_sm
*sm
,
87 size_t domain_len
= 0;
89 domain
= eap_get_erp_domain(sm
);
91 domain_len
= os_strlen(domain
);
92 plen
+= 2 + domain_len
;
95 msg
= eap_msg_alloc(EAP_VENDOR_IETF
,
96 (enum eap_type
) EAP_ERP_TYPE_REAUTH_START
, plen
,
97 EAP_CODE_INITIATE
, id
);
100 wpabuf_put_u8(msg
, 0); /* Reserved */
102 /* Domain name TLV */
103 wpabuf_put_u8(msg
, EAP_ERP_TLV_DOMAIN_NAME
);
104 wpabuf_put_u8(msg
, domain_len
);
105 wpabuf_put_data(msg
, domain
, domain_len
);
112 static int eap_copy_buf(struct wpabuf
**dst
, const struct wpabuf
*src
)
118 *dst
= wpabuf_dup(src
);
119 return *dst
? 0 : -1;
123 static int eap_copy_data(u8
**dst
, size_t *dst_len
,
124 const u8
*src
, size_t src_len
)
130 *dst
= os_malloc(src_len
);
132 os_memcpy(*dst
, src
, src_len
);
141 #define EAP_COPY(dst, src) \
142 eap_copy_data((dst), (dst ## Len), (src), (src ## Len))
146 * eap_user_get - Fetch user information from the database
147 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
148 * @identity: Identity (User-Name) of the user
149 * @identity_len: Length of identity in bytes
150 * @phase2: 0 = EAP phase1 user, 1 = EAP phase2 (tunneled) user
151 * Returns: 0 on success, or -1 on failure
153 * This function is used to fetch user information for EAP. The user will be
154 * selected based on the specified identity. sm->user and
155 * sm->user_eap_method_index are updated for the new user when a matching user
156 * is found. sm->user can be used to get user information (e.g., password).
158 int eap_user_get(struct eap_sm
*sm
, const u8
*identity
, size_t identity_len
,
161 struct eap_user
*user
;
163 if (sm
== NULL
|| sm
->eapol_cb
== NULL
||
164 sm
->eapol_cb
->get_eap_user
== NULL
)
167 eap_user_free(sm
->user
);
170 user
= os_zalloc(sizeof(*user
));
174 if (sm
->eapol_cb
->get_eap_user(sm
->eapol_ctx
, identity
,
175 identity_len
, phase2
, user
) != 0) {
181 sm
->user_eap_method_index
= 0;
187 void eap_log_msg(struct eap_sm
*sm
, const char *fmt
, ...)
193 if (sm
== NULL
|| sm
->eapol_cb
== NULL
|| sm
->eapol_cb
->log_msg
== NULL
)
197 buflen
= vsnprintf(NULL
, 0, fmt
, ap
) + 1;
200 buf
= os_malloc(buflen
);
204 vsnprintf(buf
, buflen
, fmt
, ap
);
207 sm
->eapol_cb
->log_msg(sm
->eapol_ctx
, buf
);
213 SM_STATE(EAP
, DISABLED
)
215 SM_ENTRY(EAP
, DISABLED
);
217 sm
->num_rounds_short
= 0;
221 SM_STATE(EAP
, INITIALIZE
)
223 SM_ENTRY(EAP
, INITIALIZE
);
225 if (sm
->eap_if
.eapRestart
&& !sm
->cfg
->eap_server
&& sm
->identity
) {
227 * Need to allow internal Identity method to be used instead
228 * of passthrough at the beginning of reauthentication.
230 eap_server_clear_identity(sm
);
233 sm
->try_initiate_reauth
= FALSE
;
235 sm
->eap_if
.eapSuccess
= FALSE
;
236 sm
->eap_if
.eapFail
= FALSE
;
237 sm
->eap_if
.eapTimeout
= FALSE
;
238 bin_clear_free(sm
->eap_if
.eapKeyData
, sm
->eap_if
.eapKeyDataLen
);
239 sm
->eap_if
.eapKeyData
= NULL
;
240 sm
->eap_if
.eapKeyDataLen
= 0;
241 os_free(sm
->eap_if
.eapSessionId
);
242 sm
->eap_if
.eapSessionId
= NULL
;
243 sm
->eap_if
.eapSessionIdLen
= 0;
244 sm
->eap_if
.eapKeyAvailable
= FALSE
;
245 sm
->eap_if
.eapRestart
= FALSE
;
248 * This is not defined in RFC 4137, but method state needs to be
249 * reseted here so that it does not remain in success state when
250 * re-authentication starts.
252 if (sm
->m
&& sm
->eap_method_priv
) {
253 sm
->m
->reset(sm
, sm
->eap_method_priv
);
254 sm
->eap_method_priv
= NULL
;
257 sm
->user_eap_method_index
= 0;
259 if (sm
->cfg
->backend_auth
) {
260 sm
->currentMethod
= EAP_TYPE_NONE
;
261 /* parse rxResp, respId, respMethod */
262 eap_sm_parseEapResp(sm
, sm
->eap_if
.eapRespData
);
264 sm
->currentId
= sm
->respId
;
268 sm
->num_rounds_short
= 0;
269 sm
->method_pending
= METHOD_PENDING_NONE
;
271 wpa_msg(sm
->cfg
->msg_ctx
, MSG_INFO
, WPA_EVENT_EAP_STARTED
272 MACSTR
, MAC2STR(sm
->peer_addr
));
276 SM_STATE(EAP
, PICK_UP_METHOD
)
278 SM_ENTRY(EAP
, PICK_UP_METHOD
);
280 if (eap_sm_Policy_doPickUp(sm
, sm
->respMethod
)) {
281 sm
->currentMethod
= sm
->respMethod
;
282 if (sm
->m
&& sm
->eap_method_priv
) {
283 sm
->m
->reset(sm
, sm
->eap_method_priv
);
284 sm
->eap_method_priv
= NULL
;
286 sm
->m
= eap_server_get_eap_method(EAP_VENDOR_IETF
,
288 if (sm
->m
&& sm
->m
->initPickUp
) {
289 sm
->eap_method_priv
= sm
->m
->initPickUp(sm
);
290 if (sm
->eap_method_priv
== NULL
) {
291 wpa_printf(MSG_DEBUG
, "EAP: Failed to "
292 "initialize EAP method %d",
295 sm
->currentMethod
= EAP_TYPE_NONE
;
299 sm
->currentMethod
= EAP_TYPE_NONE
;
303 wpa_msg(sm
->cfg
->msg_ctx
, MSG_INFO
, WPA_EVENT_EAP_PROPOSED_METHOD
304 "method=%u", sm
->currentMethod
);
312 sm
->eap_if
.retransWhile
= eap_sm_calculateTimeout(
313 sm
, sm
->retransCount
, sm
->eap_if
.eapSRTT
, sm
->eap_if
.eapRTTVAR
,
318 SM_STATE(EAP
, RETRANSMIT
)
320 SM_ENTRY(EAP
, RETRANSMIT
);
323 if (sm
->retransCount
<= sm
->MaxRetrans
&& sm
->lastReqData
) {
324 if (eap_copy_buf(&sm
->eap_if
.eapReqData
, sm
->lastReqData
) == 0)
325 sm
->eap_if
.eapReq
= TRUE
;
328 wpa_msg(sm
->cfg
->msg_ctx
, MSG_INFO
, WPA_EVENT_EAP_RETRANSMIT MACSTR
,
329 MAC2STR(sm
->peer_addr
));
333 SM_STATE(EAP
, RECEIVED
)
335 SM_ENTRY(EAP
, RECEIVED
);
337 /* parse rxResp, respId, respMethod */
338 eap_sm_parseEapResp(sm
, sm
->eap_if
.eapRespData
);
340 if (!sm
->eap_if
.eapRespData
|| wpabuf_len(sm
->eap_if
.eapRespData
) < 20)
341 sm
->num_rounds_short
++;
343 sm
->num_rounds_short
= 0;
347 SM_STATE(EAP
, DISCARD
)
349 SM_ENTRY(EAP
, DISCARD
);
350 sm
->eap_if
.eapResp
= FALSE
;
351 sm
->eap_if
.eapNoReq
= TRUE
;
355 SM_STATE(EAP
, SEND_REQUEST
)
357 SM_ENTRY(EAP
, SEND_REQUEST
);
359 sm
->retransCount
= 0;
360 if (sm
->eap_if
.eapReqData
) {
361 if (wpabuf_len(sm
->eap_if
.eapReqData
) >= 20)
362 sm
->num_rounds_short
= 0;
363 if (eap_copy_buf(&sm
->lastReqData
, sm
->eap_if
.eapReqData
) == 0)
365 sm
->eap_if
.eapResp
= FALSE
;
366 sm
->eap_if
.eapReq
= TRUE
;
368 sm
->eap_if
.eapResp
= FALSE
;
369 sm
->eap_if
.eapReq
= FALSE
;
372 wpa_printf(MSG_INFO
, "EAP: SEND_REQUEST - no eapReqData");
373 sm
->eap_if
.eapResp
= FALSE
;
374 sm
->eap_if
.eapReq
= FALSE
;
375 sm
->eap_if
.eapNoReq
= TRUE
;
380 SM_STATE(EAP
, INTEGRITY_CHECK
)
382 SM_ENTRY(EAP
, INTEGRITY_CHECK
);
384 if (!eap_hdr_len_valid(sm
->eap_if
.eapRespData
, 1)) {
390 sm
->ignore
= sm
->m
->check(sm
, sm
->eap_method_priv
,
391 sm
->eap_if
.eapRespData
);
396 SM_STATE(EAP
, METHOD_REQUEST
)
398 SM_ENTRY(EAP
, METHOD_REQUEST
);
401 wpa_printf(MSG_DEBUG
, "EAP: method not initialized");
405 sm
->currentId
= eap_sm_nextId(sm
, sm
->currentId
);
406 wpa_printf(MSG_DEBUG
, "EAP: building EAP-Request: Identifier %d",
408 sm
->lastId
= sm
->currentId
;
409 wpabuf_free(sm
->eap_if
.eapReqData
);
410 sm
->eap_if
.eapReqData
= sm
->m
->buildReq(sm
, sm
->eap_method_priv
,
412 if (sm
->m
->getTimeout
)
413 sm
->methodTimeout
= sm
->m
->getTimeout(sm
, sm
->eap_method_priv
);
415 sm
->methodTimeout
= 0;
419 static void eap_server_erp_init(struct eap_sm
*sm
)
424 u8 EMSKname
[EAP_EMSK_NAME_LEN
];
427 size_t domain_len
, nai_buf_len
;
428 struct eap_server_erp_key
*erp
= NULL
;
431 domain
= eap_get_erp_domain(sm
);
435 domain_len
= os_strlen(domain
);
437 nai_buf_len
= 2 * EAP_EMSK_NAME_LEN
+ 1 + domain_len
;
438 if (nai_buf_len
> 253) {
440 * keyName-NAI has a maximum length of 253 octet to fit in
443 wpa_printf(MSG_DEBUG
,
444 "EAP: Too long realm for ERP keyName-NAI maximum length");
447 nai_buf_len
++; /* null termination */
448 erp
= os_zalloc(sizeof(*erp
) + nai_buf_len
);
451 erp
->recv_seq
= (u32
) -1;
453 emsk
= sm
->m
->get_emsk(sm
, sm
->eap_method_priv
, &emsk_len
);
454 if (!emsk
|| emsk_len
== 0 || emsk_len
> ERP_MAX_KEY_LEN
) {
455 wpa_printf(MSG_DEBUG
,
456 "EAP: No suitable EMSK available for ERP");
460 wpa_hexdump_key(MSG_DEBUG
, "EAP: EMSK", emsk
, emsk_len
);
462 WPA_PUT_BE16(len
, EAP_EMSK_NAME_LEN
);
463 if (hmac_sha256_kdf(sm
->eap_if
.eapSessionId
, sm
->eap_if
.eapSessionIdLen
,
464 "EMSK", len
, sizeof(len
),
465 EMSKname
, EAP_EMSK_NAME_LEN
) < 0) {
466 wpa_printf(MSG_DEBUG
, "EAP: Could not derive EMSKname");
469 wpa_hexdump(MSG_DEBUG
, "EAP: EMSKname", EMSKname
, EAP_EMSK_NAME_LEN
);
471 pos
= wpa_snprintf_hex(erp
->keyname_nai
, nai_buf_len
,
472 EMSKname
, EAP_EMSK_NAME_LEN
);
473 erp
->keyname_nai
[pos
] = '@';
474 os_memcpy(&erp
->keyname_nai
[pos
+ 1], domain
, domain_len
);
476 WPA_PUT_BE16(len
, emsk_len
);
477 if (hmac_sha256_kdf(emsk
, emsk_len
,
478 "EAP Re-authentication Root Key@ietf.org",
479 len
, sizeof(len
), erp
->rRK
, emsk_len
) < 0) {
480 wpa_printf(MSG_DEBUG
, "EAP: Could not derive rRK for ERP");
483 erp
->rRK_len
= emsk_len
;
484 wpa_hexdump_key(MSG_DEBUG
, "EAP: ERP rRK", erp
->rRK
, erp
->rRK_len
);
486 ctx
[0] = EAP_ERP_CS_HMAC_SHA256_128
;
487 WPA_PUT_BE16(&ctx
[1], erp
->rRK_len
);
488 if (hmac_sha256_kdf(erp
->rRK
, erp
->rRK_len
,
489 "Re-authentication Integrity Key@ietf.org",
490 ctx
, sizeof(ctx
), erp
->rIK
, erp
->rRK_len
) < 0) {
491 wpa_printf(MSG_DEBUG
, "EAP: Could not derive rIK for ERP");
494 erp
->rIK_len
= erp
->rRK_len
;
495 wpa_hexdump_key(MSG_DEBUG
, "EAP: ERP rIK", erp
->rIK
, erp
->rIK_len
);
497 if (eap_erp_add_key(sm
, erp
) == 0) {
498 wpa_printf(MSG_DEBUG
, "EAP: Stored ERP keys %s",
504 bin_clear_free(emsk
, emsk_len
);
505 bin_clear_free(erp
, sizeof(*erp
));
506 #endif /* CONFIG_ERP */
510 SM_STATE(EAP
, METHOD_RESPONSE
)
512 SM_ENTRY(EAP
, METHOD_RESPONSE
);
514 if (!eap_hdr_len_valid(sm
->eap_if
.eapRespData
, 1))
517 sm
->m
->process(sm
, sm
->eap_method_priv
, sm
->eap_if
.eapRespData
);
518 if (sm
->m
->isDone(sm
, sm
->eap_method_priv
)) {
519 eap_sm_Policy_update(sm
, NULL
, 0);
520 bin_clear_free(sm
->eap_if
.eapKeyData
, sm
->eap_if
.eapKeyDataLen
);
522 sm
->eap_if
.eapKeyData
= sm
->m
->getKey(
523 sm
, sm
->eap_method_priv
,
524 &sm
->eap_if
.eapKeyDataLen
);
526 sm
->eap_if
.eapKeyData
= NULL
;
527 sm
->eap_if
.eapKeyDataLen
= 0;
529 os_free(sm
->eap_if
.eapSessionId
);
530 sm
->eap_if
.eapSessionId
= NULL
;
531 if (sm
->m
->getSessionId
) {
532 sm
->eap_if
.eapSessionId
= sm
->m
->getSessionId(
533 sm
, sm
->eap_method_priv
,
534 &sm
->eap_if
.eapSessionIdLen
);
535 wpa_hexdump(MSG_DEBUG
, "EAP: Session-Id",
536 sm
->eap_if
.eapSessionId
,
537 sm
->eap_if
.eapSessionIdLen
);
539 if (sm
->cfg
->erp
&& sm
->m
->get_emsk
&& sm
->eap_if
.eapSessionId
)
540 eap_server_erp_init(sm
);
541 sm
->methodState
= METHOD_END
;
543 sm
->methodState
= METHOD_CONTINUE
;
548 SM_STATE(EAP
, PROPOSE_METHOD
)
553 SM_ENTRY(EAP
, PROPOSE_METHOD
);
555 sm
->try_initiate_reauth
= FALSE
;
557 type
= eap_sm_Policy_getNextMethod(sm
, &vendor
);
558 if (vendor
== EAP_VENDOR_IETF
)
559 sm
->currentMethod
= type
;
561 sm
->currentMethod
= EAP_TYPE_EXPANDED
;
562 if (sm
->m
&& sm
->eap_method_priv
) {
563 sm
->m
->reset(sm
, sm
->eap_method_priv
);
564 sm
->eap_method_priv
= NULL
;
566 sm
->m
= eap_server_get_eap_method(vendor
, type
);
568 sm
->eap_method_priv
= sm
->m
->init(sm
);
569 if (sm
->eap_method_priv
== NULL
) {
570 wpa_printf(MSG_DEBUG
, "EAP: Failed to initialize EAP "
571 "method %d", sm
->currentMethod
);
573 sm
->currentMethod
= EAP_TYPE_NONE
;
574 goto try_another_method
;
578 wpa_printf(MSG_DEBUG
, "EAP: Could not find suitable EAP method");
579 eap_log_msg(sm
, "Could not find suitable EAP method");
580 sm
->decision
= DECISION_FAILURE
;
583 if (sm
->currentMethod
== EAP_TYPE_IDENTITY
||
584 sm
->currentMethod
== EAP_TYPE_NOTIFICATION
)
585 sm
->methodState
= METHOD_CONTINUE
;
587 sm
->methodState
= METHOD_PROPOSED
;
589 wpa_msg(sm
->cfg
->msg_ctx
, MSG_INFO
, WPA_EVENT_EAP_PROPOSED_METHOD
590 "vendor=%u method=%u", vendor
, sm
->currentMethod
);
591 eap_log_msg(sm
, "Propose EAP method vendor=%u method=%u",
592 vendor
, sm
->currentMethod
);
598 const struct eap_hdr
*nak
;
601 const u8
*nak_list
= NULL
;
605 if (sm
->eap_method_priv
) {
606 sm
->m
->reset(sm
, sm
->eap_method_priv
);
607 sm
->eap_method_priv
= NULL
;
611 if (!eap_hdr_len_valid(sm
->eap_if
.eapRespData
, 1))
614 nak
= wpabuf_head(sm
->eap_if
.eapRespData
);
615 if (nak
&& wpabuf_len(sm
->eap_if
.eapRespData
) > sizeof(*nak
)) {
616 len
= be_to_host16(nak
->length
);
617 if (len
> wpabuf_len(sm
->eap_if
.eapRespData
))
618 len
= wpabuf_len(sm
->eap_if
.eapRespData
);
619 pos
= (const u8
*) (nak
+ 1);
621 if (*pos
== EAP_TYPE_NAK
) {
627 eap_sm_Policy_update(sm
, nak_list
, len
);
631 SM_STATE(EAP
, SELECT_ACTION
)
633 SM_ENTRY(EAP
, SELECT_ACTION
);
635 sm
->decision
= eap_sm_Policy_getDecision(sm
);
639 SM_STATE(EAP
, TIMEOUT_FAILURE
)
641 SM_ENTRY(EAP
, TIMEOUT_FAILURE
);
643 sm
->eap_if
.eapTimeout
= TRUE
;
645 wpa_msg(sm
->cfg
->msg_ctx
, MSG_INFO
,
646 WPA_EVENT_EAP_TIMEOUT_FAILURE MACSTR
, MAC2STR(sm
->peer_addr
));
650 SM_STATE(EAP
, FAILURE
)
652 SM_ENTRY(EAP
, FAILURE
);
654 wpabuf_free(sm
->eap_if
.eapReqData
);
655 sm
->eap_if
.eapReqData
= eap_sm_buildFailure(sm
, sm
->currentId
);
656 wpabuf_free(sm
->lastReqData
);
657 sm
->lastReqData
= NULL
;
658 sm
->eap_if
.eapFail
= TRUE
;
660 wpa_msg(sm
->cfg
->msg_ctx
, MSG_INFO
, WPA_EVENT_EAP_FAILURE
661 MACSTR
, MAC2STR(sm
->peer_addr
));
665 SM_STATE(EAP
, SUCCESS
)
667 SM_ENTRY(EAP
, SUCCESS
);
669 wpabuf_free(sm
->eap_if
.eapReqData
);
670 sm
->eap_if
.eapReqData
= eap_sm_buildSuccess(sm
, sm
->currentId
);
671 wpabuf_free(sm
->lastReqData
);
672 sm
->lastReqData
= NULL
;
673 if (sm
->eap_if
.eapKeyData
)
674 sm
->eap_if
.eapKeyAvailable
= TRUE
;
675 sm
->eap_if
.eapSuccess
= TRUE
;
677 wpa_msg(sm
->cfg
->msg_ctx
, MSG_INFO
, WPA_EVENT_EAP_SUCCESS
678 MACSTR
, MAC2STR(sm
->peer_addr
));
682 SM_STATE(EAP
, INITIATE_REAUTH_START
)
684 SM_ENTRY(EAP
, INITIATE_REAUTH_START
);
686 sm
->initiate_reauth_start_sent
= TRUE
;
687 sm
->try_initiate_reauth
= TRUE
;
688 sm
->currentId
= eap_sm_nextId(sm
, sm
->currentId
);
689 wpa_printf(MSG_DEBUG
,
690 "EAP: building EAP-Initiate-Re-auth-Start: Identifier %d",
692 sm
->lastId
= sm
->currentId
;
693 wpabuf_free(sm
->eap_if
.eapReqData
);
694 sm
->eap_if
.eapReqData
= eap_sm_buildInitiateReauthStart(sm
,
696 wpabuf_free(sm
->lastReqData
);
697 sm
->lastReqData
= NULL
;
703 static void erp_send_finish_reauth(struct eap_sm
*sm
,
704 struct eap_server_erp_key
*erp
, u8 id
,
705 u8 flags
, u16 seq
, const char *nai
)
709 u8 hash
[SHA256_MAC_LEN
];
714 switch (erp
->cryptosuite
) {
715 case EAP_ERP_CS_HMAC_SHA256_256
:
718 case EAP_ERP_CS_HMAC_SHA256_128
:
727 plen
= 1 + 2 + 2 + os_strlen(nai
);
729 plen
+= 1 + hash_len
;
730 msg
= eap_msg_alloc(EAP_VENDOR_IETF
,
731 (enum eap_type
) EAP_ERP_TYPE_REAUTH
,
732 plen
, EAP_CODE_FINISH
, id
);
735 wpabuf_put_u8(msg
, flags
);
736 wpabuf_put_be16(msg
, seq
);
738 wpabuf_put_u8(msg
, EAP_ERP_TLV_KEYNAME_NAI
);
739 wpabuf_put_u8(msg
, os_strlen(nai
));
740 wpabuf_put_str(msg
, nai
);
743 wpabuf_put_u8(msg
, erp
->cryptosuite
);
744 if (hmac_sha256(erp
->rIK
, erp
->rIK_len
,
745 wpabuf_head(msg
), wpabuf_len(msg
), hash
) < 0) {
749 wpabuf_put_data(msg
, hash
, hash_len
);
752 wpa_printf(MSG_DEBUG
, "EAP: Send EAP-Finish/Re-auth (%s)",
753 flags
& 0x80 ? "failure" : "success");
755 sm
->lastId
= sm
->currentId
;
757 wpabuf_free(sm
->eap_if
.eapReqData
);
758 sm
->eap_if
.eapReqData
= msg
;
759 wpabuf_free(sm
->lastReqData
);
760 sm
->lastReqData
= NULL
;
762 if ((flags
& 0x80) || !erp
) {
763 sm
->eap_if
.eapFail
= TRUE
;
764 wpa_msg(sm
->cfg
->msg_ctx
, MSG_INFO
, WPA_EVENT_EAP_FAILURE
765 MACSTR
, MAC2STR(sm
->peer_addr
));
769 bin_clear_free(sm
->eap_if
.eapKeyData
, sm
->eap_if
.eapKeyDataLen
);
770 sm
->eap_if
.eapKeyDataLen
= 0;
771 sm
->eap_if
.eapKeyData
= os_malloc(erp
->rRK_len
);
772 if (!sm
->eap_if
.eapKeyData
)
775 WPA_PUT_BE16(seed
, seq
);
776 WPA_PUT_BE16(&seed
[2], erp
->rRK_len
);
777 if (hmac_sha256_kdf(erp
->rRK
, erp
->rRK_len
,
778 "Re-authentication Master Session Key@ietf.org",
780 sm
->eap_if
.eapKeyData
, erp
->rRK_len
) < 0) {
781 wpa_printf(MSG_DEBUG
, "EAP: Could not derive rMSK for ERP");
782 bin_clear_free(sm
->eap_if
.eapKeyData
, erp
->rRK_len
);
783 sm
->eap_if
.eapKeyData
= NULL
;
786 sm
->eap_if
.eapKeyDataLen
= erp
->rRK_len
;
787 sm
->eap_if
.eapKeyAvailable
= TRUE
;
788 wpa_hexdump_key(MSG_DEBUG
, "EAP: ERP rMSK",
789 sm
->eap_if
.eapKeyData
, sm
->eap_if
.eapKeyDataLen
);
790 sm
->eap_if
.eapSuccess
= TRUE
;
792 wpa_msg(sm
->cfg
->msg_ctx
, MSG_INFO
, WPA_EVENT_EAP_SUCCESS
793 MACSTR
, MAC2STR(sm
->peer_addr
));
797 SM_STATE(EAP
, INITIATE_RECEIVED
)
799 const u8
*pos
, *end
, *start
, *tlvs
, *hdr
;
800 const struct eap_hdr
*ehdr
;
805 struct eap_server_erp_key
*erp
;
807 u8 hash
[SHA256_MAC_LEN
];
809 struct erp_tlvs parse
;
810 u8 resp_flags
= 0x80; /* default to failure; cleared on success */
812 SM_ENTRY(EAP
, INITIATE_RECEIVED
);
814 sm
->rxInitiate
= FALSE
;
816 pos
= eap_hdr_validate(EAP_VENDOR_IETF
,
817 (enum eap_type
) EAP_ERP_TYPE_REAUTH
,
818 sm
->eap_if
.eapRespData
, &len
);
820 wpa_printf(MSG_INFO
, "EAP-Initiate: Invalid frame");
823 hdr
= wpabuf_head(sm
->eap_if
.eapRespData
);
824 ehdr
= wpabuf_head(sm
->eap_if
.eapRespData
);
826 wpa_hexdump(MSG_DEBUG
, "EAP: EAP-Initiate/Re-Auth", pos
, len
);
828 wpa_printf(MSG_INFO
, "EAP: Too short EAP-Initiate/Re-auth");
834 seq
= WPA_GET_BE16(pos
);
836 wpa_printf(MSG_DEBUG
, "EAP: Flags=0x%x SEQ=%u", flags
, seq
);
840 * Parse TVs/TLVs. Since we do not yet know the length of the
841 * Authentication Tag, stop parsing if an unknown TV/TLV is seen and
842 * just try to find the keyName-NAI first so that we can check the
843 * Authentication Tag.
845 if (erp_parse_tlvs(tlvs
, end
, &parse
, 1) < 0)
848 if (!parse
.keyname
) {
849 wpa_printf(MSG_DEBUG
,
850 "EAP: No keyName-NAI in EAP-Initiate/Re-auth Packet");
854 wpa_hexdump_ascii(MSG_DEBUG
, "EAP: EAP-Initiate/Re-auth - keyName-NAI",
855 parse
.keyname
, parse
.keyname_len
);
856 if (parse
.keyname_len
> 253) {
857 wpa_printf(MSG_DEBUG
,
858 "EAP: Too long keyName-NAI in EAP-Initiate/Re-auth");
861 os_memcpy(nai
, parse
.keyname
, parse
.keyname_len
);
862 nai
[parse
.keyname_len
] = '\0';
864 if (!sm
->cfg
->eap_server
) {
866 * In passthrough case, EAP-Initiate/Re-auth replaces
867 * EAP Identity exchange. Use keyName-NAI as the user identity
868 * and forward EAP-Initiate/Re-auth to the backend
869 * authentication server.
871 wpa_printf(MSG_DEBUG
,
872 "EAP: Use keyName-NAI as user identity for backend authentication");
873 eap_server_clear_identity(sm
);
874 sm
->identity
= (u8
*) dup_binstr(parse
.keyname
,
878 sm
->identity_len
= parse
.keyname_len
;
882 erp
= eap_erp_get_key(sm
, nai
);
884 wpa_printf(MSG_DEBUG
, "EAP: No matching ERP key found for %s",
889 if (erp
->recv_seq
!= (u32
) -1 && erp
->recv_seq
>= seq
) {
890 wpa_printf(MSG_DEBUG
,
891 "EAP: SEQ=%u replayed (already received SEQ=%u)",
896 /* Is there enough room for Cryptosuite and Authentication Tag? */
897 start
= parse
.keyname
+ parse
.keyname_len
;
898 max_len
= end
- start
;
900 1 + (erp
->cryptosuite
== EAP_ERP_CS_HMAC_SHA256_256
? 32 : 16)) {
901 wpa_printf(MSG_DEBUG
,
902 "EAP: Not enough room for Authentication Tag");
906 switch (erp
->cryptosuite
) {
907 case EAP_ERP_CS_HMAC_SHA256_256
:
908 if (end
[-33] != erp
->cryptosuite
) {
909 wpa_printf(MSG_DEBUG
,
910 "EAP: Different Cryptosuite used");
915 case EAP_ERP_CS_HMAC_SHA256_128
:
916 if (end
[-17] != erp
->cryptosuite
) {
917 wpa_printf(MSG_DEBUG
,
918 "EAP: Different Cryptosuite used");
929 if (hmac_sha256(erp
->rIK
, erp
->rIK_len
, hdr
,
930 end
- hdr
- hash_len
, hash
) < 0)
932 if (os_memcmp(end
- hash_len
, hash
, hash_len
) != 0) {
933 wpa_printf(MSG_DEBUG
,
934 "EAP: Authentication Tag mismatch");
939 /* Check if any supported CS results in matching tag */
940 if (!hash_len
&& max_len
>= 1 + 32 &&
941 end
[-33] == EAP_ERP_CS_HMAC_SHA256_256
) {
942 if (hmac_sha256(erp
->rIK
, erp
->rIK_len
, hdr
,
943 end
- hdr
- 32, hash
) < 0)
945 if (os_memcmp(end
- 32, hash
, 32) == 0) {
946 wpa_printf(MSG_DEBUG
,
947 "EAP: Authentication Tag match using HMAC-SHA256-256");
949 erp
->cryptosuite
= EAP_ERP_CS_HMAC_SHA256_256
;
953 if (!hash_len
&& end
[-17] == EAP_ERP_CS_HMAC_SHA256_128
) {
954 if (hmac_sha256(erp
->rIK
, erp
->rIK_len
, hdr
,
955 end
- hdr
- 16, hash
) < 0)
957 if (os_memcmp(end
- 16, hash
, 16) == 0) {
958 wpa_printf(MSG_DEBUG
,
959 "EAP: Authentication Tag match using HMAC-SHA256-128");
961 erp
->cryptosuite
= EAP_ERP_CS_HMAC_SHA256_128
;
966 wpa_printf(MSG_DEBUG
,
967 "EAP: No supported cryptosuite matched Authentication Tag");
973 * Parse TVs/TLVs again now that we know the exact part of the buffer
974 * that contains them.
976 wpa_hexdump(MSG_DEBUG
, "EAP: EAP-Initiate/Re-Auth TVs/TLVs",
978 if (erp_parse_tlvs(tlvs
, end
, &parse
, 0) < 0)
981 wpa_printf(MSG_DEBUG
, "EAP: ERP key %s SEQ updated to %u",
982 erp
->keyname_nai
, seq
);
984 resp_flags
&= ~0x80; /* R=0 - success */
987 erp_send_finish_reauth(sm
, erp
, ehdr
->identifier
, resp_flags
, seq
, nai
);
994 #endif /* CONFIG_ERP */
997 SM_STATE(EAP
, INITIALIZE_PASSTHROUGH
)
999 SM_ENTRY(EAP
, INITIALIZE_PASSTHROUGH
);
1001 wpabuf_free(sm
->eap_if
.aaaEapRespData
);
1002 sm
->eap_if
.aaaEapRespData
= NULL
;
1003 sm
->try_initiate_reauth
= FALSE
;
1007 SM_STATE(EAP
, IDLE2
)
1009 SM_ENTRY(EAP
, IDLE2
);
1011 sm
->eap_if
.retransWhile
= eap_sm_calculateTimeout(
1012 sm
, sm
->retransCount
, sm
->eap_if
.eapSRTT
, sm
->eap_if
.eapRTTVAR
,
1017 SM_STATE(EAP
, RETRANSMIT2
)
1019 SM_ENTRY(EAP
, RETRANSMIT2
);
1022 if (sm
->retransCount
<= sm
->MaxRetrans
&& sm
->lastReqData
) {
1023 if (eap_copy_buf(&sm
->eap_if
.eapReqData
, sm
->lastReqData
) == 0)
1024 sm
->eap_if
.eapReq
= TRUE
;
1027 wpa_msg(sm
->cfg
->msg_ctx
, MSG_INFO
, WPA_EVENT_EAP_RETRANSMIT2 MACSTR
,
1028 MAC2STR(sm
->peer_addr
));
1032 SM_STATE(EAP
, RECEIVED2
)
1034 SM_ENTRY(EAP
, RECEIVED2
);
1036 /* parse rxResp, respId, respMethod */
1037 eap_sm_parseEapResp(sm
, sm
->eap_if
.eapRespData
);
1041 SM_STATE(EAP
, DISCARD2
)
1043 SM_ENTRY(EAP
, DISCARD2
);
1044 sm
->eap_if
.eapResp
= FALSE
;
1045 sm
->eap_if
.eapNoReq
= TRUE
;
1049 SM_STATE(EAP
, SEND_REQUEST2
)
1051 SM_ENTRY(EAP
, SEND_REQUEST2
);
1053 sm
->retransCount
= 0;
1054 if (sm
->eap_if
.eapReqData
) {
1055 if (eap_copy_buf(&sm
->lastReqData
, sm
->eap_if
.eapReqData
) == 0)
1057 sm
->eap_if
.eapResp
= FALSE
;
1058 sm
->eap_if
.eapReq
= TRUE
;
1060 sm
->eap_if
.eapResp
= FALSE
;
1061 sm
->eap_if
.eapReq
= FALSE
;
1064 wpa_printf(MSG_INFO
, "EAP: SEND_REQUEST2 - no eapReqData");
1065 sm
->eap_if
.eapResp
= FALSE
;
1066 sm
->eap_if
.eapReq
= FALSE
;
1067 sm
->eap_if
.eapNoReq
= TRUE
;
1072 SM_STATE(EAP
, AAA_REQUEST
)
1074 SM_ENTRY(EAP
, AAA_REQUEST
);
1076 if (sm
->eap_if
.eapRespData
== NULL
) {
1077 wpa_printf(MSG_INFO
, "EAP: AAA_REQUEST - no eapRespData");
1082 * if (respMethod == IDENTITY)
1083 * aaaIdentity = eapRespData
1084 * This is already taken care of by the EAP-Identity method which
1085 * stores the identity into sm->identity.
1088 eap_copy_buf(&sm
->eap_if
.aaaEapRespData
, sm
->eap_if
.eapRespData
);
1092 SM_STATE(EAP
, AAA_RESPONSE
)
1094 SM_ENTRY(EAP
, AAA_RESPONSE
);
1096 eap_copy_buf(&sm
->eap_if
.eapReqData
, sm
->eap_if
.aaaEapReqData
);
1097 sm
->currentId
= eap_sm_getId(sm
->eap_if
.eapReqData
);
1098 sm
->methodTimeout
= sm
->eap_if
.aaaMethodTimeout
;
1102 SM_STATE(EAP
, AAA_IDLE
)
1104 SM_ENTRY(EAP
, AAA_IDLE
);
1106 sm
->eap_if
.aaaFail
= FALSE
;
1107 sm
->eap_if
.aaaSuccess
= FALSE
;
1108 sm
->eap_if
.aaaEapReq
= FALSE
;
1109 sm
->eap_if
.aaaEapNoReq
= FALSE
;
1110 sm
->eap_if
.aaaEapResp
= TRUE
;
1114 SM_STATE(EAP
, TIMEOUT_FAILURE2
)
1116 SM_ENTRY(EAP
, TIMEOUT_FAILURE2
);
1118 sm
->eap_if
.eapTimeout
= TRUE
;
1120 wpa_msg(sm
->cfg
->msg_ctx
, MSG_INFO
,
1121 WPA_EVENT_EAP_TIMEOUT_FAILURE2 MACSTR
, MAC2STR(sm
->peer_addr
));
1125 SM_STATE(EAP
, FAILURE2
)
1127 SM_ENTRY(EAP
, FAILURE2
);
1129 eap_copy_buf(&sm
->eap_if
.eapReqData
, sm
->eap_if
.aaaEapReqData
);
1130 sm
->eap_if
.eapFail
= TRUE
;
1132 wpa_msg(sm
->cfg
->msg_ctx
, MSG_INFO
, WPA_EVENT_EAP_FAILURE2 MACSTR
,
1133 MAC2STR(sm
->peer_addr
));
1137 SM_STATE(EAP
, SUCCESS2
)
1139 SM_ENTRY(EAP
, SUCCESS2
);
1141 eap_copy_buf(&sm
->eap_if
.eapReqData
, sm
->eap_if
.aaaEapReqData
);
1143 sm
->eap_if
.eapKeyAvailable
= sm
->eap_if
.aaaEapKeyAvailable
;
1144 if (sm
->eap_if
.aaaEapKeyAvailable
) {
1145 EAP_COPY(&sm
->eap_if
.eapKeyData
, sm
->eap_if
.aaaEapKeyData
);
1147 bin_clear_free(sm
->eap_if
.eapKeyData
, sm
->eap_if
.eapKeyDataLen
);
1148 sm
->eap_if
.eapKeyData
= NULL
;
1149 sm
->eap_if
.eapKeyDataLen
= 0;
1152 sm
->eap_if
.eapSuccess
= TRUE
;
1155 * Start reauthentication with identity request even though we know the
1156 * previously used identity. This is needed to get reauthentication
1159 sm
->start_reauth
= TRUE
;
1161 wpa_msg(sm
->cfg
->msg_ctx
, MSG_INFO
, WPA_EVENT_EAP_SUCCESS2 MACSTR
,
1162 MAC2STR(sm
->peer_addr
));
1168 if (sm
->eap_if
.eapRestart
&& sm
->eap_if
.portEnabled
)
1169 SM_ENTER_GLOBAL(EAP
, INITIALIZE
);
1170 else if (!sm
->eap_if
.portEnabled
)
1171 SM_ENTER_GLOBAL(EAP
, DISABLED
);
1172 else if (sm
->num_rounds
> sm
->cfg
->max_auth_rounds
) {
1173 if (sm
->num_rounds
== sm
->cfg
->max_auth_rounds
+ 1) {
1174 wpa_printf(MSG_DEBUG
, "EAP: more than %d "
1175 "authentication rounds - abort",
1176 sm
->cfg
->max_auth_rounds
);
1178 SM_ENTER_GLOBAL(EAP
, FAILURE
);
1180 } else if (sm
->num_rounds_short
> sm
->cfg
->max_auth_rounds_short
) {
1181 if (sm
->num_rounds_short
==
1182 sm
->cfg
->max_auth_rounds_short
+ 1) {
1183 wpa_printf(MSG_DEBUG
,
1184 "EAP: more than %d authentication rounds (short) - abort",
1185 sm
->cfg
->max_auth_rounds_short
);
1186 sm
->num_rounds_short
++;
1187 SM_ENTER_GLOBAL(EAP
, FAILURE
);
1189 } else switch (sm
->EAP_state
) {
1190 case EAP_INITIALIZE
:
1191 if (sm
->cfg
->backend_auth
) {
1193 SM_ENTER(EAP
, SELECT_ACTION
);
1194 else if (sm
->rxResp
&&
1195 (sm
->respMethod
== EAP_TYPE_NAK
||
1196 (sm
->respMethod
== EAP_TYPE_EXPANDED
&&
1197 sm
->respVendor
== EAP_VENDOR_IETF
&&
1198 sm
->respVendorMethod
== EAP_TYPE_NAK
)))
1201 SM_ENTER(EAP
, PICK_UP_METHOD
);
1203 SM_ENTER(EAP
, SELECT_ACTION
);
1206 case EAP_PICK_UP_METHOD
:
1207 if (sm
->currentMethod
== EAP_TYPE_NONE
) {
1208 SM_ENTER(EAP
, SELECT_ACTION
);
1210 SM_ENTER(EAP
, METHOD_RESPONSE
);
1214 if (sm
->eap_if
.portEnabled
)
1215 SM_ENTER(EAP
, INITIALIZE
);
1218 if (sm
->eap_if
.retransWhile
== 0) {
1219 if (sm
->try_initiate_reauth
) {
1220 sm
->try_initiate_reauth
= FALSE
;
1221 SM_ENTER(EAP
, SELECT_ACTION
);
1223 SM_ENTER(EAP
, RETRANSMIT
);
1225 } else if (sm
->eap_if
.eapResp
)
1226 SM_ENTER(EAP
, RECEIVED
);
1228 case EAP_RETRANSMIT
:
1229 if (sm
->retransCount
> sm
->MaxRetrans
)
1230 SM_ENTER(EAP
, TIMEOUT_FAILURE
);
1232 SM_ENTER(EAP
, IDLE
);
1235 if (sm
->rxResp
&& (sm
->respId
== sm
->currentId
) &&
1236 (sm
->respMethod
== EAP_TYPE_NAK
||
1237 (sm
->respMethod
== EAP_TYPE_EXPANDED
&&
1238 sm
->respVendor
== EAP_VENDOR_IETF
&&
1239 sm
->respVendorMethod
== EAP_TYPE_NAK
))
1240 && (sm
->methodState
== METHOD_PROPOSED
))
1242 else if (sm
->rxResp
&& (sm
->respId
== sm
->currentId
) &&
1243 ((sm
->respMethod
== sm
->currentMethod
) ||
1244 (sm
->respMethod
== EAP_TYPE_EXPANDED
&&
1245 sm
->respVendor
== EAP_VENDOR_IETF
&&
1246 sm
->respVendorMethod
== sm
->currentMethod
)))
1247 SM_ENTER(EAP
, INTEGRITY_CHECK
);
1249 else if (sm
->rxInitiate
)
1250 SM_ENTER(EAP
, INITIATE_RECEIVED
);
1251 #endif /* CONFIG_ERP */
1253 wpa_printf(MSG_DEBUG
, "EAP: RECEIVED->DISCARD: "
1254 "rxResp=%d respId=%d currentId=%d "
1255 "respMethod=%d currentMethod=%d",
1256 sm
->rxResp
, sm
->respId
, sm
->currentId
,
1257 sm
->respMethod
, sm
->currentMethod
);
1258 eap_log_msg(sm
, "Discard received EAP message");
1259 SM_ENTER(EAP
, DISCARD
);
1263 SM_ENTER(EAP
, IDLE
);
1265 case EAP_SEND_REQUEST
:
1266 SM_ENTER(EAP
, IDLE
);
1268 case EAP_INTEGRITY_CHECK
:
1270 SM_ENTER(EAP
, DISCARD
);
1272 SM_ENTER(EAP
, METHOD_RESPONSE
);
1274 case EAP_METHOD_REQUEST
:
1275 if (sm
->m
== NULL
) {
1277 * This transition is not mentioned in RFC 4137, but it
1278 * is needed to handle cleanly a case where EAP method
1279 * initialization fails.
1281 SM_ENTER(EAP
, FAILURE
);
1284 SM_ENTER(EAP
, SEND_REQUEST
);
1285 if (sm
->eap_if
.eapNoReq
&& !sm
->eap_if
.eapReq
) {
1287 * This transition is not mentioned in RFC 4137, but it
1288 * is needed to handle cleanly a case where EAP method
1291 wpa_printf(MSG_DEBUG
,
1292 "EAP: Method did not return a request");
1293 SM_ENTER(EAP
, FAILURE
);
1297 case EAP_METHOD_RESPONSE
:
1299 * Note: Mechanism to allow EAP methods to wait while going
1300 * through pending processing is an extension to RFC 4137
1301 * which only defines the transits to SELECT_ACTION and
1302 * METHOD_REQUEST from this METHOD_RESPONSE state.
1304 if (sm
->methodState
== METHOD_END
)
1305 SM_ENTER(EAP
, SELECT_ACTION
);
1306 else if (sm
->method_pending
== METHOD_PENDING_WAIT
) {
1307 wpa_printf(MSG_DEBUG
, "EAP: Method has pending "
1308 "processing - wait before proceeding to "
1309 "METHOD_REQUEST state");
1310 } else if (sm
->method_pending
== METHOD_PENDING_CONT
) {
1311 wpa_printf(MSG_DEBUG
, "EAP: Method has completed "
1312 "pending processing - reprocess pending "
1314 sm
->method_pending
= METHOD_PENDING_NONE
;
1315 SM_ENTER(EAP
, METHOD_RESPONSE
);
1317 SM_ENTER(EAP
, METHOD_REQUEST
);
1319 case EAP_PROPOSE_METHOD
:
1321 * Note: Mechanism to allow EAP methods to wait while going
1322 * through pending processing is an extension to RFC 4137
1323 * which only defines the transit to METHOD_REQUEST from this
1324 * PROPOSE_METHOD state.
1326 if (sm
->method_pending
== METHOD_PENDING_WAIT
) {
1327 wpa_printf(MSG_DEBUG
, "EAP: Method has pending "
1328 "processing - wait before proceeding to "
1329 "METHOD_REQUEST state");
1330 if (sm
->user_eap_method_index
> 0)
1331 sm
->user_eap_method_index
--;
1332 } else if (sm
->method_pending
== METHOD_PENDING_CONT
) {
1333 wpa_printf(MSG_DEBUG
, "EAP: Method has completed "
1334 "pending processing - reprocess pending "
1336 sm
->method_pending
= METHOD_PENDING_NONE
;
1337 SM_ENTER(EAP
, PROPOSE_METHOD
);
1339 SM_ENTER(EAP
, METHOD_REQUEST
);
1342 SM_ENTER(EAP
, SELECT_ACTION
);
1344 case EAP_SELECT_ACTION
:
1345 if (sm
->decision
== DECISION_FAILURE
)
1346 SM_ENTER(EAP
, FAILURE
);
1347 else if (sm
->decision
== DECISION_SUCCESS
)
1348 SM_ENTER(EAP
, SUCCESS
);
1349 else if (sm
->decision
== DECISION_PASSTHROUGH
)
1350 SM_ENTER(EAP
, INITIALIZE_PASSTHROUGH
);
1351 else if (sm
->decision
== DECISION_INITIATE_REAUTH_START
)
1352 SM_ENTER(EAP
, INITIATE_REAUTH_START
);
1354 else if (sm
->cfg
->eap_server
&& sm
->cfg
->erp
&& sm
->rxInitiate
)
1355 SM_ENTER(EAP
, INITIATE_RECEIVED
);
1356 #endif /* CONFIG_ERP */
1358 SM_ENTER(EAP
, PROPOSE_METHOD
);
1360 case EAP_INITIATE_REAUTH_START
:
1361 SM_ENTER(EAP
, SEND_REQUEST
);
1363 case EAP_INITIATE_RECEIVED
:
1364 if (!sm
->cfg
->eap_server
)
1365 SM_ENTER(EAP
, SELECT_ACTION
);
1367 case EAP_TIMEOUT_FAILURE
:
1374 case EAP_INITIALIZE_PASSTHROUGH
:
1375 if (sm
->currentId
== -1)
1376 SM_ENTER(EAP
, AAA_IDLE
);
1378 SM_ENTER(EAP
, AAA_REQUEST
);
1381 if (sm
->eap_if
.eapResp
)
1382 SM_ENTER(EAP
, RECEIVED2
);
1383 else if (sm
->eap_if
.retransWhile
== 0)
1384 SM_ENTER(EAP
, RETRANSMIT2
);
1386 case EAP_RETRANSMIT2
:
1387 if (sm
->retransCount
> sm
->MaxRetrans
)
1388 SM_ENTER(EAP
, TIMEOUT_FAILURE2
);
1390 SM_ENTER(EAP
, IDLE2
);
1393 if (sm
->rxResp
&& (sm
->respId
== sm
->currentId
))
1394 SM_ENTER(EAP
, AAA_REQUEST
);
1396 SM_ENTER(EAP
, DISCARD2
);
1399 SM_ENTER(EAP
, IDLE2
);
1401 case EAP_SEND_REQUEST2
:
1402 SM_ENTER(EAP
, IDLE2
);
1404 case EAP_AAA_REQUEST
:
1405 SM_ENTER(EAP
, AAA_IDLE
);
1407 case EAP_AAA_RESPONSE
:
1408 SM_ENTER(EAP
, SEND_REQUEST2
);
1411 if (sm
->eap_if
.aaaFail
)
1412 SM_ENTER(EAP
, FAILURE2
);
1413 else if (sm
->eap_if
.aaaSuccess
)
1414 SM_ENTER(EAP
, SUCCESS2
);
1415 else if (sm
->eap_if
.aaaEapReq
)
1416 SM_ENTER(EAP
, AAA_RESPONSE
);
1417 else if (sm
->eap_if
.aaaTimeout
)
1418 SM_ENTER(EAP
, TIMEOUT_FAILURE2
);
1420 case EAP_TIMEOUT_FAILURE2
:
1430 static int eap_sm_calculateTimeout(struct eap_sm
*sm
, int retransCount
,
1431 int eapSRTT
, int eapRTTVAR
,
1436 if (sm
->try_initiate_reauth
) {
1437 wpa_printf(MSG_DEBUG
,
1438 "EAP: retransmit timeout 1 second for EAP-Initiate-Re-auth-Start");
1442 if (methodTimeout
) {
1444 * EAP method (either internal or through AAA server, provided
1445 * timeout hint. Use that as-is as a timeout for retransmitting
1446 * the EAP request if no response is received.
1448 wpa_printf(MSG_DEBUG
, "EAP: retransmit timeout %d seconds "
1449 "(from EAP method hint)", methodTimeout
);
1450 return methodTimeout
;
1454 * RFC 3748 recommends algorithms described in RFC 2988 for estimation
1455 * of the retransmission timeout. This should be implemented once
1456 * round-trip time measurements are available. For nowm a simple
1457 * backoff mechanism is used instead if there are no EAP method
1460 * SRTT = smoothed round-trip time
1461 * RTTVAR = round-trip time variation
1462 * RTO = retransmission timeout
1466 * RFC 2988, 2.1: before RTT measurement, set RTO to 3 seconds for
1467 * initial retransmission and then double the RTO to provide back off
1468 * per 5.5. Limit the maximum RTO to 20 seconds per RFC 3748, 4.3
1472 for (i
= 0; i
< retransCount
; i
++) {
1480 wpa_printf(MSG_DEBUG
, "EAP: retransmit timeout %d seconds "
1481 "(from dynamic back off; retransCount=%d)",
1488 static void eap_sm_parseEapResp(struct eap_sm
*sm
, const struct wpabuf
*resp
)
1490 const struct eap_hdr
*hdr
;
1493 /* parse rxResp, respId, respMethod */
1495 sm
->rxInitiate
= FALSE
;
1497 sm
->respMethod
= EAP_TYPE_NONE
;
1498 sm
->respVendor
= EAP_VENDOR_IETF
;
1499 sm
->respVendorMethod
= EAP_TYPE_NONE
;
1501 if (resp
== NULL
|| wpabuf_len(resp
) < sizeof(*hdr
)) {
1502 wpa_printf(MSG_DEBUG
, "EAP: parseEapResp: invalid resp=%p "
1504 resp
? (unsigned long) wpabuf_len(resp
) : 0);
1508 hdr
= wpabuf_head(resp
);
1509 plen
= be_to_host16(hdr
->length
);
1510 if (plen
> wpabuf_len(resp
)) {
1511 wpa_printf(MSG_DEBUG
, "EAP: Ignored truncated EAP-Packet "
1512 "(len=%lu plen=%lu)",
1513 (unsigned long) wpabuf_len(resp
),
1514 (unsigned long) plen
);
1518 sm
->respId
= hdr
->identifier
;
1520 if (hdr
->code
== EAP_CODE_RESPONSE
)
1522 else if (hdr
->code
== EAP_CODE_INITIATE
)
1523 sm
->rxInitiate
= TRUE
;
1525 if (plen
> sizeof(*hdr
)) {
1526 u8
*pos
= (u8
*) (hdr
+ 1);
1527 sm
->respMethod
= *pos
++;
1528 if (sm
->respMethod
== EAP_TYPE_EXPANDED
) {
1529 if (plen
< sizeof(*hdr
) + 8) {
1530 wpa_printf(MSG_DEBUG
, "EAP: Ignored truncated "
1531 "expanded EAP-Packet (plen=%lu)",
1532 (unsigned long) plen
);
1535 sm
->respVendor
= WPA_GET_BE24(pos
);
1537 sm
->respVendorMethod
= WPA_GET_BE32(pos
);
1541 wpa_printf(MSG_DEBUG
,
1542 "EAP: parseEapResp: rxResp=%d rxInitiate=%d respId=%d respMethod=%u respVendor=%u respVendorMethod=%u",
1543 sm
->rxResp
, sm
->rxInitiate
, sm
->respId
, sm
->respMethod
,
1544 sm
->respVendor
, sm
->respVendorMethod
);
1548 static int eap_sm_getId(const struct wpabuf
*data
)
1550 const struct eap_hdr
*hdr
;
1552 if (data
== NULL
|| wpabuf_len(data
) < sizeof(*hdr
))
1555 hdr
= wpabuf_head(data
);
1556 wpa_printf(MSG_DEBUG
, "EAP: getId: id=%d", hdr
->identifier
);
1557 return hdr
->identifier
;
1561 static struct wpabuf
* eap_sm_buildSuccess(struct eap_sm
*sm
, u8 id
)
1564 struct eap_hdr
*resp
;
1565 wpa_printf(MSG_DEBUG
, "EAP: Building EAP-Success (id=%d)", id
);
1567 msg
= wpabuf_alloc(sizeof(*resp
));
1570 resp
= wpabuf_put(msg
, sizeof(*resp
));
1571 resp
->code
= EAP_CODE_SUCCESS
;
1572 resp
->identifier
= id
;
1573 resp
->length
= host_to_be16(sizeof(*resp
));
1579 static struct wpabuf
* eap_sm_buildFailure(struct eap_sm
*sm
, u8 id
)
1582 struct eap_hdr
*resp
;
1583 wpa_printf(MSG_DEBUG
, "EAP: Building EAP-Failure (id=%d)", id
);
1585 msg
= wpabuf_alloc(sizeof(*resp
));
1588 resp
= wpabuf_put(msg
, sizeof(*resp
));
1589 resp
->code
= EAP_CODE_FAILURE
;
1590 resp
->identifier
= id
;
1591 resp
->length
= host_to_be16(sizeof(*resp
));
1597 static int eap_sm_nextId(struct eap_sm
*sm
, int id
)
1600 /* RFC 3748 Ch 4.1: recommended to initialize Identifier with a
1603 if (id
!= sm
->lastId
)
1606 return (id
+ 1) & 0xff;
1611 * eap_sm_process_nak - Process EAP-Response/Nak
1612 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1613 * @nak_list: Nak list (allowed methods) from the supplicant
1614 * @len: Length of nak_list in bytes
1616 * This function is called when EAP-Response/Nak is received from the
1617 * supplicant. This can happen for both phase 1 and phase 2 authentications.
1619 void eap_sm_process_nak(struct eap_sm
*sm
, const u8
*nak_list
, size_t len
)
1624 if (sm
->user
== NULL
)
1627 wpa_printf(MSG_MSGDUMP
, "EAP: processing NAK (current EAP method "
1628 "index %d)", sm
->user_eap_method_index
);
1630 wpa_hexdump(MSG_MSGDUMP
, "EAP: configured methods",
1631 (u8
*) sm
->user
->methods
,
1632 EAP_MAX_METHODS
* sizeof(sm
->user
->methods
[0]));
1633 wpa_hexdump(MSG_MSGDUMP
, "EAP: list of methods supported by the peer",
1636 i
= sm
->user_eap_method_index
;
1637 while (i
< EAP_MAX_METHODS
&&
1638 (sm
->user
->methods
[i
].vendor
!= EAP_VENDOR_IETF
||
1639 sm
->user
->methods
[i
].method
!= EAP_TYPE_NONE
)) {
1640 if (sm
->user
->methods
[i
].vendor
!= EAP_VENDOR_IETF
)
1642 for (j
= 0; j
< len
; j
++) {
1643 if (nak_list
[j
] == sm
->user
->methods
[i
].method
) {
1655 /* not found - remove from the list */
1656 if (i
+ 1 < EAP_MAX_METHODS
) {
1657 os_memmove(&sm
->user
->methods
[i
],
1658 &sm
->user
->methods
[i
+ 1],
1659 (EAP_MAX_METHODS
- i
- 1) *
1660 sizeof(sm
->user
->methods
[0]));
1662 sm
->user
->methods
[EAP_MAX_METHODS
- 1].vendor
=
1664 sm
->user
->methods
[EAP_MAX_METHODS
- 1].method
= EAP_TYPE_NONE
;
1667 wpa_hexdump(MSG_MSGDUMP
, "EAP: new list of configured methods",
1668 (u8
*) sm
->user
->methods
, EAP_MAX_METHODS
*
1669 sizeof(sm
->user
->methods
[0]));
1673 static void eap_sm_Policy_update(struct eap_sm
*sm
, const u8
*nak_list
,
1676 if (nak_list
== NULL
|| sm
== NULL
|| sm
->user
== NULL
)
1679 if (sm
->user
->phase2
) {
1680 wpa_printf(MSG_DEBUG
, "EAP: EAP-Nak received after Phase2 user"
1681 " info was selected - reject");
1682 sm
->decision
= DECISION_FAILURE
;
1686 eap_sm_process_nak(sm
, nak_list
, len
);
1690 static enum eap_type
eap_sm_Policy_getNextMethod(struct eap_sm
*sm
, int *vendor
)
1693 int idx
= sm
->user_eap_method_index
;
1695 /* In theory, there should be no problems with starting
1696 * re-authentication with something else than EAP-Request/Identity and
1697 * this does indeed work with wpa_supplicant. However, at least Funk
1698 * Supplicant seemed to ignore re-auth if it skipped
1699 * EAP-Request/Identity.
1700 * Re-auth sets currentId == -1, so that can be used here to select
1701 * whether Identity needs to be requested again. */
1702 if (sm
->identity
== NULL
|| sm
->currentId
== -1) {
1703 *vendor
= EAP_VENDOR_IETF
;
1704 next
= EAP_TYPE_IDENTITY
;
1705 sm
->update_user
= TRUE
;
1706 } else if (sm
->user
&& idx
< EAP_MAX_METHODS
&&
1707 (sm
->user
->methods
[idx
].vendor
!= EAP_VENDOR_IETF
||
1708 sm
->user
->methods
[idx
].method
!= EAP_TYPE_NONE
)) {
1709 *vendor
= sm
->user
->methods
[idx
].vendor
;
1710 next
= sm
->user
->methods
[idx
].method
;
1711 sm
->user_eap_method_index
++;
1713 *vendor
= EAP_VENDOR_IETF
;
1714 next
= EAP_TYPE_NONE
;
1716 wpa_printf(MSG_DEBUG
, "EAP: getNextMethod: vendor %d type %d",
1722 static int eap_sm_Policy_getDecision(struct eap_sm
*sm
)
1724 if (!sm
->cfg
->eap_server
&& sm
->identity
&& !sm
->start_reauth
) {
1725 wpa_printf(MSG_DEBUG
, "EAP: getDecision: -> PASSTHROUGH");
1726 return DECISION_PASSTHROUGH
;
1729 if (sm
->m
&& sm
->currentMethod
!= EAP_TYPE_IDENTITY
&&
1730 sm
->m
->isSuccess(sm
, sm
->eap_method_priv
)) {
1731 wpa_printf(MSG_DEBUG
, "EAP: getDecision: method succeeded -> "
1733 sm
->update_user
= TRUE
;
1734 return DECISION_SUCCESS
;
1737 if (sm
->m
&& sm
->m
->isDone(sm
, sm
->eap_method_priv
) &&
1738 !sm
->m
->isSuccess(sm
, sm
->eap_method_priv
)) {
1739 wpa_printf(MSG_DEBUG
, "EAP: getDecision: method failed -> "
1741 sm
->update_user
= TRUE
;
1742 return DECISION_FAILURE
;
1745 if ((sm
->user
== NULL
|| sm
->update_user
) && sm
->identity
&&
1746 !sm
->start_reauth
) {
1748 * Allow Identity method to be started once to allow identity
1749 * selection hint to be sent from the authentication server,
1750 * but prevent a loop of Identity requests by only allowing
1751 * this to happen once.
1754 if (sm
->user
&& sm
->currentMethod
== EAP_TYPE_IDENTITY
&&
1755 sm
->user
->methods
[0].vendor
== EAP_VENDOR_IETF
&&
1756 sm
->user
->methods
[0].method
== EAP_TYPE_IDENTITY
)
1758 if (eap_user_get(sm
, sm
->identity
, sm
->identity_len
, 0) != 0) {
1759 wpa_printf(MSG_DEBUG
, "EAP: getDecision: user not "
1760 "found from database -> FAILURE");
1761 return DECISION_FAILURE
;
1763 if (id_req
&& sm
->user
&&
1764 sm
->user
->methods
[0].vendor
== EAP_VENDOR_IETF
&&
1765 sm
->user
->methods
[0].method
== EAP_TYPE_IDENTITY
) {
1766 wpa_printf(MSG_DEBUG
, "EAP: getDecision: stop "
1767 "identity request loop -> FAILURE");
1768 sm
->update_user
= TRUE
;
1769 return DECISION_FAILURE
;
1771 sm
->update_user
= FALSE
;
1773 sm
->start_reauth
= FALSE
;
1775 if (sm
->user
&& sm
->user_eap_method_index
< EAP_MAX_METHODS
&&
1776 (sm
->user
->methods
[sm
->user_eap_method_index
].vendor
!=
1778 sm
->user
->methods
[sm
->user_eap_method_index
].method
!=
1780 wpa_printf(MSG_DEBUG
, "EAP: getDecision: another method "
1781 "available -> CONTINUE");
1782 return DECISION_CONTINUE
;
1785 if (!sm
->identity
&& eap_get_erp_send_reauth_start(sm
) &&
1786 !sm
->initiate_reauth_start_sent
) {
1787 wpa_printf(MSG_DEBUG
,
1788 "EAP: getDecision: send EAP-Initiate/Re-auth-Start");
1789 return DECISION_INITIATE_REAUTH_START
;
1792 if (sm
->identity
== NULL
|| sm
->currentId
== -1) {
1793 wpa_printf(MSG_DEBUG
, "EAP: getDecision: no identity known "
1795 return DECISION_CONTINUE
;
1798 wpa_printf(MSG_DEBUG
, "EAP: getDecision: no more methods available -> "
1800 return DECISION_FAILURE
;
1804 static Boolean
eap_sm_Policy_doPickUp(struct eap_sm
*sm
, enum eap_type method
)
1806 return method
== EAP_TYPE_IDENTITY
? TRUE
: FALSE
;
1811 * eap_server_sm_step - Step EAP server state machine
1812 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1813 * Returns: 1 if EAP state was changed or 0 if not
1815 * This function advances EAP state machine to a new state to match with the
1816 * current variables. This should be called whenever variables used by the EAP
1817 * state machine have changed.
1819 int eap_server_sm_step(struct eap_sm
*sm
)
1823 sm
->changed
= FALSE
;
1827 } while (sm
->changed
);
1832 void eap_user_free(struct eap_user
*user
)
1836 bin_clear_free(user
->password
, user
->password_len
);
1837 user
->password
= NULL
;
1838 bin_clear_free(user
->salt
, user
->salt_len
);
1845 * eap_server_sm_init - Allocate and initialize EAP server state machine
1846 * @eapol_ctx: Context data to be used with eapol_cb calls
1847 * @eapol_cb: Pointer to EAPOL callback functions
1848 * @conf: EAP configuration
1849 * Returns: Pointer to the allocated EAP state machine or %NULL on failure
1851 * This function allocates and initializes an EAP state machine.
1853 struct eap_sm
* eap_server_sm_init(void *eapol_ctx
,
1854 const struct eapol_callbacks
*eapol_cb
,
1855 const struct eap_config
*conf
,
1856 const struct eap_session_data
*sess
)
1860 sm
= os_zalloc(sizeof(*sm
));
1863 sm
->eapol_ctx
= eapol_ctx
;
1864 sm
->eapol_cb
= eapol_cb
;
1865 sm
->MaxRetrans
= 5; /* RFC 3748: max 3-5 retransmissions suggested */
1867 if (sess
->assoc_wps_ie
)
1868 sm
->assoc_wps_ie
= wpabuf_dup(sess
->assoc_wps_ie
);
1869 if (sess
->assoc_p2p_ie
)
1870 sm
->assoc_p2p_ie
= wpabuf_dup(sess
->assoc_p2p_ie
);
1871 if (sess
->peer_addr
)
1872 os_memcpy(sm
->peer_addr
, sess
->peer_addr
, ETH_ALEN
);
1873 #ifdef CONFIG_TESTING_OPTIONS
1874 sm
->tls_test_flags
= sess
->tls_test_flags
;
1875 #endif /* CONFIG_TESTING_OPTIONS */
1877 wpa_printf(MSG_DEBUG
, "EAP: Server state machine created");
1884 * eap_server_sm_deinit - Deinitialize and free an EAP server state machine
1885 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1887 * This function deinitializes EAP state machine and frees all allocated
1890 void eap_server_sm_deinit(struct eap_sm
*sm
)
1894 wpa_printf(MSG_DEBUG
, "EAP: Server state machine removed");
1895 if (sm
->m
&& sm
->eap_method_priv
)
1896 sm
->m
->reset(sm
, sm
->eap_method_priv
);
1897 wpabuf_free(sm
->eap_if
.eapReqData
);
1898 bin_clear_free(sm
->eap_if
.eapKeyData
, sm
->eap_if
.eapKeyDataLen
);
1899 os_free(sm
->eap_if
.eapSessionId
);
1900 wpabuf_free(sm
->lastReqData
);
1901 wpabuf_free(sm
->eap_if
.eapRespData
);
1902 os_free(sm
->identity
);
1903 os_free(sm
->serial_num
);
1904 wpabuf_free(sm
->eap_if
.aaaEapReqData
);
1905 wpabuf_free(sm
->eap_if
.aaaEapRespData
);
1906 bin_clear_free(sm
->eap_if
.aaaEapKeyData
, sm
->eap_if
.aaaEapKeyDataLen
);
1907 eap_user_free(sm
->user
);
1908 wpabuf_free(sm
->assoc_wps_ie
);
1909 wpabuf_free(sm
->assoc_p2p_ie
);
1915 * eap_sm_notify_cached - Notify EAP state machine of cached PMK
1916 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1918 * This function is called when PMKSA caching is used to skip EAP
1921 void eap_sm_notify_cached(struct eap_sm
*sm
)
1926 sm
->EAP_state
= EAP_SUCCESS
;
1931 * eap_sm_pending_cb - EAP state machine callback for a pending EAP request
1932 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1934 * This function is called when data for a pending EAP-Request is received.
1936 void eap_sm_pending_cb(struct eap_sm
*sm
)
1940 wpa_printf(MSG_DEBUG
, "EAP: Callback for pending request received");
1941 if (sm
->method_pending
== METHOD_PENDING_WAIT
)
1942 sm
->method_pending
= METHOD_PENDING_CONT
;
1947 * eap_sm_method_pending - Query whether EAP method is waiting for pending data
1948 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1949 * Returns: 1 if method is waiting for pending data or 0 if not
1951 int eap_sm_method_pending(struct eap_sm
*sm
)
1955 return sm
->method_pending
== METHOD_PENDING_WAIT
;
1960 * eap_get_identity - Get the user identity (from EAP-Response/Identity)
1961 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1962 * @len: Buffer for returning identity length
1963 * Returns: Pointer to the user identity or %NULL if not available
1965 const u8
* eap_get_identity(struct eap_sm
*sm
, size_t *len
)
1967 *len
= sm
->identity_len
;
1968 return sm
->identity
;
1973 * eap_get_serial_num - Get the serial number of user certificate
1974 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1975 * Returns: Pointer to the serial number or %NULL if not available
1977 const char * eap_get_serial_num(struct eap_sm
*sm
)
1979 return sm
->serial_num
;
1984 * eap_get_method - Get the used EAP method
1985 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1986 * Returns: Pointer to the method name or %NULL if not available
1988 const char * eap_get_method(struct eap_sm
*sm
)
1997 * eap_get_imsi - Get IMSI of the user
1998 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
1999 * Returns: Pointer to IMSI or %NULL if not available
2001 const char * eap_get_imsi(struct eap_sm
*sm
)
2003 if (!sm
|| sm
->imsi
[0] == '\0')
2009 void eap_erp_update_identity(struct eap_sm
*sm
, const u8
*eap
, size_t len
)
2012 const struct eap_hdr
*hdr
;
2013 const u8
*pos
, *end
;
2014 struct erp_tlvs parse
;
2016 if (len
< sizeof(*hdr
) + 1)
2018 hdr
= (const struct eap_hdr
*) eap
;
2020 pos
= (const u8
*) (hdr
+ 1);
2021 if (hdr
->code
!= EAP_CODE_INITIATE
|| *pos
!= EAP_ERP_TYPE_REAUTH
)
2027 /* Skip Flags and SEQ */
2030 if (erp_parse_tlvs(pos
, end
, &parse
, 1) < 0 || !parse
.keyname
)
2032 wpa_hexdump_ascii(MSG_DEBUG
,
2033 "EAP: Update identity based on EAP-Initiate/Re-auth keyName-NAI",
2034 parse
.keyname
, parse
.keyname_len
);
2035 os_free(sm
->identity
);
2036 sm
->identity
= os_malloc(parse
.keyname_len
);
2038 os_memcpy(sm
->identity
, parse
.keyname
, parse
.keyname_len
);
2039 sm
->identity_len
= parse
.keyname_len
;
2041 sm
->identity_len
= 0;
2043 #endif /* CONFIG_ERP */
2048 * eap_get_interface - Get pointer to EAP-EAPOL interface data
2049 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
2050 * Returns: Pointer to the EAP-EAPOL interface data
2052 struct eap_eapol_interface
* eap_get_interface(struct eap_sm
*sm
)
2059 * eap_server_clear_identity - Clear EAP identity information
2060 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
2062 * This function can be used to clear the EAP identity information in the EAP
2063 * server context. This allows the EAP/Identity method to be used again after
2064 * EAPOL-Start or EAPOL-Logoff.
2066 void eap_server_clear_identity(struct eap_sm
*sm
)
2068 os_free(sm
->identity
);
2069 sm
->identity
= NULL
;
2073 #ifdef CONFIG_TESTING_OPTIONS
2074 void eap_server_mschap_rx_callback(struct eap_sm
*sm
, const char *source
,
2075 const u8
*username
, size_t username_len
,
2076 const u8
*challenge
, const u8
*response
)
2078 char hex_challenge
[30], hex_response
[90], user
[100];
2080 /* Print out Challenge and Response in format supported by asleap. */
2082 printf_encode(user
, sizeof(user
), username
, username_len
);
2085 wpa_snprintf_hex_sep(hex_challenge
, sizeof(hex_challenge
),
2086 challenge
, sizeof(challenge
), ':');
2087 wpa_snprintf_hex_sep(hex_response
, sizeof(hex_response
), response
, 24,
2089 wpa_printf(MSG_DEBUG
, "[%s/user=%s] asleap -C %s -R %s",
2090 source
, user
, hex_challenge
, hex_response
);
2092 #endif /* CONFIG_TESTING_OPTIONS */
2095 void eap_server_config_free(struct eap_config
*cfg
)
2099 os_free(cfg
->pac_opaque_encr_key
);
2100 os_free(cfg
->eap_fast_a_id
);
2101 os_free(cfg
->eap_fast_a_id_info
);
2102 os_free(cfg
->server_id
);