Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/der encoder decoder #5497

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

ethan-thompson
Copy link
Contributor

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.

src/protocols/der/base.c Outdated Show resolved Hide resolved
* @copyright 2024 Inkbridge Networks SAS.
*/

#include "include/build.h"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nits: we usually put #include "foo" after all of the common includes. that way any location definitions don't affect the other header files.

*/

#include "include/build.h"
#include "der.h"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#include <freeradius-devel/util/table.h> etc.

};

fr_der_tag_constructed_t tag_labels[] = {
[FR_DER_TAG_BOOLEAN] = FR_DER_TAG_PRIMATIVE,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

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 },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 :(

}

static fr_dict_flag_parser_t const der_flags[] = {
{ L("class"), { .func = dict_flag_class } },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whitespace / indentation


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 },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

repeated repetition... :(

@@ -0,0 +1,171 @@
#include "include/build.h"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use <freeradius-devel/...

#include "include/build.h"
#include "lib/util/types.h"
#include <freeradius-devel/util/dict.h>
#include <stdbool.h>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stdbool and stdint should already be included by the types.h header

*/
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},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 ?

#define DER_BOOLEAN_TRUE 0xff //!< DER encoded boolean true value.

typedef struct {
uint8_t tagnum;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe format these so that the names are further to the right, and then all lined up vertically. that makes it easier to read.

}

#define fr_der_flag_tagnum(_da) (fr_der_attr_flags(_da)->tagnum)
#define fr_der_flag_class(_da) (fr_der_attr_flags(_da)->class)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whitespace nits :)

TARGET := libfreeradius-der$(L)

SOURCES := base.c \
decode.c \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe include push this commit until after the encode.c and decode.c files have been added. otherwise the build is broken.

* @copyright 2024 Arran Cudbard-Bell ([email protected])
* @copyright 2024 Inkbridge Networks SAS.
*/
#include "include/build.h"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

#include <freeradius-devel/util/time.h>
#include <freeradius-devel/util/value.h>
#include <stdlib.h>
#include <time.h>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

util/time.h already includes time.h


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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe add CC_HINT(nonnull) for the function prototypes

[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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comments and references to standards make me happy.

return -1;
}

if (unlikely(val != DER_BOOLEAN_FALSE && val != DER_BOOLEAN_TRUE)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

brackets around things. It's not required by C, but it cam avoid typos

if ((a == b) || (c == d))


vp = fr_pair_afrom_da(ctx, parent);
if (unlikely(vp == NULL)) {
fr_strerror_const("Out of memory for boolean pair");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

}

typedef struct {
TALLOC_CTX *ctx; /**< Allocation context */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comments can be aligned vertically, and use //!< which is more consistent with the rest of the code.

char *str = NULL;

static bool const allowed_chars[] = {
[' '] = true, ['\''] = true, ['('] = true, [')'] = true, ['+'] = true, [','] = true, ['-'] = true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

format as 4 per line, which makes it a bit easier to read

char *str = NULL;

static bool const allowed_chars[] = {
[0x08] = true, [0x0A] = true, [0x0C] = true, [0x0D] = true, [0x0E] = true, [0x0F] = true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 */

/*
* We have a multi-byte tag
*
* Note: Mutli-byte tags would mean having a tag number that is greater than 30 (0x1E) (since tag
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

multi

PROTOCOL DER 11354911
BEGIN-PROTOCOL DER

$INCLUDE dictionary.test
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

run ./scripts/dict/format.dl share/dictionary/der/dictionary*

for consistent formatting

@ethan-thompson ethan-thompson force-pushed the feature/der-encoder-decoder branch from 74074a9 to 70badd1 Compare January 23, 2025 19:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants