as.c revision 1.7
1/*	$OpenBSD: as.c,v 1.7 2021/12/26 12:32:28 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 <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 */
39int
40as_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 */
72int
73as_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 inheritance 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 inheritance and multiple ASnum or "
84		    "multiple inheritance", 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 */
144int
145as_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