The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
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: 89c32c9eed0918d7eb9971075997f0a025f953b9 $")
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 slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
347 if (slen <= 0) return_slen;
348
349 if (vb->vb_ip.scope_id != 0) {
350 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_ARRAY << 5) | 3));
351 }
352
353 slen = cbor_encode_octets(&work_dbuff, (uint8_t const *) &vb->vb_ipv6addr, 16);
354 if (slen <= 0) return_slen;
355
356 if (vb->vb_ip.scope_id == 0) break;
357
358 slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, (uint8_t) 128);
359 if (slen <= 0) return_slen;
360
361 slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, vb->vb_ip.scope_id);
362 if (slen <= 0) return_slen;
363 break;
364
365 /*
366 * RFC 9164, Section 3.3
367 *
368 * tag=IPv4 + array(prefix-length, address)
369 */
371 slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
372 if (slen <= 0) return_slen;
373
374 slen = cbor_encode_array(&work_dbuff, 2);
375 if (slen <= 0) return_slen;
376
377 slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, vb->vb_ip.prefix);
378 if (slen <= 0) return_slen;
379
380 p = (uint8_t const *) &vb->vb_ipv4addr;
381 end = p + 3;
382
383 /*
384 * RFC 9164 Section 4.2 - Drop lower octets which are all zero.
385 *
386 * If this results in a zero-length string, so be it.
387 *
388 * Note also that "There is no relationship between the number of bytes omitted and the
389 * prefix length."
390 */
391 do {
392 if (*end != 0) break;
393
394 end--;
395 } while (end != p);
396
397 slen = cbor_encode_octets(&work_dbuff, p, (end - p) + (*end != 0));
398 if (slen <= 0) return_slen;
399 break;
400
401 /*
402 * RFC 9164, Section 3.2
403 *
404 * tag=IPv6 + array(prefix-length, address)
405 */
407 slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
408 if (slen <= 0) return_slen;
409
410 slen = cbor_encode_array(&work_dbuff, 2);
411 if (slen <= 0) return_slen;
412
413 slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, vb->vb_ip.prefix);
414 if (slen <= 0) return_slen;
415
416 p = (uint8_t const *) &vb->vb_ipv6addr;
417 end = p + 15;
418
419 /*
420 * RFC 9164 Section 4.2 - Drop lower octets which are all zero.
421 *
422 * If this results in a zero-length string, so be it.
423 *
424 * Note also that "There is no relationship between the number of bytes omitted and the
425 * prefix length."
426 */
427 do {
428 if (*end != 0) break;
429
430 end--;
431 } while (end != p);
432
433 slen = cbor_encode_octets(&work_dbuff, p, (end - p) + (*end != 0));
434 if (slen <= 0) return_slen;
435
436 break;
437
438 case FR_TYPE_FLOAT32:
439 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_FLOAT << 5) | CBOR_4_BYTE));
440 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, (uint8_t const *) &vb->vb_float32, sizeof(vb->vb_float32));
441 break;
442
443 case FR_TYPE_FLOAT64:
444 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_FLOAT << 5) | CBOR_8_BYTE));
445 FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, (uint8_t const *) &vb->vb_float64, sizeof(vb->vb_float64));
446 break;
447
448 case FR_TYPE_GROUP:
449 /*
450 * Zero-length array.
451 */
452 if (fr_value_box_list_num_elements(&vb->vb_group) == 0) {
453 FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_ARRAY << 5) | 0));
454 break;
455 }
456
457 /*
458 * The value is array(children)
459 */
460 slen = cbor_encode_integer(&work_dbuff, CBOR_ARRAY,
461 fr_value_box_list_num_elements(&vb->vb_group));
462 if (slen <= 0) return_slen;
463
464
465 fr_value_box_list_foreach(&vb->vb_group, child) {
466 slen = fr_cbor_encode_value_box(&work_dbuff, child);
467 if (slen <= 0) return_slen;
468 }
469 break;
470
471
472 default:
473 fr_strerror_printf("Invalid data type %s for cbor encoding", fr_type_to_str(vb->type));
474 return -1;
475 }
476
477 return fr_dbuff_set(dbuff, &work_dbuff);
478}
479
480
481static ssize_t cbor_decode_integer(uint64_t *out, uint8_t info, fr_dbuff_t *dbuff)
482{
483 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
484
485 if (info < 24) {
486 *out = info;
487 return 0;
488 }
489
490 if (info == CBOR_1_BYTE) {
492
493 FR_DBUFF_OUT_RETURN(&value, &work_dbuff);
494 *out = value;
495 goto done;
496 }
497
498 if (info == CBOR_2_BYTE) {
500
501 FR_DBUFF_OUT_RETURN(&value, &work_dbuff);
502 *out = value;
503 goto done;
504 }
505
506 if (info == CBOR_4_BYTE) {
508
509 FR_DBUFF_OUT_RETURN(&value, &work_dbuff);
510 *out = value;
511 goto done;
512 }
513
514 if (info == CBOR_8_BYTE) {
515 uint64_t value;
516
517 FR_DBUFF_OUT_RETURN(&value, &work_dbuff);
518 *out = value;
519 goto done;
520 }
521
522 /*
523 * 28 and greater are invalid according to the RFCs.
524 */
525 if (info > CBOR_8_BYTE) return -1;
526
527done:
528 return fr_dbuff_set(dbuff, &work_dbuff);
529}
530
531static ssize_t cbor_decode_count(uint64_t *out, int expected, fr_dbuff_t *dbuff)
532{
533 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
534 uint8_t major, info;
535 ssize_t slen;
536
537 FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
538
539 info = major & 0x1f;
540 major >>= 5;
541
542 if (major != expected) {
543 fr_strerror_printf("Expected cbor type '%s', got unexpected type %d ",
544 cbor_type_to_str[expected], major);
545 return -1;
546 }
547
548 slen = cbor_decode_integer(out, info, &work_dbuff);
549 if (slen < 0) return_slen;
550
551 return fr_dbuff_set(dbuff, &work_dbuff);
552}
553
554typedef ssize_t (*cbor_decode_type_t)(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff);
555
556static ssize_t cbor_decode_octets_memcpy(uint8_t *dst, size_t dst_min, size_t dst_max, fr_dbuff_t *dbuff)
557{
558 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
559 ssize_t slen;
560 uint64_t value = 0;
561
562 slen = cbor_decode_count(&value, CBOR_OCTETS, &work_dbuff);
563 if (slen < 0) return_slen;
564
565 if (value < dst_min) {
566 fr_strerror_printf("Invalid length for data - expected at least %zu got %" PRIu64, dst_min, value);
567 return -1;
568 }
569
570 if (value > dst_max) {
571 fr_strerror_printf("Invalid length for data - expected no more than %zu got %" PRIu64, dst_max, value);
572 return -1;
573 }
574
575 FR_DBUFF_OUT_MEMCPY_RETURN(dst, &work_dbuff, value);
576
577 return fr_dbuff_set(dbuff, &work_dbuff);
578}
579
580#if 0
581static ssize_t *cbor_decode_octets_memdup(TALLOC_CTX *ctx, uint8_t **out, fr_dbuff_t *dbuff)
582{
583 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
584 ssize_t slen;
585 uint64_t value;
586 uint8_t *ptr;
587
588 slen = cbor_decode_count(&value, CBOR_OCTETS, &work_dbuff);
589 if (slen < 0) return_slen;
590
591 if (value > (1 << 20)) {
592 fr_strerror_printf("cbor data string is too long (%" PRIu64 ")", value);
593 return -1;
594 }
595
596 ptr = talloc_array(ctx, uint8_t, value);
597 if (!ptr) {
598 fr_strerror_const("Out of memory");
599 return -1;
600 }
601
602 FR_DBUFF_OUT_MEMCPY_RETURN(ptr, &work_dbuff, value);
603 *out = ptr;
604
605 return fr_dbuff_set(dbuff, &work_dbuff);
606}
607#endif
608
609static ssize_t cbor_decode_ethernet(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
610{
611 return cbor_decode_octets_memcpy(vb->vb_ether, sizeof(vb->vb_ether), sizeof(vb->vb_ether), dbuff);
612}
613
615{
616 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
617 ssize_t slen;
618 uint8_t header;
619 size_t count = 0;
620 uint64_t value = 0;
621
622 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 1);
623
624 header = *fr_dbuff_current(&work_dbuff);
625 if ((header >> 5) == CBOR_ARRAY) {
626 count = header & 0x1f;
627
628 if ((count != 2) && (count != 3)) {
629 fr_strerror_printf("Invalid IPv4 interface - expected array of 2-3 elements, got %02x",
630 header);
631 return -1;
632 }
633
634 fr_dbuff_advance(&work_dbuff, 1);
635 }
636
637 vb->vb_ip.prefix = 32;
638
639 /*
640 * Get the IP address.
641 */
642 slen = cbor_decode_octets_memcpy((uint8_t *) &vb->vb_ipv4addr,
643 sizeof(vb->vb_ipv4addr),
644 sizeof(vb->vb_ipv4addr), &work_dbuff);
645 if (slen <= 0) return_slen;
646
647 if (!count) return fr_dbuff_set(dbuff, &work_dbuff);
648
649 slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
650 if (slen <= 0) return_slen;
651
652 if (value != 32) {
653 fr_strerror_printf("Invalid IPv4 address - expected prefix = 32 got %" PRIu64, value);
654 return -fr_dbuff_used(&work_dbuff);
655 }
656
657 if (count == 2) return fr_dbuff_set(dbuff, &work_dbuff);
658
659 /*
660 * Get the scope ID
661 */
662 slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
663 if (slen <= 0) return_slen;
664
665 vb->vb_ip.scope_id = value;
666
667 return fr_dbuff_set(dbuff, &work_dbuff);
668}
669
671{
672 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
673 ssize_t slen;
674 uint8_t header;
675 size_t count = 0;
676 uint64_t value = 0;
677
678 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 1);
679
680 header = *fr_dbuff_current(&work_dbuff);
681 if ((header >> 5) == CBOR_ARRAY) {
682 count = header & 0x1f;
683
684 if ((count != 2) && (count != 3)) {
685 fr_strerror_printf("Invalid IPv4 interface - expected array of 2-3 elements, got %02x",
686 header);
687 return -1;
688 }
689
690 fr_dbuff_advance(&work_dbuff, 1);
691 }
692
693 vb->vb_ip.prefix = 128;
694
695 /*
696 * Get the IP address.
697 */
698 slen = cbor_decode_octets_memcpy((uint8_t *) &vb->vb_ipv6addr,
699 sizeof(vb->vb_ipv6addr),
700 sizeof(vb->vb_ipv6addr), &work_dbuff);
701
702 if (slen <= 0) return_slen;
703
704 if (!count) return fr_dbuff_set(dbuff, &work_dbuff);
705
706 slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
707 if (slen <= 0) return_slen;
708
709 if (value != 128) {
710 fr_strerror_printf("Invalid IPv6 address - expected prefix = 128 got %" PRIu64, value);
711 return -fr_dbuff_used(&work_dbuff);
712 }
713
714 vb->vb_ip.prefix = value;
715
716 if (count == 2) return fr_dbuff_set(dbuff, &work_dbuff);
717
718 /*
719 * Get the scope ID
720 */
721 slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
722 if (slen <= 0) return_slen;
723
724 vb->vb_ip.scope_id = value;
725
726 return fr_dbuff_set(dbuff, &work_dbuff);
727}
728
730{
731 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
732 ssize_t slen;
733 uint8_t header;
734 uint64_t value = 0;
735 uint8_t buffer[sizeof(vb->vb_ipv4addr)];
736
737 FR_DBUFF_OUT_RETURN(&header, &work_dbuff);
738
739 if (header != ((CBOR_ARRAY << 5) | 2)) {
740 fr_strerror_printf("Invalid IPv4 prefix - expected array of 2 elements, got %02x",
741 header);
742 return -1;
743 }
744
745 slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
746 if (slen <= 0) return_slen;
747
748 if (value > 32) {
749 fr_strerror_printf("Invalid IPv4 prefix - expected prefix < 32, got %" PRIu64, value);
750 return -1;
751 }
752
753 /*
754 * RFC 9164 Section 4.3 - Trailing bytes of zero are omitted, so we
755 * first copy the data to a fixed-sized buffer which was
756 * zeroed out, and then (@todo) also check that unused bits in
757 * the last byte are all zero.
758 */
759 memset(buffer, 0, sizeof(buffer));
760
761 slen = cbor_decode_octets_memcpy(buffer, 0, sizeof(buffer), &work_dbuff);
762 if (slen <= 0) return_slen;
763
764 memcpy((uint8_t *) &vb->vb_ipv4addr, buffer, sizeof(vb->vb_ipv4addr));
765 vb->vb_ip.prefix = value;
766
767 return fr_dbuff_set(dbuff, &work_dbuff);
768}
769
771{
772 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
773 ssize_t slen;
774 uint8_t header;
775 uint64_t value = 0;
776 uint8_t buffer[sizeof(vb->vb_ipv6addr)];
777
778 FR_DBUFF_OUT_RETURN(&header, &work_dbuff);
779
780 if (header != ((CBOR_ARRAY << 5) | 2)) {
781 fr_strerror_printf("Invalid IPv6 prefix - expected array of 2 elements, got %02x",
782 header);
783 return -1;
784 }
785
786 slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
787 if (slen <= 0) return_slen;
788
789 if (value > 128) {
790 fr_strerror_printf("Invalid IPv6 prefix - expected prefix < 128, got %" PRIu64, value);
791 return -1;
792 }
793
794 /*
795 * RFC 9164 Section 4.3 - Trailing bytes of zero are omitted, so we
796 * first copy the data to a fixed-sized buffer which was
797 * zeroed out, and then (@todo) also check that unused bits in
798 * the last byte are all zero.
799 */
800 memset(buffer, 0, sizeof(buffer));
801
802 slen = cbor_decode_octets_memcpy(buffer, 0, sizeof(buffer), &work_dbuff);
803 if (slen <= 0) return_slen;
804
805 memcpy((uint8_t *) &vb->vb_ipv6addr, buffer, sizeof(vb->vb_ipv6addr));
806 vb->vb_ip.prefix = value;
807
808 return fr_dbuff_set(dbuff, &work_dbuff);
809}
810
812{
813 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
814 ssize_t slen;
815 uint8_t major, info;
816 uint64_t value = 0;
817 int64_t neg;
818
819 FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
820
821 info = major & 0x1f;
822 major >>= 5;
823
824 switch (major) {
825 case CBOR_INTEGER:
826 slen = cbor_decode_integer(&value, info, &work_dbuff);
827 if (slen < 0) return_slen;
828
829 if (value >= ((uint64_t) 1) << 63) { /* equal! */
830 invalid:
831 fr_strerror_printf("cbor value is too large for output data type %s",
833 return -1;
834 }
835
836 *out = value;
837 break;
838
839 case CBOR_NEGATIVE:
840 slen = cbor_decode_integer(&value, info, &work_dbuff);
841 if (slen < 0) return_slen;
842
843 if (value >= ((uint64_t) 1) << 63) goto invalid; /* greater than! */
844
845 /*
846 * Convert 0..(2^63-1) into -0..-(2^63-1)
847 * then conver to -1..-(2^63)
848 */
849 neg = -value;
850 neg--;
851
852 *out = neg;
853 break;
854
855 default:
856 fr_strerror_printf("cbor data contains invalid content %d for expected data type %s",
857 major, fr_type_to_str(type));
858 return -1;
859 }
860
861 return fr_dbuff_set(dbuff, &work_dbuff);
862
863}
864
865static ssize_t cbor_decode_date(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
866{
867 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
868 ssize_t slen;
869 int64_t neg;
870
871 slen = cbor_decode_int64(&neg, &work_dbuff, FR_TYPE_DATE);
872 if (slen <= 0) return_slen;
873
874 vb->vb_date = fr_unix_time_from_sec(neg);
875
876 return fr_dbuff_set(dbuff, &work_dbuff);
877}
878
879/*
880 * Tag 1002, followed by map of at least 2 elements
881 * key 1: seconds
882 * key -9: nanoseconds
883 */
885{
886 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
887 uint64_t count;
888 ssize_t slen;
889 int64_t key, seconds, fraction, scale;
890
891 slen = cbor_decode_count(&count, CBOR_MAP, &work_dbuff);
892 if (slen < 0) return_slen;
893
894 if (!count || (count > 2)) {
895 fr_strerror_printf("Unexpected count %" PRIu64" for time_delta, expected map of 1-2 elements", count);
896 return -1;
897 }
898
899 key = seconds = fraction = 0;
900
901 /*
902 * Expect key 1:seconds
903 */
904 slen = cbor_decode_int64(&key, &work_dbuff, FR_TYPE_TIME_DELTA);
905 if (slen < 0) return_slen;
906
907 if (key != 1) {
908 fr_strerror_printf("Unexpected key %" PRIi64 " for time_delta, expected key 1", key);
909 return -1;
910 }
911
912 slen = cbor_decode_int64(&seconds, &work_dbuff, FR_TYPE_TIME_DELTA);
913 if (slen < 0) return_slen;
914
915 if (count > 1) {
916 slen = cbor_decode_int64(&key, &work_dbuff, FR_TYPE_TIME_DELTA);
917 if (slen < 0) return_slen;
918
919 switch (key) {
920 case -3:
921 scale = MSEC;
922 break;
923
924 case -6:
925 scale = USEC;
926 break;
927
928 case -9:
929 scale = NSEC;
930 break;
931
932 default:
933 fr_strerror_printf("Unsupported time_delta key %" PRIi64, key);
934 return -fr_dbuff_used(&work_dbuff); /* point to actual key? */
935
936 }
937
938 slen = cbor_decode_int64(&fraction, &work_dbuff, FR_TYPE_TIME_DELTA);
939 if (slen < 0) return_slen;
940
941 if ((fraction < 0) || (fraction > scale)) fraction = 0;
942 } else {
943 scale = NSEC;
944 fraction = 0;
945 }
946
947 if (seconds > (INT64_MAX / scale)) {
948 vb->vb_time_delta = fr_time_delta_max();
949
950 } else if (seconds < (INT64_MIN / scale)) {
951 vb->vb_time_delta = fr_time_delta_min();
952
953 } else {
954 seconds *= scale;
955
956 if (seconds < 0) {
957 seconds -= fraction;
958 } else {
959 seconds += fraction;
960 }
961
962 vb->vb_time_delta = fr_time_delta_wrap(seconds);
963 }
964
965 return fr_dbuff_set(dbuff, &work_dbuff);
966}
967
968
981
982/*
983 * @todo - fr_cbor_encode_pair_list(). And then if we have da->flags.array, we encode the _value_ as an
984 * array of indeterminate length. This is a little bit of a special case, but not terrible.
985 */
987 fr_type_t type, fr_dict_attr_t const *enumv, bool tainted)
988{
989 fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
990 bool indefinite;
991 uint8_t major, info;
992 ssize_t slen;
993 int64_t neg;
994 uint64_t value;
995 uint8_t *ptr;
996
997 FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
998
999 if (type == FR_TYPE_NULL) {
1000 type = cbor_guess_type(&work_dbuff, false);
1001 if (type == FR_TYPE_NULL) {
1002 fr_strerror_const("Unable to determine data type from cbor");
1003 return -1;
1004 }
1005 }
1006
1007 fr_value_box_init(vb, type, enumv, tainted);
1008
1009 info = major & 0x1f;
1010 major >>= 5;
1011
1012 /*
1013 * Invalid combinations.
1014 */
1015 if (((info >= 28) && (info <= 30)) ||
1016 ((info == 31) && ((major == 0) || (major == 1) || (major == 6)))) {
1017 fr_strerror_const("Invalid cbor data - input is not 'well formed'");
1018 return -1;
1019 }
1020
1021 switch (major) {
1022 case CBOR_STRING:
1023 if (type != FR_TYPE_STRING) {
1024 mismatch:
1025 fr_strerror_printf("cbor data contains invalid content %d for expected data type %s",
1026 major, fr_type_to_str(type));
1027 return -1;
1028 }
1029
1030 if (info == 31) {
1031 no_chunks:
1032 fr_strerror_const("Chunked strings are not supported");
1033 return -1;
1034 }
1035
1036
1037 /*
1038 * @todo - undefinite length strings. Which are really "chunked" strings.
1039 */
1040 slen = cbor_decode_integer(&value, info, &work_dbuff);
1041 if (slen < 0) return_slen;
1042
1043 /*
1044 * A little bit of sanity check.
1045 */
1046 if (value > (1 << 20)) {
1047 fr_strerror_printf("cbor data string is too long (%" PRIu64 ")", value);
1048 return -1;
1049 }
1050
1051 ptr = talloc_array(ctx, uint8_t, value + 1);
1052 if (!ptr) {
1053 fr_strerror_const("Out of memory");
1054 return -1;
1055 }
1056 talloc_set_type(ptr, char);
1057 if (value) FR_DBUFF_OUT_MEMCPY_RETURN(ptr, &work_dbuff, value);
1058 ptr[value] = '\0';
1059
1060 fr_value_box_strdup_shallow(vb, NULL, (char const *) ptr, tainted);
1061
1062 break;
1063
1064 case CBOR_OCTETS:
1065 if (type != FR_TYPE_OCTETS) goto mismatch;
1066
1067 if (info == 31) goto no_chunks;
1068
1069 /*
1070 * @todo - indefinite length octet strings. Which are really "chunked" octet strings.
1071 */
1072 slen = cbor_decode_integer(&value, info, &work_dbuff);
1073 if (slen < 0) return_slen;
1074
1075 /*
1076 * A little bit of sanity check.
1077 */
1078 if (value > (1 << 20)) {
1079 fr_strerror_printf("cbor data string is too long (%" PRIu64 ")", value);
1080 return -1;
1081 }
1082
1083 ptr = talloc_array(ctx, uint8_t, value);
1084 if (!ptr) {
1085 fr_strerror_const("Out of memory");
1086 return -1;
1087 }
1088
1089 fr_value_box_memdup_shallow(vb, NULL, (uint8_t const *) ptr, value, false); /* tainted? */
1090
1091 if (value) FR_DBUFF_OUT_MEMCPY_RETURN(ptr, &work_dbuff, value);
1092 break;
1093
1094 case CBOR_INTEGER:
1095 slen = cbor_decode_integer(&value, info, &work_dbuff);
1096 if (slen < 0) return_slen;
1097
1098 switch (type) {
1099 case FR_TYPE_BOOL:
1100 if (value > 1) goto invalid_bool;
1101 vb->vb_bool = value;
1102 break;
1103
1104 case FR_TYPE_UINT8:
1105 if (value > UINT8_MAX) {
1106 invalid:
1107 fr_strerror_printf("cbor value is too large for output data type %s",
1109 return -1;
1110 }
1111 vb->vb_uint8 = value;
1112 break;
1113
1114 case FR_TYPE_UINT16:
1115 if (value > UINT16_MAX) goto invalid;
1116 vb->vb_uint16 = value;
1117 break;
1118
1119 case FR_TYPE_UINT32:
1120 if (value > UINT32_MAX) goto invalid;
1121 vb->vb_uint32 = value;
1122 break;
1123
1124 case FR_TYPE_UINT64:
1125 vb->vb_uint64 = value;
1126 break;
1127
1128 case FR_TYPE_INT8:
1129 if (value > INT8_MAX) goto invalid;
1130 vb->vb_int8 = value;
1131 break;
1132
1133 case FR_TYPE_INT16:
1134 if (value > INT16_MAX) goto invalid;
1135 vb->vb_int16 = value;
1136 break;
1137
1138 case FR_TYPE_INT32:
1139 if (value > INT32_MAX) goto invalid;
1140 vb->vb_int32 = value;
1141 break;
1142
1143 case FR_TYPE_INT64:
1144 if (value > INT64_MAX) goto invalid;
1145 vb->vb_int64 = value;
1146 break;
1147
1148 default:
1149 integer_type_mismatch:
1150 fr_strerror_printf("Unexpected cbor type 'integer' when decoding data type %s",
1152 return -1;
1153 }
1154 break;
1155
1156 case CBOR_NEGATIVE:
1157 slen = cbor_decode_integer(&value, info, &work_dbuff);
1158 if (slen < 0) return_slen;
1159
1160 /*
1161 * Signed numbers only go down to -2^63
1162 * so value must be less than 2^63
1163 */
1164 if (value >= ((uint64_t) 1) << 63) goto invalid;
1165
1166 /*
1167 * Convert 0..(2^63-1) into -0..-(2^63-1)
1168 * then conver to -1..-(2^63)
1169 */
1170 neg = -value;
1171 neg--;
1172
1173 switch (type) {
1174 case FR_TYPE_INT8:
1175 if (neg < INT8_MIN) goto invalid;
1176 vb->vb_int8 = neg;
1177 break;
1178
1179 case FR_TYPE_INT16:
1180 if (neg < INT16_MIN) goto invalid;
1181 vb->vb_int16 = neg;
1182 break;
1183
1184 case FR_TYPE_INT32:
1185 if (neg < INT32_MIN) goto invalid;
1186 vb->vb_int32 = neg;
1187 break;
1188
1189 case FR_TYPE_INT64:
1190 vb->vb_int64 = neg;
1191 break;
1192
1193 default:
1194 goto integer_type_mismatch;
1195 }
1196 break;
1197
1198 case CBOR_FLOAT:
1199 /*
1200 * Simple values. See RFC 8489 Section 3.3.
1201 *
1202 * 20 - false
1203 * 21 - true
1204 * 22 - NULL
1205 */
1206 if (info < 24) {
1207 switch (type) {
1208 case FR_TYPE_BOOL:
1209 if (info == 20) {
1210 vb->vb_bool = false;
1211 break;
1212 }
1213
1214 if (info == 21) {
1215 vb->vb_bool = true;
1216 break;
1217 }
1218
1219 invalid_bool:
1220 fr_strerror_printf("Invalid cbor - boolean is not encoded as 'true' or 'false'");
1221 return -fr_dbuff_used(&work_dbuff);
1222
1223 case FR_TYPE_OCTETS:
1224 case FR_TYPE_STRING:
1225 case FR_TYPE_TLV:
1226 case FR_TYPE_VENDOR:
1227 case FR_TYPE_GROUP:
1228 case FR_TYPE_STRUCT:
1229 /*
1230 * Be a little forgiving. 22 is NULL, so we treat that as "nothing".
1231 *
1232 * i.e. empty string, empty set, etc.
1233 */
1234 if (info == 22) break;
1235
1237
1238 default:
1239 fr_strerror_printf("Invalid cbor - unexpected 'simple value' %u", info);
1240 return -fr_dbuff_used(&work_dbuff);
1241 }
1242 break;
1243 }
1244
1245 /*
1246 * Or as one-byte integers.
1247 */
1248 if (info == CBOR_1_BYTE) {
1249 uint8_t data;
1250
1251 FR_DBUFF_OUT_RETURN(&data, &work_dbuff);
1252
1253 switch (type) {
1254 case FR_TYPE_FLOAT32:
1255 vb->vb_float32 = data;
1256 break;
1257
1258 case FR_TYPE_FLOAT64:
1259 vb->vb_float64 = data;
1260 break;
1261
1262 default:
1263 float_type_mismatch:
1264 fr_strerror_printf("Unexpected cbor type 'float' when decoding data type %s",
1266 return -1;
1267 }
1268
1269 break;
1270 }
1271
1272 /*
1273 * We don't support float16
1274 */
1275
1276 if (info == CBOR_4_BYTE) {
1277 float data;
1278
1279 FR_DBUFF_OUT_RETURN(&data, &work_dbuff);
1280
1281 switch (type) {
1282 case FR_TYPE_FLOAT32:
1283 vb->vb_float32 = data;
1284 break;
1285
1286 case FR_TYPE_FLOAT64:
1287 vb->vb_float64 = (double) data;
1288 break;
1289
1290 default:
1291 goto float_type_mismatch;
1292 }
1293
1294 break;
1295 }
1296
1297 if (info == CBOR_8_BYTE) {
1298 double data;
1299
1300 FR_DBUFF_OUT_RETURN(&data, &work_dbuff);
1301
1302 switch (type) {
1303 case FR_TYPE_FLOAT32:
1304 vb->vb_float32 = data; /* maybe loses precision? */
1305 break;
1306
1307 case FR_TYPE_FLOAT64:
1308 vb->vb_float64 = data;
1309 break;
1310
1311 default:
1312 goto float_type_mismatch;
1313 }
1314
1315 break;
1316 }
1317
1318 /*
1319 * 24 is FLOAT16, which we don't support.
1320 * 31 is BREAK, which the caller should have checked for.
1321 */
1322 goto float_type_mismatch;
1323
1324 case CBOR_TAG:
1325 /*
1326 * We only support a limited number of tags.
1327 */
1328 slen = cbor_decode_integer(&value, info, &work_dbuff);
1329 if (slen < 0) return_slen;
1330
1331 /*
1332 * No tag defined for this data type, that's on us.
1333 */
1334 if (!cbor_type_to_tag[type]) {
1335 fr_strerror_printf("Unknown cbor tag %" PRIu64 " for expected data type %s",
1337 return -fr_dbuff_used(&work_dbuff);
1338 }
1339
1340 /*
1341 * Wrong tag for this data type, that's on them.
1342 */
1343 if (cbor_type_to_tag[type] != value) {
1344 fr_strerror_printf("Invalid cbor tag %" PRIu64 " for expected data type %s",
1346 return -fr_dbuff_used(&work_dbuff);
1347 }
1348
1349 fr_value_box_init(vb, type, enumv, tainted);
1350
1351 slen = cbor_decode_type[type](ctx, vb, &work_dbuff);
1352 if (slen < 0) return_slen;
1353 break;
1354
1355 case CBOR_ARRAY:
1356 if (type != FR_TYPE_GROUP) goto invalid_type;
1357
1358 /*
1359 * Loop until done.
1360 */
1361 if (info == 31) {
1362 value = ~0;
1363 indefinite = true;
1364
1365 } else {
1366 slen = cbor_decode_integer(&value, info, &work_dbuff);
1367 if (slen < 0) return_slen;
1368
1369 indefinite = false;
1370 }
1371
1372#ifdef STATIC_ANALYZER
1373 if (value > fr_dbuff_remaining(&work_dbuff)) return -1;
1374#endif
1375
1376 /*
1377 * Loop until we decode everything. For simplicity, we handle indefinite and definite
1378 * length arrays in the same loop.
1379 */
1380 for (/* nothing */; value > 0; value--) {
1381 uint8_t header;
1382 fr_value_box_t *child;
1383
1384 /*
1385 * Require at least one byte in the buffer.
1386 */
1387 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 1);
1388
1389 /*
1390 * Peek ahead for a break.
1391 */
1392 header = *fr_dbuff_current(&work_dbuff);
1393 if (header == 0xff) {
1394 if (!indefinite) {
1395 fr_strerror_const("Unexpected 'break' found in cbor data");
1396 return -fr_dbuff_used(&work_dbuff);
1397 }
1398
1399 /*
1400 * Done!
1401 */
1402 fr_dbuff_advance(&work_dbuff, 1);
1403 break;
1404 }
1405
1406 child = fr_value_box_alloc(ctx, FR_TYPE_NULL, NULL);
1407 if (!child) {
1408 fr_strerror_const("Out of memory");
1409 return -fr_dbuff_used(&work_dbuff);
1410 }
1411
1412 /*
1413 * We have to decode at least one value.
1414 */
1415 slen = fr_cbor_decode_value_box(child, child, &work_dbuff, FR_TYPE_NULL, NULL, tainted);
1416 if (slen <= 0) {
1417 talloc_free(child);
1419 }
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_INT64;
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
1641static ssize_t cbor_decode_pair(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dbuff_t *dbuff,
1642 fr_dict_attr_t const *parent, bool tainted, int depth)
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
1681 /*
1682 * If the nesting is too deep, decode as raw octets. We have to do this manually in CBOR,
1683 * because the other protocols create a da_stack which limits the depth.
1684 */
1685 if (depth >= FR_DICT_MAX_TLV_STACK) goto raw;
1686
1688 if (!da) {
1690
1691 type = cbor_guess_type(&work_dbuff, true);
1692 if (type == FR_TYPE_NULL) return -fr_dbuff_used(&work_dbuff);
1693
1695 raw:
1697 }
1698
1699 /*
1700 * @todo - the value here isn't a cbor octets type, but is instead cbor data. Since cbor
1701 * is typed, we _could_ perhaps instead discover the type from the cbor data, and then
1702 * use that instead. This would involve creating a function which maps cbor types to our
1703 * data types.
1704 */
1706 if (!da) return -fr_dbuff_used(&work_dbuff);
1707 }
1708
1709 vp = fr_pair_afrom_da(ctx, da);
1710 if (!vp) {
1711 fr_strerror_const("Out of memory");
1712 return -fr_dbuff_used(&work_dbuff);
1713 }
1714
1715 /*
1716 * Leaf values are easy.
1717 */
1718 if (fr_type_is_leaf(da->type)) {
1719 slen = fr_cbor_decode_value_box(vp, &vp->data, &work_dbuff, da->type, da, tainted);
1720 if (slen < 0) {
1721 talloc_free(vp);
1723 }
1724
1725 goto done;
1726 }
1727
1729
1730 switch (da->type) {
1731 /*
1732 * All of these are essentially the same.
1733 */
1734 case FR_TYPE_VENDOR:
1735 case FR_TYPE_VSA:
1736 case FR_TYPE_TLV:
1737 parent = vp->da;
1738 break;
1739
1740 /*
1741 * Groups reparent to the ref.
1742 */
1743 case FR_TYPE_GROUP:
1745 fr_assert(parent != NULL);
1746 break;
1747
1748 default:
1749 fr_strerror_printf("Invalid data type %s for child %s of %s",
1750 fr_type_to_str(da->type), vp->da->name, parent->name);
1751 talloc_free(vp);
1752 return -1;
1753 }
1754
1755 /*
1756 * This should be a CBOR_ARRAY.
1757 */
1758 FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
1759
1760 info = major & 0x1f;
1761 major >>= 5;
1762
1763 if (major != CBOR_ARRAY) {
1764 /*
1765 * Allow NULL as a synonym for "no children".
1766 */
1767 if ((major == CBOR_FLOAT) && (info == 22)) goto done;
1768
1769 talloc_free(vp);
1770 fr_strerror_printf("Invalid cbor - expected 'array', got major type %d",
1771 major);
1772 return -1;
1773 }
1774
1775 if (info == 31) {
1776 value = ~0;
1777 indefinite = true;
1778
1779 } else {
1780 slen = cbor_decode_integer(&value, info, &work_dbuff);
1781 if (slen < 0) {
1782 talloc_free(vp);
1784 }
1785
1786 indefinite = false;
1787 }
1788
1789#ifdef STATIC_ANALYZER
1790 if (value > fr_dbuff_remaining(&work_dbuff)) return -1;
1791#endif
1792
1793 /*
1794 * Loop until we decode everything. For simplicity, we handle indefinite and definite
1795 * length arrays in the same loop.
1796 */
1797 for (/* nothing */; value > 0; value--) {
1798 /*
1799 * Require at least one byte in the buffer.
1800 */
1801 if (fr_dbuff_extend_lowat(NULL, &work_dbuff, 1) == 0) {
1802 talloc_free(vp);
1803 return -fr_dbuff_used(&work_dbuff);
1804 }
1805
1806 /*
1807 * Peek ahead for a break.
1808 */
1809 header = *fr_dbuff_current(&work_dbuff);
1810 if (header == 0xff) {
1811 if (!indefinite) {
1812 talloc_free(vp);
1813 fr_strerror_const("Unexpected 'break' found in cbor data");
1814 return -fr_dbuff_used(&work_dbuff);
1815 }
1816
1817 /*
1818 * Done!
1819 */
1820 fr_dbuff_advance(&work_dbuff, 1);
1821 break;
1822 }
1823
1824 slen = cbor_decode_pair(vp, &vp->vp_group, &work_dbuff, parent, tainted, depth + 1);
1825 if (slen <= 0) {
1826 talloc_free(vp);
1828 }
1829 }
1830
1831done:
1832 PAIR_VERIFY(vp);
1833
1835 return fr_dbuff_set(dbuff, &work_dbuff);
1836}
1837
1839 fr_dict_attr_t const *parent, bool tainted)
1840{
1841 return cbor_decode_pair(ctx, out, dbuff, parent, tainted, 0);
1842}
1843
1844/*
1845 * @todo - cbor_print
1846 * [] for array
1847 * [_...] for indefinite array
1848 * {a:b} for map
1849 * digits for integer
1850 * 'string' for string
1851 * h'HHHH' for octets
1852 *
1853 * https://datatracker.ietf.org/doc/html/draft-ietf-cbor-edn-literals
1854 */
static int const char char buffer[256]
Definition acutest.h:576
#define RCSID(id)
Definition build.h:512
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:343
#define UNUSED
Definition build.h:336
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:614
static ssize_t cbor_decode_int64(int64_t *out, fr_dbuff_t *dbuff, fr_type_t type)
Definition cbor.c:811
#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:670
#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:556
#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:865
#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:969
static ssize_t cbor_decode_time_delta(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
Definition cbor.c:884
static ssize_t cbor_decode_ipv4_prefix(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
Definition cbor.c:729
#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:481
static ssize_t cbor_decode_ethernet(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
Definition cbor.c:609
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:986
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:770
#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:1838
#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:1641
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:554
static ssize_t cbor_decode_count(uint64_t *out, int expected, fr_dbuff_t *dbuff)
Definition cbor.c:531
#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:1081
#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:775
#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:681
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
Definition dbuff.h:919
#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:1012
#define fr_dbuff_extend_lowat(_status, _dbuff_or_marker, _lowat)
Extend if we're below _lowat.
Definition dbuff.h:668
#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:751
#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:1761
#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:1391
#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:1594
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:230
#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:1827
#define fr_dbuff_out(_out, _dbuff_or_marker)
Copy data from a dbuff or marker to a fixed sized C type.
Definition dbuff.h:1808
#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:1481
#define FR_DICT_MAX_TLV_STACK
Maximum TLV stack size.
Definition dict.h:517
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:596
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:3570
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:1352
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:37
static bool done
Definition radclient.c:80
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:392
#define fr_type_is_leaf(_x)
Definition types.h:393
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:454
#define FR_TYPE_LEAF
Definition types.h:317
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:5163
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:4729
#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:1340
#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:1030