1 /* $OpenBSD: roa.c,v 1.78 2024/05/24 12:57:20 tb Exp $ */
2 /*
3 * Copyright (c) 2022 Theo Buehler <tb@openbsd.org>
4 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <assert.h>
20 #include <err.h>
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25
26 #include <openssl/asn1.h>
27 #include <openssl/asn1t.h>
28 #include <openssl/stack.h>
29 #include <openssl/safestack.h>
30 #include <openssl/x509.h>
31
32 #include "extern.h"
33
34 extern ASN1_OBJECT *roa_oid;
35
36 /*
37 * Types and templates for the ROA eContent, RFC 6482, section 3.
38 */
39
40 ASN1_ITEM_EXP ROAIPAddress_it;
41 ASN1_ITEM_EXP ROAIPAddressFamily_it;
42 ASN1_ITEM_EXP RouteOriginAttestation_it;
43
44 typedef struct {
45 ASN1_BIT_STRING *address;
46 ASN1_INTEGER *maxLength;
47 } ROAIPAddress;
48
49 DECLARE_STACK_OF(ROAIPAddress);
50
51 typedef struct {
52 ASN1_OCTET_STRING *addressFamily;
53 STACK_OF(ROAIPAddress) *addresses;
54 } ROAIPAddressFamily;
55
56 DECLARE_STACK_OF(ROAIPAddressFamily);
57
58 #ifndef DEFINE_STACK_OF
59 #define sk_ROAIPAddress_num(st) SKM_sk_num(ROAIPAddress, (st))
60 #define sk_ROAIPAddress_value(st, i) SKM_sk_value(ROAIPAddress, (st), (i))
61
62 #define sk_ROAIPAddressFamily_num(st) SKM_sk_num(ROAIPAddressFamily, (st))
63 #define sk_ROAIPAddressFamily_value(st, i) \
64 SKM_sk_value(ROAIPAddressFamily, (st), (i))
65 #endif
66
67 typedef struct {
68 ASN1_INTEGER *version;
69 ASN1_INTEGER *asid;
70 STACK_OF(ROAIPAddressFamily) *ipAddrBlocks;
71 } RouteOriginAttestation;
72
73 ASN1_SEQUENCE(ROAIPAddress) = {
74 ASN1_SIMPLE(ROAIPAddress, address, ASN1_BIT_STRING),
75 ASN1_OPT(ROAIPAddress, maxLength, ASN1_INTEGER),
76 } ASN1_SEQUENCE_END(ROAIPAddress);
77
78 ASN1_SEQUENCE(ROAIPAddressFamily) = {
79 ASN1_SIMPLE(ROAIPAddressFamily, addressFamily, ASN1_OCTET_STRING),
80 ASN1_SEQUENCE_OF(ROAIPAddressFamily, addresses, ROAIPAddress),
81 } ASN1_SEQUENCE_END(ROAIPAddressFamily);
82
83 ASN1_SEQUENCE(RouteOriginAttestation) = {
84 ASN1_EXP_OPT(RouteOriginAttestation, version, ASN1_INTEGER, 0),
85 ASN1_SIMPLE(RouteOriginAttestation, asid, ASN1_INTEGER),
86 ASN1_SEQUENCE_OF(RouteOriginAttestation, ipAddrBlocks,
87 ROAIPAddressFamily),
88 } ASN1_SEQUENCE_END(RouteOriginAttestation);
89
90 DECLARE_ASN1_FUNCTIONS(RouteOriginAttestation);
91 IMPLEMENT_ASN1_FUNCTIONS(RouteOriginAttestation);
92
93 /*
94 * Parses the eContent section of an ROA file, RFC 6482, section 3.
95 * Returns zero on failure, non-zero on success.
96 */
97 static int
roa_parse_econtent(const char * fn,struct roa * roa,const unsigned char * d,size_t dsz)98 roa_parse_econtent(const char *fn, struct roa *roa, const unsigned char *d,
99 size_t dsz)
100 {
101 const unsigned char *oder;
102 RouteOriginAttestation *roa_asn1;
103 const ROAIPAddressFamily *addrfam;
104 const STACK_OF(ROAIPAddress) *addrs;
105 int addrsz, ipv4_seen = 0, ipv6_seen = 0;
106 enum afi afi;
107 const ROAIPAddress *addr;
108 uint64_t maxlen;
109 struct ip_addr ipaddr;
110 struct roa_ip *res;
111 int ipaddrblocksz;
112 int i, j, rc = 0;
113
114 oder = d;
115 if ((roa_asn1 = d2i_RouteOriginAttestation(NULL, &d, dsz)) == NULL) {
116 warnx("%s: RFC 6482 section 3: failed to parse "
117 "RouteOriginAttestation", fn);
118 goto out;
119 }
120 if (d != oder + dsz) {
121 warnx("%s: %td bytes trailing garbage in eContent", fn,
122 oder + dsz - d);
123 goto out;
124 }
125
126 if (!valid_econtent_version(fn, roa_asn1->version, 0))
127 goto out;
128
129 if (!as_id_parse(roa_asn1->asid, &roa->asid)) {
130 warnx("%s: RFC 6482 section 3.2: asID: "
131 "malformed AS identifier", fn);
132 goto out;
133 }
134
135 ipaddrblocksz = sk_ROAIPAddressFamily_num(roa_asn1->ipAddrBlocks);
136 if (ipaddrblocksz != 1 && ipaddrblocksz != 2) {
137 warnx("%s: RFC 9582: unexpected number of ipAddrBlocks "
138 "(got %d, expected 1 or 2)", fn, ipaddrblocksz);
139 goto out;
140 }
141
142 for (i = 0; i < ipaddrblocksz; i++) {
143 addrfam = sk_ROAIPAddressFamily_value(roa_asn1->ipAddrBlocks,
144 i);
145 addrs = addrfam->addresses;
146 addrsz = sk_ROAIPAddress_num(addrs);
147
148 if (!ip_addr_afi_parse(fn, addrfam->addressFamily, &afi)) {
149 warnx("%s: RFC 6482 section 3.3: addressFamily: "
150 "invalid", fn);
151 goto out;
152 }
153
154 switch (afi) {
155 case AFI_IPV4:
156 if (ipv4_seen++ > 0) {
157 warnx("%s: RFC 9582 section 4.3.2: "
158 "IPv4 appears twice", fn);
159 goto out;
160 }
161 break;
162 case AFI_IPV6:
163 if (ipv6_seen++ > 0) {
164 warnx("%s: RFC 9582 section 4.3.2: "
165 "IPv6 appears twice", fn);
166 goto out;
167 }
168 break;
169 }
170
171 if (addrsz == 0) {
172 warnx("%s: RFC 9582, section 4.3.2: "
173 "empty ROAIPAddressFamily", fn);
174 goto out;
175 }
176
177 if (roa->ipsz + addrsz >= MAX_IP_SIZE) {
178 warnx("%s: too many ROAIPAddress entries: limit %d",
179 fn, MAX_IP_SIZE);
180 goto out;
181 }
182 roa->ips = recallocarray(roa->ips, roa->ipsz,
183 roa->ipsz + addrsz, sizeof(struct roa_ip));
184 if (roa->ips == NULL)
185 err(1, NULL);
186
187 for (j = 0; j < addrsz; j++) {
188 addr = sk_ROAIPAddress_value(addrs, j);
189
190 if (!ip_addr_parse(addr->address, afi, fn, &ipaddr)) {
191 warnx("%s: RFC 6482 section 3.3: address: "
192 "invalid IP address", fn);
193 goto out;
194 }
195 maxlen = ipaddr.prefixlen;
196
197 if (addr->maxLength != NULL) {
198 if (!ASN1_INTEGER_get_uint64(&maxlen,
199 addr->maxLength)) {
200 warnx("%s: RFC 6482 section 3.2: "
201 "ASN1_INTEGER_get_uint64 failed",
202 fn);
203 goto out;
204 }
205 if (ipaddr.prefixlen > maxlen) {
206 warnx("%s: prefixlen (%d) larger than "
207 "maxLength (%llu)", fn,
208 ipaddr.prefixlen,
209 (unsigned long long)maxlen);
210 goto out;
211 }
212 if (maxlen > ((afi == AFI_IPV4) ? 32 : 128)) {
213 warnx("%s: maxLength (%llu) too large",
214 fn, (unsigned long long)maxlen);
215 goto out;
216 }
217 }
218
219 res = &roa->ips[roa->ipsz++];
220 res->addr = ipaddr;
221 res->afi = afi;
222 res->maxlength = maxlen;
223 ip_roa_compose_ranges(res);
224 }
225 }
226
227 rc = 1;
228 out:
229 RouteOriginAttestation_free(roa_asn1);
230 return rc;
231 }
232
233 /*
234 * Parse a full RFC 6482 file.
235 * Returns the ROA or NULL if the document was malformed.
236 */
237 struct roa *
roa_parse(X509 ** x509,const char * fn,int talid,const unsigned char * der,size_t len)238 roa_parse(X509 **x509, const char *fn, int talid, const unsigned char *der,
239 size_t len)
240 {
241 struct roa *roa;
242 size_t cmsz;
243 unsigned char *cms;
244 struct cert *cert = NULL;
245 time_t signtime = 0;
246 int rc = 0;
247
248 cms = cms_parse_validate(x509, fn, der, len, roa_oid, &cmsz, &signtime);
249 if (cms == NULL)
250 return NULL;
251
252 if ((roa = calloc(1, sizeof(struct roa))) == NULL)
253 err(1, NULL);
254 roa->signtime = signtime;
255
256 if (!x509_get_aia(*x509, fn, &roa->aia))
257 goto out;
258 if (!x509_get_aki(*x509, fn, &roa->aki))
259 goto out;
260 if (!x509_get_sia(*x509, fn, &roa->sia))
261 goto out;
262 if (!x509_get_ski(*x509, fn, &roa->ski))
263 goto out;
264 if (roa->aia == NULL || roa->aki == NULL || roa->sia == NULL ||
265 roa->ski == NULL) {
266 warnx("%s: RFC 6487 section 4.8: "
267 "missing AIA, AKI, SIA, or SKI X509 extension", fn);
268 goto out;
269 }
270
271 if (!x509_get_notbefore(*x509, fn, &roa->notbefore))
272 goto out;
273 if (!x509_get_notafter(*x509, fn, &roa->notafter))
274 goto out;
275
276 if (!roa_parse_econtent(fn, roa, cms, cmsz))
277 goto out;
278
279 if (x509_any_inherits(*x509)) {
280 warnx("%s: inherit elements not allowed in EE cert", fn);
281 goto out;
282 }
283
284 if ((cert = cert_parse_ee_cert(fn, talid, *x509)) == NULL)
285 goto out;
286
287 if (cert->asz > 0) {
288 warnx("%s: superfluous AS Resources extension present", fn);
289 goto out;
290 }
291
292 /*
293 * If the ROA isn't valid, we accept it anyway and depend upon
294 * the code around roa_read() to check the "valid" field itself.
295 */
296 roa->valid = valid_roa(fn, cert, roa);
297
298 rc = 1;
299 out:
300 if (rc == 0) {
301 roa_free(roa);
302 roa = NULL;
303 X509_free(*x509);
304 *x509 = NULL;
305 }
306 cert_free(cert);
307 free(cms);
308 return roa;
309 }
310
311 /*
312 * Free an ROA pointer.
313 * Safe to call with NULL.
314 */
315 void
roa_free(struct roa * p)316 roa_free(struct roa *p)
317 {
318
319 if (p == NULL)
320 return;
321 free(p->aia);
322 free(p->aki);
323 free(p->sia);
324 free(p->ski);
325 free(p->ips);
326 free(p);
327 }
328
329 /*
330 * Serialise parsed ROA content.
331 * See roa_read() for reader.
332 */
333 void
roa_buffer(struct ibuf * b,const struct roa * p)334 roa_buffer(struct ibuf *b, const struct roa *p)
335 {
336 io_simple_buffer(b, &p->valid, sizeof(p->valid));
337 io_simple_buffer(b, &p->asid, sizeof(p->asid));
338 io_simple_buffer(b, &p->talid, sizeof(p->talid));
339 io_simple_buffer(b, &p->ipsz, sizeof(p->ipsz));
340 io_simple_buffer(b, &p->expires, sizeof(p->expires));
341
342 io_simple_buffer(b, p->ips, p->ipsz * sizeof(p->ips[0]));
343
344 io_str_buffer(b, p->aia);
345 io_str_buffer(b, p->aki);
346 io_str_buffer(b, p->ski);
347 }
348
349 /*
350 * Read parsed ROA content from descriptor.
351 * See roa_buffer() for writer.
352 * Result must be passed to roa_free().
353 */
354 struct roa *
roa_read(struct ibuf * b)355 roa_read(struct ibuf *b)
356 {
357 struct roa *p;
358
359 if ((p = calloc(1, sizeof(struct roa))) == NULL)
360 err(1, NULL);
361
362 io_read_buf(b, &p->valid, sizeof(p->valid));
363 io_read_buf(b, &p->asid, sizeof(p->asid));
364 io_read_buf(b, &p->talid, sizeof(p->talid));
365 io_read_buf(b, &p->ipsz, sizeof(p->ipsz));
366 io_read_buf(b, &p->expires, sizeof(p->expires));
367
368 if ((p->ips = calloc(p->ipsz, sizeof(struct roa_ip))) == NULL)
369 err(1, NULL);
370 io_read_buf(b, p->ips, p->ipsz * sizeof(p->ips[0]));
371
372 io_read_str(b, &p->aia);
373 io_read_str(b, &p->aki);
374 io_read_str(b, &p->ski);
375 assert(p->aia && p->aki && p->ski);
376
377 return p;
378 }
379
380 /*
381 * Add each IP address in the ROA into the VRP tree.
382 * Updates "vrps" to be the number of VRPs and "uniqs" to be the unique
383 * number of addresses.
384 */
385 void
roa_insert_vrps(struct vrp_tree * tree,struct roa * roa,struct repo * rp)386 roa_insert_vrps(struct vrp_tree *tree, struct roa *roa, struct repo *rp)
387 {
388 struct vrp *v, *found;
389 size_t i;
390
391 for (i = 0; i < roa->ipsz; i++) {
392 if ((v = malloc(sizeof(*v))) == NULL)
393 err(1, NULL);
394 v->afi = roa->ips[i].afi;
395 v->addr = roa->ips[i].addr;
396 v->maxlength = roa->ips[i].maxlength;
397 v->asid = roa->asid;
398 v->talid = roa->talid;
399 if (rp != NULL)
400 v->repoid = repo_id(rp);
401 else
402 v->repoid = 0;
403 v->expires = roa->expires;
404
405 /*
406 * Check if a similar VRP already exists in the tree.
407 * If the found VRP expires sooner, update it to this
408 * ROAs later expiry moment.
409 */
410 if ((found = RB_INSERT(vrp_tree, tree, v)) != NULL) {
411 /* already exists */
412 if (found->expires < v->expires) {
413 /* update found with preferred data */
414 /* adjust unique count */
415 repo_stat_inc(repo_byid(found->repoid),
416 found->talid, RTYPE_ROA, STYPE_DEC_UNIQUE);
417 found->expires = v->expires;
418 found->talid = v->talid;
419 found->repoid = v->repoid;
420 repo_stat_inc(rp, v->talid, RTYPE_ROA,
421 STYPE_UNIQUE);
422 }
423 free(v);
424 } else
425 repo_stat_inc(rp, v->talid, RTYPE_ROA, STYPE_UNIQUE);
426
427 repo_stat_inc(rp, roa->talid, RTYPE_ROA, STYPE_TOTAL);
428 }
429 }
430
431 static inline int
vrpcmp(struct vrp * a,struct vrp * b)432 vrpcmp(struct vrp *a, struct vrp *b)
433 {
434 int rv;
435
436 if (a->afi > b->afi)
437 return 1;
438 if (a->afi < b->afi)
439 return -1;
440 switch (a->afi) {
441 case AFI_IPV4:
442 rv = memcmp(&a->addr.addr, &b->addr.addr, 4);
443 if (rv)
444 return rv;
445 break;
446 case AFI_IPV6:
447 rv = memcmp(&a->addr.addr, &b->addr.addr, 16);
448 if (rv)
449 return rv;
450 break;
451 default:
452 break;
453 }
454 /* a smaller prefixlen is considered bigger, e.g. /8 vs /10 */
455 if (a->addr.prefixlen < b->addr.prefixlen)
456 return 1;
457 if (a->addr.prefixlen > b->addr.prefixlen)
458 return -1;
459 if (a->maxlength < b->maxlength)
460 return 1;
461 if (a->maxlength > b->maxlength)
462 return -1;
463
464 if (a->asid > b->asid)
465 return 1;
466 if (a->asid < b->asid)
467 return -1;
468
469 return 0;
470 }
471
472 RB_GENERATE(vrp_tree, vrp, entry, vrpcmp);
473