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.
This commit is contained in:
Tobias Brunner 2017-05-16 17:34:02 +02:00
parent 7004a59a4c
commit 1aba82bfd7
16 changed files with 1395 additions and 2 deletions

View File

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

View File

@ -1 +0,0 @@
charon.plugins.eap-aka-3ggp2.seq_check =

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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