diff options
author | Yves-Alexis Perez <corsac@corsac.net> | 2012-06-28 21:16:07 +0200 |
---|---|---|
committer | Yves-Alexis Perez <corsac@corsac.net> | 2012-06-28 21:16:07 +0200 |
commit | b34738ed08c2227300d554b139e2495ca5da97d6 (patch) | |
tree | 62f33b52820f2e49f0e53c0f8c636312037c8054 /src/libsimaka | |
parent | 0a9d51a49042a68daa15b0c74a2b7f152f52606b (diff) | |
download | vyos-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.am | 5 | ||||
-rw-r--r-- | src/libsimaka/Makefile.in | 94 | ||||
-rw-r--r-- | src/libsimaka/simaka_card.h | 129 | ||||
-rw-r--r-- | src/libsimaka/simaka_crypto.c | 136 | ||||
-rw-r--r-- | src/libsimaka/simaka_hooks.h | 55 | ||||
-rw-r--r-- | src/libsimaka/simaka_manager.c | 626 | ||||
-rw-r--r-- | src/libsimaka/simaka_manager.h | 315 | ||||
-rw-r--r-- | src/libsimaka/simaka_message.c | 169 | ||||
-rw-r--r-- | src/libsimaka/simaka_message.h | 11 | ||||
-rw-r--r-- | src/libsimaka/simaka_provider.h | 128 |
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_ @}*/ |