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