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