The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
base.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/**
18 * $Id: d454c7eb464e09b70f048bcb78657c0d7c4873aa $
19 *
20 * @file protocols/der/decode.c
21 * @brief Functions to decode DER encoded data.
22 *
23 * @author Ethan Thompson (ethan.thompson@inkbridge.io)
24 *
25 * @copyright (C) 2025 Network RADIUS SAS (legal@networkradius.com)
26 */
27RCSID("$Id: d454c7eb464e09b70f048bcb78657c0d7c4873aa $")
28
29#include <freeradius-devel/util/net.h>
30#include <freeradius-devel/util/proto.h>
31#include <freeradius-devel/util/table.h>
32#include <freeradius-devel/util/dict_ext_priv.h>
33
34#include "attrs.h"
35#include "der.h"
36
38
40//fr_dict_attr_t const *attr_oid_tree;
41
43fr_dict_autoload_t libfreeradius_der_dict[] = { { .out = &dict_der, .proto = "der" }, { NULL } };
44
47// { .out = &attr_oid_tree, .name = "OID-Tree", .type = FR_TYPE_TLV, .dict = &dict_der },
48 { NULL }
49};
50
52 { L("bitstring"), FR_DER_TAG_BITSTRING },
53 { L("bmpstring"), FR_DER_TAG_BMP_STRING },
54 { L("boolean"), FR_DER_TAG_BOOLEAN },
55 { L("choice"), FR_DER_TAG_CHOICE },
56 { L("enumerated"), FR_DER_TAG_ENUMERATED },
57 { L("generalizedtime"), FR_DER_TAG_GENERALIZED_TIME },
58 { L("generalstring"), FR_DER_TAG_GENERAL_STRING },
59 { L("ia5string"), FR_DER_TAG_IA5_STRING },
60 { L("integer"), FR_DER_TAG_INTEGER },
61 { L("null"), FR_DER_TAG_NULL },
62 { L("octetstring"), FR_DER_TAG_OCTETSTRING },
63 { L("oid"), FR_DER_TAG_OID },
64 { L("printablestring"), FR_DER_TAG_PRINTABLE_STRING },
65 { L("sequence"), FR_DER_TAG_SEQUENCE },
66 { L("set"), FR_DER_TAG_SET },
67 { L("t61string"), FR_DER_TAG_T61_STRING },
68 { L("universalstring"), FR_DER_TAG_UNIVERSAL_STRING },
69 { L("utctime"), FR_DER_TAG_UTC_TIME },
70 { L("utf8string"), FR_DER_TAG_UTF8_STRING },
71 { L("visiblestring"), FR_DER_TAG_VISIBLE_STRING },
72};
74
75
77{
78 return fr_table_str_by_value(tag_name_to_number, tag, "???");
79}
80
81#define ALL_STRINGS ((1 << FR_DER_TAG_BMP_STRING) | (1 << FR_DER_TAG_GENERAL_STRING) | \
82 (1 << FR_DER_TAG_IA5_STRING) | (1 << FR_DER_TAG_PRINTABLE_STRING) | \
83 (1 << FR_DER_TAG_T61_STRING) | (1 << FR_DER_TAG_UTF8_STRING) | \
84 (1 << FR_DER_TAG_VISIBLE_STRING))
85
98
100{
101 return (der_tags_compatible[tag1] & (1 << (uint64_t) tag2)) != 0;
102}
103
104/*
105 * Create a mapping between FR_TYPE_* and valid FR_DER_TAG_*'s
106 */
107static const bool *fr_type_to_der_tags[FR_DER_TAG_MAX] = {
108 [FR_TYPE_IPV4_ADDR] = (bool [FR_DER_TAG_MAX]) {
109 [FR_DER_TAG_BITSTRING] = true,
110 },
111
113 [FR_DER_TAG_BITSTRING] = true,
114 },
115
116 [FR_TYPE_IPV6_ADDR] = (bool [FR_DER_TAG_MAX]) {
117 [FR_DER_TAG_BITSTRING] = true,
118 },
119
121 [FR_DER_TAG_BITSTRING] = true,
122 },
123
125 [FR_DER_TAG_OCTETSTRING] = true,
126 },
127
128 [FR_TYPE_BOOL] = (bool [FR_DER_TAG_MAX]) {
129 [FR_DER_TAG_BOOLEAN] = true,
130 [FR_DER_TAG_INTEGER] = true,
131 [FR_DER_TAG_NULL] = true,
132 },
133 [FR_TYPE_INT64] = (bool [FR_DER_TAG_MAX]) {
134 [FR_DER_TAG_INTEGER] = true,
135 [FR_DER_TAG_ENUMERATED] = true,
136 },
137 [FR_TYPE_OCTETS] = (bool [FR_DER_TAG_MAX]) {
138 [FR_DER_TAG_BITSTRING] = true,
139 [FR_DER_TAG_OCTETSTRING] = true,
140 },
141 [FR_TYPE_STRING] = (bool [FR_DER_TAG_MAX]) {
142 [FR_DER_TAG_OID] = true,
143 [FR_DER_TAG_UTF8_STRING] = true,
145 [FR_DER_TAG_T61_STRING] = true,
146 [FR_DER_TAG_IA5_STRING] = true,
150 },
151 [FR_TYPE_DATE] = (bool [FR_DER_TAG_MAX]) {
152 [FR_DER_TAG_UTC_TIME] = true,
154 },
155 [FR_TYPE_TLV] = (bool [FR_DER_TAG_MAX]) {
156 [FR_DER_TAG_SEQUENCE] = true,
157 [FR_DER_TAG_SET] = true,
158 },
159 [FR_TYPE_STRUCT] = (bool [FR_DER_TAG_MAX]) {
160 [FR_DER_TAG_BITSTRING] = true,
161 },
162 [FR_TYPE_GROUP] = (bool [FR_DER_TAG_MAX]) {
163 [FR_DER_TAG_SEQUENCE] = true,
164 },
165};
166
167/*
168 * Return true if the given type can be encoded as the given tag.
169 * @param[in] type The fr_type to check.
170 * @param[in] tag The der tag to check.
171 * @return true if the type can be encoded as the given tag.
172 */
174{
175 if (!fr_type_to_der_tags[type]) return false;
176
177 return fr_type_to_der_tags[type][tag];
178}
179
180
182{
183 if (instance_count > 0) {
185 return 0;
186 }
187
189
191 fail:
193 return -1;
194 }
195
198 goto fail;
199 }
200
201 return 0;
202}
203
205{
206 if (--instance_count != 0) return;
207
209}
210
211/*
212 * Allow setting class of APPLICATION and PRIVATE.
213 */
214static int dict_flag_class(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
215{
216 static const fr_table_num_sorted_t table[] = {
217 { L("application"), FR_DER_CLASS_APPLICATION },
218 { L("private"), FR_DER_CLASS_PRIVATE },
219 };
220 static size_t table_len = NUM_ELEMENTS(table);
221
222 fr_der_attr_flags_t *flags;
223 fr_der_tag_class_t tag_class;
224
226 if (flags->der_type != FR_DER_TAG_SEQUENCE) {
227 fr_strerror_printf("Cannot use 'class' for attribute %s DER type %s - the parent must be 'sequence'",
228 (*da_p)->parent->name, fr_der_tag_to_str(flags->der_type));
229 return -1;
230 }
231
232 if ((*da_p)->attr >= FR_DER_TAG_VALUE_MAX) {
233 fr_strerror_printf("Cannot use 'class' for attribute %s - the attribute number must be 0..30",
234 (*da_p)->parent->name);
235 return -1;
236 }
237
239 if (flags->class) {
240 fr_strerror_printf("Attribute %s already has a 'class' defined", (*da_p)->name);
241 return -1;
242 }
243
245 if (tag_class == FR_DER_CLASS_INVALID) {
246 fr_strerror_printf("Unknown or invalid name in 'class=%s'", value);
247 return -1;
248 }
249
250 flags->class = tag_class;
251
252 return 0;
253}
254
256{
258
259 if (!fr_type_is_leaf((*da_p)->type)) {
260 fr_strerror_printf("Cannot set 'default=...' for attribute %s DER type %s",
261 (*da_p)->name, fr_der_tag_to_str(flags->der_type));
262 return -1;
263 }
264
265 /*
266 * The default values are parented from the dict root. That way we don't need to copy the values
267 * when we clone the attribute, we can just copy the pointer.
268 */
269 flags->default_value = fr_value_box_alloc(fr_dict_unconst((*da_p)->dict), (*da_p)->type, NULL);
270 if (!flags->default_value) return -1;
271
272 if (fr_value_box_from_str(flags->default_value, flags->default_value, (*da_p)->type, NULL,
273 value, strlen(value), NULL) < 0) {
274 fr_strerror_printf("Failed parsing 'value=...' - %s", fr_strerror());
275 return -1;
276 }
277
278 flags->has_default_value = true;
279
280 return 0;
281}
282
283static int dict_flag_der_type(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
284{
286 fr_der_tag_t der_type;
287
289 if (der_type == FR_DER_TAG_INVALID) {
290 fr_strerror_printf("Unknown type in 'der_type=%s'", value);
291 return -1;
292 }
293
294 /*
295 * The DER type and FreeRADIUS type must be compatible.
296 *
297 * Except for some der_type=integer, such as a
298 * certificate serialNumber. Those are too large for us
299 * to represent in 64 bits, so we just treat them as
300 * 'octets'.
301 */
302 if (!fr_type_to_der_tag_valid((*da_p)->type, der_type) &&
303 (der_type != FR_DER_TAG_INTEGER) && ((*da_p)->type != FR_TYPE_OCTETS)) {
304 fr_strerror_printf("Attribute type %s is not compatible with 'der_type=%s'",
305 fr_type_to_str((*da_p)->type), value);
306 return -1;
307 }
308
309 flags->der_type = der_type;
310
311 return 0;
312}
313
315{
318
319 if (flags->is_set_of) {
320 fr_strerror_const("Cannot be both 'sequence_of=...' and 'set_of=...'");
321 return -1;
322 }
323
324 if (flags->der_type != FR_DER_TAG_SEQUENCE) {
325 fr_strerror_printf("Cannot use 'sequence_of=...' for DER type '%s'", fr_der_tag_to_str(flags->der_type));
326 return -1;
327 }
328
329 if (strcmp(value, "oid_and_value") == 0) {
330 flags->is_oid_and_value = true;
331 flags->is_sequence_of = true;
332 flags->sequence_of = FR_DER_TAG_SEQUENCE;
333 return fr_dict_attr_set_group(da_p);
334 }
335
337 if (type == FR_DER_TAG_INVALID) {
338 fr_strerror_printf("Unknown type in 'sequence_of=%s'", value);
339 return -1;
340 }
341
342 flags->sequence_of = type;
343 flags->is_sequence_of = true;
344
345 return 0;
346}
347
348static int dict_flag_set_of(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
349{
352
353 if (flags->is_sequence_of) {
354 fr_strerror_const("Cannot be both 'sequence_of=...' and 'set_of=...'");
355 return -1;
356 }
357
358 if (flags->der_type != FR_DER_TAG_SET) {
359 fr_strerror_printf("Cannot use 'set_of=...' for DER type '%s'", fr_der_tag_to_str(flags->der_type));
360 return -1;
361 }
362
363 if (strcmp(value, "oid_and_value") == 0) {
364 flags->is_oid_and_value = true;
365 flags->is_sequence_of = true;
366 flags->sequence_of = FR_DER_TAG_SEQUENCE;
367 return fr_dict_attr_set_group(da_p);
368 }
369
371 if (type == FR_DER_TAG_INVALID) {
372 fr_strerror_printf("Unknown type in 'set_of=%s'", value);
373 return -1;
374 }
375
376 /*
377 * The "choice" can only be used for sequence.
378 */
379 if (type == FR_DER_TAG_CHOICE) {
380 fr_strerror_printf("Invalid type in 'set_of=%s' - 'choice' can only be used for sequences", value);
381 return -1;
382 }
383
384 flags->set_of = type;
385 flags->is_set_of = true;
386
387 return 0;
388}
389
391{
393
394 flags->is_extensions = true;
395
396 return 0;
397}
398
400{
402
403 /*
404 * is_oid_leaf is perhaps better as a property of the _parent_ sequence. It ensures that we only
405 * walk through the sequences children once.
406 */
407 if (fr_der_flag_der_type((*da_p)->parent) != FR_DER_TAG_SEQUENCE) {
408 fr_strerror_printf("Cannot set 'is_oid_leaf' for parent %s of DER type %s",
409 (*da_p)->parent->name, fr_der_tag_to_str(fr_der_flag_der_type((*da_p)->parent)));
410 return -1;
411 }
412
413 flags->is_oid_leaf = true;
414
415 return 0;
416}
417
418/*
419 * size=MIN..MAX
420 */
421static int dict_flag_size(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
422{
424 unsigned long num;
425 char const *p = value;
426 char *end = NULL;
427
428 if (fr_type_is_leaf((*da_p)->type) && !fr_type_is_variable_size((*da_p)->type)) {
429 fr_strerror_printf("Cannot use 'size=...' for type '%s'", fr_type_to_str((*da_p)->type));
430 return -1;
431 }
432
433 /*
434 * size=..max
435 */
436 if ((p[0] == '.') && (p[1] == '.')) goto check_max;
437
438 num = strtoul(p, &end, 10);
439 if (num == ULONG_MAX) {
440 invalid:
441 fr_strerror_printf("Invalid value in 'size=%s'", value);
442 return -1;
443 }
444
445 if (num > UINT8_MAX) {
446 fr_strerror_printf("Invalid value in 'size=%s' - 'min' value is too large", value);
447 return -1;
448 }
449
450 /*
451 * size=4
452 *
453 * Fixed size, but not size=0.
454 */
455 if (!*end) {
456 if (!num) goto invalid;
457
458 /*
459 * printablestring size=2
460 *
461 * instead of string[2] der_type=printablestring
462 */
463 if (((*da_p)->type == FR_TYPE_OCTETS) || ((*da_p)->type == FR_TYPE_STRING)) {
464 (*da_p)->flags.is_known_width = !fr_type_is_structural((*da_p)->type);
465 (*da_p)->flags.length = num;
466 return 0;
467 }
468
469 /*
470 * Sets and sequences can have a fixed number of elements.
471 */
472 flags->min = flags->max = num;
473 return 0;
474 }
475
476 if ((end[0] != '.') || (end[1] != '.')) {
477 fr_strerror_printf("Invalid value in 'size=%s' - unexpected data after 'min'", value);
478 return -1;
479 }
480
481 flags->min = num;
482
483 /*
484 * size=1..
485 *
486 * Sets the minimum, but not the maximum.
487 */
488 p = end + 2;
489 if (!*p) return 0;
490
491check_max:
492 num = strtoul(p, &end, 10);
493 if (num == ULONG_MAX) goto invalid;
494
495 if (*end) {
496 fr_strerror_printf("Invalid value in 'size=%s' - unexpected data after 'max'", value);
497 return -1;
498 }
499
500 flags->max = num;
501
502 return 0;
503}
504
505static int dict_flag_max(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
506{
508 unsigned long num;
509 char *end = NULL;
510
511 num = strtoul(value, &end, 10);
512 if (*end || !num || (num == ULONG_MAX)) {
513 fr_strerror_printf("Invalid value in 'max=%s'", value);
514 return -1;
515 }
516
517 flags->max = num;
518
519 return 0;
520}
521
522static int dict_flag_option(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
523{
524 fr_der_attr_flags_t *flags;
525 unsigned long num;
526 char *end = NULL;
527
528 /*
529 * Only SET and SEQUENCE can have tagged types.
530 */
532 if (!(*da_p)->parent->flags.is_root &&
533 (flags->der_type != FR_DER_TAG_SEQUENCE) && (flags->der_type != FR_DER_TAG_SET)) {
534 fr_strerror_printf("Cannot use 'option' for attribute %s DER type %s - the parent must be 'sequence' or 'set'",
535 (*da_p)->parent->name, fr_der_tag_to_str(flags->der_type));
536 return -1;
537 }
538
539 /*
540 * In the interest of laziness, allow a bare 'option', so
541 * that we don't have to give an attribute number, and
542 * then also duplicate that number in 'option='.
543 */
544 if (!value) {
545 if (!(*da_p)->state.attr_set || (*da_p)->attr > 0x1f) {
546 fr_strerror_printf("Missing value for 'option='");
547 return -1;
548 }
549
550 num = (*da_p)->attr;
551 goto check;
552 }
553
554 /*
555 * ATTRIBUTE can't have 'option='.
556 */
557 if ((*da_p)->state.attr_set) {
558 fr_strerror_printf("Cannot use 'option=%s' for attribute %s, just use 'option'", value, (*da_p)->name);
559 return -1;
560 }
561
562 /*
563 * We limit the allowed options (tag numbers) to ones
564 * which fit into the 5 bits of the first byte. We don't
565 * support continued tags.
566 */
567 num = strtoul(value, &end, 10);
568 if ((num == ULONG_MAX) || *end) {
569 fr_strerror_printf("Invalid value in 'option=%s'", value);
570 return -1;
571 }
572
573check:
574 if (num >= FR_DER_TAG_VALUE_MAX) {
575 fr_strerror_printf("Option value '%lu' is larger than 30", num);
576 return -1;
577 }
578
581 flags->option = num;
582 flags->is_option = true;
583
584 return 0;
585}
586
588{
589 fr_der_attr_flags_t *flags;
590
591 /*
592 * Only SET and SEQUENCE can have optional elements.
593 */
595 if (!(*da_p)->parent->flags.is_root &&
596 (flags->der_type != FR_DER_TAG_SEQUENCE) && (flags->der_type != FR_DER_TAG_SET)) {
597 fr_strerror_printf("Cannot use 'optional' for attribute %s DER type %s - the parent must be 'sequence' or 'set'",
598 (*da_p)->parent->name, fr_der_tag_to_str(flags->der_type));
599 return -1;
600 }
601
603 flags->optional = true;
604
605 return 0;
606}
607
609 { L("class"), { .func = dict_flag_class } },
610 { L("default"), { .func = dict_flag_default_value,.needs_value = true } },
611 { L("der_type"), { .func = dict_flag_der_type, .needs_value = true } },
612 { L("is_extensions"), { .func = dict_flag_is_extensions } },
613 { L("is_oid_leaf"), { .func = dict_flag_is_oid_leaf } },
614 { L("max"), { .func = dict_flag_max, .needs_value = true } },
615 { L("option"), { .func = dict_flag_option} },
616 { L("optional"), { .func = dict_flag_optional} },
617 { L("sequence_of"), { .func = dict_flag_sequence_of, .needs_value = true } },
618 { L("set_of"), { .func = dict_flag_set_of, .needs_value = true } },
619 { L("size"), { .func = dict_flag_size, .needs_value=true } },
620};
621
622static bool type_parse(fr_type_t *type_p,fr_dict_attr_t **da_p, char const *name)
623{
624 static const fr_table_num_sorted_t type_table[] = {
625 { L("bitstring"), FR_TYPE_OCTETS },
626// { L("bmpstring"), FR_TYPE_OCTETS },
627 { L("boolean"), FR_TYPE_BOOL },
628 { L("choice"), FR_TYPE_TLV },
629 { L("enumerated"), FR_TYPE_INT64 },
630 { L("generalizedtime"), FR_TYPE_DATE },
631 { L("generalstring"), FR_TYPE_STRING },
632 { L("ia5string"), FR_TYPE_STRING },
633 { L("integer"), FR_TYPE_INT64 },
634 { L("null"), FR_TYPE_BOOL },
635 { L("octetstring"), FR_TYPE_OCTETS },
636 { L("oid"), FR_TYPE_STRING },
637 { L("printablestring"), FR_TYPE_STRING },
638 { L("sequence"), FR_TYPE_TLV },
639 { L("set"), FR_TYPE_TLV },
640 { L("t61string"), FR_TYPE_STRING },
641 { L("universalstring"), FR_TYPE_STRING },
642 { L("utctime"), FR_TYPE_DATE },
643 { L("utf8string"), FR_TYPE_STRING },
644 { L("visiblestring"), FR_TYPE_STRING },
645 { L("x509_extensions"), FR_TYPE_GROUP }
646 };
647 static size_t type_table_len = NUM_ELEMENTS(type_table);
648
649 static const fr_table_num_sorted_t der_tag_table[] = {
650 { L("bitstring"), FR_DER_TAG_BITSTRING },
651// { L("bmpstring"), FR_DER_TAG_BMP_STRING },
652 { L("boolean"), FR_DER_TAG_BOOLEAN },
653 { L("choice"), FR_DER_TAG_SEQUENCE },
654 { L("enumerated"), FR_DER_TAG_ENUMERATED },
655 { L("generalizedtime"), FR_DER_TAG_GENERALIZED_TIME },
656 { L("generalstring"), FR_DER_TAG_GENERAL_STRING },
657 { L("ia5string"), FR_DER_TAG_IA5_STRING },
658 { L("integer"), FR_DER_TAG_INTEGER },
659 { L("null"), FR_DER_TAG_NULL },
660 { L("octetstring"), FR_DER_TAG_OCTETSTRING },
661 { L("oid"), FR_DER_TAG_OID },
662 { L("printablestring"), FR_DER_TAG_PRINTABLE_STRING },
663 { L("sequence"), FR_DER_TAG_SEQUENCE },
664 { L("set"), FR_DER_TAG_SET },
665 { L("t61string"), FR_DER_TAG_T61_STRING },
666 { L("universalstring"), FR_DER_TAG_UNIVERSAL_STRING },
667 { L("utctime"), FR_DER_TAG_UTC_TIME },
668 { L("utf8string"), FR_DER_TAG_UTF8_STRING },
669 { L("visiblestring"), FR_DER_TAG_VISIBLE_STRING },
670 { L("x509_extensions"), FR_DER_TAG_SEQUENCE }
671 };
672 static size_t der_tag_table_len = NUM_ELEMENTS(der_tag_table);
673
675 fr_der_tag_t der_type;
676 fr_type_t fr_type;
677
678 /*
679 * To avoid confusion, we want to use the DER names where
680 * possible.
681 *
682 * We only use the FreeRADIUS names where we don't have a
683 * choice. :(
684 */
685 switch (*type_p) {
686 case FR_TYPE_TLV:
687 fr_strerror_const("Cannot use 'tlv' in DER. Please use 'sequence'");
688 return false;
689
690 case FR_TYPE_IFID:
692 case FR_TYPE_ETHERNET:
693 case FR_TYPE_FLOAT32:
694 case FR_TYPE_FLOAT64:
695 case FR_TYPE_VSA:
696 case FR_TYPE_VENDOR:
698 case FR_TYPE_VOID:
699 case FR_TYPE_MAX:
700 fr_strerror_printf("Cannot use type '%s' in the DER dictionaries",
701 fr_type_to_str(*type_p));
702 return false;
703
704 /*
705 * We allow integers for now. They may be
706 * internal, or they may be inside of a struct.
707 */
708 default:
709 break;
710 }
711
712 /*
713 * Convert the DER data type to the underlying FreeRADIUS
714 * data type.
715 *
716 * If we don't know anything about the data type then
717 * it's either bad, or a data type which we don't care
718 * about. We set the der_type, and then return to the
719 * caller. It will check *type_p, which is likely
720 * FR_TYPE_NULL, and will print an error.
721 *
722 * "return true" here means "I dunno, you deal with it".
723 */
724 fr_type = fr_table_value_by_str(type_table, name, FR_TYPE_MAX);
725 if (fr_type == FR_TYPE_MAX) {
726 flags->der_type = fr_type_to_der_tag_default(*type_p);
727 return true;
728 }
729
730 /*
731 * Now that we've converted the DER type to the
732 * underlying FreeRADIUS type, we get the corresponding
733 * DER type. This MUST exist, as the two tables MUST
734 * have the same names.
735 *
736 * @todo - arguably they should be in one table....
737 */
738 der_type = fr_table_value_by_str(der_tag_table, name, FR_DER_TAG_INVALID);
739 fr_assert(der_type != FR_DER_TAG_INVALID);
740
741 /*
742 * The der type is set only if there are extra flags seen
743 * and parsed by attr_valid().
744 */
746
747 /*
748 * Only now do we update the output data type. From here
749 * on in, any validation failure will return 'false', and
750 * not 'true'.
751 */
752 *type_p = fr_type;
753 flags->der_type = der_type;
754
755 /*
756 * If it is a collection of x509 extensions, we will set
757 * a few other flags as per RFC 5280.
758 */
759 if (strcmp(name, "x509_extensions") == 0) {
760 flags->is_extensions = true;
761
763 flags->option = 3;
764 flags->is_option = true;
765
766 flags->is_sequence_of = true;
767 flags->sequence_of = FR_DER_TAG_SEQUENCE;
768 }
769
770 /*
771 * If this is a choice, then the children MUST have a limited option.
772 */
773 flags->is_choice = (strcmp(name, "choice") == 0);
774
775 return true;
776}
777
804
809
811{
814
815 /*
816 * sequence_of=oid_and_value has to have a reference to the OID tree.
817 *
818 * Group refs are added as unresolved refs, see dict_flag_ref(), and are resolved later
819 * in dict_fixup_group_apply().
820 *
821 * @todo - have a function called from dict_attr_finalize() ?
822 */
823#if 0
824 if (flags->is_oid_and_value) {
825 fr_dict_attr_t const *ref;
826
827 fr_assert(da->type == FR_TYPE_GROUP);
828
829 if (!fr_dict_attr_ref(da)) {
830 (void) dict_attr_ref_set(da, attr_oid_tree, FR_DICT_ATTR_REF_ALIAS);
831 }
832 }
833#endif
834
835 if (flags->is_choice && unlikely(!fr_type_is_tlv(da->type))) {
836 fr_strerror_printf("Attribute %s of type %s is not allowed represent a collection of choices.",
837 da->name, fr_type_to_str(da->type));
838 return false;
839 }
840
841 /*
842 * The DER encoder / decoder assume that all pairs are FR_TYPE_INT64.
843 *
844 * The "on the wire" DER data has variable-sized encoding for integers,
845 * and drops leading zeros.
846 *
847 * For consistency, we disallow data types which the
848 * encoder/decoder don't handle. Except for data types
849 * in structs, because the struct encoder/decoder takes
850 * care of those.
851 */
852 if (fr_type_is_integer_except_bool(da->type) &&
853 !da->flags.internal &&
854 (da->type != FR_TYPE_INT64) &&
855 (da->type != FR_TYPE_DATE) && (da->type != FR_TYPE_TIME_DELTA) &&
856 (da->parent->type != FR_TYPE_STRUCT)) {
857 fr_strerror_printf("All integers in DER must be 'int64', and not '%s'",
858 fr_type_to_str(da->type));
859 return false;
860 }
861
862 if (flags->is_extensions) {
863 if (da->type != FR_TYPE_GROUP) {
864 fr_strerror_printf("Extensions must be type 'group', and not '%s'",
865 fr_type_to_str(da->type));
866 return false;
867 }
868
869#if 0
870 /*
871 * Group refs are added as unresolved refs, see dict_flag_ref(), and are resolved later
872 * in dict_fixup_group_apply().
873 *
874 * @todo - have a function called from dict_attr_finalize() ?
875 */
876 if (!fr_dict_attr_ref(da)) {
877 fr_strerror_const("Attribute is 'x509_extensions', but is missing 'ref=OID-Tree'");
878 return false;
879 }
880#endif
881
882 /*
883 * Avoid run-time checks.
884 */
885 if (!flags->max) flags->max = UINT64_MAX;
886 }
887
888 /*
889 * Either complain on invalid 'max', or set it to the maximum.
890 */
891 if ((flags->der_type != FR_DER_TAG_SET) && (flags->der_type != FR_DER_TAG_SEQUENCE)) {
892 if (!flags->max) {
893 flags->max = DER_MAX_STR;
894
895 } else if (flags->max > DER_MAX_STR) {
896 fr_strerror_printf("Invalid value of 'max' for DER type '%s'",
898 return false;
899 }
900 }
901
902 /*
903 * Set the restriction types, which make the run-time decoding a lot easier.
904 */
905 if (flags->is_set_of) {
906 flags->restrictions = (1 << flags->set_of);
907 }
908
909 if (flags->is_sequence_of) {
910 /*
911 * If the sequence isn't a choice, it has to be a sequence of one thing.
912 *
913 * If the sequence is group, then it has to be a sequence of sequences.
914 *
915 * If the sequence is a TLV, then the children will update the restrictions.
916 */
917 if (flags->sequence_of != FR_DER_TAG_CHOICE) {
918 flags->restrictions = (1 << flags->sequence_of);
919
920 } else if (da->type == FR_TYPE_GROUP) {
921#ifndef NDEBUG
922 fr_dict_attr_t const *ref;
923
924 ref = fr_dict_attr_ref(da);
925 if (ref) {
927 }
928#endif
929
930 /*
931 * A group of choices is really a sequence of sequences. i.e. x509extensions
932 * contain only a sequence, as does sequence_of=oid_and_value.
933 */
934 flags->restrictions = (1 << FR_DER_TAG_SEQUENCE);
935
936 } else {
937 /*
938 * The children will update our restriction types.
939 */
940 fr_assert(da->type == FR_TYPE_TLV);
941 }
942 }
943
944 /*
945 * If the parent is a choice, then the child MUST have a limited set of options / tags.
946 */
948
949 /*
950 * The attribute was defined with the full OID, and no 'option' flag. Add it manually.
951 */
952 if ((parent->is_choice && !flags->is_option) ||
953 (flags->class == FR_DER_CLASS_PRIVATE) || (flags->class == FR_DER_CLASS_APPLICATION)) {
955
956 if (!flags->class) flags->class = FR_DER_CLASS_CONTEXT;
957 flags->option = da->attr;
958 flags->is_option = true;
959 }
960
961 /*
962 * Can't have duplicates.
963 */
964 if (flags->is_option) {
965 if ((parent->restrictions & (1 << flags->option)) != 0) {
966 fr_strerror_printf("Parent %s already has a child with option %u - duplicates are not allowed",
967 da->parent->name, flags->option);
968 return false;
969 }
970
971 parent->restrictions |= (1 << flags->option);
972
973 } else if (parent->is_sequence_of && (parent->sequence_of == FR_DER_TAG_CHOICE)) {
975
977// flags->option = flags->der_type;
978
979 if ((parent->restrictions & (1 << flags->der_type)) != 0) {
980 fr_strerror_printf("Parent %s already has a child with tag %s - duplicates are not allowed",
981 da->parent->name, fr_der_tag_to_str(flags->der_type));
982 return false;
983 }
984
985 parent->restrictions |= (1 << flags->der_type);
986
987 } else if (parent->is_sequence_of) {
988 if (flags->der_type != parent->sequence_of) {
989 fr_strerror_printf("Parent %s is a sequence_of=%s - a child cannot be %s",
990 da->parent->name, fr_der_tag_to_str(parent->set_of),
992 return false;
993 }
994
995 /*
996 * A sequence can sometimes have mixed tags && options.
997 */
998 fr_assert(!flags->is_option);
999
1000 } else if (parent->is_set_of) {
1001 if (flags->der_type != parent->set_of) {
1002 fr_strerror_printf("Parent %s is a set_of=%s - a child cannot be %s",
1003 da->parent->name, fr_der_tag_to_str(parent->set_of),
1004 fr_der_tag_to_str(flags->der_type));
1005 return false;
1006 }
1007 }
1008
1009 return true;
1010}
1011
1014 .name = "der",
1015 .default_type_size = 4,
1016 .default_type_length = 4,
1017 .attr = {
1018 .flags = {
1019 .table = der_flags,
1020 .table_len = NUM_ELEMENTS(der_flags),
1021 .len = sizeof(fr_der_attr_flags_t),
1022 },
1023 .type_parse = type_parse,
1024 .valid = attr_valid
1025 },
1026
1027 .init = fr_der_global_init,
1028 .free = fr_der_global_free,
1029
1030 // .decode = fr_der_decode_foreign,
1031 // .encode = fr_der_encode_foreign,
1032};
#define RCSID(id)
Definition build.h:485
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
#define NUM_ELEMENTS(_t)
Definition build.h:339
fr_der_tag_t
Enumeration describing the data types in a DER encoded structure.
Definition der.h:34
@ FR_DER_TAG_IA5_STRING
String of IA5 (7bit) chars.
Definition der.h:48
@ FR_DER_TAG_SEQUENCE
A sequence of DER encoded data (a structure).
Definition der.h:44
@ FR_DER_TAG_SET
A set of DER encoded data (a structure).
Definition der.h:45
@ FR_DER_TAG_BMP_STRING
String of BMP chars.
Definition der.h:54
@ FR_DER_TAG_INTEGER
Arbitrary width signed integer.
Definition der.h:37
@ FR_DER_TAG_BOOLEAN
Boolean true/false.
Definition der.h:36
@ FR_DER_TAG_CHOICE
A choice of types. Techically not a DER tag, but used to represent a choice.
Definition der.h:56
@ FR_DER_TAG_UTF8_STRING
String of UTF8 chars.
Definition der.h:43
@ FR_DER_TAG_UTC_TIME
A time in UTC "YYMMDDhhmmssZ" format.
Definition der.h:49
@ FR_DER_TAG_GENERALIZED_TIME
A time in "YYYYMMDDHHMMSS[.fff]Z" format.
Definition der.h:50
@ FR_DER_TAG_INVALID
Invalid tag.
Definition der.h:35
@ FR_DER_TAG_NULL
An empty value.
Definition der.h:40
@ FR_DER_TAG_OCTETSTRING
String of octets (length field specifies bytes).
Definition der.h:39
@ FR_DER_TAG_VISIBLE_STRING
String of visible chars.
Definition der.h:51
@ FR_DER_TAG_BITSTRING
String of bits (length field specifies bits).
Definition der.h:38
@ FR_DER_TAG_T61_STRING
String of T61 (8bit) chars.
Definition der.h:47
@ FR_DER_TAG_ENUMERATED
An enumerated value.
Definition der.h:42
@ FR_DER_TAG_UNIVERSAL_STRING
String of universal chars.
Definition der.h:53
@ FR_DER_TAG_PRINTABLE_STRING
String of printable chars.
Definition der.h:46
@ FR_DER_TAG_GENERAL_STRING
String of general chars.
Definition der.h:52
@ FR_DER_TAG_OID
Reference to an OID based attribute.
Definition der.h:41
@ FR_DER_TAG_MAX
Definition der.h:58
bool optional
optional, we MUST already have set 'option'
Definition der.h:106
bool is_extensions
a list of X.509 extensions
Definition der.h:110
#define fr_der_flag_der_type(_da)
Definition der.h:128
fr_der_tag_t der_type
the DER type, which is different from the FreeRADIUS type
Definition der.h:95
bool is_option
has an option defined
Definition der.h:105
bool is_sequence_of
sequence_of has been defined
Definition der.h:107
bool is_set_of
set_of has been defined
Definition der.h:108
uint32_t restrictions
for choice of options and tags - no dups allowed
Definition der.h:102
#define DER_MAX_STR
Definition der.h:76
uint8_t min
mininum count
Definition der.h:103
bool is_oid_and_value
is OID+value
Definition der.h:109
bool is_choice
DER name "choice".
Definition der.h:113
#define FR_DER_TAG_VALUE_MAX
tags >=max can't exist
Definition der.h:61
uint8_t option
an "attribute number" encoded in the tag field.
Definition der.h:104
bool has_default_value
a default value exists
Definition der.h:111
fr_der_tag_class_t class
tag Class
Definition der.h:94
uint64_t max
maximum count of items in a sequence, set, or string.
Definition der.h:101
fr_der_tag_class_t
Definition der.h:68
@ FR_DER_CLASS_APPLICATION
Definition der.h:70
@ FR_DER_CLASS_CONTEXT
Definition der.h:71
@ FR_DER_CLASS_INVALID
Definition der.h:73
@ FR_DER_CLASS_PRIVATE
Definition der.h:72
fr_dict_t * fr_dict_unconst(fr_dict_t const *dict)
Coerce to non-const.
Definition dict_util.c:4629
#define fr_dict_autofree(_to_free)
Definition dict.h:870
int fr_dict_attr_set_group(fr_dict_attr_t **da_p)
Definition dict_util.c:5023
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:287
int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
Definition dict_util.c:4134
@ FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC
Protocol specific extensions.
Definition dict.h:177
#define fr_dict_autoload(_to_load)
Definition dict.h:867
char const * name
name of this protocol
Definition dict.h:435
Specifies an attribute which must be present for the module to function.
Definition dict.h:273
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:286
Protocol specific custom flag definitnion.
Definition dict.h:404
Protocol-specific callbacks in libfreeradius-PROTOCOL.
Definition dict.h:434
static void * fr_dict_attr_ext(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
Definition dict_ext.h:140
static fr_dict_attr_t const * fr_dict_attr_ref(fr_dict_attr_t const *da)
Return the reference associated with a group type attribute.
Definition dict_ext.h:184
@ FR_DICT_ATTR_REF_ALIAS
The attribute is an alias for another attribute.
Definition dict_ext.h:60
static int dict_attr_ref_set(fr_dict_attr_t const *da, fr_dict_attr_t const *ref, fr_dict_attr_ref_type_t type)
Test enumeration values.
Definition dict_test.h:92
static uint32_t instance_count
Definition base.c:44
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_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_COMBO_IP_PREFIX
IPv4 or IPv6 address prefix depending on length.
@ FR_TYPE_VALUE_BOX
A boxed value.
@ 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_VOID
User data.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
@ FR_TYPE_IFID
Interface ID.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
@ FR_TYPE_FLOAT64
Double precision floating point.
unsigned int uint32_t
#define UINT8_MAX
static int dict_flag_is_oid_leaf(fr_dict_attr_t **da_p, UNUSED char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
Definition base.c:399
static int dict_flag_optional(fr_dict_attr_t **da_p, UNUSED char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
Definition base.c:587
bool fr_der_tags_compatible(fr_der_tag_t tag1, fr_der_tag_t tag2)
Definition base.c:99
#define ALL_STRINGS
Definition base.c:81
void fr_der_global_free(void)
Definition base.c:204
static const uint64_t der_tags_compatible[FR_DER_TAG_MAX]
Definition base.c:86
static const fr_dict_flag_parser_t der_flags[]
Definition base.c:608
static int dict_flag_der_type(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
Definition base.c:283
static int dict_flag_max(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
Definition base.c:505
static const fr_der_tag_t fr_type_to_der_tag_defaults[FR_TYPE_MAX+1]
Definition base.c:778
static int dict_flag_sequence_of(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
Definition base.c:314
static int dict_flag_default_value(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
Definition base.c:255
int fr_der_global_init(void)
Definition base.c:181
static int dict_flag_class(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
Definition base.c:214
fr_dict_protocol_t libfreeradius_der_dict_protocol
Definition base.c:1013
bool fr_type_to_der_tag_valid(fr_type_t type, fr_der_tag_t tag)
Definition base.c:173
static bool type_parse(fr_type_t *type_p, fr_dict_attr_t **da_p, char const *name)
Definition base.c:622
static int dict_flag_set_of(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
Definition base.c:348
fr_dict_attr_autoload_t libfreeradius_der_dict_attr[]
Definition base.c:46
static int dict_flag_is_extensions(fr_dict_attr_t **da_p, UNUSED char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
Definition base.c:390
fr_der_tag_t fr_type_to_der_tag_default(fr_type_t type)
Definition base.c:805
char const * fr_der_tag_to_str(fr_der_tag_t tag)
Definition base.c:76
static int dict_flag_option(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
Definition base.c:522
fr_dict_autoload_t libfreeradius_der_dict[]
Definition base.c:43
static size_t tag_name_to_number_len
Definition base.c:73
static const bool * fr_type_to_der_tags[FR_DER_TAG_MAX]
Definition base.c:107
fr_dict_t const * dict_der
Definition base.c:39
static fr_table_num_sorted_t const tag_name_to_number[]
Definition base.c:51
static int dict_flag_size(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
Definition base.c:421
static bool attr_valid(fr_dict_attr_t *da)
Definition base.c:443
VQP attributes.
#define fr_assert(_expr)
Definition rad_assert.h:38
static char const * name
fr_aka_sim_id_type_t type
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition table.h:653
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:772
An element in a lexicographically sorted array of name to num mappings.
Definition table.h:49
static fr_slen_t parent
Definition pair.h:839
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:553
#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_variable_size(_x)
Definition types.h:384
#define fr_type_is_structural(_x)
Definition types.h:388
#define fr_type_is_integer_except_bool(_x)
Definition types.h:376
#define fr_type_is_tlv(_x)
Definition types.h:368
#define fr_type_is_leaf(_x)
Definition types.h:389
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:450
ssize_t fr_value_box_from_str(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, char const *in, size_t inlen, fr_sbuff_unescape_rules_t const *erules)
Definition value.c:5459
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:640