1 /* $OpenBSD: rsc.c,v 1.34 2024/02/21 09:17:06 tb Exp $ */ 2 /* 3 * Copyright (c) 2022 Theo Buehler <tb@openbsd.org> 4 * Copyright (c) 2022 Job Snijders <job@fastly.com> 5 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <err.h> 21 #include <stdlib.h> 22 #include <string.h> 23 #include <unistd.h> 24 25 #include <openssl/asn1.h> 26 #include <openssl/asn1t.h> 27 #include <openssl/safestack.h> 28 #include <openssl/stack.h> 29 #include <openssl/x509.h> 30 #include <openssl/x509v3.h> 31 32 #include "extern.h" 33 34 extern ASN1_OBJECT *rsc_oid; 35 36 /* 37 * Types and templates for RSC eContent - RFC 9323 38 */ 39 40 ASN1_ITEM_EXP ConstrainedASIdentifiers_it; 41 ASN1_ITEM_EXP ConstrainedIPAddressFamily_it; 42 ASN1_ITEM_EXP ConstrainedIPAddrBlocks_it; 43 ASN1_ITEM_EXP FileNameAndHash_it; 44 ASN1_ITEM_EXP ResourceBlock_it; 45 ASN1_ITEM_EXP RpkiSignedChecklist_it; 46 47 typedef struct { 48 ASIdOrRanges *asnum; 49 } ConstrainedASIdentifiers; 50 51 ASN1_SEQUENCE(ConstrainedASIdentifiers) = { 52 ASN1_EXP_SEQUENCE_OF(ConstrainedASIdentifiers, asnum, ASIdOrRange, 0), 53 } ASN1_SEQUENCE_END(ConstrainedASIdentifiers); 54 55 typedef struct { 56 ASN1_OCTET_STRING *addressFamily; 57 STACK_OF(IPAddressOrRange) *addressesOrRanges; 58 } ConstrainedIPAddressFamily; 59 60 ASN1_SEQUENCE(ConstrainedIPAddressFamily) = { 61 ASN1_SIMPLE(ConstrainedIPAddressFamily, addressFamily, 62 ASN1_OCTET_STRING), 63 ASN1_SEQUENCE_OF(ConstrainedIPAddressFamily, addressesOrRanges, 64 IPAddressOrRange), 65 } ASN1_SEQUENCE_END(ConstrainedIPAddressFamily); 66 67 typedef STACK_OF(ConstrainedIPAddressFamily) ConstrainedIPAddrBlocks; 68 DECLARE_STACK_OF(ConstrainedIPAddressFamily); 69 70 ASN1_ITEM_TEMPLATE(ConstrainedIPAddrBlocks) = 71 ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, ConstrainedIPAddrBlocks, 72 ConstrainedIPAddressFamily) 73 ASN1_ITEM_TEMPLATE_END(ConstrainedIPAddrBlocks); 74 75 typedef struct { 76 ConstrainedASIdentifiers *asID; 77 ConstrainedIPAddrBlocks *ipAddrBlocks; 78 } ResourceBlock; 79 80 ASN1_SEQUENCE(ResourceBlock) = { 81 ASN1_EXP_OPT(ResourceBlock, asID, ConstrainedASIdentifiers, 0), 82 ASN1_EXP_SEQUENCE_OF_OPT(ResourceBlock, ipAddrBlocks, 83 ConstrainedIPAddressFamily, 1) 84 } ASN1_SEQUENCE_END(ResourceBlock); 85 86 typedef struct { 87 ASN1_IA5STRING *fileName; 88 ASN1_OCTET_STRING *hash; 89 } FileNameAndHash; 90 91 DECLARE_STACK_OF(FileNameAndHash); 92 93 #ifndef DEFINE_STACK_OF 94 #define sk_ConstrainedIPAddressFamily_num(sk) \ 95 SKM_sk_num(ConstrainedIPAddressFamily, (sk)) 96 #define sk_ConstrainedIPAddressFamily_value(sk, i) \ 97 SKM_sk_value(ConstrainedIPAddressFamily, (sk), (i)) 98 99 #define sk_FileNameAndHash_num(sk) SKM_sk_num(FileNameAndHash, (sk)) 100 #define sk_FileNameAndHash_value(sk, i) SKM_sk_value(FileNameAndHash, (sk), (i)) 101 #endif 102 103 ASN1_SEQUENCE(FileNameAndHash) = { 104 ASN1_OPT(FileNameAndHash, fileName, ASN1_IA5STRING), 105 ASN1_SIMPLE(FileNameAndHash, hash, ASN1_OCTET_STRING), 106 } ASN1_SEQUENCE_END(FileNameAndHash); 107 108 typedef struct { 109 ASN1_INTEGER *version; 110 ResourceBlock *resources; 111 X509_ALGOR *digestAlgorithm; 112 STACK_OF(FileNameAndHash) *checkList; 113 } RpkiSignedChecklist; 114 115 ASN1_SEQUENCE(RpkiSignedChecklist) = { 116 ASN1_EXP_OPT(RpkiSignedChecklist, version, ASN1_INTEGER, 0), 117 ASN1_SIMPLE(RpkiSignedChecklist, resources, ResourceBlock), 118 ASN1_SIMPLE(RpkiSignedChecklist, digestAlgorithm, X509_ALGOR), 119 ASN1_SEQUENCE_OF(RpkiSignedChecklist, checkList, FileNameAndHash), 120 } ASN1_SEQUENCE_END(RpkiSignedChecklist); 121 122 DECLARE_ASN1_FUNCTIONS(RpkiSignedChecklist); 123 IMPLEMENT_ASN1_FUNCTIONS(RpkiSignedChecklist); 124 125 /* 126 * Parse asID (inside ResourceBlock) 127 * Return 0 on failure. 128 */ 129 static int 130 rsc_parse_aslist(const char *fn, struct rsc *rsc, 131 const ConstrainedASIdentifiers *asids) 132 { 133 int i, asz; 134 135 if (asids == NULL) 136 return 1; 137 138 if ((asz = sk_ASIdOrRange_num(asids->asnum)) == 0) { 139 warnx("%s: RSC asID empty", fn); 140 return 0; 141 } 142 143 if (asz >= MAX_AS_SIZE) { 144 warnx("%s: too many AS number entries: limit %d", 145 fn, MAX_AS_SIZE); 146 return 0; 147 } 148 149 rsc->as = calloc(asz, sizeof(struct cert_as)); 150 if (rsc->as == NULL) 151 err(1, NULL); 152 153 for (i = 0; i < asz; i++) { 154 const ASIdOrRange *aor; 155 156 aor = sk_ASIdOrRange_value(asids->asnum, i); 157 158 switch (aor->type) { 159 case ASIdOrRange_id: 160 if (!sbgp_as_id(fn, rsc->as, &rsc->asz, aor->u.id)) 161 return 0; 162 break; 163 case ASIdOrRange_range: 164 if (!sbgp_as_range(fn, rsc->as, &rsc->asz, 165 aor->u.range)) 166 return 0; 167 break; 168 default: 169 warnx("%s: RSC AsList: unknown type %d", fn, aor->type); 170 return 0; 171 } 172 } 173 174 return 1; 175 } 176 177 static int 178 rsc_parse_iplist(const char *fn, struct rsc *rsc, 179 const ConstrainedIPAddrBlocks *ipAddrBlocks) 180 { 181 const ConstrainedIPAddressFamily *af; 182 const IPAddressOrRanges *aors; 183 const IPAddressOrRange *aor; 184 size_t ipsz; 185 enum afi afi; 186 int i, j; 187 188 if (ipAddrBlocks == NULL) 189 return 1; 190 191 if (sk_ConstrainedIPAddressFamily_num(ipAddrBlocks) == 0) { 192 warnx("%s: RSC ipAddrBlocks empty", fn); 193 return 0; 194 } 195 196 for (i = 0; i < sk_ConstrainedIPAddressFamily_num(ipAddrBlocks); i++) { 197 af = sk_ConstrainedIPAddressFamily_value(ipAddrBlocks, i); 198 aors = af->addressesOrRanges; 199 200 ipsz = rsc->ipsz + sk_IPAddressOrRange_num(aors); 201 if (ipsz >= MAX_IP_SIZE) { 202 warnx("%s: too many IP address entries: limit %d", 203 fn, MAX_IP_SIZE); 204 return 0; 205 } 206 207 rsc->ips = recallocarray(rsc->ips, rsc->ipsz, ipsz, 208 sizeof(struct cert_ip)); 209 if (rsc->ips == NULL) 210 err(1, NULL); 211 212 if (!ip_addr_afi_parse(fn, af->addressFamily, &afi)) { 213 warnx("%s: RSC: invalid AFI", fn); 214 return 0; 215 } 216 217 for (j = 0; j < sk_IPAddressOrRange_num(aors); j++) { 218 aor = sk_IPAddressOrRange_value(aors, j); 219 switch (aor->type) { 220 case IPAddressOrRange_addressPrefix: 221 if (!sbgp_addr(fn, rsc->ips, 222 &rsc->ipsz, afi, aor->u.addressPrefix)) 223 return 0; 224 break; 225 case IPAddressOrRange_addressRange: 226 if (!sbgp_addr_range(fn, rsc->ips, 227 &rsc->ipsz, afi, aor->u.addressRange)) 228 return 0; 229 break; 230 default: 231 warnx("%s: RFC 3779: IPAddressOrRange: " 232 "unknown type %d", fn, aor->type); 233 return 0; 234 } 235 } 236 } 237 238 return 1; 239 } 240 241 static int 242 rsc_check_digesttype(const char *fn, struct rsc *rsc, const X509_ALGOR *alg) 243 { 244 const ASN1_OBJECT *obj; 245 int type, nid; 246 247 X509_ALGOR_get0(&obj, &type, NULL, alg); 248 249 if (type != V_ASN1_UNDEF) { 250 warnx("%s: RSC DigestAlgorithmIdentifier unexpected parameters:" 251 " %d", fn, type); 252 return 0; 253 } 254 255 if ((nid = OBJ_obj2nid(obj)) != NID_sha256) { 256 warnx("%s: RSC DigestAlgorithmIdentifier: want SHA256, have %s" 257 " (NID %d)", fn, ASN1_tag2str(nid), nid); 258 return 0; 259 } 260 261 return 1; 262 } 263 264 /* 265 * Parse the FileNameAndHash sequence, RFC 9323, section 4.4. 266 * Return zero on failure, non-zero on success. 267 */ 268 static int 269 rsc_parse_checklist(const char *fn, struct rsc *rsc, 270 const STACK_OF(FileNameAndHash) *checkList) 271 { 272 FileNameAndHash *fh; 273 ASN1_IA5STRING *fileName; 274 struct rscfile *file; 275 size_t sz, i; 276 277 if ((sz = sk_FileNameAndHash_num(checkList)) == 0) { 278 warnx("%s: RSC checkList needs at least one entry", fn); 279 return 0; 280 } 281 282 if (sz >= MAX_CHECKLIST_ENTRIES) { 283 warnx("%s: %zu exceeds checklist entry limit (%d)", fn, sz, 284 MAX_CHECKLIST_ENTRIES); 285 return 0; 286 } 287 288 rsc->files = calloc(sz, sizeof(struct rscfile)); 289 if (rsc->files == NULL) 290 err(1, NULL); 291 rsc->filesz = sz; 292 293 for (i = 0; i < sz; i++) { 294 fh = sk_FileNameAndHash_value(checkList, i); 295 296 file = &rsc->files[i]; 297 298 if (fh->hash->length != SHA256_DIGEST_LENGTH) { 299 warnx("%s: RSC Digest: invalid SHA256 length", fn); 300 return 0; 301 } 302 memcpy(file->hash, fh->hash->data, SHA256_DIGEST_LENGTH); 303 304 if ((fileName = fh->fileName) == NULL) 305 continue; 306 307 if (!valid_filename(fileName->data, fileName->length)) { 308 warnx("%s: RSC FileNameAndHash: bad filename", fn); 309 return 0; 310 } 311 312 file->filename = strndup(fileName->data, fileName->length); 313 if (file->filename == NULL) 314 err(1, NULL); 315 } 316 317 return 1; 318 } 319 320 /* 321 * Parses the eContent segment of an RSC file 322 * RFC 9323, section 4 323 * Returns zero on failure, non-zero on success. 324 */ 325 static int 326 rsc_parse_econtent(const char *fn, struct rsc *rsc, const unsigned char *d, 327 size_t dsz) 328 { 329 const unsigned char *oder; 330 RpkiSignedChecklist *rsc_asn1; 331 ResourceBlock *resources; 332 int rc = 0; 333 334 /* 335 * RFC 9323 section 4 336 */ 337 338 oder = d; 339 if ((rsc_asn1 = d2i_RpkiSignedChecklist(NULL, &d, dsz)) == NULL) { 340 warnx("%s: RSC: failed to parse RpkiSignedChecklist", fn); 341 goto out; 342 } 343 if (d != oder + dsz) { 344 warnx("%s: %td bytes trailing garbage in eContent", fn, 345 oder + dsz - d); 346 goto out; 347 } 348 349 if (!valid_econtent_version(fn, rsc_asn1->version, 0)) 350 goto out; 351 352 resources = rsc_asn1->resources; 353 if (resources->asID == NULL && resources->ipAddrBlocks == NULL) { 354 warnx("%s: RSC: one of asID or ipAddrBlocks must be present", 355 fn); 356 goto out; 357 } 358 359 if (!rsc_parse_aslist(fn, rsc, resources->asID)) 360 goto out; 361 362 if (!rsc_parse_iplist(fn, rsc, resources->ipAddrBlocks)) 363 goto out; 364 365 if (!rsc_check_digesttype(fn, rsc, rsc_asn1->digestAlgorithm)) 366 goto out; 367 368 if (!rsc_parse_checklist(fn, rsc, rsc_asn1->checkList)) 369 goto out; 370 371 rc = 1; 372 out: 373 RpkiSignedChecklist_free(rsc_asn1); 374 return rc; 375 } 376 377 /* 378 * Parse a full RFC 9323 file. 379 * Returns the RSC or NULL if the object was malformed. 380 */ 381 struct rsc * 382 rsc_parse(X509 **x509, const char *fn, int talid, const unsigned char *der, 383 size_t len) 384 { 385 struct rsc *rsc; 386 unsigned char *cms; 387 size_t cmsz; 388 struct cert *cert = NULL; 389 time_t signtime = 0; 390 int rc = 0; 391 392 cms = cms_parse_validate(x509, fn, der, len, rsc_oid, &cmsz, 393 &signtime); 394 if (cms == NULL) 395 return NULL; 396 397 if ((rsc = calloc(1, sizeof(struct rsc))) == NULL) 398 err(1, NULL); 399 rsc->signtime = signtime; 400 401 if (!x509_get_aia(*x509, fn, &rsc->aia)) 402 goto out; 403 if (!x509_get_aki(*x509, fn, &rsc->aki)) 404 goto out; 405 if (!x509_get_ski(*x509, fn, &rsc->ski)) 406 goto out; 407 if (rsc->aia == NULL || rsc->aki == NULL || rsc->ski == NULL) { 408 warnx("%s: RFC 6487 section 4.8: " 409 "missing AIA, AKI or SKI X509 extension", fn); 410 goto out; 411 } 412 413 if (!x509_get_notbefore(*x509, fn, &rsc->notbefore)) 414 goto out; 415 if (!x509_get_notafter(*x509, fn, &rsc->notafter)) 416 goto out; 417 418 if (X509_get_ext_by_NID(*x509, NID_sinfo_access, -1) != -1) { 419 warnx("%s: RSC: EE cert must not have an SIA extension", fn); 420 goto out; 421 } 422 423 if (x509_any_inherits(*x509)) { 424 warnx("%s: inherit elements not allowed in EE cert", fn); 425 goto out; 426 } 427 428 if (!rsc_parse_econtent(fn, rsc, cms, cmsz)) 429 goto out; 430 431 if ((cert = cert_parse_ee_cert(fn, talid, *x509)) == NULL) 432 goto out; 433 434 rsc->valid = valid_rsc(fn, cert, rsc); 435 436 rc = 1; 437 out: 438 if (rc == 0) { 439 rsc_free(rsc); 440 rsc = NULL; 441 X509_free(*x509); 442 *x509 = NULL; 443 } 444 cert_free(cert); 445 free(cms); 446 return rsc; 447 } 448 449 /* 450 * Free an RSC pointer. 451 * Safe to call with NULL. 452 */ 453 void 454 rsc_free(struct rsc *p) 455 { 456 size_t i; 457 458 if (p == NULL) 459 return; 460 461 for (i = 0; i < p->filesz; i++) 462 free(p->files[i].filename); 463 464 free(p->aia); 465 free(p->aki); 466 free(p->ski); 467 free(p->ips); 468 free(p->as); 469 free(p->files); 470 free(p); 471 } 472