xref: /openbsd/usr.sbin/rpki-client/as.c (revision 73471bf0)
1 /*	$OpenBSD: as.c,v 1.6 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 <assert.h>
21 #include <err.h>
22 #include <stdarg.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 
28 #include "extern.h"
29 
30 /*
31  * Parse a uint32_t AS identifier from an ASN1_INTEGER.
32  * This relies on the specification for ASN1_INTEGER itself, which is
33  * essentially a series of big-endian bytes in the unsigned case.
34  * All we do here is check if the number is negative then start copying
35  * over bytes.
36  * This is necessary because ASN1_INTEGER_get() on a 32-bit machine
37  * (e.g., i386) will fail for AS numbers of UINT32_MAX.
38  */
39 int
40 as_id_parse(const ASN1_INTEGER *v, uint32_t *out)
41 {
42 	int	 i;
43 	uint32_t res = 0;
44 
45 	/* If the negative bit is set, this is wrong. */
46 
47 	if (v->type & V_ASN1_NEG)
48 		return 0;
49 
50 	/* Too many bytes for us to consider. */
51 
52 	if ((size_t)v->length > sizeof(uint32_t))
53 		return 0;
54 
55 	/* Stored as big-endian bytes. */
56 
57 	for (i = 0; i < v->length; i++) {
58 		res <<= 8;
59 		res |= v->data[i];
60 	}
61 
62 	*out = res;
63 	return 1;
64 }
65 
66 /*
67  * Given a newly-parsed AS number or range "a", make sure that "a" does
68  * not overlap with any other numbers or ranges in the "as" array.
69  * This is defined by RFC 3779 section 3.2.3.4.
70  * Returns zero on failure, non-zero on success.
71  */
72 int
73 as_check_overlap(const struct cert_as *a, const char *fn,
74     const struct cert_as *as, size_t asz)
75 {
76 	size_t	 i;
77 
78 	/* We can have only one inheritence statement. */
79 
80 	if (asz &&
81 	    (a->type == CERT_AS_INHERIT || as[0].type == CERT_AS_INHERIT)) {
82 		warnx("%s: RFC 3779 section 3.2.3.3: "
83 		    "cannot have inheritence and multiple ASnum or "
84 		    "multiple inheritence", fn);
85 		return 0;
86 	}
87 
88 	/* Now check for overlaps between singletons/ranges. */
89 
90 	for (i = 0; i < asz; i++)
91 		switch (as[i].type) {
92 		case CERT_AS_ID:
93 			switch (a->type) {
94 			case CERT_AS_ID:
95 				if (a->id != as[i].id)
96 					break;
97 				warnx("%s: RFC 3779 section 3.2.3.4: "
98 				    "cannot have overlapping ASnum", fn);
99 				return 0;
100 			case CERT_AS_RANGE:
101 				if (as->range.min > as[i].id ||
102 				    as->range.max < as[i].id)
103 					break;
104 				warnx("%s: RFC 3779 section 3.2.3.4: "
105 				    "cannot have overlapping ASnum", fn);
106 				return 0;
107 			default:
108 				abort();
109 			}
110 			break;
111 		case CERT_AS_RANGE:
112 			switch (a->type) {
113 			case CERT_AS_ID:
114 				if (as[i].range.min > a->id ||
115 				    as[i].range.max < a->id)
116 					break;
117 				warnx("%s: RFC 3779 section 3.2.3.4: "
118 				    "cannot have overlapping ASnum", fn);
119 				return 0;
120 			case CERT_AS_RANGE:
121 				if (a->range.max < as[i].range.min ||
122 				    a->range.min > as[i].range.max)
123 					break;
124 				warnx("%s: RFC 3779 section 3.2.3.4: "
125 				    "cannot have overlapping ASnum", fn);
126 				return 0;
127 			default:
128 				abort();
129 			}
130 			break;
131 		default:
132 			abort();
133 		}
134 
135 	return 1;
136 }
137 
138 /*
139  * See if a given AS range (which may be the same number, in the case of
140  * singleton AS identifiers) is covered by the AS numbers or ranges
141  * specified in the "as" array.
142  * Return <0 if there is no cover, 0 if we're inheriting, >0 if there is.
143  */
144 int
145 as_check_covered(uint32_t min, uint32_t max,
146     const struct cert_as *as, size_t asz)
147 {
148 	size_t	 i;
149 	uint32_t amin, amax;
150 
151 	for (i = 0; i < asz; i++) {
152 		if (as[i].type == CERT_AS_INHERIT)
153 			return 0;
154 		amin = as[i].type == CERT_AS_RANGE ?
155 			as[i].range.min : as[i].id;
156 		amax = as[i].type == CERT_AS_RANGE?
157 			as[i].range.max : as[i].id;
158 		if (min >= amin && max <= amax)
159 			return 1;
160 	}
161 
162 	return -1;
163 }
164