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: 04b067b7413c7309880109fe634b7925e045b6cc $
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: 04b067b7413c7309880109fe634b7925e045b6cc $")
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
48
51// { .out = &attr_oid_tree, .name = "OID-Tree", .type = FR_TYPE_TLV, .dict = &dict_der },
53};
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_OID] = true,
147 [FR_DER_TAG_UTF8_STRING] = true,
149 [FR_DER_TAG_T61_STRING] = true,
150 [FR_DER_TAG_IA5_STRING] = true,
154 },
155 [FR_TYPE_DATE] = (bool [FR_DER_TAG_MAX]) {
156 [FR_DER_TAG_UTC_TIME] = true,
158 },
159 [FR_TYPE_TLV] = (bool [FR_DER_TAG_MAX]) {
160 [FR_DER_TAG_SEQUENCE] = true,
161 [FR_DER_TAG_SET] = true,
162 },
163 [FR_TYPE_STRUCT] = (bool [FR_DER_TAG_MAX]) {
164 [FR_DER_TAG_BITSTRING] = true,
165 },
166 [FR_TYPE_GROUP] = (bool [FR_DER_TAG_MAX]) {
167 [FR_DER_TAG_SEQUENCE] = true,
168 },
169};
170
171/*
172 * Return true if the given type can be encoded as the given tag.
173 * @param[in] type The fr_type to check.
174 * @param[in] tag The der tag to check.
175 * @return true if the type can be encoded as the given tag.
176 */
178{
179 if (!fr_type_to_der_tags[type]) return false;
180
181 return fr_type_to_der_tags[type][tag];
182}
183
184
186{
187 if (instance_count > 0) {
189 return 0;
190 }
191
193
195 fail:
197 return -1;
198 }
199
202 goto fail;
203 }
204
205 return 0;
206}
207
209{
210 if (--instance_count != 0) return;
211
213}
214
215/*
216 * Allow setting class of APPLICATION and PRIVATE.
217 */
218static int dict_flag_class(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
219{
220 static const fr_table_num_sorted_t table[] = {
221 { L("application"), FR_DER_CLASS_APPLICATION },
222 { L("private"), FR_DER_CLASS_PRIVATE },
223 };
224 static size_t table_len = NUM_ELEMENTS(table);
225
226 fr_der_attr_flags_t *flags;
227 fr_der_tag_class_t tag_class;
228
230 if (flags->der_type != FR_DER_TAG_SEQUENCE) {
231 fr_strerror_printf("Cannot use 'class' for attribute %s DER type %s - the parent must be 'sequence'",
232 (*da_p)->parent->name, fr_der_tag_to_str(flags->der_type));
233 return -1;
234 }
235
236 if ((*da_p)->attr >= FR_DER_TAG_VALUE_MAX) {
237 fr_strerror_printf("Cannot use 'class' for attribute %s - the attribute number must be 0..30",
238 (*da_p)->parent->name);
239 return -1;
240 }
241
243 if (flags->class) {
244 fr_strerror_printf("Attribute %s already has a 'class' defined", (*da_p)->name);
245 return -1;
246 }
247
249 if (tag_class == FR_DER_CLASS_INVALID) {
250 fr_strerror_printf("Unknown or invalid name in 'class=%s'", value);
251 return -1;
252 }
253
254 flags->class = tag_class;
255
256 return 0;
257}
258
260{
262
263 if (!fr_type_is_leaf((*da_p)->type)) {
264 fr_strerror_printf("Cannot set 'default=...' for attribute %s DER type %s",
265 (*da_p)->name, fr_der_tag_to_str(flags->der_type));
266 return -1;
267 }
268
269 /*
270 * The default values are parented from the dict root. That way we don't need to copy the values
271 * when we clone the attribute, we can just copy the pointer.
272 */
273 flags->default_value = fr_value_box_alloc(fr_dict_unconst((*da_p)->dict), (*da_p)->type, NULL);
274 if (!flags->default_value) return -1;
275
276 if (fr_value_box_from_str(flags->default_value, flags->default_value, (*da_p)->type, NULL,
277 value, strlen(value), NULL) < 0) {
278 fr_strerror_printf("Failed parsing 'value=...' - %s", fr_strerror());
279 return -1;
280 }
281
282 flags->has_default_value = true;
283
284 return 0;
285}
286
287static int dict_flag_der_type(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
288{
290 fr_der_tag_t der_type;
291
293 if (der_type == FR_DER_TAG_INVALID) {
294 fr_strerror_printf("Unknown type in 'der_type=%s'", value);
295 return -1;
296 }
297
298 /*
299 * The DER type and FreeRADIUS type must be compatible.
300 *
301 * Except for some der_type=integer, such as a
302 * certificate serialNumber. Those are too large for us
303 * to represent in 64 bits, so we just treat them as
304 * 'octets'.
305 */
306 if (!fr_type_to_der_tag_valid((*da_p)->type, der_type) &&
307 (der_type != FR_DER_TAG_INTEGER) && ((*da_p)->type != FR_TYPE_OCTETS)) {
308 fr_strerror_printf("Attribute type %s is not compatible with 'der_type=%s'",
309 fr_type_to_str((*da_p)->type), value);
310 return -1;
311 }
312
313 flags->der_type = der_type;
314
315 return 0;
316}
317
319{
322
323 if (flags->is_set_of) {
324 fr_strerror_const("Cannot be both 'sequence_of=...' and 'set_of=...'");
325 return -1;
326 }
327
328 if (flags->der_type != FR_DER_TAG_SEQUENCE) {
329 fr_strerror_printf("Cannot use 'sequence_of=...' for DER type '%s'", fr_der_tag_to_str(flags->der_type));
330 return -1;
331 }
332
333 if (strcmp(value, "oid_and_value") == 0) {
334 flags->is_oid_and_value = true;
335 flags->is_sequence_of = true;
336 flags->sequence_of = FR_DER_TAG_SEQUENCE;
337 return fr_dict_attr_set_group(da_p);
338 }
339
341 if (type == FR_DER_TAG_INVALID) {
342 fr_strerror_printf("Unknown type in 'sequence_of=%s'", value);
343 return -1;
344 }
345
346 flags->sequence_of = type;
347 flags->is_sequence_of = true;
348
349 return 0;
350}
351
352static int dict_flag_set_of(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
353{
356
357 if (flags->is_sequence_of) {
358 fr_strerror_const("Cannot be both 'sequence_of=...' and 'set_of=...'");
359 return -1;
360 }
361
362 if (flags->der_type != FR_DER_TAG_SET) {
363 fr_strerror_printf("Cannot use 'set_of=...' for DER type '%s'", fr_der_tag_to_str(flags->der_type));
364 return -1;
365 }
366
367 if (strcmp(value, "oid_and_value") == 0) {
368 flags->is_oid_and_value = true;
369 flags->is_sequence_of = true;
370 flags->sequence_of = FR_DER_TAG_SEQUENCE;
371 return fr_dict_attr_set_group(da_p);
372 }
373
375 if (type == FR_DER_TAG_INVALID) {
376 fr_strerror_printf("Unknown type in 'set_of=%s'", value);
377 return -1;
378 }
379
380 /*
381 * The "choice" can only be used for sequence.
382 */
383 if (type == FR_DER_TAG_CHOICE) {
384 fr_strerror_printf("Invalid type in 'set_of=%s' - 'choice' can only be used for sequences", value);
385 return -1;
386 }
387
388 flags->set_of = type;
389 flags->is_set_of = true;
390
391 return 0;
392}
393
395{
397
398 flags->is_extensions = true;
399
400 return 0;
401}
402
404{
406
407 /*
408 * is_oid_leaf is perhaps better as a property of the _parent_ sequence. It ensures that we only
409 * walk through the sequences children once.
410 */
411 if (fr_der_flag_der_type((*da_p)->parent) != FR_DER_TAG_SEQUENCE) {
412 fr_strerror_printf("Cannot set 'is_oid_leaf' for parent %s of DER type %s",
413 (*da_p)->parent->name, fr_der_tag_to_str(fr_der_flag_der_type((*da_p)->parent)));
414 return -1;
415 }
416
417 flags->is_oid_leaf = true;
418
419 return 0;
420}
421
422/*
423 * size=MIN..MAX
424 */
425static int dict_flag_size(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
426{
428 unsigned long num;
429 char const *p = value;
430 char *end = NULL;
431
432 if (fr_type_is_leaf((*da_p)->type) && !fr_type_is_variable_size((*da_p)->type)) {
433 fr_strerror_printf("Cannot use 'size=...' for type '%s'", fr_type_to_str((*da_p)->type));
434 return -1;
435 }
436
437 /*
438 * size=..max
439 */
440 if ((p[0] == '.') && (p[1] == '.')) goto check_max;
441
442 num = strtoul(p, &end, 10);
443 if (num == ULONG_MAX) {
444 invalid:
445 fr_strerror_printf("Invalid value in 'size=%s'", value);
446 return -1;
447 }
448
449 if (num > UINT8_MAX) {
450 fr_strerror_printf("Invalid value in 'size=%s' - 'min' value is too large", value);
451 return -1;
452 }
453
454 /*
455 * size=4
456 *
457 * Fixed size, but not size=0.
458 */
459 if (!*end) {
460 if (!num) goto invalid;
461
462 /*
463 * printablestring size=2
464 *
465 * instead of string[2] der_type=printablestring
466 */
467 if (((*da_p)->type == FR_TYPE_OCTETS) || ((*da_p)->type == FR_TYPE_STRING)) {
468 (*da_p)->flags.is_known_width = !fr_type_is_structural((*da_p)->type);
469 (*da_p)->flags.length = num;
470 return 0;
471 }
472
473 /*
474 * Sets and sequences can have a fixed number of elements.
475 */
476 flags->min = flags->max = num;
477 return 0;
478 }
479
480 if ((end[0] != '.') || (end[1] != '.')) {
481 fr_strerror_printf("Invalid value in 'size=%s' - unexpected data after 'min'", value);
482 return -1;
483 }
484
485 flags->min = num;
486
487 /*
488 * size=1..
489 *
490 * Sets the minimum, but not the maximum.
491 */
492 p = end + 2;
493 if (!*p) return 0;
494
495check_max:
496 num = strtoul(p, &end, 10);
497 if (num == ULONG_MAX) goto invalid;
498
499 if (*end) {
500 fr_strerror_printf("Invalid value in 'size=%s' - unexpected data after 'max'", value);
501 return -1;
502 }
503
504 flags->max = num;
505
506 return 0;
507}
508
509static int dict_flag_max(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
510{
512 unsigned long num;
513 char *end = NULL;
514
515 num = strtoul(value, &end, 10);
516 if (*end || !num || (num == ULONG_MAX)) {
517 fr_strerror_printf("Invalid value in 'max=%s'", value);
518 return -1;
519 }
520
521 flags->max = num;
522
523 return 0;
524}
525
526static int dict_flag_option(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
527{
528 fr_der_attr_flags_t *flags;
529 unsigned long num;
530 char *end = NULL;
531
532 /*
533 * Only SET and SEQUENCE can have tagged types.
534 */
536 if (!(*da_p)->parent->flags.is_root &&
537 (flags->der_type != FR_DER_TAG_SEQUENCE) && (flags->der_type != FR_DER_TAG_SET)) {
538 fr_strerror_printf("Cannot use 'option' for attribute %s DER type %s - the parent must be 'sequence' or 'set'",
539 (*da_p)->parent->name, fr_der_tag_to_str(flags->der_type));
540 return -1;
541 }
542
543 /*
544 * In the interest of laziness, allow a bare 'option', so
545 * that we don't have to give an attribute number, and
546 * then also duplicate that number in 'option='.
547 */
548 if (!value) {
549 if (!(*da_p)->state.attr_set || (*da_p)->attr > 0x1f) {
550 fr_strerror_printf("Missing value for 'option='");
551 return -1;
552 }
553
554 num = (*da_p)->attr;
555 goto check;
556 }
557
558 /*
559 * ATTRIBUTE can't have 'option='.
560 */
561 if ((*da_p)->state.attr_set) {
562 fr_strerror_printf("Cannot use 'option=%s' for attribute %s, just use 'option'", value, (*da_p)->name);
563 return -1;
564 }
565
566 /*
567 * We limit the allowed options (tag numbers) to ones
568 * which fit into the 5 bits of the first byte. We don't
569 * support continued tags.
570 */
571 num = strtoul(value, &end, 10);
572 if ((num == ULONG_MAX) || *end) {
573 fr_strerror_printf("Invalid value in 'option=%s'", value);
574 return -1;
575 }
576
577check:
578 if (num >= FR_DER_TAG_VALUE_MAX) {
579 fr_strerror_printf("Option value '%lu' is larger than 30", num);
580 return -1;
581 }
582
585 flags->option = num;
586 flags->is_option = true;
587
588 return 0;
589}
590
592{
593 fr_der_attr_flags_t *flags;
594
595 /*
596 * Only SET and SEQUENCE can have optional elements.
597 */
599 if (!(*da_p)->parent->flags.is_root &&
600 (flags->der_type != FR_DER_TAG_SEQUENCE) && (flags->der_type != FR_DER_TAG_SET)) {
601 fr_strerror_printf("Cannot use 'optional' for attribute %s DER type %s - the parent must be 'sequence' or 'set'",
602 (*da_p)->parent->name, fr_der_tag_to_str(flags->der_type));
603 return -1;
604 }
605
607 flags->optional = true;
608
609 return 0;
610}
611
613 { L("class"), { .func = dict_flag_class } },
614 { L("default"), { .func = dict_flag_default_value,.needs_value = true } },
615 { L("der_type"), { .func = dict_flag_der_type, .needs_value = true } },
616 { L("is_extensions"), { .func = dict_flag_is_extensions } },
617 { L("is_oid_leaf"), { .func = dict_flag_is_oid_leaf } },
618 { L("max"), { .func = dict_flag_max, .needs_value = true } },
619 { L("option"), { .func = dict_flag_option} },
620 { L("optional"), { .func = dict_flag_optional} },
621 { L("sequence_of"), { .func = dict_flag_sequence_of, .needs_value = true } },
622 { L("set_of"), { .func = dict_flag_set_of, .needs_value = true } },
623 { L("size"), { .func = dict_flag_size, .needs_value=true } },
624};
625
626static bool type_parse(fr_type_t *type_p,fr_dict_attr_t **da_p, char const *name)
627{
628 static const fr_table_num_sorted_t type_table[] = {
629 { L("bitstring"), FR_TYPE_OCTETS },
630// { L("bmpstring"), FR_TYPE_OCTETS },
631 { L("boolean"), FR_TYPE_BOOL },
632 { L("choice"), FR_TYPE_TLV },
633 { L("enumerated"), FR_TYPE_INT64 },
634 { L("generalizedtime"), FR_TYPE_DATE },
635 { L("generalstring"), FR_TYPE_STRING },
636 { L("ia5string"), FR_TYPE_STRING },
637 { L("integer"), FR_TYPE_INT64 },
638 { L("null"), FR_TYPE_BOOL },
639 { L("octetstring"), FR_TYPE_OCTETS },
640 { L("oid"), FR_TYPE_STRING },
641 { L("printablestring"), FR_TYPE_STRING },
642 { L("sequence"), FR_TYPE_TLV },
643 { L("set"), FR_TYPE_TLV },
644 { L("t61string"), FR_TYPE_STRING },
645 { L("universalstring"), FR_TYPE_STRING },
646 { L("utctime"), FR_TYPE_DATE },
647 { L("utf8string"), FR_TYPE_STRING },
648 { L("visiblestring"), FR_TYPE_STRING },
649 { L("x509_extensions"), FR_TYPE_GROUP }
650 };
651 static size_t type_table_len = NUM_ELEMENTS(type_table);
652
653 static const fr_table_num_sorted_t der_tag_table[] = {
654 { L("bitstring"), FR_DER_TAG_BITSTRING },
655// { L("bmpstring"), FR_DER_TAG_BMP_STRING },
656 { L("boolean"), FR_DER_TAG_BOOLEAN },
657 { L("choice"), FR_DER_TAG_SEQUENCE },
658 { L("enumerated"), FR_DER_TAG_ENUMERATED },
659 { L("generalizedtime"), FR_DER_TAG_GENERALIZED_TIME },
660 { L("generalstring"), FR_DER_TAG_GENERAL_STRING },
661 { L("ia5string"), FR_DER_TAG_IA5_STRING },
662 { L("integer"), FR_DER_TAG_INTEGER },
663 { L("null"), FR_DER_TAG_NULL },
664 { L("octetstring"), FR_DER_TAG_OCTETSTRING },
665 { L("oid"), FR_DER_TAG_OID },
666 { L("printablestring"), FR_DER_TAG_PRINTABLE_STRING },
667 { L("sequence"), FR_DER_TAG_SEQUENCE },
668 { L("set"), FR_DER_TAG_SET },
669 { L("t61string"), FR_DER_TAG_T61_STRING },
670 { L("universalstring"), FR_DER_TAG_UNIVERSAL_STRING },
671 { L("utctime"), FR_DER_TAG_UTC_TIME },
672 { L("utf8string"), FR_DER_TAG_UTF8_STRING },
673 { L("visiblestring"), FR_DER_TAG_VISIBLE_STRING },
674 { L("x509_extensions"), FR_DER_TAG_SEQUENCE }
675 };
676 static size_t der_tag_table_len = NUM_ELEMENTS(der_tag_table);
677
679 fr_der_tag_t der_type;
680 fr_type_t fr_type;
681
682 /*
683 * To avoid confusion, we want to use the DER names where
684 * possible.
685 *
686 * We only use the FreeRADIUS names where we don't have a
687 * choice. :(
688 */
689 switch (*type_p) {
690 case FR_TYPE_TLV:
691 fr_strerror_const("Cannot use 'tlv' in DER. Please use 'sequence'");
692 return false;
693
694 case FR_TYPE_IFID:
696 case FR_TYPE_ETHERNET:
697 case FR_TYPE_FLOAT32:
698 case FR_TYPE_FLOAT64:
699 case FR_TYPE_VSA:
700 case FR_TYPE_VENDOR:
702 case FR_TYPE_VOID:
703 case FR_TYPE_MAX:
704 fr_strerror_printf("Cannot use type '%s' in the DER dictionaries",
705 fr_type_to_str(*type_p));
706 return false;
707
708 /*
709 * We allow integers for now. They may be
710 * internal, or they may be inside of a struct.
711 */
712 default:
713 break;
714 }
715
716 /*
717 * Convert the DER data type to the underlying FreeRADIUS
718 * data type.
719 *
720 * If we don't know anything about the data type then
721 * it's either bad, or a data type which we don't care
722 * about. We set the der_type, and then return to the
723 * caller. It will check *type_p, which is likely
724 * FR_TYPE_NULL, and will print an error.
725 *
726 * "return true" here means "I dunno, you deal with it".
727 */
728 fr_type = fr_table_value_by_str(type_table, name, FR_TYPE_MAX);
729 if (fr_type == FR_TYPE_MAX) {
730 flags->der_type = fr_type_to_der_tag_default(*type_p);
731 return true;
732 }
733
734 /*
735 * Now that we've converted the DER type to the
736 * underlying FreeRADIUS type, we get the corresponding
737 * DER type. This MUST exist, as the two tables MUST
738 * have the same names.
739 *
740 * @todo - arguably they should be in one table....
741 */
742 der_type = fr_table_value_by_str(der_tag_table, name, FR_DER_TAG_INVALID);
743 fr_assert(der_type != FR_DER_TAG_INVALID);
744
745 /*
746 * The der type is set only if there are extra flags seen
747 * and parsed by attr_valid().
748 */
750
751 /*
752 * Only now do we update the output data type. From here
753 * on in, any validation failure will return 'false', and
754 * not 'true'.
755 */
756 *type_p = fr_type;
757 flags->der_type = der_type;
758
759 /*
760 * If it is a collection of x509 extensions, we will set
761 * a few other flags as per RFC 5280.
762 */
763 if (strcmp(name, "x509_extensions") == 0) {
764 flags->is_extensions = true;
765
767 flags->option = 3;
768 flags->is_option = true;
769
770 flags->is_sequence_of = true;
771 flags->sequence_of = FR_DER_TAG_SEQUENCE;
772 }
773
774 /*
775 * If this is a choice, then the children MUST have a limited option.
776 */
777 flags->is_choice = (strcmp(name, "choice") == 0);
778
779 return true;
780}
781
808
813
815{
818
819 /*
820 * sequence_of=oid_and_value has to have a reference to the OID tree.
821 *
822 * Group refs are added as unresolved refs, see dict_flag_ref(), and are resolved later
823 * in dict_fixup_group_apply().
824 *
825 * @todo - have a function called from dict_attr_finalize() ?
826 */
827#if 0
828 if (flags->is_oid_and_value) {
829 fr_dict_attr_t const *ref;
830
831 fr_assert(da->type == FR_TYPE_GROUP);
832
833 if (!fr_dict_attr_ref(da)) {
834 (void) dict_attr_ref_set(da, attr_oid_tree, FR_DICT_ATTR_REF_ALIAS);
835 }
836 }
837#endif
838
839 if (flags->is_choice && unlikely(!fr_type_is_tlv(da->type))) {
840 fr_strerror_printf("Attribute %s of type %s is not allowed represent a collection of choices.",
841 da->name, fr_type_to_str(da->type));
842 return false;
843 }
844
845 /*
846 * The DER encoder / decoder assume that all pairs are FR_TYPE_INT64.
847 *
848 * The "on the wire" DER data has variable-sized encoding for integers,
849 * and drops leading zeros.
850 *
851 * For consistency, we disallow data types which the
852 * encoder/decoder don't handle. Except for data types
853 * in structs, because the struct encoder/decoder takes
854 * care of those.
855 */
856 if (fr_type_is_integer_except_bool(da->type) &&
857 !da->flags.internal &&
858 (da->type != FR_TYPE_INT64) &&
859 (da->type != FR_TYPE_DATE) && (da->type != FR_TYPE_TIME_DELTA) &&
860 (da->parent->type != FR_TYPE_STRUCT)) {
861 fr_strerror_printf("All integers in DER must be 'int64', and not '%s'",
862 fr_type_to_str(da->type));
863 return false;
864 }
865
866 if (flags->is_extensions) {
867 if (da->type != FR_TYPE_GROUP) {
868 fr_strerror_printf("Extensions must be type 'group', and not '%s'",
869 fr_type_to_str(da->type));
870 return false;
871 }
872
873#if 0
874 /*
875 * Group refs are added as unresolved refs, see dict_flag_ref(), and are resolved later
876 * in dict_fixup_group_apply().
877 *
878 * @todo - have a function called from dict_attr_finalize() ?
879 */
880 if (!fr_dict_attr_ref(da)) {
881 fr_strerror_const("Attribute is 'x509_extensions', but is missing 'ref=OID-Tree'");
882 return false;
883 }
884#endif
885
886 /*
887 * Avoid run-time checks.
888 */
889 if (!flags->max) flags->max = UINT64_MAX;
890 }
891
892 /*
893 * Either complain on invalid 'max', or set it to the maximum.
894 */
895 if ((flags->der_type != FR_DER_TAG_SET) && (flags->der_type != FR_DER_TAG_SEQUENCE)) {
896 if (!flags->max) {
897 flags->max = DER_MAX_STR;
898
899 } else if (flags->max > DER_MAX_STR) {
900 fr_strerror_printf("Invalid value of 'max' for DER type '%s'",
902 return false;
903 }
904 }
905
906 /*
907 * Set the restriction types, which make the run-time decoding a lot easier.
908 */
909 if (flags->is_set_of) {
910 flags->restrictions = (1 << flags->set_of);
911 }
912
913 if (flags->is_sequence_of) {
914 /*
915 * If the sequence isn't a choice, it has to be a sequence of one thing.
916 *
917 * If the sequence is group, then it has to be a sequence of sequences.
918 *
919 * If the sequence is a TLV, then the children will update the restrictions.
920 */
921 if (flags->sequence_of != FR_DER_TAG_CHOICE) {
922 flags->restrictions = (1 << flags->sequence_of);
923
924 } else if (da->type == FR_TYPE_GROUP) {
925#ifndef NDEBUG
926 fr_dict_attr_t const *ref;
927
928 ref = fr_dict_attr_ref(da);
929 if (ref) {
931 }
932#endif
933
934 /*
935 * A group of choices is really a sequence of sequences. i.e. x509extensions
936 * contain only a sequence, as does sequence_of=oid_and_value.
937 */
938 flags->restrictions = (1 << FR_DER_TAG_SEQUENCE);
939
940 } else {
941 /*
942 * The children will update our restriction types.
943 */
944 fr_assert(da->type == FR_TYPE_TLV);
945 }
946 }
947
948 /*
949 * If the parent is a choice, then the child MUST have a limited set of options / tags.
950 */
952
953 /*
954 * The attribute was defined with the full OID, and no 'option' flag. Add it manually.
955 */
956 if ((parent->is_choice && !flags->is_option) ||
957 (flags->class == FR_DER_CLASS_PRIVATE) || (flags->class == FR_DER_CLASS_APPLICATION)) {
959
960 if (!flags->class) flags->class = FR_DER_CLASS_CONTEXT;
961 flags->option = da->attr;
962 flags->is_option = true;
963 }
964
965 /*
966 * Can't have duplicates.
967 */
968 if (flags->is_option) {
969 if ((parent->restrictions & (1 << flags->option)) != 0) {
970 fr_strerror_printf("Parent %s already has a child with option %u - duplicates are not allowed",
971 da->parent->name, flags->option);
972 return false;
973 }
974
975 parent->restrictions |= (1 << flags->option);
976
977 } else if (parent->is_sequence_of && (parent->sequence_of == FR_DER_TAG_CHOICE)) {
979
981// flags->option = flags->der_type;
982
983 if ((parent->restrictions & (1 << flags->der_type)) != 0) {
984 fr_strerror_printf("Parent %s already has a child with tag %s - duplicates are not allowed",
985 da->parent->name, fr_der_tag_to_str(flags->der_type));
986 return false;
987 }
988
989 parent->restrictions |= (1 << flags->der_type);
990
991 } else if (parent->is_sequence_of) {
992 if (flags->der_type != parent->sequence_of) {
993 fr_strerror_printf("Parent %s is a sequence_of=%s - a child cannot be %s",
994 da->parent->name, fr_der_tag_to_str(parent->set_of),
996 return false;
997 }
998
999 /*
1000 * A sequence can sometimes have mixed tags && options.
1001 */
1002 fr_assert(!flags->is_option);
1003
1004 } else if (parent->is_set_of) {
1005 if (flags->der_type != parent->set_of) {
1006 fr_strerror_printf("Parent %s is a set_of=%s - a child cannot be %s",
1007 da->parent->name, fr_der_tag_to_str(parent->set_of),
1008 fr_der_tag_to_str(flags->der_type));
1009 return false;
1010 }
1011 }
1012
1013 return true;
1014}
1015
1018 .name = "der",
1019 .default_type_size = 4,
1020 .default_type_length = 4,
1021 .attr = {
1022 .flags = {
1023 .table = der_flags,
1024 .table_len = NUM_ELEMENTS(der_flags),
1025 .len = sizeof(fr_der_attr_flags_t),
1026 },
1027 .type_parse = type_parse,
1028 .valid = attr_valid
1029 },
1030
1031 .init = fr_der_global_init,
1032 .free = fr_der_global_free,
1033
1034 // .decode = fr_der_decode_foreign,
1035 // .encode = fr_der_encode_foreign,
1036};
#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:4724
#define fr_dict_autofree(_to_free)
Definition dict.h:895
int fr_dict_attr_set_group(fr_dict_attr_t **da_p)
Definition dict_util.c:5120
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:300
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:4227
@ FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC
Protocol specific extensions.
Definition dict.h:190
#define fr_dict_autoload(_to_load)
Definition dict.h:892
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:306
char const * name
name of this protocol
Definition dict.h:451
Specifies an attribute which must be present for the module to function.
Definition dict.h:286
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:299
Protocol specific custom flag definitnion.
Definition dict.h:420
Protocol-specific callbacks in libfreeradius-PROTOCOL.
Definition dict.h:450
static void * fr_dict_attr_ext(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
Definition dict_ext.h:141
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:185
@ 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
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_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:403
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:591
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:208
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:612
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:287
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:509
static const fr_der_tag_t fr_type_to_der_tag_defaults[FR_TYPE_MAX+1]
Definition base.c:782
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:318
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:259
int fr_der_global_init(void)
Definition base.c:185
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:218
fr_dict_protocol_t libfreeradius_der_dict_protocol
Definition base.c:1017
bool fr_type_to_der_tag_valid(fr_type_t type, fr_der_tag_t tag)
Definition base.c:177
static bool type_parse(fr_type_t *type_p, fr_dict_attr_t **da_p, char const *name)
Definition base.c:626
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:352
fr_dict_attr_autoload_t libfreeradius_der_dict_attr[]
Definition base.c:50
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:394
fr_der_tag_t fr_type_to_der_tag_default(fr_type_t type)
Definition base.c:809
char const * fr_der_tag_to_str(fr_der_tag_t tag)
Definition base.c:80
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:526
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:425
static bool attr_valid(fr_dict_attr_t *da)
Definition base.c:448
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:841
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:389
#define fr_type_is_structural(_x)
Definition types.h:393
#define fr_type_is_integer_except_bool(_x)
Definition types.h:381
#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:5754
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:643