The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
vector.c
Go to the documentation of this file.
1 /*
2  * This program is is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or (at
5  * your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: 82b6ad2e04adc92bf594689b7125b574b07121ec $
19  * @file src/lib/eap_aka_sim/vector.c
20  * @brief Retrieve or derive vectors for EAP-SIM.
21  *
22  * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23  *
24  * @copyright 2016 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
25  * @copyright 2016 The FreeRADIUS server project
26  */
27 RCSID("$Id: 82b6ad2e04adc92bf594689b7125b574b07121ec $")
28 
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>
37 
38 #include "base.h"
39 #include "attrs.h"
40 
41 #include <freeradius-devel/util/debug.h>
42 
43 static int vector_opc_from_op(request_t *request, uint8_t const **out, uint8_t opc_buff[MILENAGE_OPC_SIZE],
44  fr_pair_list_t *list, uint8_t const ki[MILENAGE_KI_SIZE])
45 {
46  fr_pair_t *opc_vp;
47  fr_pair_t *op_vp;
48 
49  opc_vp = fr_pair_find_by_da(list, NULL, attr_sim_opc);
50  if (opc_vp) {
51  if (opc_vp->vp_length != MILENAGE_OPC_SIZE) {
52  REDEBUG("&control.%s has incorrect length, expected %u bytes got %zu bytes",
53  attr_sim_opc->name, MILENAGE_OPC_SIZE, opc_vp->vp_length);
54  return -1;
55  }
56  *out = opc_vp->vp_octets;
57  return 0;
58  }
59 
60  op_vp = fr_pair_find_by_da(list, NULL, attr_sim_op);
61  if (op_vp) {
62  if (op_vp->vp_length != MILENAGE_OP_SIZE) {
63  REDEBUG("&control.%s has incorrect length, expected %u bytes got %zu bytes",
64  attr_sim_op->name, MILENAGE_OP_SIZE, op_vp->vp_length);
65  return -1;
66  }
67  if (milenage_opc_generate(opc_buff, op_vp->vp_octets, ki) < 0) {
68  RPEDEBUG("Deriving OPc failed");
69  return -1;
70  }
71  *out = opc_buff;
72  return 0;
73  }
74 
75  *out = NULL;
76  return 1;
77 }
78 
79 static int vector_gsm_from_ki(request_t *request, fr_pair_list_t *vps, int idx, fr_aka_sim_keys_t *keys)
80 {
81  fr_pair_t *ki_vp, *version_vp;
82  uint8_t opc_buff[MILENAGE_OPC_SIZE];
83  uint8_t const *opc_p = NULL;
84  uint32_t version;
85  unsigned int i;
86 
87  /*
88  * Generate a new RAND value, and derive Kc and SRES from Ki
89  */
90  ki_vp = fr_pair_find_by_da(vps, NULL, attr_sim_ki);
91  if (!ki_vp) {
92  RDEBUG3("No &control.%sfound, not generating triplets locally", attr_sim_ki->name);
93  return 1;
94  } else if (ki_vp->vp_length != MILENAGE_KI_SIZE) {
95  REDEBUG("&control.%s has incorrect length, expected 16 bytes got %zu bytes",
96  attr_sim_ki->name, ki_vp->vp_length);
97  return -1;
98  }
99 
100  /*
101  * Check to see if we have a Ki for the IMSI, this allows us to generate the rest
102  * of the triplets.
103  */
104  version_vp = fr_pair_find_by_da(vps, NULL, attr_sim_algo_version);
105  if (!version_vp) {
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;
108  /*
109  * Version was explicitly specified, see if we can find the prerequisite
110  * attributes.
111  */
112  } else {
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;
116  if (!opc_p) {
117  RPEDEBUG2("No &control.%s or &control.%s found, "
118  "can't run Milenage (COMP128-4)", attr_sim_op->name, attr_sim_opc->name);
119  return -1;
120  }
121  }
122  }
123 
124  for (i = 0; i < AKA_SIM_VECTOR_GSM_RAND_SIZE; i += sizeof(uint32_t)) {
125  uint32_t rand = fr_rand();
126  memcpy(&keys->gsm.vector[idx].rand[i], &rand, sizeof(rand));
127  }
128 
129  switch (version) {
130  case FR_SIM_ALGO_VERSION_VALUE_COMP128_1:
131  comp128v1(keys->gsm.vector[idx].sres,
132  keys->gsm.vector[idx].kc,
133  ki_vp->vp_octets,
134  keys->gsm.vector[idx].rand);
135  break;
136 
137  case FR_SIM_ALGO_VERSION_VALUE_COMP128_2:
138  comp128v23(keys->gsm.vector[idx].sres,
139  keys->gsm.vector[idx].kc,
140  ki_vp->vp_octets,
141  keys->gsm.vector[idx].rand, true);
142  break;
143 
144  case FR_SIM_ALGO_VERSION_VALUE_COMP128_3:
145  comp128v23(keys->gsm.vector[idx].sres,
146  keys->gsm.vector[idx].kc,
147  ki_vp->vp_octets,
148  keys->gsm.vector[idx].rand, false);
149  break;
150 
151  case FR_SIM_ALGO_VERSION_VALUE_COMP128_4:
152  if (milenage_gsm_generate(keys->gsm.vector[idx].sres,
153  keys->gsm.vector[idx].kc,
154  opc_p,
155  ki_vp->vp_octets,
156  keys->gsm.vector[idx].rand) < 0) {
157  RPEDEBUG2("Failed deriving GSM triplet");
158  return -1;
159  }
160  break;
161 
162  default:
163  REDEBUG("Unknown/unsupported algorithm %i", version);
164  return -1;
165  }
166 
167  /*
168  * Store for completeness...
169  */
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));
172  keys->vector_src = AKA_SIM_VECTOR_SRC_KI;
173 
174  return 0;
175 }
176 
178  int idx, fr_aka_sim_keys_t *keys)
179 {
180  fr_pair_t *rand = NULL, *sres = NULL, *kc = NULL;
181  fr_dcursor_t cursor;
182  int i;
183 
184  for (i = 0, (kc = fr_pair_dcursor_by_da_init(&cursor, vps, attr_eap_aka_sim_kc));
185  (i < idx) && (kc = fr_dcursor_next(&cursor));
186  i++);
187  if (!kc) {
188  RDEBUG3("No &control.%s[%i] attribute found, not using GSM triplets",
189  attr_eap_aka_sim_kc->name, idx);
190  return 1;
191  }
192  if (kc->vp_length != AKA_SIM_VECTOR_GSM_KC_SIZE) {
193  REDEBUG("&control.%s[%i] is not " STRINGIFY(AKA_SIM_VECTOR_GSM_KC_SIZE) " bytes, got %zu bytes",
194  attr_eap_aka_sim_kc->name, idx, kc->vp_length);
195  return -1;
196  }
197 
198  for (i = 0, (rand = fr_pair_dcursor_by_da_init(&cursor, vps, attr_eap_aka_sim_rand));
199  (i < idx) && (rand = fr_dcursor_next(&cursor));
200  i++);
201  if (!rand) {
202  RDEBUG3("No &control.%s[%i] attribute found, not using GSM triplets",
203  attr_eap_aka_sim_rand->name, idx);
204  return 1;
205  }
206  if (rand->vp_length != AKA_SIM_VECTOR_GSM_RAND_SIZE) {
207  REDEBUG("&control.RAND[%i] is not " STRINGIFY(SIM_RAND_SIZE) " bytes, got %zu bytes",
208  idx, rand->vp_length);
209  return -1;
210  }
211 
212  for (i = 0, (sres = fr_pair_dcursor_by_da_init(&cursor, vps, attr_eap_aka_sim_sres));
213  (i < idx) && (sres = fr_dcursor_next(&cursor));
214  i++);
215  if (!sres) {
216  RDEBUG3("No &control.%s[%i] attribute found, not using GSM triplets",
217  attr_eap_aka_sim_sres->name, idx);
218  return 1;
219  }
220  if (sres->vp_length != AKA_SIM_VECTOR_GSM_SRES_SIZE) {
221  REDEBUG("&control.%s[%i] is not " STRINGIFY(AKA_SIM_VECTOR_GSM_SRES_SIZE) " bytes, got %zu bytes",
222  attr_eap_aka_sim_sres->name, idx, sres->vp_length);
223  return -1;
224  }
225 
226  memcpy(keys->gsm.vector[idx].kc, kc->vp_strvalue, AKA_SIM_VECTOR_GSM_KC_SIZE);
227  memcpy(keys->gsm.vector[idx].rand, rand->vp_octets, AKA_SIM_VECTOR_GSM_RAND_SIZE);
228  memcpy(keys->gsm.vector[idx].sres, sres->vp_octets, AKA_SIM_VECTOR_GSM_SRES_SIZE);
229  keys->vector_src = AKA_SIM_VECTOR_SRC_TRIPLETS;
230 
231  return 0;
232 }
233 
234 /** Derive triplets from quintuplets
235  *
236  */
238  int idx, fr_aka_sim_keys_t *keys)
239 {
240  fr_dcursor_t cursor;
241 
242  fr_pair_t *ck = NULL, *ik = NULL, *rand = NULL, *xres = NULL;
243 
244  int i;
245 
246  /*
247  * Fetch CK
248  */
249  for (i = 0, (ck = fr_pair_dcursor_by_da_init(&cursor, vps, attr_eap_aka_sim_ck));
250  (i < idx) && (ck = fr_dcursor_next(&cursor));
251  i++);
252  if (!ck) {
253  RDEBUG3("No &control.%s[%i] attribute found, not using quintuplet derivation",
254  attr_eap_aka_sim_ck->name, idx);
255  return 1;
256  }
257 
258  /*
259  * Fetch IK
260  */
261  for (i = 0, (ik = fr_pair_dcursor_by_da_init(&cursor, vps, attr_eap_aka_sim_ik));
262  (i < idx) && (ik = fr_dcursor_next(&cursor));
263  i++);
264  if (!ik) {
265  RDEBUG3("No &control.%s[%i] attribute found, not using quintuplet derivation",
266  attr_eap_aka_sim_ik->name, idx);
267  return 1;
268  }
269 
270  /*
271  * Fetch RAND
272  */
273  for (i = 0, (rand = fr_pair_dcursor_by_da_init(&cursor, vps, attr_eap_aka_sim_rand));
274  (i < idx) && (rand = fr_dcursor_next(&cursor));
275  i++);
276  if (!rand) {
277  RDEBUG3("No &control.%s[%i] attribute found, not using quintuplet derivation",
278  attr_eap_aka_sim_rand->name, idx);
279  return 1;
280  }
281 
282  if (rand->vp_length != AKA_SIM_VECTOR_UMTS_RAND_SIZE) {
283  REDEBUG("&control.%s[%i] incorrect length. Expected "
285  "got %zu bytes", attr_eap_aka_sim_rand->name, idx, rand->vp_length);
286  return -1;
287  }
288 
289  /*
290  * Fetch XRES
291  */
292  for (i = 0, (xres = fr_pair_dcursor_by_da_init(&cursor, vps, attr_eap_aka_sim_xres));
293  (i < idx) && (xres = fr_dcursor_next(&cursor));
294  i++);
295  if (!xres) {
296  RDEBUG3("No &control.%s[%i] attribute found, not using quintuplet derivation",
297  attr_eap_aka_sim_xres->name, idx);
298  return 1;
299  }
300 
301  memcpy(keys->gsm.vector[idx].rand, rand->vp_octets, AKA_SIM_VECTOR_GSM_RAND_SIZE);
302 
303  milenage_gsm_from_umts(keys->gsm.vector[idx].sres,
304  keys->gsm.vector[idx].kc,
305  ik->vp_octets,
306  ck->vp_octets,
307  xres->vp_octets);
308 
309  keys->vector_src = AKA_SIM_VECTOR_SRC_QUINTUPLETS;
310 
311  return 0;
312 }
313 
314 /** Retrieve GSM triplets from sets of attributes.
315  *
316  * Hunt for a source of SIM triplets
317  *
318  * @param[in] request The current subrequest.
319  * @param[in] vps List to hunt for triplets in.
320  * @param[in] idx To write EAP-SIM triplets to.
321  * @param[in] keys EAP session keys.
322  * @param[in] src Forces triplets to be retrieved from a particular src
323  * and ensures if multiple triplets are being retrieved
324  * that they all come from the same src.
325  * @return
326  * - 1 Vector could not be retrieved from the specified src.
327  * - 0 Vector was retrieved OK and written to the specified index.
328  * - -1 Error retrieving vector from the specified src.
329  */
331  int idx, fr_aka_sim_keys_t *keys, fr_aka_sim_vector_src_t *src)
332 {
333  int ret;
334 
335  fr_assert(idx >= 0 && idx < 3);
336  fr_assert((keys->vector_type == AKA_SIM_VECTOR_NONE) || (keys->vector_type == AKA_SIM_VECTOR_GSM));
337 
338  switch (*src) {
339  default:
341  ret = vector_gsm_from_ki(request, vps, idx, keys);
342  if (ret == 0) {
343  *src = AKA_SIM_VECTOR_SRC_KI;
344  break;
345  }
346  if (ret < 0) return -1;
347  if (*src != AKA_SIM_VECTOR_SRC_AUTO) return 1;
348  FALL_THROUGH;
349 
351  ret = vector_gsm_from_triplets(request, vps, idx, keys);
352  if (ret == 0) {
354  break;
355  }
356  if (ret < 0) return -1;
357  if (*src != AKA_SIM_VECTOR_SRC_AUTO) return 1;
358  FALL_THROUGH;
359 
361  ret = vector_gsm_from_quintuplets(request, vps, idx, keys);
362  if (ret == 0) {
364  break;
365  }
366  if (ret < 0) return -1;
367  break;
368  }
369 
370  if (ret == 1) {
371  RWDEBUG("Could not find or derive data for GSM vector[%i]", idx);
372  return 1;
373  }
374 
375  if (RDEBUG_ENABLED2) {
376  RDEBUG2("GSM vector[%i]", idx);
377 
378  RINDENT();
379  /*
380  * Don't change colon indent, matches other messages later...
381  */
382  RHEXDUMP_INLINE2(keys->gsm.vector[idx].kc, AKA_SIM_VECTOR_GSM_KC_SIZE,
383  "KC :");
384  RHEXDUMP_INLINE2(keys->gsm.vector[idx].rand, AKA_SIM_VECTOR_GSM_RAND_SIZE,
385  "RAND :");
386  RHEXDUMP_INLINE2(keys->gsm.vector[idx].sres, AKA_SIM_VECTOR_GSM_SRES_SIZE,
387  "SRES :");
388  REXDENT();
389  }
390 
391  keys->vector_type = AKA_SIM_VECTOR_GSM;
392 
393  return 0;
394 }
395 
397 {
398  fr_pair_t *ki_vp, *amf_vp, *sqn_vp, *version_vp;
399 
400  size_t ki_size, amf_size;
401  uint32_t version = FR_SIM_ALGO_VERSION_VALUE_MILENAGE;
402  unsigned int i;
403 
404  /*
405  * Select the algorithm (default to Milenage)
406  */
407  version_vp = fr_pair_find_by_da(vps, NULL, attr_sim_algo_version);
408  if (version_vp) version = version_vp->vp_uint32;
409 
410  /*
411  * Get expected input sizes
412  */
413  switch (version) {
414  case FR_SIM_ALGO_VERSION_VALUE_MILENAGE:
415  ki_size = MILENAGE_KI_SIZE;
416  amf_size = MILENAGE_AMF_SIZE;
417  break;
418 
419  case FR_SIM_ALGO_VERSION_VALUE_TS_34_108_UMTS:
420  ki_size = TS_34_108_KI_SIZE;
421  amf_size = TS_34_108_AMF_SIZE;
422  break;
423 
424  /*
425  * GSM algos
426  */
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");
432  return -1;
433 
434  default:
435  REDEBUG("Unknown/unsupported algorithm %i", version);
436  return -1;
437  }
438 
439  /*
440  * Find the Ki VP and check its length
441  */
442  ki_vp = fr_pair_find_by_da(vps, NULL, attr_sim_ki);
443  if (!ki_vp) {
444  RDEBUG3("No &control.%s found, not generating quintuplets locally", attr_sim_ki->name);
445  return 1;
446  } else if (ki_vp->vp_length != ki_size) {
447  REDEBUG("&control.%s has incorrect length, expected %zu bytes got %zu bytes",
448  attr_sim_ki->name, ki_size, ki_vp->vp_length);
449  return -1;
450  }
451 
452  /*
453  * Find the Sequence Number VP or default to SQN = 2
454  */
455  sqn_vp = fr_pair_find_by_da(vps, NULL, attr_sim_sqn);
456  keys->sqn = sqn_vp ? sqn_vp->vp_uint64 : 2; /* 2 is the lowest valid SQN on our side */
457 
458  /*
459  * Check if we have an AMF value
460  */
461  amf_vp = fr_pair_find_by_da(vps, NULL, attr_sim_amf);
462  if (amf_vp) {
463  if (amf_vp->vp_length != amf_size) {
464  REDEBUG("&control.%s has incorrect length, expected %zu bytes got %zu bytes",
465  attr_sim_amf->name, amf_size, amf_vp->vp_length);
466  return -1;
467  }
468  }
469 
470  /*
471  * Generate rand
472  */
473  for (i = 0; i < AKA_SIM_VECTOR_UMTS_RAND_SIZE; i += sizeof(uint32_t)) {
474  uint32_t rand = fr_rand();
475  memcpy(&keys->umts.vector.rand[i], &rand, sizeof(rand));
476  }
477 
478  switch (version) {
479  case FR_SIM_ALGO_VERSION_VALUE_MILENAGE:
480  {
481  uint8_t amf_buff[MILENAGE_AMF_SIZE] = { 0x00, 0x00 };
482  uint8_t sqn_buff[MILENAGE_SQN_SIZE];
483  uint8_t opc_buff[MILENAGE_OPC_SIZE];
484  uint8_t const *opc_p;
485 
486  if (vector_opc_from_op(request, &opc_p, opc_buff, vps, ki_vp->vp_octets) < 0) return -1;
487 
488  uint48_to_buff(sqn_buff, keys->sqn);
489  if (amf_vp) memcpy(amf_buff, amf_vp->vp_octets, amf_size);
490 
491  RDEBUG3("Milenage inputs");
492  RINDENT();
493  /*
494  * Don't change colon indent, matches other messages later...
495  */
496  RHEXDUMP_INLINE3(ki_vp->vp_octets, ki_size,
497  "Ki :");
498  RHEXDUMP_INLINE3(opc_p, sizeof(opc_buff),
499  "OPc :");
500  RHEXDUMP_INLINE3(sqn_buff, sizeof(sqn_buff),
501  "SQN :");
502  RHEXDUMP_INLINE3(amf_buff, sizeof(amf_buff),
503  "AMF :");
504  REXDENT();
505 
506  if (milenage_umts_generate(keys->umts.vector.autn,
507  keys->umts.vector.ik,
508  keys->umts.vector.ck,
509  keys->umts.vector.ak,
510  keys->umts.vector.xres,
511  opc_p,
512  amf_buff,
513  ki_vp->vp_octets,
514  keys->sqn,
515  keys->umts.vector.rand) < 0) {
516  RPEDEBUG2("Failed deriving UMTS Quintuplet");
517  return -1;
518  }
519  keys->umts.vector.xres_len = MILENAGE_RES_SIZE;
520 
521  /*
522  * Store the keys we used for possible AUTS
523  * validation later.
524  */
525  memcpy(keys->auc.ki, ki_vp->vp_octets, sizeof(keys->auc.ki));
526  memcpy(keys->auc.opc, opc_p, sizeof(keys->auc.opc));
527  keys->vector_src = AKA_SIM_VECTOR_SRC_KI;
528  }
529  return 0;
530 
531  /*
532  * This is a dummy algorithm and should be used for testing
533  * purposes only. It offers no security and can be trivially
534  * broken and the original Ki retrieved.
535  */
536  case FR_SIM_ALGO_VERSION_VALUE_TS_34_108_UMTS:
537  {
538  uint8_t amf_buff[TS_34_108_AMF_SIZE] = { 0x00, 0x00 };
539  uint8_t sqn_buff[TS_34_108_SQN_SIZE];
540 
541  uint48_to_buff(sqn_buff, keys->sqn);
542 
543  if (amf_vp) memcpy(amf_buff, amf_vp->vp_octets, amf_size);
544 
545  RDEBUG3("TS-34-108-UMTS inputs");
546  RINDENT();
547  /*
548  * Don't change colon indent, matches other messages later...
549  */
551  ki_vp->vp_octets, ki_size,
552  "Ki :");
554  sqn_buff, sizeof(sqn_buff),
555  "SQN :");
557  amf_buff, sizeof(amf_buff),
558  "AMF :");
559  REXDENT();
560 
561  if (ts_34_108_umts_generate(keys->umts.vector.autn,
562  keys->umts.vector.ik,
563  keys->umts.vector.ck,
564  keys->umts.vector.ak,
565  keys->umts.vector.xres,
566  amf_buff,
567  ki_vp->vp_octets,
568  keys->sqn,
569  keys->umts.vector.rand) < 0) {
570  RPEDEBUG2("Failed deriving UMTS Quintuplet");
571  return -1;
572  }
573  keys->umts.vector.xres_len = TS_34_108_RES_SIZE;
574 
575  /*
576  * Store the keys we used for possible AUTS
577  * validation later.
578  */
579  memcpy(keys->auc.ki, ki_vp->vp_octets, sizeof(keys->auc.ki));
580  keys->vector_src = AKA_SIM_VECTOR_SRC_KI;
581  }
582  return 0;
583 
584  default:
585  fr_assert(0);
586  return -1;
587  }
588 }
589 
590 /** Get one set of quintuplets from the request
591  *
592  */
594 {
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;
597 
598  /*
599  * Fetch AUTN
600  */
601  autn_vp = fr_pair_find_by_da(vps, NULL, attr_eap_aka_sim_autn);
602  if (!autn_vp) {
603  RDEBUG3("No &control.%s attribute found, not using UMTS quintuplets", attr_eap_aka_sim_autn->name);
604  return 1;
605  }
606 
607  if (autn_vp->vp_length > AKA_SIM_VECTOR_UMTS_AUTN_SIZE) {
608  REDEBUG("&control.%s incorrect length. Expected "
609  STRINGIFY(AKA_SIM_VECTOR_UMTS_AUTN_SIZE) " bytes, got %zu bytes",
610  attr_eap_aka_sim_autn->name, autn_vp->vp_length);
611  return -1;
612  }
613 
614  /*
615  * Fetch CK
616  */
617  ck_vp = fr_pair_find_by_da(vps, NULL, attr_eap_aka_sim_ck);
618  if (!ck_vp) {
619  RDEBUG3("No &control.%s attribute found, not using UMTS quintuplets", attr_eap_aka_sim_ck->name);
620  return 1;
621  }
622 
623  if (ck_vp->vp_length > AKA_SIM_VECTOR_UMTS_CK_SIZE) {
624  REDEBUG("&control.%s incorrect length. Expected "
625  STRINGIFY(EAP_AKA_XRES_MAX_SIZE) " bytes, got %zu bytes",
626  attr_eap_aka_sim_ck->name, ck_vp->vp_length);
627  return -1;
628  }
629 
630  /*
631  * Fetch IK
632  */
633  ik_vp = fr_pair_find_by_da(vps, NULL, attr_eap_aka_sim_ik);
634  if (!ik_vp) {
635  RDEBUG3("No &control.%s attribute found, not using UMTS quintuplets", attr_eap_aka_sim_ik->name);
636  return 1;
637  }
638 
639  if (ik_vp->vp_length > AKA_SIM_VECTOR_UMTS_IK_SIZE) {
640  REDEBUG("&control.%s incorrect length. Expected "
641  STRINGIFY(AKA_SIM_VECTOR_UMTS_IK_SIZE) " bytes, got %zu bytes",
642  attr_eap_aka_sim_ik->name, ik_vp->vp_length);
643  return -1;
644  }
645 
646  /*
647  * Fetch RAND
648  */
649  rand_vp = fr_pair_find_by_da(vps, NULL, attr_eap_aka_sim_rand);
650  if (!rand_vp) {
651  RDEBUG3("No &control.%s attribute found, not using quintuplet derivation", attr_eap_aka_sim_rand->name);
652  return 1;
653  }
654 
655  if (rand_vp->vp_length != AKA_SIM_VECTOR_UMTS_RAND_SIZE) {
656  REDEBUG("&control.%s incorrect length. Expected " STRINGIFY(AKA_SIM_VECTOR_UMTS_RAND_SIZE) " bytes, "
657  "got %zu bytes", attr_eap_aka_sim_rand->name, rand_vp->vp_length);
658  return -1;
659  }
660 
661  /*
662  * Fetch XRES
663  */
664  xres_vp = fr_pair_find_by_da(vps, NULL, attr_eap_aka_sim_xres);
665  if (!xres_vp) {
666  RDEBUG3("No &control.%s attribute found, not using UMTS quintuplets", attr_eap_aka_sim_xres->name);
667  return 1;
668  }
669 
670  if (xres_vp->vp_length > AKA_SIM_VECTOR_UMTS_XRES_MAX_SIZE) {
671  REDEBUG("&control.%s incorrect length. Expected < "
672  STRINGIFY(EAP_AKA_XRES_MAX_SIZE) " bytes, got %zu bytes",
673  attr_eap_aka_sim_xres->name, xres_vp->vp_length);
674  return -1;
675  }
676 
677  /*
678  * Fetch (optional) AK
679  */
680  ak_vp = fr_pair_find_by_da(vps, NULL, attr_eap_aka_sim_ak);
681  if (ak_vp && (ak_vp->vp_length != MILENAGE_AK_SIZE)) {
682  REDEBUG("&control.%s incorrect length. Expected "
683  STRINGIFY(MILENAGE_AK_SIZE) " bytes, got %zu bytes",
684  attr_eap_aka_sim_ak->name, ak_vp->vp_length);
685  return -1;
686  }
687 
688  /*
689  * Fetch (optional) SQN
690  */
691  sqn_vp = fr_pair_find_by_da(vps, NULL, attr_sim_sqn);
692  if (sqn_vp && (sqn_vp->vp_length != MILENAGE_SQN_SIZE)) {
693  REDEBUG("&control.%s incorrect length. Expected "
694  STRINGIFY(MILENAGE_AK_SIZE) " bytes, got %zu bytes",
695  attr_sim_sqn->name, sqn_vp->vp_length);
696  return -1;
697  }
698 
699  /*
700  * SQN = AUTN[0..5] ⊕ AK
701  * AK = AK
702  */
703  if (ak_vp && !sqn_vp) {
704  keys->sqn = uint48_from_buff(autn_vp->vp_octets) ^ uint48_from_buff(ak_vp->vp_octets);
705  memcpy(keys->umts.vector.ak, ak_vp->vp_octets, sizeof(keys->umts.vector.ak));
706  /*
707  * SQN = SQN
708  * AK = AUTN[0..5] ⊕ SQN
709  */
710  } else if (sqn_vp && !ak_vp) {
711  keys->sqn = sqn_vp->vp_uint64;
712  uint48_to_buff(keys->umts.vector.ak, uint48_from_buff(autn_vp->vp_octets) ^ sqn_vp->vp_uint64);
713  /*
714  * SQN = SQN
715  * AK = AK
716  */
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));
720  /*
721  * SQN = AUTN[0..5]
722  * AK = 0x000000000000
723  */
724  } else {
725  keys->sqn = uint48_from_buff(autn_vp->vp_octets);
726  memset(keys->umts.vector.ak, 0, sizeof(keys->umts.vector.ak));
727  }
728 
729  memcpy(keys->umts.vector.autn, autn_vp->vp_octets, AKA_SIM_VECTOR_UMTS_AUTN_SIZE);
730  memcpy(keys->umts.vector.ck, ck_vp->vp_octets, AKA_SIM_VECTOR_UMTS_CK_SIZE);
731  memcpy(keys->umts.vector.ik, ik_vp->vp_octets, AKA_SIM_VECTOR_UMTS_IK_SIZE);
732  memcpy(keys->umts.vector.rand, rand_vp->vp_octets, AKA_SIM_VECTOR_UMTS_RAND_SIZE);
733  memcpy(keys->umts.vector.xres, xres_vp->vp_octets, xres_vp->vp_length);
734  keys->umts.vector.xres_len = xres_vp->vp_length; /* xres is variable length */
735 
736  keys->vector_src = AKA_SIM_VECTOR_SRC_QUINTUPLETS;
737 
738  return 0;
739 }
740 
741 /** Retrieve UMTS quintuplets from sets of attributes.
742  *
743  * Hunt for a source of UMTS quintuplets
744  *
745  * @param request The current request.
746  * @param vps List to hunt for triplets in.
747  * @param keys UMTS keys.
748  * @param src Forces quintuplets to be retrieved from a particular src.
749  *
750  * @return
751  * - 1 Vector could not be retrieved from the specified src.
752  * - 0 Vector was retrieved OK and written to the specified index.
753  * - -1 Error retrieving vector from the specified src.
754  */
757 {
758  int ret;
759 
760  fr_assert((keys->vector_type == AKA_SIM_VECTOR_NONE) || (keys->vector_type == AKA_SIM_VECTOR_UMTS));
761 
762  switch (*src) {
763  default:
765  ret = vector_umts_from_ki(request, vps, keys);
766  if (ret == 0) {
767  *src = AKA_SIM_VECTOR_SRC_KI;
768  break;
769  }
770  if (ret < 0) return -1;
771  if (*src != AKA_SIM_VECTOR_SRC_AUTO) return 1;
772  FALL_THROUGH;
773 
775  ret = vector_umts_from_quintuplets(request, vps, keys);
776  if (ret == 0) {
778  break;
779  }
780  if (ret < 0) return -1;
781  break;
782  }
783 
784  if (ret == 1) {
785  RWDEBUG("Could not find or derive data for UMTS vector");
786  return 1;
787  }
788 
789  if (RDEBUG_ENABLED2) {
790  RDEBUG2("UMTS vector");
791 
792  RINDENT();
793  /*
794  * Don't change colon indent, matches other messages later...
795  */
796  RHEXDUMP_INLINE2(keys->umts.vector.autn, AKA_SIM_VECTOR_UMTS_AUTN_SIZE,
797  "AUTN :");
798  RHEXDUMP_INLINE2(keys->umts.vector.ck, AKA_SIM_VECTOR_UMTS_CK_SIZE,
799  "CK :");
800  RHEXDUMP_INLINE2(keys->umts.vector.ik, AKA_SIM_VECTOR_UMTS_IK_SIZE,
801  "IK :");
802  RHEXDUMP_INLINE2(keys->umts.vector.rand, AKA_SIM_VECTOR_UMTS_RAND_SIZE,
803  "RAND :");
804  RHEXDUMP_INLINE2(keys->umts.vector.xres, keys->umts.vector.xres_len,
805  "XRES :");
806  REXDENT();
807  }
808 
809  keys->vector_type = AKA_SIM_VECTOR_UMTS;
810 
811  return 0;
812 }
813 
814 /** Populate a fr_aka_sim_keys_t structure from attributes in the session-state list
815  *
816  * @param[in] request The current request.
817  * @param[in] vps Session-state list
818  * @param[in] keys key structure to populate.
819  * @return
820  * - 1 if we do not have sufficient data.
821  * - 0 on success.
822  * - -1 on validation failure.
823  */
825 {
826  fr_pair_t *counter_vp;
827  fr_pair_t *mk_vp;
828 
829  /*
830  * This is the *old* counter value increment
831  * by 1 to get the *new* counter value
832  */
833  counter_vp = fr_pair_find_by_da_nested(vps, NULL, attr_eap_aka_sim_counter);
834  if (!counter_vp) {
835  RDEBUG2("No &session-state.%s attribute found, can't calculate re-auth keys",
837  return 1;
838  }
839  counter_vp->vp_uint16++;
840 
841  mk_vp = fr_pair_find_by_da(vps, NULL, attr_session_data);
842  if (!mk_vp) mk_vp = fr_pair_find_by_da(vps, NULL, attr_eap_aka_sim_mk);
843  if (!mk_vp) {
844  RDEBUG2("Neither &session-state.%s or &session-state.%s attributes found, "
845  "can't calculate re-auth keys", attr_session_data->name, attr_eap_aka_sim_mk->name);
846  return 1;
847  }
848 
849  if (mk_vp->vp_length != AKA_SIM_MK_SIZE) {
850  REDEBUG("&session-state.%s incorrect length. Expected %u bytes, got %zu bytes",
851  attr_eap_aka_sim_mk->name, AKA_SIM_MK_SIZE, mk_vp->vp_length);
852  return -1;
853  }
854 
855  fr_aka_sim_crypto_keys_init_kdf_0_reauth(keys, mk_vp->vp_octets, counter_vp->vp_uint16);
856 
857  keys->vector_type = AKA_SIM_VECTOR_UMTS_REAUTH_KDF_0_REAUTH; /* Didn't come from a vector */
858  keys->vector_src = AKA_SIM_VECTOR_SRC_REAUTH;
859 
860  return 0;
861 }
862 
863 /** Populate a fr_aka_sim_keys_t structure from attributes in the session-state list
864  *
865  * @param[in] request The current request.
866  * @param[in] vps Session-state list
867  * @param[in] keys key structure to populate.
868  * @return
869  * - 1 if we do not have sufficient data.
870  * - 0 on success.
871  * - -1 on validation failure.
872  */
874 {
875  fr_pair_t *counter_vp;
876  fr_pair_t *mk_vp;
877 
878  /*
879  * This is the *old* counter value increment
880  * by 1 to get the *new* counter value
881  */
882  counter_vp = fr_pair_find_by_da_nested(vps, NULL, attr_eap_aka_sim_counter);
883  if (!counter_vp) {
884  RDEBUG2("No &session-state.%s attribute found, can't calculate re-auth keys",
886  return 1;
887  }
888  counter_vp->vp_uint16++;
889 
890  mk_vp = fr_pair_find_by_da(vps, NULL, attr_session_data);
891  if (!mk_vp) mk_vp = fr_pair_find_by_da(vps, NULL, attr_eap_aka_sim_mk);
892  if (!mk_vp) {
893  RDEBUG2("Neither &session-state.%s or &session-sate:%s attributes found, "
894  "can't calculate re-auth keys", attr_session_data->name, attr_eap_aka_sim_mk->name);
895  return 1;
896  }
897 
898  if (mk_vp->vp_length != AKA_PRIME_MK_REAUTH_SIZE) {
899  REDEBUG("&session-state.%s incorrect length. Expected "
900  "%u bytes, got %zu bytes",
901  attr_eap_aka_sim_mk->name, AKA_PRIME_MK_REAUTH_SIZE, mk_vp->vp_length);
902  return -1;
903  }
904 
905  fr_aka_sim_crypto_keys_init_umts_kdf_1_reauth(keys, mk_vp->vp_octets, counter_vp->vp_uint16);
906 
907  keys->vector_type = AKA_SIM_VECTOR_UMTS_REAUTH_KDF_1_REAUTH; /* Didn't come from a vector */
908  keys->vector_src = AKA_SIM_VECTOR_SRC_REAUTH;
909 
910  return 0;
911 }
912 
913 /** Clear reauth data if reauthentication failed
914  *
915  * @param[in] keys key structure to clear.
916  */
918 {
919  memset(&keys->reauth, 0, sizeof(keys->reauth));
920  keys->vector_src = 0;
921  keys->vector_type = 0;
922 }
923 
924 /** Perform milenage AUTS validation and resynchronisation
925  *
926  * @param[out] new_sqn The new sequence number provided by the AUTS.
927  * @param[in] request The current request.
928  * @param[in] auts_vp The AUTS response.
929  * @param[in] keys UMTS keys.
930  * @return
931  * - 1 if we do not have sufficient data (lacking ki).
932  * - 0 on success.
933  * - -1 on validation failure.
934  */
935 int fr_aka_sim_umts_resync_from_attrs(uint64_t *new_sqn,
936  request_t *request, fr_pair_t *auts_vp, fr_aka_sim_keys_t *keys)
937 {
938  if (keys->vector_src != AKA_SIM_VECTOR_SRC_KI) {
939  RDEBUG2("Original vectors were not generated locally, cannot perform AUTS validation");
940  return 1;
941  }
942 
943  if (auts_vp->vp_length != MILENAGE_AUTS_SIZE) {
944  REDEBUG("&control.%s incorrect length. Expected "
945  STRINGIFY(MILENAGE_AUTS_SIZE) " bytes, got %zu bytes",
946  attr_eap_aka_sim_auts->name, auts_vp->vp_length);
947  return -1;
948  }
949 
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");
952  return -1;
953  }
954 
955  RDEBUG2("AUTS validation success, new SQN %"PRIu64, *new_sqn);
956 
957  return 0;
958 }
#define RCSID(id)
Definition: build.h:444
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition: build.h:320
#define STRINGIFY(x)
Definition: build.h:195
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.
Definition: common.h:37
static uint64_t uint48_from_buff(uint8_t const in[6])
Convert a 48bit big endian value into a unsigned 64bit integer.
Definition: common.h:52
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.
Definition: comp128.c:241
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.
Definition: comp128.c:336
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition: dcursor.h:287
#define AKA_SIM_VECTOR_UMTS_RAND_SIZE
Definition: base.h:73
#define AKA_SIM_VECTOR_GSM_RAND_SIZE
Length of RAND in GSM triplet.
Definition: base.h:65
#define AKA_SIM_VECTOR_GSM_SRES_SIZE
Length of SRES in GSM triplet.
Definition: base.h:66
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.
Definition: crypto.c:947
uint64_t sqn
Sequence number.
Definition: base.h:158
#define AKA_PRIME_MK_REAUTH_SIZE
The portion of the MK used for re-auth.
Definition: base.h:57
fr_aka_sim_vector_src_t
Where to get EAP-SIM vectors from.
Definition: base.h:99
@ AKA_SIM_VECTOR_SRC_REAUTH
Not a vector.
Definition: base.h:105
@ AKA_SIM_VECTOR_SRC_AUTO
Discover where to get Triplets from automatically.
Definition: base.h:100
@ AKA_SIM_VECTOR_SRC_QUINTUPLETS
Source of triplets is derived from EAP-AKA-* quintuplets.
Definition: base.h:102
@ AKA_SIM_VECTOR_SRC_KI
Should generate triplets locally using a Ki.
Definition: base.h:104
@ AKA_SIM_VECTOR_SRC_TRIPLETS
Source of triplets is EAP-SIM-* attributes.
Definition: base.h:101
#define AKA_SIM_VECTOR_UMTS_XRES_MAX_SIZE
Definition: base.h:74
#define AKA_SIM_VECTOR_UMTS_CK_SIZE
Definition: base.h:70
#define AKA_SIM_MK_SIZE
Definition: base.h:54
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.
Definition: crypto.c:917
#define AKA_SIM_VECTOR_GSM_KC_SIZE
Length of Kc in GSM triplet.
Definition: base.h:67
#define AKA_SIM_VECTOR_UMTS_IK_SIZE
Definition: base.h:71
#define AKA_SIM_VECTOR_UMTS_AUTN_SIZE
Definition: base.h:69
@ AKA_SIM_VECTOR_GSM
Vector is GSM triplets.
Definition: base.h:91
@ AKA_SIM_VECTOR_UMTS_REAUTH_KDF_1_REAUTH
Definition: base.h:94
@ AKA_SIM_VECTOR_UMTS
Vector is UMTS quintuplets.
Definition: base.h:92
@ AKA_SIM_VECTOR_UMTS_REAUTH_KDF_0_REAUTH
Definition: base.h:93
@ AKA_SIM_VECTOR_NONE
Definition: base.h:90
Master key state struct for all SIMlike EAP protocols.
Definition: base.h:148
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_counter
Definition: base.c:67
HIDDEN fr_dict_attr_t const * attr_session_data
Definition: base.c:102
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_ak
Definition: base.c:59
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_mk
Definition: base.c:86
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_auts
Definition: base.c:62
HIDDEN fr_dict_attr_t const * attr_sim_algo_version
Definition: base.c:110
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_xres
Definition: base.c:101
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_sres
Definition: base.c:98
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_ik
Definition: base.c:75
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_autn
Definition: base.c:61
HIDDEN fr_dict_attr_t const * attr_sim_opc
Definition: base.c:114
HIDDEN fr_dict_attr_t const * attr_sim_ki
Definition: base.c:112
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_kc
Definition: base.c:80
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_ck
Definition: base.c:65
HIDDEN fr_dict_attr_t const * attr_sim_sqn
Definition: base.c:115
HIDDEN fr_dict_attr_t const * attr_sim_op
Definition: base.c:113
HIDDEN fr_dict_attr_t const * attr_sim_amf
Definition: base.c:111
HIDDEN fr_dict_attr_t const * attr_eap_aka_sim_rand
Definition: attrs.h:39
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition: log.h:443
#define RWDEBUG(fmt,...)
Definition: log.h:361
#define RDEBUG3(fmt,...)
Definition: log.h:343
#define RHEXDUMP_INLINE2(_data, _len, _fmt,...)
Definition: log.h:685
#define RPEDEBUG(fmt,...)
Definition: log.h:376
#define RHEXDUMP_INLINE3(_data, _len, _fmt,...)
Definition: log.h:686
#define RPEDEBUG2(fmt,...)
Definition: log.h:377
#define RINDENT()
Indent R* messages by one level.
Definition: log.h:430
unsigned int uint32_t
Definition: merged_model.c:33
unsigned char uint8_t
Definition: merged_model.c:30
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.
Definition: milenage.c:282
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.
Definition: milenage.c:329
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.
Definition: milenage.c:358
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.
Definition: milenage.c:386
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.
Definition: milenage.c:243
#define MILENAGE_AK_SIZE
Anonymisation key.
Definition: milenage.h:36
#define MILENAGE_SQN_SIZE
Sequence number.
Definition: milenage.h:30
#define MILENAGE_AMF_SIZE
Authentication management field.
Definition: milenage.h:29
#define MILENAGE_KI_SIZE
Subscriber key.
Definition: milenage.h:26
#define MILENAGE_OP_SIZE
Operator code (unique to the operator)
Definition: milenage.h:27
#define MILENAGE_AUTS_SIZE
Definition: milenage.h:41
#define MILENAGE_OPC_SIZE
Derived operator code (unique to the operator and subscriber).
Definition: milenage.h:28
#define MILENAGE_RES_SIZE
Definition: milenage.h:40
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.
Definition: pair.c:688
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.
Definition: pair.c:765
VQP attributes.
#define REDEBUG(fmt,...)
Definition: radclient.h:52
#define RDEBUG_ENABLED2()
Definition: radclient.h:50
#define RDEBUG2(fmt,...)
Definition: radclient.h:54
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition: rand.c:106
fr_assert(0)
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
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])
Definition: ts_34_108.c:40
#define TS_34_108_KI_SIZE
Subscriber key.
Definition: ts_34_108.h:30
#define TS_34_108_SQN_SIZE
Sequence number.
Definition: ts_34_108.h:33
#define TS_34_108_AMF_SIZE
Authentication management field.
Definition: ts_34_108.h:32
#define TS_34_108_RES_SIZE
Definition: ts_34_108.h:43
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.
Definition: pair.h:627
static size_t char ** out
Definition: value.h:984
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.
Definition: vector.c:593
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.
Definition: vector.c:824
static int vector_umts_from_ki(request_t *request, fr_pair_list_t *vps, fr_aka_sim_keys_t *keys)
Definition: vector.c:396
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])
Definition: vector.c:43
void fr_aka_sim_vector_umts_reauth_clear(fr_aka_sim_keys_t *keys)
Clear reauth data if reauthentication failed.
Definition: vector.c:917
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.
Definition: vector.c:237
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.
Definition: vector.c:330
static int vector_gsm_from_ki(request_t *request, fr_pair_list_t *vps, int idx, fr_aka_sim_keys_t *keys)
Definition: vector.c:79
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.
Definition: vector.c:873
static int vector_gsm_from_triplets(request_t *request, fr_pair_list_t *vps, int idx, fr_aka_sim_keys_t *keys)
Definition: vector.c:177
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.
Definition: vector.c:935
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.
Definition: vector.c:755