1 /* $OpenBSD: rsc.c,v 1.37 2024/11/13 12:51:04 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
rsc_parse_aslist(const char * fn,struct rsc * rsc,const ConstrainedASIdentifiers * asids)130 rsc_parse_aslist(const char *fn, struct rsc *rsc,
131 const ConstrainedASIdentifiers *asids)
132 {
133 int i, num_ases;
134
135 if (asids == NULL)
136 return 1;
137
138 if ((num_ases = sk_ASIdOrRange_num(asids->asnum)) == 0) {
139 warnx("%s: RSC asID empty", fn);
140 return 0;
141 }
142
143 if (num_ases >= MAX_AS_SIZE) {
144 warnx("%s: too many AS number entries: limit %d",
145 fn, MAX_AS_SIZE);
146 return 0;
147 }
148
149 if ((rsc->ases = calloc(num_ases, sizeof(struct cert_as))) == NULL)
150 err(1, NULL);
151
152 for (i = 0; i < num_ases; i++) {
153 const ASIdOrRange *aor;
154
155 aor = sk_ASIdOrRange_value(asids->asnum, i);
156
157 switch (aor->type) {
158 case ASIdOrRange_id:
159 if (!sbgp_as_id(fn, rsc->ases, &rsc->num_ases,
160 aor->u.id))
161 return 0;
162 break;
163 case ASIdOrRange_range:
164 if (!sbgp_as_range(fn, rsc->ases, &rsc->num_ases,
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
rsc_parse_iplist(const char * fn,struct rsc * rsc,const ConstrainedIPAddrBlocks * ipAddrBlocks)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 num_ips;
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 num_ips = rsc->num_ips + sk_IPAddressOrRange_num(aors);
201 if (num_ips >= 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->num_ips, num_ips,
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->num_ips, afi, aor->u.addressPrefix))
223 return 0;
224 break;
225 case IPAddressOrRange_addressRange:
226 if (!sbgp_addr_range(fn, rsc->ips,
227 &rsc->num_ips, 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
rsc_check_digesttype(const char * fn,struct rsc * rsc,const X509_ALGOR * alg)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 fn, nid2str(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
rsc_parse_checklist(const char * fn,struct rsc * rsc,const STACK_OF (FileNameAndHash)* checkList)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 num_files, i;
276
277 if ((num_files = sk_FileNameAndHash_num(checkList)) == 0) {
278 warnx("%s: RSC checkList needs at least one entry", fn);
279 return 0;
280 }
281
282 if (num_files >= MAX_CHECKLIST_ENTRIES) {
283 warnx("%s: %zu exceeds checklist entry limit (%d)", fn,
284 num_files, MAX_CHECKLIST_ENTRIES);
285 return 0;
286 }
287
288 rsc->files = calloc(num_files, sizeof(struct rscfile));
289 if (rsc->files == NULL)
290 err(1, NULL);
291 rsc->num_files = num_files;
292
293 for (i = 0; i < num_files; 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
rsc_parse_econtent(const char * fn,struct rsc * rsc,const unsigned char * d,size_t dsz)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 *
rsc_parse(X509 ** x509,const char * fn,int talid,const unsigned char * der,size_t len)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
rsc_free(struct rsc * p)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->num_files; 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->ases);
469 free(p->files);
470 free(p);
471 }
472