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