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: b6543428c2956fb4e9f4655263f20aa521e9d8dc $")
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 if ((fraction < 0) || (fraction > scale)) fraction = 0;
946 } else {
947 scale = NSEC;
948 fraction = 0;
949 }
950
951 if (seconds > (INT64_MAX / scale)) {
952 vb->vb_time_delta = fr_time_delta_max();
953
954 } else if (seconds < (INT64_MIN / scale)) {
955 vb->vb_time_delta = fr_time_delta_min();
956
957 } else {
958 seconds *= scale;
959
960 if (seconds < 0) {
961 seconds -= fraction;
962 } else {
963 seconds += fraction;
964 }
965
966 vb->vb_time_delta = fr_time_delta_wrap(seconds);
967 }
968
969 return fr_dbuff_set(dbuff, &work_dbuff);
970}
971
972
985
986/*
987 * @todo - fr_cbor_encode_pair_list(). And then if we have da->flags.array, we encode the _value_ as an
988 * array of indeterminate length. This is a little bit of a special case, but not terrible.
989 */
991 fr_type_t type, fr_dict_attr_t const *enumv, bool tainted)
992{
993 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
994 bool indefinite;
995 uint8_t major, info;
996 ssize_t slen;
997 int64_t neg;
998 uint64_t value;
999 uint8_t *ptr;
1000
1001 FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
1002
1003 if (type == FR_TYPE_NULL) {
1004 type = cbor_guess_type(&work_dbuff, false);
1005 if (type == FR_TYPE_NULL) return 0;
1006 }
1007
1008 fr_value_box_init(vb, type, enumv, tainted);
1009
1010 info = major & 0x1f;
1011 major >>= 5;
1012
1013 /*
1014 * Invalid combinations.
1015 */
1016 if (((info >= 28) && (info <= 30)) ||
1017 ((info == 31) && ((major == 0) || (major == 1) || (major == 6)))) {
1018 fr_strerror_const("Invalid cbor data - input is not 'well formed'");
1019 return 0;
1020 }
1021
1022 switch (major) {
1023 case CBOR_STRING:
1024 if (type != FR_TYPE_STRING) {
1025 mismatch:
1026 fr_strerror_printf("cbor data contains invalid content %d for expected data type %s",
1027 major, fr_type_to_str(type));
1028 return -1;
1029 }
1030
1031 if (info == 31) {
1032 no_chunks:
1033 fr_strerror_const("Chunked strings are not supported");
1034 return 0;
1035 }
1036
1037
1038 /*
1039 * @todo - undefinite length strings. Which are really "chunked" strings.
1040 */
1041 slen = cbor_decode_integer(&value, info, &work_dbuff);
1042 if (slen < 0) return_slen;
1043
1044 /*
1045 * A little bit of sanity check.
1046 */
1047 if (value > (1 << 20)) {
1048 fr_strerror_printf("cbor data string is too long (%" PRIu64 ")", value);
1049 return -1;
1050 }
1051
1052 ptr = talloc_array(ctx, uint8_t, value + 1);
1053 if (!ptr) {
1054 fr_strerror_const("Out of memory");
1055 return -1;
1056 }
1057 talloc_set_type(ptr, char);
1058 if (value) FR_DBUFF_OUT_MEMCPY_RETURN(ptr, &work_dbuff, value);
1059 ptr[value] = '\0';
1060
1061 fr_value_box_strdup_shallow(vb, NULL, (char const *) ptr, tainted);
1062
1063 break;
1064
1065 case CBOR_OCTETS:
1066 if (type != FR_TYPE_OCTETS) goto mismatch;
1067
1068 if (info == 31) goto no_chunks;
1069
1070 /*
1071 * @todo - indefinite length octet strings. Which are really "chunked" octet strings.
1072 */
1073 slen = cbor_decode_integer(&value, info, &work_dbuff);
1074 if (slen < 0) return_slen;
1075
1076 /*
1077 * A little bit of sanity check.
1078 */
1079 if (value > (1 << 20)) {
1080 fr_strerror_printf("cbor data string is too long (%" PRIu64 ")", value);
1081 return -1;
1082 }
1083
1084 ptr = talloc_array(ctx, uint8_t, value);
1085 if (!ptr) {
1086 fr_strerror_const("Out of memory");
1087 return -1;
1088 }
1089
1090 fr_value_box_memdup_shallow(vb, NULL, (uint8_t const *) ptr, value, false); /* tainted? */
1091
1092 if (value) FR_DBUFF_OUT_MEMCPY_RETURN(ptr, &work_dbuff, value);
1093 break;
1094
1095 case CBOR_INTEGER:
1096 slen = cbor_decode_integer(&value, info, &work_dbuff);
1097 if (slen < 0) return_slen;
1098
1099 switch (type) {
1100 case FR_TYPE_BOOL:
1101 if (value > 1) goto invalid_bool;
1102 vb->vb_bool = value;
1103 break;
1104
1105 case FR_TYPE_UINT8:
1106 if (value > UINT8_MAX) {
1107 invalid:
1108 fr_strerror_printf("cbor value is too large for output data type %s",
1110 return -1;
1111 }
1112 vb->vb_uint8 = value;
1113 break;
1114
1115 case FR_TYPE_UINT16:
1116 if (value > UINT16_MAX) goto invalid;
1117 vb->vb_uint16 = value;
1118 break;
1119
1120 case FR_TYPE_UINT32:
1121 if (value > UINT32_MAX) goto invalid;
1122 vb->vb_uint32 = value;
1123 break;
1124
1125 case FR_TYPE_UINT64:
1126 vb->vb_uint64 = value;
1127 break;
1128
1129 case FR_TYPE_INT8:
1130 if (value > INT8_MAX) goto invalid;
1131 vb->vb_int8 = value;
1132 break;
1133
1134 case FR_TYPE_INT16:
1135 if (value > INT16_MAX) goto invalid;
1136 vb->vb_int16 = value;
1137 break;
1138
1139 case FR_TYPE_INT32:
1140 if (value > INT32_MAX) goto invalid;
1141 vb->vb_int32 = value;
1142 break;
1143
1144 case FR_TYPE_INT64:
1145 if (value > INT64_MAX) goto invalid;
1146 vb->vb_int64 = value;
1147 break;
1148
1149 default:
1150 integer_type_mismatch:
1151 fr_strerror_printf("Unexpected cbor type 'integer' when decoding data type %s",
1153 return -1;
1154 }
1155 break;
1156
1157 case CBOR_NEGATIVE:
1158 slen = cbor_decode_integer(&value, info, &work_dbuff);
1159 if (slen < 0) return_slen;
1160
1161 /*
1162 * Signed numbers only go down to -2^63
1163 * so value must be less than 2^63
1164 */
1165 if (value >= ((uint64_t) 1) << 63) goto invalid;
1166
1167 /*
1168 * Convert 0..(2^63-1) into -0..-(2^63-1)
1169 * then conver to -1..-(2^63)
1170 */
1171 neg = -value;
1172 neg--;
1173
1174 switch (type) {
1175 case FR_TYPE_INT8:
1176 if (neg < INT8_MIN) goto invalid;
1177 vb->vb_int8 = neg;
1178 break;
1179
1180 case FR_TYPE_INT16:
1181 if (neg < INT16_MIN) goto invalid;
1182 vb->vb_int16 = neg;
1183 break;
1184
1185 case FR_TYPE_INT32:
1186 if (neg < INT32_MIN) goto invalid;
1187 vb->vb_int32 = neg;
1188 break;
1189
1190 case FR_TYPE_INT64:
1191 vb->vb_int64 = neg;
1192 break;
1193
1194 default:
1195 goto integer_type_mismatch;
1196 }
1197 break;
1198
1199 case CBOR_FLOAT:
1200 /*
1201 * Simple values. See RFC 8489 Section 3.3.
1202 *
1203 * 20 - false
1204 * 21 - true
1205 * 22 - NULL
1206 */
1207 if (info < 24) {
1208 switch (type) {
1209 case FR_TYPE_BOOL:
1210 if (info == 20) {
1211 vb->vb_bool = false;
1212 break;
1213 }
1214
1215 if (info == 21) {
1216 vb->vb_bool = true;
1217 break;
1218 }
1219
1220 invalid_bool:
1221 fr_strerror_printf("Invalid cbor - boolean is not encoded as 'true' or 'false'");
1222 return -fr_dbuff_used(&work_dbuff);
1223
1224 case FR_TYPE_OCTETS:
1225 case FR_TYPE_STRING:
1226 case FR_TYPE_TLV:
1227 case FR_TYPE_VENDOR:
1228 case FR_TYPE_GROUP:
1229 case FR_TYPE_STRUCT:
1230 /*
1231 * Be a little forgiving. 22 is NULL, so we treat that as "nothing".
1232 *
1233 * i.e. empty string, empty set, etc.
1234 */
1235 if (info == 22) break;
1236
1238
1239 default:
1240 fr_strerror_printf("Invalid cbor - unexpected 'simple value' %u", info);
1241 return -fr_dbuff_used(&work_dbuff);
1242 }
1243 break;
1244 }
1245
1246 /*
1247 * Or as one-byte integers.
1248 */
1249 if (info == CBOR_1_BYTE) {
1250 uint8_t data;
1251
1252 FR_DBUFF_OUT_RETURN(&data, &work_dbuff);
1253
1254 switch (type) {
1255 case FR_TYPE_FLOAT32:
1256 vb->vb_float32 = data;
1257 break;
1258
1259 case FR_TYPE_FLOAT64:
1260 vb->vb_float64 = data;
1261 break;
1262
1263 default:
1264 float_type_mismatch:
1265 fr_strerror_printf("Unexpected cbor type 'float' when decoding data type %s",
1267 return -1;
1268 }
1269
1270 break;
1271 }
1272
1273 /*
1274 * We don't support float16
1275 */
1276
1277 if (info == CBOR_4_BYTE) {
1278 float data;
1279
1280 FR_DBUFF_OUT_RETURN(&data, &work_dbuff);
1281
1282 switch (type) {
1283 case FR_TYPE_FLOAT32:
1284 vb->vb_float32 = data;
1285 break;
1286
1287 case FR_TYPE_FLOAT64:
1288 vb->vb_float64 = (double) data;
1289 break;
1290
1291 default:
1292 goto float_type_mismatch;
1293 }
1294
1295 break;
1296 }
1297
1298 if (info == CBOR_8_BYTE) {
1299 double data;
1300
1301 FR_DBUFF_OUT_RETURN(&data, &work_dbuff);
1302
1303 switch (type) {
1304 case FR_TYPE_FLOAT32:
1305 vb->vb_float32 = data; /* maybe loses precision? */
1306 break;
1307
1308 case FR_TYPE_FLOAT64:
1309 vb->vb_float64 = data;
1310 break;
1311
1312 default:
1313 goto float_type_mismatch;
1314 }
1315
1316 break;
1317 }
1318
1319 /*
1320 * 24 is FLOAT16, which we don't support.
1321 * 31 is BREAK, which the caller should have checked for.
1322 */
1323 goto float_type_mismatch;
1324
1325 case CBOR_TAG:
1326 /*
1327 * We only support a limited number of tags.
1328 */
1329 slen = cbor_decode_integer(&value, info, &work_dbuff);
1330 if (slen < 0) return_slen;
1331
1333
1334 /*
1335 * No tag defined for this data type, that's on us.
1336 */
1337 if (!cbor_type_to_tag[type]) {
1338 fr_strerror_printf("Unknown cbor tag %" PRIu64 " for expected data type %s",
1340 return -fr_dbuff_used(&work_dbuff);
1341 }
1342
1343 /*
1344 * Wrong tag for this data type, that's on them.
1345 */
1346 if (cbor_type_to_tag[type] != value) {
1347 fr_strerror_printf("Invalid cbor tag %" PRIu64 " for expected data type %s",
1349 return -fr_dbuff_used(&work_dbuff);
1350 }
1351
1352 fr_value_box_init(vb, type, enumv, tainted);
1353
1354 slen = cbor_decode_type[type](ctx, vb, &work_dbuff);
1355 if (slen < 0) return_slen;
1356 break;
1357
1358 case CBOR_ARRAY:
1359 if (type != FR_TYPE_GROUP) goto invalid_type;
1360
1361 /*
1362 * Loop until done.
1363 */
1364 if (info == 31) {
1365 value = ~0;
1366 indefinite = true;
1367
1368 } else {
1369 slen = cbor_decode_integer(&value, info, &work_dbuff);
1370 if (slen < 0) return_slen;
1371
1372 indefinite = false;
1373 }
1374
1375#ifdef STATIC_ANALYZER
1376 if (value > fr_dbuff_remaining(&work_dbuff)) return -1;
1377#endif
1378
1379 /*
1380 * Loop until we decode everything. For simplicity, we handle indefinite and definite
1381 * length arrays in the same loop.
1382 */
1383 for (/* nothing */; value > 0; value--) {
1384 uint8_t header;
1385 fr_value_box_t *child;
1386
1387 /*
1388 * Require at least one byte in the buffer.
1389 */
1390 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 1);
1391
1392 /*
1393 * Peek ahead for a break.
1394 */
1395 header = *fr_dbuff_current(&work_dbuff);
1396 if (header == 0xff) {
1397 if (!indefinite) {
1398 fr_strerror_const("Unexpected 'break' found in cbor data");
1399 return -fr_dbuff_used(&work_dbuff);
1400 }
1401
1402 /*
1403 * Done!
1404 */
1405 fr_dbuff_advance(&work_dbuff, 1);
1406 break;
1407 }
1408
1409 child = fr_value_box_alloc(ctx, FR_TYPE_NULL, NULL);
1410 if (!child) {
1411 fr_strerror_const("Out of memory");
1412 return -fr_dbuff_used(&work_dbuff);
1413 }
1414
1415 /*
1416 * We have to decode at least one value.
1417 */
1418 slen = fr_cbor_decode_value_box(child, child, &work_dbuff, FR_TYPE_NULL, NULL, tainted);
1419 if (slen <= 0) return_slen;
1420
1421 fr_value_box_list_insert_tail(&vb->vb_group, child);
1422 }
1423 break;
1424
1425 /*
1426 * These are not value-box types.
1427 */
1428 case CBOR_MAP:
1430 fr_strerror_printf("Invalid data type %s for cbor to value-box", fr_type_to_str(type));
1431 return -1;
1432 }
1433
1434 return fr_dbuff_set(dbuff, &work_dbuff);
1435}
1436
1437/** Encode a pair
1438 *
1439 */
1441{
1442 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
1443 ssize_t slen;
1444 fr_dict_attr_t const *parent;
1445 size_t count;
1446
1447 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_MAP << 5) | 1)); /* map of 1 item */
1448
1449 /*
1450 * Key is the attribute number.
1451 */
1452 slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, vp->da->attr);
1453 if (slen <= 0) return_slen;
1454
1455 /*
1456 * Value is the actual value of the leaf, or the array of children.
1457 */
1458 switch (vp->vp_type) {
1459 case FR_TYPE_LEAF:
1460 slen = fr_cbor_encode_value_box(&work_dbuff, &vp->data);
1461 if (slen <= 0) return_slen;
1462 break;
1463
1464 /*
1465 * Groups reparent to the ref.
1466 */
1467 case FR_TYPE_GROUP:
1469 fr_assert(parent != NULL);
1470 goto encode_children;
1471
1472 /*
1473 * The only difference between TLV and VSA is that the children of VSA are all VENDORs.
1474 */
1475 case FR_TYPE_VENDOR:
1476 case FR_TYPE_VSA:
1477 case FR_TYPE_TLV:
1478 parent = vp->da;
1479
1480 /*
1481 * The value is array(children)
1482 */
1483encode_children:
1484 if (fr_pair_list_num_elements(&vp->vp_group) == 0) {
1485 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_FLOAT << 5) | 22)); /* NULL */
1486 break;
1487 }
1488
1489 /*
1490 * The groups, etc. may contain internal attributes. We don't yet deal with those.
1491 */
1492 count = 0;
1493 fr_pair_list_foreach(&vp->vp_group, child) {
1494 if (child->da->parent != parent) continue;
1495 count++;
1496 }
1497
1498 slen = cbor_encode_integer(&work_dbuff, CBOR_ARRAY, count);
1499 if (slen <= 0) return_slen;
1500
1501 fr_pair_list_foreach(&vp->vp_group, child) {
1502 /*
1503 * We don't allow changing dictionaries here.
1504 */
1505 if (child->da->parent != parent) continue;
1506
1507 slen = fr_cbor_encode_pair(&work_dbuff, child);
1508 if (slen <= 0) return_slen;
1509 }
1510 break;
1511
1512 /*
1513 * @todo - struct, except if we hit the end of the struct, check if the next child is the child
1514 * of the key? That makes it all more annoying :(
1515 */
1516
1517 default:
1518 fr_strerror_printf("Invalid data type %s for cbor encoding", fr_type_to_str(vp->vp_type));
1519 return -1;
1520 }
1521
1522 return fr_dbuff_set(dbuff, &work_dbuff);
1523}
1524
1525/** Guess the data type of the CBOR data.
1526 *
1527 * We've parsed the attribute number, and found that we don't have a dictionary entry for it. But rather
1528 * than create an attribute of type octets, we try to guess the data type.
1529 */
1530static fr_type_t cbor_guess_type(fr_dbuff_t *dbuff, bool pair)
1531{
1532 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
1533 ssize_t slen;
1534 uint8_t major, info;
1535 uint64_t value;
1536
1537 /*
1538 * get the next byte, which is a CBOR header.
1539 */
1540 slen = fr_dbuff_out(&major, &work_dbuff);
1541 if (slen <= 0) {
1542 no_data:
1543 fr_strerror_const("Invalid cbor - insufficient data");
1544 return FR_TYPE_NULL;
1545 }
1546
1547 info = major & 0x1f;
1548 major >>= 5;
1549
1550 switch (major) {
1551 case CBOR_INTEGER:
1552 return FR_TYPE_UINT64;
1553
1554 case CBOR_NEGATIVE:
1555 return FR_TYPE_UINT64;
1556
1557 case CBOR_STRING:
1558 return FR_TYPE_STRING;
1559
1560 case CBOR_OCTETS:
1561 return FR_TYPE_OCTETS;
1562
1563 case CBOR_ARRAY:
1564 if (!pair) return FR_TYPE_GROUP;
1565 break;
1566
1567 case CBOR_MAP:
1568 return FR_TYPE_TLV;
1569
1570 /*
1571 * Look at the tag to determine what it is
1572 */
1573 case CBOR_TAG:
1574 slen = cbor_decode_integer(&value, info, &work_dbuff);
1575 if (slen < 0) break;
1576
1577 switch (value) {
1578 case 1:
1579 case 1001:
1580 return FR_TYPE_DATE;
1581
1582 case 1002:
1583 return FR_TYPE_TIME_DELTA;
1584
1585 case 48:
1586 return FR_TYPE_ETHERNET;
1587
1588 case 52:
1589 slen = fr_dbuff_out(&major, &work_dbuff);
1590 if (slen <= 0) goto no_data;
1591
1592 major >>= 5;
1593
1594 if (major == CBOR_ARRAY) {
1595 return FR_TYPE_IPV4_PREFIX;
1596 }
1597 return FR_TYPE_IPV4_ADDR;
1598
1599 case 54:
1600 slen = fr_dbuff_out(&major, &work_dbuff);
1601 if (slen <= 0) goto no_data;
1602
1603 major >>= 5;
1604
1605 if (major == CBOR_ARRAY) {
1606 return FR_TYPE_IPV6_PREFIX;
1607 }
1608 return FR_TYPE_IPV6_ADDR;
1609
1610 default:
1611 break;
1612 }
1613
1614 break;
1615
1616 case CBOR_FLOAT:
1617 /*
1618 * In-place values are special. false / true / NULL
1619 */
1620 if (info < 24) {
1621 if ((info == 20) || (info == 21)) return FR_TYPE_BOOL;
1622
1623 return FR_TYPE_NULL;
1624 }
1625
1626 return FR_TYPE_FLOAT64;
1627 }
1628
1629
1630 /*
1631 * No idea. :(
1632 *
1633 * @todo - also check the cbor data, and return the length of cbor data which needs to be
1634 * converted to data type 'octets'. This work involves mostly parsing the cbor data, which isn't
1635 * trivial.
1636 */
1637 fr_strerror_const("Invalid cbor - unable to determine data type");
1638 return FR_TYPE_NULL;
1639}
1640
1642 fr_dict_attr_t const *parent, bool tainted)
1643{
1644 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
1645 uint8_t header, major, info;
1646 bool indefinite;
1647 ssize_t slen;
1648 fr_pair_t *vp;
1649 uint64_t value = 0;
1650 fr_dict_attr_t const *da;
1651
1652 FR_DBUFF_OUT_RETURN(&header, &work_dbuff);
1653
1654 /*
1655 * We require a 2-element array(attribute number, value)
1656 */
1657 if (header != (((CBOR_MAP) << 5) | 1)) {
1658 fr_strerror_printf("Invalid cbor header - expected map of 1 elements, got %02x", header);
1659 return -1;
1660 }
1661
1662 /*
1663 * This should be a CBOR_INTEGER.
1664 */
1665 FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
1666
1667 info = major & 0x1f;
1668 major >>= 5;
1669
1670 if (major != CBOR_INTEGER) {
1671 fr_strerror_printf("Invalid cbor - expected 'integer', got major type %d",
1672 major);
1673 return -1;
1674 }
1675
1676 slen = cbor_decode_integer(&value, info, &work_dbuff);
1677 if (slen < 0) {
1679 }
1680
1682 if (!da) {
1684
1685 type = cbor_guess_type(&work_dbuff, true);
1686 if (type == FR_TYPE_NULL) return -fr_dbuff_used(&work_dbuff);
1687
1688 /*
1689 * @todo - the value here isn't a cbor octets type, but is instead cbor data. Since cbor
1690 * is typed, we _could_ perhaps instead discover the type from the cbor data, and then
1691 * use that instead. This would involve creating a function which maps cbor types to our
1692 * data types.
1693 */
1695 if (!da) goto oom;
1696 }
1697
1698 vp = fr_pair_afrom_da(ctx, da);
1699 if (!vp) {
1700 oom:
1701 fr_strerror_const("Out of memory");
1702 return -fr_dbuff_used(&work_dbuff);
1703 }
1704
1705 /*
1706 * Leaf values are easy.
1707 */
1708 if (fr_type_is_leaf(da->type)) {
1709 slen = fr_cbor_decode_value_box(vp, &vp->data, &work_dbuff, da->type, da, tainted);
1710 if (slen <= 0) {
1711 talloc_free(vp);
1713 }
1714
1715 goto done;
1716 }
1717
1719
1720 switch (da->type) {
1721 /*
1722 * All of these are essentially the same.
1723 */
1724 case FR_TYPE_VENDOR:
1725 case FR_TYPE_VSA:
1726 case FR_TYPE_TLV:
1727 parent = vp->da;
1728 break;
1729
1730 /*
1731 * Groups reparent to the ref.
1732 */
1733 case FR_TYPE_GROUP:
1735 fr_assert(parent != NULL);
1736 break;
1737
1738 default:
1739 fr_strerror_printf("Invalid data type %s for child %s of %s",
1740 fr_type_to_str(da->type), vp->da->name, parent->name);
1741 talloc_free(vp);
1742 return -1;
1743 }
1744
1745 /*
1746 * This should be a CBOR_ARRAY.
1747 */
1748 FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
1749
1750 info = major & 0x1f;
1751 major >>= 5;
1752
1753 if (major != CBOR_ARRAY) {
1754 /*
1755 * Allow NULL as a synonym for "no children".
1756 */
1757 if ((major == CBOR_FLOAT) && (info == 22)) goto done;
1758
1759 talloc_free(vp);
1760 fr_strerror_printf("Invalid cbor - expected 'array', got major type %d",
1761 major);
1762 return -1;
1763 }
1764
1765 if (info == 31) {
1766 value = ~0;
1767 indefinite = true;
1768
1769 } else {
1770 slen = cbor_decode_integer(&value, info, &work_dbuff);
1771 if (slen < 0) {
1772 talloc_free(vp);
1774 }
1775
1776 indefinite = false;
1777 }
1778
1779#ifdef STATIC_ANALYZER
1780 if (value > fr_dbuff_remaining(&work_dbuff)) return -1;
1781#endif
1782
1783 /*
1784 * Loop until we decode everything. For simplicity, we handle indefinite and definite
1785 * length arrays in the same loop.
1786 */
1787 for (/* nothing */; value > 0; value--) {
1788 /*
1789 * Require at least one byte in the buffer.
1790 */
1791 if (fr_dbuff_extend_lowat(NULL, &work_dbuff, 1) == 0) {
1792 talloc_free(vp);
1793 return -fr_dbuff_used(&work_dbuff);
1794 }
1795
1796 /*
1797 * Peek ahead for a break.
1798 */
1799 header = *fr_dbuff_current(&work_dbuff);
1800 if (header == 0xff) {
1801 if (!indefinite) {
1802 talloc_free(vp);
1803 fr_strerror_const("Unexpected 'break' found in cbor data");
1804 return -fr_dbuff_used(&work_dbuff);
1805 }
1806
1807 /*
1808 * Done!
1809 */
1810 fr_dbuff_advance(&work_dbuff, 1);
1811 break;
1812 }
1813
1814 slen = fr_cbor_decode_pair(vp, &vp->vp_group, &work_dbuff, parent, tainted);
1815 if (slen <= 0) {
1816 talloc_free(vp);
1818 }
1819 }
1820
1821done:
1822 PAIR_VERIFY(vp);
1823
1825 return fr_dbuff_set(dbuff, &work_dbuff);
1826}
1827
1828/*
1829 * @todo - cbor_print
1830 * [] for array
1831 * [_...] for indefinite array
1832 * {a:b} for map
1833 * digits for integer
1834 * 'string' for string
1835 * h'HHHH' for octets
1836 *
1837 * https://datatracker.ietf.org/doc/html/draft-ietf-cbor-edn-literals
1838 */
static int const char char buffer[256]
Definition acutest.h:576
#define RCSID(id)
Definition build.h:485
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:324
#define UNUSED
Definition build.h:317
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:1440
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:973
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:1530
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:990
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:1641
#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:571
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:3331
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:1351
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:287
#define fr_assert(_expr)
Definition rad_assert.h:38
static bool done
Definition radclient.c:81
return count
Definition module.c:155
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:845
#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_structural(_x)
Definition types.h:388
#define fr_type_is_leaf(_x)
Definition types.h:389
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:450
#define FR_TYPE_LEAF
Definition types.h:313
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:4700
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:4267
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:640
static fr_slen_t data
Definition value.h:1288
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
Definition value.h:606
#define fr_value_box_list_foreach(_list_head, _iter)
Definition value.h:222
static size_t char ** out
Definition value.h:1020