The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
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: 889596d0f4c7572f4ffc55229a1b577401ae134d $
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 */
27RCSID("$Id: 889596d0f4c7572f4ffc55229a1b577401ae134d $")
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
43static int vector_opc_from_op(request_t *request, uint8_t const **out, uint8_t opc_buff[MILENAGE_OPC_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 %d 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 %d 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
79static 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 %u", 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) {
344 break;
345 }
346 if (ret < 0) return -1;
347 if (*src != AKA_SIM_VECTOR_SRC_AUTO) return 1;
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;
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 %u", 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) {
768 break;
769 }
770 if (ret < 0) return -1;
771 if (*src != AKA_SIM_VECTOR_SRC_AUTO) return 1;
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 */
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 */
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 */
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:483
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:322
#define STRINGIFY(x)
Definition build.h:197
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:288
#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
unsigned char uint8_t
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_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:770
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:693
VQP attributes.
#define fr_assert(_expr)
Definition rad_assert.h:38
#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:105
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:628
static size_t char ** out
Definition value.h:997
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