Merge branch 'tkm'

This adds charon-tkm a special build of the charon IKEv2 daemon that delegates
security critical operations to a separate process (TKM = Trusted Key Manager).
This commit is contained in:
Tobias Brunner 2013-03-19 15:25:38 +01:00
commit 7f0f185bed
136 changed files with 6567 additions and 42 deletions

View File

@ -18,6 +18,7 @@ the code, you need the following tools:
- lex/flex
- yacc/bison
- gperf
- check
- optionally Doxygen
To check out the master branch, use:

8
NEWS
View File

@ -43,6 +43,14 @@ strongswan-5.0.3
any authentication. Therefore, to use this backend it has to be selected
explicitly with rightauth2=xauth-noauth.
- The new charon-tkm IKEv2 daemon delegates security critical operations to a
separate process. This has the benefit that the network facing daemon has no
knowledge of keying material used to protect child SAs. Thus subverting
charon-tkm does not result in the compromise of cryptographic keys.
The extracted functionality has been implemented from scratch in a minimal TCB
(trusted computing base) in the Ada programming language. Further information
can be found at http://www.codelabs.ch/tkm/.
strongswan-5.0.2
----------------

View File

@ -236,6 +236,8 @@ ARG_ENABL_SET([radattr], [enable plugin to inject and process custom RADI
ARG_ENABL_SET([vstr], [enforce using the Vstr string library to replace glibc-like printf hooks.])
ARG_ENABL_SET([monolithic], [build monolithic version of libstrongswan that includes all enabled plugins. Similarly, the plugins of charon are assembled in libcharon.])
ARG_ENABL_SET([bfd-backtraces], [use binutils libbfd to resolve backtraces for memory leaks and segfaults.])
ARG_ENABL_SET([unit-tests], [enable unit tests using the check test framework.])
ARG_ENABL_SET([tkm], [enable Trusted Key Manager support.])
# ===================================
# option to disable default options
@ -258,6 +260,8 @@ if test -z "$CFLAGS"; then
CFLAGS="-g -O2 -Wall -Wno-format -Wno-pointer-sign"
fi
AC_PROG_CC
AM_PROG_CC_C_O
AC_LIB_PREFIX
AC_C_BIGENDIAN
@ -894,6 +898,16 @@ AC_SUBST(dev_headers)
CFLAGS="$CFLAGS -include `pwd`/config.h"
if test x$tkm = xtrue; then
AC_PATH_PROG([GPRBUILD], [gprbuild], [], [$PATH:/bin:/usr/bin:/usr/local/bin])
fi
if test x$unit_tests = xtrue; then
PKG_CHECK_MODULES(CHECK, [check >= 0.9.4])
AC_SUBST(CHECK_CFLAGS)
AC_SUBST(CHECK_LIBS)
fi
# ===============================================
# collect plugin list for strongSwan components
# ===============================================
@ -1190,9 +1204,9 @@ AM_CONDITIONAL(USE_NM, test x$nm = xtrue)
AM_CONDITIONAL(USE_TOOLS, test x$tools = xtrue)
AM_CONDITIONAL(USE_SCRIPTS, test x$scripts = xtrue)
AM_CONDITIONAL(USE_CONFTEST, test x$conftest = xtrue)
AM_CONDITIONAL(USE_LIBSTRONGSWAN, test x$charon = xtrue -o x$tools = xtrue -o x$conftest = xtrue -o x$fast = xtrue -o x$imcv = xtrue -o x$nm = xtrue)
AM_CONDITIONAL(USE_LIBHYDRA, test x$charon = xtrue -o x$nm = xtrue)
AM_CONDITIONAL(USE_LIBCHARON, test x$charon = xtrue -o x$conftest = xtrue -o x$nm = xtrue)
AM_CONDITIONAL(USE_LIBSTRONGSWAN, test x$charon = xtrue -o x$tools = xtrue -o x$conftest = xtrue -o x$fast = xtrue -o x$imcv = xtrue -o x$nm = xtrue -o x$tkm = xtrue)
AM_CONDITIONAL(USE_LIBHYDRA, test x$charon = xtrue -o x$nm = xtrue -o x$tkm = xtrue)
AM_CONDITIONAL(USE_LIBCHARON, test x$charon = xtrue -o x$conftest = xtrue -o x$nm = xtrue -o x$tkm = xtrue)
AM_CONDITIONAL(USE_LIBIPSEC, test x$libipsec = xtrue)
AM_CONDITIONAL(USE_LIBTNCIF, test x$tnc_tnccs = xtrue -o x$imcv = xtrue)
AM_CONDITIONAL(USE_LIBTNCCS, test x$tnc_tnccs = xtrue)
@ -1208,6 +1222,8 @@ AM_CONDITIONAL(USE_IMCV, test x$imcv = xtrue)
AM_CONDITIONAL(USE_PTS, test x$pts = xtrue)
AM_CONDITIONAL(USE_TROUSERS, test x$tss = xtrousers)
AM_CONDITIONAL(MONOLITHIC, test x$monolithic = xtrue)
AM_CONDITIONAL(UNITTESTS, test x$unit_tests = xtrue)
AM_CONDITIONAL(USE_TKM, test x$tkm = xtrue)
# ========================
# set global definitions
@ -1309,6 +1325,7 @@ AC_CONFIG_FILES([
src/libimcv/plugins/imv_os/Makefile
src/charon/Makefile
src/charon-nm/Makefile
src/charon-tkm/Makefile
src/libcharon/Makefile
src/libcharon/plugins/eap_aka/Makefile
src/libcharon/plugins/eap_aka_3gpp2/Makefile

View File

@ -100,6 +100,10 @@ if USE_INTEGRITY_TEST
SUBDIRS += checksum
endif
if USE_TKM
SUBDIRS += charon-tkm
endif
EXTRA_DIST = strongswan.conf
install-exec-local :

1
src/charon-tkm/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
obj

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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_ @}*/

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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_ @}*/

View File

@ -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;

View File

@ -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;

1
src/charon-tkm/src/tkm/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
obj

View File

@ -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;
}

View File

@ -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 occured
*/
bool tkm_init();
/**
* Deinitialize trusted key manager, destroys "tkm" instance.
*/
void tkm_deinit();
/**
* Trusted key manager instance, set after tkm_init() and before tkm_deinit()
* calls.
*/
extern tkm_t *tkm;
#endif /** TKM_H_ @}*/

View File

@ -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;
}

