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