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