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 . + * + * 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 + +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 . + * + * 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 + +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 . + * + * 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 +#include +#include + +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 . + * + * 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 +#include +#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 . + * + * 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 + +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 . + * + * 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 + +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 . + * + * 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 + +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 . + * + * 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 + +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_ @}*/