aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorReto Buerki <reet@codelabs.ch>2012-05-18 14:09:24 +0200
committerTobias Brunner <tobias@strongswan.org>2013-03-19 15:23:45 +0100
commit559fe48c5040788c5d8135f00905afb16e5ccaf7 (patch)
treedce9886c360bd9f342b72386a7d94a834f603032 /src
parent4dc3ef94a1b697c64bfc714bb129a5a5d0e1873c (diff)
downloadstrongswan-559fe48c5040788c5d8135f00905afb16e5ccaf7.tar.bz2
strongswan-559fe48c5040788c5d8135f00905afb16e5ccaf7.tar.xz
Introduce TKM specific charon daemon (charon-tkm)
Analogous to charon-nm the charon-tkm daemon is a specialized charon instance used in combination with the trusted key manager (TKM) written in Ada. The charon-tkm is basically a copy of the charon-nm code which will register it's own TKM specific plugins. The daemon binary is built using the gprbuild utility. This is needed because it uses the tkm-rpc Ada library and consequently the Ada runtime. gprbuild takes care of the complete binding and linker steps required to properly initialize the Ada runtime.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am4
-rw-r--r--src/charon-tkm/.gitignore1
-rw-r--r--src/charon-tkm/Makefile.am63
-rw-r--r--src/charon-tkm/build_charon.gpr15
-rw-r--r--src/charon-tkm/build_common.gpr10
-rw-r--r--src/charon-tkm/build_tests.gpr14
-rw-r--r--src/charon-tkm/src/charon-tkm.c330
-rw-r--r--src/charon-tkm/src/tkm/.gitignore1
-rw-r--r--src/charon-tkm/src/tkm/tkm.c67
-rw-r--r--src/charon-tkm/src/tkm/tkm.h54
-rw-r--r--src/charon-tkm/src/tkm/tkm_id_manager.c176
-rw-r--r--src/charon-tkm/src/tkm/tkm_id_manager.h79
-rw-r--r--src/charon-tkm/src/tkm/tkm_nonceg.c71
-rw-r--r--src/charon-tkm/src/tkm/tkm_nonceg.h42
-rw-r--r--src/charon-tkm/tests/.gitignore1
-rw-r--r--src/charon-tkm/tests/id_manager_tests.c131
-rw-r--r--src/charon-tkm/tests/nonceg_tests.c92
-rw-r--r--src/charon-tkm/tests/test_runner.c36
-rw-r--r--src/charon-tkm/tests/test_runner.h25
19 files changed, 1212 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index e71f73db3..07953b0b0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -100,6 +100,10 @@ if USE_INTEGRITY_TEST
SUBDIRS += checksum
endif
+if USE_TKM
+ SUBDIRS += charon-tkm
+endif
+
EXTRA_DIST = strongswan.conf
install-exec-local :
diff --git a/src/charon-tkm/.gitignore b/src/charon-tkm/.gitignore
new file mode 100644
index 000000000..b672fdeaf
--- /dev/null
+++ b/src/charon-tkm/.gitignore
@@ -0,0 +1 @@
+obj
diff --git a/src/charon-tkm/Makefile.am b/src/charon-tkm/Makefile.am
new file mode 100644
index 000000000..44586dc4a
--- /dev/null
+++ b/src/charon-tkm/Makefile.am
@@ -0,0 +1,63 @@
+SRC = $(top_builddir)/src
+
+# includes relative to obj directory
+INCLUDES = \
+ -include $(top_builddir)/config.h \
+ -I../$(SRC)/libstrongswan \
+ -I../$(SRC)/libhydra \
+ -I../$(SRC)/libcharon
+
+LIBLD = \
+ -L$(SRC)/libstrongswan/.libs \
+ -L$(SRC)/libhydra/.libs \
+ -L$(SRC)/libcharon/.libs
+LIBPT = $(SRC)/libstrongswan/.libs:$(SRC)/libhydra/.libs:$(SRC)/libcharon/.libs
+LIBFL = -lstrongswan -lhydra -lcharon
+
+DEFS += -DPLUGINS=\""$(PLUGINS)\"" -DIPSEC_PIDDIR=\"${piddir}\"
+
+BUILD_OPTS = \
+ -cargs $(INCLUDES) $(DEFS) \
+ -largs $(LIBLD) $(LIBFL)
+
+# plugins to enable
+PLUGINS = \
+ aes \
+ constraints \
+ gmp \
+ hmac \
+ kernel-netlink \
+ nonce \
+ pem \
+ pkcs1 \
+ pkcs8 \
+ random \
+ sha1 \
+ sha2 \
+ stroke \
+ socket-default \
+ x509
+
+all: build_charon
+
+build_charon: build_charon.gpr src/charon-tkm.c
+ @$(GPRBUILD) -p $< $(BUILD_OPTS)
+
+build_tests: build_tests.gpr
+ @$(GPRBUILD) -p $< $(BUILD_OPTS) -cargs @CHECK_CFLAGS@ -largs @CHECK_LIBS@
+
+if UNITTESTS
+check: build_tests
+ @LD_LIBRARY_PATH=$(LIBPT) obj/test_runner
+else
+check:
+ @echo "reconfigure with --enable-unit-tests"
+endif
+
+install: build_charon
+ $(INSTALL) -m 755 obj/charon-tkm $(DESTDIR)$(ipsecdir)
+
+clean:
+ rm -rf obj
+
+EXTRA_DIST = build_charon.gpr build_common.gpr build_tests.gpr src tests
diff --git a/src/charon-tkm/build_charon.gpr b/src/charon-tkm/build_charon.gpr
new file mode 100644
index 000000000..c162376a8
--- /dev/null
+++ b/src/charon-tkm/build_charon.gpr
@@ -0,0 +1,15 @@
+with "build_common";
+
+project Build_Charon is
+
+ for Languages use ("C");
+ for Source_Dirs use ("src/**");
+ for Main use ("charon-tkm");
+ for Object_Dir use Build_Common.Obj_Dir;
+
+ package Compiler is
+ for Default_Switches ("c") use Build_Common.C_Compiler_Switches
+ & "-Werror";
+ end Compiler;
+
+end Build_Charon;
diff --git a/src/charon-tkm/build_common.gpr b/src/charon-tkm/build_common.gpr
new file mode 100644
index 000000000..d742692ef
--- /dev/null
+++ b/src/charon-tkm/build_common.gpr
@@ -0,0 +1,10 @@
+with "tkmrpc_client";
+
+project Build_Common is
+
+ for Source_Dirs use ();
+
+ Obj_Dir := "obj";
+ Compiler_Switches := ("-W", "-Wall", "-Wno-unused-parameter");
+
+end Build_Common;
diff --git a/src/charon-tkm/build_tests.gpr b/src/charon-tkm/build_tests.gpr
new file mode 100644
index 000000000..35f0c9bdd
--- /dev/null
+++ b/src/charon-tkm/build_tests.gpr
@@ -0,0 +1,14 @@
+with "build_common";
+
+project Build_Tests is
+
+ for Languages use ("C");
+ for Source_Dirs use ("src/tkm", "tests");
+ for Main use ("test_runner");
+ for Object_Dir use Build_Common.Obj_Dir;
+
+ package Compiler is
+ for Default_Switches ("c") use Build_Common.Compiler_Switches;
+ end Compiler;
+
+end Build_Tests;
diff --git a/src/charon-tkm/src/charon-tkm.c b/src/charon-tkm/src/charon-tkm.c
new file mode 100644
index 000000000..8731d7831
--- /dev/null
+++ b/src/charon-tkm/src/charon-tkm.c
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * Copyright (C) 2012 Reto Buerki
+ * Copyright (C) 2012 Adrian-Ken Rueegsegger
+ * 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.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <syslog.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <libgen.h>
+
+#include <hydra.h>
+#include <daemon.h>
+
+#include <library.h>
+#include <utils/backtrace.h>
+#include <threading/thread.h>
+
+#include <tkm/client.h>
+
+/**
+ * PID file, in which charon-tkm stores its process id
+ */
+static char *pidfile_name = NULL;
+
+/**
+ * Global reference to PID file (required to truncate, if undeletable)
+ */
+static FILE *pidfile = NULL;
+
+/**
+ * Hook in library for debugging messages
+ */
+extern void (*dbg) (debug_t group, level_t level, char *fmt, ...);
+
+/**
+ * Simple logging hook for library logs, using syslog output
+ */
+static void dbg_syslog(debug_t group, level_t level, char *fmt, ...)
+{
+ if (level <= 1)
+ {
+ char buffer[8192];
+ va_list args;
+
+ va_start(args, fmt);
+ /* write in memory buffer first */
+ vsnprintf(buffer, sizeof(buffer), fmt, args);
+ syslog(LOG_DAEMON|LOG_INFO, "00[%s] %s", debug_names->names[group],
+ buffer);
+ va_end(args);
+ }
+}
+
+/**
+ * Run the daemon and handle unix signals
+ */
+static void run()
+{
+ sigset_t set;
+
+ /* handle SIGINT and SIGTERM in this handler */
+ sigemptyset(&set);
+ sigaddset(&set, SIGINT);
+ sigaddset(&set, SIGTERM);
+ sigprocmask(SIG_BLOCK, &set, NULL);
+
+ while (TRUE)
+ {
+ int sig;
+ int error;
+
+ error = sigwait(&set, &sig);
+ if (error)
+ {
+ DBG1(DBG_DMN, "error %d while waiting for a signal", error);
+ return;
+ }
+ switch (sig)
+ {
+ case SIGINT:
+ {
+ DBG1(DBG_DMN, "signal of type SIGINT received. Shutting down");
+ charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
+ return;
+ }
+ case SIGTERM:
+ {
+ DBG1(DBG_DMN, "signal of type SIGTERM received. Shutting down");
+ charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig);
+ return;
+ }
+ default:
+ {
+ DBG1(DBG_DMN, "unknown signal %d received. Ignored", sig);
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * Handle SIGSEGV/SIGILL signals raised by threads
+ */
+static void segv_handler(int signal)
+{
+ backtrace_t *backtrace;
+
+ DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal);
+ backtrace = backtrace_create(2);
+ backtrace->log(backtrace, stderr, TRUE);
+ backtrace->destroy(backtrace);
+
+ DBG1(DBG_DMN, "killing ourself, received critical signal");
+ abort();
+}
+
+/**
+ * Lookup UID and GID
+ */
+static bool lookup_uid_gid()
+{
+#ifdef IPSEC_USER
+ if (!charon->caps->resolve_uid(charon->caps, IPSEC_USER))
+ {
+ return FALSE;
+ }
+#endif
+#ifdef IPSEC_GROUP
+ if (!charon->caps->resolve_gid(charon->caps, IPSEC_GROUP))
+ {
+ return FALSE;
+ }
+#endif
+ return TRUE;
+}
+
+/**
+ * Check/create PID file, return TRUE if already running
+ */
+static bool check_pidfile()
+{
+ struct stat stb;
+
+ if (stat(pidfile_name, &stb) == 0)
+ {
+ pidfile = fopen(pidfile_name, "r");
+ if (pidfile)
+ {
+ char buf[64];
+ pid_t pid = 0;
+
+ memset(buf, 0, sizeof(buf));
+ if (fread(buf, 1, sizeof(buf), pidfile))
+ {
+ buf[sizeof(buf) - 1] = '\0';
+ pid = atoi(buf);
+ }
+ fclose(pidfile);
+ if (pid && kill(pid, 0) == 0)
+ { /* such a process is running */
+ return TRUE;
+ }
+ }
+ DBG1(DBG_DMN, "removing pidfile '%s', process not running", pidfile_name);
+ unlink(pidfile_name);
+ }
+
+ /* create new pidfile */
+ pidfile = fopen(pidfile_name, "w");
+ if (pidfile)
+ {
+ ignore_result(fchown(fileno(pidfile),
+ charon->caps->get_uid(charon->caps),
+ charon->caps->get_gid(charon->caps)));
+ fprintf(pidfile, "%d\n", getpid());
+ fflush(pidfile);
+ }
+ return FALSE;
+}
+
+/**
+ * Delete/truncate the PID file
+ */
+static void unlink_pidfile()
+{
+ /* because unlinking the PID file may fail, we truncate it to ensure the
+ * daemon can be properly restarted. one probable cause for this is the
+ * combination of not running as root and the effective user lacking
+ * permissions on the parent dir(s) of the PID file */
+ if (pidfile)
+ {
+ ignore_result(ftruncate(fileno(pidfile), 0));
+ fclose(pidfile);
+ }
+ unlink(pidfile_name);
+}
+/**
+ * Main function, starts TKM backend.
+ */
+int main(int argc, char *argv[])
+{
+ char *dmn_name;
+ if (argc > 0 && strlen(argv[0]) > 0)
+ {
+ dmn_name = basename(argv[0]);
+ }
+ else
+ {
+ dmn_name = "charon-tkm";
+ }
+
+ struct sigaction action;
+ int status = SS_RC_INITIALIZATION_FAILED;
+
+ /* logging for library during initialization, as we have no bus yet */
+ dbg = dbg_syslog;
+
+ /* initialize library */
+ if (!library_init(NULL))
+ {
+ library_deinit();
+ exit(status);
+ }
+
+ if (!libhydra_init(dmn_name))
+ {
+ dbg_syslog(DBG_DMN, 1, "initialization failed - aborting %s", dmn_name);
+ libhydra_deinit();
+ library_deinit();
+ exit(status);
+ }
+
+ if (!libcharon_init(dmn_name))
+ {
+ dbg_syslog(DBG_DMN, 1, "initialization failed - aborting %s", dmn_name);
+ goto deinit;
+ }
+
+ if (!lookup_uid_gid())
+ {
+ dbg_syslog(DBG_DMN, 1, "invalid uid/gid - aborting %s", dmn_name);
+ goto deinit;
+ }
+
+ /* make sure we log to the DAEMON facility by default */
+ lib->settings->set_int(lib->settings, "%s.syslog.daemon.default",
+ lib->settings->get_int(lib->settings, "%s.syslog.daemon.default", 1,
+ dmn_name), dmn_name);
+ charon->load_loggers(charon, NULL, FALSE);
+
+ DBG1(DBG_DMN, "Starting charon with TKM backend (strongSwan "VERSION")");
+
+ /* initialize daemon */
+ if (!charon->initialize(charon, PLUGINS))
+ {
+ DBG1(DBG_DMN, "initialization failed - aborting %s", dmn_name);
+ goto deinit;
+ }
+
+ /* set global pidfile name depending on daemon name */
+ if (asprintf(&pidfile_name, IPSEC_PIDDIR"/%s.pid", dmn_name) < 0)
+ {
+ DBG1(DBG_DMN, "unable to set pidfile name - aborting %s", dmn_name);
+ goto deinit;
+ };
+
+ if (check_pidfile())
+ {
+ DBG1(DBG_DMN, "%s already running (\"%s\" exists)", dmn_name,
+ pidfile_name);
+ goto deinit;
+ }
+
+ if (!charon->caps->drop(charon->caps))
+ {
+ DBG1(DBG_DMN, "capability dropping failed - aborting %s", dmn_name);
+ goto deinit;
+ }
+
+ /* initialize TKM client lib */
+ tkmlib_init();
+
+ /* add handler for SEGV and ILL,
+ * INT and TERM are handled by sigwait() in run() */
+ action.sa_handler = segv_handler;
+ action.sa_flags = 0;
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, SIGINT);
+ sigaddset(&action.sa_mask, SIGTERM);
+ sigaction(SIGSEGV, &action, NULL);
+ sigaction(SIGILL, &action, NULL);
+ sigaction(SIGBUS, &action, NULL);
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &action, NULL);
+
+ pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);
+
+ /* start daemon (i.e. the threads in the thread-pool) */
+ charon->start(charon);
+
+ /* main thread goes to run loop */
+ run();
+
+ unlink_pidfile();
+ status = 0;
+ tkmlib_final();
+
+deinit:
+ libcharon_deinit();
+ libhydra_deinit();
+ library_deinit();
+ return status;
+}
diff --git a/src/charon-tkm/src/tkm/.gitignore b/src/charon-tkm/src/tkm/.gitignore
new file mode 100644
index 000000000..b672fdeaf
--- /dev/null
+++ b/src/charon-tkm/src/tkm/.gitignore
@@ -0,0 +1 @@
+obj
diff --git a/src/charon-tkm/src/tkm/tkm.c b/src/charon-tkm/src/tkm/tkm.c
new file mode 100644
index 000000000..1e61f882b
--- /dev/null
+++ b/src/charon-tkm/src/tkm/tkm.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2012 Reto Buerki
+ * Copyright (C) 2012 Adrian-Ken Rueegsegger
+ * 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 "tkm.h"
+
+typedef struct private_tkm_t private_tkm_t;
+
+/**
+ * Private additions to tkm_t.
+ */
+struct private_tkm_t {
+
+ /**
+ * Public members of tkm_t.
+ */
+ tkm_t public;
+};
+
+/**
+ * Single instance of tkm_t.
+ */
+tkm_t *tkm = NULL;
+
+/**
+ * Described in header.
+ */
+bool tkm_init()
+{
+ private_tkm_t *this;
+
+ INIT(this,
+ .public = {
+ .idmgr = tkm_id_manager_create(),
+ },
+ );
+ tkm = &this->public;
+
+ return TRUE;
+}
+
+/**
+ * Described in header.
+ */
+void tkm_deinit()
+{
+ if (!tkm)
+ {
+ return;
+ }
+ private_tkm_t *this = (private_tkm_t*)tkm;
+ this->public.idmgr->destroy(this->public.idmgr);
+ free(this);
+ tkm = NULL;
+}
diff --git a/src/charon-tkm/src/tkm/tkm.h b/src/charon-tkm/src/tkm/tkm.h
new file mode 100644
index 000000000..6bb8331d4
--- /dev/null
+++ b/src/charon-tkm/src/tkm/tkm.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2012 Reto Buerki
+ * Copyright (C) 2012 Adrian-Ken Rueegsegger
+ * 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.
+ */
+
+#ifndef TKM_H_
+#define TKM_H_
+
+#include "tkm_id_manager.h"
+
+typedef struct tkm_t tkm_t;
+
+/**
+ * Trusted key manager context, contains tkm related globals.
+ */
+struct tkm_t {
+
+ /**
+ * Context ID manager.
+ */
+ tkm_id_manager_t *idmgr;
+
+};
+
+/**
+ * Initialize trusted key manager, creates "tkm" instance.
+ *
+ * @return FALSE if initialization error occured
+ */
+bool tkm_init();
+
+/**
+ * Deinitialize trusted key manager, destroys "tkm" instance.
+ */
+void tkm_deinit();
+
+/**
+ * Trusted key manager instance, set after tkm_init() and before tkm_deinit()
+ * calls.
+ */
+extern tkm_t *tkm;
+
+#endif /** TKM_H_ */
diff --git a/src/charon-tkm/src/tkm/tkm_id_manager.c b/src/charon-tkm/src/tkm/tkm_id_manager.c
new file mode 100644
index 000000000..4a1afe37f
--- /dev/null
+++ b/src/charon-tkm/src/tkm/tkm_id_manager.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2012 Reto Buerki
+ * Copyright (C) 2012 Adrian-Ken Rueegsegger
+ * 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 "tkm_id_manager.h"
+
+#include <utils/debug.h>
+#include <collections/linked_list.h>
+#include <threading/rwlock.h>
+
+ENUM_BEGIN(tkm_context_kind_names, TKM_CTX_NONCE, TKM_CTX_NONCE,
+ "NONCE_CONTEXT");
+ENUM_END(tkm_context_kind_names, TKM_CTX_NONCE);
+
+typedef struct private_tkm_id_manager_t private_tkm_id_manager_t;
+
+/**
+ * private data of tkm_id_manager
+ */
+struct private_tkm_id_manager_t {
+
+ /**
+ * public functions
+ */
+ tkm_id_manager_t public;
+
+ /**
+ * Next free context id values.
+ */
+ int nextids[TKM_CTX_MAX];
+
+ /**
+ * Per-kind list of acquired context ids
+ */
+ linked_list_t *ctxids[TKM_CTX_MAX];
+
+ /**
+ * rwlocks for context id lists
+ */
+ rwlock_t *locks[TKM_CTX_MAX];
+
+};
+
+/**
+ * Check if given kind is a valid context kind value.
+ *
+ * @param kind context kind to check
+ * @return TRUE if given kind is a valid context kind,
+ * FALSE otherwise
+ */
+static bool is_valid_kind(const tkm_context_kind_t kind)
+{
+ return (int)kind >= 0 && kind < TKM_CTX_MAX;
+};
+
+METHOD(tkm_id_manager_t, acquire_id, int,
+ private_tkm_id_manager_t * const this, const tkm_context_kind_t kind)
+{
+ int *current;
+ int id = 0;
+
+ if (!is_valid_kind(kind))
+ {
+ DBG1(DBG_LIB, "tried to acquire id for invalid context kind '%d'",
+ kind);
+ return 0;
+ }
+
+ this->locks[kind]->write_lock(this->locks[kind]);
+
+ id = this->nextids[kind];
+ current = malloc(sizeof(int));
+ *current = id;
+ this->ctxids[kind]->insert_last(this->ctxids[kind], current);
+ this->nextids[kind]++;
+
+ this->locks[kind]->unlock(this->locks[kind]);
+
+ if (!id)
+ {
+ DBG1(DBG_LIB, "acquiring %N context id failed",
+ tkm_context_kind_names, kind);
+ }
+
+ return id;
+}
+
+METHOD(tkm_id_manager_t, release_id, bool,
+ private_tkm_id_manager_t * const this, const tkm_context_kind_t kind,
+ const int id)
+{
+ enumerator_t *enumerator;
+ int *current;
+ bool found = FALSE;
+
+ if (!is_valid_kind(kind))
+ {
+ DBG1(DBG_LIB, "tried to release id %d for invalid context kind '%d'",
+ id, kind);
+ return FALSE;
+ }
+
+ this->locks[kind]->write_lock(this->locks[kind]);
+ enumerator = this->ctxids[kind]->create_enumerator(this->ctxids[kind]);
+ while (enumerator->enumerate(enumerator, &current))
+ {
+ if (*current == id)
+ {
+ this->ctxids[kind]->remove_at(this->ctxids[kind], enumerator);
+ found = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->locks[kind]->unlock(this->locks[kind]);
+
+ if (!found)
+ {
+ DBG3(DBG_LIB, "releasing non-existent %N context id %d, nothing to do",
+ tkm_context_kind_names, kind, id);
+ }
+
+ return TRUE;
+}
+
+
+METHOD(tkm_id_manager_t, destroy, void,
+ private_tkm_id_manager_t *this)
+{
+ int i;
+
+ for (i = 0; i < TKM_CTX_MAX; i++)
+ {
+ this->ctxids[i]->destroy(this->ctxids[i]);
+ this->locks[i]->destroy(this->locks[i]);
+ }
+ free(this);
+}
+
+/*
+ * see header file
+ */
+tkm_id_manager_t *tkm_id_manager_create()
+{
+ private_tkm_id_manager_t *this;
+ int i;
+
+ INIT(this,
+ .public = {
+ .acquire_id = _acquire_id,
+ .release_id = _release_id,
+ .destroy = _destroy,
+ },
+ );
+
+ for (i = 0; i < TKM_CTX_MAX; i++)
+ {
+ this->nextids[i] = 1;
+ this->ctxids[i] = linked_list_create();
+ this->locks[i] = rwlock_create(RWLOCK_TYPE_DEFAULT);
+ }
+
+ return &this->public;
+}
diff --git a/src/charon-tkm/src/tkm/tkm_id_manager.h b/src/charon-tkm/src/tkm/tkm_id_manager.h
new file mode 100644
index 000000000..f348b6d57
--- /dev/null
+++ b/src/charon-tkm/src/tkm/tkm_id_manager.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2012 Reto Buerki
+ * Copyright (C) 2012 Adrian-Ken Rueegsegger
+ * 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.
+ */
+
+#ifndef TKM_ID_MANAGER_H_
+#define TKM_ID_MANAGER_H_
+
+#include <library.h>
+
+typedef struct tkm_id_manager_t tkm_id_manager_t;
+typedef enum tkm_context_kind_t tkm_context_kind_t;
+
+/**
+ * Trusted key manager context kinds.
+ */
+enum tkm_context_kind_t {
+ /** Nonce context */
+ TKM_CTX_NONCE,
+
+ /** helper to determine the number of elements in this enum */
+ TKM_CTX_MAX,
+};
+
+/**
+ * enum name for context_kind_t.
+ */
+extern enum_name_t *tkm_context_kind_names;
+
+/**
+ * The tkm id manager hands out context ids for all context kinds (e.g. nonce).
+ */
+struct tkm_id_manager_t {
+
+ /**
+ * Acquire new context id for a specific context kind.
+ *
+ * @param kind kind of context id to acquire
+ * @return context id of given kind,
+ * 0 if no id of given kind could be acquired
+ */
+ int (*acquire_id)(tkm_id_manager_t * const this,
+ const tkm_context_kind_t kind);
+
+ /**
+ * Release a previously acquired context id.
+ *
+ * @param kind kind of context id to release
+ * @param id id to release
+ * @return TRUE if id was released, FALSE otherwise
+ */
+ bool (*release_id)(tkm_id_manager_t * const this,
+ const tkm_context_kind_t kind,
+ const int id);
+
+ /**
+ * Destroy a tkm_id_manager instance.
+ */
+ void (*destroy)(tkm_id_manager_t *this);
+
+};
+
+/**
+ * Create a tkm id manager instance.
+ */
+tkm_id_manager_t *tkm_id_manager_create();
+
+#endif /** TKM_ID_MANAGER_H_ */
diff --git a/src/charon-tkm/src/tkm/tkm_nonceg.c b/src/charon-tkm/src/tkm/tkm_nonceg.c
new file mode 100644
index 000000000..1a83a5b16
--- /dev/null
+++ b/src/charon-tkm/src/tkm/tkm_nonceg.c
@@ -0,0 +1,71 @@
+/*
+ * Copyrigth (C) 2012 Reto Buerki
+ * Copyright (C) 2012 Adrian-Ken Rueegsegger
+ * 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 "tkm_nonceg.h"
+
+typedef struct private_tkm_nonceg_t private_tkm_nonceg_t;
+
+/**
+ * Private data of a tkm_nonceg_t object.
+ */
+struct private_tkm_nonceg_t {
+
+ /**
+ * Public tkm_nonceg_t interface.
+ */
+ tkm_nonceg_t public;
+
+};
+
+METHOD(nonce_gen_t, get_nonce, bool,
+ private_tkm_nonceg_t *this, size_t size, u_int8_t *buffer)
+{
+ // TODO: Request nonce from TKM and fill it into buffer.
+ return TRUE;
+}
+
+METHOD(nonce_gen_t, allocate_nonce, bool,
+ private_tkm_nonceg_t *this, size_t size, chunk_t *chunk)
+{
+ *chunk = chunk_alloc(size);
+ return get_nonce(this, chunk->len, chunk->ptr);
+}
+
+METHOD(nonce_gen_t, destroy, void,
+ private_tkm_nonceg_t *this)
+{
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+tkm_nonceg_t *tkm_nonceg_create()
+{
+ private_tkm_nonceg_t *this;
+
+ INIT(this,
+ .public = {
+ .nonce_gen = {
+ .get_nonce = _get_nonce,
+ .allocate_nonce = _allocate_nonce,
+ .destroy = _destroy,
+ },
+ },
+ );
+
+ return &this->public;
+}
diff --git a/src/charon-tkm/src/tkm/tkm_nonceg.h b/src/charon-tkm/src/tkm/tkm_nonceg.h
new file mode 100644
index 000000000..907890bbd
--- /dev/null
+++ b/src/charon-tkm/src/tkm/tkm_nonceg.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2012 Reto Buerki
+ * Copyright (C) 2012 Adrian-Ken Rueegsegger
+ * 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.
+ */
+
+#ifndef TKM_NONCEG_H_
+#define TKM_NONCEG_H_
+
+typedef struct tkm_nonceg_t tkm_nonceg_t;
+
+#include <library.h>
+
+/**
+ * nonce_gen_t implementation using the trusted key manager.
+ */
+struct tkm_nonceg_t {
+
+ /**
+ * Implements nonce_gen_t.
+ */
+ nonce_gen_t nonce_gen;
+};
+
+/**
+ * Creates a tkm_nonceg_t instance.
+ *
+ * @return created tkm_nonceg_t
+ */
+tkm_nonceg_t *tkm_nonceg_create();
+
+#endif /** TKM_NONCEG_H_ */
diff --git a/src/charon-tkm/tests/.gitignore b/src/charon-tkm/tests/.gitignore
new file mode 100644
index 000000000..35429f617
--- /dev/null
+++ b/src/charon-tkm/tests/.gitignore
@@ -0,0 +1 @@
+test_runner
diff --git a/src/charon-tkm/tests/id_manager_tests.c b/src/charon-tkm/tests/id_manager_tests.c
new file mode 100644
index 000000000..0942c299a
--- /dev/null
+++ b/src/charon-tkm/tests/id_manager_tests.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2012 Reto Buerki
+ * Copyright (C) 2012 Adrian-Ken Rueegsegger
+ * 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 <stdlib.h>
+#include <check.h>
+
+#include "tkm_id_manager.h"
+
+START_TEST(test_id_mgr_creation)
+{
+ tkm_id_manager_t *idmgr = NULL;
+
+ idmgr = tkm_id_manager_create();
+ fail_if(idmgr == NULL, "Error creating tkm id manager");
+
+ idmgr->destroy(idmgr);
+}
+END_TEST
+
+START_TEST(test_acquire_id)
+{
+ int i, id = 0;
+ tkm_id_manager_t *idmgr = tkm_id_manager_create();
+
+ for (i = 0; i < TKM_CTX_MAX; i++)
+ {
+ id = idmgr->acquire_id(idmgr, i);
+ fail_unless(id > 0, "Error acquiring id of context kind %d", i);
+
+ /* Reset test variable */
+ id = 0;
+ }
+
+ idmgr->destroy(idmgr);
+}
+END_TEST
+
+START_TEST(test_acquire_id_invalid_kind)
+{
+ int id = 0;
+ tkm_id_manager_t *idmgr = tkm_id_manager_create();
+
+ id = idmgr->acquire_id(idmgr, TKM_CTX_MAX);
+ fail_unless(id == 0, "Acquired id for invalid context kind %d", TKM_CTX_MAX);
+
+ /* Reset test variable */
+ id = 0;
+
+ id = idmgr->acquire_id(idmgr, -1);
+ fail_unless(id == 0, "Acquired id for invalid context kind %d", -1);
+
+ idmgr->destroy(idmgr);
+}
+END_TEST
+
+START_TEST(test_release_id)
+{
+ int i, id = 0;
+ bool released = false;
+ tkm_id_manager_t *idmgr = tkm_id_manager_create();
+
+ for (i = 0; i < TKM_CTX_MAX; i++)
+ {
+ id = idmgr->acquire_id(idmgr, i);
+ released = idmgr->release_id(idmgr, i, id);
+
+ fail_unless(released, "Error releasing id of context kind %d", i);
+
+ /* Reset released variable */
+ released = FALSE;
+ }
+
+ idmgr->destroy(idmgr);
+}
+END_TEST
+
+START_TEST(test_release_id_invalid_kind)
+{
+ bool released = TRUE;
+ tkm_id_manager_t *idmgr = tkm_id_manager_create();
+
+ released = idmgr->release_id(idmgr, TKM_CTX_MAX, 1);
+ fail_if(released, "Released id for invalid context kind %d", TKM_CTX_MAX);
+
+ /* Reset test variable */
+ released = TRUE;
+
+ released = idmgr->release_id(idmgr, -1, 1);
+ fail_if(released, "Released id for invalid context kind %d", -1);
+
+ idmgr->destroy(idmgr);
+}
+END_TEST
+
+START_TEST(test_release_id_nonexistent)
+{
+ bool released = FALSE;
+ tkm_id_manager_t *idmgr = tkm_id_manager_create();
+
+ released = idmgr->release_id(idmgr, TKM_CTX_NONCE, 1);
+ fail_unless(released, "Release of nonexistent id failed");
+
+ idmgr->destroy(idmgr);
+}
+END_TEST
+
+TCase *make_id_manager_tests(void)
+{
+ TCase *tc = tcase_create("Context id manager tests");
+ tcase_add_test(tc, test_id_mgr_creation);
+ tcase_add_test(tc, test_acquire_id);
+ tcase_add_test(tc, test_acquire_id_invalid_kind);
+ tcase_add_test(tc, test_release_id);
+ tcase_add_test(tc, test_release_id_invalid_kind);
+ tcase_add_test(tc, test_release_id_nonexistent);
+
+ return tc;
+}
diff --git a/src/charon-tkm/tests/nonceg_tests.c b/src/charon-tkm/tests/nonceg_tests.c
new file mode 100644
index 000000000..202a9e5c7
--- /dev/null
+++ b/src/charon-tkm/tests/nonceg_tests.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2012 Reto Buerki
+ * Copyright (C) 2012 Adrian-Ken Rueegsegger
+ * 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 <check.h>
+#include <tkm/client.h>
+
+#include "tkm.h"
+#include "tkm_nonceg.h"
+
+START_TEST(test_nonceg_creation)
+{
+ tkm_nonceg_t *ng = NULL;
+
+ ng = tkm_nonceg_create();
+ fail_if(ng == NULL, "Error creating tkm nonce generator");
+
+ ng->nonce_gen.destroy(&ng->nonce_gen);
+}
+END_TEST
+
+START_TEST(test_nonceg_allocate_nonce)
+{
+ tkm_nonceg_t *ng = tkm_nonceg_create();
+
+ const size_t length = 256;
+ u_int8_t zero[length];
+ memset(zero, 0, length);
+
+ chunk_t nonce;
+ const bool got_nonce = ng->nonce_gen.allocate_nonce(&ng->nonce_gen,
+ length, &nonce);
+
+ fail_unless(got_nonce, "Call to allocate_nonce failed");
+ fail_unless(nonce.len = length, "Allocated nonce length mismatch");
+ fail_if(memcmp(nonce.ptr, zero, length) == 0, "Unable to allocate nonce");
+
+ tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_NONCE, 1);
+ ike_nc_reset(1);
+
+ chunk_free(&nonce);
+ ng->nonce_gen.destroy(&ng->nonce_gen);
+}
+END_TEST
+
+START_TEST(test_nonceg_get_nonce)
+{
+ tkm_nonceg_t *ng = tkm_nonceg_create();
+
+ const size_t length = 128;
+ u_int8_t zero[length];
+ memset(zero, 0, length);
+
+ u_int8_t *buf = malloc(length + 1);
+ memset(buf, 0, length);
+ /* set end marker */
+ buf[length] = 255;
+
+ const bool got_nonce = ng->nonce_gen.get_nonce(&ng->nonce_gen, length, buf);
+ fail_unless(got_nonce, "Call to get_nonce failed");
+ fail_if(memcmp(buf, zero, length) == 0, "Unable to get nonce");
+ fail_if(buf[length] != 255, "End marker not found");
+
+ tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_NONCE, 1);
+ ike_nc_reset(1);
+
+ free(buf);
+ ng->nonce_gen.destroy(&ng->nonce_gen);
+}
+END_TEST
+
+TCase *make_nonceg_tests(void)
+{
+ TCase *tc = tcase_create("Nonce generator tests");
+ tcase_add_test(tc, test_nonceg_creation);
+ tcase_add_test(tc, test_nonceg_allocate_nonce);
+ tcase_add_test(tc, test_nonceg_get_nonce);
+
+ return tc;
+}
diff --git a/src/charon-tkm/tests/test_runner.c b/src/charon-tkm/tests/test_runner.c
new file mode 100644
index 000000000..61c252416
--- /dev/null
+++ b/src/charon-tkm/tests/test_runner.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2012 Reto Buerki
+ * Copyright (C) 2012 Adrian-Ken Rueegsegger
+ * 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 <stdlib.h>
+
+#include "test_runner.h"
+
+int main(void)
+{
+ int number_failed;
+ Suite *s = suite_create("TKM tests");
+ suite_add_tcase(s, make_id_manager_tests());
+ suite_add_tcase(s, make_nonceg_tests());
+
+ SRunner *sr = srunner_create(s);
+
+ srunner_run_all(sr, CK_NORMAL);
+ number_failed = srunner_ntests_failed(sr);
+
+ srunner_free(sr);
+
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/src/charon-tkm/tests/test_runner.h b/src/charon-tkm/tests/test_runner.h
new file mode 100644
index 000000000..3d15fb99f
--- /dev/null
+++ b/src/charon-tkm/tests/test_runner.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2012 Reto Buerki
+ * Copyright (C) 2012 Adrian-Ken Rueegsegger
+ * 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.
+ */
+
+#ifndef TEST_RUNNER_H_
+#define TEST_RUNNER_H_
+
+#include <check.h>
+
+TCase *make_id_manager_tests(void);
+TCase *make_nonceg_tests(void);
+
+#endif /** TEST_RUNNER_H_ */