1*381ee599Stb /* $OpenBSD: ip.c,v 1.34 2024/11/12 09:23:07 tb Exp $ */ 29a7e9e7fSjob /* 39a7e9e7fSjob * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> 49a7e9e7fSjob * 59a7e9e7fSjob * Permission to use, copy, modify, and distribute this software for any 69a7e9e7fSjob * purpose with or without fee is hereby granted, provided that the above 79a7e9e7fSjob * copyright notice and this permission notice appear in all copies. 89a7e9e7fSjob * 99a7e9e7fSjob * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 109a7e9e7fSjob * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 119a7e9e7fSjob * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 129a7e9e7fSjob * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 139a7e9e7fSjob * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 149a7e9e7fSjob * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 159a7e9e7fSjob * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 169a7e9e7fSjob */ 179a7e9e7fSjob 189a7e9e7fSjob #include <sys/socket.h> 1928d71d25Sderaadt #include <arpa/inet.h> 209a7e9e7fSjob 219a7e9e7fSjob #include <err.h> 229a7e9e7fSjob #include <stdlib.h> 239a7e9e7fSjob #include <string.h> 249a7e9e7fSjob #include <unistd.h> 259a7e9e7fSjob 269a7e9e7fSjob #include "extern.h" 279a7e9e7fSjob 2822bf1969Sclaudio #define PREFIX_SIZE(x) (((x) + 7) / 8) 2922bf1969Sclaudio 309a7e9e7fSjob /* 319a7e9e7fSjob * Parse an IP address family. 329a7e9e7fSjob * This is defined in different places in the ROA/X509 standards, but 339a7e9e7fSjob * it's the same thing. 349a7e9e7fSjob * We prohibit all but IPv4 and IPv6, without SAFI. 359a7e9e7fSjob * Return zero on failure, non-zero on success. 369a7e9e7fSjob */ 379a7e9e7fSjob int 3880272c49Sderaadt ip_addr_afi_parse(const char *fn, const ASN1_OCTET_STRING *p, enum afi *afi) 399a7e9e7fSjob { 40fac5751dSclaudio uint16_t v; 419a7e9e7fSjob 429a7e9e7fSjob if (p->length == 0 || p->length > 3) { 4380272c49Sderaadt warnx("%s: invalid field length, want 1--3, have %d", 4480272c49Sderaadt fn, p->length); 459a7e9e7fSjob return 0; 469a7e9e7fSjob } 479a7e9e7fSjob 48fac5751dSclaudio memcpy(&v, p->data, sizeof(v)); 49fac5751dSclaudio v = ntohs(v); 509a7e9e7fSjob 519a7e9e7fSjob /* Only accept IPv4 and IPv6 AFIs. */ 529a7e9e7fSjob 5322bf1969Sclaudio if (v != AFI_IPV4 && v != AFI_IPV6) { 5422bf1969Sclaudio warnx("%s: only AFI for IPV4 (1) and IPV6 (2) allowed: " 5522bf1969Sclaudio "have %hd", fn, v); 569a7e9e7fSjob return 0; 579a7e9e7fSjob } 589a7e9e7fSjob 599a7e9e7fSjob /* Disallow the optional SAFI. */ 609a7e9e7fSjob 619a7e9e7fSjob if (p->length == 3) { 629a7e9e7fSjob warnx("%s: SAFI not allowed", fn); 639a7e9e7fSjob return 0; 649a7e9e7fSjob } 659a7e9e7fSjob 6622bf1969Sclaudio *afi = v; 679a7e9e7fSjob return 1; 689a7e9e7fSjob } 699a7e9e7fSjob 709a7e9e7fSjob /* 719a7e9e7fSjob * See if a given IP prefix is covered by the IP prefixes or ranges 729a7e9e7fSjob * specified in the "ips" array. 739a7e9e7fSjob * This means that the IP prefix must be strictly within the ranges or 749a7e9e7fSjob * singletons given in the array. 75335482abStb * Return 0 if we're inheriting from the issuer, >0 if we're covered, 769a7e9e7fSjob * or <0 if we're not covered. 779a7e9e7fSjob */ 789a7e9e7fSjob int 799a7e9e7fSjob ip_addr_check_covered(enum afi afi, 809a7e9e7fSjob const unsigned char *min, const unsigned char *max, 81*381ee599Stb const struct cert_ip *ips, size_t num_ips) 829a7e9e7fSjob { 839a7e9e7fSjob size_t i, sz = AFI_IPV4 == afi ? 4 : 16; 849a7e9e7fSjob 85*381ee599Stb for (i = 0; i < num_ips; i++) { 869a7e9e7fSjob if (ips[i].afi != afi) 879a7e9e7fSjob continue; 889a7e9e7fSjob if (ips[i].type == CERT_IP_INHERIT) 899a7e9e7fSjob return 0; 909a7e9e7fSjob if (memcmp(ips[i].min, min, sz) <= 0 && 919a7e9e7fSjob memcmp(ips[i].max, max, sz) >= 0) 929a7e9e7fSjob return 1; 939a7e9e7fSjob } 949a7e9e7fSjob 959a7e9e7fSjob return -1; 969a7e9e7fSjob } 979a7e9e7fSjob 989a7e9e7fSjob /* 999a7e9e7fSjob * Given a newly-parsed IP address or range "ip", make sure that "ip" 1009a7e9e7fSjob * does not overlap with any addresses or ranges in the "ips" array. 1019a7e9e7fSjob * This is defined by RFC 3779 section 2.2.3.6. 1029a7e9e7fSjob * Returns zero on failure, non-zero on success. 1039a7e9e7fSjob */ 1049a7e9e7fSjob int 1059a7e9e7fSjob ip_addr_check_overlap(const struct cert_ip *ip, const char *fn, 106*381ee599Stb const struct cert_ip *ips, size_t num_ips, int quiet) 1079a7e9e7fSjob { 10860b5b204Sderaadt size_t i, sz = ip->afi == AFI_IPV4 ? 4 : 16; 10980272c49Sderaadt int inherit_v4 = 0, inherit_v6 = 0; 1108b5bbbc5Stb int has_v4 = 0, has_v6 = 0; 1119a7e9e7fSjob 1129a7e9e7fSjob /* 1139a7e9e7fSjob * FIXME: cache this by having a flag on the cert_ip, else we're 1149a7e9e7fSjob * going to need to do a lot of scanning for big allocations. 1159a7e9e7fSjob */ 1169a7e9e7fSjob 117*381ee599Stb for (i = 0; i < num_ips; i++) 1189a7e9e7fSjob if (ips[i].type == CERT_IP_INHERIT) { 1199a7e9e7fSjob if (ips[i].afi == AFI_IPV4) 1209a7e9e7fSjob inherit_v4 = 1; 1219a7e9e7fSjob else 1229a7e9e7fSjob inherit_v6 = 1; 1239a7e9e7fSjob } else { 1249a7e9e7fSjob if (ips[i].afi == AFI_IPV4) 1259a7e9e7fSjob has_v4 = 1; 1269a7e9e7fSjob else 1279a7e9e7fSjob has_v6 = 1; 1289a7e9e7fSjob } 1299a7e9e7fSjob 1306822deefStb /* Disallow multiple inheritance per type. */ 1319a7e9e7fSjob 1329a7e9e7fSjob if ((inherit_v4 && ip->afi == AFI_IPV4) || 1339a7e9e7fSjob (inherit_v6 && ip->afi == AFI_IPV6) || 1349a7e9e7fSjob (has_v4 && ip->afi == AFI_IPV4 && 1359a7e9e7fSjob ip->type == CERT_IP_INHERIT) || 1369a7e9e7fSjob (has_v6 && ip->afi == AFI_IPV6 && 1379a7e9e7fSjob ip->type == CERT_IP_INHERIT)) { 1388b5bbbc5Stb if (!quiet) { 13980272c49Sderaadt warnx("%s: RFC 3779 section 2.2.3.5: " 1408b5bbbc5Stb "cannot have multiple inheritance or inheritance " 1418b5bbbc5Stb "and addresses of the same class", fn); 1428b5bbbc5Stb } 1439a7e9e7fSjob return 0; 1449a7e9e7fSjob } 1459a7e9e7fSjob 1469a7e9e7fSjob /* Check our ranges. */ 1479a7e9e7fSjob 148*381ee599Stb for (i = 0; i < num_ips; i++) { 1499a7e9e7fSjob if (ips[i].afi != ip->afi) 1509a7e9e7fSjob continue; 1519a7e9e7fSjob if (memcmp(ips[i].max, ip->min, sz) <= 0 || 1529a7e9e7fSjob memcmp(ips[i].min, ip->max, sz) >= 0) 1539a7e9e7fSjob continue; 1548b5bbbc5Stb if (!quiet) { 1559a7e9e7fSjob warnx("%s: RFC 3779 section 2.2.3.5: " 1569a7e9e7fSjob "cannot have overlapping IP addresses", fn); 1574032f119Stb ip_warn(fn, "certificate IP", ip); 1584032f119Stb ip_warn(fn, "offending IP", &ips[i]); 1598b5bbbc5Stb } 1609a7e9e7fSjob return 0; 1619a7e9e7fSjob } 1629a7e9e7fSjob 1639a7e9e7fSjob return 1; 1649a7e9e7fSjob } 1659a7e9e7fSjob 1669a7e9e7fSjob /* 1679a7e9e7fSjob * Parse an IP address, RFC 3779, 2.2.3.8. 1689a7e9e7fSjob * Return zero on failure, non-zero on success. 1699a7e9e7fSjob */ 1709a7e9e7fSjob int 1719a7e9e7fSjob ip_addr_parse(const ASN1_BIT_STRING *p, 1729a7e9e7fSjob enum afi afi, const char *fn, struct ip_addr *addr) 1739a7e9e7fSjob { 1749a7e9e7fSjob long unused = 0; 1759a7e9e7fSjob 1769a7e9e7fSjob /* Weird OpenSSL-ism to get unused bit count. */ 1779a7e9e7fSjob 17822bf1969Sclaudio if ((p->flags & ASN1_STRING_FLAG_BITS_LEFT)) 1799eb589bcStb unused = p->flags & 0x07; 1809a7e9e7fSjob 1819eb589bcStb if (p->length == 0 && unused != 0) { 1829ddda1aeSclaudio warnx("%s: RFC 3779 section 2.2.3.8: " 1839ddda1aeSclaudio "unused bit count must be zero if length is zero", fn); 1849ddda1aeSclaudio return 0; 1859a7e9e7fSjob } 1869a7e9e7fSjob 1879a7e9e7fSjob /* 1889a7e9e7fSjob * Check that the unused bits are set to zero. 1899a7e9e7fSjob * If we don't do this, stray bits will corrupt our composition 1909a7e9e7fSjob * of the [minimum] address ranges. 1919a7e9e7fSjob */ 1929a7e9e7fSjob 19322bf1969Sclaudio if (p->length != 0 && 1949a7e9e7fSjob (p->data[p->length - 1] & ((1 << unused) - 1))) { 19580272c49Sderaadt warnx("%s: RFC 3779 section 2.2.3.8: " 19680272c49Sderaadt "unused bits must be set to zero", fn); 1979a7e9e7fSjob return 0; 1989a7e9e7fSjob } 1999a7e9e7fSjob 2009a7e9e7fSjob /* Limit possible sizes of addresses. */ 2019a7e9e7fSjob 2029a7e9e7fSjob if ((afi == AFI_IPV4 && p->length > 4) || 2039a7e9e7fSjob (afi == AFI_IPV6 && p->length > 16)) { 2049a7e9e7fSjob warnx("%s: RFC 3779 section 2.2.3.8: " 2059a7e9e7fSjob "IP address too long", fn); 2069a7e9e7fSjob return 0; 2079a7e9e7fSjob } 2089a7e9e7fSjob 20900a1e1b3Sclaudio memset(addr, 0, sizeof(struct ip_addr)); 21022bf1969Sclaudio addr->prefixlen = p->length * 8 - unused; 2119a7e9e7fSjob memcpy(addr->addr, p->data, p->length); 2129a7e9e7fSjob return 1; 2139a7e9e7fSjob } 2149a7e9e7fSjob 2159a7e9e7fSjob /* 2169a7e9e7fSjob * Convert a ip_addr into a NUL-terminated CIDR notation string 2179a7e9e7fSjob * conforming to RFC 4632 or 4291. 2189a7e9e7fSjob * The size of the buffer must be at least 64 (inclusive). 2199a7e9e7fSjob */ 2209a7e9e7fSjob void 2219a7e9e7fSjob ip_addr_print(const struct ip_addr *addr, 2229a7e9e7fSjob enum afi afi, char *buf, size_t bufsz) 2239a7e9e7fSjob { 22483e5a181Sclaudio char ipbuf[INET6_ADDRSTRLEN]; 22583e5a181Sclaudio int ret, af; 2269a7e9e7fSjob 22783e5a181Sclaudio switch (afi) { 22883e5a181Sclaudio case AFI_IPV4: 22983e5a181Sclaudio af = AF_INET; 23083e5a181Sclaudio break; 23183e5a181Sclaudio case AFI_IPV6: 23283e5a181Sclaudio af = AF_INET6; 23383e5a181Sclaudio break; 23483e5a181Sclaudio default: 23583e5a181Sclaudio errx(1, "unsupported address family identifier"); 23683e5a181Sclaudio } 23783e5a181Sclaudio 23883e5a181Sclaudio if (inet_ntop(af, addr->addr, ipbuf, sizeof(ipbuf)) == NULL) 23983e5a181Sclaudio err(1, "inet_ntop"); 24083e5a181Sclaudio ret = snprintf(buf, bufsz, "%s/%hhu", ipbuf, addr->prefixlen); 24183e5a181Sclaudio if (ret < 0 || (size_t)ret >= bufsz) 24283e5a181Sclaudio err(1, "malformed IP address"); 2439a7e9e7fSjob } 2449a7e9e7fSjob 2459a7e9e7fSjob /* 246782a58ffSjob * Convert a ip_addr into a NUL-terminated range notation string. 247782a58ffSjob * The size of the buffer must be at least 95 (inclusive). 248782a58ffSjob */ 2494032f119Stb static void 250782a58ffSjob ip_addr_range_print(const struct ip_addr_range *range, 251782a58ffSjob enum afi afi, char *buf, size_t bufsz) 252782a58ffSjob { 2534032f119Stb struct cert_ip ip; 254782a58ffSjob char min[INET6_ADDRSTRLEN], max[INET6_ADDRSTRLEN]; 255782a58ffSjob int ret, af; 256782a58ffSjob 257782a58ffSjob switch (afi) { 258782a58ffSjob case AFI_IPV4: 259782a58ffSjob af = AF_INET; 260782a58ffSjob break; 261782a58ffSjob case AFI_IPV6: 262782a58ffSjob af = AF_INET6; 263782a58ffSjob break; 264782a58ffSjob default: 265782a58ffSjob errx(1, "unsupported address family identifier"); 266782a58ffSjob } 267782a58ffSjob 2684032f119Stb memset(&ip, 0, sizeof(ip)); 2694032f119Stb 2704032f119Stb ip.afi = afi; 2714032f119Stb ip.type = CERT_IP_RANGE; 2724032f119Stb ip.range = *range; 2734032f119Stb if (!ip_cert_compose_ranges(&ip)) 2744032f119Stb errx(1, "failed to compose ranges"); 2754032f119Stb 2764032f119Stb if (inet_ntop(af, ip.min, min, sizeof(min)) == NULL) 277782a58ffSjob err(1, "inet_ntop"); 2784032f119Stb if (inet_ntop(af, ip.max, max, sizeof(max)) == NULL) 279782a58ffSjob err(1, "inet_ntop"); 280782a58ffSjob 281782a58ffSjob ret = snprintf(buf, bufsz, "%s--%s", min, max); 282782a58ffSjob if (ret < 0 || (size_t)ret >= bufsz) 283782a58ffSjob err(1, "malformed IP address"); 284782a58ffSjob } 285782a58ffSjob 286782a58ffSjob /* 2879a7e9e7fSjob * Given the addresses (range or IP) in cert_ip, fill in the "min" and 2889a7e9e7fSjob * "max" fields with the minimum and maximum possible IP addresses given 2899a7e9e7fSjob * those ranges (or singleton prefixed range). 2909a7e9e7fSjob * This does nothing if CERT_IP_INHERIT. 2919a7e9e7fSjob * Returns zero on failure (misordered ranges), non-zero on success. 2929a7e9e7fSjob */ 2939a7e9e7fSjob int 2949a7e9e7fSjob ip_cert_compose_ranges(struct cert_ip *p) 2959a7e9e7fSjob { 29622bf1969Sclaudio size_t sz; 2979a7e9e7fSjob 2989a7e9e7fSjob switch (p->type) { 2999a7e9e7fSjob case CERT_IP_ADDR: 30022bf1969Sclaudio sz = PREFIX_SIZE(p->ip.prefixlen); 30122bf1969Sclaudio memset(p->min, 0x0, sizeof(p->min)); 30222bf1969Sclaudio memcpy(p->min, p->ip.addr, sz); 3039a7e9e7fSjob memset(p->max, 0xff, sizeof(p->max)); 30422bf1969Sclaudio memcpy(p->max, p->ip.addr, sz); 30522bf1969Sclaudio if (sz > 0 && p->ip.prefixlen % 8 != 0) 30622bf1969Sclaudio p->max[sz - 1] |= (1 << (8 - p->ip.prefixlen % 8)) - 1; 3079a7e9e7fSjob break; 3089a7e9e7fSjob case CERT_IP_RANGE: 30922bf1969Sclaudio memset(p->min, 0x0, sizeof(p->min)); 31022bf1969Sclaudio sz = PREFIX_SIZE(p->range.min.prefixlen); 31122bf1969Sclaudio memcpy(p->min, p->range.min.addr, sz); 3129a7e9e7fSjob memset(p->max, 0xff, sizeof(p->max)); 31322bf1969Sclaudio sz = PREFIX_SIZE(p->range.max.prefixlen); 31422bf1969Sclaudio memcpy(p->max, p->range.max.addr, sz); 31522bf1969Sclaudio if (sz > 0 && p->range.max.prefixlen % 8 != 0) 31622bf1969Sclaudio p->max[sz - 1] |= 31722bf1969Sclaudio (1 << (8 - p->range.max.prefixlen % 8)) - 1; 3189a7e9e7fSjob break; 3199a7e9e7fSjob default: 3209a7e9e7fSjob return 1; 3219a7e9e7fSjob } 3229a7e9e7fSjob 3234032f119Stb sz = p->afi == AFI_IPV4 ? 4 : 16; 3249a7e9e7fSjob return memcmp(p->min, p->max, sz) <= 0; 3259a7e9e7fSjob } 3269a7e9e7fSjob 3279a7e9e7fSjob /* 3289a7e9e7fSjob * Given the ROA's acceptable prefix, compute the minimum and maximum 3299a7e9e7fSjob * address accepted by the prefix. 3309a7e9e7fSjob */ 3319a7e9e7fSjob void 3329a7e9e7fSjob ip_roa_compose_ranges(struct roa_ip *p) 3339a7e9e7fSjob { 33422bf1969Sclaudio size_t sz = PREFIX_SIZE(p->addr.prefixlen); 3359a7e9e7fSjob 33622bf1969Sclaudio memset(p->min, 0x0, sizeof(p->min)); 33722bf1969Sclaudio memcpy(p->min, p->addr.addr, sz); 3389a7e9e7fSjob memset(p->max, 0xff, sizeof(p->max)); 33922bf1969Sclaudio memcpy(p->max, p->addr.addr, sz); 34022bf1969Sclaudio if (sz > 0 && p->addr.prefixlen % 8 != 0) 34122bf1969Sclaudio p->max[sz - 1] |= (1 << (8 - p->addr.prefixlen % 8)) - 1; 3429a7e9e7fSjob } 343891d6bceSjob 344891d6bceSjob void 3454032f119Stb ip_warn(const char *fn, const char *msg, const struct cert_ip *ip) 346891d6bceSjob { 347891d6bceSjob char buf[128]; 348891d6bceSjob 3494032f119Stb switch (ip->type) { 350891d6bceSjob case CERT_IP_ADDR: 3514032f119Stb ip_addr_print(&ip->ip, ip->afi, buf, sizeof(buf)); 3524032f119Stb warnx("%s: %s: %s", fn, msg, buf); 353891d6bceSjob break; 354891d6bceSjob case CERT_IP_RANGE: 3554032f119Stb ip_addr_range_print(&ip->range, ip->afi, buf, sizeof(buf)); 3564032f119Stb warnx("%s: %s: %s", fn, msg, buf); 357891d6bceSjob break; 35876dbb2b6Stb case CERT_IP_INHERIT: 3594032f119Stb warnx("%s: %s: IP (inherit)", fn, msg); 36076dbb2b6Stb break; 361891d6bceSjob default: 362891d6bceSjob warnx("%s: corrupt cert", fn); 363891d6bceSjob break; 364891d6bceSjob } 365891d6bceSjob } 366