Skip to content

Commit 3a57d57

Browse files
committed
allow 'class=private' and 'class=enterprise'
1 parent 64a82c1 commit 3a57d57

File tree

3 files changed

+54
-16
lines changed

3 files changed

+54
-16
lines changed

src/protocols/der/base.c

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -207,36 +207,49 @@ void fr_der_global_free(void)
207207
fr_dict_autofree(libfreeradius_der_dict);
208208
}
209209

210-
#if 0
210+
/*
211+
* Allow setting class of APPLICATION and PRIVATE.
212+
*/
211213
static int dict_flag_class(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
212214
{
213215
static const fr_table_num_sorted_t table[] = {
214216
{ L("application"), FR_DER_CLASS_APPLICATION },
215-
{ L("context-specific"), FR_DER_CLASS_CONTEXT },
216217
{ L("private"), FR_DER_CLASS_PRIVATE },
217-
{ L("universal"), FR_DER_CLASS_UNIVERSAL },
218218
};
219219
static size_t table_len = NUM_ELEMENTS(table);
220220

221-
fr_der_attr_flags_t *flags = fr_dict_attr_ext(*da_p, FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC);
221+
fr_der_attr_flags_t *flags;
222222
fr_der_tag_class_t tag_class;
223223

224+
flags = fr_dict_attr_ext((*da_p)->parent, FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC);
225+
if (flags->der_type != FR_DER_TAG_SEQUENCE) {
226+
fr_strerror_printf("Cannot use 'class' for attribute %s DER type %s - the parent must be 'sequence'",
227+
(*da_p)->parent->name, fr_der_tag_to_str(flags->der_type));
228+
return -1;
229+
}
230+
231+
if ((*da_p)->attr >= FR_DER_TAG_VALUE_MAX) {
232+
fr_strerror_printf("Cannot use 'class' for attribute %s - the attribute number must be 0..30",
233+
(*da_p)->parent->name);
234+
return -1;
235+
}
236+
237+
flags = fr_dict_attr_ext(*da_p, FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC);
224238
if (flags->class) {
225-
fr_strerror_printf("Attribute already has a 'class' defined");
239+
fr_strerror_printf("Attribute %s already has a 'class' defined", (*da_p)->name);
226240
return -1;
227241
}
228242

229243
tag_class = fr_table_value_by_str(table, value, FR_DER_CLASS_INVALID);
230244
if (tag_class == FR_DER_CLASS_INVALID) {
231-
fr_strerror_printf("Invalid value in 'class=%s'", value);
245+
fr_strerror_printf("Unknown or invalid name in 'class=%s'", value);
232246
return -1;
233247
}
234248

235249
flags->class = tag_class;
236250

237251
return 0;
238252
}
239-
#endif
240253

241254
static int dict_flag_has_default(fr_dict_attr_t **da_p, UNUSED char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
242255
{
@@ -573,7 +586,7 @@ static int dict_flag_optional(fr_dict_attr_t **da_p, UNUSED char const *value, U
573586
}
574587

575588
static const fr_dict_flag_parser_t der_flags[] = {
576-
// { L("class"), { .func = dict_flag_class } },
589+
{ L("class"), { .func = dict_flag_class } },
577590
{ L("der_type"), { .func = dict_flag_der_type, .needs_value = true } },
578591
{ L("has_default"), { .func = dict_flag_has_default } },
579592
{ L("is_extensions"), { .func = dict_flag_is_extensions } },
@@ -912,15 +925,23 @@ static bool attr_valid(fr_dict_attr_t *da)
912925
* If the parent is a choice, then the child MUST have a limited set of options / tags.
913926
*/
914927
parent = fr_dict_attr_ext(da->parent, FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC);
915-
if (parent->is_choice || flags->is_option) {
916-
if (!flags->class) {
917-
fr_assert(da->attr < FR_DER_TAG_VALUE_MAX);
918928

919-
flags->class = FR_DER_CLASS_CONTEXT;
920-
flags->option = da->attr;
921-
flags->is_option = true;
922-
}
929+
/*
930+
* The attribute was defined with the full OID, and no 'option' flag. Add it manually.
931+
*/
932+
if ((parent->is_choice && !flags->is_option) ||
933+
(flags->class == FR_DER_CLASS_PRIVATE) || (flags->class == FR_DER_CLASS_APPLICATION)) {
934+
fr_assert(da->attr < FR_DER_TAG_VALUE_MAX);
935+
936+
if (!flags->class) flags->class = FR_DER_CLASS_CONTEXT;
937+
flags->option = da->attr;
938+
flags->is_option = true;
939+
}
923940

941+
/*
942+
* Can't have duplicates.
943+
*/
944+
if (flags->is_option) {
924945
if ((parent->restrictions & (1 << flags->option)) != 0) {
925946
fr_strerror_printf("Parent %s already has a child with option %u - duplicates are not allowed",
926947
da->parent->name, flags->option);

src/tests/unit/protocols/der/base.txt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -918,5 +918,16 @@ match Test-GeneralNames = { dNSName = "foo.bar" }
918918
decode-pair 30 06 87 04 0a 00 05 04
919919
match Test-GeneralNames = { iPAddress = 10.0.5.4 }
920920

921+
#
922+
# private / application class
923+
#
924+
proto-dictionary-root Test-Choice
925+
decode-pair 30 06 c0 01 01 c1 01 02
926+
match Test-Choice = { option0 = 1, option1 = 2 }
927+
928+
encode-pair option0 = 1, option1 = 2
929+
match c0 01 01 c1 01 02
930+
931+
921932
count
922-
match 553
933+
match 558

src/tests/unit/protocols/der/dictionary.test

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,3 +177,9 @@ BEGIN Test-Set-TLV
177177
DEFINE Test-Integer integer
178178
DEFINE Test-Boolean bool
179179
END Test-Set-TLV
180+
181+
DEFINE Test-Choice sequence
182+
BEGIN Test-Choice
183+
ATTRIBUTE option0 0 integer class=private
184+
ATTRIBUTE option1 1 integer class=private
185+
END Test-Choice

0 commit comments

Comments
 (0)