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