View File

@ -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 specifiying 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_ @}*/

View File

@ -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;
}

View File

@ -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_ @}*/

View File

@ -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;
}

View File

@ -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_ @}*/

View File

@ -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;
}
}

View File

@ -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_ @}*/

View File

@ -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;
}

View File

@ -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_ @}*/

View File

@ -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;
}

View File

@ -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_ @}*/

View File

@ -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 **)&current))
{
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;
}

View File

@ -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_ @}*/

View File

@ -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;
}

View File

@ -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_ @}*/

View File

@ -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;
}

View File

@ -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_ @}*/

View File

@ -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;
}

View File

@ -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_ @}*/

View File

@ -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;
}

View File

@ -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_ @}*/

View File

@ -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;
}

View File

@ -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_ @}*/

View File

@ -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_ @}*/

View File

@ -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);
}

View File

@ -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_ @}*/

1
src/charon-tkm/tests/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
test_runner

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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_ */

View File

@ -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;
}

View File

@ -18,6 +18,9 @@
PATH="/sbin:/bin:/usr/sbin:/usr/bin:@IPSEC_SBINDIR@"
export PATH
# set daemon name
[ -z "$DAEMON_NAME" ] && DAEMON_NAME="charon"
# name and version of the ipsec implementation
OS_NAME=`uname -s`
IPSEC_NAME="@IPSEC_NAME@"
@ -30,8 +33,8 @@ IPSEC_CONFDIR="@IPSEC_CONFDIR@"
IPSEC_PIDDIR="@IPSEC_PIDDIR@"
IPSEC_SCRIPT="@IPSEC_SCRIPT@"
IPSEC_STARTER_PID="${IPSEC_PIDDIR}/starter.pid"
IPSEC_CHARON_PID="${IPSEC_PIDDIR}/charon.pid"
IPSEC_STARTER_PID="${IPSEC_PIDDIR}/starter.${DAEMON_NAME}.pid"
IPSEC_CHARON_PID="${IPSEC_PIDDIR}/${DAEMON_NAME}.pid"
IPSEC_STROKE="${IPSEC_DIR}/stroke"
IPSEC_STARTER="${IPSEC_DIR}/starter"
@ -220,7 +223,7 @@ start)
if [ -d /var/lock/subsys ]; then
touch /var/lock/subsys/ipsec
fi
exec $IPSEC_STARTER "$@"
exec $IPSEC_STARTER --daemon $DAEMON_NAME "$@"
;;
status|statusall)
op="$1"

View File

@ -190,7 +190,7 @@ static void load_setup(starter_config_t *cfg, config_parsed_t *cfgp)
/* verify the executables are actually available */
#ifdef START_CHARON
cfg->setup.charonstart = cfg->setup.charonstart &&
daemon_exists("charon", CHARON_CMD);
daemon_exists(daemon_name, cmd);
#else
cfg->setup.charonstart = FALSE;
#endif

View File

