Feature/der encoder decoder#5497
Conversation
src/protocols/der/base.c
Outdated
| * @copyright 2024 Inkbridge Networks SAS. | ||
| */ | ||
|
|
||
| #include "include/build.h" |
There was a problem hiding this comment.
nits: we usually put #include "foo" after all of the common includes. that way any location definitions don't affect the other header files.
src/protocols/der/base.c
Outdated
| */ | ||
|
|
||
| #include "include/build.h" | ||
| #include "der.h" |
There was a problem hiding this comment.
#include <freeradius-devel/util/table.h> etc.
src/protocols/der/base.c
Outdated
| }; | ||
|
|
||
| fr_der_tag_constructed_t tag_labels[] = { | ||
| [FR_DER_TAG_BOOLEAN] = FR_DER_TAG_PRIMATIVE, |
There was a problem hiding this comment.
PRIMATIVE? Is that a DER thing, or is it PRIMITIVE?
| { | ||
| fr_der_attr_flags_t *flags = fr_dict_attr_ext(*da_p, FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC); | ||
|
|
||
| flags->tagnum = (uint8_t)atoi(value); |
There was a problem hiding this comment.
do we want sanity checks here for overflow, or for bad formats?
Admins make mistakes. An error of "you screwed up" is usually better than silently doing the wrong thing.
src/protocols/der/base.c
Outdated
| static int dict_flag_set_of(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules) | ||
| { | ||
| static fr_table_num_sorted_t const table[] = { | ||
| { L("bitstring"), FR_DER_TAG_BITSTRING }, |
There was a problem hiding this comment.
with repeated tables like this, it may be useful to put them into a common macro? depending on whether or not the C preprocessor likes the L() macro inside another macro :(
src/protocols/der/base.c
Outdated
| } | ||
|
|
||
| static fr_dict_flag_parser_t const der_flags[] = { | ||
| { L("class"), { .func = dict_flag_class } }, |
src/protocols/der/base.c
Outdated
|
|
||
| if (fr_der_flag_is_sequence_of(da->parent) || fr_der_flag_is_set_of(da->parent)) { | ||
| static fr_table_num_sorted_t const table[] = { | ||
| { L("bitstring"), FR_DER_TAG_BITSTRING }, |
src/protocols/der/der.h
Outdated
| @@ -0,0 +1,171 @@ | |||
| #include "include/build.h" | |||
src/protocols/der/der.h
Outdated
| #include "include/build.h" | ||
| #include "lib/util/types.h" | ||
| #include <freeradius-devel/util/dict.h> | ||
| #include <stdbool.h> |
There was a problem hiding this comment.
stdbool and stdint should already be included by the types.h header
src/protocols/der/der.h
Outdated
| */ | ||
| static bool *fr_type_to_der_tags[] = { | ||
| [FR_TYPE_MAX] = NULL, | ||
| [FR_TYPE_BOOL] = (bool []){[FR_DER_TAG_BOOLEAN] = true, [FR_DER_TAG_INTEGER] = true, [FR_DER_TAG_NULL] = true, [FR_DER_TAG_MAX] = false}, |
There was a problem hiding this comment.
maybe put line breaks after the , which can make the lines shorter, and a bit easier to read.
|
|
||
| static inline CC_HINT(always_inline) fr_der_tag_num_t fr_type_to_der_tag_default(fr_type_t type) | ||
| { | ||
| return fr_type_to_der_tag_defaults[type]; |
There was a problem hiding this comment.
what about data types like FR_TYPE_IPADDR which aren't listed in the above table? The C compiler will initialize the array entry to 0. Is there a FR_DER_TAG_INVALID which is defined as 0 ?
src/protocols/der/der.h
Outdated
| #define DER_BOOLEAN_TRUE 0xff //!< DER encoded boolean true value. | ||
|
|
||
| typedef struct { | ||
| uint8_t tagnum; |
There was a problem hiding this comment.
maybe format these so that the names are further to the right, and then all lined up vertically. that makes it easier to read.
src/protocols/der/der.h
Outdated
| } | ||
|
|
||
| #define fr_der_flag_tagnum(_da) (fr_der_attr_flags(_da)->tagnum) | ||
| #define fr_der_flag_class(_da) (fr_der_attr_flags(_da)->class) |
| TARGET := libfreeradius-der$(L) | ||
|
|
||
| SOURCES := base.c \ | ||
| decode.c \ |
There was a problem hiding this comment.
maybe include push this commit until after the encode.c and decode.c files have been added. otherwise the build is broken.
src/protocols/der/decode.c
Outdated
| * @copyright 2024 Arran Cudbard-Bell (a.cudbardb@freeradius.org) | ||
| * @copyright 2024 Inkbridge Networks SAS. | ||
| */ | ||
| #include "include/build.h" |
There was a problem hiding this comment.
header name / "" versus <>
I'll stop commenting here. just take a pass through the code for these, and also stdbool etc. likely most of the std* includes can be dropped.
src/protocols/der/decode.c
Outdated
| #include <freeradius-devel/util/time.h> | ||
| #include <freeradius-devel/util/value.h> | ||
| #include <stdlib.h> | ||
| #include <time.h> |
There was a problem hiding this comment.
util/time.h already includes time.h
src/protocols/der/decode.c
Outdated
|
|
||
| typedef ssize_t (*fr_der_decode_oid_t)(uint64_t subidentifier, void *uctx, bool is_last); | ||
|
|
||
| static ssize_t fr_der_decode_oid(fr_pair_list_t *out, fr_dbuff_t *in, fr_der_decode_oid_t func, void *uctx); |
There was a problem hiding this comment.
maybe add CC_HINT(nonnull) for the function prototypes
src/protocols/der/decode.c
Outdated
| [UINT8_MAX] = { .constructed = FR_DER_TAG_PRIMATIVE, .decode = NULL }, | ||
| }; | ||
|
|
||
| static int decode_test_ctx(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict) |
There was a problem hiding this comment.
move the various test_ctx stuff to the bottom of the file, where it's located for the other protocols
| } | ||
|
|
||
| /* | ||
| * ISO/IEC 8825-1:2021 |
There was a problem hiding this comment.
comments and references to standards make me happy.
src/protocols/der/decode.c
Outdated
| return -1; | ||
| } | ||
|
|
||
| if (unlikely(val != DER_BOOLEAN_FALSE && val != DER_BOOLEAN_TRUE)) { |
There was a problem hiding this comment.
brackets around things. It's not required by C, but it cam avoid typos
if ((a == b) || (c == d))
src/protocols/der/decode.c
Outdated
|
|
||
| vp = fr_pair_afrom_da(ctx, parent); | ||
| if (unlikely(vp == NULL)) { | ||
| fr_strerror_const("Out of memory for boolean pair"); |
There was a problem hiding this comment.
just Out of memory is fine, like all of the other uses. arguably we could have a macro for this somewhere else in the code.
src/protocols/der/decode.c
Outdated
| } | ||
|
|
||
| typedef struct { | ||
| TALLOC_CTX *ctx; /**< Allocation context */ |
There was a problem hiding this comment.
comments can be aligned vertically, and use //!< which is more consistent with the rest of the code.
src/protocols/der/decode.c
Outdated
| char *str = NULL; | ||
|
|
||
| static bool const allowed_chars[] = { | ||
| [' '] = true, ['\''] = true, ['('] = true, [')'] = true, ['+'] = true, [','] = true, ['-'] = true, |
There was a problem hiding this comment.
format as 4 per line, which makes it a bit easier to read
src/protocols/der/decode.c
Outdated
| char *str = NULL; | ||
|
|
||
| static bool const allowed_chars[] = { | ||
| [0x08] = true, [0x0A] = true, [0x0C] = true, [0x0D] = true, [0x0E] = true, [0x0F] = true, |
There was a problem hiding this comment.
see src/lib/util/token.c. GCC and clang support ranges, which makes these tables a lot easier
/*
* This is fine. Don't complain.
*/
#ifdef __clang__
#pragma clang diagnostic ignored "-Wgnu-designator"
#endif
...
[ 0 ... T_HASH ] = '?', /* GCC extension for range initialization, also allowed by clang */
src/protocols/der/decode.c
Outdated
| /* | ||
| * We have a multi-byte tag | ||
| * | ||
| * Note: Mutli-byte tags would mean having a tag number that is greater than 30 (0x1E) (since tag |
share/dictionary/der/dictionary
Outdated
| PROTOCOL DER 11354911 | ||
| BEGIN-PROTOCOL DER | ||
|
|
||
| $INCLUDE dictionary.test |
There was a problem hiding this comment.
probably don't want test dictionaries in the default build.
the src/tests/unit stuff allows for local dictionaries to be loaded
| DEFINE GeneralName choice | ||
| BEGIN GeneralName | ||
|
|
||
| ATTRIBUTE otherName 0 sequence option=0 |
There was a problem hiding this comment.
run ./scripts/dict/format.dl share/dictionary/der/dictionary*
for consistent formatting
74074a9 to
70badd1
Compare
| # Copyright (C) 2025 The FreeRADIUS Server project and contributors | ||
| # This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0 | ||
| # Version $Id$ | ||
| DEFINE Certificate-Extensions x509_extensions ref=OID-Tree |
There was a problem hiding this comment.
run the dicts through scripts/dict/format.pl. I like pretty things
There was a problem hiding this comment.
That was the format after having run the format.pl script on the dictionaries
share/dictionary/der/dictionary
Outdated
| # | ||
|
|
||
| PROTOCOL DER 11354911 | ||
| BEGIN-PROTOCOL DER |
There was a problem hiding this comment.
Delete those two lines, and replace them with
BEGIN PROTOCOL DER 11354911
I think the server supports 64-bit protocol numbers? I haven't checked recently.
what's the significance of 11354911 ?
There was a problem hiding this comment.
I will update that line. There was no significance in 11354911. I believe @arr2036 may have used this number to avoid collision
70badd1 to
ad1bf39
Compare
| fr_dbuff_t our_in = FR_DBUFF(in); | ||
| uint8_t val; | ||
|
|
||
| size_t len = fr_dbuff_remaining(&our_in); |
There was a problem hiding this comment.
You should check the return code of fr_dbuff_out instead of manually checking the length
|
Default value flag should produce a value box. Using a |
|
Where possible you should still remove fr_dbuff_remaining where fr_dbuff_out would perform the same check |
|
Have some bad news |
|
Even with the artificial windows, it's probably better to use fr_dbuff_extend_lowat and check the return values. That lets the artificial "end" point to unrealised data. |
ad1bf39 to
d65db71
Compare
66c9ed8 to
41652a7
Compare
Signed-off-by: ethan-thompson <ethan.thompson@networkradius.com>
Signed-off-by: ethan-thompson <ethan.thompson@networkradius.com>
Signed-off-by: ethan-thompson <ethan.thompson@networkradius.com>
Signed-off-by: ethan-thompson <ethan.thompson@networkradius.com>
Signed-off-by: ethan-thompson <ethan.thompson@networkradius.com>
Signed-off-by: ethan-thompson <ethan.thompson@networkradius.com>
Signed-off-by: ethan-thompson <ethan.thompson@networkradius.com>
41652a7 to
c4d809c
Compare
| fr_dbuff_in(dbuff, (uint8_t)((slen) >> ((len_len - i - 1) * 8))); | ||
| } | ||
|
|
||
| fr_dbuff_set(dbuff, fr_dbuff_current(length_start) + len_len + 1 + slen); |
There was a problem hiding this comment.
This doesn't seem right? The function encodes the length, and then skips over the length + the data which will be encoded?
and almost all calls to this function do
...fr_der_encode_len(&our_dbuff, &length_start, fr_dbuff_behind(&length_start) - 1)
except for one...
| */ | ||
| fr_dict_enum_value_t const *evp; | ||
|
|
||
| evp = fr_dict_enum_by_name(vp->da, "DEFAULT", strlen("DEFAULT")); |
There was a problem hiding this comment.
I'll leave this in for now, but it could be in the dict_ext stuff?
There was a problem hiding this comment.
I made similar comments on the review call. It can just be a flag.
Wrote an encoder and decoder for DER. This adds the ability to decoder DER encoded X509 certificates and CSR's into dictionary attributes, as well as encode into DER.