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