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. */
27int
28as_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 */
46int
47as_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 */
118int
119as_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
139void
140as_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