Coverage Report

Created: 2026-08-14 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/freeradius-server/src/lib/util/cbor.c
Line
Count
Source
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
 */
23
RCSID("$Id: 89c32c9eed0918d7eb9971075997f0a025f953b9 $")
24
25
#include <freeradius-devel/util/cbor.h>
26
27
0
#define CBOR_INTEGER  (0)
28
0
#define CBOR_NEGATIVE (1)
29
0
#define CBOR_OCTETS (2)
30
0
#define CBOR_STRING (3)
31
0
#define CBOR_ARRAY  (4)
32
0
#define CBOR_MAP  (5)
33
0
#define CBOR_TAG  (6)
34
0
#define CBOR_FLOAT  (7)
35
36
0
#define CBOR_1_BYTE ((uint8_t) 24)
37
0
#define CBOR_2_BYTE ((uint8_t) 25)
38
0
#define CBOR_4_BYTE ((uint8_t) 26)
39
0
#define CBOR_8_BYTE ((uint8_t) 27)
40
41
static 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
 */
53
static 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,
57
  [FR_TYPE_IPV4_PREFIX] = 52,
58
  [FR_TYPE_IPV6_ADDR] = 54,
59
  [FR_TYPE_IPV6_PREFIX] = 54,
60
  [FR_TYPE_TIME_DELTA] = 1002,
61
};
62
63
static fr_type_t cbor_guess_type(fr_dbuff_t *dbuff, bool pair);
64
65
static ssize_t cbor_encode_integer(fr_dbuff_t *dbuff, uint8_t type, uint64_t data)
66
0
{
67
0
  fr_dbuff_t  work_dbuff = FR_DBUFF(dbuff);
68
0
  uint8_t   value[8];
69
70
0
  fr_assert(type < 8);
71
0
  type <<= 5;
72
73
0
  if (data < 24) {
74
0
    data |= type;
75
76
0
    FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) (data & 0xff));
77
0
    goto done;
78
0
  }
79
80
0
  if (data < (((uint64_t) 1) << 8)) {
81
0
    value[0] = data;
82
83
0
    FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) (type | CBOR_1_BYTE));
84
0
    FR_DBUFF_IN_RETURN(&work_dbuff, value[0]);
85
0
    goto done;
86
0
  }
87
88
0
  if (data < (((uint64_t) 1) << 16)) {
89
0
    fr_nbo_from_uint16(value, data);
90
91
0
    FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) (type | CBOR_2_BYTE));
92
0
    FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, value, 2);
93
0
    goto done;
94
0
  }
95
96
0
  if (data < (((uint64_t) 1) << 32)) {
97
0
    fr_nbo_from_uint32(value, data);
98
99
0
    FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) (type | CBOR_4_BYTE));
100
0
    FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, value, 4);
101
0
    goto done;
102
0
  }
103
104
0
  fr_nbo_from_uint64(value, data);
105
106
  /*
107
   *  Has to be 8 bytes.
108
   */
109
0
  FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, type | CBOR_8_BYTE);
110
0
  FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, value, 8);
111
112
0
done:
113
0
  return fr_dbuff_set(dbuff, &work_dbuff);
114
0
}
115
116
0
#define cbor_encode_array(_dbuff, _size) cbor_encode_integer(_dbuff, CBOR_ARRAY, _size)
117
118
0
#define cbor_encode_tag(_dbuff, _tag) cbor_encode_integer(_dbuff, CBOR_TAG, _tag)
119
120
/*
121
 *  Make many things easier
122
 */
123
0
#define return_slen return FR_DBUFF_ERROR_OFFSET(slen, fr_dbuff_used(&work_dbuff))
124
125
/*
126
 *  Octets is length + data
127
 */
128
static ssize_t cbor_encode_octets(fr_dbuff_t *dbuff, uint8_t const *data, size_t data_len)
129
0
{
130
0
  fr_dbuff_t  work_dbuff = FR_DBUFF(dbuff);
131
0
  ssize_t slen;
132
133
0
  slen = cbor_encode_integer(&work_dbuff, CBOR_OCTETS, data_len);
134
0
  if (slen <= 0) return_slen;
135
136
0
  if (data_len > 0) FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, data, data_len);
137
138
0
  return fr_dbuff_set(dbuff, &work_dbuff);
139
0
}
140
141
static ssize_t cbor_encode_int64(fr_dbuff_t *dbuff, int64_t neg)
142
0
{
143
0
  fr_dbuff_t  work_dbuff = FR_DBUFF(dbuff);
144
0
  ssize_t slen;
145
146
0
  if (neg >= 0) {
147
0
    slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, neg);
148
0
  } else {
149
0
    uint64_t data;
150
151
0
    neg++;
152
0
    data = -neg;
153
0
    slen = cbor_encode_integer(&work_dbuff, CBOR_NEGATIVE, data);
154
0
  }
155
0
  if (slen <= 0) return_slen;
156
157
0
  return fr_dbuff_set(dbuff, &work_dbuff);
158
0
}
159
160
0
#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
 */
166
ssize_t fr_cbor_encode_value_box(fr_dbuff_t *dbuff, fr_value_box_t *vb)
167
0
{
168
0
  fr_dbuff_t  work_dbuff = FR_DBUFF(dbuff);
169
0
  uint8_t   type = CBOR_INTEGER;
170
0
  uint64_t  data;
171
0
  int64_t   neg;
172
0
  ssize_t   slen;
173
0
  uint8_t   const *p, *end;
174
175
0
  switch (vb->type) {
176
0
  case FR_TYPE_BOOL:
177
    /*
178
     *  One byte of FLOAT (i.e. special value), and the boolean as a "simple value".
179
     */
180
0
    FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_FLOAT << 5) | (20 + vb->vb_bool)));
181
0
    break;
182
183
0
  case FR_TYPE_UINT8:
184
0
    data = vb->vb_uint8;
185
0
    goto encode_int;
186
187
0
  case FR_TYPE_UINT16:
188
0
    data = vb->vb_uint16;
189
0
    goto encode_int;
190
191
0
  case FR_TYPE_UINT32:
192
0
    data = vb->vb_uint32;
193
0
    goto encode_int;
194
195
0
  case FR_TYPE_UINT64:
196
0
    data = vb->vb_uint64;
197
0
    goto encode_int;
198
199
  /*
200
   *  Negative numbers.
201
   */
202
0
  case FR_TYPE_INT8:
203
0
    neg = vb->vb_int8;
204
0
    goto encode_neg;
205
206
0
  case FR_TYPE_INT16:
207
0
    neg = vb->vb_int16;
208
0
    goto encode_neg;
209
210
0
  case FR_TYPE_INT32:
211
0
    neg = vb->vb_int32;
212
0
    goto encode_neg;
213
214
0
  case FR_TYPE_INT64:
215
0
    neg = vb->vb_int64;
216
0
  encode_neg:
217
0
    if (neg >= 0) {
218
0
      type = CBOR_INTEGER;
219
0
      data = neg;
220
0
      goto encode_int;
221
0
    }
222
223
    /*
224
     *  convert -1..-2^63 to 0..-(2^63-1)
225
     *  and then it fits into a positive integer.
226
     */
227
0
    neg++;
228
0
    data = -neg;
229
230
0
  encode_int:
231
0
    return cbor_encode_integer(dbuff, type, data);
232
233
0
  case FR_TYPE_OCTETS:
234
0
    return cbor_encode_octets(dbuff, vb->vb_octets, vb->vb_length);
235
236
0
  case FR_TYPE_STRING:
237
0
    slen = cbor_encode_integer(&work_dbuff, CBOR_STRING, vb->vb_length);