@ -15,8 +15,6 @@
#ifndef _STARTER_FILES_H_
#define _STARTER_FILES_H_
#define STARTER_PID_FILE IPSEC_PIDDIR "/starter.pid"
#define PROC_NETKEY "/proc/net/pfkey"
#define PROC_KLIPS "/proc/net/pf_key"
#define PROC_MODULES "/proc/modules"
@ -24,9 +22,11 @@
#define CONFIG_FILE IPSEC_CONFDIR "/ipsec.conf"
#define SECRETS_FILE IPSEC_CONFDIR "/ipsec.secrets"
#define CHARON_CMD IPSEC_DIR "/charon"
#define CHARON_CTL_FILE IPSEC_PIDDIR "/charon.ctl"
#define CHARON_PID_FILE IPSEC_PIDDIR "/charon.pid"
extern char *daemon_name;
extern char *cmd;
extern char *pid_file;
#define DYNIP_DIR IPSEC_PIDDIR "/dynip"

View File

@ -46,22 +46,22 @@ void starter_charon_sigchild(pid_t pid, int status)
if (status == SS_RC_LIBSTRONGSWAN_INTEGRITY ||
status == SS_RC_DAEMON_INTEGRITY)
{
DBG1(DBG_APP, "charon has quit: integrity test of %s failed",
(status == 64) ? "libstrongswan" : "charon");
DBG1(DBG_APP, "%s has quit: integrity test of %s failed",
daemon_name, (status == 64) ? "libstrongswan" : daemon_name);
_stop_requested = 1;
}
else if (status == SS_RC_INITIALIZATION_FAILED)
{
DBG1(DBG_APP, "charon has quit: initialization failed");
DBG1(DBG_APP, "%s has quit: initialization failed", daemon_name);
_stop_requested = 1;
}
if (!_stop_requested)
{
DBG1(DBG_APP, "charon has died -- restart scheduled (%dsec)",
CHARON_RESTART_DELAY);
DBG1(DBG_APP, "%s has died -- restart scheduled (%dsec)",
daemon_name, CHARON_RESTART_DELAY);
alarm(CHARON_RESTART_DELAY); // restart in 5 sec
}
unlink(CHARON_PID_FILE);
unlink(pid_file);
}
}
@ -88,7 +88,8 @@ int starter_stop_charon (void)
else if (i == 40)
{
kill(pid, SIGKILL);
DBG1(DBG_APP, "starter_stop_charon(): charon does not respond, sending KILL");
DBG1(DBG_APP, "starter_stop_charon(): %s does not respond, sending KILL",
daemon_name);
}
else
{
@ -98,15 +99,15 @@ int starter_stop_charon (void)
}
if (_charon_pid == 0)
{
DBG1(DBG_APP, "charon stopped after %d ms", 200*i);
DBG1(DBG_APP, "%s stopped after %d ms", daemon_name, 200*i);
return 0;
}
DBG1(DBG_APP, "starter_stop_charon(): can't stop charon !!!");
DBG1(DBG_APP, "starter_stop_charon(): can't stop %s !!!", daemon_name);
return -1;
}
else
{
DBG1(DBG_APP, "stater_stop_charon(): charon was not started...");
DBG1(DBG_APP, "stater_stop_charon(): %s was not started...", daemon_name);
}
return -1;
}
@ -119,7 +120,7 @@ int starter_start_charon (starter_config_t *cfg, bool no_fork, bool attach_gdb)
char buffer[BUF_LEN];
int argc = 1;
char *arg[] = {
CHARON_CMD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
cmd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
@ -130,7 +131,7 @@ int starter_start_charon (starter_config_t *cfg, bool no_fork, bool attach_gdb)
argc = 0;
arg[argc++] = "/usr/bin/gdb";
arg[argc++] = "--args";
arg[argc++] = CHARON_CMD;
arg[argc++] = cmd;
}
if (!no_fork)
{
@ -172,7 +173,8 @@ int starter_start_charon (starter_config_t *cfg, bool no_fork, bool attach_gdb)
if (_charon_pid)
{
DBG1(DBG_APP, "starter_start_charon(): charon already started...");
DBG1(DBG_APP, "starter_start_charon(): %s already started...",
daemon_name);
return -1;
}
else
@ -203,9 +205,9 @@ int starter_start_charon (starter_config_t *cfg, bool no_fork, bool attach_gdb)
{
/* wait for charon for a maximum of 500 x 20 ms = 10 s */
usleep(20000);
if (stat(CHARON_PID_FILE, &stb) == 0)
if (stat(pid_file, &stb) == 0)
{
DBG1(DBG_APP, "charon (%d) started after %d ms",
DBG1(DBG_APP, "%s (%d) started after %d ms", daemon_name,
_charon_pid, 20*(i+1));
return 0;
}
@ -213,7 +215,8 @@ int starter_start_charon (starter_config_t *cfg, bool no_fork, bool attach_gdb)
if (_charon_pid)
{
/* If charon is started but with no ctl file, stop it */
DBG1(DBG_APP, "charon too long to start... - kill kill");
DBG1(DBG_APP, "%s too long to start... - kill kill",
daemon_name);
for (i = 0; i < 20 && (pid = _charon_pid) != 0; i++)
{
if (i == 0)
@ -233,7 +236,7 @@ int starter_start_charon (starter_config_t *cfg, bool no_fork, bool attach_gdb)
}
else
{
DBG1(DBG_APP, "charon refused to be started");
DBG1(DBG_APP, "%s refused to be started", daemon_name);
}
return -1;
}

View File

@ -12,6 +12,8 @@
* for more details.
*/
#define _GNU_SOURCE
#include <sys/select.h>
#include <sys/types.h>
#include <sys/wait.h>
@ -50,6 +52,15 @@
#define CHARON_RESTART_DELAY 5
static const char* cmd_default = IPSEC_DIR "/charon";
static const char* pid_file_default = IPSEC_PIDDIR "/charon.pid";
static const char* starter_pid_file_default = IPSEC_PIDDIR "/starter.pid";
char *daemon_name = NULL;
char *cmd = NULL;
char *pid_file = NULL;
char *starter_pid_file = NULL;
/* logging */
static bool log_to_stderr = TRUE;
static bool log_to_syslog = TRUE;
@ -162,7 +173,10 @@ static void signal_handler(int signal)
{
if (pid == starter_charon_pid())
{
name = " (Charon)";
if (asprintf(&name, " (%s)", daemon_name) < 0)
{
name = NULL;
}
}
if (WIFSIGNALED(status))
{
@ -193,6 +207,11 @@ static void signal_handler(int signal)
starter_charon_sigchild(pid, exit_status);
}
}
if (name)
{
free(name);
}
}
break;
@ -325,11 +344,56 @@ static bool check_pid(char *pid_file)
return FALSE;
}
/* Set daemon name and adjust command and pid filenames accordingly */
static bool set_daemon_name()
{
if (!daemon_name)
{
daemon_name = "charon";
}
if (asprintf(&cmd, IPSEC_DIR"/%s", daemon_name) < 0)
{
cmd = (char*)cmd_default;
}
if (asprintf(&pid_file, IPSEC_PIDDIR"/%s.pid", daemon_name) < 0)
{
pid_file = (char*)pid_file_default;
}
if (asprintf(&starter_pid_file, IPSEC_PIDDIR"/starter.%s.pid",
daemon_name) < 0)
{
starter_pid_file = (char*)starter_pid_file_default;
}
return TRUE;
}
static void cleanup()
{
if (cmd != cmd_default)
{
free(cmd);
}
if (pid_file != pid_file_default)
{
free(pid_file);
}
if (starter_pid_file != starter_pid_file_default)
{
free(starter_pid_file);
}
}
static void usage(char *name)
{
fprintf(stderr, "Usage: starter [--nofork] [--auto-update <sec>]\n"
" [--debug|--debug-more|--debug-all|--nolog]\n"
" [--attach-gdb]\n");
" [--attach-gdb] [--daemon <name>]\n");
exit(LSB_RC_INVALID_ARGUMENT);
}
@ -392,12 +456,22 @@ int main (int argc, char **argv)
if (!auto_update)
usage(argv[0]);
}
else if (streq(argv[i], "--daemon") && i+1 < argc)
{
daemon_name = argv[++i];
}
else
{
usage(argv[0]);
}
}
if (!set_daemon_name())
{
DBG1(DBG_APP, "unable to set daemon name");
exit(LSB_RC_FAILURE);
}
init_log("ipsec_starter");
DBG1(DBG_APP, "Starting %sSwan "VERSION" IPsec [starter]...",
@ -423,13 +497,14 @@ int main (int argc, char **argv)
if (getuid() != 0)
{
DBG1(DBG_APP, "permission denied (must be superuser)");
cleanup();
exit(LSB_RC_NOT_ALLOWED);
}
if (check_pid(CHARON_PID_FILE))
if (check_pid(pid_file))
{
DBG1(DBG_APP, "charon is already running (%s exists) -- skipping charon start",
CHARON_PID_FILE);
DBG1(DBG_APP, "%s is already running (%s exists) -- skipping daemon start",
daemon_name, pid_file);
}
else
{
@ -438,12 +513,14 @@ int main (int argc, char **argv)
if (stat(DEV_RANDOM, &stb) != 0)
{
DBG1(DBG_APP, "unable to start strongSwan IPsec -- no %s!", DEV_RANDOM);
cleanup();
exit(LSB_RC_FAILURE);
}
if (stat(DEV_URANDOM, &stb)!= 0)
{
DBG1(DBG_APP, "unable to start strongSwan IPsec -- no %s!", DEV_URANDOM);
cleanup();
exit(LSB_RC_FAILURE);
}
@ -455,6 +532,7 @@ int main (int argc, char **argv)
{
confread_free(cfg);
}
cleanup();
exit(LSB_RC_INVALID_ARGUMENT);
}
@ -471,11 +549,12 @@ int main (int argc, char **argv)
last_reload = time_monotonic(NULL);
if (check_pid(STARTER_PID_FILE))
if (check_pid(starter_pid_file))
{
DBG1(DBG_APP, "starter is already running (%s exists) -- no fork done",
STARTER_PID_FILE);
starter_pid_file);
confread_free(cfg);
cleanup();
exit(LSB_RC_SUCCESS);
}
@ -515,13 +594,14 @@ int main (int argc, char **argv)
break;
default:
confread_free(cfg);
cleanup();
exit(LSB_RC_SUCCESS);
}
}
/* save pid file in /var/run/starter.pid */
/* save pid file in /var/run/starter[.daemon_name].pid */
{
FILE *fd = fopen(STARTER_PID_FILE, "w");
FILE *fd = fopen(starter_pid_file, "w");
if (fd)
{
@ -576,7 +656,8 @@ int main (int argc, char **argv)
}
starter_netkey_cleanup();
confread_free(cfg);
unlink(STARTER_PID_FILE);
unlink(starter_pid_file);
cleanup();
DBG1(DBG_APP, "ipsec starter stopped");
close_log();
exit(LSB_RC_SUCCESS);
@ -709,13 +790,13 @@ int main (int argc, char **argv)
}
/*
* Start charon
* Start daemon
*/
if (_action_ & FLAG_ACTION_START_CHARON)
{
if (cfg->setup.charonstart && !starter_charon_pid())
{
DBG2(DBG_APP, "Attempting to start charon...");
DBG2(DBG_APP, "Attempting to start %s...", daemon_name);
if (starter_start_charon(cfg, no_fork, attach_gdb))
{
/* schedule next try */
@ -807,7 +888,8 @@ int main (int argc, char **argv)
/*
* Wait for something to happen
*/
if (pselect(0, NULL, NULL, NULL, auto_update ? &ts : NULL,
if (!_action_ &&
pselect(0, NULL, NULL, NULL, auto_update ? &ts : NULL,
&action.sa_mask) == 0)
{
/* timeout -> auto_update */

View File

@ -0,0 +1 @@
/usr/local/lib/ipsec

View File

@ -0,0 +1,29 @@
#!/bin/bash
#
# Wait until a given file appears
#
# Params:
# $1 - filename
# $2 - maximum time to wait in seconds, default is 5 seconds
if [[ $# -lt 1 || $# -gt 2 ]]
then
echo "invalid arguments"
exit 1
fi
secs=$2
[ ! $secs ] && secs=5
let steps=$secs*10
for i in `seq 1 $steps`
do
# -f does not work for special files (e.g. UNIX domain sockets), use ls
# instead
ls $1 >/dev/null 2>&1
[ $? -eq 0 ] && exit 0
sleep 0.1
done
echo "File '$1' not available after $secs second(s)"
exit 1

View File

@ -16,6 +16,8 @@ INC=$INC,libxml2-dev,libtspi-dev,libsqlite3-dev,openssh-server,tcpdump,psmisc
INC=$INC,openssl,vim,sqlite3,conntrack,gdb,cmake,libxerces-c2-dev,libltdl-dev
INC=$INC,liblog4cxx10-dev,libboost-thread-dev,libboost-system-dev,git-core
INC=$INC,less,acpid,acpi-support-base,libldns-dev,libunbound-dev,dnsutils,screen
INC=$INC,gnat,gprbuild,libahven3-dev,libxmlada4.1-dev,libgmpada3-dev
INC=$INC,libalog0.4.1-base-dev
SERVICES="apache2 dbus isc-dhcp-server slapd bind9"
INC=$INC,${SERVICES// /,}
EXC=iptables

View File

@ -46,6 +46,8 @@ do
execute "mount $NBDPARTITION $LOOPDIR" 0
execute "cp -rf $HOSTSDIR/${host}/etc $LOOPDIR" 0
execute "cp -rf $HOSTSDIR/default/* $LOOPDIR" 0
execute_chroot "ldconfig" 0
if [ "$host" = "winnetou" ]
then
execute "mkdir $LOOPDIR/var/log/apache2/ocsp" 0

View File

@ -0,0 +1,19 @@
#!/usr/bin/make
PKG = anet
SRC = http://git.codelabs.ch/git/$(PKG).git
REV = v0.2.2
all: install
.$(PKG)-cloned:
git clone $(SRC) $(PKG)
cd $(PKG) && git checkout $(REV)
@touch $@
.$(PKG)-built: .$(PKG)-cloned
cd $(PKG) && make tests && make LIBRARY_KIND=static
@touch $@
install: .$(PKG)-built
cd $(PKG) && make LIBRARY_KIND=static install

View File

@ -0,0 +1,21 @@
#!/usr/bin/make
PKG = tkm-rpc
SRC = http://git.codelabs.ch/git/$(PKG).git
REV = v0.1
export ADA_PROJECT_PATH=/root/libraries/lib/gnat
all: install
.$(PKG)-cloned:
git clone $(SRC) $(PKG)
cd $(PKG) && git checkout $(REV)
@touch $@
.$(PKG)-built: .$(PKG)-cloned
cd $(PKG) && make tests && make
@touch $@
install: .$(PKG)-built
cd $(PKG) && make install

View File

@ -0,0 +1,19 @@
#!/usr/bin/make
PKG = x509-ada
SRC = http://git.codelabs.ch/git/$(PKG).git
REV = v0.1
all: install
.$(PKG)-cloned:
git clone $(SRC) $(PKG)
cd $(PKG) && git checkout $(REV)
@touch $@
.$(PKG)-built: .$(PKG)-cloned
cd $(PKG) && make tests && make
@touch $@
install: .$(PKG)-built
cd $(PKG) && make install

View File

@ -0,0 +1,21 @@
#!/usr/bin/make
PKG = xfrm-ada
SRC = http://git.codelabs.ch/git/$(PKG).git
REV = v0.1
export ADA_PROJECT_PATH=/root/libraries/lib/gnat
all: install
.$(PKG)-cloned:
git clone $(SRC) $(PKG)
cd $(PKG) && git checkout $(REV)
@touch $@
.$(PKG)-built: .$(PKG)-cloned
cd $(PKG) && make
@touch $@
install: .$(PKG)-built
cd $(PKG) && make install

View File

@ -0,0 +1,21 @@
#!/usr/bin/make
PKG = tkm
SRC = http://git.codelabs.ch/git/$(PKG).git
REV = v0.1
export ADA_PROJECT_PATH=/root/libraries/lib/gnat
all: install
.$(PKG)-cloned:
git clone $(SRC) $(PKG)
cd $(PKG) && git checkout $(REV)
@touch $@
.$(PKG)-built: .$(PKG)-cloned
cd $(PKG) && make tests && make
@touch $@
install: .$(PKG)-built
cd $(PKG) && make install

View File

@ -69,7 +69,10 @@ CONFIG_OPTS = \
--enable-pkcs8 \
--enable-unity \
--enable-unbound \
--enable-ipseckey
--enable-ipseckey \
--enable-tkm
export ADA_PROJECT_PATH=/root/libraries/lib/gnat
all: install

View File

@ -0,0 +1,21 @@
#!/usr/bin/make
PKG = xfrm-proxy
SRC = http://git.codelabs.ch/git/$(PKG).git
REV = v0.1
export ADA_PROJECT_PATH=/root/libraries/lib/gnat
all: install
.$(PKG)-cloned:
git clone $(SRC) $(PKG)
cd $(PKG) && git checkout $(REV)
@touch $@
.$(PKG)-built: .$(PKG)-cloned
cd $(PKG) && make
@touch $@
install: .$(PKG)-built
cd $(PKG) && make install

View File

@ -0,0 +1,3 @@
A connection between the hosts <b>moon</b> and <b>sun</b> is set up. The host
<b>moon</b> uses the Trusted Key Manager (TKM) and is the initiator of the
transport connection. The authentication is based on X.509 certificates.

View File

@ -0,0 +1,12 @@
moon::ipsec stroke status 2> /dev/null::conn1.*ESTABLISHED.*moon.strongswan.org.*sun.strongswan.org::YES
sun::ipsec status 2> /dev/null::host-host.*ESTABLISHED.*sun.strongswan.org.*moon.strongswan.org::YES
moon::ipsec stroke status 2> /dev/null::conn1.*INSTALLED, TRANSPORT::YES
sun::ipsec status 2> /dev/null::host-host.*INSTALLED, TRANSPORT::YES
moon::ping -c 1 PH_IP_SUN::64 bytes from PH_IP_SUN: icmp_req=1::YES
sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES
sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES
moon::cat /tmp/tkm.log::RSA private key '/etc/tkm/moonKey.der' loaded::YES
moon::cat /tmp/tkm.log::Adding policy \[ 1, 192.168.0.1 <-> 192.168.0.2 \]::YES
moon::cat /tmp/tkm.log::Checked CA certificate of CC context 1::YES
moon::cat /tmp/tkm.log::Authentication of ISA context 1 successful::YES
moon::cat /tmp/tkm.log::Adding SA \[ 1, 192.168.0.1 <-> 192.168.0.2, SPI_in.*, SPI_out.*, soft 30, hard 60 \]::YES

View File

@ -0,0 +1,21 @@
<tkmconfig>
<local_identity id="1">
<identity>moon.strongswan.org</identity>
<certificate>moonCert.pem</certificate>
</local_identity>
<policy id="1">
<mode>transport</mode>
<local>
<identity_id>1</identity_id>
<ip>192.168.0.1</ip>
</local>
<remote>
<identity>sun.strongswan.org</identity>
<ip>192.168.0.2</ip>
</remote>
<lifetime>
<soft>30</soft>
<hard>60</hard>
</lifetime>
</policy>
</tkmconfig>

View File

@ -0,0 +1,20 @@
# /etc/ipsec.conf - strongSwan IPsec configuration file
config setup
conn %default
ikelifetime=60m
keylife=20m
rekeymargin=3m
keyingtries=1
keyexchange=ikev2
conn host-host
left=PH_IP_SUN
leftcert=sunCert.pem
leftid=sun.strongswan.org
right=PH_IP_MOON
rightid=moon.strongswan.org
ike=aes256-sha512-modp4096!
esp=aes256-sha512-modp4096!
auto=add

View File

@ -0,0 +1,5 @@
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 revocation hmac xcbc stroke kernel-netlink socket-default updown
}

View File

@ -0,0 +1,4 @@
moon::DAEMON_NAME=charon-tkm ipsec stop
moon::killall tkm_keymanager
moon::rm -f /tmp/tkm.rpc.ike /tmp/tkm.rpc.ees /tmp/tkm.log
sun::ipsec stop

View File

@ -0,0 +1,10 @@
moon::rm /etc/ipsec.secrets
moon::tkm_cfgtool -c /etc/tkm/tkm.conf -i /etc/ipsec.conf -t /etc/tkm/tkm.bin -s /usr/local/share/tkm/tkmconfig.xsd
moon::cat /etc/ipsec.conf
moon::tkm_keymanager -c /etc/tkm/tkm.bin -k /etc/tkm/moonKey.der -r /etc/tkm/strongswanCert.der >/tmp/tkm.log 2>&1 &
moon::expect-file /tmp/tkm.rpc.ike
moon::DAEMON_NAME=charon-tkm ipsec start
sun::ipsec start
sun::expect-connection host-host
moon::DAEMON_NAME=charon-tkm expect-connection conn1
moon::DAEMON_NAME=charon-tkm ipsec up conn1

View File

@ -0,0 +1,21 @@
#!/bin/bash
#
# This configuration file provides information on the
# guest instances used for this test
# All guest instances that are required for this test
#
VIRTHOSTS="moon winnetou sun"
# Corresponding block diagram
#
DIAGRAM="m-w-s.png"
# Guest instances on which tcpdump is to be started
#
TCPDUMPHOSTS="sun"
# Guest instances on which IPsec is started
# Used for IPsec logging purposes
#
IPSECHOSTS="moon sun"

View File

@ -0,0 +1,3 @@
A connection between the hosts <b>moon</b> and <b>sun</b> is set up. The host
<b>moon</b> uses the Trusted Key Manager (TKM) and is the responder of the
transport connection. The authentication is based on X.509 certificates.

View File

@ -0,0 +1,12 @@
moon::ipsec stroke status 2> /dev/null::conn1.*ESTABLISHED.*moon.strongswan.org.*sun.strongswan.org::YES
sun::ipsec status 2> /dev/null::host-host.*ESTABLISHED.*sun.strongswan.org.*moon.strongswan.org::YES
moon::ipsec stroke status 2> /dev/null::conn1.*INSTALLED, TRANSPORT::YES
sun::ipsec status 2> /dev/null::host-host.*INSTALLED, TRANSPORT::YES
moon::ping -c 1 PH_IP_SUN::64 bytes from PH_IP_SUN: icmp_req=1::YES
sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES
sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES
moon::cat /tmp/tkm.log::RSA private key '/etc/tkm/moonKey.der' loaded::YES
moon::cat /tmp/tkm.log::Adding policy \[ 1, 192.168.0.1 <-> 192.168.0.2 \]::YES
moon::cat /tmp/tkm.log::Checked CA certificate of CC context 1::YES
moon::cat /tmp/tkm.log::Authentication of ISA context 1 successful::YES
moon::cat /tmp/tkm.log::Adding SA \[ 1, 192.168.0.1 <-> 192.168.0.2, SPI_in.*, SPI_out.*, soft 30, hard 60 \]::YES

View File

@ -0,0 +1,21 @@
<tkmconfig>
<local_identity id="1">
<identity>moon.strongswan.org</identity>
<certificate>moonCert.pem</certificate>
</local_identity>
<policy id="1">
<mode>transport</mode>
<local>
<identity_id>1</identity_id>
<ip>192.168.0.1</ip>
</local>
<remote>
<identity>sun.strongswan.org</identity>
<ip>192.168.0.2</ip>
</remote>
<lifetime>
<soft>30</soft>
<hard>60</hard>
</lifetime>
</policy>
</tkmconfig>

View File

@ -0,0 +1,21 @@
# /etc/ipsec.conf - strongSwan IPsec configuration file
config setup
conn %default
ikelifetime=60m
keylife=20m
rekeymargin=3m
keyingtries=1
keyexchange=ikev2
conn host-host
left=PH_IP_SUN
leftcert=sunCert.pem
leftid=sun.strongswan.org
right=PH_IP_MOON
rightid=moon.strongswan.org
ike=aes256-sha512-modp4096!
esp=aes256-sha512-modp4096!
auto=add
type=transport

View File

@ -0,0 +1,5 @@
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 revocation hmac xcbc stroke kernel-netlink socket-default updown
}

View File

@ -0,0 +1,4 @@
moon::DAEMON_NAME=charon-tkm ipsec stop
moon::killall tkm_keymanager
moon::rm -f /tmp/tkm.rpc.ike /tmp/tkm.rpc.ees /tmp/tkm.log
sun::ipsec stop

View File

@ -0,0 +1,10 @@
moon::rm /etc/ipsec.secrets
moon::tkm_cfgtool -c /etc/tkm/tkm.conf -i /etc/ipsec.conf -t /etc/tkm/tkm.bin -s /usr/local/share/tkm/tkmconfig.xsd
moon::cat /etc/ipsec.conf
moon::tkm_keymanager -c /etc/tkm/tkm.bin -k /etc/tkm/moonKey.der -r /etc/tkm/strongswanCert.der >/tmp/tkm.log 2>&1 &
moon::expect-file /tmp/tkm.rpc.ike
moon::DAEMON_NAME=charon-tkm ipsec start
sun::ipsec start
sun::expect-connection host-host
moon::DAEMON_NAME=charon-tkm expect-connection conn1
sun::ipsec up host-host

View File

@ -0,0 +1,21 @@
#!/bin/bash
#
# This configuration file provides information on the
# guest instances used for this test
# All guest instances that are required for this test
#
VIRTHOSTS="moon winnetou sun"
# Corresponding block diagram
#
DIAGRAM="m-w-s.png"
# Guest instances on which tcpdump is to be started
#
TCPDUMPHOSTS="sun"
# Guest instances on which IPsec is started
# Used for IPsec logging purposes
#
IPSECHOSTS="moon sun"

View File

@ -0,0 +1,5 @@
A transport connection between the hosts <b>moon</b> and <b>sun</b> is set up.
The host <b>moon</b> starts the Trusted Key Manager (TKM) and the Ada XFRM
proxy, which relays XFRM kernel messages to charon. The authentication is based
on X.509 certificates. The connection is initiated by a ping from <b>moon</b> to
<b>sun</b>.

View File

@ -0,0 +1,13 @@
moon::ipsec stroke status 2> /dev/null::conn1.*ESTABLISHED.*moon.strongswan.org.*sun.strongswan.org::YES
sun::ipsec status 2> /dev/null::host-host.*ESTABLISHED.*sun.strongswan.org.*moon.strongswan.org::YES
moon::ipsec stroke status 2> /dev/null::conn1.*INSTALLED, TRANSPORT::YES
sun::ipsec status 2> /dev/null::host-host.*INSTALLED, TRANSPORT::YES
moon::ping -c 1 PH_IP_SUN::64 bytes from PH_IP_SUN: icmp_req=1::YES
sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES
sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES
moon::cat /tmp/tkm.log::RSA private key '/etc/tkm/moonKey.der' loaded::YES
moon::cat /tmp/tkm.log::Adding policy \[ 1, 192.168.0.1 <-> 192.168.0.2 \]::YES
moon::cat /tmp/tkm.log::Checked CA certificate of CC context 1::YES
moon::cat /tmp/tkm.log::Authentication of ISA context 1 successful::YES
moon::cat /tmp/tkm.log::Adding SA \[ 1, 192.168.0.1 <-> 192.168.0.2, SPI_in.*, SPI_out.*, soft 30, hard 60 \]::YES
moon::cat /tmp/xfrm_proxy.log::Initiating ESA acquire for reqid 1::YES

View File

@ -0,0 +1,21 @@
<tkmconfig>
<local_identity id="1">
<identity>moon.strongswan.org</identity>
<certificate>moonCert.pem</certificate>
</local_identity>
<policy id="1">
<mode>transport</mode>
<local>
<identity_id>1</identity_id>
<ip>192.168.0.1</ip>
</local>
<remote>
<identity>sun.strongswan.org</identity>
<ip>192.168.0.2</ip>
</remote>
<lifetime>
<soft>30</soft>
<hard>60</hard>
</lifetime>
</policy>
</tkmconfig>

Some files were not shown because too many files have changed in this diff Show More