27RCSID(
"$Id: e0508c569b43a122b63f284d252e18d1ea16c526 $")
29#include <freeradius-devel/eap/base.h>
30#include <freeradius-devel/sim/common.h>
31#include <freeradius-devel/sim/milenage.h>
32#include <freeradius-devel/sim/ts_34_108.h>
33#include <freeradius-devel/sim/comp128.h>
34#include <freeradius-devel/protocol/freeradius/freeradius.internal.sim.h>
35#include <freeradius-devel/util/rand.h>
50 REDEBUG(
"control.%s has incorrect length, expected %d bytes got %zu bytes",
54 *
out = opc_vp->vp_octets;
61 REDEBUG(
"control.%s has incorrect length, expected %d bytes got %zu bytes",
93 REDEBUG(
"control.%s has incorrect length, expected 16 bytes got %zu bytes",
104 if (
vector_opc_from_op(request, &opc_p, opc_buff, vps, ki_vp->vp_octets) < 0)
return -1;
105 version = opc_p ? FR_SIM_ALGO_VERSION_VALUE_COMP128_4 : FR_SIM_ALGO_VERSION_VALUE_COMP128_3;
111 version = version_vp->vp_uint32;
112 if (version == FR_SIM_ALGO_VERSION_VALUE_COMP128_4) {
113 if (
vector_opc_from_op(request, &opc_p, opc_buff, vps, ki_vp->vp_octets) < 0)
return -1;
115 RPEDEBUG2(
"No control.%s or control.%s found, "
124 memcpy(&keys->gsm.vector[idx].rand[i], &rand,
sizeof(rand));
128 case FR_SIM_ALGO_VERSION_VALUE_COMP128_1:
130 keys->gsm.vector[idx].kc,
132 keys->gsm.vector[idx].rand);
135 case FR_SIM_ALGO_VERSION_VALUE_COMP128_2:
137 keys->gsm.vector[idx].kc,
139 keys->gsm.vector[idx].rand,
true);
142 case FR_SIM_ALGO_VERSION_VALUE_COMP128_3:
144 keys->gsm.vector[idx].kc,
146 keys->gsm.vector[idx].rand,
false);
149 case FR_SIM_ALGO_VERSION_VALUE_COMP128_4:
151 keys->gsm.vector[idx].kc,
154 keys->gsm.vector[idx].rand) < 0) {
155 RPEDEBUG2(
"Failed deriving GSM triplet");
161 REDEBUG(
"Unknown/unsupported algorithm %u", version);
168 memcpy(keys->auc.ki, ki_vp->vp_octets,
sizeof(keys->auc.ki));
169 if (opc_p) memcpy(keys->auc.opc, opc_p,
sizeof(keys->auc.opc));
178 fr_pair_t *rand = NULL, *sres = NULL, *kc = NULL;
186 RDEBUG3(
"No control.%s[%i] attribute found, not using GSM triplets",
200 RDEBUG3(
"No control.%s[%i] attribute found, not using GSM triplets",
205 REDEBUG(
"control.RAND[%i] is not " STRINGIFY(SIM_RAND_SIZE)
" bytes, got %zu bytes",
206 idx, rand->vp_length);
214 RDEBUG3(
"No control.%s[%i] attribute found, not using GSM triplets",
240 fr_pair_t *ck = NULL, *ik = NULL, *rand = NULL, *xres = NULL;
251 RDEBUG3(
"No control.%s[%i] attribute found, not using quintuplet derivation",
263 RDEBUG3(
"No control.%s[%i] attribute found, not using quintuplet derivation",
275 RDEBUG3(
"No control.%s[%i] attribute found, not using quintuplet derivation",
281 REDEBUG(
"control.%s[%i] incorrect length. Expected "
294 RDEBUG3(
"No control.%s[%i] attribute found, not using quintuplet derivation",
302 keys->gsm.vector[idx].kc,
344 if (ret < 0)
return -1;
354 if (ret < 0)
return -1;
364 if (ret < 0)
return -1;
369 RWDEBUG(
"Could not find or derive data for GSM vector[%i]", idx);
374 RDEBUG2(
"GSM vector[%i]", idx);
396 fr_pair_t *ki_vp, *amf_vp, *sqn_vp, *version_vp;
398 size_t ki_size, amf_size;
399 uint32_t version = FR_SIM_ALGO_VERSION_VALUE_MILENAGE;
406 if (version_vp) version = version_vp->vp_uint32;
412 case FR_SIM_ALGO_VERSION_VALUE_MILENAGE:
417 case FR_SIM_ALGO_VERSION_VALUE_TS_34_108_UMTS:
425 case FR_SIM_ALGO_VERSION_VALUE_COMP128_1:
426 case FR_SIM_ALGO_VERSION_VALUE_COMP128_2:
427 case FR_SIM_ALGO_VERSION_VALUE_COMP128_3:
428 case FR_SIM_ALGO_VERSION_VALUE_COMP128_4:
429 REDEBUG(
"COMP128-* algorithms cannot generate UMTS vectors");
433 REDEBUG(
"Unknown/unsupported algorithm %u", version);
442 RDEBUG3(
"No control.%s found, not generating quintuplets locally",
attr_sim_ki->name);
444 }
else if (ki_vp->vp_length != ki_size) {
445 REDEBUG(
"control.%s has incorrect length, expected %zu bytes got %zu bytes",
454 keys->
sqn = sqn_vp ? sqn_vp->vp_uint64 : 2;
461 if (amf_vp->vp_length != amf_size) {
462 REDEBUG(
"control.%s has incorrect length, expected %zu bytes got %zu bytes",
473 memcpy(&keys->umts.vector.rand[i], &rand,
sizeof(rand));
477 case FR_SIM_ALGO_VERSION_VALUE_MILENAGE:
484 if (
vector_opc_from_op(request, &opc_p, opc_buff, vps, ki_vp->vp_octets) < 0)
return -1;
486 RPEDEBUG2(
"No control.%s or control.%s found, "
492 if (amf_vp) memcpy(amf_buff, amf_vp->vp_octets, amf_size);
510 keys->umts.vector.ik,
511 keys->umts.vector.ck,
512 keys->umts.vector.ak,
513 keys->umts.vector.xres,
518 keys->umts.vector.rand) < 0) {
519 RPEDEBUG2(
"Failed deriving UMTS Quintuplet");
528 memcpy(keys->auc.ki, ki_vp->vp_octets,
sizeof(keys->auc.ki));
529 memcpy(keys->auc.opc, opc_p,
sizeof(keys->auc.opc));
539 case FR_SIM_ALGO_VERSION_VALUE_TS_34_108_UMTS:
546 if (amf_vp) memcpy(amf_buff, amf_vp->vp_octets, amf_size);
548 RDEBUG3(
"TS-34-108-UMTS inputs");
554 ki_vp->vp_octets, ki_size,
557 sqn_buff,
sizeof(sqn_buff),
560 amf_buff,
sizeof(amf_buff),
565 keys->umts.vector.ik,
566 keys->umts.vector.ck,
567 keys->umts.vector.ak,
568 keys->umts.vector.xres,
572 keys->umts.vector.rand) < 0) {
573 RPEDEBUG2(
"Failed deriving UMTS Quintuplet");
582 memcpy(keys->auc.ki, ki_vp->vp_octets,
sizeof(keys->auc.ki));
598 fr_pair_t *rand_vp = NULL, *xres_vp = NULL, *ck_vp = NULL, *ik_vp = NULL;
599 fr_pair_t *autn_vp = NULL, *sqn_vp = NULL, *ak_vp = NULL;
611 REDEBUG(
"control.%s incorrect length. Expected "
627 REDEBUG(
"control.%s incorrect length. Expected "
628 STRINGIFY(EAP_AKA_XRES_MAX_SIZE)
" bytes, got %zu bytes",
643 REDEBUG(
"control.%s incorrect length. Expected "
674 REDEBUG(
"control.%s incorrect length. Expected < "
675 STRINGIFY(EAP_AKA_XRES_MAX_SIZE)
" bytes, got %zu bytes",
685 REDEBUG(
"control.%s incorrect length. Expected "
696 REDEBUG(
"control.%s incorrect length. Expected "
706 if (ak_vp && !sqn_vp) {
708 memcpy(keys->umts.vector.ak, ak_vp->vp_octets,
sizeof(keys->umts.vector.ak));
713 }
else if (sqn_vp && !ak_vp) {
714 keys->
sqn = sqn_vp->vp_uint64;
720 }
else if (sqn_vp && ak_vp) {
721 keys->
sqn = sqn_vp->vp_uint64;
722 memcpy(keys->umts.vector.ak, ak_vp->vp_octets,
sizeof(keys->umts.vector.ak));
729 memset(keys->umts.vector.ak, 0,
sizeof(keys->umts.vector.ak));
736 memcpy(keys->umts.vector.xres, xres_vp->vp_octets, xres_vp->vp_length);
737 keys->umts.vector.xres_len = xres_vp->vp_length;
773 if (ret < 0)
return -1;
783 if (ret < 0)
return -1;
788 RWDEBUG(
"Could not find or derive data for UMTS vector");
838 RDEBUG2(
"No session-state.%s attribute found, can't calculate re-auth keys",
842 counter_vp->vp_uint16++;
847 RDEBUG2(
"Neither session-state.%s or session-state.%s attributes found, "
853 REDEBUG(
"session-state.%s incorrect length. Expected %u bytes, got %zu bytes",
887 RDEBUG2(
"No session-state.%s attribute found, can't calculate re-auth keys",
891 counter_vp->vp_uint16++;
896 RDEBUG2(
"Neither session-state.%s or session-sate:%s attributes found, "
902 REDEBUG(
"session-state.%s incorrect length. Expected "
903 "%u bytes, got %zu bytes",
922 memset(&keys->reauth, 0,
sizeof(keys->reauth));
923 keys->vector_src = 0;
924 keys->vector_type = 0;
942 RDEBUG2(
"Original vectors were not generated locally, cannot perform AUTS validation");
947 REDEBUG(
"control.%s incorrect length. Expected "
953 if (
milenage_auts(new_sqn, keys->auc.opc, keys->auc.ki, keys->umts.vector.rand, auts_vp->vp_octets) < 0) {
954 REDEBUG(
"AUTS validation failed");
958 RDEBUG2(
"AUTS validation success, new SQN %"PRIu64, *new_sqn);
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
void comp128v1(uint8_t sres[static 4], uint8_t kc[static 8], uint8_t const ki[static 16], uint8_t const rand[static 16])
Calculate comp128v1 sres and kc from ki and rand.
void comp128v23(uint8_t sres[static 4], uint8_t kc[static 8], uint8_t const ki[static 16], uint8_t const rand[static 16], bool v2)
Calculate comp128v2 or comp128v3 sres and kc from ki and rand.
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
#define AKA_SIM_VECTOR_UMTS_RAND_SIZE
#define AKA_SIM_VECTOR_GSM_RAND_SIZE
Length of RAND in GSM triplet.
#define AKA_SIM_VECTOR_GSM_SRES_SIZE
Length of SRES in GSM triplet.
void fr_aka_sim_crypto_keys_init_umts_kdf_1_reauth(fr_aka_sim_keys_t *keys, uint8_t const mk[static AKA_PRIME_MK_REAUTH_SIZE], uint16_t counter)
Initialise fr_aka_sim_keys_t with EAP-AKA['] reauthentication data.
uint64_t sqn
Sequence number.
#define AKA_PRIME_MK_REAUTH_SIZE
The portion of the MK used for re-auth.
fr_aka_sim_vector_src_t
Where to get EAP-SIM vectors from.
@ AKA_SIM_VECTOR_SRC_REAUTH
Not a vector.
@ AKA_SIM_VECTOR_SRC_AUTO
Discover where to get Triplets from automatically.
@ AKA_SIM_VECTOR_SRC_QUINTUPLETS
Source of triplets is derived from EAP-AKA-* quintuplets.
@ AKA_SIM_VECTOR_SRC_KI
Should generate triplets locally using a Ki.
@ AKA_SIM_VECTOR_SRC_TRIPLETS
Source of triplets is EAP-SIM-* attributes.
#define AKA_SIM_VECTOR_UMTS_XRES_MAX_SIZE
#define AKA_SIM_VECTOR_UMTS_CK_SIZE
void fr_aka_sim_crypto_keys_init_kdf_0_reauth(fr_aka_sim_keys_t *keys, uint8_t const mk[static AKA_SIM_MK_SIZE], uint16_t counter)
Initialise fr_aka_sim_keys_t with EAP-SIM reauthentication data.
#define AKA_SIM_VECTOR_GSM_KC_SIZE
Length of Kc in GSM triplet.
#define AKA_SIM_VECTOR_UMTS_IK_SIZE
#define AKA_SIM_VECTOR_UMTS_AUTN_SIZE
@ AKA_SIM_VECTOR_GSM
Vector is GSM triplets.
@ AKA_SIM_VECTOR_UMTS_REAUTH_KDF_1_REAUTH
@ AKA_SIM_VECTOR_UMTS
Vector is UMTS quintuplets.
@ AKA_SIM_VECTOR_UMTS_REAUTH_KDF_0_REAUTH
Master key state struct for all SIMlike EAP protocols.
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_counter
HIDDEN fr_dict_attr_t const * attr_session_data
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_ak
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_mk
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_auts
HIDDEN fr_dict_attr_t const * attr_sim_algo_version
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_xres
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_sres
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_ik
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_autn
HIDDEN fr_dict_attr_t const * attr_sim_opc
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_rand
HIDDEN fr_dict_attr_t const * attr_sim_ki
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_kc
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_ck
HIDDEN fr_dict_attr_t const * attr_sim_sqn
HIDDEN fr_dict_attr_t const * attr_sim_op
HIDDEN fr_dict_attr_t const * attr_sim_amf
#define REXDENT()
Exdent (unindent) R* messages by one level.
#define RHEXDUMP_INLINE2(_data, _len, _fmt,...)
#define RPEDEBUG(fmt,...)
#define RHEXDUMP_INLINE3(_data, _len, _fmt,...)
#define RPEDEBUG2(fmt,...)
#define RINDENT()
Indent R* messages by one level.
static uint8_t * uint48_to_buff(uint8_t out[static 6], uint64_t i)
Copy a 48bit value from a 64bit integer into a uint8_t buff in big endian byte order.
static uint64_t uint48_from_buff(uint8_t const in[6])
Convert a 48bit big endian value into a unsigned 64bit integer.
int milenage_umts_generate(uint8_t autn[MILENAGE_AUTN_SIZE], uint8_t ik[MILENAGE_IK_SIZE], uint8_t ck[MILENAGE_CK_SIZE], uint8_t ak[MILENAGE_AK_SIZE], uint8_t res[MILENAGE_RES_SIZE], uint8_t const opc[MILENAGE_OPC_SIZE], uint8_t const amf[MILENAGE_AMF_SIZE], uint8_t const ki[MILENAGE_KI_SIZE], uint64_t sqn, uint8_t const rand[MILENAGE_RAND_SIZE])
Generate AKA AUTN, IK, CK, RES.
int milenage_auts(uint64_t *sqn, uint8_t const opc[MILENAGE_OPC_SIZE], uint8_t const ki[MILENAGE_KI_SIZE], uint8_t const rand[MILENAGE_RAND_SIZE], uint8_t const auts[MILENAGE_AUTS_SIZE])
Milenage AUTS validation.
void milenage_gsm_from_umts(uint8_t sres[MILENAGE_SRES_SIZE], uint8_t kc[MILENAGE_KC_SIZE], uint8_t const ik[MILENAGE_IK_SIZE], uint8_t const ck[MILENAGE_CK_SIZE], uint8_t const res[MILENAGE_RES_SIZE])
Generate GSM-Milenage (3GPP TS 55.205) authentication triplet from a quintuplet.
int milenage_gsm_generate(uint8_t sres[MILENAGE_SRES_SIZE], uint8_t kc[MILENAGE_KC_SIZE], uint8_t const opc[MILENAGE_OPC_SIZE], uint8_t const ki[MILENAGE_KI_SIZE], uint8_t const rand[MILENAGE_RAND_SIZE])
Generate GSM-Milenage (3GPP TS 55.205) authentication triplet.
int milenage_opc_generate(uint8_t opc[MILENAGE_OPC_SIZE], uint8_t const op[MILENAGE_OP_SIZE], uint8_t const ki[MILENAGE_KI_SIZE])
Derive OPc from OP and Ki.
#define MILENAGE_AK_SIZE
Anonymisation key.
#define MILENAGE_SQN_SIZE
Sequence number.
#define MILENAGE_AMF_SIZE
Authentication management field.
#define MILENAGE_KI_SIZE
Subscriber key.
#define MILENAGE_OP_SIZE
Operator code (unique to the operator)
#define MILENAGE_AUTS_SIZE
#define MILENAGE_OPC_SIZE
Derived operator code (unique to the operator and subscriber).
#define MILENAGE_RES_SIZE
fr_pair_t * fr_pair_find_by_da_nested(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find a pair with a matching fr_dict_attr_t, by walking the nested fr_dict_attr_t tree.
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
#define RDEBUG_ENABLED2()
uint32_t fr_rand(void)
Return a 32-bit random number.
Stores an attribute, a value and various bits of other data.
int ts_34_108_umts_generate(uint8_t autn[TS_34_108_AUTN_SIZE], uint8_t ik[TS_34_108_IK_SIZE], uint8_t ck[TS_34_108_CK_SIZE], uint8_t ak[TS_34_108_AK_SIZE], uint8_t res[TS_34_108_RES_SIZE], uint8_t const amf[TS_34_108_AMF_SIZE], uint8_t const ki[TS_34_108_KI_SIZE], uint64_t sqn, uint8_t const rand[TS_34_108_RAND_SIZE])
#define TS_34_108_KI_SIZE
Subscriber key.
#define TS_34_108_SQN_SIZE
Sequence number.
#define TS_34_108_AMF_SIZE
Authentication management field.
#define TS_34_108_RES_SIZE
Master include file to access all functions and structures in the library.
#define fr_pair_dcursor_by_da_init(_cursor, _list, _da)
Initialise a cursor that will return only attributes matching the specified fr_dict_attr_t.
static size_t char ** out
static int vector_umts_from_quintuplets(request_t *request, fr_pair_list_t *vps, fr_aka_sim_keys_t *keys)
Get one set of quintuplets from the request.
int fr_aka_sim_vector_gsm_umts_kdf_0_reauth_from_attrs(request_t *request, fr_pair_list_t *vps, fr_aka_sim_keys_t *keys)
Populate a fr_aka_sim_keys_t structure from attributes in the session-state list.
static int vector_umts_from_ki(request_t *request, fr_pair_list_t *vps, fr_aka_sim_keys_t *keys)
static int vector_opc_from_op(request_t *request, uint8_t const **out, uint8_t opc_buff[MILENAGE_OPC_SIZE], fr_pair_list_t *list, uint8_t const ki[MILENAGE_KI_SIZE])
void fr_aka_sim_vector_umts_reauth_clear(fr_aka_sim_keys_t *keys)
Clear reauth data if reauthentication failed.
static int vector_gsm_from_quintuplets(request_t *request, fr_pair_list_t *vps, int idx, fr_aka_sim_keys_t *keys)
Derive triplets from quintuplets.
int fr_aka_sim_vector_gsm_from_attrs(request_t *request, fr_pair_list_t *vps, int idx, fr_aka_sim_keys_t *keys, fr_aka_sim_vector_src_t *src)
Retrieve GSM triplets from sets of attributes.
static int vector_gsm_from_ki(request_t *request, fr_pair_list_t *vps, int idx, fr_aka_sim_keys_t *keys)
int fr_aka_sim_vector_umts_kdf_1_reauth_from_attrs(request_t *request, fr_pair_list_t *vps, fr_aka_sim_keys_t *keys)
Populate a fr_aka_sim_keys_t structure from attributes in the session-state list.
static int vector_gsm_from_triplets(request_t *request, fr_pair_list_t *vps, int idx, fr_aka_sim_keys_t *keys)
int fr_aka_sim_umts_resync_from_attrs(uint64_t *new_sqn, request_t *request, fr_pair_t *auts_vp, fr_aka_sim_keys_t *keys)
Perform milenage AUTS validation and resynchronisation.
int fr_aka_sim_vector_umts_from_attrs(request_t *request, fr_pair_list_t *vps, fr_aka_sim_keys_t *keys, fr_aka_sim_vector_src_t *src)
Retrieve UMTS quintuplets from sets of attributes.