238
0
    if (slen <= 0) return_slen;
239
240
0
    if (vb->vb_length) FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, vb->vb_strvalue, vb->vb_length);
241
0
    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
0
  case FR_TYPE_ETHERNET:
248
0
    slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
249
0
    if (slen <= 0) return_slen;
250
251
0
    slen = cbor_encode_octets(&work_dbuff, vb->vb_ether, sizeof(vb->vb_ether));
252
0
    if (slen <= 0) return_slen;
253
0
    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
0
  case FR_TYPE_DATE:
269
0
    slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
270
0
    if (slen <= 0) return_slen;
271
272
0
    neg = fr_unix_time_to_sec(vb->vb_date);
273
0
    slen = cbor_encode_int64(&work_dbuff, neg);
274
0
    if (slen <= 0) return_slen;
275
0
    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
     */
283
0
  case FR_TYPE_TIME_DELTA:
284
0
    slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
285
0
    if (slen <= 0) return_slen;
286
287
0
    neg = fr_time_delta_unwrap(vb->vb_time_delta) % NSEC;
288
289
0
    slen = cbor_encode_integer(&work_dbuff, CBOR_MAP, 1 + (neg != 0));
290
0
    if (slen <= 0) return_slen;
291
292
    /*
293
     *  1: seconds
294
     */
295
0
    slen = cbor_encode_key(&work_dbuff, 1);
296
0
    if (slen <= 0) return_slen;
297
298
0
    slen = cbor_encode_int64(&work_dbuff, fr_time_delta_to_sec(vb->vb_time_delta));
299
0
    if (slen <= 0) return_slen;
300
301
    /*
302
     *  -9: nanoseconds
303
     */
304
0
    if (neg) {
305
0
      slen = cbor_encode_key(&work_dbuff, -9);
306
0
      if (slen <= 0) return_slen;
307
308
0
      slen = cbor_encode_int64(&work_dbuff, neg);
309
0
      if (slen <= 0) return_slen;
310
0
    }
311
0
    break;
312
313
    /*
314
     *  RFC 9164, Section 3.3
315
     *
316
     *
317
     *  tag=IPv4 + address + optional (prefix + scope)
318
     */
319
0
  case FR_TYPE_IPV4_ADDR:
320
0
    slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
321
0
    if (slen <= 0) return_slen;
322
323
0
    if (vb->vb_ip.scope_id != 0) {
324
0
      FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_ARRAY << 5) | 3));
325
326
0
    }
327
328
0
    slen = cbor_encode_octets(&work_dbuff, (uint8_t const *) &vb->vb_ipv4addr, 4);
329
0
    if (slen <= 0) return_slen;
330
331
0
    if (vb->vb_ip.scope_id == 0) break;
332
333
0
    slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, (uint8_t) 32);
334
0
    if (slen <= 0) return_slen;
335
336
0
    slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, vb->vb_ip.scope_id);
337
0
    if (slen <= 0) return_slen;
338
0
    break;
339
340
    /*
341
     *  RFC 9164, Section 3.2
342
     *
343
     *  tag=IPv6 + address + optional (prefix + scope)
344
     */
345
0
  case FR_TYPE_IPV6_ADDR:
346
0
    slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
347
0
    if (slen <= 0) return_slen;
348
349
0
    if (vb->vb_ip.scope_id != 0) {
350
0
      FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_ARRAY << 5) | 3));
351
0
    }
352
353
0
    slen = cbor_encode_octets(&work_dbuff, (uint8_t const *) &vb->vb_ipv6addr, 16);
354
0
    if (slen <= 0) return_slen;
355
356
0
    if (vb->vb_ip.scope_id == 0) break;
357
358
0
    slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, (uint8_t) 128);
359
0
    if (slen <= 0) return_slen;
360
361
0
    slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, vb->vb_ip.scope_id);
362
0
    if (slen <= 0) return_slen;
363
0
    break;
364
365
    /*
366
     *  RFC 9164, Section 3.3
367
     *
368
     *  tag=IPv4 + array(prefix-length, address)
369
     */
370
0
  case FR_TYPE_IPV4_PREFIX:
371
0
    slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
372
0
    if (slen <= 0) return_slen;
373
374
0
    slen = cbor_encode_array(&work_dbuff, 2);
375
0
    if (slen <= 0) return_slen;
376
377
0
    slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, vb->vb_ip.prefix);
378
0
    if (slen <= 0) return_slen;
379
380
0
    p = (uint8_t const *) &vb->vb_ipv4addr;
381
0
    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
0
    do {
392
0
      if (*end != 0) break;
393
394
0
      end--;
395
0
    } while (end != p);
396
397
0
    slen = cbor_encode_octets(&work_dbuff, p, (end - p) + (*end != 0));
398
0
    if (slen <= 0) return_slen;
399
0
    break;
400
401
    /*
402
     *  RFC 9164, Section 3.2
403
     *
404
     *  tag=IPv6 + array(prefix-length, address)
405
     */
406
0
  case FR_TYPE_IPV6_PREFIX:
407
0
    slen = cbor_encode_tag(&work_dbuff, cbor_type_to_tag[vb->type]);
408
0
    if (slen <= 0) return_slen;
409
410
0
    slen = cbor_encode_array(&work_dbuff, 2);
411
0
    if (slen <= 0) return_slen;
412
413
0
    slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, vb->vb_ip.prefix);
414
0
    if (slen <= 0) return_slen;
415
416
0
    p = (uint8_t const *) &vb->vb_ipv6addr;
417
0
    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
0
    do {
428
0
      if (*end != 0) break;
429
430
0
      end--;
431
0
    } while (end != p);
432
433
0
    slen = cbor_encode_octets(&work_dbuff, p, (end - p) + (*end != 0));
434
0
    if (slen <= 0) return_slen;
435
436
0
    break;
437
438
0
  case FR_TYPE_FLOAT32:
439
0
    FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_FLOAT << 5) | CBOR_4_BYTE));
440
0
    FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, (uint8_t const *) &vb->vb_float32, sizeof(vb->vb_float32));
441
0
    break;
442
443
0
  case FR_TYPE_FLOAT64:
444
0
    FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_FLOAT << 5) | CBOR_8_BYTE));
445
0
    FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, (uint8_t const *) &vb->vb_float64, sizeof(vb->vb_float64));
446
0
    break;
447
448
0
  case FR_TYPE_GROUP:
449
    /*
450
     *  Zero-length array.
451
     */
452
0
    if (fr_value_box_list_num_elements(&vb->vb_group) == 0) {
453
0
      FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_ARRAY << 5) | 0));
454
0
      break;
455
0
    }
456
457
    /*
458
     *  The value is array(children)
459
     */
460
0
    slen = cbor_encode_integer(&work_dbuff, CBOR_ARRAY,
461
0
             fr_value_box_list_num_elements(&vb->vb_group));
462
0
    if (slen <= 0) return_slen;
463
464
465
0
    fr_value_box_list_foreach(&vb->vb_group, child) {
466
0
      slen = fr_cbor_encode_value_box(&work_dbuff, child);
467
0
      if (slen <= 0) return_slen;
468
0
    }
469
0
    break;
470
471
472
0
  default:
473
0
    fr_strerror_printf("Invalid data type %s for cbor encoding", fr_type_to_str(vb->type));
474
0
    return -1;
475
0
  }
476
477
0
  return fr_dbuff_set(dbuff, &work_dbuff);
