]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
unit-tests: Add helper class/object to test IKE exchanges
authorTobias Brunner <tobias@strongswan.org>
Thu, 12 May 2016 15:03:44 +0000 (17:03 +0200)
committerTobias Brunner <tobias@strongswan.org>
Fri, 17 Jun 2016 16:48:01 +0000 (18:48 +0200)
src/libcharon/tests/Makefile.am
src/libcharon/tests/utils/exchange_test_helper.c [new file with mode: 0644]
src/libcharon/tests/utils/exchange_test_helper.h [new file with mode: 0644]

index 0d2dd4b00e64d9bdde8ee67ad47a839a4051f699..65d44898cf971c5aab2463a84e410f848c90c538 100644 (file)
@@ -6,6 +6,7 @@ libcharon_tests_SOURCES = \
   suites/test_ike_cfg.c \
   suites/test_mem_pool.c \
   suites/test_message_chapoly.c \
+  utils/exchange_test_helper.h utils/exchange_test_helper.c \
   utils/mock_ipsec.h utils/mock_ipsec.c \
   utils/mock_sender.h utils/mock_sender.c \
   libcharon_tests.h libcharon_tests.c
diff --git a/src/libcharon/tests/utils/exchange_test_helper.c b/src/libcharon/tests/utils/exchange_test_helper.c
new file mode 100644 (file)
index 0000000..f3f6996
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2016 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * 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 "exchange_test_helper.h"
+#include "mock_ipsec.h"
+
+#include <credentials/sets/mem_cred.h>
+
+typedef struct private_exchange_test_helper_t private_exchange_test_helper_t;
+
+/**
+ * Private data
+ */
+struct private_exchange_test_helper_t {
+
+       /**
+        * Public interface
+        */
+       exchange_test_helper_t public;
+
+       /**
+        * Config backend
+        */
+       backend_t backend;
+
+       /**
+        * Credentials
+        */
+       mem_cred_t *creds;
+};
+
+/*
+ * Described in header
+ */
+exchange_test_helper_t *exchange_test_helper;
+
+static ike_cfg_t *create_ike_cfg()
+{
+       ike_cfg_t *ike_cfg;
+
+       ike_cfg = ike_cfg_create(IKEV2, TRUE, FALSE, "127.0.0.1", IKEV2_UDP_PORT,
+                                                        "127.0.0.1", IKEV2_UDP_PORT, FRAGMENTATION_NO, 0);
+       ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
+       return ike_cfg;
+}
+
+static child_cfg_t *create_child_cfg(bool initiator)
+{
+       child_cfg_t *child_cfg;
+       child_cfg_create_t child = {
+               .mode = MODE_TUNNEL,
+       };
+
+       child_cfg = child_cfg_create(initiator ? "init" : "resp", &child);
+       child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP));
+       child_cfg->add_proposal(child_cfg, proposal_create_default_aead(PROTO_ESP));
+       child_cfg->add_traffic_selector(child_cfg, TRUE,
+                                                               traffic_selector_create_dynamic(0, 0, 65535));
+       child_cfg->add_traffic_selector(child_cfg, FALSE,
+                                                               traffic_selector_create_dynamic(0, 0, 65535));
+       return child_cfg;
+}
+
+static void add_auth_cfg(peer_cfg_t *peer_cfg, bool initiator, bool local)
+{
+       auth_cfg_t *auth;
+       char *id = "init";
+
+       auth = auth_cfg_create();
+       auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
+       if (initiator ^ local)
+       {
+               id = "resp";
+       }
+       auth->add(auth, AUTH_RULE_IDENTITY, identification_create_from_string(id));
+       peer_cfg->add_auth_cfg(peer_cfg, auth, local);
+}
+
+static peer_cfg_t *create_peer_cfg(bool initiator)
+{
+       peer_cfg_t *peer_cfg;
+       peer_cfg_create_t peer = {
+               .cert_policy = CERT_SEND_IF_ASKED,
+               .unique = UNIQUE_REPLACE,
+               .keyingtries = 1,
+       };
+
+       peer_cfg = peer_cfg_create(initiator ? "init" : "resp", create_ike_cfg(),
+                                                          &peer);
+       add_auth_cfg(peer_cfg, initiator, TRUE);
+       add_auth_cfg(peer_cfg, initiator, FALSE);
+       peer_cfg->add_child_cfg(peer_cfg, create_child_cfg(initiator));
+       return peer_cfg;
+}
+
+METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*,
+       backend_t *this, host_t *me, host_t *other)
+{
+       ike_cfg_t *ike_cfg = create_ike_cfg();
+       return enumerator_create_single(ike_cfg, (void*)ike_cfg->destroy);
+}
+
+METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
+       backend_t *this, identification_t *me, identification_t *other)
+{
+       peer_cfg_t *peer_cfg = create_peer_cfg(FALSE);
+       return enumerator_create_single(peer_cfg, (void*)peer_cfg->destroy);
+}
+
+METHOD(exchange_test_helper_t, process_message, void,
+       private_exchange_test_helper_t *this, ike_sa_t *ike_sa, message_t *message)
+{
+       if (!message)
+       {
+               message = this->public.sender->dequeue(this->public.sender);
+       }
+       charon->bus->set_sa(charon->bus, ike_sa);
+       ike_sa->process_message(ike_sa, message);
+       charon->bus->set_sa(charon->bus, NULL);
+       message->destroy(message);
+}
+
+METHOD(exchange_test_helper_t, establish_sa, void,
+       private_exchange_test_helper_t *this, ike_sa_t **init, ike_sa_t **resp)
+{
+       ike_sa_id_t *id_i, *id_r;
+       ike_sa_t *sa_i, *sa_r;
+       peer_cfg_t *peer_cfg;
+
+       sa_i = *init = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
+                                                                                                               IKEV2, TRUE);
+       id_i = sa_i->get_id(sa_i);
+
+       sa_r = *resp = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
+                                                                                                               IKEV2, FALSE);
+       id_r = sa_r->get_id(sa_r);
+
+       peer_cfg = create_peer_cfg(TRUE);
+       sa_i->set_peer_cfg(sa_i, peer_cfg);
+       peer_cfg->destroy(peer_cfg);
+       charon->bus->set_sa(charon->bus, sa_i);
+       sa_i->initiate(sa_i, create_child_cfg(TRUE), 0, NULL, NULL);
+       /* IKE_SA_INIT --> */
+       id_r->set_initiator_spi(id_r, id_i->get_initiator_spi(id_i));
+       process_message(this, sa_r, NULL);
+       /* <-- IKE_SA_INIT */
+       id_i->set_responder_spi(id_i, id_r->get_responder_spi(id_r));
+       process_message(this, sa_i, NULL);
+       /* IKE_AUTH --> */
+       process_message(this, sa_r, NULL);
+       /* <-- IKE_AUTH */
+       process_message(this, sa_i, NULL);
+}
+
+/**
+ * Enable logging in charon as requested
+ */
+static void initialize_logging()
+{
+       int level = LEVEL_SILENT;
+       char *verbosity;
+
+       verbosity = getenv("TESTS_VERBOSITY");
+       if (verbosity)
+       {
+               level = atoi(verbosity);
+       }
+       lib->settings->set_int(lib->settings, "%s.filelog.stderr.default",
+                       lib->settings->get_int(lib->settings, "%s.filelog.stderr.default",
+                                                                  level, lib->ns), lib->ns);
+       lib->settings->set_bool(lib->settings, "%s.filelog.stderr.ike_name", TRUE,
+                                                       lib->ns);
+       charon->load_loggers(charon, NULL, TRUE);
+}
+
+/*
+ * Described in header
+ */
+void exchange_test_helper_init(char *plugins)
+{
+       private_exchange_test_helper_t *this;
+
+       INIT(this,
+               .public = {
+                       .sender = mock_sender_create(),
+                       .establish_sa = _establish_sa,
+                       .process_message = _process_message,
+               },
+               .backend = {
+                       .create_ike_cfg_enumerator = _create_ike_cfg_enumerator,
+                       .create_peer_cfg_enumerator = _create_peer_cfg_enumerator,
+                       .get_peer_cfg_by_name = (void*)return_null,
+               },
+               .creds = mem_cred_create(),
+       );
+
+       initialize_logging();
+       /* the libcharon unit tests only load the libstrongswan plugins, unless
+        * TESTS_PLUGINS is defined */
+       charon->initialize(charon, plugins);
+       lib->plugins->status(lib->plugins, LEVEL_CTRL);
+       /* the original sender is not initialized because there is no socket */
+       charon->sender = (sender_t*)this->public.sender;
+       /* and there is no kernel plugin loaded
+        * TODO: we'd have more control if we'd implement kernel_interface_t */
+       charon->kernel->add_ipsec_interface(charon->kernel, mock_ipsec_create);
+
+       charon->backends->add_backend(charon->backends, &this->backend);
+       lib->credmgr->add_set(lib->credmgr, &this->creds->set);
+
+       this->creds->add_shared(this->creds,
+                       shared_key_create(SHARED_IKE, chunk_clone(chunk_from_str("test"))),
+                       identification_create_from_string("%any"), NULL);
+
+       exchange_test_helper = &this->public;
+}
+
+/*
+ * Described in header
+ */
+void exchange_test_helper_deinit()
+{
+       private_exchange_test_helper_t *this;
+
+       this = (private_exchange_test_helper_t*)exchange_test_helper;
+
+       charon->backends->remove_backend(charon->backends, &this->backend);
+       lib->credmgr->remove_set(lib->credmgr, &this->creds->set);
+       this->creds->destroy(this->creds);
+       /* can't let charon do it as it happens too late */
+       charon->sender->destroy(charon->sender);
+       charon->sender = NULL;
+       free(this);
+}
diff --git a/src/libcharon/tests/utils/exchange_test_helper.h b/src/libcharon/tests/utils/exchange_test_helper.h
new file mode 100644 (file)
index 0000000..891ce28
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * 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.
+ */
+
+/**
+ * This class and singleton object initializes charon and provides helper
+ * methods to create unit tests for IKEv2 exchanges.
+ *
+ * It also registers special implementations for the kernel_ipsec_t interface,
+ * the sender and provides dummy configs and credentials.
+ *
+ * @defgroup exchange_test_helper exchange_test_helper
+ * @{ @ingroup test_utils_c
+ */
+
+#ifndef EXCHANGE_TEST_HELPER_H_
+#define EXCHANGE_TEST_HELPER_H_
+
+#include <daemon.h>
+
+#include "mock_sender.h"
+
+typedef struct exchange_test_helper_t exchange_test_helper_t;
+
+struct exchange_test_helper_t {
+
+       /**
+        * Sender instance used during tests
+        */
+       mock_sender_t *sender;
+
+       /**
+        * Creates an established IKE_SA/CHILD_SA
+        *
+        * @param[out] init             IKE_SA of the initiator
+        * @param[out] resp             IKE_SA of the responder
+        */
+       void (*establish_sa)(exchange_test_helper_t *this, ike_sa_t **init,
+                                                ike_sa_t **resp);
+
+       /**
+        * Pass a message to the given IKE_SA for processing, setting the IKE_SA on
+        * the bus while processing the message.
+        *
+        * @param ike_sa                the IKE_SA receiving the message
+        * @param message               the message, or NULL to pass the next message in the
+        *                                              send queue (adopted)
+        */
+       void (*process_message)(exchange_test_helper_t *this, ike_sa_t *sa,
+                                                       message_t *message);
+};
+
+/**
+ * The one and only instance of the helper object.
+ *
+ * Set between exchange_test_helper_setup() and exchange_test_helper_teardown()
+ * calls.
+ */
+extern exchange_test_helper_t *exchange_test_helper;
+
+/**
+ * Initialize charon and the helper object.
+ *
+ * @param plugins                      plugins to load
+ */
+void exchange_test_helper_init(char *plugins);
+
+/**
+ * Deinitialize the helper object.
+ */
+void exchange_test_helper_deinit();
+
+#endif /** EXCHANGE_TEST_HELPER_H_ @} */