Commit 0ca16aba33 for strongswan.org
commit 0ca16aba3300472cd3868d9a7f564c7fd409e7ac
Author: Tobias Brunner <tobias@strongswan.org>
Date: Mon Jul 27 12:02:38 2026 +0200
unit-tests: Add possibility to test EAP authentication
diff --git a/src/libcharon/tests/Makefile.am b/src/libcharon/tests/Makefile.am
index 1d925019cf..8a3a432895 100644
--- a/src/libcharon/tests/Makefile.am
+++ b/src/libcharon/tests/Makefile.am
@@ -35,6 +35,7 @@ exchange_tests_SOURCES = \
utils/exchange_test_asserts.h utils/exchange_test_asserts.c \
utils/exchange_test_helper.h utils/exchange_test_helper.c \
utils/job_asserts.h \
+ utils/mock_eap.h utils/mock_eap.c \
utils/mock_dh.h utils/mock_dh.c \
utils/mock_ipsec.h utils/mock_ipsec.c \
utils/mock_net.h utils/mock_net.c \
diff --git a/src/libcharon/tests/utils/exchange_test_helper.c b/src/libcharon/tests/utils/exchange_test_helper.c
index 42530be44b..93aa35ca2d 100644
--- a/src/libcharon/tests/utils/exchange_test_helper.c
+++ b/src/libcharon/tests/utils/exchange_test_helper.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016-2018 Tobias Brunner
+ * Copyright (C) 2016-2026 Tobias Brunner
*
* Copyright (C) secunet Security Networks AG
*
@@ -15,6 +15,7 @@
*/
#include "exchange_test_helper.h"
+#include "mock_eap.h"
#include "mock_dh.h"
#include "mock_ipsec.h"
#include "mock_net.h"
@@ -163,16 +164,24 @@ static child_cfg_t *create_child_cfg(bool initiator,
return child_cfg;
}
-static void add_auth_cfg(peer_cfg_t *peer_cfg, bool initiator, bool local)
+static void add_auth_cfg(peer_cfg_t *peer_cfg, bool initiator, bool local,
+ exchange_test_sa_conf_t *conf)
{
auth_cfg_t *auth;
char *id = "init";
+ bool eap = conf ? conf->initiator.eap : FALSE;
- auth = auth_cfg_create();
- auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
- if (initiator ^ local)
+ if (initiator != local)
{
id = "resp";
+ eap = conf ? conf->responder.eap : FALSE;
+ }
+
+ auth = auth_cfg_create();
+ auth->add(auth, AUTH_RULE_AUTH_CLASS, eap ? AUTH_CLASS_EAP : AUTH_CLASS_PSK);
+ if (eap)
+ {
+ auth->add(auth, AUTH_RULE_EAP_TYPE, EAP_GTC);
}
auth->add(auth, AUTH_RULE_IDENTITY, identification_create_from_string(id));
peer_cfg->add_auth_cfg(peer_cfg, auth, local);
@@ -190,8 +199,8 @@ static peer_cfg_t *create_peer_cfg(bool initiator,
peer_cfg = peer_cfg_create(initiator ? "init" : "resp",
create_ike_cfg(initiator, conf), &peer);
- add_auth_cfg(peer_cfg, initiator, TRUE);
- add_auth_cfg(peer_cfg, initiator, FALSE);
+ add_auth_cfg(peer_cfg, initiator, TRUE, conf);
+ add_auth_cfg(peer_cfg, initiator, FALSE, conf);
return peer_cfg;
}
@@ -380,6 +389,10 @@ void exchange_test_helper_init(char *plugins)
PLUGIN_REGISTER(NONCE_GEN, create_nonce_gen),
PLUGIN_PROVIDE(NONCE_GEN),
PLUGIN_DEPENDS(RNG, RNG_WEAK),
+ PLUGIN_CALLBACK(eap_method_register, mock_eap_create_server),
+ PLUGIN_PROVIDE(EAP_SERVER, EAP_GTC),
+ PLUGIN_CALLBACK(eap_method_register, mock_eap_create_peer),
+ PLUGIN_PROVIDE(EAP_PEER, EAP_GTC),
};
INIT(backend,
diff --git a/src/libcharon/tests/utils/exchange_test_helper.h b/src/libcharon/tests/utils/exchange_test_helper.h
index b42f79d645..9746e4d238 100644
--- a/src/libcharon/tests/utils/exchange_test_helper.h
+++ b/src/libcharon/tests/utils/exchange_test_helper.h
@@ -112,6 +112,8 @@ struct exchange_test_sa_conf_t {
char *esp;
/** Support for childless IKE_SAs */
childless_t childless;
+ /** Use EAP authentication */
+ bool eap;
} initiator, responder;
};
diff --git a/src/libcharon/tests/utils/mock_eap.c b/src/libcharon/tests/utils/mock_eap.c
new file mode 100644
index 0000000000..f39b395906
--- /dev/null
+++ b/src/libcharon/tests/utils/mock_eap.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2026 Tobias Brunner
+ *
+ * Copyright (C) secunet Security Networks AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "mock_eap.h"
+
+#define REQUEST_MSG "password"
+#define MOCK_PW_MSG "mock password"
+
+typedef struct private_eap_method_t private_eap_method_t;
+
+/**
+ * Private data
+ */
+struct private_eap_method_t {
+
+ /**
+ * Public interface
+ */
+ eap_method_t public;
+
+ /**
+ * ID of the server
+ */
+ identification_t *server;
+
+ /**
+ * ID of the peer
+ */
+ identification_t *peer;
+
+ /**
+ * EAP message identifier
+ */
+ uint8_t identifier;
+};
+
+typedef struct eap_gtc_header_t eap_gtc_header_t;
+
+/**
+ * packed eap GTC header struct
+ */
+struct eap_gtc_header_t {
+ /** EAP code (REQUEST/RESPONSE) */
+ uint8_t code;
+ /** unique message identifier */
+ uint8_t identifier;
+ /** length of whole message */
+ uint16_t length;
+ /** EAP type */
+ uint8_t type;
+ /** type data */
+ uint8_t data[];
+} __attribute__((__packed__));
+
+METHOD(eap_method_t, initiate_peer, status_t,
+ private_eap_method_t *this, eap_payload_t **out)
+{
+ /* peer never initiates */
+ return FAILED;
+}
+
+METHOD(eap_method_t, initiate_server, status_t,
+ private_eap_method_t *this, eap_payload_t **out)
+{
+ eap_gtc_header_t *req;
+ size_t len;
+
+ len = strlen(REQUEST_MSG);
+ req = alloca(sizeof(eap_gtc_header_t) + len);
+ req->length = htons(sizeof(eap_gtc_header_t) + len);
+ req->code = EAP_REQUEST;
+ req->identifier = this->identifier;
+ req->type = EAP_GTC;
+ memcpy(req->data, REQUEST_MSG, len);
+
+ *out = eap_payload_create_data(chunk_create((void*)req,
+ sizeof(eap_gtc_header_t) + len));
+ return NEED_MORE;
+}
+
+METHOD(eap_method_t, process_peer, status_t,
+ private_eap_method_t *this, eap_payload_t *in, eap_payload_t **out)
+{
+ eap_gtc_header_t *res;
+ size_t len;
+
+ len = strlen(MOCK_PW_MSG);
+ this->identifier = in->get_identifier(in);
+ res = alloca(sizeof(eap_gtc_header_t) + len);
+ res->length = htons(sizeof(eap_gtc_header_t) + len);
+ res->code = EAP_RESPONSE;
+ res->identifier = this->identifier;
+ res->type = EAP_GTC;
+ memcpy(res->data, MOCK_PW_MSG, len);
+
+ *out = eap_payload_create_data(chunk_create((void*)res,
+ sizeof(eap_gtc_header_t) + len));
+ return NEED_MORE;
+}
+
+METHOD(eap_method_t, process_server, status_t,
+ private_eap_method_t *this, eap_payload_t *in, eap_payload_t **out)
+{
+ chunk_t pass;
+
+ pass = chunk_skip(in->get_data(in), 5);
+ if (this->identifier != in->get_identifier(in) || !pass.len ||
+ !chunk_equals_const(chunk_from_str(MOCK_PW_MSG), pass))
+ {
+ DBG1(DBG_IKE, "received invalid EAP-GTC message");
+ return FAILED;
+ }
+ return SUCCESS;
+}
+
+METHOD(eap_method_t, get_type, eap_type_t,
+ private_eap_method_t *this, pen_t *vendor)
+{
+ *vendor = 0;
+ return EAP_GTC;
+}
+
+METHOD(eap_method_t, get_msk, status_t,
+ private_eap_method_t *this, chunk_t *msk)
+{
+ return NOT_SUPPORTED;
+}
+
+METHOD(eap_method_t, get_identifier, uint8_t,
+ private_eap_method_t *this)
+{
+ return this->identifier;
+}
+
+METHOD(eap_method_t, set_identifier, void,
+ private_eap_method_t *this, uint8_t identifier)
+{
+ this->identifier = identifier;
+}
+
+METHOD(eap_method_t, is_mutual, bool,
+ private_eap_method_t *this)
+{
+ return FALSE;
+}
+
+METHOD(eap_method_t, destroy, void,
+ private_eap_method_t *this)
+{
+ this->peer->destroy(this->peer);
+ this->server->destroy(this->server);
+ free(this);
+}
+
+/**
+ * Generic constructor
+ */
+static private_eap_method_t *mock_eap_create_generic(identification_t *server,
+ identification_t *peer)
+{
+ private_eap_method_t *this;
+
+ INIT(this,
+ .public = {
+ .get_type = _get_type,
+ .is_mutual = _is_mutual,
+ .get_msk = _get_msk,
+ .get_identifier = _get_identifier,
+ .set_identifier = _set_identifier,
+ .destroy = _destroy,
+ },
+ .peer = peer->clone(peer),
+ .server = server->clone(server),
+ );
+
+ return this;
+}
+
+/*
+ * Described in header
+ */
+eap_method_t *mock_eap_create_server(identification_t *server,
+ identification_t *peer)
+{
+ private_eap_method_t *this = mock_eap_create_generic(server, peer);
+
+ this->public.initiate = _initiate_server;
+ this->public.process = _process_server;
+
+ /* generate a non-zero identifier */
+ do {
+ this->identifier = random();
+ } while (!this->identifier);
+
+ return &this->public;
+}
+
+/*
+ * Described in header
+ */
+eap_method_t *mock_eap_create_peer(identification_t *server,
+ identification_t *peer)
+{
+ private_eap_method_t *this = mock_eap_create_generic(server, peer);
+
+ this->public.initiate = _initiate_peer;
+ this->public.process = _process_peer;
+
+ return &this->public;
+}
diff --git a/src/libcharon/tests/utils/mock_eap.h b/src/libcharon/tests/utils/mock_eap.h
new file mode 100644
index 0000000000..2707949363
--- /dev/null
+++ b/src/libcharon/tests/utils/mock_eap.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2026 Tobias Brunner
+ *
+ * Copyright (C) secunet Security Networks AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * Provides an EAP method implementation that does no real work.
+ *
+ * @defgroup mock_eap mock_eap
+ * @{ @ingroup test_utils_c
+ */
+
+#ifndef MOCK_EAP_H_
+#define MOCK_EAP_H_
+
+#include <sa/eap/eap_method.h>
+
+/**
+ * Creates an EAP method acting as server.
+ *
+ * @param server ID of the EAP server
+ * @param peer ID of the EAP client
+ * @return created object
+ */
+eap_method_t *mock_eap_create_server(identification_t *server,
+ identification_t *peer);
+
+/**
+ * Creates an EAP method acting as client.
+ *
+ * @param server ID of the EAP server
+ * @param peer ID of the EAP client
+ * @return created object
+ */
+eap_method_t *mock_eap_create_peer(identification_t *server,
+ identification_t *peer);
+
+#endif /** MOCK_EAP_H_ @}*/