478
0
}
479
480
481
static ssize_t cbor_decode_integer(uint64_t *out, uint8_t info, fr_dbuff_t *dbuff)
482
0
{
483
0
  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
484
485
0
  if (info < 24) {
486
0
    *out = info;
487
0
    return 0;
488
0
  }
489
490
0
  if (info == CBOR_1_BYTE) {
491
0
    uint8_t value;
492
493
0
    FR_DBUFF_OUT_RETURN(&value, &work_dbuff);
494
0
    *out = value;
495
0
    goto done;
496
0
  }
497
498
0
  if (info == CBOR_2_BYTE) {
499
0
    uint16_t value;
500
501
0
    FR_DBUFF_OUT_RETURN(&value, &work_dbuff);
502
0
    *out = value;
503
0
    goto done;
504
0
  }
505
506
0
  if (info == CBOR_4_BYTE) {
507
0
    uint32_t value;
508
509
0
    FR_DBUFF_OUT_RETURN(&value, &work_dbuff);
510
0
    *out = value;
511
0
    goto done;
512
0
  }
513
514
0
  if (info == CBOR_8_BYTE) {
515
0
    uint64_t value;
516
517
0
    FR_DBUFF_OUT_RETURN(&value, &work_dbuff);
518
0
    *out = value;
519
0
    goto done;
520
0
  }
521
522
  /*
523
   *  28 and greater are invalid according to the RFCs.
524
   */
525
0
  if (info > CBOR_8_BYTE) return -1;
526
527
0
done:
528
0
  return fr_dbuff_set(dbuff, &work_dbuff);
529
0
}
530
531
static ssize_t cbor_decode_count(uint64_t *out, int expected, fr_dbuff_t *dbuff)
532
0
{
533
0
  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
534
0
  uint8_t major, info;
535
0
  ssize_t slen;
536
537
0
  FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
538
539
0
  info = major & 0x1f;
540
0
  major >>= 5;
541
542
0
  if (major != expected) {
543
0
    fr_strerror_printf("Expected cbor type '%s', got unexpected type %d ",
544
0
           cbor_type_to_str[expected], major);
545
0
    return -1;
546
0
  }
547
548
0
  slen = cbor_decode_integer(out, info, &work_dbuff);
549
0
  if (slen < 0) return_slen;
550
551
0
  return fr_dbuff_set(dbuff, &work_dbuff);
552
0
}
553
554
typedef ssize_t (*cbor_decode_type_t)(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff);
555
556
static ssize_t cbor_decode_octets_memcpy(uint8_t *dst, size_t dst_min, size_t dst_max, fr_dbuff_t *dbuff)
557
0
{
558
0
  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
559
0
  ssize_t slen;
560
0
  uint64_t value = 0;
561
562
0
  slen = cbor_decode_count(&value, CBOR_OCTETS, &work_dbuff);
563
0
  if (slen < 0) return_slen;
564
565
0
  if (value < dst_min) {
566
0
    fr_strerror_printf("Invalid length for data - expected at least %zu got %" PRIu64, dst_min, value);
567
0
    return -1;
568
0
  }
569
570
0
  if (value > dst_max) {
571
0
    fr_strerror_printf("Invalid length for data - expected no more than %zu got %" PRIu64, dst_max, value);
572
0
    return -1;
573
0
  }
574
575
0
  FR_DBUFF_OUT_MEMCPY_RETURN(dst, &work_dbuff, value);
576
577
0
  return fr_dbuff_set(dbuff, &work_dbuff);
578
0
}
579
580
#if 0
581
static 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
609
static ssize_t cbor_decode_ethernet(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
610
0
{
611
0
  return cbor_decode_octets_memcpy(vb->vb_ether, sizeof(vb->vb_ether), sizeof(vb->vb_ether), dbuff);
612
0
}
613
614
static ssize_t cbor_decode_ipv4_addr(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
615
0
{
616
0
  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
617
0
  ssize_t slen;
618
0
  uint8_t header;
619
0
  size_t count = 0;
620
0
  uint64_t value = 0;
621
622
0
  FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 1);
623
624
0
  header = *fr_dbuff_current(&work_dbuff);
625
0
  if ((header >> 5) == CBOR_ARRAY) {
626
0
    count = header & 0x1f;
627
628
0
    if ((count != 2) && (count != 3)) {
629
0
      fr_strerror_printf("Invalid IPv4 interface - expected array of 2-3 elements, got %02x",
630
0
             header);
631
0
      return -1;
632
0
    }
633
634
0
    fr_dbuff_advance(&work_dbuff, 1);
635
0
  }
636
637
0
  vb->vb_ip.prefix = 32;
638
639
  /*
640
   *  Get the IP address.
641
   */
642
0
  slen = cbor_decode_octets_memcpy((uint8_t *) &vb->vb_ipv4addr,
643
0
           sizeof(vb->vb_ipv4addr),
644
0
           sizeof(vb->vb_ipv4addr), &work_dbuff);
645
0
  if (slen <= 0) return_slen;
646
647
0
  if (!count) return fr_dbuff_set(dbuff, &work_dbuff);
648
649
0
  slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
650
0
  if (slen <= 0) return_slen;
651
652
0
  if (value != 32) {
653
0
    fr_strerror_printf("Invalid IPv4 address - expected prefix = 32 got %" PRIu64, value);
654
0
    return -fr_dbuff_used(&work_dbuff);
655
0
  }
656
657
0
  if (count == 2) return fr_dbuff_set(dbuff, &work_dbuff);
658
659
  /*
660
   *  Get the scope ID
661
   */
662
0
  slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
663
0
  if (slen <= 0) return_slen;
664
665
0
  vb->vb_ip.scope_id = value;
666
667
0
  return fr_dbuff_set(dbuff, &work_dbuff);
668
0
}
669
670
static ssize_t cbor_decode_ipv6_addr(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
671
0
{
672
0
  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
673
0
  ssize_t slen;
674
0
  uint8_t header;
675
0
  size_t count = 0;
676
0
  uint64_t value = 0;
677
678
0
  FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 1);
679
680
0
  header = *fr_dbuff_current(&work_dbuff);
681
0
  if ((header >> 5) == CBOR_ARRAY) {
682
0
    count = header & 0x1f;
683
684
0
    if ((count != 2) && (count != 3)) {
685
0
      fr_strerror_printf("Invalid IPv4 interface - expected array of 2-3 elements, got %02x",
686
0
             header);
687
0
      return -1;
688
0
    }
689
690
0
    fr_dbuff_advance(&work_dbuff, 1);
691
0
  }
692
693
0
  vb->vb_ip.prefix = 128;
694
695
  /*
696
   *  Get the IP address.
697
   */
698
0
  slen = cbor_decode_octets_memcpy((uint8_t *) &vb->vb_ipv6addr,
699
0
           sizeof(vb->vb_ipv6addr),
700
0
           sizeof(vb->vb_ipv6addr), &work_dbuff);
701
702
0
  if (slen <= 0) return_slen;
703
704
0
  if (!count) return fr_dbuff_set(dbuff, &work_dbuff);
705
706
0
  slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
707
0
  if (slen <= 0) return_slen;
708
709
0
  if (value != 128) {
710
0
    fr_strerror_printf("Invalid IPv6 address - expected prefix = 128 got %" PRIu64, value);
711
0
    return -fr_dbuff_used(&work_dbuff);
712
0
  }
713
714
0
  vb->vb_ip.prefix = value;
715
716
0
  if (count == 2) return fr_dbuff_set(dbuff, &work_dbuff);
717
718
  /*
719
   *  Get the scope ID
720
   */
721
0
  slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
722
0
  if (slen <= 0) return_slen;
723
724
0
  vb->vb_ip.scope_id = value;
725
726
0
  return fr_dbuff_set(dbuff, &work_dbuff);
727
0
}
728
729
static ssize_t cbor_decode_ipv4_prefix(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
730
0
{
731
0
  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
732
0
  ssize_t slen;
733
0
  uint8_t header;
734
0
  uint64_t value = 0;
735
0
  uint8_t buffer[sizeof(vb->vb_ipv4addr)];
736
737
0
  FR_DBUFF_OUT_RETURN(&header, &work_dbuff);
738
739
0
  if (header != ((CBOR_ARRAY << 5) | 2)) {
740
0
    fr_strerror_printf("Invalid IPv4 prefix - expected array of 2 elements, got %02x",
741
0
           header);
742
0
    return -1;
743
0
  }
744
745
0
  slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
746
0
  if (slen <= 0) return_slen;
747
748
0
  if (value > 32) {
749
0
    fr_strerror_printf("Invalid IPv4 prefix - expected prefix < 32, got %" PRIu64, value);
750
0
    return -1;
751
0
  }
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
0
  memset(buffer, 0, sizeof(buffer));
760
761
0
  slen = cbor_decode_octets_memcpy(buffer, 0, sizeof(buffer), &work_dbuff);
762
0
  if (slen <= 0) return_slen;
763
764
0
  memcpy((uint8_t *) &vb->vb_ipv4addr, buffer, sizeof(vb->vb_ipv4addr));
765
0
  vb->vb_ip.prefix = value;
766
767
0
  return fr_dbuff_set(dbuff, &work_dbuff);
768
0
}
769
770
static ssize_t cbor_decode_ipv6_prefix(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
771
0
{
772
0
  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
773
0
  ssize_t slen;
774
0
  uint8_t header;
775
0
  uint64_t value = 0;
776
0
  uint8_t buffer[sizeof(vb->vb_ipv6addr)];
777
778
0
  FR_DBUFF_OUT_RETURN(&header, &work_dbuff);
779
780
0
  if (header != ((CBOR_ARRAY << 5) | 2)) {
781
0
    fr_strerror_printf("Invalid IPv6 prefix - expected array of 2 elements, got %02x",
782
0
           header);
783
0
    return -1;
784
0
  }
785
786
0
  slen = cbor_decode_count(&value, CBOR_INTEGER, &work_dbuff);
787
0
  if (slen <= 0) return_slen;
788
789
0
  if (value > 128) {
790
0
    fr_strerror_printf("Invalid IPv6 prefix - expected prefix < 128, got %" PRIu64, value);
791
0
    return -1;
792
0
  }
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
0
  memset(buffer, 0, sizeof(buffer));
801
802
0
  slen = cbor_decode_octets_memcpy(buffer, 0, sizeof(buffer), &work_dbuff);
803
0
  if (slen <= 0) return_slen;
804
805
0
  memcpy((uint8_t *) &vb->vb_ipv6addr, buffer, sizeof(vb->vb_ipv6addr));
806
0
  vb->vb_ip.prefix = value;
807
808
0
  return fr_dbuff_set(dbuff, &work_dbuff);
809
0
}
810
811
static ssize_t cbor_decode_int64(int64_t *out, fr_dbuff_t *dbuff, fr_type_t type)
812
0
{
813
0
  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
814
0
  ssize_t slen;
815
0
  uint8_t major, info;
816
0
  uint64_t value = 0;
817
0
  int64_t neg;
818
819
0
  FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
820
821
0
  info = major & 0x1f;
822
0
  major >>= 5;
823
824
0
  switch (major) {
825
0
  case CBOR_INTEGER:
826
0
    slen = cbor_decode_integer(&value, info, &work_dbuff);
827
0
    if (slen < 0) return_slen;
828
829
0
    if (value >= ((uint64_t) 1) << 63) { /* equal! */
830
0
    invalid:
831
0
      fr_strerror_printf("cbor value is too large for output data type %s",
832
0
             fr_type_to_str(type));
833
0
      return -1;
834
0
    }
835
836
0
    *out = value;
837
0
    break;
838
839
0
  case CBOR_NEGATIVE:
840
0
    slen = cbor_decode_integer(&value, info, &work_dbuff);
841
0
    if (slen < 0) return_slen;
842
843
0
    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
0
    neg = -value;
850
0
    neg--;
851
852
0
    *out = neg;
853
0
    break;
854
855
0
  default:
856
0
    fr_strerror_printf("cbor data contains invalid content %d for expected data type %s",
857
0
           major, fr_type_to_str(type));
858
0
    return -1;
859
0
  }
860
861
0
  return fr_dbuff_set(dbuff, &work_dbuff);
862
863
0
}
864
865
static ssize_t cbor_decode_date(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
866
0
{
867
0
  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
868
0
  ssize_t slen;
869
0
  int64_t neg;
870
871
0
  slen = cbor_decode_int64(&neg, &work_dbuff, FR_TYPE_DATE);
872
0
  if (slen <= 0) return_slen;
873
874
0
  vb->vb_date = fr_unix_time_from_sec(neg);
875
876
0
  return fr_dbuff_set(dbuff, &work_dbuff);
877
0
}
878
879
/*
880
 *  Tag 1002, followed by map of at least 2 elements
881
 *  key 1: seconds
882
 *  key -9: nanoseconds
883
 */
884
static ssize_t cbor_decode_time_delta(UNUSED TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff)
885
0
{
886
0
  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
887
0
  uint64_t count;
888
0
  ssize_t slen;
889
0
  int64_t key, seconds, fraction, scale;
890
891
0
  slen = cbor_decode_count(&count, CBOR_MAP, &work_dbuff);
892
0
  if (slen < 0) return_slen;
893
894
0
  if (!count || (count > 2)) {
895
0
    fr_strerror_printf("Unexpected count %" PRIu64"  for time_delta, expected map of 1-2 elements", count);
896
0
    return -1;
897
0
  }
898
899
0
  key = seconds = fraction = 0;
900
901
  /*
902
   *  Expect key 1:seconds
903
   */
904
0
  slen = cbor_decode_int64(&key, &work_dbuff, FR_TYPE_TIME_DELTA);
905
0
  if (slen < 0) return_slen;
906
907
0
  if (key != 1) {
908
0
    fr_strerror_printf("Unexpected key %" PRIi64 " for time_delta, expected key 1", key);
909
0
    return -1;
910
0
  }
911
912
0
  slen = cbor_decode_int64(&seconds, &work_dbuff, FR_TYPE_TIME_DELTA);
913
0
  if (slen < 0) return_slen;
914
915
0
  if (count > 1) {
916
0
    slen = cbor_decode_int64(&key, &work_dbuff, FR_TYPE_TIME_DELTA);
917
0
    if (slen < 0) return_slen;
918
919
0
    switch (key) {
920
0
    case -3:
921
0
      scale = MSEC;
922
0
      break;
923
924
0
    case -6:
925
0
      scale = USEC;
926
0
      break;
927
928
0
    case -9:
929
0
      scale = NSEC;
930
0
      break;
931
932
0
    default:
933
0
      fr_strerror_printf("Unsupported time_delta key %" PRIi64, key);
934
0
      return -fr_dbuff_used(&work_dbuff); /* point to actual key? */
935
936
0
    }
937
938
0
    slen = cbor_decode_int64(&fraction, &work_dbuff, FR_TYPE_TIME_DELTA);
939
0
    if (slen < 0) return_slen;
940
941
0
    if ((fraction < 0) || (fraction > scale)) fraction = 0;
942
0
  } else {
943
0
    scale = NSEC;
944
0
    fraction = 0;
945
0
  }
946
947
0
  if (seconds > (INT64_MAX / scale)) {
948
0
    vb->vb_time_delta = fr_time_delta_max();
949
950
0
  } else if (seconds < (INT64_MIN / scale)) {
951
0
    vb->vb_time_delta = fr_time_delta_min();
952
953
0
  } else {
954
0
    seconds *= scale;
955
956
0
    if (seconds < 0) {
957
0
      seconds -= fraction;
958
0
    } else {
959
0
      seconds += fraction;
960
0
    }
961
962
0
    vb->vb_time_delta = fr_time_delta_wrap(seconds);
963
0
  }
964
965
0
  return fr_dbuff_set(dbuff, &work_dbuff);
966
0
}
967
968
969
static cbor_decode_type_t cbor_decode_type[FR_TYPE_MAX] = {
970
  [FR_TYPE_ETHERNET] = cbor_decode_ethernet,
971
972
  [FR_TYPE_DATE] = cbor_decode_date,
973
  [FR_TYPE_TIME_DELTA] = cbor_decode_time_delta,
974
975
  [FR_TYPE_IPV4_ADDR] = cbor_decode_ipv4_addr,
976
  [FR_TYPE_IPV6_ADDR] = cbor_decode_ipv6_addr,
977
978
  [FR_TYPE_IPV4_PREFIX] = cbor_decode_ipv4_prefix,
979
  [FR_TYPE_IPV6_PREFIX] = cbor_decode_ipv6_prefix,
980
};
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
 */
986
ssize_t fr_cbor_decode_value_box(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_dbuff_t *dbuff,
987
         fr_type_t type, fr_dict_attr_t const *enumv, bool tainted)
988
0
{
989
0
  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
990
0
  bool indefinite;
991
0
  uint8_t major, info;
992
0
  ssize_t slen;
993
0
  int64_t neg;
994
0
  uint64_t value;
995
0
  uint8_t *ptr;
996
997
0
  FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
998
999
0
  if (type == FR_TYPE_NULL) {
1000
0
    type = cbor_guess_type(&work_dbuff, false);
1001
0
    if (type == FR_TYPE_NULL) {
1002
0
      fr_strerror_const("Unable to determine data type from cbor");
1003
0
      return -1;
1004
0
    }
1005
0
  }
1006
1007
0
  fr_value_box_init(vb, type, enumv, tainted);
1008
1009
0
  info = major & 0x1f;
1010
0
  major >>= 5;
1011
1012
  /*
1013
   *  Invalid combinations.
1014
   */
1015
0
  if (((info >= 28) && (info <= 30)) ||
1016
0
      ((info == 31) && ((major == 0) || (major == 1) || (major == 6)))) {
1017
0
    fr_strerror_const("Invalid cbor data - input is not 'well formed'");
1018
0
    return -1;
1019
0
  }
1020
1021
0
  switch (major) {
1022
0
  case CBOR_STRING:
1023
0
    if (type != FR_TYPE_STRING) {
1024
0
    mismatch:
1025
0
      fr_strerror_printf("cbor data contains invalid content %d for expected data type %s",
1026
0
             major, fr_type_to_str(type));
1027
0
      return -1;
1028
0
    }
1029
1030
0
    if (info == 31) {
1031
0
    no_chunks:
1032
0
      fr_strerror_const("Chunked strings are not supported");
1033
0
      return -1;
1034
0
    }
1035
1036
1037
    /*
1038
     *  @todo - undefinite length strings.  Which are really "chunked" strings.
1039
     */
1040
0
    slen = cbor_decode_integer(&value, info, &work_dbuff);
1041
0
    if (slen < 0) return_slen;
1042
1043
    /*
1044
     *  A little bit of sanity check.
1045
     */
1046
0
    if (value > (1 << 20)) {
1047
0
      fr_strerror_printf("cbor data string is too long (%" PRIu64 ")", value);
1048
0
      return -1;
1049
0
    }
1050
1051
0
    ptr = talloc_array(ctx, uint8_t, value + 1);
1052
0
    if (!ptr) {
1053
0
      fr_strerror_const("Out of memory");
1054
0
      return -1;
1055
0
    }
1056
0
    talloc_set_type(ptr, char);
1057
0
    if (value) FR_DBUFF_OUT_MEMCPY_RETURN(ptr, &work_dbuff, value);
1058
0
    ptr[value] = '\0';
1059
1060
0
    fr_value_box_strdup_shallow(vb, NULL, (char const *) ptr, tainted);
1061
1062
0
    break;
1063
1064
0
  case CBOR_OCTETS:
1065
0
    if (type != FR_TYPE_OCTETS) goto mismatch;
1066
1067
0
    if (info == 31) goto no_chunks;
1068
1069
    /*
1070
     *  @todo - indefinite length octet strings.  Which are really "chunked" octet strings.
1071
     */
1072
0
    slen = cbor_decode_integer(&value, info, &work_dbuff);
1073
0
    if (slen < 0) return_slen;
1074
1075
    /*
1076
     *  A little bit of sanity check.
1077
     */
1078
0
    if (value > (1 << 20)) {
1079
0
      fr_strerror_printf("cbor data string is too long (%" PRIu64 ")", value);
1080
0
      return -1;
1081
0
    }
1082
1083
0
    ptr = talloc_array(ctx, uint8_t, value);
1084
0
    if (!ptr) {
1085
0
      fr_strerror_const("Out of memory");
1086
0
      return -1;
1087
0
    }
1088
1089
0
    fr_value_box_memdup_shallow(vb, NULL, (uint8_t const *) ptr, value, false); /* tainted? */
1090
1091
0
    if (value) FR_DBUFF_OUT_MEMCPY_RETURN(ptr, &work_dbuff, value);
1092
0
    break;
1093
1094
0
  case CBOR_INTEGER:
1095
0
    slen = cbor_decode_integer(&value, info, &work_dbuff);
1096
0
    if (slen < 0) return_slen;
1097
1098
0
    switch (type) {
1099
0
    case FR_TYPE_BOOL:
1100
0
      if (value > 1) goto invalid_bool;
1101
0
      vb->vb_bool = value;
1102
0
      break;
1103
1104
0
    case FR_TYPE_UINT8:
1105
0
      if (value > UINT8_MAX) {
1106
0
      invalid:
1107
0
        fr_strerror_printf("cbor value is too large for output data type %s",
1108
0
               fr_type_to_str(type));
1109
0
        return -1;
1110
0
      }
1111
0
      vb->vb_uint8 = value;
1112
0
      break;
1113
1114
0
    case FR_TYPE_UINT16:
1115
0
      if (value > UINT16_MAX) goto invalid;
1116
0
      vb->vb_uint16 = value;
1117
0
      break;
1118
1119
0
    case FR_TYPE_UINT32:
1120
0
      if (value > UINT32_MAX) goto invalid;
1121
0
      vb->vb_uint32 = value;
1122
0
      break;
1123
1124
0
    case FR_TYPE_UINT64:
1125
0
      vb->vb_uint64 = value;
1126
0
      break;
1127
1128
0
    case FR_TYPE_INT8:
1129
0
      if (value > INT8_MAX) goto invalid;
1130
0
      vb->vb_int8 = value;
1131
0
      break;
1132
1133
0
    case FR_TYPE_INT16:
1134
0
      if (value > INT16_MAX) goto invalid;
1135
0
      vb->vb_int16 = value;
1136
0
      break;
1137
1138
0
    case FR_TYPE_INT32:
1139
0
      if (value > INT32_MAX) goto invalid;
1140
0
      vb->vb_int32 = value;
1141
0
      break;
1142
1143
0
    case FR_TYPE_INT64:
1144
0
      if (value > INT64_MAX) goto invalid;
1145
0
      vb->vb_int64 = value;
1146
0
      break;
1147
1148
0
    default:
1149
0
    integer_type_mismatch:
1150
0
      fr_strerror_printf("Unexpected cbor type 'integer' when decoding data type %s",
1151
0
             fr_type_to_str(type));
1152
0
      return -1;
1153
0
    }
1154
0
    break;
1155
1156
0
  case CBOR_NEGATIVE:
1157
0
    slen = cbor_decode_integer(&value, info, &work_dbuff);
1158
0
    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
0
    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
0
    neg = -value;
1171
0
    neg--;
1172
1173
0
    switch (type) {
1174
0
    case FR_TYPE_INT8:
1175
0
      if (neg < INT8_MIN) goto invalid;
1176
0
      vb->vb_int8 = neg;
1177
0
      break;
1178
1179
0
    case FR_TYPE_INT16:
1180
0
      if (neg < INT16_MIN) goto invalid;
1181
0
      vb->vb_int16 = neg;
1182
0
      break;
1183
1184
0
    case FR_TYPE_INT32:
1185
0
      if (neg < INT32_MIN) goto invalid;
1186
0
      vb->vb_int32 = neg;
1187
0
      break;
1188
1189
0
    case FR_TYPE_INT64:
1190
0
      vb->vb_int64 = neg;
1191
0
      break;
1192
1193
0
    default:
1194
0
      goto integer_type_mismatch;
1195
0
    }
1196
0
    break;
1197
1198
0
  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
0
    if (info < 24) {
1207
0
      switch (type) {
1208
0
      case FR_TYPE_BOOL:
1209
0
        if (info == 20) {
1210
0
          vb->vb_bool = false;
1211
0
          break;
1212
0
        }
1213
1214
0
        if (info == 21) {
1215
0
          vb->vb_bool = true;
1216
0
          break;
1217
0
        }
1218
1219
0
      invalid_bool:
1220
0
        fr_strerror_printf("Invalid cbor - boolean is not encoded as 'true' or 'false'");
1221
0
        return -fr_dbuff_used(&work_dbuff);
1222
1223
0
      case FR_TYPE_OCTETS:
1224
0
      case FR_TYPE_STRING:
1225
0
      case FR_TYPE_TLV:
1226
0
      case FR_TYPE_VENDOR:
1227
0
      case FR_TYPE_GROUP:
1228
0
      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
0
        if (info == 22) break;
1235
1236
0
        FALL_THROUGH;
1237
1238
0
      default:
1239
0
        fr_strerror_printf("Invalid cbor - unexpected 'simple value' %u", info);
1240
0
        return -fr_dbuff_used(&work_dbuff);
1241
0
      }
1242
0
      break;
1243
0
    }
1244
1245
    /*
1246
     *  Or as one-byte integers.
1247
     */
1248
0
    if (info == CBOR_1_BYTE) {
1249
0
      uint8_t data;
1250
1251
0
      FR_DBUFF_OUT_RETURN(&data, &work_dbuff);
1252
1253
0
      switch (type) {
1254
0
      case FR_TYPE_FLOAT32:
1255
0
        vb->vb_float32 = data;
1256
0
        break;
1257
1258
0
      case FR_TYPE_FLOAT64:
1259
0
        vb->vb_float64 = data;
1260
0
        break;
1261
1262
0
      default:
1263
0
      float_type_mismatch:
1264
0
        fr_strerror_printf("Unexpected cbor type 'float' when decoding data type %s",
1265
0
               fr_type_to_str(type));
1266
0
        return -1;
1267
0
      }
1268
1269
0
      break;
1270
0
    }
1271
1272
    /*
1273
     *  We don't support float16
1274
     */
1275
1276
0
    if (info == CBOR_4_BYTE) {
1277
0
      float data;
1278
1279
0
      FR_DBUFF_OUT_RETURN(&data, &work_dbuff);
1280
1281
0
      switch (type) {
1282
0
      case FR_TYPE_FLOAT32:
1283
0
        vb->vb_float32 = data;
1284
0
        break;
1285
1286
0
      case FR_TYPE_FLOAT64:
1287
0
        vb->vb_float64 = (double) data;
1288
0
        break;
1289
1290
0
      default:
1291
0
        goto float_type_mismatch;
1292
0
      }
1293
1294
0
      break;
1295
0
    }
1296
1297
0
    if (info == CBOR_8_BYTE) {
1298
0
      double data;
1299
1300
0
      FR_DBUFF_OUT_RETURN(&data, &work_dbuff);
1301
1302
0
      switch (type) {
1303
0
      case FR_TYPE_FLOAT32:
1304
0
        vb->vb_float32 = data; /* maybe loses precision? */
1305
0
        break;
1306
1307
0
      case FR_TYPE_FLOAT64:
1308
0
        vb->vb_float64 = data;
1309
0
        break;
1310
1311
0
      default:
1312
0
        goto float_type_mismatch;
1313
0
      }
1314
1315
0
      break;
1316
0
    }
1317
1318
    /*
1319
     *  24 is FLOAT16, which we don't support.
1320
     *  31 is BREAK, which the caller should have checked for.
1321
     */
1322
0
    goto float_type_mismatch;
1323
1324
0
  case CBOR_TAG:
1325
    /*
1326
     *  We only support a limited number of tags.
1327
     */
1328
0
    slen = cbor_decode_integer(&value, info, &work_dbuff);
1329
0
    if (slen < 0) return_slen;
1330
1331
    /*
1332
     *  No tag defined for this data type, that's on us.
1333
     */
1334
0
    if (!cbor_type_to_tag[type]) {
1335
0
      fr_strerror_printf("Unknown cbor tag %" PRIu64 " for expected data type %s",
1336
0
             value, fr_type_to_str(type));
1337
0
      return -fr_dbuff_used(&work_dbuff);
1338
0
    }
1339
1340
    /*
1341
     *  Wrong tag for this data type, that's on them.
1342
     */
1343
0
    if (cbor_type_to_tag[type] != value) {
1344
0
      fr_strerror_printf("Invalid cbor tag %" PRIu64 " for expected data type %s",
1345
0
             value, fr_type_to_str(type));
1346
0
      return -fr_dbuff_used(&work_dbuff);
1347
0
    }
1348
1349
0
    fr_value_box_init(vb, type, enumv, tainted);
1350
1351
0
    slen = cbor_decode_type[type](ctx, vb, &work_dbuff);
1352
0
    if (slen < 0) return_slen;
1353
0
    break;
1354
1355
0
  case CBOR_ARRAY:
1356
0
    if (type != FR_TYPE_GROUP) goto invalid_type;
1357
1358
    /*
1359
     *  Loop until done.
1360
     */
1361
0
    if (info == 31) {
1362
0
      value = ~0;
1363
0
      indefinite = true;
1364
1365
0
    } else {
1366
0
      slen = cbor_decode_integer(&value, info, &work_dbuff);
1367
0
      if (slen < 0) return_slen;
1368
1369
0
      indefinite = false;
1370
0
    }
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
0
    for (/* nothing */; value > 0; value--) {
1381
0
      uint8_t header;
1382
0
      fr_value_box_t *child;
1383
1384
      /*
1385
       *  Require at least one byte in the buffer.
1386
       */
1387
0
      FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, 1);
1388
1389
      /*
1390
       *  Peek ahead for a break.
1391
       */
1392
0
      header = *fr_dbuff_current(&work_dbuff);
1393
0
      if (header == 0xff) {
1394
0
        if (!indefinite) {
1395
0
          fr_strerror_const("Unexpected 'break' found in cbor data");
1396
0
          return -fr_dbuff_used(&work_dbuff);
1397
0
        }
1398
1399
        /*
1400
         *  Done!
1401
         */
1402
0
        fr_dbuff_advance(&work_dbuff, 1);
1403
0
        break;
1404
0
      }
1405
1406
0
      child = fr_value_box_alloc(ctx, FR_TYPE_NULL, NULL);
1407
0
      if (!child) {
1408
0
        fr_strerror_const("Out of memory");
1409
0
        return -fr_dbuff_used(&work_dbuff);
1410
0
      }
1411
1412
      /*
1413
       *  We have to decode at least one value.
1414
       */
1415
0
      slen = fr_cbor_decode_value_box(child, child, &work_dbuff, FR_TYPE_NULL, NULL, tainted);
1416
0
      if (slen <= 0) {
1417
0
        talloc_free(child);
1418
0
        return_slen;
1419
0
      }
1420
1421
0
      fr_value_box_list_insert_tail(&vb->vb_group, child);
1422
0
    }
1423
0
    break;
1424
1425
    /*
1426
     *  These are not value-box types.
1427
     */
1428
0
  case CBOR_MAP:
1429
0
  invalid_type:
1430
0
    fr_strerror_printf("Invalid data type %s for cbor to value-box", fr_type_to_str(type));
1431
0
    return -1;
1432
0
  }
1433
1434
0
  return fr_dbuff_set(dbuff, &work_dbuff);
1435
0
}
1436
1437
/** Encode a pair
1438
 *
1439
 */
1440
ssize_t fr_cbor_encode_pair(fr_dbuff_t *dbuff, fr_pair_t *vp)
1441
0
{
1442
0
  fr_dbuff_t  work_dbuff = FR_DBUFF(dbuff);
1443
0
  ssize_t   slen;
1444
0
  fr_dict_attr_t const *parent;
1445
0
  size_t    count;
1446
1447
0
  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
0
  slen = cbor_encode_integer(&work_dbuff, CBOR_INTEGER, vp->da->attr);
1453
0
  if (slen <= 0) return_slen;
1454
1455
  /*
1456
   *  Value is the actual value of the leaf, or the array of children.
1457
   */
1458
0
  switch (vp->vp_type) {
1459
0
  case FR_TYPE_LEAF:
1460
0
    slen = fr_cbor_encode_value_box(&work_dbuff, &vp->data);
1461
0
    if (slen <= 0) return_slen;
1462
0
    break;
1463
1464
    /*
1465
     *  Groups reparent to the ref.
1466
     */
1467
0
  case FR_TYPE_GROUP:
1468
0
    parent = fr_dict_attr_ref(vp->da);
1469
0
    fr_assert(parent != NULL);
1470
0
    goto encode_children;
1471
1472
    /*
1473
     *  The only difference between TLV and VSA is that the children of VSA are all VENDORs.
1474
     */
1475
0
  case FR_TYPE_VENDOR:
1476
0
  case FR_TYPE_VSA:
1477
0
  case FR_TYPE_TLV:
1478
0
    parent = vp->da;
1479
1480
    /*
1481
     *  The value is array(children)
1482
     */
1483
0
encode_children:
1484
0
    if (fr_pair_list_num_elements(&vp->vp_group) == 0) {
1485
0
      FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t) ((CBOR_FLOAT << 5) | 22)); /* NULL */
1486
0
      break;
1487
0
    }
1488
1489
    /*
1490
     *  The groups, etc. may contain internal attributes.  We don't yet deal with those.
1491
     */
1492
0
    count = 0;
1493
0
    fr_pair_list_foreach(&vp->vp_group, child) {
1494
0
      if (child->da->parent != parent) continue;
1495
0
      count++;
1496
0
    }
1497
1498
0
    slen = cbor_encode_integer(&work_dbuff, CBOR_ARRAY, count);
1499
0
    if (slen <= 0) return_slen;
1500
1501
0
    fr_pair_list_foreach(&vp->vp_group, child) {
1502
      /*
1503
       *  We don't allow changing dictionaries here.
1504
       */
1505
0
      if (child->da->parent != parent) continue;
1506
1507
0
      slen = fr_cbor_encode_pair(&work_dbuff, child);
1508
0
      if (slen <= 0) return_slen;
1509
0
    }
1510
0
    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
0
  default:
1518
0
    fr_strerror_printf("Invalid data type %s for cbor encoding", fr_type_to_str(vp->vp_type));
1519
0
    return -1;
1520
0
  }
1521
1522
0
  return fr_dbuff_set(dbuff, &work_dbuff);
1523
0
}
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
 */
1530
static fr_type_t cbor_guess_type(fr_dbuff_t *dbuff, bool pair)
1531
0
{
1532
0
  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
1533
0
  ssize_t slen;
1534
0
  uint8_t major, info;
1535
0
  uint64_t value;
1536
1537
  /*
1538
   *  get the next byte, which is a CBOR header.
1539
   */
1540
0
  slen = fr_dbuff_out(&major, &work_dbuff);
1541
0
  if (slen <= 0) {
1542
0
  no_data:
1543
0
    fr_strerror_const("Invalid cbor - insufficient data");
1544
0
    return FR_TYPE_NULL;
1545
0
  }
1546
1547
0
  info = major & 0x1f;
1548
0
  major >>= 5;
1549
1550
0
  switch (major) {
1551
0
  case CBOR_INTEGER:
1552
0
    return FR_TYPE_UINT64;
1553
1554
0
  case CBOR_NEGATIVE:
1555
0
    return FR_TYPE_INT64;
1556
1557
0
  case CBOR_STRING:
1558
0
    return FR_TYPE_STRING;
1559
1560
0
  case CBOR_OCTETS:
1561
0
    return FR_TYPE_OCTETS;
1562
1563
0
  case CBOR_ARRAY:
1564
0
    if (!pair) return FR_TYPE_GROUP;
1565
0
    break;
1566
1567
0
  case CBOR_MAP:
1568
0
    return FR_TYPE_TLV;
1569
1570
    /*
1571
     *  Look at the tag to determine what it is
1572
     */
1573
0
  case CBOR_TAG:
1574
0
    slen = cbor_decode_integer(&value, info, &work_dbuff);
1575
0
    if (slen < 0) break;
1576
1577
0
    switch (value) {
1578
0
    case 1:
1579
0
    case 1001:
1580
0
      return FR_TYPE_DATE;
1581
1582
0
    case 1002:
1583
0
      return FR_TYPE_TIME_DELTA;
1584
1585
0
    case 48:
1586
0
      return FR_TYPE_ETHERNET;
1587
1588
0
    case 52:
1589
0
      slen = fr_dbuff_out(&major, &work_dbuff);
1590
0
      if (slen <= 0) goto no_data;
1591
1592
0
      major >>= 5;
1593
1594
0
      if (major == CBOR_ARRAY) {
1595
0
        return FR_TYPE_IPV4_PREFIX;
1596
0
      }
1597
0
      return FR_TYPE_IPV4_ADDR;
1598
1599
0
    case 54:
1600
0
      slen = fr_dbuff_out(&major, &work_dbuff);
1601
0
      if (slen <= 0) goto no_data;
1602
1603
0
      major >>= 5;
1604
1605
0
      if (major == CBOR_ARRAY) {
1606
0
        return FR_TYPE_IPV6_PREFIX;
1607
0
      }
1608
0
      return FR_TYPE_IPV6_ADDR;
1609
1610
0
    default:
1611
0
      break;
1612
0
    }
1613
1614
0
    break;
1615
1616
0
  case CBOR_FLOAT:
1617
    /*
1618
     *  In-place values are special. false / true / NULL
1619
     */
1620
0
    if (info < 24) {
1621
0
      if ((info == 20) || (info == 21)) return FR_TYPE_BOOL;
1622
1623
0
      return FR_TYPE_NULL;
1624
0
    }
1625
1626
0
    return FR_TYPE_FLOAT64;
1627
0
  }
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
0
  fr_strerror_const("Invalid cbor - unable to determine data type");
1638
0
  return FR_TYPE_NULL;
1639
0
}
1640
1641
static 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
0
{
1644
0
  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
1645
0
  uint8_t header, major, info;
1646
0
  bool indefinite;
1647
0
  ssize_t slen;
1648
0
  fr_pair_t *vp;
1649
0
  uint64_t value = 0;
1650
0
  fr_dict_attr_t const *da;
1651
1652
0
  FR_DBUFF_OUT_RETURN(&header, &work_dbuff);
1653
1654
  /*
1655
   *  We require a 2-element array(attribute number, value)
1656
   */
1657
0
  if (header != (((CBOR_MAP) << 5) | 1)) {
1658
0
    fr_strerror_printf("Invalid cbor header - expected map of 1 elements, got %02x", header);
1659
0
    return -1;
1660
0
  }
1661
1662
  /*
1663
   *  This should be a CBOR_INTEGER.
1664
   */
1665
0
  FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
1666
1667
0
  info = major & 0x1f;
1668
0
  major >>= 5;
1669
1670
0
  if (major != CBOR_INTEGER) {
1671
0
    fr_strerror_printf("Invalid cbor - expected 'integer', got major type %d",
1672
0
           major);
1673
0
    return -1;
1674
0
  }
1675
1676
0
  slen = cbor_decode_integer(&value, info, &work_dbuff);
1677
0
  if (slen < 0) {
1678
0
    return_slen;
1679
0
  }
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
0
  if (depth >= FR_DICT_MAX_TLV_STACK) goto raw;
1686
1687
0
  da = fr_dict_attr_child_by_num(parent, value);
1688
0
  if (!da) {
1689
0
    fr_type_t type;
1690
1691
0
    type = cbor_guess_type(&work_dbuff, true);
1692
0
    if (type == FR_TYPE_NULL) return -fr_dbuff_used(&work_dbuff);
1693
1694
0
    if (depth >= FR_DICT_MAX_TLV_STACK) {
1695
0
    raw:
1696
0
      type = FR_TYPE_OCTETS;
1697
0
    }
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
     */
1705
0
    da = fr_dict_attr_unknown_typed_afrom_num(ctx, parent, value, type);
1706
0
    if (!da) return -fr_dbuff_used(&work_dbuff);
1707
0
  }
1708
1709
0
  vp = fr_pair_afrom_da(ctx, da);
1710
0
  if (!vp) {
1711
0
    fr_strerror_const("Out of memory");
1712
0
    return -fr_dbuff_used(&work_dbuff);
1713
0
  }
1714
1715
  /*
1716
   *  Leaf values are easy.
1717
   */
1718
0
  if (fr_type_is_leaf(da->type)) {
1719
0
    slen = fr_cbor_decode_value_box(vp, &vp->data, &work_dbuff, da->type, da, tainted);
1720
0
    if (slen < 0) {
1721
0
      talloc_free(vp);
1722
0
      return_slen;
1723
0
    }
1724
1725
0
    goto done;
1726
0
  }
1727
1728
0
  fr_assert(fr_type_is_structural(da->type));
1729
1730
0
  switch (da->type) {
1731
    /*
1732
     *  All of these are essentially the same.
1733
     */
1734
0
  case FR_TYPE_VENDOR:
1735
0
  case FR_TYPE_VSA:
1736
0
  case FR_TYPE_TLV:
1737
0
    parent = vp->da;
1738
0
    break;
1739
1740
    /*
1741
     *  Groups reparent to the ref.
1742
     */
1743
0
  case FR_TYPE_GROUP:
1744
0
    parent = fr_dict_attr_ref(vp->da);
1745
0
    fr_assert(parent != NULL);
1746
0
    break;
1747
1748
0
  default:
1749
0
    fr_strerror_printf("Invalid data type %s for child %s of %s",
1750
0
           fr_type_to_str(da->type), vp->da->name, parent->name);
1751
0
    talloc_free(vp);
1752
0
    return -1;
1753
0
  }
1754
1755
  /*
1756
   *  This should be a CBOR_ARRAY.
1757
   */
1758
0
  FR_DBUFF_OUT_RETURN(&major, &work_dbuff);
1759
1760
0
  info = major & 0x1f;
1761
0
  major >>= 5;
1762
1763
0
  if (major != CBOR_ARRAY) {
1764
    /*
1765
     *  Allow NULL as a synonym for "no children".
1766
     */
1767
0
    if ((major == CBOR_FLOAT) && (info == 22)) goto done;
1768
1769
0
    talloc_free(vp);
1770
0
    fr_strerror_printf("Invalid cbor - expected 'array', got major type %d",
1771
0
           major);
1772
0
    return -1;
1773
0
  }
1774
1775
0
  if (info == 31) {
1776
0
    value = ~0;
1777
0
    indefinite = true;
1778
1779
0
  } else {
1780
0
    slen = cbor_decode_integer(&value, info, &work_dbuff);
1781
0
    if (slen < 0) {
1782
0
      talloc_free(vp);
1783
0
      return_slen;
1784
0
    }
1785
1786
0
    indefinite = false;
1787
0
  }
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
0
  for (/* nothing */; value > 0; value--) {
1798
    /*
1799
     *  Require at least one byte in the buffer.
1800
     */
1801
0
    if (fr_dbuff_extend_lowat(NULL, &work_dbuff, 1) == 0) {
1802
0
      talloc_free(vp);
1803
0
      return -fr_dbuff_used(&work_dbuff);
1804
0
    }
1805
1806
    /*
1807
     *  Peek ahead for a break.
1808
     */
1809
0
    header = *fr_dbuff_current(&work_dbuff);
1810
0
    if (header == 0xff) {
1811
0
      if (!indefinite) {
1812
0
        talloc_free(vp);
1813
0
        fr_strerror_const("Unexpected 'break' found in cbor data");
1814
0
        return -fr_dbuff_used(&work_dbuff);
1815
0
      }
1816
1817
      /*
1818
       *  Done!
1819
       */
1820
0
      fr_dbuff_advance(&work_dbuff, 1);
1821
0
      break;
1822
0
    }
1823
1824
0
    slen = cbor_decode_pair(vp, &vp->vp_group, &work_dbuff, parent, tainted, depth + 1);
1825
0
    if (slen <= 0) {
1826
0
      talloc_free(vp);
1827
0
      return_slen;
1828
0
    }
1829
0
  }
1830
1831
0
done:
1832
0
  PAIR_VERIFY(vp);
1833
1834
0
  fr_pair_append(out, vp);
1835
0
  return fr_dbuff_set(dbuff, &work_dbuff);
1836
0
}
1837
1838
ssize_t fr_cbor_decode_pair(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dbuff_t *dbuff,
1839
          fr_dict_attr_t const *parent, bool tainted)
1840
0
{
1841
0
  return cbor_decode_pair(ctx, out, dbuff, parent, tainted, 0);
1842
0
}
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
 */