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