27RCSID(
"$Id: f84f1e8c0201d0dadf05a5791d003adf05d25271 $")
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;
487 if (amf_vp) memcpy(amf_buff, amf_vp->vp_octets, amf_size);
505 keys->umts.vector.ik,
506 keys->umts.vector.ck,
507 keys->umts.vector.ak,
508 keys->umts.vector.xres,
513 keys->umts.vector.rand) < 0) {
514 RPEDEBUG2(
"Failed deriving UMTS Quintuplet");
523 memcpy(keys->auc.ki, ki_vp->vp_octets,
sizeof(keys->auc.ki));
524 memcpy(keys->auc.opc, opc_p,
sizeof(keys->auc.opc));
534 case FR_SIM_ALGO_VERSION_VALUE_TS_34_108_UMTS:
541 if (amf_vp) memcpy(amf_buff, amf_vp->vp_octets, amf_size);
543 RDEBUG3(
"TS-34-108-UMTS inputs");
549 ki_vp->vp_octets, ki_size,
552 sqn_buff,
sizeof(sqn_buff),
555 amf_buff,
sizeof(amf_buff),
560 keys->umts.vector.ik,
561 keys->umts.vector.ck,
562 keys->umts.vector.ak,
563 keys->umts.vector.xres,
567 keys->umts.vector.rand) < 0) {
568 RPEDEBUG2(
"Failed deriving UMTS Quintuplet");
577 memcpy(keys->auc.ki, ki_vp->vp_octets,
sizeof(keys->auc.ki));
593 fr_pair_t *rand_vp = NULL, *xres_vp = NULL, *ck_vp = NULL, *ik_vp = NULL;
594 fr_pair_t *autn_vp = NULL, *sqn_vp = NULL, *ak_vp = NULL;
606 REDEBUG(
"control.%s incorrect length. Expected "
622 REDEBUG(
"control.%s incorrect length. Expected "
623 STRINGIFY(EAP_AKA_XRES_MAX_SIZE)
" bytes, got %zu bytes",
638 REDEBUG(
"control.%s incorrect length. Expected "
669 REDEBUG(
"control.%s incorrect length. Expected < "
670 STRINGIFY(EAP_AKA_XRES_MAX_SIZE)
" bytes, got %zu bytes",
680 REDEBUG(
"control.%s incorrect length. Expected "
691 REDEBUG(
"control.%s incorrect length. Expected "
701 if (ak_vp && !sqn_vp) {
703 memcpy(keys->umts.vector.ak, ak_vp->vp_octets,
sizeof(keys->umts.vector.ak));
708 }
else if (sqn_vp && !ak_vp) {
709 keys->
sqn = sqn_vp->vp_uint64;
715 }
else if (sqn_vp && ak_vp) {
716 keys->
sqn = sqn_vp->vp_uint64;
717 memcpy(keys->umts.vector.ak, ak_vp->vp_octets,
sizeof(keys->umts.vector.ak));
724 memset(keys->umts.vector.ak, 0,
sizeof(keys->umts.vector.ak));
731 memcpy(keys->umts.vector.xres, xres_vp->vp_octets, xres_vp->vp_length);
732 keys->umts.vector.xres_len = xres_vp->vp_length;
768 if (ret < 0)
return -1;
778 if (ret < 0)
return -1;
783 RWDEBUG(
"Could not find or derive data for UMTS vector");
833 RDEBUG2(
"No session-state.%s attribute found, can't calculate re-auth keys",
837 counter_vp->vp_uint16++;
842 RDEBUG2(
"Neither session-state.%s or session-state.%s attributes found, "
848 REDEBUG(
"session-state.%s incorrect length. Expected %u bytes, got %zu bytes",
882 RDEBUG2(
"No session-state.%s attribute found, can't calculate re-auth keys",
886 counter_vp->vp_uint16++;
891 RDEBUG2(
"Neither session-state.%s or session-sate:%s attributes found, "
897 REDEBUG(
"session-state.%s incorrect length. Expected "
898 "%u bytes, got %zu bytes",
917 memset(&keys->reauth, 0,
sizeof(keys->reauth));
918 keys->vector_src = 0;
919 keys->vector_type = 0;
937 RDEBUG2(
"Original vectors were not generated locally, cannot perform AUTS validation");
942 REDEBUG(
"control.%s incorrect length. Expected "
948 if (
milenage_auts(new_sqn, keys->auc.opc, keys->auc.ki, keys->umts.vector.rand, auts_vp->vp_octets) < 0) {
949 REDEBUG(
"AUTS validation failed");
953 RDEBUG2(
"AUTS validation success, new SQN %"PRIu64, *new_sqn);
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
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.
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_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
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_rand
#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.
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.