xref: /openbsd/usr.sbin/rpki-client/cert.c (revision 5a38ef86)
1 /*	$OpenBSD: cert.c,v 1.47 2021/11/05 10:50:41 claudio Exp $ */
2 /*
3  * Copyright (c) 2021 Job Snijders <job@openbsd.org>
4  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/socket.h>
20 
21 #include <arpa/inet.h>
22 #include <assert.h>
23 #include <err.h>
24 #include <inttypes.h>
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 
30 #include <openssl/asn1.h>
31 #include <openssl/x509.h>
32 
33 #include "extern.h"
34 
35 /*
36  * Type of ASIdentifier (RFC 3779, 3.2.3).
37  */
38 #define	ASID_TYPE_ASNUM	0x00
39 #define ASID_TYPE_RDI	0x01
40 #define ASID_TYPE_MAX	ASID_TYPE_RDI
41 
42 /*
43  * A parsing sequence of a file (which may just be <stdin>).
44  */
45 struct	parse {
46 	struct cert	*res; /* result */
47 	const char	*fn; /* currently-parsed file */
48 };
49 
50 static ASN1_OBJECT	*carepo_oid;	/* 1.3.6.1.5.5.7.48.5 (caRepository) */
51 static ASN1_OBJECT	*mft_oid;	/* 1.3.6.1.5.5.7.48.10 (rpkiManifest) */
52 static ASN1_OBJECT	*notify_oid;	/* 1.3.6.1.5.5.7.48.13 (rpkiNotify) */
53 
54 static void
55 cert_init_oid(void)
56 {
57 	if ((carepo_oid = OBJ_txt2obj("1.3.6.1.5.5.7.48.5", 1)) == NULL)
58 		errx(1, "OBJ_txt2obj for %s failed", "1.3.6.1.5.5.7.48.5");
59 	if ((mft_oid = OBJ_txt2obj("1.3.6.1.5.5.7.48.10", 1)) == NULL)
60 		errx(1, "OBJ_txt2obj for %s failed", "1.3.6.1.5.5.7.48.10");
61 	if ((notify_oid = OBJ_txt2obj("1.3.6.1.5.5.7.48.13", 1)) == NULL)
62 		errx(1, "OBJ_txt2obj for %s failed", "1.3.6.1.5.5.7.48.13");
63 }
64 
65 /*
66  * Append an IP address structure to our list of results.
67  * This will also constrain us to having at most one inheritence
68  * statement per AFI and also not have overlapping rages (as prohibited
69  * in section 2.2.3.6).
70  * It does not make sure that ranges can't coalesce, that is, that any
71  * two ranges abut each other.
72  * This is warned against in section 2.2.3.6, but doesn't change the
73  * semantics of the system.
74  * Return zero on failure (IP overlap) non-zero on success.
75  */
76 static int
77 append_ip(struct parse *p, const struct cert_ip *ip)
78 {
79 	struct cert	*res = p->res;
80 
81 	if (!ip_addr_check_overlap(ip, p->fn, p->res->ips, p->res->ipsz))
82 		return 0;
83 	if (res->ipsz >= MAX_IP_SIZE)
84 		return 0;
85 	res->ips = reallocarray(res->ips, res->ipsz + 1,
86 	    sizeof(struct cert_ip));
87 	if (res->ips == NULL)
88 		err(1, NULL);
89 	res->ips[res->ipsz++] = *ip;
90 	return 1;
91 }
92 
93 /*
94  * Append an AS identifier structure to our list of results.
95  * Makes sure that the identifiers do not overlap or improperly inherit
96  * as defined by RFC 3779 section 3.3.
97  */
98 static int
99 append_as(struct parse *p, const struct cert_as *as)
100 {
101 
102 	if (!as_check_overlap(as, p->fn, p->res->as, p->res->asz))
103 		return 0;
104 	if (p->res->asz >= MAX_AS_SIZE)
105 		return 0;
106 	p->res->as = reallocarray(p->res->as, p->res->asz + 1,
107 	    sizeof(struct cert_as));
108 	if (p->res->as == NULL)
109 		err(1, NULL);
110 	p->res->as[p->res->asz++] = *as;
111 	return 1;
112 }
113 
114 /*
115  * Construct a RFC 3779 2.2.3.8 range by its bit string.
116  * Return zero on failure, non-zero on success.
117  */
118 static int
119 sbgp_addr(struct parse *p,
120 	struct cert_ip *ip, const ASN1_BIT_STRING *bs)
121 {
122 
123 	if (!ip_addr_parse(bs, ip->afi, p->fn, &ip->ip)) {
124 		warnx("%s: RFC 3779 section 2.2.3.8: IPAddress: "
125 		    "invalid IP address", p->fn);
126 		return 0;
127 	}
128 	if (!ip_cert_compose_ranges(ip)) {
129 		warnx("%s: RFC 3779 section 2.2.3.8: IPAddress: "
130 		    "IP address range reversed", p->fn);
131 		return 0;
132 	}
133 	return append_ip(p, ip);
134 }
135 
136 /*
137  * Parse the SIA notify URL, 4.8.8.1.
138  * Returns zero on failure, non-zero on success.
139  */
140 static int
141 sbgp_sia_resource_notify(struct parse *p, const char *d, size_t dsz)
142 {
143 	if (p->res->notify != NULL) {
144 		warnx("%s: RFC 6487 section 4.8.8: SIA: "
145 		    "Notify location already specified", p->fn);
146 		return 0;
147 	}
148 
149 	/* Make sure it's a https:// address. */
150 	if (!valid_uri(d, dsz, "https://")) {
151 		warnx("%s: RFC 8182 section 3.2: bad Notify URI", p->fn);
152 		return 0;
153 	}
154 
155 	if ((p->res->notify = strndup(d, dsz)) == NULL)
156 		err(1, NULL);
157 
158 	return 1;
159 }
160 
161 /*
162  * Parse the SIA manifest, 4.8.8.1.
163  * Returns zero on failure, non-zero on success.
164  */
165 static int
166 sbgp_sia_resource_mft(struct parse *p, const char *d, size_t dsz)
167 {
168 	if (p->res->mft != NULL) {
169 		warnx("%s: RFC 6487 section 4.8.8: SIA: "
170 		    "MFT location already specified", p->fn);
171 		return 0;
172 	}
173 
174 	/* Make sure it's an MFT rsync address. */
175 	if (!valid_uri(d, dsz, "rsync://")) {
176 		warnx("%s: RFC 6487 section 4.8.8: bad MFT location", p->fn);
177 		return 0;
178 	}
179 
180 	if (dsz < 4 || strcasecmp(d + dsz - 4, ".mft") != 0) {
181 		warnx("%s: RFC 6487 section 4.8.8: SIA: "
182 		    "not an MFT file", p->fn);
183 		return 0;
184 	}
185 
186 	if ((p->res->mft = strndup(d, dsz)) == NULL)
187 		err(1, NULL);
188 
189 	return 1;
190 }
191 
192 /*
193  * Parse the SIA manifest, 4.8.8.1.
194  * Returns zero on failure, non-zero on success.
195  */
196 static int
197 sbgp_sia_resource_carepo(struct parse *p, const char *d, size_t dsz)
198 {
199 	if (p->res->repo != NULL) {
200 		warnx("%s: RFC 6487 section 4.8.8: SIA: "
201 		    "CA repository already specified", p->fn);
202 		return 0;
203 	}
204 
205 	/* Make sure it's an rsync:// address. */
206 	if (!valid_uri(d, dsz, "rsync://")) {
207 		warnx("%s: RFC 6487 section 4.8.8: bad CA repository URI",
208 		    p->fn);
209 		return 0;
210 	}
211 
212 	if ((p->res->repo = strndup(d, dsz)) == NULL)
213 		err(1, NULL);
214 
215 	return 1;
216 }
217 
218 /*
219  * Parse the SIA entries, 4.8.8.1.
220  * There may be multiple different resources at this location, so throw
221  * out all but the matching resource type. Currently only two entries
222  * are of interest: rpkiManifest and rpkiNotify.
223  * Returns zero on failure, non-zero on success.
224  */
225 static int
226 sbgp_sia_resource_entry(struct parse *p,
227 	const unsigned char *d, size_t dsz)
228 {
229 	ASN1_SEQUENCE_ANY	*seq;
230 	ASN1_OBJECT		*oid;
231 	const ASN1_TYPE		*t;
232 	int			 rc = 0, ptag;
233 	long			 plen;
234 
235 	if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
236 		cryptowarnx("%s: RFC 6487 section 4.8.8: SIA: "
237 		    "failed ASN.1 sequence parse", p->fn);
238 		goto out;
239 	}
240 	if (sk_ASN1_TYPE_num(seq) != 2) {
241 		warnx("%s: RFC 6487 section 4.8.8: SIA: "
242 		    "want 2 elements, have %d",
243 		    p->fn, sk_ASN1_TYPE_num(seq));
244 		goto out;
245 	}
246 
247 	/* Composed of an OID and its continuation. */
248 
249 	t = sk_ASN1_TYPE_value(seq, 0);
250 	if (t->type != V_ASN1_OBJECT) {
251 		warnx("%s: RFC 6487 section 4.8.8: SIA: "
252 		    "want ASN.1 object, have %s (NID %d)",
253 		    p->fn, ASN1_tag2str(t->type), t->type);
254 		goto out;
255 	}
256 	oid = t->value.object;
257 
258 	t = sk_ASN1_TYPE_value(seq, 1);
259 	if (t->type != V_ASN1_OTHER) {
260 		warnx("%s: RFC 6487 section 4.8.8: SIA: "
261 		    "want ASN.1 external, have %s (NID %d)",
262 		    p->fn, ASN1_tag2str(t->type), t->type);
263 		goto out;
264 	}
265 
266 	/* FIXME: there must be a way to do this without ASN1_frame. */
267 
268 	d = t->value.asn1_string->data;
269 	dsz = t->value.asn1_string->length;
270 	if (!ASN1_frame(p->fn, dsz, &d, &plen, &ptag))
271 		goto out;
272 
273 	if (carepo_oid == NULL)
274 		cert_init_oid();
275 
276 	if (OBJ_cmp(oid, carepo_oid) == 0)
277 		rc = sbgp_sia_resource_carepo(p, d, plen);
278 	else if (OBJ_cmp(oid, mft_oid) == 0)
279 		rc = sbgp_sia_resource_mft(p, d, plen);
280 	else if (OBJ_cmp(oid, notify_oid) == 0)
281 		rc = sbgp_sia_resource_notify(p, d, plen);
282 	else
283 		rc = 1;	/* silently ignore */
284 out:
285 	sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
286 	return rc;
287 }
288 
289 /*
290  * Multiple locations as defined in RFC 6487, 4.8.8.1.
291  * Returns zero on failure, non-zero on success.
292  */
293 static int
294 sbgp_sia_resource(struct parse *p, const unsigned char *d, size_t dsz)
295 {
296 	ASN1_SEQUENCE_ANY	*seq;
297 	const ASN1_TYPE		*t;
298 	int			 rc = 0, i;
299 
300 	if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
301 		cryptowarnx("%s: RFC 6487 section 4.8.8: SIA: "
302 		    "failed ASN.1 sequence parse", p->fn);
303 		goto out;
304 	}
305 
306 	for (i = 0; i < sk_ASN1_TYPE_num(seq); i++) {
307 		t = sk_ASN1_TYPE_value(seq, i);
308 		if (t->type != V_ASN1_SEQUENCE) {
309 			warnx("%s: RFC 6487 section 4.8.8: SIA: "
310 			    "want ASN.1 sequence, have %s (NID %d)",
311 			    p->fn, ASN1_tag2str(t->type), t->type);
312 			goto out;
313 		}
314 		d = t->value.asn1_string->data;
315 		dsz = t->value.asn1_string->length;
316 		if (!sbgp_sia_resource_entry(p, d, dsz))
317 			goto out;
318 	}
319 
320 	if (strstr(p->res->mft, p->res->repo) != p->res->mft) {
321 		warnx("%s: RFC 6487 section 4.8.8: SIA: "
322 		    "conflicting URIs for caRepository and rpkiManifest",
323 		    p->fn);
324 		goto out;
325 	}
326 	rc = 1;
327 out:
328 	sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
329 	return rc;
330 }
331 
332 /*
333  * Parse "Subject Information Access" extension, RFC 6487 4.8.8.
334  * Returns zero on failure, non-zero on success.
335  */
336 static int
337 sbgp_sia(struct parse *p, X509_EXTENSION *ext)
338 {
339 	unsigned char		*sv = NULL;
340 	const unsigned char	*d;
341 	ASN1_SEQUENCE_ANY	*seq = NULL;
342 	const ASN1_TYPE		*t;
343 	int			 dsz, rc = 0;
344 
345 	if ((dsz = i2d_X509_EXTENSION(ext, &sv)) < 0) {
346 		cryptowarnx("%s: RFC 6487 section 4.8.8: SIA: "
347 		    "failed extension parse", p->fn);
348 		goto out;
349 	}
350 	d = sv;
351 
352 	if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
353 		cryptowarnx("%s: RFC 6487 section 4.8.8: SIA: "
354 		    "failed ASN.1 sequence parse", p->fn);
355 		goto out;
356 	}
357 	if (sk_ASN1_TYPE_num(seq) != 2) {
358 		warnx("%s: RFC 6487 section 4.8.8: SIA: "
359 		    "want 2 elements, have %d", p->fn,
360 		    sk_ASN1_TYPE_num(seq));
361 		goto out;
362 	}
363 
364 	t = sk_ASN1_TYPE_value(seq, 0);
365 	if (t->type != V_ASN1_OBJECT) {
366 		warnx("%s: RFC 6487 section 4.8.8: SIA: "
367 		    "want ASN.1 object, have %s (NID %d)",
368 		    p->fn, ASN1_tag2str(t->type), t->type);
369 		goto out;
370 	}
371 	if (OBJ_obj2nid(t->value.object) != NID_sinfo_access) {
372 		warnx("%s: RFC 6487 section 4.8.8: SIA: "
373 		    "incorrect OID, have %s (NID %d)", p->fn,
374 		    ASN1_tag2str(OBJ_obj2nid(t->value.object)),
375 		    OBJ_obj2nid(t->value.object));
376 		goto out;
377 	}
378 
379 	t = sk_ASN1_TYPE_value(seq, 1);
380 	if (t->type != V_ASN1_OCTET_STRING) {
381 		warnx("%s: RFC 6487 section 4.8.8: SIA: "
382 		    "want ASN.1 octet string, have %s (NID %d)",
383 		    p->fn, ASN1_tag2str(t->type), t->type);
384 		goto out;
385 	}
386 
387 	d = t->value.octet_string->data;
388 	dsz = t->value.octet_string->length;
389 	if (!sbgp_sia_resource(p, d, dsz))
390 		goto out;
391 
392 	rc = 1;
393 out:
394 	sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
395 	free(sv);
396 	return rc;
397 }
398 
399 /*
400  * Parse a range of addresses as in 3.2.3.8.
401  * Returns zero on failure, non-zero on success.
402  */
403 static int
404 sbgp_asrange(struct parse *p, const unsigned char *d, size_t dsz)
405 {
406 	struct cert_as		 as;
407 	ASN1_SEQUENCE_ANY	*seq;
408 	const ASN1_TYPE		*t;
409 	int			 rc = 0;
410 
411 	if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
412 		cryptowarnx("%s: RFC 3779 section 3.2.3.8: ASRange: "
413 		    "failed ASN.1 sequence parse", p->fn);
414 		goto out;
415 	}
416 	if (sk_ASN1_TYPE_num(seq) != 2) {
417 		warnx("%s: RFC 3779 section 3.2.3.8: ASRange: "
418 		    "want 2 elements, have %d", p->fn,
419 		    sk_ASN1_TYPE_num(seq));
420 		goto out;
421 	}
422 
423 	memset(&as, 0, sizeof(struct cert_as));
424 	as.type = CERT_AS_RANGE;
425 
426 	t = sk_ASN1_TYPE_value(seq, 0);
427 	if (t->type != V_ASN1_INTEGER) {
428 		warnx("%s: RFC 3779 section 3.2.3.8: ASRange: "
429 		    "want ASN.1 integer, have %s (NID %d)",
430 		    p->fn, ASN1_tag2str(t->type), t->type);
431 		goto out;
432 	}
433 	if (!as_id_parse(t->value.integer, &as.range.min)) {
434 		warnx("%s: RFC 3779 section 3.2.3.8 (via RFC 1930): "
435 		    "malformed AS identifier", p->fn);
436 		return 0;
437 	}
438 
439 	t = sk_ASN1_TYPE_value(seq, 1);
440 	if (t->type != V_ASN1_INTEGER) {
441 		warnx("%s: RFC 3779 section 3.2.3.8: ASRange: "
442 		    "want ASN.1 integer, have %s (NID %d)",
443 		    p->fn, ASN1_tag2str(t->type), t->type);
444 		goto out;
445 	}
446 	if (!as_id_parse(t->value.integer, &as.range.max)) {
447 		warnx("%s: RFC 3779 section 3.2.3.8 (via RFC 1930): "
448 		    "malformed AS identifier", p->fn);
449 		return 0;
450 	}
451 
452 	if (as.range.max == as.range.min) {
453 		warnx("%s: RFC 3379 section 3.2.3.8: ASRange: "
454 		    "range is singular", p->fn);
455 		goto out;
456 	} else if (as.range.max < as.range.min) {
457 		warnx("%s: RFC 3379 section 3.2.3.8: ASRange: "
458 		    "range is out of order", p->fn);
459 		goto out;
460 	}
461 
462 	if (!append_as(p, &as))
463 		goto out;
464 	rc = 1;
465 out:
466 	sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
467 	return rc;
468 }
469 
470 /*
471  * Parse an entire 3.2.3.10 integer type.
472  */
473 static int
474 sbgp_asid(struct parse *p, const ASN1_INTEGER *i)
475 {
476 	struct cert_as	 as;
477 
478 	memset(&as, 0, sizeof(struct cert_as));
479 	as.type = CERT_AS_ID;
480 
481 	if (!as_id_parse(i, &as.id)) {
482 		warnx("%s: RFC 3779 section 3.2.3.10 (via RFC 1930): "
483 		    "malformed AS identifier", p->fn);
484 		return 0;
485 	}
486 	if (as.id == 0) {
487 		warnx("%s: RFC 3779 section 3.2.3.10 (via RFC 1930): "
488 		    "AS identifier zero is reserved", p->fn);
489 		return 0;
490 	}
491 
492 	return append_as(p, &as);
493 }
494 
495 /*
496  * Parse one of RFC 3779 3.2.3.2.
497  * Returns zero on failure, non-zero on success.
498  */
499 static int
500 sbgp_asnum(struct parse *p, const unsigned char *d, size_t dsz)
501 {
502 	struct cert_as		 as;
503 	ASN1_TYPE		*t, *tt;
504 	ASN1_SEQUENCE_ANY	*seq = NULL;
505 	int			 i, rc = 0;
506 	const unsigned char	*sv = d;
507 
508 	/* We can either be a null (inherit) or sequence. */
509 
510 	if ((t = d2i_ASN1_TYPE(NULL, &d, dsz)) == NULL) {
511 		cryptowarnx("%s: RFC 3779 section 3.2.3.2: ASIdentifierChoice: "
512 		    "failed ASN.1 type parse", p->fn);
513 		goto out;
514 	}
515 
516 	/*
517 	 * Section 3779 3.2.3.3 is to inherit with an ASN.1 NULL type,
518 	 * which is the easy case.
519 	 */
520 
521 	switch (t->type) {
522 	case V_ASN1_NULL:
523 		memset(&as, 0, sizeof(struct cert_as));
524 		as.type = CERT_AS_INHERIT;
525 		if (!append_as(p, &as))
526 			goto out;
527 		rc = 1;
528 		goto out;
529 	case V_ASN1_SEQUENCE:
530 		break;
531 	default:
532 		warnx("%s: RFC 3779 section 3.2.3.2: ASIdentifierChoice: "
533 		    "want ASN.1 sequence or null, have %s (NID %d)",
534 		    p->fn, ASN1_tag2str(t->type), t->type);
535 		goto out;
536 	}
537 
538 	/* This is RFC 3779 3.2.3.4. */
539 
540 	if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &sv, dsz)) == NULL) {
541 		cryptowarnx("%s: RFC 3779 section 3.2.3.2: ASIdentifierChoice: "
542 		    "failed ASN.1 sequence parse", p->fn);
543 		goto out;
544 	}
545 
546 	/* Accepts RFC 3779 3.2.3.6 or 3.2.3.7 (sequence). */
547 
548 	for (i = 0; i < sk_ASN1_TYPE_num(seq); i++) {
549 		tt = sk_ASN1_TYPE_value(seq, i);
550 		switch (tt->type) {
551 		case V_ASN1_INTEGER:
552 			if (!sbgp_asid(p, tt->value.integer))
553 				goto out;
554 			break;
555 		case V_ASN1_SEQUENCE:
556 			d = tt->value.asn1_string->data;
557 			dsz = tt->value.asn1_string->length;
558 			if (!sbgp_asrange(p, d, dsz))
559 				goto out;
560 			break;
561 		default:
562 			warnx("%s: RFC 3779 section 3.2.3.5: ASIdOrRange: "
563 			    "want ASN.1 sequence or integer, have %s (NID %d)",
564 			    p->fn, ASN1_tag2str(tt->type), tt->type);
565 			goto out;
566 		}
567 	}
568 
569 	rc = 1;
570 out:
571 	ASN1_TYPE_free(t);
572 	sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
573 	return rc;
574 }
575 
576 /*
577  * Parse RFC 6487 4.8.11 X509v3 extension, with syntax documented in RFC
578  * 3779 starting in section 3.2.
579  * Returns zero on failure, non-zero on success.
580  */
581 static int
582 sbgp_assysnum(struct parse *p, X509_EXTENSION *ext)
583 {
584 	unsigned char		*sv = NULL;
585 	const unsigned char	*d;
586 	ASN1_SEQUENCE_ANY	*seq = NULL, *sseq = NULL;
587 	const ASN1_TYPE		*t;
588 	int			 dsz, rc = 0, i, ptag;
589 	long			 plen;
590 
591 	if ((dsz = i2d_X509_EXTENSION(ext, &sv)) < 0) {
592 		cryptowarnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: "
593 		    "failed extension parse", p->fn);
594 		goto out;
595 	}
596 
597 	/* Start with RFC 3779, section 3.2 top-level. */
598 
599 	d = sv;
600 	if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
601 		cryptowarnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: "
602 		    "failed ASN.1 sequence parse", p->fn);
603 		goto out;
604 	}
605 	if (sk_ASN1_TYPE_num(seq) != 3) {
606 		warnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: "
607 		    "want 3 elements, have %d", p->fn,
608 		    sk_ASN1_TYPE_num(seq));
609 		goto out;
610 	}
611 
612 	t = sk_ASN1_TYPE_value(seq, 0);
613 	if (t->type != V_ASN1_OBJECT) {
614 		warnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: "
615 		    "want ASN.1 object, have %s (NID %d)",
616 		    p->fn, ASN1_tag2str(t->type), t->type);
617 		goto out;
618 	}
619 
620 	/* FIXME: verify OID. */
621 
622 	t = sk_ASN1_TYPE_value(seq, 1);
623 	if (t->type != V_ASN1_BOOLEAN) {
624 		warnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: "
625 		    "want ASN.1 boolean, have %s (NID %d)",
626 		    p->fn, ASN1_tag2str(t->type), t->type);
627 		goto out;
628 	}
629 
630 	t = sk_ASN1_TYPE_value(seq, 2);
631 	if (t->type != V_ASN1_OCTET_STRING) {
632 		warnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: "
633 		    "want ASN.1 octet string, have %s (NID %d)",
634 		    p->fn, ASN1_tag2str(t->type), t->type);
635 		goto out;
636 	}
637 
638 	/* Within RFC 3779 3.2.3, check 3.2.3.1. */
639 
640 	d = t->value.octet_string->data;
641 	dsz = t->value.octet_string->length;
642 
643 	if ((sseq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
644 		cryptowarnx("%s: RFC 3779 section 3.2.3.1: ASIdentifiers: "
645 		    "failed ASN.1 sequence parse", p->fn);
646 		goto out;
647 	}
648 
649 	/* Scan through for private 3.2.3.2 classes. */
650 
651 	for (i = 0; i < sk_ASN1_TYPE_num(sseq); i++) {
652 		t = sk_ASN1_TYPE_value(sseq, i);
653 		if (t->type != V_ASN1_OTHER) {
654 			warnx("%s: RFC 3779 section 3.2.3.1: ASIdentifiers: "
655 			    "want ASN.1 explicit, have %s (NID %d)", p->fn,
656 			    ASN1_tag2str(t->type), t->type);
657 			goto out;
658 		}
659 
660 		/* Use the low-level ASN1_frame. */
661 
662 		d = t->value.asn1_string->data;
663 		dsz = t->value.asn1_string->length;
664 		if (!ASN1_frame(p->fn, dsz, &d, &plen, &ptag))
665 			goto out;
666 
667 		/* Ignore bad AS identifiers and RDI entries. */
668 
669 		if (ptag > ASID_TYPE_MAX) {
670 			warnx("%s: RFC 3779 section 3.2.3.1: ASIdentifiers: "
671 			    "unknown explicit tag 0x%02x", p->fn, ptag);
672 			goto out;
673 		} else if (ptag == ASID_TYPE_RDI)
674 			continue;
675 
676 		if (!sbgp_asnum(p, d, plen))
677 			goto out;
678 	}
679 
680 	rc = 1;
681 out:
682 	sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
683 	sk_ASN1_TYPE_pop_free(sseq, ASN1_TYPE_free);
684 	free(sv);
685 	return rc;
686 }
687 
688 /*
689  * Parse RFC 3779 2.2.3.9 range of addresses.
690  * Return zero on failure, non-zero on success.
691  */
692 static int
693 sbgp_addr_range(struct parse *p, struct cert_ip *ip,
694 	const unsigned char *d, size_t dsz)
695 {
696 	ASN1_SEQUENCE_ANY	*seq;
697 	const ASN1_TYPE		*t;
698 	int			 rc = 0;
699 
700 	if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
701 		cryptowarnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
702 		    "failed ASN.1 sequence parse", p->fn);
703 		goto out;
704 	}
705 	if (sk_ASN1_TYPE_num(seq) != 2) {
706 		warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
707 		    "want 2 elements, have %d", p->fn, sk_ASN1_TYPE_num(seq));
708 		goto out;
709 	}
710 
711 	t = sk_ASN1_TYPE_value(seq, 0);
712 	if (t->type != V_ASN1_BIT_STRING) {
713 		warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
714 		    "want ASN.1 bit string, have %s (NID %d)",
715 		    p->fn, ASN1_tag2str(t->type), t->type);
716 		goto out;
717 	}
718 	if (!ip_addr_parse(t->value.bit_string,
719 	    ip->afi, p->fn, &ip->range.min)) {
720 		warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
721 		    "invalid IP address", p->fn);
722 		goto out;
723 	}
724 
725 	t = sk_ASN1_TYPE_value(seq, 1);
726 	if (t->type != V_ASN1_BIT_STRING) {
727 		warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
728 		    "want ASN.1 bit string, have %s (NID %d)",
729 		    p->fn, ASN1_tag2str(t->type), t->type);
730 		goto out;
731 	}
732 	if (!ip_addr_parse(t->value.bit_string,
733 	    ip->afi, p->fn, &ip->range.max)) {
734 		warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
735 		    "invalid IP address", p->fn);
736 		goto out;
737 	}
738 
739 	if (!ip_cert_compose_ranges(ip)) {
740 		warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
741 		    "IP address range reversed", p->fn);
742 		return 0;
743 	}
744 
745 	rc = append_ip(p, ip);
746 out:
747 	sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
748 	return rc;
749 }
750 
751 /*
752  * Parse an IP address or range, RFC 3779 2.2.3.7.
753  * We don't constrain this parse (as specified in section 2.2.3.6) to
754  * having any kind of order.
755  * Returns zero on failure, non-zero on success.
756  */
757 static int
758 sbgp_addr_or_range(struct parse *p, struct cert_ip *ip,
759 	const unsigned char *d, size_t dsz)
760 {
761 	struct cert_ip		 nip;
762 	ASN1_SEQUENCE_ANY	*seq;
763 	const ASN1_TYPE		*t;
764 	int			 i, rc = 0;
765 
766 	if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
767 		cryptowarnx("%s: RFC 3779 section 2.2.3.7: IPAddressOrRange: "
768 		    "failed ASN.1 sequence parse", p->fn);
769 		goto out;
770 	}
771 
772 	/* Either RFC 3779 2.2.3.8 or 2.2.3.9. */
773 
774 	for (i = 0; i < sk_ASN1_TYPE_num(seq); i++) {
775 		nip = *ip;
776 		t = sk_ASN1_TYPE_value(seq, i);
777 		switch (t->type) {
778 		case V_ASN1_BIT_STRING:
779 			nip.type = CERT_IP_ADDR;
780 			if (!sbgp_addr(p, &nip, t->value.bit_string))
781 				goto out;
782 			break;
783 		case V_ASN1_SEQUENCE:
784 			nip.type = CERT_IP_RANGE;
785 			d = t->value.asn1_string->data;
786 			dsz = t->value.asn1_string->length;
787 			if (!sbgp_addr_range(p, &nip, d, dsz))
788 				goto out;
789 			break;
790 		default:
791 			warnx("%s: RFC 3779 section 2.2.3.7: IPAddressOrRange: "
792 			    "want ASN.1 sequence or bit string, have %s (NID %d)",
793 			    p->fn, ASN1_tag2str(t->type), t->type);
794 			goto out;
795 		}
796 	}
797 
798 	rc = 1;
799 out:
800 	sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
801 	return rc;
802 }
803 
804 /*
805  * Parse a sequence of address families as in RFC 3779 sec. 2.2.3.2.
806  * Ignore several stipulations of the RFC (2.2.3.3).
807  * Namely, we don't require entries to be ordered in any way (type, AFI
808  * or SAFI group, etc.).
809  * This is because it doesn't matter for our purposes: we're going to
810  * validate in the same way regardless.
811  * Returns zero no failure, non-zero on success.
812  */
813 static int
814 sbgp_ipaddrfam(struct parse *p, const unsigned char *d, size_t dsz)
815 {
816 	struct cert_ip		 ip;
817 	ASN1_SEQUENCE_ANY	*seq;
818 	const ASN1_TYPE		*t;
819 	int			 rc = 0;
820 
821 	memset(&ip, 0, sizeof(struct cert_ip));
822 
823 	if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
824 		cryptowarnx("%s: RFC 3779 section 2.2.3.2: IPAddressFamily: "
825 		    "failed ASN.1 sequence parse", p->fn);
826 		goto out;
827 	}
828 	if (sk_ASN1_TYPE_num(seq) != 2) {
829 		warnx("%s: RFC 3779 section 2.2.3.2: IPAddressFamily: "
830 		    "want 2 elements, have %d",
831 		    p->fn, sk_ASN1_TYPE_num(seq));
832 		goto out;
833 	}
834 
835 	/* Get address family, RFC 3779, 2.2.3.3. */
836 
837 	t = sk_ASN1_TYPE_value(seq, 0);
838 	if (t->type != V_ASN1_OCTET_STRING) {
839 		warnx("%s: RFC 3779 section 2.2.3.2: addressFamily: "
840 		    "want ASN.1 octet string, have %s (NID %d)",
841 		    p->fn, ASN1_tag2str(t->type), t->type);
842 		goto out;
843 	}
844 
845 	if (!ip_addr_afi_parse(p->fn, t->value.octet_string, &ip.afi)) {
846 		warnx("%s: RFC 3779 section 2.2.3.2: addressFamily: "
847 		    "invalid AFI", p->fn);
848 		goto out;
849 	}
850 
851 	/* Either sequence or null (inherit), RFC 3779 sec. 2.2.3.4. */
852 
853 	t = sk_ASN1_TYPE_value(seq, 1);
854 	switch (t->type) {
855 	case V_ASN1_SEQUENCE:
856 		d = t->value.asn1_string->data;
857 		dsz = t->value.asn1_string->length;
858 		if (!sbgp_addr_or_range(p, &ip, d, dsz))
859 			goto out;
860 		break;
861 	case V_ASN1_NULL:
862 		ip.type = CERT_IP_INHERIT;
863 		if (!append_ip(p, &ip))
864 			goto out;
865 		break;
866 	default:
867 		warnx("%s: RFC 3779 section 2.2.3.2: IPAddressChoice: "
868 		    "want ASN.1 sequence or null, have %s (NID %d)",
869 		    p->fn, ASN1_tag2str(t->type), t->type);
870 		goto out;
871 	}
872 
873 	rc = 1;
874 out:
875 	sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
876 	return rc;
877 }
878 
879 /*
880  * Parse an sbgp-ipAddrBlock X509 extension, RFC 6487 4.8.10, with
881  * syntax documented in RFC 3779 starting in section 2.2.
882  * Returns zero on failure, non-zero on success.
883  */
884 static int
885 sbgp_ipaddrblk(struct parse *p, X509_EXTENSION *ext)
886 {
887 	int			 dsz, rc = 0;
888 	unsigned char		*sv = NULL;
889 	const unsigned char	*d;
890 	ASN1_SEQUENCE_ANY	*seq = NULL, *sseq = NULL;
891 	const ASN1_TYPE		*t = NULL;
892 	int			 i;
893 
894 	if ((dsz = i2d_X509_EXTENSION(ext, &sv)) < 0) {
895 		cryptowarnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: "
896 		    "failed extension parse", p->fn);
897 		goto out;
898 	}
899 	d = sv;
900 
901 	if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
902 		cryptowarnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: "
903 		    "failed ASN.1 sequence parse", p->fn);
904 		goto out;
905 	}
906 	if (sk_ASN1_TYPE_num(seq) != 3) {
907 		warnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: "
908 		    "want 3 elements, have %d",
909 		    p->fn, sk_ASN1_TYPE_num(seq));
910 		goto out;
911 	}
912 
913 	t = sk_ASN1_TYPE_value(seq, 0);
914 	if (t->type != V_ASN1_OBJECT) {
915 		warnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: "
916 		    "want ASN.1 object, have %s (NID %d)",
917 		    p->fn, ASN1_tag2str(t->type), t->type);
918 		goto out;
919 	}
920 
921 	/* FIXME: verify OID. */
922 
923 	t = sk_ASN1_TYPE_value(seq, 1);
924 	if (t->type != V_ASN1_BOOLEAN) {
925 		warnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: "
926 		    "want ASN.1 boolean, have %s (NID %d)",
927 		    p->fn, ASN1_tag2str(t->type), t->type);
928 		goto out;
929 	}
930 
931 	t = sk_ASN1_TYPE_value(seq, 2);
932 	if (t->type != V_ASN1_OCTET_STRING) {
933 		warnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: "
934 		    "want ASN.1 octet string, have %s (NID %d)",
935 		    p->fn, ASN1_tag2str(t->type), t->type);
936 		goto out;
937 	}
938 
939 	/* The blocks sequence, RFC 3779 2.2.3.1. */
940 
941 	d = t->value.octet_string->data;
942 	dsz = t->value.octet_string->length;
943 
944 	if ((sseq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
945 		cryptowarnx("%s: RFC 3779 section 2.2.3.1: IPAddrBlocks: "
946 		    "failed ASN.1 sequence parse", p->fn);
947 		goto out;
948 	}
949 
950 	/* Each sequence element contains RFC 3779 sec. 2.2.3.2. */
951 
952 	for (i = 0; i < sk_ASN1_TYPE_num(sseq); i++) {
953 		t = sk_ASN1_TYPE_value(sseq, i);
954 		if (t->type != V_ASN1_SEQUENCE) {
955 			warnx("%s: RFC 3779 section 2.2.3.2: IPAddressFamily: "
956 			    "want ASN.1 sequence, have %s (NID %d)",
957 			    p->fn, ASN1_tag2str(t->type), t->type);
958 			goto out;
959 		}
960 		d = t->value.asn1_string->data;
961 		dsz = t->value.asn1_string->length;
962 		if (!sbgp_ipaddrfam(p, d, dsz))
963 			goto out;
964 	}
965 
966 	rc = 1;
967 out:
968 	sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
969 	sk_ASN1_TYPE_pop_free(sseq, ASN1_TYPE_free);
970 	free(sv);
971 	return rc;
972 }
973 
974 /*
975  * Parse and partially validate an RPKI X509 certificate (either a trust
976  * anchor or a certificate) as defined in RFC 6487.
977  * If "ta" is set, this is a trust anchor and must be self-signed.
978  * Returns the parse results or NULL on failure ("xp" will be NULL too).
979  * On success, free the pointer with cert_free() and make sure that "xp"
980  * is also dereferenced.
981  */
982 static struct cert *
983 cert_parse_inner(X509 **xp, const char *fn, const unsigned char *der,
984     size_t len, int ta)
985 {
986 	int		 rc = 0, extsz, c;
987 	int		 sia_present = 0;
988 	size_t		 i;
989 	X509		*x = NULL;
990 	X509_EXTENSION	*ext = NULL;
991 	ASN1_OBJECT	*obj;
992 	struct parse	 p;
993 
994 	*xp = NULL;
995 
996 	/* just fail for empty buffers, the warning was printed elsewhere */
997 	if (der == NULL)
998 		return NULL;
999 
1000 	memset(&p, 0, sizeof(struct parse));
1001 	p.fn = fn;
1002 	if ((p.res = calloc(1, sizeof(struct cert))) == NULL)
1003 		err(1, NULL);
1004 
1005 	if ((x = *xp = d2i_X509(NULL, &der, len)) == NULL) {
1006 		cryptowarnx("%s: d2i_X509_bio", p.fn);
1007 		goto out;
1008 	}
1009 
1010 	/* Look for X509v3 extensions. */
1011 
1012 	if ((extsz = X509_get_ext_count(x)) < 0)
1013 		cryptoerrx("X509_get_ext_count");
1014 
1015 	for (i = 0; i < (size_t)extsz; i++) {
1016 		ext = X509_get_ext(x, i);
1017 		assert(ext != NULL);
1018 		obj = X509_EXTENSION_get_object(ext);
1019 		assert(obj != NULL);
1020 		c = 1;
1021 
1022 		switch (OBJ_obj2nid(obj)) {
1023 		case NID_sbgp_ipAddrBlock:
1024 			c = sbgp_ipaddrblk(&p, ext);
1025 			break;
1026 		case NID_sbgp_autonomousSysNum:
1027 			c = sbgp_assysnum(&p, ext);
1028 			break;
1029 		case NID_sinfo_access:
1030 			sia_present = 1;
1031 			c = sbgp_sia(&p, ext);
1032 			break;
1033 		case NID_crl_distribution_points:
1034 			/* ignored here, handled later */
1035 			break;
1036 		case NID_info_access:
1037 			break;
1038 		case NID_authority_key_identifier:
1039 			break;
1040 		case NID_subject_key_identifier:
1041 			break;
1042 		case NID_ext_key_usage:
1043 			break;
1044 		default:
1045 			/* {
1046 				char objn[64];
1047 				OBJ_obj2txt(objn, sizeof(objn), obj, 0);
1048 				warnx("%s: ignoring %s (NID %d)",
1049 					p.fn, objn, OBJ_obj2nid(obj));
1050 			} */
1051 			break;
1052 		}
1053 		if (c == 0)
1054 			goto out;
1055 	}
1056 
1057 	p.res->aki = x509_get_aki(x, ta, p.fn);
1058 	p.res->ski = x509_get_ski(x, p.fn);
1059 	if (!ta) {
1060 		p.res->aia = x509_get_aia(x, p.fn);
1061 		p.res->crl = x509_get_crl(x, p.fn);
1062 	}
1063 	if (!x509_get_expire(x, p.fn, &p.res->expires))
1064 		goto out;
1065 	p.res->purpose = x509_get_purpose(x, p.fn);
1066 
1067 	/* Validation on required fields. */
1068 
1069 	switch (p.res->purpose) {
1070 	case CERT_PURPOSE_CA:
1071 		if (p.res->mft == NULL) {
1072 			warnx("%s: RFC 6487 section 4.8.8: missing SIA", p.fn);
1073 			goto out;
1074 		}
1075 		if (p.res->asz == 0 && p.res->ipsz == 0) {
1076 			warnx("%s: missing IP or AS resources", p.fn);
1077 			goto out;
1078 		}
1079 		break;
1080 	case CERT_PURPOSE_BGPSEC_ROUTER:
1081 		p.res->pubkey = x509_get_pubkey(x, p.fn);
1082 		if (p.res->pubkey == NULL) {
1083 			warnx("%s: x509_get_pubkey failed", p.fn);
1084 			goto out;
1085 		}
1086 		if (p.res->ipsz > 0) {
1087 			warnx("%s: unexpected IP resources in BGPsec cert",
1088 			   p.fn);
1089 			goto out;
1090 		}
1091 		if (sia_present) {
1092 			warnx("%s: unexpected SIA extension in BGPsec cert",
1093 			   p.fn);
1094 			goto out;
1095 		}
1096 		if (ta) {
1097 			warnx("%s: BGPsec cert can not be a trust anchor",
1098 			   p.fn);
1099 			goto out;
1100 		}
1101 		break;
1102 	default:
1103 		warnx("%s: x509_get_purpose failed in %s", p.fn, __func__);
1104 		goto out;
1105 	}
1106 
1107 	if (p.res->ski == NULL) {
1108 		warnx("%s: RFC 6487 section 8.4.2: missing SKI", p.fn);
1109 		goto out;
1110 	}
1111 
1112 	if (ta && p.res->aki != NULL && strcmp(p.res->aki, p.res->ski)) {
1113 		warnx("%s: RFC 6487 section 8.4.2: "
1114 		    "trust anchor AKI, if specified, must match SKI", p.fn);
1115 		goto out;
1116 	}
1117 
1118 	if (!ta && p.res->aki == NULL) {
1119 		warnx("%s: RFC 6487 section 8.4.2: "
1120 		    "non-trust anchor missing AKI", p.fn);
1121 		goto out;
1122 	} else if (!ta && strcmp(p.res->aki, p.res->ski) == 0) {
1123 		warnx("%s: RFC 6487 section 8.4.2: "
1124 		    "non-trust anchor AKI may not match SKI", p.fn);
1125 		goto out;
1126 	}
1127 
1128 	if (!ta && p.res->aia == NULL) {
1129 		warnx("%s: RFC 6487 section 8.4.7: "
1130 		    "non-trust anchor missing AIA", p.fn);
1131 		goto out;
1132 	} else if (ta && p.res->aia != NULL) {
1133 		warnx("%s: RFC 6487 section 8.4.7: "
1134 		    "trust anchor must not have AIA", p.fn);
1135 		goto out;
1136 	}
1137 
1138 	if (ta && p.res->crl != NULL) {
1139 		warnx("%s: RFC 6487 section 8.4.2: "
1140 		    "trust anchor may not specify CRL resource", p.fn);
1141 		goto out;
1142 	}
1143 
1144 	if (X509_up_ref(x) == 0)
1145 		errx(1, "%s: X509_up_ref failed", __func__);
1146 
1147 	p.res->x509 = x;
1148 
1149 	rc = 1;
1150 out:
1151 	if (rc == 0) {
1152 		cert_free(p.res);
1153 		X509_free(x);
1154 		*xp = NULL;
1155 	}
1156 	return (rc == 0) ? NULL : p.res;
1157 }
1158 
1159 struct cert *
1160 cert_parse(X509 **xp, const char *fn, const unsigned char *der, size_t len)
1161 {
1162 	return cert_parse_inner(xp, fn, der, len, 0);
1163 }
1164 
1165 struct cert *
1166 ta_parse(X509 **xp, const char *fn, const unsigned char *der, size_t len,
1167     const unsigned char *pkey, size_t pkeysz)
1168 {
1169 	EVP_PKEY	*pk = NULL, *opk = NULL;
1170 	struct cert	*p;
1171 	int		 rc = 0;
1172 
1173 	if ((p = cert_parse_inner(xp, fn, der, len, 1)) == NULL)
1174 		return NULL;
1175 
1176 	if (pkey != NULL) {
1177 		assert(*xp != NULL);
1178 		pk = d2i_PUBKEY(NULL, &pkey, pkeysz);
1179 		assert(pk != NULL);
1180 
1181 		if ((opk = X509_get_pubkey(*xp)) == NULL)
1182 			cryptowarnx("%s: RFC 6487 (trust anchor): "
1183 			    "missing pubkey", fn);
1184 		else if (EVP_PKEY_cmp(pk, opk) != 1)
1185 			cryptowarnx("%s: RFC 6487 (trust anchor): "
1186 			    "pubkey does not match TAL pubkey", fn);
1187 		else
1188 			rc = 1;
1189 
1190 		EVP_PKEY_free(pk);
1191 		EVP_PKEY_free(opk);
1192 	}
1193 
1194 	if (rc == 0) {
1195 		cert_free(p);
1196 		p = NULL;
1197 		X509_free(*xp);
1198 		*xp = NULL;
1199 	}
1200 
1201 	return p;
1202 }
1203 
1204 /*
1205  * Free parsed certificate contents.
1206  * Passing NULL is a noop.
1207  */
1208 void
1209 cert_free(struct cert *p)
1210 {
1211 	if (p == NULL)
1212 		return;
1213 
1214 	free(p->crl);
1215 	free(p->repo);
1216 	free(p->mft);
1217 	free(p->notify);
1218 	free(p->ips);
1219 	free(p->as);
1220 	free(p->aia);
1221 	free(p->aki);
1222 	free(p->ski);
1223 	free(p->pubkey);
1224 	X509_free(p->x509);
1225 	free(p);
1226 }
1227 
1228 /*
1229  * Write certificate parsed content into buffer.
1230  * See cert_read() for the other side of the pipe.
1231  */
1232 void
1233 cert_buffer(struct ibuf *b, const struct cert *p)
1234 {
1235 	io_simple_buffer(b, &p->expires, sizeof(p->expires));
1236 	io_simple_buffer(b, &p->purpose, sizeof(p->purpose));
1237 	io_simple_buffer(b, &p->talid, sizeof(p->talid));
1238 	io_simple_buffer(b, &p->ipsz, sizeof(p->ipsz));
1239 	io_simple_buffer(b, &p->asz, sizeof(p->asz));
1240 
1241 	io_simple_buffer(b, p->ips, p->ipsz * sizeof(p->ips[0]));
1242 	io_simple_buffer(b, p->as, p->asz * sizeof(p->as[0]));
1243 
1244 	io_str_buffer(b, p->mft);
1245 	io_str_buffer(b, p->notify);
1246 	io_str_buffer(b, p->repo);
1247 	io_str_buffer(b, p->crl);
1248 	io_str_buffer(b, p->aia);
1249 	io_str_buffer(b, p->aki);
1250 	io_str_buffer(b, p->ski);
1251 	io_str_buffer(b, p->pubkey);
1252 }
1253 
1254 /*
1255  * Allocate and read parsed certificate content from descriptor.
1256  * The pointer must be freed with cert_free().
1257  * Always returns a valid pointer.
1258  */
1259 struct cert *
1260 cert_read(struct ibuf *b)
1261 {
1262 	struct cert	*p;
1263 
1264 	if ((p = calloc(1, sizeof(struct cert))) == NULL)
1265 		err(1, NULL);
1266 
1267 	io_read_buf(b, &p->expires, sizeof(p->expires));
1268 	io_read_buf(b, &p->purpose, sizeof(p->purpose));
1269 	io_read_buf(b, &p->talid, sizeof(p->talid));
1270 	io_read_buf(b, &p->ipsz, sizeof(p->ipsz));
1271 	io_read_buf(b, &p->asz, sizeof(p->asz));
1272 
1273 	p->ips = calloc(p->ipsz, sizeof(struct cert_ip));
1274 	if (p->ips == NULL)
1275 		err(1, NULL);
1276 	io_read_buf(b, p->ips, p->ipsz * sizeof(p->ips[0]));
1277 
1278 	p->as = calloc(p->asz, sizeof(struct cert_as));
1279 	if (p->as == NULL)
1280 		err(1, NULL);
1281 	io_read_buf(b, p->as, p->asz * sizeof(p->as[0]));
1282 
1283 	io_read_str(b, &p->mft);
1284 	io_read_str(b, &p->notify);
1285 	io_read_str(b, &p->repo);
1286 	io_read_str(b, &p->crl);
1287 	io_read_str(b, &p->aia);
1288 	io_read_str(b, &p->aki);
1289 	io_read_str(b, &p->ski);
1290 	io_read_str(b, &p->pubkey);
1291 
1292 	assert(p->mft != NULL || p->purpose == CERT_PURPOSE_BGPSEC_ROUTER);
1293 	assert(p->ski);
1294 	return p;
1295 }
1296 
1297 struct auth *
1298 auth_find(struct auth_tree *auths, const char *aki)
1299 {
1300 	struct auth a;
1301 	struct cert c;
1302 
1303 	/* we look up the cert where the ski == aki */
1304 	c.ski = (char *)aki;
1305 	a.cert = &c;
1306 
1307 	return RB_FIND(auth_tree, auths, &a);
1308 }
1309 
1310 int
1311 auth_insert(struct auth_tree *auths, struct cert *cert, struct auth *parent)
1312 {
1313 	struct auth *na;
1314 
1315 	na = malloc(sizeof(*na));
1316 	if (na == NULL)
1317 		err(1, NULL);
1318 
1319 	na->parent = parent;
1320 	na->cert = cert;
1321 
1322 	if (RB_INSERT(auth_tree, auths, na) != NULL)
1323 		err(1, "auth tree corrupted");
1324 
1325 	return 1;
1326 }
1327 
1328 static inline int
1329 authcmp(struct auth *a, struct auth *b)
1330 {
1331 	return strcmp(a->cert->ski, b->cert->ski);
1332 }
1333 
1334 RB_GENERATE(auth_tree, auth, entry, authcmp);
1335 
1336 static void
1337 insert_brk(struct brk_tree *tree, struct cert *cert, int asid)
1338 {
1339 	struct brk	*b, *found;
1340 
1341 	if ((b = calloc(1, sizeof(*b))) == NULL)
1342 		err(1, NULL);
1343 
1344 	b->asid = asid;
1345 	b->expires = cert->expires;
1346 	b->talid = cert->talid;
1347 	if ((b->ski = strdup(cert->ski)) == NULL)
1348 		err(1, NULL);
1349 	if ((b->pubkey = strdup(cert->pubkey)) == NULL)
1350 		err(1, NULL);
1351 
1352 	/*
1353 	 * Check if a similar BRK already exists in the tree. If the found BRK
1354 	 * expires sooner, update it to this BRK's later expiry moment.
1355 	 */
1356 	if ((found = RB_INSERT(brk_tree, tree, b)) != NULL) {
1357 		if (found->expires < b->expires) {
1358 			found->expires = b->expires;
1359 			found->talid = b->talid;
1360 		}
1361 		free(b->ski);
1362 		free(b->pubkey);
1363 		free(b);
1364 	}
1365 }
1366 
1367 /*
1368  * Add each BGPsec Router Key into the BRK tree.
1369  */
1370 void
1371 cert_insert_brks(struct brk_tree *tree, struct cert *cert)
1372 {
1373 	size_t		 i, asid;
1374 
1375 	for (i = 0; i < cert->asz; i++) {
1376 		switch (cert->as[i].type) {
1377 		case CERT_AS_ID:
1378 			insert_brk(tree, cert, cert->as[i].id);
1379 			break;
1380 		case CERT_AS_RANGE:
1381 			for (asid = cert->as[i].range.min;
1382 			    asid <= cert->as[i].range.max; asid++)
1383 				insert_brk(tree, cert, asid);
1384 			break;
1385 		default:
1386 			warnx("invalid AS identifier type");
1387 			continue;
1388 		}
1389 	}
1390 }
1391 
1392 static inline int
1393 brkcmp(struct brk *a, struct brk *b)
1394 {
1395 	int rv;
1396 
1397 	if (a->asid > b->asid)
1398 		return 1;
1399 	if (a->asid < b->asid)
1400 		return -1;
1401 
1402 	rv = strcmp(a->ski, b->ski);
1403 	if (rv > 0)
1404 		return 1;
1405 	if (rv < 0)
1406 		return -1;
1407 
1408 	return strcmp(a->pubkey, b->pubkey);
1409 }
1410 
1411 RB_GENERATE(brk_tree, brk, entry, brkcmp);
1412