xref: /openbsd/usr.sbin/rpki-client/cert.c (revision a56972eb)
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, &notify))
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