xref: /openbsd-src/usr.sbin/rpki-client/validate.c (revision c1a45aed656e7d5627c30c92421893a76f370ccb)
1 /*	$OpenBSD: validate.c,v 1.31 2022/04/21 09:53:07 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 <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 
33 extern 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  */
40 static int
41 valid_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 	if (a->cert->asz) {
50 		c = as_check_covered(min, max, a->cert->as, a->cert->asz);
51 		if (c > 0)
52 			return 1;
53 		else if (c < 0)
54 			return 0;
55 	}
56 
57 	/* If it doesn't, walk up the chain. */
58 	return valid_as(a->parent, min, max);
59 }
60 
61 /*
62  * Walk up the chain of certificates (really just the last one, but in
63  * the case of inheritance, the ones before) making sure that our IP
64  * prefix is covered in the first non-inheriting specification.
65  * Returns 1 if covered or 0 if not.
66  */
67 static int
68 valid_ip(struct auth *a, enum afi afi,
69     const unsigned char *min, const unsigned char *max)
70 {
71 	int	 c;
72 
73 	if (a == NULL)
74 		return 0;
75 
76 	/* Does this certificate cover our IP prefix? */
77 	c = ip_addr_check_covered(afi, min, max, a->cert->ips, a->cert->ipsz);
78 	if (c > 0)
79 		return 1;
80 	else if (c < 0)
81 		return 0;
82 
83 	/* If it doesn't, walk up the chain. */
84 	return valid_ip(a->parent, afi, min, max);
85 }
86 
87 /*
88  * Make sure that the SKI doesn't already exist and return the parent by
89  * its AKI.
90  * Returns the parent auth or NULL on failure.
91  */
92 struct auth *
93 valid_ski_aki(const char *fn, struct auth_tree *auths,
94     const char *ski, const char *aki)
95 {
96 	struct auth *a;
97 
98 	if (auth_find(auths, ski) != NULL) {
99 		warnx("%s: RFC 6487: duplicate SKI", fn);
100 		return NULL;
101 	}
102 
103 	a = auth_find(auths, aki);
104 	if (a == NULL)
105 		warnx("%s: RFC 6487: unknown AKI", fn);
106 
107 	return a;
108 }
109 
110 /*
111  * Authenticate a trust anchor by making sure its resources are not
112  * inheriting and that the SKI is unique.
113  * Returns 1 if valid, 0 otherwise.
114  */
115 int
116 valid_ta(const char *fn, struct auth_tree *auths, const struct cert *cert)
117 {
118 	size_t	 i;
119 
120 	/* AS and IP resources must not inherit. */
121 	if (cert->asz && cert->as[0].type == CERT_AS_INHERIT) {
122 		warnx("%s: RFC 6487 (trust anchor): "
123 		    "inheriting AS resources", fn);
124 		return 0;
125 	}
126 	for (i = 0; i < cert->ipsz; i++)
127 		if (cert->ips[i].type == CERT_IP_INHERIT) {
128 			warnx("%s: RFC 6487 (trust anchor): "
129 			    "inheriting IP resources", fn);
130 			return 0;
131 		}
132 
133 	/* SKI must not be a dupe. */
134 	if (auth_find(auths, cert->ski) != NULL) {
135 		warnx("%s: RFC 6487: duplicate SKI", fn);
136 		return 0;
137 	}
138 
139 	return 1;
140 }
141 
142 /*
143  * Validate a non-TA certificate: make sure its IP and AS resources are
144  * fully covered by those in the authority key (which must exist).
145  * Returns 1 if valid, 0 otherwise.
146  */
147 int
148 valid_cert(const char *fn, struct auth *a, const struct cert *cert)
149 {
150 	size_t		 i;
151 	uint32_t	 min, max;
152 	char		 buf1[64], buf2[64];
153 
154 	for (i = 0; i < cert->asz; i++) {
155 		if (cert->as[i].type == CERT_AS_INHERIT) {
156 			if (cert->purpose == CERT_PURPOSE_BGPSEC_ROUTER)
157 				return 0; /* BGPsec doesn't permit inheriting */
158 			continue;
159 		}
160 		min = cert->as[i].type == CERT_AS_ID ?
161 		    cert->as[i].id : cert->as[i].range.min;
162 		max = cert->as[i].type == CERT_AS_ID ?
163 		    cert->as[i].id : cert->as[i].range.max;
164 		if (valid_as(a, min, max))
165 			continue;
166 		warnx("%s: RFC 6487: uncovered AS: "
167 		    "%u--%u", fn, min, max);
168 		return 0;
169 	}
170 
171 	for (i = 0; i < cert->ipsz; i++) {
172 		if (valid_ip(a, cert->ips[i].afi, cert->ips[i].min,
173 		    cert->ips[i].max))
174 			continue;
175 		switch (cert->ips[i].type) {
176 		case CERT_IP_RANGE:
177 			ip_addr_print(&cert->ips[i].range.min,
178 			    cert->ips[i].afi, buf1, sizeof(buf1));
179 			ip_addr_print(&cert->ips[i].range.max,
180 			    cert->ips[i].afi, buf2, sizeof(buf2));
181 			warnx("%s: RFC 6487: uncovered IP: "
182 			    "%s--%s", fn, buf1, buf2);
183 			break;
184 		case CERT_IP_ADDR:
185 			ip_addr_print(&cert->ips[i].ip,
186 			    cert->ips[i].afi, buf1, sizeof(buf1));
187 			warnx("%s: RFC 6487: uncovered IP: "
188 			    "%s", fn, buf1);
189 			break;
190 		case CERT_IP_INHERIT:
191 			warnx("%s: RFC 6487: uncovered IP: "
192 			    "(inherit)", fn);
193 			break;
194 		}
195 		return 0;
196 	}
197 
198 	return 1;
199 }
200 
201 /*
202  * Validate our ROA: check that the prefixes (ipAddrBlocks) are contained.
203  * Returns 1 if valid, 0 otherwise.
204  */
205 int
206 valid_roa(const char *fn, struct auth *a, struct roa *roa)
207 {
208 	size_t	 i;
209 	char	 buf[64];
210 
211 	for (i = 0; i < roa->ipsz; i++) {
212 		if (valid_ip(a, roa->ips[i].afi, roa->ips[i].min,
213 		    roa->ips[i].max))
214 			continue;
215 		ip_addr_print(&roa->ips[i].addr,
216 		    roa->ips[i].afi, buf, sizeof(buf));
217 		warnx("%s: RFC 6482: uncovered IP: "
218 		    "%s", fn, buf);
219 		return 0;
220 	}
221 
222 	return 1;
223 }
224 
225 /*
226  * Validate a file by verifying the SHA256 hash of that file.
227  * The file to check is passed as a file descriptor.
228  * Returns 1 if hash matched, 0 otherwise. Closes fd when done.
229  */
230 int
231 valid_filehash(int fd, const char *hash, size_t hlen)
232 {
233 	SHA256_CTX ctx;
234 	char	filehash[SHA256_DIGEST_LENGTH];
235 	char	buffer[8192];
236 	ssize_t	nr;
237 
238 	if (hlen != sizeof(filehash))
239 		errx(1, "bad hash size");
240 
241 	if (fd == -1)
242 		return 0;
243 
244 	SHA256_Init(&ctx);
245 	while ((nr = read(fd, buffer, sizeof(buffer))) > 0)
246 		SHA256_Update(&ctx, buffer, nr);
247 	close(fd);
248 	SHA256_Final(filehash, &ctx);
249 
250 	if (memcmp(hash, filehash, sizeof(filehash)) != 0)
251 		return 0;
252 	return 1;
253 }
254 
255 /*
256  * Same as above but with a buffer instead of a fd.
257  */
258 int
259 valid_hash(unsigned char *buf, size_t len, const char *hash, size_t hlen)
260 {
261 	char	filehash[SHA256_DIGEST_LENGTH];
262 
263 	if (hlen != sizeof(filehash))
264 		errx(1, "bad hash size");
265 
266 	if (buf == NULL || len == 0)
267 		return 0;
268 
269 	if (!EVP_Digest(buf, len, filehash, NULL, EVP_sha256(), NULL))
270 		errx(1, "EVP_Digest failed");
271 
272 	if (memcmp(hash, filehash, sizeof(filehash)) != 0)
273 		return 0;
274 	return 1;
275 }
276 
277 /*
278  * Validate a URI to make sure it is pure ASCII and does not point backwards
279  * or doing some other silly tricks. To enforce the protocol pass either
280  * https:// or rsync:// as proto, if NULL is passed no protocol is enforced.
281  * Returns 1 if valid, 0 otherwise.
282  */
283 int
284 valid_uri(const char *uri, size_t usz, const char *proto)
285 {
286 	size_t s;
287 
288 	if (usz > MAX_URI_LENGTH)
289 		return 0;
290 
291 	for (s = 0; s < usz; s++)
292 		if (!isalnum((unsigned char)uri[s]) &&
293 		    !ispunct((unsigned char)uri[s]))
294 			return 0;
295 
296 	if (proto != NULL) {
297 		s = strlen(proto);
298 		if (strncasecmp(uri, proto, s) != 0)
299 			return 0;
300 	}
301 
302 	/* do not allow files or directories to start with a '.' */
303 	if (strstr(uri, "/.") != NULL)
304 		return 0;
305 
306 	return 1;
307 }
308 
309 /*
310  * Validate that a URI has the same host as the URI passed in proto.
311  * Returns 1 if valid, 0 otherwise.
312  */
313 int
314 valid_origin(const char *uri, const char *proto)
315 {
316 	const char *to;
317 
318 	/* extract end of host from proto URI */
319 	to = strstr(proto, "://");
320 	if (to == NULL)
321 		return 0;
322 	to += strlen("://");
323 	if ((to = strchr(to, '/')) == NULL)
324 		return 0;
325 
326 	/* compare hosts including the / for the start of the path section */
327 	if (strncasecmp(uri, proto, to - proto + 1) != 0)
328 		return 0;
329 
330 	return 1;
331 }
332 
333 /*
334  * Callback for X509_verify_cert() to handle critical extensions in old
335  * LibreSSL libraries or OpenSSL libs without RFC3779 support.
336  */
337 static int
338 verify_cb(int ok, X509_STORE_CTX *store_ctx)
339 {
340 	X509				*cert;
341 	const STACK_OF(X509_EXTENSION)	*exts;
342 	X509_EXTENSION			*ext;
343 	ASN1_OBJECT			*obj;
344 	char				*file;
345 	int				 depth, error, i, nid;
346 
347 	error = X509_STORE_CTX_get_error(store_ctx);
348 	depth = X509_STORE_CTX_get_error_depth(store_ctx);
349 
350 	if (error != X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION)
351 		return ok;
352 
353 	if ((file = X509_STORE_CTX_get_app_data(store_ctx)) == NULL)
354 		cryptoerrx("X509_STORE_CTX_get_app_data");
355 
356 	if ((cert = X509_STORE_CTX_get_current_cert(store_ctx)) == NULL) {
357 		warnx("%s: got no current cert", file);
358 		return 0;
359 	}
360 	if ((exts = X509_get0_extensions(cert)) == NULL) {
361 		warnx("%s: got no cert extensions", file);
362 		return 0;
363 	}
364 
365 	for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) {
366 		ext = sk_X509_EXTENSION_value(exts, i);
367 
368 		/* skip over non-critical and known extensions */
369 		if (!X509_EXTENSION_get_critical(ext))
370 			continue;
371 		if (X509_supported_extension(ext))
372 			continue;
373 
374 		if ((obj = X509_EXTENSION_get_object(ext)) == NULL) {
375 			warnx("%s: got no extension object", file);
376 			return 0;
377 		}
378 
379 		nid = OBJ_obj2nid(obj);
380 		switch (nid) {
381 		case NID_sbgp_ipAddrBlock:
382 		case NID_sbgp_autonomousSysNum:
383 			continue;
384 		default:
385 			warnx("%s: depth %d: unknown extension: nid %d",
386 			    file, depth, nid);
387 			return 0;
388 		}
389 	}
390 
391 	return 1;
392 }
393 
394 /*
395  * Walk the certificate tree to the root and build a certificate
396  * chain from cert->x509. All certs in the tree are validated and
397  * can be loaded as trusted stack into the validator.
398  */
399 static void
400 build_chain(const struct auth *a, STACK_OF(X509) **chain)
401 {
402 	*chain = NULL;
403 
404 	if (a == NULL)
405 		return;
406 
407 	if ((*chain = sk_X509_new_null()) == NULL)
408 		err(1, "sk_X509_new_null");
409 	for (; a != NULL; a = a->parent) {
410 		assert(a->cert->x509 != NULL);
411 		if (!sk_X509_push(*chain, a->cert->x509))
412 			errx(1, "sk_X509_push");
413 	}
414 }
415 
416 /*
417  * Add the CRL based on the certs SKI value.
418  * No need to insert any other CRL since those were already checked.
419  */
420 static void
421 build_crls(const struct crl *crl, STACK_OF(X509_CRL) **crls)
422 {
423 	*crls = NULL;
424 
425 	if (crl == NULL)
426 		return;
427 	if ((*crls = sk_X509_CRL_new_null()) == NULL)
428 		errx(1, "sk_X509_CRL_new_null");
429 	if (!sk_X509_CRL_push(*crls, crl->x509_crl))
430 		err(1, "sk_X509_CRL_push");
431 }
432 
433 /*
434  * Validate the X509 certificate.  If crl is NULL don't check CRL.
435  * Returns 1 for valid certificates, returns 0 if there is a verify error
436  */
437 int
438 valid_x509(char *file, X509_STORE_CTX *store_ctx, X509 *x509, struct auth *a,
439     struct crl *crl, int nowarn)
440 {
441 	X509_VERIFY_PARAM	*params;
442 	ASN1_OBJECT		*cp_oid;
443 	STACK_OF(X509)		*chain;
444 	STACK_OF(X509_CRL)	*crls = NULL;
445 	unsigned long		 flags;
446 	int			 c;
447 
448 	build_chain(a, &chain);
449 	build_crls(crl, &crls);
450 
451 	assert(store_ctx != NULL);
452 	assert(x509 != NULL);
453 	if (!X509_STORE_CTX_init(store_ctx, NULL, x509, NULL))
454 		cryptoerrx("X509_STORE_CTX_init");
455 
456 	if ((params = X509_STORE_CTX_get0_param(store_ctx)) == NULL)
457 		cryptoerrx("X509_STORE_CTX_get0_param");
458 	if ((cp_oid = OBJ_dup(certpol_oid)) == NULL)
459 		cryptoerrx("OBJ_dup");
460 	if (!X509_VERIFY_PARAM_add0_policy(params, cp_oid))
461 		cryptoerrx("X509_VERIFY_PARAM_add0_policy");
462 
463 	X509_STORE_CTX_set_verify_cb(store_ctx, verify_cb);
464 	if (!X509_STORE_CTX_set_app_data(store_ctx, file))
465 		cryptoerrx("X509_STORE_CTX_set_app_data");
466 	flags = X509_V_FLAG_CRL_CHECK;
467 	flags |= X509_V_FLAG_EXPLICIT_POLICY;
468 	flags |= X509_V_FLAG_INHIBIT_MAP;
469 	X509_STORE_CTX_set_flags(store_ctx, flags);
470 	X509_STORE_CTX_set_depth(store_ctx, MAX_CERT_DEPTH);
471 	X509_STORE_CTX_set0_trusted_stack(store_ctx, chain);
472 	X509_STORE_CTX_set0_crls(store_ctx, crls);
473 
474 	if (X509_verify_cert(store_ctx) <= 0) {
475 		c = X509_STORE_CTX_get_error(store_ctx);
476 		if (!nowarn || verbose > 1)
477 			warnx("%s: %s", file, X509_verify_cert_error_string(c));
478 		X509_STORE_CTX_cleanup(store_ctx);
479 		sk_X509_free(chain);
480 		sk_X509_CRL_free(crls);
481 		return 0;
482 	}
483 
484 	X509_STORE_CTX_cleanup(store_ctx);
485 	sk_X509_free(chain);
486 	sk_X509_CRL_free(crls);
487 	return 1;
488 }
489