xref: /openbsd/usr.sbin/rpki-client/rsc.c (revision 00ee6dc4)
1 /*	$OpenBSD: rsc.c,v 1.34 2024/02/21 09:17:06 tb Exp $ */
2 /*
3  * Copyright (c) 2022 Theo Buehler <tb@openbsd.org>
4  * Copyright (c) 2022 Job Snijders <job@fastly.com>
5  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <err.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 
25 #include <openssl/asn1.h>
26 #include <openssl/asn1t.h>
27 #include <openssl/safestack.h>
28 #include <openssl/stack.h>
29 #include <openssl/x509.h>
30 #include <openssl/x509v3.h>
31 
32 #include "extern.h"
33 
34 extern ASN1_OBJECT	*rsc_oid;
35 
36 /*
37  * Types and templates for RSC eContent - RFC 9323
38  */
39 
40 ASN1_ITEM_EXP ConstrainedASIdentifiers_it;
41 ASN1_ITEM_EXP ConstrainedIPAddressFamily_it;
42 ASN1_ITEM_EXP ConstrainedIPAddrBlocks_it;
43 ASN1_ITEM_EXP FileNameAndHash_it;
44 ASN1_ITEM_EXP ResourceBlock_it;
45 ASN1_ITEM_EXP RpkiSignedChecklist_it;
46 
47 typedef struct {
48 	ASIdOrRanges		*asnum;
49 } ConstrainedASIdentifiers;
50 
51 ASN1_SEQUENCE(ConstrainedASIdentifiers) = {
52 	ASN1_EXP_SEQUENCE_OF(ConstrainedASIdentifiers, asnum, ASIdOrRange, 0),
53 } ASN1_SEQUENCE_END(ConstrainedASIdentifiers);
54 
55 typedef struct {
56 	ASN1_OCTET_STRING		*addressFamily;
57 	STACK_OF(IPAddressOrRange)	*addressesOrRanges;
58 } ConstrainedIPAddressFamily;
59 
60 ASN1_SEQUENCE(ConstrainedIPAddressFamily) = {
61 	ASN1_SIMPLE(ConstrainedIPAddressFamily, addressFamily,
62 	    ASN1_OCTET_STRING),
63 	ASN1_SEQUENCE_OF(ConstrainedIPAddressFamily, addressesOrRanges,
64 	    IPAddressOrRange),
65 } ASN1_SEQUENCE_END(ConstrainedIPAddressFamily);
66 
67 typedef STACK_OF(ConstrainedIPAddressFamily) ConstrainedIPAddrBlocks;
68 DECLARE_STACK_OF(ConstrainedIPAddressFamily);
69 
70 ASN1_ITEM_TEMPLATE(ConstrainedIPAddrBlocks) =
71 	ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, ConstrainedIPAddrBlocks,
72 	    ConstrainedIPAddressFamily)
73 ASN1_ITEM_TEMPLATE_END(ConstrainedIPAddrBlocks);
74 
75 typedef struct {
76 	ConstrainedASIdentifiers	*asID;
77 	ConstrainedIPAddrBlocks		*ipAddrBlocks;
78 } ResourceBlock;
79 
80 ASN1_SEQUENCE(ResourceBlock) = {
81 	ASN1_EXP_OPT(ResourceBlock, asID, ConstrainedASIdentifiers, 0),
82 	ASN1_EXP_SEQUENCE_OF_OPT(ResourceBlock, ipAddrBlocks,
83 	    ConstrainedIPAddressFamily, 1)
84 } ASN1_SEQUENCE_END(ResourceBlock);
85 
86 typedef struct {
87 	ASN1_IA5STRING		*fileName;
88 	ASN1_OCTET_STRING	*hash;
89 } FileNameAndHash;
90 
91 DECLARE_STACK_OF(FileNameAndHash);
92 
93 #ifndef DEFINE_STACK_OF
94 #define sk_ConstrainedIPAddressFamily_num(sk) \
95     SKM_sk_num(ConstrainedIPAddressFamily, (sk))
96 #define sk_ConstrainedIPAddressFamily_value(sk, i) \
97     SKM_sk_value(ConstrainedIPAddressFamily, (sk), (i))
98 
99 #define sk_FileNameAndHash_num(sk)	SKM_sk_num(FileNameAndHash, (sk))
100 #define sk_FileNameAndHash_value(sk, i)	SKM_sk_value(FileNameAndHash, (sk), (i))
101 #endif
102 
103 ASN1_SEQUENCE(FileNameAndHash) = {
104 	ASN1_OPT(FileNameAndHash, fileName, ASN1_IA5STRING),
105 	ASN1_SIMPLE(FileNameAndHash, hash, ASN1_OCTET_STRING),
106 } ASN1_SEQUENCE_END(FileNameAndHash);
107 
108 typedef struct {
109 	ASN1_INTEGER			*version;
110 	ResourceBlock			*resources;
111 	X509_ALGOR			*digestAlgorithm;
112 	STACK_OF(FileNameAndHash)	*checkList;
113 } RpkiSignedChecklist;
114 
115 ASN1_SEQUENCE(RpkiSignedChecklist) = {
116 	ASN1_EXP_OPT(RpkiSignedChecklist, version, ASN1_INTEGER, 0),
117 	ASN1_SIMPLE(RpkiSignedChecklist, resources, ResourceBlock),
118 	ASN1_SIMPLE(RpkiSignedChecklist, digestAlgorithm, X509_ALGOR),
119 	ASN1_SEQUENCE_OF(RpkiSignedChecklist, checkList, FileNameAndHash),
120 } ASN1_SEQUENCE_END(RpkiSignedChecklist);
121 
122 DECLARE_ASN1_FUNCTIONS(RpkiSignedChecklist);
123 IMPLEMENT_ASN1_FUNCTIONS(RpkiSignedChecklist);
124 
125 /*
126  * Parse asID (inside ResourceBlock)
127  * Return 0 on failure.
128  */
129 static int
130 rsc_parse_aslist(const char *fn, struct rsc *rsc,
131     const ConstrainedASIdentifiers *asids)
132 {
133 	int	 i, asz;
134 
135 	if (asids == NULL)
136 		return 1;
137 
138 	if ((asz = sk_ASIdOrRange_num(asids->asnum)) == 0) {
139 		warnx("%s: RSC asID empty", fn);
140 		return 0;
141 	}
142 
143 	if (asz >= MAX_AS_SIZE) {
144 		warnx("%s: too many AS number entries: limit %d",
145 		    fn, MAX_AS_SIZE);
146 		return 0;
147 	}
148 
149 	rsc->as = calloc(asz, sizeof(struct cert_as));
150 	if (rsc->as == NULL)
151 		err(1, NULL);
152 
153 	for (i = 0; i < asz; i++) {
154 		const ASIdOrRange *aor;
155 
156 		aor = sk_ASIdOrRange_value(asids->asnum, i);
157 
158 		switch (aor->type) {
159 		case ASIdOrRange_id:
160 			if (!sbgp_as_id(fn, rsc->as, &rsc->asz, aor->u.id))
161 				return 0;
162 			break;
163 		case ASIdOrRange_range:
164 			if (!sbgp_as_range(fn, rsc->as, &rsc->asz,
165 			    aor->u.range))
166 				return 0;
167 			break;
168 		default:
169 			warnx("%s: RSC AsList: unknown type %d", fn, aor->type);
170 			return 0;
171 		}
172 	}
173 
174 	return 1;
175 }
176 
177 static int
178 rsc_parse_iplist(const char *fn, struct rsc *rsc,
179     const ConstrainedIPAddrBlocks *ipAddrBlocks)
180 {
181 	const ConstrainedIPAddressFamily	*af;
182 	const IPAddressOrRanges			*aors;
183 	const IPAddressOrRange			*aor;
184 	size_t					 ipsz;
185 	enum afi				 afi;
186 	int					 i, j;
187 
188 	if (ipAddrBlocks == NULL)
189 		return 1;
190 
191 	if (sk_ConstrainedIPAddressFamily_num(ipAddrBlocks) == 0) {
192 		warnx("%s: RSC ipAddrBlocks empty", fn);
193 		return 0;
194 	}
195 
196 	for (i = 0; i < sk_ConstrainedIPAddressFamily_num(ipAddrBlocks); i++) {
197 		af = sk_ConstrainedIPAddressFamily_value(ipAddrBlocks, i);
198 		aors = af->addressesOrRanges;
199 
200 		ipsz = rsc->ipsz + sk_IPAddressOrRange_num(aors);
201 		if (ipsz >= MAX_IP_SIZE) {
202 			warnx("%s: too many IP address entries: limit %d",
203 			    fn, MAX_IP_SIZE);
204 			return 0;
205 		}
206 
207 		rsc->ips = recallocarray(rsc->ips, rsc->ipsz, ipsz,
208 		    sizeof(struct cert_ip));
209 		if (rsc->ips == NULL)
210 			err(1, NULL);
211 
212 		if (!ip_addr_afi_parse(fn, af->addressFamily, &afi)) {
213 			warnx("%s: RSC: invalid AFI", fn);
214 			return 0;
215 		}
216 
217 		for (j = 0; j < sk_IPAddressOrRange_num(aors); j++) {
218 			aor = sk_IPAddressOrRange_value(aors, j);
219 			switch (aor->type) {
220 			case IPAddressOrRange_addressPrefix:
221 				if (!sbgp_addr(fn, rsc->ips,
222 				    &rsc->ipsz, afi, aor->u.addressPrefix))
223 					return 0;
224 				break;
225 			case IPAddressOrRange_addressRange:
226 				if (!sbgp_addr_range(fn, rsc->ips,
227 				    &rsc->ipsz, afi, aor->u.addressRange))
228 					return 0;
229 				break;
230 			default:
231 				warnx("%s: RFC 3779: IPAddressOrRange: "
232 				    "unknown type %d", fn, aor->type);
233 				return 0;
234 			}
235 		}
236 	}
237 
238 	return 1;
239 }
240 
241 static int
242 rsc_check_digesttype(const char *fn, struct rsc *rsc, const X509_ALGOR *alg)
243 {
244 	const ASN1_OBJECT	*obj;
245 	int			 type, nid;
246 
247 	X509_ALGOR_get0(&obj, &type, NULL, alg);
248 
249 	if (type != V_ASN1_UNDEF) {
250 		warnx("%s: RSC DigestAlgorithmIdentifier unexpected parameters:"
251 		    " %d", fn, type);
252 		return 0;
253 	}
254 
255 	if ((nid = OBJ_obj2nid(obj)) != NID_sha256) {
256 		warnx("%s: RSC DigestAlgorithmIdentifier: want SHA256, have %s"
257 		    " (NID %d)", fn, ASN1_tag2str(nid), nid);
258 		return 0;
259 	}
260 
261 	return 1;
262 }
263 
264 /*
265  * Parse the FileNameAndHash sequence, RFC 9323, section 4.4.
266  * Return zero on failure, non-zero on success.
267  */
268 static int
269 rsc_parse_checklist(const char *fn, struct rsc *rsc,
270     const STACK_OF(FileNameAndHash) *checkList)
271 {
272 	FileNameAndHash		*fh;
273 	ASN1_IA5STRING		*fileName;
274 	struct rscfile		*file;
275 	size_t			 sz, i;
276 
277 	if ((sz = sk_FileNameAndHash_num(checkList)) == 0) {
278 		warnx("%s: RSC checkList needs at least one entry", fn);
279 		return 0;
280 	}
281 
282 	if (sz >= MAX_CHECKLIST_ENTRIES) {
283 		warnx("%s: %zu exceeds checklist entry limit (%d)", fn, sz,
284 		    MAX_CHECKLIST_ENTRIES);
285 		return 0;
286 	}
287 
288 	rsc->files = calloc(sz, sizeof(struct rscfile));
289 	if (rsc->files == NULL)
290 		err(1, NULL);
291 	rsc->filesz = sz;
292 
293 	for (i = 0; i < sz; i++) {
294 		fh = sk_FileNameAndHash_value(checkList, i);
295 
296 		file = &rsc->files[i];
297 
298 		if (fh->hash->length != SHA256_DIGEST_LENGTH) {
299 			warnx("%s: RSC Digest: invalid SHA256 length", fn);
300 			return 0;
301 		}
302 		memcpy(file->hash, fh->hash->data, SHA256_DIGEST_LENGTH);
303 
304 		if ((fileName = fh->fileName) == NULL)
305 			continue;
306 
307 		if (!valid_filename(fileName->data, fileName->length)) {
308 			warnx("%s: RSC FileNameAndHash: bad filename", fn);
309 			return 0;
310 		}
311 
312 		file->filename = strndup(fileName->data, fileName->length);
313 		if (file->filename == NULL)
314 			err(1, NULL);
315 	}
316 
317 	return 1;
318 }
319 
320 /*
321  * Parses the eContent segment of an RSC file
322  * RFC 9323, section 4
323  * Returns zero on failure, non-zero on success.
324  */
325 static int
326 rsc_parse_econtent(const char *fn, struct rsc *rsc, const unsigned char *d,
327     size_t dsz)
328 {
329 	const unsigned char	*oder;
330 	RpkiSignedChecklist	*rsc_asn1;
331 	ResourceBlock		*resources;
332 	int			 rc = 0;
333 
334 	/*
335 	 * RFC 9323 section 4
336 	 */
337 
338 	oder = d;
339 	if ((rsc_asn1 = d2i_RpkiSignedChecklist(NULL, &d, dsz)) == NULL) {
340 		warnx("%s: RSC: failed to parse RpkiSignedChecklist", fn);
341 		goto out;
342 	}
343 	if (d != oder + dsz) {
344 		warnx("%s: %td bytes trailing garbage in eContent", fn,
345 		    oder + dsz - d);
346 		goto out;
347 	}
348 
349 	if (!valid_econtent_version(fn, rsc_asn1->version, 0))
350 		goto out;
351 
352 	resources = rsc_asn1->resources;
353 	if (resources->asID == NULL && resources->ipAddrBlocks == NULL) {
354 		warnx("%s: RSC: one of asID or ipAddrBlocks must be present",
355 		    fn);
356 		goto out;
357 	}
358 
359 	if (!rsc_parse_aslist(fn, rsc, resources->asID))
360 		goto out;
361 
362 	if (!rsc_parse_iplist(fn, rsc, resources->ipAddrBlocks))
363 		goto out;
364 
365 	if (!rsc_check_digesttype(fn, rsc, rsc_asn1->digestAlgorithm))
366 		goto out;
367 
368 	if (!rsc_parse_checklist(fn, rsc, rsc_asn1->checkList))
369 		goto out;
370 
371 	rc = 1;
372  out:
373 	RpkiSignedChecklist_free(rsc_asn1);
374 	return rc;
375 }
376 
377 /*
378  * Parse a full RFC 9323 file.
379  * Returns the RSC or NULL if the object was malformed.
380  */
381 struct rsc *
382 rsc_parse(X509 **x509, const char *fn, int talid, const unsigned char *der,
383     size_t len)
384 {
385 	struct rsc		*rsc;
386 	unsigned char		*cms;
387 	size_t			 cmsz;
388 	struct cert		*cert = NULL;
389 	time_t			 signtime = 0;
390 	int			 rc = 0;
391 
392 	cms = cms_parse_validate(x509, fn, der, len, rsc_oid, &cmsz,
393 	    &signtime);
394 	if (cms == NULL)
395 		return NULL;
396 
397 	if ((rsc = calloc(1, sizeof(struct rsc))) == NULL)
398 		err(1, NULL);
399 	rsc->signtime = signtime;
400 
401 	if (!x509_get_aia(*x509, fn, &rsc->aia))
402 		goto out;
403 	if (!x509_get_aki(*x509, fn, &rsc->aki))
404 		goto out;
405 	if (!x509_get_ski(*x509, fn, &rsc->ski))
406 		goto out;
407 	if (rsc->aia == NULL || rsc->aki == NULL || rsc->ski == NULL) {
408 		warnx("%s: RFC 6487 section 4.8: "
409 		    "missing AIA, AKI or SKI X509 extension", fn);
410 		goto out;
411 	}
412 
413 	if (!x509_get_notbefore(*x509, fn, &rsc->notbefore))
414 		goto out;
415 	if (!x509_get_notafter(*x509, fn, &rsc->notafter))
416 		goto out;
417 
418 	if (X509_get_ext_by_NID(*x509, NID_sinfo_access, -1) != -1) {
419 		warnx("%s: RSC: EE cert must not have an SIA extension", fn);
420 		goto out;
421 	}
422 
423 	if (x509_any_inherits(*x509)) {
424 		warnx("%s: inherit elements not allowed in EE cert", fn);
425 		goto out;
426 	}
427 
428 	if (!rsc_parse_econtent(fn, rsc, cms, cmsz))
429 		goto out;
430 
431 	if ((cert = cert_parse_ee_cert(fn, talid, *x509)) == NULL)
432 		goto out;
433 
434 	rsc->valid = valid_rsc(fn, cert, rsc);
435 
436 	rc = 1;
437  out:
438 	if (rc == 0) {
439 		rsc_free(rsc);
440 		rsc = NULL;
441 		X509_free(*x509);
442 		*x509 = NULL;
443 	}
444 	cert_free(cert);
445 	free(cms);
446 	return rsc;
447 }
448 
449 /*
450  * Free an RSC pointer.
451  * Safe to call with NULL.
452  */
453 void
454 rsc_free(struct rsc *p)
455 {
456 	size_t	i;
457 
458 	if (p == NULL)
459 		return;
460 
461 	for (i = 0; i < p->filesz; i++)
462 		free(p->files[i].filename);
463 
464 	free(p->aia);
465 	free(p->aki);
466 	free(p->ski);
467 	free(p->ips);
468 	free(p->as);
469 	free(p->files);
470 	free(p);
471 }
472