From: Alan T. DeKok Date: Wed, 26 Feb 2025 19:33:43 +0000 (-0500) Subject: add encoder, decoder, and tests for combo-ip X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=84fb8e1857d8e02d1ef22a2fb200d8e4c33c1230;p=thirdparty%2Ffreeradius-server.git add encoder, decoder, and tests for combo-ip --- diff --git a/share/dictionary/der/dictionary.common b/share/dictionary/der/dictionary.common index e5e2d49789..bc9a4c3628 100644 --- a/share/dictionary/der/dictionary.common +++ b/share/dictionary/der/dictionary.common @@ -38,6 +38,7 @@ END RDNSequence END directoryName ATTRIBUTE uniformResourceIdentifier 6 ia5string option +ATTRIBUTE iPAddress 7 combo-ip option END GeneralName diff --git a/src/protocols/der/base.c b/src/protocols/der/base.c index 2707033fb2..931a06e720 100644 --- a/src/protocols/der/base.c +++ b/src/protocols/der/base.c @@ -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, diff --git a/src/protocols/der/decode.c b/src/protocols/der/decode.c index f0305bc1d4..fa4a904fca 100644 --- a/src/protocols/der/decode.c +++ b/src/protocols/der/decode.c @@ -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 diff --git a/src/protocols/der/encode.c b/src/protocols/der/encode.c index 153aff2522..2e1da652e8 100644 --- a/src/protocols/der/encode.c +++ b/src/protocols/der/encode.c @@ -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 }, }; diff --git a/src/tests/unit/protocols/der/base.txt b/src/tests/unit/protocols/der/base.txt index da4b8b88a8..af19dacb65 100644 --- a/src/tests/unit/protocols/der/base.txt +++ b/src/tests/unit/protocols/der/base.txt @@ -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 diff --git a/src/tests/unit/protocols/der/dictionary.test b/src/tests/unit/protocols/der/dictionary.test index 0677a6966f..0f93b18212 100644 --- a/src/tests/unit/protocols/der/dictionary.test +++ b/src/tests/unit/protocols/der/dictionary.test @@ -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