aboutsummaryrefslogtreecommitdiffstats
path: root/src/charon/sa/authenticators/eap_authenticator.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/charon/sa/authenticators/eap_authenticator.c')
-rw-r--r--src/charon/sa/authenticators/eap_authenticator.c767
1 files changed, 422 insertions, 345 deletions
diff --git a/src/charon/sa/authenticators/eap_authenticator.c b/src/charon/sa/authenticators/eap_authenticator.c
index 9d7113fd2..876cb7b74 100644
--- a/src/charon/sa/authenticators/eap_authenticator.c
+++ b/src/charon/sa/authenticators/eap_authenticator.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006-2008 Martin Willi
+ * Copyright (C) 2006-2009 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -15,13 +15,12 @@
* $Id$
*/
-#include <string.h>
-
#include "eap_authenticator.h"
#include <daemon.h>
-#include <config/peer_cfg.h>
#include <sa/authenticators/eap/eap_method.h>
+#include <encoding/payloads/auth_payload.h>
+#include <encoding/payloads/eap_payload.h>
typedef struct private_eap_authenticator_t private_eap_authenticator_t;
@@ -41,9 +40,14 @@ struct private_eap_authenticator_t {
ike_sa_t *ike_sa;
/**
- * Role of this authenticator, PEER or SERVER
+ * nonce to include in AUTH calculation
*/
- eap_role_t role;
+ chunk_t nonce;
+
+ /**
+ * IKE_SA_INIT message data to include in AUTH calculation
+ */
+ chunk_t ike_sa_init;
/**
* Current EAP method processing
@@ -56,442 +60,509 @@ struct private_eap_authenticator_t {
chunk_t msk;
/**
- * should we do a EAP-Identity exchange as server?
+ * EAP authentication method completed successfully
*/
- bool do_eap_identity;
+ bool eap_complete;
/**
- * saved EAP type if we do eap_identity
+ * authentication payload verified successfully
*/
- eap_type_t type;
+ bool auth_complete;
/**
- * saved vendor id if we do eap_identity
+ * generated EAP payload
*/
- u_int32_t vendor;
+ eap_payload_t *eap_payload;
+
+ /**
+ * EAP identity of peer
+ */
+ identification_t *eap_identity;
};
+
/**
- * Implementation of authenticator_t.verify.
+ * load an EAP method
*/
-static status_t verify(private_eap_authenticator_t *this, chunk_t ike_sa_init,
- chunk_t my_nonce, auth_payload_t *auth_payload)
+static eap_method_t *load_method(private_eap_authenticator_t *this,
+ eap_type_t type, u_int32_t vendor, eap_role_t role)
{
- chunk_t auth_data, recv_auth_data;
- identification_t *other_id;
- keymat_t *keymat;
-
- other_id = this->ike_sa->get_other_id(this->ike_sa);
- keymat = this->ike_sa->get_keymat(this->ike_sa);
-
- auth_data = keymat->get_psk_sig(keymat, TRUE, ike_sa_init, my_nonce,
- this->msk, other_id);
+ identification_t *server, *peer;
- recv_auth_data = auth_payload->get_data(auth_payload);
- if (!auth_data.len || !chunk_equals(auth_data, recv_auth_data))
+ if (role == EAP_SERVER)
{
- DBG1(DBG_IKE, "verification of AUTH payload created from EAP MSK failed");
- chunk_free(&auth_data);
- return FAILED;
+ server = this->ike_sa->get_my_id(this->ike_sa);
+ peer = this->ike_sa->get_other_id(this->ike_sa);
}
- chunk_free(&auth_data);
-
- DBG1(DBG_IKE, "authentication of '%D' with %N successful",
- other_id, auth_class_names, AUTH_CLASS_EAP);
- return SUCCESS;
-}
-
-/**
- * Implementation of authenticator_t.build.
- */
-static status_t build(private_eap_authenticator_t *this, chunk_t ike_sa_init,
- chunk_t other_nonce, auth_payload_t **auth_payload)
-{
- identification_t *my_id;
- chunk_t auth_data;
- keymat_t *keymat;
-
- my_id = this->ike_sa->get_my_id(this->ike_sa);
- keymat = this->ike_sa->get_keymat(this->ike_sa);
-
- DBG1(DBG_IKE, "authentication of '%D' (myself) with %N",
- my_id, auth_class_names, AUTH_CLASS_EAP);
-
- auth_data = keymat->get_psk_sig(keymat, FALSE, ike_sa_init, other_nonce,
- this->msk, my_id);
-
- *auth_payload = auth_payload_create();
- (*auth_payload)->set_auth_method(*auth_payload, AUTH_PSK);
- (*auth_payload)->set_data(*auth_payload, auth_data);
- chunk_free(&auth_data);
-
- return SUCCESS;
+ else
+ {
+ server = this->ike_sa->get_other_id(this->ike_sa);
+ peer = this->ike_sa->get_my_id(this->ike_sa);
+ }
+ if (this->eap_identity)
+ {
+ peer = this->eap_identity;
+ }
+ return charon->eap->create_instance(charon->eap, type, vendor,
+ role, server, peer);
}
/**
- * get the peers identity to use in the EAP method
+ * Initiate EAP conversation as server
*/
-static identification_t *get_peer_id(private_eap_authenticator_t *this)
+static eap_payload_t* server_initiate_eap(private_eap_authenticator_t *this,
+ bool do_identity)
{
+ auth_cfg_t *auth;
+ eap_type_t type;
identification_t *id;
- peer_cfg_t *config;
- auth_info_t *auth;
+ u_int32_t vendor;
+ eap_payload_t *out;
- id = this->ike_sa->get_eap_identity(this->ike_sa);
- if (!id)
+ auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
+
+ /* initiate EAP-Identity exchange if required */
+ if (!this->eap_identity && do_identity)
{
- config = this->ike_sa->get_peer_cfg(this->ike_sa);
- auth = config->get_auth(config);
- if (!auth->get_item(auth, AUTHN_EAP_IDENTITY, (void**)&id) ||
- id->get_type(id) == ID_ANY)
+ id = auth->get(auth, AUTH_RULE_EAP_IDENTITY);
+ if (id)
{
- if (this->role == EAP_PEER)
- {
- id = this->ike_sa->get_my_id(this->ike_sa);
- }
- else
+ this->method = load_method(this, EAP_IDENTITY, 0, EAP_SERVER);
+ if (this->method)
{
- id = this->ike_sa->get_other_id(this->ike_sa);
+ if (this->method->initiate(this->method, &out) == NEED_MORE)
+ {
+ DBG1(DBG_IKE, "initiating EAP-Identity request");
+ return out;
+ }
+ this->method->destroy(this->method);
}
+ DBG1(DBG_IKE, "EAP-Identity request configured, but not supported");
}
}
- if (id->get_type(id) == ID_EAP)
+ /* invoke real EAP method */
+ type = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE);
+ vendor = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR);
+ this->method = load_method(this, type, vendor, EAP_SERVER);
+ if (this->method &&
+ this->method->initiate(this->method, &out) == NEED_MORE)
{
- return id->clone(id);
+ if (vendor)
+ {
+ DBG1(DBG_IKE, "initiating EAP vendor type %d-%d", type, vendor);
+
+ }
+ else
+ {
+ DBG1(DBG_IKE, "initiating %N", eap_type_names, type);
+ }
+ return out;
}
- return identification_create_from_encoding(ID_EAP, id->get_encoding(id));
-}
-
-/**
- * get the servers identity to use in the EAP method
- */
-static identification_t *get_server_id(private_eap_authenticator_t *this)
-{
- identification_t *id;
-
- if (this->role == EAP_SERVER)
+ if (vendor)
{
- id = this->ike_sa->get_my_id(this->ike_sa);
+ DBG1(DBG_IKE, "initiating EAP vendor type %d-%d failed", type, vendor);
}
else
{
- id = this->ike_sa->get_other_id(this->ike_sa);
- }
- if (id->get_type(id) == ID_EAP)
- {
- return id->clone(id);
+ DBG1(DBG_IKE, "initiating %N failed", eap_type_names, type);
}
- return identification_create_from_encoding(ID_EAP, id->get_encoding(id));
+ return eap_payload_create_code(EAP_FAILURE, 0);
}
/**
- * load an EAP method using the correct identities
+ * Handle EAP exchange as server
*/
-static eap_method_t *load_method(private_eap_authenticator_t *this,
- eap_type_t type, u_int32_t vendor, eap_role_t role)
+static eap_payload_t* server_process_eap(private_eap_authenticator_t *this,
+ eap_payload_t *in)
{
- identification_t *server, *peer;
- eap_method_t *method;
+ eap_type_t type, received_type;
+ u_int32_t vendor, received_vendor;
+ eap_payload_t *out;
+ auth_cfg_t *cfg;
- server = get_server_id(this);
- peer = get_peer_id(this);
- method = charon->eap->create_instance(charon->eap, type, vendor, role,
- server, peer);
- server->destroy(server);
- peer->destroy(peer);
- return method;
-}
-
-/**
- * Implementation of eap_authenticator_t.initiate
- */
-static status_t initiate(private_eap_authenticator_t *this, eap_type_t type,
- u_int32_t vendor, eap_payload_t **out)
-{
- /* if initiate() is called, role is always server */
- this->role = EAP_SERVER;
-
- if (this->do_eap_identity)
- { /* do an EAP-Identity request first */
- this->type = type;
- this->vendor = vendor;
- vendor = 0;
- type = EAP_IDENTITY;
- }
-
- if (type == 0)
+ if (in->get_code(in) != EAP_RESPONSE)
{
- DBG1(DBG_IKE,
- "client requested EAP authentication, but configuration forbids it");
- *out = eap_payload_create_code(EAP_FAILURE, 0);
- return FAILED;
+ DBG1(DBG_IKE, "received %N, sending %N",
+ eap_code_names, in->get_code(in), eap_code_names, EAP_FAILURE);
+ return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in));
}
- if (vendor)
- {
- DBG1(DBG_IKE, "requesting vendor specific EAP method %d-%d",
- type, vendor);
- }
- else
- {
- DBG1(DBG_IKE, "requesting EAP method %N", eap_type_names, type);
- }
- this->method = load_method(this, type, vendor, this->role);
- if (this->method == NULL)
+ type = this->method->get_type(this->method, &vendor);
+ received_type = in->get_type(in, &received_vendor);
+ if (type != received_type || vendor != received_vendor)
{
- if (vendor == 0 && type == EAP_IDENTITY)
+ if (received_vendor == 0 && received_type == EAP_NAK)
{
- DBG1(DBG_IKE, "skipping %N, no implementation found",
- eap_type_names, type);
- this->do_eap_identity = FALSE;
- return initiate(this, this->type, this->vendor, out);
+ DBG1(DBG_IKE, "received %N, sending %N",
+ eap_type_names, EAP_NAK, eap_code_names, EAP_FAILURE);
}
- DBG1(DBG_IKE, "configured EAP server method not supported, sending %N",
- eap_code_names, EAP_FAILURE);
- *out = eap_payload_create_code(EAP_FAILURE, 0);
- return FAILED;
+ else
+ {
+ DBG1(DBG_IKE, "received invalid EAP response, sending %N",
+ eap_code_names, EAP_FAILURE);
+ }
+ return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in));
}
- if (this->method->initiate(this->method, out) != NEED_MORE)
+
+ switch (this->method->process(this->method, in, &out))
{
- DBG1(DBG_IKE, "failed to initiate EAP exchange, sending %N",
- eap_code_names, EAP_FAILURE);
- *out = eap_payload_create_code(EAP_FAILURE, 0);
- return FAILED;
+ case NEED_MORE:
+ return out;
+ case SUCCESS:
+ if (type == EAP_IDENTITY)
+ {
+ chunk_t data;
+ char buf[256];
+
+ if (this->method->get_msk(this->method, &data) == SUCCESS)
+ {
+ snprintf(buf, sizeof(buf), "%.*s", data.len, data.ptr);
+ this->eap_identity = identification_create_from_string(buf);
+ DBG1(DBG_IKE, "received EAP identity '%D'",
+ this->eap_identity);
+ }
+ /* restart EAP exchange, but with real method */
+ this->method->destroy(this->method);
+ return server_initiate_eap(this, FALSE);
+ }
+ if (this->method->get_msk(this->method, &this->msk) == SUCCESS)
+ {
+ this->msk = chunk_clone(this->msk);
+ }
+ if (vendor)
+ {
+ DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeeded, "
+ "%sMSK established", type, vendor,
+ this->msk.ptr ? "" : "no ");
+ }
+ else
+ {
+ DBG1(DBG_IKE, "EAP method %N succeeded, %sMSK established",
+ eap_type_names, type, this->msk.ptr ? "" : "no ");
+ }
+ this->ike_sa->set_condition(this->ike_sa, COND_EAP_AUTHENTICATED,
+ TRUE);
+ cfg = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
+ cfg->add(cfg, AUTH_RULE_EAP_TYPE, type);
+ if (vendor)
+ {
+ cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor);
+ }
+ this->eap_complete = TRUE;
+ return eap_payload_create_code(EAP_SUCCESS, in->get_identifier(in));
+ case FAILED:
+ default:
+ if (vendor)
+ {
+ DBG1(DBG_IKE, "EAP vendor specific method %d-%d failed for "
+ "peer %D", type, vendor,
+ this->ike_sa->get_other_id(this->ike_sa));
+ }
+ else
+ {
+ DBG1(DBG_IKE, "EAP method %N failed for peer %D",
+ eap_type_names, type,
+ this->ike_sa->get_other_id(this->ike_sa));
+ }
+ return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in));
}
- return NEED_MORE;
}
/**
* Processing method for a peer
*/
-static status_t process_peer(private_eap_authenticator_t *this,
- eap_payload_t *in, eap_payload_t **out)
+static eap_payload_t* client_process_eap(private_eap_authenticator_t *this,
+ eap_payload_t *in)
{
eap_type_t type;
u_int32_t vendor;
+ auth_cfg_t *auth;
+ eap_payload_t *out;
+ identification_t *id;
type = in->get_type(in, &vendor);
if (!vendor && type == EAP_IDENTITY)
{
- eap_method_t *method;
+ DESTROY_IF(this->eap_identity);
+ auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
+ id = auth->get(auth, AUTH_RULE_EAP_IDENTITY);
+ if (!id || id->get_type(id) == ID_ANY)
+ {
+ id = this->ike_sa->get_my_id(this->ike_sa);
+ }
+ DBG1(DBG_IKE, "server requested %N, sending '%D'",
+ eap_type_names, type, id);
+ this->eap_identity = id->clone(id);
- method = load_method(this, type, 0, EAP_PEER);
- if (method == NULL || method->process(method, in, out) != SUCCESS)
+ this->method = load_method(this, type, vendor, EAP_PEER);
+ if (this->method)
{
- DBG1(DBG_IKE, "EAP server requested %N, but unable to process",
- eap_type_names, type);
- DESTROY_IF(method);
- return FAILED;
+ if (this->method->process(this->method, in, &out) == SUCCESS)
+ {
+ this->method->destroy(this->method);
+ this->method = NULL;
+ return out;
+ }
+ this->method->destroy(this->method);
+ this->method = NULL;
}
- DBG1(DBG_IKE, "EAP server requested %N", eap_type_names, type);
- method->destroy(method);
- return NEED_MORE;
+ DBG1(DBG_IKE, "%N not supported, sending EAP_NAK",
+ eap_type_names, type);
+ return eap_payload_create_nak(in->get_identifier(in));
}
-
- /* create an eap_method for the first call */
if (this->method == NULL)
{
if (vendor)
{
- DBG1(DBG_IKE, "EAP server requested vendor specific EAP method %d-%d",
+ DBG1(DBG_IKE, "server requested vendor specific EAP method %d-%d",
type, vendor);
}
else
{
- DBG1(DBG_IKE, "EAP server requested %N authentication",
+ DBG1(DBG_IKE, "server requested %N authentication",
eap_type_names, type);
}
this->method = load_method(this, type, vendor, EAP_PEER);
- if (this->method == NULL)
+ if (!this->method)
{
- DBG1(DBG_IKE, "EAP server requested unsupported "
- "EAP method, sending EAP_NAK");
- *out = eap_payload_create_nak(in->get_identifier(in));
- return NEED_MORE;
+ DBG1(DBG_IKE, "EAP method not supported, sending EAP_NAK");
+ return eap_payload_create_nak(in->get_identifier(in));
}
}
type = this->method->get_type(this->method, &vendor);
- switch (this->method->process(this->method, in, out))
+ if (this->method->process(this->method, in, &out) == NEED_MORE)
+ { /* client methods should never return SUCCESS */
+ return out;
+ }
+
+ if (vendor)
{
- case NEED_MORE:
- return NEED_MORE;
- case SUCCESS:
- if (vendor)
- {
- DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeded",
- type, vendor);
- }
- else
- {
- DBG1(DBG_IKE, "EAP method %N succeeded", eap_type_names, type);
- }
- return SUCCESS;
- case FAILED:
- default:
- if (vendor)
- {
- DBG1(DBG_IKE, "EAP vendor specific method %d-%d failed",
- type, vendor);
- }
- else
- {
- DBG1(DBG_IKE, "EAP method %N failed",
- eap_type_names, type);
- }
- return FAILED;
+ DBG1(DBG_IKE, "vendor specific EAP method %d-%d failed", type, vendor);
+ }
+ else
+ {
+ DBG1(DBG_IKE, "%N method failed", eap_type_names, type);
}
+ return NULL;
}
/**
- * handle an EAP-Identity response on the server
+ * Verify AUTH payload
*/
-static status_t process_eap_identity(private_eap_authenticator_t *this,
- eap_payload_t **out)
+static bool verify_auth(private_eap_authenticator_t *this, message_t *message)
{
- chunk_t data;
- identification_t *id;
-
- if (this->method->get_msk(this->method, &data) == SUCCESS)
+ auth_payload_t *auth_payload;
+ chunk_t auth_data, recv_auth_data;
+ identification_t *other_id;
+ auth_cfg_t *auth;
+ keymat_t *keymat;
+
+ auth_payload = (auth_payload_t*)message->get_payload(message,
+ AUTHENTICATION);
+ if (!auth_payload)
{
- id = identification_create_from_encoding(ID_EAP, data);
- DBG1(DBG_IKE, "using EAP identity '%D'", id);
- this->ike_sa->set_eap_identity(this->ike_sa, id);
+ DBG1(DBG_IKE, "AUTH payload missing");
+ return FALSE;
}
- /* restart EAP exchange, but with real method */
- this->method->destroy(this->method);
- this->method = NULL;
- this->do_eap_identity = FALSE;
- return initiate(this, this->type, this->vendor, out);
+ other_id = this->ike_sa->get_other_id(this->ike_sa);
+ keymat = this->ike_sa->get_keymat(this->ike_sa);
+ auth_data = keymat->get_psk_sig(keymat, TRUE, this->ike_sa_init,
+ this->nonce, this->msk, other_id);
+ recv_auth_data = auth_payload->get_data(auth_payload);
+ if (!auth_data.len || !chunk_equals(auth_data, recv_auth_data))
+ {
+ DBG1(DBG_IKE, "verification of AUTH payload with%s EAP MSK failed",
+ this->msk.ptr ? "" : "out");
+ chunk_free(&auth_data);
+ return FALSE;
+ }
+ chunk_free(&auth_data);
+
+ DBG1(DBG_IKE, "authentication of '%D' with %N successful",
+ other_id, auth_class_names, AUTH_CLASS_EAP);
+ this->auth_complete = TRUE;
+ auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
+ auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
+ return TRUE;
+}
+
+/**
+ * Build AUTH payload
+ */
+static void build_auth(private_eap_authenticator_t *this, message_t *message)
+{
+ auth_payload_t *auth_payload;
+ identification_t *my_id;
+ chunk_t auth_data;
+ keymat_t *keymat;
+
+ my_id = this->ike_sa->get_my_id(this->ike_sa);
+ keymat = this->ike_sa->get_keymat(this->ike_sa);
+
+ DBG1(DBG_IKE, "authentication of '%D' (myself) with %N",
+ my_id, auth_class_names, AUTH_CLASS_EAP);
+
+ auth_data = keymat->get_psk_sig(keymat, FALSE, this->ike_sa_init,
+ this->nonce, this->msk, my_id);
+ auth_payload = auth_payload_create();
+ auth_payload->set_auth_method(auth_payload, AUTH_PSK);
+ auth_payload->set_data(auth_payload, auth_data);
+ message->add_payload(message, (payload_t*)auth_payload);
+ chunk_free(&auth_data);
}
/**
- * Processing method for a server
+ * Implementation of authenticator_t.process for a server
*/
static status_t process_server(private_eap_authenticator_t *this,
- eap_payload_t *in, eap_payload_t **out)
+ message_t *message)
{
- eap_type_t type;
- u_int32_t vendor;
+ eap_payload_t *eap_payload;
- type = this->method->get_type(this->method, &vendor);
+ if (this->eap_complete)
+ {
+ if (!verify_auth(this, message))
+ {
+ return FAILED;
+ }
+ return NEED_MORE;
+ }
- switch (this->method->process(this->method, in, out))
+ if (!this->method)
{
- case NEED_MORE:
- return NEED_MORE;
- case SUCCESS:
- if (this->do_eap_identity)
- {
- return process_eap_identity(this, out);
- }
- if (this->method->get_msk(this->method, &this->msk) == SUCCESS)
- {
- this->msk = chunk_clone(this->msk);
- }
- if (vendor)
- {
- DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeded, "
- "%sMSK established", type, vendor,
- this->msk.ptr ? "" : "no ");
- }
- else
- {
- DBG1(DBG_IKE, "EAP method %N succeded, %sMSK established",
- eap_type_names, type, this->msk.ptr ? "" : "no ");
- }
- *out = eap_payload_create_code(EAP_SUCCESS, in->get_identifier(in));
- return SUCCESS;
- case FAILED:
- default:
- if (vendor)
- {
- DBG1(DBG_IKE, "EAP vendor specific method %d-%d failed for "
- "peer %D", type, vendor,
- this->ike_sa->get_other_id(this->ike_sa));
- }
- else
- {
- DBG1(DBG_IKE, "EAP method %N failed for peer '%D'",
- eap_type_names, type,
- this->ike_sa->get_other_id(this->ike_sa));
- }
- *out = eap_payload_create_code(EAP_FAILURE, in->get_identifier(in));
+ this->eap_payload = server_initiate_eap(this, TRUE);
+ }
+ else
+ {
+ eap_payload = (eap_payload_t*)message->get_payload(message,
+ EXTENSIBLE_AUTHENTICATION);
+ if (!eap_payload)
+ {
return FAILED;
+ }
+ this->eap_payload = server_process_eap(this, eap_payload);
}
+ return NEED_MORE;
}
/**
- * Implementation of eap_authenticator_t.process
+ * Implementation of authenticator_t.build for a server
*/
-static status_t process(private_eap_authenticator_t *this, eap_payload_t *in,
- eap_payload_t **out)
+static status_t build_server(private_eap_authenticator_t *this,
+ message_t *message)
{
- eap_code_t code = in->get_code(in);
+ if (this->eap_payload)
+ {
+ eap_code_t code;
+
+ code = this->eap_payload->get_code(this->eap_payload);
+ message->add_payload(message, (payload_t*)this->eap_payload);
+ this->eap_payload = NULL;
+ if (code == EAP_FAILURE)
+ {
+ return FAILED;
+ }
+ return NEED_MORE;
+ }
+ if (this->eap_complete && this->auth_complete)
+ {
+ build_auth(this, message);
+ return SUCCESS;
+ }
+ return FAILED;
+}
+
+/**
+ * Implementation of authenticator_t.process for a client
+ */
+static status_t process_client(private_eap_authenticator_t *this,
+ message_t *message)
+{
+ eap_payload_t *eap_payload;
- switch (this->role)
+ if (this->eap_complete)
{
- case EAP_SERVER:
+ if (!verify_auth(this, message))
{
- switch (code)
- {
- case EAP_RESPONSE:
- {
- return process_server(this, in, out);
- }
- default:
- {
- DBG1(DBG_IKE, "received %N, sending %N",
- eap_code_names, code, eap_code_names, EAP_FAILURE);
- *out = eap_payload_create_code(EAP_FAILURE,
- in->get_identifier(in));
- return FAILED;
- }
- }
+ return FAILED;
}
- case EAP_PEER:
+ return SUCCESS;
+ }
+
+ eap_payload = (eap_payload_t*)message->get_payload(message,
+ EXTENSIBLE_AUTHENTICATION);
+ if (eap_payload)
+ {
+ switch (eap_payload->get_code(eap_payload))
{
- switch (code)
+ case EAP_REQUEST:
+ {
+ this->eap_payload = client_process_eap(this, eap_payload);
+ return NEED_MORE;
+ }
+ case EAP_SUCCESS:
{
- case EAP_REQUEST:
+ eap_type_t type;
+ u_int32_t vendor;
+ auth_cfg_t *cfg;
+
+ if (this->method->get_msk(this->method, &this->msk) == SUCCESS)
{
- return process_peer(this, in, out);
+ this->msk = chunk_clone(this->msk);
}
- case EAP_SUCCESS:
+ type = this->method->get_type(this->method, &vendor);
+ if (vendor)
{
- if (this->method->get_msk(this->method, &this->msk) == SUCCESS)
- {
- this->msk = chunk_clone(this->msk);
- }
- return SUCCESS;
+ DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeeded, "
+ "%sMSK established", type, vendor,
+ this->msk.ptr ? "" : "no ");
}
- case EAP_FAILURE:
- default:
+ else
{
- DBG1(DBG_IKE, "received %N, EAP authentication failed",
- eap_code_names, code);
- return FAILED;
+ DBG1(DBG_IKE, "EAP method %N succeeded, %sMSK established",
+ eap_type_names, type, this->msk.ptr ? "" : "no ");
}
+ cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
+ cfg->add(cfg, AUTH_RULE_EAP_TYPE, type);
+ if (vendor)
+ {
+ cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor);
+ }
+ this->eap_complete = TRUE;
+ return NEED_MORE;
+ }
+ case EAP_FAILURE:
+ default:
+ {
+ DBG1(DBG_IKE, "received %N, EAP authentication failed",
+ eap_code_names, eap_payload->get_code(eap_payload));
+ return FAILED;
}
- }
- default:
- {
- return FAILED;
}
}
+ return FAILED;
}
/**
- * Implementation of authenticator_t.is_mutual.
+ * Implementation of authenticator_t.build for a client
*/
-static bool is_mutual(private_eap_authenticator_t *this)
+static status_t build_client(private_eap_authenticator_t *this,
+ message_t *message)
{
- if (this->method)
+ if (this->eap_payload)
{
- return this->method->is_mutual(this->method);
+ message->add_payload(message, (payload_t*)this->eap_payload);
+ this->eap_payload = NULL;
+ return NEED_MORE;
}
- return FALSE;
+ if (this->eap_complete)
+ {
+ build_auth(this, message);
+ return NEED_MORE;
+ }
+ return NEED_MORE;
}
/**
@@ -500,6 +571,8 @@ static bool is_mutual(private_eap_authenticator_t *this)
static void destroy(private_eap_authenticator_t *this)
{
DESTROY_IF(this->method);
+ DESTROY_IF(this->eap_payload);
+ DESTROY_IF(this->eap_identity);
chunk_free(&this->msk);
free(this);
}
@@ -507,46 +580,50 @@ static void destroy(private_eap_authenticator_t *this)
/*
* Described in header.
*/
-eap_authenticator_t *eap_authenticator_create(ike_sa_t *ike_sa)
+eap_authenticator_t *eap_authenticator_create_builder(ike_sa_t *ike_sa,
+ chunk_t received_nonce, chunk_t sent_init)
{
- peer_cfg_t *config;
- auth_info_t *auth;
- identification_t *id;
private_eap_authenticator_t *this = malloc_thing(private_eap_authenticator_t);
- /* public functions */
- this->public.authenticator_interface.verify = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t*))verify;
- this->public.authenticator_interface.build = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t**))build;
- this->public.authenticator_interface.destroy = (void(*)(authenticator_t*))destroy;
-
- this->public.is_mutual = (bool(*)(eap_authenticator_t*))is_mutual;
- this->public.initiate = (status_t(*)(eap_authenticator_t*,eap_type_t,u_int32_t,eap_payload_t**))initiate;
- this->public.process = (status_t(*)(eap_authenticator_t*,eap_payload_t*,eap_payload_t**))process;
+ this->public.authenticator.build = (status_t(*)(authenticator_t*, message_t *message))build_client;
+ this->public.authenticator.process = (status_t(*)(authenticator_t*, message_t *message))process_client;
+ this->public.authenticator.destroy = (void(*)(authenticator_t*))destroy;
- /* private data */
this->ike_sa = ike_sa;
- this->role = EAP_PEER;
+ this->ike_sa_init = sent_init;
+ this->nonce = received_nonce;
+ this->msk = chunk_empty;
this->method = NULL;
+ this->eap_payload = NULL;
+ this->eap_complete = FALSE;
+ this->auth_complete = FALSE;
+ this->eap_identity = NULL;
+
+ return &this->public;
+}
+
+/*
+ * Described in header.
+ */
+eap_authenticator_t *eap_authenticator_create_verifier(ike_sa_t *ike_sa,
+ chunk_t sent_nonce, chunk_t received_init)
+{
+ private_eap_authenticator_t *this = malloc_thing(private_eap_authenticator_t);
+
+ this->public.authenticator.build = (status_t(*)(authenticator_t*, message_t *messageh))build_server;
+ this->public.authenticator.process = (status_t(*)(authenticator_t*, message_t *message))process_server;
+ this->public.authenticator.destroy = (void(*)(authenticator_t*))destroy;
+
+ this->ike_sa = ike_sa;
+ this->ike_sa_init = received_init;
+ this->nonce = sent_nonce;
this->msk = chunk_empty;
- this->do_eap_identity = FALSE;
- this->type = 0;
- this->vendor = 0;
+ this->method = NULL;
+ this->eap_payload = NULL;
+ this->eap_complete = FALSE;
+ this->auth_complete = FALSE;
+ this->eap_identity = NULL;
- config = ike_sa->get_peer_cfg(ike_sa);
- if (config)
- {
- auth = config->get_auth(config);
- if (auth->get_item(auth, AUTHN_EAP_IDENTITY, (void**)&id))
- {
- if (id->get_type(id) == ID_ANY)
- { /* %any as configured EAP identity runs EAP-Identity first */
- this->do_eap_identity = TRUE;
- }
- else
- {
- ike_sa->set_eap_identity(ike_sa, id->clone(id));
- }
- }
- }
return &this->public;
}
+