1 /* $OpenBSD: cert.c,v 1.155 2024/12/18 21:12:26 tb Exp $ */
2 /*
3 * Copyright (c) 2022 Theo Buehler <tb@openbsd.org>
4 * Copyright (c) 2021 Job Snijders <job@openbsd.org>
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 <assert.h>
21 #include <err.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25
26 #include <openssl/asn1.h>
27 #include <openssl/x509.h>
28 #include <openssl/x509v3.h>
29
30 #include "extern.h"
31
32 extern ASN1_OBJECT *certpol_oid; /* id-cp-ipAddr-asNumber cert policy */
33 extern ASN1_OBJECT *carepo_oid; /* 1.3.6.1.5.5.7.48.5 (caRepository) */
34 extern ASN1_OBJECT *manifest_oid; /* 1.3.6.1.5.5.7.48.10 (rpkiManifest) */
35 extern ASN1_OBJECT *notify_oid; /* 1.3.6.1.5.5.7.48.13 (rpkiNotify) */
36
37 int certid = TALSZ_MAX;
38
39 /*
40 * Append an IP address structure to our list of results.
41 * This will also constrain us to having at most one inheritance
42 * statement per AFI and also not have overlapping ranges (as prohibited
43 * in section 2.2.3.6).
44 * It does not make sure that ranges can't coalesce, that is, that any
45 * two ranges abut each other.
46 * This is warned against in section 2.2.3.6, but doesn't change the
47 * semantics of the system.
48 * Returns zero on failure (IP overlap) non-zero on success.
49 */
50 static int
append_ip(const char * fn,struct cert_ip * ips,size_t * num_ips,const struct cert_ip * ip)51 append_ip(const char *fn, struct cert_ip *ips, size_t *num_ips,
52 const struct cert_ip *ip)
53 {
54 if (!ip_addr_check_overlap(ip, fn, ips, *num_ips, 0))
55 return 0;
56 ips[(*num_ips)++] = *ip;
57 return 1;
58 }
59
60 /*
61 * Append an AS identifier structure to our list of results.
62 * Makes sure that the identifiers do not overlap or improperly inherit
63 * as defined by RFC 3779 section 3.3.
64 */
65 static int
append_as(const char * fn,struct cert_as * ases,size_t * num_ases,const struct cert_as * as)66 append_as(const char *fn, struct cert_as *ases, size_t *num_ases,
67 const struct cert_as *as)
68 {
69 if (!as_check_overlap(as, fn, ases, *num_ases, 0))
70 return 0;
71 ases[(*num_ases)++] = *as;
72 return 1;
73 }
74
75 /*
76 * Parse a range of AS identifiers as in 3.2.3.8.
77 * Returns zero on failure, non-zero on success.
78 */
79 int
sbgp_as_range(const char * fn,struct cert_as * ases,size_t * num_ases,const ASRange * range)80 sbgp_as_range(const char *fn, struct cert_as *ases, size_t *num_ases,
81 const ASRange *range)
82 {
83 struct cert_as as;
84
85 memset(&as, 0, sizeof(struct cert_as));
86 as.type = CERT_AS_RANGE;
87
88 if (!as_id_parse(range->min, &as.range.min)) {
89 warnx("%s: RFC 3779 section 3.2.3.8 (via RFC 1930): "
90 "malformed AS identifier", fn);
91 return 0;
92 }
93
94 if (!as_id_parse(range->max, &as.range.max)) {
95 warnx("%s: RFC 3779 section 3.2.3.8 (via RFC 1930): "
96 "malformed AS identifier", fn);
97 return 0;
98 }
99
100 if (as.range.max == as.range.min) {
101 warnx("%s: RFC 3379 section 3.2.3.8: ASRange: "
102 "range is singular", fn);
103 return 0;
104 } else if (as.range.max < as.range.min) {
105 warnx("%s: RFC 3379 section 3.2.3.8: ASRange: "
106 "range is out of order", fn);
107 return 0;
108 }
109
110 return append_as(fn, ases, num_ases, &as);
111 }
112
113 /*
114 * Parse an entire 3.2.3.10 integer type.
115 */
116 int
sbgp_as_id(const char * fn,struct cert_as * ases,size_t * num_ases,const ASN1_INTEGER * i)117 sbgp_as_id(const char *fn, struct cert_as *ases, size_t *num_ases,
118 const ASN1_INTEGER *i)
119 {
120 struct cert_as as;
121
122 memset(&as, 0, sizeof(struct cert_as));
123 as.type = CERT_AS_ID;
124
125 if (!as_id_parse(i, &as.id)) {
126 warnx("%s: RFC 3779 section 3.2.3.10 (via RFC 1930): "
127 "malformed AS identifier", fn);
128 return 0;
129 }
130 if (as.id == 0) {
131 warnx("%s: RFC 3779 section 3.2.3.10 (via RFC 1930): "
132 "AS identifier zero is reserved", fn);
133 return 0;
134 }
135
136 return append_as(fn, ases, num_ases, &as);
137 }
138
139 static int
sbgp_as_inherit(const char * fn,struct cert_as * ases,size_t * num_ases)140 sbgp_as_inherit(const char *fn, struct cert_as *ases, size_t *num_ases)
141 {
142 struct cert_as as;
143
144 memset(&as, 0, sizeof(struct cert_as));
145 as.type = CERT_AS_INHERIT;
146
147 return append_as(fn, ases, num_ases, &as);
148 }
149
150 int
sbgp_parse_assysnum(const char * fn,const ASIdentifiers * asidentifiers,struct cert_as ** out_as,size_t * out_num_ases)151 sbgp_parse_assysnum(const char *fn, const ASIdentifiers *asidentifiers,
152 struct cert_as **out_as, size_t *out_num_ases)
153 {
154 const ASIdOrRanges *aors = NULL;
155 struct cert_as *as = NULL;
156 size_t num_ases = 0, num;
157 int i;
158
159 assert(*out_as == NULL && *out_num_ases == 0);
160
161 if (asidentifiers->rdi != NULL) {
162 warnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: "
163 "should not have RDI values", fn);
164 goto out;
165 }
166
167 if (asidentifiers->asnum == NULL) {
168 warnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: "
169 "no AS number resource set", fn);
170 goto out;
171 }
172
173 switch (asidentifiers->asnum->type) {
174 case ASIdentifierChoice_inherit:
175 num = 1;
176 break;
177 case ASIdentifierChoice_asIdsOrRanges:
178 aors = asidentifiers->asnum->u.asIdsOrRanges;
179 num = sk_ASIdOrRange_num(aors);
180 break;
181 default:
182 warnx("%s: RFC 3779 section 3.2.3.2: ASIdentifierChoice: "
183 "unknown type %d", fn, asidentifiers->asnum->type);
184 goto out;
185 }
186
187 if (num == 0) {
188 warnx("%s: RFC 6487 section 4.8.11: empty asIdsOrRanges", fn);
189 goto out;
190 }
191 if (num >= MAX_AS_SIZE) {
192 warnx("%s: too many AS number entries: limit %d",
193 fn, MAX_AS_SIZE);
194 goto out;
195 }
196 as = calloc(num, sizeof(struct cert_as));
197 if (as == NULL)
198 err(1, NULL);
199
200 if (aors == NULL) {
201 if (!sbgp_as_inherit(fn, as, &num_ases))
202 goto out;
203 }
204
205 for (i = 0; i < sk_ASIdOrRange_num(aors); i++) {
206 const ASIdOrRange *aor;
207
208 aor = sk_ASIdOrRange_value(aors, i);
209 switch (aor->type) {
210 case ASIdOrRange_id:
211 if (!sbgp_as_id(fn, as, &num_ases, aor->u.id))
212 goto out;
213 break;
214 case ASIdOrRange_range:
215 if (!sbgp_as_range(fn, as, &num_ases, aor->u.range))
216 goto out;
217 break;
218 default:
219 warnx("%s: RFC 3779 section 3.2.3.5: ASIdOrRange: "
220 "unknown type %d", fn, aor->type);
221 goto out;
222 }
223 }
224
225 *out_as = as;
226 *out_num_ases = num_ases;
227
228 return 1;
229
230 out:
231 free(as);
232
233 return 0;
234 }
235
236 /*
237 * Parse RFC 6487 4.8.11 X509v3 extension, with syntax documented in RFC
238 * 3779 starting in section 3.2.
239 * Returns zero on failure, non-zero on success.
240 */
241 static int
sbgp_assysnum(const char * fn,struct cert * cert,X509_EXTENSION * ext)242 sbgp_assysnum(const char *fn, struct cert *cert, X509_EXTENSION *ext)
243 {
244 ASIdentifiers *asidentifiers = NULL;
245 int rc = 0;
246
247 if (!X509_EXTENSION_get_critical(ext)) {
248 warnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: "
249 "extension not critical", fn);
250 goto out;
251 }
252
253 if ((asidentifiers = X509V3_EXT_d2i(ext)) == NULL) {
254 warnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: "
255 "failed extension parse", fn);
256 goto out;
257 }
258
259 if (!sbgp_parse_assysnum(fn, asidentifiers, &cert->ases,
260 &cert->num_ases))
261 goto out;
262
263 rc = 1;
264 out:
265 ASIdentifiers_free(asidentifiers);
266 return rc;
267 }
268
269 /*
270 * Construct a RFC 3779 2.2.3.8 range from its bit string.
271 * Returns zero on failure, non-zero on success.
272 */
273 int
sbgp_addr(const char * fn,struct cert_ip * ips,size_t * num_ips,enum afi afi,const ASN1_BIT_STRING * bs)274 sbgp_addr(const char *fn, struct cert_ip *ips, size_t *num_ips, enum afi afi,
275 const ASN1_BIT_STRING *bs)
276 {
277 struct cert_ip ip;
278
279 memset(&ip, 0, sizeof(struct cert_ip));
280
281 ip.afi = afi;
282 ip.type = CERT_IP_ADDR;
283
284 if (!ip_addr_parse(bs, afi, fn, &ip.ip)) {
285 warnx("%s: RFC 3779 section 2.2.3.8: IPAddress: "
286 "invalid IP address", fn);
287 return 0;
288 }
289
290 if (!ip_cert_compose_ranges(&ip)) {
291 warnx("%s: RFC 3779 section 2.2.3.8: IPAddress: "
292 "IP address range reversed", fn);
293 return 0;
294 }
295
296 return append_ip(fn, ips, num_ips, &ip);
297 }
298
299 /*
300 * Parse RFC 3779 2.2.3.9 range of addresses.
301 * Returns zero on failure, non-zero on success.
302 */
303 int
sbgp_addr_range(const char * fn,struct cert_ip * ips,size_t * num_ips,enum afi afi,const IPAddressRange * range)304 sbgp_addr_range(const char *fn, struct cert_ip *ips, size_t *num_ips,
305 enum afi afi, const IPAddressRange *range)
306 {
307 struct cert_ip ip;
308
309 memset(&ip, 0, sizeof(struct cert_ip));
310
311 ip.afi = afi;
312 ip.type = CERT_IP_RANGE;
313
314 if (!ip_addr_parse(range->min, afi, fn, &ip.range.min)) {
315 warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
316 "invalid IP address", fn);
317 return 0;
318 }
319
320 if (!ip_addr_parse(range->max, afi, fn, &ip.range.max)) {
321 warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
322 "invalid IP address", fn);
323 return 0;
324 }
325
326 if (!ip_cert_compose_ranges(&ip)) {
327 warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
328 "IP address range reversed", fn);
329 return 0;
330 }
331
332 return append_ip(fn, ips, num_ips, &ip);
333 }
334
335 static int
sbgp_addr_inherit(const char * fn,struct cert_ip * ips,size_t * num_ips,enum afi afi)336 sbgp_addr_inherit(const char *fn, struct cert_ip *ips, size_t *num_ips,
337 enum afi afi)
338 {
339 struct cert_ip ip;
340
341 memset(&ip, 0, sizeof(struct cert_ip));
342
343 ip.afi = afi;
344 ip.type = CERT_IP_INHERIT;
345
346 return append_ip(fn, ips, num_ips, &ip);
347 }
348
349 int
sbgp_parse_ipaddrblk(const char * fn,const IPAddrBlocks * addrblk,struct cert_ip ** out_ips,size_t * out_num_ips)350 sbgp_parse_ipaddrblk(const char *fn, const IPAddrBlocks *addrblk,
351 struct cert_ip **out_ips, size_t *out_num_ips)
352 {
353 const IPAddressFamily *af;
354 const IPAddressOrRanges *aors;
355 const IPAddressOrRange *aor;
356 enum afi afi;
357 struct cert_ip *ips = NULL;
358 size_t num_ips = 0, num;
359 int ipv4_seen = 0, ipv6_seen = 0;
360 int i, j, ipaddrblocksz;
361
362 assert(*out_ips == NULL && *out_num_ips == 0);
363
364 ipaddrblocksz = sk_IPAddressFamily_num(addrblk);
365 if (ipaddrblocksz != 1 && ipaddrblocksz != 2) {
366 warnx("%s: RFC 6487 section 4.8.10: unexpected number of "
367 "ipAddrBlocks (got %d, expected 1 or 2)",
368 fn, ipaddrblocksz);
369 goto out;
370 }
371
372 for (i = 0; i < ipaddrblocksz; i++) {
373 af = sk_IPAddressFamily_value(addrblk, i);
374
375 switch (af->ipAddressChoice->type) {
376 case IPAddressChoice_inherit:
377 aors = NULL;
378 num = num_ips + 1;
379 break;
380 case IPAddressChoice_addressesOrRanges:
381 aors = af->ipAddressChoice->u.addressesOrRanges;
382 num = num_ips + sk_IPAddressOrRange_num(aors);
383 break;
384 default:
385 warnx("%s: RFC 3779: IPAddressChoice: unknown type %d",
386 fn, af->ipAddressChoice->type);
387 goto out;
388 }
389 if (num == num_ips) {
390 warnx("%s: RFC 6487 section 4.8.10: "
391 "empty ipAddressesOrRanges", fn);
392 goto out;
393 }
394
395 if (num >= MAX_IP_SIZE)
396 goto out;
397 ips = recallocarray(ips, num_ips, num, sizeof(struct cert_ip));
398 if (ips == NULL)
399 err(1, NULL);
400
401 if (!ip_addr_afi_parse(fn, af->addressFamily, &afi)) {
402 warnx("%s: RFC 3779: invalid AFI", fn);
403 goto out;
404 }
405
406 switch (afi) {
407 case AFI_IPV4:
408 if (ipv4_seen++ > 0) {
409 warnx("%s: RFC 6487 section 4.8.10: "
410 "IPv4 appears twice", fn);
411 goto out;
412 }
413 break;
414 case AFI_IPV6:
415 if (ipv6_seen++ > 0) {
416 warnx("%s: RFC 6487 section 4.8.10: "
417 "IPv6 appears twice", fn);
418 goto out;
419 }
420 break;
421 }
422
423 if (aors == NULL) {
424 if (!sbgp_addr_inherit(fn, ips, &num_ips, afi))
425 goto out;
426 continue;
427 }
428
429 for (j = 0; j < sk_IPAddressOrRange_num(aors); j++) {
430 aor = sk_IPAddressOrRange_value(aors, j);
431 switch (aor->type) {
432 case IPAddressOrRange_addressPrefix:
433 if (!sbgp_addr(fn, ips, &num_ips, afi,
434 aor->u.addressPrefix))
435 goto out;
436 break;
437 case IPAddressOrRange_addressRange:
438 if (!sbgp_addr_range(fn, ips, &num_ips, afi,
439 aor->u.addressRange))
440 goto out;
441 break;
442 default:
443 warnx("%s: RFC 3779: IPAddressOrRange: "
444 "unknown type %d", fn, aor->type);
445 goto out;
446 }
447 }
448 }
449
450 *out_ips = ips;
451 *out_num_ips = num_ips;
452
453 return 1;
454
455 out:
456 free(ips);
457
458 return 0;
459 }
460
461 /*
462 * Parse an sbgp-ipAddrBlock X509 extension, RFC 6487 4.8.10, with
463 * syntax documented in RFC 3779 starting in section 2.2.
464 * Returns zero on failure, non-zero on success.
465 */
466 static int
sbgp_ipaddrblk(const char * fn,struct cert * cert,X509_EXTENSION * ext)467 sbgp_ipaddrblk(const char *fn, struct cert *cert, X509_EXTENSION *ext)
468 {
469 IPAddrBlocks *addrblk = NULL;
470 int rc = 0;
471
472 if (!X509_EXTENSION_get_critical(ext)) {
473 warnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: "
474 "extension not critical", fn);
475 goto out;
476 }
477
478 if ((addrblk = X509V3_EXT_d2i(ext)) == NULL) {
479 warnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: "
480 "failed extension parse", fn);
481 goto out;
482 }
483
484 if (!sbgp_parse_ipaddrblk(fn, addrblk, &cert->ips, &cert->num_ips))
485 goto out;
486
487 if (cert->num_ips == 0) {
488 warnx("%s: RFC 6487 section 4.8.10: empty ipAddrBlock", fn);
489 goto out;
490 }
491
492 rc = 1;
493 out:
494 IPAddrBlocks_free(addrblk);
495 return rc;
496 }
497
498 /*
499 * Parse "Subject Information Access" extension for a CA cert,
500 * RFC 6487, section 4.8.8.1 and RFC 8182, section 3.2.
501 * Returns zero on failure, non-zero on success.
502 */
503 static int
sbgp_sia(const char * fn,struct cert * cert,X509_EXTENSION * ext)504 sbgp_sia(const char *fn, struct cert *cert, X509_EXTENSION *ext)
505 {
506 AUTHORITY_INFO_ACCESS *sia = NULL;
507 ACCESS_DESCRIPTION *ad;
508 ASN1_OBJECT *oid;
509 const char *mftfilename;
510 char *carepo = NULL, *rpkimft = NULL, *notify = NULL;
511 int i, rc = 0;
512
513 assert(cert->repo == NULL && cert->mft == NULL && cert->notify == NULL);
514
515 if (X509_EXTENSION_get_critical(ext)) {
516 warnx("%s: RFC 6487 section 4.8.8: SIA: "
517 "extension not non-critical", fn);
518 goto out;
519 }
520
521 if ((sia = X509V3_EXT_d2i(ext)) == NULL) {
522 warnx("%s: RFC 6487 section 4.8.8: SIA: failed extension parse",
523 fn);
524 goto out;
525 }
526
527 for (i = 0; i < sk_ACCESS_DESCRIPTION_num(sia); i++) {
528 ad = sk_ACCESS_DESCRIPTION_value(sia, i);
529
530 oid = ad->method;
531
532 if (OBJ_cmp(oid, carepo_oid) == 0) {
533 if (!x509_location(fn, "SIA: caRepository",
534 ad->location, &carepo))
535 goto out;
536 if (cert->repo == NULL && strncasecmp(carepo,
537 RSYNC_PROTO, RSYNC_PROTO_LEN) == 0) {
538 if (carepo[strlen(carepo) - 1] != '/') {
539 char *carepo_tmp;
540
541 if (asprintf(&carepo_tmp, "%s/",
542 carepo) == -1)
543 errx(1, NULL);
544 free(carepo);
545 carepo = carepo_tmp;
546 }
547
548 cert->repo = carepo;
549 carepo = NULL;
550 continue;
551 }
552 if (verbose)
553 warnx("%s: RFC 6487 section 4.8.8: SIA: "
554 "ignoring location %s", fn, carepo);
555 free(carepo);
556 carepo = NULL;
557 } else if (OBJ_cmp(oid, manifest_oid) == 0) {
558 if (!x509_location(fn, "SIA: rpkiManifest",
559 ad->location, &rpkimft))
560 goto out;
561 if (cert->mft == NULL && strncasecmp(rpkimft,
562 RSYNC_PROTO, RSYNC_PROTO_LEN) == 0) {
563 cert->mft = rpkimft;
564 rpkimft = NULL;
565 continue;
566 }
567 if (verbose)
568 warnx("%s: RFC 6487 section 4.8.8: SIA: "
569 "ignoring location %s", fn, rpkimft);
570 free(rpkimft);
571 rpkimft = NULL;
572 } else if (OBJ_cmp(oid, notify_oid) == 0) {
573 if (!x509_location(fn, "SIA: rpkiNotify",
574 ad->location, ¬ify))
575 goto out;
576 if (strncasecmp(notify, HTTPS_PROTO,
577 HTTPS_PROTO_LEN) != 0) {
578 warnx("%s: non-https uri in rpkiNotify: %s",
579 fn, cert->notify);
580 free(notify);
581 goto out;
582 }
583 if (cert->notify != NULL) {
584 warnx("%s: unexpected rpkiNotify accessMethod",
585 fn);
586 free(notify);
587 goto out;
588 }
589 cert->notify = notify;
590 notify = NULL;
591 } else {
592 char buf[128];
593
594 OBJ_obj2txt(buf, sizeof(buf), oid, 0);
595 warnx("%s: RFC 6487 section 4.8.8.1: unexpected"
596 " accessMethod: %s", fn, buf);
597 goto out;
598 }
599 }
600
601 if (cert->mft == NULL || cert->repo == NULL) {
602 warnx("%s: RFC 6487 section 4.8.8: SIA: missing caRepository "
603 "or rpkiManifest", fn);
604 goto out;
605 }
606
607 mftfilename = strrchr(cert->mft, '/');
608 if (mftfilename == NULL) {
609 warnx("%s: SIA: invalid rpkiManifest entry", fn);
610 goto out;
611 }
612 mftfilename++;
613 if (!valid_filename(mftfilename, strlen(mftfilename))) {
614 warnx("%s: SIA: rpkiManifest filename contains invalid "
615 "characters", fn);
616 goto out;
617 }
618
619 if (strstr(cert->mft, cert->repo) != cert->mft ||
620 cert->mft + strlen(cert->repo) != mftfilename) {
621 warnx("%s: RFC 6487 section 4.8.8: SIA: "
622 "conflicting URIs for caRepository and rpkiManifest", fn);
623 goto out;
624 }
625
626 if (rtype_from_file_extension(cert->mft) != RTYPE_MFT) {
627 warnx("%s: RFC 6487 section 4.8.8: SIA: not an MFT file", fn);
628 goto out;
629 }
630
631 rc = 1;
632 out:
633 AUTHORITY_INFO_ACCESS_free(sia);
634 return rc;
635 }
636
637 /*
638 * Parse the certificate policies extension and check that it follows RFC 7318.
639 * Returns zero on failure, non-zero on success.
640 */
641 static int
certificate_policies(const char * fn,struct cert * cert,X509_EXTENSION * ext)642 certificate_policies(const char *fn, struct cert *cert, X509_EXTENSION *ext)
643 {
644 STACK_OF(POLICYINFO) *policies = NULL;
645 POLICYINFO *policy;
646 STACK_OF(POLICYQUALINFO) *qualifiers;
647 POLICYQUALINFO *qualifier;
648 int nid;
649 int rc = 0;
650
651 if (!X509_EXTENSION_get_critical(ext)) {
652 warnx("%s: RFC 6487 section 4.8.9: certificatePolicies: "
653 "extension not critical", fn);
654 goto out;
655 }
656
657 if ((policies = X509V3_EXT_d2i(ext)) == NULL) {
658 warnx("%s: RFC 6487 section 4.8.9: certificatePolicies: "
659 "failed extension parse", fn);
660 goto out;
661 }
662
663 if (sk_POLICYINFO_num(policies) != 1) {
664 warnx("%s: RFC 6487 section 4.8.9: certificatePolicies: "
665 "want 1 policy, got %d", fn, sk_POLICYINFO_num(policies));
666 goto out;
667 }
668
669 policy = sk_POLICYINFO_value(policies, 0);
670 assert(policy != NULL && policy->policyid != NULL);
671
672 if (OBJ_cmp(policy->policyid, certpol_oid) != 0) {
673 char pbuf[128], cbuf[128];
674
675 OBJ_obj2txt(pbuf, sizeof(pbuf), policy->policyid, 1);
676 OBJ_obj2txt(cbuf, sizeof(cbuf), certpol_oid, 1);
677 warnx("%s: RFC 7318 section 2: certificatePolicies: "
678 "unexpected OID: %s, want %s", fn, pbuf, cbuf);
679 goto out;
680 }
681
682 /* Policy qualifiers are optional. If they're absent, we're done. */
683 if ((qualifiers = policy->qualifiers) == NULL) {
684 rc = 1;
685 goto out;
686 }
687
688 if (sk_POLICYQUALINFO_num(qualifiers) != 1) {
689 warnx("%s: RFC 7318 section 2: certificatePolicies: "
690 "want 1 policy qualifier, got %d", fn,
691 sk_POLICYQUALINFO_num(qualifiers));
692 goto out;
693 }
694
695 qualifier = sk_POLICYQUALINFO_value(qualifiers, 0);
696 assert(qualifier != NULL && qualifier->pqualid != NULL);
697
698 if ((nid = OBJ_obj2nid(qualifier->pqualid)) != NID_id_qt_cps) {
699 warnx("%s: RFC 7318 section 2: certificatePolicies: "
700 "want CPS, got %s", fn, nid2str(nid));
701 goto out;
702 }
703
704 if (verbose > 1 && !filemode)
705 warnx("%s: CPS %.*s", fn, qualifier->d.cpsuri->length,
706 qualifier->d.cpsuri->data);
707
708 rc = 1;
709 out:
710 sk_POLICYINFO_pop_free(policies, POLICYINFO_free);
711 return rc;
712 }
713
714 static int
cert_check_subject_and_issuer(const char * fn,const X509 * x)715 cert_check_subject_and_issuer(const char *fn, const X509 *x)
716 {
717 const X509_NAME *name;
718
719 if ((name = X509_get_subject_name(x)) == NULL) {
720 warnx("%s: X509_get_subject_name", fn);
721 return 0;
722 }
723 if (!x509_valid_name(fn, "subject", name))
724 return 0;
725
726 if ((name = X509_get_issuer_name(x)) == NULL) {
727 warnx("%s: X509_get_issuer_name", fn);
728 return 0;
729 }
730 if (!x509_valid_name(fn, "issuer", name))
731 return 0;
732
733 return 1;
734 }
735
736 /*
737 * Lightweight version of cert_parse_pre() for EE certs.
738 * Parses the two RFC 3779 extensions, and performs some sanity checks.
739 * Returns cert on success and NULL on failure.
740 */
741 struct cert *
cert_parse_ee_cert(const char * fn,int talid,X509 * x)742 cert_parse_ee_cert(const char *fn, int talid, X509 *x)
743 {
744 struct cert *cert;
745 X509_EXTENSION *ext;
746 int index;
747
748 if ((cert = calloc(1, sizeof(struct cert))) == NULL)
749 err(1, NULL);
750
751 if (X509_get_version(x) != 2) {
752 warnx("%s: RFC 6487 4.1: X.509 version must be v3", fn);
753 goto out;
754 }
755
756 if (!cert_check_subject_and_issuer(fn, x))
757 goto out;
758
759 if (!x509_cache_extensions(x, fn))
760 goto out;
761
762 if ((cert->purpose = x509_get_purpose(x, fn)) != CERT_PURPOSE_EE) {
763 warnx("%s: expected EE cert, got %s", fn,
764 purpose2str(cert->purpose));
765 goto out;
766 }
767
768 index = X509_get_ext_by_NID(x, NID_sbgp_ipAddrBlock, -1);
769 if ((ext = X509_get_ext(x, index)) != NULL) {
770 if (!sbgp_ipaddrblk(fn, cert, ext))
771 goto out;
772 }
773
774 index = X509_get_ext_by_NID(x, NID_sbgp_autonomousSysNum, -1);
775 if ((ext = X509_get_ext(x, index)) != NULL) {
776 if (!sbgp_assysnum(fn, cert, ext))
777 goto out;
778 }
779
780 if (!X509_up_ref(x)) {
781 warnx("%s: X509_up_ref failed", fn);
782 goto out;
783 }
784
785 cert->x509 = x;
786 cert->talid = talid;
787
788 if (!constraints_validate(fn, cert))
789 goto out;
790
791 return cert;
792
793 out:
794 cert_free(cert);
795 return NULL;
796 }
797
798 /*
799 * Parse and partially validate an RPKI X509 certificate (either a trust
800 * anchor or a certificate) as defined in RFC 6487.
801 * Returns the parse results or NULL on failure.
802 */
803 struct cert *
cert_parse_pre(const char * fn,const unsigned char * der,size_t len)804 cert_parse_pre(const char *fn, const unsigned char *der, size_t len)
805 {
806 struct cert *cert;
807 const unsigned char *oder;
808 size_t j;
809 int i, extsz;
810 X509 *x = NULL;
811 X509_EXTENSION *ext = NULL;
812 const ASN1_BIT_STRING *issuer_uid = NULL, *subject_uid = NULL;
813 ASN1_OBJECT *obj;
814 EVP_PKEY *pkey;
815 int nid, ip, as, sia, cp, crldp, aia, aki, ski,
816 eku, bc, ku;
817
818 nid = ip = as = sia = cp = crldp = aia = aki = ski = eku = bc = ku = 0;
819
820 /* just fail for empty buffers, the warning was printed elsewhere */
821 if (der == NULL)
822 return NULL;
823
824 if ((cert = calloc(1, sizeof(struct cert))) == NULL)
825 err(1, NULL);
826
827 oder = der;
828 if ((x = d2i_X509(NULL, &der, len)) == NULL) {
829 warnx("%s: d2i_X509", fn);
830 goto out;
831 }
832 if (der != oder + len) {
833 warnx("%s: %td bytes trailing garbage", fn, oder + len - der);
834 goto out;
835 }
836
837 if (!x509_cache_extensions(x, fn))
838 goto out;
839
840 if (X509_get_version(x) != 2) {
841 warnx("%s: RFC 6487 4.1: X.509 version must be v3", fn);
842 goto out;
843 }
844
845 if ((nid = X509_get_signature_nid(x)) == NID_undef) {
846 warnx("%s: unknown signature type", fn);
847 goto out;
848 }
849 if (experimental && nid == NID_ecdsa_with_SHA256) {
850 if (verbose)
851 warnx("%s: P-256 support is experimental", fn);
852 } else if (nid != NID_sha256WithRSAEncryption) {
853 warnx("%s: RFC 7935: wrong signature algorithm %s, want %s",
854 fn, nid2str(nid), LN_sha256WithRSAEncryption);
855 goto out;
856 }
857
858 X509_get0_uids(x, &issuer_uid, &subject_uid);
859 if (issuer_uid != NULL || subject_uid != NULL) {
860 warnx("%s: issuer or subject unique identifiers not allowed",
861 fn);
862 goto out;
863 }
864
865 if (!cert_check_subject_and_issuer(fn, x))
866 goto out;
867
868 /* Look for X509v3 extensions. */
869 if ((extsz = X509_get_ext_count(x)) <= 0) {
870 warnx("%s: certificate without X.509v3 extensions", fn);
871 goto out;
872 }
873
874 for (i = 0; i < extsz; i++) {
875 ext = X509_get_ext(x, i);
876 assert(ext != NULL);
877 obj = X509_EXTENSION_get_object(ext);
878 assert(obj != NULL);
879
880 switch (nid = OBJ_obj2nid(obj)) {
881 case NID_sbgp_ipAddrBlock:
882 if (ip++ > 0)
883 goto dup;
884 if (!sbgp_ipaddrblk(fn, cert, ext))
885 goto out;
886 break;
887 case NID_sbgp_autonomousSysNum:
888 if (as++ > 0)
889 goto dup;
890 if (!sbgp_assysnum(fn, cert, ext))
891 goto out;
892 break;
893 case NID_sinfo_access:
894 if (sia++ > 0)
895 goto dup;
896 /*
897 * This will fail for BGPsec certs, but they must omit
898 * this extension anyway (RFC 8209, section 3.1.3.3).
899 */
900 if (!sbgp_sia(fn, cert, ext))
901 goto out;
902 break;
903 case NID_certificate_policies:
904 if (cp++ > 0)
905 goto dup;
906 if (!certificate_policies(fn, cert, ext))
907 goto out;
908 break;
909 case NID_crl_distribution_points:
910 if (crldp++ > 0)
911 goto dup;
912 break;
913 case NID_info_access:
914 if (aia++ > 0)
915 goto dup;
916 break;
917 case NID_authority_key_identifier:
918 if (aki++ > 0)
919 goto dup;
920 break;
921 case NID_subject_key_identifier:
922 if (ski++ > 0)
923 goto dup;
924 break;
925 case NID_ext_key_usage:
926 if (eku++ > 0)
927 goto dup;
928 break;
929 case NID_basic_constraints:
930 if (bc++ > 0)
931 goto dup;
932 break;
933 case NID_key_usage:
934 if (ku++ > 0)
935 goto dup;
936 break;
937 default:
938 /* unexpected extensions warrant investigation */
939 {
940 char objn[64];
941 OBJ_obj2txt(objn, sizeof(objn), obj, 0);
942 warnx("%s: ignoring %s (NID %d)",
943 fn, objn, OBJ_obj2nid(obj));
944 }
945 break;
946 }
947 }
948
949 if (!x509_get_aki(x, fn, &cert->aki))
950 goto out;
951 if (!x509_get_ski(x, fn, &cert->ski))
952 goto out;
953 if (!x509_get_aia(x, fn, &cert->aia))
954 goto out;
955 if (!x509_get_crl(x, fn, &cert->crl))
956 goto out;
957 if (!x509_get_notbefore(x, fn, &cert->notbefore))
958 goto out;
959 if (!x509_get_notafter(x, fn, &cert->notafter))
960 goto out;
961
962 /* Validation on required fields. */
963 cert->purpose = x509_get_purpose(x, fn);
964 switch (cert->purpose) {
965 case CERT_PURPOSE_TA:
966 /* XXX - caller should indicate if it expects TA or CA cert */
967 case CERT_PURPOSE_CA:
968 if ((pkey = X509_get0_pubkey(x)) == NULL) {
969 warnx("%s: X509_get0_pubkey failed", fn);
970 goto out;
971 }
972 if (!valid_ca_pkey(fn, pkey))
973 goto out;
974
975 if (cert->mft == NULL) {
976 warnx("%s: RFC 6487 section 4.8.8: missing SIA", fn);
977 goto out;
978 }
979 if (cert->num_ases == 0 && cert->num_ips == 0) {
980 warnx("%s: missing IP or AS resources", fn);
981 goto out;
982 }
983 break;
984 case CERT_PURPOSE_BGPSEC_ROUTER:
985 cert->pubkey = x509_get_pubkey(x, fn);
986 if (cert->pubkey == NULL) {
987 warnx("%s: x509_get_pubkey failed", fn);
988 goto out;
989 }
990 if (cert->num_ips > 0) {
991 warnx("%s: unexpected IP resources in BGPsec cert", fn);
992 goto out;
993 }
994 for (j = 0; j < cert->num_ases; j++) {
995 if (cert->ases[j].type == CERT_AS_INHERIT) {
996 warnx("%s: inherit elements not allowed in EE"
997 " cert", fn);
998 goto out;
999 }
1000 }
1001 if (sia) {
1002 warnx("%s: unexpected SIA extension in BGPsec cert",
1003 fn);
1004 goto out;
1005 }
1006 break;
1007 case CERT_PURPOSE_EE:
1008 warn("%s: unexpected EE cert", fn);
1009 goto out;
1010 default:
1011 warnx("%s: x509_get_purpose failed in %s", fn, __func__);
1012 goto out;
1013 }
1014
1015 if (cert->ski == NULL) {
1016 warnx("%s: RFC 6487 section 8.4.2: missing SKI", fn);
1017 goto out;
1018 }
1019
1020 cert->x509 = x;
1021 return cert;
1022
1023 dup:
1024 warnx("%s: RFC 5280 section 4.2: duplicate extension: %s", fn,
1025 nid2str(nid));
1026 out:
1027 cert_free(cert);
1028 X509_free(x);
1029 return NULL;
1030 }
1031
1032 struct cert *
cert_parse(const char * fn,struct cert * p)1033 cert_parse(const char *fn, struct cert *p)
1034 {
1035 if (p == NULL)
1036 return NULL;
1037
1038 if (p->aki == NULL) {
1039 warnx("%s: RFC 6487 section 8.4.2: "
1040 "non-trust anchor missing AKI", fn);
1041 goto badcert;
1042 }
1043 if (strcmp(p->aki, p->ski) == 0) {
1044 warnx("%s: RFC 6487 section 8.4.2: "
1045 "non-trust anchor AKI may not match SKI", fn);
1046 goto badcert;
1047 }
1048 if (p->aia == NULL) {
1049 warnx("%s: RFC 6487 section 8.4.7: AIA: extension missing", fn);
1050 goto badcert;
1051 }
1052 if (p->crl == NULL) {
1053 warnx("%s: RFC 6487 section 4.8.6: CRL: "
1054 "no CRL distribution point extension", fn);
1055 goto badcert;
1056 }
1057 return p;
1058
1059 badcert:
1060 cert_free(p);
1061 return NULL;
1062 }
1063
1064 /*
1065 * Reject TA certificates with an overly long validity period.
1066 *
1067 * The schedule is as follows:
1068 * Before February 2nd, 2026, warn on TA certs valid for longer than 15 years.
1069 * After February 2nd, 2026, reject TA certs valid for longer than 15 years.
1070 * Before March 3rd, 2027, warn on TA certs valid for longer than 3 years.
1071 * After March 3rd, 2027, reject TA certs valid for longer than 3 years.
1072 *
1073 * Return 1 if the validity period is acceptable and 0 otherwise.
1074 */
1075 static int
ta_check_validity(const char * fn,const struct cert * p,time_t now)1076 ta_check_validity(const char *fn, const struct cert *p, time_t now)
1077 {
1078 time_t validity = p->notafter - p->notbefore;
1079 time_t cutoff_15y = 1769990400; /* 2026-02-02T00:00:00Z */
1080 time_t cutoff_3y = 1804032000; /* 2027-03-03T00:00:00Z */
1081 time_t cutoff = cutoff_3y;
1082 int warn_years = 3;
1083 int exceeds_15y = 0, exceeds_3y = 0;
1084 int complain = 0, acceptable = 1;
1085
1086 if (validity >= 15 * 365 * 86400)
1087 exceeds_15y = 1;
1088 if (validity >= 3 * 365 * 86400)
1089 exceeds_3y = 1;
1090
1091 if (now < cutoff_15y) {
1092 warn_years = 15;
1093 cutoff = cutoff_15y;
1094 if (exceeds_15y)
1095 complain = 1;
1096 } else if (now < cutoff_3y) {
1097 if (exceeds_15y)
1098 acceptable = 0;
1099 if (exceeds_3y)
1100 complain = 1;
1101 } else if (exceeds_3y) {
1102 acceptable = 0;
1103 complain = 1;
1104 }
1105
1106 /*
1107 * Suppress warnings for previously fetched TA certs.
1108 */
1109 if (verbose == 0 && strncmp(fn, "ta/", strlen("ta/")) == 0)
1110 goto out;
1111
1112 if (!acceptable) {
1113 warnx("%s: TA cert rejected: validity period exceeds %d years. "
1114 "Ask the TA operator to reissue their TA cert with a "
1115 "shorter validity period.", fn, warn_years);
1116 goto out;
1117 }
1118
1119 if (complain) {
1120 warnx("%s: TA validity period exceeds %d years. After %s this "
1121 "certificate will be rejected.", fn, warn_years,
1122 time2str(cutoff));
1123 goto out;
1124 }
1125
1126 out:
1127 return acceptable;
1128 }
1129
1130 struct cert *
ta_parse(const char * fn,struct cert * p,const unsigned char * pkey,size_t pkeysz)1131 ta_parse(const char *fn, struct cert *p, const unsigned char *pkey,
1132 size_t pkeysz)
1133 {
1134 EVP_PKEY *pk, *opk;
1135 time_t now = get_current_time();
1136
1137 if (p == NULL)
1138 return NULL;
1139
1140 /* first check pubkey against the one from the TAL */
1141 pk = d2i_PUBKEY(NULL, &pkey, pkeysz);
1142 if (pk == NULL) {
1143 warnx("%s: RFC 6487 (trust anchor): bad TAL pubkey", fn);
1144 goto badcert;
1145 }
1146 if ((opk = X509_get0_pubkey(p->x509)) == NULL) {
1147 warnx("%s: RFC 6487 (trust anchor): missing pubkey", fn);
1148 goto badcert;
1149 }
1150 if (EVP_PKEY_cmp(pk, opk) != 1) {
1151 warnx("%s: RFC 6487 (trust anchor): "
1152 "pubkey does not match TAL pubkey", fn);
1153 goto badcert;
1154 }
1155
1156 if (p->notbefore > now) {
1157 warnx("%s: certificate not yet valid", fn);
1158 goto badcert;
1159 }
1160 if (p->notafter < now) {
1161 warnx("%s: certificate has expired", fn);
1162 goto badcert;
1163 }
1164 if (!ta_check_validity(fn, p, now))
1165 goto badcert;
1166
1167 if (p->aki != NULL && strcmp(p->aki, p->ski)) {
1168 warnx("%s: RFC 6487 section 4.8.3: "
1169 "trust anchor AKI, if specified, must match SKI", fn);
1170 goto badcert;
1171 }
1172 if (p->aia != NULL) {
1173 warnx("%s: RFC 6487 section 4.8.7: "
1174 "trust anchor must not have AIA", fn);
1175 goto badcert;
1176 }
1177 if (p->crl != NULL) {
1178 warnx("%s: RFC 6487 section 4.8.6: "
1179 "trust anchor may not specify CRL resource", fn);
1180 goto badcert;
1181 }
1182 if (p->purpose != CERT_PURPOSE_TA) {
1183 warnx("%s: expected trust anchor purpose, got %s", fn,
1184 purpose2str(p->purpose));
1185 goto badcert;
1186 }
1187 /*
1188 * Do not replace with a <= 0 check since OpenSSL 3 broke that:
1189 * https://github.com/openssl/openssl/issues/24575
1190 */
1191 if (X509_verify(p->x509, pk) != 1) {
1192 warnx("%s: failed to verify signature", fn);
1193 goto badcert;
1194 }
1195 if (x509_any_inherits(p->x509)) {
1196 warnx("%s: Trust anchor IP/AS resources may not inherit", fn);
1197 goto badcert;
1198 }
1199
1200 EVP_PKEY_free(pk);
1201 return p;
1202
1203 badcert:
1204 EVP_PKEY_free(pk);
1205 cert_free(p);
1206 return NULL;
1207 }
1208
1209 /*
1210 * Free parsed certificate contents.
1211 * Passing NULL is a noop.
1212 */
1213 void
cert_free(struct cert * p)1214 cert_free(struct cert *p)
1215 {
1216 if (p == NULL)
1217 return;
1218
1219 free(p->crl);
1220 free(p->repo);
1221 free(p->mft);
1222 free(p->notify);
1223 free(p->ips);
1224 free(p->ases);
1225 free(p->aia);
1226 free(p->aki);
1227 free(p->ski);
1228 free(p->pubkey);
1229 X509_free(p->x509);
1230 free(p);
1231 }
1232
1233 /*
1234 * Write certificate parsed content into buffer.
1235 * See cert_read() for the other side of the pipe.
1236 */
1237 void
cert_buffer(struct ibuf * b,const struct cert * p)1238 cert_buffer(struct ibuf *b, const struct cert *p)
1239 {
1240 io_simple_buffer(b, &p->notafter, sizeof(p->notafter));
1241 io_simple_buffer(b, &p->purpose, sizeof(p->purpose));
1242 io_simple_buffer(b, &p->talid, sizeof(p->talid));
1243 io_simple_buffer(b, &p->certid, sizeof(p->certid));
1244 io_simple_buffer(b, &p->repoid, sizeof(p->repoid));
1245 io_simple_buffer(b, &p->num_ips, sizeof(p->num_ips));
1246 io_simple_buffer(b, &p->num_ases, sizeof(p->num_ases));
1247
1248 io_simple_buffer(b, p->ips, p->num_ips * sizeof(p->ips[0]));
1249 io_simple_buffer(b, p->ases, p->num_ases * sizeof(p->ases[0]));
1250
1251 io_str_buffer(b, p->mft);
1252 io_str_buffer(b, p->notify);
1253 io_str_buffer(b, p->repo);
1254 io_str_buffer(b, p->crl);
1255 io_str_buffer(b, p->aia);
1256 io_str_buffer(b, p->aki);
1257 io_str_buffer(b, p->ski);
1258 io_str_buffer(b, p->pubkey);
1259 }
1260
1261 /*
1262 * Allocate and read parsed certificate content from descriptor.
1263 * The pointer must be freed with cert_free().
1264 * Always returns a valid pointer.
1265 */
1266 struct cert *
cert_read(struct ibuf * b)1267 cert_read(struct ibuf *b)
1268 {
1269 struct cert *p;
1270
1271 if ((p = calloc(1, sizeof(struct cert))) == NULL)
1272 err(1, NULL);
1273
1274 io_read_buf(b, &p->notafter, sizeof(p->notafter));
1275 io_read_buf(b, &p->purpose, sizeof(p->purpose));
1276 io_read_buf(b, &p->talid, sizeof(p->talid));
1277 io_read_buf(b, &p->certid, sizeof(p->certid));
1278 io_read_buf(b, &p->repoid, sizeof(p->repoid));
1279 io_read_buf(b, &p->num_ips, sizeof(p->num_ips));
1280 io_read_buf(b, &p->num_ases, sizeof(p->num_ases));
1281
1282 if (p->num_ips > 0) {
1283 if ((p->ips = calloc(p->num_ips, sizeof(p->ips[0]))) == NULL)
1284 err(1, NULL);
1285 io_read_buf(b, p->ips, p->num_ips * sizeof(p->ips[0]));
1286 }
1287
1288 if (p->num_ases > 0) {
1289 if ((p->ases = calloc(p->num_ases, sizeof(p->ases[0]))) == NULL)
1290 err(1, NULL);
1291 io_read_buf(b, p->ases, p->num_ases * sizeof(p->ases[0]));
1292 }
1293
1294 io_read_str(b, &p->mft);
1295 io_read_str(b, &p->notify);
1296 io_read_str(b, &p->repo);
1297 io_read_str(b, &p->crl);
1298 io_read_str(b, &p->aia);
1299 io_read_str(b, &p->aki);
1300 io_read_str(b, &p->ski);
1301 io_read_str(b, &p->pubkey);
1302
1303 assert(p->mft != NULL || p->purpose == CERT_PURPOSE_BGPSEC_ROUTER);
1304 assert(p->ski);
1305 return p;
1306 }
1307
1308 static inline int
authcmp(struct auth * a,struct auth * b)1309 authcmp(struct auth *a, struct auth *b)
1310 {
1311 if (a->cert->certid > b->cert->certid)
1312 return 1;
1313 if (a->cert->certid < b->cert->certid)
1314 return -1;
1315 return 0;
1316 }
1317
1318 RB_GENERATE_STATIC(auth_tree, auth, entry, authcmp);
1319
1320 void
auth_tree_free(struct auth_tree * auths)1321 auth_tree_free(struct auth_tree *auths)
1322 {
1323 struct auth *auth, *tauth;
1324
1325 RB_FOREACH_SAFE(auth, auth_tree, auths, tauth) {
1326 RB_REMOVE(auth_tree, auths, auth);
1327 cert_free(auth->cert);
1328 free(auth);
1329 }
1330 }
1331
1332 struct auth *
auth_find(struct auth_tree * auths,int id)1333 auth_find(struct auth_tree *auths, int id)
1334 {
1335 struct auth a;
1336 struct cert c;
1337
1338 c.certid = id;
1339 a.cert = &c;
1340
1341 return RB_FIND(auth_tree, auths, &a);
1342 }
1343
1344 struct auth *
auth_insert(const char * fn,struct auth_tree * auths,struct cert * cert,struct auth * issuer)1345 auth_insert(const char *fn, struct auth_tree *auths, struct cert *cert,
1346 struct auth *issuer)
1347 {
1348 struct auth *na;
1349
1350 na = calloc(1, sizeof(*na));
1351 if (na == NULL)
1352 err(1, NULL);
1353
1354 if (issuer == NULL) {
1355 cert->certid = cert->talid;
1356 } else {
1357 cert->certid = ++certid;
1358 if (certid > CERTID_MAX) {
1359 if (certid == CERTID_MAX + 1)
1360 warnx("%s: too many certificates in store", fn);
1361 free(na);
1362 return NULL;
1363 }
1364 na->depth = issuer->depth + 1;
1365 }
1366
1367 if (na->depth >= MAX_CERT_DEPTH) {
1368 warnx("%s: maximum certificate chain depth exhausted", fn);
1369 free(na);
1370 return NULL;
1371 }
1372
1373 na->issuer = issuer;
1374 na->cert = cert;
1375 na->any_inherits = x509_any_inherits(cert->x509);
1376
1377 if (RB_INSERT(auth_tree, auths, na) != NULL)
1378 errx(1, "auth tree corrupted");
1379
1380 return na;
1381 }
1382
1383 static void
insert_brk(struct brk_tree * tree,struct cert * cert,int asid)1384 insert_brk(struct brk_tree *tree, struct cert *cert, int asid)
1385 {
1386 struct brk *b, *found;
1387
1388 if ((b = calloc(1, sizeof(*b))) == NULL)
1389 err(1, NULL);
1390
1391 b->asid = asid;
1392 b->expires = cert->notafter;
1393 b->talid = cert->talid;
1394 if ((b->ski = strdup(cert->ski)) == NULL)
1395 err(1, NULL);
1396 if ((b->pubkey = strdup(cert->pubkey)) == NULL)
1397 err(1, NULL);
1398
1399 /*
1400 * Check if a similar BRK already exists in the tree. If the found BRK
1401 * expires sooner, update it to this BRK's later expiry moment.
1402 */
1403 if ((found = RB_INSERT(brk_tree, tree, b)) != NULL) {
1404 if (found->expires < b->expires) {
1405 found->expires = b->expires;
1406 found->talid = b->talid;
1407 }
1408 free(b->ski);
1409 free(b->pubkey);
1410 free(b);
1411 }
1412 }
1413
1414 /*
1415 * Add each BGPsec Router Key into the BRK tree.
1416 */
1417 void
cert_insert_brks(struct brk_tree * tree,struct cert * cert)1418 cert_insert_brks(struct brk_tree *tree, struct cert *cert)
1419 {
1420 size_t i, asid;
1421
1422 for (i = 0; i < cert->num_ases; i++) {
1423 switch (cert->ases[i].type) {
1424 case CERT_AS_ID:
1425 insert_brk(tree, cert, cert->ases[i].id);
1426 break;
1427 case CERT_AS_RANGE:
1428 for (asid = cert->ases[i].range.min;
1429 asid <= cert->ases[i].range.max; asid++)
1430 insert_brk(tree, cert, asid);
1431 break;
1432 default:
1433 warnx("invalid AS identifier type");
1434 continue;
1435 }
1436 }
1437 }
1438
1439 static inline int
brkcmp(struct brk * a,struct brk * b)1440 brkcmp(struct brk *a, struct brk *b)
1441 {
1442 int rv;
1443
1444 if (a->asid > b->asid)
1445 return 1;
1446 if (a->asid < b->asid)
1447 return -1;
1448
1449 rv = strcmp(a->ski, b->ski);
1450 if (rv > 0)
1451 return 1;
1452 if (rv < 0)
1453 return -1;
1454
1455 return strcmp(a->pubkey, b->pubkey);
1456 }
1457
1458 RB_GENERATE(brk_tree, brk, entry, brkcmp);
1459