summaryrefslogtreecommitdiff
path: root/src/eapol_supp/eapol_supp_sm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/eapol_supp/eapol_supp_sm.c')
-rw-r--r--src/eapol_supp/eapol_supp_sm.c158
1 files changed, 99 insertions, 59 deletions
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index 77cd564b0d43b..f90fb6257880f 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -1,15 +1,9 @@
/*
* 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"
@@ -145,46 +139,6 @@ struct eapol_sm {
};
-#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 */
-
-
static void eapol_sm_txLogoff(struct eapol_sm *sm);
static void eapol_sm_txStart(struct eapol_sm *sm);
static void eapol_sm_processKey(struct eapol_sm *sm);
@@ -268,6 +222,15 @@ SM_STATE(SUPP_PAE, DISCONNECTED)
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;
}
@@ -535,6 +498,15 @@ SM_STATE(SUPP_BE, INITIALIZE)
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;
}
@@ -561,7 +533,7 @@ SM_STEP(SUPP_BE)
* 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
@@ -652,6 +624,7 @@ struct eap_key_data {
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;
@@ -659,6 +632,7 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
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)
@@ -671,9 +645,12 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
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;
}
@@ -739,7 +716,7 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
}
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);
@@ -810,6 +787,7 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
sm->ctx->eapol_done_cb(sm->ctx->ctx);
}
}
+#endif /* CONFIG_FIPS */
}
@@ -1029,6 +1007,21 @@ void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
}
+/**
+ * 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
@@ -1476,10 +1469,7 @@ void eapol_sm_notify_cached(struct eapol_sm *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);
}
@@ -1751,7 +1741,8 @@ static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
switch (variable) {
case EAPOL_idleWhile:
sm->idleWhile = value;
- eapol_enable_timer_tick(sm);
+ if (sm->idleWhile > 0)
+ eapol_enable_timer_tick(sm);
break;
}
}
@@ -1798,7 +1789,7 @@ static void eapol_sm_notify_pending(void *ctx)
#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;
@@ -1810,6 +1801,35 @@ static void eapol_sm_eap_param_needed(void *ctx, const char *field,
#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 *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,
+ cert_hash, cert);
+}
+
+
+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);
+}
+
+
+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 struct eapol_callbacks eapol_cb =
{
@@ -1822,7 +1842,10 @@ static struct eapol_callbacks eapol_cb =
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,
+ eapol_sm_set_anon_id
};
@@ -1858,6 +1881,7 @@ struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
conf.pkcs11_module_path = ctx->pkcs11_module_path;
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) {
@@ -1896,3 +1920,19 @@ void eapol_sm_deinit(struct eapol_sm *sm)
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;
+}