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: 550f2942686b2f1e89ab100a8d8d89443b30da3f $")
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 FR_DBUFF_ERROR_OFFSET(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_uint32;
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_int32;
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_ipv4addr, 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_ipv6addr, 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) 128);
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_ipv4addr;
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_ipv6addr;
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 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, (uint8_t const *) &vb->vb_float32, sizeof(vb->vb_float32));
442 break;
443
444 case FR_TYPE_FLOAT64:
445 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_FLOAT << 5) | CBOR_8_BYTE));
446 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, (uint8_t const *) &vb->vb_float64, sizeof(vb->vb_float64));
447 break;
448
449 case FR_TYPE_GROUP:
450 /*
451 * Zero-length array.
452 */
453 if (fr_value_box_list_num_elements(&vb->vb_group) == 0) {
454 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_ARRAY << 5) | 0));
455 break;
456 }
457
458 /*
459 * The value is array(children)
460 */
461 slen = cbor_encode_integer(&work_dbuff, CBOR_ARRAY,
462 fr_value_box_list_num_elements(&vb->vb_group));
463 if (slen <= 0) return_slen;
464
465
466 fr_value_box_list_foreach(&vb->vb_group, child) {
467 slen = fr_cbor_encode_value_box(&work_dbuff, child);
468 if (slen <= 0) return_slen;
469 }
470 break;
471
472
473 default:
474 fr_strerror_printf("Invalid data type %s for cbor encoding", fr_type_to_str(vb->type));
475 return -1;
476 }
477
478 return fr_dbuff_set(dbuff, &work_dbuff);
479}
480
481
482static ssize_t cbor_decode_integer(uint64_t *out, uint8_t info, fr_dbuff_t *dbuff)
483{
484 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
485
486 if (info < 24) {
487 *out = info;
488 return 0;
489 }
490
491 if (info == CBOR_1_BYTE) {
493
494 FR_DBUFF_OUT_RETURN(&value, &work_dbuff);
495 *out = value;
496 goto done;
497 }
498
499 if (info == CBOR_2_BYTE) {
501
502 FR_DBUFF_OUT_RETURN(&value, &work_dbuff);
503 *out = value;
504 goto done;
505 }
506
507 if (info == CBOR_4_BYTE) {
509
510 FR_DBUFF_OUT_RETURN(&value, &work_dbuff);
511 *out = value;
512 goto done;
513 }
514
515 if (info == CBOR_8_BYTE) {
516 uint64_t value;
517
518 FR_DBUFF_OUT_RETURN(&value, &work_dbuff);
519 *out = value;
520 goto done;
521 }
522
523 /*
524 * 28 and greater are invalid according to the RFCs.
525 */
526 if (info > CBOR_8_BYTE) return -1;
527
528done:
529 return fr_dbuff_set(dbuff, &work_dbuff);
530}
531
532static ssize_t cbor_decode_count(uint64_t *out, int expected, fr_dbuff_t *dbuff)
533{
534 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
535 uint8_t major, info;
536 ssize_t slen;
537
538 FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
539
540 info = major & 0x1f;
541 major >>= 5;
542
543 if (major != expected) {
544 fr_strerror_printf("Expected cbor type '%s', got unexpected type %d ",
545 cbor_type_to_str[expected], major);
546 return -1;
547 }
548
549 slen = cbor_decode_integer(out, info, &work_dbuff);
550 if (slen < 0) return_slen;
551
552 return fr_dbuff_set(dbuff, &work_dbuff);
553}
554
555typedef ssize_t (*cbor_decode_type_t)(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff);
556
557static ssize_t cbor_decode_octets_memcpy(uint8_t *dst, size_t dst_min, size_t dst_max, fr_dbuff_t *dbuff)
558{
559 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
560 ssize_t slen;
561 uint64_t value = 0;
562
563 slen = cbor_decode_count(&value, CBOR_OCTETS, &work_dbuff);
564 if (slen < 0) return_slen;
565
566 if (value < dst_min) {
567 fr_strerror_printf("Invalid length for data - expected at least %zu got %" PRIu64, dst_min, value);
568 return -1;
569 }
570
571 if (value > dst_max) {
572 fr_strerror_printf("Invalid length for data - expected no more than %zu got %" PRIu64, dst_max, value);
573 return -1;
574 }
575
576 FR_DBUFF_OUT_MEMCPY_RETURN(dst, &work_dbuff, value);
577
578 return fr_dbuff_set(dbuff, &work_dbuff);
579}
580
581#if 0
582static ssize_t *cbor_decode_octets_memdup(TALLOC_CTX *ctx, uint8_t **out, fr_dbuff_t *dbuff)
583{
584 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
585 ssize_t slen;
586 uint64_t value;
587 uint8_t *ptr;
588
589 slen = cbor_decode_count(&value, CBOR_OCTETS, &work_dbuff);
590 if (slen < 0) return_slen;
591
592 if (value > (1 << 20)) {
593 fr_strerror_printf("cbor data string is too long (%" PRIu64 ")", value);
594 return -1;
595 }
596
597 ptr = talloc_array(ctx, uint8_t, value);
598 if (!ptr) {
599 fr_strerror_const("Out of memory");
600 return -1;
601 }
602
603 FR_DBUFF_OUT_MEMCPY_RETURN(ptr, &work_dbuff, value);
604 *out = ptr;
605
606 return fr_dbuff_set(dbuff, &work_dbuff);
607}
608#endif
609
610static ssize_t cbor_decode_ethernet(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
611{
612 return cbor_decode_octets_memcpy(vb->vb_ether, sizeof(vb->vb_ether), sizeof(vb->vb_ether), dbuff);
613}
614
616{
617 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
618 ssize_t slen;
619 uint8_t header;
620 size_t count = 0;
621 uint64_t value = 0;
622
623 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 1);
624
625 header = *fr_dbuff_current(&work_dbuff);
626 if ((header >> 5) == CBOR_ARRAY) {
627 count = header & 0x1f;
628
629 if ((count != 2) && (count != 3)) {
630 fr_strerror_printf("Invalid IPv4 interface - expected array of 2-3 elements, got %02x",
631 header);
632 return -1;
633 }
634
635 fr_dbuff_advance(&work_dbuff, 1);
636 }
637
638 vb->vb_ip.prefix = 32;
639
640 /*
641 * Get the IP address.
642 */
643 slen = cbor_decode_octets_memcpy((uint8_t *) &vb->vb_ipv4addr,
644 sizeof(vb->vb_ipv4addr),
645 sizeof(vb->vb_ipv4addr), &work_dbuff);
646 if (slen <= 0) return_slen;
647
648 if (!count) return fr_dbuff_set(dbuff, &work_dbuff);
649
650 slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
651 if (slen <= 0) return_slen;
652
653 if (value != 32) {
654 fr_strerror_printf("Invalid IPv4 address - expected prefix = 32 got %" PRIu64, value);
655 return -fr_dbuff_used(&work_dbuff);
656 }
657
658 if (count == 2) return fr_dbuff_set(dbuff, &work_dbuff);
659
660 /*
661 * Get the scope ID
662 */
663 slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
664 if (slen <= 0) return_slen;
665
666 vb->vb_ip.scope_id = value;
667
668 return fr_dbuff_set(dbuff, &work_dbuff);
669}
670
672{
673 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
674 ssize_t slen;
675 uint8_t header;
676 size_t count = 0;
677 uint64_t value = 0;
678
679 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 1);
680
681 header = *fr_dbuff_current(&work_dbuff);
682 if ((header >> 5) == CBOR_ARRAY) {
683 count = header & 0x1f;
684
685 if ((count != 2) && (count != 3)) {
686 fr_strerror_printf("Invalid IPv4 interface - expected array of 2-3 elements, got %02x",
687 header);
688 return -1;
689 }
690
691 fr_dbuff_advance(&work_dbuff, 1);
692 }
693
694 vb->vb_ip.prefix = 128;
695
696 /*
697 * Get the IP address.
698 */
699 slen = cbor_decode_octets_memcpy((uint8_t *) &vb->vb_ipv6addr,
700 sizeof(vb->vb_ipv6addr),
701 sizeof(vb->vb_ipv6addr), &work_dbuff);
702
703 if (slen <= 0) return_slen;
704
705 if (!count) return fr_dbuff_set(dbuff, &work_dbuff);
706
707 slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
708 if (slen <= 0) return_slen;
709
710 if (value != 128) {
711 fr_strerror_printf("Invalid IPv6 address - expected prefix = 128 got %" PRIu64, value);
712 return -fr_dbuff_used(&work_dbuff);
713 }
714
715 vb->vb_ip.prefix = value;
716
717 if (count == 2) return fr_dbuff_set(dbuff, &work_dbuff);
718
719 /*
720 * Get the scope ID
721 */
722 slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
723 if (slen <= 0) return_slen;
724
725 vb->vb_ip.scope_id = value;
726
727 return fr_dbuff_set(dbuff, &work_dbuff);
728}
729
731{
732 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
733 ssize_t slen;
734 uint8_t header;
735 uint64_t value = 0;
736 uint8_t buffer[sizeof(vb->vb_ipv4addr)];
737
738 FR_DBUFF_OUT_RETURN(&header, &work_dbuff);
739
740 if (header != ((CBOR_ARRAY << 5) | 2)) {
741 fr_strerror_printf("Invalid IPv4 prefix - expected array of 2 elements, got %02x",
742 header);
743 return -1;
744 }
745
746 slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
747 if (slen <= 0) return_slen;
748
749 if (value > 32) {
750 fr_strerror_printf("Invalid IPv4 prefix - expected prefix < 32, got %" PRIu64, value);
751 return -1;
752 }
753
754 /*
755 * RFC 9164 Section 4.3 - Trailing bytes of zero are omitted, so we
756 * first copy the data to a fixed-sized buffer which was
757 * zeroed out, and then (@todo) also check that unused bits in
758 * the last byte are all zero.
759 */
760 memset(buffer, 0, sizeof(buffer));
761
762 slen = cbor_decode_octets_memcpy(buffer, 0, sizeof(buffer), &work_dbuff);
763 if (slen <= 0) return_slen;
764
765 memcpy((uint8_t *) &vb->vb_ipv4addr, buffer, sizeof(vb->vb_ipv4addr));
766 vb->vb_ip.prefix = value;
767
768 return fr_dbuff_set(dbuff, &work_dbuff);
769}
770
772{
773 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
774 ssize_t slen;
775 uint8_t header;
776 uint64_t value = 0;
777 uint8_t buffer[sizeof(vb->vb_ipv6addr)];
778
779 FR_DBUFF_OUT_RETURN(&header, &work_dbuff);
780
781 if (header != ((CBOR_ARRAY << 5) | 2)) {
782 fr_strerror_printf("Invalid IPv6 prefix - expected array of 2 elements, got %02x",
783 header);
784 return -1;
785 }
786
787 slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
788 if (slen <= 0) return_slen;
789
790 if (value > 128) {
791 fr_strerror_printf("Invalid IPv6 prefix - expected prefix < 128, got %" PRIu64, value);
792 return -1;
793 }
794
795 /*
796 * RFC 9164 Section 4.3 - Trailing bytes of zero are omitted, so we
797 * first copy the data to a fixed-sized buffer which was
798 * zeroed out, and then (@todo) also check that unused bits in
799 * the last byte are all zero.
800 */
801 memset(buffer, 0, sizeof(buffer));
802
803 slen = cbor_decode_octets_memcpy(buffer, 0, sizeof(buffer), &work_dbuff);
804 if (slen <= 0) return_slen;
805
806 memcpy((uint8_t *) &vb->vb_ipv6addr, buffer, sizeof(vb->vb_ipv6addr));
807 vb->vb_ip.prefix = value;
808
809 return fr_dbuff_set(dbuff, &work_dbuff);
810}
811
813{
814 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
815 ssize_t slen;
816 uint8_t major, info;
817 uint64_t value = 0;
818 int64_t neg;
819
820 FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
821
822 info = major & 0x1f;
823 major >>= 5;
824
825 switch (major) {
826 case CBOR_INTEGER:
827 slen = cbor_decode_integer(&value, info, &work_dbuff);
828 if (slen < 0) return_slen;
829
830 if (value >= ((uint64_t) 1) << 63) { /* equal! */
831 invalid:
832 fr_strerror_printf("cbor value is too large for output data type %s",
834 return -1;
835 }
836
837 *out = value;
838 break;
839
840 case CBOR_NEGATIVE:
841 slen = cbor_decode_integer(&value, info, &work_dbuff);
842 if (slen < 0) return_slen;
843
844 if (value >= ((uint64_t) 1) << 63) goto invalid; /* greater than! */
845
846 /*
847 * Convert 0..(2^63-1) into -0..-(2^63-1)
848 * then conver to -1..-(2^63)
849 */
850 neg = -value;
851 neg--;
852
853 *out = neg;
854 break;
855
856 default:
857 fr_strerror_printf("cbor data contains invalid content %d for expected data type %s",
858 major, fr_type_to_str(type));
859 return -1;
860 }
861
862 return fr_dbuff_set(dbuff, &work_dbuff);
863
864}
865
866static ssize_t cbor_decode_date(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
867{
868 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
869 ssize_t slen;
870 int64_t neg;
871
872 slen = cbor_decode_int64(&neg, &work_dbuff, FR_TYPE_DATE);
873 if (slen <= 0) return_slen;
874
875 vb->vb_date = fr_unix_time_from_sec(neg);
876
877 return fr_dbuff_set(dbuff, &work_dbuff);
878}
879
880/*
881 * Tag 1002, followed by map of at least 2 elements
882 * key 1: seconds
883 * key -9: nanoseconds
884 */
886{
887 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
888 uint64_t count;
889 ssize_t slen;
890 int64_t key, seconds, fraction, scale;
891
892 slen = cbor_decode_count(&count, CBOR_MAP, &work_dbuff);
893 if (slen < 0) return_slen;
894
895 if (!count || (count > 2)) {
896 fr_strerror_printf("Unexpected count %" PRIu64" for time_delta, expected map of 1-2 elements", count);
897 return -1;
898 }
899
900 key = seconds = fraction = 0;
901
902 /*
903 * Expect key 1:seconds
904 */
905 slen = cbor_decode_int64(&key, &work_dbuff, FR_TYPE_TIME_DELTA);
906 if (slen < 0) return_slen;
907
908 if (key != 1) {
909 fr_strerror_printf("Unexpected key %" PRIi64 " for time_delta, expected key 1", key);
910 return -1;
911 }
912
913 slen = cbor_decode_int64(&seconds, &work_dbuff, FR_TYPE_TIME_DELTA);
914 if (slen < 0) return_slen;
915
916 if (count > 1) {
917 slen = cbor_decode_int64(&key, &work_dbuff, FR_TYPE_TIME_DELTA);
918 if (slen < 0) return_slen;
919
920 switch (key) {
921 case -3:
922 scale = MSEC;
923 break;
924
925 case -6:
926 scale = USEC;
927 break;
928
929 case -9:
930 scale = NSEC;
931 break;
932
933 default:
934 fr_strerror_printf("Unsupported time_delta key %" PRIi64, key);
935 return -fr_dbuff_used(&work_dbuff); /* point to actual key? */
936
937 }
938
939 slen = cbor_decode_int64(&fraction, &work_dbuff, FR_TYPE_TIME_DELTA);
940 if (slen < 0) return_slen;
941
942 if ((fraction < 0) || (fraction > scale)) fraction = 0;
943 } else {
944 scale = NSEC;
945 fraction = 0;
946 }
947
948 if (seconds > (INT64_MAX / scale)) {
949 vb->vb_time_delta = fr_time_delta_max();
950
951 } else if (seconds < (INT64_MIN / scale)) {
952 vb->vb_time_delta = fr_time_delta_min();
953
954 } else {
955 seconds *= scale;
956
957 if (seconds < 0) {
958 seconds -= fraction;
959 } else {
960 seconds += fraction;
961 }
962
963 vb->vb_time_delta = fr_time_delta_wrap(seconds);
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) {
1003 fr_strerror_const("Unable to determine data type from cbor");
1004 return -1;
1005 }
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 -1;
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 -1;
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
1332 /*
1333 * No tag defined for this data type, that's on us.
1334 */
1335 if (!cbor_type_to_tag[type]) {
1336 fr_strerror_printf("Unknown cbor tag %" PRIu64 " for expected data type %s",
1338 return -fr_dbuff_used(&work_dbuff);
1339 }
1340
1341 /*
1342 * Wrong tag for this data type, that's on them.
1343 */
1344 if (cbor_type_to_tag[type] != value) {
1345 fr_strerror_printf("Invalid cbor tag %" PRIu64 " for expected data type %s",
1347 return -fr_dbuff_used(&work_dbuff);
1348 }
1349
1350 fr_value_box_init(vb, type, enumv, tainted);
1351
1352 slen = cbor_decode_type[type](ctx, vb, &work_dbuff);
1353 if (slen < 0) return_slen;
1354 break;
1355
1356 case CBOR_ARRAY:
1357 if (type != FR_TYPE_GROUP) goto invalid_type;
1358
1359 /*
1360 * Loop until done.
1361 */
1362 if (info == 31) {
1363 value = ~0;
1364 indefinite = true;
1365
1366 } else {
1367 slen = cbor_decode_integer(&value, info, &work_dbuff);
1368 if (slen < 0) return_slen;
1369
1370 indefinite = false;
1371 }
1372
1373#ifdef STATIC_ANALYZER
1374 if (value > fr_dbuff_remaining(&work_dbuff)) return -1;
1375#endif
1376
1377 /*
1378 * Loop until we decode everything. For simplicity, we handle indefinite and definite
1379 * length arrays in the same loop.
1380 */
1381 for (/* nothing */; value > 0; value--) {
1382 uint8_t header;
1383 fr_value_box_t *child;
1384
1385 /*
1386 * Require at least one byte in the buffer.
1387 */
1388 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 1);
1389
1390 /*
1391 * Peek ahead for a break.
1392 */
1393 header = *fr_dbuff_current(&work_dbuff);
1394 if (header == 0xff) {
1395 if (!indefinite) {
1396 fr_strerror_const("Unexpected 'break' found in cbor data");
1397 return -fr_dbuff_used(&work_dbuff);
1398 }
1399
1400 /*
1401 * Done!
1402 */
1403 fr_dbuff_advance(&work_dbuff, 1);
1404 break;
1405 }
1406
1407 child = fr_value_box_alloc(ctx, FR_TYPE_NULL, NULL);
1408 if (!child) {
1409 fr_strerror_const("Out of memory");
1410 return -fr_dbuff_used(&work_dbuff);
1411 }
1412
1413 /*
1414 * We have to decode at least one value.
1415 */
1416 slen = fr_cbor_decode_value_box(child, child, &work_dbuff, FR_TYPE_NULL, NULL, tainted);
1417 if (slen <= 0) {
1418 talloc_free(child);
1420 }
1421
1422 fr_value_box_list_insert_tail(&vb->vb_group, child);
1423 }
1424 break;
1425
1426 /*
1427 * These are not value-box types.
1428 */
1429 case CBOR_MAP:
1431 fr_strerror_printf("Invalid data type %s for cbor to value-box", fr_type_to_str(type));
1432 return -1;
1433 }
1434
1435 return fr_dbuff_set(dbuff, &work_dbuff);
1436}
1437
1438/** Encode a pair
1439 *
1440 */
1442{
1443 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
1444 ssize_t slen;
1445 fr_dict_attr_t const *parent;
1446 size_t count;
1447
1448 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_MAP << 5) | 1)); /* map of 1 item */
1449
1450 /*
1451 * Key is the attribute number.
1452 */
1453 slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, vp->da->attr);
1454 if (slen <= 0) return_slen;
1455
1456 /*
1457 * Value is the actual value of the leaf, or the array of children.
1458 */
1459 switch (vp->vp_type) {
1460 case FR_TYPE_LEAF:
1461 slen = fr_cbor_encode_value_box(&work_dbuff, &vp->data);
1462 if (slen <= 0) return_slen;
1463 break;
1464
1465 /*
1466 * Groups reparent to the ref.
1467 */
1468 case FR_TYPE_GROUP:
1470 fr_assert(parent != NULL);
1471 goto encode_children;
1472
1473 /*
1474 * The only difference between TLV and VSA is that the children of VSA are all VENDORs.
1475 */
1476 case FR_TYPE_VENDOR:
1477 case FR_TYPE_VSA:
1478 case FR_TYPE_TLV:
1479 parent = vp->da;
1480
1481 /*
1482 * The value is array(children)
1483 */
1484encode_children:
1485 if (fr_pair_list_num_elements(&vp->vp_group) == 0) {
1486 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_FLOAT << 5) | 22)); /* NULL */
1487 break;
1488 }
1489
1490 /*
1491 * The groups, etc. may contain internal attributes. We don't yet deal with those.
1492 */
1493 count = 0;
1494 fr_pair_list_foreach(&vp->vp_group, child) {
1495 if (child->da->parent != parent) continue;
1496 count++;
1497 }
1498
1499 slen = cbor_encode_integer(&work_dbuff, CBOR_ARRAY, count);
1500 if (slen <= 0) return_slen;
1501
1502 fr_pair_list_foreach(&vp->vp_group, child) {
1503 /*
1504 * We don't allow changing dictionaries here.
1505 */
1506 if (child->da->parent != parent) continue;
1507
1508 slen = fr_cbor_encode_pair(&work_dbuff, child);
1509 if (slen <= 0) return_slen;
1510 }
1511 break;
1512
1513 /*
1514 * @todo - struct, except if we hit the end of the struct, check if the next child is the child
1515 * of the key? That makes it all more annoying :(
1516 */
1517
1518 default:
1519 fr_strerror_printf("Invalid data type %s for cbor encoding", fr_type_to_str(vp->vp_type));
1520 return -1;
1521 }
1522
1523 return fr_dbuff_set(dbuff, &work_dbuff);
1524}
1525
1526/** Guess the data type of the CBOR data.
1527 *
1528 * We've parsed the attribute number, and found that we don't have a dictionary entry for it. But rather
1529 * than create an attribute of type octets, we try to guess the data type.
1530 */
1531static fr_type_t cbor_guess_type(fr_dbuff_t *dbuff, bool pair)
1532{
1533 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
1534 ssize_t slen;
1535 uint8_t major, info;
1536 uint64_t value;
1537
1538 /*
1539 * get the next byte, which is a CBOR header.
1540 */
1541 slen = fr_dbuff_out(&major, &work_dbuff);
1542 if (slen <= 0) {
1543 no_data:
1544 fr_strerror_const("Invalid cbor - insufficient data");
1545 return FR_TYPE_NULL;
1546 }
1547
1548 info = major & 0x1f;
1549 major >>= 5;
1550
1551 switch (major) {
1552 case CBOR_INTEGER:
1553 return FR_TYPE_UINT64;
1554
1555 case CBOR_NEGATIVE:
1556 return FR_TYPE_INT64;
1557
1558 case CBOR_STRING:
1559 return FR_TYPE_STRING;
1560
1561 case CBOR_OCTETS:
1562 return FR_TYPE_OCTETS;
1563
1564 case CBOR_ARRAY:
1565 if (!pair) return FR_TYPE_GROUP;
1566 break;
1567
1568 case CBOR_MAP:
1569 return FR_TYPE_TLV;
1570
1571 /*
1572 * Look at the tag to determine what it is
1573 */
1574 case CBOR_TAG:
1575 slen = cbor_decode_integer(&value, info, &work_dbuff);
1576 if (slen < 0) break;
1577
1578 switch (value) {
1579 case 1:
1580 case 1001:
1581 return FR_TYPE_DATE;
1582
1583 case 1002:
1584 return FR_TYPE_TIME_DELTA;
1585
1586 case 48:
1587 return FR_TYPE_ETHERNET;
1588
1589 case 52:
1590 slen = fr_dbuff_out(&major, &work_dbuff);
1591 if (slen <= 0) goto no_data;
1592
1593 major >>= 5;
1594
1595 if (major == CBOR_ARRAY) {
1596 return FR_TYPE_IPV4_PREFIX;
1597 }
1598 return FR_TYPE_IPV4_ADDR;
1599
1600 case 54:
1601 slen = fr_dbuff_out(&major, &work_dbuff);
1602 if (slen <= 0) goto no_data;
1603
1604 major >>= 5;
1605
1606 if (major == CBOR_ARRAY) {
1607 return FR_TYPE_IPV6_PREFIX;
1608 }
1609 return FR_TYPE_IPV6_ADDR;
1610
1611 default:
1612 break;
1613 }
1614
1615 break;
1616
1617 case CBOR_FLOAT:
1618 /*
1619 * In-place values are special. false / true / NULL
1620 */
1621 if (info < 24) {
1622 if ((info == 20) || (info == 21)) return FR_TYPE_BOOL;
1623
1624 return FR_TYPE_NULL;
1625 }
1626
1627 return FR_TYPE_FLOAT64;
1628 }
1629
1630
1631 /*
1632 * No idea. :(
1633 *
1634 * @todo - also check the cbor data, and return the length of cbor data which needs to be
1635 * converted to data type 'octets'. This work involves mostly parsing the cbor data, which isn't
1636 * trivial.
1637 */
1638 fr_strerror_const("Invalid cbor - unable to determine data type");
1639 return FR_TYPE_NULL;
1640}
1641
1642static ssize_t cbor_decode_pair(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dbuff_t *dbuff,
1643 fr_dict_attr_t const *parent, bool tainted, int depth)
1644{
1645 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
1646 uint8_t header, major, info;
1647 bool indefinite;
1648 ssize_t slen;
1649 fr_pair_t *vp;
1650 uint64_t value = 0;
1651 fr_dict_attr_t const *da;
1652
1653 FR_DBUFF_OUT_RETURN(&header, &work_dbuff);
1654
1655 /*
1656 * We require a 2-element array(attribute number, value)
1657 */
1658 if (header != (((CBOR_MAP) << 5) | 1)) {
1659 fr_strerror_printf("Invalid cbor header - expected map of 1 elements, got %02x", header);
1660 return -1;
1661 }
1662
1663 /*
1664 * This should be a CBOR_INTEGER.
1665 */
1666 FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
1667
1668 info = major & 0x1f;
1669 major >>= 5;
1670
1671 if (major != CBOR_INTEGER) {
1672 fr_strerror_printf("Invalid cbor - expected 'integer', got major type %d",
1673 major);
1674 return -1;
1675 }
1676
1677 slen = cbor_decode_integer(&value, info, &work_dbuff);
1678 if (slen < 0) {
1680 }
1681
1682 /*
1683 * If the nesting is too deep, decode as raw octets. We have to do this manually in CBOR,
1684 * because the other protocols create a da_stack which limits the depth.
1685 */
1686 if (depth >= FR_DICT_MAX_TLV_STACK) goto raw;
1687
1689 if (!da) {
1691
1692 type = cbor_guess_type(&work_dbuff, true);
1693 if (type == FR_TYPE_NULL) return -fr_dbuff_used(&work_dbuff);
1694
1696 raw:
1698 }
1699
1700 /*
1701 * @todo - the value here isn't a cbor octets type, but is instead cbor data. Since cbor
1702 * is typed, we _could_ perhaps instead discover the type from the cbor data, and then
1703 * use that instead. This would involve creating a function which maps cbor types to our
1704 * data types.
1705 */
1707 if (!da) return -fr_dbuff_used(&work_dbuff);
1708 }
1709
1710 vp = fr_pair_afrom_da(ctx, da);
1711 if (!vp) {
1712 fr_strerror_const("Out of memory");
1713 return -fr_dbuff_used(&work_dbuff);
1714 }
1715
1716 /*
1717 * Leaf values are easy.
1718 */
1719 if (fr_type_is_leaf(da->type)) {
1720 slen = fr_cbor_decode_value_box(vp, &vp->data, &work_dbuff, da->type, da, tainted);
1721 if (slen < 0) {
1722 talloc_free(vp);
1724 }
1725
1726 goto done;
1727 }
1728
1730
1731 switch (da->type) {
1732 /*
1733 * All of these are essentially the same.
1734 */
1735 case FR_TYPE_VENDOR:
1736 case FR_TYPE_VSA:
1737 case FR_TYPE_TLV:
1738 parent = vp->da;
1739 break;
1740
1741 /*
1742 * Groups reparent to the ref.
1743 */
1744 case FR_TYPE_GROUP:
1746 fr_assert(parent != NULL);
1747 break;
1748
1749 default:
1750 fr_strerror_printf("Invalid data type %s for child %s of %s",
1751 fr_type_to_str(da->type), vp->da->name, parent->name);
1752 talloc_free(vp);
1753 return -1;
1754 }
1755
1756 /*
1757 * This should be a CBOR_ARRAY.
1758 */
1759 FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
1760
1761 info = major & 0x1f;
1762 major >>= 5;
1763
1764 if (major != CBOR_ARRAY) {
1765 /*
1766 * Allow NULL as a synonym for "no children".
1767 */
1768 if ((major == CBOR_FLOAT) && (info == 22)) goto done;
1769
1770 talloc_free(vp);
1771 fr_strerror_printf("Invalid cbor - expected 'array', got major type %d",
1772 major);
1773 return -1;
1774 }
1775
1776 if (info == 31) {
1777 value = ~0;
1778 indefinite = true;
1779
1780 } else {
1781 slen = cbor_decode_integer(&value, info, &work_dbuff);
1782 if (slen < 0) {
1783 talloc_free(vp);
1785 }
1786
1787 indefinite = false;
1788 }
1789
1790#ifdef STATIC_ANALYZER
1791 if (value > fr_dbuff_remaining(&work_dbuff)) return -1;
1792#endif
1793
1794 /*
1795 * Loop until we decode everything. For simplicity, we handle indefinite and definite
1796 * length arrays in the same loop.
1797 */
1798 for (/* nothing */; value > 0; value--) {
1799 /*
1800 * Require at least one byte in the buffer.
1801 */
1802 if (fr_dbuff_extend_lowat(NULL, &work_dbuff, 1) == 0) {
1803 talloc_free(vp);
1804 return -fr_dbuff_used(&work_dbuff);
1805 }
1806
1807 /*
1808 * Peek ahead for a break.
1809 */
1810 header = *fr_dbuff_current(&work_dbuff);
1811 if (header == 0xff) {
1812 if (!indefinite) {
1813 talloc_free(vp);
1814 fr_strerror_const("Unexpected 'break' found in cbor data");
1815 return -fr_dbuff_used(&work_dbuff);
1816 }
1817
1818 /*
1819 * Done!
1820 */
1821 fr_dbuff_advance(&work_dbuff, 1);
1822 break;
1823 }
1824
1825 slen = cbor_decode_pair(vp, &vp->vp_group, &work_dbuff, parent, tainted, depth + 1);
1826 if (slen <= 0) {
1827 talloc_free(vp);
1829 }
1830 }
1831
1832done:
1833 PAIR_VERIFY(vp);
1834
1836 return fr_dbuff_set(dbuff, &work_dbuff);
1837}
1838
1840 fr_dict_attr_t const *parent, bool tainted)
1841{
1842 return cbor_decode_pair(ctx, out, dbuff, parent, tainted, 0);
1843}
1844
1845/*
1846 * @todo - cbor_print
1847 * [] for array
1848 * [_...] for indefinite array
1849 * {a:b} for map
1850 * digits for integer
1851 * 'string' for string
1852 * h'HHHH' for octets
1853 *
1854 * https://datatracker.ietf.org/doc/html/draft-ietf-cbor-edn-literals
1855 */
static int const char char buffer[256]
Definition acutest.h:578
#define RCSID(id)
Definition build.h:487
#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:615
static ssize_t cbor_decode_int64(int64_t *out, fr_dbuff_t *dbuff, fr_type_t type)
Definition cbor.c:812
#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:671
#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:557
#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:1441
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:866
#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:885
static ssize_t cbor_decode_ipv4_prefix(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
Definition cbor.c:730
#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:1531
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:482
static ssize_t cbor_decode_ethernet(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
Definition cbor.c:610
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:771
#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:1839
#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 ssize_t cbor_decode_pair(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dbuff_t *dbuff, fr_dict_attr_t const *parent, bool tainted, int depth)
Definition cbor.c:1642
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:555
static ssize_t cbor_decode_count(uint64_t *out, int expected, fr_dbuff_t *dbuff)
Definition cbor.c:532
#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:1083
#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:777
#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:683
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
Definition dbuff.h:921
#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:1014
#define fr_dbuff_extend_lowat(_status, _dbuff_or_marker, _lowat)
Extend if we're below _lowat.
Definition dbuff.h:670
#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:753
#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:1763
#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:1393
#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:1596
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:232
#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:1829
#define fr_dbuff_out(_out, _dbuff_or_marker)
Copy data from a dbuff or marker to a fixed sized C type.
Definition dbuff.h:1810
#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:1483
#define FR_DICT_MAX_TLV_STACK
Maximum TLV stack size.
Definition dict.h:519
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:598
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:3594
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:148
Test enumeration values.
Definition dict_test.h:92
talloc_free(hp)
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 uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
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:290
#define fr_assert(_expr)
Definition rad_assert.h:38
static bool done
Definition radclient.c:83
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:204
#define fr_pair_list_foreach(_list_head, _iter)
Iterate over the contents of a fr_pair_list_t.
Definition pair.h:279
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:858
#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:393
#define fr_type_is_leaf(_x)
Definition types.h:394
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:455
#define FR_TYPE_LEAF
Definition types.h:318
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:5178
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:4744
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:644
static fr_slen_t data
Definition value.h:1334
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
Definition value.h:610
#define fr_value_box_list_foreach(_list_head, _iter)
Definition value.h:224
static size_t char ** out
Definition value.h:1024