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: b40d355d46838505f4beb6adcc88a8a79400ce97 $
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: b40d355d46838505f4beb6adcc88a8a79400ce97 $")
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
41
48
54
56 { L("bitstring"), FR_DER_TAG_BITSTRING },
57 { L("bmpstring"), FR_DER_TAG_BMP_STRING },
58 { L("boolean"), FR_DER_TAG_BOOLEAN },
59 { L("choice"), FR_DER_TAG_CHOICE },
60 { L("enumerated"), FR_DER_TAG_ENUMERATED },
61 { L("generalizedtime"), FR_DER_TAG_GENERALIZED_TIME },
62 { L("generalstring"), FR_DER_TAG_GENERAL_STRING },
63 { L("ia5string"), FR_DER_TAG_IA5_STRING },
64 { L("integer"), FR_DER_TAG_INTEGER },
65 { L("null"), FR_DER_TAG_NULL },
66 { L("octetstring"), FR_DER_TAG_OCTETSTRING },
67 { L("oid"), FR_DER_TAG_OID },
68 { L("printablestring"), FR_DER_TAG_PRINTABLE_STRING },
69 { L("sequence"), FR_DER_TAG_SEQUENCE },
70 { L("set"), FR_DER_TAG_SET },
71 { L("t61string"), FR_DER_TAG_T61_STRING },
72 { L("universalstring"), FR_DER_TAG_UNIVERSAL_STRING },
73 { L("utctime"), FR_DER_TAG_UTC_TIME },
74 { L("utf8string"), FR_DER_TAG_UTF8_STRING },
75 { L("visiblestring"), FR_DER_TAG_VISIBLE_STRING },
76};
78
79
81{
82 return fr_table_str_by_value(tag_name_to_number, tag, "???");
83}
84
85#define ALL_STRINGS ((1 << FR_DER_TAG_BMP_STRING) | (1 << FR_DER_TAG_GENERAL_STRING) | \
86 (1 << FR_DER_TAG_IA5_STRING) | (1 << FR_DER_TAG_PRINTABLE_STRING) | \
87 (1 << FR_DER_TAG_T61_STRING) | (1 << FR_DER_TAG_UTF8_STRING) | \
88 (1 << FR_DER_TAG_VISIBLE_STRING))
89
102
104{
105 return (der_tags_compatible[tag1] & (1 << (uint64_t) tag2)) != 0;
106}
107
108/*
109 * Create a mapping between FR_TYPE_* and valid FR_DER_TAG_*'s
110 */
111static const bool *fr_type_to_der_tags[FR_DER_TAG_MAX] = {
112 [FR_TYPE_IPV4_ADDR] = (bool [FR_DER_TAG_MAX]) {
113 [FR_DER_TAG_BITSTRING] = true,
114 },
115
117 [FR_DER_TAG_BITSTRING] = true,
118 },
119
120 [FR_TYPE_IPV6_ADDR] = (bool [FR_DER_TAG_MAX]) {
121 [FR_DER_TAG_BITSTRING] = true,
122 },
123
125 [FR_DER_TAG_BITSTRING] = true,
126 },
127
129 [FR_DER_TAG_OCTETSTRING] = true,
130 },
131
132 [FR_TYPE_BOOL] = (bool [FR_DER_TAG_MAX]) {
133 [FR_DER_TAG_BOOLEAN] = true,
134 [FR_DER_TAG_INTEGER] = true,
135 [FR_DER_TAG_NULL] = true,
136 },
137 [FR_TYPE_INT64] = (bool [FR_DER_TAG_MAX]) {
138 [FR_DER_TAG_INTEGER] = true,
139 [FR_DER_TAG_ENUMERATED] = true,
140 },
141 [FR_TYPE_OCTETS] = (bool [FR_DER_TAG_MAX]) {
142 [FR_DER_TAG_BITSTRING] = true,
143 [FR_DER_TAG_OCTETSTRING] = true,
144 },
145 [FR_TYPE_STRING] = (bool [FR_DER_TAG_MAX]) {
146 [FR_DER_TAG_UTF8_STRING] = true,
148 [FR_DER_TAG_T61_STRING] = true,
149 [FR_DER_TAG_IA5_STRING] = true,
153 },
154 [FR_TYPE_DATE] = (bool [FR_DER_TAG_MAX]) {
155 [FR_DER_TAG_UTC_TIME] = true,
157 },
158 [FR_TYPE_ATTR] = (bool [FR_DER_TAG_MAX]) {
159 [FR_DER_TAG_OID] = true,
160 },
161 [FR_TYPE_TLV] = (bool [FR_DER_TAG_MAX]) {
162 [FR_DER_TAG_SEQUENCE] = true,
163 [FR_DER_TAG_SET] = true,
164 },
165 [FR_TYPE_STRUCT] = (bool [FR_DER_TAG_MAX]) {
166 [FR_DER_TAG_BITSTRING] = true,
167 },
168 [FR_TYPE_GROUP] = (bool [FR_DER_TAG_MAX]) {
169 [FR_DER_TAG_SEQUENCE] = true,
170 },
171};
172
173/*
174 * Return true if the given type can be encoded as the given tag.
175 * @param[in] type The fr_type to check.
176 * @param[in] tag The der tag to check.
177 * @return true if the type can be encoded as the given tag.
178 */
180{
181 if (!fr_type_to_der_tags[type]) return false;
182
183 return fr_type_to_der_tags[type][tag];
184}
185
186
188{
189 if (instance_count > 0) {
191 return 0;
192 }
193
195
197 fail:
199 return -1;
200 }
201
204 goto fail;
205 }
206
207 return 0;
208}
209
211{
212 if (--instance_count != 0) return;
213
215}
216
217/*
218 * Allow setting class of APPLICATION and PRIVATE.
219 */
220static int dict_flag_class(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
221{
222 static const fr_table_num_sorted_t table[] = {
223 { L("application"), FR_DER_CLASS_APPLICATION },
224 { L("private"), FR_DER_CLASS_PRIVATE },
225 };
226 static size_t table_len = NUM_ELEMENTS(table);
227
228 fr_der_attr_flags_t *flags;
229 fr_der_tag_class_t tag_class;
230
232 if (flags->der_type != FR_DER_TAG_SEQUENCE) {
233 fr_strerror_printf("Cannot use 'class' for attribute %s DER type %s - the parent must be 'sequence'",
234 (*da_p)->parent->name, fr_der_tag_to_str(flags->der_type));
235 return -1;
236 }
237
238 if ((*da_p)->attr >= FR_DER_TAG_VALUE_MAX) {
239 fr_strerror_printf("Cannot use 'class' for attribute %s - the attribute number must be 0..30",
240 (*da_p)->parent->name);
241 return -1;
242 }
243
245 if (flags->class) {
246 fr_strerror_printf("Attribute %s already has a 'class' defined", (*da_p)->name);
247 return -1;
248 }
249
251 if (tag_class == FR_DER_CLASS_INVALID) {
252 fr_strerror_printf("Unknown or invalid name in 'class=%s'", value);
253 return -1;
254 }
255
256 flags->class = tag_class;
257
258 return 0;
259}
260
262{
264
265 if (!fr_type_is_leaf((*da_p)->type)) {
266 fr_strerror_printf("Cannot set 'default=...' for attribute %s DER type %s",
267 (*da_p)->name, fr_der_tag_to_str(flags->der_type));
268 return -1;
269 }
270
271 /*
272 * The default values are parented from the dict root. That way we don't need to copy the values
273 * when we clone the attribute, we can just copy the pointer.
274 */
275 flags->default_value = fr_value_box_alloc(fr_dict_unconst((*da_p)->dict), (*da_p)->type, NULL);
276 if (!flags->default_value) return -1;
277
278 if (fr_value_box_from_str(flags->default_value, flags->default_value, (*da_p)->type, NULL,
279 value, strlen(value), NULL) < 0) {
280 fr_strerror_printf("Failed parsing 'value=...' - %s", fr_strerror());
281 return -1;
282 }
283
284 flags->has_default_value = true;
285
286 return 0;
287}
288
289static int dict_flag_der_type(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
290{
292 fr_der_tag_t der_type;
293
295 if (der_type == FR_DER_TAG_INVALID) {
296 fr_strerror_printf("Unknown type in 'der_type=%s'", value);
297 return -1;
298 }
299
300 /*
301 * The DER type and FreeRADIUS type must be compatible.
302 *
303 * Except for some der_type=integer, such as a
304 * certificate serialNumber. Those are too large for us
305 * to represent in 64 bits, so we just treat them as
306 * 'octets'.
307 */
308 if (!fr_type_to_der_tag_valid((*da_p)->type, der_type) &&
309 (der_type != FR_DER_TAG_INTEGER) && ((*da_p)->type != FR_TYPE_OCTETS)) {
310 fr_strerror_printf("Attribute type %s is not compatible with 'der_type=%s'",
311 fr_type_to_str((*da_p)->type), value);
312 return -1;
313 }
314
315 flags->der_type = der_type;
316
317 return 0;
318}
319
321{
322 flags->is_oid_and_value = true;
323 flags->is_sequence_of = true;
324 flags->sequence_of = FR_DER_TAG_SEQUENCE;
325
326 /*
327 * The dict autoload things aren't set until after we load all of the dictionary entries. So we
328 * just manually set it here for laziness.
329 */
330 if (!attr_oid_tree) {
331 attr_oid_tree = fr_dict_attr_by_name(NULL, fr_dict_root((*da_p)->dict), "OID-Tree");
332 if (!attr_oid_tree) return -1;
333 }
334
335 if (fr_dict_attr_set_group(da_p, attr_oid_tree) < 0) return -1;
336
337 (*da_p)->flags.allow_flat = true;
338 return 0;
339}
340
342{
345
346 if (flags->is_set_of) {
347 fr_strerror_const("Cannot be both 'sequence_of=...' and 'set_of=...'");
348 return -1;
349 }
350
351 if (flags->der_type != FR_DER_TAG_SEQUENCE) {
352 fr_strerror_printf("Cannot use 'sequence_of=...' for DER type '%s'", fr_der_tag_to_str(flags->der_type));
353 return -1;
354 }
355
356 if (strcmp(value, "oid_and_value") == 0) {
357 return dict_flag_set_oid_and_value(da_p, flags);
358 }
359
361 if (type == FR_DER_TAG_INVALID) {
362 fr_strerror_printf("Unknown type in 'sequence_of=%s'", value);
363 return -1;
364 }
365
366 flags->sequence_of = type;
367 flags->is_sequence_of = true;
368
369 return 0;
370}
371
372static int dict_flag_set_of(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
373{
376
377 if (flags->is_sequence_of) {
378 fr_strerror_const("Cannot be both 'sequence_of=...' and 'set_of=...'");
379 return -1;
380 }
381
382 if (flags->der_type != FR_DER_TAG_SET) {
383 fr_strerror_printf("Cannot use 'set_of=...' for DER type '%s'", fr_der_tag_to_str(flags->der_type));
384 return -1;
385 }
386
387 if (strcmp(value, "oid_and_value") == 0) {
388 return dict_flag_set_oid_and_value(da_p, flags);
389 }
390
392 if (type == FR_DER_TAG_INVALID) {
393 fr_strerror_printf("Unknown type in 'set_of=%s'", value);
394 return -1;
395 }
396
397 /*
398 * The "choice" can only be used for sequence.
399 */
400 if (type == FR_DER_TAG_CHOICE) {
401 fr_strerror_printf("Invalid type in 'set_of=%s' - 'choice' can only be used for sequences", value);
402 return -1;
403 }
404
405 flags->set_of = type;
406 flags->is_set_of = true;
407
408 return 0;
409}
410
412{
414
415 flags->is_extensions = true;
416
417 return 0;
418}
419
420static int dict_flag_leaf(fr_dict_attr_t **da_p, UNUSED char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
421{
423
424 /*
425 * The "leaf" property means that when we're encoding a nested set of attributes, we encode the
426 * OIDs until we hit one which has the "leaf" property set. We then encode the OID of this
427 * attribute, along with its value.
428 */
429 if (fr_der_flag_der_type((*da_p)->parent) != FR_DER_TAG_SEQUENCE) {
430 fr_strerror_printf("Cannot set 'leaf' for parent %s of DER type %s",
431 (*da_p)->parent->name, fr_der_tag_to_str(fr_der_flag_der_type((*da_p)->parent)));
432 return -1;
433 }
434
435 flags->leaf = true;
436
437 return 0;
438}
439
440/*
441 * size=MIN..MAX
442 */
443static int dict_flag_size(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
444{
446 unsigned long num;
447 char const *p = value;
448 char *end = NULL;
449
450 if (fr_type_is_leaf((*da_p)->type) && !fr_type_is_variable_size((*da_p)->type)) {
451 fr_strerror_printf("Cannot use 'size=...' for type '%s'", fr_type_to_str((*da_p)->type));
452 return -1;
453 }
454
455 /*
456 * size=..max
457 */
458 if ((p[0] == '.') && (p[1] == '.')) goto check_max;
459
460 num = strtoul(p, &end, 10);
461 if (num == ULONG_MAX) {
462 invalid:
463 fr_strerror_printf("Invalid value in 'size=%s'", value);
464 return -1;
465 }
466
467 if (num > UINT8_MAX) {
468 fr_strerror_printf("Invalid value in 'size=%s' - 'min' value is too large", value);
469 return -1;
470 }
471
472 /*
473 * size=4
474 *
475 * Fixed size, but not size=0.
476 */
477 if (!*end) {
478 if (!num) goto invalid;
479
480 /*
481 * printablestring size=2
482 *
483 * instead of string[2] der_type=printablestring
484 */
485 if (((*da_p)->type == FR_TYPE_OCTETS) || ((*da_p)->type == FR_TYPE_STRING)) {
486 (*da_p)->flags.is_known_width = !fr_type_is_structural((*da_p)->type);
487 (*da_p)->flags.length = num;
488 return 0;
489 }
490
491 /*
492 * Sets and sequences can have a fixed number of elements.
493 */
494 flags->min = flags->max = num;
495 return 0;
496 }
497
498 if ((end[0] != '.') || (end[1] != '.')) {
499 fr_strerror_printf("Invalid value in 'size=%s' - unexpected data after 'min'", value);
500 return -1;
501 }
502
503 flags->min = num;
504
505 /*
506 * size=1..
507 *
508 * Sets the minimum, but not the maximum.
509 */
510 p = end + 2;
511 if (!*p) return 0;
512
513check_max:
514 num = strtoul(p, &end, 10);
515 if (num == ULONG_MAX) goto invalid;
516
517 if (*end) {
518 fr_strerror_printf("Invalid value in 'size=%s' - unexpected data after 'max'", value);
519 return -1;
520 }
521
522 flags->max = num;
523
524 return 0;
525}
526
527static int dict_flag_max(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
528{
530 unsigned long num;
531 char *end = NULL;
532
533 num = strtoul(value, &end, 10);
534 if (*end || !num || (num == ULONG_MAX)) {
535 fr_strerror_printf("Invalid value in 'max=%s'", value);
536 return -1;
537 }
538
539 flags->max = num;
540
541 return 0;
542}
543
544static int dict_flag_option(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
545{
546 fr_der_attr_flags_t *flags;
547 unsigned long num;
548 char *end = NULL;
549
550 /*
551 * Only SET and SEQUENCE can have tagged types.
552 */
554 if (!(*da_p)->parent->flags.is_root &&
555 (flags->der_type != FR_DER_TAG_SEQUENCE) && (flags->der_type != FR_DER_TAG_SET)) {
556 fr_strerror_printf("Cannot use 'option' for attribute %s DER type %s - the parent must be 'sequence' or 'set'",
557 (*da_p)->parent->name, fr_der_tag_to_str(flags->der_type));
558 return -1;
559 }
560
561 /*
562 * In the interest of laziness, allow a bare 'option', so
563 * that we don't have to give an attribute number, and
564 * then also duplicate that number in 'option='.
565 */
566 if (!value) {
567 if (!(*da_p)->state.attr_set || (*da_p)->attr > 0x1f) {
568 fr_strerror_printf("Missing value for 'option='");
569 return -1;
570 }
571
572 num = (*da_p)->attr;
573 goto check;
574 }
575
576 /*
577 * ATTRIBUTE can't have 'option='.
578 */
579 if ((*da_p)->state.attr_set) {
580 fr_strerror_printf("Cannot use 'option=%s' for attribute %s, just use 'option'", value, (*da_p)->name);
581 return -1;
582 }
583
584 /*
585 * We limit the allowed options (tag numbers) to ones
586 * which fit into the 5 bits of the first byte. We don't
587 * support continued tags.
588 */
589 num = strtoul(value, &end, 10);
590 if ((num == ULONG_MAX) || *end) {
591 fr_strerror_printf("Invalid value in 'option=%s'", value);
592 return -1;
593 }
594
595check:
596 if (num >= FR_DER_TAG_VALUE_MAX) {
597 fr_strerror_printf("Option value '%lu' is larger than 30", num);
598 return -1;
599 }
600
603 flags->option = num;
604 flags->is_option = true;
605
606 return 0;
607}
608
610{
611 fr_der_attr_flags_t *flags;
612
613 /*
614 * Only SET and SEQUENCE can have optional elements.
615 */
617 if (!(*da_p)->parent->flags.is_root &&
618 (flags->der_type != FR_DER_TAG_SEQUENCE) && (flags->der_type != FR_DER_TAG_SET)) {
619 fr_strerror_printf("Cannot use 'optional' for attribute %s DER type %s - the parent must be 'sequence' or 'set'",
620 (*da_p)->parent->name, fr_der_tag_to_str(flags->der_type));
621 return -1;
622 }
623
625 flags->optional = true;
626
627 return 0;
628}
629
631 { L("class"), { .func = dict_flag_class } },
632 { L("default"), { .func = dict_flag_default_value,.needs_value = true } },
633 { L("der_type"), { .func = dict_flag_der_type, .needs_value = true } },
634 { L("is_extensions"), { .func = dict_flag_is_extensions } },
635 { L("leaf"), { .func = dict_flag_leaf } },
636 { L("max"), { .func = dict_flag_max, .needs_value = true } },
637 { L("option"), { .func = dict_flag_option} },
638 { L("optional"), { .func = dict_flag_optional} },
639 { L("sequence_of"), { .func = dict_flag_sequence_of, .needs_value = true } },
640 { L("set_of"), { .func = dict_flag_set_of, .needs_value = true } },
641 { L("size"), { .func = dict_flag_size, .needs_value=true } },
642};
643
644static bool type_parse(fr_type_t *type_p,fr_dict_attr_t **da_p, char const *name)
645{
646 static const fr_table_num_sorted_t type_table[] = {
647 { L("bitstring"), FR_TYPE_OCTETS },
648// { L("bmpstring"), FR_TYPE_OCTETS },
649 { L("boolean"), FR_TYPE_BOOL },
650 { L("choice"), FR_TYPE_TLV },
651 { L("enumerated"), FR_TYPE_INT64 },
652 { L("generalizedtime"), FR_TYPE_DATE },
653 { L("generalstring"), FR_TYPE_STRING },
654 { L("ia5string"), FR_TYPE_STRING },
655 { L("integer"), FR_TYPE_INT64 },
656 { L("null"), FR_TYPE_BOOL },
657 { L("octetstring"), FR_TYPE_OCTETS },
658 { L("oid"), FR_TYPE_ATTR },
659 { L("printablestring"), FR_TYPE_STRING },
660 { L("sequence"), FR_TYPE_TLV },
661 { L("set"), FR_TYPE_TLV },
662 { L("t61string"), FR_TYPE_STRING },
663 { L("universalstring"), FR_TYPE_STRING },
664 { L("utctime"), FR_TYPE_DATE },
665 { L("utf8string"), FR_TYPE_STRING },
666 { L("visiblestring"), FR_TYPE_STRING },
667 { L("x509_extensions"), FR_TYPE_GROUP }
668 };
669 static size_t type_table_len = NUM_ELEMENTS(type_table);
670
671 static const fr_table_num_sorted_t der_tag_table[] = {
672 { L("bitstring"), FR_DER_TAG_BITSTRING },
673// { L("bmpstring"), FR_DER_TAG_BMP_STRING },
674 { L("boolean"), FR_DER_TAG_BOOLEAN },
675 { L("choice"), FR_DER_TAG_SEQUENCE },
676 { L("enumerated"), FR_DER_TAG_ENUMERATED },
677 { L("generalizedtime"), FR_DER_TAG_GENERALIZED_TIME },
678 { L("generalstring"), FR_DER_TAG_GENERAL_STRING },
679 { L("ia5string"), FR_DER_TAG_IA5_STRING },
680 { L("integer"), FR_DER_TAG_INTEGER },
681 { L("null"), FR_DER_TAG_NULL },
682 { L("octetstring"), FR_DER_TAG_OCTETSTRING },
683 { L("oid"), FR_DER_TAG_OID },
684 { L("printablestring"), FR_DER_TAG_PRINTABLE_STRING },
685 { L("sequence"), FR_DER_TAG_SEQUENCE },
686 { L("set"), FR_DER_TAG_SET },
687 { L("t61string"), FR_DER_TAG_T61_STRING },
688 { L("universalstring"), FR_DER_TAG_UNIVERSAL_STRING },
689 { L("utctime"), FR_DER_TAG_UTC_TIME },
690 { L("utf8string"), FR_DER_TAG_UTF8_STRING },
691 { L("visiblestring"), FR_DER_TAG_VISIBLE_STRING },
692 { L("x509_extensions"), FR_DER_TAG_SEQUENCE }
693 };
694 static size_t der_tag_table_len = NUM_ELEMENTS(der_tag_table);
695
697 fr_der_tag_t der_type;
698 fr_type_t fr_type;
699
700 /*
701 * To avoid confusion, we want to use the DER names where
702 * possible.
703 *
704 * We only use the FreeRADIUS names where we don't have a
705 * choice. :(
706 */
707 switch (*type_p) {
708 case FR_TYPE_TLV:
709 fr_strerror_const("Cannot use 'tlv' in DER. Please use 'sequence'");
710 return false;
711
712 default:
714 fr_strerror_printf("Cannot use type '%s' in the DER dictionaries",
715 fr_type_to_str(*type_p));
716 return false;
717
718 /*
719 * We allow all integer types. They may be
720 * internal, or they may be inside of a struct.
721 */
722 case FR_TYPE_NULL:
723 case FR_TYPE_INTEGER:
730 case FR_TYPE_STRUCT:
731 case FR_TYPE_GROUP:
732 case FR_TYPE_ATTR:
733 break;
734 }
735
736 /*
737 * Convert the DER data type to the underlying FreeRADIUS
738 * data type.
739 *
740 * If we don't know anything about the data type then
741 * it's either bad, or a data type which we don't care
742 * about. We set the der_type, and then return to the
743 * caller. It will check *type_p, which is likely
744 * FR_TYPE_NULL, and will print an error.
745 *
746 * "return true" here means "I dunno, you deal with it".
747 */
748 fr_type = fr_table_value_by_str(type_table, name, FR_TYPE_MAX);
749 if (fr_type == FR_TYPE_MAX) {
750 flags->der_type = fr_type_to_der_tag_default(*type_p);
751 if (!flags->der_type) goto invalid_type;
752 return true;
753 }
754
755 /*
756 * Now that we've converted the DER type to the
757 * underlying FreeRADIUS type, we get the corresponding
758 * DER type. This MUST exist, as the two tables MUST
759 * have the same names.
760 *
761 * @todo - arguably they should be in one table....
762 */
763 der_type = fr_table_value_by_str(der_tag_table, name, FR_DER_TAG_INVALID);
764 fr_assert(der_type != FR_DER_TAG_INVALID);
765
766 /*
767 * The der type is set only if there are extra flags seen
768 * and parsed by attr_valid().
769 */
771
772 /*
773 * Only now do we update the output data type. From here
774 * on in, any validation failure will return 'false', and
775 * not 'true'.
776 */
777 *type_p = fr_type;
778 flags->der_type = der_type;
779
780 if (der_type == FR_DER_TAG_OID) {
782
783 fr_assert(fr_type == FR_TYPE_ATTR);
784
786
787 ext = dict_attr_ext_alloc(da_p, FR_DICT_ATTR_EXT_REF); /* can change da_p */
788 if (unlikely(!ext)) return -1;
789
790 if (!attr_oid_tree) {
791 attr_oid_tree = fr_dict_attr_by_name(NULL, fr_dict_root((*da_p)->dict), "OID-Tree");
792 fr_assert(attr_oid_tree != NULL);
793 }
794
796 ext->ref = attr_oid_tree;
797 }
798
799 /*
800 * If it is a collection of x509 extensions, we will set
801 * a few other flags as per RFC 5280.
802 */
803 if (strcmp(name, "x509_extensions") == 0) {
804 flags->is_extensions = true;
805
807 flags->option = 3;
808 flags->is_option = true;
809
810 if (dict_flag_set_oid_and_value(da_p, flags) < 0) return false;
811 }
812
813 /*
814 * If this is a choice, then the children MUST have a limited option.
815 */
816 flags->is_choice = (strcmp(name, "choice") == 0);
817
818 return true;
819}
820
847
852
854{
857
858 if (flags->is_choice && unlikely(!fr_type_is_tlv(da->type))) {
859 fr_strerror_printf("Attribute %s of type %s is not allowed represent a collection of choices.",
860 da->name, fr_type_to_str(da->type));
861 return false;
862 }
863
864 /*
865 * The DER encoder / decoder assume that all pairs are FR_TYPE_INT64.
866 *
867 * The "on the wire" DER data has variable-sized encoding for integers,
868 * and drops leading zeros.
869 *
870 * For consistency, we disallow data types which the
871 * encoder/decoder don't handle. Except for data types
872 * in structs, because the struct encoder/decoder takes
873 * care of those.
874 */
875 if (fr_type_is_integer_except_bool(da->type) &&
876 !da->flags.internal &&
877 (da->type != FR_TYPE_INT64) &&
878 (da->type != FR_TYPE_DATE) && (da->type != FR_TYPE_TIME_DELTA) &&
879 (da->parent->type != FR_TYPE_STRUCT)) {
880 fr_strerror_printf("All integers in DER must be 'int64', and not '%s'",
881 fr_type_to_str(da->type));
882 return false;
883 }
884
885 if (flags->is_extensions) {
886 if (da->type != FR_TYPE_GROUP) {
887 fr_strerror_printf("Extensions must be type 'group', and not '%s'",
888 fr_type_to_str(da->type));
889 return false;
890 }
891
892#if 0
893 /*
894 * Group refs are added as unresolved refs, see dict_flag_ref(), and are resolved later
895 * in dict_fixup_group_apply().
896 *
897 * @todo - have a function called from dict_attr_finalize() ?
898 */
899 if (!fr_dict_attr_ref(da)) {
900 fr_strerror_const("Attribute is 'x509_extensions', but is missing 'ref=OID-Tree'");
901 return false;
902 }
903#endif
904
905 /*
906 * Avoid run-time checks.
907 */
908 if (!flags->max) flags->max = UINT64_MAX;
909 }
910
911 /*
912 * Either complain on invalid 'max', or set it to the maximum.
913 */
914 if ((flags->der_type != FR_DER_TAG_SET) && (flags->der_type != FR_DER_TAG_SEQUENCE)) {
915 if (!flags->max) {
916 flags->max = DER_MAX_STR;
917
918 } else if (flags->max > DER_MAX_STR) {
919 fr_strerror_printf("Invalid value of 'max' for DER type '%s'",
921 return false;
922 }
923 }
924
925 /*
926 * Set the restriction types, which make the run-time decoding a lot easier.
927 */
928 if (flags->is_set_of) {
929 flags->restrictions = (1 << flags->set_of);
930 }
931
932 if (flags->is_sequence_of) {
933 /*
934 * If the sequence isn't a choice, it has to be a sequence of one thing.
935 *
936 * If the sequence is group, then it has to be a sequence of sequences.
937 *
938 * If the sequence is a TLV, then the children will update the restrictions.
939 */
940 if (flags->sequence_of != FR_DER_TAG_CHOICE) {
941 flags->restrictions = (1 << flags->sequence_of);
942
943 } else if (da->type == FR_TYPE_GROUP) {
944#ifndef NDEBUG
945 fr_dict_attr_t const *ref;
946
947 ref = fr_dict_attr_ref(da);
948 if (ref) {
950 }
951#endif
952
953 /*
954 * A group of choices is really a sequence of sequences. i.e. x509extensions
955 * contain only a sequence, as does sequence_of=oid_and_value.
956 */
957 flags->restrictions = (1 << FR_DER_TAG_SEQUENCE);
958
959 } else {
960 /*
961 * The children will update our restriction types.
962 */
963 fr_assert(da->type == FR_TYPE_TLV);
964 }
965 }
966
967 /*
968 * If the parent is a choice, then the child MUST have a limited set of options / tags.
969 */
971
972 /*
973 * The attribute was defined with the full OID, and no 'option' flag. Add it manually.
974 */
975 if ((parent->is_choice && !flags->is_option) ||
976 (flags->class == FR_DER_CLASS_PRIVATE) || (flags->class == FR_DER_CLASS_APPLICATION)) {
978
979 if (!flags->class) flags->class = FR_DER_CLASS_CONTEXT;
980 flags->option = da->attr;
981 flags->is_option = true;
982 }
983
984 /*
985 * Can't have duplicates.
986 */
987 if (flags->is_option) {
988 if ((parent->restrictions & (1 << flags->option)) != 0) {
989 fr_strerror_printf("Parent %s already has a child with option %u - duplicates are not allowed",
990 da->parent->name, flags->option);
991 return false;
992 }
993
994 parent->restrictions |= (1 << flags->option);
995
996 } else if (parent->is_sequence_of && (parent->sequence_of == FR_DER_TAG_CHOICE)) {
998
1000// flags->option = flags->der_type;
1001
1002 if ((parent->restrictions & (1 << flags->der_type)) != 0) {
1003 fr_strerror_printf("Parent %s already has a child with tag %s - duplicates are not allowed",
1004 da->parent->name, fr_der_tag_to_str(flags->der_type));
1005 return false;
1006 }
1007
1008 parent->restrictions |= (1 << flags->der_type);
1009
1010 } else if (parent->is_sequence_of) {
1011 if (flags->der_type != parent->sequence_of) {
1012 fr_strerror_printf("Parent %s is a sequence_of=%s - a child cannot be %s",
1013 da->parent->name, fr_der_tag_to_str(parent->set_of),
1014 fr_der_tag_to_str(flags->der_type));
1015 return false;
1016 }
1017
1018 /*
1019 * A sequence can sometimes have mixed tags && options.
1020 */
1021 fr_assert(!flags->is_option);
1022
1023 } else if (parent->is_set_of) {
1024 if (flags->der_type != parent->set_of) {
1025 fr_strerror_printf("Parent %s is a set_of=%s - a child cannot be %s",
1026 da->parent->name, fr_der_tag_to_str(parent->set_of),
1027 fr_der_tag_to_str(flags->der_type));
1028 return false;
1029 }
1030 }
1031
1032 if ((da->type == FR_TYPE_GROUP) && !da->flags.allow_flat) {
1033 if ((da->parent == attr_oid_tree) || da->parent->flags.allow_flat) {
1034 da->flags.allow_flat = true;
1035 } else {
1036 fr_dict_attr_t const *oid;
1037
1038 for (oid = da->parent; !oid->flags.is_root; oid = oid->parent) {
1039 if (oid == attr_oid_tree) {
1040 da->flags.allow_flat = true;
1041 break;
1042 }
1043 }
1044 }
1045 }
1046
1047 return true;
1048}
1049
1052 .name = "der",
1053 .default_type_size = 4,
1054 .default_type_length = 4,
1055 .attr = {
1056 .flags = {
1057 .table = der_flags,
1058 .table_len = NUM_ELEMENTS(der_flags),
1059 .len = sizeof(fr_der_attr_flags_t),
1060 },
1061 .type_parse = type_parse,
1062 .valid = attr_valid
1063 },
1064
1065 .init = fr_der_global_init,
1066 .free = fr_der_global_free,
1067
1068 // .decode = fr_der_decode_foreign,
1069 // .encode = fr_der_encode_foreign,
1070};
#define RCSID(id)
Definition build.h:487
#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
static int invalid_type(fr_type_t type)
Definition calc.c:698
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
bool leaf
encode this OID along with its value
Definition der.h:112
#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
int fr_dict_attr_set_group(fr_dict_attr_t **da_p, fr_dict_attr_t const *ref)
Definition dict_util.c:5281
fr_dict_t * fr_dict_unconst(fr_dict_t const *dict)
Coerce to non-const.
Definition dict_util.c:4897
#define fr_dict_autofree(_to_free)
Definition dict.h:917
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *attr))
Locate a fr_dict_attr_t by its name.
Definition dict_util.c:3532
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2669
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:294
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:307
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:4400
@ FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC
Protocol specific extensions.
Definition dict.h:192
@ FR_DICT_ATTR_EXT_REF
Attribute references another attribute and/or dictionary.
Definition dict.h:186
#define fr_dict_autoload(_to_load)
Definition dict.h:914
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:313
char const * name
name of this protocol
Definition dict.h:458
Specifies an attribute which must be present for the module to function.
Definition dict.h:293
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:306
Protocol specific custom flag definitnion.
Definition dict.h:427
Protocol-specific callbacks in libfreeradius-PROTOCOL.
Definition dict.h:457
fr_dict_attr_ref_type_t type
The state of the reference.
Definition dict_ext.h:78
static void * fr_dict_attr_ext(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
Definition dict_ext.h:121
static fr_dict_attr_t const * fr_dict_attr_ref(fr_dict_attr_t const *da)
Return the reference associated with a group type attribute.
Definition dict_ext.h:148
@ FR_DICT_ATTR_REF_ROOT
only for FR_TYPE_ATTR, point to the default root for enums
Definition dict_ext.h:65
Attribute extension - Holds a reference to an attribute in another dictionary.
Definition dict_ext.h:77
static void * dict_attr_ext_alloc(fr_dict_attr_t **da_p, fr_dict_attr_ext_t ext)
Allocate an attribute extension.
Test enumeration values.
Definition dict_test.h:92
static uint32_t instance_count
Definition base.c:44
HIDDEN fr_dict_t const * dict_der
Definition base.c:39
fr_type_t
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_INT8
8 Bit signed integer.
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_MAX
Number of defined data types.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_UINT16
16 Bit unsigned integer.
@ FR_TYPE_INT64
64 Bit signed integer.
@ FR_TYPE_INT16
16 Bit signed integer.
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
@ FR_TYPE_INT32
32 Bit signed integer.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
unsigned int uint32_t
#define UINT8_MAX
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:609
bool fr_der_tags_compatible(fr_der_tag_t tag1, fr_der_tag_t tag2)
Definition base.c:103
#define ALL_STRINGS
Definition base.c:85
void fr_der_global_free(void)
Definition base.c:210
static const uint64_t der_tags_compatible[FR_DER_TAG_MAX]
Definition base.c:90
static const fr_dict_flag_parser_t der_flags[]
Definition base.c:630
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:289
static int dict_flag_leaf(fr_dict_attr_t **da_p, UNUSED char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
Definition base.c:420
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:527
static const fr_der_tag_t fr_type_to_der_tag_defaults[FR_TYPE_MAX+1]
Definition base.c:821
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:341
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:261
int fr_der_global_init(void)
Definition base.c:187
static bool attr_valid(fr_dict_attr_t *da)
Definition base.c:853
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:220
fr_dict_protocol_t libfreeradius_der_dict_protocol
Definition base.c:1051
bool fr_type_to_der_tag_valid(fr_type_t type, fr_der_tag_t tag)
Definition base.c:179
static bool type_parse(fr_type_t *type_p, fr_dict_attr_t **da_p, char const *name)
Definition base.c:644
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:372
fr_dict_attr_autoload_t libfreeradius_der_dict_attr[]
Definition base.c:50
fr_dict_attr_t const * attr_oid_tree
Definition base.c:40
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:411
fr_der_tag_t fr_type_to_der_tag_default(fr_type_t type)
Definition base.c:848
char const * fr_der_tag_to_str(fr_der_tag_t tag)
Definition base.c:80
static int dict_flag_set_oid_and_value(fr_dict_attr_t **da_p, fr_der_attr_flags_t *flags)
Definition base.c:320
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:544
fr_dict_autoload_t libfreeradius_der_dict[]
Definition base.c:43
static size_t tag_name_to_number_len
Definition base.c:77
static const bool * fr_type_to_der_tags[FR_DER_TAG_MAX]
Definition base.c:111
static fr_table_num_sorted_t const tag_name_to_number[]
Definition base.c:55
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: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:857
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_VARIABLE_SIZE
Definition types.h:312
#define fr_type_is_variable_size(_x)
Definition types.h:389
#define fr_type_is_structural(_x)
Definition types.h:393
@ FR_TYPE_ATTR
A contains an attribute reference.
Definition types.h:84
#define fr_type_is_integer_except_bool(_x)
Definition types.h:381
#define FR_TYPE_INTEGER
Definition types.h:305
#define fr_type_is_tlv(_x)
Definition types.h:373
#define fr_type_is_leaf(_x)
Definition types.h:394
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:455
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:5978
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:643