The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
decode.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 * @file src/lib/eap_aka_sim/decode.c
19 * @brief Code common to EAP-SIM/AKA/AKA' clients and servers.
20 *
21 * The development of the EAP-SIM support was funded by Internet Foundation
22 * Austria (http://www.nic.at/ipa).
23 *
24 * @copyright 2003 Michael Richardson (mcr@sandelman.ottawa.on.ca)
25 * @copyright 2003-2016 The FreeRADIUS server project
26 */
27
28RCSID("$Id: 2b18253a25906232dab9609c3b4a897bf5b37d4b $")
29
30#include <freeradius-devel/io/test_point.h>
31#include <freeradius-devel/server/module.h>
32#include <freeradius-devel/tls/strerror.h>
33#include <freeradius-devel/util/debug.h>
34#include <freeradius-devel/util/sha1.h>
35#include <freeradius-devel/util/decode.h>
36
37#include <freeradius-devel/eap/types.h>
38#include "attrs.h"
39#include "base.h"
40#include "crypto_priv.h"
41
42/*
43 * EAP-SIM/AKA/AKA' PACKET FORMAT
44 * ---------------- ------ ------
45 *
46 * EAP Request and Response Packet Format
47 * --- ------- --- -------- ------ ------
48 * 0 1 2 3
49 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
50 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51 * | Code | Identifier | Length |
52 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
53 * | Type | AT-Type | AT-Length | value ... |
54 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
55 *
56 * With AT-Type/AT-Length/Value... repeating. Length is in units
57 * of 32 bits, and includes the Type/Length fields.
58 */
59
61 uint8_t const *data, size_t data_len, void *decode_ctx);
62
64 uint8_t const *data, size_t const attr_len, size_t const data_len,
65 void *decode_ctx);
66
67/** Extract the IV value from an AT_IV attribute
68 *
69 * SIM uses padding at the start of the attribute to make it a multiple of 4.
70 * We need to strip packet_ctx and check that it was set to zero.
71 *
72 * @param[out] out Where to write IV.
73 * @param[in] in value of AT_IV attribute.
74 * @param[in] in_len the length of the AT_IV attribute (should be 18).
75 * @return
76 * - 0 on success.
77 * - < 0 on failure (bad IV).
78 */
79static inline int sim_iv_extract(uint8_t out[AKA_SIM_IV_SIZE], uint8_t const *in, size_t in_len)
80{
81 /*
82 * Two bytes are reserved, so although
83 * the IV is actually 16 bytes, we
84 * check for 18.
85 */
86 if (in_len != (AKA_SIM_IV_SIZE + 2)) {
87 fr_strerror_printf("%s: Invalid IV length, expected %u got %zu",
88 __FUNCTION__, (AKA_SIM_IV_SIZE + 2), in_len);
89 return -1;
90 }
91
92 if ((in[0] != 0x00) || (in[1] != 0x00)) {
93 fr_strerror_printf("%s: Reserved bytes in IV are not zeroed", __FUNCTION__);
94 return -1;
95 }
96
97 /* skip reserved bytes */
98 memcpy(out, in + 2, AKA_SIM_IV_SIZE);
99
100 return 0;
101}
102
103/** Decrypt an AES-128-CBC encrypted attribute
104 *
105 * @param[in] ctx to allocate decr buffer in.
106 * @param[out] out where to write pointer to decr buffer.
107 * @param[in] data to decrypt.
108 * @param[in] attr_len length of encrypted data.
109 * @param[in] data_len length of data remaining in the packet.
110 * @param[in] decode_ctx containing keys, and the IV (if we already found it).
111 * @return
112 * - Number of decr bytes decrypted on success.
113 * - < 0 on failure.
114 */
115static ssize_t sim_value_decrypt(TALLOC_CTX *ctx, uint8_t **out,
116 uint8_t const *data, size_t const attr_len, size_t const data_len,
117 void *decode_ctx)
118{
119 fr_aka_sim_ctx_t *packet_ctx = decode_ctx;
120 EVP_CIPHER_CTX *evp_ctx;
121 EVP_CIPHER const *evp_cipher = EVP_aes_128_cbc();
122 size_t block_size = EVP_CIPHER_block_size(evp_cipher);
123 size_t len = 0, decr_len = 0;
124 uint8_t *decr = NULL;
125
126 if (!fr_cond_assert(attr_len <= data_len)) return -1;
127
128 FR_PROTO_HEX_DUMP(data, attr_len, "ciphertext");
129
130 /*
131 * Encrypted values must be a multiple of 16.
132 *
133 * There's a padding attribute to ensure they
134 * always can be...
135 */
136 if (attr_len % block_size) {
137 fr_strerror_printf("%s: Encrypted attribute is not a multiple of cipher's block size (%zu)",
138 __FUNCTION__, block_size);
139 return -1;
140 }
141
142 /*
143 * Ugh, now we have to go hunting for it....
144 */
145 if (!packet_ctx->have_iv) {
146 uint8_t const *p = data + attr_len; /* Skip to the end of packet_ctx attribute */
147 uint8_t const *end = data + data_len;
148
149 while ((size_t)(end - p) >= sizeof(uint32_t)) {
150 uint8_t sim_at = p[0];
151 size_t sim_at_len = p[1] * sizeof(uint32_t);
152
153 if (sim_at_len == 0) {
154 fr_strerror_printf("%s: Failed IV search. AT Length field is zero", __FUNCTION__);
155 return -1;
156 }
157
158 if ((p + sim_at_len) > end) {
159 fr_strerror_printf("%s: Invalid IV length, longer than remaining data", __FUNCTION__);
160 return -1;
161 }
162
163 if (sim_at == FR_IV) {
164 if (sim_iv_extract(&(packet_ctx->iv[0]), p + 2, sim_at_len - 2) < 0) return -1;
165 packet_ctx->have_iv = true;
166 break;
167 }
168 p += sim_at_len;
169 }
170
171 if (!packet_ctx->have_iv) {
172 fr_strerror_printf("%s: No IV present in packet, can't decrypt data", __FUNCTION__);
173 return -1;
174 }
175 }
176
177 if (unlikely(!packet_ctx->k_encr)) {
178 fr_strerror_printf("%s: No k_encr set, cannot decrypt attributes", __FUNCTION__);
180 }
181
182 evp_ctx = aka_sim_crypto_cipher_ctx();
183 if (!EVP_DecryptInit_ex(evp_ctx, evp_cipher, NULL, packet_ctx->k_encr, packet_ctx->iv)) {
184 fr_tls_strerror_printf("%s: Failed setting decryption parameters", __FUNCTION__);
185 error:
186 talloc_free(decr);
187 return -1;
188 }
189
190 MEM(decr = talloc_zero_array(ctx, uint8_t, attr_len));
191
192 /*
193 * By default OpenSSL expects 16 bytes of cleartext
194 * to produce 32 bytes of ciphertext, due to padding
195 * being added if the decr is a multiple of 16.
196 *
197 * There's no way for OpenSSL to determine if a
198 * 16 byte ciphertext was padded or not, so we need to
199 * inform OpenSSL explicitly that there's no padding.
200 */
201 EVP_CIPHER_CTX_set_padding(evp_ctx, 0);
202 if (!EVP_DecryptUpdate(evp_ctx, decr, (int *)&len, data, attr_len)) {
203 fr_tls_strerror_printf("%s: Failed decrypting attribute", __FUNCTION__);
204 goto error;
205 }
206 decr_len = len;
207
208 if (!EVP_DecryptFinal_ex(evp_ctx, decr + decr_len, (int *)&len)) {
209 fr_tls_strerror_printf("%s: Failed decrypting attribute", __FUNCTION__);
210 goto error;
211 }
212 decr_len += len;
213
214 /*
215 * Note: packet_ctx implicitly validates the length of the padding
216 * attribute (if present), so we don't have to do it later.
217 */
218 if (decr_len % block_size) {
219 fr_strerror_printf("%s: Expected decrypted value length to be multiple of %zu, got %zu",
220 __FUNCTION__, block_size, decr_len);
221 goto error;
222 }
223
224 /*
225 * Ciphertext should be same length as plaintext.
226 */
227 if (unlikely(attr_len != decr_len)) {
228 fr_strerror_printf("%s: Invalid plaintext length, expected %zu, got %zu",
229 __FUNCTION__, attr_len, decr_len);
230 goto error;
231 }
232
233 FR_PROTO_TRACE("decryption successful, got %zu bytes of cleartext", decr_len);
234 FR_PROTO_HEX_DUMP(decr, decr_len, "cleartext");
235
236 *out = decr;
237
238 return decr_len;
239}
240
241/** Returns the number of array members for arrays with fixed element sizes
242 *
243 * @param[out] out The element length.
244 * @param[in] len the total length of the array.
245 * @param[in] da the specifying the array type.
246 * @return
247 * - The number of elements in the array on success.
248 * - < 0 on error (array length not a multiple of element size).
249 */
250static int sim_array_members(size_t *out, size_t len, fr_dict_attr_t const *da)
251{
252 size_t element_len;
253
254 /*
255 * Could be an array of bytes, integers, etc.
256 */
257 switch (da->type) {
258 case FR_TYPE_OCTETS:
259 if (da->flags.length == 0) {
260 fr_strerror_printf("%s: Octets array must have fixed length elements", __FUNCTION__);
261 return -1;
262 }
263 element_len = da->flags.length;
264 break;
265
266 default:
267 element_len = fr_aka_sim_attr_sizes[da->type][0];
268 break;
269 }
270
271 if (element_len == 1) {
272 *out = 1;
273 return 1; /* Fast path */
274 }
275
276 if (!fr_cond_assert(element_len > 0)) return -1;
277
278 if (element_len > len) {
279 fr_strerror_printf("%s: Element length (%zu) > array length (%zu)", __FUNCTION__,
280 element_len, len);
281 return -1;
282 }
283
284 /*
285 * Number of elements must divide exactly
286 */
287 if (len % element_len) {
288 fr_strerror_printf("%s: Expected array actual length to be multiple of %zu, got %zu",
289 __FUNCTION__, element_len, len);
290 return -1;
291 }
292 *out = element_len;
293
294 return len / element_len;
295}
296
298 fr_dict_attr_t const *parent,
299 uint8_t const *data, size_t const attr_len, UNUSED size_t data_len,
300 void *decode_ctx)
301{
302 uint8_t const *p = data, *end = p + attr_len;
303 uint16_t actual_len;
304 int elements, i;
305 size_t element_len;
306 ssize_t ret;
307
308 FR_PROTO_TRACE("Array attribute");
309
310 fr_assert(parent->flags.array);
311 fr_assert(attr_len >= 2); /* Should have been caught earlier */
312
313 /*
314 * Arrays with fixed length members that
315 * are a multiple of 4 don't need an
316 * actual_len value, as we can get the
317 * number of elements from the attribute
318 * length.
319 */
320 if (!parent->flags.length || (parent->flags.length % 4)) {
321 actual_len = fr_nbo_to_uint16(p);
322 if (actual_len > (attr_len - 2)) {
323 fr_strerror_printf("%s: Actual length field value (%hu) > attribute value length (%zu)",
324 __FUNCTION__, actual_len, attr_len - 2);
325 return -1;
326 }
327 } else {
328 actual_len = attr_len - 2; /* -2 for the reserved bytes */
329 }
330 p += 2;
331
332 /*
333 * Zero length array
334 */
335 if (!actual_len) return p - data;
336
337 /*
338 * Get the number of elements
339 */
340 elements = sim_array_members(&element_len, actual_len, parent);
341 if (elements < 0) return elements;
342
343 for (i = 0; i < elements; i++) {
344 ret = sim_decode_pair_value(ctx, out, parent, p, element_len, end - p, decode_ctx);
345 if (ret < 0) return ret;
346
347 p += ret;
348
349 if (!fr_cond_assert(p <= end)) break;
350 }
351
352 return attr_len; /* Say we consumed attr_len because it may have padding */
353}
354
355/** Break apart a TLV attribute into individual attributes
356 *
357 * @param[in] ctx to allocate new attributes in.
358 * @param[in] out to add new attributes to.
359 * @param[in] parent the current attribute TLV attribute we're processing.
360 * @param[in] data to parse. Points to the data field of the attribute.
361 * @param[in] attr_len length of the TLV attribute.
362 * @param[in] data_len remaining data in the packet.
363 * @param[in] decode_ctx IVs, keys etc...
364 * @return
365 * - Length on success.
366 * - < 0 on malformed attribute.
367 */
368static ssize_t sim_decode_tlv(TALLOC_CTX *ctx, fr_pair_list_t *out,
369 fr_dict_attr_t const *parent,
370 uint8_t const *data, size_t const attr_len, size_t data_len,
371 void *decode_ctx)
372{
373 uint8_t const *p = data, *end = p + attr_len;
374 uint8_t *decr = NULL;
375 ssize_t decr_len;
376 fr_dict_attr_t const *child;
377 fr_pair_t *tlv;
378 ssize_t ret;
379
380 if (data_len < 2) {
381 fr_strerror_printf("%s: Insufficient data", __FUNCTION__);
382 return -1; /* minimum attr size */
383 }
384
385 tlv = fr_pair_afrom_da(ctx, parent);
386 if (!tlv) return PAIR_DECODE_OOM;
387
388 /*
389 * We have an AES-128-CBC encrypted attribute
390 *
391 * IV is from AT_IV, key is from k_encr.
392 *
393 * unfortunately the ordering of these two attributes
394 * aren't specified, so we may have to hunt for the IV.
395 */
397 FR_PROTO_TRACE("found encrypted attribute '%s'", parent->name);
398
399 decr_len = sim_value_decrypt(ctx, &decr, p + 2,
400 attr_len - 2, data_len - 2, decode_ctx); /* Skip reserved */
401 if (decr_len < 0) return -1;
402
403 p = decr;
404 end = p + decr_len;
405 } else {
406 p += 2; /* Skip the reserved bytes */
407 }
408
409 FR_PROTO_HEX_DUMP(p, end - p, "tlvs");
410
411 /*
412 * Record where we were in the list when packet_ctx function was called
413 */
414 while ((size_t)(end - p) >= sizeof(uint32_t)) {
415 uint8_t sim_at = p[0];
416 size_t sim_at_len = ((size_t)p[1]) << 2;
417 fr_dict_attr_t const *unknown_child = NULL;
418
419 if ((p + sim_at_len) > end) {
420 fr_strerror_printf("%s: Malformed nested attribute %d: Length field (%zu bytes) value "
421 "longer than remaining data in parent (%zu bytes)",
422 __FUNCTION__, sim_at, sim_at_len, (size_t) (end - p));
423
424 error:
425 talloc_free(decr);
426 talloc_free(tlv);
427 return -1;
428 }
429
430 if (sim_at_len == 0) {
431 fr_strerror_printf("%s: Malformed nested attribute %d: Length field 0", __FUNCTION__, sim_at);
432 goto error;
433 }
434
435 /*
436 * Padding attributes are cleartext inside of
437 * encrypted TLVs to pad out the value to the
438 * correct length for the block cipher
439 * (16 in the case of AES-128-CBC).
440 */
441 if (sim_at == FR_PADDING) {
442 uint8_t zero = 0;
443 uint8_t i;
444
446 fr_strerror_printf("%s: Found padding attribute outside of an encrypted TLV",
447 __FUNCTION__);
448 goto error;
449 }
450
451 if (!fr_cond_assert(data_len % 4)) goto error;
452
453 if (sim_at_len > 12) {
454 fr_strerror_printf("%s: Expected padding attribute length <= 12 bytes, got %zu bytes",
455 __FUNCTION__, sim_at_len);
456 goto error;
457 }
458
459 /*
460 * RFC says we MUST verify that FR_PADDING
461 * data is zeroed out.
462 */
463 for (i = 2; i < sim_at_len; i++) zero |= p[i];
464 if (zero) {
465 fr_strerror_printf("%s: Padding attribute value not zeroed 0x%pH", __FUNCTION__,
466 fr_box_octets(p + 2, sim_at_len - 2));
467 goto error;
468 }
469
470 p += sim_at_len;
471 continue;
472 }
473
474 child = fr_dict_attr_child_by_num(parent, p[0]);
475 if (!child) {
476 FR_PROTO_TRACE("Failed to find child %u of TLV %s", p[0], parent->name);
477
478 /*
479 * Encountered none skippable attribute
480 *
481 * RFC says we need to die on these if we don't
482 * understand them. non-skippables are < 128.
483 */
484 if (sim_at <= AKA_SIM_SKIPPABLE_MAX) {
485 fr_strerror_printf("%s: Unknown (non-skippable) attribute %i",
486 __FUNCTION__, sim_at);
487 goto error;
488 }
489
490 /*
491 * Build an unknown attr
492 */
493 unknown_child = fr_dict_attr_unknown_raw_afrom_num(ctx, parent, p[0]);
494 if (!unknown_child) goto error;
495 child = unknown_child;
496 }
497 FR_PROTO_TRACE("decode context changed %s -> %s", parent->name, child->name);
498
499 ret = sim_decode_pair_value(tlv, &tlv->vp_group, child, p + 2, sim_at_len - 2, (end - p) - 2,
500 decode_ctx);
501 fr_dict_attr_unknown_free(&unknown_child);
502 if (ret < 0) goto error;
503 p += sim_at_len;
504 }
505 fr_pair_append(out, tlv);
506
507 talloc_free(decr);
508
509 return attr_len;
510}
511
512/** Create any kind of VP from the attribute contents
513 *
514 * @param[in] ctx to allocate new attributes in.
515 * @param[in] out to add new attributes to.
516 * @param[in] parent the current attribute we're processing.
517 * @param[in] data to parse. Points to the data field of the attribute.
518 * @param[in] attr_len length of the attribute being parsed.
519 * @param[in] data_len length of the remaining data in the packet.
520 * @param[in] decode_ctx IVs, keys etc...
521 * @return
522 * - Length on success.
523 * - -1 on failure.
524 */
526 uint8_t const *data, size_t const attr_len, size_t const data_len,
527 void *decode_ctx)
528{
529 fr_pair_t *vp;
530 uint8_t const *p = data;
531 size_t prefix = 0;
532
533 fr_aka_sim_ctx_t *packet_ctx = decode_ctx;
534
535 if (!fr_cond_assert(attr_len <= data_len)) return -1;
536 if (!fr_cond_assert(parent)) return -1;
537
538 FR_PROTO_TRACE("Parent %s len %zu", parent->name, attr_len);
539 FR_PROTO_HEX_DUMP(data, attr_len, __FUNCTION__ );
540
541 FR_PROTO_TRACE("Type \"%s\" (%u)", fr_type_to_str(parent->type), parent->type);
542
543 /*
544 * Special cases, attributes that either have odd formats, or need
545 * have information we need to decode the packet.
546 */
547 switch (parent->attr) {
548 /*
549 * We need to record packet_ctx so we can decrypt AT_ENCR attributes.
550 *
551 * If we don't find it before, then that's fine, we'll try and
552 * find it in the rest of the packet after the encrypted
553 * attribute.
554 *
555 * 0 1 2 3
556 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
557 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
558 * | AT_IV | Length = 5 | Reserved |
559 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
560 * | |
561 * | Initialization Vector |
562 * | |
563 * | |
564 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
565 */
566 case FR_IV:
567 if (sim_iv_extract(&packet_ctx->iv[0], data, attr_len) < 0) return -1;
568 packet_ctx->have_iv = true;
569 break; /* Now create the attribute */
570
571 /*
572 * AT_RES - Special case (RES length is in bits)
573 *
574 * 0 1 2 3
575 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
576 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
577 * | AT_RES | Length | RES Length |
578 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
579 * | |
580 * | RES |
581 * | |
582 * | |
583 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
584 */
585 case FR_RES:
586 {
587 uint16_t res_len;
588
589 if (attr_len < 2) goto raw; /* Need at least two bytes for the length field */
590
591 res_len = fr_nbo_to_uint16(p);
592 if (res_len % 8) {
593 fr_strerror_printf("%s: RES Length (%hu) is not a multiple of 8",
594 __FUNCTION__, res_len);
595 return -1;
596 }
597 res_len /= 8;
598
599 if (res_len > (attr_len - 2)) {
600 fr_strerror_printf("%s: RES Length field value (%d bits) > attribute value length (%zu bits)",
601 __FUNCTION__, res_len * 8, (attr_len - 2) * 8);
602 return -1;
603 }
604
605 if ((res_len < 4) || (res_len > 16)) {
606 fr_strerror_printf("%s: RES Length field value must be between 32-128 bits, got %d bits",
607 __FUNCTION__, (res_len * 8));
608 return -1;
609 }
610
611 vp = fr_pair_afrom_da(ctx, parent);
612 if (!vp) return -1;
613
614 fr_pair_value_memdup(vp, p + 2, res_len, true);
615 }
616 goto done;
617
618 /*
619 * AT_CHECKCODE - Special case (Variable length with no length field)
620 *
621 * 0 1 2 3
622 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
623 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
624 * | AT_CHECKCODE | Length | Reserved |
625 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
626 * | |
627 * | Checkcode (0 or 20 bytes) |
628 * | |
629 * | |
630 * | |
631 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
632 */
633 case FR_CHECKCODE:
634 if (attr_len < 2) goto raw; /* Need at least two bytes for reserved field */
635
636 vp = fr_pair_afrom_da(ctx, parent);
637 if (!vp) return -1;
638
639 fr_pair_value_memdup(vp, p + 2, attr_len - 2, true);
640 goto done;
641
642 default:
643 break;
644 }
645
646 switch (parent->type) {
647 case FR_TYPE_STRING:
648 if (attr_len < 2) goto raw; /* Need at least two bytes for the length field */
649 if (parent->flags.length && (attr_len != parent->flags.length)) {
650 wrong_len:
651 fr_strerror_printf("%s: Attribute \"%s\" needs a value of exactly %zu bytes, "
652 "but value was %zu bytes", __FUNCTION__,
653 parent->name, (size_t)parent->flags.length, attr_len);
654 goto raw;
655 }
656 break;
657
658 case FR_TYPE_OCTETS:
659 if (parent->flags.is_unknown) goto raw;
660
661 /*
662 * Get the number of bytes we expect before the value
663 */
665 if (attr_len < prefix) goto raw;
666 if (parent->flags.length && (attr_len != (parent->flags.length + prefix))) goto wrong_len;
667 break;
668
669 case FR_TYPE_BOOL:
670 case FR_TYPE_UINT8:
671 case FR_TYPE_UINT16:
672 case FR_TYPE_UINT32:
673 case FR_TYPE_UINT64:
674 if (attr_len != fr_aka_sim_attr_sizes[parent->type][0]) goto raw;
675 break;
676
677 case FR_TYPE_TLV:
678 if (attr_len < 2) goto raw;
679
680 /*
681 * We presume that the TLVs all fit into one
682 * attribute, OR they've already been grouped
683 * into a contiguous memory buffer.
684 */
685 return sim_decode_tlv(ctx, out, parent, p, attr_len, data_len, decode_ctx);
686
687 default:
688 raw:
689 /*
690 * We can't create unknowns for non-skippable attributes
691 * as we're prohibited from continuing by the SIM RFCs.
692 */
693 if (parent->attr <= AKA_SIM_SKIPPABLE_MAX) {
694 fr_strerror_printf_push("%s: Failed parsing non-skippable attribute '%s'",
695 __FUNCTION__, parent->name);
696 return -1;
697 }
698
699#ifdef STATIC_ANALYZER
700 if (!parent->parent) return -1; /* stupid static analyzers */
701#endif
702 fr_assert(parent->parent);
703
704 if (fr_pair_raw_from_network(ctx, out, parent, p, attr_len) < 0) return -1;
705
706 return attr_len;
707 }
708
709 fr_assert(!parent->flags.is_unknown);
710
711 vp = fr_pair_afrom_da(ctx, parent);
712 if (!vp) return -1;
713
714 switch (parent->type) {
715 /*
716 * 0 1 2 3
717 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
718 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
719 * | AT_<STRING> | Length | Actual <STRING> Length |
720 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
721 * | |
722 * . String .
723 * . .
724 * | |
725 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
726 */
727 case FR_TYPE_STRING:
728 {
729 uint16_t actual_len = fr_nbo_to_uint16(p);
730
731 if (actual_len > (attr_len - 2)) {
732 fr_strerror_printf("%s: Actual length field value (%hu) > attribute value length (%zu)",
733 __FUNCTION__, actual_len, attr_len - 2);
734 return -1;
735 }
736
737 fr_pair_value_bstrndup(vp, (char const *)p + 2, actual_len, true);
738 }
739 break;
740
741 case FR_TYPE_OCTETS:
742 /*
743 * Variable length octets buffer
744 */
745 if (!parent->flags.length) {
746 uint16_t actual_len = fr_nbo_to_uint16(p);
747
748 if (actual_len > (attr_len - prefix)) {
749 fr_strerror_printf("%s: Actual length field value (%hu) > attribute value length (%zu)",
750 __FUNCTION__, actual_len, attr_len - 2);
751 return -1;
752 }
753
754 fr_pair_value_memdup(vp, p + prefix, actual_len, true);
755 /*
756 * Fixed length octets buffer
757 */
758 } else {
759 fr_pair_value_memdup(vp, p + prefix, attr_len - prefix, true);
760 }
761 break;
762
763 /*
764 * Not proper bool. We Use packet_ctx to represent
765 * flag attributes like AT_FULLAUTH_ID_REQ
766 *
767 * 0 1 2 3
768 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
769 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
770 * | AT_<BOOL> | Length = 1 | Reserved |
771 * +---------------+---------------+-------------------------------+
772 */
773 case FR_TYPE_BOOL:
774 vp->vp_bool = true;
775 break;
776
777 /*
778 * Numbers are network byte order.
779 *
780 * In the base RFCs only short (16bit) unsigned integers are used.
781 * We add support for more, just for completeness.
782 *
783 * 0 1 2 3
784 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
785 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
786 * | AT_<SHORT> | Length = 1 | Short 1 | Short 2 |
787 * +---------------+---------------+-------------------------------+
788 */
789 case FR_TYPE_UINT8:
790 vp->vp_uint8 = p[0];
791 break;
792
793 case FR_TYPE_UINT16:
794 vp->vp_uint16 = fr_nbo_to_uint16(p);
795 break;
796
797 case FR_TYPE_UINT32:
798 vp->vp_uint32 = fr_nbo_to_uint32(p);
799 break;
800
801 case FR_TYPE_UINT64:
802 vp->vp_uint64 = fr_nbo_to_uint64(p);
803 break;
804
805 default:
806 talloc_free(&vp);
807 fr_strerror_printf_push("%s[%d]: Internal sanity check failed", __FUNCTION__, __LINE__);
808 return -1;
809 }
810
811done:
813
814 return attr_len;
815}
816
817/** Decode SIM/AKA/AKA' attributes
818 *
819 * @param[in] ctx to allocate attributes in.
820 * @param[in] out where to insert the attributes.
821 * @param[in] parent of current attribute being decoded.
822 * @param[in] data data to parse.
823 * @param[in] data_len length of data. For top level attributes packet_ctx must be the length
824 * of the packet (so we can hunt for AT_IV), for Sub-TLVs it should
825 * be the length of the container value.
826 * @param[in] decode_ctx extra context to pass to the decoder.
827 * @return
828 * - The number of bytes parsed.
829 * - -1 on error.
830 */
832 uint8_t const *data, size_t data_len, void *decode_ctx)
833{
834 uint8_t sim_at;
835 size_t sim_at_len;
836
837 ssize_t ret;
838 fr_dict_attr_t const *da;
839
840
841 /*
842 * We need at least 2 bytes. We really need 4 but it's
843 * useful to print the attribute number in the errors.
844 */
845 if (data_len < 2) {
846 fr_strerror_printf("%s: Insufficient data: Expected >= 2 bytes, got %zu bytes",
847 __FUNCTION__, data_len);
848 return -1;
849 }
850
851 sim_at = data[0];
852
853 sim_at_len = ((size_t)data[1]) << 2;
854 if (sim_at_len > data_len) {
855 fr_strerror_printf("%s: Insufficient data for attribute %d: Length field %zu, remaining data %zu",
856 __FUNCTION__, sim_at, sim_at_len, data_len);
857 return -1;
858 }
859
860 if (sim_at_len == 0) {
861 fr_strerror_printf("%s: Malformed attribute %d: Length field 0", __FUNCTION__, sim_at);
862 return -1;
863 }
864
865 da = fr_dict_attr_child_by_num(parent, sim_at);
866 if (!da) {
867 FR_PROTO_TRACE("Unknown attribute %u", sim_at);
868
869 /*
870 * Encountered none skippable attribute
871 *
872 * RFC says we need to die on these if we don't
873 * understand them. non-skippables are < 128.
874 */
875 if (sim_at <= AKA_SIM_SKIPPABLE_MAX) {
876 fr_strerror_printf("Unknown (non-skippable) attribute %i", sim_at);
877 return -1;
878 }
880 }
881 if (!da) return -1;
882
883 FR_PROTO_TRACE("decode context changed %s -> %s", da->parent->name, da->name);
884
885 if (da->flags.array) {
886 ret = sim_decode_array(ctx, out, da, data + 2, sim_at_len - 2, data_len - 2, decode_ctx);
887 } else {
888 ret = sim_decode_pair_value(ctx, out, da, data + 2, sim_at_len - 2, data_len - 2, decode_ctx);
889 }
890 if (ret < 0) return ret;
891
892 return 2 + ret;
893}
894
895/** Decode SIM/AKA/AKA' attributes
896 *
897 * @param[in] ctx to allocate attributes in.
898 * @param[in] out where to insert the attributes.
899 * @param[in] parent for looking up attributes.
900 * @param[in] data data to parse.
901 * @param[in] data_len length of data. For top level attributes packet_ctx must be the length
902 * of the packet (so we can hunt for AT_IV), for Sub-TLVs it should
903 * be the length of the container value.
904 * @param[in] decode_ctx extra context to pass to the decoder.
905 * @return
906 * - The number of bytes parsed.
907 * - -1 on error.
908 */
910 uint8_t const *data, size_t data_len, void *decode_ctx)
911{
912 return sim_decode_pair_internal(ctx, out, parent, data, data_len, decode_ctx);
913}
914
915/** Decode SIM/AKA/AKA' specific packet data
916 *
917 * @note data should point to the subtype field in the EAP packet.
918 *
919 * Extracts the SUBTYPE and adds it an attribute, then decodes any TLVs in the
920 * SIM/AKA/AKA' packet.
921 *
922 * 0 1 2 3
923 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
924 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
925 * | Code | Identifier | Length |
926 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
927 * | Type | Subtype | Reserved |
928 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
929 *
930 * The first byte of the data pointer should be the subtype.
931 *
932 * @param[in] ctx where to allocate the pairs.
933 * @param[in] out where to write out attributes.
934 * @param[in] dict for looking up attributes.
935 * @param[in] data to convert to pairs.
936 * @param[in] data_len length of data to convert.
937 * @param[in] decode_ctx holds the state of the decoder.
938 * @return
939 * - 0 on success.
940 * - -1 on failure.
941 */
942int fr_aka_sim_decode(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_t const *dict,
943 uint8_t const *data, size_t data_len, fr_aka_sim_ctx_t *decode_ctx)
944{
945 ssize_t ret;
946 uint8_t const *p = data;
947 uint8_t const *end = p + data_len;
948 fr_dict_attr_t const *parent;
949
950 /*
951 * We need at least enough data for the subtype
952 * and reserved bytes.
953 *
954 * Note: Not all packets should contain attrs.
955 * When the client acknowledges an
956 * AKA-Notification from the server, the
957 * AKA-Notification is returns contains no
958 * attributes.
959 */
960 if (data_len < 3) {
961 fr_strerror_printf("Packet data too small, expected at least 3 bytes got %zu bytes", data_len);
962 return -1;
963 }
964 p += 3;
965 parent = fr_dict_root(dict);
966
967 /*
968 * Loop over all the attributes decoding
969 * them into the appropriate attributes
970 * in the SIM/AKA/AKA' dict.
971 */
972 while (p < end) {
973 ret = fr_aka_sim_decode_pair(ctx, out, parent, p, end - p, decode_ctx);
974 if (ret <= 0) {
975 fr_strerror_const_push("Failed decoding AT");
976 error:
977 fr_pair_list_free(out); /* Free any attributes we added */
978 return -1;
979 }
980
981 p += ret;
982 fr_assert(p <= end);
983 }
984
985 /*
986 * No point in doing packet_ctx until we known the rest
987 * of the data is OK!
988 */
989 {
990 fr_pair_t *vp;
991
992 vp = fr_pair_afrom_child_num(ctx, parent, FR_SUBTYPE);
993 if (!vp) {
994 fr_strerror_const("Failed allocating subtype attribute");
995 goto error;
996 }
997 vp->vp_uint32 = data[0];
999 }
1000
1001 return 0;
1002}
1003
1005{
1007
1008 return 0;
1009}
1010
1011static fr_aka_sim_ctx_t *test_ctx_init(TALLOC_CTX *ctx, uint8_t const *k_encr, size_t k_encr_len)
1012{
1013 fr_aka_sim_ctx_t *test_ctx;
1014
1015 if (fr_aka_sim_init() < 0) return NULL;
1016
1017 test_ctx = talloc_zero(ctx, fr_aka_sim_ctx_t);
1018 test_ctx->k_encr = talloc_memdup(test_ctx, k_encr, k_encr_len);
1019 talloc_set_destructor(test_ctx, _test_ctx_free);
1020
1021 return test_ctx;
1022}
1023/*
1024 * Test ctx data
1025 */
1026static int decode_test_ctx_sim(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict)
1027{
1028 fr_aka_sim_ctx_t *test_ctx;
1029 static uint8_t k_encr[] = { 0x00, 0x01, 0x02, 0x03, 0x04 ,0x05, 0x06, 0x07,
1030 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
1031
1032 test_ctx = test_ctx_init(ctx, k_encr, sizeof(k_encr));
1033 if (!test_ctx) return -1;
1034
1035 test_ctx->have_iv = true; /* Ensures IV is all zeros */
1036
1037 *out = test_ctx;
1038
1039 return 0;
1040}
1041
1042
1043static int decode_test_ctx_aka(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict)
1044{
1045 fr_aka_sim_ctx_t *test_ctx;
1046 static uint8_t k_encr[] = { 0x00, 0x01, 0x02, 0x03, 0x04 ,0x05, 0x06, 0x07,
1047 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
1048
1049 test_ctx = test_ctx_init(ctx, k_encr, sizeof(k_encr));
1050 if (!test_ctx) return -1;
1051
1052 test_ctx->have_iv = true; /* Ensures IV is all zeros */
1053
1054 *out = test_ctx;
1055
1056 return 0;
1057}
1058
1059static int decode_test_ctx_sim_rfc4186(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict)
1060{
1061 fr_aka_sim_ctx_t *test_ctx;
1062 static uint8_t k_encr[] = { 0x53, 0x6e, 0x5e, 0xbc, 0x44 ,0x65, 0x58, 0x2a,
1063 0xa6, 0xa8, 0xec, 0x99, 0x86, 0xeb, 0xb6, 0x20 };
1064
1065 test_ctx = test_ctx_init(ctx, k_encr, sizeof(k_encr));
1066 if (!test_ctx) return -1;
1067
1068 *out = test_ctx;
1069
1070 return 0;
1071}
1072
1073/*
1074 * Test points
1075 */
1081
1087
#define RCSID(id)
Definition build.h:483
#define unlikely(_x)
Definition build.h:381
#define UNUSED
Definition build.h:315
EAP-SIM/EAP-AKA Private crypto functions.
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:139
#define MEM(x)
Definition debug.h:36
static fr_dict_attr_t * fr_dict_attr_unknown_raw_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr)
Definition dict.h:580
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2400
void fr_dict_attr_unknown_free(fr_dict_attr_t const **da)
Free dynamically allocated (unknown attributes)
fr_dict_attr_t const * fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Check if a child attribute exists in a parent using an attribute number.
Definition dict_util.c:3328
static fr_slen_t in
Definition dict.h:824
#define AKA_SIM_IV_SIZE
Length of the IV used when processing AT_ENCR.
Definition base.h:41
#define AKA_SIM_SKIPPABLE_MAX
The last non-skippable attribute.
Definition base.h:63
bool have_iv
Whether we found the IV already.
Definition base.h:236
uint8_t const * k_encr
The encryption key used for encrypting.
Definition base.h:246
uint8_t iv[AKA_SIM_IV_SIZE]
From the current packet.
Definition base.h:235
#define fr_aka_sim_flag_encrypted(_da)
Definition base.h:270
Encoder/decoder ctx.
Definition base.h:234
EVP_CIPHER_CTX * aka_sim_crypto_cipher_ctx(void)
Allocate and reset a resumable EVP_CIPHER_CTX for each thread.
Definition crypto.c:70
#define PAIR_DECODE_OOM
Fatal error - Out of memory.
Definition pair.h:45
#define PAIR_DECODE_FATAL_ERROR
Fatal error - Failed decoding the packet.
Definition pair.h:49
void fr_aka_sim_free(void)
Definition base.c:315
int fr_aka_sim_init(void)
Definition base.c:284
size_t fr_aka_sim_octets_prefix_len(fr_dict_attr_t const *da)
Return the number of bytes before the octets value.
Definition base.c:276
size_t const fr_aka_sim_attr_sizes[FR_TYPE_MAX+1][2]
SIM AT on-the-wire format attribute sizes.
Definition base.c:210
ssize_t fr_aka_sim_decode_pair(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, void *decode_ctx)
Decode SIM/AKA/AKA' attributes.
Definition decode.c:909
static int sim_iv_extract(uint8_t out[AKA_SIM_IV_SIZE], uint8_t const *in, size_t in_len)
Extract the IV value from an AT_IV attribute.
Definition decode.c:79
static ssize_t sim_decode_pair_value(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const attr_len, size_t const data_len, void *decode_ctx)
Create any kind of VP from the attribute contents.
Definition decode.c:525
static ssize_t sim_value_decrypt(TALLOC_CTX *ctx, uint8_t **out, uint8_t const *data, size_t const attr_len, size_t const data_len, void *decode_ctx)
Decrypt an AES-128-CBC encrypted attribute.
Definition decode.c:115
static int decode_test_ctx_sim(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict)
Definition decode.c:1026
static int sim_array_members(size_t *out, size_t len, fr_dict_attr_t const *da)
Returns the number of array members for arrays with fixed element sizes.
Definition decode.c:250
fr_test_point_pair_decode_t aka_tp_decode
Definition decode.c:1089
fr_test_point_pair_decode_t sim_tp_decode_rfc4186
Definition decode.c:1083
static ssize_t sim_decode_array(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const attr_len, UNUSED size_t data_len, void *decode_ctx)
Definition decode.c:297
int fr_aka_sim_decode(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_t const *dict, uint8_t const *data, size_t data_len, fr_aka_sim_ctx_t *decode_ctx)
Decode SIM/AKA/AKA' specific packet data.
Definition decode.c:942
static ssize_t sim_decode_tlv(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const attr_len, size_t data_len, void *decode_ctx)
Break apart a TLV attribute into individual attributes.
Definition decode.c:368
static int decode_test_ctx_sim_rfc4186(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict)
Definition decode.c:1059
static int decode_test_ctx_aka(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict)
Definition decode.c:1043
fr_test_point_pair_decode_t sim_tp_decode
Definition decode.c:1077
static fr_aka_sim_ctx_t * test_ctx_init(TALLOC_CTX *ctx, uint8_t const *k_encr, size_t k_encr_len)
Definition decode.c:1011
static int _test_ctx_free(UNUSED fr_aka_sim_ctx_t *ctx)
Definition decode.c:1004
static ssize_t sim_decode_pair_internal(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, void *decode_ctx)
Decode SIM/AKA/AKA' attributes.
Definition decode.c:831
ssize_t fr_pair_raw_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len)
Create a "raw" pair from the network data.
Definition decode.c:79
talloc_free(reap)
static const uint8_t * zero
Definition md4.c:358
unsigned short uint16_t
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT16
16 Bit unsigned integer.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_OCTETS
Raw octets.
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
unsigned long int size_t
static uint64_t fr_nbo_to_uint64(uint8_t const data[static sizeof(uint64_t)])
Read an unsigned 64bit integer from wire format (big endian)
Definition nbo.h:177
static uint16_t fr_nbo_to_uint16(uint8_t const data[static sizeof(uint16_t)])
Read an unsigned 16bit integer from wire format (big endian)
Definition nbo.h:146
static uint32_t fr_nbo_to_uint32(uint8_t const data[static sizeof(uint32_t)])
Read an unsigned 32bit integer from wire format (big endian)
Definition nbo.h:167
int fr_pair_value_memdup(fr_pair_t *vp, uint8_t const *src, size_t len, bool tainted)
Copy data into an "octets" data type.
Definition pair.c:2981
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition pair.c:1345
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
Definition pair.c:283
int fr_pair_value_bstrndup(fr_pair_t *vp, char const *src, size_t len, bool tainted)
Copy data into a "string" type value pair.
Definition pair.c:2784
fr_pair_t * fr_pair_afrom_child_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr)
Create a new valuepair.
Definition pair.c:371
VQP attributes.
#define fr_assert(_expr)
Definition rad_assert.h:38
static bool done
Definition radclient.c:80
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
Definition test_point.h:85
Entry point for pair decoders.
Definition test_point.h:84
Master include file to access all functions and structures in the library.
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
static fr_slen_t parent
Definition pair.h:851
#define FR_PROTO_HEX_DUMP(_data, _data_len, _fmt,...)
Definition proto.h:41
#define FR_PROTO_TRACE(_fmt,...)
Definition proto.h:40
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_printf_push(_fmt,...)
Add a message to an existing stack of messages at the tail.
Definition strerror.h:84
#define fr_strerror_const_push(_msg)
Definition strerror.h:227
#define fr_strerror_const(_msg)
Definition strerror.h:223
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:433
static fr_slen_t data
Definition value.h:1265
static size_t char ** out
Definition value.h:997
#define fr_box_octets(_val, _len)
Definition value.h:288