xref: /openbsd/usr.sbin/rpki-client/as.c (revision 4032f119)
1 /*	$OpenBSD: as.c,v 1.16 2023/12/27 07:15:55 tb 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 <err.h>
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 
24 #include "extern.h"
25 
26 /* Parse a uint32_t AS identifier from an ASN1_INTEGER. */
27 int
as_id_parse(const ASN1_INTEGER * v,uint32_t * out)28 as_id_parse(const ASN1_INTEGER *v, uint32_t *out)
29 {
30 	uint64_t res = 0;
31 
32 	if (!ASN1_INTEGER_get_uint64(&res, v))
33 		return 0;
34 	if (res > UINT32_MAX)
35 		return 0;
36 	*out = res;
37 	return 1;
38 }
39 
40 /*
41  * Given a newly-parsed AS number or range "a", make sure that "a" does
42  * not overlap with any other numbers or ranges in the "as" array.
43  * This is defined by RFC 3779 section 3.2.3.4.
44  * Returns zero on failure, non-zero on success.
45  */
46 int
as_check_overlap(const struct cert_as * a,const char * fn,const struct cert_as * as,size_t asz,int quiet)47 as_check_overlap(const struct cert_as *a, const char *fn,
48     const struct cert_as *as, size_t asz, int quiet)
49 {
50 	size_t	 i;
51 
52 	/* We can have only one inheritance statement. */
53 
54 	if (asz &&
55 	    (a->type == CERT_AS_INHERIT || as[0].type == CERT_AS_INHERIT)) {
56 		if (!quiet) {
57 			warnx("%s: RFC 3779 section 3.2.3.3: "
58 			    "cannot have inheritance and multiple ASnum or "
59 			    "multiple inheritance", fn);
60 		}
61 		return 0;
62 	}
63 
64 	/* Now check for overlaps between singletons/ranges. */
65 
66 	for (i = 0; i < asz; i++) {
67 		switch (as[i].type) {
68 		case CERT_AS_ID:
69 			switch (a->type) {
70 			case CERT_AS_ID:
71 				if (a->id != as[i].id)
72 					continue;
73 				break;
74 			case CERT_AS_RANGE:
75 				if (as->range.min > as[i].id ||
76 				    as->range.max < as[i].id)
77 					continue;
78 				break;
79 			default:
80 				abort();
81 			}
82 			break;
83 		case CERT_AS_RANGE:
84 			switch (a->type) {
85 			case CERT_AS_ID:
86 				if (as[i].range.min > a->id ||
87 				    as[i].range.max < a->id)
88 					continue;
89 				break;
90 			case CERT_AS_RANGE:
91 				if (a->range.max < as[i].range.min ||
92 				    a->range.min > as[i].range.max)
93 					continue;
94 				break;
95 			default:
96 				abort();
97 			}
98 			break;
99 		default:
100 			abort();
101 		}
102 		if (!quiet) {
103 			warnx("%s: RFC 3779 section 3.2.3.4: "
104 			    "cannot have overlapping ASnum", fn);
105 		}
106 		return 0;
107 	}
108 
109 	return 1;
110 }
111 
112 /*
113  * See if a given AS range (which may be the same number, in the case of
114  * singleton AS identifiers) is covered by the AS numbers or ranges
115  * specified in the "as" array.
116  * Return <0 if there is no cover, 0 if we're inheriting, >0 if there is.
117  */
118 int
as_check_covered(uint32_t min,uint32_t max,const struct cert_as * as,size_t asz)119 as_check_covered(uint32_t min, uint32_t max,
120     const struct cert_as *as, size_t asz)
121 {
122 	size_t	 i;
123 	uint32_t amin, amax;
124 
125 	for (i = 0; i < asz; i++) {
126 		if (as[i].type == CERT_AS_INHERIT)
127 			return 0;
128 		amin = as[i].type == CERT_AS_RANGE ?
129 		    as[i].range.min : as[i].id;
130 		amax = as[i].type == CERT_AS_RANGE ?
131 		    as[i].range.max : as[i].id;
132 		if (min >= amin && max <= amax)
133 			return 1;
134 	}
135 
136 	return -1;
137 }
138 
139 void
as_warn(const char * fn,const char * msg,const struct cert_as * as)140 as_warn(const char *fn, const char *msg, const struct cert_as *as)
141 {
142 	switch (as->type) {
143 	case CERT_AS_ID:
144 		warnx("%s: %s: AS %u", fn, msg, as->id);
145 		break;
146 	case CERT_AS_RANGE:
147 		warnx("%s: %s: AS range %u--%u", fn, msg, as->range.min,
148 		    as->range.max);
149 		break;
150 	case CERT_AS_INHERIT:
151 		warnx("%s: %s: AS (inherit)", fn, msg);
152 		break;
153 	default:
154 		warnx("%s: corrupt cert", fn);
155 		break;
156 	}
157 }
158