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: 562bebad6b3046979757ebddb5757dbb0c3288bc $
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: 562bebad6b3046979757ebddb5757dbb0c3288bc $")
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 default:
696 fr_strerror_printf("Cannot use type '%s' in the DER dictionaries",
697 fr_type_to_str(*type_p));
698 return false;
699
700 /*
701 * We allow all integer types. They may be
702 * internal, or they may be inside of a struct.
703 */
704 case FR_TYPE_NULL:
705 case FR_TYPE_INTEGER:
712 case FR_TYPE_STRUCT:
713 case FR_TYPE_GROUP:
714 case FR_TYPE_ATTR:
715 break;
716 }
717
718 /*
719 * Convert the DER data type to the underlying FreeRADIUS
720 * data type.
721 *
722 * If we don't know anything about the data type then
723 * it's either bad, or a data type which we don't care
724 * about. We set the der_type, and then return to the
725 * caller. It will check *type_p, which is likely
726 * FR_TYPE_NULL, and will print an error.
727 *
728 * "return true" here means "I dunno, you deal with it".
729 */
730 fr_type = fr_table_value_by_str(type_table, name, FR_TYPE_MAX);
731 if (fr_type == FR_TYPE_MAX) {
732 flags->der_type = fr_type_to_der_tag_default(*type_p);
733 if (!flags->der_type) goto invalid_type;
734 return true;
735 }
736
737 /*
738 * Now that we've converted the DER type to the
739 * underlying FreeRADIUS type, we get the corresponding
740 * DER type. This MUST exist, as the two tables MUST
741 * have the same names.
742 *
743 * @todo - arguably they should be in one table....
744 */
745 der_type = fr_table_value_by_str(der_tag_table, name, FR_DER_TAG_INVALID);
746 fr_assert(der_type != FR_DER_TAG_INVALID);
747
748 /*
749 * The der type is set only if there are extra flags seen
750 * and parsed by attr_valid().
751 */
753
754 /*
755 * Only now do we update the output data type. From here
756 * on in, any validation failure will return 'false', and
757 * not 'true'.
758 */
759 *type_p = fr_type;
760 flags->der_type = der_type;
761
762 /*
763 * If it is a collection of x509 extensions, we will set
764 * a few other flags as per RFC 5280.
765 */
766 if (strcmp(name, "x509_extensions") == 0) {
767 flags->is_extensions = true;
768
770 flags->option = 3;
771 flags->is_option = true;
772
773 flags->is_sequence_of = true;
774 flags->sequence_of = FR_DER_TAG_SEQUENCE;
775 }
776
777 /*
778 * If this is a choice, then the children MUST have a limited option.
779 */
780 flags->is_choice = (strcmp(name, "choice") == 0);
781
782 return true;
783}
784
811
816
818{
821
822 /*
823 * sequence_of=oid_and_value has to have a reference to the OID tree.
824 *
825 * Group refs are added as unresolved refs, see dict_flag_ref(), and are resolved later
826 * in dict_fixup_group_apply().
827 *
828 * @todo - have a function called from dict_attr_finalize() ?
829 */
830#if 0
831 if (flags->is_oid_and_value) {
832 fr_dict_attr_t const *ref;
833
834 fr_assert(da->type == FR_TYPE_GROUP);
835
836 if (!fr_dict_attr_ref(da)) {
837 (void) dict_attr_ref_set(da, attr_oid_tree, FR_DICT_ATTR_REF_ALIAS);
838 }
839 }
840#endif
841
842 if (flags->is_choice && unlikely(!fr_type_is_tlv(da->type))) {
843 fr_strerror_printf("Attribute %s of type %s is not allowed represent a collection of choices.",
844 da->name, fr_type_to_str(da->type));
845 return false;
846 }
847
848 /*
849 * The DER encoder / decoder assume that all pairs are FR_TYPE_INT64.
850 *
851 * The "on the wire" DER data has variable-sized encoding for integers,
852 * and drops leading zeros.
853 *
854 * For consistency, we disallow data types which the
855 * encoder/decoder don't handle. Except for data types
856 * in structs, because the struct encoder/decoder takes
857 * care of those.
858 */
859 if (fr_type_is_integer_except_bool(da->type) &&
860 !da->flags.internal &&
861 (da->type != FR_TYPE_INT64) &&
862 (da->type != FR_TYPE_DATE) && (da->type != FR_TYPE_TIME_DELTA) &&
863 (da->parent->type != FR_TYPE_STRUCT)) {
864 fr_strerror_printf("All integers in DER must be 'int64', and not '%s'",
865 fr_type_to_str(da->type));
866 return false;
867 }
868
869 if (flags->is_extensions) {
870 if (da->type != FR_TYPE_GROUP) {
871 fr_strerror_printf("Extensions must be type 'group', and not '%s'",
872 fr_type_to_str(da->type));
873 return false;
874 }
875
876#if 0
877 /*
878 * Group refs are added as unresolved refs, see dict_flag_ref(), and are resolved later
879 * in dict_fixup_group_apply().
880 *
881 * @todo - have a function called from dict_attr_finalize() ?
882 */
883 if (!fr_dict_attr_ref(da)) {
884 fr_strerror_const("Attribute is 'x509_extensions', but is missing 'ref=OID-Tree'");
885 return false;
886 }
887#endif
888
889 /*
890 * Avoid run-time checks.
891 */
892 if (!flags->max) flags->max = UINT64_MAX;
893 }
894
895 /*
896 * Either complain on invalid 'max', or set it to the maximum.
897 */
898 if ((flags->der_type != FR_DER_TAG_SET) && (flags->der_type != FR_DER_TAG_SEQUENCE)) {
899 if (!flags->max) {
900 flags->max = DER_MAX_STR;
901
902 } else if (flags->max > DER_MAX_STR) {
903 fr_strerror_printf("Invalid value of 'max' for DER type '%s'",
905 return false;
906 }
907 }
908
909 /*
910 * Set the restriction types, which make the run-time decoding a lot easier.
911 */
912 if (flags->is_set_of) {
913 flags->restrictions = (1 << flags->set_of);
914 }
915
916 if (flags->is_sequence_of) {
917 /*
918 * If the sequence isn't a choice, it has to be a sequence of one thing.
919 *
920 * If the sequence is group, then it has to be a sequence of sequences.
921 *
922 * If the sequence is a TLV, then the children will update the restrictions.
923 */
924 if (flags->sequence_of != FR_DER_TAG_CHOICE) {
925 flags->restrictions = (1 << flags->sequence_of);
926
927 } else if (da->type == FR_TYPE_GROUP) {
928#ifndef NDEBUG
929 fr_dict_attr_t const *ref;
930
931 ref = fr_dict_attr_ref(da);
932 if (ref) {
934 }
935#endif
936
937 /*
938 * A group of choices is really a sequence of sequences. i.e. x509extensions
939 * contain only a sequence, as does sequence_of=oid_and_value.
940 */
941 flags->restrictions = (1 << FR_DER_TAG_SEQUENCE);
942
943 } else {
944 /*
945 * The children will update our restriction types.
946 */
947 fr_assert(da->type == FR_TYPE_TLV);
948 }
949 }
950
951 /*
952 * If the parent is a choice, then the child MUST have a limited set of options / tags.
953 */
955
956 /*
957 * The attribute was defined with the full OID, and no 'option' flag. Add it manually.
958 */
959 if ((parent->is_choice && !flags->is_option) ||
960 (flags->class == FR_DER_CLASS_PRIVATE) || (flags->class == FR_DER_CLASS_APPLICATION)) {
962
963 if (!flags->class) flags->class = FR_DER_CLASS_CONTEXT;
964 flags->option = da->attr;
965 flags->is_option = true;
966 }
967
968 /*
969 * Can't have duplicates.
970 */
971 if (flags->is_option) {
972 if ((parent->restrictions & (1 << flags->option)) != 0) {
973 fr_strerror_printf("Parent %s already has a child with option %u - duplicates are not allowed",
974 da->parent->name, flags->option);
975 return false;
976 }
977
978 parent->restrictions |= (1 << flags->option);
979
980 } else if (parent->is_sequence_of && (parent->sequence_of == FR_DER_TAG_CHOICE)) {
982
984// flags->option = flags->der_type;
985
986 if ((parent->restrictions & (1 << flags->der_type)) != 0) {
987 fr_strerror_printf("Parent %s already has a child with tag %s - duplicates are not allowed",
988 da->parent->name, fr_der_tag_to_str(flags->der_type));
989 return false;
990 }
991
992 parent->restrictions |= (1 << flags->der_type);
993
994 } else if (parent->is_sequence_of) {
995 if (flags->der_type != parent->sequence_of) {
996 fr_strerror_printf("Parent %s is a sequence_of=%s - a child cannot be %s",
997 da->parent->name, fr_der_tag_to_str(parent->set_of),
999 return false;
1000 }
1001
1002 /*
1003 * A sequence can sometimes have mixed tags && options.
1004 */
1005 fr_assert(!flags->is_option);
1006
1007 } else if (parent->is_set_of) {
1008 if (flags->der_type != parent->set_of) {
1009 fr_strerror_printf("Parent %s is a set_of=%s - a child cannot be %s",
1010 da->parent->name, fr_der_tag_to_str(parent->set_of),
1011 fr_der_tag_to_str(flags->der_type));
1012 return false;
1013 }
1014 }
1015
1016 return true;
1017}
1018
1021 .name = "der",
1022 .default_type_size = 4,
1023 .default_type_length = 4,
1024 .attr = {
1025 .flags = {
1026 .table = der_flags,
1027 .table_len = NUM_ELEMENTS(der_flags),
1028 .len = sizeof(fr_der_attr_flags_t),
1029 },
1030 .type_parse = type_parse,
1031 .valid = attr_valid
1032 },
1033
1034 .init = fr_der_global_init,
1035 .free = fr_der_global_free,
1036
1037 // .decode = fr_der_decode_foreign,
1038 // .encode = fr_der_encode_foreign,
1039};
#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
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
#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:4767
#define fr_dict_autofree(_to_free)
Definition dict.h:900
int fr_dict_attr_set_group(fr_dict_attr_t **da_p)
Definition dict_util.c:5151
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:305
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:4270
@ FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC
Protocol specific extensions.
Definition dict.h:190
#define fr_dict_autoload(_to_load)
Definition dict.h:897
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:311
char const * name
name of this protocol
Definition dict.h:456
Specifies an attribute which must be present for the module to function.
Definition dict.h:291
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:304
Protocol specific custom flag definitnion.
Definition dict.h:425
Protocol-specific callbacks in libfreeradius-PROTOCOL.
Definition dict.h:455
static void * fr_dict_attr_ext(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
Definition dict_ext.h:134
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:178
@ 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_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_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:785
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:1020
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:812
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_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:5780
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:643