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