27 RCSID(
"$Id: 82b6ad2e04adc92bf594689b7125b574b07121ec $")
29 #include <freeradius-devel/eap/base.h>
30 #include <freeradius-devel/eap/types.h>
31 #include <freeradius-devel/sim/common.h>
32 #include <freeradius-devel/sim/milenage.h>
33 #include <freeradius-devel/sim/ts_34_108.h>
34 #include <freeradius-devel/sim/comp128.h>
35 #include <freeradius-devel/protocol/freeradius/freeradius.internal.sim.h>
36 #include <freeradius-devel/util/rand.h>
41 #include <freeradius-devel/util/debug.h>
52 REDEBUG(
"&control.%s has incorrect length, expected %u bytes got %zu bytes",
56 *
out = opc_vp->vp_octets;
63 REDEBUG(
"&control.%s has incorrect length, expected %u bytes got %zu bytes",
95 REDEBUG(
"&control.%s has incorrect length, expected 16 bytes got %zu bytes",
106 if (
vector_opc_from_op(request, &opc_p, opc_buff, vps, ki_vp->vp_octets) < 0)
return -1;
107 version = opc_p ? FR_SIM_ALGO_VERSION_VALUE_COMP128_4 : FR_SIM_ALGO_VERSION_VALUE_COMP128_3;
113 version = version_vp->vp_uint32;
114 if (version == FR_SIM_ALGO_VERSION_VALUE_COMP128_4) {
115 if (
vector_opc_from_op(request, &opc_p, opc_buff, vps, ki_vp->vp_octets) < 0)
return -1;
117 RPEDEBUG2(
"No &control.%s or &control.%s found, "
126 memcpy(&keys->gsm.vector[idx].rand[i], &rand,
sizeof(rand));
130 case FR_SIM_ALGO_VERSION_VALUE_COMP128_1:
132 keys->gsm.vector[idx].kc,
134 keys->gsm.vector[idx].rand);
137 case FR_SIM_ALGO_VERSION_VALUE_COMP128_2:
139 keys->gsm.vector[idx].kc,
141 keys->gsm.vector[idx].rand,
true);
144 case FR_SIM_ALGO_VERSION_VALUE_COMP128_3:
146 keys->gsm.vector[idx].kc,
148 keys->gsm.vector[idx].rand,
false);
151 case FR_SIM_ALGO_VERSION_VALUE_COMP128_4:
153 keys->gsm.vector[idx].kc,
156 keys->gsm.vector[idx].rand) < 0) {
157 RPEDEBUG2(
"Failed deriving GSM triplet");
163 REDEBUG(
"Unknown/unsupported algorithm %i", version);
170 memcpy(keys->auc.ki, ki_vp->vp_octets,
sizeof(keys->auc.ki));
171 if (opc_p) memcpy(keys->auc.opc, opc_p,
sizeof(keys->auc.opc));
180 fr_pair_t *rand = NULL, *sres = NULL, *kc = NULL;
188 RDEBUG3(
"No &control.%s[%i] attribute found, not using GSM triplets",
202 RDEBUG3(
"No &control.%s[%i] attribute found, not using GSM triplets",
207 REDEBUG(
"&control.RAND[%i] is not " STRINGIFY(SIM_RAND_SIZE)
" bytes, got %zu bytes",
208 idx, rand->vp_length);
216 RDEBUG3(
"No &control.%s[%i] attribute found, not using GSM triplets",
242 fr_pair_t *ck = NULL, *ik = NULL, *rand = NULL, *xres = NULL;
253 RDEBUG3(
"No &control.%s[%i] attribute found, not using quintuplet derivation",
265 RDEBUG3(
"No &control.%s[%i] attribute found, not using quintuplet derivation",
277 RDEBUG3(
"No &control.%s[%i] attribute found, not using quintuplet derivation",
283 REDEBUG(
"&control.%s[%i] incorrect length. Expected "
296 RDEBUG3(
"No &control.%s[%i] attribute found, not using quintuplet derivation",
304 keys->gsm.vector[idx].kc,
346 if (ret < 0)
return -1;
356 if (ret < 0)
return -1;
366 if (ret < 0)
return -1;
371 RWDEBUG(
"Could not find or derive data for GSM vector[%i]", idx);
376 RDEBUG2(
"GSM vector[%i]", idx);
398 fr_pair_t *ki_vp, *amf_vp, *sqn_vp, *version_vp;
400 size_t ki_size, amf_size;
401 uint32_t version = FR_SIM_ALGO_VERSION_VALUE_MILENAGE;
408 if (version_vp) version = version_vp->vp_uint32;
414 case FR_SIM_ALGO_VERSION_VALUE_MILENAGE:
419 case FR_SIM_ALGO_VERSION_VALUE_TS_34_108_UMTS:
427 case FR_SIM_ALGO_VERSION_VALUE_COMP128_1:
428 case FR_SIM_ALGO_VERSION_VALUE_COMP128_2:
429 case FR_SIM_ALGO_VERSION_VALUE_COMP128_3:
430 case FR_SIM_ALGO_VERSION_VALUE_COMP128_4:
431 REDEBUG(
"COMP128-* algorithms cannot generate UMTS vectors");
435 REDEBUG(
"Unknown/unsupported algorithm %i", version);
444 RDEBUG3(
"No &control.%s found, not generating quintuplets locally",
attr_sim_ki->name);
446 }
else if (ki_vp->vp_length != ki_size) {
447 REDEBUG(
"&control.%s has incorrect length, expected %zu bytes got %zu bytes",
456 keys->
sqn = sqn_vp ? sqn_vp->vp_uint64 : 2;
463 if (amf_vp->vp_length != amf_size) {
464 REDEBUG(
"&control.%s has incorrect length, expected %zu bytes got %zu bytes",
475 memcpy(&keys->umts.vector.rand[i], &rand,
sizeof(rand));
479 case FR_SIM_ALGO_VERSION_VALUE_MILENAGE:
486 if (
vector_opc_from_op(request, &opc_p, opc_buff, vps, ki_vp->vp_octets) < 0)
return -1;
489 if (amf_vp) memcpy(amf_buff, amf_vp->vp_octets, amf_size);
507 keys->umts.vector.ik,
508 keys->umts.vector.ck,
509 keys->umts.vector.ak,
510 keys->umts.vector.xres,
515 keys->umts.vector.rand) < 0) {
516 RPEDEBUG2(
"Failed deriving UMTS Quintuplet");
525 memcpy(keys->auc.ki, ki_vp->vp_octets,
sizeof(keys->auc.ki));
526 memcpy(keys->auc.opc, opc_p,
sizeof(keys->auc.opc));
536 case FR_SIM_ALGO_VERSION_VALUE_TS_34_108_UMTS:
543 if (amf_vp) memcpy(amf_buff, amf_vp->vp_octets, amf_size);
545 RDEBUG3(
"TS-34-108-UMTS inputs");
551 ki_vp->vp_octets, ki_size,
554 sqn_buff,
sizeof(sqn_buff),
557 amf_buff,
sizeof(amf_buff),
562 keys->umts.vector.ik,
563 keys->umts.vector.ck,
564 keys->umts.vector.ak,
565 keys->umts.vector.xres,
569 keys->umts.vector.rand) < 0) {
570 RPEDEBUG2(
"Failed deriving UMTS Quintuplet");
579 memcpy(keys->auc.ki, ki_vp->vp_octets,
sizeof(keys->auc.ki));
595 fr_pair_t *rand_vp = NULL, *xres_vp = NULL, *ck_vp = NULL, *ik_vp = NULL;
596 fr_pair_t *autn_vp = NULL, *sqn_vp = NULL, *ak_vp = NULL;
608 REDEBUG(
"&control.%s incorrect length. Expected "
624 REDEBUG(
"&control.%s incorrect length. Expected "
625 STRINGIFY(EAP_AKA_XRES_MAX_SIZE)
" bytes, got %zu bytes",
640 REDEBUG(
"&control.%s incorrect length. Expected "
671 REDEBUG(
"&control.%s incorrect length. Expected < "
672 STRINGIFY(EAP_AKA_XRES_MAX_SIZE)
" bytes, got %zu bytes",
682 REDEBUG(
"&control.%s incorrect length. Expected "
693 REDEBUG(
"&control.%s incorrect length. Expected "
703 if (ak_vp && !sqn_vp) {
705 memcpy(keys->umts.vector.ak, ak_vp->vp_octets,
sizeof(keys->umts.vector.ak));
710 }
else if (sqn_vp && !ak_vp) {
711 keys->
sqn = sqn_vp->vp_uint64;
717 }
else if (sqn_vp && ak_vp) {
718 keys->
sqn = sqn_vp->vp_uint64;
719 memcpy(keys->umts.vector.ak, ak_vp->vp_octets,
sizeof(keys->umts.vector.ak));
726 memset(keys->umts.vector.ak, 0,
sizeof(keys->umts.vector.ak));
733 memcpy(keys->umts.vector.xres, xres_vp->vp_octets, xres_vp->vp_length);
734 keys->umts.vector.xres_len = xres_vp->vp_length;
770 if (ret < 0)
return -1;
780 if (ret < 0)
return -1;
785 RWDEBUG(
"Could not find or derive data for UMTS vector");
835 RDEBUG2(
"No &session-state.%s attribute found, can't calculate re-auth keys",
839 counter_vp->vp_uint16++;
844 RDEBUG2(
"Neither &session-state.%s or &session-state.%s attributes found, "
850 REDEBUG(
"&session-state.%s incorrect length. Expected %u bytes, got %zu bytes",
884 RDEBUG2(
"No &session-state.%s attribute found, can't calculate re-auth keys",
888 counter_vp->vp_uint16++;
893 RDEBUG2(
"Neither &session-state.%s or &session-sate:%s attributes found, "
899 REDEBUG(
"&session-state.%s incorrect length. Expected "
900 "%u bytes, got %zu bytes",
919 memset(&keys->reauth, 0,
sizeof(keys->reauth));
920 keys->vector_src = 0;
921 keys->vector_type = 0;
939 RDEBUG2(
"Original vectors were not generated locally, cannot perform AUTS validation");
944 REDEBUG(
"&control.%s incorrect length. Expected "
950 if (
milenage_auts(new_sqn, keys->auc.opc, keys->auc.ki, keys->umts.vector.rand, auts_vp->vp_octets) < 0) {
951 REDEBUG(
"AUTS validation failed");
955 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(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.
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.
#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.