aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Brunner <tobias@strongswan.org>2017-05-16 17:34:02 +0200
committerTobias Brunner <tobias@strongswan.org>2017-07-05 10:03:38 +0200
commit1aba82bfd736cbbfc78408e7bab588c25e49d12a (patch)
treef187b55d12dc4632e2e44d9a62035e260b6d7f31
parent7004a59a4caefa15209636216b9e0a2d6d798be9 (diff)
downloadstrongswan-1aba82bfd736cbbfc78408e7bab588c25e49d12a.tar.bz2
strongswan-1aba82bfd736cbbfc78408e7bab588c25e49d12a.tar.xz
eap-aka-3gpp: Add plugin that implements 3GPP MILENAGE algorithm in software
This is similar to the eap-aka-3gpp2 plugin. K (optionally concatenated with OPc) may be configured as binary EAP secret in ipsec.secrets or swanctl.conf. Based on a patch by Thomas Strangert. Fixes #2326.
-rw-r--r--conf/Makefile.am3
-rw-r--r--conf/plugins/eap-aka-3ggp2.opt1
-rw-r--r--conf/plugins/eap-aka-3gpp.opt3
-rw-r--r--conf/plugins/eap-aka-3gpp2.opt4
-rw-r--r--configure.ac4
-rw-r--r--src/libcharon/Android.mk2
-rw-r--r--src/libcharon/Makefile.am7
-rw-r--r--src/libcharon/plugins/eap_aka_3gpp/Makefile.am22
-rw-r--r--src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_card.c208
-rw-r--r--src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_card.h75
-rw-r--r--src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_functions.c364
-rw-r--r--src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_functions.h172
-rw-r--r--src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_plugin.c164
-rw-r--r--src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_plugin.h89
-rw-r--r--src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_provider.c205
-rw-r--r--src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_provider.h74
16 files changed, 1395 insertions, 2 deletions
diff --git a/conf/Makefile.am b/conf/Makefile.am
index eb5c9c2eb..0c48bd0c1 100644
--- a/conf/Makefile.am
+++ b/conf/Makefile.am
@@ -39,7 +39,8 @@ plugins = \
plugins/dnscert.opt \
plugins/duplicheck.opt \
plugins/eap-aka.opt \
- plugins/eap-aka-3ggp2.opt \
+ plugins/eap-aka-3gpp.opt \
+ plugins/eap-aka-3gpp2.opt \
plugins/eap-dynamic.opt \
plugins/eap-gtc.opt \
plugins/eap-peap.opt \
diff --git a/conf/plugins/eap-aka-3ggp2.opt b/conf/plugins/eap-aka-3ggp2.opt
deleted file mode 100644
index 9e2a42b3f..000000000
--- a/conf/plugins/eap-aka-3ggp2.opt
+++ /dev/null
@@ -1 +0,0 @@
-charon.plugins.eap-aka-3ggp2.seq_check =
diff --git a/conf/plugins/eap-aka-3gpp.opt b/conf/plugins/eap-aka-3gpp.opt
new file mode 100644
index 000000000..1bc733ab1
--- /dev/null
+++ b/conf/plugins/eap-aka-3gpp.opt
@@ -0,0 +1,3 @@
+charon.plugins.eap-aka-3gpp.seq_check =
+ Enable to activate sequence check of the AKA SQN values in order to trigger
+ resync cycles.
diff --git a/conf/plugins/eap-aka-3gpp2.opt b/conf/plugins/eap-aka-3gpp2.opt
new file mode 100644
index 000000000..679c386b8
--- /dev/null
+++ b/conf/plugins/eap-aka-3gpp2.opt
@@ -0,0 +1,4 @@
+charon.plugins.eap-aka-3gpp2.seq_check =
+ Enable to activate sequence check of the AKA SQN values in order to trigger
+ resync cycles.
+
diff --git a/configure.ac b/configure.ac
index 21563f7f3..6a2bc1f3b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -185,6 +185,7 @@ ARG_ENABL_SET([eap-sim], [enable SIM authentication module for EAP.])
ARG_ENABL_SET([eap-sim-file], [enable EAP-SIM backend based on a triplet file.])
ARG_ENABL_SET([eap-sim-pcsc], [enable EAP-SIM backend based on a smartcard reader. Requires libpcsclite.])
ARG_ENABL_SET([eap-aka], [enable EAP AKA authentication module.])
+ARG_ENABL_SET([eap-aka-3gpp], [enable EAP AKA backend implementing 3GPP MILENAGE algorithms in software.])
ARG_ENABL_SET([eap-aka-3gpp2], [enable EAP AKA backend implementing 3GPP2 algorithms in software. Requires libgmp.])
ARG_ENABL_SET([eap-simaka-sql], [enable EAP-SIM/AKA backend based on a triplet/quintuplet SQL database.])
ARG_ENABL_SET([eap-simaka-pseudonym], [enable EAP-SIM/AKA pseudonym storage plugin.])
@@ -1399,6 +1400,7 @@ ADD_PLUGIN([eap-sim], [c charon])
ADD_PLUGIN([eap-sim-file], [c charon])
ADD_PLUGIN([eap-sim-pcsc], [c charon])
ADD_PLUGIN([eap-aka], [c charon])
+ADD_PLUGIN([eap-aka-3gpp], [c charon])
ADD_PLUGIN([eap-aka-3gpp2], [c charon])
ADD_PLUGIN([eap-simaka-sql], [c charon])
ADD_PLUGIN([eap-simaka-pseudonym], [c charon])
@@ -1574,6 +1576,7 @@ AM_CONDITIONAL(USE_EAP_IDENTITY, test x$eap_identity = xtrue)
AM_CONDITIONAL(USE_EAP_MD5, test x$eap_md5 = xtrue)
AM_CONDITIONAL(USE_EAP_GTC, test x$eap_gtc = xtrue)
AM_CONDITIONAL(USE_EAP_AKA, test x$eap_aka = xtrue)
+AM_CONDITIONAL(USE_EAP_AKA_3GPP, test x$eap_aka_3gpp = xtrue)
AM_CONDITIONAL(USE_EAP_AKA_3GPP2, test x$eap_aka_3gpp2 = xtrue)
AM_CONDITIONAL(USE_EAP_MSCHAPV2, test x$eap_mschapv2 = xtrue)
AM_CONDITIONAL(USE_EAP_TLS, test x$eap_tls = xtrue)
@@ -1840,6 +1843,7 @@ AC_CONFIG_FILES([
src/charon-systemd/Makefile
src/libcharon/Makefile
src/libcharon/plugins/eap_aka/Makefile
+ src/libcharon/plugins/eap_aka_3gpp/Makefile
src/libcharon/plugins/eap_aka_3gpp2/Makefile
src/libcharon/plugins/eap_dynamic/Makefile
src/libcharon/plugins/eap_identity/Makefile
diff --git a/src/libcharon/Android.mk b/src/libcharon/Android.mk
index 1a8e068d1..f381860b9 100644
--- a/src/libcharon/Android.mk
+++ b/src/libcharon/Android.mk
@@ -163,6 +163,8 @@ LOCAL_SRC_FILES += $(call add_plugin, p-cscf)
LOCAL_SRC_FILES += $(call add_plugin, eap-aka)
+LOCAL_SRC_FILES += $(call add_plugin, eap-aka-3gpp)
+
LOCAL_SRC_FILES += $(call add_plugin, eap-aka-3gpp2)
ifneq ($(call plugin_enabled, eap-aka-3gpp2),)
LOCAL_C_INCLUDES += $(libgmp_PATH)
diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am
index 3fcaedc3b..ed2236e04 100644
--- a/src/libcharon/Makefile.am
+++ b/src/libcharon/Makefile.am
@@ -370,6 +370,13 @@ if MONOLITHIC
endif
endif
+if USE_EAP_AKA_3GPP
+ SUBDIRS += plugins/eap_aka_3gpp
+if MONOLITHIC
+ libcharon_la_LIBADD += plugins/eap_aka_3gpp/libstrongswan-eap-aka-3gpp.la
+endif
+endif
+
if USE_EAP_AKA_3GPP2
SUBDIRS += plugins/eap_aka_3gpp2
if MONOLITHIC
diff --git a/src/libcharon/plugins/eap_aka_3gpp/Makefile.am b/src/libcharon/plugins/eap_aka_3gpp/Makefile.am
new file mode 100644
index 000000000..5e230ea3b
--- /dev/null
+++ b/src/libcharon/plugins/eap_aka_3gpp/Makefile.am
@@ -0,0 +1,22 @@
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/libstrongswan \
+ -I$(top_srcdir)/src/libcharon \
+ -I$(top_srcdir)/src/libsimaka
+
+AM_CFLAGS = \
+ $(PLUGIN_CFLAGS)
+
+libstrongswan_eap_aka_3gpp_la_LDFLAGS = -module -avoid-version
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-eap-aka-3gpp.la
+else
+plugin_LTLIBRARIES = libstrongswan-eap-aka-3gpp.la
+libstrongswan_eap_aka_3gpp_la_LIBADD = $(top_builddir)/src/libsimaka/libsimaka.la
+endif
+
+libstrongswan_eap_aka_3gpp_la_SOURCES = \
+ eap_aka_3gpp_plugin.h eap_aka_3gpp_plugin.c \
+ eap_aka_3gpp_card.h eap_aka_3gpp_card.c \
+ eap_aka_3gpp_provider.h eap_aka_3gpp_provider.c \
+ eap_aka_3gpp_functions.h eap_aka_3gpp_functions.c
diff --git a/src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_card.c b/src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_card.c
new file mode 100644
index 000000000..22c1181ad
--- /dev/null
+++ b/src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_card.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2008-2009 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.
+ */
+/*
+ * Copyright (C) 2015 Thomas Strangert
+ * Polystar System AB, Sweden
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "eap_aka_3gpp_card.h"
+
+#include <daemon.h>
+
+typedef struct private_eap_aka_3gpp_card_t private_eap_aka_3gpp_card_t;
+
+/**
+ * Private data of an eap_aka_3gpp_card_t object.
+ */
+struct private_eap_aka_3gpp_card_t {
+
+ /**
+ * Public eap_aka_3gpp_card_t interface.
+ */
+ eap_aka_3gpp_card_t public;
+
+ /**
+ * AKA functions
+ */
+ eap_aka_3gpp_functions_t *f;
+
+ /**
+ * do sequence number checking?
+ */
+ bool seq_check;
+
+ /**
+ * SQN stored in this pseudo-USIM
+ */
+ uint8_t sqn[AKA_SQN_LEN];
+};
+
+METHOD(simaka_card_t, get_quintuplet, status_t,
+ private_eap_aka_3gpp_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)
+{
+ uint8_t *amf, *mac;
+ uint8_t k[AKA_K_LEN], opc[AKA_OPC_LEN], ak[AKA_AK_LEN], sqn[AKA_SQN_LEN],
+ xmac[AKA_MAC_LEN];
+
+ if (!eap_aka_3gpp_get_k_opc(id, k, opc))
+ {
+ DBG1(DBG_IKE, "no EAP key found for %Y to authenticate with AKA", id);
+ return FAILED;
+ }
+ DBG4(DBG_IKE, "EAP key found for id %Y, using K %b and OPc %b", id, k,
+ AKA_K_LEN, opc, AKA_OPC_LEN);
+
+ /* AUTN = SQN xor AK | AMF | MAC */
+ memcpy(sqn, autn, AKA_SQN_LEN);
+ amf = autn + AKA_SQN_LEN;
+ mac = autn + AKA_SQN_LEN + AKA_AMF_LEN;
+ DBG3(DBG_IKE, "received AUTN %b", autn, AKA_AUTN_LEN);
+ DBG3(DBG_IKE, "received AMF %b", amf, AKA_AMF_LEN);
+ DBG3(DBG_IKE, "received MAC %b", mac, AKA_MAC_LEN);
+
+ /* generate RES, CK, IK, AK from received RAND */
+ DBG3(DBG_IKE, "received RAND %b", rand, AKA_RAND_LEN);
+ if (!this->f->f2345(this->f, k, opc, rand, res, ck, ik, ak))
+ {
+ return FAILED;
+ }
+ *res_len = AKA_RES_LEN;
+ DBG3(DBG_IKE, "using RES %b", res, AKA_RES_LEN);
+ DBG3(DBG_IKE, "using CK %b", ck, AKA_CK_LEN);
+ DBG3(DBG_IKE, "using IK %b", ik, AKA_IK_LEN);
+ DBG3(DBG_IKE, "using AK %b", ak, AKA_AK_LEN);
+
+ /* XOR anonymity key AK into SQN to decrypt it */
+ memxor(sqn, ak, AKA_SQN_LEN);
+ DBG3(DBG_IKE, "using SQN %b", sqn, AKA_SQN_LEN);
+
+ /* calculate expected MAC and compare against received one */
+ if (!this->f->f1(this->f, k, opc, rand, sqn, amf, xmac))
+ {
+ return FAILED;
+ }
+ if (!memeq_const(mac, xmac, AKA_MAC_LEN))
+ {
+ DBG1(DBG_IKE, "received MAC does not match XMAC");
+ DBG3(DBG_IKE, "MAC %b\nXMAC %b", mac, AKA_MAC_LEN, xmac, AKA_MAC_LEN);
+ return FAILED;
+ }
+ DBG3(DBG_IKE, "MAC equals XMAC %b", mac, AKA_MAC_LEN);
+
+ if (this->seq_check && memcmp(this->sqn, sqn, AKA_SQN_LEN) >= 0)
+ {
+ DBG3(DBG_IKE, "received SQN %b\ncurrent SQN %b",
+ sqn, AKA_SQN_LEN, this->sqn, AKA_SQN_LEN);
+ return INVALID_STATE;
+ }
+
+ /* update stored SQN to the received one */
+ memcpy(this->sqn, sqn, AKA_SQN_LEN);
+
+ return SUCCESS;
+}
+
+METHOD(simaka_card_t, resync, bool,
+ private_eap_aka_3gpp_card_t *this, identification_t *id,
+ char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN])
+{
+ uint8_t amf[AKA_AMF_LEN], k[AKA_K_LEN], opc[AKA_OPC_LEN], aks[AKA_AK_LEN],
+ macs[AKA_MAC_LEN];
+
+ if (!eap_aka_3gpp_get_k_opc(id, k, opc))
+ {
+ DBG1(DBG_IKE, "no EAP key found for %Y to resync AKA", id);
+ return FALSE;
+ }
+ DBG4(DBG_IKE, "EAP key found for id %Y, using K %b and OPc %b to resync AKA",
+ id, k, AKA_K_LEN, opc, AKA_OPC_LEN);
+
+ /* AMF is set to zero in resync */
+ memset(amf, 0, AKA_AMF_LEN);
+ if (!this->f->f5star(this->f, k, opc, rand, aks) ||
+ !this->f->f1star(this->f, k, opc, rand, this->sqn, amf, macs))
+ {
+ return FALSE;
+ }
+ /* AUTS = SQN xor AKS | MACS */
+ memcpy(auts, this->sqn, AKA_SQN_LEN);
+ memxor(auts, aks, AKA_AK_LEN);
+ memcpy(auts + AKA_AK_LEN, macs, AKA_MAC_LEN);
+ DBG3(DBG_IKE, "generated AUTS %b", auts, AKA_AUTN_LEN);
+
+ return TRUE;
+}
+
+METHOD(eap_aka_3gpp_card_t, destroy, void,
+ private_eap_aka_3gpp_card_t *this)
+{
+ free(this);
+}
+
+/**
+ * See header
+ */
+eap_aka_3gpp_card_t *eap_aka_3gpp_card_create(eap_aka_3gpp_functions_t *f)
+{
+ private_eap_aka_3gpp_card_t *this;
+
+ INIT(this,
+ .public = {
+ .card = {
+ .get_triplet = (void*)return_false,
+ .get_quintuplet = _get_quintuplet,
+ .resync = _resync,
+ .get_pseudonym = (void*)return_null,
+ .set_pseudonym = (void*)nop,
+ .get_reauth = (void*)return_null,
+ .set_reauth = (void*)nop,
+ },
+ .destroy = _destroy,
+ },
+ .f = f,
+ .seq_check = lib->settings->get_bool(lib->settings,
+ "%s.plugins.eap-aka-3gpp.seq_check",
+#ifdef SEQ_CHECK /* handle legacy compile time configuration as default */
+ TRUE,
+#else /* !SEQ_CHECK */
+ FALSE,
+#endif /* SEQ_CHECK */
+ lib->ns),
+ );
+
+ eap_aka_3gpp_get_sqn(this->sqn, 0);
+
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_card.h b/src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_card.h
new file mode 100644
index 000000000..0ef90681f
--- /dev/null
+++ b/src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_card.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2008-2009 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.
+ */
+/*
+ * Copyright (C) 2015 Thomas Strangert
+ * Polystar System AB, Sweden
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup eap_aka_3gpp_card eap_aka_3gpp_card
+ * @{ @ingroup eap_aka_3gpp
+ */
+
+#ifndef EAP_AKA_3GPP_CARD_H_
+#define EAP_AKA_3GPP_CARD_H_
+
+#include "eap_aka_3gpp_functions.h"
+
+#include <simaka_card.h>
+
+typedef struct eap_aka_3gpp_card_t eap_aka_3gpp_card_t;
+
+/**
+ * SIM card implementation using a set of AKA functions.
+ */
+struct eap_aka_3gpp_card_t {
+
+ /**
+ * Implements simaka_card_t interface
+ */
+ simaka_card_t card;
+
+ /**
+ * Destroy a eap_aka_3gpp_card_t.
+ */
+ void (*destroy)(eap_aka_3gpp_card_t *this);
+};
+
+/**
+ * Create a eap_aka_3gpp_card instance.
+ *
+ * @param f AKA functions
+ */
+eap_aka_3gpp_card_t *eap_aka_3gpp_card_create(eap_aka_3gpp_functions_t *f);
+
+#endif /** EAP_AKA_3GPP_CARD_H_ @}*/
diff --git a/src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_functions.c b/src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_functions.c
new file mode 100644
index 000000000..d017d2c99
--- /dev/null
+++ b/src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_functions.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2017 Tobias Brunner
+ * Copyright (C) 2008-2009 Martin Willi
+ * HSR 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.
+ */
+/*
+ * Copyright (C) 2015 Thomas Strangert
+ * Polystar System AB, Sweden
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "eap_aka_3gpp_functions.h"
+
+#include <limits.h>
+#include <ctype.h>
+#include <daemon.h>
+
+typedef struct private_eap_aka_3gpp_functions_t private_eap_aka_3gpp_functions_t;
+
+/**
+ * Private data of an eap_aka_3gpp_functions_t object.
+ */
+struct private_eap_aka_3gpp_functions_t {
+
+ /**
+ * Public eap_aka_3gpp_functions_t interface.
+ */
+ eap_aka_3gpp_functions_t public;
+
+ /**
+ * AES instance
+ */
+ crypter_t *crypter;
+};
+
+/*
+ * Described in header
+ */
+bool eap_aka_3gpp_get_k_opc(identification_t *id, uint8_t k[AKA_K_LEN],
+ uint8_t opc[AKA_OPC_LEN])
+{
+ shared_key_t *shared;
+ chunk_t key;
+
+ shared = lib->credmgr->get_shared(lib->credmgr, SHARED_EAP, id, NULL);
+ if (!shared)
+ {
+ return FALSE;
+ }
+ key = shared->get_key(shared);
+
+ if (key.len == AKA_K_LEN)
+ {
+ memcpy(k, key.ptr, AKA_K_LEN);
+ /* set OPc to a neutral default value, harmless to XOR with */
+ memset(opc, '\0', AKA_OPC_LEN);
+ }
+ else if (key.len == AKA_K_LEN + AKA_OPC_LEN)
+ {
+ memcpy(k, key.ptr, AKA_K_LEN);
+ memcpy(opc, key.ptr + AKA_K_LEN, AKA_OPC_LEN);
+ }
+ else
+ {
+ DBG1(DBG_IKE, "invalid EAP K or K+OPc key found for %Y to authenticate "
+ "with AKA, should be a %d or %d byte long binary value", id,
+ AKA_K_LEN, AKA_K_LEN + AKA_OPC_LEN);
+ shared->destroy(shared);
+ return FALSE;
+ }
+ shared->destroy(shared);
+ return TRUE;
+}
+
+/*
+ * Described in header
+ */
+void eap_aka_3gpp_get_sqn(uint8_t sqn[AKA_SQN_LEN], int offset)
+{
+ timeval_t time;
+
+ gettimeofday(&time, NULL);
+ /* set sqn to an integer containing 4 bytes seconds + 2 bytes usecs */
+ time.tv_sec = htonl(time.tv_sec + offset);
+ /* usec's are never larger than 0x000f423f, so we shift the 12 first bits */
+ time.tv_usec = htonl(time.tv_usec << 12);
+ memcpy(sqn, (uint8_t*)&time.tv_sec + sizeof(time_t) - 4, 4);
+ memcpy(sqn + 4, &time.tv_usec, 2);
+}
+
+static bool f1andf1star(private_eap_aka_3gpp_functions_t *this,
+ const uint8_t k[AKA_K_LEN], const uint8_t opc[AKA_OPC_LEN],
+ const uint8_t rand[AKA_RAND_LEN], const uint8_t sqn[AKA_SQN_LEN],
+ const uint8_t amf[AKA_AMF_LEN], uint8_t mac[16])
+{
+ uint8_t i, data[16], in[16], iv[16] = { 0 };
+
+ if (!this->crypter->set_key(this->crypter,
+ chunk_create((uint8_t*)k, AKA_K_LEN)))
+ {
+ return FALSE;
+ }
+
+ /* XOR RAND and OPc */
+ memcpy(data, rand, sizeof(data));
+ memxor(data, opc, sizeof(data));
+ if (!this->crypter->encrypt(this->crypter, chunk_create(data, sizeof(data)),
+ chunk_create(iv, sizeof(iv)), NULL))
+ {
+ return FALSE;
+ }
+
+ /* concatenate SQN || AMF ||SQN || AMF */
+ memcpy(in, sqn, 6);
+ memcpy(&in[6], amf, 2);
+ memcpy(&in[8], in, 8);
+
+ /* XOR opc and in, rotate by r1=64, and XOR
+ * on the constant c1 (which is all zeroes) and finally the output above */
+ for (i = 0; i < 16; i++)
+ {
+ data[(i + 8) % 16] ^= in[i] ^ opc[i];
+ }
+ if (!this->crypter->encrypt(this->crypter, chunk_create(data, sizeof(data)),
+ chunk_create(iv, sizeof(iv)), NULL))
+ {
+ return FALSE;
+ }
+ memxor(data, opc, sizeof(data));
+ memcpy(mac, data, 16);
+ return TRUE;
+}
+
+METHOD(eap_aka_3gpp_functions_t, f1, bool,
+ private_eap_aka_3gpp_functions_t *this, const uint8_t k[AKA_K_LEN],
+ const uint8_t opc[AKA_OPC_LEN], const uint8_t rand[AKA_RAND_LEN],
+ const uint8_t sqn[AKA_SQN_LEN], const uint8_t amf[AKA_AMF_LEN],
+ uint8_t maca[AKA_MAC_LEN])
+{
+ uint8_t mac[16];
+
+ if (!f1andf1star(this, k, opc, rand, sqn, amf, mac))
+ {
+ return FALSE;
+ }
+ /* only diff between f1 and f1* is here:
+ * f1 uses bytes 0-7 as MAC-A
+ * f1* uses bytes 8-15 as MAC-S */
+ memcpy(maca, mac, AKA_MAC_LEN);
+ return TRUE;
+}
+
+METHOD(eap_aka_3gpp_functions_t, f1star, bool,
+ private_eap_aka_3gpp_functions_t *this, const uint8_t k[AKA_K_LEN],
+ const uint8_t opc[AKA_OPC_LEN], const uint8_t rand[AKA_RAND_LEN],
+ const uint8_t sqn[AKA_SQN_LEN], const uint8_t amf[AKA_AMF_LEN],
+ uint8_t macs[AKA_MAC_LEN])
+{
+ uint8_t mac[16];
+
+ if (!f1andf1star(this, k, opc, rand, sqn, amf, mac))
+ {
+ return FALSE;
+ }
+ /* only diff between f1 and f1* is here:
+ * f1 uses bytes 0-7 as MAC-A
+ * f1* uses bytes 8-15 as MAC-S */
+ memcpy(macs, &mac[8], AKA_MAC_LEN);
+ return TRUE;
+}
+
+METHOD(eap_aka_3gpp_functions_t, f2345, bool,
+ private_eap_aka_3gpp_functions_t *this, const uint8_t k[AKA_K_LEN],
+ const uint8_t opc[AKA_OPC_LEN], const uint8_t rand[AKA_RAND_LEN],
+ uint8_t res[AKA_RES_LEN], uint8_t ck[AKA_CK_LEN], uint8_t ik[AKA_IK_LEN],
+ uint8_t ak[AKA_AK_LEN])
+{
+ uint8_t data[16], iv[16] = { 0 };
+ chunk_t temp;
+ uint8_t i;
+
+ if (!this->crypter->set_key(this->crypter,
+ chunk_create((uint8_t*)k, AKA_K_LEN)))
+ {
+ return FALSE;
+ }
+
+ /* XOR RAND and OPc */
+ memcpy(data, rand, sizeof(data));
+ memxor(data, opc, sizeof(data));
+ if (!this->crypter->encrypt(this->crypter, chunk_create(data, sizeof(data)),
+ chunk_create(iv, sizeof(iv)), &temp))
+ {
+ return FALSE;
+ }
+
+ /* to obtain output block OUT2: XOR OPc and TEMP,
+ * rotate by r2=0, and XOR on the constant c2 (which is all zeroes except
+ * that the last bit is 1). */
+ for (i = 0; i < 16; i++)
+ {
+ data[i] = temp.ptr[i] ^ opc[i];
+ }
+ data[15] ^= 1;
+
+ if (!this->crypter->encrypt(this->crypter, chunk_create(data, sizeof(data)),
+ chunk_create(iv, sizeof(iv)), NULL))
+ {
+ chunk_free(&temp);
+ return FALSE;
+ }
+ memxor(data, opc, sizeof(data));
+
+ /* f5 output */
+ memcpy(ak, data, 6);
+ /* f2 output */
+ memcpy(res, &data[8], 8);
+
+ /* to obtain output block OUT3: XOR OPc and TEMP,
+ * rotate by r3=32, and XOR on the constant c3 (which
+ * is all zeroes except that the next to last bit is 1) */
+ for (i = 0; i < 16; i++)
+ {
+ data[(i + 12) % 16] = temp.ptr[i] ^ opc[i];
+ }
+ data[15] ^= 2;
+
+ if (!this->crypter->encrypt(this->crypter, chunk_create(data, sizeof(data)),
+ chunk_create(iv, sizeof(iv)), NULL))
+ {
+ chunk_free(&temp);
+ return FALSE;
+ }
+ memxor(data, opc, sizeof(data));
+
+ /* f3 output */
+ memcpy(ck, data, 16);
+
+ /* to obtain output block OUT4: XOR OPc and TEMP,
+ * rotate by r4=64, and XOR on the constant c4 (which
+ * is all zeroes except that the 2nd from last bit is 1). */
+ for (i = 0; i < 16; i++)
+ {
+ data[(i + 8) % 16] = temp.ptr[i] ^ opc[i];
+ }
+ data[15] ^= 4;
+
+ if (!this->crypter->encrypt(this->crypter, chunk_create(data, sizeof(data)),
+ chunk_create(iv, sizeof(iv)), NULL))
+ {
+ chunk_free(&temp);
+ return FALSE;
+ }
+ memxor(data, opc, sizeof(data));
+ /* f4 output */
+ memcpy(ik, data, 16);
+ chunk_free(&temp);
+ return TRUE;
+
+}
+
+METHOD(eap_aka_3gpp_functions_t, f5star, bool,
+ private_eap_aka_3gpp_functions_t *this, const uint8_t k[AKA_K_LEN],
+ const uint8_t opc[AKA_OPC_LEN], const uint8_t rand[AKA_RAND_LEN],
+ uint8_t aks[AKA_AK_LEN])
+{
+ uint8_t i, data[16], iv[16] = { 0 };
+ chunk_t temp;
+
+ if (!this->crypter->set_key(this->crypter,
+ chunk_create((uint8_t*)k, AKA_K_LEN)))
+ {
+ return FALSE;
+ }
+
+ /* XOR RAND and OPc */
+ memcpy(data, rand, sizeof(data));
+ memxor(data, opc, sizeof(data));
+ if (!this->crypter->encrypt(this->crypter, chunk_create(data, sizeof(data)),
+ chunk_create(iv, sizeof(iv)), &temp))
+ {
+ return FALSE;
+ }
+
+ /* to obtain output block OUT5: XOR OPc and the output above,
+ * rotate by r5=96, and XOR on the constant c5 (which
+ * is all zeroes except that the 3rd from last bit is 1). */
+ for (i = 0; i < 16; i++)
+ {
+ data[(i + 4) % 16] = temp.ptr[i] ^ opc[i];
+ }
+ data[15] ^= 8;
+ chunk_free(&temp);
+
+ if (!this->crypter->encrypt(this->crypter, chunk_create(data, sizeof(data)),
+ chunk_create(iv, sizeof(iv)), NULL))
+ {
+ return FALSE;
+ }
+ memxor(data, opc, sizeof(data));
+ memcpy(aks, data, 6);
+ return TRUE;
+}
+
+METHOD(eap_aka_3gpp_functions_t, destroy, void,
+ private_eap_aka_3gpp_functions_t *this)
+{
+ this->crypter->destroy(this->crypter);
+ free(this);
+}
+
+/**
+ * See header
+ */
+eap_aka_3gpp_functions_t *eap_aka_3gpp_functions_create()
+{
+ private_eap_aka_3gpp_functions_t *this;
+
+ INIT(this,
+ .public = {
+ .f1 = _f1,
+ .f1star = _f1star,
+ .f2345 = _f2345,
+ .f5star = _f5star,
+ .destroy = _destroy,
+ },
+ .crypter = lib->crypto->create_crypter(lib->crypto, ENCR_AES_CBC, 16),
+ );
+ if (!this->crypter)
+ {
+ DBG1(DBG_IKE, "%N not supported, unable to use 3GPP algorithm",
+ encryption_algorithm_names, ENCR_AES_CBC);
+ free(this);
+ return NULL;
+ }
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_functions.h b/src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_functions.h
new file mode 100644
index 000000000..c089cd385
--- /dev/null
+++ b/src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_functions.h
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2008-2009 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.
+ */
+/*
+ * Copyright (C) 2015 Thomas Strangert
+ * Polystar System AB, Sweden
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup eap_aka_3gpp_functions eap_aka_3gpp_functions
+ * @{ @ingroup eap_aka_3gpp
+ */
+
+#ifndef EAP_AKA_3GPP_FUNCTIONS_H_
+#define EAP_AKA_3GPP_FUNCTIONS_H_
+
+#include <credentials/keys/shared_key.h>
+#include <simaka_manager.h>
+#include "eap_aka_3gpp_plugin.h"
+
+#define AKA_SQN_LEN 6
+#define AKA_K_LEN 16
+#define AKA_OPC_LEN 16
+#define AKA_MAC_LEN 8
+#define AKA_AK_LEN 6
+#define AKA_AMF_LEN 2
+#define AKA_RES_LEN 8
+
+typedef struct eap_aka_3gpp_functions_t eap_aka_3gpp_functions_t;
+
+/**
+ * Get a shared key K and OPc of a particular user from the credential database.
+ *
+ * @param id user identity
+ * @param[out] k (16 byte) scratchpad to receive secret key K
+ * @param[out] opc (16 byte) scratchpad to receive operator variant key
+ * derivate OPc
+ */
+bool eap_aka_3gpp_get_k_opc(identification_t *id, uint8_t k[AKA_K_LEN],
+ uint8_t opc[AKA_OPC_LEN]);
+
+/**
+ * Get SQN using current time. Only used when creating/initializing
+ * an eap_aka_3gpp_card_t or eap_aka_3gpp_provider_t object.
+ *
+ * @param offset time offset to add to current time to avoid initial
+ * SQN resync
+ * @param[out] sqn (6 byte) scratchpad to receive generated SQN
+ */
+void eap_aka_3gpp_get_sqn(uint8_t sqn[AKA_SQN_LEN], int offset);
+
+/**
+ * f1, f1*(), f2345() and f5*() functions from 3GPP as specified
+ * in the TS 35.205, .206, .207, .208 standards.
+ */
+struct eap_aka_3gpp_functions_t {
+
+ /**
+ * f1 : Calculate MAC-A from RAND, SQN, AMF using K and OPc
+ *
+ * @param k (128 bit) secret key K
+ * @param opc (128 bit) operator variant key derivate OPc
+ * @param rand (128 bit) random value RAND
+ * @param sqn (48 bit) sequence number SQN
+ * @param amf (16 bit) authentication management field AMF
+ * @param[out] maca (64 bit) scratchpad to receive network auth code MAC-A
+ * @return TRUE if calculations successful
+ */
+ bool (*f1)(eap_aka_3gpp_functions_t *this,
+ const uint8_t k[AKA_K_LEN], const uint8_t opc[AKA_OPC_LEN],
+ const uint8_t rand[AKA_RAND_LEN], const uint8_t sqn[AKA_SQN_LEN],
+ const uint8_t amf[AKA_AMF_LEN],
+ uint8_t maca[AKA_MAC_LEN]);
+
+
+ /**
+ * f1* : Calculate MAC-S from RAND, SQN, AMF using K and OPc
+ *
+ * @param k (128 bit) secret key K
+ * @param opc (128 bit) operator variant key derivate OPc
+ * @param rand (128 bit) random value RAND
+ * @param sqn (48 bit) sequence number SQN
+ * @param amf (16 bit) authentication management field AMF
+ * @param[out] macs (64 bit) scratchpad to receive resync auth code MAC-S
+ * @return TRUE if calculations successful
+ */
+ bool (*f1star)(eap_aka_3gpp_functions_t *this,
+ const uint8_t k[AKA_K_LEN], const uint8_t opc[AKA_OPC_LEN],
+ const uint8_t rand[AKA_RAND_LEN], const uint8_t sqn[AKA_SQN_LEN],
+ const uint8_t amf[AKA_AMF_LEN],
+ uint8_t macs[AKA_MAC_LEN]);
+
+ /**
+ * f2345 : Do f2, f3, f4 and f5 in a single scoop, where:
+ * f2 : Calculates RES from RAND using K and OPc
+ * f3 : Calculates CK from RAND using K and OPc
+ * f4 : Calculates IK from RAND using K and OPc
+ * f5 : Calculates AK from RAND using K and OPc
+ *
+ * @param k (128 bit) secret key K
+ * @param opc (128 bit) operator variant key derivate OPc
+ * @param rand (128 bit) random value RAND
+ * @param[out] res (64 bit) scratchpad to receive signed response RES
+ * @param[out] ck (128 bit) scratchpad to receive encryption key CK
+ * @param[out] ik (128 bit) scratchpad to receive integrity key IK
+ * @param[out] ak (48 bit) scratchpad to receive anonymity key AK
+ * @return TRUE if calculations successful
+ */
+ bool (*f2345)(eap_aka_3gpp_functions_t *this,
+ const uint8_t k[AKA_K_LEN], const uint8_t opc[AKA_OPC_LEN],
+ const uint8_t rand[AKA_RAND_LEN],
+ uint8_t res[AKA_RES_LEN], uint8_t ck[AKA_CK_LEN],
+ uint8_t ik[AKA_IK_LEN], uint8_t ak[AKA_AK_LEN]);
+
+
+ /**
+ * f5* : Calculates resync AKS from RAND using K and OPc
+ *
+ * @param k (128 bit) secret key K
+ * @param opc (128 bit) operator variant key derivate OPc
+ * @param rand (128 bit) random value RAND
+ * @param[out] aks (48 bit) scratchpad to receive resync anonymity key AKS
+ * @return TRUE if calculations successful
+ */
+ bool (*f5star)(eap_aka_3gpp_functions_t *this,
+ const uint8_t k[AKA_K_LEN], const uint8_t opc[AKA_OPC_LEN],
+ const uint8_t rand[AKA_RAND_LEN],
+ uint8_t aks[AKA_AK_LEN]);
+
+ /**
+ * Destroy a eap_aka_3gpp_functions_t.
+ */
+ void (*destroy)(eap_aka_3gpp_functions_t *this);
+};
+
+/**
+ * Create a eap_aka_3gpp_functions instance.
+ *
+ * @return function set, NULL on error
+ */
+eap_aka_3gpp_functions_t *eap_aka_3gpp_functions_create();
+
+#endif /** EAP_AKA_3GPP_FUNCTIONS_H_ @}*/
diff --git a/src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_plugin.c b/src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_plugin.c
new file mode 100644
index 000000000..3d0e06146
--- /dev/null
+++ b/src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_plugin.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2008-2009 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.
+ */
+/*
+ * Copyright (C) 2015 Thomas Strangert
+ * Polystar System AB, Sweden
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "eap_aka_3gpp_plugin.h"
+#include "eap_aka_3gpp_card.h"
+#include "eap_aka_3gpp_provider.h"
+#include "eap_aka_3gpp_functions.h"
+
+#include <daemon.h>
+
+typedef struct private_eap_aka_3gpp_t private_eap_aka_3gpp_t;
+
+/**
+ * Private data of an eap_aka_3gpp_t object.
+ */
+struct private_eap_aka_3gpp_t {
+
+ /**
+ * Public eap_aka_3gpp_plugin_t interface.
+ */
+ eap_aka_3gpp_plugin_t public;
+
+ /**
+ * USIM/EAP-AKA card
+ */
+ eap_aka_3gpp_card_t *card;
+
+ /**
+ * EAP-AKA provider
+ */
+ eap_aka_3gpp_provider_t *provider;
+
+ /**
+ * AKA functions
+ */
+ eap_aka_3gpp_functions_t *functions;
+};
+
+METHOD(plugin_t, get_name, char*,
+ private_eap_aka_3gpp_t *this)
+{
+ return "eap-aka-3gpp";
+}
+
+/**
+ * Try to instanciate ea_aka_3gpp functions and card/provider backends
+ */
+static bool register_functions(private_eap_aka_3gpp_t *this,
+ plugin_feature_t *feature, bool reg, void *data)
+{
+ if (reg)
+ {
+ this->functions = eap_aka_3gpp_functions_create();
+ if (!this->functions)
+ {
+ return FALSE;
+ }
+ this->card = eap_aka_3gpp_card_create(this->functions);
+ this->provider = eap_aka_3gpp_provider_create(this->functions);
+ return TRUE;
+ }
+ this->card->destroy(this->card);
+ this->provider->destroy(this->provider);
+ this->functions->destroy(this->functions);
+ this->card = NULL;
+ this->provider = NULL;
+ this->functions = NULL;
+ return TRUE;
+}
+
+/**
+ * Callback providing our card to register
+ */
+static simaka_card_t* get_card(private_eap_aka_3gpp_t *this)
+{
+ return &this->card->card;
+}
+
+/**
+ * Callback providing our provider to register
+ */
+static simaka_provider_t* get_provider(private_eap_aka_3gpp_t *this)
+{
+ return &this->provider->provider;
+}
+
+METHOD(plugin_t, get_features, int,
+ private_eap_aka_3gpp_t *this, plugin_feature_t *features[])
+{
+ static plugin_feature_t f[] = {
+ PLUGIN_CALLBACK((void*)register_functions, NULL),
+ PLUGIN_PROVIDE(CUSTOM, "eap-aka-3gpp-functions"),
+ PLUGIN_DEPENDS(CRYPTER, ENCR_AES_CBC, 16),
+ PLUGIN_CALLBACK(simaka_manager_register, get_card),
+ PLUGIN_PROVIDE(CUSTOM, "aka-card"),
+ PLUGIN_DEPENDS(CUSTOM, "aka-manager"),
+ PLUGIN_DEPENDS(CUSTOM, "eap-aka-3gpp-functions"),
+ PLUGIN_CALLBACK(simaka_manager_register, get_provider),
+ PLUGIN_PROVIDE(CUSTOM, "aka-provider"),
+ PLUGIN_DEPENDS(CUSTOM, "aka-manager"),
+ PLUGIN_DEPENDS(CUSTOM, "eap-aka-3gpp-functions"),
+ };
+ *features = f;
+ return countof(f);
+}
+
+METHOD(plugin_t, destroy, void, private_eap_aka_3gpp_t *this)
+{
+ free(this);
+}
+
+/**
+ * See header
+ */
+plugin_t *eap_aka_3gpp_plugin_create()
+{
+ private_eap_aka_3gpp_t *this;
+
+ INIT(this,
+ .public = {
+ .plugin = {
+ .get_name = _get_name,
+ .get_features = _get_features,
+ .destroy = _destroy,
+ },
+ },
+ );
+
+ return &this->public.plugin;
+}
diff --git a/src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_plugin.h b/src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_plugin.h
new file mode 100644
index 000000000..e101f4be6
--- /dev/null
+++ b/src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_plugin.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2008-2009 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.
+ */
+/*
+ * Copyright (C) 2015 Thomas Strangert
+ * Polystar System AB, Sweden
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup eap_aka_3gpp eap_aka_3gpp
+ * @ingroup cplugins
+ *
+ * @defgroup eap_aka_3gpp_plugin eap_aka_3gpp_plugin
+ * @{ @ingroup eap_aka_3gpp
+ */
+
+#ifndef EAP_AKA_3GPP_PLUGIN_H_
+#define EAP_AKA_3GPP_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct eap_aka_3gpp_plugin_t eap_aka_3gpp_plugin_t;
+
+/**
+ * Plugin to provide a USIM card/provider according to the 3GPP standard.
+ *
+ * This plugin implements the 3GPP standards TS 35.205, .206, .207, .208
+ * completely in software using the MILENAGE algorithm.
+ * The shared keys used for authentication (K, OPc) are from ipsec.secrets.
+ * The peers ID is used to query it.
+ *
+ * To enable SEQ sequence check by default define SEQ_CHECK. Left undefined/off,
+ * it makes the USIM 'card' to accept any SEQ number, not comparing received
+ * SQN with its own locally stored value. This potentially allows an attacker
+ * to do replay attacks. But since the server has proven his identity via IKE,
+ * such an attack is only possible between server and AAA (if any).
+ * Note that SEQ_CHECK only controls the compile-time default behaviour,
+ * but the run-time behaviour can always be controlled by setting the
+ * charon.plugins.eap-aka-3gpp.seq_check config variable.
+ */
+struct eap_aka_3gpp_plugin_t {
+
+ /**
+ * implements plugin interface
+ */
+ plugin_t plugin;
+};
+
+/**
+ * The AKA mechanism uses sequence numbers to detect replay attacks. The
+ * peer stores the sequence number normally in a USIM and accepts
+ * incremental sequence numbers (incremental for lifetime of the USIM). To
+ * prevent a complex sequence number management, this implementation uses
+ * a sequence number derived from time. It is initialized to the startup
+ * time of the daemon. On the provider side, an offset can optionally be
+ * added to allow for a time sqew towards the card side.
+ */
+#define SQN_TIME_OFFSET 180
+
+#endif /** EAP_AKA_3GPP_PLUGIN_H_ @}*/
diff --git a/src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_provider.c b/src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_provider.c
new file mode 100644
index 000000000..d5112d390
--- /dev/null
+++ b/src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_provider.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2008-2009 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.
+ */
+/*
+ * Copyright (C) 2015 Thomas Strangert
+ * Polystar System AB, Sweden
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "eap_aka_3gpp_provider.h"
+
+#include <daemon.h>
+
+typedef struct private_eap_aka_3gpp_provider_t private_eap_aka_3gpp_provider_t;
+
+/**
+ * Private data of an eap_aka_3gpp_provider_t object.
+ */
+struct private_eap_aka_3gpp_provider_t {
+
+ /**
+ * Public eap_aka_3gpp_provider_t interface.
+ */
+ eap_aka_3gpp_provider_t public;
+
+ /**
+ * AKA functions
+ */
+ eap_aka_3gpp_functions_t *f;
+
+ /**
+ * time based SQN, we use the same for all peers
+ */
+ uint8_t sqn[AKA_SQN_LEN];
+};
+
+/** Authentication management field, AMF, as defined in 3GPP TS 33.102 V12.2.0
+ *
+ * The 16 bits in the AMF are numbered from "0" to "15" where bit "0" is
+ * the most significant bit and bit "15" is the least significant bit.
+ * Bit "0" is called the "AMF separation bit". It is used for the purposes
+ * of EPS (Evolved Packet System) and is specified in
+ * - TS 33.401 [28] for E-UTRAN access to EPS;
+ * - TS 33.402 [29] for non-3GPP access to EPS.
+ * Bits "1" to "7" are reserved for future standardization use.
+ * Bits "1" to "7" shall be set to 0 while not yet specified for a particular use.
+ * Bits "8" to "15" can be used for proprietary purposes.
+ */
+static const uint8_t amf[AKA_AMF_LEN] = {0x80, 0x00};
+
+METHOD(simaka_provider_t, get_quintuplet, bool,
+ private_eap_aka_3gpp_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])
+{
+ rng_t *rng;
+ uint8_t maca[AKA_MAC_LEN], ak[AKA_AK_LEN], k[AKA_K_LEN], opc[AKA_OPC_LEN];
+
+ /* generate RAND: we use a RNG already registered as f0(). */
+ rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
+ if (!rng || !rng->get_bytes(rng, AKA_RAND_LEN, rand))
+ {
+ DBG1(DBG_IKE, "generating RAND for AKA failed");
+ DESTROY_IF(rng);
+ return FALSE;
+ }
+ rng->destroy(rng);
+ DBG3(DBG_IKE, "generated rand %b", rand, AKA_RAND_LEN);
+
+ if (!eap_aka_3gpp_get_k_opc(id, k, opc))
+ {
+ DBG1(DBG_IKE, "no EAP key found for %Y to authenticate with AKA", id);
+ return FALSE;
+ }
+ DBG4(DBG_IKE, "EAP key found for id %Y, using K %b and OPc %b", id, k,
+ AKA_K_LEN, opc, AKA_OPC_LEN);
+
+ /* generate MAC and XRES, CK, IK, AK */
+ if (!this->f->f1(this->f, k, opc, rand, this->sqn, amf, maca) ||
+ !this->f->f2345(this->f, k, opc, rand, xres, ck, ik, ak))
+ {
+ return FALSE;
+ }
+ *xres_len = AKA_RES_LEN;
+
+ /* create AUTN = (SQN xor AK) || AMF || MAC */
+ memcpy(autn, this->sqn, AKA_SQN_LEN);
+ memxor(autn, ak, AKA_AK_LEN);
+ memcpy(autn + AKA_SQN_LEN, amf, AKA_AMF_LEN);
+ memcpy(autn + AKA_SQN_LEN + AKA_AMF_LEN, maca, AKA_MAC_LEN);
+ DBG3(DBG_IKE, "AUTN %b", autn, AKA_AUTN_LEN);
+
+ chunk_increment(chunk_create(this->sqn, AKA_SQN_LEN));
+
+ return TRUE;
+}
+
+METHOD(simaka_provider_t, resync, bool,
+ private_eap_aka_3gpp_provider_t *this, identification_t *id,
+ char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN])
+{
+ uint8_t *sqn, *macs;
+ uint8_t aks[AKA_AK_LEN], k[AKA_K_LEN], opc[AKA_OPC_LEN], amfs[AKA_AMF_LEN],
+ xmacs[AKA_MAC_LEN];
+
+ if (!eap_aka_3gpp_get_k_opc(id, k, opc))
+ {
+ DBG1(DBG_IKE, "no EAP key found for %Y to authenticate with AKA", id);
+ return FALSE;
+ }
+ DBG4(DBG_IKE, "EAP key found for id %Y, using K %b and OPc %b", id, k,
+ AKA_K_LEN, opc, AKA_OPC_LEN);
+
+ /* get SQNms out of the AUTS the card created as:
+ * AUTS = (SQNms xor AKS) || MAC-S */
+ sqn = auts;
+ macs = auts + AKA_SQN_LEN;
+ if (!this->f->f5star(this->f, k, opc, rand, aks))
+ {
+ return FALSE;
+ }
+ memxor(sqn, aks, AKA_AK_LEN);
+
+ /* generate resync XMAC-S... */
+ memset(amfs, 0, AKA_AMF_LEN);
+ if (!this->f->f1star(this->f, k, opc, rand, sqn, amfs, xmacs))
+ {
+ return FALSE;
+ }
+ /* ...and compare it with the card's MAC-S */
+ if (!memeq_const(xmacs, macs, AKA_MAC_LEN))
+ {
+ DBG1(DBG_IKE, "received MACS does not match XMACS");
+ DBG3(DBG_IKE, "MACS %b XMACS %b",
+ macs, AKA_MAC_LEN, xmacs, AKA_MAC_LEN);
+ return FALSE;
+ }
+ /* update stored SQN to received SQN + 1 */
+ memcpy(this->sqn, sqn, AKA_SQN_LEN);
+ chunk_increment(chunk_create(this->sqn, AKA_SQN_LEN));
+ return TRUE;
+}
+
+METHOD(eap_aka_3gpp_provider_t, destroy, void,
+ private_eap_aka_3gpp_provider_t *this)
+{
+ free(this);
+}
+
+/**
+ * See header
+ */
+eap_aka_3gpp_provider_t *eap_aka_3gpp_provider_create(
+ eap_aka_3gpp_functions_t *f)
+{
+ private_eap_aka_3gpp_provider_t *this;
+
+ INIT(this,
+ .public = {
+ .provider = {
+ .get_triplet = (void*)return_false,
+ .get_quintuplet = _get_quintuplet,
+ .resync = _resync,
+ .is_pseudonym = (void*)return_null,
+ .gen_pseudonym = (void*)return_null,
+ .is_reauth = (void*)return_null,
+ .gen_reauth = (void*)return_null,
+ },
+ .destroy = _destroy,
+ },
+ .f = f,
+ );
+ /* use an offset to accept clock skew between client/server without resync */
+ eap_aka_3gpp_get_sqn(this->sqn, SQN_TIME_OFFSET);
+
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_provider.h b/src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_provider.h
new file mode 100644
index 000000000..6af8b4b4f
--- /dev/null
+++ b/src/libcharon/plugins/eap_aka_3gpp/eap_aka_3gpp_provider.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2008-2009 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.
+ */
+/*
+ * Copyright (C) 2015 Thomas Strangert
+ * Polystar System AB, Sweden
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup eap_aka_3gpp_provider eap_aka_3gpp_provider
+ * @{ @ingroup eap_aka_3gpp
+ */
+
+#ifndef EAP_AKA_3GPP_PROVIDER_H_
+#define EAP_AKA_3GPP_PROVIDER_H_
+
+#include "eap_aka_3gpp_functions.h"
+
+#include <simaka_provider.h>
+
+typedef struct eap_aka_3gpp_provider_t eap_aka_3gpp_provider_t;
+
+/**
+ * SIM provider implementation using a set of AKA functions.
+ */
+struct eap_aka_3gpp_provider_t {
+
+ /**
+ * Implements simaka_provider_t interface.
+ */
+ simaka_provider_t provider;
+
+ /**
+ * Destroy a eap_aka_3gpp_provider_t.
+ */
+ void (*destroy)(eap_aka_3gpp_provider_t *this);
+};
+
+/**
+ * Create a eap_aka_3gpp_provider instance.
+ */
+eap_aka_3gpp_provider_t *eap_aka_3gpp_provider_create(
+ eap_aka_3gpp_functions_t *f);
+
+#endif /** EAP_AKA_3GPP_PROVIDER_H_ @}*/