diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c index d71d00cad..ada3c6db6 100644 --- a/src/eap_peer/eap.c +++ b/src/eap_peer/eap.c @@ -32,7 +32,8 @@ #define STATE_MACHINE_DATA struct eap_sm #define STATE_MACHINE_DEBUG_PREFIX "EAP" -#define EAP_MAX_AUTH_ROUNDS 50 +#define EAP_MAX_AUTH_ROUNDS 100 +#define EAP_MAX_AUTH_ROUNDS_SHORT 50 #define EAP_CLIENT_TIMEOUT_DEFAULT 60 @@ -260,6 +261,7 @@ SM_STATE(EAP, INITIALIZE) */ sm->ignore = 0; sm->num_rounds = 0; + sm->num_rounds_short = 0; sm->prev_failure = 0; sm->expected_failure = 0; sm->reauthInit = FALSE; @@ -276,6 +278,7 @@ SM_STATE(EAP, DISABLED) { SM_ENTRY(EAP, DISABLED); sm->num_rounds = 0; + sm->num_rounds_short = 0; /* * RFC 4137 does not describe clearing of idleWhile here, but doing so * allows the timer tick to be stopped more quickly when EAP is not in @@ -309,6 +312,10 @@ SM_STATE(EAP, RECEIVED) /* parse rxReq, rxSuccess, rxFailure, reqId, reqMethod */ eap_sm_parseEapReq(sm, eapReqData); sm->num_rounds++; + if (!eapReqData || wpabuf_len(eapReqData) < 20) + sm->num_rounds_short++; + else + sm->num_rounds_short = 0; } @@ -950,6 +957,8 @@ SM_STATE(EAP, SEND_RESPONSE) SM_ENTRY(EAP, SEND_RESPONSE); wpabuf_free(sm->lastRespData); if (sm->eapRespData) { + if (wpabuf_len(sm->eapRespData) >= 20) + sm->num_rounds_short = 0; if (sm->workaround) os_memcpy(sm->last_sha1, sm->req_sha1, 20); sm->lastId = sm->reqId; @@ -1342,6 +1351,14 @@ SM_STEP(EAP) sm->num_rounds++; SM_ENTER_GLOBAL(EAP, FAILURE); } + } else if (sm->num_rounds_short > EAP_MAX_AUTH_ROUNDS_SHORT) { + if (sm->num_rounds_short == EAP_MAX_AUTH_ROUNDS_SHORT + 1) { + wpa_msg(sm->msg_ctx, MSG_INFO, + "EAP: more than %d authentication rounds (short) - abort", + EAP_MAX_AUTH_ROUNDS_SHORT); + sm->num_rounds_short++; + SM_ENTER_GLOBAL(EAP, FAILURE); + } } else { /* Local transitions */ eap_peer_sm_step_local(sm); diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h index 629bc336e..7c633236c 100644 --- a/src/eap_peer/eap_i.h +++ b/src/eap_peer/eap_i.h @@ -366,6 +366,7 @@ struct eap_sm { u8 *peer_challenge, *auth_challenge; int num_rounds; + int num_rounds_short; int force_disabled; struct wps_context *wps; diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h index cbdad5f19..c56011639 100644 --- a/src/eap_server/eap_i.h +++ b/src/eap_server/eap_i.h @@ -172,6 +172,7 @@ struct eap_sm { Boolean update_user; int num_rounds; + int num_rounds_short; enum { METHOD_PENDING_NONE, METHOD_PENDING_WAIT, METHOD_PENDING_CONT } method_pending; diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c index 4c6ba6d34..677fc4e2e 100644 --- a/src/eap_server/eap_server.c +++ b/src/eap_server/eap_server.c @@ -23,7 +23,8 @@ #define STATE_MACHINE_DATA struct eap_sm #define STATE_MACHINE_DEBUG_PREFIX "EAP" -#define EAP_MAX_AUTH_ROUNDS 50 +#define EAP_MAX_AUTH_ROUNDS 100 +#define EAP_MAX_AUTH_ROUNDS_SHORT 50 /* EAP state machines are described in RFC 4137 */ @@ -216,6 +217,7 @@ SM_STATE(EAP, DISABLED) { SM_ENTRY(EAP, DISABLED); sm->num_rounds = 0; + sm->num_rounds_short = 0; } @@ -266,6 +268,7 @@ SM_STATE(EAP, INITIALIZE) } } sm->num_rounds = 0; + sm->num_rounds_short = 0; sm->method_pending = METHOD_PENDING_NONE; wpa_msg(sm->cfg->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED @@ -337,6 +340,10 @@ SM_STATE(EAP, RECEIVED) /* parse rxResp, respId, respMethod */ eap_sm_parseEapResp(sm, sm->eap_if.eapRespData); sm->num_rounds++; + if (!sm->eap_if.eapRespData || wpabuf_len(sm->eap_if.eapRespData) < 20) + sm->num_rounds_short++; + else + sm->num_rounds_short = 0; } @@ -354,6 +361,8 @@ SM_STATE(EAP, SEND_REQUEST) sm->retransCount = 0; if (sm->eap_if.eapReqData) { + if (wpabuf_len(sm->eap_if.eapReqData) >= 20) + sm->num_rounds_short = 0; if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0) { sm->eap_if.eapResp = FALSE; @@ -1171,6 +1180,14 @@ SM_STEP(EAP) sm->num_rounds++; SM_ENTER_GLOBAL(EAP, FAILURE); } + } else if (sm->num_rounds_short > EAP_MAX_AUTH_ROUNDS_SHORT) { + if (sm->num_rounds_short == EAP_MAX_AUTH_ROUNDS_SHORT + 1) { + wpa_printf(MSG_DEBUG, + "EAP: more than %d authentication rounds (short) - abort", + EAP_MAX_AUTH_ROUNDS_SHORT); + sm->num_rounds_short++; + SM_ENTER_GLOBAL(EAP, FAILURE); + } } else switch (sm->EAP_state) { case EAP_INITIALIZE: if (sm->cfg->backend_auth) {