1 /* $OpenBSD: cert.c,v 1.130 2024/04/21 19:27:44 claudio Exp $ */
2 /*
3 * Copyright (c) 2022 Theo Buehler <tb@openbsd.org>
4 * Copyright (c) 2021 Job Snijders <job@openbsd.org>
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 <assert.h>
21 #include <err.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25
26 #include <openssl/asn1.h>
27 #include <openssl/x509.h>
28 #include <openssl/x509v3.h>
29
30 #include "extern.h"
31
32 extern ASN1_OBJECT *certpol_oid; /* id-cp-ipAddr-asNumber cert policy */
33 extern ASN1_OBJECT *carepo_oid; /* 1.3.6.1.5.5.7.48.5 (caRepository) */
34 extern ASN1_OBJECT *manifest_oid; /* 1.3.6.1.5.5.7.48.10 (rpkiManifest) */
35 extern ASN1_OBJECT *notify_oid; /* 1.3.6.1.5.5.7.48.13 (rpkiNotify) */
36
37 /*
38 * Append an IP address structure to our list of results.
39 * This will also constrain us to having at most one inheritance
40 * statement per AFI and also not have overlapping ranges (as prohibited
41 * in section 2.2.3.6).
42 * It does not make sure that ranges can't coalesce, that is, that any
43 * two ranges abut each other.
44 * This is warned against in section 2.2.3.6, but doesn't change the
45 * semantics of the system.
46 * Returns zero on failure (IP overlap) non-zero on success.
47 */
48 static int
append_ip(const char * fn,struct cert_ip * ips,size_t * ipsz,const struct cert_ip * ip)49 append_ip(const char *fn, struct cert_ip *ips, size_t *ipsz,
50 const struct cert_ip *ip)
51 {
52 if (!ip_addr_check_overlap(ip, fn, ips, *ipsz, 0))
53 return 0;
54 ips[(*ipsz)++] = *ip;
55 return 1;
56 }
57
58 /*
59 * Append an AS identifier structure to our list of results.
60 * Makes sure that the identifiers do not overlap or improperly inherit
61 * as defined by RFC 3779 section 3.3.
62 */
63 static int
append_as(const char * fn,struct cert_as * ases,size_t * asz,const struct cert_as * as)64 append_as(const char *fn, struct cert_as *ases, size_t *asz,
65 const struct cert_as *as)
66 {
67 if (!as_check_overlap(as, fn, ases, *asz, 0))
68 return 0;
69 ases[(*asz)++] = *as;
70 return 1;
71 }
72
73 /*
74 * Parse a range of AS identifiers as in 3.2.3.8.
75 * Returns zero on failure, non-zero on success.
76 */
77 int
sbgp_as_range(const char * fn,struct cert_as * ases,size_t * asz,const ASRange * range)78 sbgp_as_range(const char *fn, struct cert_as *ases, size_t *asz,
79 const ASRange *range)
80 {
81 struct cert_as as;
82
83 memset(&as, 0, sizeof(struct cert_as));
84 as.type = CERT_AS_RANGE;
85
86 if (!as_id_parse(range->min, &as.range.min)) {
87 warnx("%s: RFC 3779 section 3.2.3.8 (via RFC 1930): "
88 "malformed AS identifier", fn);
89 return 0;
90 }
91
92 if (!as_id_parse(range->max, &as.range.max)) {
93 warnx("%s: RFC 3779 section 3.2.3.8 (via RFC 1930): "
94 "malformed AS identifier", fn);
95 return 0;
96 }
97
98 if (as.range.max == as.range.min) {
99 warnx("%s: RFC 3379 section 3.2.3.8: ASRange: "
100 "range is singular", fn);
101 return 0;
102 } else if (as.range.max < as.range.min) {
103 warnx("%s: RFC 3379 section 3.2.3.8: ASRange: "
104 "range is out of order", fn);
105 return 0;
106 }
107
108 return append_as(fn, ases, asz, &as);
109 }
110
111 /*
112 * Parse an entire 3.2.3.10 integer type.
113 */
114 int
sbgp_as_id(const char * fn,struct cert_as * ases,size_t * asz,const ASN1_INTEGER * i)115 sbgp_as_id(const char *fn, struct cert_as *ases, size_t *asz,
116 const ASN1_INTEGER *i)
117 {
118 struct cert_as as;
119
120 memset(&as, 0, sizeof(struct cert_as));
121 as.type = CERT_AS_ID;
122
123 if (!as_id_parse(i, &as.id)) {
124 warnx("%s: RFC 3779 section 3.2.3.10 (via RFC 1930): "
125 "malformed AS identifier", fn);
126 return 0;
127 }
128 if (as.id == 0) {
129 warnx("%s: RFC 3779 section 3.2.3.10 (via RFC 1930): "
130 "AS identifier zero is reserved", fn);
131 return 0;
132 }
133
134 return append_as(fn, ases, asz, &as);
135 }
136
137 static int
sbgp_as_inherit(const char * fn,struct cert_as * ases,size_t * asz)138 sbgp_as_inherit(const char *fn, struct cert_as *ases, size_t *asz)
139 {
140 struct cert_as as;
141
142 memset(&as, 0, sizeof(struct cert_as));
143 as.type = CERT_AS_INHERIT;
144
145 return append_as(fn, ases, asz, &as);
146 }
147
148 int
sbgp_parse_assysnum(const char * fn,const ASIdentifiers * asidentifiers,struct cert_as ** out_as,size_t * out_asz)149 sbgp_parse_assysnum(const char *fn, const ASIdentifiers *asidentifiers,
150 struct cert_as **out_as, size_t *out_asz)
151 {
152 const ASIdOrRanges *aors = NULL;
153 struct cert_as *as = NULL;
154 size_t asz = 0, sz;
155 int i;
156
157 assert(*out_as == NULL && *out_asz == 0);
158
159 if (asidentifiers->rdi != NULL) {
160 warnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: "
161 "should not have RDI values", fn);
162 goto out;
163 }
164
165 if (asidentifiers->asnum == NULL) {
166 warnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: "
167 "no AS number resource set", fn);
168 goto out;
169 }
170
171 switch (asidentifiers->asnum->type) {
172 case ASIdentifierChoice_inherit:
173 sz = 1;
174 break;
175 case ASIdentifierChoice_asIdsOrRanges:
176 aors = asidentifiers->asnum->u.asIdsOrRanges;
177 sz = sk_ASIdOrRange_num(aors);
178 break;
179 default:
180 warnx("%s: RFC 3779 section 3.2.3.2: ASIdentifierChoice: "
181 "unknown type %d", fn, asidentifiers->asnum->type);
182 goto out;
183 }
184
185 if (sz == 0) {
186 warnx("%s: RFC 6487 section 4.8.11: empty asIdsOrRanges", fn);
187 goto out;
188 }
189 if (sz >= MAX_AS_SIZE) {
190 warnx("%s: too many AS number entries: limit %d",
191 fn, MAX_AS_SIZE);
192 goto out;
193 }
194 as = calloc(sz, sizeof(struct cert_as));
195 if (as == NULL)
196 err(1, NULL);
197
198 if (aors == NULL) {
199 if (!sbgp_as_inherit(fn, as, &asz))
200 goto out;
201 }
202
203 for (i = 0; i < sk_ASIdOrRange_num(aors); i++) {
204 const ASIdOrRange *aor;
205
206 aor = sk_ASIdOrRange_value(aors, i);
207 switch (aor->type) {
208 case ASIdOrRange_id:
209 if (!sbgp_as_id(fn, as, &asz, aor->u.id))
210 goto out;
211 break;
212 case ASIdOrRange_range:
213 if (!sbgp_as_range(fn, as, &asz, aor->u.range))
214 goto out;
215 break;
216 default:
217 warnx("%s: RFC 3779 section 3.2.3.5: ASIdOrRange: "
218 "unknown type %d", fn, aor->type);
219 goto out;
220 }
221 }
222
223 *out_as = as;
224 *out_asz = asz;
225
226 return 1;
227
228 out:
229 free(as);
230
231 return 0;
232 }
233
234 /*
235 * Parse RFC 6487 4.8.11 X509v3 extension, with syntax documented in RFC
236 * 3779 starting in section 3.2.
237 * Returns zero on failure, non-zero on success.
238 */
239 static int
sbgp_assysnum(const char * fn,struct cert * cert,X509_EXTENSION * ext)240 sbgp_assysnum(const char *fn, struct cert *cert, X509_EXTENSION *ext)
241 {
242 ASIdentifiers *asidentifiers = NULL;
243 int rc = 0;
244
245 if (!X509_EXTENSION_get_critical(ext)) {
246 warnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: "
247 "extension not critical", fn);
248 goto out;
249 }
250
251 if ((asidentifiers = X509V3_EXT_d2i(ext)) == NULL) {
252 warnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: "
253 "failed extension parse", fn);
254 goto out;
255 }
256
257 if (!sbgp_parse_assysnum(fn, asidentifiers, &cert->as, &cert->asz))
258 goto out;
259
260 rc = 1;
261 out:
262 ASIdentifiers_free(asidentifiers);
263 return rc;
264 }
265
266 /*
267 * Construct a RFC 3779 2.2.3.8 range from its bit string.
268 * Returns zero on failure, non-zero on success.
269 */
270 int
sbgp_addr(const char * fn,struct cert_ip * ips,size_t * ipsz,enum afi afi,const ASN1_BIT_STRING * bs)271 sbgp_addr(const char *fn, struct cert_ip *ips, size_t *ipsz, enum afi afi,
272 const ASN1_BIT_STRING *bs)
273 {
274 struct cert_ip ip;
275
276 memset(&ip, 0, sizeof(struct cert_ip));
277
278 ip.afi = afi;
279 ip.type = CERT_IP_ADDR;
280
281 if (!ip_addr_parse(bs, afi, fn, &ip.ip)) {
282 warnx("%s: RFC 3779 section 2.2.3.8: IPAddress: "
283 "invalid IP address", fn);
284 return 0;
285 }
286
287 if (!ip_cert_compose_ranges(&ip)) {
288 warnx("%s: RFC 3779 section 2.2.3.8: IPAddress: "
289 "IP address range reversed", fn);
290 return 0;
291 }
292
293 return append_ip(fn, ips, ipsz, &ip);
294 }
295
296 /*
297 * Parse RFC 3779 2.2.3.9 range of addresses.
298 * Returns zero on failure, non-zero on success.
299 */
300 int
sbgp_addr_range(const char * fn,struct cert_ip * ips,size_t * ipsz,enum afi afi,const IPAddressRange * range)301 sbgp_addr_range(const char *fn, struct cert_ip *ips, size_t *ipsz,
302 enum afi afi, const IPAddressRange *range)
303 {
304 struct cert_ip ip;
305
306 memset(&ip, 0, sizeof(struct cert_ip));
307
308 ip.afi = afi;
309 ip.type = CERT_IP_RANGE;
310
311 if (!ip_addr_parse(range->min, afi, fn, &ip.range.min)) {
312 warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
313 "invalid IP address", fn);
314 return 0;
315 }
316
317 if (!ip_addr_parse(range->max, afi, fn, &ip.range.max)) {
318 warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
319 "invalid IP address", fn);
320 return 0;
321 }
322
323 if (!ip_cert_compose_ranges(&ip)) {
324 warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
325 "IP address range reversed", fn);
326 return 0;
327 }
328
329 return append_ip(fn, ips, ipsz, &ip);
330 }
331
332 static int
sbgp_addr_inherit(const char * fn,struct cert_ip * ips,size_t * ipsz,enum afi afi)333 sbgp_addr_inherit(const char *fn, struct cert_ip *ips, size_t *ipsz,
334 enum afi afi)
335 {
336 struct cert_ip ip;
337
338 memset(&ip, 0, sizeof(struct cert_ip));
339
340 ip.afi = afi;
341 ip.type = CERT_IP_INHERIT;
342
343 return append_ip(fn, ips, ipsz, &ip);
344 }
345
346 int
sbgp_parse_ipaddrblk(const char * fn,const IPAddrBlocks * addrblk,struct cert_ip ** out_ips,size_t * out_ipsz)347 sbgp_parse_ipaddrblk(const char *fn, const IPAddrBlocks *addrblk,
348 struct cert_ip **out_ips, size_t *out_ipsz)
349 {
350 const IPAddressFamily *af;
351 const IPAddressOrRanges *aors;
352 const IPAddressOrRange *aor;
353 enum afi afi;
354 struct cert_ip *ips = NULL;
355 size_t ipsz = 0, sz;
356 int ipv4_seen = 0, ipv6_seen = 0;
357 int i, j, ipaddrblocksz;
358
359 assert(*out_ips == NULL && *out_ipsz == 0);
360
361 ipaddrblocksz = sk_IPAddressFamily_num(addrblk);
362 if (ipaddrblocksz != 1 && ipaddrblocksz != 2) {
363 warnx("%s: RFC 6487 section 4.8.10: unexpected number of "
364 "ipAddrBlocks (got %d, expected 1 or 2)",
365 fn, ipaddrblocksz);
366 goto out;
367 }
368
369 for (i = 0; i < ipaddrblocksz; i++) {
370 af = sk_IPAddressFamily_value(addrblk, i);
371
372 switch (af->ipAddressChoice->type) {
373 case IPAddressChoice_inherit:
374 aors = NULL;
375 sz = ipsz + 1;
376 break;
377 case IPAddressChoice_addressesOrRanges:
378 aors = af->ipAddressChoice->u.addressesOrRanges;
379 sz = ipsz + sk_IPAddressOrRange_num(aors);
380 break;
381 default:
382 warnx("%s: RFC 3779: IPAddressChoice: unknown type %d",
383 fn, af->ipAddressChoice->type);
384 goto out;
385 }
386 if (sz == ipsz) {
387 warnx("%s: RFC 6487 section 4.8.10: "
388 "empty ipAddressesOrRanges", fn);
389 goto out;
390 }
391
392 if (sz >= MAX_IP_SIZE)
393 goto out;
394 ips = recallocarray(ips, ipsz, sz, sizeof(struct cert_ip));
395 if (ips == NULL)
396 err(1, NULL);
397
398 if (!ip_addr_afi_parse(fn, af->addressFamily, &afi)) {
399 warnx("%s: RFC 3779: invalid AFI", fn);
400 goto out;
401 }
402
403 switch (afi) {
404 case AFI_IPV4:
405 if (ipv4_seen++ > 0) {
406 warnx("%s: RFC 6487 section 4.8.10: "
407 "IPv4 appears twice", fn);
408 goto out;
409 }
410 break;
411 case AFI_IPV6:
412 if (ipv6_seen++ > 0) {
413 warnx("%s: RFC 6487 section 4.8.10: "
414 "IPv6 appears twice", fn);
415 goto out;
416 }
417 break;
418 }
419
420 if (aors == NULL) {
421 if (!sbgp_addr_inherit(fn, ips, &ipsz, afi))
422 goto out;
423 continue;
424 }
425
426 for (j = 0; j < sk_IPAddressOrRange_num(aors); j++) {
427 aor = sk_IPAddressOrRange_value(aors, j);
428 switch (aor->type) {
429 case IPAddressOrRange_addressPrefix:
430 if (!sbgp_addr(fn, ips, &ipsz, afi,
431 aor->u.addressPrefix))
432 goto out;
433 break;
434 case IPAddressOrRange_addressRange:
435 if (!sbgp_addr_range(fn, ips, &ipsz, afi,
436 aor->u.addressRange))
437 goto out;
438 break;
439 default:
440 warnx("%s: RFC 3779: IPAddressOrRange: "
441 "unknown type %d", fn, aor->type);
442 goto out;
443 }
444 }
445 }
446
447 *out_ips = ips;
448 *out_ipsz = ipsz;
449
450 return 1;
451
452 out:
453 free(ips);
454
455 return 0;
456 }
457
458 /*
459 * Parse an sbgp-ipAddrBlock X509 extension, RFC 6487 4.8.10, with
460 * syntax documented in RFC 3779 starting in section 2.2.
461 * Returns zero on failure, non-zero on success.
462 */
463 static int
sbgp_ipaddrblk(const char * fn,struct cert * cert,X509_EXTENSION * ext)464 sbgp_ipaddrblk(const char *fn, struct cert *cert, X509_EXTENSION *ext)
465 {
466 IPAddrBlocks *addrblk = NULL;
467 int rc = 0;
468
469 if (!X509_EXTENSION_get_critical(ext)) {
470 warnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: "
471 "extension not critical", fn);
472 goto out;
473 }
474
475 if ((addrblk = X509V3_EXT_d2i(ext)) == NULL) {
476 warnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: "
477 "failed extension parse", fn);
478 goto out;
479 }
480
481 if (!sbgp_parse_ipaddrblk(fn, addrblk, &cert->ips, &cert->ipsz))
482 goto out;
483
484 if (cert->ipsz == 0) {
485 warnx("%s: RFC 6487 section 4.8.10: empty ipAddrBlock", fn);
486 goto out;
487 }
488
489 rc = 1;
490 out:
491 IPAddrBlocks_free(addrblk);
492 return rc;
493 }
494
495 /*
496 * Parse "Subject Information Access" extension, RFC 6487 4.8.8.
497 * Returns zero on failure, non-zero on success.
498 */
499 static int
sbgp_sia(const char * fn,struct cert * cert,X509_EXTENSION * ext)500 sbgp_sia(const char *fn, struct cert *cert, X509_EXTENSION *ext)
501 {
502 AUTHORITY_INFO_ACCESS *sia = NULL;
503 ACCESS_DESCRIPTION *ad;
504 ASN1_OBJECT *oid;
505 const char *mftfilename;
506 int i, rc = 0;
507
508 if (X509_EXTENSION_get_critical(ext)) {
509 warnx("%s: RFC 6487 section 4.8.8: SIA: "
510 "extension not non-critical", fn);
511 goto out;
512 }
513
514 if ((sia = X509V3_EXT_d2i(ext)) == NULL) {
515 warnx("%s: RFC 6487 section 4.8.8: SIA: failed extension parse",
516 fn);
517 goto out;
518 }
519
520 for (i = 0; i < sk_ACCESS_DESCRIPTION_num(sia); i++) {
521 ad = sk_ACCESS_DESCRIPTION_value(sia, i);
522
523 oid = ad->method;
524
525 if (OBJ_cmp(oid, carepo_oid) == 0) {
526 if (!x509_location(fn, "SIA: caRepository",
527 RSYNC_PROTO, ad->location, &cert->repo))
528 goto out;
529 } else if (OBJ_cmp(oid, manifest_oid) == 0) {
530 if (!x509_location(fn, "SIA: rpkiManifest",
531 RSYNC_PROTO, ad->location, &cert->mft))
532 goto out;
533 } else if (OBJ_cmp(oid, notify_oid) == 0) {
534 if (!x509_location(fn, "SIA: rpkiNotify",
535 HTTPS_PROTO, ad->location, &cert->notify))
536 goto out;
537 }
538 }
539
540 if (cert->mft == NULL || cert->repo == NULL) {
541 warnx("%s: RFC 6487 section 4.8.8: SIA: missing caRepository "
542 "or rpkiManifest", fn);
543 goto out;
544 }
545
546 mftfilename = strrchr(cert->mft, '/');
547 if (mftfilename == NULL) {
548 warnx("%s: SIA: invalid rpkiManifest entry", fn);
549 goto out;
550 }
551 mftfilename++;
552 if (!valid_filename(mftfilename, strlen(mftfilename))) {
553 warnx("%s: SIA: rpkiManifest filename contains invalid "
554 "characters", fn);
555 goto out;
556 }
557
558 if (strstr(cert->mft, cert->repo) != cert->mft) {
559 warnx("%s: RFC 6487 section 4.8.8: SIA: "
560 "conflicting URIs for caRepository and rpkiManifest", fn);
561 goto out;
562 }
563
564 if (rtype_from_file_extension(cert->mft) != RTYPE_MFT) {
565 warnx("%s: RFC 6487 section 4.8.8: SIA: not an MFT file", fn);
566 goto out;
567 }
568
569 rc = 1;
570 out:
571 AUTHORITY_INFO_ACCESS_free(sia);
572 return rc;
573 }
574
575 /*
576 * Parse the certificate policies extension and check that it follows RFC 7318.
577 * Returns zero on failure, non-zero on success.
578 */
579 static int
certificate_policies(const char * fn,struct cert * cert,X509_EXTENSION * ext)580 certificate_policies(const char *fn, struct cert *cert, X509_EXTENSION *ext)
581 {
582 STACK_OF(POLICYINFO) *policies = NULL;
583 POLICYINFO *policy;
584 STACK_OF(POLICYQUALINFO) *qualifiers;
585 POLICYQUALINFO *qualifier;
586 int nid;
587 int rc = 0;
588
589 if (!X509_EXTENSION_get_critical(ext)) {
590 warnx("%s: RFC 6487 section 4.8.9: certificatePolicies: "
591 "extension not critical", fn);
592 goto out;
593 }
594
595 if ((policies = X509V3_EXT_d2i(ext)) == NULL) {
596 warnx("%s: RFC 6487 section 4.8.9: certificatePolicies: "
597 "failed extension parse", fn);
598 goto out;
599 }
600
601 if (sk_POLICYINFO_num(policies) != 1) {
602 warnx("%s: RFC 6487 section 4.8.9: certificatePolicies: "
603 "want 1 policy, got %d", fn, sk_POLICYINFO_num(policies));
604 goto out;
605 }
606
607 policy = sk_POLICYINFO_value(policies, 0);
608 assert(policy != NULL && policy->policyid != NULL);
609
610 if (OBJ_cmp(policy->policyid, certpol_oid) != 0) {
611 char pbuf[128], cbuf[128];
612
613 OBJ_obj2txt(pbuf, sizeof(pbuf), policy->policyid, 1);
614 OBJ_obj2txt(cbuf, sizeof(cbuf), certpol_oid, 1);
615 warnx("%s: RFC 7318 section 2: certificatePolicies: "
616 "unexpected OID: %s, want %s", fn, pbuf, cbuf);
617 goto out;
618 }
619
620 /* Policy qualifiers are optional. If they're absent, we're done. */
621 if ((qualifiers = policy->qualifiers) == NULL) {
622 rc = 1;
623 goto out;
624 }
625
626 if (sk_POLICYQUALINFO_num(qualifiers) != 1) {
627 warnx("%s: RFC 7318 section 2: certificatePolicies: "
628 "want 1 policy qualifier, got %d", fn,
629 sk_POLICYQUALINFO_num(qualifiers));
630 goto out;
631 }
632
633 qualifier = sk_POLICYQUALINFO_value(qualifiers, 0);
634 assert(qualifier != NULL && qualifier->pqualid != NULL);
635
636 if ((nid = OBJ_obj2nid(qualifier->pqualid)) != NID_id_qt_cps) {
637 warnx("%s: RFC 7318 section 2: certificatePolicies: "
638 "want CPS, got %s", fn, nid2str(nid));
639 goto out;
640 }
641
642 if (verbose > 1 && !filemode)
643 warnx("%s: CPS %.*s", fn, qualifier->d.cpsuri->length,
644 qualifier->d.cpsuri->data);
645
646 rc = 1;
647 out:
648 sk_POLICYINFO_pop_free(policies, POLICYINFO_free);
649 return rc;
650 }
651
652 /*
653 * Lightweight version of cert_parse_pre() for EE certs.
654 * Parses the two RFC 3779 extensions, and performs some sanity checks.
655 * Returns cert on success and NULL on failure.
656 */
657 struct cert *
cert_parse_ee_cert(const char * fn,int talid,X509 * x)658 cert_parse_ee_cert(const char *fn, int talid, X509 *x)
659 {
660 struct cert *cert;
661 X509_EXTENSION *ext;
662 int index;
663
664 if ((cert = calloc(1, sizeof(struct cert))) == NULL)
665 err(1, NULL);
666
667 if (X509_get_version(x) != 2) {
668 warnx("%s: RFC 6487 4.1: X.509 version must be v3", fn);
669 goto out;
670 }
671
672 if (!x509_valid_subject(fn, x))
673 goto out;
674
675 if (X509_get_key_usage(x) != KU_DIGITAL_SIGNATURE) {
676 warnx("%s: RFC 6487 section 4.8.4: KU must be digitalSignature",
677 fn);
678 goto out;
679 }
680
681 /* EKU may be allowed for some purposes in the future. */
682 if (X509_get_extended_key_usage(x) != UINT32_MAX) {
683 warnx("%s: RFC 6487 section 4.8.5: EKU not allowed", fn);
684 goto out;
685 }
686
687 index = X509_get_ext_by_NID(x, NID_sbgp_ipAddrBlock, -1);
688 if ((ext = X509_get_ext(x, index)) != NULL) {
689 if (!sbgp_ipaddrblk(fn, cert, ext))
690 goto out;
691 }
692
693 index = X509_get_ext_by_NID(x, NID_sbgp_autonomousSysNum, -1);
694 if ((ext = X509_get_ext(x, index)) != NULL) {
695 if (!sbgp_assysnum(fn, cert, ext))
696 goto out;
697 }
698
699 if (!X509_up_ref(x)) {
700 warnx("%s: X509_up_ref failed", fn);
701 goto out;
702 }
703
704 cert->x509 = x;
705 cert->talid = talid;
706
707 if (!constraints_validate(fn, cert))
708 goto out;
709
710 return cert;
711
712 out:
713 cert_free(cert);
714 return NULL;
715 }
716
717 /*
718 * Parse and partially validate an RPKI X509 certificate (either a trust
719 * anchor or a certificate) as defined in RFC 6487.
720 * Returns the parse results or NULL on failure.
721 */
722 struct cert *
cert_parse_pre(const char * fn,const unsigned char * der,size_t len)723 cert_parse_pre(const char *fn, const unsigned char *der, size_t len)
724 {
725 struct cert *cert;
726 const unsigned char *oder;
727 size_t j;
728 int i, extsz;
729 X509 *x = NULL;
730 X509_EXTENSION *ext = NULL;
731 const X509_ALGOR *palg;
732 const ASN1_BIT_STRING *piuid = NULL, *psuid = NULL;
733 const ASN1_OBJECT *cobj;
734 ASN1_OBJECT *obj;
735 EVP_PKEY *pkey;
736 int nid, ip, as, sia, cp, crldp, aia, aki, ski,
737 eku, bc, ku;
738
739 nid = ip = as = sia = cp = crldp = aia = aki = ski = eku = bc = ku = 0;
740
741 /* just fail for empty buffers, the warning was printed elsewhere */
742 if (der == NULL)
743 return NULL;
744
745 if ((cert = calloc(1, sizeof(struct cert))) == NULL)
746 err(1, NULL);
747
748 oder = der;
749 if ((x = d2i_X509(NULL, &der, len)) == NULL) {
750 warnx("%s: d2i_X509", fn);
751 goto out;
752 }
753 if (der != oder + len) {
754 warnx("%s: %td bytes trailing garbage", fn, oder + len - der);
755 goto out;
756 }
757
758 /* Cache X509v3 extensions, see X509_check_ca(3). */
759 if (X509_check_purpose(x, -1, -1) <= 0) {
760 warnx("%s: could not cache X509v3 extensions", fn);
761 goto out;
762 }
763
764 if (X509_get_version(x) != 2) {
765 warnx("%s: RFC 6487 4.1: X.509 version must be v3", fn);
766 goto out;
767 }
768
769 X509_get0_signature(NULL, &palg, x);
770 if (palg == NULL) {
771 warnx("%s: X509_get0_signature", fn);
772 goto out;
773 }
774 X509_ALGOR_get0(&cobj, NULL, NULL, palg);
775 nid = OBJ_obj2nid(cobj);
776 if (experimental && nid == NID_ecdsa_with_SHA256) {
777 if (verbose)
778 warnx("%s: P-256 support is experimental", fn);
779 } else if (nid != NID_sha256WithRSAEncryption) {
780 warnx("%s: RFC 7935: wrong signature algorithm %s, want %s",
781 fn, nid2str(nid), LN_sha256WithRSAEncryption);
782 goto out;
783 }
784
785 X509_get0_uids(x, &piuid, &psuid);
786 if (piuid != NULL || psuid != NULL) {
787 warnx("%s: issuer or subject unique identifiers not allowed",
788 fn);
789 goto out;
790 }
791
792 if (!x509_valid_subject(fn, x))
793 goto out;
794
795 /* Look for X509v3 extensions. */
796 if ((extsz = X509_get_ext_count(x)) <= 0) {
797 warnx("%s: certificate without X.509v3 extensions", fn);
798 goto out;
799 }
800
801 for (i = 0; i < extsz; i++) {
802 ext = X509_get_ext(x, i);
803 assert(ext != NULL);
804 obj = X509_EXTENSION_get_object(ext);
805 assert(obj != NULL);
806
807 switch (nid = OBJ_obj2nid(obj)) {
808 case NID_sbgp_ipAddrBlock:
809 if (ip++ > 0)
810 goto dup;
811 if (!sbgp_ipaddrblk(fn, cert, ext))
812 goto out;
813 break;
814 case NID_sbgp_autonomousSysNum:
815 if (as++ > 0)
816 goto dup;
817 if (!sbgp_assysnum(fn, cert, ext))
818 goto out;
819 break;
820 case NID_sinfo_access:
821 if (sia++ > 0)
822 goto dup;
823 if (!sbgp_sia(fn, cert, ext))
824 goto out;
825 break;
826 case NID_certificate_policies:
827 if (cp++ > 0)
828 goto dup;
829 if (!certificate_policies(fn, cert, ext))
830 goto out;
831 break;
832 case NID_crl_distribution_points:
833 if (crldp++ > 0)
834 goto dup;
835 break;
836 case NID_info_access:
837 if (aia++ > 0)
838 goto dup;
839 break;
840 case NID_authority_key_identifier:
841 if (aki++ > 0)
842 goto dup;
843 break;
844 case NID_subject_key_identifier:
845 if (ski++ > 0)
846 goto dup;
847 break;
848 case NID_ext_key_usage:
849 if (eku++ > 0)
850 goto dup;
851 break;
852 case NID_basic_constraints:
853 if (bc++ > 0)
854 goto dup;
855 break;
856 case NID_key_usage:
857 if (ku++ > 0)
858 goto dup;
859 break;
860 default:
861 /* unexpected extensions warrant investigation */
862 {
863 char objn[64];
864 OBJ_obj2txt(objn, sizeof(objn), obj, 0);
865 warnx("%s: ignoring %s (NID %d)",
866 fn, objn, OBJ_obj2nid(obj));
867 }
868 break;
869 }
870 }
871
872 if (!x509_get_aki(x, fn, &cert->aki))
873 goto out;
874 if (!x509_get_ski(x, fn, &cert->ski))
875 goto out;
876 if (!x509_get_aia(x, fn, &cert->aia))
877 goto out;
878 if (!x509_get_crl(x, fn, &cert->crl))
879 goto out;
880 if (!x509_get_notbefore(x, fn, &cert->notbefore))
881 goto out;
882 if (!x509_get_notafter(x, fn, &cert->notafter))
883 goto out;
884 cert->purpose = x509_get_purpose(x, fn);
885
886 /* Validation on required fields. */
887
888 switch (cert->purpose) {
889 case CERT_PURPOSE_CA:
890 if ((pkey = X509_get0_pubkey(x)) == NULL) {
891 warnx("%s: X509_get0_pubkey failed", fn);
892 goto out;
893 }
894 if (!valid_ca_pkey(fn, pkey))
895 goto out;
896
897 if (X509_get_key_usage(x) != (KU_KEY_CERT_SIGN | KU_CRL_SIGN)) {
898 warnx("%s: RFC 6487 section 4.8.4: key usage violation",
899 fn);
900 goto out;
901 }
902
903 /* EKU may be allowed for some purposes in the future. */
904 if (X509_get_extended_key_usage(x) != UINT32_MAX) {
905 warnx("%s: RFC 6487 section 4.8.5: EKU not allowed",
906 fn);
907 goto out;
908 }
909
910 if (cert->mft == NULL) {
911 warnx("%s: RFC 6487 section 4.8.8: missing SIA", fn);
912 goto out;
913 }
914 if (cert->asz == 0 && cert->ipsz == 0) {
915 warnx("%s: missing IP or AS resources", fn);
916 goto out;
917 }
918 break;
919 case CERT_PURPOSE_BGPSEC_ROUTER:
920 cert->pubkey = x509_get_pubkey(x, fn);
921 if (cert->pubkey == NULL) {
922 warnx("%s: x509_get_pubkey failed", fn);
923 goto out;
924 }
925 if (cert->ipsz > 0) {
926 warnx("%s: unexpected IP resources in BGPsec cert", fn);
927 goto out;
928 }
929 for (j = 0; j < cert->asz; j++) {
930 if (cert->as[j].type == CERT_AS_INHERIT) {
931 warnx("%s: inherit elements not allowed in EE"
932 " cert", fn);
933 goto out;
934 }
935 }
936 if (sia) {
937 warnx("%s: unexpected SIA extension in BGPsec cert",
938 fn);
939 goto out;
940 }
941 break;
942 default:
943 warnx("%s: x509_get_purpose failed in %s", fn, __func__);
944 goto out;
945 }
946
947 if (cert->ski == NULL) {
948 warnx("%s: RFC 6487 section 8.4.2: missing SKI", fn);
949 goto out;
950 }
951
952 cert->x509 = x;
953 return cert;
954
955 dup:
956 warnx("%s: RFC 5280 section 4.2: duplicate extension: %s", fn,
957 nid2str(nid));
958 out:
959 cert_free(cert);
960 X509_free(x);
961 return NULL;
962 }
963
964 struct cert *
cert_parse(const char * fn,struct cert * p)965 cert_parse(const char *fn, struct cert *p)
966 {
967 if (p == NULL)
968 return NULL;
969
970 if (p->aki == NULL) {
971 warnx("%s: RFC 6487 section 8.4.2: "
972 "non-trust anchor missing AKI", fn);
973 goto badcert;
974 }
975 if (strcmp(p->aki, p->ski) == 0) {
976 warnx("%s: RFC 6487 section 8.4.2: "
977 "non-trust anchor AKI may not match SKI", fn);
978 goto badcert;
979 }
980 if (p->aia == NULL) {
981 warnx("%s: RFC 6487 section 8.4.7: AIA: extension missing", fn);
982 goto badcert;
983 }
984 if (p->crl == NULL) {
985 warnx("%s: RFC 6487 section 4.8.6: CRL: "
986 "no CRL distribution point extension", fn);
987 goto badcert;
988 }
989 return p;
990
991 badcert:
992 cert_free(p);
993 return NULL;
994 }
995
996 struct cert *
ta_parse(const char * fn,struct cert * p,const unsigned char * pkey,size_t pkeysz)997 ta_parse(const char *fn, struct cert *p, const unsigned char *pkey,
998 size_t pkeysz)
999 {
1000 ASN1_TIME *notBefore, *notAfter;
1001 EVP_PKEY *pk, *opk;
1002 time_t now = get_current_time();
1003
1004 if (p == NULL)
1005 return NULL;
1006
1007 /* first check pubkey against the one from the TAL */
1008 pk = d2i_PUBKEY(NULL, &pkey, pkeysz);
1009 if (pk == NULL) {
1010 warnx("%s: RFC 6487 (trust anchor): bad TAL pubkey", fn);
1011 goto badcert;
1012 }
1013 if ((opk = X509_get0_pubkey(p->x509)) == NULL) {
1014 warnx("%s: RFC 6487 (trust anchor): missing pubkey", fn);
1015 goto badcert;
1016 }
1017 if (EVP_PKEY_cmp(pk, opk) != 1) {
1018 warnx("%s: RFC 6487 (trust anchor): "
1019 "pubkey does not match TAL pubkey", fn);
1020 goto badcert;
1021 }
1022
1023 if ((notBefore = X509_get_notBefore(p->x509)) == NULL) {
1024 warnx("%s: certificate has invalid notBefore", fn);
1025 goto badcert;
1026 }
1027 if ((notAfter = X509_get_notAfter(p->x509)) == NULL) {
1028 warnx("%s: certificate has invalid notAfter", fn);
1029 goto badcert;
1030 }
1031 if (X509_cmp_time(notBefore, &now) != -1) {
1032 warnx("%s: certificate not yet valid", fn);
1033 goto badcert;
1034 }
1035 if (X509_cmp_time(notAfter, &now) != 1) {
1036 warnx("%s: certificate has expired", fn);
1037 goto badcert;
1038 }
1039 if (p->aki != NULL && strcmp(p->aki, p->ski)) {
1040 warnx("%s: RFC 6487 section 8.4.2: "
1041 "trust anchor AKI, if specified, must match SKI", fn);
1042 goto badcert;
1043 }
1044 if (p->aia != NULL) {
1045 warnx("%s: RFC 6487 section 8.4.7: "
1046 "trust anchor must not have AIA", fn);
1047 goto badcert;
1048 }
1049 if (p->crl != NULL) {
1050 warnx("%s: RFC 6487 section 8.4.2: "
1051 "trust anchor may not specify CRL resource", fn);
1052 goto badcert;
1053 }
1054 if (p->purpose == CERT_PURPOSE_BGPSEC_ROUTER) {
1055 warnx("%s: BGPsec cert cannot be a trust anchor", fn);
1056 goto badcert;
1057 }
1058 if (x509_any_inherits(p->x509)) {
1059 warnx("%s: Trust anchor IP/AS resources may not inherit", fn);
1060 goto badcert;
1061 }
1062
1063 EVP_PKEY_free(pk);
1064 return p;
1065
1066 badcert:
1067 EVP_PKEY_free(pk);
1068 cert_free(p);
1069 return NULL;
1070 }
1071
1072 /*
1073 * Free parsed certificate contents.
1074 * Passing NULL is a noop.
1075 */
1076 void
cert_free(struct cert * p)1077 cert_free(struct cert *p)
1078 {
1079 if (p == NULL)
1080 return;
1081
1082 free(p->crl);
1083 free(p->repo);
1084 free(p->mft);
1085 free(p->notify);
1086 free(p->ips);
1087 free(p->as);
1088 free(p->aia);
1089 free(p->aki);
1090 free(p->ski);
1091 free(p->pubkey);
1092 X509_free(p->x509);
1093 free(p);
1094 }
1095
1096 /*
1097 * Write certificate parsed content into buffer.
1098 * See cert_read() for the other side of the pipe.
1099 */
1100 void
cert_buffer(struct ibuf * b,const struct cert * p)1101 cert_buffer(struct ibuf *b, const struct cert *p)
1102 {
1103 io_simple_buffer(b, &p->notafter, sizeof(p->notafter));
1104 io_simple_buffer(b, &p->purpose, sizeof(p->purpose));
1105 io_simple_buffer(b, &p->talid, sizeof(p->talid));
1106 io_simple_buffer(b, &p->repoid, sizeof(p->repoid));
1107 io_simple_buffer(b, &p->ipsz, sizeof(p->ipsz));
1108 io_simple_buffer(b, &p->asz, sizeof(p->asz));
1109
1110 io_simple_buffer(b, p->ips, p->ipsz * sizeof(p->ips[0]));
1111 io_simple_buffer(b, p->as, p->asz * sizeof(p->as[0]));
1112
1113 io_str_buffer(b, p->mft);
1114 io_str_buffer(b, p->notify);
1115 io_str_buffer(b, p->repo);
1116 io_str_buffer(b, p->crl);
1117 io_str_buffer(b, p->aia);
1118 io_str_buffer(b, p->aki);
1119 io_str_buffer(b, p->ski);
1120 io_str_buffer(b, p->pubkey);
1121 }
1122
1123 /*
1124 * Allocate and read parsed certificate content from descriptor.
1125 * The pointer must be freed with cert_free().
1126 * Always returns a valid pointer.
1127 */
1128 struct cert *
cert_read(struct ibuf * b)1129 cert_read(struct ibuf *b)
1130 {
1131 struct cert *p;
1132
1133 if ((p = calloc(1, sizeof(struct cert))) == NULL)
1134 err(1, NULL);
1135
1136 io_read_buf(b, &p->notafter, sizeof(p->notafter));
1137 io_read_buf(b, &p->purpose, sizeof(p->purpose));
1138 io_read_buf(b, &p->talid, sizeof(p->talid));
1139 io_read_buf(b, &p->repoid, sizeof(p->repoid));
1140 io_read_buf(b, &p->ipsz, sizeof(p->ipsz));
1141 io_read_buf(b, &p->asz, sizeof(p->asz));
1142
1143 p->ips = calloc(p->ipsz, sizeof(struct cert_ip));
1144 if (p->ips == NULL)
1145 err(1, NULL);
1146 io_read_buf(b, p->ips, p->ipsz * sizeof(p->ips[0]));
1147
1148 p->as = calloc(p->asz, sizeof(struct cert_as));
1149 if (p->as == NULL)
1150 err(1, NULL);
1151 io_read_buf(b, p->as, p->asz * sizeof(p->as[0]));
1152
1153 io_read_str(b, &p->mft);
1154 io_read_str(b, &p->notify);
1155 io_read_str(b, &p->repo);
1156 io_read_str(b, &p->crl);
1157 io_read_str(b, &p->aia);
1158 io_read_str(b, &p->aki);
1159 io_read_str(b, &p->ski);
1160 io_read_str(b, &p->pubkey);
1161
1162 assert(p->mft != NULL || p->purpose == CERT_PURPOSE_BGPSEC_ROUTER);
1163 assert(p->ski);
1164 return p;
1165 }
1166
1167 static inline int
authcmp(struct auth * a,struct auth * b)1168 authcmp(struct auth *a, struct auth *b)
1169 {
1170 return strcmp(a->cert->ski, b->cert->ski);
1171 }
1172
1173 RB_GENERATE_STATIC(auth_tree, auth, entry, authcmp);
1174
1175 void
auth_tree_free(struct auth_tree * auths)1176 auth_tree_free(struct auth_tree *auths)
1177 {
1178 struct auth *auth, *tauth;
1179
1180 RB_FOREACH_SAFE(auth, auth_tree, auths, tauth) {
1181 RB_REMOVE(auth_tree, auths, auth);
1182 cert_free(auth->cert);
1183 free(auth);
1184 }
1185 }
1186
1187 struct auth *
auth_find(struct auth_tree * auths,const char * aki)1188 auth_find(struct auth_tree *auths, const char *aki)
1189 {
1190 struct auth a;
1191 struct cert c;
1192
1193 /* we look up the cert where the ski == aki */
1194 c.ski = (char *)aki;
1195 a.cert = &c;
1196
1197 return RB_FIND(auth_tree, auths, &a);
1198 }
1199
1200 struct auth *
auth_insert(struct auth_tree * auths,struct cert * cert,struct auth * issuer)1201 auth_insert(struct auth_tree *auths, struct cert *cert, struct auth *issuer)
1202 {
1203 struct auth *na;
1204
1205 na = malloc(sizeof(*na));
1206 if (na == NULL)
1207 err(1, NULL);
1208
1209 na->issuer = issuer;
1210 na->cert = cert;
1211 na->any_inherits = x509_any_inherits(cert->x509);
1212
1213 if (RB_INSERT(auth_tree, auths, na) != NULL)
1214 err(1, "auth tree corrupted");
1215
1216 return na;
1217 }
1218
1219 static void
insert_brk(struct brk_tree * tree,struct cert * cert,int asid)1220 insert_brk(struct brk_tree *tree, struct cert *cert, int asid)
1221 {
1222 struct brk *b, *found;
1223
1224 if ((b = calloc(1, sizeof(*b))) == NULL)
1225 err(1, NULL);
1226
1227 b->asid = asid;
1228 b->expires = cert->notafter;
1229 b->talid = cert->talid;
1230 if ((b->ski = strdup(cert->ski)) == NULL)
1231 err(1, NULL);
1232 if ((b->pubkey = strdup(cert->pubkey)) == NULL)
1233 err(1, NULL);
1234
1235 /*
1236 * Check if a similar BRK already exists in the tree. If the found BRK
1237 * expires sooner, update it to this BRK's later expiry moment.
1238 */
1239 if ((found = RB_INSERT(brk_tree, tree, b)) != NULL) {
1240 if (found->expires < b->expires) {
1241 found->expires = b->expires;
1242 found->talid = b->talid;
1243 }
1244 free(b->ski);
1245 free(b->pubkey);
1246 free(b);
1247 }
1248 }
1249
1250 /*
1251 * Add each BGPsec Router Key into the BRK tree.
1252 */
1253 void
cert_insert_brks(struct brk_tree * tree,struct cert * cert)1254 cert_insert_brks(struct brk_tree *tree, struct cert *cert)
1255 {
1256 size_t i, asid;
1257
1258 for (i = 0; i < cert->asz; i++) {
1259 switch (cert->as[i].type) {
1260 case CERT_AS_ID:
1261 insert_brk(tree, cert, cert->as[i].id);
1262 break;
1263 case CERT_AS_RANGE:
1264 for (asid = cert->as[i].range.min;
1265 asid <= cert->as[i].range.max; asid++)
1266 insert_brk(tree, cert, asid);
1267 break;
1268 default:
1269 warnx("invalid AS identifier type");
1270 continue;
1271 }
1272 }
1273 }
1274
1275 static inline int
brkcmp(struct brk * a,struct brk * b)1276 brkcmp(struct brk *a, struct brk *b)
1277 {
1278 int rv;
1279
1280 if (a->asid > b->asid)
1281 return 1;
1282 if (a->asid < b->asid)
1283 return -1;
1284
1285 rv = strcmp(a->ski, b->ski);
1286 if (rv > 0)
1287 return 1;
1288 if (rv < 0)
1289 return -1;
1290
1291 return strcmp(a->pubkey, b->pubkey);
1292 }
1293
1294 RB_GENERATE(brk_tree, brk, entry, brkcmp);
1295