Introduce TKM specific charon daemon (charon-tkm)
authorReto Buerki <reet@codelabs.ch>
Fri, 18 May 2012 12:09:24 +0000 (14:09 +0200)
committerTobias Brunner <tobias@strongswan.org>
Tue, 19 Mar 2013 14:23:45 +0000 (15:23 +0100)
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.

20 files changed:
configure.in
src/Makefile.am
src/charon-tkm/.gitignore [new file with mode: 0644]
src/charon-tkm/Makefile.am [new file with mode: 0644]
src/charon-tkm/build_charon.gpr [new file with mode: 0644]
src/charon-tkm/build_common.gpr [new file with mode: 0644]
src/charon-tkm/build_tests.gpr [new file with mode: 0644]
src/charon-tkm/src/charon-tkm.c [new file with mode: 0644]
src/charon-tkm/src/tkm/.gitignore [new file with mode: 0644]
src/charon-tkm/src/tkm/tkm.c [new file with mode: 0644]
src/charon-tkm/src/tkm/tkm.h [new file with mode: 0644]
src/charon-tkm/src/tkm/tkm_id_manager.c [new file with mode: 0644]
src/charon-tkm/src/tkm/tkm_id_manager.h [new file with mode: 0644]
src/charon-tkm/src/tkm/tkm_nonceg.c [new file with mode: 0644]
src/charon-tkm/src/tkm/tkm_nonceg.h [new file with mode: 0644]
src/charon-tkm/tests/.gitignore [new file with mode: 0644]
src/charon-tkm/tests/id_manager_tests.c [new file with mode: 0644]
src/charon-tkm/tests/nonceg_tests.c [new file with mode: 0644]
src/charon-tkm/tests/test_runner.c [new file with mode: 0644]
src/charon-tkm/tests/test_runner.h [new file with mode: 0644]

index 54e4abb..82f90da 100644 (file)
@@ -237,6 +237,7 @@ ARG_ENABL_SET([vstr],           [enforce using the Vstr string library to replac
 ARG_ENABL_SET([monolithic],     [build monolithic version of libstrongswan that includes all enabled plugins. Similarly, the plugins of charon are assembled in libcharon.])
 ARG_ENABL_SET([bfd-backtraces], [use binutils libbfd to resolve backtraces for memory leaks and segfaults.])
 ARG_ENABL_SET([unit-tests],     [enable unit tests using the check test framework.])
+ARG_ENABL_SET([tkm],            [enable Trusted Key Manager support.])
 
 # ===================================
 #  option to disable default options
@@ -897,6 +898,10 @@ AC_SUBST(dev_headers)
 
 CFLAGS="$CFLAGS -include `pwd`/config.h"
 
+if test x$tkm = xtrue; then
+       AC_PATH_PROG([GPRBUILD], [gprbuild], [], [$PATH:/bin:/usr/bin:/usr/local/bin])
+fi
+
 if test x$unit_tests = xtrue; then
        PKG_CHECK_MODULES(CHECK, [check >= 0.9.4])
        AC_SUBST(CHECK_CFLAGS)
@@ -1199,9 +1204,9 @@ AM_CONDITIONAL(USE_NM, test x$nm = xtrue)
 AM_CONDITIONAL(USE_TOOLS, test x$tools = xtrue)
 AM_CONDITIONAL(USE_SCRIPTS, test x$scripts = xtrue)
 AM_CONDITIONAL(USE_CONFTEST, test x$conftest = xtrue)
-AM_CONDITIONAL(USE_LIBSTRONGSWAN, test x$charon = xtrue -o x$tools = xtrue -o x$conftest = xtrue -o x$fast = xtrue -o x$imcv = xtrue -o x$nm = xtrue)
-AM_CONDITIONAL(USE_LIBHYDRA, test x$charon = xtrue -o x$nm = xtrue)
-AM_CONDITIONAL(USE_LIBCHARON, test x$charon = xtrue -o x$conftest = xtrue -o x$nm = xtrue)
+AM_CONDITIONAL(USE_LIBSTRONGSWAN, test x$charon = xtrue -o x$tools = xtrue -o x$conftest = xtrue -o x$fast = xtrue -o x$imcv = xtrue -o x$nm = xtrue -o x$tkm = xtrue)
+AM_CONDITIONAL(USE_LIBHYDRA, test x$charon = xtrue -o x$nm = xtrue -o x$tkm = xtrue)
+AM_CONDITIONAL(USE_LIBCHARON, test x$charon = xtrue -o x$conftest = xtrue -o x$nm = xtrue -o x$tkm = xtrue)
 AM_CONDITIONAL(USE_LIBIPSEC, test x$libipsec = xtrue)
 AM_CONDITIONAL(USE_LIBTNCIF, test x$tnc_tnccs = xtrue -o x$imcv = xtrue)
 AM_CONDITIONAL(USE_LIBTNCCS, test x$tnc_tnccs = xtrue)
@@ -1218,6 +1223,7 @@ AM_CONDITIONAL(USE_PTS, test x$pts = xtrue)
 AM_CONDITIONAL(USE_TROUSERS, test x$tss = xtrousers)
 AM_CONDITIONAL(MONOLITHIC, test x$monolithic = xtrue)
 AM_CONDITIONAL(UNITTESTS, test x$unit_tests = xtrue)
+AM_CONDITIONAL(USE_TKM, test x$tkm = xtrue)
 
 # ========================
 #  set global definitions
@@ -1319,6 +1325,7 @@ AC_CONFIG_FILES([
        src/libimcv/plugins/imv_os/Makefile
        src/charon/Makefile
        src/charon-nm/Makefile
+       src/charon-tkm/Makefile
        src/libcharon/Makefile
        src/libcharon/plugins/eap_aka/Makefile
        src/libcharon/plugins/eap_aka_3gpp2/Makefile
index e71f73d..07953b0 100644 (file)
@@ -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 (file)
index 0000000..b672fde
--- /dev/null
@@ -0,0 +1 @@
+obj
diff --git a/src/charon-tkm/Makefile.am b/src/charon-tkm/Makefile.am
new file mode 100644 (file)
index 0000000..44586dc
--- /dev/null
@@ -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 (file)
index 0000000..c162376
--- /dev/null
@@ -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 (file)
index 0000000..d742692
--- /dev/null
@@ -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 (file)
index 0000000..35f0c9b
--- /dev/null
@@ -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 (file)
index 0000000..8731d78
--- /dev/null
@@ -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 (file)
index 0000000..b672fde
--- /dev/null
@@ -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 (file)
index 0000000..1e61f88
--- /dev/null
@@ -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 (file)
index 0000000..6bb8331
--- /dev/null
@@ -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 (file)
index 0000000..4a1afe3
--- /dev/null
@@ -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 (file)
index 0000000..f348b6d
--- /dev/null
@@ -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 (file)
index 0000000..1a83a5b
--- /dev/null
@@ -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 (file)
index 0000000..907890b
--- /dev/null
@@ -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 (file)
index 0000000..35429f6
--- /dev/null
@@ -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 (file)
index 0000000..0942c29
--- /dev/null
@@ -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 (file)
index 0000000..202a9e5
--- /dev/null
@@ -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 (file)
index 0000000..61c2524
--- /dev/null
@@ -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 (file)
index 0000000..3d15fb9
--- /dev/null
@@ -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_ */