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