xref: /openbsd-src/usr.sbin/rpki-client/filemode.c (revision fc405d53b73a2d73393cb97f684863d17b583e38)
1 /*	$OpenBSD: filemode.c,v 1.31 2023/05/03 10:22:30 tb Exp $ */
2 /*
3  * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
4  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/queue.h>
20 #include <sys/tree.h>
21 #include <sys/types.h>
22 
23 #include <assert.h>
24 #include <err.h>
25 #include <fcntl.h>
26 #include <poll.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <limits.h>
31 #include <unistd.h>
32 #include <imsg.h>
33 
34 #include <openssl/asn1.h>
35 #include <openssl/err.h>
36 #include <openssl/evp.h>
37 #include <openssl/pem.h>
38 #include <openssl/x509.h>
39 #include <openssl/x509v3.h>
40 
41 #include "extern.h"
42 
43 extern int		 verbose;
44 
45 static X509_STORE_CTX	*ctx;
46 static struct auth_tree	 auths = RB_INITIALIZER(&auths);
47 static struct crl_tree	 crlt = RB_INITIALIZER(&crlt);
48 
49 struct tal		*talobj[TALSZ_MAX];
50 
51 /*
52  * Use the X509 CRL Distribution Points to locate the CRL needed for
53  * verification.
54  */
55 static void
56 parse_load_crl(char *uri)
57 {
58 	struct crl *crl;
59 	char *f;
60 	size_t flen;
61 
62 	if (uri == NULL)
63 		return;
64 	if (strncmp(uri, "rsync://", strlen("rsync://")) != 0) {
65 		warnx("bad CRL distribution point URI %s", uri);
66 		return;
67 	}
68 	uri += strlen("rsync://");
69 
70 	f = load_file(uri, &flen);
71 	if (f == NULL) {
72 		warn("parse file %s", uri);
73 		return;
74 	}
75 
76 	crl = crl_parse(uri, f, flen);
77 	if (crl != NULL && !crl_insert(&crlt, crl))
78 		crl_free(crl);
79 
80 	free(f);
81 }
82 
83 /*
84  * Parse the cert pointed at by the AIA URI while doing that also load
85  * the CRL of this cert. While the CRL is validated the returned cert
86  * is not. The caller needs to make sure it is validated once all
87  * necessary certs were loaded. Returns NULL on failure.
88  */
89 static struct cert *
90 parse_load_cert(char *uri)
91 {
92 	struct cert *cert = NULL;
93 	char *f;
94 	size_t flen;
95 
96 	if (uri == NULL)
97 		return NULL;
98 
99 	if (strncmp(uri, "rsync://", strlen("rsync://")) != 0) {
100 		warnx("bad authority information access URI %s", uri);
101 		return NULL;
102 	}
103 	uri += strlen("rsync://");
104 
105 	f = load_file(uri, &flen);
106 	if (f == NULL) {
107 		warn("parse file %s", uri);
108 		goto done;
109 	}
110 
111 	cert = cert_parse_pre(uri, f, flen);
112 	free(f);
113 
114 	if (cert == NULL)
115 		goto done;
116 	if (cert->purpose != CERT_PURPOSE_CA) {
117 		warnx("AIA reference to bgpsec cert %s", uri);
118 		goto done;
119 	}
120 	/* try to load the CRL of this cert */
121 	parse_load_crl(cert->crl);
122 
123 	return cert;
124 
125  done:
126 	cert_free(cert);
127 	return NULL;
128 }
129 
130 /*
131  * Build the certificate chain by using the Authority Information Access.
132  * This requires that the TA are already validated and added to the auths
133  * tree. Once the TA is located in the chain the chain is validated in
134  * reverse order.
135  */
136 static void
137 parse_load_certchain(char *uri)
138 {
139 	struct cert *stack[MAX_CERT_DEPTH] = { 0 };
140 	char *filestack[MAX_CERT_DEPTH];
141 	struct cert *cert;
142 	struct crl *crl;
143 	struct auth *a;
144 	const char *errstr;
145 	int i;
146 
147 	for (i = 0; i < MAX_CERT_DEPTH; i++) {
148 		filestack[i] = uri;
149 		stack[i] = cert = parse_load_cert(uri);
150 		if (cert == NULL || cert->purpose != CERT_PURPOSE_CA) {
151 			warnx("failed to build authority chain");
152 			goto fail;
153 		}
154 		if (auth_find(&auths, cert->ski) != NULL) {
155 			assert(i == 0);
156 			goto fail;
157 		}
158 		if ((a = auth_find(&auths, cert->aki)) != NULL)
159 			break;	/* found chain to TA */
160 		uri = cert->aia;
161 	}
162 
163 	if (i >= MAX_CERT_DEPTH) {
164 		warnx("authority chain exceeds max depth of %d",
165 		    MAX_CERT_DEPTH);
166 		goto fail;
167 	}
168 
169 	/* TA found play back the stack and add all certs */
170 	for (; i >= 0; i--) {
171 		cert = stack[i];
172 		uri = filestack[i];
173 
174 		crl = crl_get(&crlt, a);
175 		if (!valid_x509(uri, ctx, cert->x509, a, crl, &errstr) ||
176 		    !valid_cert(uri, a, cert)) {
177 			if (errstr != NULL)
178 				warnx("%s: %s", uri, errstr);
179 			goto fail;
180 		}
181 		cert->talid = a->cert->talid;
182 		a = auth_insert(&auths, cert, a);
183 		stack[i] = NULL;
184 	}
185 
186 	return;
187 fail:
188 	for (i = 0; i < MAX_CERT_DEPTH; i++)
189 		cert_free(stack[i]);
190 }
191 
192 static void
193 parse_load_ta(struct tal *tal)
194 {
195 	const char *filename;
196 	struct cert *cert;
197 	unsigned char *f = NULL;
198 	char *file;
199 	size_t flen;
200 
201 	/* does not matter which URI, all end with same filename */
202 	filename = strrchr(tal->uri[0], '/');
203 	assert(filename);
204 
205 	if (asprintf(&file, "ta/%s%s", tal->descr, filename) == -1)
206 		err(1, NULL);
207 
208 	f = load_file(file, &flen);
209 	if (f == NULL) {
210 		warn("parse file %s", file);
211 		goto out;
212 	}
213 
214 	/* Extract certificate data. */
215 	cert = cert_parse_pre(file, f, flen);
216 	cert = ta_parse(file, cert, tal->pkey, tal->pkeysz);
217 	if (cert == NULL)
218 		goto out;
219 
220 	cert->talid = tal->id;
221 
222 	if (!valid_ta(file, &auths, cert))
223 		cert_free(cert);
224 	else
225 		auth_insert(&auths, cert, NULL);
226 out:
227 	free(file);
228 	free(f);
229 }
230 
231 static struct tal *
232 find_tal(struct cert *cert)
233 {
234 	EVP_PKEY	*pk, *opk;
235 	struct tal	*tal;
236 	int		 i;
237 
238 	if ((opk = X509_get0_pubkey(cert->x509)) == NULL)
239 		return NULL;
240 
241 	for (i = 0; i < TALSZ_MAX; i++) {
242 		const unsigned char *pkey;
243 
244 		if (talobj[i] == NULL)
245 			break;
246 		tal = talobj[i];
247 		pkey = tal->pkey;
248 		pk = d2i_PUBKEY(NULL, &pkey, tal->pkeysz);
249 		if (pk == NULL)
250 			continue;
251 		if (EVP_PKEY_cmp(pk, opk) == 1) {
252 			EVP_PKEY_free(pk);
253 			return tal;
254 		}
255 		EVP_PKEY_free(pk);
256 	}
257 	return NULL;
258 }
259 
260 static void
261 print_signature_path(const char *crl, const char *aia, const struct auth *a)
262 {
263 	if (crl != NULL)
264 		printf("Signature path:           %s\n", crl);
265 	if (a->cert->mft != NULL)
266 		printf("                          %s\n", a->cert->mft);
267 	if (aia != NULL)
268 		printf("                          %s\n", aia);
269 
270 	for (; a != NULL; a = a->parent) {
271 		if (a->cert->crl != NULL)
272 			printf("                          %s\n", a->cert->crl);
273 		if (a->parent != NULL && a->parent->cert != NULL &&
274 		    a->parent->cert->mft != NULL)
275 			printf("                          %s\n",
276 			    a->parent->cert->mft);
277 		if (a->cert->aia != NULL)
278 			printf("                          %s\n", a->cert->aia);
279 	}
280 }
281 
282 /*
283  * Parse file passed with -f option.
284  */
285 static void
286 proc_parser_file(char *file, unsigned char *buf, size_t len)
287 {
288 	static int num;
289 	X509 *x509 = NULL;
290 	struct aspa *aspa = NULL;
291 	struct cert *cert = NULL;
292 	struct crl *crl = NULL;
293 	struct gbr *gbr = NULL;
294 	struct geofeed *geofeed = NULL;
295 	struct mft *mft = NULL;
296 	struct roa *roa = NULL;
297 	struct rsc *rsc = NULL;
298 	struct tak *tak = NULL;
299 	struct tal *tal = NULL;
300 	char *aia = NULL, *aki = NULL;
301 	char *crl_uri = NULL;
302 	time_t *expires = NULL, *notafter = NULL;
303 	struct auth *a;
304 	struct crl *c;
305 	const char *errstr = NULL;
306 	int status = 0;
307 	char filehash[SHA256_DIGEST_LENGTH];
308 	char *hash;
309 	enum rtype type;
310 	int is_ta = 0;
311 
312 	if (num++ > 0) {
313 		if ((outformats & FORMAT_JSON) == 0)
314 			printf("--\n");
315 	}
316 
317 	if (strncmp(file, "rsync://", strlen("rsync://")) == 0) {
318 		file += strlen("rsync://");
319 		buf = load_file(file, &len);
320 		if (buf == NULL) {
321 			warn("parse file %s", file);
322 			return;
323 		}
324 	}
325 
326 	if (!EVP_Digest(buf, len, filehash, NULL, EVP_sha256(), NULL))
327 		errx(1, "EVP_Digest failed in %s", __func__);
328 
329 	if (base64_encode(filehash, sizeof(filehash), &hash) == -1)
330 		errx(1, "base64_encode failed in %s", __func__);
331 
332 	if (outformats & FORMAT_JSON) {
333 		printf("{\n\t\"file\": \"%s\",\n", file);
334 		printf("\t\"hash_id\": \"%s\",\n", hash);
335 	} else {
336 		printf("File:                     %s\n", file);
337 		printf("Hash identifier:          %s\n", hash);
338 	}
339 
340 	free(hash);
341 
342 	type = rtype_from_file_extension(file);
343 
344 	switch (type) {
345 	case RTYPE_ASPA:
346 		aspa = aspa_parse(&x509, file, buf, len);
347 		if (aspa == NULL)
348 			break;
349 		aia = aspa->aia;
350 		aki = aspa->aki;
351 		expires = &aspa->expires;
352 		notafter = &aspa->notafter;
353 		break;
354 	case RTYPE_CER:
355 		cert = cert_parse_pre(file, buf, len);
356 		if (cert == NULL)
357 			break;
358 		is_ta = X509_get_extension_flags(cert->x509) & EXFLAG_SS;
359 		if (!is_ta)
360 			cert = cert_parse(file, cert);
361 		if (cert == NULL)
362 			break;
363 		aia = cert->aia;
364 		aki = cert->aki;
365 		x509 = cert->x509;
366 		if (X509_up_ref(x509) == 0)
367 			errx(1, "%s: X509_up_ref failed", __func__);
368 		expires = &cert->expires;
369 		notafter = &cert->notafter;
370 		break;
371 	case RTYPE_CRL:
372 		crl = crl_parse(file, buf, len);
373 		if (crl == NULL)
374 			break;
375 		crl_print(crl);
376 		break;
377 	case RTYPE_MFT:
378 		mft = mft_parse(&x509, file, buf, len);
379 		if (mft == NULL)
380 			break;
381 		aia = mft->aia;
382 		aki = mft->aki;
383 		expires = &mft->expires;
384 		notafter = &mft->nextupdate;
385 		break;
386 	case RTYPE_GBR:
387 		gbr = gbr_parse(&x509, file, buf, len);
388 		if (gbr == NULL)
389 			break;
390 		aia = gbr->aia;
391 		aki = gbr->aki;
392 		expires = &gbr->expires;
393 		notafter = &gbr->notafter;
394 		break;
395 	case RTYPE_GEOFEED:
396 		geofeed = geofeed_parse(&x509, file, buf, len);
397 		if (geofeed == NULL)
398 			break;
399 		aia = geofeed->aia;
400 		aki = geofeed->aki;
401 		expires = &geofeed->expires;
402 		notafter = &geofeed->notafter;
403 		break;
404 	case RTYPE_ROA:
405 		roa = roa_parse(&x509, file, buf, len);
406 		if (roa == NULL)
407 			break;
408 		aia = roa->aia;
409 		aki = roa->aki;
410 		expires = &roa->expires;
411 		notafter = &roa->notafter;
412 		break;
413 	case RTYPE_RSC:
414 		rsc = rsc_parse(&x509, file, buf, len);
415 		if (rsc == NULL)
416 			break;
417 		aia = rsc->aia;
418 		aki = rsc->aki;
419 		expires = &rsc->expires;
420 		notafter = &rsc->notafter;
421 		break;
422 	case RTYPE_TAK:
423 		tak = tak_parse(&x509, file, buf, len);
424 		if (tak == NULL)
425 			break;
426 		aia = tak->aia;
427 		aki = tak->aki;
428 		expires = &tak->expires;
429 		notafter = &tak->notafter;
430 		break;
431 	case RTYPE_TAL:
432 		tal = tal_parse(file, buf, len);
433 		if (tal == NULL)
434 			break;
435 		tal_print(tal);
436 		break;
437 	default:
438 		printf("%s: unsupported file type\n", file);
439 		break;
440 	}
441 
442 	if (aia != NULL) {
443 		x509_get_crl(x509, file, &crl_uri);
444 		parse_load_crl(crl_uri);
445 		if (auth_find(&auths, aki) == NULL)
446 			parse_load_certchain(aia);
447 		a = auth_find(&auths, aki);
448 		c = crl_get(&crlt, a);
449 
450 		if ((status = valid_x509(file, ctx, x509, a, c, &errstr))) {
451 			switch (type) {
452 			case RTYPE_ASPA:
453 				status = aspa->valid;
454 				break;
455 			case RTYPE_GEOFEED:
456 				status = geofeed->valid;
457 				break;
458 			case RTYPE_ROA:
459 				status = roa->valid;
460 				break;
461 			case RTYPE_RSC:
462 				status = rsc->valid;
463 				break;
464 			default:
465 				break;
466 			}
467 		}
468 	} else if (is_ta) {
469 		if ((tal = find_tal(cert)) != NULL) {
470 			cert = ta_parse(file, cert, tal->pkey, tal->pkeysz);
471 			status = (cert != NULL);
472 			if (outformats & FORMAT_JSON)
473 				printf("\t\"tal\": \"%s\",\n", tal->descr);
474 			else
475 				printf("TAL:                      %s\n",
476 				    tal->descr);
477 			tal = NULL;
478 		} else {
479 			cert_free(cert);
480 			cert = NULL;
481 			expires = NULL;
482 			status = 0;
483 		}
484 	}
485 
486 	if (expires != NULL) {
487 		if (status && aia != NULL)
488 			*expires = x509_find_expires(*notafter, a, &crlt);
489 
490 		switch (type) {
491 		case RTYPE_ASPA:
492 			aspa_print(x509, aspa);
493 			break;
494 		case RTYPE_CER:
495 			cert_print(cert);
496 			break;
497 		case RTYPE_GBR:
498 			gbr_print(x509, gbr);
499 			break;
500 		case RTYPE_GEOFEED:
501 			geofeed_print(x509, geofeed);
502 			break;
503 		case RTYPE_MFT:
504 			mft_print(x509, mft);
505 			break;
506 		case RTYPE_ROA:
507 			roa_print(x509, roa);
508 			break;
509 		case RTYPE_RSC:
510 			rsc_print(x509, rsc);
511 			break;
512 		case RTYPE_TAK:
513 			tak_print(x509, tak);
514 			break;
515 		default:
516 			break;
517 		}
518 	}
519 
520 	if (outformats & FORMAT_JSON)
521 		printf("\t\"validation\": \"");
522 	else
523 		printf("Validation:               ");
524 
525 	if (status)
526 		printf("OK");
527 	else {
528 		if (aia == NULL)
529 			printf("N/A");
530 		else {
531 			printf("Failed");
532 			if (errstr != NULL)
533 				printf(", %s", errstr);
534 		}
535 	}
536 
537 	if (outformats & FORMAT_JSON)
538 		printf("\"\n}\n");
539 	else {
540 		printf("\n");
541 
542 		if (status && aia != NULL) {
543 			print_signature_path(crl_uri, aia, a);
544 			if (expires != NULL)
545 				printf("Signature path expires:   %s\n",
546 				    time2str(*expires));
547 		}
548 
549 		if (x509 == NULL)
550 			goto out;
551 		if (type == RTYPE_TAL || type == RTYPE_CRL)
552 			goto out;
553 
554 		if (verbose) {
555 			if (!X509_print_fp(stdout, x509))
556 				errx(1, "X509_print_fp");
557 		}
558 
559 		if (verbose > 1) {
560 			if (!PEM_write_X509(stdout, x509))
561 				errx(1, "PEM_write_X509");
562 		}
563 	}
564 
565  out:
566 	free(crl_uri);
567 	X509_free(x509);
568 	aspa_free(aspa);
569 	cert_free(cert);
570 	crl_free(crl);
571 	gbr_free(gbr);
572 	geofeed_free(geofeed);
573 	mft_free(mft);
574 	roa_free(roa);
575 	rsc_free(rsc);
576 	tak_free(tak);
577 	tal_free(tal);
578 }
579 
580 /*
581  * Process a file request, in general don't send anything back.
582  */
583 static void
584 parse_file(struct entityq *q, struct msgbuf *msgq)
585 {
586 	struct entity	*entp;
587 	struct ibuf	*b;
588 	struct tal	*tal;
589 
590 	while ((entp = TAILQ_FIRST(q)) != NULL) {
591 		TAILQ_REMOVE(q, entp, entries);
592 
593 		switch (entp->type) {
594 		case RTYPE_FILE:
595 			proc_parser_file(entp->file, entp->data, entp->datasz);
596 			break;
597 		case RTYPE_TAL:
598 			if ((tal = tal_parse(entp->file, entp->data,
599 			    entp->datasz)) == NULL)
600 				errx(1, "%s: could not parse tal file",
601 				    entp->file);
602 			tal->id = entp->talid;
603 			talobj[tal->id] = tal;
604 			parse_load_ta(tal);
605 			break;
606 		default:
607 			errx(1, "unhandled entity type %d", entp->type);
608 		}
609 
610 		b = io_new_buffer();
611 		io_simple_buffer(b, &entp->type, sizeof(entp->type));
612 		io_simple_buffer(b, &entp->repoid, sizeof(entp->repoid));
613 		io_simple_buffer(b, &entp->talid, sizeof(entp->talid));
614 		io_str_buffer(b, entp->file);
615 		io_close_buffer(msgq, b);
616 		entity_free(entp);
617 	}
618 }
619 
620 /*
621  * Process responsible for parsing and validating content.
622  * All this process does is wait to be told about a file to parse, then
623  * it parses it and makes sure that the data being returned is fully
624  * validated and verified.
625  * The process will exit cleanly only when fd is closed.
626  */
627 void
628 proc_filemode(int fd)
629 {
630 	struct entityq	 q;
631 	struct msgbuf	 msgq;
632 	struct pollfd	 pfd;
633 	struct entity	*entp;
634 	struct ibuf	*b, *inbuf = NULL;
635 
636 	/* Only allow access to the cache directory. */
637 	if (unveil(".", "r") == -1)
638 		err(1, "unveil cachedir");
639 	if (pledge("stdio rpath", NULL) == -1)
640 		err(1, "pledge");
641 
642 	ERR_load_crypto_strings();
643 	OpenSSL_add_all_ciphers();
644 	OpenSSL_add_all_digests();
645 	x509_init_oid();
646 
647 	if ((ctx = X509_STORE_CTX_new()) == NULL)
648 		cryptoerrx("X509_STORE_CTX_new");
649 	TAILQ_INIT(&q);
650 
651 	msgbuf_init(&msgq);
652 	msgq.fd = fd;
653 
654 	pfd.fd = fd;
655 
656 	for (;;) {
657 		pfd.events = POLLIN;
658 		if (msgq.queued)
659 			pfd.events |= POLLOUT;
660 
661 		if (poll(&pfd, 1, INFTIM) == -1) {
662 			if (errno == EINTR)
663 				continue;
664 			err(1, "poll");
665 		}
666 		if ((pfd.revents & (POLLERR|POLLNVAL)))
667 			errx(1, "poll: bad descriptor");
668 
669 		/* If the parent closes, return immediately. */
670 
671 		if ((pfd.revents & POLLHUP))
672 			break;
673 
674 		if ((pfd.revents & POLLIN)) {
675 			b = io_buf_read(fd, &inbuf);
676 			if (b != NULL) {
677 				entp = calloc(1, sizeof(struct entity));
678 				if (entp == NULL)
679 					err(1, NULL);
680 				entity_read_req(b, entp);
681 				TAILQ_INSERT_TAIL(&q, entp, entries);
682 				ibuf_free(b);
683 			}
684 		}
685 
686 		if (pfd.revents & POLLOUT) {
687 			switch (msgbuf_write(&msgq)) {
688 			case 0:
689 				errx(1, "write: connection closed");
690 			case -1:
691 				err(1, "write");
692 			}
693 		}
694 
695 		parse_file(&q, &msgq);
696 	}
697 
698 	msgbuf_clear(&msgq);
699 	while ((entp = TAILQ_FIRST(&q)) != NULL) {
700 		TAILQ_REMOVE(&q, entp, entries);
701 		entity_free(entp);
702 	}
703 
704 	auth_tree_free(&auths);
705 	crl_tree_free(&crlt);
706 
707 	X509_STORE_CTX_free(ctx);
708 	ibuf_free(inbuf);
709 
710 	exit(0);
711 }
712