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