summaryrefslogtreecommitdiff
path: root/src/libsimaka
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@corsac.net>2012-06-28 21:16:07 +0200
committerYves-Alexis Perez <corsac@corsac.net>2012-06-28 21:16:07 +0200
commitb34738ed08c2227300d554b139e2495ca5da97d6 (patch)
tree62f33b52820f2e49f0e53c0f8c636312037c8054 /src/libsimaka
parent0a9d51a49042a68daa15b0c74a2b7f152f52606b (diff)
downloadvyos-strongswan-b34738ed08c2227300d554b139e2495ca5da97d6.tar.gz
vyos-strongswan-b34738ed08c2227300d554b139e2495ca5da97d6.zip
Imported Upstream version 4.6.4
Diffstat (limited to 'src/libsimaka')
-rw-r--r--src/libsimaka/Makefile.am5
-rw-r--r--src/libsimaka/Makefile.in94
-rw-r--r--src/libsimaka/simaka_card.h129
-rw-r--r--src/libsimaka/simaka_crypto.c136
-rw-r--r--src/libsimaka/simaka_hooks.h55
-rw-r--r--src/libsimaka/simaka_manager.c626
-rw-r--r--src/libsimaka/simaka_manager.h315
-rw-r--r--src/libsimaka/simaka_message.c169
-rw-r--r--src/libsimaka/simaka_message.h11
-rw-r--r--src/libsimaka/simaka_provider.h128
10 files changed, 1499 insertions, 169 deletions
diff --git a/src/libsimaka/Makefile.am b/src/libsimaka/Makefile.am
index 8e7a1f0d3..80d4fb814 100644
--- a/src/libsimaka/Makefile.am
+++ b/src/libsimaka/Makefile.am
@@ -1,6 +1,7 @@
INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra -I$(top_srcdir)/src/libcharon
-noinst_LTLIBRARIES = libsimaka.la
+ipseclib_LTLIBRARIES = libsimaka.la
libsimaka_la_SOURCES = simaka_message.h simaka_message.c \
- simaka_crypto.h simaka_crypto.c
+ simaka_crypto.h simaka_crypto.c simaka_manager.h simaka_manager.c \
+ simaka_card.h simaka_provider.h simaka_hooks.h
diff --git a/src/libsimaka/Makefile.in b/src/libsimaka/Makefile.in
index 30af27406..59919e559 100644
--- a/src/libsimaka/Makefile.in
+++ b/src/libsimaka/Makefile.in
@@ -51,9 +51,32 @@ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
mkinstalldirs = $(install_sh) -d
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
-LTLIBRARIES = $(noinst_LTLIBRARIES)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(ipseclibdir)"
+LTLIBRARIES = $(ipseclib_LTLIBRARIES)
libsimaka_la_LIBADD =
-am_libsimaka_la_OBJECTS = simaka_message.lo simaka_crypto.lo
+am_libsimaka_la_OBJECTS = simaka_message.lo simaka_crypto.lo \
+ simaka_manager.lo
libsimaka_la_OBJECTS = $(am_libsimaka_la_OBJECTS)
DEFAULT_INCLUDES = -I.@am__isrc@
depcomp = $(SHELL) $(top_srcdir)/depcomp
@@ -164,6 +187,9 @@ am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
+attest_plugins = @attest_plugins@
+axis2c_CFLAGS = @axis2c_CFLAGS@
+axis2c_LIBS = @axis2c_LIBS@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
@@ -172,6 +198,7 @@ build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
c_plugins = @c_plugins@
+clearsilver_LIBS = @clearsilver_LIBS@
datadir = @datadir@
datarootdir = @datarootdir@
dbusservicedir = @dbusservicedir@
@@ -188,11 +215,13 @@ host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
+imcvdir = @imcvdir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
ipsecdir = @ipsecdir@
ipsecgroup = @ipsecgroup@
+ipseclibdir = @ipseclibdir@
ipsecuser = @ipsecuser@
libcharon_plugins = @libcharon_plugins@
libdir = @libdir@
@@ -236,6 +265,7 @@ sharedstatedir = @sharedstatedir@
soup_CFLAGS = @soup_CFLAGS@
soup_LIBS = @soup_LIBS@
srcdir = @srcdir@
+starter_plugins = @starter_plugins@
strongswan_conf = @strongswan_conf@
sysconfdir = @sysconfdir@
systemdsystemunitdir = @systemdsystemunitdir@
@@ -247,9 +277,10 @@ urandom_device = @urandom_device@
xml_CFLAGS = @xml_CFLAGS@
xml_LIBS = @xml_LIBS@
INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra -I$(top_srcdir)/src/libcharon
-noinst_LTLIBRARIES = libsimaka.la
+ipseclib_LTLIBRARIES = libsimaka.la
libsimaka_la_SOURCES = simaka_message.h simaka_message.c \
- simaka_crypto.h simaka_crypto.c
+ simaka_crypto.h simaka_crypto.c simaka_manager.h simaka_manager.c \
+ simaka_card.h simaka_provider.h simaka_hooks.h
all: all-am
@@ -285,17 +316,39 @@ $(top_srcdir)/configure: $(am__configure_deps)
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
+install-ipseclibLTLIBRARIES: $(ipseclib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(ipseclibdir)" || $(MKDIR_P) "$(DESTDIR)$(ipseclibdir)"
+ @list='$(ipseclib_LTLIBRARIES)'; test -n "$(ipseclibdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(ipseclibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(ipseclibdir)"; \
+ }
+
+uninstall-ipseclibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(ipseclib_LTLIBRARIES)'; test -n "$(ipseclibdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(ipseclibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(ipseclibdir)/$$f"; \
+ done
-clean-noinstLTLIBRARIES:
- -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
- @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+clean-ipseclibLTLIBRARIES:
+ -test -z "$(ipseclib_LTLIBRARIES)" || rm -f $(ipseclib_LTLIBRARIES)
+ @list='$(ipseclib_LTLIBRARIES)'; for p in $$list; do \
dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
test "$$dir" != "$$p" || dir=.; \
echo "rm -f \"$${dir}/so_locations\""; \
rm -f "$${dir}/so_locations"; \
done
libsimaka.la: $(libsimaka_la_OBJECTS) $(libsimaka_la_DEPENDENCIES)
- $(LINK) $(libsimaka_la_OBJECTS) $(libsimaka_la_LIBADD) $(LIBS)
+ $(LINK) -rpath $(ipseclibdir) $(libsimaka_la_OBJECTS) $(libsimaka_la_LIBADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -304,6 +357,7 @@ distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simaka_crypto.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simaka_manager.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simaka_message.Plo@am__quote@
.c.o:
@@ -419,6 +473,9 @@ check-am: all-am
check: check-am
all-am: Makefile $(LTLIBRARIES)
installdirs:
+ for dir in "$(DESTDIR)$(ipseclibdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
@@ -446,7 +503,7 @@ maintainer-clean-generic:
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
-clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+clean-am: clean-generic clean-ipseclibLTLIBRARIES clean-libtool \
mostlyclean-am
distclean: distclean-am
@@ -467,7 +524,7 @@ info: info-am
info-am:
-install-data-am:
+install-data-am: install-ipseclibLTLIBRARIES
install-dvi: install-dvi-am
@@ -513,22 +570,23 @@ ps: ps-am
ps-am:
-uninstall-am:
+uninstall-am: uninstall-ipseclibLTLIBRARIES
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
- clean-libtool clean-noinstLTLIBRARIES ctags distclean \
+ clean-ipseclibLTLIBRARIES clean-libtool ctags distclean \
distclean-compile distclean-generic distclean-libtool \
distclean-tags distdir dvi dvi-am html html-am info info-am \
install install-am install-data install-data-am install-dvi \
install-dvi-am install-exec install-exec-am install-html \
- install-html-am install-info install-info-am install-man \
- install-pdf install-pdf-am install-ps install-ps-am \
- install-strip installcheck installcheck-am installdirs \
- maintainer-clean maintainer-clean-generic mostlyclean \
- mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
- pdf pdf-am ps ps-am tags uninstall uninstall-am
+ install-html-am install-info install-info-am \
+ install-ipseclibLTLIBRARIES install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-ipseclibLTLIBRARIES
# Tell versions [3.59,3.63) of GNU make to not export all variables.
diff --git a/src/libsimaka/simaka_card.h b/src/libsimaka/simaka_card.h
new file mode 100644
index 000000000..52cb32514
--- /dev/null
+++ b/src/libsimaka/simaka_card.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2008-2011 Martin Willi
+ * 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 simaka_card simaka_card
+ * @{ @ingroup libsimaka
+ */
+
+#ifndef SIMAKA_CARD_H_
+#define SIMAKA_CARD_H_
+
+typedef struct simaka_card_t simaka_card_t;
+
+#include "simaka_manager.h"
+
+#include <utils/identification.h>
+
+/**
+ * Interface for a (U)SIM card (used as EAP client).
+ *
+ * The SIM card completes triplets/quintuplets requested in a challenge
+ * received from the server.
+ * An implementation supporting only one of SIM/AKA authentication may
+ * implement the other methods with return_false()/return NOT_SUPPORTED/NULL.
+ */
+struct simaka_card_t {
+
+ /**
+ * Calculate SRES/KC from a RAND for SIM authentication.
+ *
+ * @param id permanent identity to get a triplet for
+ * @param rand RAND input buffer, fixed size 16 bytes
+ * @param sres SRES output buffer, fixed size 4 byte
+ * @param kc KC output buffer, fixed size 8 bytes
+ * @return TRUE if SRES/KC calculated, FALSE on error/wrong identity
+ */
+ bool (*get_triplet)(simaka_card_t *this, identification_t *id,
+ char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN],
+ char kc[SIM_KC_LEN]);
+
+ /**
+ * Calculate CK/IK/RES from RAND/AUTN for AKA authentication.
+ *
+ * If the received sequence number (in autn) is out of sync, INVALID_STATE
+ * is returned.
+ * The RES value is the only one with variable length. Pass a buffer
+ * of at least AKA_RES_MAX, the actual number of bytes is written to the
+ * res_len value. While the standard would allow any bit length between
+ * 32 and 128 bits, we support only full bytes for now.
+ *
+ * @param id permanent identity to request quintuplet for
+ * @param rand random value rand
+ * @param autn authentication token autn
+ * @param ck buffer receiving encryption key ck
+ * @param ik buffer receiving integrity key ik
+ * @param res buffer receiving authentication result res
+ * @param res_len nubmer of bytes written to res buffer
+ * @return SUCCESS, FAILED, or INVALID_STATE if out of sync
+ */
+ status_t (*get_quintuplet)(simaka_card_t *this, identification_t *id,
+ char rand[AKA_RAND_LEN], char autn[AKA_AUTN_LEN],
+ char ck[AKA_CK_LEN], char ik[AKA_IK_LEN],
+ char res[AKA_RES_MAX], int *res_len);
+
+ /**
+ * Calculate AUTS from RAND for AKA resynchronization.
+ *
+ * @param id permanent identity to request quintuplet for
+ * @param rand random value rand
+ * @param auts resynchronization parameter auts
+ * @return TRUE if parameter generated successfully
+ */
+ bool (*resync)(simaka_card_t *this, identification_t *id,
+ char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN]);
+
+ /**
+ * Set the pseudonym to use for next authentication.
+ *
+ * @param id permanent identity of the peer
+ * @param pseudonym pseudonym identity received from the server
+ */
+ void (*set_pseudonym)(simaka_card_t *this, identification_t *id,
+ identification_t *pseudonym);
+
+ /**
+ * Get the pseudonym previously stored via set_pseudonym().
+ *
+ * @param id permanent identity of the peer
+ * @return associated pseudonym identity, NULL if none stored
+ */
+ identification_t* (*get_pseudonym)(simaka_card_t *this, identification_t *id);
+
+ /**
+ * Store parameters to use for the next fast reauthentication.
+ *
+ * @param id permanent identity of the peer
+ * @param next next fast reauthentication identity to use
+ * @param mk master key MK to store for reauthentication
+ * @param counter counter value to store, host order
+ */
+ void (*set_reauth)(simaka_card_t *this, identification_t *id,
+ identification_t *next, char mk[HASH_SIZE_SHA1],
+ u_int16_t counter);
+
+ /**
+ * Retrieve parameters for fast reauthentication stored via set_reauth().
+ *
+ * @param id permanent identity of the peer
+ * @param mk buffer receiving master key MK
+ * @param counter pointer receiving counter value, in host order
+ * @return fast reauthentication identity, NULL if not found
+ */
+ identification_t* (*get_reauth)(simaka_card_t *this, identification_t *id,
+ char mk[HASH_SIZE_SHA1], u_int16_t *counter);
+};
+
+#endif /** SIMAKA_CARD_H_ @}*/
diff --git a/src/libsimaka/simaka_crypto.c b/src/libsimaka/simaka_crypto.c
index b85502012..4819d1b99 100644
--- a/src/libsimaka/simaka_crypto.c
+++ b/src/libsimaka/simaka_crypto.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 Martin Willi
+ * Copyright (C) 2009-2011 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -15,7 +15,9 @@
#include "simaka_crypto.h"
-#include <daemon.h>
+#include "simaka_manager.h"
+
+#include <debug.h>
/** length of the k_encr key */
#define KENCR_LEN 16
@@ -39,6 +41,11 @@ struct private_simaka_crypto_t {
simaka_crypto_t public;
/**
+ * EAP type this crypto is used, SIM or AKA
+ */
+ eap_type_t type;
+
+ /**
* signer to create/verify AT_MAC
*/
signer_t *signer;
@@ -69,35 +76,48 @@ struct private_simaka_crypto_t {
bool derived;
};
-/**
- * Implementation of simaka_crypto_t.get_signer
- */
-static signer_t* get_signer(private_simaka_crypto_t *this)
+METHOD(simaka_crypto_t, get_signer, signer_t*,
+ private_simaka_crypto_t *this)
{
return this->derived ? this->signer : NULL;
}
-/**
- * Implementation of simaka_crypto_t.get_crypter
- */
-static crypter_t* get_crypter(private_simaka_crypto_t *this)
+METHOD(simaka_crypto_t, get_crypter, crypter_t*,
+ private_simaka_crypto_t *this)
{
return this->derived ? this->crypter : NULL;
}
-/**
- * Implementation of simaka_crypto_t.get_rng
- */
-static rng_t* get_rng(private_simaka_crypto_t *this)
+METHOD(simaka_crypto_t, get_rng, rng_t*,
+ private_simaka_crypto_t *this)
{
return this->rng;
}
/**
- * Implementation of simaka_crypto_t.derive_keys_full
+ * Call SIM/AKA key hook
*/
-static chunk_t derive_keys_full(private_simaka_crypto_t *this,
- identification_t *id, chunk_t data, chunk_t *mk)
+static void call_hook(private_simaka_crypto_t *this, chunk_t encr, chunk_t auth)
+{
+ simaka_manager_t *mgr;
+
+ switch (this->type)
+ {
+ case EAP_SIM:
+ mgr = lib->get(lib, "sim-manager");
+ break;
+ case EAP_AKA:
+ mgr = lib->get(lib, "aka-manager");
+ break;
+ default:
+ return;
+ }
+ mgr->key_hook(mgr, encr, auth);
+}
+
+METHOD(simaka_crypto_t, derive_keys_full, chunk_t,
+ private_simaka_crypto_t *this, identification_t *id,
+ chunk_t data, chunk_t *mk)
{
chunk_t str, msk, k_encr, k_auth;
int i;
@@ -106,7 +126,7 @@ static chunk_t derive_keys_full(private_simaka_crypto_t *this,
* For AKA: MK = SHA1(Identity|IK|CK) */
this->hasher->get_hash(this->hasher, id->get_encoding(id), NULL);
this->hasher->allocate_hash(this->hasher, data, mk);
- DBG3(DBG_IKE, "MK %B", mk);
+ DBG3(DBG_LIB, "MK %B", mk);
/* K_encr | K_auth | MSK | EMSK = prf() | prf() | prf() | prf() */
this->prf->set_key(this->prf, *mk);
@@ -119,21 +139,19 @@ static chunk_t derive_keys_full(private_simaka_crypto_t *this,
k_encr = chunk_create(str.ptr, KENCR_LEN);
k_auth = chunk_create(str.ptr + KENCR_LEN, KAUTH_LEN);
msk = chunk_create(str.ptr + KENCR_LEN + KAUTH_LEN, MSK_LEN);
- DBG3(DBG_IKE, "K_encr %B\nK_auth %B\nMSK %B", &k_encr, &k_auth, &msk);
+ DBG3(DBG_LIB, "K_encr %B\nK_auth %B\nMSK %B", &k_encr, &k_auth, &msk);
this->signer->set_key(this->signer, k_auth);
this->crypter->set_key(this->crypter, k_encr);
- charon->sim->key_hook(charon->sim, k_encr, k_auth);
+ call_hook(this, k_encr, k_auth);
this->derived = TRUE;
return chunk_clone(msk);
}
-/**
- * Implementation of simaka_crypto_t.derive_keys_reauth
- */
-static void derive_keys_reauth(private_simaka_crypto_t *this, chunk_t mk)
+METHOD(simaka_crypto_t, derive_keys_reauth, void,
+ private_simaka_crypto_t *this, chunk_t mk)
{
chunk_t str, k_encr, k_auth;
int i;
@@ -147,22 +165,19 @@ static void derive_keys_reauth(private_simaka_crypto_t *this, chunk_t mk)
}
k_encr = chunk_create(str.ptr, KENCR_LEN);
k_auth = chunk_create(str.ptr + KENCR_LEN, KAUTH_LEN);
- DBG3(DBG_IKE, "K_encr %B\nK_auth %B", &k_encr, &k_auth);
+ DBG3(DBG_LIB, "K_encr %B\nK_auth %B", &k_encr, &k_auth);
this->signer->set_key(this->signer, k_auth);
this->crypter->set_key(this->crypter, k_encr);
- charon->sim->key_hook(charon->sim, k_encr, k_auth);
+ call_hook(this, k_encr, k_auth);
this->derived = TRUE;
}
-/**
- * Implementation of simaka_crypto_t.derive_keys_reauth_msk
- */
-static chunk_t derive_keys_reauth_msk(private_simaka_crypto_t *this,
- identification_t *id, chunk_t counter,
- chunk_t nonce_s, chunk_t mk)
+METHOD(simaka_crypto_t, derive_keys_reauth_msk, chunk_t,
+ private_simaka_crypto_t *this, identification_t *id, chunk_t counter,
+ chunk_t nonce_s, chunk_t mk)
{
char xkey[HASH_SIZE_SHA1];
chunk_t str, msk;
@@ -181,23 +196,19 @@ static chunk_t derive_keys_reauth_msk(private_simaka_crypto_t *this,
this->prf->get_bytes(this->prf, chunk_empty, str.ptr + str.len / 2 * i);
}
msk = chunk_create(str.ptr, MSK_LEN);
- DBG3(DBG_IKE, "MSK %B", &msk);
+ DBG3(DBG_LIB, "MSK %B", &msk);
return chunk_clone(msk);
}
-/**
- * Implementation of simaka_crypto_t.clear_keys
- */
-static void clear_keys(private_simaka_crypto_t *this)
+METHOD(simaka_crypto_t, clear_keys, void,
+ private_simaka_crypto_t *this)
{
this->derived = FALSE;
}
-/**
- * Implementation of simaka_crypto_t.destroy.
- */
-static void destroy(private_simaka_crypto_t *this)
+METHOD(simaka_crypto_t, destroy, void,
+ private_simaka_crypto_t *this)
{
DESTROY_IF(this->rng);
DESTROY_IF(this->hasher);
@@ -210,32 +221,35 @@ static void destroy(private_simaka_crypto_t *this)
/**
* See header
*/
-simaka_crypto_t *simaka_crypto_create()
+simaka_crypto_t *simaka_crypto_create(eap_type_t type)
{
- private_simaka_crypto_t *this = malloc_thing(private_simaka_crypto_t);
-
- this->public.get_signer = (signer_t*(*)(simaka_crypto_t*))get_signer;
- this->public.get_crypter = (crypter_t*(*)(simaka_crypto_t*))get_crypter;
- this->public.get_rng = (rng_t*(*)(simaka_crypto_t*))get_rng;
- this->public.derive_keys_full = (chunk_t(*)(simaka_crypto_t*, identification_t *id, chunk_t data, chunk_t *mk))derive_keys_full;
- this->public.derive_keys_reauth = (void(*)(simaka_crypto_t*, chunk_t mk))derive_keys_reauth;
- this->public.derive_keys_reauth_msk = (chunk_t(*)(simaka_crypto_t*, identification_t *id, chunk_t counter, chunk_t nonce_s, chunk_t mk))derive_keys_reauth_msk;
- this->public.clear_keys = (void(*)(simaka_crypto_t*))clear_keys;
- this->public.destroy = (void(*)(simaka_crypto_t*))destroy;
-
- this->derived = FALSE;
- this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
- this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
- this->prf = lib->crypto->create_prf(lib->crypto, PRF_FIPS_SHA1_160);
- this->signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_SHA1_128);
- this->crypter = lib->crypto->create_crypter(lib->crypto, ENCR_AES_CBC, 16);
+ private_simaka_crypto_t *this;
+
+ INIT(this,
+ .public = {
+ .get_signer = _get_signer,
+ .get_crypter = _get_crypter,
+ .get_rng = _get_rng,
+ .derive_keys_full = _derive_keys_full,
+ .derive_keys_reauth = _derive_keys_reauth,
+ .derive_keys_reauth_msk = _derive_keys_reauth_msk,
+ .clear_keys = _clear_keys,
+ .destroy = _destroy,
+ },
+ .type = type,
+ .rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK),
+ .hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1),
+ .prf = lib->crypto->create_prf(lib->crypto, PRF_FIPS_SHA1_160),
+ .signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_SHA1_128),
+ .crypter = lib->crypto->create_crypter(lib->crypto, ENCR_AES_CBC, 16),
+ );
if (!this->rng || !this->hasher || !this->prf ||
!this->signer || !this->crypter)
{
- DBG1(DBG_IKE, "unable to use EAP-SIM, missing algorithms");
+ DBG1(DBG_LIB, "unable to use %N, missing algorithms",
+ eap_type_names, type);
destroy(this);
return NULL;
}
return &this->public;
}
-
diff --git a/src/libsimaka/simaka_hooks.h b/src/libsimaka/simaka_hooks.h
new file mode 100644
index 000000000..ffe1c25b6
--- /dev/null
+++ b/src/libsimaka/simaka_hooks.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2008-2011 Martin Willi
+ * 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 simaka_hooks simaka_hooks
+ * @{ @ingroup libsimaka
+ */
+
+#ifndef SIMAKA_HOOKS_H_
+#define SIMAKA_HOOKS_H_
+
+typedef struct simaka_hooks_t simaka_hooks_t;
+
+#include "simaka_message.h"
+
+/**
+ * Additional hooks invoked during EAP-SIM/AKA message processing.
+ */
+struct simaka_hooks_t {
+
+ /**
+ * SIM/AKA message parsing.
+ *
+ * As a SIM/AKA optionally contains encrypted attributes, the hook
+ * might get invoked twice, once before and once after decryption.
+ *
+ * @param message SIM/AKA message
+ * @param inbound TRUE for incoming messages, FALSE for outgoing
+ * @param decrypted TRUE if AT_ENCR_DATA has been decrypted
+ */
+ void (*message)(simaka_hooks_t *this, simaka_message_t *message,
+ bool inbound, bool decrypted);
+
+ /**
+ * SIM/AKA encryption/authentication key hooks.
+ *
+ * @param k_encr derived SIM/AKA encryption key k_encr
+ * @param k_auth derived SIM/AKA authentication key k_auth
+ */
+ void (*keys)(simaka_hooks_t *this, chunk_t k_encr, chunk_t k_auth);
+};
+
+#endif /** SIMAKA_HOOKS_H_ @}*/
diff --git a/src/libsimaka/simaka_manager.c b/src/libsimaka/simaka_manager.c
new file mode 100644
index 000000000..65de1c5ab
--- /dev/null
+++ b/src/libsimaka/simaka_manager.c
@@ -0,0 +1,626 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * 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 "simaka_manager.h"
+
+#include <debug.h>
+#include <utils/linked_list.h>
+#include <threading/rwlock.h>
+
+typedef struct private_simaka_manager_t private_simaka_manager_t;
+
+/**
+ * Private data of an simaka_manager_t object.
+ */
+struct private_simaka_manager_t {
+
+ /**
+ * Public simaka_manager_t interface.
+ */
+ simaka_manager_t public;
+
+ /**
+ * list of added cards
+ */
+ linked_list_t *cards;
+
+ /**
+ * list of added provider
+ */
+ linked_list_t *providers;
+
+ /**
+ * list of added hooks
+ */
+ linked_list_t *hooks;
+
+ /**
+ * lock for lists above
+ */
+ rwlock_t *lock;
+};
+
+/**
+ * Described in header.
+ */
+void libsimaka_init(void)
+{
+ /* empty */
+}
+
+METHOD(simaka_manager_t, add_card, void,
+ private_simaka_manager_t *this, simaka_card_t *card)
+{
+ this->lock->write_lock(this->lock);
+ this->cards->insert_last(this->cards, card);
+ this->lock->unlock(this->lock);
+}
+
+METHOD(simaka_manager_t, remove_card, void,
+ private_simaka_manager_t *this, simaka_card_t *card)
+{
+ this->lock->write_lock(this->lock);
+ this->cards->remove(this->cards, card, NULL);
+ this->lock->unlock(this->lock);
+}
+
+METHOD(simaka_manager_t, card_get_triplet, bool,
+ private_simaka_manager_t *this, identification_t *id,
+ char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN], char kc[SIM_KC_LEN])
+{
+ enumerator_t *enumerator;
+ simaka_card_t *card;
+ int tried = 0;
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->cards->create_enumerator(this->cards);
+ while (enumerator->enumerate(enumerator, &card))
+ {
+ if (card->get_triplet(card, id, rand, sres, kc))
+ {
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ return TRUE;
+ }
+ tried++;
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ DBG1(DBG_LIB, "tried %d SIM cards, but none has triplets for '%Y'",
+ tried, id);
+ return FALSE;
+}
+
+METHOD(simaka_manager_t, card_get_quintuplet, status_t,
+ private_simaka_manager_t *this, identification_t *id, char rand[AKA_RAND_LEN],
+ char autn[AKA_AUTN_LEN], char ck[AKA_CK_LEN], char ik[AKA_IK_LEN],
+ char res[AKA_RES_MAX], int *res_len)
+{
+ enumerator_t *enumerator;
+ simaka_card_t *card;
+ status_t status = NOT_FOUND;
+ int tried = 0;
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->cards->create_enumerator(this->cards);
+ while (enumerator->enumerate(enumerator, &card))
+ {
+ status = card->get_quintuplet(card, id, rand, autn, ck, ik, res, res_len);
+ switch (status)
+ { /* try next on error, but not on INVALID_STATE */
+ case SUCCESS:
+ case INVALID_STATE:
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ return status;
+ case NOT_SUPPORTED:
+ case FAILED:
+ default:
+ tried++;
+ continue;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ DBG1(DBG_LIB, "tried %d SIM cards, but none has quintuplets for '%Y'",
+ tried, id);
+ return status;
+}
+
+METHOD(simaka_manager_t, card_resync, bool,
+ private_simaka_manager_t *this, identification_t *id,
+ char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN])
+{
+ enumerator_t *enumerator;
+ simaka_card_t *card;
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->cards->create_enumerator(this->cards);
+ while (enumerator->enumerate(enumerator, &card))
+ {
+ if (card->resync(card, id, rand, auts))
+ {
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ return TRUE;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ return FALSE;
+}
+
+METHOD(simaka_manager_t, card_set_pseudonym, void,
+ private_simaka_manager_t *this, identification_t *id,
+ identification_t *pseudonym)
+{
+ enumerator_t *enumerator;
+ simaka_card_t *card;
+
+ DBG1(DBG_LIB, "storing pseudonym '%Y' for '%Y'", pseudonym, id);
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->cards->create_enumerator(this->cards);
+ while (enumerator->enumerate(enumerator, &card))
+ {
+ card->set_pseudonym(card, id, pseudonym);
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+}
+
+METHOD(simaka_manager_t, card_get_pseudonym, identification_t*,
+ private_simaka_manager_t *this, identification_t *id)
+{
+ enumerator_t *enumerator;
+ simaka_card_t *card;
+ identification_t *pseudonym = NULL;
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->cards->create_enumerator(this->cards);
+ while (enumerator->enumerate(enumerator, &card))
+ {
+ pseudonym = card->get_pseudonym(card, id);
+ if (pseudonym)
+ {
+ DBG1(DBG_LIB, "using stored pseudonym identity '%Y' "
+ "instead of '%Y'", pseudonym, id);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ return pseudonym;
+}
+
+METHOD(simaka_manager_t, card_set_reauth, void,
+ private_simaka_manager_t *this, identification_t *id, identification_t *next,
+ char mk[HASH_SIZE_SHA1], u_int16_t counter)
+{
+ enumerator_t *enumerator;
+ simaka_card_t *card;
+
+ DBG1(DBG_LIB, "storing next reauthentication identity '%Y' for '%Y'",
+ next, id);
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->cards->create_enumerator(this->cards);
+ while (enumerator->enumerate(enumerator, &card))
+ {
+ card->set_reauth(card, id, next, mk, counter);
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+}
+
+METHOD(simaka_manager_t, card_get_reauth, identification_t*,
+ private_simaka_manager_t *this, identification_t *id, char mk[HASH_SIZE_SHA1],
+ u_int16_t *counter)
+{
+ enumerator_t *enumerator;
+ simaka_card_t *card;
+ identification_t *reauth = NULL;
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->cards->create_enumerator(this->cards);
+ while (enumerator->enumerate(enumerator, &card))
+ {
+ reauth = card->get_reauth(card, id, mk, counter);
+ if (reauth)
+ {
+ DBG1(DBG_LIB, "using stored reauthentication identity '%Y' "
+ "instead of '%Y'", reauth, id);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ return reauth;
+}
+
+METHOD(simaka_manager_t, add_provider, void,
+ private_simaka_manager_t *this, simaka_provider_t *provider)
+{
+ this->lock->write_lock(this->lock);
+ this->providers->insert_last(this->providers, provider);
+ this->lock->unlock(this->lock);
+}
+
+METHOD(simaka_manager_t, remove_provider, void,
+ private_simaka_manager_t *this, simaka_provider_t *provider)
+{
+ this->lock->write_lock(this->lock);
+ this->providers->remove(this->providers, provider, NULL);
+ this->lock->unlock(this->lock);
+}
+
+METHOD(simaka_manager_t, provider_get_triplet, bool,
+ private_simaka_manager_t *this, identification_t *id,
+ char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN], char kc[SIM_KC_LEN])
+{
+ enumerator_t *enumerator;
+ simaka_provider_t *provider;
+ int tried = 0;
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->providers->create_enumerator(this->providers);
+ while (enumerator->enumerate(enumerator, &provider))
+ {
+ if (provider->get_triplet(provider, id, rand, sres, kc))
+ {
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ return TRUE;
+ }
+ tried++;
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ DBG1(DBG_LIB, "tried %d SIM providers, but none had a triplet for '%Y'",
+ tried, id);
+ return FALSE;
+}
+
+METHOD(simaka_manager_t, provider_get_quintuplet, bool,
+ private_simaka_manager_t *this, identification_t *id,
+ char rand[AKA_RAND_LEN], char xres[AKA_RES_MAX], int *xres_len,
+ char ck[AKA_CK_LEN], char ik[AKA_IK_LEN], char autn[AKA_AUTN_LEN])
+{
+ enumerator_t *enumerator;
+ simaka_provider_t *provider;
+ int tried = 0;
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->providers->create_enumerator(this->providers);
+ while (enumerator->enumerate(enumerator, &provider))
+ {
+ if (provider->get_quintuplet(provider, id, rand, xres, xres_len,
+ ck, ik, autn))
+ {
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ return TRUE;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ DBG1(DBG_LIB, "tried %d SIM providers, but none had a quintuplet for '%Y'",
+ tried, id);
+ return FALSE;
+}
+
+METHOD(simaka_manager_t, provider_resync, bool,
+ private_simaka_manager_t *this, identification_t *id,
+ char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN])
+{
+ enumerator_t *enumerator;
+ simaka_provider_t *provider;
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->providers->create_enumerator(this->providers);
+ while (enumerator->enumerate(enumerator, &provider))
+ {
+ if (provider->resync(provider, id, rand, auts))
+ {
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ return TRUE;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ return FALSE;
+}
+
+METHOD(simaka_manager_t, provider_is_pseudonym, identification_t*,
+ private_simaka_manager_t *this, identification_t *id)
+{
+ enumerator_t *enumerator;
+ simaka_provider_t *provider;
+ identification_t *permanent = NULL;
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->providers->create_enumerator(this->providers);
+ while (enumerator->enumerate(enumerator, &provider))
+ {
+ permanent = provider->is_pseudonym(provider, id);
+ if (permanent)
+ {
+ DBG1(DBG_LIB, "received pseudonym identity '%Y' "
+ "mapping to '%Y'", id, permanent);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ return permanent;
+}
+
+METHOD(simaka_manager_t, provider_gen_pseudonym, identification_t*,
+ private_simaka_manager_t *this, identification_t *id)
+{
+ enumerator_t *enumerator;
+ simaka_provider_t *provider;
+ identification_t *pseudonym = NULL;
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->providers->create_enumerator(this->providers);
+ while (enumerator->enumerate(enumerator, &provider))
+ {
+ pseudonym = provider->gen_pseudonym(provider, id);
+ if (pseudonym)
+ {
+ DBG1(DBG_LIB, "proposing new pseudonym '%Y'", pseudonym);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ return pseudonym;
+}
+
+METHOD(simaka_manager_t, provider_is_reauth, identification_t*,
+ private_simaka_manager_t *this, identification_t *id, char mk[HASH_SIZE_SHA1],
+ u_int16_t *counter)
+{
+ enumerator_t *enumerator;
+ simaka_provider_t *provider;
+ identification_t *permanent = NULL;
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->providers->create_enumerator(this->providers);
+ while (enumerator->enumerate(enumerator, &provider))
+ {
+ permanent = provider->is_reauth(provider, id, mk, counter);
+ if (permanent)
+ {
+ DBG1(DBG_LIB, "received reauthentication identity '%Y' "
+ "mapping to '%Y'", id, permanent);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ return permanent;
+}
+
+METHOD(simaka_manager_t, provider_gen_reauth, identification_t*,
+ private_simaka_manager_t *this, identification_t *id, char mk[HASH_SIZE_SHA1])
+{
+ enumerator_t *enumerator;
+ simaka_provider_t *provider;
+ identification_t *reauth = NULL;
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->providers->create_enumerator(this->providers);
+ while (enumerator->enumerate(enumerator, &provider))
+ {
+ reauth = provider->gen_reauth(provider, id, mk);
+ if (reauth)
+ {
+ DBG1(DBG_LIB, "proposing new reauthentication identity '%Y'", reauth);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ return reauth;
+}
+
+METHOD(simaka_manager_t, add_hooks, void,
+ private_simaka_manager_t *this, simaka_hooks_t *hooks)
+{
+ this->lock->write_lock(this->lock);
+ this->hooks->insert_last(this->hooks, hooks);
+ this->lock->unlock(this->lock);
+}
+
+METHOD(simaka_manager_t, remove_hooks, void,
+ private_simaka_manager_t *this, simaka_hooks_t *hooks)
+{
+ this->lock->write_lock(this->lock);
+ this->hooks->remove(this->hooks, hooks, NULL);
+ this->lock->unlock(this->lock);
+}
+
+METHOD(simaka_manager_t, message_hook, void,
+ private_simaka_manager_t *this, simaka_message_t *message,
+ bool inbound, bool decrypted)
+{
+ enumerator_t *enumerator;
+ simaka_hooks_t *hooks;
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->hooks->create_enumerator(this->hooks);
+ while (enumerator->enumerate(enumerator, &hooks))
+ {
+ hooks->message(hooks, message, inbound, decrypted);
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+}
+
+METHOD(simaka_manager_t, key_hook, void,
+ private_simaka_manager_t *this, chunk_t k_encr, chunk_t k_auth)
+{
+ enumerator_t *enumerator;
+ simaka_hooks_t *hooks;
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->hooks->create_enumerator(this->hooks);
+ while (enumerator->enumerate(enumerator, &hooks))
+ {
+ hooks->keys(hooks, k_encr, k_auth);
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+}
+
+METHOD(simaka_manager_t, destroy, void,
+ private_simaka_manager_t *this)
+{
+ this->cards->destroy(this->cards);
+ this->providers->destroy(this->providers);
+ this->hooks->destroy(this->hooks);
+ this->lock->destroy(this->lock);
+ free(this);
+}
+
+/**
+ * See header
+ */
+simaka_manager_t *simaka_manager_create()
+{
+ private_simaka_manager_t *this;
+
+ INIT(this,
+ .public = {
+ .add_card = _add_card,
+ .remove_card = _remove_card,
+ .card_get_triplet = _card_get_triplet,
+ .card_get_quintuplet = _card_get_quintuplet,
+ .card_resync = _card_resync,
+ .card_set_pseudonym = _card_set_pseudonym,
+ .card_get_pseudonym = _card_get_pseudonym,
+ .card_set_reauth = _card_set_reauth,
+ .card_get_reauth = _card_get_reauth,
+ .add_provider = _add_provider,
+ .remove_provider = _remove_provider,
+ .provider_get_triplet = _provider_get_triplet,
+ .provider_get_quintuplet = _provider_get_quintuplet,
+ .provider_resync = _provider_resync,
+ .provider_is_pseudonym = _provider_is_pseudonym,
+ .provider_gen_pseudonym = _provider_gen_pseudonym,
+ .provider_is_reauth = _provider_is_reauth,
+ .provider_gen_reauth = _provider_gen_reauth,
+ .add_hooks = _add_hooks,
+ .remove_hooks = _remove_hooks,
+ .message_hook = _message_hook,
+ .key_hook = _key_hook,
+ .destroy = _destroy,
+ },
+ .cards = linked_list_create(),
+ .providers = linked_list_create(),
+ .hooks = linked_list_create(),
+ .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+ );
+
+ return &this->public;
+}
+
+/**
+ * (Un-)register a provider to a simaka manager
+ */
+static bool register_card(char *mgr_name, bool reg, simaka_card_t *card)
+{
+ simaka_manager_t *mgr;
+
+ if (!card)
+ {
+ return FALSE;
+ }
+ mgr = lib->get(lib, mgr_name);
+ if (mgr)
+ {
+ if (reg)
+ {
+ mgr->add_card(mgr, card);
+ }
+ else
+ {
+ mgr->remove_card(mgr, card);
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * (Un-)register a provider to a simaka manager
+ */
+static bool register_provider(char *mgr_name, bool reg,
+ simaka_provider_t *provider)
+{
+ simaka_manager_t *mgr;
+
+ if (!provider)
+ {
+ return FALSE;
+ }
+ mgr = lib->get(lib, mgr_name);
+ if (mgr)
+ {
+ if (reg)
+ {
+ mgr->add_provider(mgr, provider);
+ }
+ else
+ {
+ mgr->remove_provider(mgr, provider);
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * See header
+ */
+bool simaka_manager_register(plugin_t *plugin, plugin_feature_t *feature,
+ bool reg, void *data)
+{
+ simaka_manager_register_cb_t get = (simaka_manager_register_cb_t)data;
+
+ if (feature->type == FEATURE_CUSTOM)
+ {
+ if (streq(feature->arg.custom, "aka-card"))
+ {
+ return register_card("aka-manager", reg, get(plugin));
+ }
+ else if (streq(feature->arg.custom, "aka-provider"))
+ {
+ return register_provider("aka-manager", reg, get(plugin));
+ }
+ else if (streq(feature->arg.custom, "sim-card"))
+ {
+ return register_card("sim-manager", reg, get(plugin));
+ }
+ else if (streq(feature->arg.custom, "sim-provider"))
+ {
+ return register_provider("sim-manager", reg, get(plugin));
+ }
+ }
+ return FALSE;
+}
diff --git a/src/libsimaka/simaka_manager.h b/src/libsimaka/simaka_manager.h
new file mode 100644
index 000000000..64a67e56c
--- /dev/null
+++ b/src/libsimaka/simaka_manager.h
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2008-2011 Martin Willi
+ * 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 simaka_manager simaka_manager
+ * @{ @ingroup libsimaka
+ */
+
+#ifndef SIMAKA_MANAGER_H_
+#define SIMAKA_MANAGER_H_
+
+#include <crypto/hashers/hasher.h>
+#include <utils/identification.h>
+#include <utils/enumerator.h>
+#include <plugins/plugin.h>
+
+typedef struct simaka_manager_t simaka_manager_t;
+
+#define SIM_RAND_LEN 16
+#define SIM_SRES_LEN 4
+#define SIM_KC_LEN 8
+
+#define AKA_RAND_LEN 16
+#define AKA_RES_MAX 16
+#define AKA_CK_LEN 16
+#define AKA_IK_LEN 16
+#define AKA_AUTN_LEN 16
+#define AKA_AUTS_LEN 14
+
+#include "simaka_card.h"
+#include "simaka_provider.h"
+#include "simaka_hooks.h"
+
+/**
+ * The SIM manager handles multiple (U)SIM cards/providers and hooks.
+ */
+struct simaka_manager_t {
+
+ /**
+ * Register a SIM card (client) at the manager.
+ *
+ * @param card sim card to register
+ */
+ void (*add_card)(simaka_manager_t *this, simaka_card_t *card);
+
+ /**
+ * Unregister a previously registered card from the manager.
+ *
+ * @param card sim card to unregister
+ */
+ void (*remove_card)(simaka_manager_t *this, simaka_card_t *card);
+
+ /**
+ * Calculate SIM triplets on one of the registered SIM cards.
+ *
+ * @param id permanent identity to get a triplet for
+ * @param rand RAND input buffer, fixed size 16 bytes
+ * @param sres SRES output buffer, fixed size 4 byte
+ * @param kc KC output buffer, fixed size 8 bytes
+ * @return TRUE if calculated, FALSE if no matching card found
+ */
+ bool (*card_get_triplet)(simaka_manager_t *this, identification_t *id,
+ char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN],
+ char kc[SIM_KC_LEN]);
+
+ /**
+ * Calculate AKA quitpulets on one of the registered SIM cards.
+ *
+ * @param id permanent identity to request quintuplet for
+ * @param rand random value rand
+ * @param autn authentication token autn
+ * @param ck buffer receiving encryption key ck
+ * @param ik buffer receiving integrity key ik
+ * @param res buffer receiving authentication result res
+ * @param res_len nubmer of bytes written to res buffer
+ * @return SUCCESS, FAILED, or INVALID_STATE if out of sync
+ */
+ status_t (*card_get_quintuplet)(simaka_manager_t *this, identification_t *id,
+ char rand[AKA_RAND_LEN], char autn[AKA_AUTN_LEN],
+ char ck[AKA_CK_LEN], char ik[AKA_IK_LEN],
+ char res[AKA_RES_MAX], int *res_len);
+
+ /**
+ * Calculate resynchronization data on one of the registered SIM cards.
+ *
+ * @param id permanent identity to request quintuplet for
+ * @param rand random value rand
+ * @param auts resynchronization parameter auts
+ * @return TRUE if calculated, FALSE if no matcing card found
+ */
+ bool (*card_resync)(simaka_manager_t *this, identification_t *id,
+ char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN]);
+
+ /**
+ * Store a received pseudonym on one of the registered SIM cards.
+ *
+ * @param id permanent identity of the peer
+ * @param pseudonym pseudonym identity received from the server
+ */
+ void (*card_set_pseudonym)(simaka_manager_t *this, identification_t *id,
+ identification_t *pseudonym);
+
+ /**
+ * Get a stored pseudonym from one of the registered SIM cards.
+ *
+ * @param id permanent identity of the peer
+ * @return associated pseudonym identity, NULL if none found
+ */
+ identification_t* (*card_get_pseudonym)(simaka_manager_t *this,
+ identification_t *id);
+
+ /**
+ * Store fast reauthentication parameters on one of the registered cards.
+ *
+ * @param id permanent identity of the peer
+ * @param next next fast reauthentication identity to use
+ * @param mk master key MK to store for reauthentication
+ * @param counter counter value to store, host order
+ */
+ void (*card_set_reauth)(simaka_manager_t *this, identification_t *id,
+ identification_t *next, char mk[HASH_SIZE_SHA1],
+ u_int16_t counter);
+
+ /**
+ * Retrieve fast reauthentication parameters from one of the registered cards.
+ *
+ * @param id permanent identity of the peer
+ * @param mk buffer receiving master key MK
+ * @param counter pointer receiving counter value, in host order
+ * @return fast reauthentication identity, NULL if none found
+ */
+ identification_t* (*card_get_reauth)(simaka_manager_t *this,
+ identification_t *id, char mk[HASH_SIZE_SHA1],
+ u_int16_t *counter);
+
+ /**
+ * Register a triplet provider (server) at the manager.
+ *
+ * @param card sim card to register
+ */
+ void (*add_provider)(simaka_manager_t *this, simaka_provider_t *provider);
+
+ /**
+ * Unregister a previously registered provider from the manager.
+ *
+ * @param card sim card to unregister
+ */
+ void (*remove_provider)(simaka_manager_t *this, simaka_provider_t *provider);
+
+ /**
+ * Get a SIM triplet from one of the registered providers.
+ *
+ * @param id permanent identity of peer to gen triplet for
+ * @param rand RAND output buffer, fixed size 16 bytes
+ * @param sres SRES output buffer, fixed size 4 byte
+ * @param kc KC output buffer, fixed size 8 bytes
+ * @return TRUE if triplet received, FALSE if no match found
+ */
+ bool (*provider_get_triplet)(simaka_manager_t *this, identification_t *id,
+ char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN],
+ char kc[SIM_KC_LEN]);
+
+ /**
+ * Get a AKA quintuplet from one of the registered providers.
+ *
+ * @param id permanent identity of peer to create challenge for
+ * @param rand buffer receiving random value rand
+ * @param xres buffer receiving expected authentication result xres
+ * @param ck buffer receiving encryption key ck
+ * @param ik buffer receiving integrity key ik
+ * @param autn authentication token autn
+ * @return TRUE if quintuplet received, FALSE if no match found
+ */
+ bool (*provider_get_quintuplet)(simaka_manager_t *this, identification_t *id,
+ char rand[AKA_RAND_LEN],
+ char xres[AKA_RES_MAX], int *xres_len,
+ char ck[AKA_CK_LEN], char ik[AKA_IK_LEN],
+ char autn[AKA_AUTN_LEN]);
+
+ /**
+ * Pass AKA resynchronization data to one of the registered providers.
+ *
+ * @param id permanent identity of peer requesting resynchronisation
+ * @param rand random value rand
+ * @param auts synchronization parameter auts
+ * @return TRUE if resynchronized, FALSE if not handled
+ */
+ bool (*provider_resync)(simaka_manager_t *this, identification_t *id,
+ char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN]);
+
+ /**
+ * Check if a peer uses a pseudonym using one of the registered providers.
+ *
+ * @param id pseudonym identity candidate
+ * @return permanent identity, NULL if id not a pseudonym
+ */
+ identification_t* (*provider_is_pseudonym)(simaka_manager_t *this,
+ identification_t *id);
+
+ /**
+ * Generate a new pseudonym using one of the registered providers.
+ *
+ * @param id permanent identity to generate a pseudonym for
+ * @return generated pseudonym, NULL to not use a pseudonym identity
+ */
+ identification_t* (*provider_gen_pseudonym)(simaka_manager_t *this,
+ identification_t *id);
+
+ /**
+ * Check if a peer uses a reauth id using one of the registered providers.
+ *
+ * @param id reauthentication identity (candidate)
+ * @param mk buffer receiving master key MK
+ * @param counter pointer receiving current counter value, host order
+ * @return permanent identity, NULL if not a known reauth identity
+ */
+ identification_t* (*provider_is_reauth)(simaka_manager_t *this,
+ identification_t *id, char mk[HASH_SIZE_SHA1],
+ u_int16_t *counter);
+
+ /**
+ * Generate a fast reauth id using one of the registered providers.
+ *
+ * @param id permanent peer identity
+ * @param mk master key to store along with generated identity
+ * @return fast reauthentication identity, NULL to not use reauth
+ */
+ identification_t* (*provider_gen_reauth)(simaka_manager_t *this,
+ identification_t *id, char mk[HASH_SIZE_SHA1]);
+
+ /**
+ * Register a set of hooks to the manager.
+ *
+ * @param hooks hook interface implementation to register
+ */
+ void (*add_hooks)(simaka_manager_t *this, simaka_hooks_t *hooks);
+
+ /**
+ * Unregister a set of hooks from the manager.
+ *
+ * @param hooks hook interface implementation to unregister
+ */
+ void (*remove_hooks)(simaka_manager_t *this, simaka_hooks_t *hooks);
+
+ /**
+ * Invoke SIM/AKA message hook.
+ *
+ * @param message SIM message
+ * @param inbound TRUE for incoming messages, FALSE for outgoing
+ * @param decrypted TRUE if AT_ENCR_DATA has been decrypted
+ */
+ void (*message_hook)(simaka_manager_t *this, simaka_message_t *message,
+ bool inbound, bool decrypted);
+
+ /**
+ * Invoke SIM/AKA key hook.
+ *
+ * @param k_encr SIM/AKA encryption key k_encr
+ * @param k_auth SIM/AKA authentication key k_auth
+ */
+ void (*key_hook)(simaka_manager_t *this, chunk_t k_encr, chunk_t k_auth);
+
+ /**
+ * Destroy a manager instance.
+ */
+ void (*destroy)(simaka_manager_t *this);
+};
+
+/**
+ * Dummy libsimaka initialization function needed for integrity test
+ */
+void libsimaka_init(void);
+
+/**
+ * Create an SIM/AKA manager to handle multiple (U)SIM cards/providers.
+ *
+ * @return simaka_t object
+ */
+simaka_manager_t *simaka_manager_create();
+
+/**
+ * Callback for the simaka_manager_register_cb_t, provides backend to register.
+ *
+ * @param plugin plugin registering a backend (card or provider)
+ * @return a simaka_card_t* or simaka_provider_t*, NULL on failure
+ */
+typedef void* (*simaka_manager_register_cb_t)(plugin_t *plugin);
+
+/**
+ * Helper function to (un-)register SIM/AKA backend plugin features.
+ *
+ * This function is a plugin_feature_callback_t and can be used with the
+ * PLUGIN_CALLBACK macro to register a SIM/AKA backend.
+ *
+ * @param plugin plugin registering the SIM/AKA backend
+ * @param feature associated plugin feature
+ * @param reg TRUE to register, FALSE to unregister.
+ * @param data data passed to callback, an simaka_manager_register_cb_t
+ */
+bool simaka_manager_register(plugin_t *plugin, plugin_feature_t *feature,
+ bool reg, void *data);
+
+#endif /** SIMAKA_MANAGER_H_ @}*/
diff --git a/src/libsimaka/simaka_message.c b/src/libsimaka/simaka_message.c
index 3a8f4beaf..a5754b985 100644
--- a/src/libsimaka/simaka_message.c
+++ b/src/libsimaka/simaka_message.c
@@ -15,6 +15,11 @@
#include "simaka_message.h"
+#include "simaka_manager.h"
+
+#include <debug.h>
+#include <utils/linked_list.h>
+
typedef struct private_simaka_message_t private_simaka_message_t;
typedef struct hdr_t hdr_t;
typedef struct attr_hdr_t attr_hdr_t;
@@ -134,9 +139,9 @@ ENUM(simaka_client_error_names, SIM_UNABLE_TO_PROCESS, SIM_RANDS_NOT_FRESH,
*/
bool simaka_attribute_skippable(simaka_attribute_t attribute)
{
- bool skippable = !(attribute >= 0 && attribute <= 127);
+ bool skippable = !((int)attribute >= 0 && attribute <= 127);
- DBG1(DBG_IKE, "%sskippable EAP-SIM/AKA attribute %N",
+ DBG1(DBG_LIB, "%sskippable EAP-SIM/AKA attribute %N",
skippable ? "ignoring " : "found non-",
simaka_attribute_names, attribute);
return skippable;
@@ -193,34 +198,26 @@ struct private_simaka_message_t {
chunk_t iv;
};
-/**
- * Implementation of simaka_message_t.is_request
- */
-static bool is_request(private_simaka_message_t *this)
+METHOD(simaka_message_t, is_request, bool,
+ private_simaka_message_t *this)
{
return this->hdr->code == EAP_REQUEST;
}
-/**
- * Implementation of simaka_message_t.get_identifier
- */
-static u_int8_t get_identifier(private_simaka_message_t *this)
+METHOD(simaka_message_t, get_identifier, u_int8_t,
+ private_simaka_message_t *this)
{
return this->hdr->identifier;
}
-/**
- * Implementation of simaka_message_t.get_subtype
- */
-static simaka_subtype_t get_subtype(private_simaka_message_t *this)
+METHOD(simaka_message_t, get_subtype, simaka_subtype_t,
+ private_simaka_message_t *this)
{
return this->hdr->subtype;
}
-/**
- * Implementation of simaka_message_t.get_type
- */
-static eap_type_t get_type(private_simaka_message_t *this)
+METHOD(simaka_message_t, get_type, eap_type_t,
+ private_simaka_message_t *this)
{
return this->hdr->type;
}
@@ -238,21 +235,16 @@ static bool attr_enum_filter(void *null, attr_t **in, simaka_attribute_t *type,
return TRUE;
}
-/**
- * Implementation of simaka_message_t.create_attribute_enumerator
- */
-static enumerator_t* create_attribute_enumerator(private_simaka_message_t *this)
+METHOD(simaka_message_t, create_attribute_enumerator, enumerator_t*,
+ private_simaka_message_t *this)
{
return enumerator_create_filter(
this->attributes->create_enumerator(this->attributes),
(void*)attr_enum_filter, NULL, NULL);
}
-/**
- * Implementation of simaka_message_t.add_attribute
- */
-static void add_attribute(private_simaka_message_t *this,
- simaka_attribute_t type, chunk_t data)
+METHOD(simaka_message_t, add_attribute, void,
+ private_simaka_message_t *this, simaka_attribute_t type, chunk_t data)
{
attr_t *attr;
@@ -269,7 +261,7 @@ static void add_attribute(private_simaka_message_t *this,
*/
static bool not_encrypted(simaka_attribute_t type)
{
- DBG1(DBG_IKE, "received unencrypted %N", simaka_attribute_names, type);
+ DBG1(DBG_LIB, "received unencrypted %N", simaka_attribute_names, type);
return FALSE;
}
@@ -278,11 +270,33 @@ static bool not_encrypted(simaka_attribute_t type)
*/
static bool invalid_length(simaka_attribute_t type)
{
- DBG1(DBG_IKE, "invalid length of %N", simaka_attribute_names, type);
+ DBG1(DBG_LIB, "invalid length of %N", simaka_attribute_names, type);
return FALSE;
}
/**
+ * Call SIM/AKA message hooks
+ */
+static void call_hook(private_simaka_message_t *this,
+ bool inbound, bool decrypted)
+{
+ simaka_manager_t *mgr;
+
+ switch (this->hdr->type)
+ {
+ case EAP_SIM:
+ mgr = lib->get(lib, "sim-manager");
+ break;
+ case EAP_AKA:
+ mgr = lib->get(lib, "aka-manager");
+ break;
+ default:
+ return;
+ }
+ mgr->message_hook(mgr, &this->public, inbound, decrypted);
+}
+
+/**
* Parse attributes from a chunk of data
*/
static bool parse_attributes(private_simaka_message_t *this, chunk_t in)
@@ -294,7 +308,7 @@ static bool parse_attributes(private_simaka_message_t *this, chunk_t in)
if (in.len < sizeof(attr_hdr_t))
{
- DBG1(DBG_IKE, "found short %N attribute header",
+ DBG1(DBG_LIB, "found short %N attribute header",
eap_type_names, this->hdr->type);
return FALSE;
}
@@ -450,7 +464,7 @@ static bool parse_attributes(private_simaka_message_t *this, chunk_t in)
}
else if (!this->encrypted)
{
- DBG1(DBG_IKE, "found P-bit 0 notify in unencrypted message");
+ DBG1(DBG_LIB, "found P-bit 0 notify in unencrypted message");
return FALSE;
}
/* FALL */
@@ -460,7 +474,7 @@ static bool parse_attributes(private_simaka_message_t *this, chunk_t in)
}
}
- charon->sim->message_hook(charon->sim, &this->public, TRUE, this->encrypted);
+ call_hook(this, TRUE, this->encrypted);
return TRUE;
}
@@ -481,7 +495,7 @@ static bool decrypt(private_simaka_message_t *this)
}
if (this->encr.len % crypter->get_block_size(crypter))
{
- DBG1(DBG_IKE, "%N ENCR_DATA not a multiple of block size",
+ DBG1(DBG_LIB, "%N ENCR_DATA not a multiple of block size",
eap_type_names, this->hdr->type);
return FALSE;
}
@@ -495,10 +509,8 @@ static bool decrypt(private_simaka_message_t *this)
return success;
}
-/**
- * Implementation of simaka_message_t.parse
- */
-static bool parse(private_simaka_message_t *this)
+METHOD(simaka_message_t, parse, bool,
+ private_simaka_message_t *this)
{
chunk_t in;
@@ -516,10 +528,8 @@ static bool parse(private_simaka_message_t *this)
return decrypt(this);
}
-/**
- * Implementation of simaka_message_t.verify
- */
-static bool verify(private_simaka_message_t *this, chunk_t sigdata)
+METHOD(simaka_message_t, verify, bool,
+ private_simaka_message_t *this, chunk_t sigdata)
{
chunk_t data, backup;
signer_t *signer;
@@ -543,7 +553,7 @@ static bool verify(private_simaka_message_t *this, chunk_t sigdata)
{
if (!this->mac.ptr || !signer)
{ /* require MAC, but not found */
- DBG1(DBG_IKE, "%N message requires a MAC, but none found",
+ DBG1(DBG_LIB, "%N message requires a MAC, but none found",
simaka_subtype_names, this->hdr->subtype);
return FALSE;
}
@@ -558,7 +568,7 @@ static bool verify(private_simaka_message_t *this, chunk_t sigdata)
}
if (!this->mac.ptr || !signer)
{
- DBG1(DBG_IKE, "%N message has a phase 0 notify, but "
+ DBG1(DBG_LIB, "%N message has a phase 0 notify, but "
"no MAC found", simaka_subtype_names, this->hdr->subtype);
return FALSE;
}
@@ -566,7 +576,7 @@ static bool verify(private_simaka_message_t *this, chunk_t sigdata)
}
default:
/* unknown message? */
- DBG1(DBG_IKE, "signature rule for %N messages missing",
+ DBG1(DBG_LIB, "signature rule for %N messages missing",
simaka_subtype_names, this->hdr->subtype);
return FALSE;
}
@@ -582,17 +592,15 @@ static bool verify(private_simaka_message_t *this, chunk_t sigdata)
}
if (!signer->verify_signature(signer, data, backup))
{
- DBG1(DBG_IKE, "%N MAC verification failed",
+ DBG1(DBG_LIB, "%N MAC verification failed",
eap_type_names, this->hdr->type);
return FALSE;
}
return TRUE;
}
-/**
- * Implementation of simaka_message_t.generate
- */
-static eap_payload_t* generate(private_simaka_message_t *this, chunk_t sigdata)
+METHOD(simaka_message_t, generate, chunk_t,
+ private_simaka_message_t *this, chunk_t sigdata)
{
/* buffers large enough for messages we generate */
char out_buf[1024], encr_buf[512];
@@ -603,7 +611,7 @@ static eap_payload_t* generate(private_simaka_message_t *this, chunk_t sigdata)
u_int16_t len;
signer_t *signer;
- charon->sim->message_hook(charon->sim, &this->public, FALSE, TRUE);
+ call_hook(this, FALSE, TRUE);
out = chunk_create(out_buf, sizeof(out_buf));
encr = chunk_create(encr_buf, sizeof(encr_buf));
@@ -723,7 +731,7 @@ static eap_payload_t* generate(private_simaka_message_t *this, chunk_t sigdata)
}
default:
{
- DBG1(DBG_IKE, "no rule to encode %N, skipped",
+ DBG1(DBG_LIB, "no rule to encode %N, skipped",
simaka_attribute_names, type);
break;
}
@@ -817,15 +825,13 @@ static eap_payload_t* generate(private_simaka_message_t *this, chunk_t sigdata)
signer->get_signature(signer, data, mac.ptr);
}
- charon->sim->message_hook(charon->sim, &this->public, FALSE, FALSE);
+ call_hook(this, FALSE, FALSE);
- return eap_payload_create_data(out);
+ return chunk_clone(out);
}
-/**
- * Implementation of simaka_message_t.destroy.
- */
-static void destroy(private_simaka_message_t *this)
+METHOD(simaka_message_t, destroy, void,
+ private_simaka_message_t *this)
{
this->attributes->destroy_function(this->attributes, free);
free(this->hdr);
@@ -843,43 +849,40 @@ static simaka_message_t *simaka_message_create_data(chunk_t data,
if (data.len < sizeof(hdr_t) || hdr->length != htons(data.len))
{
- DBG1(DBG_IKE, "EAP-SIM/AKA header has invalid length");
+ DBG1(DBG_LIB, "EAP-SIM/AKA header has invalid length");
return NULL;
}
if (hdr->code != EAP_REQUEST && hdr->code != EAP_RESPONSE)
{
- DBG1(DBG_IKE, "invalid EAP code in EAP-SIM/AKA message",
+ DBG1(DBG_LIB, "invalid EAP code in EAP-SIM/AKA message",
eap_type_names, hdr->type);
return NULL;
}
if (hdr->type != EAP_SIM && hdr->type != EAP_AKA)
{
- DBG1(DBG_IKE, "invalid EAP type in EAP-SIM/AKA message",
+ DBG1(DBG_LIB, "invalid EAP type in EAP-SIM/AKA message",
eap_type_names, hdr->type);
return NULL;
}
- this = malloc_thing(private_simaka_message_t);
-
- this->public.is_request = (bool(*)(simaka_message_t*))is_request;
- this->public.get_identifier = (u_int8_t(*)(simaka_message_t*))get_identifier;
- this->public.get_type = (eap_type_t(*)(simaka_message_t*))get_type;
- this->public.get_subtype = (simaka_subtype_t(*)(simaka_message_t*))get_subtype;
- this->public.create_attribute_enumerator = (enumerator_t*(*)(simaka_message_t*))create_attribute_enumerator;
- this->public.add_attribute = (void(*)(simaka_message_t*, simaka_attribute_t type, chunk_t data))add_attribute;
- this->public.parse = (bool(*)(simaka_message_t*))parse;
- this->public.verify = (bool(*)(simaka_message_t*, chunk_t sigdata))verify;
- this->public.generate = (eap_payload_t*(*)(simaka_message_t*, chunk_t sigdata))generate;
- this->public.destroy = (void(*)(simaka_message_t*))destroy;
-
- this->attributes = linked_list_create();
- this->encrypted = FALSE;
- this->crypto = crypto;
- this->p_bit = TRUE;
- this->mac = chunk_empty;
- this->encr = chunk_empty;
- this->iv = chunk_empty;
- this->hdr = malloc(data.len);
+ INIT(this,
+ .public = {
+ .is_request = _is_request,
+ .get_identifier = _get_identifier,
+ .get_type = _get_type,
+ .get_subtype = _get_subtype,
+ .create_attribute_enumerator = _create_attribute_enumerator,
+ .add_attribute = _add_attribute,
+ .parse = _parse,
+ .verify = _verify,
+ .generate = _generate,
+ .destroy = _destroy,
+ },
+ .attributes = linked_list_create(),
+ .crypto = crypto,
+ .p_bit = TRUE,
+ .hdr = malloc(data.len),
+ );
memcpy(this->hdr, hdr, data.len);
return &this->public;
@@ -888,10 +891,10 @@ static simaka_message_t *simaka_message_create_data(chunk_t data,
/**
* See header.
*/
-simaka_message_t *simaka_message_create_from_payload(eap_payload_t *payload,
+simaka_message_t *simaka_message_create_from_payload(chunk_t data,
simaka_crypto_t *crypto)
{
- return simaka_message_create_data(payload->get_data(payload), crypto);
+ return simaka_message_create_data(data, crypto);
}
/**
diff --git a/src/libsimaka/simaka_message.h b/src/libsimaka/simaka_message.h
index 341f72959..28fe21823 100644
--- a/src/libsimaka/simaka_message.h
+++ b/src/libsimaka/simaka_message.h
@@ -27,7 +27,7 @@
#define SIMAKA_MESSAGE_H_
#include <enum.h>
-#include <daemon.h>
+#include <eap/eap.h>
#include "simaka_crypto.h"
@@ -35,6 +35,7 @@ typedef enum simaka_attribute_t simaka_attribute_t;
typedef enum simaka_subtype_t simaka_subtype_t;
typedef enum simaka_notification_t simaka_notification_t;
typedef enum simaka_client_error_t simaka_client_error_t;
+typedef struct simaka_message_t simaka_message_t;
/**
* Subtypes of EAP-SIM/AKA messages
@@ -235,9 +236,9 @@ struct simaka_message_t {
* Generate a message, optionally encrypt attributes and create a MAC.
*
* @param sigdata additional data to include in signature, if any
- * @return generated eap payload, NULL if failed
+ * @return allocated data of generated message
*/
- eap_payload_t* (*generate)(simaka_message_t *this, chunk_t sigdata);
+ chunk_t (*generate)(simaka_message_t *this, chunk_t sigdata);
/**
* Destroy a simaka_message_t.
@@ -262,11 +263,11 @@ simaka_message_t *simaka_message_create(bool request, u_int8_t identifier,
/**
* Create an simaka_message from a chunk of data.
*
- * @param payload payload to create message from
+ * @param data message data to parse
* @param crypto EAP-SIM/AKA crypto helper
* @return EAP message, NULL on error
*/
-simaka_message_t *simaka_message_create_from_payload(eap_payload_t *payload,
+simaka_message_t *simaka_message_create_from_payload(chunk_t data,
simaka_crypto_t *crypto);
#endif /** SIMAKA_MESSAGE_H_ @}*/
diff --git a/src/libsimaka/simaka_provider.h b/src/libsimaka/simaka_provider.h
new file mode 100644
index 000000000..f1bf80049
--- /dev/null
+++ b/src/libsimaka/simaka_provider.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2008-2011 Martin Willi
+ * 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 simaka_provider simaka_provider
+ * @{ @ingroup libsimaka
+ */
+
+#ifndef SIMAKA_PROVIDER_H_
+#define SIMAKA_PROVIDER_H_
+
+typedef struct simaka_provider_t simaka_provider_t;
+
+#include "simaka_manager.h"
+
+#include <utils/identification.h>
+
+/**
+ * Interface for a triplet/quintuplet provider (used as EAP server).
+ *
+ * A SIM provider hands out triplets for SIM authentication and quintuplets
+ * for AKA authentication. Multiple SIM provider instances can serve as
+ * authentication backend to authenticate clients using SIM/AKA.
+ * An implementation supporting only one of SIM/AKA authentication may
+ * implement the other methods with return_false().
+ */
+struct simaka_provider_t {
+
+ /**
+ * Create a challenge for SIM authentication.
+ *
+ * @param id permanent identity of peer to gen triplet for
+ * @param rand RAND output buffer, fixed size 16 bytes
+ * @param sres SRES output buffer, fixed size 4 byte
+ * @param kc KC output buffer, fixed size 8 bytes
+ * @return TRUE if triplet received, FALSE otherwise
+ */
+ bool (*get_triplet)(simaka_provider_t *this, identification_t *id,
+ char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN],
+ char kc[SIM_KC_LEN]);
+
+ /**
+ * Create a challenge for AKA authentication.
+ *
+ * The XRES value is the only one with variable length. Pass a buffer
+ * of at least AKA_RES_MAX, the actual number of bytes is written to the
+ * xres_len value. While the standard would allow any bit length between
+ * 32 and 128 bits, we support only full bytes for now.
+ *
+ * @param id permanent identity of peer to create challenge for
+ * @param rand buffer receiving random value rand
+ * @param xres buffer receiving expected authentication result xres
+ * @param xres_len nubmer of bytes written to xres buffer
+ * @param ck buffer receiving encryption key ck
+ * @param ik buffer receiving integrity key ik
+ * @param autn authentication token autn
+ * @return TRUE if quintuplet generated successfully
+ */
+ bool (*get_quintuplet)(simaka_provider_t *this, identification_t *id,
+ char rand[AKA_RAND_LEN],
+ char xres[AKA_RES_MAX], int *xres_len,
+ char ck[AKA_CK_LEN], char ik[AKA_IK_LEN],
+ char autn[AKA_AUTN_LEN]);
+
+ /**
+ * Process AKA resynchroniusation request of a peer.
+ *
+ * @param id permanent identity of peer requesting resynchronisation
+ * @param rand random value rand
+ * @param auts synchronization parameter auts
+ * @return TRUE if resynchronized successfully
+ */
+ bool (*resync)(simaka_provider_t *this, identification_t *id,
+ char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN]);
+
+ /**
+ * Check if peer uses a pseudonym, get permanent identity.
+ *
+ * @param id pseudonym identity candidate
+ * @return permanent identity, NULL if id not a pseudonym
+ */
+ identification_t* (*is_pseudonym)(simaka_provider_t *this,
+ identification_t *id);
+
+ /**
+ * Generate a pseudonym identitiy for a given peer identity.
+ *
+ * @param id permanent identity to generate a pseudonym for
+ * @return generated pseudonym, NULL to not use a pseudonym identity
+ */
+ identification_t* (*gen_pseudonym)(simaka_provider_t *this,
+ identification_t *id);
+
+ /**
+ * Check if peer uses reauthentication, retrieve reauth parameters.
+ *
+ * @param id reauthentication identity (candidate)
+ * @param mk buffer receiving master key MK
+ * @param counter pointer receiving current counter value, host order
+ * @return permanent identity, NULL if id not a reauth identity
+ */
+ identification_t* (*is_reauth)(simaka_provider_t *this, identification_t *id,
+ char mk[HASH_SIZE_SHA1], u_int16_t *counter);
+
+ /**
+ * Generate a fast reauthentication identity, associated to a master key.
+ *
+ * @param id permanent peer identity
+ * @param mk master key to store along with generated identity
+ * @return fast reauthentication identity, NULL to not use reauth
+ */
+ identification_t* (*gen_reauth)(simaka_provider_t *this, identification_t *id,
+ char mk[HASH_SIZE_SHA1]);
+};
+
+#endif /** SIMAKA_CARD_H_ @}*/