LIBRESSL-X509V3_ASID_ADD_ID_OR_RANGE(3)
π¦ X509v3_asid_add_id_or_range β the RFC 3779 AS identifier delegation extension family β¨
okay so bestie, buckle up π this one's from the Library Functions Manual and it's the whole X509v3_asid_add_id_or_range squad β four functions that handle the autonomous system identifier delegation extension. it's giving "niche but important", and there are some bugs at the bottom that are genuinely going to make you scream π
πΈ NAME πΈ
X509v3_asid_add_id_or_rangeX509v3_asid_add_inheritX509v3_asid_canonizeX509v3_asid_is_canonical
β¦all four of them handle the RFC 3779 autonomous system identifier delegation extension. that's the whole vibe π
β¨ SYNOPSIS β¨
library βlibcryptoβ #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 just the content of the certificate extension defined in RFC 3779, section 3.2.3.1. you make one with ASIdentifiers_new(3), and if you wanna peek at its guts, that's all documented in ASRange_new(3) π«Ά
an autonomous system is identified by an unsigned 32-bit integer β that's your AS identifier, aka your AS number. an ASIdentifiers object can hold two lists:
- a list of type
V3_ASID_ASNUM, holding individual AS identifiers and ranges of AS identifiers π - an obsolete list of type
V3_ASID_RDI, holding routing domain identifiers (RDIs) β yeah, obsolete, we said it π
either of those lists can be absent, or it can contain nothing but a special βinheritβ marker. that marker means the list is inherited from the issuer of the certificate. cute concept, slightly cursed in practice (see BUGS, iykyk).
π X509v3_asid_add_id_or_range() π
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 β no prep needed, she builds it herself π
if a list of type already exists and it contains the βinheritβ marker, the call fails. sorry babe.
min must be a non-NULL ASN1_INTEGER. if max is NULL, then min gets added as an individual identifier. ownership of min and max is transferred to asid on success β so like, hands off after that π
now the part where the caller has to do actual work: it is your responsibility to make sure the resulting asid doesn't end up with lists containing overlapping ranges, and that min is strictly less than max if both are non-NULL. you should also make sure the AS identifiers are 32-bit integers. fail to do that and you may end up with an asid that cannot be brought into canonical form by X509v3_asid_canonize(). no cap, it's on you π«
π X509v3_asid_add_inherit() π
adds the list of type (either V3_ASID_ASNUM or V3_ASID_RDI) inside 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() π
attempts to bring both lists in asid into canonical form. if asid is NULL, the call succeeds and nothing happens at all β nothing, zero, zip β¨
so a list is in canonical form if it's one of these:
- absent, or
- marked βinheritβ, or
- non-empty, and all identifiers and ranges are listed in increasing order (and 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. example time π
- the adjacent ranges
[a,b]and[b+1,c]get merged into the single range[a,c]β slay β - but if both
[a,b]and[b,c]appear in a list, that's an error, because they count as overlapping π - likewise, the identifier
agets absorbed into the adjacent range[a+1,b]to yield[a,b]π«Ά
it also errors if the minimum of any range is larger than the maximum. but heads up: minimum and maximum of a range may be equal. that's allowed, bestie.
π X509v3_asid_is_canonical() π
checks whether asid is in canonical form. once X509v3_asid_canonize() has been called successfully on asid, all subsequent calls to X509v3_asid_is_canonical() succeed on an unmodified asid β unless memory allocation fails, because of course that's the one thing that can still ruin it π
π₯ RETURN VALUES π₯
all these functions return 1 on success and 0 on failure. periodt.
X509v3_asid_add_id_or_range() and X509v3_asid_add_inherit() fail if:
- asid is NULL, or
- type is distinct from
V3_ASID_ASNUMandV3_ASID_RDI, or - memory allocation fails
and on top of that: X509v3_asid_add_id_or_range() fails if asid contains a list of type that is marked βinheritβ, while X509v3_asid_add_inherit() fails if asid contains a list of type that is not marked βinheritβ. they're opposites, it's giving enemies to lovers π§
X509v3_asid_canonize() fails if either list is empty and not marked βinheritβ, or if it is malformed, or if memory allocation fails. βmalformedβ covers 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, so at least you get a hint πΈ
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 this section is the main character of the whole page, please read it π
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. genuinely the worst kind of bug β the "works until it doesn't and you have no idea why" kind π
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. in addition, X509v3_asid_add_id_or_range() may already have freed the min and max arguments on failure. so like, don't touch them afterward. they're gone. π«
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. but β and this is the tea π΅ β the encodings of the two representations produced by i2d_ASIdentifiers(3) are distinct.
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. yeah. that one. iconic in the worst way π₯
and that's the page bestie, hope it slayed π
π Debian Β· June 8, 2025 Β· X509V3_ASID_ADD_ID_OR_RANGE(3) π
go forth and canonize responsibly πβ¨
π¦ where this page comes from
- alpine 3.24: libressl-doc 4.3.1-r0 Β· custom
- arch rolling: libressl 4.4.0-1 Β· ISC AND custom:OpenSSL
- Copyright (c) 2023 Theo Buehler <tb@openbsd.org>
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms