xref: /openbsd-src/usr.sbin/rpki-client/validate.c (revision 3374c67d44f9b75b98444cbf63020f777792342e)
1 /*	$OpenBSD: validate.c,v 1.52 2023/01/04 14:22:43 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 <arpa/inet.h>
19 #include <assert.h>
20 #include <ctype.h>
21 #include <err.h>
22 #include <fcntl.h>
23 #include <inttypes.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 
28 #include "extern.h"
29 
30 extern ASN1_OBJECT	*certpol_oid;
31 
32 /*
33  * Walk up the chain of certificates trying to match our AS number to
34  * one of the allocations in that chain.
35  * Returns 1 if covered or 0 if not.
36  */
37 static int
38 valid_as(struct auth *a, uint32_t min, uint32_t max)
39 {
40 	int	 c;
41 
42 	if (a == NULL)
43 		return 0;
44 
45 	/* Does this certificate cover our AS number? */
46 	c = as_check_covered(min, max, a->cert->as, a->cert->asz);
47 	if (c > 0)
48 		return 1;
49 	else if (c < 0)
50 		return 0;
51 
52 	/* If it inherits, walk up the chain. */
53 	return valid_as(a->parent, min, max);
54 }
55 
56 /*
57  * Walk up the chain of certificates (really just the last one, but in
58  * the case of inheritance, the ones before) making sure that our IP
59  * prefix is covered in the first non-inheriting specification.
60  * Returns 1 if covered or 0 if not.
61  */
62 static int
63 valid_ip(struct auth *a, enum afi afi,
64     const unsigned char *min, const unsigned char *max)
65 {
66 	int	 c;
67 
68 	if (a == NULL)
69 		return 0;
70 
71 	/* Does this certificate cover our IP prefix? */
72 	c = ip_addr_check_covered(afi, min, max, a->cert->ips, a->cert->ipsz);
73 	if (c > 0)
74 		return 1;
75 	else if (c < 0)
76 		return 0;
77 
78 	/* If it inherits, walk up the chain. */
79 	return valid_ip(a->parent, afi, min, max);
80 }
81 
82 /*
83  * Make sure that the SKI doesn't already exist and return the parent by
84  * its AKI.
85  * Returns the parent auth or NULL on failure.
86  */
87 struct auth *
88 valid_ski_aki(const char *fn, struct auth_tree *auths,
89     const char *ski, const char *aki)
90 {
91 	struct auth *a;
92 
93 	if (auth_find(auths, ski) != NULL) {
94 		warnx("%s: RFC 6487: duplicate SKI", fn);
95 		return NULL;
96 	}
97 
98 	a = auth_find(auths, aki);
99 	if (a == NULL)
100 		warnx("%s: RFC 6487: unknown AKI", fn);
101 
102 	return a;
103 }
104 
105 /*
106  * Validate a trust anchor by making sure that the SKI is unique.
107  * Returns 1 if valid, 0 otherwise.
108  */
109 int
110 valid_ta(const char *fn, struct auth_tree *auths, const struct cert *cert)
111 {
112 	/* SKI must not be a dupe. */
113 	if (auth_find(auths, cert->ski) != NULL) {
114 		warnx("%s: RFC 6487: duplicate SKI", fn);
115 		return 0;
116 	}
117 
118 	return 1;
119 }
120 
121 /*
122  * Validate a non-TA certificate: make sure its IP and AS resources are
123  * fully covered by those in the authority key (which must exist).
124  * Returns 1 if valid, 0 otherwise.
125  */
126 int
127 valid_cert(const char *fn, struct auth *a, const struct cert *cert)
128 {
129 	size_t		 i;
130 	uint32_t	 min, max;
131 	char		 buf1[64], buf2[64];
132 
133 	for (i = 0; i < cert->asz; i++) {
134 		if (cert->as[i].type == CERT_AS_INHERIT)
135 			continue;
136 		min = cert->as[i].type == CERT_AS_ID ?
137 		    cert->as[i].id : cert->as[i].range.min;
138 		max = cert->as[i].type == CERT_AS_ID ?
139 		    cert->as[i].id : cert->as[i].range.max;
140 		if (valid_as(a, min, max))
141 			continue;
142 		warnx("%s: RFC 6487: uncovered AS: "
143 		    "%u--%u", fn, min, max);
144 		return 0;
145 	}
146 
147 	for (i = 0; i < cert->ipsz; i++) {
148 		if (valid_ip(a, cert->ips[i].afi, cert->ips[i].min,
149 		    cert->ips[i].max))
150 			continue;
151 		switch (cert->ips[i].type) {
152 		case CERT_IP_RANGE:
153 			ip_addr_print(&cert->ips[i].range.min,
154 			    cert->ips[i].afi, buf1, sizeof(buf1));
155 			ip_addr_print(&cert->ips[i].range.max,
156 			    cert->ips[i].afi, buf2, sizeof(buf2));
157 			warnx("%s: RFC 6487: uncovered IP: "
158 			    "%s--%s", fn, buf1, buf2);
159 			break;
160 		case CERT_IP_ADDR:
161 			ip_addr_print(&cert->ips[i].ip,
162 			    cert->ips[i].afi, buf1, sizeof(buf1));
163 			warnx("%s: RFC 6487: uncovered IP: "
164 			    "%s", fn, buf1);
165 			break;
166 		case CERT_IP_INHERIT:
167 			warnx("%s: RFC 6487: uncovered IP: "
168 			    "(inherit)", fn);
169 			break;
170 		}
171 		return 0;
172 	}
173 
174 	return 1;
175 }
176 
177 /*
178  * Validate our ROA: check that the prefixes (ipAddrBlocks) are contained.
179  * Returns 1 if valid, 0 otherwise.
180  */
181 int
182 valid_roa(const char *fn, struct cert *cert, struct roa *roa)
183 {
184 	size_t	 i;
185 	char	 buf[64];
186 
187 	for (i = 0; i < roa->ipsz; i++) {
188 		if (ip_addr_check_covered(roa->ips[i].afi, roa->ips[i].min,
189 		    roa->ips[i].max, cert->ips, cert->ipsz) > 0)
190 			continue;
191 
192 		ip_addr_print(&roa->ips[i].addr, roa->ips[i].afi, buf,
193 		    sizeof(buf));
194 		warnx("%s: RFC 6482: uncovered IP: %s", fn, buf);
195 		return 0;
196 	}
197 
198 	return 1;
199 }
200 
201 /*
202  * Validate a file by verifying the SHA256 hash of that file.
203  * The file to check is passed as a file descriptor.
204  * Returns 1 if hash matched, 0 otherwise. Closes fd when done.
205  */
206 int
207 valid_filehash(int fd, const char *hash, size_t hlen)
208 {
209 	SHA256_CTX	ctx;
210 	char		filehash[SHA256_DIGEST_LENGTH];
211 	char		buffer[8192];
212 	ssize_t		nr;
213 
214 	if (hlen != sizeof(filehash))
215 		errx(1, "bad hash size");
216 
217 	if (fd == -1)
218 		return 0;
219 
220 	SHA256_Init(&ctx);
221 	while ((nr = read(fd, buffer, sizeof(buffer))) > 0)
222 		SHA256_Update(&ctx, buffer, nr);
223 	close(fd);
224 	SHA256_Final(filehash, &ctx);
225 
226 	if (memcmp(hash, filehash, sizeof(filehash)) != 0)
227 		return 0;
228 	return 1;
229 }
230 
231 /*
232  * Same as above but with a buffer instead of a fd.
233  */
234 int
235 valid_hash(unsigned char *buf, size_t len, const char *hash, size_t hlen)
236 {
237 	char	filehash[SHA256_DIGEST_LENGTH];
238 
239 	if (hlen != sizeof(filehash))
240 		errx(1, "bad hash size");
241 
242 	if (buf == NULL || len == 0)
243 		return 0;
244 
245 	if (!EVP_Digest(buf, len, filehash, NULL, EVP_sha256(), NULL))
246 		errx(1, "EVP_Digest failed");
247 
248 	if (memcmp(hash, filehash, sizeof(filehash)) != 0)
249 		return 0;
250 	return 1;
251 }
252 
253 /*
254  * Validate that a filename only contains characters from the POSIX portable
255  * filename character set [A-Za-z0-9._-], see IEEE Std 1003.1-2013, 3.278.
256  */
257 int
258 valid_filename(const char *fn, size_t len)
259 {
260 	const unsigned char *c;
261 	size_t i;
262 
263 	for (c = fn, i = 0; i < len; i++, c++)
264 		if (!isalnum(*c) && *c != '-' && *c != '_' && *c != '.')
265 			return 0;
266 	return 1;
267 }
268 
269 /*
270  * Validate a URI to make sure it is pure ASCII and does not point backwards
271  * or doing some other silly tricks. To enforce the protocol pass either
272  * https:// or rsync:// as proto, if NULL is passed no protocol is enforced.
273  * Returns 1 if valid, 0 otherwise.
274  */
275 int
276 valid_uri(const char *uri, size_t usz, const char *proto)
277 {
278 	size_t s;
279 
280 	if (usz > MAX_URI_LENGTH)
281 		return 0;
282 
283 	for (s = 0; s < usz; s++)
284 		if (!isalnum((unsigned char)uri[s]) &&
285 		    !ispunct((unsigned char)uri[s]))
286 			return 0;
287 
288 	if (proto != NULL) {
289 		s = strlen(proto);
290 		if (s >= usz)
291 			return 0;
292 		if (strncasecmp(uri, proto, s) != 0)
293 			return 0;
294 	}
295 
296 	/* do not allow files or directories to start with a '.' */
297 	if (strstr(uri, "/.") != NULL)
298 		return 0;
299 
300 	return 1;
301 }
302 
303 /*
304  * Validate that a URI has the same host as the URI passed in proto.
305  * Returns 1 if valid, 0 otherwise.
306  */
307 int
308 valid_origin(const char *uri, const char *proto)
309 {
310 	const char *to;
311 
312 	/* extract end of host from proto URI */
313 	to = strstr(proto, "://");
314 	if (to == NULL)
315 		return 0;
316 	to += strlen("://");
317 	if ((to = strchr(to, '/')) == NULL)
318 		return 0;
319 
320 	/* compare hosts including the / for the start of the path section */
321 	if (strncasecmp(uri, proto, to - proto + 1) != 0)
322 		return 0;
323 
324 	return 1;
325 }
326 
327 /*
328  * Walk the certificate tree to the root and build a certificate
329  * chain from cert->x509. All certs in the tree are validated and
330  * can be loaded as trusted stack into the validator.
331  */
332 static void
333 build_chain(const struct auth *a, STACK_OF(X509) **chain)
334 {
335 	*chain = NULL;
336 
337 	if (a == NULL)
338 		return;
339 
340 	if ((*chain = sk_X509_new_null()) == NULL)
341 		err(1, "sk_X509_new_null");
342 	for (; a != NULL; a = a->parent) {
343 		assert(a->cert->x509 != NULL);
344 		if (!sk_X509_push(*chain, a->cert->x509))
345 			errx(1, "sk_X509_push");
346 	}
347 }
348 
349 /*
350  * Add the CRL based on the certs SKI value.
351  * No need to insert any other CRL since those were already checked.
352  */
353 static void
354 build_crls(const struct crl *crl, STACK_OF(X509_CRL) **crls)
355 {
356 	*crls = NULL;
357 
358 	if (crl == NULL)
359 		return;
360 	if ((*crls = sk_X509_CRL_new_null()) == NULL)
361 		errx(1, "sk_X509_CRL_new_null");
362 	if (!sk_X509_CRL_push(*crls, crl->x509_crl))
363 		err(1, "sk_X509_CRL_push");
364 }
365 
366 /*
367  * Validate the X509 certificate. Returns 1 for valid certificates,
368  * returns 0 if there is a verify error and sets *errstr to the error
369  * returned by X509_verify_cert_error_string().
370  */
371 int
372 valid_x509(char *file, X509_STORE_CTX *store_ctx, X509 *x509, struct auth *a,
373     struct crl *crl, const char **errstr)
374 {
375 	X509_VERIFY_PARAM	*params;
376 	ASN1_OBJECT		*cp_oid;
377 	STACK_OF(X509)		*chain;
378 	STACK_OF(X509_CRL)	*crls = NULL;
379 	unsigned long		 flags;
380 	int			 error;
381 
382 	*errstr = NULL;
383 	build_chain(a, &chain);
384 	build_crls(crl, &crls);
385 
386 	assert(store_ctx != NULL);
387 	assert(x509 != NULL);
388 	if (!X509_STORE_CTX_init(store_ctx, NULL, x509, NULL))
389 		cryptoerrx("X509_STORE_CTX_init");
390 
391 	if ((params = X509_STORE_CTX_get0_param(store_ctx)) == NULL)
392 		cryptoerrx("X509_STORE_CTX_get0_param");
393 	if ((cp_oid = OBJ_dup(certpol_oid)) == NULL)
394 		cryptoerrx("OBJ_dup");
395 	if (!X509_VERIFY_PARAM_add0_policy(params, cp_oid))
396 		cryptoerrx("X509_VERIFY_PARAM_add0_policy");
397 
398 	flags = X509_V_FLAG_CRL_CHECK;
399 	flags |= X509_V_FLAG_EXPLICIT_POLICY;
400 	flags |= X509_V_FLAG_INHIBIT_MAP;
401 	X509_STORE_CTX_set_flags(store_ctx, flags);
402 	X509_STORE_CTX_set_depth(store_ctx, MAX_CERT_DEPTH);
403 	X509_STORE_CTX_set0_trusted_stack(store_ctx, chain);
404 	X509_STORE_CTX_set0_crls(store_ctx, crls);
405 
406 	if (X509_verify_cert(store_ctx) <= 0) {
407 		error = X509_STORE_CTX_get_error(store_ctx);
408 		*errstr = X509_verify_cert_error_string(error);
409 		X509_STORE_CTX_cleanup(store_ctx);
410 		sk_X509_free(chain);
411 		sk_X509_CRL_free(crls);
412 		return 0;
413 	}
414 
415 	X509_STORE_CTX_cleanup(store_ctx);
416 	sk_X509_free(chain);
417 	sk_X509_CRL_free(crls);
418 	return 1;
419 }
420 
421 /*
422  * Validate our RSC: check that all items in the ResourceBlock are contained.
423  * Returns 1 if valid, 0 otherwise.
424  */
425 int
426 valid_rsc(const char *fn, struct cert *cert, struct rsc *rsc)
427 {
428 	size_t		i;
429 	uint32_t	min, max;
430 	char		buf1[64], buf2[64];
431 
432 	for (i = 0; i < rsc->asz; i++) {
433 		min = rsc->as[i].type == CERT_AS_RANGE ? rsc->as[i].range.min
434 		    : rsc->as[i].id;
435 		max = rsc->as[i].type == CERT_AS_RANGE ? rsc->as[i].range.max
436 		    : rsc->as[i].id;
437 
438 		if (as_check_covered(min, max, cert->as, cert->asz) > 0)
439 			continue;
440 
441 		switch (rsc->as[i].type) {
442 		case CERT_AS_ID:
443 			warnx("%s: RSC resourceBlock: uncovered AS Identifier: "
444 			    "%u", fn, rsc->as[i].id);
445 			break;
446 		case CERT_AS_RANGE:
447 			warnx("%s: RSC resourceBlock: uncovered AS Range: "
448 			    "%u--%u", fn, min, max);
449 			break;
450 		default:
451 			break;
452 		}
453 		return 0;
454 	}
455 
456 	for (i = 0; i < rsc->ipsz; i++) {
457 		if (ip_addr_check_covered(rsc->ips[i].afi, rsc->ips[i].min,
458 		    rsc->ips[i].max, cert->ips, cert->ipsz) > 0)
459 			continue;
460 
461 		switch (rsc->ips[i].type) {
462 		case CERT_IP_RANGE:
463 			ip_addr_print(&rsc->ips[i].range.min,
464 			    rsc->ips[i].afi, buf1, sizeof(buf1));
465 			ip_addr_print(&rsc->ips[i].range.max,
466 			    rsc->ips[i].afi, buf2, sizeof(buf2));
467 			warnx("%s: RSC ResourceBlock: uncovered IP Range: "
468 			    "%s--%s", fn, buf1, buf2);
469 			break;
470 		case CERT_IP_ADDR:
471 			ip_addr_print(&rsc->ips[i].ip,
472 			    rsc->ips[i].afi, buf1, sizeof(buf1));
473 			warnx("%s: RSC ResourceBlock: uncovered IP: "
474 			    "%s", fn, buf1);
475 			break;
476 		default:
477 			break;
478 		}
479 		return 0;
480 	}
481 
482 	return 1;
483 }
484 
485 int
486 valid_econtent_version(const char *fn, const ASN1_INTEGER *aint)
487 {
488 	long version;
489 
490 	if (aint == NULL)
491 		return 1;
492 
493 	if ((version = ASN1_INTEGER_get(aint)) < 0) {
494 		warnx("%s: ASN1_INTEGER_get failed", fn);
495 		return 0;
496 	}
497 
498 	switch (version) {
499 	case 0:
500 		warnx("%s: incorrect encoding for version 0", fn);
501 		return 0;
502 	default:
503 		warnx("%s: version %ld not supported (yet)", fn, version);
504 		return 0;
505 	}
506 }
507 
508 /*
509  * Validate the ASPA: check that the customerASID is contained.
510  * Returns 1 if valid, 0 otherwise.
511  */
512 int
513 valid_aspa(const char *fn, struct cert *cert, struct aspa *aspa)
514 {
515 
516 	if (as_check_covered(aspa->custasid, aspa->custasid,
517 	    cert->as, cert->asz) > 0)
518 		return 1;
519 
520 	warnx("%s: ASPA: uncovered Customer ASID: %u", fn, aspa->custasid);
521 
522 	return 0;
523 }
524 
525 /*
526  * Validate Geofeed prefixes: check that the prefixes are contained.
527  * Returns 1 if valid, 0 otherwise.
528  */
529 int
530 valid_geofeed(const char *fn, struct cert *cert, struct geofeed *g)
531 {
532 	size_t	 i;
533 	char	 buf[64];
534 
535 	for (i = 0; i < g->geoipsz; i++) {
536 		if (ip_addr_check_covered(g->geoips[i].ip->afi,
537 		    g->geoips[i].ip->min, g->geoips[i].ip->max, cert->ips,
538 		    cert->ipsz) > 0)
539 			continue;
540 
541 		ip_addr_print(&g->geoips[i].ip->ip, g->geoips[i].ip->afi, buf,
542 		    sizeof(buf));
543 		warnx("%s: Geofeed: uncovered IP: %s", fn, buf);
544 		return 0;
545 	}
546 
547 	return 1;
548 }
549 
550 /*
551  * Validate whether a given string is a valid UUID.
552  * Returns 1 if valid, 0 otherwise.
553  */
554 int
555 valid_uuid(const char *s)
556 {
557 	int n = 0;
558 
559 	while (1) {
560 		switch (n) {
561 		case 8:
562 		case 13:
563 		case 18:
564 		case 23:
565 			if (s[n] != '-')
566 				return 0;
567 			break;
568 #ifdef NOTYET	/* World is not yet ready to enfoce UUID version and variant */
569 		/* Check UUID is version 4 */
570 		case 14:
571 			if (s[n] != '4')
572 				return 0;
573 			break;
574 		/* Check UUID variant is 1 */
575 		case 19:
576 			if (s[n] != '8' && s[n] != '9' && s[n] != 'a' &&
577 			    s[n] != 'A' && s[n] != 'b' && s[n] != 'B')
578 				return 0;
579 			break;
580 #endif
581 		case 36:
582 			return s[n] == '\0';
583 		default:
584 			if (!isxdigit((unsigned char)s[n]))
585 				return 0;
586 			break;
587 		}
588 		n++;
589 	}
590 }
591 
592