From 7eb157f1e92f2f2333a383bb2493b3cc7b468e56 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 18 Aug 2019 17:18:17 +0300 Subject: [PATCH] EAP: Increase the maximum number of message exchanges Allow 100 rounds of EAP messages if there is data being transmitted. Keep the old 50 round limit for cases where only short EAP messages are sent (i.e., the likely case of getting stuck in ACK loop). This allows larger EAP data (e.g., large certificates) to be exchanged without breaking the workaround for ACK loop interop issues. Signed-off-by: Jouni Malinen --- src/eap_peer/eap.c | 19 ++++++++++++++++++- src/eap_peer/eap_i.h | 1 + src/eap_server/eap_i.h | 1 + src/eap_server/eap_server.c | 19 ++++++++++++++++++- 4 files changed, 38 insertions(+), 2 deletions(-) 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) {