summaryrefslogtreecommitdiffstats
path: root/contrib/wpa_supplicant/eap.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/wpa_supplicant/eap.c')
-rw-r--r--contrib/wpa_supplicant/eap.c705
1 files changed, 627 insertions, 78 deletions
diff --git a/contrib/wpa_supplicant/eap.c b/contrib/wpa_supplicant/eap.c
index 267907c..5d81870 100644
--- a/contrib/wpa_supplicant/eap.c
+++ b/contrib/wpa_supplicant/eap.c
@@ -1,5 +1,5 @@
/*
- * WPA Supplicant / EAP state machines
+ * WPA Supplicant / EAP state machines (RFC 4137)
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
@@ -15,13 +15,16 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <ctype.h>
#include "common.h"
#include "eap_i.h"
#include "wpa_supplicant.h"
#include "config_ssid.h"
#include "tls.h"
-#include "md5.h"
+#include "crypto.h"
+#include "pcsc_funcs.h"
+#include "wpa_ctrl.h"
#define EAP_MAX_AUTH_ROUNDS 50
@@ -63,6 +66,9 @@ extern const struct eap_method eap_method_aka;
#ifdef EAP_FAST
extern const struct eap_method eap_method_fast;
#endif
+#ifdef EAP_PAX
+extern const struct eap_method eap_method_pax;
+#endif
static const struct eap_method *eap_methods[] =
{
@@ -102,10 +108,18 @@ static const struct eap_method *eap_methods[] =
#ifdef EAP_FAST
&eap_method_fast,
#endif
+#ifdef EAP_PAX
+ &eap_method_pax,
+#endif
};
#define NUM_EAP_METHODS (sizeof(eap_methods) / sizeof(eap_methods[0]))
+/**
+ * eap_sm_get_eap_methods - Get EAP method based on type number
+ * @method: EAP type number
+ * Returns: Pointer to EAP method of %NULL if not found
+ */
const struct eap_method * eap_sm_get_eap_methods(int method)
{
int i;
@@ -119,10 +133,11 @@ const struct eap_method * eap_sm_get_eap_methods(int method)
static Boolean eap_sm_allowMethod(struct eap_sm *sm, EapType method);
static u8 * eap_sm_buildNak(struct eap_sm *sm, int id, size_t *len);
-static void eap_sm_processIdentity(struct eap_sm *sm, u8 *req, size_t len);
-static void eap_sm_processNotify(struct eap_sm *sm, u8 *req, size_t len);
+static void eap_sm_processIdentity(struct eap_sm *sm, const u8 *req,
+ size_t len);
+static void eap_sm_processNotify(struct eap_sm *sm, const u8 *req, size_t len);
static u8 * eap_sm_buildNotify(struct eap_sm *sm, int id, size_t *len);
-static void eap_sm_parseEapReq(struct eap_sm *sm, u8 *req, size_t len);
+static void eap_sm_parseEapReq(struct eap_sm *sm, const u8 *req, size_t len);
static const char * eap_sm_method_state_txt(int state);
static const char * eap_sm_decision_txt(int decision);
@@ -219,12 +234,14 @@ SM_STATE(EAP, INITIALIZE)
eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
sm->lastId = -1; /* new session - make sure this does not match with
* the first EAP-Packet */
- /* draft-ietf-eap-statemachine-02.pdf does not reset eapResp and
- * eapNoResp here. However, this seemed to be able to trigger cases
- * where both were set and if EAPOL state machine uses eapNoResp first,
- * it may end up not sending a real reply correctly. This occurred
- * when the workaround in FAIL state set eapNoResp = TRUE.. Maybe that
- * workaround needs to be fixed to do something else(?) */
+ /*
+ * RFC 4137 does not reset eapResp and eapNoResp here. However, this
+ * seemed to be able to trigger cases where both were set and if EAPOL
+ * state machine uses eapNoResp first, it may end up not sending a real
+ * reply correctly. This occurred when the workaround in FAIL state set
+ * eapNoResp = TRUE.. Maybe that workaround needs to be fixed to do
+ * something else(?)
+ */
eapol_set_bool(sm, EAPOL_eapResp, FALSE);
eapol_set_bool(sm, EAPOL_eapNoResp, FALSE);
sm->num_rounds = 0;
@@ -246,7 +263,7 @@ SM_STATE(EAP, IDLE)
SM_STATE(EAP, RECEIVED)
{
- u8 *eapReqData;
+ const u8 *eapReqData;
size_t eapReqDataLen;
SM_ENTRY(EAP, RECEIVED);
@@ -284,14 +301,35 @@ SM_STATE(EAP, GET_METHOD)
else
sm->eap_method_priv = sm->m->init(sm);
if (sm->eap_method_priv == NULL) {
- wpa_printf(MSG_DEBUG, "EAP: Failed to "
- "initialize EAP method %d",
- sm->selectedMethod);
+ struct wpa_ssid *config = eap_get_config(sm);
+ wpa_msg(sm->msg_ctx, MSG_INFO,
+ "EAP: Failed to initialize EAP method "
+ "%d (%s)",
+ sm->selectedMethod, sm->m->name);
sm->m = NULL;
sm->methodState = METHOD_NONE;
sm->selectedMethod = EAP_TYPE_NONE;
+ if (sm->reqMethod == EAP_TYPE_TLS &&
+ config &&
+ (config->pending_req_pin ||
+ config->pending_req_passphrase)) {
+ /*
+ * Return without generating Nak in
+ * order to allow entering of PIN code
+ * or passphrase to retry the current
+ * EAP packet.
+ */
+ wpa_printf(MSG_DEBUG, "EAP: Pending "
+ "PIN/passphrase request - "
+ "skip Nak");
+ return;
+ }
} else {
sm->methodState = METHOD_INIT;
+ wpa_msg(sm->msg_ctx, MSG_INFO,
+ WPA_EVENT_EAP_METHOD
+ "EAP method %d (%s) selected",
+ sm->selectedMethod, sm->m->name);
return;
}
}
@@ -381,7 +419,7 @@ SM_STATE(EAP, DISCARD)
SM_STATE(EAP, IDENTITY)
{
- u8 *eapReqData;
+ const u8 *eapReqData;
size_t eapReqDataLen;
SM_ENTRY(EAP, IDENTITY);
@@ -395,7 +433,7 @@ SM_STATE(EAP, IDENTITY)
SM_STATE(EAP, NOTIFICATION)
{
- u8 *eapReqData;
+ const u8 *eapReqData;
size_t eapReqDataLen;
SM_ENTRY(EAP, NOTIFICATION);
@@ -429,15 +467,24 @@ SM_STATE(EAP, SUCCESS)
if (sm->eapKeyData != NULL)
sm->eapKeyAvailable = TRUE;
eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
- /* draft-ietf-eap-statemachine-02.pdf does not clear eapReq here, but
- * this seems to be required to avoid processing the same request
- * twice when state machine is initialized. */
+
+ /*
+ * RFC 4137 does not clear eapReq here, but this seems to be required
+ * to avoid processing the same request twice when state machine is
+ * initialized.
+ */
eapol_set_bool(sm, EAPOL_eapReq, FALSE);
- /* draft-ietf-eap-statemachine-02.pdf does not set eapNoResp here, but
- * this seems to be required to get EAPOL Supplicant backend state
- * machine into SUCCESS state. In addition, either eapResp or eapNoResp
- * is required to be set after processing the received EAP frame. */
+
+ /*
+ * RFC 4137 does not set eapNoResp here, but this seems to be required
+ * to get EAPOL Supplicant backend state machine into SUCCESS state. In
+ * addition, either eapResp or eapNoResp is required to be set after
+ * processing the received EAP frame.
+ */
eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
+ "EAP authentication completed successfully");
}
@@ -445,14 +492,23 @@ SM_STATE(EAP, FAILURE)
{
SM_ENTRY(EAP, FAILURE);
eapol_set_bool(sm, EAPOL_eapFail, TRUE);
- /* draft-ietf-eap-statemachine-02.pdf does not clear eapReq here, but
- * this seems to be required to avoid processing the same request
- * twice when state machine is initialized. */
+
+ /*
+ * RFC 4137 does not clear eapReq here, but this seems to be required
+ * to avoid processing the same request twice when state machine is
+ * initialized.
+ */
eapol_set_bool(sm, EAPOL_eapReq, FALSE);
- /* draft-ietf-eap-statemachine-02.pdf does not set eapNoResp here.
- * However, either eapResp or eapNoResp is required to be set after
- * processing the received EAP frame. */
+
+ /*
+ * RFC 4137 does not set eapNoResp here. However, either eapResp or
+ * eapNoResp is required to be set after processing the received EAP
+ * frame.
+ */
eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
+ "EAP authentication failed");
}
@@ -461,9 +517,8 @@ static int eap_success_workaround(struct eap_sm *sm, int reqId, int lastId)
/*
* At least Microsoft IAS and Meetinghouse Aegis seem to be sending
* EAP-Success/Failure with lastId + 1 even though RFC 3748 and
- * draft-ietf-eap-statemachine-05.pdf require that reqId == lastId.
- * In addition, it looks like Ringmaster v2.1.2.0 would be using
- * lastId + 2 in EAP-Success.
+ * RFC 4137 require that reqId == lastId. In addition, it looks like
+ * Ringmaster v2.1.2.0 would be using lastId + 2 in EAP-Success.
*
* Accept this kind of Id if EAP workarounds are enabled. These are
* unauthenticated plaintext messages, so this should have minimal
@@ -490,13 +545,13 @@ SM_STEP(EAP)
if (eapol_get_bool(sm, EAPOL_eapRestart) &&
eapol_get_bool(sm, EAPOL_portEnabled))
SM_ENTER_GLOBAL(EAP, INITIALIZE);
- else if (!eapol_get_bool(sm, EAPOL_portEnabled))
+ else if (!eapol_get_bool(sm, EAPOL_portEnabled) || sm->force_disabled)
SM_ENTER_GLOBAL(EAP, DISABLED);
else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
- wpa_printf(MSG_DEBUG, "EAP: more than %d "
- "authentication rounds - abort",
- EAP_MAX_AUTH_ROUNDS);
+ wpa_msg(sm->msg_ctx, MSG_INFO, "EAP: more than %d "
+ "authentication rounds - abort",
+ EAP_MAX_AUTH_ROUNDS);
sm->num_rounds++;
SM_ENTER_GLOBAL(EAP, FAILURE);
}
@@ -505,7 +560,8 @@ SM_STEP(EAP)
SM_ENTER(EAP, IDLE);
break;
case EAP_DISABLED:
- if (eapol_get_bool(sm, EAPOL_portEnabled))
+ if (eapol_get_bool(sm, EAPOL_portEnabled) &&
+ !sm->force_disabled)
SM_ENTER(EAP, INITIALIZE);
break;
case EAP_IDLE:
@@ -533,16 +589,18 @@ SM_STEP(EAP)
SM_ENTER(EAP, SUCCESS);
break;
case EAP_RECEIVED:
- duplicate = sm->reqId == sm->lastId;
+ duplicate = (sm->reqId == sm->lastId) && sm->rxReq;
if (sm->workaround && duplicate &&
memcmp(sm->req_md5, sm->last_md5, 16) != 0) {
- /* draft-ietf-eap-statemachine-05.txt uses
- * (reqId == lastId) as the only verification for
- * duplicate EAP requests. However, this misses cases
- * where the AS is incorrectly using the same id again;
- * and unfortunately, such implementations exist. Use
- * MD5 hash as an extra verification for the packets
- * being duplicate to workaround these issues. */
+ /*
+ * RFC 4137 uses (reqId == lastId) as the only
+ * verification for duplicate EAP requests. However,
+ * this misses cases where the AS is incorrectly using
+ * the same id again; and unfortunately, such
+ * implementations exist. Use MD5 hash as an extra
+ * verification for the packets being duplicate to
+ * workaround these issues.
+ */
wpa_printf(MSG_DEBUG, "EAP: AS used the same Id again,"
" but EAP packets were not identical");
wpa_printf(MSG_DEBUG, "EAP: workaround - assume this "
@@ -558,7 +616,9 @@ SM_STEP(EAP)
else if (sm->methodState != METHOD_CONT &&
((sm->rxFailure &&
sm->decision != DECISION_UNCOND_SUCC) ||
- (sm->rxSuccess && sm->decision == DECISION_FAIL)) &&
+ (sm->rxSuccess && sm->decision == DECISION_FAIL &&
+ (sm->selectedMethod != EAP_TYPE_LEAP ||
+ sm->methodState != METHOD_MAY_CONT))) &&
(sm->reqId == sm->lastId ||
eap_success_workaround(sm, sm->reqId, sm->lastId)))
SM_ENTER(EAP, FAILURE);
@@ -657,7 +717,8 @@ static u8 *eap_sm_buildNak(struct eap_sm *sm, int id, size_t *len)
*pos++ = EAP_TYPE_NAK;
for (i = 0; i < NUM_EAP_METHODS; i++) {
- if (wpa_config_allowed_eap_method(config,
+ if (eap_methods[i]->method != sm->reqMethod &&
+ wpa_config_allowed_eap_method(config,
eap_methods[i]->method)) {
*pos++ = eap_methods[i]->method;
(*len)++;
@@ -677,11 +738,16 @@ static u8 *eap_sm_buildNak(struct eap_sm *sm, int id, size_t *len)
}
-static void eap_sm_processIdentity(struct eap_sm *sm, u8 *req, size_t len)
+static void eap_sm_processIdentity(struct eap_sm *sm, const u8 *req,
+ size_t len)
{
- struct eap_hdr *hdr = (struct eap_hdr *) req;
- u8 *pos = (u8 *) (hdr + 1);
+ const struct eap_hdr *hdr = (const struct eap_hdr *) req;
+ const u8 *pos = (const u8 *) (hdr + 1);
pos++;
+
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
+ "EAP authentication started");
+
/* TODO: could save displayable message so that it can be shown to the
* user in case of interaction is required */
wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Identity data",
@@ -689,8 +755,77 @@ static void eap_sm_processIdentity(struct eap_sm *sm, u8 *req, size_t len)
}
-u8 *eap_sm_buildIdentity(struct eap_sm *sm, int id, size_t *len,
- int encrypted)
+static int eap_sm_imsi_identity(struct eap_sm *sm, struct wpa_ssid *ssid)
+{
+ int aka = 0;
+ char imsi[100];
+ size_t imsi_len;
+ u8 *pos = ssid->eap_methods;
+
+ imsi_len = sizeof(imsi);
+ if (scard_get_imsi(sm->scard_ctx, imsi, &imsi_len)) {
+ wpa_printf(MSG_WARNING, "Failed to get IMSI from SIM");
+ return -1;
+ }
+
+ wpa_hexdump_ascii(MSG_DEBUG, "IMSI", (u8 *) imsi, imsi_len);
+
+ while (pos && *pos != EAP_TYPE_NONE) {
+ if (*pos == EAP_TYPE_AKA) {
+ aka = 1;
+ break;
+ }
+ pos++;
+ }
+
+ free(ssid->identity);
+ ssid->identity = malloc(1 + imsi_len);
+ if (ssid->identity == NULL) {
+ wpa_printf(MSG_WARNING, "Failed to allocate buffer for "
+ "IMSI-based identity");
+ return -1;
+ }
+
+ ssid->identity[0] = aka ? '0' : '1';
+ memcpy(ssid->identity + 1, imsi, imsi_len);
+ ssid->identity_len = 1 + imsi_len;
+ return 0;
+}
+
+
+static int eap_sm_get_scard_identity(struct eap_sm *sm, struct wpa_ssid *ssid)
+{
+ if (scard_set_pin(sm->scard_ctx, ssid->pin)) {
+ /*
+ * Make sure the same PIN is not tried again in order to avoid
+ * blocking SIM.
+ */
+ free(ssid->pin);
+ ssid->pin = NULL;
+
+ wpa_printf(MSG_WARNING, "PIN validation failed");
+ eap_sm_request_pin(sm, ssid);
+ return -1;
+ }
+
+ return eap_sm_imsi_identity(sm, ssid);
+}
+
+
+/**
+ * eap_sm_buildIdentity - Build EAP-Identity/Response for the current network
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @id: EAP identifier for the packet
+ * @len: Pointer to variable that will be set to the length of the response
+ * @encrypted: Whether the packet is for enrypted tunnel (EAP phase 2)
+ * Returns: Pointer to the allocated EAP-Identity/Response packet or %NULL on
+ * failure
+ *
+ * This function allocates and builds an EAP-Identity/Response packet for the
+ * current network. The caller is responsible for freeing the returned data.
+ */
+u8 * eap_sm_buildIdentity(struct eap_sm *sm, int id, size_t *len,
+ int encrypted)
{
struct wpa_ssid *config = eap_get_config(sm);
struct eap_hdr *resp;
@@ -724,8 +859,17 @@ u8 *eap_sm_buildIdentity(struct eap_sm *sm, int id, size_t *len,
if (identity == NULL) {
wpa_printf(MSG_WARNING, "EAP: buildIdentity: identity "
"configuration was not available");
- eap_sm_request_identity(sm, config);
- return NULL;
+ if (config->pcsc) {
+ if (eap_sm_get_scard_identity(sm, config) < 0)
+ return NULL;
+ identity = config->identity;
+ identity_len = config->identity_len;
+ wpa_hexdump_ascii(MSG_DEBUG, "permanent identity from "
+ "IMSI", identity, identity_len);
+ } else {
+ eap_sm_request_identity(sm, config);
+ return NULL;
+ }
}
@@ -745,14 +889,33 @@ u8 *eap_sm_buildIdentity(struct eap_sm *sm, int id, size_t *len,
}
-static void eap_sm_processNotify(struct eap_sm *sm, u8 *req, size_t len)
+static void eap_sm_processNotify(struct eap_sm *sm, const u8 *req, size_t len)
{
- struct eap_hdr *hdr = (struct eap_hdr *) req;
- u8 *pos = (u8 *) (hdr + 1);
+ const struct eap_hdr *hdr = (const struct eap_hdr *) req;
+ const u8 *pos;
+ char *msg;
+ size_t msg_len;
+ int i;
+
+ pos = (const u8 *) (hdr + 1);
pos++;
- /* TODO: log the Notification Request and make it available for UI */
+
+ msg_len = be_to_host16(hdr->length);
+ if (msg_len < 5)
+ return;
+ msg_len -= 5;
wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Notification data",
- pos, be_to_host16(hdr->length) - 5);
+ pos, msg_len);
+
+ msg = malloc(msg_len + 1);
+ if (msg == NULL)
+ return;
+ for (i = 0; i < msg_len; i++)
+ msg[i] = isprint(pos[i]) ? (char) pos[i] : '_';
+ msg[msg_len] = '\0';
+ wpa_msg(sm->msg_ctx, MSG_INFO, "%s%s",
+ WPA_EVENT_EAP_NOTIFICATION, msg);
+ free(msg);
}
@@ -777,11 +940,10 @@ static u8 *eap_sm_buildNotify(struct eap_sm *sm, int id, size_t *len)
}
-static void eap_sm_parseEapReq(struct eap_sm *sm, u8 *req, size_t len)
+static void eap_sm_parseEapReq(struct eap_sm *sm, const u8 *req, size_t len)
{
- struct eap_hdr *hdr;
+ const struct eap_hdr *hdr;
size_t plen;
- MD5_CTX context;
sm->rxReq = sm->rxSuccess = sm->rxFailure = FALSE;
sm->reqId = 0;
@@ -790,7 +952,7 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, u8 *req, size_t len)
if (req == NULL || len < sizeof(*hdr))
return;
- hdr = (struct eap_hdr *) req;
+ hdr = (const struct eap_hdr *) req;
plen = be_to_host16(hdr->length);
if (plen > len) {
wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
@@ -802,9 +964,7 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, u8 *req, size_t len)
sm->reqId = hdr->identifier;
if (sm->workaround) {
- MD5Init(&context);
- MD5Update(&context, req, len);
- MD5Final(sm->req_md5, &context);
+ md5_vector(1, (const u8 **) &req, &len, sm->req_md5);
}
switch (hdr->code) {
@@ -843,10 +1003,22 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, u8 *req, size_t len)
}
-struct eap_sm *eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
- void *msg_ctx)
+/**
+ * eap_sm_init - Allocate and initialize EAP state machine
+ * @eapol_ctx: Context data to be used with eapol_cb calls
+ * @eapol_cb: Pointer to EAPOL callback functions
+ * @msg_ctx: Context data for wpa_msg() calls
+ * @conf: EAP configuration
+ * Returns: Pointer to the allocated EAP state machine or %NULL on failure
+ *
+ * This function allocates and initializes an EAP state machine. In addition,
+ * this initializes TLS library for the new EAP state machine.
+ */
+struct eap_sm * eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
+ void *msg_ctx, struct eap_config *conf)
{
struct eap_sm *sm;
+ struct tls_config tlsconf;
sm = malloc(sizeof(*sm));
if (sm == NULL)
@@ -857,7 +1029,11 @@ struct eap_sm *eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
sm->msg_ctx = msg_ctx;
sm->ClientTimeout = 60;
- sm->ssl_ctx = tls_init();
+ memset(&tlsconf, 0, sizeof(tlsconf));
+ tlsconf.opensc_engine_path = conf->opensc_engine_path;
+ tlsconf.pkcs11_engine_path = conf->pkcs11_engine_path;
+ tlsconf.pkcs11_module_path = conf->pkcs11_module_path;
+ sm->ssl_ctx = tls_init(&tlsconf);
if (sm->ssl_ctx == NULL) {
wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS "
"context.");
@@ -869,6 +1045,13 @@ struct eap_sm *eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
}
+/**
+ * eap_sm_deinit - Deinitialize and free an EAP state machine
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ *
+ * This function deinitializes EAP state machine and frees all allocated
+ * resources.
+ */
void eap_sm_deinit(struct eap_sm *sm)
{
if (sm == NULL)
@@ -882,6 +1065,15 @@ void eap_sm_deinit(struct eap_sm *sm)
}
+/**
+ * eap_sm_step - Step EAP state machine
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * Returns: 1 if EAP state was changed or 0 if not
+ *
+ * This function advances EAP state machine to a new state to match with the
+ * current variables. This should be called whenever variables used by the EAP
+ * state machine have changed.
+ */
int eap_sm_step(struct eap_sm *sm)
{
int res = 0;
@@ -895,10 +1087,15 @@ int eap_sm_step(struct eap_sm *sm)
}
+/**
+ * eap_sm_abort - Abort EAP authentication
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ *
+ * Release system resources that have been allocated for the authentication
+ * session without fully deinitializing the EAP state machine.
+ */
void eap_sm_abort(struct eap_sm *sm)
{
- /* release system resources that may have been allocated for the
- * authentication session */
free(sm->eapRespData);
sm->eapRespData = NULL;
free(sm->eapKeyData);
@@ -975,6 +1172,19 @@ static const char * eap_sm_decision_txt(int decision)
}
+/**
+ * eap_sm_get_status - Get EAP state machine status
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @buf: buffer for status information
+ * @buflen: maximum buffer length
+ * @verbose: whether to include verbose status information
+ * Returns: number of bytes written to buf.
+ *
+ * Query EAP state machine for status information. This function fills in a
+ * text area with current status information from the EAPOL state machine. If
+ * the buffer (buf) is not large enough, status information will be truncated
+ * to fit the buffer.
+ */
int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
{
int len;
@@ -1025,10 +1235,14 @@ int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
}
-typedef enum { TYPE_IDENTITY, TYPE_PASSWORD, TYPE_OTP } eap_ctrl_req_type;
+typedef enum {
+ TYPE_IDENTITY, TYPE_PASSWORD, TYPE_OTP, TYPE_PIN, TYPE_NEW_PASSWORD,
+ TYPE_PASSPHRASE
+} eap_ctrl_req_type;
static void eap_sm_request(struct eap_sm *sm, struct wpa_ssid *config,
- eap_ctrl_req_type type, char *msg, size_t msglen)
+ eap_ctrl_req_type type, const char *msg,
+ size_t msglen)
{
char *buf;
size_t buflen;
@@ -1050,6 +1264,16 @@ static void eap_sm_request(struct eap_sm *sm, struct wpa_ssid *config,
txt = "Password";
config->pending_req_password++;
break;
+ case TYPE_NEW_PASSWORD:
+ field = "NEW_PASSWORD";
+ txt = "New Password";
+ config->pending_req_new_password++;
+ break;
+ case TYPE_PIN:
+ field = "PIN";
+ txt = "PIN";
+ config->pending_req_pin++;
+ break;
case TYPE_OTP:
field = "OTP";
if (msg) {
@@ -1070,6 +1294,11 @@ static void eap_sm_request(struct eap_sm *sm, struct wpa_ssid *config,
txt = config->pending_req_otp;
}
break;
+ case TYPE_PASSPHRASE:
+ field = "PASSPHRASE";
+ txt = "Private key passphrase";
+ config->pending_req_passphrase++;
+ break;
default:
return;
}
@@ -1078,37 +1307,123 @@ static void eap_sm_request(struct eap_sm *sm, struct wpa_ssid *config,
buf = malloc(buflen);
if (buf == NULL)
return;
- len = snprintf(buf, buflen, "CTRL-REQ-%s-%d:%s needed for SSID ",
+ len = snprintf(buf, buflen, WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
field, config->id, txt);
if (config->ssid && buflen > len + config->ssid_len) {
memcpy(buf + len, config->ssid, config->ssid_len);
len += config->ssid_len;
buf[len] = '\0';
}
- wpa_msg(sm->msg_ctx, MSG_INFO, buf);
+ wpa_msg(sm->msg_ctx, MSG_INFO, "%s", buf);
free(buf);
}
+/**
+ * eap_sm_request_identity - Request identity from user (ctrl_iface)
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @config: Pointer to the current network configuration
+ *
+ * EAP methods can call this function to request identity information for the
+ * current network. This is normally called when the identity is not included
+ * in the network configuration. The request will be sent to monitor programs
+ * through the control interface.
+ */
void eap_sm_request_identity(struct eap_sm *sm, struct wpa_ssid *config)
{
eap_sm_request(sm, config, TYPE_IDENTITY, NULL, 0);
}
+/**
+ * eap_sm_request_password - Request password from user (ctrl_iface)
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @config: Pointer to the current network configuration
+ *
+ * EAP methods can call this function to request password information for the
+ * current network. This is normally called when the password is not included
+ * in the network configuration. The request will be sent to monitor programs
+ * through the control interface.
+ */
void eap_sm_request_password(struct eap_sm *sm, struct wpa_ssid *config)
{
eap_sm_request(sm, config, TYPE_PASSWORD, NULL, 0);
}
+/**
+ * eap_sm_request_new_password - Request new password from user (ctrl_iface)
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @config: Pointer to the current network configuration
+ *
+ * EAP methods can call this function to request new password information for
+ * the current network. This is normally called when the EAP method indicates
+ * that the current password has expired and password change is required. The
+ * request will be sent to monitor programs through the control interface.
+ */
+void eap_sm_request_new_password(struct eap_sm *sm, struct wpa_ssid *config)
+{
+ eap_sm_request(sm, config, TYPE_NEW_PASSWORD, NULL, 0);
+}
+
+
+/**
+ * eap_sm_request_pin - Request SIM or smart card PIN from user (ctrl_iface)
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @config: Pointer to the current network configuration
+ *
+ * EAP methods can call this function to request SIM or smart card PIN
+ * information for the current network. This is normally called when the PIN is
+ * not included in the network configuration. The request will be sent to
+ * monitor programs through the control interface.
+ */
+void eap_sm_request_pin(struct eap_sm *sm, struct wpa_ssid *config)
+{
+ eap_sm_request(sm, config, TYPE_PIN, NULL, 0);
+}
+
+
+/**
+ * eap_sm_request_otp - Request one time password from user (ctrl_iface)
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @config: Pointer to the current network configuration
+ * @msg: Message to be displayed to the user when asking for OTP
+ * @msg_len: Length of the user displayable message
+ *
+ * EAP methods can call this function to request open time password (OTP) for
+ * the current network. The request will be sent to monitor programs through
+ * the control interface.
+ */
void eap_sm_request_otp(struct eap_sm *sm, struct wpa_ssid *config,
- char *msg, size_t msg_len)
+ const char *msg, size_t msg_len)
{
eap_sm_request(sm, config, TYPE_OTP, msg, msg_len);
}
+/**
+ * eap_sm_request_passphrase - Request passphrase from user (ctrl_iface)
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @config: Pointer to the current network configuration
+ *
+ * EAP methods can call this function to request passphrase for a private key
+ * for the current network. This is normally called when the passphrase is not
+ * included in the network configuration. The request will be sent to monitor
+ * programs through the control interface.
+ */
+void eap_sm_request_passphrase(struct eap_sm *sm, struct wpa_ssid *config)
+{
+ eap_sm_request(sm, config, TYPE_PASSPHRASE, NULL, 0);
+}
+
+
+/**
+ * eap_sm_notify_ctrl_attached - Notification of attached monitor
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ *
+ * Notify EAP state machines that a monitor was attached to the control
+ * interface to trigger re-sending of pending requests for user input.
+ */
void eap_sm_notify_ctrl_attached(struct eap_sm *sm)
{
struct wpa_ssid *config = eap_get_config(sm);
@@ -1124,11 +1439,25 @@ void eap_sm_notify_ctrl_attached(struct eap_sm *sm)
eap_sm_request_identity(sm, config);
if (config->pending_req_password)
eap_sm_request_password(sm, config);
+ if (config->pending_req_new_password)
+ eap_sm_request_new_password(sm, config);
if (config->pending_req_otp)
eap_sm_request_otp(sm, config, NULL, 0);
+ if (config->pending_req_pin)
+ eap_sm_request_pin(sm, config);
+ if (config->pending_req_passphrase)
+ eap_sm_request_passphrase(sm, config);
}
+/**
+ * eap_get_type - Get EAP type for the given EAP method name
+ * @name: EAP method name, e.g., TLS
+ * Returns: EAP method type or %EAP_TYPE_NONE if not found
+ *
+ * This function maps EAP type names into EAP type numbers based on the list of
+ * EAP methods included in the build.
+ */
u8 eap_get_type(const char *name)
{
int i;
@@ -1140,6 +1469,49 @@ u8 eap_get_type(const char *name)
}
+/**
+ * eap_get_name - Get EAP method name for the given EAP type
+ * @type: EAP method type
+ * Returns: EAP method name, e.g., TLS, or %NULL if not found
+ *
+ * This function maps EAP type numbers into EAP type names based on the list of
+ * EAP methods included in the build.
+ */
+const char * eap_get_name(EapType type)
+{
+ int i;
+ for (i = 0; i < NUM_EAP_METHODS; i++) {
+ if (eap_methods[i]->method == type)
+ return eap_methods[i]->name;
+ }
+ return NULL;
+}
+
+
+/**
+ * eap_get_names - Get space separated list of names for supported EAP methods
+ * @buf: Buffer for names
+ * @buflen: Buffer length
+ * Returns: Number of characters written into buf (not including nul
+ * termination)
+ */
+size_t eap_get_names(char *buf, size_t buflen)
+{
+ char *pos, *end;
+ int i;
+
+ pos = buf;
+ end = pos + buflen;
+
+ for (i = 0; i < NUM_EAP_METHODS; i++) {
+ pos += snprintf(pos, end - pos, "%s%s",
+ i == 0 ? "" : " ", eap_methods[i]->name);
+ }
+
+ return pos - buf;
+}
+
+
static int eap_allowed_phase2_type(int type)
{
return type != EAP_TYPE_PEAP && type != EAP_TYPE_TTLS &&
@@ -1147,6 +1519,15 @@ static int eap_allowed_phase2_type(int type)
}
+/**
+ * eap_get_phase2_type - Get EAP type for the given EAP phase 2 method name
+ * @name: EAP method name, e.g., MD5
+ * Returns: EAP method type or %EAP_TYPE_NONE if not found
+ *
+ * This function maps EAP type names into EAP type numbers that are allowed for
+ * Phase 2, i.e., for tunneled authentication. Phase 2 is used, e.g., with
+ * EAP-PEAP, EAP-TTLS, and EAP-FAST.
+ */
u8 eap_get_phase2_type(const char *name)
{
u8 type = eap_get_type(name);
@@ -1156,6 +1537,15 @@ u8 eap_get_phase2_type(const char *name)
}
+/**
+ * eap_get_phase2_types - Get list of allowed EAP phase 2 types
+ * @config: Pointer to a network configuration
+ * @count: Pointer to variable filled with number of returned EAP types
+ * Returns: Pointer to allocated type list or %NULL on failure
+ *
+ * This function generates an array of allowed EAP phase 2 (tunneled) types for
+ * the given network configuration.
+ */
u8 *eap_get_phase2_types(struct wpa_ssid *config, size_t *count)
{
u8 *buf, method;
@@ -1181,30 +1571,59 @@ u8 *eap_get_phase2_types(struct wpa_ssid *config, size_t *count)
}
+/**
+ * eap_set_fast_reauth - Update fast_reauth setting
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @enabled: 1 = fast reauthentication is enabled, 0 = disabled
+ */
void eap_set_fast_reauth(struct eap_sm *sm, int enabled)
{
sm->fast_reauth = enabled;
}
+/**
+ * eap_set_workaround - Update EAP workarounds setting
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @workaround: 1 = Enable EAP workarounds, 0 = Disable EAP workarounds
+ */
void eap_set_workaround(struct eap_sm *sm, unsigned int workaround)
{
sm->workaround = workaround;
}
+/**
+ * eap_get_config - Get current network configuration
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * Returns: Pointer to the current network configuration or %NULL if not found
+ */
struct wpa_ssid * eap_get_config(struct eap_sm *sm)
{
return sm->eapol_cb->get_config(sm->eapol_ctx);
}
+/**
+ * eap_key_available - Get key availability (eapKeyAvailable variable)
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * Returns: 1 if EAP keying material is available, 0 if not
+ */
int eap_key_available(struct eap_sm *sm)
{
return sm ? sm->eapKeyAvailable : 0;
}
+/**
+ * eap_notify_success - Notify EAP state machine about external success trigger
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ *
+ * This function is called when external event, e.g., successful completion of
+ * WPA-PSK key handshake, is indicating that EAP state machine should move to
+ * success state. This is mainly used with security modes that do not use EAP
+ * state machine (e.g., WPA-PSK).
+ */
void eap_notify_success(struct eap_sm *sm)
{
if (sm) {
@@ -1212,9 +1631,45 @@ void eap_notify_success(struct eap_sm *sm)
sm->EAP_state = EAP_SUCCESS;
}
}
+/**
+ * eap_notify_lower_layer_success - Notification of lower layer success
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ *
+ * Notify EAP state machines that a lower layer has detected a successful
+ * authentication. This is used to recover from dropped EAP-Success messages.
+ */
+void eap_notify_lower_layer_success(struct eap_sm *sm)
+{
+ if (sm == NULL)
+ return;
+ if (eapol_get_bool(sm, EAPOL_eapSuccess) ||
+ sm->decision == DECISION_FAIL ||
+ (sm->methodState != METHOD_MAY_CONT &&
+ sm->methodState != METHOD_DONE))
+ return;
-u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len)
+ if (sm->eapKeyData != NULL)
+ sm->eapKeyAvailable = TRUE;
+ eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
+ "EAP authentication completed successfully (based on lower "
+ "layer success)");
+}
+
+
+/**
+ * eap_get_eapKeyData - Get master session key (MSK) from EAP state machine
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @len: Pointer to variable that will be set to number of bytes in the key
+ * Returns: Pointer to the EAP keying data or %NULL on failure
+ *
+ * Fetch EAP keying material (MSK, eapKeyData) from the EAP state machine. The
+ * key is available only after a successful authentication. EAP state machine
+ * continues to manage the key data and the caller must not change or free the
+ * returned data.
+ */
+const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len)
{
if (sm == NULL || sm->eapKeyData == NULL) {
*len = 0;
@@ -1226,6 +1681,17 @@ u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len)
}
+/**
+ * eap_get_eapKeyData - Get EAP response data
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @len: Pointer to variable that will be set to the length of the response
+ * Returns: Pointer to the EAP response (eapRespData) or %NULL on failure
+ *
+ * Fetch EAP response (eapRespData) from the EAP state machine. This data is
+ * available when EAP state machine has processed an incoming EAP request. The
+ * EAP state machine does not maintain a reference to the response after this
+ * function is called and the caller is responsible for freeing the data.
+ */
u8 * eap_get_eapRespData(struct eap_sm *sm, size_t *len)
{
u8 *resp;
@@ -1244,8 +1710,91 @@ u8 * eap_get_eapRespData(struct eap_sm *sm, size_t *len)
}
+/**
+ * eap_sm_register_scard_ctx - Notification of smart card context
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @ctx: context data for smart card operations
+ *
+ * Notify EAP state machines of context data for smart card operations. This
+ * context data will be used as a parameter for scard_*() functions.
+ */
void eap_register_scard_ctx(struct eap_sm *sm, void *ctx)
{
if (sm)
sm->scard_ctx = ctx;
}
+
+
+/**
+ * eap_hdr_validate - Validate EAP header
+ * @eap_type: Expected EAP type number
+ * @msg: EAP frame (starting with EAP header)
+ * @msglen: Length of msg
+ * @plen: Pointer for return payload length
+ * Returns: Pointer to EAP payload (after type field), or %NULL on failure
+ *
+ * This is a helper function for EAP method implementations. This is usually
+ * called in the beginning of struct eap_method::process() function.
+ */
+const u8 * eap_hdr_validate(EapType eap_type, const u8 *msg, size_t msglen,
+ size_t *plen)
+{
+ const struct eap_hdr *hdr;
+ const u8 *pos;
+ size_t len;
+
+ hdr = (const struct eap_hdr *) msg;
+ pos = (const u8 *) (hdr + 1);
+ if (msglen < sizeof(*hdr) + 1 || *pos != eap_type) {
+ wpa_printf(MSG_INFO, "EAP: Invalid frame type");
+ return NULL;
+ }
+ len = be_to_host16(hdr->length);
+ if (len < sizeof(*hdr) + 1 || len > msglen) {
+ wpa_printf(MSG_INFO, "EAP: Invalid EAP length");
+ return NULL;
+ }
+ *plen = len - sizeof(*hdr) - 1;
+ return pos + 1;
+}
+
+
+/**
+ * eap_set_config_blob - Set or add a named configuration blob
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @blob: New value for the blob
+ *
+ * Adds a new configuration blob or replaces the current value of an existing
+ * blob.
+ */
+void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob)
+{
+ sm->eapol_cb->set_config_blob(sm->eapol_ctx, blob);
+}
+
+
+/**
+ * eap_get_config_blob - Get a named configuration blob
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @name: Name of the blob
+ * Returns: Pointer to blob data or %NULL if not found
+ */
+const struct wpa_config_blob * eap_get_config_blob(struct eap_sm *sm,
+ const char *name)
+{
+ return sm->eapol_cb->get_config_blob(sm->eapol_ctx, name);
+}
+
+
+/**
+ * eap_set_force_disabled - Set force_disabled flag
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @disabled: 1 = EAP disabled, 0 = EAP enabled
+ *
+ * This function is used to force EAP state machine to be disabled when it is
+ * not in use (e.g., with WPA-PSK or plaintext connections).
+ */
+void eap_set_force_disabled(struct eap_sm *sm, int disabled)
+{
+ sm->force_disabled = disabled;
+}
OpenPOWER on IntegriCloud