The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
cbor.c
Go to the documentation of this file.
1/*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2.1 of the License, or (at your option) any later version.
6 *
7 * This library 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 GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/** CBPR encoding and decoding
18 *
19 * @file src/lib/util/cbor.c
20 *
21 * @copyright 2024 Network RADIUS SAS (legal@networkradius.com)
22 */
23RCSID("$Id: 7fba7673eee7d145b742110df7058c472e9dabd1 $")
24
25#include <freeradius-devel/util/cbor.h>
26
27#define CBOR_INTEGER (0)
28#define CBOR_NEGATIVE (1)
29#define CBOR_OCTETS (2)
30#define CBOR_STRING (3)
31#define CBOR_ARRAY (4)
32#define CBOR_MAP (5)
33#define CBOR_TAG (6)
34#define CBOR_FLOAT (7)
35
36#define CBOR_1_BYTE ((uint8_t) 24)
37#define CBOR_2_BYTE ((uint8_t) 25)
38#define CBOR_4_BYTE ((uint8_t) 26)
39#define CBOR_8_BYTE ((uint8_t) 27)
40
41static const char *cbor_type_to_str[8] = {
42 "integer", "negative", "octets", "string",
43 "array", "map", "tag", "float"
44};
45
46/*
47 * Some of our data types need tags.
48 *
49 * We don't have a tag to data type array. When decoding, we should usually have the enclosing pair
50 * number, which includes our data type. If the tag type doesn't match the value here, then something is
51 * wrong.
52 */
53static const uint64_t cbor_type_to_tag[FR_TYPE_MAX + 1] = {
54 [FR_TYPE_DATE] = 1,
55 [FR_TYPE_ETHERNET] = 48,
56 [FR_TYPE_IPV4_ADDR] = 52,
58 [FR_TYPE_IPV6_ADDR] = 54,
60 [FR_TYPE_TIME_DELTA] = 1002,
61};
62
63static fr_type_t cbor_guess_type(fr_dbuff_t *dbuff, bool pair);
64
66{
67 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
68 uint8_t value[8];
69
70 fr_assert(type < 8);
71 type <<= 5;
72
73 if (data < 24) {
74 data |= type;
75
76 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) (data & 0xff));
77 goto done;
78 }
79
80 if (data < (((uint64_t) 1) << 8)) {
81 value[0] = data;
82
84 FR_DBUFF_IN_RETURN(&work_dbuff, value[0]);
85 goto done;
86 }
87
88 if (data < (((uint64_t) 1) << 16)) {
90
92 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, value, 2);
93 goto done;
94 }
95
96 if (data < (((uint64_t) 1) << 32)) {
98
100 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, value, 4);
101 goto done;
102 }
103
105
106 /*
107 * Has to be 8 bytes.
108 */
110 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, value, 8);
111
112done:
113 return fr_dbuff_set(dbuff, &work_dbuff);
114}
115
116#define cbor_encode_array(_dbuff, _size) cbor_encode_integer(_dbuff, CBOR_ARRAY, _size)
117
118#define cbor_encode_tag(_dbuff, _tag) cbor_encode_integer(_dbuff, CBOR_TAG, _tag)
119
120/*
121 * Make many things easier
122 */
123#define return_slen return slen - fr_dbuff_used(&work_dbuff)
124
125/*
126 * Octets is length + data
127 */
128static ssize_t cbor_encode_octets(fr_dbuff_t *dbuff, uint8_t const *data, size_t data_len)
129{
130 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
131 ssize_t slen;
132
133 slen = cbor_encode_integer(&work_dbuff, CBOR_OCTETS, data_len);
134 if (slen <= 0) return_slen;
135
136 if (data_len > 0) FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, data, data_len);
137
138 return fr_dbuff_set(dbuff, &work_dbuff);
139}
140
141static ssize_t cbor_encode_int64(fr_dbuff_t *dbuff, int64_t neg)
142{
143 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
144 ssize_t slen;
145
146 if (neg >= 0) {
147 slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, neg);
148 } else {
149 uint64_t data;
150
151 neg++;
152 data = -neg;
153 slen = cbor_encode_integer(&work_dbuff, CBOR_NEGATIVE, data);
154 }
155 if (slen <= 0) return_slen;
156
157 return fr_dbuff_set(dbuff, &work_dbuff);
158}
159
160#define cbor_encode_key cbor_encode_int64
161
162/** Encode CBOR
163 *
164 * Values 0..23 can be encoded in place. Other values can be encoded using the closest smallest integer
165 */
167{
168 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
170 uint64_t data;
171 int64_t neg;
172 ssize_t slen;
173 uint8_t const *p, *end;
174
175 switch (vb->type) {
176 case FR_TYPE_BOOL:
177 /*
178 * One byte of FLOAT (i.e. special value), and the boolean as a "simple value".
179 */
180 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_FLOAT << 5) | (20 + vb->vb_bool)));
181 break;
182
183 case FR_TYPE_UINT8:
184 data = vb->vb_uint8;
185 goto encode_int;
186
187 case FR_TYPE_UINT16:
188 data = vb->vb_uint16;
189 goto encode_int;
190
191 case FR_TYPE_UINT32:
192 data = vb->vb_uint64;
193 goto encode_int;
194
195 case FR_TYPE_UINT64:
196 data = vb->vb_uint64;
197 goto encode_int;
198
199 /*
200 * Negative numbers.
201 */
202 case FR_TYPE_INT8:
203 neg = vb->vb_int8;
204 goto encode_neg;
205
206 case FR_TYPE_INT16:
207 neg = vb->vb_int16;
208 goto encode_neg;
209
210 case FR_TYPE_INT32:
211 neg = vb->vb_int64;
212 goto encode_neg;
213
214 case FR_TYPE_INT64:
215 neg = vb->vb_int64;
216 encode_neg:
217 if (neg >= 0) {
219 data = neg;
220 goto encode_int;
221 }
222
223 /*
224 * convert -1..-2^63 to 0..-(2^63-1)
225 * and then it fits into a positive integer.
226 */
227 neg++;
228 data = -neg;
229
230 encode_int:
231 return cbor_encode_integer(dbuff, type, data);
232
233 case FR_TYPE_OCTETS:
234 return cbor_encode_octets(dbuff, vb->vb_octets, vb->vb_length);
235
236 case FR_TYPE_STRING:
237 slen = cbor_encode_integer(&work_dbuff, CBOR_STRING, vb->vb_length);
238 if (slen <= 0) return_slen;
239
240 if (vb->vb_length) FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, vb->vb_strvalue, vb->vb_length);
241 break;
242
243 /*
244 * More complex data types are represented by type "tag", followed by a tag number. The
245 * actual data is then encoded as the next item after the tag.
246 */
247 case FR_TYPE_ETHERNET:
248 slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
249 if (slen <= 0) return_slen;
250
251 slen = cbor_encode_octets(&work_dbuff, vb->vb_ether, sizeof(vb->vb_ether));
252 if (slen <= 0) return_slen;
253 break;
254
255 /*
256 * Tag 1, with integer seconds since epoch.
257 *
258 * @todo - if the input has time resolution, then save it in that format.
259 *
260 * RFC 9581 Section 3.
261 *
262 * A tag with key 1001, and then: a map with required key 1 (integer epoch seconds) and
263 * optional key -3 (milliseconds), -6 (microseconds), or -9 (integer nanoseconds).
264 *
265 * For the encoder, there are a ton of different formats for dates, and we shouldn't
266 * bother to parse them all. :(
267 */
268 case FR_TYPE_DATE:
269 slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
270 if (slen <= 0) return_slen;
271
272 neg = fr_unix_time_to_sec(vb->vb_date);
273 slen = cbor_encode_int64(&work_dbuff, neg);
274 if (slen <= 0) return_slen;
275 break;
276
277 /*
278 * RFC 9581 Section 4.
279 *
280 * A tag with key 1002, and then: a map with required key 1 (integer seconds) and
281 * optional key -3 (milliseconds), -6 (microseconds), or -9 (integer nanoseconds).
282 */
284 slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
285 if (slen <= 0) return_slen;
286
287 neg = fr_time_delta_unwrap(vb->vb_time_delta) % NSEC;
288
289 slen = cbor_encode_integer(&work_dbuff, CBOR_MAP, 1 + (neg != 0));
290 if (slen <= 0) return_slen;
291
292 /*
293 * 1: seconds
294 */
295 slen = cbor_encode_key(&work_dbuff, 1);
296 if (slen <= 0) return_slen;
297
298 slen = cbor_encode_int64(&work_dbuff, fr_time_delta_to_sec(vb->vb_time_delta));
299 if (slen <= 0) return_slen;
300
301 /*
302 * -9: nanoseconds
303 */
304 if (neg) {
305 slen = cbor_encode_key(&work_dbuff, -9);
306 if (slen <= 0) return_slen;
307
308 slen = cbor_encode_int64(&work_dbuff, neg);
309 if (slen <= 0) return_slen;
310 }
311 break;
312
313 /*
314 * RFC 9164, Section 3.3
315 *
316 *
317 * tag=IPv4 + address + optional (prefix + scope)
318 */
320 slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
321 if (slen <= 0) return_slen;
322
323 if (vb->vb_ip.scope_id != 0) {
324 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_ARRAY << 5) | 3));
325
326 }
327
328 slen = cbor_encode_octets(&work_dbuff, (uint8_t const *) &vb->vb_ip.addr.v4.s_addr, 4);
329 if (slen <= 0) return_slen;
330
331 if (vb->vb_ip.scope_id == 0) break;
332
333 slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, (uint8_t) 32);
334 if (slen <= 0) return_slen;
335
336 slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, vb->vb_ip.scope_id);
337 if (slen <= 0) return_slen;
338 break;
339
340 /*
341 * RFC 9164, Section 3.2
342 *
343 * tag=IPv6 + address + optional (prefix + scope)
344 */
346 if (vb->vb_ip.scope_id != 0) {
347 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_ARRAY << 5) | 3));
348
349 }
350
351 slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
352 if (slen <= 0) return_slen;
353
354 slen = cbor_encode_octets(&work_dbuff, (uint8_t const *) &vb->vb_ip.addr.v6.s6_addr, 16);
355 if (slen <= 0) return_slen;
356
357 if (vb->vb_ip.scope_id == 0) break;
358
359 slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, (uint8_t) 32);
360 if (slen <= 0) return_slen;
361
362 slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, vb->vb_ip.scope_id);
363 if (slen <= 0) return_slen;
364 break;
365
366 /*
367 * RFC 9164, Section 3.3
368 *
369 * tag=IPv4 + array(prefix-length, address)
370 */
372 slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
373 if (slen <= 0) return_slen;
374
375 slen = cbor_encode_array(&work_dbuff, 2);
376 if (slen <= 0) return_slen;
377
378 slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, vb->vb_ip.prefix);
379 if (slen <= 0) return_slen;
380
381 p = (uint8_t const *) &vb->vb_ip.addr.v4.s_addr;
382 end = p + 3;
383
384 /*
385 * RFC 9164 Section 4.2 - Drop lower octets which are all zero.
386 *
387 * If this results in a zero-length string, so be it.
388 *
389 * Note also that "There is no relationship between the number of bytes omitted and the
390 * prefix length."
391 */
392 do {
393 if (*end != 0) break;
394
395 end--;
396 } while (end != p);
397
398 slen = cbor_encode_octets(&work_dbuff, p, (end - p) + (*end != 0));
399 if (slen <= 0) return_slen;
400 break;
401
402 /*
403 * RFC 9164, Section 3.2
404 *
405 * tag=IPv6 + array(prefix-length, address)
406 */
408 slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
409 if (slen <= 0) return_slen;
410
411 slen = cbor_encode_array(&work_dbuff, 2);
412 if (slen <= 0) return_slen;
413
414 slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, vb->vb_ip.prefix);
415 if (slen <= 0) return_slen;
416
417 p = (uint8_t const *) &vb->vb_ip.addr.v6.s6_addr;
418 end = p + 15;
419
420 /*
421 * RFC 9164 Section 4.2 - Drop lower octets which are all zero.
422 *
423 * If this results in a zero-length string, so be it.
424 *
425 * Note also that "There is no relationship between the number of bytes omitted and the
426 * prefix length."
427 */
428 do {
429 if (*end != 0) break;
430
431 end--;
432 } while (end != p);
433
434 slen = cbor_encode_octets(&work_dbuff, p, (end - p) + (*end != 0));
435 if (slen <= 0) return_slen;
436
437 break;
438
439 case FR_TYPE_FLOAT32:
440 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_FLOAT << 5) | CBOR_4_BYTE));
441
442 slen = cbor_encode_octets(&work_dbuff, (uint8_t const *) &vb->vb_float32, 4);
443 if (slen <= 0) return_slen;
444 break;
445
446 case FR_TYPE_FLOAT64:
447 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_FLOAT << 5) | CBOR_8_BYTE));
448
449 slen = cbor_encode_octets(&work_dbuff, (uint8_t const *) &vb->vb_float64, 8);
450 if (slen <= 0) return_slen;
451 break;
452
453 case FR_TYPE_GROUP:
454 /*
455 * Zero-length array.
456 */
457 if (fr_value_box_list_num_elements(&vb->vb_group) == 0) {
458 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_ARRAY << 5) | 0));
459 break;
460 }
461
462 /*
463 * The value is array(children)
464 */
465 slen = cbor_encode_integer(&work_dbuff, CBOR_ARRAY,
466 fr_value_box_list_num_elements(&vb->vb_group));
467 if (slen <= 0) return_slen;
468
469
470 fr_value_box_list_foreach(&vb->vb_group, child) {
471 slen = fr_cbor_encode_value_box(&work_dbuff, child);
472 if (slen <= 0) return_slen;
473 }
474 break;
475
476
477 default:
478 fr_strerror_printf("Invalid data type %s for cbor encoding", fr_type_to_str(vb->type));
479 return -1;
480 }
481
482 return fr_dbuff_set(dbuff, &work_dbuff);
483}
484
485
486static ssize_t cbor_decode_integer(uint64_t *out, uint8_t info, fr_dbuff_t *dbuff)
487{
488 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
489
490 if (info < 24) {
491 *out = info;
492 return 0;
493 }
494
495 if (info == CBOR_1_BYTE) {
497
498 FR_DBUFF_OUT_RETURN(&value, &work_dbuff);
499 *out = value;
500 goto done;
501 }
502
503 if (info == CBOR_2_BYTE) {
505
506 FR_DBUFF_OUT_RETURN(&value, &work_dbuff);
507 *out = value;
508 goto done;
509 }
510
511 if (info == CBOR_4_BYTE) {
513
514 FR_DBUFF_OUT_RETURN(&value, &work_dbuff);
515 *out = value;
516 goto done;
517 }
518
519 if (info == CBOR_8_BYTE) {
520 uint64_t value;
521
522 FR_DBUFF_OUT_RETURN(&value, &work_dbuff);
523 *out = value;
524 goto done;
525 }
526
527 /*
528 * 28 and greater are invalid according to the RFCs.
529 */
530
531done:
532 return fr_dbuff_set(dbuff, &work_dbuff);
533}
534
535static ssize_t cbor_decode_count(uint64_t *out, int expected, fr_dbuff_t *dbuff)
536{
537 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
538 uint8_t major, info;
539 ssize_t slen;
540
541 FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
542
543 info = major & 0x1f;
544 major >>= 5;
545
546 if (major != expected) {
547 fr_strerror_printf("Expected cbor type '%s', got unexpected type %d ",
548 cbor_type_to_str[expected], major);
549 return -1;
550 }
551
552 slen = cbor_decode_integer(out, info, &work_dbuff);
553 if (slen < 0) return_slen;
554
555 return fr_dbuff_set(dbuff, &work_dbuff);
556}
557
558typedef ssize_t (*cbor_decode_type_t)(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff);
559
560static ssize_t cbor_decode_octets_memcpy(uint8_t *dst, size_t dst_min, size_t dst_max, fr_dbuff_t *dbuff)
561{
562 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
563 ssize_t slen;
564 uint64_t value = 0;
565
566 slen = cbor_decode_count(&value, CBOR_OCTETS, &work_dbuff);
567 if (slen < 0) return_slen;
568
569 if (value < dst_min) {
570 fr_strerror_printf("Invalid length for data - expected at least %zu got %" PRIu64, dst_min, value);
571 return -1;
572 }
573
574 if (value > dst_max) {
575 fr_strerror_printf("Invalid length for data - expected no more than %zu got %" PRIu64, dst_max, value);
576 return -1;
577 }
578
579 FR_DBUFF_OUT_MEMCPY_RETURN(dst, &work_dbuff, value);
580
581 return fr_dbuff_set(dbuff, &work_dbuff);
582}
583
584#if 0
585static ssize_t *cbor_decode_octets_memdup(TALLOC_CTX *ctx, uint8_t **out, fr_dbuff_t *dbuff)
586{
587 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
588 ssize_t slen;
589 uint64_t value;
590 uint8_t *ptr;
591
592 slen = cbor_decode_count(&value, CBOR_OCTETS, &work_dbuff);
593 if (slen < 0) return_slen;
594
595 if (value > (1 << 20)) {
596 fr_strerror_printf("cbor data string is too long (%" PRIu64 ")", value);
597 return -1;
598 }
599
600 ptr = talloc_array(ctx, uint8_t, value);
601 if (!ptr) {
602 fr_strerror_const("Out of memory");
603 return -1;
604 }
605
606 FR_DBUFF_OUT_MEMCPY_RETURN(ptr, &work_dbuff, value);
607 *out = ptr;
608
609 return fr_dbuff_set(dbuff, &work_dbuff);
610}
611#endif
612
613static ssize_t cbor_decode_ethernet(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
614{
615 return cbor_decode_octets_memcpy(vb->vb_ether, sizeof(vb->vb_ether), sizeof(vb->vb_ether), dbuff);
616}
617
619{
620 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
621 ssize_t slen;
622 uint8_t header;
623 size_t count = 0;
624 uint64_t value = 0;
625
626 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 1);
627
628 header = *fr_dbuff_current(&work_dbuff);
629 if ((header >> 5) == CBOR_ARRAY) {
630 count = header & 0x1f;
631
632 if ((count != 2) && (count != 3)) {
633 fr_strerror_printf("Invalid IPv4 interface - expected array of 2-3 elements, got %02x",
634 header);
635 return -1;
636 }
637
638 fr_dbuff_advance(&work_dbuff, 1);
639 }
640
641 vb->vb_ip.prefix = 32;
642
643 /*
644 * Get the IP address.
645 */
646 slen = cbor_decode_octets_memcpy((uint8_t *) &vb->vb_ip.addr.v4.s_addr,
647 sizeof(vb->vb_ip.addr.v4.s_addr),
648 sizeof(vb->vb_ip.addr.v4.s_addr), &work_dbuff);
649 if (slen <= 0) return_slen;
650
651 if (!count) return fr_dbuff_set(dbuff, &work_dbuff);
652
653 slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
654 if (slen <= 0) return_slen;
655
656 if (value != 32) {
657 fr_strerror_printf("Invalid IPv4 address - expected prefix = 32 got %" PRIu64, value);
658 return -fr_dbuff_used(&work_dbuff);
659 }
660
661 if (count == 2) return fr_dbuff_set(dbuff, &work_dbuff);
662
663 /*
664 * Get the scope ID
665 */
666 slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
667 if (slen <= 0) return_slen;
668
669 vb->vb_ip.scope_id = value;
670
671 return fr_dbuff_set(dbuff, &work_dbuff);
672}
673
675{
676 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
677 ssize_t slen;
678 uint8_t header;
679 size_t count = 0;
680 uint64_t value = 0;
681
682 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 1);
683
684 header = *fr_dbuff_current(&work_dbuff);
685 if ((header >> 5) == CBOR_ARRAY) {
686 count = header & 0x1f;
687
688 if ((count != 2) && (count != 3)) {
689 fr_strerror_printf("Invalid IPv4 interface - expected array of 2-3 elements, got %02x",
690 header);
691 return -1;
692 }
693
694 fr_dbuff_advance(&work_dbuff, 1);
695 }
696
697 vb->vb_ip.prefix = 128;
698
699 /*
700 * Get the IP address.
701 */
702 slen = cbor_decode_octets_memcpy((uint8_t *) &vb->vb_ip.addr.v6.s6_addr,
703 sizeof(vb->vb_ip.addr.v6.s6_addr),
704 sizeof(vb->vb_ip.addr.v6.s6_addr), dbuff);
705
706 if (slen <= 0) return_slen;
707
708 if (!count) return fr_dbuff_set(dbuff, &work_dbuff);
709
710 slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
711 if (slen <= 0) return_slen;
712
713 if (value != 128) {
714 fr_strerror_printf("Invalid IPv6 address - expected prefix = 128 got %" PRIu64, value);
715 return -fr_dbuff_used(&work_dbuff);
716 }
717
718 vb->vb_ip.prefix = value;
719
720 if (count == 2) return fr_dbuff_set(dbuff, &work_dbuff);
721
722 /*
723 * Get the scope ID
724 */
725 slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
726 if (slen <= 0) return_slen;
727
728 vb->vb_ip.scope_id = value;
729
730 return fr_dbuff_set(dbuff, &work_dbuff);
731}
732
734{
735 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
736 ssize_t slen;
737 uint8_t header;
738 uint64_t value = 0;
739 uint8_t buffer[sizeof(vb->vb_ip.addr.v4.s_addr)];
740
741 FR_DBUFF_OUT_RETURN(&header, &work_dbuff);
742
743 if (header != ((CBOR_ARRAY << 5) | 2)) {
744 fr_strerror_printf("Invalid IPv4 prefix - expected array of 2 elements, got %02x",
745 header);
746 return -1;
747 }
748
749 slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
750 if (slen <= 0) return_slen;
751
752 if (value > 32) {
753 fr_strerror_printf("Invalid IPv4 prefix - expected prefix < 32, got %" PRIu64, value);
754 return -1;
755 }
756
757 /*
758 * RFC 9164 Section 4.3 - Trailing bytes of zero are omitted, so we
759 * first copy the data to a fixed-sized buffer which was
760 * zeroed out, and then (@todo) also check that unused bits in
761 * the last byte are all zero.
762 */
763 memset(buffer, 0, sizeof(buffer));
764
765 slen = cbor_decode_octets_memcpy(buffer, 0, sizeof(buffer), &work_dbuff);
766 if (slen <= 0) return_slen;
767
768 memcpy((uint8_t *) &vb->vb_ip.addr.v4.s_addr, buffer, sizeof(vb->vb_ip.addr.v4.s_addr));
769 vb->vb_ip.prefix = value;
770
771 return fr_dbuff_set(dbuff, &work_dbuff);
772}
773
775{
776 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
777 ssize_t slen;
778 uint8_t header;
779 uint64_t value = 0;
780 uint8_t buffer[sizeof(vb->vb_ip.addr.v6.s6_addr)];
781
782 FR_DBUFF_OUT_RETURN(&header, &work_dbuff);
783
784 if (header != ((CBOR_ARRAY << 5) | 2)) {
785 fr_strerror_printf("Invalid IPv6 prefix - expected array of 2 elements, got %02x",
786 header);
787 return -1;
788 }
789
790 slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
791 if (slen <= 0) return_slen;
792
793 if (value > 128) {
794 fr_strerror_printf("Invalid IPv6 prefix - expected prefix < 128, got %" PRIu64, value);
795 return -1;
796 }
797
798 /*
799 * RFC 9164 Section 4.3 - Trailing bytes of zero are omitted, so we
800 * first copy the data to a fixed-sized buffer which was
801 * zeroed out, and then (@todo) also check that unused bits in
802 * the last byte are all zero.
803 */
804 memset(buffer, 0, sizeof(buffer));
805
806 slen = cbor_decode_octets_memcpy(buffer, 0, sizeof(buffer), &work_dbuff);
807 if (slen <= 0) return_slen;
808
809 memcpy((uint8_t *) &vb->vb_ip.addr.v6.s6_addr, buffer, sizeof(vb->vb_ip.addr.v6.s6_addr));
810 vb->vb_ip.prefix = value;
811
812 return fr_dbuff_set(dbuff, &work_dbuff);
813}
814
816{
817 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
818 ssize_t slen;
819 uint8_t major, info;
820 uint64_t value = 0;
821 int64_t neg;
822
823 FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
824
825 info = major & 0x1f;
826 major >>= 5;
827
828 switch (major) {
829 case CBOR_INTEGER:
830 slen = cbor_decode_integer(&value, info, &work_dbuff);
831 if (slen < 0) return_slen;
832
833 if (value >= ((uint64_t) 1) << 63) { /* equal! */
834 invalid:
835 fr_strerror_printf("cbor value is too large for output data type %s",
837 return -1;
838 }
839
840 *out = value;
841 break;
842
843 case CBOR_NEGATIVE:
844 slen = cbor_decode_integer(&value, info, &work_dbuff);
845 if (slen < 0) return_slen;
846
847 if (value >= ((uint64_t) 1) << 63) goto invalid; /* greater than! */
848
849 /*
850 * Convert 0..(2^63-1) into -0..-(2^63-1)
851 * then conver to -1..-(2^63)
852 */
853 neg = -value;
854 neg--;
855
856 *out = neg;
857 break;
858
859 default:
860 fr_strerror_printf("cbor data contains invalid content %d for expected data type %s",
861 major, fr_type_to_str(type));
862 return -1;
863 }
864
865 return fr_dbuff_set(dbuff, &work_dbuff);
866
867}
868
869static ssize_t cbor_decode_date(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
870{
871 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
872 ssize_t slen;
873 int64_t neg;
874
875 slen = cbor_decode_int64(&neg, dbuff, FR_TYPE_DATE);
876 if (slen <= 0) return_slen;
877
878 vb->vb_date = fr_unix_time_from_sec(neg);
879
880 return fr_dbuff_set(dbuff, &work_dbuff);
881}
882
883/*
884 * Tag 1002, followed by map of at least 2 elements
885 * key 1: seconds
886 * key -9: nanoseconds
887 */
889{
890 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
891 uint64_t count;
892 ssize_t slen;
893 int64_t key, seconds, fraction, scale;
894
895 slen = cbor_decode_count(&count, CBOR_MAP, &work_dbuff);
896 if (slen < 0) return_slen;
897
898 if (!count || (count > 2)) {
899 fr_strerror_printf("Unexpected count %" PRIu64" for time_delta, expected map of 1-2 elements", count);
900 return -1;
901 }
902
903 key = seconds = fraction = 0;
904
905 /*
906 * Expect key 1:seconds
907 */
908 slen = cbor_decode_int64(&key, &work_dbuff, FR_TYPE_TIME_DELTA);
909 if (slen < 0) return_slen;
910
911 if (key != 1) {
912 fr_strerror_printf("Unexpected key %" PRIi64 " for time_delta, expected key 1", key);
913 return -1;
914 }
915
916 slen = cbor_decode_int64(&seconds, &work_dbuff, FR_TYPE_TIME_DELTA);
917 if (slen < 0) return_slen;
918
919 if (count > 1) {
920 slen = cbor_decode_int64(&key, &work_dbuff, FR_TYPE_TIME_DELTA);
921 if (slen < 0) return_slen;
922
923 switch (key) {
924 case -3:
925 scale = MSEC;
926 break;
927
928 case -6:
929 scale = USEC;
930 break;
931
932 case -9:
933 scale = NSEC;
934 break;
935
936 default:
937 fr_strerror_printf("Unsupported time_delta key %" PRIi64, key);
938 return -fr_dbuff_used(&work_dbuff); /* point to actual key? */
939
940 }
941
942 slen = cbor_decode_int64(&fraction, &work_dbuff, FR_TYPE_TIME_DELTA);
943 if (slen < 0) return_slen;
944
945 } else {
946 scale = NSEC;
947 fraction = 0;
948 }
949
950 if (seconds > (INT64_MAX / scale)) {
951 vb->vb_time_delta = fr_time_delta_max();
952
953 } else if (seconds < (INT64_MIN / scale)) {
954 vb->vb_time_delta = fr_time_delta_min();
955
956 } else {
957 /*
958 * We don't worry too much about positive seconds and negative nanoseconds.
959 *
960 * We also don't worry too much about overflow / underflow here.
961 */
962 fraction += seconds * scale;
963 vb->vb_time_delta = fr_time_delta_wrap(fraction);
964 }
965
966 return fr_dbuff_set(dbuff, &work_dbuff);
967}
968
969
982
983/*
984 * @todo - fr_cbor_encode_pair_list(). And then if we have da->flags.array, we encode the _value_ as an
985 * array of indeterminate length. This is a little bit of a special case, but not terrible.
986 */
988 fr_type_t type, fr_dict_attr_t const *enumv, bool tainted)
989{
990 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
991 bool indefinite;
992 uint8_t major, info;
993 ssize_t slen;
994 int64_t neg;
995 uint64_t value;
996 uint8_t *ptr;
997
998 FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
999
1000 if (type == FR_TYPE_NULL) {
1001 type = cbor_guess_type(&work_dbuff, false);
1002 if (type == FR_TYPE_NULL) return 0;
1003 }
1004
1005 fr_value_box_init(vb, type, enumv, tainted);
1006
1007 info = major & 0x1f;
1008 major >>= 5;
1009
1010 /*
1011 * Invalid combinations.
1012 */
1013 if (((info >= 28) && (info <= 30)) ||
1014 ((info == 31) && ((major == 0) || (major == 1) || (major == 6)))) {
1015 fr_strerror_const("Invalid cbor data - input is not 'well formed'");
1016 return 0;
1017 }
1018
1019 switch (major) {
1020 case CBOR_STRING:
1021 if (type != FR_TYPE_STRING) {
1022 mismatch:
1023 fr_strerror_printf("cbor data contains invalid content %d for expected data type %s",
1024 major, fr_type_to_str(type));
1025 return -1;
1026 }
1027
1028 if (info == 31) {
1029 no_chunks:
1030 fr_strerror_const("Chunked strings are not supported");
1031 return 0;
1032 }
1033
1034
1035 /*
1036 * @todo - undefinite length strings. Which are really "chunked" strings.
1037 */
1038 slen = cbor_decode_integer(&value, info, &work_dbuff);
1039 if (slen < 0) return_slen;
1040
1041 /*
1042 * A little bit of sanity check.
1043 */
1044 if (value > (1 << 20)) {
1045 fr_strerror_printf("cbor data string is too long (%" PRIu64 ")", value);
1046 return -1;
1047 }
1048
1049 ptr = talloc_array(ctx, uint8_t, value + 1);
1050 if (!ptr) {
1051 fr_strerror_const("Out of memory");
1052 return -1;
1053 }
1054 talloc_set_type(ptr, char);
1055 if (value) FR_DBUFF_OUT_MEMCPY_RETURN(ptr, &work_dbuff, value);
1056 ptr[value] = '\0';
1057
1058 fr_value_box_strdup_shallow(vb, NULL, (char const *) ptr, tainted);
1059
1060 break;
1061
1062 case CBOR_OCTETS:
1063 if (type != FR_TYPE_OCTETS) goto mismatch;
1064
1065 if (info == 31) goto no_chunks;
1066
1067 /*
1068 * @todo - indefinite length octet strings. Which are really "chunked" octet strings.
1069 */
1070 slen = cbor_decode_integer(&value, info, &work_dbuff);
1071 if (slen < 0) return_slen;
1072
1073 /*
1074 * A little bit of sanity check.
1075 */
1076 if (value > (1 << 20)) {
1077 fr_strerror_printf("cbor data string is too long (%" PRIu64 ")", value);
1078 return -1;
1079 }
1080
1081 ptr = talloc_array(ctx, uint8_t, value);
1082 if (!ptr) {
1083 fr_strerror_const("Out of memory");
1084 return -1;
1085 }
1086
1087 fr_value_box_memdup_shallow(vb, NULL, (uint8_t const *) ptr, value, false); /* tainted? */
1088
1089 if (value) FR_DBUFF_OUT_MEMCPY_RETURN(ptr, &work_dbuff, value);
1090 break;
1091
1092 case CBOR_INTEGER:
1093 slen = cbor_decode_integer(&value, info, &work_dbuff);
1094 if (slen < 0) return_slen;
1095
1096 switch (type) {
1097 case FR_TYPE_BOOL:
1098 if (value > 1) goto invalid_bool;
1099 vb->vb_bool = value;
1100 break;
1101
1102 case FR_TYPE_UINT8:
1103 if (value > UINT8_MAX) {
1104 invalid:
1105 fr_strerror_printf("cbor value is too large for output data type %s",
1107 return -1;
1108 }
1109 vb->vb_uint8 = value;
1110 break;
1111
1112 case FR_TYPE_UINT16:
1113 if (value > UINT16_MAX) goto invalid;
1114 vb->vb_uint16 = value;
1115 break;
1116
1117 case FR_TYPE_UINT32:
1118 if (value > UINT32_MAX) goto invalid;
1119 vb->vb_uint32 = value;
1120 break;
1121
1122 case FR_TYPE_UINT64:
1123 vb->vb_uint64 = value;
1124 break;
1125
1126 case FR_TYPE_INT8:
1127 if (value > INT8_MAX) goto invalid;
1128 vb->vb_int8 = value;
1129 break;
1130
1131 case FR_TYPE_INT16:
1132 if (value > INT16_MAX) goto invalid;
1133 vb->vb_int16 = value;
1134 break;
1135
1136 case FR_TYPE_INT32:
1137 if (value > INT32_MAX) goto invalid;
1138 vb->vb_int32 = value;
1139 break;
1140
1141 case FR_TYPE_INT64:
1142 if (value > INT64_MAX) goto invalid;
1143 vb->vb_int64 = value;
1144 break;
1145
1146 default:
1147 integer_type_mismatch:
1148 fr_strerror_printf("Unexpected cbor type 'integer' when decoding data type %s",
1150 return -1;
1151 }
1152 break;
1153
1154 case CBOR_NEGATIVE:
1155 slen = cbor_decode_integer(&value, info, &work_dbuff);
1156 if (slen < 0) return_slen;
1157
1158 /*
1159 * Signed numbers only go down to -2^63
1160 * so value must be less than 2^63
1161 */
1162 if (value >= ((uint64_t) 1) << 63) goto invalid;
1163
1164 /*
1165 * Convert 0..(2^63-1) into -0..-(2^63-1)
1166 * then conver to -1..-(2^63)
1167 */
1168 neg = -value;
1169 neg--;
1170
1171 switch (type) {
1172 case FR_TYPE_INT8:
1173 if (neg < INT8_MIN) goto invalid;
1174 vb->vb_int8 = neg;
1175 break;
1176
1177 case FR_TYPE_INT16:
1178 if (neg < INT16_MIN) goto invalid;
1179 vb->vb_int16 = neg;
1180 break;
1181
1182 case FR_TYPE_INT32:
1183 if (neg < INT32_MIN) goto invalid;
1184 vb->vb_int32 = neg;
1185 break;
1186
1187 case FR_TYPE_INT64:
1188 vb->vb_int64 = neg;
1189 break;
1190
1191 default:
1192 goto integer_type_mismatch;
1193 }
1194 break;
1195
1196 case CBOR_FLOAT:
1197 /*
1198 * Simple values. See RFC 8489 Section 3.3.
1199 *
1200 * 20 - false
1201 * 21 - true
1202 * 22 - NULL
1203 */
1204 if (info < 24) {
1205 switch (type) {
1206 case FR_TYPE_BOOL:
1207 if (info == 20) {
1208 vb->vb_bool = false;
1209 break;
1210 }
1211
1212 if (info == 21) {
1213 vb->vb_bool = true;
1214 break;
1215 }
1216
1217 invalid_bool:
1218 fr_strerror_printf("Invalid cbor - boolean is not encoded as 'true' or 'false'");
1219 return -fr_dbuff_used(&work_dbuff);
1220
1221 case FR_TYPE_OCTETS:
1222 case FR_TYPE_STRING:
1223 case FR_TYPE_TLV:
1224 case FR_TYPE_VENDOR:
1225 case FR_TYPE_GROUP:
1226 case FR_TYPE_STRUCT:
1227 /*
1228 * Be a little forgiving. 22 is NULL, so we treat that as "nothing".
1229 *
1230 * i.e. empty string, empty set, etc.
1231 */
1232 if (info == 22) break;
1233
1235
1236 default:
1237 fr_strerror_printf("Invalid cbor - unexpected 'simple value' %u", info);
1238 return -fr_dbuff_used(&work_dbuff);
1239 }
1240 break;
1241 }
1242
1243 /*
1244 * Or as one-byte integers.
1245 */
1246 if (info == CBOR_1_BYTE) {
1247 uint8_t data;
1248
1249 FR_DBUFF_OUT_RETURN(&data, &work_dbuff);
1250
1251 switch (type) {
1252 case FR_TYPE_FLOAT32:
1253 vb->vb_float32 = data;
1254 break;
1255
1256 case FR_TYPE_FLOAT64:
1257 vb->vb_float64 = data;
1258 break;
1259
1260 default:
1261 float_type_mismatch:
1262 fr_strerror_printf("Unexpected cbor type 'float' when decoding data type %s",
1264 return -1;
1265 }
1266
1267 break;
1268 }
1269
1270 /*
1271 * We don't support float16
1272 */
1273
1274 if (info == CBOR_4_BYTE) {
1275 float data;
1276
1277 FR_DBUFF_OUT_RETURN(&data, &work_dbuff);
1278
1279 switch (type) {
1280 case FR_TYPE_FLOAT32:
1281 vb->vb_float32 = data;
1282 break;
1283
1284 case FR_TYPE_FLOAT64:
1285 vb->vb_float64 = (double) data;
1286 break;
1287
1288 default:
1289 goto float_type_mismatch;
1290 }
1291
1292 break;
1293 }
1294
1295 if (info == CBOR_8_BYTE) {
1296 double data;
1297
1298 FR_DBUFF_OUT_RETURN(&data, &work_dbuff);
1299
1300 switch (type) {
1301 case FR_TYPE_FLOAT32:
1302 vb->vb_float32 = data; /* maybe loses precision? */
1303 break;
1304
1305 case FR_TYPE_FLOAT64:
1306 vb->vb_float64 = data;
1307 break;
1308
1309 default:
1310 goto float_type_mismatch;
1311 }
1312
1313 break;
1314 }
1315
1316 /*
1317 * 24 is FLOAT16, which we don't support.
1318 * 31 is BREAK, which the caller should have checked for.
1319 */
1320 goto float_type_mismatch;
1321
1322 case CBOR_TAG:
1323 /*
1324 * We only support a limited number of tags.
1325 */
1326 slen = cbor_decode_integer(&value, info, &work_dbuff);
1327 if (slen < 0) return_slen;
1328
1330
1331 /*
1332 * No tag defined for this data type, that's on us.
1333 */
1334 if (!cbor_type_to_tag[type]) {
1335 fr_strerror_printf("Unknown cbor tag %" PRIu64 " for expected data type %s",
1337 return -fr_dbuff_used(&work_dbuff);
1338 }
1339
1340 /*
1341 * Wrong tag for this data type, that's on them.
1342 */
1343 if (cbor_type_to_tag[type] != value) {
1344 fr_strerror_printf("Invalid cbor tag %" PRIu64 " for expected data type %s",
1346 return -fr_dbuff_used(&work_dbuff);
1347 }
1348
1349 fr_value_box_init(vb, type, enumv, tainted);
1350
1351 slen = cbor_decode_type[type](ctx, vb, &work_dbuff);
1352 if (slen < 0) return_slen;
1353 break;
1354
1355 case CBOR_ARRAY:
1356 if (type != FR_TYPE_GROUP) goto invalid_type;
1357
1358 /*
1359 * Loop until done.
1360 */
1361 if (info == 31) {
1362 value = ~0;
1363 indefinite = true;
1364
1365 } else {
1366 slen = cbor_decode_integer(&value, info, &work_dbuff);
1367 if (slen < 0) return_slen;
1368
1369 indefinite = false;
1370 }
1371
1372#ifdef STATIC_ANALYZER
1373 if (value > fr_dbuff_remaining(&work_dbuff)) return -1;
1374#endif
1375
1376 /*
1377 * Loop until we decode everything. For simplicity, we handle indefinite and definite
1378 * length arrays in the same loop.
1379 */
1380 for (/* nothing */; value > 0; value--) {
1381 uint8_t header;
1382 fr_value_box_t *child;
1383
1384 /*
1385 * Require at least one byte in the buffer.
1386 */
1387 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 1);
1388
1389 /*
1390 * Peek ahead for a break.
1391 */
1392 header = *fr_dbuff_current(&work_dbuff);
1393 if (header == 0xff) {
1394 if (!indefinite) {
1395 fr_strerror_const("Unexpected 'break' found in cbor data");
1396 return -fr_dbuff_used(&work_dbuff);
1397 }
1398
1399 /*
1400 * Done!
1401 */
1402 fr_dbuff_advance(&work_dbuff, 1);
1403 break;
1404 }
1405
1406 child = fr_value_box_alloc(ctx, FR_TYPE_NULL, NULL);
1407 if (!child) {
1408 fr_strerror_const("Out of memory");
1409 return -fr_dbuff_used(&work_dbuff);
1410 }
1411
1412 /*
1413 * We have to decode at least one value.
1414 */
1415 slen = fr_cbor_decode_value_box(child, child, &work_dbuff, FR_TYPE_NULL, NULL, tainted);
1416 if (slen <= 0) return_slen;
1417
1418 fr_value_box_list_insert_tail(&vb->vb_group, child);
1419 }
1420 break;
1421
1422 /*
1423 * These are not value-box types.
1424 */
1425 case CBOR_MAP:
1427 fr_strerror_printf("Invalid data type %s for cbor to value-box", fr_type_to_str(type));
1428 return -1;
1429 }
1430
1431 return fr_dbuff_set(dbuff, &work_dbuff);
1432}
1433
1434/** Encode a pair
1435 *
1436 */
1438{
1439 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
1440 ssize_t slen;
1441 fr_dict_attr_t const *parent;
1442 size_t count;
1443
1444 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_MAP << 5) | 1)); /* map of 1 item */
1445
1446 /*
1447 * Key is the attribute number.
1448 */
1449 slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, vp->da->attr);
1450 if (slen <= 0) return_slen;
1451
1452 /*
1453 * Value is the actual value of the leaf, or the array of children.
1454 */
1455 switch (vp->vp_type) {
1456 case FR_TYPE_LEAF:
1457 slen = fr_cbor_encode_value_box(&work_dbuff, &vp->data);
1458 if (slen <= 0) return_slen;
1459 break;
1460
1461 /*
1462 * Groups reparent to the ref.
1463 */
1464 case FR_TYPE_GROUP:
1466 fr_assert(parent != NULL);
1467 goto encode_children;
1468
1469 /*
1470 * The only difference between TLV and VSA is that the children of VSA are all VENDORs.
1471 */
1472 case FR_TYPE_VENDOR:
1473 case FR_TYPE_VSA:
1474 case FR_TYPE_TLV:
1475 parent = vp->da;
1476
1477 /*
1478 * The value is array(children)
1479 */
1480encode_children:
1481 if (fr_pair_list_num_elements(&vp->vp_group) == 0) {
1482 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_FLOAT << 5) | 22)); /* NULL */
1483 break;
1484 }
1485
1486 /*
1487 * The groups, etc. may contain internal attributes. We don't yet deal with those.
1488 */
1489 count = 0;
1490 fr_pair_list_foreach(&vp->vp_group, child) {
1491 if (child->da->parent != parent) continue;
1492 count++;
1493 }
1494
1495 slen = cbor_encode_integer(&work_dbuff, CBOR_ARRAY, count);
1496 if (slen <= 0) return_slen;
1497
1498 fr_pair_list_foreach(&vp->vp_group, child) {
1499 /*
1500 * We don't allow changing dictionaries here.
1501 */
1502 if (child->da->parent != parent) continue;
1503
1504 slen = fr_cbor_encode_pair(&work_dbuff, child);
1505 if (slen <= 0) return_slen;
1506 }
1507 break;
1508
1509 /*
1510 * @todo - struct, except if we hit the end of the struct, check if the next child is the child
1511 * of the key? That makes it all more annoying :(
1512 */
1513
1514 default:
1515 fr_strerror_printf("Invalid data type %s for cbor encoding", fr_type_to_str(vp->vp_type));
1516 return -1;
1517 }
1518
1519 return fr_dbuff_set(dbuff, &work_dbuff);
1520}
1521
1522/** Guess the data type of the CBOR data.
1523 *
1524 * We've parsed the attribute number, and found that we don't have a dictionary entry for it. But rather
1525 * than create an attribute of type octets, we try to guess the data type.
1526 */
1527static fr_type_t cbor_guess_type(fr_dbuff_t *dbuff, bool pair)
1528{
1529 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
1530 ssize_t slen;
1531 uint8_t major, info;
1532 uint64_t value;
1533
1534 /*
1535 * get the next byte, which is a CBOR header.
1536 */
1537 slen = fr_dbuff_out(&major, &work_dbuff);
1538 if (slen <= 0) {
1539 no_data:
1540 fr_strerror_const("Invalid cbor - insufficient data");
1541 return FR_TYPE_NULL;
1542 }
1543
1544 info = major & 0x1f;
1545 major >>= 5;
1546
1547 switch (major) {
1548 case CBOR_INTEGER:
1549 return FR_TYPE_UINT64;
1550
1551 case CBOR_NEGATIVE:
1552 return FR_TYPE_UINT64;
1553
1554 case CBOR_STRING:
1555 return FR_TYPE_STRING;
1556
1557 case CBOR_OCTETS:
1558 return FR_TYPE_OCTETS;
1559
1560 case CBOR_ARRAY:
1561 if (!pair) return FR_TYPE_GROUP;
1562 break;
1563
1564 case CBOR_MAP:
1565 return FR_TYPE_TLV;
1566
1567 /*
1568 * Look at the tag to determine what it is
1569 */
1570 case CBOR_TAG:
1571 slen = cbor_decode_integer(&value, info, &work_dbuff);
1572 if (slen < 0) break;
1573
1574 switch (value) {
1575 case 1:
1576 case 1001:
1577 return FR_TYPE_DATE;
1578
1579 case 1002:
1580 return FR_TYPE_TIME_DELTA;
1581
1582 case 48:
1583 return FR_TYPE_ETHERNET;
1584
1585 case 52:
1586 slen = fr_dbuff_out(&major, &work_dbuff);
1587 if (slen <= 0) goto no_data;
1588
1589 major >>= 5;
1590
1591 if (major == CBOR_ARRAY) {
1592 return FR_TYPE_IPV4_PREFIX;
1593 }
1594 return FR_TYPE_IPV4_ADDR;
1595
1596 case 54:
1597 slen = fr_dbuff_out(&major, &work_dbuff);
1598 if (slen <= 0) goto no_data;
1599
1600 major >>= 5;
1601
1602 if (major == CBOR_ARRAY) {
1603 return FR_TYPE_IPV6_PREFIX;
1604 }
1605 return FR_TYPE_IPV6_ADDR;
1606
1607 default:
1608 break;
1609 }
1610
1611 break;
1612
1613 case CBOR_FLOAT:
1614 /*
1615 * In-place values are special. false / true / NULL
1616 */
1617 if (info < 24) {
1618 if ((info == 20) || (info == 21)) return FR_TYPE_BOOL;
1619
1620 return FR_TYPE_NULL;
1621 }
1622
1623 return FR_TYPE_FLOAT64;
1624 }
1625
1626
1627 /*
1628 * No idea. :(
1629 *
1630 * @todo - also check the cbor data, and return the length of cbor data which needs to be
1631 * converted to data type 'octets'. This work involves mostly parsing the cbor data, which isn't
1632 * trivial.
1633 */
1634 fr_strerror_const("Invalid cbor - unable to determine data type");
1635 return FR_TYPE_NULL;
1636}
1637
1639 fr_dict_attr_t const *parent, bool tainted)
1640{
1641 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
1642 uint8_t header, major, info;
1643 bool indefinite;
1644 ssize_t slen;
1645 fr_pair_t *vp;
1646 uint64_t value = 0;
1647 fr_dict_attr_t const *da;
1648
1649 FR_DBUFF_OUT_RETURN(&header, &work_dbuff);
1650
1651 /*
1652 * We require a 2-element array(attribute number, value)
1653 */
1654 if (header != (((CBOR_MAP) << 5) | 1)) {
1655 fr_strerror_printf("Invalid cbor header - expected map of 1 elements, got %02x", header);
1656 return -1;
1657 }
1658
1659 /*
1660 * This should be a CBOR_INTEGER.
1661 */
1662 FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
1663
1664 info = major & 0x1f;
1665 major >>= 5;
1666
1667 if (major != CBOR_INTEGER) {
1668 fr_strerror_printf("Invalid cbor - expected 'integer', got major type %d",
1669 major);
1670 return -1;
1671 }
1672
1673 slen = cbor_decode_integer(&value, info, &work_dbuff);
1674 if (slen < 0) {
1676 }
1677
1679 if (!da) {
1681
1682 type = cbor_guess_type(&work_dbuff, true);
1683 if (type == FR_TYPE_NULL) return -fr_dbuff_used(&work_dbuff);
1684
1685 /*
1686 * @todo - the value here isn't a cbor octets type, but is instead cbor data. Since cbor
1687 * is typed, we _could_ perhaps instead discover the type from the cbor data, and then
1688 * use that instead. This would involve creating a function which maps cbor types to our
1689 * data types.
1690 */
1692 if (!da) goto oom;
1693 }
1694
1695 vp = fr_pair_afrom_da(ctx, da);
1696 if (!vp) {
1697 oom:
1698 fr_strerror_const("Out of memory");
1699 return -fr_dbuff_used(&work_dbuff);
1700 }
1701
1702 /*
1703 * Leaf values are easy.
1704 */
1705 if (fr_type_is_leaf(da->type)) {
1706 slen = fr_cbor_decode_value_box(vp, &vp->data, &work_dbuff, da->type, da, tainted);
1707 if (slen <= 0) {
1708 talloc_free(vp);
1710 }
1711
1712 goto done;
1713 }
1714
1715 switch (da->type) {
1716 /*
1717 * All of these are essentially the same.
1718 */
1719 case FR_TYPE_VENDOR:
1720 case FR_TYPE_VSA:
1721 case FR_TYPE_TLV:
1722 parent = vp->da;
1723 break;
1724
1725 /*
1726 * Groups reparent to the ref.
1727 */
1728 case FR_TYPE_GROUP:
1730 fr_assert(parent != NULL);
1731 break;
1732
1733 default:
1734 fr_strerror_printf("Invalid data type %s for child %s of %s",
1735 fr_type_to_str(da->type), vp->da->name, parent->name);
1736 talloc_free(vp);
1737 return -1;
1738 }
1739
1740 /*
1741 * This should be a CBOR_ARRAY.
1742 */
1743 FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
1744
1745 info = major & 0x1f;
1746 major >>= 5;
1747
1748 if (major != CBOR_ARRAY) {
1749 /*
1750 * Allow NULL as a synonym for "no children".
1751 */
1752 if ((major == CBOR_FLOAT) && (info == 22)) goto done;
1753
1754 talloc_free(vp);
1755 fr_strerror_printf("Invalid cbor - expected 'array', got major type %d",
1756 major);
1757 return -1;
1758 }
1759
1760 if (info == 31) {
1761 value = ~0;
1762 indefinite = true;
1763
1764 } else {
1765 slen = cbor_decode_integer(&value, info, &work_dbuff);
1766 if (slen < 0) {
1767 talloc_free(vp);
1769 }
1770
1771 indefinite = false;
1772 }
1773
1774#ifdef STATIC_ANALYZER
1775 if (value > fr_dbuff_remaining(&work_dbuff)) return -1;
1776#endif
1777
1778 /*
1779 * Loop until we decode everything. For simplicity, we handle indefinite and definite
1780 * length arrays in the same loop.
1781 */
1782 for (/* nothing */; value > 0; value--) {
1783 /*
1784 * Require at least one byte in the buffer.
1785 */
1786 if (fr_dbuff_extend_lowat(NULL, &work_dbuff, 1) == 0) {
1787 talloc_free(vp);
1788 return -fr_dbuff_used(&work_dbuff);
1789 }
1790
1791 /*
1792 * Peek ahead for a break.
1793 */
1794 header = *fr_dbuff_current(&work_dbuff);
1795 if (header == 0xff) {
1796 if (!indefinite) {
1797 talloc_free(vp);
1798 fr_strerror_const("Unexpected 'break' found in cbor data");
1799 return -fr_dbuff_used(&work_dbuff);
1800 }
1801
1802 /*
1803 * Done!
1804 */
1805 fr_dbuff_advance(&work_dbuff, 1);
1806 break;
1807 }
1808
1809 slen = fr_cbor_decode_pair(vp, &vp->vp_group, &work_dbuff, parent, tainted);
1810 if (slen <= 0) {
1811 talloc_free(vp);
1813 }
1814 }
1815
1816done:
1817 PAIR_VERIFY(vp);
1818
1820 return fr_dbuff_set(dbuff, &work_dbuff);
1821}
1822
1823/*
1824 * @todo - cbor_print
1825 * [] for array
1826 * [_...] for indefinite array
1827 * {a:b} for map
1828 * digits for integer
1829 * 'string' for string
1830 * h'HHHH' for octets
1831 *
1832 * https://datatracker.ietf.org/doc/html/draft-ietf-cbor-edn-literals
1833 */
static int const char char buffer[256]
Definition acutest.h:576
#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 UNUSED
Definition build.h:315
static int invalid_type(fr_type_t type)
Definition calc.c:698
ssize_t fr_cbor_encode_value_box(fr_dbuff_t *dbuff, fr_value_box_t *vb)
Encode CBOR.
Definition cbor.c:166
static ssize_t cbor_decode_ipv4_addr(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
Definition cbor.c:618
static ssize_t cbor_decode_int64(int64_t *out, fr_dbuff_t *dbuff, fr_type_t type)
Definition cbor.c:815
#define CBOR_2_BYTE
Definition cbor.c:37
static ssize_t cbor_decode_ipv6_addr(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
Definition cbor.c:674
#define CBOR_TAG
Definition cbor.c:33
static ssize_t cbor_decode_octets_memcpy(uint8_t *dst, size_t dst_min, size_t dst_max, fr_dbuff_t *dbuff)
Definition cbor.c:560
#define cbor_encode_tag(_dbuff, _tag)
Definition cbor.c:118
static ssize_t cbor_encode_octets(fr_dbuff_t *dbuff, uint8_t const *data, size_t data_len)
Definition cbor.c:128
ssize_t fr_cbor_encode_pair(fr_dbuff_t *dbuff, fr_pair_t *vp)
Encode a pair.
Definition cbor.c:1437
static const uint64_t cbor_type_to_tag[FR_TYPE_MAX+1]
Definition cbor.c:53
#define CBOR_INTEGER
Definition cbor.c:27
#define CBOR_1_BYTE
Definition cbor.c:36
#define CBOR_OCTETS
Definition cbor.c:29
static ssize_t cbor_decode_date(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
Definition cbor.c:869
#define return_slen
Definition cbor.c:123
#define CBOR_FLOAT
Definition cbor.c:34
static cbor_decode_type_t cbor_decode_type[FR_TYPE_MAX]
Definition cbor.c:970
static ssize_t cbor_decode_time_delta(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
Definition cbor.c:888
static ssize_t cbor_decode_ipv4_prefix(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
Definition cbor.c:733
#define CBOR_NEGATIVE
Definition cbor.c:28
#define CBOR_4_BYTE
Definition cbor.c:38
static fr_type_t cbor_guess_type(fr_dbuff_t *dbuff, bool pair)
Guess the data type of the CBOR data.
Definition cbor.c:1527
static ssize_t cbor_encode_integer(fr_dbuff_t *dbuff, uint8_t type, uint64_t data)
Definition cbor.c:65
static ssize_t cbor_decode_integer(uint64_t *out, uint8_t info, fr_dbuff_t *dbuff)
Definition cbor.c:486
static ssize_t cbor_decode_ethernet(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
Definition cbor.c:613
ssize_t fr_cbor_decode_value_box(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff, fr_type_t type, fr_dict_attr_t const *enumv, bool tainted)
Definition cbor.c:987
static ssize_t cbor_encode_int64(fr_dbuff_t *dbuff, int64_t neg)
Definition cbor.c:141
static ssize_t cbor_decode_ipv6_prefix(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
Definition cbor.c:774
#define cbor_encode_array(_dbuff, _size)
Definition cbor.c:116
ssize_t fr_cbor_decode_pair(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dbuff_t *dbuff, fr_dict_attr_t const *parent, bool tainted)
Definition cbor.c:1638
#define CBOR_8_BYTE
Definition cbor.c:39
#define cbor_encode_key
Definition cbor.c:160
#define CBOR_MAP
Definition cbor.c:32
#define CBOR_ARRAY
Definition cbor.c:31
static const char * cbor_type_to_str[8]
Definition cbor.c:41
ssize_t(* cbor_decode_type_t)(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
Definition cbor.c:558
static ssize_t cbor_decode_count(uint64_t *out, int expected, fr_dbuff_t *dbuff)
Definition cbor.c:535
#define CBOR_STRING
Definition cbor.c:30
#define fr_dbuff_advance(_dbuff_or_marker, _len)
Advance 'current' position in dbuff or marker by _len bytes.
Definition dbuff.h:1072
#define fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
Definition dbuff.h:767
#define FR_DBUFF_EXTEND_LOWAT_OR_RETURN(_dbuff_or_marker, _lowat)
Extend if we're below _lowat and return if we can't extend above _lowat.
Definition dbuff.h:673
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
Definition dbuff.h:911
#define fr_dbuff_set(_dst, _src)
Set the 'current' position in a dbuff or marker using another dbuff or marker, a char pointer,...
Definition dbuff.h:1004
#define fr_dbuff_extend_lowat(_status, _dbuff_or_marker, _lowat)
Extend if we're below _lowat.
Definition dbuff.h:660
#define fr_dbuff_remaining(_dbuff_or_marker)
Return the number of bytes remaining between the dbuff or marker and the end of the buffer.
Definition dbuff.h:743
#define FR_DBUFF_OUT_MEMCPY_RETURN(_out, _dbuff_or_marker, _outlen)
Copy outlen bytes from the dbuff returning if there's insufficient data in the dbuff.
Definition dbuff.h:1752
#define FR_DBUFF_IN_MEMCPY_RETURN(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into dbuff or marker returning if there's insufficient space.
Definition dbuff.h:1382
#define FR_DBUFF_IN_RETURN(_dbuff_or_marker, _in)
Copy data from a fixed sized C type into a dbuff returning if there is insufficient space.
Definition dbuff.h:1585
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:222
#define FR_DBUFF_OUT_RETURN(_out, _dbuff_or_marker)
Copy data from a dbuff or marker to a fixed sized C type returning if there is insufficient data.
Definition dbuff.h:1818
#define fr_dbuff_out(_out, _dbuff_or_marker)
Copy data from a dbuff or marker to a fixed sized C type.
Definition dbuff.h:1799
#define FR_DBUFF_IN_BYTES_RETURN(_dbuff_or_marker,...)
Copy a byte sequence into a dbuff or marker returning if there's insufficient space.
Definition dbuff.h:1472
static fr_dict_attr_t * fr_dict_attr_unknown_typed_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int num, fr_type_t type)
Definition dict.h:565
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_dict_attr_t const * fr_dict_attr_ref(fr_dict_attr_t const *da)
Return the reference associated with a group type attribute.
Definition dict_ext.h:184
Test enumeration values.
Definition dict_test.h:92
talloc_free(reap)
unsigned short uint16_t
fr_type_t
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
@ FR_TYPE_FLOAT32
Single precision floating point.
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_INT8
8 Bit signed integer.
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_ETHERNET
48 Bit Mac-Address.
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_MAX
Number of defined data types.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_UINT16
16 Bit unsigned integer.
@ FR_TYPE_INT64
64 Bit signed integer.
@ FR_TYPE_INT16
16 Bit signed integer.
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
@ FR_TYPE_INT32
32 Bit signed integer.
@ FR_TYPE_VENDOR
Attribute that represents a vendor in the attribute tree.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
@ FR_TYPE_FLOAT64
Double precision floating point.
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
#define UINT8_MAX
static void fr_nbo_from_uint16(uint8_t out[static sizeof(uint16_t)], uint16_t num)
Write out an unsigned 16bit integer in wire format (big endian)
Definition nbo.h:38
static void fr_nbo_from_uint64(uint8_t out[static sizeof(uint64_t)], uint64_t num)
Write out an unsigned 64bit integer in wire format (big endian)
Definition nbo.h:72
static void fr_nbo_from_uint32(uint8_t out[static sizeof(uint32_t)], uint32_t num)
Write out an unsigned 32bit integer in wire format (big endian)
Definition nbo.h:61
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
#define fr_assert(_expr)
Definition rad_assert.h:38
static bool done
Definition radclient.c:80
return count
Definition module.c:163
fr_aka_sim_id_type_t type
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition pair.h:69
#define MSEC
Definition time.h:381
#define fr_time_delta_min()
Definition time.h:151
static int64_t fr_time_delta_unwrap(fr_time_delta_t time)
Definition time.h:154
static int64_t fr_unix_time_to_sec(fr_unix_time_t delta)
Definition time.h:506
#define fr_time_delta_wrap(_time)
Definition time.h:152
static int64_t fr_time_delta_to_sec(fr_time_delta_t delta)
Definition time.h:647
static fr_unix_time_t fr_unix_time_from_sec(int64_t sec)
Definition time.h:449
#define NSEC
Definition time.h:379
#define USEC
Definition time.h:380
#define fr_time_delta_max()
Definition time.h:150
#define PAIR_VERIFY(_x)
Definition pair.h:191
#define fr_pair_list_foreach(_list_head, _iter)
Iterate over the contents of a fr_pair_list_t.
Definition pair.h:261
size_t fr_pair_list_num_elements(fr_pair_list_t const *list)
Get the length of a list of fr_pair_t.
static fr_slen_t parent
Definition pair.h:851
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
#define fr_type_is_leaf(_x)
Definition types.h:372
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:433
#define FR_TYPE_LEAF
Definition types.h:297
void fr_value_box_memdup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, uint8_t const *src, size_t len, bool tainted)
Assign a buffer to a box, but don't copy it.
Definition value.c:4548
void fr_value_box_strdup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Assign a buffer containing a nul terminated string to a box, but don't copy it.
Definition value.c:4036
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:621
static fr_slen_t data
Definition value.h:1265
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
Definition value.h:587
#define fr_value_box_list_foreach(_list_head, _iter)
Definition value.h:206
static size_t char ** out
Definition value.h:997