]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add encode / decode of ipv4add and ipv6addr
authorAlan T. DeKok <aland@freeradius.org>
Tue, 25 Feb 2025 20:01:06 +0000 (15:01 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Tue, 25 Feb 2025 20:22:56 +0000 (15:22 -0500)
RFC 3779 defines a format for IP addresses, and IP prefixes

src/protocols/der/base.c
src/protocols/der/decode.c
src/protocols/der/encode.c
src/tests/unit/protocols/der/base.txt
src/tests/unit/protocols/der/dictionary.test

index 457b844ffd88b137eff3f544cac14f2b9e7386dd..8d082bc76ff638c38a4be3c1d6a12681d00f3f8a 100644 (file)
@@ -104,6 +104,14 @@ bool fr_der_tags_compatible(fr_der_tag_t tag1, fr_der_tag_t tag2)
  *     Create a mapping between FR_TYPE_* and valid FR_DER_TAG_*'s
  */
 static const bool *fr_type_to_der_tags[FR_DER_TAG_MAX] = {
+       [FR_TYPE_IPV4_ADDR] = (bool [FR_DER_TAG_MAX]) {
+               [FR_DER_TAG_BITSTRING] = true,
+       },
+
+       [FR_TYPE_IPV6_ADDR] = (bool [FR_DER_TAG_MAX]) {
+               [FR_DER_TAG_BITSTRING] = true,
+       },
+
        [FR_TYPE_BOOL] = (bool [FR_DER_TAG_MAX]) {
                [FR_DER_TAG_BOOLEAN] = true,
                [FR_DER_TAG_INTEGER] = true,
@@ -587,9 +595,7 @@ static bool type_parse(fr_type_t *type_p,fr_dict_attr_t **da_p, char const *name
                fr_strerror_const("Cannot use 'tlv' in DER.  Please use 'sequence'");
                return false;
 
-       case FR_TYPE_IPV4_ADDR:
        case FR_TYPE_IPV4_PREFIX:
-       case FR_TYPE_IPV6_ADDR:
        case FR_TYPE_IPV6_PREFIX:
        case FR_TYPE_IFID:
        case FR_TYPE_COMBO_IP_ADDR:
@@ -677,7 +683,14 @@ static bool type_parse(fr_type_t *type_p,fr_dict_attr_t **da_p, char const *name
 }
 
 static const fr_der_tag_t fr_type_to_der_tag_defaults[FR_TYPE_MAX + 1] = {
+       [FR_TYPE_OCTETS]        = FR_DER_TAG_OCTETSTRING,
+       [FR_TYPE_STRING]        = FR_DER_TAG_UTF8_STRING,
+
+       [FR_TYPE_IPV4_ADDR]     = FR_DER_TAG_BITSTRING,
+       [FR_TYPE_IPV6_ADDR]     = FR_DER_TAG_BITSTRING,
+
        [FR_TYPE_BOOL]          = FR_DER_TAG_BOOLEAN,
+
        [FR_TYPE_UINT8]         = FR_DER_TAG_INTEGER,
        [FR_TYPE_UINT16]        = FR_DER_TAG_INTEGER,
        [FR_TYPE_UINT32]        = FR_DER_TAG_INTEGER,
@@ -686,8 +699,6 @@ static const fr_der_tag_t fr_type_to_der_tag_defaults[FR_TYPE_MAX + 1] = {
        [FR_TYPE_INT16]         = FR_DER_TAG_INTEGER,
        [FR_TYPE_INT32]         = FR_DER_TAG_INTEGER,
        [FR_TYPE_INT64]         = FR_DER_TAG_INTEGER,
-       [FR_TYPE_OCTETS]        = FR_DER_TAG_OCTETSTRING,
-       [FR_TYPE_STRING]        = FR_DER_TAG_UTF8_STRING,
        [FR_TYPE_DATE]          = FR_DER_TAG_GENERALIZED_TIME,
        [FR_TYPE_TLV]           = FR_DER_TAG_SEQUENCE,
        [FR_TYPE_STRUCT]        = FR_DER_TAG_SEQUENCE,
index c14273ac5267fc2e5f42186cb0f6f309206552d4..4977beff0e78bda9dcbf4c2f640358e6ea5e5652 100644 (file)
@@ -82,84 +82,6 @@ typedef struct {
 static ssize_t fr_der_decode_pair_dbuff(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent,
                                        fr_dbuff_t *in, fr_der_decode_ctx_t *decode_ctx) CC_HINT(nonnull);
 
-static ssize_t fr_der_decode_boolean(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, fr_dbuff_t *in,
-                                    fr_der_decode_ctx_t *decode_ctx) CC_HINT(nonnull);
-
-static ssize_t fr_der_decode_integer(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, fr_dbuff_t *in,
-                                    fr_der_decode_ctx_t *decode_ctx) CC_HINT(nonnull);
-
-static ssize_t fr_der_decode_bitstring(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent,
-                                      fr_dbuff_t *in, fr_der_decode_ctx_t *decode_ctx) CC_HINT(nonnull);
-
-static ssize_t fr_der_decode_octetstring(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent,
-                                        fr_dbuff_t *in, fr_der_decode_ctx_t *decode_ctx) CC_HINT(nonnull);
-
-static ssize_t fr_der_decode_null(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, fr_dbuff_t *in,
-                                 fr_der_decode_ctx_t *decode_ctx) CC_HINT(nonnull);
-
-static ssize_t fr_der_decode_utf8_string(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent,
-                                        fr_dbuff_t *in, fr_der_decode_ctx_t *decode_ctx) CC_HINT(nonnull);
-
-static ssize_t fr_der_decode_sequence(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent,
-                                     fr_dbuff_t *in, fr_der_decode_ctx_t *decode_ctx) CC_HINT(nonnull);
-
-static ssize_t fr_der_decode_set(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, fr_dbuff_t *in,
-                                fr_der_decode_ctx_t *decode_ctx) CC_HINT(nonnull);
-
-static ssize_t fr_der_decode_printable_string(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent,
-                                             fr_dbuff_t *in, fr_der_decode_ctx_t *decode_ctx) CC_HINT(nonnull);
-
-static ssize_t fr_der_decode_t61_string(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent,
-                                       fr_dbuff_t *in, fr_der_decode_ctx_t *decode_ctx) CC_HINT(nonnull);
-
-static ssize_t fr_der_decode_ia5_string(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent,
-                                       fr_dbuff_t *in, fr_der_decode_ctx_t *decode_ctx) CC_HINT(nonnull);
-
-static ssize_t fr_der_decode_utc_time(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent,
-                                     fr_dbuff_t *in, fr_der_decode_ctx_t *decode_ctx) CC_HINT(nonnull);
-
-static ssize_t fr_der_decode_generalized_time(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent,
-                                             fr_dbuff_t *in, fr_der_decode_ctx_t *decode_ctx) CC_HINT(nonnull);
-
-static ssize_t fr_der_decode_visible_string(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent,
-                                           fr_dbuff_t *in, fr_der_decode_ctx_t *decode_ctx) CC_HINT(nonnull);
-
-static ssize_t fr_der_decode_general_string(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent,
-                                           fr_dbuff_t *in, fr_der_decode_ctx_t *decode_ctx) CC_HINT(nonnull);
-
-static ssize_t fr_der_decode_universal_string(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent,
-                                             fr_dbuff_t *in, fr_der_decode_ctx_t *decode_ctx) CC_HINT(nonnull);
-
-/*
- *     We have per-type function names to make it clear that different types have different decoders.
- *     However, the methods to decode them are the same.  So rather than having trampoline functions, we just
- *     use defines.
- */
-#define fr_der_decode_enumerated fr_der_decode_integer
-
-static fr_der_tag_decode_t tag_funcs[FR_DER_TAG_MAX] = {
-       [FR_DER_TAG_BOOLEAN]          = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_boolean },
-       [FR_DER_TAG_INTEGER]          = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_integer },
-       [FR_DER_TAG_BITSTRING]        = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_bitstring },
-       [FR_DER_TAG_OCTETSTRING]      = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_octetstring },
-       [FR_DER_TAG_NULL]             = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_null },
-       [FR_DER_TAG_ENUMERATED]       = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_enumerated },
-       [FR_DER_TAG_UTF8_STRING]      = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_utf8_string },
-       [FR_DER_TAG_SEQUENCE]         = { .constructed = FR_DER_TAG_CONSTRUCTED, .decode = fr_der_decode_sequence },
-       [FR_DER_TAG_SET]              = { .constructed = FR_DER_TAG_CONSTRUCTED, .decode = fr_der_decode_set },
-       [FR_DER_TAG_PRINTABLE_STRING] = { .constructed = FR_DER_TAG_PRIMITIVE,
-                                         .decode      = fr_der_decode_printable_string },
-       [FR_DER_TAG_T61_STRING]       = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_t61_string },
-       [FR_DER_TAG_IA5_STRING]       = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_ia5_string },
-       [FR_DER_TAG_UTC_TIME]         = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_utc_time },
-       [FR_DER_TAG_GENERALIZED_TIME] = { .constructed = FR_DER_TAG_PRIMITIVE,
-                                         .decode      = fr_der_decode_generalized_time },
-       [FR_DER_TAG_VISIBLE_STRING]   = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_visible_string },
-       [FR_DER_TAG_GENERAL_STRING]   = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_general_string },
-       [FR_DER_TAG_UNIVERSAL_STRING] = { .constructed = FR_DER_TAG_PRIMITIVE,
-                                         .decode      = fr_der_decode_universal_string },
-};
-
 static ssize_t fr_der_decode_string(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, fr_dbuff_t *in,
                                    bool const allowed_chars[], fr_der_decode_ctx_t *decode_ctx) CC_HINT(nonnull(1,2,3,4,6));
 
@@ -1504,6 +1426,13 @@ static ssize_t fr_der_decode_visible_string(TALLOC_CTX *ctx, fr_pair_list_t *out
        return fr_der_decode_string(ctx, out, parent, in, allowed_chars, decode_ctx);
 }
 
+/*
+ *     We have per-type function names to make it clear that different types have different decoders.
+ *     However, the methods to decode them are the same.  So rather than having trampoline functions, we just
+ *     use defines.
+ */
+#define fr_der_decode_enumerated fr_der_decode_integer
+
 static ssize_t fr_der_decode_general_string(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent,
                                            fr_dbuff_t *in, UNUSED fr_der_decode_ctx_t *decode_ctx)
 {
@@ -1516,6 +1445,102 @@ static ssize_t fr_der_decode_universal_string(TALLOC_CTX *ctx, fr_pair_list_t *o
        return fr_der_decode_string(ctx, out, parent, in, NULL, decode_ctx);
 }
 
+static ssize_t fr_der_decode_ipv4_addr(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent,
+                                      fr_dbuff_t *in, UNUSED fr_der_decode_ctx_t *decode_ctx)
+{
+       uint8_t byte;
+       fr_pair_t *vp;
+       fr_dbuff_t our_in = FR_DBUFF(in);
+
+       if (fr_dbuff_remaining(&our_in) != 1 + sizeof(vp->vp_ipv4addr)) {
+               fr_strerror_printf("Invalid ipv4addr size.  Expected %zu, got %zu",
+                                  1 + sizeof(vp->vp_ipv4addr), fr_dbuff_remaining(&our_in));
+               return -1;
+       }
+
+       FR_DBUFF_OUT_RETURN(&byte, &our_in);
+       if (byte != 0) {
+               fr_strerror_printf("Invalid ipv4addr prefix is non-zero (%02x)", byte);
+               return -1;
+       }
+
+       vp = fr_pair_afrom_da(ctx, parent);
+       if (unlikely(!vp)) {
+               fr_strerror_const("Out of memory");
+               return -1;
+       }
+
+       vp->vp_ip.af = AF_INET;
+       vp->vp_ip.prefix = 32;
+       FR_DBUFF_OUT_MEMCPY_RETURN((uint8_t *) &vp->vp_ipv4addr, &our_in, sizeof(vp->vp_ipv4addr));
+
+       fr_pair_append(out, vp);
+
+       return fr_dbuff_set(in, &our_in);
+}
+
+static ssize_t fr_der_decode_ipv6_addr(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent,
+                                      fr_dbuff_t *in, UNUSED fr_der_decode_ctx_t *decode_ctx)
+{
+       uint8_t byte;
+       fr_pair_t *vp;
+       fr_dbuff_t our_in = FR_DBUFF(in);
+
+       if (fr_dbuff_remaining(&our_in) != 1 + sizeof(vp->vp_ipv6addr)) {
+               fr_strerror_printf("Invalid ipv6addr size.  Expected %zu, got %zu",
+                                  1 + sizeof(vp->vp_ipv6addr), fr_dbuff_remaining(&our_in));
+               return -1;
+       }
+
+       FR_DBUFF_OUT_RETURN(&byte, &our_in);
+       if (byte != 0) {
+               fr_strerror_printf("Invalid ipv6addr prefix is non-zero (%02x)", byte);
+               return -1;
+       }
+
+       vp = fr_pair_afrom_da(ctx, parent);
+       if (unlikely(!vp)) {
+               fr_strerror_const("Out of memory");
+               return -1;
+       }
+
+       vp->vp_ip.af = AF_INET;
+       vp->vp_ip.prefix = 128;
+       FR_DBUFF_OUT_MEMCPY_RETURN((uint8_t *) &vp->vp_ipv6addr, &our_in, sizeof(vp->vp_ipv6addr));
+
+       fr_pair_append(out, vp);
+
+       return fr_dbuff_set(in, &our_in);
+}
+
+static const fr_der_tag_decode_t tag_funcs[FR_DER_TAG_MAX] = {
+       [FR_DER_TAG_BOOLEAN]          = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_boolean },
+       [FR_DER_TAG_INTEGER]          = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_integer },
+       [FR_DER_TAG_BITSTRING]        = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_bitstring },
+       [FR_DER_TAG_OCTETSTRING]      = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_octetstring },
+       [FR_DER_TAG_NULL]             = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_null },
+       [FR_DER_TAG_ENUMERATED]       = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_enumerated },
+       [FR_DER_TAG_UTF8_STRING]      = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_utf8_string },
+       [FR_DER_TAG_SEQUENCE]         = { .constructed = FR_DER_TAG_CONSTRUCTED, .decode = fr_der_decode_sequence },
+       [FR_DER_TAG_SET]              = { .constructed = FR_DER_TAG_CONSTRUCTED, .decode = fr_der_decode_set },
+       [FR_DER_TAG_PRINTABLE_STRING] = { .constructed = FR_DER_TAG_PRIMITIVE,
+                                         .decode      = fr_der_decode_printable_string },
+       [FR_DER_TAG_T61_STRING]       = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_t61_string },
+       [FR_DER_TAG_IA5_STRING]       = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_ia5_string },
+       [FR_DER_TAG_UTC_TIME]         = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_utc_time },
+       [FR_DER_TAG_GENERALIZED_TIME] = { .constructed = FR_DER_TAG_PRIMITIVE,
+                                         .decode      = fr_der_decode_generalized_time },
+       [FR_DER_TAG_VISIBLE_STRING]   = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_visible_string },
+       [FR_DER_TAG_GENERAL_STRING]   = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_general_string },
+       [FR_DER_TAG_UNIVERSAL_STRING] = { .constructed = FR_DER_TAG_PRIMITIVE,
+                                         .decode      = fr_der_decode_universal_string },
+};
+
+static const fr_der_tag_decode_t type_funcs[FR_TYPE_MAX] = {
+       [FR_TYPE_IPV4_ADDR]     = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_ipv4_addr },
+       [FR_TYPE_IPV6_ADDR]     = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_ipv6_addr },
+};
+
 /** Decode the tag and length fields of a DER encoded structure
  *
  * @param[in] parent   Parent attribute
@@ -1530,7 +1555,7 @@ static ssize_t fr_der_decode_hdr(fr_dict_attr_t const *parent, fr_dbuff_t *in, u
        fr_dbuff_t               our_in = FR_DBUFF(in);
        uint8_t                  tag_byte;
        uint8_t                  len_byte;
-       fr_der_tag_decode_t     *func;
+       fr_der_tag_decode_t const *func;
        fr_der_tag_class_t       tag_class;
        fr_der_tag_constructed_t constructed;
        fr_der_attr_flags_t const *flags;
@@ -1601,7 +1626,18 @@ static ssize_t fr_der_decode_hdr(fr_dict_attr_t const *parent, fr_dbuff_t *in, u
                return -1;
        }
 
-       func = &tag_funcs[*tag];
+       if (parent) switch (parent->type) {
+       case FR_TYPE_IPV4_ADDR:
+       case FR_TYPE_IPV6_ADDR:
+               func = &type_funcs[parent->type];
+               break;
+
+       default:
+               func = &tag_funcs[*tag];
+               break;
+       } else {
+               func = &tag_funcs[*tag];
+       }
 
        /*
         *      Check if the tag is an OID. OID tags will be handled differently
@@ -2148,7 +2184,7 @@ static ssize_t fr_der_decode_pair_dbuff(TALLOC_CTX *ctx, fr_pair_list_t *out, fr
                                        fr_dbuff_t *in, fr_der_decode_ctx_t *decode_ctx)
 {
        fr_dbuff_t           our_in = FR_DBUFF(in);
-       fr_der_tag_decode_t *func;
+       fr_der_tag_decode_t const *func;
        ssize_t              slen;
        uint8_t              tag;
        size_t               len;
@@ -2334,7 +2370,17 @@ static ssize_t fr_der_decode_pair_dbuff(TALLOC_CTX *ctx, fr_pair_list_t *out, fr
                return fr_dbuff_set(in, &our_in);
        }
 
-       func = &tag_funcs[tag];
+       switch (parent->type) {
+       case FR_TYPE_IPV4_ADDR:
+       case FR_TYPE_IPV6_ADDR:
+               func = &type_funcs[parent->type];
+               break;
+
+       default:
+               func = &tag_funcs[tag];
+               break;
+       }
+       fr_assert(func != NULL);
 
        /*
         *      Enforce limits on min/max.
index b035040781dd161570949a4d5594b65d65e4fd4b..e1a9befbd732259b0da9272dd8dc5e7717a6cfa5 100644 (file)
@@ -62,21 +62,9 @@ typedef struct {
        fr_der_encode_t          encode;
 } fr_der_tag_encode_t;
 
-static ssize_t fr_der_encode_boolean(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, fr_der_encode_ctx_t *encode_ctx) CC_HINT(nonnull(1,2));
-static ssize_t fr_der_encode_integer(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, fr_der_encode_ctx_t *encode_ctx) CC_HINT(nonnull(1,2));
-static ssize_t fr_der_encode_bitstring(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, fr_der_encode_ctx_t *encode_ctx) CC_HINT(nonnull);
-static ssize_t fr_der_encode_octetstring(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, fr_der_encode_ctx_t *encode_ctx) CC_HINT(nonnull);
-static ssize_t fr_der_encode_null(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, fr_der_encode_ctx_t *encode_ctx) CC_HINT(nonnull(2));
-static ssize_t fr_der_encode_oid(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, fr_der_encode_ctx_t *encode_ctx) CC_HINT(nonnull(1,2));
-static ssize_t fr_der_encode_sequence(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, fr_der_encode_ctx_t *encode_ctx) CC_HINT(nonnull);
-static ssize_t fr_der_encode_set(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, fr_der_encode_ctx_t *encode_ctx) CC_HINT(nonnull);
-static ssize_t fr_der_encode_utc_time(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, fr_der_encode_ctx_t *encode_ctx) CC_HINT(nonnull(1,2));
-static ssize_t fr_der_encode_generalized_time(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, fr_der_encode_ctx_t *encode_ctx) CC_HINT(nonnull(1,2));
 
 static ssize_t fr_der_encode_oid_value_pair(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, fr_der_encode_ctx_t *encode_ctx) CC_HINT(nonnull);
 
-static ssize_t fr_der_encode_string(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, fr_der_encode_ctx_t *encode_ctx) CC_HINT(nonnull(1,2));
-
 /*
  *     We have per-type function names to make it clear that different types have different encoders.
  *     However, the methods to encode them are the same.  So rather than having trampoline functions, we just
@@ -95,30 +83,6 @@ static ssize_t encode_pair(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned
                           void *encode_ctx);
 static ssize_t der_encode_pair(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, void *encode_ctx) CC_HINT(nonnull);
 
-static fr_der_tag_encode_t tag_funcs[FR_DER_TAG_MAX] = {
-       [FR_DER_TAG_BOOLEAN]          = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_boolean },
-       [FR_DER_TAG_INTEGER]          = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_integer },
-       [FR_DER_TAG_BITSTRING]        = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_bitstring },
-       [FR_DER_TAG_OCTETSTRING]      = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_octetstring },
-       [FR_DER_TAG_NULL]             = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_null },
-       [FR_DER_TAG_OID]              = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_oid },
-       [FR_DER_TAG_ENUMERATED]       = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_enumerated },
-       [FR_DER_TAG_UTF8_STRING]      = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_string },
-       [FR_DER_TAG_SEQUENCE]         = { .constructed = FR_DER_TAG_CONSTRUCTED, .encode = fr_der_encode_sequence },
-       [FR_DER_TAG_SET]              = { .constructed = FR_DER_TAG_CONSTRUCTED, .encode = fr_der_encode_set },
-       [FR_DER_TAG_PRINTABLE_STRING] = { .constructed = FR_DER_TAG_PRIMITIVE,
-                                         .encode      = fr_der_encode_string },
-       [FR_DER_TAG_T61_STRING]       = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_string },
-       [FR_DER_TAG_IA5_STRING]       = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_string },
-       [FR_DER_TAG_UTC_TIME]         = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_utc_time },
-       [FR_DER_TAG_GENERALIZED_TIME] = { .constructed = FR_DER_TAG_PRIMITIVE,
-                                         .encode      = fr_der_encode_generalized_time },
-       [FR_DER_TAG_VISIBLE_STRING]   = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_string },
-       [FR_DER_TAG_GENERAL_STRING]   = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_string },
-       [FR_DER_TAG_UNIVERSAL_STRING] = { .constructed = FR_DER_TAG_PRIMITIVE,
-                                         .encode      = fr_der_encode_string },
-};
-
 /** Compare two pairs by their tag number.
  *
  * @param[in] a        First pair.
@@ -381,7 +345,7 @@ static ssize_t fr_der_encode_bitstring(fr_dbuff_t *dbuff, fr_dcursor_t *cursor,
         *      because this information should be retained when encoding/decoding.
         */
        if (vp->vp_length == 0) {
-               FR_DBUFF_IN_RETURN(&our_dbuff, 0x00);
+               FR_DBUFF_IN_RETURN(&our_dbuff, (uint8_t) 0x00);
 
        } else {
                FR_DBUFF_IN_MEMCPY_RETURN(&our_dbuff, vp->vp_octets, vp->vp_length);
@@ -390,6 +354,72 @@ static ssize_t fr_der_encode_bitstring(fr_dbuff_t *dbuff, fr_dcursor_t *cursor,
        return fr_dbuff_set(dbuff, &our_dbuff);
 }
 
+static ssize_t fr_der_encode_ipv4_addr(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, UNUSED fr_der_encode_ctx_t *encode_ctx)
+{
+       fr_dbuff_t       our_dbuff = FR_DBUFF(dbuff);
+       fr_pair_t const *vp;
+
+       vp = fr_dcursor_current(cursor);
+       PAIR_VERIFY(vp);
+       fr_assert(!vp->da->flags.is_raw);
+
+       /*
+        *      RFC3779 Section 2.1.1.
+        *
+        *      An IP address or prefix is encoded in the IP address delegation
+        *      extension as a DER-encoded ASN.1 BIT STRING containing the constant
+        *      most-significant bits.  Recall [X.690] that the DER encoding of a BIT
+        *      STRING consists of the BIT STRING type (0x03), followed by (an
+        *      encoding of) the number of value octets, followed by the value.  The
+        *      value consists of an "initial octet" that specifies the number of
+        *      unused bits in the last value octet, followed by the "subsequent
+        *      octets" that contain the octets of the bit string.  (For IP
+        *      addresses, the encoding of the length will be just the length.)
+        */
+
+       /*
+        *      The number of unused bits in the last byte is always zero.
+        */
+       FR_DBUFF_IN_RETURN(&our_dbuff, (uint8_t) 0x00);
+       FR_DBUFF_IN_MEMCPY_RETURN(&our_dbuff, (uint8_t const *) &vp->vp_ipv4addr, sizeof(vp->vp_ipv4addr));
+
+       return fr_dbuff_set(dbuff, &our_dbuff);
+}
+
+static ssize_t fr_der_encode_ipv6_addr(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, UNUSED fr_der_encode_ctx_t *encode_ctx)
+{
+       fr_dbuff_t       our_dbuff = FR_DBUFF(dbuff);
+       fr_pair_t const *vp;
+
+       vp = fr_dcursor_current(cursor);
+       PAIR_VERIFY(vp);
+       fr_assert(!vp->da->flags.is_raw);
+
+       /*
+        *      RFC3779 Section 2.1.1.
+        *
+        *      An IP address or prefix is encoded in the IP address delegation
+        *      extension as a DER-encoded ASN.1 BIT STRING containing the constant
+        *      most-significant bits.  Recall [X.690] that the DER encoding of a BIT
+        *      STRING consists of the BIT STRING type (0x03), followed by (an
+        *      encoding of) the number of value octets, followed by the value.  The
+        *      value consists of an "initial octet" that specifies the number of
+        *      unused bits in the last value octet, followed by the "subsequent
+        *      octets" that contain the octets of the bit string.  (For IP
+        *      addresses, the encoding of the length will be just the length.)
+        */
+
+       /*
+        *      The number of unused bits in the last byte is always zero.
+        */
+       FR_DBUFF_IN_RETURN(&our_dbuff, (uint8_t) 0x00);
+       FR_DBUFF_IN_MEMCPY_RETURN(&our_dbuff, (uint8_t const *) &vp->vp_ipv6addr, sizeof(vp->vp_ipv6addr));
+
+       return fr_dbuff_set(dbuff, &our_dbuff);
+}
+
+
+
 static ssize_t fr_der_encode_octetstring(fr_dbuff_t *dbuff, fr_dcursor_t *cursor,
                                         UNUSED fr_der_encode_ctx_t *encode_ctx)
 {
@@ -429,6 +459,7 @@ static ssize_t fr_der_encode_octetstring(fr_dbuff_t *dbuff, fr_dcursor_t *cursor
        return fr_dbuff_set(dbuff, &our_dbuff);
 }
 
+
 static ssize_t fr_der_encode_null(UNUSED fr_dbuff_t *dbuff, fr_dcursor_t *cursor,
                                  UNUSED fr_der_encode_ctx_t *encode_ctx)
 {
@@ -1519,6 +1550,36 @@ static ssize_t fr_der_encode_string(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, UNU
        return fr_dbuff_set(dbuff, &our_dbuff);
 }
 
+static const fr_der_tag_encode_t tag_funcs[FR_DER_TAG_MAX] = {
+       [FR_DER_TAG_BOOLEAN]          = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_boolean },
+       [FR_DER_TAG_INTEGER]          = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_integer },
+       [FR_DER_TAG_BITSTRING]        = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_bitstring },
+       [FR_DER_TAG_OCTETSTRING]      = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_octetstring },
+       [FR_DER_TAG_NULL]             = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_null },
+       [FR_DER_TAG_OID]              = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_oid },
+       [FR_DER_TAG_ENUMERATED]       = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_enumerated },
+       [FR_DER_TAG_UTF8_STRING]      = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_string },
+       [FR_DER_TAG_SEQUENCE]         = { .constructed = FR_DER_TAG_CONSTRUCTED, .encode = fr_der_encode_sequence },
+       [FR_DER_TAG_SET]              = { .constructed = FR_DER_TAG_CONSTRUCTED, .encode = fr_der_encode_set },
+       [FR_DER_TAG_PRINTABLE_STRING] = { .constructed = FR_DER_TAG_PRIMITIVE,
+                                         .encode      = fr_der_encode_string },
+       [FR_DER_TAG_T61_STRING]       = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_string },
+       [FR_DER_TAG_IA5_STRING]       = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_string },
+       [FR_DER_TAG_UTC_TIME]         = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_utc_time },
+       [FR_DER_TAG_GENERALIZED_TIME] = { .constructed = FR_DER_TAG_PRIMITIVE,
+                                         .encode      = fr_der_encode_generalized_time },
+       [FR_DER_TAG_VISIBLE_STRING]   = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_string },
+       [FR_DER_TAG_GENERAL_STRING]   = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_string },
+       [FR_DER_TAG_UNIVERSAL_STRING] = { .constructed = FR_DER_TAG_PRIMITIVE,
+                                         .encode      = fr_der_encode_string },
+};
+
+static const fr_der_tag_encode_t type_funcs[FR_TYPE_MAX] = {
+       [FR_TYPE_IPV4_ADDR]       = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_ipv4_addr },
+       [FR_TYPE_IPV6_ADDR]       = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_ipv6_addr },
+};
+
+
 /** Encode the length field of a DER structure
  *
  *  The input dbuff is composed of the following data:
@@ -1646,7 +1707,7 @@ static ssize_t encode_value(fr_dbuff_t *dbuff, UNUSED fr_da_stack_t *da_stack, U
        fr_pair_t const     *vp;
        fr_dbuff_t           our_dbuff = FR_DBUFF(dbuff);
        fr_dbuff_marker_t    marker, encoding_start;
-       fr_der_tag_encode_t *func;
+       fr_der_tag_encode_t const *func;
        fr_der_tag_t         tag;
        fr_der_tag_class_t   tag_class;
        fr_der_encode_ctx_t *uctx = encode_ctx;
@@ -1749,11 +1810,17 @@ static ssize_t encode_value(fr_dbuff_t *dbuff, UNUSED fr_da_stack_t *da_stack, U
 
        fr_assert(tag < FR_DER_TAG_MAX);
 
-       func = &tag_funcs[tag];
-       if (!func->encode) {
-               fr_strerror_printf("No encoding function for type %s", fr_type_to_str(vp->vp_type));
-               return -1;
+       switch (vp->vp_type) {
+       case FR_TYPE_IPV4_ADDR:
+       case FR_TYPE_IPV6_ADDR:
+               func = &type_funcs[tag];
+               break;
+
+       default:
+               func = &tag_funcs[tag];
+               break;
        }
+       fr_assert(func->encode != NULL);
 
        /*
         *      Default flag class is 0, which is FR_DER_CLASS_UNIVERSAL.
index d41fefed8751f205b3720b24987ea1d5092e9a71..c7750ed338bac0813c4486ae88290e77a55e987a 100644 (file)
@@ -874,5 +874,15 @@ match 30 03 01 01 ff
 encode-pair Issuer = { RelativeDistinguishedName = { AttributeTypeAndValue = { joint-iso-itu-t = { ds = { attributeType = { organizationName = "Digital Signature Trust Co." } } } } }, RelativeDistinguishedName = { AttributeTypeAndValue = { joint-iso-itu-t = { ds = { attributeType = { commonName = "DST Root CA X3" } } } } } }
 match 30 3f 31 24 30 22 06 03 55 04 0a 13 1b 44 69 67 69 74 61 6c 20 53 69 67 6e 61 74 75 72 65 20 54 72 75 73 74 20 43 6f 2e 31 17 30 15 06 03 55 04 03 13 0e 44 53 54 20 52 6f 6f 74 20 43 41 20 58 33
 
+proto-dictionary der
+
+encode-pair Test-IPv4-Address = 10.5.0.4
+match 03 05 00 0a 05 00 04
+
+proto-dictionary-root Test-IPv4-Address
+
+decode-pair 03 05 00 0a 05 00 04
+match Test-IPv4-Address = 10.5.0.4
+
 count
-match 529
+match 535
index ff9c5d1114c8c645fc59e9281561d1e5111f88b0..7ce33f51eeee69cc08d6d92d17f666009d82e933 100644 (file)
@@ -30,6 +30,9 @@ DEFINE        Test-Boolean                                    bool
 
 DEFINE Test-Integer                                    integer
 
+DEFINE Test-IPv4-Address                               ipv4addr
+DEFINE Test-IPv6-Address                               ipv4addr
+
 DEFINE Foo                                             sequence sequence_of=integer
 BEGIN Foo
 DEFINE         Test-Integer                            integer