X509V3_ASID_ADD_ID_OR_RANGE(3ssl)

πŸ“¦ version 4.1.0, in opensuse-leap 16.0

✨ X509V3_ASID_ADD_ID_OR_RANGE(3ssl) ✨

okay bestie, buckle up πŸ’– this is the manual page for the RFC 3779 autonomous system identifier delegation extension, and it's giving cryptography core πŸŽ€


🌸 NAME 🌸

X509v3_asid_add_id_or_range, X509v3_asid_add_inherit, X509v3_asid_canonize, X509v3_asid_is_canonical β€” RFC 3779 autonomous system identifier delegation extension


πŸ¦‹ SYNOPSIS πŸ¦‹

#include <openssl/x509v3.h>

int
X509v3_asid_add_id_or_range(ASIdentifiers *asid, int type,
    ASN1_INTEGER *min, ASN1_INTEGER *max);

int
X509v3_asid_add_inherit(ASIdentifiers *asid, int type);

int
X509v3_asid_canonize(ASIdentifiers *asid);

int
X509v3_asid_is_canonical(ASIdentifiers *asid);

πŸ’… DESCRIPTION πŸ’…

So an ASIdentifiers object is literally the content of the cert extension from RFC 3779, section 3.2.3.1. You instantiate it with ASIdentifiers_new(3) and its internals are documented over in ASRange_new(3). iykyk πŸ’œ

An autonomous system? It's identified by an unsigned 32-bit integer, called an AS identifier or AS number. And an ASIdentifiers object can hold two lists:

  • a list of type V3_ASID_ASNUM β€” full of individual AS identifiers and ranges of AS identifiers
  • an obsolete list of type V3_ASID_RDI β€” full of routing domain identifiers (RDIs)

Either of these lists can be absent, OR it can contain literally nothing but a special β€œinherit” marker that says "bestie this list is inherited from the issuer of the certificate" πŸ‘‘

πŸŽ€ X509v3_asid_add_id_or_range()

This one adds an individual identifier or a range of identifiers to the list of type (either V3_ASID_ASNUM or V3_ASID_RDI) inside asid. If no such list exists yet, it gets created first, slay ✨

But β€” if a list of type already exists and contains the β€œinherit” marker, the call fails. min must be a non-NULL ASN1_INTEGER. If max is NULL, then min is added as an individual identifier.

Ownership of min and max is transferred to asid on success 🫢

⚠️ It is the responsibility of the caller to make sure the resulting asid doesn't contain lists with overlapping ranges, and that min is strictly less than max if both are non-NULL. The caller should also make sure the AS identifiers are 32-bit integers. Not doing this may result in an asid that literally cannot be brought into canonical form by X509v3_asid_canonize() 😭 no cap.

🌈 X509v3_asid_add_inherit()

This adds the list of type (either V3_ASID_ASNUM or V3_ASID_RDI) in asid if necessary, then marks it β€œinherit”. This fails if asid already contains a list of type that is not marked β€œinherit”.

⭐ X509v3_asid_canonize()

This attempts to bring both lists in asid into canonical form. If asid is NULL, the call succeeds and no action occurs (iconic behavior honestly).

A list is in canonical form if it is either one of:

  • absent,
  • marked β€œinherit”,
  • non-empty and all identifiers and ranges are listed in increasing order. Ranges must not overlap, and adjacent ranges must be fully merged.

X509v3_asid_canonize() merges adjacent ranges but refuses to merge overlapping ranges or to discard duplicates. For example, the adjacent ranges [a,b] and [b+1,c] are merged into the single range [a,c] πŸ”₯ but if both [a,b] and [b,c] appear in a list, that's an error since they count as overlapping. Likewise, the identifier a is absorbed into the adjacent range [a+1,b] to yield [a,b]. And X509v3_asid_canonize() errors if the minimum of any range is larger than the maximum. In contrast β€” minimum and maximum of a range may be equal πŸ‘€

πŸ’€ X509v3_asid_is_canonical()

This checks whether asid is in canonical form. Once X509v3_asid_canonize() is called successfully on asid, all subsequent calls to X509v3_asid_is_canonical() succeed on an unmodified asid β€” unless memory allocation fails πŸ™ˆ


πŸ“ RETURN VALUES πŸ“

All these functions return 1 on success and 0 on failure.

X509v3_asid_add_id_or_range() and X509v3_asid_add_inherit() fail if:

  • asid is NULL
  • type is distinct from V3_ASID_ASNUM and V3_ASID_RDI
  • memory allocation fails

Plus specifically: X509v3_asid_add_id_or_range() fails if asid contains a list of type that is marked β€œinherit”, and X509v3_asid_add_inherit() fails if asid contains a list of type that is not marked β€œinherit”.

X509v3_asid_canonize() fails if:

  • either list is empty and not marked β€œinherit”
  • it is malformed
  • memory allocation fails

Malformed lists include lists containing duplicate, overlapping, or malformed elements β€” for example AS ranges where the minimum is larger than the maximum. Some of these failure modes result in an error being pushed onto the error stack, fyi πŸ‘‘

X509v3_asid_is_canonical() returns 1 if asid is canonical and 0 if it is not canonical or on memory allocation failure.


🧚 SEE ALSO 🧚

ASIdentifiers_new(3), crypto(3), s2i_ASN1_INTEGER(3), X509_new(3), X509v3_addr_add_inherit(3), X509v3_addr_validate_path(3)


πŸ‘‘ STANDARDS πŸ‘‘

RFC 3779: X.509 Extensions for IP Addresses and AS Identifiers,

  • section 3: Autonomous System Delegation Extension

Autonomous System (AS) Numbers, https://www.iana.org/assignments/as-numbers.


πŸ”₯ HISTORY πŸ”₯

These functions first appeared in OpenSSL 0.9.8e and have been available since OpenBSD 7.1. vintage but still serving πŸ’…


😭 BUGS 😭

Okay bestie, this is the part where we get real. 🫢

X509v3_asid_add_id_or_range() does not check for inverted range bounds and overlaps on insertion. It is very easy to create an asid that fails to be canonized by X509v3_asid_canonize() β€” and it is very hard to diagnose why. πŸ’€

Both X509v3_asid_add_id_or_range() and X509v3_asid_add_inherit() can leave asid in a corrupted state if memory allocation fails during their execution. On top of that, X509v3_asid_add_id_or_range() may already have freed the min and max arguments on failure πŸ™ˆ

RFC 3779 does not explicitly disallow ranges where the minimum is equal to the maximum. The isolated AS identifier min and the AS range [min,min] (where the minimum and the maximum are equal to min) have the same semantics. X509v3_asid_is_canonical() accepts both representations as valid, and X509v3_asid_canonize() does not prefer either representation over the other. The encodings of the two representations produced by i2d_ASIdentifiers(3) are distinct πŸ‘€

And finally β€” X509v3_asid_is_canonical() does not fully check inheriting lists to be well formed. It only checks the type to be ASIdentifierChoice_inherit and ignores the presence or absence of the inherit element. X509v3_asid_canonize() does not fix that up either. This can lead to incorrect or unexpected DER encoding of "canonical" ASIdentifiers objects. In particular, it is possible to construct an ASIdentifiers object for which both X509v3_asid_is_canonical() and X509v3_asid_inherits(3) return 1, and after a round trip through DER the latter returns 0. not me crying over DER encoding 😭


kisses, this page was brought to you by Debian, dated September 30, 2023, and the manpage title X509V3_ASID_ADD_ID_OR_RANGE(3) β€” stay canonical bestie πŸ’–βœ¨

πŸ“¦ where this page comes from