]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
add encoder, decoder, and tests for combo-ip
authorAlan T. DeKok <aland@freeradius.org>
Wed, 26 Feb 2025 19:33:43 +0000 (14:33 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Wed, 26 Feb 2025 19:40:42 +0000 (14:40 -0500)
share/dictionary/der/dictionary.common
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 e5e2d497896e83f2dc217e16f34dfa143e82bd5f..bc9a4c36281011c797bf7fb8a9eeb2fc390fb362 100644 (file)
@@ -38,6 +38,7 @@ END RDNSequence
 END directoryName
 
 ATTRIBUTE      uniformResourceIdentifier               6       ia5string option
+ATTRIBUTE      iPAddress                               7       combo-ip option
 
 END GeneralName
 
index 2707033fb240292988e0b1ead1e888aa799f268b..931a06e720844a13d08fa54022579821d003451f 100644 (file)
@@ -120,6 +120,10 @@ static const bool *fr_type_to_der_tags[FR_DER_TAG_MAX] = {
                [FR_DER_TAG_BITSTRING] = true,
        },
 
+       [FR_TYPE_COMBO_IP_ADDR] = (bool [FR_DER_TAG_MAX]) {
+               [FR_DER_TAG_OCTETSTRING] = true,
+       },
+
        [FR_TYPE_BOOL] = (bool [FR_DER_TAG_MAX]) {
                [FR_DER_TAG_BOOLEAN] = true,
                [FR_DER_TAG_INTEGER] = true,
@@ -618,7 +622,6 @@ static bool type_parse(fr_type_t *type_p,fr_dict_attr_t **da_p, char const *name
                return false;
 
        case FR_TYPE_IFID:
-       case FR_TYPE_COMBO_IP_ADDR:
        case FR_TYPE_COMBO_IP_PREFIX:
        case FR_TYPE_ETHERNET:
        case FR_TYPE_FLOAT32:
@@ -714,6 +717,8 @@ static const fr_der_tag_t fr_type_to_der_tag_defaults[FR_TYPE_MAX + 1] = {
        [FR_TYPE_IPV6_ADDR]     = FR_DER_TAG_BITSTRING,
        [FR_TYPE_IPV6_PREFIX]   = FR_DER_TAG_BITSTRING,
 
+       [FR_TYPE_COMBO_IP_ADDR] = FR_DER_TAG_OCTETSTRING,
+
        [FR_TYPE_BOOL]          = FR_DER_TAG_BOOLEAN,
 
        [FR_TYPE_UINT8]         = FR_DER_TAG_INTEGER,
index f0305bc1d4014cc5c87c8c4d1ae742db374200ef..fa4a904fca30371114616f61c5f159dc713ea035 100644 (file)
@@ -857,6 +857,14 @@ static ssize_t fr_der_decode_sequence(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_d
                                        child = fr_dict_attr_unknown_raw_afrom_num(decode_ctx->tmp_ctx, parent, current_tag);
                                        if (!child) return -1;
                                }
+
+                               /*
+                                *      Options always have to have the context field set.
+                                */
+                               if ((tag_byte & DER_TAG_CLASS_MASK) != FR_DER_CLASS_CONTEXT) {
+                                       fr_strerror_printf("Tag has unexpected class %20x", tag_byte & DER_TAG_CLASS_MASK);
+                                       return -1;
+                               }
                        }
 
                        FR_PROTO_TRACE("decode context %s -> %s", parent->name, child->name);
@@ -1644,6 +1652,53 @@ static ssize_t fr_der_decode_ipv6_prefix(TALLOC_CTX *ctx, fr_pair_list_t *out, f
        return fr_dbuff_set(in, &our_in);
 }
 
+static ssize_t fr_der_decode_combo_ip_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)
+{
+       fr_pair_t *vp;
+       fr_dbuff_t our_in = FR_DBUFF(in);
+       size_t len = fr_dbuff_remaining(&our_in);
+
+       /*
+        *      RFC5280 Section 4.2.1.6
+        *
+        *      When the subjectAltName extension contains an iPAddress, the address
+        *      MUST be stored in the octet string in "network byte order", as
+        *      specified in [RFC791].  The least significant bit (LSB) of each octet
+        *      is the LSB of the corresponding byte in the network address.  For IP
+        *      version 4, as specified in [RFC791], the octet string MUST contain
+        *      exactly four octets.  For IP version 6, as specified in
+        *      [RFC2460], the octet string MUST contain exactly sixteen octets.
+        */
+       if ((len != 4) && (len != 16)) {
+               fr_strerror_printf("Invalid combo_ip_addr size.  Expected 4 or 16, got %zu",
+                                  len);
+               return -1;
+       }
+
+       vp = fr_pair_afrom_da(ctx, parent);
+       if (unlikely(!vp)) {
+               fr_strerror_const("Out of memory");
+               return -1;
+       }
+
+       if (len == 4) {
+               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));
+
+       } else {
+               vp->vp_ip.af = AF_INET6;
+               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 },
@@ -1672,6 +1727,8 @@ static const fr_der_tag_decode_t type_funcs[FR_TYPE_MAX] = {
        [FR_TYPE_IPV4_PREFIX]   = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_ipv4_prefix },
        [FR_TYPE_IPV6_ADDR]     = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_ipv6_addr },
        [FR_TYPE_IPV6_PREFIX]   = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_ipv6_prefix },
