/*
* EAPOL supplicant state machines
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
#include "crypto/md5.h"
#include "common/eapol_common.h"
#include "eap_peer/eap.h"
+#include "eap_peer/eap_proxy.h"
#include "eapol_supp_sm.h"
#define STATE_MACHINE_DATA struct eapol_sm
struct wpabuf *eapReqData; /* for EAP */
Boolean altAccept; /* for EAP */
Boolean altReject; /* for EAP */
+ Boolean eapTriggerStart;
Boolean replay_counter_valid;
u8 last_replay_counter[16];
struct eapol_config conf;
Boolean cached_pmk;
Boolean unicast_key_received, broadcast_key_received;
-};
+ Boolean force_authorized_update;
-#define IEEE8021X_REPLAY_COUNTER_LEN 8
-#define IEEE8021X_KEY_SIGN_LEN 16
-#define IEEE8021X_KEY_IV_LEN 16
-
-#define IEEE8021X_KEY_INDEX_FLAG 0x80
-#define IEEE8021X_KEY_INDEX_MASK 0x03
-
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-struct ieee802_1x_eapol_key {
- u8 type;
- /* Note: key_length is unaligned */
- u8 key_length[2];
- /* does not repeat within the life of the keying material used to
- * encrypt the Key field; 64-bit NTP timestamp MAY be used here */
- u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN];
- u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */
- u8 key_index; /* key flag in the most significant bit:
- * 0 = broadcast (default key),
- * 1 = unicast (key mapping key); key index is in the
- * 7 least significant bits */
- /* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as
- * the key */
- u8 key_signature[IEEE8021X_KEY_SIGN_LEN];
-
- /* followed by key: if packet body length = 44 + key length, then the
- * key field (of key_length bytes) contains the key in encrypted form;
- * if packet body length = 44, key field is absent and key_length
- * represents the number of least significant octets from
- * MS-MPPE-Send-Key attribute to be used as the keying material;
- * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
-} STRUCT_PACKED;
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
+#ifdef CONFIG_EAP_PROXY
+ Boolean use_eap_proxy;
+ struct eap_proxy_sm *eap_proxy;
+#endif /* CONFIG_EAP_PROXY */
+};
static void eapol_sm_txLogoff(struct eapol_sm *sm);
SM_ENTRY(SUPP_PAE, LOGOFF);
eapol_sm_txLogoff(sm);
sm->logoffSent = TRUE;
- sm->suppPortStatus = Unauthorized;
eapol_sm_set_port_unauthorized(sm);
}
SM_ENTRY(SUPP_PAE, DISCONNECTED);
sm->sPortMode = Auto;
sm->startCount = 0;
+ sm->eapTriggerStart = FALSE;
sm->logoffSent = FALSE;
- sm->suppPortStatus = Unauthorized;
eapol_sm_set_port_unauthorized(sm);
sm->suppAbort = TRUE;
sm->unicast_key_received = FALSE;
sm->broadcast_key_received = FALSE;
+
+ /*
+ * IEEE Std 802.1X-2004 does not clear heldWhile here, but doing so
+ * allows the timer tick to be stopped more quickly when the port is
+ * not enabled. Since this variable is used only within HELD state,
+ * clearing it on initialization does not change actual state machine
+ * behavior.
+ */
+ sm->heldWhile = 0;
}
SM_STATE(SUPP_PAE, CONNECTING)
{
- int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING;
+ int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING ||
+ sm->SUPP_PAE_state == SUPP_PAE_HELD;
SM_ENTRY(SUPP_PAE, CONNECTING);
+
+ if (sm->eapTriggerStart)
+ send_start = 1;
+ sm->eapTriggerStart = FALSE;
+
if (send_start) {
sm->startWhen = sm->startPeriod;
sm->startCount++;
* delay authentication. Use a short timeout to send the first
* EAPOL-Start if Authenticator does not start authentication.
*/
-#ifdef CONFIG_WPS
- /* Reduce latency on starting WPS negotiation. */
- sm->startWhen = 1;
-#else /* CONFIG_WPS */
- sm->startWhen = 3;
-#endif /* CONFIG_WPS */
+ if (sm->conf.wps && !(sm->conf.wps & EAPOL_PEER_IS_WPS20_AP)) {
+ /* Reduce latency on starting WPS negotiation. */
+ wpa_printf(MSG_DEBUG,
+ "EAPOL: Using shorter startWhen for WPS");
+ sm->startWhen = 1;
+ } else {
+ sm->startWhen = 2;
+ }
}
eapol_enable_timer_tick(sm);
sm->eapolEap = FALSE;
SM_ENTRY(SUPP_PAE, HELD);
sm->heldWhile = sm->heldPeriod;
eapol_enable_timer_tick(sm);
- sm->suppPortStatus = Unauthorized;
eapol_sm_set_port_unauthorized(sm);
sm->cb_status = EAPOL_CB_FAILURE;
}
SM_STATE(SUPP_PAE, AUTHENTICATED)
{
SM_ENTRY(SUPP_PAE, AUTHENTICATED);
- sm->suppPortStatus = Authorized;
eapol_sm_set_port_authorized(sm);
sm->cb_status = EAPOL_CB_SUCCESS;
}
{
SM_ENTRY(SUPP_PAE, RESTART);
sm->eapRestart = TRUE;
+ if (sm->altAccept) {
+ /*
+ * Prevent EAP peer state machine from failing due to prior
+ * external EAP success notification (altSuccess=TRUE in the
+ * IDLE state could result in a transition to the FAILURE state.
+ */
+ wpa_printf(MSG_DEBUG, "EAPOL: Clearing prior altAccept TRUE");
+ sm->eapSuccess = FALSE;
+ sm->altAccept = FALSE;
+ }
}
SM_STATE(SUPP_PAE, S_FORCE_AUTH)
{
SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
- sm->suppPortStatus = Authorized;
eapol_sm_set_port_authorized(sm);
sm->sPortMode = ForceAuthorized;
}
SM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
{
SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
- sm->suppPortStatus = Unauthorized;
eapol_sm_set_port_unauthorized(sm);
sm->sPortMode = ForceUnauthorized;
eapol_sm_txLogoff(sm);
SM_ENTER(SUPP_PAE, HELD);
else if (sm->suppTimeout)
SM_ENTER(SUPP_PAE, CONNECTING);
+ else if (sm->eapTriggerStart)
+ SM_ENTER(SUPP_PAE, CONNECTING);
break;
case SUPP_PAE_HELD:
if (sm->heldWhile == 0)
sm->keyRun = TRUE;
sm->suppSuccess = TRUE;
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy) {
+ if (eap_proxy_key_available(sm->eap_proxy)) {
+ /* New key received - clear IEEE 802.1X EAPOL-Key replay
+ * counter */
+ sm->replay_counter_valid = FALSE;
+ }
+ return;
+ }
+#endif /* CONFIG_EAP_PROXY */
+
if (eap_key_available(sm->eap)) {
/* New key received - clear IEEE 802.1X EAPOL-Key replay
* counter */
SM_ENTRY(SUPP_BE, INITIALIZE);
eapol_sm_abortSupp(sm);
sm->suppAbort = FALSE;
+
+ /*
+ * IEEE Std 802.1X-2004 does not clear authWhile here, but doing so
+ * allows the timer tick to be stopped more quickly when the port is
+ * not enabled. Since this variable is used only within RECEIVE state,
+ * clearing it on initialization does not change actual state machine
+ * behavior.
+ */
+ sm->authWhile = 0;
}
* IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
* and SUCCESS based on eapFail and eapSuccess, respectively.
* However, IEEE Std 802.1X-2004 is also specifying that
- * eapNoResp should be set in conjuction with eapSuccess and
+ * eapNoResp should be set in conjunction with eapSuccess and
* eapFail which would mean that more than one of the
* transitions here would be activated at the same time.
* Skipping RESPONSE and/or RECEIVE states in these cases can
static void eapol_sm_processKey(struct eapol_sm *sm)
{
+#ifndef CONFIG_FIPS
struct ieee802_1x_hdr *hdr;
struct ieee802_1x_eapol_key *key;
struct eap_key_data keydata;
u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
+#ifndef CONFIG_NO_RC4
u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
+#endif /* CONFIG_NO_RC4 */
int key_len, res, sign_key_len, encr_key_len;
u16 rx_key_length;
+ size_t plen;
wpa_printf(MSG_DEBUG, "EAPOL: processKey");
if (sm->last_rx_key == NULL)
return;
}
+ if (sm->last_rx_key_len < sizeof(*hdr) + sizeof(*key))
+ return;
hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
key = (struct ieee802_1x_eapol_key *) (hdr + 1);
- if (sizeof(*hdr) + be_to_host16(hdr->length) > sm->last_rx_key_len) {
+ plen = be_to_host16(hdr->length);
+ if (sizeof(*hdr) + plen > sm->last_rx_key_len || plen < sizeof(*key)) {
wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
return;
}
hmac_md5(keydata.sign_key, sign_key_len,
sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
key->key_signature);
- if (os_memcmp(orig_key_sign, key->key_signature,
- IEEE8021X_KEY_SIGN_LEN) != 0) {
+ if (os_memcmp_const(orig_key_sign, key->key_signature,
+ IEEE8021X_KEY_SIGN_LEN) != 0) {
wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
"EAPOL-Key packet");
os_memcpy(key->key_signature, orig_key_sign,
}
wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
- key_len = be_to_host16(hdr->length) - sizeof(*key);
+ key_len = plen - sizeof(*key);
if (key_len > 32 || rx_key_length > 32) {
wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
key_len ? key_len : rx_key_length);
return;
}
if (key_len == rx_key_length) {
+#ifdef CONFIG_NO_RC4
+ if (encr_key_len) {
+ /* otherwise unused */
+ }
+ wpa_printf(MSG_ERROR, "EAPOL: RC4 not supported in the build");
+ return;
+#else /* CONFIG_NO_RC4 */
os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
encr_key_len);
datakey, key_len);
wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
datakey, key_len);
+#endif /* CONFIG_NO_RC4 */
} else if (key_len == 0) {
/*
* IEEE 802.1X-2004 specifies that least significant Key Length
sm->ctx->eapol_done_cb(sm->ctx->ctx);
}
}
+#endif /* CONFIG_FIPS */
}
struct wpabuf *resp;
wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
+
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy) {
+ /* Get EAP Response from EAP Proxy */
+ resp = eap_proxy_get_eapRespData(sm->eap_proxy);
+ if (resp == NULL) {
+ wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP Proxy "
+ "response data not available");
+ return;
+ }
+ } else
+#endif /* CONFIG_EAP_PROXY */
+
resp = eap_get_eapRespData(sm->eap);
if (resp == NULL) {
wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
static void eapol_sm_set_port_authorized(struct eapol_sm *sm)
{
- if (sm->ctx->port_cb)
+ int cb;
+
+ cb = sm->suppPortStatus != Authorized || sm->force_authorized_update;
+ sm->force_authorized_update = FALSE;
+ sm->suppPortStatus = Authorized;
+ if (cb && sm->ctx->port_cb)
sm->ctx->port_cb(sm->ctx->ctx, 1);
}
static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm)
{
- if (sm->ctx->port_cb)
+ int cb;
+
+ cb = sm->suppPortStatus != Unauthorized || sm->force_authorized_update;
+ sm->force_authorized_update = FALSE;
+ sm->suppPortStatus = Unauthorized;
+ if (cb && sm->ctx->port_cb)
sm->ctx->port_cb(sm->ctx->ctx, 0);
}
SM_STEP_RUN(SUPP_PAE);
SM_STEP_RUN(KEY_RX);
SM_STEP_RUN(SUPP_BE);
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy) {
+ /* Drive the EAP proxy state machine */
+ if (eap_proxy_sm_step(sm->eap_proxy, sm->eap))
+ sm->changed = TRUE;
+ } else
+#endif /* CONFIG_EAP_PROXY */
if (eap_peer_sm_step(sm->eap))
sm->changed = TRUE;
if (!sm->changed)
}
if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
- int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0;
+ enum eapol_supp_result result;
+ if (sm->cb_status == EAPOL_CB_SUCCESS)
+ result = EAPOL_SUPP_RESULT_SUCCESS;
+ else if (eap_peer_was_failure_expected(sm->eap))
+ result = EAPOL_SUPP_RESULT_EXPECTED_FAILURE;
+ else
+ result = EAPOL_SUPP_RESULT_FAILURE;
sm->cb_status = EAPOL_CB_IN_PROGRESS;
- sm->ctx->cb(sm, success, sm->ctx->cb_ctx);
+ sm->ctx->cb(sm, result, sm->ctx->cb_ctx);
}
}
}
+/**
+ * eapol_sm_get_method_name - Get EAPOL method name
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * Returns: Static string containing name of current eap method or NULL
+ */
+const char * eapol_sm_get_method_name(struct eapol_sm *sm)
+{
+ if (sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED ||
+ sm->suppPortStatus != Authorized)
+ return NULL;
+
+ return eap_sm_get_method_name(sm->eap);
+}
+
+
#ifdef CONFIG_CTRL_IFACE
/**
* eapol_sm_get_status - Get EAPOL state machine status
"suppPortStatus=%s\n",
eapol_supp_pae_state(sm->SUPP_PAE_state),
eapol_port_status(sm->suppPortStatus));
- if (len < 0 || (size_t) len >= buflen)
+ if (os_snprintf_error(buflen, len))
return 0;
if (verbose) {
sm->maxStart,
eapol_port_control(sm->portControl),
eapol_supp_be_state(sm->SUPP_BE_state));
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
}
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy)
+ len += eap_proxy_sm_get_status(sm->eap_proxy,
+ buf + len, buflen - len,
+ verbose);
+ else
+#endif /* CONFIG_EAP_PROXY */
len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
return len;
"Authorized" : "Unauthorized",
sm->SUPP_BE_state);
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return 0;
len = ret;
sm->dot1xSuppLastEapolFrameVersion,
MAC2STR(sm->dot1xSuppLastEapolFrameSource));
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
return 0;
}
#ifdef CONFIG_WPS
- if (sm->conf.workaround &&
+ if (sm->conf.wps && sm->conf.workaround &&
plen < len - sizeof(*hdr) &&
hdr->type == IEEE802_1X_TYPE_EAP_PACKET &&
len - sizeof(*hdr) > sizeof(struct eap_hdr)) {
switch (hdr->type) {
case IEEE802_1X_TYPE_EAP_PACKET:
+ if (sm->conf.workaround) {
+ /*
+ * An AP has been reported to send out EAP message with
+ * undocumented code 10 at some point near the
+ * completion of EAP authentication. This can result in
+ * issues with the unexpected EAP message triggering
+ * restart of EAPOL authentication. Avoid this by
+ * skipping the message without advancing the state
+ * machine.
+ */
+ const struct eap_hdr *ehdr =
+ (const struct eap_hdr *) (hdr + 1);
+ if (plen >= sizeof(*ehdr) && ehdr->code == 10) {
+ wpa_printf(MSG_DEBUG, "EAPOL: Ignore EAP packet with unknown code 10");
+ break;
+ }
+ }
+
if (sm->cached_pmk) {
/* Trying to use PMKSA caching, but Authenticator did
* not seem to have a matching entry. Need to restart
wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
"frame");
sm->eapolEap = TRUE;
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy) {
+ eap_proxy_packet_update(
+ sm->eap_proxy,
+ wpabuf_mhead_u8(sm->eapReqData),
+ wpabuf_len(sm->eapReqData));
+ wpa_printf(MSG_DEBUG, "EAPOL: eap_proxy "
+ "EAP Req updated");
+ }
+#endif /* CONFIG_EAP_PROXY */
eapol_sm_step(sm);
}
break;
eapol_sm_step(sm);
}
break;
+#ifdef CONFIG_MACSEC
+ case IEEE802_1X_TYPE_EAPOL_MKA:
+ wpa_printf(MSG_EXCESSIVE,
+ "EAPOL type %d will be handled by MKA",
+ hdr->type);
+ break;
+#endif /* CONFIG_MACSEC */
default:
wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
hdr->type);
return;
wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
"portEnabled=%d", enabled);
+ if (sm->portEnabled != enabled)
+ sm->force_authorized_update = TRUE;
sm->portEnabled = enabled;
eapol_sm_step(sm);
}
return;
sm->config = config;
+#ifdef CONFIG_EAP_PROXY
+ sm->use_eap_proxy = eap_proxy_notify_config(sm->eap_proxy, config) > 0;
+#endif /* CONFIG_EAP_PROXY */
if (conf == NULL)
return;
sm->conf.required_keys = conf->required_keys;
sm->conf.fast_reauth = conf->fast_reauth;
sm->conf.workaround = conf->workaround;
+ sm->conf.wps = conf->wps;
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy) {
+ /* Using EAP Proxy, so skip EAP state machine update */
+ return;
+ }
+#endif /* CONFIG_EAP_PROXY */
if (sm->eap) {
eap_set_fast_reauth(sm->eap, conf->fast_reauth);
eap_set_workaround(sm->eap, conf->workaround);
eap_set_force_disabled(sm->eap, conf->eap_disabled);
+ eap_set_external_sim(sm->eap, conf->external_sim);
}
}
const u8 *eap_key;
size_t eap_len;
+#ifdef CONFIG_EAP_PROXY
+ if (sm && sm->use_eap_proxy) {
+ /* Get key from EAP proxy */
+ if (sm == NULL || !eap_proxy_key_available(sm->eap_proxy)) {
+ wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
+ return -1;
+ }
+ eap_key = eap_proxy_get_eapKeyData(sm->eap_proxy, &eap_len);
+ if (eap_key == NULL) {
+ wpa_printf(MSG_DEBUG, "EAPOL: Failed to get "
+ "eapKeyData");
+ return -1;
+ }
+ goto key_fetched;
+ }
+#endif /* CONFIG_EAP_PROXY */
if (sm == NULL || !eap_key_available(sm->eap)) {
wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
return -1;
wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData");
return -1;
}
+#ifdef CONFIG_EAP_PROXY
+key_fetched:
+#endif /* CONFIG_EAP_PROXY */
if (len > eap_len) {
wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not "
"available (len=%lu)",
/**
+ * eapol_sm_get_session_id - Get EAP Session-Id
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @len: Pointer to variable that will be set to number of bytes in the session
+ * Returns: Pointer to the EAP Session-Id or %NULL on failure
+ *
+ * The Session-Id is available only after a successful authentication.
+ */
+const u8 * eapol_sm_get_session_id(struct eapol_sm *sm, size_t *len)
+{
+ if (sm == NULL || !eap_key_available(sm->eap)) {
+ wpa_printf(MSG_DEBUG, "EAPOL: EAP Session-Id not available");
+ return NULL;
+ }
+ return eap_get_eapSessionId(sm->eap, len);
+}
+
+
+/**
* eapol_sm_notify_logoff - Notification of logon/logoff commands
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
* @logoff: Whether command was logoff
{
if (sm) {
sm->userLogoff = logoff;
+ if (!logoff) {
+ /* If there is a delayed txStart queued, start now. */
+ sm->startWhen = 0;
+ }
eapol_sm_step(sm);
}
}
if (sm == NULL)
return;
wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL");
- sm->SUPP_PAE_state = SUPP_PAE_AUTHENTICATED;
- sm->suppPortStatus = Authorized;
- eapol_sm_set_port_authorized(sm);
- sm->portValid = TRUE;
+ sm->eapSuccess = TRUE;
eap_notify_success(sm->eap);
eapol_sm_step(sm);
}
/**
* eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @attempt: Whether PMKSA caching is tried
*
- * Notify EAPOL state machines whether PMKSA caching is used.
+ * Notify EAPOL state machines if PMKSA caching is used.
*/
-void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt)
+void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm)
{
if (sm == NULL)
return;
- if (attempt) {
- wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
- sm->cached_pmk = TRUE;
- } else {
- wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA");
- sm->cached_pmk = FALSE;
- }
+ wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
+ sm->cached_pmk = TRUE;
}
return;
sm->cached_pmk = FALSE;
sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
- sm->suppPortStatus = Unauthorized;
eapol_sm_set_port_unauthorized(sm);
/* Make sure we do not start sending EAPOL-Start frames first, but
return sm->altAccept;
case EAPOL_altReject:
return sm->altReject;
+ case EAPOL_eapTriggerStart:
+ return sm->eapTriggerStart;
}
return FALSE;
}
case EAPOL_altReject:
sm->altReject = value;
break;
+ case EAPOL_eapTriggerStart:
+ sm->eapTriggerStart = value;
+ break;
}
}
switch (variable) {
case EAPOL_idleWhile:
sm->idleWhile = value;
- eapol_enable_timer_tick(sm);
+ if (sm->idleWhile > 0)
+ eapol_enable_timer_tick(sm);
break;
}
}
#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
-static void eapol_sm_eap_param_needed(void *ctx, const char *field,
+static void eapol_sm_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field,
const char *txt)
{
struct eapol_sm *sm = ctx;
#define eapol_sm_eap_param_needed NULL
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+static void eapol_sm_notify_cert(void *ctx, int depth, const char *subject,
+ const char *altsubject[],
+ int num_altsubject, const char *cert_hash,
+ const struct wpabuf *cert)
+{
+ struct eapol_sm *sm = ctx;
+ if (sm->ctx->cert_cb)
+ sm->ctx->cert_cb(sm->ctx->ctx, depth, subject, altsubject,
+ num_altsubject, cert_hash, cert);
+}
+
-static struct eapol_callbacks eapol_cb =
+static void eapol_sm_notify_status(void *ctx, const char *status,
+ const char *parameter)
+{
+ struct eapol_sm *sm = ctx;
+
+ if (sm->ctx->status_cb)
+ sm->ctx->status_cb(sm->ctx->ctx, status, parameter);
+}
+
+
+#ifdef CONFIG_EAP_PROXY
+static void eapol_sm_eap_proxy_cb(void *ctx)
+{
+ struct eapol_sm *sm = ctx;
+
+ if (sm->ctx->eap_proxy_cb)
+ sm->ctx->eap_proxy_cb(sm->ctx->ctx);
+}
+#endif /* CONFIG_EAP_PROXY */
+
+
+static void eapol_sm_set_anon_id(void *ctx, const u8 *id, size_t len)
+{
+ struct eapol_sm *sm = ctx;
+
+ if (sm->ctx->set_anon_id)
+ sm->ctx->set_anon_id(sm->ctx->ctx, id, len);
+}
+
+
+static const struct eapol_callbacks eapol_cb =
{
eapol_sm_get_config,
eapol_sm_get_bool,
eapol_sm_set_config_blob,
eapol_sm_get_config_blob,
eapol_sm_notify_pending,
- eapol_sm_eap_param_needed
+ eapol_sm_eap_param_needed,
+ eapol_sm_notify_cert,
+ eapol_sm_notify_status,
+#ifdef CONFIG_EAP_PROXY
+ eapol_sm_eap_proxy_cb,
+#endif /* CONFIG_EAP_PROXY */
+ eapol_sm_set_anon_id
};
conf.opensc_engine_path = ctx->opensc_engine_path;
conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
conf.pkcs11_module_path = ctx->pkcs11_module_path;
+ conf.openssl_ciphers = ctx->openssl_ciphers;
conf.wps = ctx->wps;
+ conf.cert_in_cb = ctx->cert_in_cb;
sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
if (sm->eap == NULL) {
return NULL;
}
+#ifdef CONFIG_EAP_PROXY
+ sm->use_eap_proxy = FALSE;
+ sm->eap_proxy = eap_proxy_init(sm, &eapol_cb, sm->ctx->msg_ctx);
+ if (sm->eap_proxy == NULL) {
+ wpa_printf(MSG_ERROR, "Unable to initialize EAP Proxy");
+ }
+#endif /* CONFIG_EAP_PROXY */
+
/* Initialize EAPOL state machines */
+ sm->force_authorized_update = TRUE;
sm->initialize = TRUE;
eapol_sm_step(sm);
sm->initialize = FALSE;
eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
eap_peer_sm_deinit(sm->eap);
+#ifdef CONFIG_EAP_PROXY
+ eap_proxy_deinit(sm->eap_proxy);
+#endif /* CONFIG_EAP_PROXY */
os_free(sm->last_rx_key);
wpabuf_free(sm->eapReqData);
os_free(sm->ctx);
os_free(sm);
}
+
+
+void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
+ struct ext_password_data *ext)
+{
+ if (sm && sm->eap)
+ eap_sm_set_ext_pw_ctx(sm->eap, ext);
+}
+
+
+int eapol_sm_failed(struct eapol_sm *sm)
+{
+ if (sm == NULL)
+ return 0;
+ return !sm->eapSuccess && sm->eapFail;
+}
+
+
+int eapol_sm_get_eap_proxy_imsi(struct eapol_sm *sm, char *imsi, size_t *len)
+{
+#ifdef CONFIG_EAP_PROXY
+ if (sm->eap_proxy == NULL)
+ return -1;
+ return eap_proxy_get_imsi(sm->eap_proxy, imsi, len);
+#else /* CONFIG_EAP_PROXY */
+ return -1;
+#endif /* CONFIG_EAP_PROXY */
+}
+
+
+void eapol_sm_erp_flush(struct eapol_sm *sm)
+{
+ if (sm)
+ eap_peer_erp_free_keys(sm->eap);
+}