(term - bss->eap_req_id_text) - 1);
bss->eap_req_id_text_len--;
}
+ } else if (os_strcmp(buf, "erp_send_reauth_start") == 0) {
+ bss->erp_send_reauth_start = atoi(pos);
+ } else if (os_strcmp(buf, "erp_domain") == 0) {
+ os_free(bss->erp_domain);
+ bss->erp_domain = os_strdup(pos);
} else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
bss->default_wep_key_len = atoi(pos);
if (bss->default_wep_key_len > 13) {
# is only used by one station.
#use_pae_group_addr=1
+# EAP Re-authentication Protocol (ERP) authenticator (RFC 6696)
+#
+# Whether to initiate EAP authentication with EAP-Initiate/Re-auth-Start before
+# EAP-Identity/Request
+#erp_send_reauth_start=1
+#
+# Domain name for EAP-Initiate/Re-auth-Start. Omitted from the message if not
+# set (no local ER server).
+#erp_domain=example.com
+
##### Integrated EAP server ###################################################
# Optionally, hostapd can be configured to use an integrated EAP server
os_free(conf->eap_user_sqlite);
os_free(conf->eap_req_id_text);
+ os_free(conf->erp_domain);
os_free(conf->accept_mac);
os_free(conf->deny_mac);
os_free(conf->nas_identifier);
int wep_rekeying_period;
int broadcast_key_idx_min, broadcast_key_idx_max;
int eap_reauth_period;
+ int erp_send_reauth_start;
+ char *erp_domain;
int ieee802_11f; /* use IEEE 802.11f (IAPP) */
char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast
conf.eap_sim_db_priv = hapd->eap_sim_db_priv;
conf.eap_req_id_text = hapd->conf->eap_req_id_text;
conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len;
+ conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start;
+ conf.erp_domain = hapd->conf->erp_domain;
conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key;
conf.eap_fast_a_id = hapd->conf->eap_fast_a_id;
conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len;
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 {
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 */
Boolean ignore;
enum {
DECISION_SUCCESS, DECISION_FAILURE, DECISION_CONTINUE,
- DECISION_PASSTHROUGH
+ DECISION_PASSTHROUGH, DECISION_INITIATE_REAUTH_START
} decision;
/* Miscellaneous variables */
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 */
/*
* 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.
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)
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;
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)
}
+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);
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:
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:
{
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
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");
/*
* IEEE 802.1X-2004 Authenticator - EAPOL state machine
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
static void eapol_sm_step_run(struct eapol_state_machine *sm);
static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx);
static void eapol_auth_initialize(struct eapol_state_machine *sm);
+static void eapol_auth_conf_free(struct eapol_auth_config *conf);
static void eapol_auth_logger(struct eapol_authenticator *eapol,
}
+static int eapol_sm_get_erp_send_reauth_start(void *ctx)
+{
+ struct eapol_state_machine *sm = ctx;
+ return sm->eapol->conf.erp_send_reauth_start;
+}
+
+
+static const char * eapol_sm_get_erp_domain(void *ctx)
+{
+ struct eapol_state_machine *sm = ctx;
+ return sm->eapol->conf.erp_domain;
+}
+
+
static struct eapol_callbacks eapol_cb =
{
eapol_sm_get_eap_user,
eapol_sm_get_eap_req_id_text,
- NULL
+ NULL,
+ eapol_sm_get_erp_send_reauth_start,
+ eapol_sm_get_erp_domain,
};
}
if (src->pac_opaque_encr_key) {
dst->pac_opaque_encr_key = os_malloc(16);
- if (dst->pac_opaque_encr_key == NULL) {
- os_free(dst->eap_req_id_text);
- return -1;
- }
+ if (dst->pac_opaque_encr_key == NULL)
+ goto fail;
os_memcpy(dst->pac_opaque_encr_key, src->pac_opaque_encr_key,
16);
} else
dst->pac_opaque_encr_key = NULL;
if (src->eap_fast_a_id) {
dst->eap_fast_a_id = os_malloc(src->eap_fast_a_id_len);
- if (dst->eap_fast_a_id == NULL) {
- os_free(dst->eap_req_id_text);
- os_free(dst->pac_opaque_encr_key);
- return -1;
- }
+ if (dst->eap_fast_a_id == NULL)
+ goto fail;
os_memcpy(dst->eap_fast_a_id, src->eap_fast_a_id,
src->eap_fast_a_id_len);
dst->eap_fast_a_id_len = src->eap_fast_a_id_len;
dst->eap_fast_a_id = NULL;
if (src->eap_fast_a_id_info) {
dst->eap_fast_a_id_info = os_strdup(src->eap_fast_a_id_info);
- if (dst->eap_fast_a_id_info == NULL) {
- os_free(dst->eap_req_id_text);
- os_free(dst->pac_opaque_encr_key);
- os_free(dst->eap_fast_a_id);
- return -1;
- }
+ if (dst->eap_fast_a_id_info == NULL)
+ goto fail;
} else
dst->eap_fast_a_id_info = NULL;
dst->eap_fast_prov = src->eap_fast_prov;
dst->tnc = src->tnc;
dst->wps = src->wps;
dst->fragment_size = src->fragment_size;
+
+ os_free(dst->erp_domain);
+ if (src->erp_domain) {
+ dst->erp_domain = os_strdup(src->erp_domain);
+ if (dst->erp_domain == NULL)
+ goto fail;
+ } else {
+ dst->erp_domain = NULL;
+ }
+ dst->erp_send_reauth_start = src->erp_send_reauth_start;
+
return 0;
+
+fail:
+ eapol_auth_conf_free(dst);
+ return -1;
}
conf->eap_fast_a_id = NULL;
os_free(conf->eap_fast_a_id_info);
conf->eap_fast_a_id_info = NULL;
+ os_free(conf->erp_domain);
+ conf->erp_domain = NULL;
}
void *eap_sim_db_priv;
char *eap_req_id_text; /* a copy of this will be allocated */
size_t eap_req_id_text_len;
+ int erp_send_reauth_start;
+ char *erp_domain; /* a copy of this will be allocated */
u8 *pac_opaque_encr_key;
u8 *eap_fast_a_id;
size_t eap_fast_a_id_len;
.get_eap_user = radius_server_get_eap_user,
.get_eap_req_id_text = radius_server_get_eap_req_id_text,
.log_msg = radius_server_log_msg,
+ NULL,
+ NULL,
};