ERP: Add optional EAP-Initiate/Re-auth-Start transmission

hostapd can now be configured to transmit EAP-Initiate/Re-auth-Start
before EAP-Request/Identity to try to initiate ERP. This is disabled by
default and can be enabled with erp_send_reauth_start=1 and optional
erp_reauth_start_domain=<domain>.

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2014-11-29 20:33:09 +02:00
parent 19e2b3b6ba
commit 2a5156a66c
11 changed files with 169 additions and 23 deletions

View file

@ -85,6 +85,8 @@ struct eapol_callbacks {
int phase2, struct eap_user *user);
const char * (*get_eap_req_id_text)(void *ctx, size_t *len);
void (*log_msg)(void *ctx, const char *msg);
int (*get_erp_send_reauth_start)(void *ctx);
const char * (*get_erp_domain)(void *ctx);
};
struct eap_config {

View file

@ -116,7 +116,8 @@ struct eap_sm {
EAP_INITIALIZE_PASSTHROUGH, EAP_IDLE2, EAP_RETRANSMIT2,
EAP_RECEIVED2, EAP_DISCARD2, EAP_SEND_REQUEST2,
EAP_AAA_REQUEST, EAP_AAA_RESPONSE, EAP_AAA_IDLE,
EAP_TIMEOUT_FAILURE2, EAP_FAILURE2, EAP_SUCCESS2
EAP_TIMEOUT_FAILURE2, EAP_FAILURE2, EAP_SUCCESS2,
EAP_INITIATE_REAUTH_START
} EAP_state;
/* Constants */
@ -145,7 +146,7 @@ struct eap_sm {
Boolean ignore;
enum {
DECISION_SUCCESS, DECISION_FAILURE, DECISION_CONTINUE,
DECISION_PASSTHROUGH
DECISION_PASSTHROUGH, DECISION_INITIATE_REAUTH_START
} decision;
/* Miscellaneous variables */
@ -205,6 +206,9 @@ struct eap_sm {
const u8 *server_id;
size_t server_id_len;
Boolean initiate_reauth_start_sent;
Boolean try_initiate_reauth;
#ifdef CONFIG_TESTING_OPTIONS
u32 tls_test_flags;
#endif /* CONFIG_TESTING_OPTIONS */

View file

@ -1,6 +1,6 @@
/*
* hostapd / EAP Full Authenticator state machine (RFC 4137)
* Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
* Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -44,6 +44,52 @@ static int eap_sm_Policy_getDecision(struct eap_sm *sm);
static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method);
static int eap_get_erp_send_reauth_start(struct eap_sm *sm)
{
if (sm->eapol_cb->get_erp_send_reauth_start)
return sm->eapol_cb->get_erp_send_reauth_start(sm->eapol_ctx);
return 0;
}
static const char * eap_get_erp_domain(struct eap_sm *sm)
{
if (sm->eapol_cb->get_erp_domain)
return sm->eapol_cb->get_erp_domain(sm->eapol_ctx);
return NULL;
}
static struct wpabuf * eap_sm_buildInitiateReauthStart(struct eap_sm *sm,
u8 id)
{
const char *domain;
size_t plen = 1;
struct wpabuf *msg;
size_t domain_len = 0;
domain = eap_get_erp_domain(sm);
if (domain) {
domain_len = os_strlen(domain);
plen += 2 + domain_len;;
}
msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_ERP_TYPE_REAUTH_START, plen,
EAP_CODE_INITIATE, id);
if (msg == NULL)
return NULL;
wpabuf_put_u8(msg, 0); /* Reserved */
if (domain) {
/* Domain name TLV */
wpabuf_put_u8(msg, EAP_ERP_TLV_DOMAIN_NAME);
wpabuf_put_u8(msg, domain_len);
wpabuf_put_data(msg, domain, domain_len);
}
return msg;
}
static int eap_copy_buf(struct wpabuf **dst, const struct wpabuf *src)
{
if (src == NULL)
@ -164,6 +210,8 @@ SM_STATE(EAP, INITIALIZE)
eap_server_clear_identity(sm);
}
sm->initiate_reauth_start_sent = FALSE;
sm->try_initiate_reauth = FALSE;
sm->currentId = -1;
sm->eap_if.eapSuccess = FALSE;
sm->eap_if.eapFail = FALSE;
@ -382,6 +430,7 @@ SM_STATE(EAP, PROPOSE_METHOD)
SM_ENTRY(EAP, PROPOSE_METHOD);
sm->try_initiate_reauth = FALSE;
try_another_method:
type = eap_sm_Policy_getNextMethod(sm, &vendor);
if (vendor == EAP_VENDOR_IETF)
@ -505,6 +554,25 @@ SM_STATE(EAP, SUCCESS)
}
SM_STATE(EAP, INITIATE_REAUTH_START)
{
SM_ENTRY(EAP, INITIATE_REAUTH_START);
sm->initiate_reauth_start_sent = TRUE;
sm->try_initiate_reauth = TRUE;
sm->currentId = eap_sm_nextId(sm, sm->currentId);
wpa_printf(MSG_DEBUG,
"EAP: building EAP-Initiate-Re-auth-Start: Identifier %d",
sm->currentId);
sm->lastId = sm->currentId;
wpabuf_free(sm->eap_if.eapReqData);
sm->eap_if.eapReqData = eap_sm_buildInitiateReauthStart(sm,
sm->currentId);
wpabuf_free(sm->lastReqData);
sm->lastReqData = NULL;
}
SM_STATE(EAP, INITIALIZE_PASSTHROUGH)
{
SM_ENTRY(EAP, INITIALIZE_PASSTHROUGH);
@ -704,9 +772,14 @@ SM_STEP(EAP)
SM_ENTER(EAP, INITIALIZE);
break;
case EAP_IDLE:
if (sm->eap_if.retransWhile == 0)
SM_ENTER(EAP, RETRANSMIT);
else if (sm->eap_if.eapResp)
if (sm->eap_if.retransWhile == 0) {
if (sm->try_initiate_reauth) {
sm->try_initiate_reauth = FALSE;
SM_ENTER(EAP, SELECT_ACTION);
} else {
SM_ENTER(EAP, RETRANSMIT);
}
} else if (sm->eap_if.eapResp)
SM_ENTER(EAP, RECEIVED);
break;
case EAP_RETRANSMIT:
@ -817,9 +890,14 @@ SM_STEP(EAP)
SM_ENTER(EAP, SUCCESS);
else if (sm->decision == DECISION_PASSTHROUGH)
SM_ENTER(EAP, INITIALIZE_PASSTHROUGH);
else if (sm->decision == DECISION_INITIATE_REAUTH_START)
SM_ENTER(EAP, INITIATE_REAUTH_START);
else
SM_ENTER(EAP, PROPOSE_METHOD);
break;
case EAP_INITIATE_REAUTH_START:
SM_ENTER(EAP, SEND_REQUEST);
break;
case EAP_TIMEOUT_FAILURE:
break;
case EAP_FAILURE:
@ -889,6 +967,12 @@ static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
{
int rto, i;
if (sm->try_initiate_reauth) {
wpa_printf(MSG_DEBUG,
"EAP: retransmit timeout 1 second for EAP-Initiate-Re-auth-Start");
return 1;
}
if (methodTimeout) {
/*
* EAP method (either internal or through AAA server, provided
@ -1229,6 +1313,13 @@ static int eap_sm_Policy_getDecision(struct eap_sm *sm)
return DECISION_CONTINUE;
}
if (!sm->identity && eap_get_erp_send_reauth_start(sm) &&
!sm->initiate_reauth_start_sent) {
wpa_printf(MSG_DEBUG,
"EAP: getDecision: send EAP-Initiate/Re-auth-Start");
return DECISION_INITIATE_REAUTH_START;
}
if (sm->identity == NULL || sm->currentId == -1) {
wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known "
"yet -> CONTINUE");