1.\" $OpenBSD: X509v3_addr_add_inherit.3,v 1.11 2023/10/01 22:46:21 tb Exp $ 2.\" 3.\" Copyright (c) 2023 Theo Buehler <tb@openbsd.org> 4.\" 5.\" Permission to use, copy, modify, and distribute this software for any 6.\" purpose with or without fee is hereby granted, provided that the above 7.\" copyright notice and this permission notice appear in all copies. 8.\" 9.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16.\" 17.Dd $Mdocdate: October 1 2023 $ 18.Dt X509V3_ADDR_ADD_INHERIT 3 19.Os 20.Sh NAME 21.Nm X509v3_addr_add_inherit , 22.Nm X509v3_addr_add_prefix , 23.Nm X509v3_addr_add_range , 24.Nm X509v3_addr_canonize , 25.Nm X509v3_addr_is_canonical 26.Nd RFC 3779 IP address delegation extensions 27.Sh SYNOPSIS 28.In openssl/x509v3.h 29.Ft int 30.Fo X509v3_addr_add_inherit 31.Fa "IPAddrBlocks *addrblocks" 32.Fa "const unsigned afi" 33.Fa "const unsigned *safi" 34.Fc 35.Ft int 36.Fo X509v3_addr_add_prefix 37.Fa "IPAddrBlocks *addrblocks" 38.Fa "const unsigned afi" 39.Fa "const unsigned *safi" 40.Fa "unsigned char *prefix" 41.Fa "const int prefixlen" 42.Fc 43.Ft int 44.Fo X509v3_addr_add_range 45.Fa "IPAddrBlocks *addrblocks" 46.Fa "const unsigned afi" 47.Fa "const unsigned *safi" 48.Fa "unsigned char *min" 49.Fa "unsigned char *max" 50.Fc 51.Ft int 52.Fo X509v3_addr_canonize 53.Fa "IPAddrBlocks *addrblocks" 54.Fc 55.Ft int 56.Fo X509v3_addr_is_canonical 57.Fa "IPAddrBlocks *addrblocks" 58.Fc 59.Sh DESCRIPTION 60An 61.Vt IPAddrBlocks 62object represents the content of 63an IP address delegation extension 64as defined in RFC 3779, section 2.2.3.1. 65It holds lists of IP address prefixes and IP address ranges 66delegated from the issuer to the subject of the certificate. 67It can be instantiated as explained in the EXAMPLES section 68and its internals are documented in 69.Xr IPAddressRange_new 3 . 70.Pp 71Each list in a well-formed 72.Vt IPAddrBlocks 73object is uniquely identified by 74an address family identifier (AFI) and 75an optional subsequent address family identifier (SAFI). 76Lists can be absent or can contain an 77.Dq inherit 78marker to indicate that the resources are to be inherited 79from the corresponding list of the issuer certificate. 80.Pp 81Per specification, an AFI is an unsigned 16-bit integer and 82a SAFI is an unsigned 8-bit integer. 83For IPv4 and IPv6 there are the predefined constants 84.Dv IANA_AFI_IPV4 85and 86.Dv IANA_AFI_IPV6 , 87which should be the only values used for 88.Fa afi 89in this API. 90In practice, 91.Fa safi 92is always NULL. 93.Fa afi 94is generally silently truncated to its lowest 16 bits and, if 95.Fa safi 96is non-NULL, 97only the lowest 8 bits of the value pointed at are used. 98.Pp 99.Fn X509v3_addr_add_inherit 100adds a list with an 101.Dq inherit 102marker to 103.Fa addrblocks . 104If a list corresponding to 105.Fa afi 106and 107.Fa safi 108already exists, no action occurs if it is marked 109.Dq inherit , 110otherwise the call fails. 111.Pp 112.Fn X509v3_addr_add_prefix 113adds a newly allocated internal representation of the 114.Fa prefix 115of length 116.Fa prefixlen 117to the list corresponding to 118.Fa afi 119and the optional 120.Fa safi 121in 122.Fa addrblocks . 123If no such list exists, it is created first. 124If the list exists and is marked 125.Dq inherit , 126the call fails. 127.Fa prefix 128is expected to be a byte array in network byte order. 129It should point at enough memory to accommodate 130.Fa prefixlen 131bits and it is recommended that all the bits not covered by the 132.Fa prefixlen 133be set to 0. 134It is the caller's responsibility to ensure that the 135.Fa prefix 136has no address in common with any of 137the prefixes or ranges already in the list. 138If 139.Fa afi 140is 141.Dv IANA_AFI_IPV4 , 142.Fa prefixlen 143should be between 0 and 32 (inclusive) and if 144.Fa afi 145is 146.Dv IANA_AFI_IPV6 , 147.Fa prefixlen 148should be between 0 and 128 (inclusive). 149.Pp 150.Fn X509v3_addr_add_range 151is similar to 152.Fn X509v3_addr_add_prefix 153for the closed interval of IP addresses between 154.Fa min 155and 156.Fa max 157in network presentation. 158If 159.Fa afi 160is 161.Dv IANA_AFI_IPV4 , 162.Fa min 163and 164.Fa max 165should point at 4 bytes of memory 166and if 167.Fa afi 168is 169.Dv IANA_AFI_IPV6 , 170.Fa min 171and 172.Fa max 173should point at 16 bytes of memory. 174In case the range of IP addresses between 175.Fa min 176and 177.Fa max 178is a prefix, a prefix will be added instead of a range. 179It is the caller's responsibility to ensure that 180.Fa min 181is less than or equal to 182.Fa max 183and that it does not contain any address already present 184in the list. 185Failure to do so will result in a subsequent failure of 186.Fn X509v3_addr_canonize . 187.Pp 188.Fn X509v3_addr_canonize 189attempts to bring the 190.Pf non- Dv NULL 191.Fa addrblocks 192into canonical form. 193An 194.Vt IPAddrBlocks 195object is said to be in canonical form if it conforms 196to the ordering specified in RFC 3779: 197section 2.2.3.3 requires that 198the list of lists be sorted first by increasing 199.Fa afi 200and then by increasing 201.Fa safi , 202where NULL is the minimal SAFI; 203section 2.2.3.6 requires that each list be in minimal form and sorted. 204The minimality requirement is that all adjacent prefixes 205and ranges must be merged into a single range and that each 206range must be expressed as a prefix, if possible. 207In particular, any given address can be in at most one list entry. 208The order is by increasing minimal IP address in network byte order. 209.Pp 210.Fn X509v3_addr_is_canonical 211indicates whether 212.Fa addrblocks 213is in canonical form. 214.Sh RETURN VALUES 215All these functions return 1 on success and 0 on failure. 216Memory allocation failure is one possible reason for all of them. 217Sometimes an error code can be obtained by 218.Xr ERR_get_error 3 . 219.Pp 220.Fn X509v3_addr_add_inherit 221fails if the list corresponding to 222.Fa afi 223and the optional 224.Fa safi 225already exists and is not marked 226.Dq inherit . 227.Pp 228.Fn X509v3_addr_add_prefix 229and 230.Fn X509v3_addr_add_range 231fail if a list corresponding to 232.Fa afi 233and the optional 234.Fa safi 235already exists and is marked 236.Dq inherit , 237or if 238.Fa prefixlen 239is outside the interval [0,32] for IPv4 addresses 240or [0,128] for IPv6 addresses. 241.Pp 242.Fn X509v3_addr_canonize 243fails if one of the lists in 244.Fa addrblocks 245is malformed, 246in particular if it contains corrupt, overlapping, 247or duplicate entries. 248Corruption includes ranges where 249.Fa max 250is strictly smaller than 251.Fa min . 252The error conditions are generally indistinguishable. 253.Pp 254.Fn X509v3_addr_is_canonical 255returns 1 if 256.Fa addrblocks 257is in canonical form. 258A return value of 0 can indicate non-canonical form or a corrupted list. 259.Sh EXAMPLES 260Construct the first extension from RFC 3779, Appendix B. 261.Bd -literal 262#include <sys/socket.h> 263#include <arpa/inet.h> 264 265#include <err.h> 266#include <stdio.h> 267#include <unistd.h> 268 269#include <openssl/asn1.h> 270#include <openssl/objects.h> 271#include <openssl/x509.h> 272#include <openssl/x509v3.h> 273 274const char *prefixes[] = { 275 "10.0.32/20", "10.0.64/24", "10.1/16", 276 "10.2.48/20", "10.2.64/24", "10.3/16", 277}; 278#define N_PREFIXES (sizeof(prefixes) / sizeof(prefixes[0])) 279 280static void 281hexdump(const unsigned char *buf, size_t len) 282{ 283 size_t i; 284 285 for (i = 1; i <= len; i++) 286 printf(" 0x%02x,%s", buf[i \- 1], i % 8 ? "" : "\en"); 287 if (len % 8) 288 printf("\en"); 289} 290 291int 292main(void) 293{ 294 IPAddrBlocks *addrblocks; 295 X509_EXTENSION *ext; 296 unsigned char *der; 297 int der_len; 298 size_t i; 299 300 if (pledge("stdio", NULL) == \-1) 301 err(1, "pledge"); 302 303 /* 304 * Somebody forgot to implement IPAddrBlocks_new(). IPAddrBlocks 305 * is the same as STACK_OF(IPAddressFamily). As such, it should 306 * have IPAddressFamily_cmp() as its comparison function. It is 307 * not possible to call sk_new(3) because IPAddressFamily_cmp() 308 * is not part of the public API. The correct comparison function 309 * can be installed as a side-effect of X509v3_addr_canonize(3). 310 */ 311 if ((addrblocks = sk_IPAddressFamily_new_null()) == NULL) 312 err(1, "sk_IPAddressFamily_new_null"); 313 if (!X509v3_addr_canonize(addrblocks)) 314 errx(1, "X509v3_addr_canonize"); 315 316 /* Add the prefixes as IPv4 unicast. */ 317 for (i = 0; i < N_PREFIXES; i++) { 318 unsigned char addr[16] = {0}; 319 int len; 320 int unicast = 1; /* SAFI for unicast forwarding. */ 321 322 len = inet_net_pton(AF_INET, prefixes[i], addr, 323 sizeof(addr)); 324 if (len == \-1) 325 errx(1, "inet_net_pton(%s)", prefixes[i]); 326 if (!X509v3_addr_add_prefix(addrblocks, IANA_AFI_IPV4, 327 &unicast, addr, len)) 328 errx(1, "X509v3_addr_add_prefix(%s)", prefixes[i]); 329 } 330 if (!X509v3_addr_add_inherit(addrblocks, IANA_AFI_IPV6, NULL)) 331 errx(1, "X509v3_addr_add_inherit"); 332 333 /* 334 * Ensure the extension is in canonical form. Otherwise the two 335 * adjacent prefixes 10.2.48/20 and 10.2.64/24 are not merged into 336 * the range 10.2.48.0--10.2.64.255. This results in invalid DER 337 * encoding from X509V3_EXT_i2d(3) and i2d_X509_EXTENSION(3). 338 */ 339 if (!X509v3_addr_canonize(addrblocks)) 340 errx(1, "X509v3_addr_canonize"); 341 342 /* Create the extension with the correct OID; mark it critical. */ 343 ext = X509V3_EXT_i2d(NID_sbgp_ipAddrBlock, 1, addrblocks); 344 if (ext == NULL) 345 errx(1, "X509V3_EXT_i2d"); 346 347 der = NULL; 348 if ((der_len = i2d_X509_EXTENSION(ext, &der)) <= 0) 349 errx(1, "i2d_X509_EXTENSION"); 350 351 hexdump(der, der_len); 352 353 /* One way of implementing IPAddrBlocks_free(). */ 354 sk_IPAddressFamily_pop_free(addrblocks, IPAddressFamily_free); 355 X509_EXTENSION_free(ext); 356 free(der); 357 358 return 0; 359} 360.Ed 361.Pp 362Implement the missing public API 363.Fn d2i_IPAddrBlocks 364and 365.Fn i2d_IPAddrBlocks 366using 367.Xr ASN1_item_d2i 3 : 368.Bd -literal 369IPAddrBlocks * 370d2i_IPAddrBlocks(IPAddrBlocks **addrblocks, const unsigned char **in, 371 long len) 372{ 373 const X509V3_EXT_METHOD *v3_addr; 374 375 if ((v3_addr = X509V3_EXT_get_nid(NID_sbgp_ipAddrBlock)) == NULL) 376 return NULL; 377 return (IPAddrBlocks *)ASN1_item_d2i((ASN1_VALUE **)addrblocks, 378 in, len, ASN1_ITEM_ptr(v3_addr\->it)); 379} 380 381int 382i2d_IPAddrBlocks(IPAddrBlocks *addrblocks, unsigned char **out) 383{ 384 const X509V3_EXT_METHOD *v3_addr; 385 386 if ((v3_addr = X509V3_EXT_get_nid(NID_sbgp_ipAddrBlock)) == NULL) 387 return \-1; 388 return ASN1_item_i2d((ASN1_VALUE *)addrblocks, out, 389 ASN1_ITEM_ptr(v3_addr\->it)); 390} 391.Ed 392.Pp 393The use of the undocumented macro 394.Dv ASN1_ITEM_ptr() 395is necessary if compatibility with modern versions of other implementations 396is desired. 397.Sh SEE ALSO 398.Xr ASIdentifiers_new 3 , 399.Xr crypto 3 , 400.Xr inet_net_ntop 3 , 401.Xr inet_ntop 3 , 402.Xr IPAddressRange_new 3 , 403.Xr X509_new 3 , 404.Xr X509v3_addr_get_range 3 , 405.Xr X509v3_addr_validate_path 3 , 406.Xr X509v3_asid_add_id_or_range 3 407.Sh STANDARDS 408RFC 3779: X.509 Extensions for IP Addresses and AS Identifiers: 409.Bl -dash -compact 410.It 411section 2: IP Address delegation extension 412.El 413.Pp 414RFC 7020: The Internet Numbers Registry System 415.Pp 416RFC 7249: Internet Number Registries 417.Pp 418.Rs 419.%T Address Family Numbers 420.%U https://www.iana.org/assignments/address\-family\-numbers 421.Re 422.Pp 423.Rs 424.%T Subsequent Address Family Identifiers (SAFI) Parameters 425.%U https://www.iana.org/assignments/safi\-namespace 426.Re 427.Sh HISTORY 428These functions first appeared in OpenSSL 0.9.8e 429and have been available since 430.Ox 7.1 . 431.Sh BUGS 432.Fn IPAddrBlocks_new , 433.Fn IPAddrBlocks_free , 434.Fn d2i_IPAddrBlocks , 435and 436.Fn i2d_IPAddrBlocks 437do not exist and 438.Fa IPAddrBlocks_it 439is not public. 440The above examples show how to implement the four missing functions 441with public API. 442.Pp 443.Fn X509v3_addr_add_range 444should check for inverted range bounds and overlaps 445on insertion and fail instead of creating a nonsensical 446.Fa addrblocks 447that fails to be canonized by 448.Fn X509v3_addr_canonize . 449.Pp 450If 451.Dv NULL 452is passed to 453.Xr X509v3_asid_canonize 3 , 454it succeeds. 455.Fn X509v3_addr_is_canonical 456considers 457.Dv NULL 458to be a canonical 459.Vt IPAddrBlocks . 460In contrast, 461.Fn X509v3_addr_canonize 462crashes with a 463.Dv NULL 464dereference. 465.Pp 466The code only supports the IPv4 and IPv6 AFIs. 467This is not consistently enforced across implementations. 468.Pp 469.Fn X509v3_addr_add_range 470fails to clear the unused bits set to 1 in the last octet of 471the 472.Vt ASN1_BIT_STRING 473representation of 474.Fa max . 475This confuses some software. 476