xref: /openbsd-src/usr.sbin/rpki-client/validate.c (revision 46035553bfdd96e63c94e32da0210227ec2e3cf1)
1 /*	$OpenBSD: validate.c,v 1.11 2020/09/12 15:46:48 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 <err.h>
23 #include <inttypes.h>
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 
29 #include "extern.h"
30 
31 static void
32 tracewarn(const struct auth *a)
33 {
34 
35 	for (; a != NULL; a = a->parent)
36 		warnx(" ...inheriting from: %s", a->fn);
37 }
38 
39 /*
40  * Walk up the chain of certificates trying to match our AS number to
41  * one of the allocations in that chain.
42  * Returns 1 if covered or 0 if not.
43  */
44 static int
45 valid_as(struct auth *a, uint32_t min, uint32_t max)
46 {
47 	int	 c;
48 
49 	if (a == NULL)
50 		return 0;
51 
52 	/* Does this certificate cover our AS number? */
53 	if (a->cert->asz) {
54 		c = as_check_covered(min, max,
55 		    a->cert->as, a->cert->asz);
56 		if (c > 0)
57 			return 1;
58 		else if (c < 0)
59 			return 0;
60 	}
61 
62 	/* If it doesn't, walk up the chain. */
63 	return valid_as(a->parent, min, max);
64 }
65 
66 /*
67  * Walk up the chain of certificates (really just the last one, but in
68  * the case of inheritence, the ones before) making sure that our IP
69  * prefix is covered in the first non-inheriting specification.
70  * Returns 1 if covered or 0 if not.
71  */
72 static int
73 valid_ip(struct auth *a, enum afi afi,
74     const unsigned char *min, const unsigned char *max)
75 {
76 	int	 c;
77 
78 	if (a == NULL)
79 		return 0;
80 
81 	/* Does this certificate cover our IP prefix? */
82 	c = ip_addr_check_covered(afi, min, max,
83 	    a->cert->ips, a->cert->ipsz);
84 	if (c > 0)
85 		return 1;
86 	else if (c < 0)
87 		return 0;
88 
89 	/* If it doesn't, walk up the chain. */
90 	return valid_ip(a->parent, afi, min, max);
91 }
92 
93 /*
94  * Make sure that the SKI doesn't already exist and return the parent by
95  * its AKI.
96  * Returns the parent auth or NULL on failure.
97  */
98 struct auth *
99 valid_ski_aki(const char *fn, struct auth_tree *auths,
100     const char *ski, const char *aki)
101 {
102 	struct auth *a;
103 
104 	if (auth_find(auths, ski) != NULL) {
105 		warnx("%s: RFC 6487: duplicate SKI", fn);
106 		return NULL;
107 	}
108 
109 	a = auth_find(auths, aki);
110 	if (a == NULL)
111 		warnx("%s: RFC 6487: unknown AKI", fn);
112 
113 	return a;
114 }
115 
116 /*
117  * Authenticate a trust anchor by making sure its resources are not
118  * inheriting and that the SKI is unique.
119  * Returns 1 if valid, 0 otherwise.
120  */
121 int
122 valid_ta(const char *fn, struct auth_tree *auths, const struct cert *cert)
123 {
124 	size_t	 i;
125 
126 	/* AS and IP resources must not inherit. */
127 	if (cert->asz && cert->as[0].type == CERT_AS_INHERIT) {
128 		warnx("%s: RFC 6487 (trust anchor): "
129 		    "inheriting AS resources", fn);
130 		return 0;
131 	}
132 	for (i = 0; i < cert->ipsz; i++)
133 		if (cert->ips[i].type == CERT_IP_INHERIT) {
134 			warnx("%s: RFC 6487 (trust anchor): "
135 			    "inheriting IP resources", fn);
136 			return 0;
137 		}
138 
139 	/* SKI must not be a dupe. */
140 	if (auth_find(auths, cert->ski) != NULL) {
141 		warnx("%s: RFC 6487: duplicate SKI", fn);
142 		return 0;
143 	}
144 
145 	return 1;
146 }
147 
148 /*
149  * Validate a non-TA certificate: make sure its IP and AS resources are
150  * fully covered by those in the authority key (which must exist).
151  * Returns 1 if valid, 0 otherwise.
152  */
153 int
154 valid_cert(const char *fn, struct auth_tree *auths, const struct cert *cert)
155 {
156 	struct auth	*a;
157 	size_t		 i;
158 	uint32_t	 min, max;
159 	char		 buf1[64], buf2[64];
160 
161 	a = valid_ski_aki(fn, auths, cert->ski, cert->aki);
162 	if (a == NULL)
163 		return 0;
164 
165 	for (i = 0; i < cert->asz; i++) {
166 		if (cert->as[i].type == CERT_AS_INHERIT)
167 			continue;
168 		min = cert->as[i].type == CERT_AS_ID ?
169 		    cert->as[i].id : cert->as[i].range.min;
170 		max = cert->as[i].type == CERT_AS_ID ?
171 		    cert->as[i].id : cert->as[i].range.max;
172 		if (valid_as(a, min, max))
173 			continue;
174 		warnx("%s: RFC 6487: uncovered AS: "
175 		    "%u--%u", fn, min, max);
176 		tracewarn(a);
177 		return 0;
178 	}
179 
180 	for (i = 0; i < cert->ipsz; i++) {
181 		if (valid_ip(a, cert->ips[i].afi, cert->ips[i].min,
182 		    cert->ips[i].max))
183 			continue;
184 		switch (cert->ips[i].type) {
185 		case CERT_IP_RANGE:
186 			ip_addr_print(&cert->ips[i].range.min,
187 			    cert->ips[i].afi, buf1, sizeof(buf1));
188 			ip_addr_print(&cert->ips[i].range.max,
189 			    cert->ips[i].afi, buf2, sizeof(buf2));
190 			warnx("%s: RFC 6487: uncovered IP: "
191 			    "%s--%s", fn, buf1, buf2);
192 			break;
193 		case CERT_IP_ADDR:
194 			ip_addr_print(&cert->ips[i].ip,
195 			    cert->ips[i].afi, buf1, sizeof(buf1));
196 			warnx("%s: RFC 6487: uncovered IP: "
197 			    "%s", fn, buf1);
198 		case CERT_IP_INHERIT:
199 			warnx("%s: RFC 6487: uncovered IP: "
200 			    "(inherit)", fn);
201 			break;
202 		}
203 		tracewarn(a);
204 		return 0;
205 	}
206 
207 	return 1;
208 }
209 
210 /*
211  * Validate our ROA: check that the SKI is unique, the AKI exists, and
212  * the IP prefix is also contained.
213  * Returns 1 if valid, 0 otherwise.
214  */
215 int
216 valid_roa(const char *fn, struct auth_tree *auths, struct roa *roa)
217 {
218 	struct auth	*a;
219 	size_t	 i;
220 	char	 buf[64];
221 
222 	a = valid_ski_aki(fn, auths, roa->ski, roa->aki);
223 	if (a == NULL)
224 		return 0;
225 
226 	if ((roa->tal = strdup(a->tal)) == NULL)
227 		err(1, NULL);
228 
229 	for (i = 0; i < roa->ipsz; i++) {
230 		if (valid_ip(a, roa->ips[i].afi, roa->ips[i].min,
231 		    roa->ips[i].max))
232 			continue;
233 		ip_addr_print(&roa->ips[i].addr,
234 		    roa->ips[i].afi, buf, sizeof(buf));
235 		warnx("%s: RFC 6482: uncovered IP: "
236 		    "%s", fn, buf);
237 		tracewarn(a);
238 		return 0;
239 	}
240 
241 	return 1;
242 }
243