diff options
Diffstat (limited to 'src/charon-tkm')
55 files changed, 6088 insertions, 0 deletions
diff --git a/src/charon-tkm/Makefile.am b/src/charon-tkm/Makefile.am new file mode 100644 index 000000000..457e5e44e --- /dev/null +++ b/src/charon-tkm/Makefile.am @@ -0,0 +1,54 @@ +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 = \ + -XOBJ_DIR=$(CURDIR)/obj \ + -cargs $(INCLUDES) $(DEFS) \ + -largs $(LIBLD) $(LIBFL) + +# plugins to enable +PLUGINS = \ + kernel-netlink \ + pem \ + socket-default \ + openssl \ + stroke + +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/Makefile.in b/src/charon-tkm/Makefile.in new file mode 100644 index 000000000..74e842115 --- /dev/null +++ b/src/charon-tkm/Makefile.in @@ -0,0 +1,506 @@ +# Makefile.in generated by automake 1.11.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +am__make_dryrun = \ + { \ + am__dry=no; \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ + | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ + *) \ + for am__flg in $$MAKEFLAGS; do \ + case $$am__flg in \ + *=*|--*) ;; \ + *n*) am__dry=yes; break;; \ + esac; \ + done;; \ + esac; \ + test $$am__dry = yes; \ + } +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/charon-tkm +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ + $(top_srcdir)/m4/config/ltoptions.m4 \ + $(top_srcdir)/m4/config/ltsugar.m4 \ + $(top_srcdir)/m4/config/ltversion.m4 \ + $(top_srcdir)/m4/config/lt~obsolete.m4 \ + $(top_srcdir)/m4/macros/with.m4 \ + $(top_srcdir)/m4/macros/enable-disable.m4 \ + $(top_srcdir)/m4/macros/add-plugin.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BFDLIB = @BFDLIB@ +BTLIB = @BTLIB@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CHECK_CFLAGS = @CHECK_CFLAGS@ +CHECK_LIBS = @CHECK_LIBS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ -DPLUGINS=\""$(PLUGINS)\"" -DIPSEC_PIDDIR=\"${piddir}\" +DEPDIR = @DEPDIR@ +DLLIB = @DLLIB@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GPERF = @GPERF@ +GPRBUILD = @GPRBUILD@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MYSQLCFLAG = @MYSQLCFLAG@ +MYSQLCONFIG = @MYSQLCONFIG@ +MYSQLLIB = @MYSQLLIB@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PTHREADLIB = @PTHREADLIB@ +RANLIB = @RANLIB@ +RTLIB = @RTLIB@ +RUBY = @RUBY@ +RUBYINCLUDE = @RUBYINCLUDE@ +RUBYLIB = @RUBYLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SOCKLIB = @SOCKLIB@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +attest_plugins = @attest_plugins@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ +clearsilver_LIBS = @clearsilver_LIBS@ +datadir = @datadir@ +datarootdir = @datarootdir@ +dbusservicedir = @dbusservicedir@ +dev_headers = @dev_headers@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ +h_plugins = @h_plugins@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +imcvdir = @imcvdir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ +ipsecdir = @ipsecdir@ +ipsecgroup = @ipsecgroup@ +ipseclibdir = @ipseclibdir@ +ipsecuser = @ipsecuser@ +libdir = @libdir@ +libexecdir = @libexecdir@ +linux_headers = @linux_headers@ +localedir = @localedir@ +localstatedir = @localstatedir@ +maemo_CFLAGS = @maemo_CFLAGS@ +maemo_LIBS = @maemo_LIBS@ +manager_plugins = @manager_plugins@ +mandir = @mandir@ +medsrv_plugins = @medsrv_plugins@ +mkdir_p = @mkdir_p@ +nm_CFLAGS = @nm_CFLAGS@ +nm_LIBS = @nm_LIBS@ +nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ +oldincludedir = @oldincludedir@ +openac_plugins = @openac_plugins@ +pcsclite_CFLAGS = @pcsclite_CFLAGS@ +pcsclite_LIBS = @pcsclite_LIBS@ +pdfdir = @pdfdir@ +piddir = @piddir@ +pki_plugins = @pki_plugins@ +plugindir = @plugindir@ +pool_plugins = @pool_plugins@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +random_device = @random_device@ +resolv_conf = @resolv_conf@ +routing_table = @routing_table@ +routing_table_prio = @routing_table_prio@ +s_plugins = @s_plugins@ +sbindir = @sbindir@ +scepclient_plugins = @scepclient_plugins@ +scripts_plugins = @scripts_plugins@ +sharedstatedir = @sharedstatedir@ +soup_CFLAGS = @soup_CFLAGS@ +soup_LIBS = @soup_LIBS@ +srcdir = @srcdir@ +starter_plugins = @starter_plugins@ +strongswan_conf = @strongswan_conf@ +sysconfdir = @sysconfdir@ +systemdsystemunitdir = @systemdsystemunitdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +urandom_device = @urandom_device@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +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 +BUILD_OPTS = \ + -XOBJ_DIR=$(CURDIR)/obj \ + -cargs $(INCLUDES) $(DEFS) \ + -largs $(LIBLD) $(LIBFL) + + +# plugins to enable +PLUGINS = \ + kernel-netlink \ + pem \ + socket-default \ + openssl \ + stroke + +EXTRA_DIST = build_charon.gpr build_common.gpr build_tests.gpr src tests +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/charon-tkm/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/charon-tkm/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + distclean distclean-generic distclean-libtool distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am + + +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@ + +@UNITTESTS_TRUE@check: build_tests +@UNITTESTS_TRUE@ @LD_LIBRARY_PATH=$(LIBPT) obj/test_runner +@UNITTESTS_FALSE@check: +@UNITTESTS_FALSE@ @echo "reconfigure with --enable-unit-tests" + +install: build_charon + $(INSTALL) -m 755 obj/charon-tkm $(DESTDIR)$(ipsecdir) + +clean: + rm -rf obj + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/charon-tkm/build_charon.gpr b/src/charon-tkm/build_charon.gpr new file mode 100644 index 000000000..b208667a3 --- /dev/null +++ b/src/charon-tkm/build_charon.gpr @@ -0,0 +1,20 @@ +with "build_common"; + +project Build_Charon is + + for Languages use ("Ada", "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 ("ada") use Build_Common.Ada_Compiler_Switches; + for Default_Switches ("c") use Build_Common.C_Compiler_Switches + & "-Werror"; + end Compiler; + + package Binder is + for Default_Switches ("ada") use Build_Common.Ada_Binder_Switches; + end Binder; + +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..ac322d713 --- /dev/null +++ b/src/charon-tkm/build_common.gpr @@ -0,0 +1,25 @@ +with "tkmrpc_client"; +with "tkmrpc_server-ees"; + +project Build_Common is + + for Source_Dirs use (); + + Obj_Dir := "obj"; + + C_Compiler_Switches := ("-W", + "-Wall", + "-Wno-unused-parameter"); + Ada_Compiler_Switches := ("-gnatwale", + "-gnatygAdISuxo", + "-gnata", + "-gnatVa", + "-gnat05", + "-gnatf", + "-fstack-check", + "-gnato", + "-g"); + + Ada_Binder_Switches := ("-E"); + +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..032c7969e --- /dev/null +++ b/src/charon-tkm/build_tests.gpr @@ -0,0 +1,14 @@ +with "build_common"; + +project Build_Tests is + + for Languages use ("Ada", "C"); + for Source_Dirs use ("src/ees", "src/ehandler", "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.C_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..0b39058a6 --- /dev/null +++ b/src/charon-tkm/src/charon-tkm.c @@ -0,0 +1,387 @@ +/* + * 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 <sa/keymat.h> +#include <credentials/credential_manager.h> + +#include "tkm.h" +#include "tkm_nonceg.h" +#include "tkm_diffie_hellman.h" +#include "tkm_keymat.h" +#include "tkm_listener.h" +#include "tkm_kernel_ipsec.h" +#include "tkm_public_key.h" +#include "tkm_cred.h" +#include "tkm_encoder.h" + +/** + * TKM bus listener for IKE authorize events. + */ +static tkm_listener_t *listener; + +/** + * 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"; + } + + /* TKM credential set */ + tkm_cred_t *creds; + + 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")"); + + /* register TKM specific plugins */ + static plugin_feature_t features[] = { + PLUGIN_REGISTER(NONCE_GEN, tkm_nonceg_create), + PLUGIN_PROVIDE(NONCE_GEN), + PLUGIN_REGISTER(DH, tkm_diffie_hellman_create), + PLUGIN_PROVIDE(DH, MODP_2048_BIT), + PLUGIN_PROVIDE(DH, MODP_3072_BIT), + PLUGIN_PROVIDE(DH, MODP_4096_BIT), + PLUGIN_REGISTER(PUBKEY, tkm_public_key_load, TRUE), + PLUGIN_PROVIDE(PUBKEY, KEY_RSA), + PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA1), + PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA256), + PLUGIN_CALLBACK(kernel_ipsec_register, tkm_kernel_ipsec_create), + PLUGIN_PROVIDE(CUSTOM, "kernel-ipsec"), + }; + lib->plugins->add_static_features(lib->plugins, "tkm-backend", features, + countof(features), TRUE); + + /* register TKM keymat variant */ + keymat_register_constructor(IKEV2, (keymat_constructor_t)tkm_keymat_create); + + /* 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 */ + if (!tkm_init()) + { + DBG1(DBG_DMN, "init of TKM client failed - aborting %s", dmn_name); + goto deinit; + } + + /* register TKM authorization hook */ + listener = tkm_listener_create(); + charon->bus->add_listener(charon->bus, &listener->listener); + + /* register TKM credential set */ + creds = tkm_cred_create(); + lib->credmgr->add_set(lib->credmgr, (credential_set_t*)creds); + + /* register TKM credential encoder */ + lib->encoding->add_encoder(lib->encoding, tkm_encoder_encode); + + /* 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; + charon->bus->remove_listener(charon->bus, &listener->listener); + listener->destroy(listener); + creds->destroy(creds); + lib->encoding->remove_encoder(lib->encoding, tkm_encoder_encode); + +deinit: + libcharon_deinit(); + libhydra_deinit(); + library_deinit(); + tkm_deinit(); + return status; +} diff --git a/src/charon-tkm/src/ees/ees_callbacks.c b/src/charon-tkm/src/ees/ees_callbacks.c new file mode 100644 index 000000000..2d9653837 --- /dev/null +++ b/src/charon-tkm/src/ees/ees_callbacks.c @@ -0,0 +1,40 @@ +/* + * 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 <hydra.h> +#include <utils/debug.h> +#include <tkm/constants.h> +#include <tkm/types.h> + +#include "ees_callbacks.h" + +void charon_esa_acquire(result_type *res, const sp_id_type sp_id) +{ + DBG1(DBG_KNL, "ees: acquire received for reqid {%d}", sp_id); + hydra->kernel_interface->acquire(hydra->kernel_interface, sp_id, NULL, + NULL); + *res = TKM_OK; +} + +void charon_esa_expire(result_type *res, const sp_id_type sp_id, + const esp_spi_type spi_rem, const protocol_type protocol, + const expiry_flag_type hard) +{ + DBG1(DBG_KNL, "ees: expire received for reqid {%d}", sp_id); + hydra->kernel_interface->expire(hydra->kernel_interface, sp_id, protocol, + spi_rem, hard != 0); + *res = TKM_OK; +} diff --git a/src/charon-tkm/src/ees/ees_callbacks.h b/src/charon-tkm/src/ees/ees_callbacks.h new file mode 100644 index 000000000..b73dc6cb5 --- /dev/null +++ b/src/charon-tkm/src/ees/ees_callbacks.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. + */ + +/** + * @defgroup tkm-eescallbacks ees callbacks + * @{ @ingroup tkm + * + * ESP SA Event Service (EES) callbacks. + * The xfrm-proxy forwards acquire and expire events from the kernel to + * charon-tkm using the EES interface. Upon reception of an event the + * corresponding callback is executed. + */ + +#ifndef EES_CALLBACKS_H_ +#define EES_CALLBACKS_H_ + +/** + * Process Acquire event for given security policy. + */ +void charon_esa_acquire(result_type *res, const sp_id_type sp_id); + +/** + * Process Expire event for given security policy. + */ +void charon_esa_expire(result_type *res, const sp_id_type sp_id, + const esp_spi_type spi_rem, const protocol_type protocol, + const expiry_flag_type hard); + +#endif /** EES_CALLBACKS_H_ @}*/ diff --git a/src/charon-tkm/src/ees/esa_event_service.adb b/src/charon-tkm/src/ees/esa_event_service.adb new file mode 100644 index 000000000..5b5d7003b --- /dev/null +++ b/src/charon-tkm/src/ees/esa_event_service.adb @@ -0,0 +1,57 @@ +-- +-- 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. +-- + +with Anet.Sockets.Unix; +with Anet.Receivers.Stream; + +with Tkmrpc.Dispatchers.Ees; +with Tkmrpc.Process_Stream; + +pragma Elaborate_All (Anet.Receivers.Stream); +pragma Elaborate_All (Tkmrpc.Process_Stream); + +package body Esa_Event_Service +is + + package Unix_TCP_Receiver is new Anet.Receivers.Stream + (Socket_Type => Anet.Sockets.Unix.TCP_Socket_Type); + + procedure Dispatch is new Tkmrpc.Process_Stream + (Dispatch => Tkmrpc.Dispatchers.Ees.Dispatch); + + Sock : aliased Anet.Sockets.Unix.TCP_Socket_Type; + Receiver : Unix_TCP_Receiver.Receiver_Type (S => Sock'Access); + + ------------------------------------------------------------------------- + + procedure Finalize + is + begin + Receiver.Stop; + end Finalize; + + ------------------------------------------------------------------------- + + procedure Init (Address : Interfaces.C.Strings.chars_ptr) + is + Path : constant String := Interfaces.C.Strings.Value (Address); + begin + Sock.Init; + Sock.Bind (Path => Anet.Sockets.Unix.Path_Type (Path)); + Receiver.Listen (Callback => Dispatch'Access); + end Init; + +end Esa_Event_Service; diff --git a/src/charon-tkm/src/ees/esa_event_service.ads b/src/charon-tkm/src/ees/esa_event_service.ads new file mode 100644 index 000000000..f3630b7ac --- /dev/null +++ b/src/charon-tkm/src/ees/esa_event_service.ads @@ -0,0 +1,30 @@ +-- +-- 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. +-- + +with Interfaces.C.Strings; + +package Esa_Event_Service +is + + procedure Init (Address : Interfaces.C.Strings.chars_ptr); + pragma Export (C, Init, "ees_server_init"); + -- Initialize Esa Event Service (EES) with given address. + + procedure Finalize; + pragma Export (C, Finalize, "ees_server_finalize"); + -- Finalize EES. + +end Esa_Event_Service; diff --git a/src/charon-tkm/src/ees/tkmrpc-servers-ees.adb b/src/charon-tkm/src/ees/tkmrpc-servers-ees.adb new file mode 100644 index 000000000..2240065c2 --- /dev/null +++ b/src/charon-tkm/src/ees/tkmrpc-servers-ees.adb @@ -0,0 +1,65 @@ +package body Tkmrpc.Servers.Ees +is + + -------------------------------- + -- charon callback signatures -- + -------------------------------- + + procedure Charon_Esa_Acquire + (Result : out Results.Result_Type; + Sp_Id : Types.Sp_Id_Type); + pragma Import (C, Charon_Esa_Acquire, "charon_esa_acquire"); + + procedure Charon_Esa_Expire + (Result : out Results.Result_Type; + Sp_Id : Types.Sp_Id_Type; + Spi_Rem : Types.Esp_Spi_Type; + Protocol : Types.Protocol_Type; + Hard : Types.Expiry_Flag_Type); + pragma Import (C, Charon_Esa_Expire, "charon_esa_expire"); + + ------------------------------------------------------------------------- + + procedure Esa_Acquire + (Result : out Results.Result_Type; + Sp_Id : Types.Sp_Id_Type) + is + begin + Charon_Esa_Acquire (Result => Result, + Sp_Id => Sp_Id); + end Esa_Acquire; + + ------------------------------------------------------------------------- + + procedure Esa_Expire + (Result : out Results.Result_Type; + Sp_Id : Types.Sp_Id_Type; + Spi_Rem : Types.Esp_Spi_Type; + Protocol : Types.Protocol_Type; + Hard : Types.Expiry_Flag_Type) + is + begin + Charon_Esa_Expire (Result => Result, + Sp_Id => Sp_Id, + Spi_Rem => Spi_Rem, + Protocol => Protocol, + Hard => Hard); + end Esa_Expire; + + ------------------------------------------------------------------------- + + procedure Finalize + is + begin + null; + end Finalize; + + ------------------------------------------------------------------------- + + procedure Init + is + begin + null; + end Init; + +end Tkmrpc.Servers.Ees; diff --git a/src/charon-tkm/src/ehandler/eh_callbacks.c b/src/charon-tkm/src/ehandler/eh_callbacks.c new file mode 100644 index 000000000..7dca97c3e --- /dev/null +++ b/src/charon-tkm/src/ehandler/eh_callbacks.c @@ -0,0 +1,28 @@ +/* + * 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 <sys/types.h> +#include <signal.h> +#include <utils/debug.h> + +#include "eh_callbacks.h" + +void charon_terminate(char *msg) +{ + DBG1(DBG_DMN, "critical TKM error, terminating!"); + DBG1(DBG_DMN, msg); + kill(0, SIGTERM); +} diff --git a/src/charon-tkm/src/ehandler/eh_callbacks.h b/src/charon-tkm/src/ehandler/eh_callbacks.h new file mode 100644 index 000000000..db325dcd2 --- /dev/null +++ b/src/charon-tkm/src/ehandler/eh_callbacks.h @@ -0,0 +1,34 @@ +/* + * 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. + */ + +/** + * @defgroup tkm-ehandler exception handler + * @{ @ingroup tkm + * + * The exception handler callback is registered as global exception action in + * the Ada runtime. If an exception is raised in Ada code this callback is + * executed. + */ + +#ifndef EH_CALLBACKS_H_ +#define EH_CALLBACKS_H_ + +/** + * Log given message and terminate charon. + */ +void charon_terminate(char *msg); + +#endif /** EH_CALLBACKS_H_ @}*/ diff --git a/src/charon-tkm/src/ehandler/exception_handler.adb b/src/charon-tkm/src/ehandler/exception_handler.adb new file mode 100644 index 000000000..3f165e1cd --- /dev/null +++ b/src/charon-tkm/src/ehandler/exception_handler.adb @@ -0,0 +1,57 @@ +-- +-- 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. +-- + +with Ada.Exceptions; + +with GNAT.Exception_Actions; + +with Interfaces.C.Strings; + +package body Exception_Handler +is + + procedure Charon_Terminate (Message : Interfaces.C.Strings.chars_ptr); + pragma Import (C, Charon_Terminate, "charon_terminate"); + + procedure Bailout (Ex : Ada.Exceptions.Exception_Occurrence); + -- Signal critical condition to charon daemon. + + ------------------------------------------------------------------------- + + procedure Bailout (Ex : Ada.Exceptions.Exception_Occurrence) + is + begin + if Ada.Exceptions.Exception_Name (Ex) = "_ABORT_SIGNAL" then + + -- Ignore runtime-internal abort signal exception. + + return; + end if; + + Charon_Terminate (Message => Interfaces.C.Strings.New_String + (Ada.Exceptions.Exception_Information (Ex))); + end Bailout; + + ------------------------------------------------------------------------- + + procedure Init + is + begin + GNAT.Exception_Actions.Register_Global_Action + (Action => Bailout'Access); + end Init; + +end Exception_Handler; diff --git a/src/charon-tkm/src/ehandler/exception_handler.ads b/src/charon-tkm/src/ehandler/exception_handler.ads new file mode 100644 index 000000000..29dd3d8f4 --- /dev/null +++ b/src/charon-tkm/src/ehandler/exception_handler.ads @@ -0,0 +1,24 @@ +-- +-- 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. +-- + +package Exception_Handler +is + + procedure Init; + pragma Export (C, Init, "ehandler_init"); + -- Register last-chance exception handler. + +end Exception_Handler; 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..a39221dc2 --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm.c @@ -0,0 +1,123 @@ +/* + * 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 <daemon.h> + +#include <tkm/client.h> +#include <tkm/constants.h> + +#include "tkm.h" + +#define IKE_SOCKET "/tmp/tkm.rpc.ike" +#define EES_SOCKET "/tmp/tkm.rpc.ees" + +typedef struct private_tkm_t private_tkm_t; + +extern result_type ees_server_init(const char * const address); +extern void ees_server_finalize(void); +extern void ehandler_init(void); + +/* + * 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; + active_requests_type max_requests; + char *ikesock, *eessock; + tkm_limits_t limits; + + /* initialize TKM client library */ + tkmlib_init(); + ehandler_init(); + + ikesock = lib->settings->get_str(lib->settings, "%s.ike_socket", IKE_SOCKET, + charon->name); + if (ike_init(ikesock) != TKM_OK) + { + tkmlib_final(); + return FALSE; + } + DBG1(DBG_DMN, "connected to TKM via socket '%s'", ikesock); + + eessock = lib->settings->get_str(lib->settings, "%s.ees_socket", EES_SOCKET, + charon->name); + ees_server_init(eessock); + DBG1(DBG_DMN, "serving EES requests on socket '%s'", eessock); + + if (ike_tkm_reset() != TKM_OK) + { + ees_server_finalize(); + tkmlib_final(); + return FALSE; + } + + /* get limits from tkm */ + if (ike_tkm_limits(&max_requests, &limits[TKM_CTX_NONCE], &limits[TKM_CTX_DH], + &limits[TKM_CTX_CC], &limits[TKM_CTX_AE], + &limits[TKM_CTX_ISA], &limits[TKM_CTX_ESA]) != TKM_OK) + { + ees_server_finalize(); + tkmlib_final(); + return FALSE; + } + + INIT(this, + .public = { + .idmgr = tkm_id_manager_create(limits), + .chunk_map = tkm_chunk_map_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); + this->public.chunk_map->destroy(this->public.chunk_map); + + ees_server_finalize(); + + tkmlib_final(); + 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..fb5acd117 --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm.h @@ -0,0 +1,113 @@ +/* + * 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. + */ + +/** + * @defgroup tkm tkm + * + * @addtogroup tkm + * @{ + * + * Untrusted IKEv2 component used with Trusted Key Manager for IKE + * disaggregation. + * + * The untrusted IKEv2 component used in conjunction with the Trusted Key + * Manager infrastructure is implemented as a separate charon instance located + * in its own directory below the strongSwan top-level source directory + * (src/charon-tkm). This has the advantage that the TKM code is contained and + * does not mix with other strongSwan files. The charon-tkm binary startup code + * is modeled after the charon-nm instance, a special charon daemon variant to + * be used with the GNOME NetworkManager project. The major difference is the + * registration of custom TKM plugins as the final step of the startup phase. + * The charon-tkm daemon does not rely on the dynamic plugin loading mechanism + * for its core plugins, they are statically registered before entering the main + * processing loop. + * + * The following diagram shows the main components of the system and how they + * communicate. + @verbatim + + +------------+ +------------+ +------------+ + | xfrm-proxy |<-[tkm-rpc->| charon-tkm |<-[tkm-rpc]->| TKM | + +------------+ +------------+ +------------+ + ^ ^ + [Netlink | XFRM] [XFRM | Netlink] + | v + +-----------------------------------------------------------------+ + | Kernel | + +-----------------------------------------------------------------+ + + @endverbatim + * Since the charon-tkm code uses the tkm-rpc library written in Ada, the daemon + * has to be built using an Ada-aware toolchain. The integration of Ada code + * into the strongSwan codebase is explained in the TKM documentation, section + * 5.4.1: http://www.codelabs.ch/tkm#anchor-doc. + * + * The Trusted Key Manager (TKM) is a minimal Trusted Computing Base which + * implements security-critical functions of the IKEv2 protocol. + * + * The xfrm-proxy receives XFRM Acquire and Expiry events from the kernel and + * forwards them to the charon-tkm IKE daemon for further processing. + * + * The underlying concept of IKE disaggregation and the design of TKM and all + * related components, of which charon-tkm is one component, is presented in + * detail in the project documentation found at + * http://www.codelabs.ch/tkm#anchor-doc. + */ + +#ifndef TKM_H_ +#define TKM_H_ + +#include "tkm_id_manager.h" +#include "tkm_chunk_map.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; + + /** + * Chunk-to-ID mappings. + */ + tkm_chunk_map_t *chunk_map; + +}; + +/** + * Initialize trusted key manager, creates "tkm" instance. + * + * @return FALSE if initialization error occurred + */ +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_chunk_map.c b/src/charon-tkm/src/tkm/tkm_chunk_map.c new file mode 100644 index 000000000..03ff22836 --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_chunk_map.c @@ -0,0 +1,171 @@ +/* + * 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 <collections/hashtable.h> +#include <threading/rwlock.h> +#include <utils/chunk.h> +#include <utils/debug.h> + +#include "tkm_chunk_map.h" + +typedef struct private_tkm_chunk_map_t private_tkm_chunk_map_t; + +/** + * Private data of tkm chunk map. + */ +struct private_tkm_chunk_map_t { + + /** + * public functions + */ + tkm_chunk_map_t public; + + /** + * Hashtable to store mappings. + */ + hashtable_t *mappings; + + /** + * rwlock for table. + */ + rwlock_t *lock; + +}; + +/** + * Entry for hashtables + */ +typedef struct { + /** Key chunk */ + chunk_t key; + /** Entry value */ + uint64_t value; +} entry_t; + +/** + * Destroy a hashtable entry + */ +static void entry_destroy(entry_t *this) +{ + chunk_free(&this->key); + free(this); +} + +METHOD(tkm_chunk_map_t, insert, void, + private_tkm_chunk_map_t * const this, const chunk_t * const data, + const uint64_t id) +{ + entry_t *entry; + INIT(entry, + .key = chunk_clone(*data), + .value = id + ); + + this->lock->write_lock(this->lock); + entry = this->mappings->put(this->mappings, (void*)&entry->key, entry); + this->lock->unlock(this->lock); + + if (entry) + { + entry_destroy(entry); + } +} + +METHOD(tkm_chunk_map_t, get_id, uint64_t, + private_tkm_chunk_map_t * const this, chunk_t *data) +{ + entry_t *entry; + this->lock->read_lock(this->lock); + entry = this->mappings->get(this->mappings, data); + this->lock->unlock(this->lock); + + if (!entry) + { + return 0; + } + + return entry->value; +} + +METHOD(tkm_chunk_map_t, remove_, bool, + private_tkm_chunk_map_t * const this, chunk_t *data) +{ + entry_t *entry; + + this->lock->write_lock(this->lock); + entry = this->mappings->remove(this->mappings, data); + this->lock->unlock(this->lock); + + if (entry) + { + entry_destroy(entry); + return TRUE; + } + else + { + return FALSE; + } +} + +METHOD(tkm_chunk_map_t, destroy, void, + private_tkm_chunk_map_t *this) +{ + entry_t *entry; + enumerator_t *enumerator; + + this->lock->write_lock(this->lock); + enumerator = this->mappings->create_enumerator(this->mappings); + while (enumerator->enumerate(enumerator, NULL, &entry)) + { + entry_destroy(entry); + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + + this->mappings->destroy(this->mappings); + this->lock->destroy(this->lock); + free(this); +} + +/** + * Hashtable hash function. + */ +static u_int hash(chunk_t *key) +{ + return chunk_hash(*key); +} + +/* + * see header file + */ +tkm_chunk_map_t *tkm_chunk_map_create() +{ + private_tkm_chunk_map_t *this; + + INIT(this, + .public = { + .insert = _insert, + .get_id = _get_id, + .remove = _remove_, + .destroy = _destroy, + }, + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + .mappings = hashtable_create((hashtable_hash_t)hash, + (hashtable_equals_t)chunk_equals_ptr, 32), + ); + + return &this->public; +} diff --git a/src/charon-tkm/src/tkm/tkm_chunk_map.h b/src/charon-tkm/src/tkm/tkm_chunk_map.h new file mode 100644 index 000000000..c183937c1 --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_chunk_map.h @@ -0,0 +1,72 @@ +/* + * 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. + */ + +/** + * @defgroup tkm-chunk-map chunk map + * @{ @ingroup tkm + */ + +#ifndef TKM_CHUNK_MAP_H_ +#define TKM_CHUNK_MAP_H_ + +#include <stdint.h> +#include <utils/chunk.h> + +typedef struct tkm_chunk_map_t tkm_chunk_map_t; + +/** + * The tkm chunk map handles mappings of chunks to ids. + */ +struct tkm_chunk_map_t { + + /** + * Store new mapping for given chunk and id. + * + * @param data data associated with id + * @param id id associated with data + */ + void (*insert)(tkm_chunk_map_t * const this, const chunk_t * const data, + const uint64_t id); + + /** + * Get id for given chunk. + * + * @param data data specifying the mapping + * @return id of given chunk, 0 if not found + */ + uint64_t (*get_id)(tkm_chunk_map_t * const this, chunk_t *data); + + /** + * Remove mapping for given chunk. + * + * @param data data specifying the mapping to remove + * @return TRUE if mapping was removed, FALSE otherwise + */ + bool (*remove)(tkm_chunk_map_t * const this, chunk_t *data); + + /** + * Destroy a tkm chunk map instance. + */ + void (*destroy)(tkm_chunk_map_t *this); + +}; + +/** + * Create a tkm chunk map instance. + */ +tkm_chunk_map_t *tkm_chunk_map_create(); + +#endif /** TKM_CHUNK_MAP_H_ @}*/ diff --git a/src/charon-tkm/src/tkm/tkm_cred.c b/src/charon-tkm/src/tkm/tkm_cred.c new file mode 100644 index 000000000..d9517f908 --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_cred.c @@ -0,0 +1,148 @@ +/* + * 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 <credentials/sets/mem_cred.h> +#include <collections/hashtable.h> +#include <threading/rwlock.h> +#include <utils/debug.h> + +#include "tkm_private_key.h" +#include "tkm_cred.h" + +typedef struct private_tkm_cred_t private_tkm_cred_t; + +/** + * Private data of a tkm_cred_t object. + */ +struct private_tkm_cred_t { + + /** + * Public tkm_cred_t interface. + */ + tkm_cred_t public; + + /** + * In-memory credential set. + */ + mem_cred_t *creds; + + /** + * Key-id hashtable. + */ + hashtable_t *known_keys; + + /** + * rwlock for hashtable. + */ + rwlock_t *lock; + +}; + +METHOD(credential_set_t, create_private_enumerator, enumerator_t*, + private_tkm_cred_t *this, key_type_t type, identification_t *id) +{ + identification_t *entry; + + if (!id) + { + return this->known_keys->create_enumerator(this->known_keys); + } + + this->lock->write_lock(this->lock); + entry = this->known_keys->get(this->known_keys, id); + + if (!entry) + { + identification_t *clone = id->clone(id); + tkm_private_key_t *key = tkm_private_key_init(id); + + DBG1(DBG_CFG, "adding private key proxy for id '%Y'", clone); + if (!key) + { + DBG1(DBG_CFG, "unable to create private key for id '%Y'", clone); + this->lock->unlock(this->lock); + return NULL; + } + this->creds->add_key(this->creds, (private_key_t *)key); + entry = this->known_keys->put(this->known_keys, clone, clone); + } + this->lock->unlock(this->lock); + + return this->creds->set.create_private_enumerator(&this->creds->set, + type, id); +} + +METHOD(tkm_cred_t, destroy, void, + private_tkm_cred_t *this) +{ + enumerator_t *enumerator; + identification_t *entry; + + enumerator = this->known_keys->create_enumerator(this->known_keys); + while (enumerator->enumerate(enumerator, NULL, &entry)) + { + entry->destroy(entry); + } + enumerator->destroy(enumerator); + this->known_keys->destroy(this->known_keys); + + this->creds->destroy(this->creds); + this->lock->destroy(this->lock); + free(this); +} + +/** + * Hashtable hash function. + */ +static u_int hash(identification_t *id) +{ + return chunk_hash(id->get_encoding(id)); +} + +/** + * Hashtable equals function. + */ +static bool equals(identification_t *a, identification_t *b) +{ + return a->equals(a, b); +} + +/** + * See header + */ +tkm_cred_t *tkm_cred_create() +{ + private_tkm_cred_t *this; + + INIT(this, + .public = { + .set = { + .create_shared_enumerator = (void*)return_null, + .create_private_enumerator = _create_private_enumerator, + .create_cert_enumerator = (void*)return_null, + .create_cdp_enumerator = (void*)return_null, + .cache_cert = (void*)nop, + }, + .destroy = _destroy, + }, + .creds = mem_cred_create(), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + .known_keys = hashtable_create((hashtable_hash_t)hash, + (hashtable_equals_t)equals, 4), + ); + + return &this->public; +} diff --git a/src/charon-tkm/src/tkm/tkm_cred.h b/src/charon-tkm/src/tkm/tkm_cred.h new file mode 100644 index 000000000..1cfb5b9c7 --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_cred.h @@ -0,0 +1,51 @@ +/* + * 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. + */ + +/** + * @defgroup tkm-credential credential set + * @{ @ingroup tkm + */ + +#ifndef TKM_CRED_H_ +#define TKM_CRED_H_ + +typedef struct tkm_cred_t tkm_cred_t; + +#include <credentials/credential_set.h> + +/** + * TKM in-memory credential set. + */ +struct tkm_cred_t { + + /** + * Implements credential_set_t. + */ + credential_set_t set; + + /** + * Destroy a tkm_cred_t. + */ + void (*destroy)(tkm_cred_t *this); + +}; + +/** + * Create a tkm_cred instance. + */ +tkm_cred_t *tkm_cred_create(); + +#endif /** TKM_CRED_H_ @}*/ diff --git a/src/charon-tkm/src/tkm/tkm_diffie_hellman.c b/src/charon-tkm/src/tkm/tkm_diffie_hellman.c new file mode 100644 index 000000000..19f57de01 --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_diffie_hellman.c @@ -0,0 +1,140 @@ +/* + * 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/client.h> +#include <tkm/constants.h> + +#include "tkm.h" +#include "tkm_utils.h" +#include "tkm_diffie_hellman.h" + +#include <utils/debug.h> + +typedef struct private_tkm_diffie_hellman_t private_tkm_diffie_hellman_t; + +/** + * Private data of a tkm_diffie_hellman_t object. + */ +struct private_tkm_diffie_hellman_t { + + /** + * Public tkm_diffie_hellman_t interface. + */ + tkm_diffie_hellman_t public; + + /** + * Diffie Hellman group number. + */ + u_int16_t group; + + /** + * Diffie Hellman public value. + */ + dh_pubvalue_type pubvalue; + + /** + * Context id. + */ + dh_id_type context_id; + +}; + +METHOD(diffie_hellman_t, get_my_public_value, void, + private_tkm_diffie_hellman_t *this, chunk_t *value) +{ + sequence_to_chunk(this->pubvalue.data, this->pubvalue.size, value); +} + +METHOD(diffie_hellman_t, get_shared_secret, status_t, + private_tkm_diffie_hellman_t *this, chunk_t *secret) +{ + *secret = chunk_empty; + return SUCCESS; +} + + +METHOD(diffie_hellman_t, set_other_public_value, void, + private_tkm_diffie_hellman_t *this, chunk_t value) +{ + // TODO: unvoid this function + + dh_pubvalue_type othervalue; + othervalue.size = value.len; + memcpy(&othervalue.data, value.ptr, value.len); + + ike_dh_generate_key(this->context_id, othervalue); +} + +METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t, + private_tkm_diffie_hellman_t *this) +{ + return this->group; +} + +METHOD(diffie_hellman_t, destroy, void, + private_tkm_diffie_hellman_t *this) +{ + if (ike_dh_reset(this->context_id) != TKM_OK) + { + DBG1(DBG_LIB, "failed to reset DH context %d", this->context_id); + } + + tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_DH, this->context_id); + free(this); +} + +METHOD(tkm_diffie_hellman_t, get_id, dh_id_type, + private_tkm_diffie_hellman_t *this) +{ + return this->context_id; +} + +/* + * Described in header. + */ +tkm_diffie_hellman_t *tkm_diffie_hellman_create(diffie_hellman_group_t group) +{ + private_tkm_diffie_hellman_t *this; + + INIT(this, + .public = { + .dh = { + .get_shared_secret = _get_shared_secret, + .set_other_public_value = _set_other_public_value, + .get_my_public_value = _get_my_public_value, + .get_dh_group = _get_dh_group, + .destroy = _destroy, + }, + .get_id = _get_id, + }, + .group = group, + .context_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_DH), + ); + + if (!this->context_id) + { + free(this); + return NULL; + } + + if (ike_dh_create(this->context_id, group, &this->pubvalue) != TKM_OK) + { + free(this); + return NULL; + } + + return &this->public; +} diff --git a/src/charon-tkm/src/tkm/tkm_diffie_hellman.h b/src/charon-tkm/src/tkm/tkm_diffie_hellman.h new file mode 100644 index 000000000..a144303fa --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_diffie_hellman.h @@ -0,0 +1,57 @@ +/* + * 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. + */ + +/** + * @defgroup tkm-dh diffie hellman + * @{ @ingroup tkm + */ + +#ifndef TKM_DIFFIE_HELLMAN_H_ +#define TKM_DIFFIE_HELLMAN_H_ + +typedef struct tkm_diffie_hellman_t tkm_diffie_hellman_t; + +#include <library.h> +#include <tkm/types.h> + +/** + * diffie_hellman_t implementation using the trusted key manager. + */ +struct tkm_diffie_hellman_t { + + /** + * Implements diffie_hellman_t interface. + */ + diffie_hellman_t dh; + + /** + * Get Diffie-Hellman context id. + * + * @return id of this DH context. + */ + dh_id_type (*get_id)(tkm_diffie_hellman_t * const this); + +}; + +/** + * Creates a new tkm_diffie_hellman_t object. + * + * @param group Diffie Hellman group number to use + * @return tkm_diffie_hellman_t object, NULL if not supported + */ +tkm_diffie_hellman_t *tkm_diffie_hellman_create(diffie_hellman_group_t group); + +#endif /** TKM_DIFFIE_HELLMAN_H_ @}*/ diff --git a/src/charon-tkm/src/tkm/tkm_encoder.c b/src/charon-tkm/src/tkm/tkm_encoder.c new file mode 100644 index 000000000..d5367ea78 --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_encoder.c @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2013 Reto Buerki + * Copyright (C) 2013 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 <utils/debug.h> +#include <asn1/asn1.h> +#include <asn1/oid.h> + +#include "tkm_encoder.h" + +/** + * Build the SHA1 hash of pubkey(info) ASN.1 data. + */ +static bool hash_pubkey(chunk_t pubkey, chunk_t *hash) +{ + hasher_t *hasher; + + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (!hasher || !hasher->allocate_hash(hasher, pubkey, hash)) + { + DBG1(DBG_LIB, "SHA1 hash algorithm not supported, " + "fingerprinting failed"); + DESTROY_IF(hasher); + chunk_free(&pubkey); + return FALSE; + } + hasher->destroy(hasher); + chunk_free(&pubkey); + return TRUE; +} + +/** + * Encode the public key blob into subjectPublicKeyInfo. + */ +static bool build_pub_info(chunk_t *encoding, va_list args) +{ + chunk_t blob; + + if (cred_encoding_args(args, CRED_PART_RSA_PUB_ASN1_DER, &blob, + CRED_PART_END)) + { + *encoding = asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_algorithmIdentifier(OID_RSA_ENCRYPTION), + asn1_bitstring("c", blob)); + return TRUE; + } + return FALSE; +} + +/** + * Build the fingerprint of the subjectPublicKeyInfo object. + */ +static bool build_info_sha1(chunk_t *encoding, va_list args) +{ + chunk_t pubkey; + + if (build_pub_info(&pubkey, args)) + { + return hash_pubkey(pubkey, encoding); + } + return FALSE; +} + +/** + * Build the fingerprint of the subjectPublicKey object. + */ +static bool build_sha1(chunk_t *encoding, va_list args) +{ + chunk_t blob; + + if (cred_encoding_args(args, CRED_PART_RSA_PUB_ASN1_DER, &blob, + CRED_PART_END)) + { + return hash_pubkey(chunk_clone(blob), encoding); + } + return FALSE; +} + +/** + * See header. + */ +bool tkm_encoder_encode(cred_encoding_type_t type, chunk_t *encoding, + va_list args) +{ + switch (type) + { + case KEYID_PUBKEY_INFO_SHA1: + return build_info_sha1(encoding, args); + case KEYID_PUBKEY_SHA1: + return build_sha1(encoding, args); + default: + return FALSE; + } +} diff --git a/src/charon-tkm/src/tkm/tkm_encoder.h b/src/charon-tkm/src/tkm/tkm_encoder.h new file mode 100644 index 000000000..7c6a4989d --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_encoder.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2013 Reto Buerki + * Copyright (C) 2013 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. + */ + +/** + * @defgroup tkm-credential-enc credential encoder + * @{ @ingroup tkm + */ + +#ifndef TKM_ENCODER_H_ +#define TKM_ENCODER_H_ + +#include <credentials/cred_encoding.h> + +/** + * Encoding function for TKM key fingerprints. + */ +bool tkm_encoder_encode(cred_encoding_type_t type, chunk_t *encoding, + va_list args); + +#endif /** TKM_ENCODER_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..407d0a87f --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_id_manager.c @@ -0,0 +1,168 @@ +/* + * 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> + +#define TKM_LIMIT 100 + +ENUM_BEGIN(tkm_context_kind_names, TKM_CTX_NONCE, TKM_CTX_ESA, + "NONCE_CONTEXT", + "DH_CONTEXT", + "CC_CONTEXT" + "ISA_CONTEXT", + "AE_CONTEXT", + "ESA_CONTEXT"); +ENUM_END(tkm_context_kind_names, TKM_CTX_ESA); + +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; + + /** + * Per-kind array of free context ids + */ + bool* ctxids[TKM_CTX_MAX]; + + /** + * Per-kind context limits. + */ + tkm_limits_t limits; + + /** + * 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 id = 0; + uint64_t j; + + 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]); + for (j = 0; j < this->limits[kind]; j++) + { + if (!this->ctxids[kind][j]) + { + this->ctxids[kind][j] = true; + id = j + 1; + break; + } + } + 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) +{ + const int idx = id - 1; + + 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]); + this->ctxids[kind][idx] = false; + this->locks[kind]->unlock(this->locks[kind]); + + 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++) + { + free(this->ctxids[i]); + this->locks[i]->destroy(this->locks[i]); + } + free(this); +} + +/* + * see header file + */ +tkm_id_manager_t *tkm_id_manager_create(const tkm_limits_t limits) +{ + 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->limits[i] = limits[i]; + this->ctxids[i] = calloc(limits[i], sizeof(bool)); + this->locks[i] = rwlock_create(RWLOCK_TYPE_DEFAULT); + DBG2(DBG_LIB, "%N initialized, %llu slot(s)", tkm_context_kind_names, i, + limits[i]); + } + + 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..0fc9ff8ef --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_id_manager.h @@ -0,0 +1,99 @@ +/* + * 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. + */ + +/** + * @defgroup tkm-id-manager id manager + * @{ @ingroup tkm + */ + +#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, + /** Diffie-Hellman context */ + TKM_CTX_DH, + /** Certificate chain context */ + TKM_CTX_CC, + /** IKE SA context */ + TKM_CTX_ISA, + /** Authenticated Endpoint context */ + TKM_CTX_AE, + /** ESP SA context */ + TKM_CTX_ESA, + + /** 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; + +/** + * TKM context limits. + */ +typedef uint64_t tkm_limits_t[TKM_CTX_MAX]; + +/** + * 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 using the given context limits. + */ +tkm_id_manager_t *tkm_id_manager_create(const tkm_limits_t limits); + +#endif /** TKM_ID_MANAGER_H_ @}*/ diff --git a/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c b/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c new file mode 100644 index 000000000..69aefea97 --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c @@ -0,0 +1,392 @@ +/* + * 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 <errno.h> +#include <netinet/udp.h> +#include <linux/xfrm.h> +#include <utils/debug.h> +#include <utils/chunk.h> +#include <tkm/constants.h> +#include <tkm/client.h> + +#include "tkm.h" +#include "tkm_utils.h" +#include "tkm_types.h" +#include "tkm_keymat.h" +#include "tkm_kernel_sad.h" +#include "tkm_kernel_ipsec.h" + +/** From linux/in.h */ +#ifndef IP_XFRM_POLICY +#define IP_XFRM_POLICY 17 +#endif + +typedef struct private_tkm_kernel_ipsec_t private_tkm_kernel_ipsec_t; + +/** + * Private variables and functions of TKM kernel ipsec instance. + */ +struct private_tkm_kernel_ipsec_t { + + /** + * Public tkm_kernel_ipsec interface. + */ + tkm_kernel_ipsec_t public; + + /** + * RNG used for SPI generation. + */ + rng_t *rng; + + /** + * CHILD/ESP SA database. + */ + tkm_kernel_sad_t *sad; + +}; + +METHOD(kernel_ipsec_t, get_spi, status_t, + private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst, + u_int8_t protocol, u_int32_t reqid, u_int32_t *spi) +{ + bool result; + + if (!this->rng) + { + this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!this->rng) + { + DBG1(DBG_KNL, "unable to create RNG"); + return FAILED; + } + } + + DBG1(DBG_KNL, "getting SPI for reqid {%u}", reqid); + result = this->rng->get_bytes(this->rng, sizeof(u_int32_t), + (u_int8_t *)spi); + return result ? SUCCESS : FAILED; +} + +METHOD(kernel_ipsec_t, get_cpi, status_t, + private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst, + u_int32_t reqid, u_int16_t *cpi) +{ + return NOT_SUPPORTED; +} + +METHOD(kernel_ipsec_t, add_sa, status_t, + private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst, + u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark, + u_int32_t tfc, lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key, + u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp, + u_int16_t cpi, bool encap, bool esn, bool inbound, + traffic_selector_t* src_ts, traffic_selector_t* dst_ts) +{ + esa_info_t esa; + bool initiator; + esp_spi_type spi_loc, spi_rem; + host_t *local, *peer; + chunk_t *nonce_loc, *nonce_rem; + nc_id_type nonce_loc_id; + esa_id_type esa_id; + nonce_type nc_rem; + + if (enc_key.ptr == NULL) + { + DBG1(DBG_KNL, "Unable to get ESA information"); + return FAILED; + } + esa = *(esa_info_t *)(enc_key.ptr); + + /* only handle the case where we have both distinct ESP spi's available */ + if (esa.spi_r == spi) + { + chunk_free(&esa.nonce_i); + chunk_free(&esa.nonce_r); + return SUCCESS; + } + + /* Initiator if encr_r is passed as enc_key to the inbound add_sa call */ + initiator = esa.is_encr_r && inbound; + if (initiator) + { + spi_loc = spi; + spi_rem = esa.spi_r; + local = dst; + peer = src; + nonce_loc = &esa.nonce_i; + nonce_rem = &esa.nonce_r; + } + else + { + spi_loc = esa.spi_r; + spi_rem = spi; + local = src; + peer = dst; + nonce_loc = &esa.nonce_r; + nonce_rem = &esa.nonce_i; + } + + esa_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_ESA); + if (!this->sad->insert(this->sad, esa_id, peer, local, spi_loc, protocol)) + { + DBG1(DBG_KNL, "unable to add entry (%llu) to SAD", esa_id); + goto sad_failure; + } + + /* + * creation of first CHILD SA: + * no nonce and no dh contexts because the ones from the IKE SA are re-used + */ + nonce_loc_id = tkm->chunk_map->get_id(tkm->chunk_map, nonce_loc); + if (nonce_loc_id == 0 && esa.dh_id == 0) + { + if (ike_esa_create_first(esa_id, esa.isa_id, reqid, 1, spi_loc, spi_rem) + != TKM_OK) + { + DBG1(DBG_KNL, "child SA (%llu, first) creation failed", esa_id); + goto failure; + } + } + /* creation of child SA without PFS: no dh context */ + else if (nonce_loc_id != 0 && esa.dh_id == 0) + { + chunk_to_sequence(nonce_rem, &nc_rem, sizeof(nonce_type)); + if (ike_esa_create_no_pfs(esa_id, esa.isa_id, reqid, 1, nonce_loc_id, + nc_rem, initiator, spi_loc, spi_rem) + != TKM_OK) + { + DBG1(DBG_KNL, "child SA (%llu, no PFS) creation failed", esa_id); + goto failure; + } + tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_NONCE, nonce_loc_id); + } + /* creation of subsequent child SA with PFS: nonce and dh context are set */ + else + { + chunk_to_sequence(nonce_rem, &nc_rem, sizeof(nonce_type)); + if (ike_esa_create(esa_id, esa.isa_id, reqid, 1, esa.dh_id, nonce_loc_id, + nc_rem, initiator, spi_loc, spi_rem) != TKM_OK) + { + DBG1(DBG_KNL, "child SA (%llu) creation failed", esa_id); + goto failure; + } + tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_NONCE, nonce_loc_id); + } + if (ike_esa_select(esa_id) != TKM_OK) + { + DBG1(DBG_KNL, "error selecting new child SA (%llu)", esa_id); + if (ike_esa_reset(esa_id) != TKM_OK) + { + DBG1(DBG_KNL, "child SA (%llu) deletion failed", esa_id); + } + goto failure; + } + + DBG1(DBG_KNL, "added child SA (esa: %llu, isa: %llu, esp_spi_loc: %x, " + "esp_spi_rem: %x, role: %s)", esa_id, esa.isa_id, ntohl(spi_loc), + ntohl(spi_rem), initiator ? "initiator" : "responder"); + chunk_free(&esa.nonce_i); + chunk_free(&esa.nonce_r); + + return SUCCESS; + +failure: + this->sad->remove(this->sad, esa_id); +sad_failure: + tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_ESA, esa_id); + chunk_free(&esa.nonce_i); + chunk_free(&esa.nonce_r); + return FAILED; +} + +METHOD(kernel_ipsec_t, query_sa, status_t, + private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst, + u_int32_t spi, u_int8_t protocol, mark_t mark, u_int64_t *bytes, + u_int64_t *packets) +{ + return NOT_SUPPORTED; +} + +METHOD(kernel_ipsec_t, del_sa, status_t, + private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst, + u_int32_t spi, u_int8_t protocol, u_int16_t cpi, mark_t mark) +{ + esa_id_type esa_id; + + esa_id = this->sad->get_esa_id(this->sad, src, dst, spi, protocol); + if (esa_id) + { + DBG1(DBG_KNL, "deleting child SA (esa: %llu, spi: %x)", esa_id, + ntohl(spi)); + if (ike_esa_reset(esa_id) != TKM_OK) + { + DBG1(DBG_KNL, "child SA (%llu) deletion failed", esa_id); + return FAILED; + } + this->sad->remove(this->sad, esa_id); + tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_ESA, esa_id); + } + return SUCCESS; +} + +METHOD(kernel_ipsec_t, update_sa, status_t, + private_tkm_kernel_ipsec_t *this, u_int32_t spi, u_int8_t protocol, + u_int16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst, + bool old_encap, bool new_encap, mark_t mark) +{ + return NOT_SUPPORTED; +} + +METHOD(kernel_ipsec_t, flush_sas, status_t, + private_tkm_kernel_ipsec_t *this) +{ + DBG1(DBG_KNL, "flushing child SA entries"); + return SUCCESS; +} + +METHOD(kernel_ipsec_t, add_policy, status_t, + private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts, + policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, + mark_t mark, policy_priority_t priority) +{ + return SUCCESS; +} + +METHOD(kernel_ipsec_t, query_policy, status_t, + private_tkm_kernel_ipsec_t *this, traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, + u_int32_t *use_time) +{ + return NOT_SUPPORTED; +} + +METHOD(kernel_ipsec_t, del_policy, status_t, + private_tkm_kernel_ipsec_t *this, traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid, + mark_t mark, policy_priority_t prio) +{ + return SUCCESS; +} + +METHOD(kernel_ipsec_t, flush_policies, status_t, + private_tkm_kernel_ipsec_t *this) +{ + return SUCCESS; +} + + +METHOD(kernel_ipsec_t, bypass_socket, bool, + private_tkm_kernel_ipsec_t *this, int fd, int family) +{ + struct xfrm_userpolicy_info policy; + u_int sol, ipsec_policy; + + switch (family) + { + case AF_INET: + sol = SOL_IP; + ipsec_policy = IP_XFRM_POLICY; + break; + case AF_INET6: + sol = SOL_IPV6; + ipsec_policy = IPV6_XFRM_POLICY; + break; + default: + return FALSE; + } + + memset(&policy, 0, sizeof(policy)); + policy.action = XFRM_POLICY_ALLOW; + policy.sel.family = family; + + policy.dir = XFRM_POLICY_OUT; + if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0) + { + DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s", + strerror(errno)); + return FALSE; + } + policy.dir = XFRM_POLICY_IN; + if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0) + { + DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s", + strerror(errno)); + return FALSE; + } + return TRUE; +} + +METHOD(kernel_ipsec_t, enable_udp_decap, bool, + private_tkm_kernel_ipsec_t *this, int fd, int family, u_int16_t port) +{ + int type = UDP_ENCAP_ESPINUDP; + + if (setsockopt(fd, SOL_UDP, UDP_ENCAP, &type, sizeof(type)) < 0) + { + DBG1(DBG_KNL, "unable to set UDP_ENCAP: %s", strerror(errno)); + return FALSE; + } + return TRUE; +} + +METHOD(kernel_ipsec_t, destroy, void, + private_tkm_kernel_ipsec_t *this) +{ + DESTROY_IF(this->rng); + DESTROY_IF(this->sad); + free(this); +} + +/* + * Described in header. + */ +tkm_kernel_ipsec_t *tkm_kernel_ipsec_create() +{ + private_tkm_kernel_ipsec_t *this; + + INIT(this, + .public = { + .interface = { + .get_spi = _get_spi, + .get_cpi = _get_cpi, + .add_sa = _add_sa, + .update_sa = _update_sa, + .query_sa = _query_sa, + .del_sa = _del_sa, + .flush_sas = _flush_sas, + .add_policy = _add_policy, + .query_policy = _query_policy, + .del_policy = _del_policy, + .flush_policies = _flush_policies, + .bypass_socket = _bypass_socket, + .enable_udp_decap = _enable_udp_decap, + .destroy = _destroy, + }, + }, + .sad = tkm_kernel_sad_create(), + ); + + if (!this->sad) + { + DBG1(DBG_KNL, "unable to create SAD"); + destroy(this); + return NULL; + } + + return &this->public; +} diff --git a/src/charon-tkm/src/tkm/tkm_kernel_ipsec.h b/src/charon-tkm/src/tkm/tkm_kernel_ipsec.h new file mode 100644 index 000000000..14db21266 --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_kernel_ipsec.h @@ -0,0 +1,47 @@ +/* + * 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. + */ + +/** + * @defgroup tkm-kernel-ipsec kernel ipsec + * @{ @ingroup tkm + */ + +#ifndef TKM_KERNEL_IPSEC_H_ +#define TKM_KERNEL_IPSEC_H_ + +#include <kernel/kernel_ipsec.h> + +typedef struct tkm_kernel_ipsec_t tkm_kernel_ipsec_t; + +/** + * TKM implementation of the kernel ipsec interface. + */ +struct tkm_kernel_ipsec_t { + + /** + * Implements kernel_ipsec_t interface + */ + kernel_ipsec_t interface; +}; + +/** + * Create a TKM kernel ipsec interface instance. + * + * @return tkm_kernel_ipsec_t instance + */ +tkm_kernel_ipsec_t *tkm_kernel_ipsec_create(); + +#endif /** TKM_KERNEL_IPSEC_H_ @}*/ diff --git a/src/charon-tkm/src/tkm/tkm_kernel_sad.c b/src/charon-tkm/src/tkm/tkm_kernel_sad.c new file mode 100644 index 000000000..360a47bdc --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_kernel_sad.c @@ -0,0 +1,253 @@ +/* + * 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 <collections/linked_list.h> +#include <threading/mutex.h> +#include <utils/debug.h> + +#include "tkm_kernel_sad.h" + +typedef struct private_tkm_kernel_sad_t private_tkm_kernel_sad_t; + +/** + * Private data of tkm_kernel_sad. + */ +struct private_tkm_kernel_sad_t { + + /** + * Public functions. + */ + tkm_kernel_sad_t public; + + /** + * Linked list of SAD entries. + */ + linked_list_t *data; + + /** + * Lock used to protect SA data. + */ + mutex_t *mutex; + +}; + +typedef struct sad_entry_t sad_entry_t; + +/** + * Data structure holding all information of an SAD entry. + */ +struct sad_entry_t { + + /** + * ESA identifier. + */ + esa_id_type esa_id; + + /** + * Source address of CHILD SA. + */ + host_t *src; + + /** + * Destination address of CHILD SA. + */ + host_t *dst; + + /** + * SPI of CHILD SA. + */ + u_int32_t spi; + + /** + * Protocol of CHILD SA (ESP/AH). + */ + u_int8_t proto; + +}; + +/** + * Destroy an sad_entry_t object. + */ +static void sad_entry_destroy(sad_entry_t *entry) +{ + if (entry) + { + DESTROY_IF(entry->src); + DESTROY_IF(entry->dst); + free(entry); + } +} + +/** + * Find a list entry with given src, dst, spi and proto values. + */ +static bool sad_entry_match(sad_entry_t * const entry, const host_t * const src, + const host_t * const dst, const u_int32_t * const spi, + const u_int8_t * const proto) +{ + if (entry->src == NULL || entry->dst == NULL) + { + return FALSE; + } + + return src->ip_equals(entry->src, (host_t *)src) && + dst->ip_equals(entry->dst, (host_t *)dst) && + entry->spi == *spi && entry->proto == *proto; +} + +/** + * Compare two SAD entries for equality. + */ +static bool sad_entry_equal(sad_entry_t * const left, sad_entry_t * const right) +{ + if (left->src == NULL || left->dst == NULL || right->src == NULL || + right->dst == NULL) + { + return FALSE; + } + return left->esa_id == right->esa_id && + left->src->ip_equals(left->src, right->src) && + left->dst->ip_equals(left->dst, right->dst) && + left->spi == right->spi && left->proto == right->proto; +} + +METHOD(tkm_kernel_sad_t, insert, bool, + private_tkm_kernel_sad_t * const this, const esa_id_type esa_id, + const host_t * const src, const host_t * const dst, const u_int32_t spi, + const u_int8_t proto) +{ + status_t result; + sad_entry_t *new_entry; + + INIT(new_entry, + .esa_id = esa_id, + .src = (host_t *)src, + .dst = (host_t *)dst, + .spi = spi, + .proto = proto, + ); + + this->mutex->lock(this->mutex); + result = this->data->find_first(this->data, + (linked_list_match_t)sad_entry_equal, NULL, + new_entry); + if (result == NOT_FOUND) + { + DBG3(DBG_KNL, "inserting SAD entry (esa: %llu, src: %H, dst: %H, " + "spi: %x, proto: %u)", esa_id, src, dst, ntohl(spi), proto); + new_entry->src = src->clone((host_t *)src); + new_entry->dst = dst->clone((host_t *)dst); + this->data->insert_last(this->data, new_entry); + } + else + { + DBG1(DBG_KNL, "SAD entry with esa id %llu already exists!", esa_id); + free(new_entry); + } + this->mutex->unlock(this->mutex); + return result == NOT_FOUND; +} + +METHOD(tkm_kernel_sad_t, get_esa_id, esa_id_type, + private_tkm_kernel_sad_t * const this, const host_t * const src, + const host_t * const dst, const u_int32_t spi, const u_int8_t proto) +{ + esa_id_type id = 0; + sad_entry_t *entry = NULL; + + this->mutex->lock(this->mutex); + const status_t res = this->data->find_first(this->data, + (linked_list_match_t)sad_entry_match, + (void**)&entry, src, dst, &spi, + &proto); + if (res == SUCCESS && entry) + { + id = entry->esa_id; + DBG3(DBG_KNL, "getting ESA id of SAD entry (esa: %llu, src: %H, " + "dst: %H, spi: %x, proto: %u)", id, src, dst, ntohl(spi), + proto); + } + else + { + DBG3(DBG_KNL, "no SAD entry found"); + } + this->mutex->unlock(this->mutex); + return id; +} + +METHOD(tkm_kernel_sad_t, _remove, bool, + private_tkm_kernel_sad_t * const this, const esa_id_type esa_id) +{ + sad_entry_t *current; + bool removed = FALSE; + enumerator_t *enumerator; + + this->mutex->lock(this->mutex); + enumerator = this->data->create_enumerator(this->data); + while (enumerator->enumerate(enumerator, (void **)¤t)) + { + if (current->esa_id == esa_id) + { + this->data->remove_at(this->data, enumerator); + sad_entry_destroy(current); + removed = TRUE; + break; + } + } + enumerator->destroy(enumerator); + + if (removed) + { + DBG3(DBG_KNL, "removed SAD entry (esa: %llu)", esa_id); + } + else + { + DBG1(DBG_KNL, "no SAD entry with ESA id %llu found!", esa_id); + } + this->mutex->unlock(this->mutex); + + return removed; +} + + +METHOD(tkm_kernel_sad_t, destroy, void, + private_tkm_kernel_sad_t *this) +{ + this->mutex->destroy(this->mutex); + this->data->destroy_function(this->data, (void*)sad_entry_destroy); + free(this); +} + +/* + * see header file + */ +tkm_kernel_sad_t *tkm_kernel_sad_create() +{ + private_tkm_kernel_sad_t *this; + + INIT(this, + .public = { + .insert = _insert, + .get_esa_id = _get_esa_id, + .remove = __remove, + .destroy = _destroy, + }, + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + .data = linked_list_create(), + ); + + return &this->public; +} diff --git a/src/charon-tkm/src/tkm/tkm_kernel_sad.h b/src/charon-tkm/src/tkm/tkm_kernel_sad.h new file mode 100644 index 000000000..0194cd3bc --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_kernel_sad.h @@ -0,0 +1,83 @@ +/* + * 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. + */ + +/** + * @defgroup tkm-kernel-sad kernel sad + * @{ @ingroup tkm + */ + +#ifndef TKM_KERNEL_SAD_H_ +#define TKM_KERNEL_SAD_H_ + +#include <networking/host.h> +#include <tkm/types.h> + +typedef struct tkm_kernel_sad_t tkm_kernel_sad_t; + +/** + * The TKM kernel SAD (security association database) stores information about + * CHILD SAs. + */ +struct tkm_kernel_sad_t { + + /** + * Insert new SAD entry with specified parameters. + * + * @param esa_id ESP SA context identifier + * @param src source address of CHILD SA + * @param dst destination address of CHILD SA + * @param spi SPI of CHILD SA + * @param proto protocol of CHILD SA (ESP/AH) + * @return TRUE if entry was inserted, FALSE otherwise + */ + bool (*insert)(tkm_kernel_sad_t * const this, const esa_id_type esa_id, + const host_t * const src, const host_t * const dst, + const u_int32_t spi, const u_int8_t proto); + + /** + * Get ESA id for entry with given parameters. + * + * @param src source address of CHILD SA + * @param dst destination address of CHILD SA + * @param spi SPI of CHILD SA + * @param proto protocol of CHILD SA (ESP/AH) + * @return ESA id of entry if found, 0 otherwise + */ + esa_id_type (*get_esa_id)(tkm_kernel_sad_t * const this, + const host_t * const src, const host_t * const dst, + const u_int32_t spi, const u_int8_t proto); + + /** + * Remove entry with given ESA id from SAD. + * + * @param esa_id ESA identifier of entry to remove + * @return TRUE if entry was removed, FALSE otherwise + */ + bool (*remove)(tkm_kernel_sad_t * const this, const esa_id_type esa_id); + + /** + * Destroy a tkm_kernel_sad instance. + */ + void (*destroy)(tkm_kernel_sad_t *this); + +}; + +/** + * Create a TKM kernel SAD instance. + */ +tkm_kernel_sad_t *tkm_kernel_sad_create(); + +#endif /** TKM_KERNEL_SAD_H_ @}*/ diff --git a/src/charon-tkm/src/tkm/tkm_keymat.c b/src/charon-tkm/src/tkm/tkm_keymat.c new file mode 100644 index 000000000..772fac8b0 --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_keymat.c @@ -0,0 +1,511 @@ +/* + * 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 <daemon.h> +#include <tkm/constants.h> +#include <tkm/client.h> + +#include "tkm.h" +#include "tkm_types.h" +#include "tkm_utils.h" +#include "tkm_diffie_hellman.h" +#include "tkm_keymat.h" + +typedef struct private_tkm_keymat_t private_tkm_keymat_t; + +/** + * Private data of a keymat_t object. + */ +struct private_tkm_keymat_t { + + /** + * Public tkm_keymat_t interface. + */ + tkm_keymat_t public; + + /** + * IKE_SA Role, initiator or responder. + */ + bool initiator; + + /** + * Inbound AEAD. + */ + aead_t *aead_in; + + /** + * Outbound AEAD. + */ + aead_t *aead_out; + + /** + * ISA context id. + */ + isa_id_type isa_ctx_id; + + /** + * AE context id. + */ + ae_id_type ae_ctx_id; + + /** + * AUTH payload chunk. + */ + chunk_t auth_payload; + + /** + * Peer init message chunk. + */ + chunk_t other_init_msg; + +}; + +/** + * Create AEAD transforms from given key chunks. + * + * @param in inbound AEAD transform to allocate, NULL if failed + * @param out outbound AEAD transform to allocate, NULL if failed + * @param sk_ai SK_ai key chunk + * @param sk_ar SK_ar key chunk + * @param sk_ei SK_ei key chunk + * @param sk_er SK_er key chunk + * @param enc_alg encryption algorithm to use + * @param int_alg integrity algorithm to use + * @param key_size encryption key size in bytes + * @param initiator TRUE if initiator + */ +static void aead_create_from_keys(aead_t **in, aead_t **out, + const chunk_t * const sk_ai, const chunk_t * const sk_ar, + const chunk_t * const sk_ei, const chunk_t * const sk_er, + const u_int16_t enc_alg, const u_int16_t int_alg, + const u_int16_t key_size, bool initiator) +{ + *in = *out = NULL; + signer_t *signer_i, *signer_r; + crypter_t *crypter_i, *crypter_r; + + signer_i = lib->crypto->create_signer(lib->crypto, int_alg); + signer_r = lib->crypto->create_signer(lib->crypto, int_alg); + if (signer_i == NULL || signer_r == NULL) + { + DBG1(DBG_IKE, "%N %N not supported!", + transform_type_names, INTEGRITY_ALGORITHM, + integrity_algorithm_names, int_alg); + return; + } + crypter_i = lib->crypto->create_crypter(lib->crypto, enc_alg, key_size); + crypter_r = lib->crypto->create_crypter(lib->crypto, enc_alg, key_size); + if (crypter_i == NULL || crypter_r == NULL) + { + signer_i->destroy(signer_i); + signer_r->destroy(signer_r); + DBG1(DBG_IKE, "%N %N (key size %d) not supported!", + transform_type_names, ENCRYPTION_ALGORITHM, + encryption_algorithm_names, enc_alg, key_size); + return; + } + + DBG4(DBG_IKE, "Sk_ai %B", sk_ai); + if (!signer_i->set_key(signer_i, *sk_ai)) + { + return; + } + DBG4(DBG_IKE, "Sk_ar %B", sk_ar); + if (!signer_r->set_key(signer_r, *sk_ar)) + { + return; + } + DBG4(DBG_IKE, "Sk_ei %B", sk_ei); + if (!crypter_i->set_key(crypter_i, *sk_ei)) + { + return; + } + DBG4(DBG_IKE, "Sk_er %B", sk_er); + if (!crypter_r->set_key(crypter_r, *sk_er)) + { + return; + } + + if (initiator) + { + *in = aead_create(crypter_r, signer_r); + *out = aead_create(crypter_i, signer_i); + } + else + { + *in = aead_create(crypter_i, signer_i); + *out = aead_create(crypter_r, signer_r); + } +} + +METHOD(keymat_t, get_version, ike_version_t, + private_tkm_keymat_t *this) +{ + return IKEV2; +} + +METHOD(keymat_t, create_dh, diffie_hellman_t*, + private_tkm_keymat_t *this, diffie_hellman_group_t group) +{ + return lib->crypto->create_dh(lib->crypto, group); +} + +METHOD(keymat_t, create_nonce_gen, nonce_gen_t*, + private_tkm_keymat_t *this) +{ + return lib->crypto->create_nonce_gen(lib->crypto); +} + +METHOD(keymat_v2_t, derive_ike_keys, bool, + private_tkm_keymat_t *this, proposal_t *proposal, diffie_hellman_t *dh, + chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id, + pseudo_random_function_t rekey_function, chunk_t rekey_skd) +{ + u_int16_t enc_alg, int_alg, key_size; + u_int64_t nc_id, spi_loc, spi_rem; + chunk_t *nonce, c_ai, c_ar, c_ei, c_er; + tkm_diffie_hellman_t *tkm_dh; + dh_id_type dh_id; + nonce_type nonce_rem; + result_type res; + key_type sk_ai, sk_ar, sk_ei, sk_er; + + /* Check encryption and integrity algorithms */ + if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &enc_alg, + &key_size)) + { + DBG1(DBG_IKE, "no %N selected", transform_type_names, + ENCRYPTION_ALGORITHM); + return FALSE; + } + if (encryption_algorithm_is_aead(enc_alg)) + { + DBG1(DBG_IKE, "AEAD algorithm %N not supported", + encryption_algorithm_names, enc_alg); + return FALSE; + } + if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &int_alg, NULL)) + { + DBG1(DBG_IKE, "no %N selected", transform_type_names, + INTEGRITY_ALGORITHM); + return FALSE; + } + if (!(enc_alg == ENCR_AES_CBC && key_size == 256 && + int_alg == AUTH_HMAC_SHA2_512_256)) + { + DBG1(DBG_IKE, "the TKM only supports aes256-sha512 at the moment, " + "please update your configuration"); + return FALSE; + } + + DBG2(DBG_IKE, "using %N for encryption, %N for integrity", + encryption_algorithm_names, enc_alg, integrity_algorithm_names, + int_alg); + + /* Acquire nonce context id */ + nonce = this->initiator ? &nonce_i : &nonce_r; + nc_id = tkm->chunk_map->get_id(tkm->chunk_map, nonce); + if (!nc_id) + { + DBG1(DBG_IKE, "unable to acquire context id for nonce"); + return FALSE; + } + + /* Get DH context id */ + tkm_dh = (tkm_diffie_hellman_t *)dh; + dh_id = tkm_dh->get_id(tkm_dh); + + if (this->initiator) + { + chunk_to_sequence(&nonce_r, &nonce_rem, sizeof(nonce_type)); + spi_loc = id->get_initiator_spi(id); + spi_rem = id->get_responder_spi(id); + } + else + { + chunk_to_sequence(&nonce_i, &nonce_rem, sizeof(nonce_type)); + spi_loc = id->get_responder_spi(id); + spi_rem = id->get_initiator_spi(id); + } + + if (rekey_function == PRF_UNDEFINED) + { + this->ae_ctx_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_AE); + if (!this->ae_ctx_id) + { + DBG1(DBG_IKE, "unable to acquire ae context id"); + return FALSE; + } + DBG1(DBG_IKE, "deriving IKE keys (nc: %llu, dh: %llu, spi_loc: %llx, " + "spi_rem: %llx)", nc_id, dh_id, spi_loc, spi_rem); + res = ike_isa_create(this->isa_ctx_id, this->ae_ctx_id, 1, dh_id, nc_id, + nonce_rem, this->initiator, spi_loc, spi_rem, + &sk_ai, &sk_ar, &sk_ei, &sk_er); + } + else + { + isa_info_t isa_info; + + if (rekey_skd.ptr == NULL || rekey_skd.len != sizeof(isa_info_t)) + { + DBG1(DBG_IKE, "unable to retrieve parent isa info"); + return FALSE; + } + isa_info = *((isa_info_t *)(rekey_skd.ptr)); + DBG1(DBG_IKE, "deriving IKE keys (parent_isa: %llu, ae: %llu, nc: %llu," + "dh: %llu, spi_loc: %llx, spi_rem: %llx)", isa_info.parent_isa_id, + isa_info.ae_id, nc_id, dh_id, spi_loc, spi_rem); + this->ae_ctx_id = isa_info.ae_id; + res = ike_isa_create_child(this->isa_ctx_id, isa_info.parent_isa_id, 1, + dh_id, nc_id, nonce_rem, this->initiator, + spi_loc, spi_rem, &sk_ai, &sk_ar, &sk_ei, + &sk_er); + chunk_free(&rekey_skd); + } + + if (res != TKM_OK) + { + DBG1(DBG_IKE, "key derivation failed (isa: %llu)", this->isa_ctx_id); + return FALSE; + } + + sequence_to_chunk(sk_ai.data, sk_ai.size, &c_ai); + sequence_to_chunk(sk_ar.data, sk_ar.size, &c_ar); + sequence_to_chunk(sk_ei.data, sk_ei.size, &c_ei); + sequence_to_chunk(sk_er.data, sk_er.size, &c_er); + + aead_create_from_keys(&this->aead_in, &this->aead_out, &c_ai, &c_ar, &c_ei, + &c_er, enc_alg, int_alg, key_size / 8, + this->initiator); + + chunk_clear(&c_ai); + chunk_clear(&c_ar); + chunk_clear(&c_ei); + chunk_clear(&c_er); + + if (!this->aead_in || !this->aead_out) + { + DBG1(DBG_IKE, "could not initialize AEAD transforms"); + return FALSE; + } + + /* TODO: Add failure handler (see keymat_v2.c) */ + + tkm->chunk_map->remove(tkm->chunk_map, nonce); + if (ike_nc_reset(nc_id) != TKM_OK) + { + DBG1(DBG_IKE, "failed to reset nonce context %llu", nc_id); + } + tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_NONCE, nc_id); + + return TRUE; +} + +METHOD(keymat_v2_t, derive_child_keys, bool, + private_tkm_keymat_t *this, proposal_t *proposal, diffie_hellman_t *dh, + chunk_t nonce_i, chunk_t nonce_r, chunk_t *encr_i, chunk_t *integ_i, + chunk_t *encr_r, chunk_t *integ_r) +{ + esa_info_t *esa_info_i, *esa_info_r; + dh_id_type dh_id = 0; + + if (dh) + { + dh_id = ((tkm_diffie_hellman_t *)dh)->get_id((tkm_diffie_hellman_t *)dh); + } + + INIT(esa_info_i, + .isa_id = this->isa_ctx_id, + .spi_r = proposal->get_spi(proposal), + .nonce_i = chunk_clone(nonce_i), + .nonce_r = chunk_clone(nonce_r), + .is_encr_r = FALSE, + .dh_id = dh_id, + ); + + INIT(esa_info_r, + .isa_id = this->isa_ctx_id, + .spi_r = proposal->get_spi(proposal), + .nonce_i = chunk_clone(nonce_i), + .nonce_r = chunk_clone(nonce_r), + .is_encr_r = TRUE, + .dh_id = dh_id, + ); + + DBG1(DBG_CHD, "passing on esa info (isa: %llu, spi_r: %x, dh_id: %llu)", + esa_info_i->isa_id, ntohl(esa_info_i->spi_r), esa_info_i->dh_id); + + /* store ESA info in encr_i/r, which is passed to add_sa */ + *encr_i = chunk_create((u_char *)esa_info_i, sizeof(esa_info_t)); + *encr_r = chunk_create((u_char *)esa_info_r, sizeof(esa_info_t)); + *integ_i = chunk_empty; + *integ_r = chunk_empty; + + return TRUE; +} + +METHOD(keymat_t, get_aead, aead_t*, + private_tkm_keymat_t *this, bool in) +{ + return in ? this->aead_in : this->aead_out; +} + +METHOD(keymat_v2_t, get_auth_octets, bool, + private_tkm_keymat_t *this, bool verify, chunk_t ike_sa_init, + chunk_t nonce, identification_t *id, char reserved[3], chunk_t *octets) +{ + sign_info_t *sign; + + if (verify) + { + /* store peer init message for authentication step */ + this->other_init_msg = chunk_clone(ike_sa_init); + *octets = chunk_empty; + return TRUE; + } + + INIT(sign, + .isa_id = this->isa_ctx_id, + .init_message = chunk_clone(ike_sa_init), + ); + + /* + * store signature info in AUTH octets, which is passed to the private key + * sign() operation + */ + *octets = chunk_create((u_char *)sign, sizeof(sign_info_t)); + return TRUE; +} + +METHOD(keymat_v2_t, get_skd, pseudo_random_function_t, + private_tkm_keymat_t *this, chunk_t *skd) +{ + isa_info_t *isa_info; + + INIT(isa_info, + .parent_isa_id = this->isa_ctx_id, + .ae_id = this->ae_ctx_id, + ); + + *skd = chunk_create((u_char *)isa_info, sizeof(isa_info_t)); + + /* + * remove ae context id, since control has now been handed over to the new + * IKE SA keymat + */ + this->ae_ctx_id = 0; + return PRF_HMAC_SHA2_512; +} + +METHOD(keymat_v2_t, get_psk_sig, bool, + private_tkm_keymat_t *this, bool verify, chunk_t ike_sa_init, chunk_t nonce, + chunk_t secret, identification_t *id, char reserved[3], chunk_t *sig) +{ + return FALSE; +} + +METHOD(keymat_t, destroy, void, + private_tkm_keymat_t *this) +{ + if (ike_isa_reset(this->isa_ctx_id) != TKM_OK) + { + DBG1(DBG_IKE, "failed to reset ISA context %d", this->isa_ctx_id); + } + tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_ISA, this->isa_ctx_id); + /* only reset ae context if set */ + if (this->ae_ctx_id != 0) + { + if (ike_ae_reset(this->ae_ctx_id) != TKM_OK) + { + DBG1(DBG_IKE, "failed to reset AE context %d", this->ae_ctx_id); + } + tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_AE, this->ae_ctx_id); + } + + DESTROY_IF(this->aead_in); + DESTROY_IF(this->aead_out); + chunk_free(&this->auth_payload); + chunk_free(&this->other_init_msg); + free(this); +} + +METHOD(tkm_keymat_t, get_isa_id, isa_id_type, + private_tkm_keymat_t *this) +{ + return this->isa_ctx_id; +} + +METHOD(tkm_keymat_t, set_auth_payload, void, + private_tkm_keymat_t *this, const chunk_t * const payload) +{ + this->auth_payload = chunk_clone(*payload); +} + +METHOD(tkm_keymat_t, get_auth_payload, chunk_t*, + private_tkm_keymat_t *this) +{ + return &this->auth_payload; +} + +METHOD(tkm_keymat_t, get_peer_init_msg, chunk_t*, + private_tkm_keymat_t *this) +{ + return &this->other_init_msg; +} + +/** + * See header. + */ +tkm_keymat_t *tkm_keymat_create(bool initiator) +{ + private_tkm_keymat_t *this; + + INIT(this, + .public = { + .keymat_v2 = { + .keymat = { + .get_version = _get_version, + .create_dh = _create_dh, + .create_nonce_gen = _create_nonce_gen, + .get_aead = _get_aead, + .destroy = _destroy, + }, + .derive_ike_keys = _derive_ike_keys, + .derive_child_keys = _derive_child_keys, + .get_skd = _get_skd, + .get_auth_octets = _get_auth_octets, + .get_psk_sig = _get_psk_sig, + }, + .get_isa_id = _get_isa_id, + .set_auth_payload = _set_auth_payload, + .get_auth_payload = _get_auth_payload, + .get_peer_init_msg = _get_peer_init_msg, + }, + .initiator = initiator, + .isa_ctx_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_ISA), + .ae_ctx_id = 0, + .auth_payload = chunk_empty, + .other_init_msg = chunk_empty, + ); + + if (!this->isa_ctx_id) + { + free(this); + return NULL; + } + + return &this->public; +} diff --git a/src/charon-tkm/src/tkm/tkm_keymat.h b/src/charon-tkm/src/tkm/tkm_keymat.h new file mode 100644 index 000000000..ee90bead5 --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_keymat.h @@ -0,0 +1,77 @@ +/* + * 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. + */ + +/** + * @defgroup tkm-keymat keymat + * @{ @ingroup tkm + */ + +#ifndef TKM_KEYMAT_H_ +#define TKM_KEYMAT_H_ + +#include <sa/ikev2/keymat_v2.h> + +typedef struct tkm_keymat_t tkm_keymat_t; + +/** + * Derivation and management of sensitive keying material, TKM variant. + */ +struct tkm_keymat_t { + + /** + * Implements keymat_v2_t. + */ + keymat_v2_t keymat_v2; + + /** + * Get ISA context id. + * + * @return id of associated ISA context. + */ + isa_id_type (*get_isa_id)(tkm_keymat_t * const this); + + /** + * Set IKE AUTH payload. + * + * @param payload AUTH payload + */ + void (*set_auth_payload)(tkm_keymat_t *this, const chunk_t * const payload); + + /** + * Get IKE AUTH payload. + * + * @return AUTH payload if set, chunk_empty otherwise + */ + chunk_t* (*get_auth_payload)(tkm_keymat_t * const this); + + /** + * Get IKE init message of peer. + * + * @return init message if set, chunk_empty otherwise + */ + chunk_t* (*get_peer_init_msg)(tkm_keymat_t * const this); + +}; + +/** + * Create TKM keymat instance. + * + * @param initiator TRUE if we are the initiator + * @return keymat instance + */ +tkm_keymat_t *tkm_keymat_create(bool initiator); + +#endif /** KEYMAT_TKM_H_ @}*/ diff --git a/src/charon-tkm/src/tkm/tkm_listener.c b/src/charon-tkm/src/tkm/tkm_listener.c new file mode 100644 index 000000000..050586456 --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_listener.c @@ -0,0 +1,355 @@ +/* + * 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 <daemon.h> +#include <encoding/payloads/auth_payload.h> +#include <utils/chunk.h> +#include <tkm/types.h> +#include <tkm/constants.h> +#include <tkm/client.h> + +#include "tkm.h" +#include "tkm_listener.h" +#include "tkm_keymat.h" +#include "tkm_utils.h" + +typedef struct private_tkm_listener_t private_tkm_listener_t; + +/** + * Private data of a tkm_listener_t object. + */ +struct private_tkm_listener_t { + + /** + * Public tkm_listener_t interface. + */ + tkm_listener_t public; + +}; + +/** + * Return id of remote identity. + * + * TODO: Replace this with the lookup for the remote identitiy id. + * + * Currently the reqid of the first child SA in peer config of IKE SA is + * returned. Might choose wrong reqid if IKE SA has multiple child configs + * with different reqids. + * + * @param peer_cfg Remote peer config + * @return remote identity id if found, 0 otherwise + */ +static ri_id_type get_remote_identity_id(peer_cfg_t *peer) +{ + ri_id_type remote_id = 0; + child_cfg_t *child; + enumerator_t* children; + + children = peer->create_child_cfg_enumerator(peer); + + /* pick the reqid of the first child, no need to enumerate all children. */ + children->enumerate(children, &child); + remote_id = child->get_reqid(child); + children->destroy(children); + + return remote_id; +} + +/** + * Build a TKM certificate chain context with given cc id. + * + * @param ike_sa IKE SA containing auth config to build certificate chain from + * @param cc_id Certificate chain ID + * @return TRUE if certificate chain was built successfully, + * FALSE otherwise + */ +static bool build_cert_chain(const ike_sa_t * const ike_sa, cc_id_type cc_id) +{ + auth_cfg_t *auth; + certificate_t *cert; + enumerator_t *rounds; + + DBG1(DBG_IKE, "building certificate chain context %llu for IKE SA %s", + cc_id, ike_sa->get_name((ike_sa_t *)ike_sa)); + + rounds = ike_sa->create_auth_cfg_enumerator((ike_sa_t *)ike_sa, FALSE); + while (rounds->enumerate(rounds, &auth)) + { + cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT); + if (cert) + { + chunk_t enc_user_cert; + ri_id_type ri_id; + certificate_type user_cert; + auth_rule_t rule; + enumerator_t *enumerator; + + /* set user certificate */ + if (!cert->get_encoding(cert, CERT_ASN1_DER, &enc_user_cert)) + { + DBG1(DBG_IKE, "unable to extract encoded user certificate"); + rounds->destroy(rounds); + return FALSE; + } + + ri_id = get_remote_identity_id(ike_sa->get_peer_cfg((ike_sa_t *)ike_sa)); + chunk_to_sequence(&enc_user_cert, &user_cert, sizeof(certificate_type)); + chunk_free(&enc_user_cert); + if (ike_cc_set_user_certificate(cc_id, ri_id, 1, user_cert) != TKM_OK) + { + DBG1(DBG_IKE, "error setting user certificate of cert chain" + " (cc_id: %llu)", cc_id); + rounds->destroy(rounds); + return FALSE; + } + + /* process intermediate CA certificates */ + enumerator = auth->create_enumerator(auth); + while (enumerator->enumerate(enumerator, &rule, &cert)) + { + if (rule == AUTH_RULE_IM_CERT) + { + chunk_t enc_im_cert; + certificate_type im_cert; + + if (!cert->get_encoding(cert, CERT_ASN1_DER, &enc_im_cert)) + { + DBG1(DBG_IKE, "unable to extract encoded intermediate CA" + " certificate"); + rounds->destroy(rounds); + enumerator->destroy(enumerator); + return FALSE; + } + + chunk_to_sequence(&enc_im_cert, &im_cert, + sizeof(certificate_type)); + chunk_free(&enc_im_cert); + if (ike_cc_add_certificate(cc_id, 1, im_cert) != TKM_OK) + { + DBG1(DBG_IKE, "error adding intermediate certificate to" + " cert chain (cc_id: %llu)", cc_id); + rounds->destroy(rounds); + enumerator->destroy(enumerator); + return FALSE; + } + } + } + enumerator->destroy(enumerator); + + /* finally add CA certificate */ + cert = auth->get(auth, AUTH_RULE_CA_CERT); + if (cert) + { + const ca_id_type ca_id = 1; + certificate_type ca_cert; + chunk_t enc_ca_cert; + + if (!cert->get_encoding(cert, CERT_ASN1_DER, &enc_ca_cert)) + { + DBG1(DBG_IKE, "unable to extract encoded CA certificate"); + rounds->destroy(rounds); + return FALSE; + } + + chunk_to_sequence(&enc_ca_cert, &ca_cert, + sizeof(certificate_type)); + chunk_free(&enc_ca_cert); + if (ike_cc_add_certificate(cc_id, 1, ca_cert) != TKM_OK) + { + DBG1(DBG_IKE, "error adding CA certificate to cert chain " + "(cc_id: %llu)", cc_id); + rounds->destroy(rounds); + return FALSE; + } + + if (ike_cc_check_ca(cc_id, ca_id) != TKM_OK) + { + DBG1(DBG_IKE, "certificate chain (cc_id: %llu) not based on" + " trusted CA (ca_id: %llu)", cc_id, ca_id); + rounds->destroy(rounds); + return FALSE; + } + + rounds->destroy(rounds); + return TRUE; + } + else + { + DBG1(DBG_IKE, "no CA certificate"); + } + } + else + { + DBG1(DBG_IKE, "no subject certificate for remote peer"); + } + } + + rounds->destroy(rounds); + return FALSE; +} + +METHOD(listener_t, alert, bool, + private_tkm_listener_t *this, ike_sa_t *ike_sa, + alert_t alert, va_list args) +{ + if (alert == ALERT_KEEP_ON_CHILD_SA_FAILURE) + { + tkm_keymat_t *keymat; + isa_id_type isa_id; + + keymat = (tkm_keymat_t*)ike_sa->get_keymat(ike_sa); + isa_id = keymat->get_isa_id(keymat); + + DBG1(DBG_IKE, "TKM alert listener called for ISA context %llu", isa_id); + if (ike_isa_skip_create_first(isa_id) != TKM_OK) + { + DBG1(DBG_IKE, "Skip of first child SA creation failed for ISA " + "context %llu", isa_id); + } + } + + return TRUE; +} + +METHOD(listener_t, authorize, bool, + private_tkm_listener_t *this, ike_sa_t *ike_sa, + bool final, bool *success) +{ + tkm_keymat_t *keymat; + isa_id_type isa_id; + cc_id_type cc_id; + chunk_t *auth, *other_init_msg; + signature_type signature; + init_message_type init_msg; + + if (!final) + { + return TRUE; + } + + keymat = (tkm_keymat_t*)ike_sa->get_keymat(ike_sa); + isa_id = keymat->get_isa_id(keymat); + DBG1(DBG_IKE, "TKM authorize listener called for ISA context %llu", isa_id); + + cc_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_CC); + if (!cc_id) + { + DBG1(DBG_IKE, "unable to acquire CC context id"); + *success = FALSE; + return TRUE; + } + if (!build_cert_chain(ike_sa, cc_id)) + { + DBG1(DBG_IKE, "unable to build certificate chain"); + *success = FALSE; + return TRUE; + } + + auth = keymat->get_auth_payload(keymat); + if (!auth->ptr) + { + DBG1(DBG_IKE, "no AUTHENTICATION data available"); + *success = FALSE; + } + + other_init_msg = keymat->get_peer_init_msg(keymat); + if (!other_init_msg->ptr) + { + DBG1(DBG_IKE, "no peer init message available"); + *success = FALSE; + } + + chunk_to_sequence(auth, &signature, sizeof(signature_type)); + chunk_to_sequence(other_init_msg, &init_msg, sizeof(init_message_type)); + + if (ike_isa_auth(isa_id, cc_id, init_msg, signature) != TKM_OK) + { + DBG1(DBG_IKE, "TKM based authentication failed" + " for ISA context %llu", isa_id); + *success = FALSE; + } + else + { + DBG1(DBG_IKE, "TKM based authentication successful" + " for ISA context %llu", isa_id); + *success = TRUE; + } + + return TRUE; +} + +METHOD(listener_t, message, bool, + private_tkm_listener_t *this, ike_sa_t *ike_sa, + message_t *message, bool incoming, bool plain) +{ + tkm_keymat_t *keymat; + isa_id_type isa_id; + auth_payload_t *auth_payload; + + if (!incoming || !plain || message->get_exchange_type(message) != IKE_AUTH) + { + return TRUE; + } + + keymat = (tkm_keymat_t*)ike_sa->get_keymat(ike_sa); + isa_id = keymat->get_isa_id(keymat); + DBG1(DBG_IKE, "saving AUTHENTICATION payload for authorize hook" + " (ISA context %llu)", isa_id); + + auth_payload = (auth_payload_t*)message->get_payload(message, + AUTHENTICATION); + if (auth_payload) + { + chunk_t auth_data; + + auth_data = auth_payload->get_data(auth_payload); + keymat->set_auth_payload(keymat, &auth_data); + } + else + { + DBG1(DBG_IKE, "unable to extract AUTHENTICATION payload, authorize will" + " fail"); + } + + return TRUE; +} + +METHOD(tkm_listener_t, destroy, void, + private_tkm_listener_t *this) +{ + free(this); +} + +/** + * See header + */ +tkm_listener_t *tkm_listener_create() +{ + private_tkm_listener_t *this; + + INIT(this, + .public = { + .listener = { + .authorize = _authorize, + .message = _message, + .alert = _alert, + }, + .destroy = _destroy, + }, + ); + + return &this->public; +} diff --git a/src/charon-tkm/src/tkm/tkm_listener.h b/src/charon-tkm/src/tkm/tkm_listener.h new file mode 100644 index 000000000..1162a77be --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_listener.h @@ -0,0 +1,52 @@ +/* + * 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. + */ + +/** + * @defgroup tkm-listener listener + * @{ @ingroup tkm + */ + +#ifndef TKM_LISTENER_H_ +#define TKM_LISTENER_H_ + +#include <bus/listeners/listener.h> + +typedef struct tkm_listener_t tkm_listener_t; + +/** + * TKM bus listener. + */ +struct tkm_listener_t { + + /** + * Implements listener_t interface. + */ + listener_t listener; + + /** + * Destroy a tkm_listener_t. + */ + void (*destroy)(tkm_listener_t *this); +}; + +/** + * Create a tkm_listener instance. + * + * @return listener instance + */ +tkm_listener_t *tkm_listener_create(); + +#endif /** TKM_LISTENER_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..a07326798 --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_nonceg.c @@ -0,0 +1,106 @@ +/* + * 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/client.h> +#include <tkm/constants.h> + +#include "tkm.h" +#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; + + /** + * Context id. + */ + nc_id_type context_id; + +}; + +METHOD(nonce_gen_t, get_nonce, bool, + private_tkm_nonceg_t *this, size_t size, u_int8_t *buffer) +{ + nonce_type nonce; + + if (ike_nc_create(this->context_id, size, &nonce) != TKM_OK) + { + return FALSE; + } + + memcpy(buffer, &nonce.data, size); + return TRUE; +} + +METHOD(nonce_gen_t, allocate_nonce, bool, + private_tkm_nonceg_t *this, size_t size, chunk_t *chunk) +{ + *chunk = chunk_alloc(size); + if (get_nonce(this, chunk->len, chunk->ptr)) + { + tkm->chunk_map->insert(tkm->chunk_map, chunk, this->context_id); + return TRUE; + } + return FALSE; +} + +METHOD(nonce_gen_t, destroy, void, + private_tkm_nonceg_t *this) +{ + free(this); +} + +METHOD(tkm_nonceg_t, get_id, nc_id_type, + private_tkm_nonceg_t *this) +{ + return this->context_id; +} + +/* + * 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, + }, + .get_id = _get_id, + }, + .context_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_NONCE), + ); + + if (!this->context_id) + { + free(this); + return NULL; + } + + 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..ceadb081f --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_nonceg.h @@ -0,0 +1,56 @@ +/* + * 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. + */ + +/** + * @defgroup tkm-nonceg nonce generator + * @{ @ingroup tkm + */ + +#ifndef TKM_NONCEG_H_ +#define TKM_NONCEG_H_ + +typedef struct tkm_nonceg_t tkm_nonceg_t; + +#include <library.h> +#include <tkm/types.h> + +/** + * nonce_gen_t implementation using the trusted key manager. + */ +struct tkm_nonceg_t { + + /** + * Implements nonce_gen_t. + */ + nonce_gen_t nonce_gen; + + /** + * Get nonce context id. + * + * @return context id of this nonce generator. + */ + nc_id_type (*get_id)(tkm_nonceg_t * const this); + +}; + +/** + * 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/src/tkm/tkm_private_key.c b/src/charon-tkm/src/tkm/tkm_private_key.c new file mode 100644 index 000000000..db57ec1c7 --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_private_key.c @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2012-2013 Reto Buerki + * Copyright (C) 2012-2013 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 <utils/debug.h> +#include <tkm/constants.h> +#include <tkm/client.h> + +#include "tkm_utils.h" +#include "tkm_types.h" +#include "tkm_private_key.h" + +typedef struct private_tkm_private_key_t private_tkm_private_key_t; + +/** + * Private data of a tkm_private_key_t object. + */ +struct private_tkm_private_key_t { + + /** + * Public interface for this signer. + */ + tkm_private_key_t public; + + /** + * Key ID. + */ + identification_t *id; + + /** + * Key type. + */ + key_type_t key_type; + + /** + * Reference count. + */ + refcount_t ref; + +}; + +METHOD(private_key_t, get_type, key_type_t, + private_tkm_private_key_t *this) +{ + return this->key_type; +} + +METHOD(private_key_t, sign, bool, + private_tkm_private_key_t *this, signature_scheme_t scheme, + chunk_t data, chunk_t *signature) +{ + signature_type sig; + init_message_type msg; + sign_info_t sign; + isa_id_type isa_id; + + if (data.ptr == NULL) + { + DBG1(DBG_LIB, "unable to get signature information"); + return FALSE; + } + sign = *(sign_info_t *)(data.ptr); + + chunk_to_sequence(&sign.init_message, &msg, sizeof(init_message_type)); + isa_id = sign.isa_id; + chunk_free(&sign.init_message); + + if (ike_isa_sign(isa_id, 1, msg, &sig) != TKM_OK) + { + DBG1(DBG_LIB, "signature operation failed"); + return FALSE; + } + + sequence_to_chunk(sig.data, sig.size, signature); + return TRUE; +} + +METHOD(private_key_t, decrypt, bool, + private_tkm_private_key_t *this, encryption_scheme_t scheme, + chunk_t crypto, chunk_t *plain) +{ + return FALSE; +} + +METHOD(private_key_t, get_keysize, int, + private_tkm_private_key_t *this) +{ + return 0; +} + +METHOD(private_key_t, get_public_key, public_key_t*, + private_tkm_private_key_t *this) +{ + return NULL; +} + +METHOD(private_key_t, get_encoding, bool, + private_tkm_private_key_t *this, cred_encoding_type_t type, + chunk_t *encoding) +{ + return FALSE; +} + +METHOD(private_key_t, get_fingerprint, bool, + private_tkm_private_key_t *this, cred_encoding_type_t type, chunk_t *fp) +{ + *fp = this->id->get_encoding(this->id); + return TRUE; +} + +METHOD(private_key_t, get_ref, private_key_t*, + private_tkm_private_key_t *this) +{ + ref_get(&this->ref); + return &this->public.key; +} + +METHOD(private_key_t, destroy, void, + private_tkm_private_key_t *this) +{ + if (ref_put(&this->ref)) + { + this->id->destroy(this->id); + free(this); + } +} + +/** + * See header. + */ +tkm_private_key_t *tkm_private_key_init(identification_t * const id) +{ + private_tkm_private_key_t *this; + certificate_t *cert; + public_key_t *pubkey; + + INIT(this, + .public = { + .key = { + .get_type = _get_type, + .sign = _sign, + .decrypt = _decrypt, + .get_keysize = _get_keysize, + .get_public_key = _get_public_key, + .equals = private_key_equals, + .belongs_to = private_key_belongs_to, + .get_fingerprint = _get_fingerprint, + .has_fingerprint = private_key_has_fingerprint, + .get_encoding = _get_encoding, + .get_ref = _get_ref, + .destroy = _destroy, + }, + }, + .ref = 1, + .id = id->clone(id), + ); + + /* get key type from associated public key */ + cert = lib->credmgr->get_cert(lib->credmgr, CERT_ANY, KEY_ANY, id, FALSE); + if (!cert) + { + destroy(this); + return NULL; + } + + pubkey = cert->get_public_key(cert); + if (!pubkey) + { + cert->destroy(cert); + destroy(this); + return NULL; + } + this->key_type = pubkey->get_type(pubkey); + pubkey->destroy(pubkey); + cert->destroy(cert); + + return &this->public; +} diff --git a/src/charon-tkm/src/tkm/tkm_private_key.h b/src/charon-tkm/src/tkm/tkm_private_key.h new file mode 100644 index 000000000..ded8300ca --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_private_key.h @@ -0,0 +1,45 @@ +/* + * 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. + */ + +/** + * @defgroup tkm-privkey private key + * @{ @ingroup tkm + */ + +#ifndef TKM_PRIVATE_KEY_H_ +#define TKM_PRIVATE_KEY_H_ + +#include <credentials/keys/private_key.h> + +typedef struct tkm_private_key_t tkm_private_key_t; + +/** + * TKM private_key_t implementation. + */ +struct tkm_private_key_t { + + /** + * Implements private_key_t interface + */ + private_key_t key; +}; + +/** + * Initialize TKM private key with given key ID. + */ +tkm_private_key_t *tkm_private_key_init(identification_t * const id); + +#endif /** TKM_PRIVATE_KEY_H_ @}*/ diff --git a/src/charon-tkm/src/tkm/tkm_public_key.c b/src/charon-tkm/src/tkm/tkm_public_key.c new file mode 100644 index 000000000..9ebdc29e6 --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_public_key.c @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2012-2013 Reto Buerki + * Copyright (C) 2012-2013 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 <utils/debug.h> + +#include "tkm_public_key.h" + +typedef struct private_tkm_public_key_t private_tkm_public_key_t; + +/** + * Private data of tkm_public_key_t object. + */ +struct private_tkm_public_key_t { + + /** + * Public interface for this signer. + */ + tkm_public_key_t public; + + /** + * ASN.1 blob of pubkey. + */ + chunk_t asn_blob; + + /** + * Key type. + */ + key_type_t key_type; + + /** + * Reference count. + */ + refcount_t ref; +}; + +METHOD(public_key_t, get_type, key_type_t, + private_tkm_public_key_t *this) +{ + return this->key_type; +} + +METHOD(public_key_t, verify, bool, + private_tkm_public_key_t *this, signature_scheme_t scheme, + chunk_t data, chunk_t signature) +{ + return TRUE; +} + +METHOD(public_key_t, encrypt_, bool, + private_tkm_public_key_t *this, encryption_scheme_t scheme, + chunk_t plain, chunk_t *crypto) +{ + return FALSE; +} + +METHOD(public_key_t, get_keysize, int, + private_tkm_public_key_t *this) +{ + return 0; +} + +METHOD(public_key_t, get_encoding, bool, + private_tkm_public_key_t *this, cred_encoding_type_t type, + chunk_t *encoding) +{ + return NULL; +} + +METHOD(public_key_t, get_fingerprint, bool, + private_tkm_public_key_t *this, cred_encoding_type_t type, chunk_t *fp) +{ + if (lib->encoding->get_cache(lib->encoding, type, this, fp)) + { + return TRUE; + } + switch(this->key_type) + { + case KEY_RSA: + return lib->encoding->encode(lib->encoding, type, this, fp, + CRED_PART_RSA_PUB_ASN1_DER, + this->asn_blob, CRED_PART_END); + default: + DBG1(DBG_LIB, "%N public key not supported, fingerprinting failed", + key_type_names, this->key_type); + return FALSE; + } +} + +METHOD(public_key_t, get_ref, public_key_t*, + private_tkm_public_key_t *this) +{ + ref_get(&this->ref); + return &this->public.key; +} + +METHOD(public_key_t, destroy, void, + private_tkm_public_key_t *this) +{ + if (ref_put(&this->ref)) + { + lib->encoding->clear_cache(lib->encoding, this); + chunk_free(&this->asn_blob); + free(this); + } +} + +/** + * See header. + */ +tkm_public_key_t *tkm_public_key_load(key_type_t type, va_list args) +{ + private_tkm_public_key_t *this; + chunk_t blob = chunk_empty; + + while (TRUE) + { + switch (va_arg(args, builder_part_t)) + { + case BUILD_BLOB_ASN1_DER: + blob = va_arg(args, chunk_t); + continue; + case BUILD_END: + break; + default: + return NULL; + } + break; + } + + if (!blob.ptr) + { + return NULL; + } + + INIT(this, + .public = { + .key = { + .get_type = _get_type, + .verify = _verify, + .encrypt = _encrypt_, + .equals = public_key_equals, + .get_keysize = _get_keysize, + .get_fingerprint = _get_fingerprint, + .has_fingerprint = public_key_has_fingerprint, + .get_encoding = _get_encoding, + .get_ref = _get_ref, + .destroy = _destroy, + }, + }, + .ref = 1, + .asn_blob = chunk_clone(blob), + .key_type = type, + ); + + return &this->public; +} diff --git a/src/charon-tkm/src/tkm/tkm_public_key.h b/src/charon-tkm/src/tkm/tkm_public_key.h new file mode 100644 index 000000000..5b21287b7 --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_public_key.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2012-2013 Reto Buerki + * Copyright (C) 2012-2013 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. + */ + +/** + * @defgroup tkm-pubkey public key + * @{ @ingroup tkm + */ + +#ifndef TKM_PUBLIC_KEY_H_ +#define TKM_PUBLIC_KEY_H_ + +#include <credentials/keys/public_key.h> + +typedef struct tkm_public_key_t tkm_public_key_t; + +/** + * TKM public_key_t implementation. + */ +struct tkm_public_key_t { + + /** + * Implements the public_key_t interface + */ + public_key_t key; +}; + +/** + * Load a TKM public key. + * + * @param type type of the key + * @param args builder_part_t argument list + * @return loaded key, NULL on failure + */ +tkm_public_key_t *tkm_public_key_load(key_type_t type, va_list args); + +#endif /** TKM_PUBLIC_KEY_H_ @}*/ diff --git a/src/charon-tkm/src/tkm/tkm_types.h b/src/charon-tkm/src/tkm/tkm_types.h new file mode 100644 index 000000000..cef53deb3 --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_types.h @@ -0,0 +1,128 @@ +/* + * 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. + */ + +/** + * @defgroup tkm-types types + * @{ @ingroup tkm + */ + +#ifndef TKM_TYPES_H_ +#define TKM_TYPES_H_ + +#include <tkm/types.h> +#include <utils/chunk.h> + +typedef struct esa_info_t esa_info_t; + +/** + * ESP SA info data structure. + * + * This type is used to transfer ESA information from the keymat + * derive_child_keys to the kernel IPsec interface add_sa operation. This is + * necessary because the CHILD SA key derivation and installation is handled + * by a single exchange with the TKM (esa_create*) in add_sa. + * For this purpose the out parameters encr_i and encr_r of the + * derive_child_keys function are (ab)used and the data is stored in these + * data chunks. This is possible since the child SA keys are treated as opaque + * values and handed to the add_sa procedure of the kernel interface as-is + * without any processing. + */ +struct esa_info_t { + + /** + * ISA context id. + */ + isa_id_type isa_id; + + /** + * Responder SPI of child SA. + */ + esp_spi_type spi_r; + + /** + * Initiator nonce. + */ + chunk_t nonce_i; + + /** + * Responder nonce. + */ + chunk_t nonce_r; + + /** + * Flag specifying if this esa info struct is contained in encr_r. + * It is set to TRUE for encr_r and FALSE for encr_i. + */ + bool is_encr_r; + + /** + * Diffie-Hellman context id. + */ + dh_id_type dh_id; + +}; + +typedef struct isa_info_t isa_info_t; + +/** + * IKE SA info data structure. + * + * This type is used to transfer ISA information from the keymat of the parent + * SA to the keymat of the new IKE SA. For this purpose the skd data chunk is + * (ab)used. This is possible since the sk_d chunk is treated as an opaque value + * and handed to the derive_ike_keys procedure of the new keymat as-is without + * any processing. + */ +struct isa_info_t { + + /** + * Parent isa context id. + */ + isa_id_type parent_isa_id; + + /** + * Authenticated endpoint context id. + */ + ae_id_type ae_id; + +}; + +typedef struct sign_info_t sign_info_t; + +/** + * AUTH signature info data structure. + * + * This type is used to transfer an ISA context id and the initial message + * from the keymat to the TKM private key sign operation. For this purpose the + * auth octets chunk is (ab)used and the data is stored in this chunk. + * This is possible since the auth octets are treated as opaque value and handed + * to the private key sign function as-is without any processing. + */ +struct sign_info_t { + + /** + * ISA context id. + */ + isa_id_type isa_id; + + /** + * Init message. + */ + chunk_t init_message; + +}; + +#endif /** TKM_TYPES_H_ @}*/ diff --git a/src/charon-tkm/src/tkm/tkm_utils.c b/src/charon-tkm/src/tkm/tkm_utils.c new file mode 100644 index 000000000..e0692b893 --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_utils.c @@ -0,0 +1,53 @@ +/* + * 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 <utils/debug.h> + +#include "tkm_utils.h" + +/* Generic variable-length sequence */ +struct sequence_type { + uint32_t size; + byte_t data[]; +}; +typedef struct sequence_type sequence_type; + +void sequence_to_chunk(const byte_t * const first, const uint32_t len, + chunk_t * const chunk) +{ + *chunk = chunk_alloc(len); + memcpy(chunk->ptr, first, len); +} + +void chunk_to_sequence(const chunk_t * const chunk, void *sequence, + const uint32_t typelen) +{ + const uint32_t seqlenmax = typelen - sizeof(uint32_t); + sequence_type *seq = sequence; + + memset(sequence, 0, typelen); + if (chunk->len > seqlenmax) + { + DBG1(DBG_LIB, "chunk too large to fit into sequence %d > %d, limiting" + " to %d bytes", chunk->len, seqlenmax, seqlenmax); + seq->size = seqlenmax; + } + else + { + seq->size = chunk->len; + } + memcpy(seq->data, chunk->ptr, seq->size); +} diff --git a/src/charon-tkm/src/tkm/tkm_utils.h b/src/charon-tkm/src/tkm/tkm_utils.h new file mode 100644 index 000000000..308c58fbb --- /dev/null +++ b/src/charon-tkm/src/tkm/tkm_utils.h @@ -0,0 +1,48 @@ +/* + * 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. + */ + +/** + * @defgroup tkm-utils utils + * @{ @ingroup tkm + */ + +#ifndef TKM_UTILS_H_ +#define TKM_UTILS_H_ + +#include <utils/chunk.h> +#include <tkm/types.h> + +/** + * Convert byte sequence to chunk. + * + * @param first pointer to first byte of sequence + * @param len length of byte sequence + * @param chunk pointer to chunk struct + */ +void sequence_to_chunk(const byte_t * const first, const uint32_t len, + chunk_t * const chunk); + +/** + * Convert chunk to variable-length byte sequence. + * + * @param chunk pointer to chunk struct + * @param sequence pointer to variable-length sequence + * @param typelen length of sequence type + */ +void chunk_to_sequence(const chunk_t * const chunk, void *sequence, + const uint32_t typelen); + +#endif /** TKM_UTILS_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/chunk_map_tests.c b/src/charon-tkm/tests/chunk_map_tests.c new file mode 100644 index 000000000..6deef9a80 --- /dev/null +++ b/src/charon-tkm/tests/chunk_map_tests.c @@ -0,0 +1,58 @@ +/* + * 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_chunk_map.h" + +START_TEST(test_chunk_map_creation) +{ + tkm_chunk_map_t *map = NULL; + + map = tkm_chunk_map_create(); + fail_if(map == NULL, "Error creating chunk map"); + + map->destroy(map); +} +END_TEST + +START_TEST(test_chunk_map_handling) +{ + tkm_chunk_map_t *map = NULL; + const int ref = 35; + chunk_t data = chunk_from_thing(ref); + + map = tkm_chunk_map_create(); + fail_if(map == NULL, "Error creating chunk map"); + + map->insert(map, &data, 24); + fail_if(map->get_id(map, &data) != 24, "Id mismatch"); + + fail_unless(map->remove(map, &data), "Unable to remove mapping"); + fail_unless(!map->get_id(map, &data), "Error removing mapping"); + + map->destroy(map); +} +END_TEST + +TCase *make_chunk_map_tests(void) +{ + TCase *tc = tcase_create("Chunk map tests"); + tcase_add_test(tc, test_chunk_map_creation); + tcase_add_test(tc, test_chunk_map_handling); + + return tc; +} diff --git a/src/charon-tkm/tests/diffie_hellman_tests.c b/src/charon-tkm/tests/diffie_hellman_tests.c new file mode 100644 index 000000000..ffe99614d --- /dev/null +++ b/src/charon-tkm/tests/diffie_hellman_tests.c @@ -0,0 +1,59 @@ +/* + * 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_diffie_hellman.h" + +START_TEST(test_dh_creation) +{ + tkm_diffie_hellman_t *dh = NULL; + + dh = tkm_diffie_hellman_create(MODP_768_BIT); + fail_if(dh, "MODP_768 created"); + + dh = tkm_diffie_hellman_create(MODP_4096_BIT); + fail_if(!dh, "MODP_4096 not created"); + fail_if(!dh->get_id(dh), "Invalid context id (0)"); + + dh->dh.destroy(&dh->dh); +} +END_TEST + +START_TEST(test_dh_get_my_pubvalue) +{ + tkm_diffie_hellman_t *dh = tkm_diffie_hellman_create(MODP_4096_BIT); + fail_if(!dh, "Unable to create DH"); + + chunk_t value; + dh->dh.get_my_public_value(&dh->dh, &value); + dh->dh.destroy(&dh->dh); + + fail_if(value.ptr == NULL, "Pubvalue is NULL"); + fail_if(value.len != 512, "Pubvalue size mismatch"); + + chunk_free(&value); +} +END_TEST + +TCase *make_diffie_hellman_tests(void) +{ + TCase *tc = tcase_create("Diffie-Hellman tests"); + tcase_add_test(tc, test_dh_creation); + tcase_add_test(tc, test_dh_get_my_pubvalue); + + return tc; +} 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..15522f118 --- /dev/null +++ b/src/charon-tkm/tests/id_manager_tests.c @@ -0,0 +1,150 @@ +/* + * 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_id_manager.h" + +static const tkm_limits_t limits = {125, 100, 55, 30, 200, 42}; + +START_TEST(test_id_mgr_creation) +{ + tkm_id_manager_t *idmgr = NULL; + + idmgr = tkm_id_manager_create(limits); + 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(limits); + + 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(limits); + + 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_acquire_id_same) +{ + int id1 = 0, id2 = 0; + tkm_id_manager_t *idmgr = tkm_id_manager_create(limits); + + id1 = idmgr->acquire_id(idmgr, TKM_CTX_NONCE); + fail_unless(id1 > 0, "Unable to acquire first id"); + + /* Acquire another id, must be different than first */ + id2 = idmgr->acquire_id(idmgr, TKM_CTX_NONCE); + fail_unless(id2 > 0, "Unable to acquire second id"); + fail_unless(id1 != id2, "Same id received twice"); + + 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(limits); + + 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(limits); + + 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(limits); + + 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_acquire_id_same); + 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/kernel_sad_tests.c b/src/charon-tkm/tests/kernel_sad_tests.c new file mode 100644 index 000000000..11785602d --- /dev/null +++ b/src/charon-tkm/tests/kernel_sad_tests.c @@ -0,0 +1,122 @@ +/* + * 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_kernel_sad.h" + +START_TEST(test_sad_creation) +{ + tkm_kernel_sad_t *sad = NULL; + + sad = tkm_kernel_sad_create(); + fail_if(!sad, "Error creating tkm kernel SAD"); + + sad->destroy(sad); +} +END_TEST + +START_TEST(test_insert) +{ + host_t *addr = host_create_from_string("127.0.0.1", 1024); + tkm_kernel_sad_t *sad = tkm_kernel_sad_create(); + + fail_unless(sad->insert(sad, 1, addr, addr, 42, 50), + "Error inserting SAD entry"); + + sad->destroy(sad); + addr->destroy(addr); +} +END_TEST + +START_TEST(test_insert_duplicate) +{ + host_t *addr = host_create_from_string("127.0.0.1", 1024); + tkm_kernel_sad_t *sad = tkm_kernel_sad_create(); + + fail_unless(sad->insert(sad, 1, addr, addr, 42, 50), + "Error inserting SAD entry"); + fail_if(sad->insert(sad, 1, addr, addr, 42, 50), + "Expected error inserting duplicate entry"); + + sad->destroy(sad); + addr->destroy(addr); +} +END_TEST + +START_TEST(test_get_esa_id) +{ + host_t *addr = host_create_from_string("127.0.0.1", 1024); + tkm_kernel_sad_t *sad = tkm_kernel_sad_create(); + fail_unless(sad->insert(sad, 23, addr, addr, 42, 50), + "Error inserting SAD entry"); + fail_unless(sad->get_esa_id(sad, addr, addr, 42, 50) == 23, + "Error getting esa id"); + sad->destroy(sad); + addr->destroy(addr); +} +END_TEST + +START_TEST(test_get_esa_id_nonexistent) +{ + host_t *addr = host_create_from_string("127.0.0.1", 1024); + tkm_kernel_sad_t *sad = tkm_kernel_sad_create(); + fail_unless(sad->get_esa_id(sad, addr, addr, 42, 50) == 0, + "Got esa id for nonexistent SAD entry"); + sad->destroy(sad); + addr->destroy(addr); +} +END_TEST + +START_TEST(test_remove) +{ + host_t *addr = host_create_from_string("127.0.0.1", 1024); + tkm_kernel_sad_t *sad = tkm_kernel_sad_create(); + fail_unless(sad->insert(sad, 23, addr, addr, 42, 50), + "Error inserting SAD entry"); + fail_unless(sad->get_esa_id(sad, addr, addr, 42, 50) == 23, + "Error getting esa id"); + fail_unless(sad->remove(sad, 23), + "Error removing SAD entry"); + fail_unless(sad->get_esa_id(sad, addr, addr, 42, 50) == 0, + "Got esa id for removed SAD entry"); + sad->destroy(sad); + addr->destroy(addr); +} +END_TEST + +START_TEST(test_remove_nonexistent) +{ + tkm_kernel_sad_t *sad = tkm_kernel_sad_create(); + fail_if(sad->remove(sad, 1), + "Expected error removing nonexistent SAD entry"); + sad->destroy(sad); +} +END_TEST + +TCase *make_kernel_sad_tests(void) +{ + TCase *tc = tcase_create("Kernel SAD tests"); + tcase_add_test(tc, test_sad_creation); + tcase_add_test(tc, test_insert); + tcase_add_test(tc, test_insert_duplicate); + tcase_add_test(tc, test_get_esa_id); + tcase_add_test(tc, test_get_esa_id_nonexistent); + tcase_add_test(tc, test_remove); + tcase_add_test(tc, test_remove_nonexistent); + + return tc; +} diff --git a/src/charon-tkm/tests/keymat_tests.c b/src/charon-tkm/tests/keymat_tests.c new file mode 100644 index 000000000..2a7525d4e --- /dev/null +++ b/src/charon-tkm/tests/keymat_tests.c @@ -0,0 +1,149 @@ +/* + * 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 <daemon.h> +#include <hydra.h> +#include <config/proposal.h> +#include <encoding/payloads/ike_header.h> +#include <tkm/client.h> + +#include "tkm.h" +#include "tkm_nonceg.h" +#include "tkm_diffie_hellman.h" +#include "tkm_keymat.h" +#include "tkm_types.h" + +START_TEST(test_derive_ike_keys) +{ + proposal_t *proposal = proposal_create_from_string(PROTO_IKE, + "aes256-sha512-modp4096"); + fail_if(!proposal, "Unable to create proposal"); + ike_sa_id_t *ike_sa_id = ike_sa_id_create(IKEV2_MAJOR_VERSION, + 123912312312, 32312313122, TRUE); + fail_if(!ike_sa_id, "Unable to create IKE SA ID"); + + tkm_keymat_t *keymat = tkm_keymat_create(TRUE); + fail_if(!keymat, "Unable to create keymat"); + fail_if(!keymat->get_isa_id(keymat), "Invalid ISA context id (0)"); + + chunk_t nonce; + tkm_nonceg_t *ng = tkm_nonceg_create(); + fail_if(!ng, "Unable to create nonce generator"); + fail_unless(ng->nonce_gen.allocate_nonce(&ng->nonce_gen, 32, &nonce), + "Unable to allocate nonce"); + ng->nonce_gen.destroy(&ng->nonce_gen); + + tkm_diffie_hellman_t *dh = tkm_diffie_hellman_create(MODP_4096_BIT); + fail_if(!dh, "Unable to create DH"); + + /* Use the same pubvalue for both sides */ + chunk_t pubvalue; + dh->dh.get_my_public_value(&dh->dh, &pubvalue); + dh->dh.set_other_public_value(&dh->dh, pubvalue); + + fail_unless(keymat->keymat_v2.derive_ike_keys(&keymat->keymat_v2, proposal, + &dh->dh, nonce, nonce, ike_sa_id, PRF_UNDEFINED, chunk_empty), + "Key derivation failed"); + chunk_free(&nonce); + + aead_t * const aead = keymat->keymat_v2.keymat.get_aead(&keymat->keymat_v2.keymat, TRUE); + fail_if(!aead, "AEAD is NULL"); + + fail_if(aead->get_key_size(aead) != 96, "Key size mismatch %d", + aead->get_key_size(aead)); + fail_if(aead->get_block_size(aead) != 16, "Block size mismatch %d", + aead->get_block_size(aead)); + + proposal->destroy(proposal); + dh->dh.destroy(&dh->dh); + ike_sa_id->destroy(ike_sa_id); + keymat->keymat_v2.keymat.destroy(&keymat->keymat_v2.keymat); + chunk_free(&pubvalue); +} +END_TEST + +START_TEST(test_derive_child_keys) +{ + tkm_diffie_hellman_t *dh = tkm_diffie_hellman_create(MODP_4096_BIT); + fail_if(!dh, "Unable to create DH object"); + proposal_t *proposal = proposal_create_from_string(PROTO_ESP, + "aes256-sha512-modp4096"); + fail_if(!proposal, "Unable to create proposal"); + proposal->set_spi(proposal, 42); + + tkm_keymat_t *keymat = tkm_keymat_create(TRUE); + fail_if(!keymat, "Unable to create keymat"); + + chunk_t encr_i, encr_r, integ_i, integ_r; + chunk_t nonce = chunk_from_chars("test chunk"); + + fail_unless(keymat->keymat_v2.derive_child_keys(&keymat->keymat_v2, proposal, + (diffie_hellman_t *)dh, + nonce, nonce, &encr_i, + &integ_i, &encr_r, &integ_r), + "Child key derivation failed"); + + esa_info_t *info = (esa_info_t *)encr_i.ptr; + fail_if(!info, "encr_i does not contain esa information"); + fail_if(info->isa_id != keymat->get_isa_id(keymat), + "Isa context id mismatch (encr_i)"); + fail_if(info->spi_r != 42, + "SPI mismatch (encr_i)"); + fail_unless(chunk_equals(info->nonce_i, nonce), + "nonce_i mismatch (encr_i)"); + fail_unless(chunk_equals(info->nonce_r, nonce), + "nonce_r mismatch (encr_i)"); + fail_if(info->is_encr_r, + "Flag is_encr_r set for encr_i"); + fail_if(info->dh_id != dh->get_id(dh), + "DH context id mismatch (encr_i)"); + chunk_free(&info->nonce_i); + chunk_free(&info->nonce_r); + + info = (esa_info_t *)encr_r.ptr; + fail_if(!info, "encr_r does not contain esa information"); + fail_if(info->isa_id != keymat->get_isa_id(keymat), + "Isa context id mismatch (encr_r)"); + fail_if(info->spi_r != 42, + "SPI mismatch (encr_r)"); + fail_unless(chunk_equals(info->nonce_i, nonce), + "nonce_i mismatch (encr_r)"); + fail_unless(chunk_equals(info->nonce_r, nonce), + "nonce_r mismatch (encr_r)"); + fail_unless(info->is_encr_r, + "Flag is_encr_r set for encr_r"); + fail_if(info->dh_id != dh->get_id(dh), + "DH context id mismatch (encr_i)"); + chunk_free(&info->nonce_i); + chunk_free(&info->nonce_r); + + proposal->destroy(proposal); + dh->dh.destroy(&dh->dh); + keymat->keymat_v2.keymat.destroy(&keymat->keymat_v2.keymat); + chunk_free(&encr_i); + chunk_free(&encr_r); +} +END_TEST + +TCase *make_keymat_tests(void) +{ + TCase *tc = tcase_create("Keymat tests"); + tcase_add_test(tc, test_derive_ike_keys); + tcase_add_test(tc, test_derive_child_keys); + + 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..3a1effab8 --- /dev/null +++ b/src/charon-tkm/tests/nonceg_tests.c @@ -0,0 +1,93 @@ +/* + * 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"); + fail_if(ng->get_id(ng) == 0, "Invalid context id (0)"); + + 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..5ae032935 --- /dev/null +++ b/src/charon-tkm/tests/test_runner.c @@ -0,0 +1,84 @@ +/* + * 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 <library.h> +#include <hydra.h> +#include <daemon.h> + +#include "tkm.h" +#include "tkm_nonceg.h" +#include "tkm_diffie_hellman.h" +#include "tkm_kernel_ipsec.h" +#include "test_runner.h" + +int main(void) +{ + library_init(NULL); + libhydra_init("test_runner"); + libcharon_init("test_runner"); + + lib->settings->set_int(lib->settings, "test_runner.filelog.stdout.default", + 1); + charon->load_loggers(charon, NULL, FALSE); + + /* Register TKM specific plugins */ + static plugin_feature_t features[] = { + PLUGIN_REGISTER(NONCE_GEN, tkm_nonceg_create), + PLUGIN_PROVIDE(NONCE_GEN), + PLUGIN_REGISTER(DH, tkm_diffie_hellman_create), + PLUGIN_PROVIDE(DH, MODP_3072_BIT), + PLUGIN_PROVIDE(DH, MODP_4096_BIT), + PLUGIN_CALLBACK(kernel_ipsec_register, tkm_kernel_ipsec_create), + PLUGIN_PROVIDE(CUSTOM, "kernel-ipsec"), + }; + lib->plugins->add_static_features(lib->plugins, "tkm-tests", features, + countof(features), TRUE); + + if (!charon->initialize(charon, PLUGINS)) + { + fprintf(stderr, "Unable to init charon"); + return EXIT_FAILURE; + } + + if (!tkm_init()) + { + fprintf(stderr, "Could not connect to TKM, aborting tests\n"); + return EXIT_FAILURE; + } + + int number_failed; + Suite *s = suite_create("TKM tests"); + suite_add_tcase(s, make_id_manager_tests()); + suite_add_tcase(s, make_chunk_map_tests()); + suite_add_tcase(s, make_utility_tests()); + suite_add_tcase(s, make_nonceg_tests()); + suite_add_tcase(s, make_diffie_hellman_tests()); + suite_add_tcase(s, make_keymat_tests()); + suite_add_tcase(s, make_kernel_sad_tests()); + + SRunner *sr = srunner_create(s); + + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + + tkm_deinit(); + libcharon_deinit(); + libhydra_deinit(); + library_deinit(); + 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..236a7f2a6 --- /dev/null +++ b/src/charon-tkm/tests/test_runner.h @@ -0,0 +1,30 @@ +/* + * 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_chunk_map_tests(void); +TCase *make_utility_tests(void); +TCase *make_nonceg_tests(void); +TCase *make_diffie_hellman_tests(void); +TCase *make_keymat_tests(void); +TCase *make_kernel_sad_tests(void); + +#endif /** TEST_RUNNER_H_ */ diff --git a/src/charon-tkm/tests/utils_tests.c b/src/charon-tkm/tests/utils_tests.c new file mode 100644 index 000000000..b3ead7633 --- /dev/null +++ b/src/charon-tkm/tests/utils_tests.c @@ -0,0 +1,63 @@ +/* + * 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/types.h> + +#include "tkm_utils.h" + +START_TEST(test_sequence_to_chunk) +{ + key_type key = {5, {0, 1, 2, 3, 4}}; + chunk_t chunk = chunk_empty; + + sequence_to_chunk(key.data, key.size, &chunk); + fail_if(chunk.len != key.size, "Chunk size mismatch"); + + uint32_t i; + for (i = 0; i < key.size; i++) + { + fail_if(chunk.ptr[i] != i, "Data mismatch"); + } + chunk_free(&chunk); +} +END_TEST + +START_TEST(test_chunk_to_sequence) +{ + chunk_t chunk = chunk_from_thing("ABCDEFGH"); + key_type key; + + chunk_to_sequence(&chunk, &key, sizeof(key_type)); + fail_if(key.size != chunk.len, "Seq size mismatch"); + + uint32_t i; + for (i = 0; i < key.size - 1; i++) + { + fail_if(key.data[i] != 65 + i, "Data mismatch (1)"); + } + fail_if(key.data[key.size - 1] != 0, "Data mismatch (2)"); +} +END_TEST + +TCase *make_utility_tests(void) +{ + TCase *tc = tcase_create("Utility tests"); + tcase_add_test(tc, test_sequence_to_chunk); + tcase_add_test(tc, test_chunk_to_sequence); + + return tc; +} |