1 /* $OpenBSD: roa.c,v 1.78 2024/05/24 12:57:20 tb Exp $ */ 2 /* 3 * Copyright (c) 2022 Theo Buehler <tb@openbsd.org> 4 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <assert.h> 20 #include <err.h> 21 #include <stdint.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <unistd.h> 25 26 #include <openssl/asn1.h> 27 #include <openssl/asn1t.h> 28 #include <openssl/stack.h> 29 #include <openssl/safestack.h> 30 #include <openssl/x509.h> 31 32 #include "extern.h" 33 34 extern ASN1_OBJECT *roa_oid; 35 36 /* 37 * Types and templates for the ROA eContent, RFC 6482, section 3. 38 */ 39 40 ASN1_ITEM_EXP ROAIPAddress_it; 41 ASN1_ITEM_EXP ROAIPAddressFamily_it; 42 ASN1_ITEM_EXP RouteOriginAttestation_it; 43 44 typedef struct { 45 ASN1_BIT_STRING *address; 46 ASN1_INTEGER *maxLength; 47 } ROAIPAddress; 48 49 DECLARE_STACK_OF(ROAIPAddress); 50 51 typedef struct { 52 ASN1_OCTET_STRING *addressFamily; 53 STACK_OF(ROAIPAddress) *addresses; 54 } ROAIPAddressFamily; 55 56 DECLARE_STACK_OF(ROAIPAddressFamily); 57 58 #ifndef DEFINE_STACK_OF 59 #define sk_ROAIPAddress_num(st) SKM_sk_num(ROAIPAddress, (st)) 60 #define sk_ROAIPAddress_value(st, i) SKM_sk_value(ROAIPAddress, (st), (i)) 61 62 #define sk_ROAIPAddressFamily_num(st) SKM_sk_num(ROAIPAddressFamily, (st)) 63 #define sk_ROAIPAddressFamily_value(st, i) \ 64 SKM_sk_value(ROAIPAddressFamily, (st), (i)) 65 #endif 66 67 typedef struct { 68 ASN1_INTEGER *version; 69 ASN1_INTEGER *asid; 70 STACK_OF(ROAIPAddressFamily) *ipAddrBlocks; 71 } RouteOriginAttestation; 72 73 ASN1_SEQUENCE(ROAIPAddress) = { 74 ASN1_SIMPLE(ROAIPAddress, address, ASN1_BIT_STRING), 75 ASN1_OPT(ROAIPAddress, maxLength, ASN1_INTEGER), 76 } ASN1_SEQUENCE_END(ROAIPAddress); 77 78 ASN1_SEQUENCE(ROAIPAddressFamily) = { 79 ASN1_SIMPLE(ROAIPAddressFamily, addressFamily, ASN1_OCTET_STRING), 80 ASN1_SEQUENCE_OF(ROAIPAddressFamily, addresses, ROAIPAddress), 81 } ASN1_SEQUENCE_END(ROAIPAddressFamily); 82 83 ASN1_SEQUENCE(RouteOriginAttestation) = { 84 ASN1_EXP_OPT(RouteOriginAttestation, version, ASN1_INTEGER, 0), 85 ASN1_SIMPLE(RouteOriginAttestation, asid, ASN1_INTEGER), 86 ASN1_SEQUENCE_OF(RouteOriginAttestation, ipAddrBlocks, 87 ROAIPAddressFamily), 88 } ASN1_SEQUENCE_END(RouteOriginAttestation); 89 90 DECLARE_ASN1_FUNCTIONS(RouteOriginAttestation); 91 IMPLEMENT_ASN1_FUNCTIONS(RouteOriginAttestation); 92 93 /* 94 * Parses the eContent section of an ROA file, RFC 6482, section 3. 95 * Returns zero on failure, non-zero on success. 96 */ 97 static int 98 roa_parse_econtent(const char *fn, struct roa *roa, const unsigned char *d, 99 size_t dsz) 100 { 101 const unsigned char *oder; 102 RouteOriginAttestation *roa_asn1; 103 const ROAIPAddressFamily *addrfam; 104 const STACK_OF(ROAIPAddress) *addrs; 105 int addrsz, ipv4_seen = 0, ipv6_seen = 0; 106 enum afi afi; 107 const ROAIPAddress *addr; 108 uint64_t maxlen; 109 struct ip_addr ipaddr; 110 struct roa_ip *res; 111 int ipaddrblocksz; 112 int i, j, rc = 0; 113 114 oder = d; 115 if ((roa_asn1 = d2i_RouteOriginAttestation(NULL, &d, dsz)) == NULL) { 116 warnx("%s: RFC 6482 section 3: failed to parse " 117 "RouteOriginAttestation", fn); 118 goto out; 119 } 120 if (d != oder + dsz) { 121 warnx("%s: %td bytes trailing garbage in eContent", fn, 122 oder + dsz - d); 123 goto out; 124 } 125 126 if (!valid_econtent_version(fn, roa_asn1->version, 0)) 127 goto out; 128 129 if (!as_id_parse(roa_asn1->asid, &roa->asid)) { 130 warnx("%s: RFC 6482 section 3.2: asID: " 131 "malformed AS identifier", fn); 132 goto out; 133 } 134 135 ipaddrblocksz = sk_ROAIPAddressFamily_num(roa_asn1->ipAddrBlocks); 136 if (ipaddrblocksz != 1 && ipaddrblocksz != 2) { 137 warnx("%s: RFC 9582: unexpected number of ipAddrBlocks " 138 "(got %d, expected 1 or 2)", fn, ipaddrblocksz); 139 goto out; 140 } 141 142 for (i = 0; i < ipaddrblocksz; i++) { 143 addrfam = sk_ROAIPAddressFamily_value(roa_asn1->ipAddrBlocks, 144 i); 145 addrs = addrfam->addresses; 146 addrsz = sk_ROAIPAddress_num(addrs); 147 148 if (!ip_addr_afi_parse(fn, addrfam->addressFamily, &afi)) { 149 warnx("%s: RFC 6482 section 3.3: addressFamily: " 150 "invalid", fn); 151 goto out; 152 } 153 154 switch (afi) { 155 case AFI_IPV4: 156 if (ipv4_seen++ > 0) { 157 warnx("%s: RFC 9582 section 4.3.2: " 158 "IPv4 appears twice", fn); 159 goto out; 160 } 161 break; 162 case AFI_IPV6: 163 if (ipv6_seen++ > 0) { 164 warnx("%s: RFC 9582 section 4.3.2: " 165 "IPv6 appears twice", fn); 166 goto out; 167 } 168 break; 169 } 170 171 if (addrsz == 0) { 172 warnx("%s: RFC 9582, section 4.3.2: " 173 "empty ROAIPAddressFamily", fn); 174 goto out; 175 } 176 177 if (roa->ipsz + addrsz >= MAX_IP_SIZE) { 178 warnx("%s: too many ROAIPAddress entries: limit %d", 179 fn, MAX_IP_SIZE); 180 goto out; 181 } 182 roa->ips = recallocarray(roa->ips, roa->ipsz, 183 roa->ipsz + addrsz, sizeof(struct roa_ip)); 184 if (roa->ips == NULL) 185 err(1, NULL); 186 187 for (j = 0; j < addrsz; j++) { 188 addr = sk_ROAIPAddress_value(addrs, j); 189 190 if (!ip_addr_parse(addr->address, afi, fn, &ipaddr)) { 191 warnx("%s: RFC 6482 section 3.3: address: " 192 "invalid IP address", fn); 193 goto out; 194 } 195 maxlen = ipaddr.prefixlen; 196 197 if (addr->maxLength != NULL) { 198 if (!ASN1_INTEGER_get_uint64(&maxlen, 199 addr->maxLength)) { 200 warnx("%s: RFC 6482 section 3.2: " 201 "ASN1_INTEGER_get_uint64 failed", 202 fn); 203 goto out; 204 } 205 if (ipaddr.prefixlen > maxlen) { 206 warnx("%s: prefixlen (%d) larger than " 207 "maxLength (%llu)", fn, 208 ipaddr.prefixlen, 209 (unsigned long long)maxlen); 210 goto out; 211 } 212 if (maxlen > ((afi == AFI_IPV4) ? 32 : 128)) { 213 warnx("%s: maxLength (%llu) too large", 214 fn, (unsigned long long)maxlen); 215 goto out; 216 } 217 } 218 219 res = &roa->ips[roa->ipsz++]; 220 res->addr = ipaddr; 221 res->afi = afi; 222 res->maxlength = maxlen; 223 ip_roa_compose_ranges(res); 224 } 225 } 226 227 rc = 1; 228 out: 229 RouteOriginAttestation_free(roa_asn1); 230 return rc; 231 } 232 233 /* 234 * Parse a full RFC 6482 file. 235 * Returns the ROA or NULL if the document was malformed. 236 */ 237 struct roa * 238 roa_parse(X509 **x509, const char *fn, int talid, const unsigned char *der, 239 size_t len) 240 { 241 struct roa *roa; 242 size_t cmsz; 243 unsigned char *cms; 244 struct cert *cert = NULL; 245 time_t signtime = 0; 246 int rc = 0; 247 248 cms = cms_parse_validate(x509, fn, der, len, roa_oid, &cmsz, &signtime); 249 if (cms == NULL) 250 return NULL; 251 252 if ((roa = calloc(1, sizeof(struct roa))) == NULL) 253 err(1, NULL); 254 roa->signtime = signtime; 255 256 if (!x509_get_aia(*x509, fn, &roa->aia)) 257 goto out; 258 if (!x509_get_aki(*x509, fn, &roa->aki)) 259 goto out; 260 if (!x509_get_sia(*x509, fn, &roa->sia)) 261 goto out; 262 if (!x509_get_ski(*x509, fn, &roa->ski)) 263 goto out; 264 if (roa->aia == NULL || roa->aki == NULL || roa->sia == NULL || 265 roa->ski == NULL) { 266 warnx("%s: RFC 6487 section 4.8: " 267 "missing AIA, AKI, SIA, or SKI X509 extension", fn); 268 goto out; 269 } 270 271 if (!x509_get_notbefore(*x509, fn, &roa->notbefore)) 272 goto out; 273 if (!x509_get_notafter(*x509, fn, &roa->notafter)) 274 goto out; 275 276 if (!roa_parse_econtent(fn, roa, cms, cmsz)) 277 goto out; 278 279 if (x509_any_inherits(*x509)) { 280 warnx("%s: inherit elements not allowed in EE cert", fn); 281 goto out; 282 } 283 284 if ((cert = cert_parse_ee_cert(fn, talid, *x509)) == NULL) 285 goto out; 286 287 if (cert->asz > 0) { 288 warnx("%s: superfluous AS Resources extension present", fn); 289 goto out; 290 } 291 292 /* 293 * If the ROA isn't valid, we accept it anyway and depend upon 294 * the code around roa_read() to check the "valid" field itself. 295 */ 296 roa->valid = valid_roa(fn, cert, roa); 297 298 rc = 1; 299 out: 300 if (rc == 0) { 301 roa_free(roa); 302 roa = NULL; 303 X509_free(*x509); 304 *x509 = NULL; 305 } 306 cert_free(cert); 307 free(cms); 308 return roa; 309 } 310 311 /* 312 * Free an ROA pointer. 313 * Safe to call with NULL. 314 */ 315 void 316 roa_free(struct roa *p) 317 { 318 319 if (p == NULL) 320 return; 321 free(p->aia); 322 free(p->aki); 323 free(p->sia); 324 free(p->ski); 325 free(p->ips); 326 free(p); 327 } 328 329 /* 330 * Serialise parsed ROA content. 331 * See roa_read() for reader. 332 */ 333 void 334 roa_buffer(struct ibuf *b, const struct roa *p) 335 { 336 io_simple_buffer(b, &p->valid, sizeof(p->valid)); 337 io_simple_buffer(b, &p->asid, sizeof(p->asid)); 338 io_simple_buffer(b, &p->talid, sizeof(p->talid)); 339 io_simple_buffer(b, &p->ipsz, sizeof(p->ipsz)); 340 io_simple_buffer(b, &p->expires, sizeof(p->expires)); 341 342 io_simple_buffer(b, p->ips, p->ipsz * sizeof(p->ips[0])); 343 344 io_str_buffer(b, p->aia); 345 io_str_buffer(b, p->aki); 346 io_str_buffer(b, p->ski); 347 } 348 349 /* 350 * Read parsed ROA content from descriptor. 351 * See roa_buffer() for writer. 352 * Result must be passed to roa_free(). 353 */ 354 struct roa * 355 roa_read(struct ibuf *b) 356 { 357 struct roa *p; 358 359 if ((p = calloc(1, sizeof(struct roa))) == NULL) 360 err(1, NULL); 361 362 io_read_buf(b, &p->valid, sizeof(p->valid)); 363 io_read_buf(b, &p->asid, sizeof(p->asid)); 364 io_read_buf(b, &p->talid, sizeof(p->talid)); 365 io_read_buf(b, &p->ipsz, sizeof(p->ipsz)); 366 io_read_buf(b, &p->expires, sizeof(p->expires)); 367 368 if ((p->ips = calloc(p->ipsz, sizeof(struct roa_ip))) == NULL) 369 err(1, NULL); 370 io_read_buf(b, p->ips, p->ipsz * sizeof(p->ips[0])); 371 372 io_read_str(b, &p->aia); 373 io_read_str(b, &p->aki); 374 io_read_str(b, &p->ski); 375 assert(p->aia && p->aki && p->ski); 376 377 return p; 378 } 379 380 /* 381 * Add each IP address in the ROA into the VRP tree. 382 * Updates "vrps" to be the number of VRPs and "uniqs" to be the unique 383 * number of addresses. 384 */ 385 void 386 roa_insert_vrps(struct vrp_tree *tree, struct roa *roa, struct repo *rp) 387 { 388 struct vrp *v, *found; 389 size_t i; 390 391 for (i = 0; i < roa->ipsz; i++) { 392 if ((v = malloc(sizeof(*v))) == NULL) 393 err(1, NULL); 394 v->afi = roa->ips[i].afi; 395 v->addr = roa->ips[i].addr; 396 v->maxlength = roa->ips[i].maxlength; 397 v->asid = roa->asid; 398 v->talid = roa->talid; 399 if (rp != NULL) 400 v->repoid = repo_id(rp); 401 else 402 v->repoid = 0; 403 v->expires = roa->expires; 404 405 /* 406 * Check if a similar VRP already exists in the tree. 407 * If the found VRP expires sooner, update it to this 408 * ROAs later expiry moment. 409 */ 410 if ((found = RB_INSERT(vrp_tree, tree, v)) != NULL) { 411 /* already exists */ 412 if (found->expires < v->expires) { 413 /* update found with preferred data */ 414 /* adjust unique count */ 415 repo_stat_inc(repo_byid(found->repoid), 416 found->talid, RTYPE_ROA, STYPE_DEC_UNIQUE); 417 found->expires = v->expires; 418 found->talid = v->talid; 419 found->repoid = v->repoid; 420 repo_stat_inc(rp, v->talid, RTYPE_ROA, 421 STYPE_UNIQUE); 422 } 423 free(v); 424 } else 425 repo_stat_inc(rp, v->talid, RTYPE_ROA, STYPE_UNIQUE); 426 427 repo_stat_inc(rp, roa->talid, RTYPE_ROA, STYPE_TOTAL); 428 } 429 } 430 431 static inline int 432 vrpcmp(struct vrp *a, struct vrp *b) 433 { 434 int rv; 435 436 if (a->afi > b->afi) 437 return 1; 438 if (a->afi < b->afi) 439 return -1; 440 switch (a->afi) { 441 case AFI_IPV4: 442 rv = memcmp(&a->addr.addr, &b->addr.addr, 4); 443 if (rv) 444 return rv; 445 break; 446 case AFI_IPV6: 447 rv = memcmp(&a->addr.addr, &b->addr.addr, 16); 448 if (rv) 449 return rv; 450 break; 451 default: 452 break; 453 } 454 /* a smaller prefixlen is considered bigger, e.g. /8 vs /10 */ 455 if (a->addr.prefixlen < b->addr.prefixlen) 456 return 1; 457 if (a->addr.prefixlen > b->addr.prefixlen) 458 return -1; 459 if (a->maxlength < b->maxlength) 460 return 1; 461 if (a->maxlength > b->maxlength) 462 return -1; 463 464 if (a->asid > b->asid) 465 return 1; 466 if (a->asid < b->asid) 467 return -1; 468 469 return 0; 470 } 471 472 RB_GENERATE(vrp_tree, vrp, entry, vrpcmp); 473