--- /dev/null
+.\" $OpenBSD: ASIdentifiers_new.3,v 1.1 2023/09/25 01:14:34 tb Exp $
+.\"
+.\" Copyright (c) 2021 Theo Buehler <tb@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: September 25 2023 $
+.Dt ASIDENTIFIERS_NEW 3
+.Os
+.Sh NAME
+.Nm ASIdentifiers_new ,
+.Nm ASIdentifiers_free ,
+.Nm d2i_ASIdentifiers ,
+.Nm i2d_ASIdentifiers
+.Nd X509v3 certificate extension for autonomous system identifier delegation
+.Sh SYNOPSIS
+.In openssl/x509v3.h
+.Ft ASIdentifiers *
+.Fo ASIdentifiers_new
+.Fa "void"
+.Fc
+.Ft void
+.Fo ASIdentifiers_free
+.Fa "ASIdentifiers *asid"
+.Fc
+.Ft ASIdentifiers *
+.Fo d2i_ASIdentifiers
+.Fa "ASIdentifiers **asid"
+.Fa "const unsigned char **in"
+.Fa "long len"
+.Fc
+.Ft int
+.Fo i2d_ASIdentifiers
+.Fa "ASIdentifiers *asid"
+.Fa "unsigned char **out"
+.Fc
+.Sh DESCRIPTION
+RFC 3779 defines two X.509v3 certificate extensions that allow the
+delegation of
+IP address blocks and autonomous system (AS) identifiers
+from the issuer to the subject of the certificate.
+An
+.Vt ASIdentifiers
+object contains collections of individual AS numbers and
+ranges of AS numbers to be delegated.
+.Pp
+.Fn ASIdentifiers_new
+allocates and initializes a new, empty
+.Vt ASIdentifiers
+object that can be populated with
+.Xr X509v3_asid_add_id_or_range 3 .
+.Pp
+.Fn ASIdentifiers_free
+frees
+.Fa asid
+including any data contained in it.
+If
+.Fa asid
+is
+.Dv NULL ,
+no action occurs.
+.Pp
+.Fn d2i_ASIdentifiers
+and
+.Fn i2d_ASIdentifiers
+decode and encode ASN.1
+.Vt ASIdentifiers
+structures as defined in RFC 3779, section 3.2.3.1.
+For details about the semantics, examples, caveats, and bugs, see
+.Xr ASN1_item_d2i 3 .
+In order for the encoding produced by
+.Fn d2i_ASIdentifiers
+to conform to RFC 3779,
+.Fa asid
+must be in
+.Dq canonical form ,
+see
+.Xr X509v3_asid_canonize 3 .
+.Sh RETURN VALUES
+.Fn ASIdentifiers_new
+returns a new
+.Vt ASIdentifiers
+object or
+.Dv NULL
+on if an error occurs.
+.Pp
+.Fn d2i_ASIdentifiers
+returns an
+.Vt ASIdentifiers
+object or
+.Dv NULL
+on if a decoding or memory allocation error occurs.
+.Pp
+.Fn i2d_ASIdentifiers
+returns the number of bytes successfully encoded
+or a value <= 0 if an error occurs.
+.Sh SEE ALSO
+.Xr crypto 3 ,
+.Xr X509_new 3 ,
+.Xr X509v3_asid_add_id_or_range 3 ,
+.Xr X509v3_asid_is_canonical 3
+.Sh STANDARDS
+RFC 3779: X.509 Extensions for IP Addresses and AS Identifiers:
+.Bl -dash -compact
+.It
+section 3: Autonomous System Identifier Delegation Extension
+.El
+.Pp
+RFC 7020: The Internet Numbers Registry System
+.Pp
+RFC 7249: Internet Numbers Registries
+.Sh HISTORY
+These functions first appeared in OpenSSL 0.9.8e
+and have been available since
+.Ox 7.1 .
+.Sh BUGS
+There are no corresponding functions for the RFC 3779
+IP address blocks delegation extension represented by
+.Vt IPAddrBlocks .
--- /dev/null
+.\" $OpenBSD: X509v3_addr_add_inherit.3,v 1.1 2023/09/25 01:14:34 tb Exp $
+.\"
+.\" Copyright (c) 2023 Theo Buehler <tb@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: September 25 2023 $
+.Dt X509V3_ADDR_ADD_INHERIT 3
+.Os
+.Sh NAME
+.Nm X509v3_addr_add_inherit ,
+.Nm X509v3_addr_add_prefix ,
+.Nm X509v3_addr_add_range ,
+.Nm X509v3_addr_canonize ,
+.Nm X509v3_addr_is_canonical
+.Nd construct X509v3 IP address blocks extensions and
+bring them into canonical form
+.Sh SYNOPSIS
+.In openssl/x509v3.h
+.Ft int
+.Fo X509v3_addr_add_inherit
+.Fa "IPAddrBlocks *addrblocks"
+.Fa "const unsigned afi"
+.Fa "const unsigned *safi"
+.Fc
+.Ft int
+.Fo X509v3_addr_add_prefix
+.Fa "IPAddrBlocks *addrblocks"
+.Fa "const unsigned afi"
+.Fa "const unsigned *safi"
+.Fa "unsigned char *prefix"
+.Fa "const int prefixlen"
+.Fc
+.Ft int
+.Fo X509v3_addr_add_range
+.Fa "IPAddrBlocks *addrblocks"
+.Fa "const unsigned afi"
+.Fa "const unsigned *safi"
+.Fa "unsigned char *min"
+.Fa "unsigned char *max"
+.Fc
+.Ft int
+.Fo X509v3_addr_canonize
+.Fa "IPAddrBlocks *addrblocks"
+.Fc
+.Ft int
+.Fo X509v3_addr_is_canonical
+.Fa "IPAddrBlocks *addrblocks"
+.Fc
+.Sh DESCRIPTION
+An
+.Vt IPAddrBlocks
+object represents the content of
+an X509v3 IP address blocks delegation extension
+as defined in RFC 3779, section 2.2.3.1.
+It can hold lists of delegated IP address prefixes and
+IP address ranges.
+Each list is uniquely identified by
+an address family identifier (AFI) and
+an optional subsequent address family identifier (SAFI).
+Each list can be absent or it can contain a single
+.Dq inherit
+marker to indicate that the resources are to be inherited
+from the corresponding list of the issuer certificate.
+.Pp
+Per specification, an AFI is an unsigned 16-bit integer and
+a SAFI is an unsigned 8-bit integer.
+For IPv4 and IPv6 there are the predefined constants
+.Dv IANA_AFI_IPV4
+and
+.Dv IANA_AFI_IPV6 ,
+which should be the only values used for
+.Fa afi
+in this API.
+In practice,
+.Fa safi
+is always NULL.
+.Fa afi
+is generally silently truncated to its lowest 16 bits and, if
+.Fa safi
+is non-NULL,
+only the lowest 8 bits of the value pointed at are used.
+.Pp
+.Fn X509v3_addr_add_inherit
+adds a list with an
+.Dq inherit
+marker to
+.Fa addrblocks .
+If a list corresponding to
+.Fa afi
+and
+.Fa safi
+already exists, no action occurs if it is marked
+.Dq inherit ,
+otherwise the call fails.
+.Pp
+.Fn X509v3_addr_add_prefix
+adds a newly allocated internal representation of the
+.Fa prefix
+of length
+.Fa prefixlen
+to the list corresponding to
+.Fa afi
+and the optional
+.Fa safi
+in
+.Fa addrblocks .
+If no such list exists, it is created first.
+If the list exists and is marked
+.Dq inherit ,
+the call fails.
+.Fa prefix
+is expected to be a byte array in network byte order.
+It should point at enough memory to accommodate
+.Fa prefixlen
+bits and it is recommended that all the bits not covered by
+the prefixlen be set to 0.
+It is the caller's responsibility to ensure that the prefix
+has no address in common with any of
+the prefixes or ranges already in the list.
+If
+.Fa afi
+is
+.Dv IANA_AFI_IPV4 ,
+.Fa prefixlen
+should be between 0 and 32 (inclusive) and if
+.Fa afi
+is
+.Dv IANA_AFI_IPV6 ,
+.Fa prefixlen
+should be between 0 and 128 (inclusive).
+.Pp
+.Fn X509v3_addr_add_range
+is similar to
+.Fn X509v3_addr_add_prefix
+for the closed interval of IP addresses between
+.Fa min
+and
+.Fa max
+in network presentation.
+If
+.Fa afi
+is
+.Dv IANA_AFI_IPV4 ,
+.Fa min
+and
+.Fa max
+should point at 4 bytes of memory
+and if
+.Fa afi
+is
+.Dv IANA_AFI_IPV6 ,
+.Fa min
+and
+.Fa max
+should point at 16 bytes of memory.
+In case the range of IP addresses between
+.Fa min
+and
+.Fa max
+is a prefix, a prefix will be added.
+It is the caller's responsibility to ensure that
+.Fa min
+is less than or equal to
+.Fa max
+and that it does not contain any address already present
+in the list.
+Failure to do so will result in a subsequent failure of
+.Fn X509v3_addr_canonize .
+.Pp
+.Fn X509v3_addr_canonize
+attempts to bring the
+.Pf non- Dv NULL
+.Fa addrblocks
+into canonical form.
+An
+.Vt IPAddrBlocks
+object is said to be in canonical form if it conforms
+to the ordering specified in RFC 3779:
+section 2.2.3.3 requires that the lists be sorted first by increasing
+.Fa afi
+and then by increasing
+.Fa safi ,
+where NULL is the minimal SAFI;
+section 2.2.3.6 requires that each list be in minimal form and sorted.
+The minimality requirement is that all adjacent prefixes
+and ranges must be merged into a single range and that each
+range must be expressed as a prefix, if possible.
+In particular, any given address can be in at most one list entry.
+The order is by increasing minimal IP address in network byte order.
+.Pp
+.Fn X509v3_addr_is_canonical
+indicates whether
+.Fa addrblocks
+is in canonical form.
+.Sh RETURN VALUES
+All these functions return 1 on success and 0 on failure.
+Memory allocation failure is one possible reason for all of them.
+Sometimes an error code can be obtained by
+.Xr ERR_get_error 3 .
+.Pp
+.Fn X509v3_addr_add_inherit
+fails if the list corresponding to
+.Fa afi
+and the optional
+.Fa safi
+already exists and is not marked
+.Dq inherit .
+.Pp
+.Fn X509v3_addr_add_prefix
+and
+.Fn X509v3_addr_add_range
+fail if a list corresponding to
+.Fa afi
+and the optional
+.Fa safi
+already exists and is marked
+.Dq inherit ,
+or if
+.Fa prefixlen
+is outside the interval [0,32] for IPv4 addresses
+or [0,128] for IPv6 addresses.
+.Pp
+.Fn X509v3_addr_canonize
+fails if one of the lists in
+.Fa addrblocks
+is malformed,
+in particular if it contains corrupt, overlapping,
+or duplicate entries.
+Corruption includes ranges where
+.Fa max
+is strictly smaller than
+.Fa min .
+The error conditions are generally indistinguishable.
+.Pp
+.Fn X509v3_addr_is_canonical
+returns 1 if
+.Fa addrblocks
+is in canonical form.
+A return value of 0 can indicate non-canonical form or corrupted list.
+.Sh EXAMPLES
+Construct the first extension from RFC 3779, Appendix B.
+.Bd -literal
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <openssl/asn1.h>
+#include <openssl/objects.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+const char *prefixes[6] = {
+ "10.0.32/20", "10.0.64/24", "10.1/16",
+ "10.2.48/20", "10.2.64/24", "10.3/16",
+};
+#define N_PREFIXES (sizeof(prefixes) / sizeof(prefixes[0]))
+
+static void
+hexdump(const unsigned char *buf, size_t len)
+{
+ size_t i;
+
+ for (i = 1; i <= len; i++)
+ printf(" 0x%02x,%s", buf[i - 1], i % 8 ? "" : "\en");
+ if (len % 8)
+ printf("\en");
+}
+
+int
+main(void)
+{
+ IPAddrBlocks *addrblocks;
+ X509_EXTENSION *ext;
+ unsigned char *der;
+ int der_len;
+ size_t i;
+
+ if (pledge("stdio", NULL) == -1)
+ err(1, "pledge");
+
+ /*
+ * Somebody forgot to implement IPAddrBlocks_new(). IPAddrBlocks
+ * is the same as STACK_OF(IPAddressFamily). As such, it should
+ * have IPAddressFamily_cmp() as its comparison function. It is
+ * not possible to call sk_new(3) because IPAddressFamily_cmp()
+ * is not part of the public API. The correct comparison function
+ * can be installed as a side-effect of X509v3_addr_canonize(3).
+ */
+ if ((addrblocks = sk_IPAddressFamily_new_null()) == NULL)
+ err(1, "sk_IPAddressFamily_new_null");
+ if (!X509v3_addr_canonize(addrblocks))
+ errx(1, "X509v3_addr_canonize");
+
+ /* Add the prefixes as IPv4 unicast. */
+ for (i = 0; i < N_PREFIXES; i++) {
+ unsigned char addr[16] = {0};
+ int len;
+ int unicast = 1; /* SAFI for unicast forwarding. */
+
+ len = inet_net_pton(AF_INET, prefixes[i], addr,
+ sizeof(addr));
+ if (len == -1)
+ errx(1, "inet_net_pton(%s)", prefixes[i]);
+ if (!X509v3_addr_add_prefix(addrblocks, IANA_AFI_IPV4,
+ &unicast, addr, len))
+ errx(1, "X509v3_addr_add_prefix(%s)", prefixes[i]);
+ }
+ if (!X509v3_addr_add_inherit(addrblocks, IANA_AFI_IPV6, NULL))
+ errx(1, "X509v3_addr_add_inherit");
+
+ /*
+ * Ensure the extension is in canonical form. Otherwise the two
+ * adjacent prefixes 10.2.48/20 and 10.2.64/24 are not merged into
+ * the range 10.2.48.0--10.2.64.255. This results in invalid DER
+ * encoding from X509V3_EXT_i2d(3) and i2d_X509_EXTENSION(3).
+ */
+ if (!X509v3_addr_canonize(addrblocks))
+ errx(1, "X509v3_addr_canonize");
+
+ /* Create the extension. The 1 indicates that it is critical. */
+ ext = X509V3_EXT_i2d(NID_sbgp_ipAddrBlock, 1, addrblocks);
+ if (ext == NULL)
+ errx(1, "X509V3_EXT_i2d");
+
+ der = NULL;
+ if ((der_len = i2d_X509_EXTENSION(ext, &der)) <= 0)
+ errx(1, "i2d_X509_EXTENSION");
+
+ hexdump(der, der_len);
+
+ /* One way of implementing IPAddrBlocks_free(). */
+ sk_IPAddressFamily_pop_free(addrblocks, IPAddressFamily_free);
+ X509_EXTENSION_free(ext);
+ free(der);
+
+ return 0;
+}
+.Ed
+.Pp
+Implement the missing public API
+.Fn d2i_IPAddrBlocks
+and
+.Fn i2d_IPAddrBlocks
+using
+.Xr ASN1_item_d2i 3 :
+.Bd -literal
+IPAddrBlocks *
+d2i_IPAddrBlocks(IPAddrBlocks **addrblocks, const unsigned char **in,
+ long len)
+{
+ const X509V3_EXT_METHOD *v3_addr;
+
+ if ((v3_addr = X509V3_EXT_get_nid(NID_sbgp_ipAddrBlock)) == NULL)
+ return NULL;
+ return (IPAddrBlocks *)ASN1_item_d2i((ASN1_VALUE **)addrblocks,
+ in, len, ASN1_ITEM_ptr(v3_addr->it));
+}
+
+int
+i2d_IPAddrBlocks(IPAddrBlocks *addrblocks, unsigned char **out)
+{
+ const X509V3_EXT_METHOD *v3_addr;
+
+ if ((v3_addr = X509V3_EXT_get_nid(NID_sbgp_ipAddrBlock)) == NULL)
+ return -1;
+ return ASN1_item_i2d((ASN1_VALUE *)addrblocks, out,
+ ASN1_ITEM_ptr(v3_addr->it));
+}
+.Ed
+.Pp
+the use of the undocumented macro
+.Dv ASN1_ITEM_ptr()
+is necessary if compatibility with modern versions of other implementations
+is desired.
+.Sh SEE ALSO
+.Xr ASIdentifiers_new 3 ,
+.Xr crypto 3 ,
+.Xr inet_net_ntop 3 ,
+.Xr inet_ntop 3 ,
+.Xr X509_new 3 ,
+.Xr X509v3_asid_add_id_or_range 3
+.Sh STANDARDS
+RFC 3779: X.509 Extensions for IP Addresses and AS Identifiers:
+.Bl -dash -compact
+.It
+section 2: IP Address delegation extension
+.El
+.Pp
+RFC 7020: The Internet Numbers Registry System
+.Pp
+RFC 7249: Internet Number Registries
+.Pp
+.Rs
+.%T Address Family Numbers
+.%U https://www.iana.org/assignments/address-family-numbers
+.Re
+.Pp
+.Rs
+.%T Subsequent Address Family Identifiers (SAFI) Parameters
+.%U https://www.iana.org/assignments/safi-namespace
+.Re
+.Sh HISTORY
+These functions first appeared in OpenSSL 0.9.8e
+and have been available since
+.Ox 7.1 .
+.Sh BUGS
+.Fn IPAddrBlocks_new ,
+.Fn IPAddrBlocks_free ,
+.Fn d2i_IPAddrBlocks ,
+and
+.Fn i2d_IPAddrBlocks
+do not exist and
+.Fa IPAddrBlocks_it
+is not public.
+The above examples show how to implement the four missing functions
+with public API.
+.Pp
+.Fn X509v3_asid_add_range
+should check for inverted range bounds and overlaps
+on insertion and fail instead of creating a nonsensical
+.Fa asid
+that fails to be canonized by
+.Fn X509v3_asid_canonize .
+.Pp
+If
+.Dv NULL
+is passed to
+.Xr X509v3_asid_canonize 3 ,
+it succeeds.
+.Fn X509v3_addr_is_canonical
+considers
+.Dv NULL
+to be a canonical
+.Vt IPAddrBlocks .
+In contrast,
+.Fn X509v3_addr_canonize
+crashes with a
+.Dv NULL
+dereference.
+.Pp
+The only supported AFIs are IPv4 and IPv6, but this is not enforced.
--- /dev/null
+.\" $OpenBSD: X509v3_asid_add_id_or_range.3,v 1.1 2023/09/25 01:14:34 tb Exp $
+.\"
+.\" Copyright (c) 2021-2023 Theo Buehler <tb@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: September 25 2023 $
+.Dt X509V3_ASID_ADD_ID_OR_RANGE 3
+.Os
+.Sh NAME
+.Nm X509v3_asid_add_id_or_range ,
+.Nm X509v3_asid_add_inherit ,
+.Nm X509v3_asid_canonize ,
+.Nm X509v3_asid_is_canonical
+.Nd construct and validate individual X509v3 certificate extensions for
+autonomous system identifier delegation
+.Sh SYNOPSIS
+.In openssl/x509v3.h
+.Ft int
+.Fo X509v3_asid_add_id_or_range
+.Fa "ASIdentifiers *asid"
+.Fa "int type"
+.Fa "ASN1_INTEGER *min"
+.Fa "ASN1_INTEGER *max"
+.Fc
+.Ft int
+.Fo X509v3_asid_add_inherit
+.Fa "ASIdentifiers *asid"
+.Fa "int type"
+.Fc
+.Ft int
+.Fo X509v3_asid_canonize
+.Fa "ASIdentifiers *asid"
+.Fc
+.Ft int
+.Fo X509v3_asid_is_canonical
+.Fa "ASIdentifiers *asid"
+.Fc
+.Sh DESCRIPTION
+An
+.Vt ASIdentifiers
+object represents the content of the X509v3 certificate extension
+defined in RFC 3779, section 3.2.3.1.
+An autonomous system is identified by an unsigned 32-bit integer,
+called an AS number.
+An
+.Vt ASIdentifiers
+object can hold two lists:
+a list of
+.Fa type
+.Dv V3_ASID_ASNUM
+containing individual AS identifiers and ranges of AS identifiers,
+and an obsolete list of
+.Fa type
+.Dv V3_ASID_RDI
+containing routing domain identifiers (RDIs).
+Either of these lists may be absent, or it may contain nothing
+but a special
+.Dq inherit
+marker that indicates that the list is inherited from the issuer
+of the certificate.
+.Pp
+.Fn X509v3_asid_add_id_or_range
+adds an individual identifier or a range of identifiers to the list of
+.Fa type
+(either
+.Dv V3_ASID_ASNUM
+or
+.Dv V3_ASID_RDI )
+in
+.Fa asid .
+If no such list exists, it is created first.
+If a list of
+.Fa type
+already exists and contains the
+.Dq inherit
+marker, the call fails.
+.Fa min
+must be a
+.Pf non- Dv NULL
+.Vt ASN1_INTEGER .
+If
+.Fa max
+is
+.Dv NULL ,
+.Fa min
+is added as an individual identifier.
+Ownership of
+.Fa min
+and
+.Fa max
+is transferred to
+.Fa asid
+on success.
+It is the responsibility of the caller to ensure that
+the resulting
+.Fa asid
+does not contain lists with overlapping ranges and that
+.Fa min
+is strictly less than
+.Fa max
+if both are
+.Pf non- Dv NULL .
+The caller should also ensure that the AS identifiers are
+32-bit integers.
+Failure to do so may result in an
+.Fa asid
+that cannot be brought into canonical form by
+.Fn X509v3_asid_canonize .
+.Pp
+.Fn X509v3_asid_add_inherit
+adds the list of
+.Fa type
+(either
+.Dv V3_ASID_ASNUM
+or
+.Dv V3_ASID_RDI )
+in
+.Fa asid
+and marks it
+.Dq inherit .
+This fails if
+.Fa asid
+already contains a list of
+.Fa type
+that isn't marked
+.Dq inherit ,
+otherwise no action occurs.
+.Pp
+.Fn X509v3_asid_canonize
+attempts to bring both lists in
+.Fa asid
+into canonical form.
+If
+.Fa asid
+is
+.Dv NULL
+the call succeeds and no action occurs.
+A list is in canonical form if it is either one of
+.Bl -dash -compact
+.It
+absent,
+.It
+marked
+.Dq inherit ,
+.It
+non-empty and all identifiers and ranges are listed in increasing order.
+Ranges must not overlap,
+.\" the following is not currently specified and leads to ambiguity:
+.\" contain at least two elements,
+and adjacent ranges must be fully merged.
+.El
+.Fn 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,
+this results in an error since they are considered overlapping.
+Likewise, the identifier a is absorbed into the adjacent
+range [a+1,b] to yield [a,b].
+.Fn 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.
+.Pp
+.Fn X509v3_asid_is_canonical
+checks whether
+.Fa asid
+is in canonical form.
+Once
+.Fn X509v3_asid_canonize
+is called successfully on
+.Fa asid ,
+all subsequent calls to
+.Fn X509v3_asid_is_canonical
+succeed on an unmodified
+.Fa asid
+unless memory allocation fails.
+.Sh RETURN VALUES
+All these functions return 1 on success and 0 on failure.
+.Pp
+.Fn X509v3_asid_add_id_or_range
+and
+.Fn X509v3_asid_add_inherit
+fail if
+.Fa asid
+is
+.Dv NULL
+or if
+.Fa type
+is distinct from
+.Dv V3_ASID_ASNUM
+and
+.Dv V3_ASID_RDI ,
+or on memory allocation failure.
+In addition,
+.Fn X509v3_asid_add_id_or_range
+fails if
+.Fa asid
+contains a list of
+.Fa type
+that is marked
+.Dq inherit ,
+and
+.Fn X509v3_asid_add_inherit
+fails if
+.Fa asid
+contains a list of
+.Fa type
+that is not marked
+.Dq inherit .
+.Pp
+.Fn X509v3_asid_canonize
+fails if either list is empty and not marked
+.Dq inherit ,
+or if it is malformed, or if 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.
+.Pp
+.Fn X509v3_asid_is_canonical
+returns 1 if
+.Fa asid
+is canonical and 0 if it is not canonical or on memory allocation
+failure.
+.Sh SEE ALSO
+.Xr ASIdentifiers_new 3 ,
+.Xr crypto 3 ,
+.Xr s2i_ASN1_INTEGER 3 ,
+.Xr X509_new 3 ,
+.Xr X509v3_addr_add_range 3
+.Sh STANDARDS
+RFC 3779: X.509 Extensions for IP Addresses and AS Identifiers,
+.Bl -dash -compact
+.It
+section 3: Autonomous System Delegation Extension
+.El
+.Pp
+.Rs
+.%T Autonomous System (AS) Numbers
+.%U https://www.iana.org/assignments/as-numbers
+.Re
+.Sh HISTORY
+These functions first appeared in OpenSSL 0.9.8e
+and have been available since
+.Ox 7.1 .
+.Sh BUGS
+.Fn X509v3_asid_add_id_or_range
+does not check for inverted range bounds and overlaps
+on insertion.
+It is very easy to create an
+.Fa asid
+that fails to be canonized by
+.Fn X509v3_asid_canonize
+and it is very hard to diagnose why.
+.Pp
+Both
+.Fn X509v3_asid_add_id_or_range
+and
+.Fn X509v3_asid_add_inherit
+can leave
+.Fa asid
+in a corrupted state if memory allocation fails during their execution.
+In addition,
+.Fn X509v3_asid_add_id_or_range
+may already have freed the
+.Fa min
+and
+.Fa max
+arguments on failure.
+.Pp
+RFC 3779 does not explicitly disallow ranges where the minimum
+is equal to the maximum.
+The isolated AS identifier a and
+the AS range [a,a] where the minimum and the maximum are equal to a
+have the same semantics.
+.Fn X509v3_asid_is_canonical
+accepts both representations as valid and
+.Fn X509v3_asid_canonize
+does not prefer either representation over the other.
+The encodings of the two representations produced by
+.Xr i2d_ASIdentifiers 3
+are distinct.