+
+       [FR_TYPE_COMBO_IP_ADDR] = { .constructed = FR_DER_TAG_PRIMITIVE, .decode = fr_der_decode_combo_ip_addr },
 };
 
 /** Decode the tag and length fields of a DER encoded structure
index 153aff2522f7e30b69b30e1b4b6520d589d9c338..2e1da652e891baa1fbecefd3a21fc96cb2be561b 100644 (file)
@@ -501,6 +501,36 @@ static ssize_t fr_der_encode_ipv6_prefix(fr_dbuff_t *dbuff, fr_dcursor_t *cursor
 }
 
 
+static ssize_t fr_der_encode_combo_ip(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);
+
+       /*
+        *      RFC5280 Section 4.2.1.6
+        *
+        *      When the subjectAltName extension contains an iPAddress, the address
+        *      MUST be stored in the octet string in "network byte order", as
+        *      specified in [RFC791].  The least significant bit (LSB) of each octet
+        *      is the LSB of the corresponding byte in the network address.  For IP
+        *      version 4, as specified in [RFC791], the octet string MUST contain
+        *      exactly four octets.  For IP version 6, as specified in
+        *      [RFC2460], the octet string MUST contain exactly sixteen octets.
+        */
+       if (vp->vp_ip.af == AF_INET) {
+               FR_DBUFF_IN_MEMCPY_RETURN(&our_dbuff, (uint8_t const *) &vp->vp_ipv4addr, sizeof(vp->vp_ipv4addr));
+       } else {
+               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)
 {
@@ -1637,6 +1667,8 @@ static const fr_der_tag_encode_t type_funcs[FR_TYPE_MAX] = {
        [FR_TYPE_IPV4_PREFIX]     = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_ipv4_prefix },
        [FR_TYPE_IPV6_ADDR]       = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_ipv6_addr },
        [FR_TYPE_IPV6_PREFIX]     = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_ipv6_prefix },
+
+       [FR_TYPE_COMBO_IP_ADDR]   = { .constructed = FR_DER_TAG_PRIMITIVE, .encode = fr_der_encode_combo_ip },
 };
 
 
index da4b8b88a8337f17107c4eab883d9ad278f5b06b..af19dacb65914d4bbacbbd0f7d76f25b4a448334 100644 (file)
@@ -900,5 +900,24 @@ match Test-IPv4-Prefix = 10.5.0.4/32
 decode-pair 03 01 00
 match Test-IPv4-Prefix = 0.0.0.0/0
 
+proto-dictionary der
+
+#
+#  IP address as fixed-size octets  i.e. GeneralName.iPAddress
+#
+encode-pair Test-GeneralNames = { dNSName = "foo.bar" }
+match 30 09 82 07 66 6f 6f 2e 62 61 72
+
+encode-pair Test-GeneralNames = { iPAddress = 10.0.5.4 }
+match 30 06 87 04 0a 00 05 04
+
+proto-dictionary-root Test-GeneralNames
+
+decode-pair 30 09 82 07 66 6f 6f 2e 62 61 72
+match Test-GeneralNames = { dNSName = "foo.bar" }
+
+decode-pair 30 06 87 04 0a 00 05 04
+match Test-GeneralNames = { iPAddress = 10.0.5.4 }
+
 count
-match 543
+match 553
index 0677a6966fccb640c31fed8db89afa673cbe0d0d..0f93b18212822ba407cf7163bab9d7f3c2239bd4 100644 (file)
@@ -4,6 +4,8 @@
 # Version $Id$
 DEFINE Certificate-Extensions                          x509_extensions ref=@.OID-Tree
 
+DEFINE Test-GeneralNames                               group sequence_of=choice,ref=@.GeneralName
+
 DEFINE Issuer                                          sequence sequence_of=set
 BEGIN Issuer
 DEFINE RelativeDistinguishedName                       set clone=@.RelativeDistinguishedName