xref: /openbsd/usr.sbin/rpki-client/roa.c (revision 771fbea0)
1 /*	$OpenBSD: roa.c,v 1.19 2021/05/11 11:32:51 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 <assert.h>
19 #include <err.h>
20 #include <stdarg.h>
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 
26 #include <openssl/asn1.h>
27 #include <openssl/x509.h>
28 
29 #include "extern.h"
30 
31 /*
32  * Parse results and data of the manifest file.
33  */
34 struct	parse {
35 	const char	 *fn; /* manifest file name */
36 	struct roa	 *res; /* results */
37 };
38 
39 /*
40  * Parse IP address (ROAIPAddress), RFC 6482, section 3.3.
41  * Returns zero on failure, non-zero on success.
42  */
43 static int
44 roa_parse_addr(const ASN1_OCTET_STRING *os, enum afi afi, struct parse *p)
45 {
46 	ASN1_SEQUENCE_ANY	*seq;
47 	const unsigned char	*d = os->data;
48 	size_t			 dsz = os->length;
49 	int			 rc = 0;
50 	const ASN1_TYPE		*t;
51 	const ASN1_INTEGER	*maxlength = NULL;
52 	struct ip_addr		 addr;
53 	struct roa_ip		*res;
54 
55 	if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
56 		cryptowarnx("%s: RFC 6482 section 3.3: address: "
57 		    "failed ASN.1 sequence parse", p->fn);
58 		goto out;
59 	}
60 
61 	/* ROAIPAddress has the address and optional maxlength. */
62 
63 	if (sk_ASN1_TYPE_num(seq) != 1 &&
64 	    sk_ASN1_TYPE_num(seq) != 2) {
65 		warnx("%s: RFC 6482 section 3.3: adddress: "
66 		    "want 1 or 2 elements, have %d",
67 		    p->fn, sk_ASN1_TYPE_num(seq));
68 		goto out;
69 	}
70 
71 	t = sk_ASN1_TYPE_value(seq, 0);
72 	if (t->type != V_ASN1_BIT_STRING) {
73 		warnx("%s: RFC 6482 section 3.3: address: "
74 		    "want ASN.1 bit string, have %s (NID %d)",
75 		    p->fn, ASN1_tag2str(t->type), t->type);
76 		goto out;
77 	}
78 	if (!ip_addr_parse(t->value.bit_string, afi, p->fn, &addr)) {
79 		warnx("%s: RFC 6482 section 3.3: address: "
80 		    "invalid IP address", p->fn);
81 		goto out;
82 	}
83 
84 	/*
85 	 * RFC 6482, section 3.3 doesn't ever actually state that the
86 	 * maximum length can't be negative, but it needs to be >=0.
87 	 */
88 
89 	if (sk_ASN1_TYPE_num(seq) == 2) {
90 		t = sk_ASN1_TYPE_value(seq, 1);
91 		if (t->type != V_ASN1_INTEGER) {
92 			warnx("%s: RFC 6482 section 3.1: maxLength: "
93 			    "want ASN.1 integer, have %s (NID %d)",
94 			    p->fn, ASN1_tag2str(t->type), t->type);
95 			goto out;
96 		}
97 		maxlength = t->value.integer;
98 
99 		/*
100 		 * It's safe to use ASN1_INTEGER_get() here
101 		 * because we're not going to have more than signed 32
102 		 * bit maximum of length.
103 		 */
104 
105 		if (ASN1_INTEGER_get(maxlength) < 0) {
106 			warnx("%s: RFC 6482 section 3.2: maxLength: "
107 			    "want positive integer, have %ld",
108 			    p->fn, ASN1_INTEGER_get(maxlength));
109 			goto out;
110 		}
111 		/* FIXME: maximum check. */
112 	}
113 
114 	p->res->ips = recallocarray(p->res->ips, p->res->ipsz, p->res->ipsz + 1,
115 	    sizeof(struct roa_ip));
116 	if (p->res->ips == NULL)
117 		err(1, NULL);
118 	res = &p->res->ips[p->res->ipsz++];
119 
120 	res->addr = addr;
121 	res->afi = afi;
122 	res->maxlength = (maxlength == NULL) ? addr.prefixlen :
123 	    ASN1_INTEGER_get(maxlength);
124 	ip_roa_compose_ranges(res);
125 
126 	rc = 1;
127 out:
128 	sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
129 	return rc;
130 }
131 
132 /*
133  * Parse IP address family, RFC 6482, section 3.3.
134  * Returns zero on failure, non-zero on success.
135  */
136 static int
137 roa_parse_ipfam(const ASN1_OCTET_STRING *os, struct parse *p)
138 {
139 	ASN1_SEQUENCE_ANY	*seq, *sseq = NULL;
140 	const unsigned char	*d = os->data;
141 	size_t			 dsz = os->length;
142 	int			 i, rc = 0;
143 	const ASN1_TYPE		*t;
144 	enum afi		 afi;
145 
146 	if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
147 		cryptowarnx("%s: RFC 6482 section 3.3: ROAIPAddressFamily: "
148 		    "failed ASN.1 sequence parse", p->fn);
149 		goto out;
150 	} else if (sk_ASN1_TYPE_num(seq) != 2) {
151 		warnx("%s: RFC 6482 section 3.3: ROAIPAddressFamily: "
152 		    "want 2 elements, have %d",
153 		    p->fn, sk_ASN1_TYPE_num(seq));
154 		goto out;
155 	}
156 
157 	t = sk_ASN1_TYPE_value(seq, 0);
158 	if (t->type != V_ASN1_OCTET_STRING) {
159 		warnx("%s: RFC 6482 section 3.3: addressFamily: "
160 		    "want ASN.1 octet string, have %s (NID %d)",
161 		    p->fn, ASN1_tag2str(t->type), t->type);
162 		goto out;
163 	}
164 	if (!ip_addr_afi_parse(p->fn, t->value.octet_string, &afi)) {
165 		warnx("%s: RFC 6482 section 3.3: addressFamily: "
166 		    "invalid", p->fn);
167 		goto out;
168 	}
169 
170 	t = sk_ASN1_TYPE_value(seq, 1);
171 	if (t->type != V_ASN1_SEQUENCE) {
172 		warnx("%s: RFC 6482 section 3.3: addresses: "
173 		    "want ASN.1 sequence, have %s (NID %d)",
174 		    p->fn, ASN1_tag2str(t->type), t->type);
175 		goto out;
176 	}
177 
178 	d = t->value.octet_string->data;
179 	dsz = t->value.octet_string->length;
180 
181 	if ((sseq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
182 		cryptowarnx("%s: RFC 6482 section 3.3: addresses: "
183 		    "failed ASN.1 sequence parse", p->fn);
184 		goto out;
185 	}
186 
187 	for (i = 0; i < sk_ASN1_TYPE_num(sseq); i++) {
188 		t = sk_ASN1_TYPE_value(sseq, i);
189 		if (t->type != V_ASN1_SEQUENCE) {
190 			warnx("%s: RFC 6482 section 3.3: ROAIPAddress: "
191 			    "want ASN.1 sequence, have %s (NID %d)",
192 			    p->fn, ASN1_tag2str(t->type), t->type);
193 			goto out;
194 		}
195 		if (!roa_parse_addr(t->value.octet_string, afi, p))
196 			goto out;
197 	}
198 
199 	rc = 1;
200 out:
201 	sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
202 	sk_ASN1_TYPE_pop_free(sseq, ASN1_TYPE_free);
203 	return rc;
204 }
205 
206 /*
207  * Parse IP blocks, RFC 6482, section 3.3.
208  * Returns zero on failure, non-zero on success.
209  */
210 static int
211 roa_parse_ipblocks(const ASN1_OCTET_STRING *os, struct parse *p)
212 {
213 	ASN1_SEQUENCE_ANY	*seq;
214 	const unsigned char	*d = os->data;
215 	size_t			 dsz = os->length;
216 	int			 i, rc = 0;
217 	const ASN1_TYPE		*t;
218 
219 	if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
220 		cryptowarnx("%s: RFC 6482 section 3.3: ipAddrBlocks: "
221 		    "failed ASN.1 sequence parse", p->fn);
222 		goto out;
223 	}
224 
225 	for (i = 0; i < sk_ASN1_TYPE_num(seq); i++) {
226 		t = sk_ASN1_TYPE_value(seq, i);
227 		if (t->type != V_ASN1_SEQUENCE) {
228 			warnx("%s: RFC 6482 section 3.3: ROAIPAddressFamily: "
229 			    "want ASN.1 sequence, have %s (NID %d)",
230 			    p->fn, ASN1_tag2str(t->type), t->type);
231 			goto out;
232 		} else if (!roa_parse_ipfam(t->value.octet_string, p))
233 			goto out;
234 	}
235 
236 	rc = 1;
237 out:
238 	sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
239 	return rc;
240 }
241 
242 /*
243  * Parses the eContent section of an ROA file, RFC 6482, section 3.
244  * Returns zero on failure, non-zero on success.
245  */
246 static int
247 roa_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p)
248 {
249 	ASN1_SEQUENCE_ANY	*seq;
250 	int			 i = 0, rc = 0, sz;
251 	const ASN1_TYPE		*t;
252 
253 	/* RFC 6482, section 3. */
254 
255 	if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
256 		cryptowarnx("%s: RFC 6482 section 3: RouteOriginAttestation: "
257 		    "failed ASN.1 sequence parse", p->fn);
258 		goto out;
259 	}
260 
261 	if ((sz = sk_ASN1_TYPE_num(seq)) != 2 && sz != 3) {
262 		warnx("%s: RFC 6482 section 3: RouteOriginAttestation: "
263 		    "want 2 or 3 elements, have %d",
264 		    p->fn, sk_ASN1_TYPE_num(seq));
265 		goto out;
266 	}
267 
268 	/* RFC 6482, section 3.1. */
269 
270 	if (sz == 3) {
271 		t = sk_ASN1_TYPE_value(seq, i++);
272 
273 		/*
274 		 * This check with ASN1_INTEGER_get() is fine since
275 		 * we're looking for a value of zero anyway, so any
276 		 * overflowing number will be definition be wrong.
277 		 */
278 
279 		if (t->type != V_ASN1_INTEGER) {
280 			warnx("%s: RFC 6482 section 3.1: version: "
281 			    "want ASN.1 integer, have %s (NID %d)",
282 			    p->fn, ASN1_tag2str(t->type), t->type);
283 			goto out;
284 		} else if (ASN1_INTEGER_get(t->value.integer) != 0) {
285 			warnx("%s: RFC 6482 section 3.1: version: "
286 			    "want version 0, have %ld",
287 			    p->fn, ASN1_INTEGER_get(t->value.integer));
288 			goto out;
289 		}
290 	}
291 
292 	/*
293 	 * RFC 6482, section 3.2.
294 	 * It doesn't ever actually state that AS numbers can't be
295 	 * negative, but...?
296 	 */
297 
298 	t = sk_ASN1_TYPE_value(seq, i++);
299 	if (t->type != V_ASN1_INTEGER) {
300 		warnx("%s: RFC 6482 section 3.2: asID: "
301 		    "want ASN.1 integer, have %s (NID %d)",
302 		    p->fn, ASN1_tag2str(t->type), t->type);
303 		goto out;
304 	} else if (!as_id_parse(t->value.integer, &p->res->asid)) {
305 		warnx("%s: RFC 6482 section 3.2: asID: "
306 		    "malformed AS identifier", p->fn);
307 		goto out;
308 	}
309 
310 	/* RFC 6482, section 3.3. */
311 
312 	t = sk_ASN1_TYPE_value(seq, i++);
313 	if (t->type != V_ASN1_SEQUENCE) {
314 		warnx("%s: RFC 6482 section 3.3: ipAddrBlocks: "
315 		    "want ASN.1 sequence, have %s (NID %d)",
316 		    p->fn, ASN1_tag2str(t->type), t->type);
317 		goto out;
318 	} else if (!roa_parse_ipblocks(t->value.octet_string, p))
319 		goto out;
320 
321 	rc = 1;
322 out:
323 	sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
324 	return rc;
325 }
326 
327 /*
328  * Parse a full RFC 6482 file.
329  * Returns the ROA or NULL if the document was malformed.
330  */
331 struct roa *
332 roa_parse(X509 **x509, const char *fn)
333 {
334 	struct parse	 p;
335 	size_t		 cmsz;
336 	unsigned char	*cms;
337 	int		 rc = 0;
338 	const ASN1_TIME	*at;
339 	struct tm	 expires_tm;
340 	time_t		 expires;
341 
342 	memset(&p, 0, sizeof(struct parse));
343 	p.fn = fn;
344 
345 	/* OID from section 2, RFC 6482. */
346 
347 	cms = cms_parse_validate(x509, fn,
348 	    "1.2.840.113549.1.9.16.1.24", &cmsz);
349 	if (cms == NULL)
350 		return NULL;
351 
352 	if ((p.res = calloc(1, sizeof(struct roa))) == NULL)
353 		err(1, NULL);
354 
355 	p.res->aia = x509_get_aia(*x509, fn);
356 	p.res->aki = x509_get_aki(*x509, 0, fn);
357 	p.res->ski = x509_get_ski(*x509, fn);
358 	if (p.res->aia == NULL || p.res->aki == NULL || p.res->ski == NULL) {
359 		warnx("%s: RFC 6487 section 4.8: "
360 		    "missing AIA, AKI or SKI X509 extension", fn);
361 		goto out;
362 	}
363 
364 	at = X509_get0_notAfter(*x509);
365 	if (at == NULL) {
366 		warnx("%s: X509_get0_notAfter failed", fn);
367 		goto out;
368 	}
369 	memset(&expires_tm, 0, sizeof(expires_tm));
370 	if (ASN1_time_parse(at->data, at->length, &expires_tm, 0) == -1) {
371 		warnx("%s: ASN1_time_parse failed", fn);
372 		goto out;
373 	}
374 	if ((expires = mktime(&expires_tm)) == -1) {
375 		err(1, "mktime failed");
376 		goto out;
377 	}
378 	p.res->expires = expires;
379 
380 	if (!roa_parse_econtent(cms, cmsz, &p))
381 		goto out;
382 
383 	rc = 1;
384 out:
385 	if (rc == 0) {
386 		roa_free(p.res);
387 		p.res = NULL;
388 		X509_free(*x509);
389 		*x509 = NULL;
390 	}
391 	free(cms);
392 	return p.res;
393 
394 }
395 
396 /*
397  * Free an ROA pointer.
398  * Safe to call with NULL.
399  */
400 void
401 roa_free(struct roa *p)
402 {
403 
404 	if (p == NULL)
405 		return;
406 	free(p->aia);
407 	free(p->aki);
408 	free(p->ski);
409 	free(p->ips);
410 	free(p->tal);
411 	free(p);
412 }
413 
414 /*
415  * Serialise parsed ROA content.
416  * See roa_read() for reader.
417  */
418 void
419 roa_buffer(struct ibuf *b, const struct roa *p)
420 {
421 	size_t	 i;
422 
423 	io_simple_buffer(b, &p->valid, sizeof(int));
424 	io_simple_buffer(b, &p->asid, sizeof(uint32_t));
425 	io_simple_buffer(b, &p->ipsz, sizeof(size_t));
426 	io_simple_buffer(b, &p->expires, sizeof(time_t));
427 
428 	for (i = 0; i < p->ipsz; i++) {
429 		io_simple_buffer(b, &p->ips[i].afi, sizeof(enum afi));
430 		io_simple_buffer(b, &p->ips[i].maxlength, sizeof(size_t));
431 		io_simple_buffer(b, p->ips[i].min, sizeof(p->ips[i].min));
432 		io_simple_buffer(b, p->ips[i].max, sizeof(p->ips[i].max));
433 		ip_addr_buffer(b, &p->ips[i].addr);
434 	}
435 
436 	io_str_buffer(b, p->aia);
437 	io_str_buffer(b, p->aki);
438 	io_str_buffer(b, p->ski);
439 	io_str_buffer(b, p->tal);
440 }
441 
442 /*
443  * Read parsed ROA content from descriptor.
444  * See roa_buffer() for writer.
445  * Result must be passed to roa_free().
446  */
447 struct roa *
448 roa_read(int fd)
449 {
450 	struct roa	*p;
451 	size_t		 i;
452 
453 	if ((p = calloc(1, sizeof(struct roa))) == NULL)
454 		err(1, NULL);
455 
456 	io_simple_read(fd, &p->valid, sizeof(int));
457 	io_simple_read(fd, &p->asid, sizeof(uint32_t));
458 	io_simple_read(fd, &p->ipsz, sizeof(size_t));
459 	io_simple_read(fd, &p->expires, sizeof(time_t));
460 
461 	if ((p->ips = calloc(p->ipsz, sizeof(struct roa_ip))) == NULL)
462 		err(1, NULL);
463 
464 	for (i = 0; i < p->ipsz; i++) {
465 		io_simple_read(fd, &p->ips[i].afi, sizeof(enum afi));
466 		io_simple_read(fd, &p->ips[i].maxlength, sizeof(size_t));
467 		io_simple_read(fd, &p->ips[i].min, sizeof(p->ips[i].min));
468 		io_simple_read(fd, &p->ips[i].max, sizeof(p->ips[i].max));
469 		ip_addr_read(fd, &p->ips[i].addr);
470 	}
471 
472 	io_str_read(fd, &p->aia);
473 	io_str_read(fd, &p->aki);
474 	io_str_read(fd, &p->ski);
475 	io_str_read(fd, &p->tal);
476 	assert(p->aia && p->aki && p->ski && p->tal);
477 
478 	return p;
479 }
480 
481 /*
482  * Add each IP address in the ROA into the VRP tree.
483  * Updates "vrps" to be the number of VRPs and "uniqs" to be the unique
484  * number of addresses.
485  */
486 void
487 roa_insert_vrps(struct vrp_tree *tree, struct roa *roa, size_t *vrps,
488     size_t *uniqs)
489 {
490 	struct vrp	*v, *found;
491 	size_t		 i;
492 
493 	for (i = 0; i < roa->ipsz; i++) {
494 		if ((v = malloc(sizeof(*v))) == NULL)
495 			err(1, NULL);
496 		v->afi = roa->ips[i].afi;
497 		v->addr = roa->ips[i].addr;
498 		v->maxlength = roa->ips[i].maxlength;
499 		v->asid = roa->asid;
500 		if ((v->tal = strdup(roa->tal)) == NULL)
501 			err(1, NULL);
502 		v->expires = roa->expires;
503 
504 		/*
505 		 * Check if a similar VRP already exists in the tree.
506 		 * If the found VRP expires sooner, update it to this
507 		 * ROAs later expiry moment.
508 		 */
509 		if ((found = RB_INSERT(vrp_tree, tree, v)) != NULL) {
510 			/* already exists */
511 			if (found->expires < v->expires) {
512 				/* update found with preferred data */
513 				found->expires = roa->expires;
514 				free(found->tal);
515 				found->tal = v->tal;
516 				v->tal = NULL;
517 			}
518 			free(v->tal);
519 			free(v);
520 		} else
521 			(*uniqs)++;
522 
523 		(*vrps)++;
524 	}
525 }
526 
527 static inline int
528 vrpcmp(struct vrp *a, struct vrp *b)
529 {
530 	int rv;
531 
532 	if (a->afi > b->afi)
533 		return 1;
534 	if (a->afi < b->afi)
535 		return -1;
536 	switch (a->afi) {
537 	case AFI_IPV4:
538 		rv = memcmp(&a->addr.addr, &b->addr.addr, 4);
539 		if (rv)
540 			return rv;
541 		break;
542 	case AFI_IPV6:
543 		rv = memcmp(&a->addr.addr, &b->addr.addr, 16);
544 		if (rv)
545 			return rv;
546 		break;
547 	}
548 	/* a smaller prefixlen is considered bigger, e.g. /8 vs /10 */
549 	if (a->addr.prefixlen < b->addr.prefixlen)
550 		return 1;
551 	if (a->addr.prefixlen > b->addr.prefixlen)
552 		return -1;
553 	if (a->maxlength < b->maxlength)
554 		return 1;
555 	if (a->maxlength > b->maxlength)
556 		return -1;
557 
558 	if (a->asid > b->asid)
559 		return 1;
560 	if (a->asid < b->asid)
561 		return -1;
562 
563 	return 0;
564 }
565 
566 RB_GENERATE(vrp_tree, vrp, entry, vrpcmp);
567