1 /* $OpenBSD: x509.c,v 1.104 2024/10/16 06:09:45 tb Exp $ */
2 /*
3 * Copyright (c) 2022 Theo Buehler <tb@openbsd.org>
4 * Copyright (c) 2021 Claudio Jeker <claudio@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/evp.h>
27 #include <openssl/x509v3.h>
28
29 #include "extern.h"
30
31 ASN1_OBJECT *certpol_oid; /* id-cp-ipAddr-asNumber cert policy */
32 ASN1_OBJECT *carepo_oid; /* 1.3.6.1.5.5.7.48.5 (caRepository) */
33 ASN1_OBJECT *manifest_oid; /* 1.3.6.1.5.5.7.48.10 (rpkiManifest) */
34 ASN1_OBJECT *signedobj_oid; /* 1.3.6.1.5.5.7.48.11 (signedObject) */
35 ASN1_OBJECT *notify_oid; /* 1.3.6.1.5.5.7.48.13 (rpkiNotify) */
36 ASN1_OBJECT *roa_oid; /* id-ct-routeOriginAuthz CMS content type */
37 ASN1_OBJECT *mft_oid; /* id-ct-rpkiManifest CMS content type */
38 ASN1_OBJECT *gbr_oid; /* id-ct-rpkiGhostbusters CMS content type */
39 ASN1_OBJECT *bgpsec_oid; /* id-kp-bgpsec-router Key Purpose */
40 ASN1_OBJECT *cnt_type_oid; /* pkcs-9 id-contentType */
41 ASN1_OBJECT *msg_dgst_oid; /* pkcs-9 id-messageDigest */
42 ASN1_OBJECT *sign_time_oid; /* pkcs-9 id-signingTime */
43 ASN1_OBJECT *rsc_oid; /* id-ct-signedChecklist */
44 ASN1_OBJECT *aspa_oid; /* id-ct-ASPA */
45 ASN1_OBJECT *tak_oid; /* id-ct-SignedTAL */
46 ASN1_OBJECT *geofeed_oid; /* id-ct-geofeedCSVwithCRLF */
47 ASN1_OBJECT *spl_oid; /* id-ct-signedPrefixList */
48
49 static const struct {
50 const char *oid;
51 ASN1_OBJECT **ptr;
52 } oid_table[] = {
53 {
54 .oid = "1.3.6.1.5.5.7.14.2",
55 .ptr = &certpol_oid,
56 },
57 {
58 .oid = "1.3.6.1.5.5.7.48.5",
59 .ptr = &carepo_oid,
60 },
61 {
62 .oid = "1.3.6.1.5.5.7.48.10",
63 .ptr = &manifest_oid,
64 },
65 {
66 .oid = "1.3.6.1.5.5.7.48.11",
67 .ptr = &signedobj_oid,
68 },
69 {
70 .oid = "1.3.6.1.5.5.7.48.13",
71 .ptr = ¬ify_oid,
72 },
73 {
74 .oid = "1.2.840.113549.1.9.16.1.24",
75 .ptr = &roa_oid,
76 },
77 {
78 .oid = "1.2.840.113549.1.9.16.1.26",
79 .ptr = &mft_oid,
80 },
81 {
82 .oid = "1.2.840.113549.1.9.16.1.35",
83 .ptr = &gbr_oid,
84 },
85 {
86 .oid = "1.3.6.1.5.5.7.3.30",
87 .ptr = &bgpsec_oid,
88 },
89 {
90 .oid = "1.2.840.113549.1.9.3",
91 .ptr = &cnt_type_oid,
92 },
93 {
94 .oid = "1.2.840.113549.1.9.4",
95 .ptr = &msg_dgst_oid,
96 },
97 {
98 .oid = "1.2.840.113549.1.9.5",
99 .ptr = &sign_time_oid,
100 },
101 {
102 .oid = "1.2.840.113549.1.9.16.1.47",
103 .ptr = &geofeed_oid,
104 },
105 {
106 .oid = "1.2.840.113549.1.9.16.1.48",
107 .ptr = &rsc_oid,
108 },
109 {
110 .oid = "1.2.840.113549.1.9.16.1.49",
111 .ptr = &aspa_oid,
112 },
113 {
114 .oid = "1.2.840.113549.1.9.16.1.50",
115 .ptr = &tak_oid,
116 },
117 {
118 .oid = "1.2.840.113549.1.9.16.1.51",
119 .ptr = &spl_oid,
120 },
121 };
122
123 void
x509_init_oid(void)124 x509_init_oid(void)
125 {
126 size_t i;
127
128 for (i = 0; i < sizeof(oid_table) / sizeof(oid_table[0]); i++) {
129 *oid_table[i].ptr = OBJ_txt2obj(oid_table[i].oid, 1);
130 if (*oid_table[i].ptr == NULL)
131 errx(1, "OBJ_txt2obj for %s failed", oid_table[i].oid);
132 }
133 }
134
135 /*
136 * A number of critical OpenSSL API functions can't properly indicate failure
137 * and are unreliable if the extensions aren't already cached. An old trick is
138 * to cache the extensions using an error-checked call to X509_check_purpose()
139 * with a purpose of -1. This way functions such as X509_check_ca(), X509_cmp(),
140 * X509_get_key_usage(), X509_get_extended_key_usage() won't lie.
141 *
142 * Should be called right after deserialization and is essentially free to call
143 * multiple times.
144 */
145 int
x509_cache_extensions(X509 * x509,const char * fn)146 x509_cache_extensions(X509 *x509, const char *fn)
147 {
148 if (X509_check_purpose(x509, -1, 0) <= 0) {
149 warnx("%s: could not cache X509v3 extensions", fn);
150 return 0;
151 }
152 return 1;
153 }
154
155 /*
156 * Parse X509v3 authority key identifier (AKI), RFC 6487 sec. 4.8.3.
157 * Returns the AKI or NULL if it could not be parsed.
158 * The AKI is formatted as a hex string.
159 */
160 int
x509_get_aki(X509 * x,const char * fn,char ** aki)161 x509_get_aki(X509 *x, const char *fn, char **aki)
162 {
163 const unsigned char *d;
164 AUTHORITY_KEYID *akid;
165 ASN1_OCTET_STRING *os;
166 int dsz, crit, rc = 0;
167
168 *aki = NULL;
169 akid = X509_get_ext_d2i(x, NID_authority_key_identifier, &crit, NULL);
170 if (akid == NULL) {
171 if (crit != -1) {
172 warnx("%s: RFC 6487 section 4.8.3: error parsing AKI",
173 fn);
174 return 0;
175 }
176 return 1;
177 }
178 if (crit != 0) {
179 warnx("%s: RFC 6487 section 4.8.3: "
180 "AKI: extension not non-critical", fn);
181 goto out;
182 }
183 if (akid->issuer != NULL || akid->serial != NULL) {
184 warnx("%s: RFC 6487 section 4.8.3: AKI: "
185 "authorityCertIssuer or authorityCertSerialNumber present",
186 fn);
187 goto out;
188 }
189
190 os = akid->keyid;
191 if (os == NULL) {
192 warnx("%s: RFC 6487 section 4.8.3: AKI: "
193 "Key Identifier missing", fn);
194 goto out;
195 }
196
197 d = os->data;
198 dsz = os->length;
199
200 if (dsz != SHA_DIGEST_LENGTH) {
201 warnx("%s: RFC 6487 section 4.8.2: AKI: "
202 "want %d bytes SHA1 hash, have %d bytes",
203 fn, SHA_DIGEST_LENGTH, dsz);
204 goto out;
205 }
206
207 *aki = hex_encode(d, dsz);
208 rc = 1;
209 out:
210 AUTHORITY_KEYID_free(akid);
211 return rc;
212 }
213
214 /*
215 * Validate the X509v3 subject key identifier (SKI), RFC 6487 section 4.8.2:
216 * "The SKI is a SHA-1 hash of the value of the DER-encoded ASN.1 BIT STRING of
217 * the Subject Public Key, as described in Section 4.2.1.2 of RFC 5280."
218 * Returns the SKI formatted as hex string, or NULL if it couldn't be parsed.
219 */
220 int
x509_get_ski(X509 * x,const char * fn,char ** ski)221 x509_get_ski(X509 *x, const char *fn, char **ski)
222 {
223 ASN1_OCTET_STRING *os;
224 unsigned char md[EVP_MAX_MD_SIZE];
225 unsigned int md_len = EVP_MAX_MD_SIZE;
226 int crit, rc = 0;
227
228 *ski = NULL;
229 os = X509_get_ext_d2i(x, NID_subject_key_identifier, &crit, NULL);
230 if (os == NULL) {
231 if (crit != -1) {
232 warnx("%s: RFC 6487 section 4.8.2: error parsing SKI",
233 fn);
234 return 0;
235 }
236 return 1;
237 }
238 if (crit != 0) {
239 warnx("%s: RFC 6487 section 4.8.2: "
240 "SKI: extension not non-critical", fn);
241 goto out;
242 }
243
244 if (!X509_pubkey_digest(x, EVP_sha1(), md, &md_len)) {
245 warnx("%s: X509_pubkey_digest", fn);
246 goto out;
247 }
248
249 if (os->length < 0 || md_len != (size_t)os->length) {
250 warnx("%s: RFC 6487 section 4.8.2: SKI: "
251 "want %u bytes SHA1 hash, have %d bytes",
252 fn, md_len, os->length);
253 goto out;
254 }
255
256 if (memcmp(os->data, md, md_len) != 0) {
257 warnx("%s: SKI does not match SHA1 hash of SPK", fn);
258 goto out;
259 }
260
261 *ski = hex_encode(md, md_len);
262 rc = 1;
263 out:
264 ASN1_OCTET_STRING_free(os);
265 return rc;
266 }
267
268 /*
269 * Check the cert's purpose: the cA bit in basic constraints distinguishes
270 * between TA/CA and EE/BGPsec router and the key usage bits must match.
271 * TAs are self-signed, CAs not self-issued, EEs have no extended key usage,
272 * BGPsec router have id-kp-bgpsec-router OID.
273 */
274 enum cert_purpose
x509_get_purpose(X509 * x,const char * fn)275 x509_get_purpose(X509 *x, const char *fn)
276 {
277 BASIC_CONSTRAINTS *bc = NULL;
278 EXTENDED_KEY_USAGE *eku = NULL;
279 const X509_EXTENSION *ku;
280 int crit, ext_flags, i, is_ca, ku_idx;
281 enum cert_purpose purpose = CERT_PURPOSE_INVALID;
282
283 if (!x509_cache_extensions(x, fn))
284 goto out;
285
286 ext_flags = X509_get_extension_flags(x);
287
288 /* Key usage must be present and critical. KU bits are checked below. */
289 if ((ku_idx = X509_get_ext_by_NID(x, NID_key_usage, -1)) < 0) {
290 warnx("%s: RFC 6487, section 4.8.4: missing KeyUsage", fn);
291 goto out;
292 }
293 if ((ku = X509_get_ext(x, ku_idx)) == NULL) {
294 warnx("%s: RFC 6487, section 4.8.4: missing KeyUsage", fn);
295 goto out;
296 }
297 if (!X509_EXTENSION_get_critical(ku)) {
298 warnx("%s: RFC 6487, section 4.8.4: KeyUsage not critical", fn);
299 goto out;
300 }
301
302 /* This weird API can return 0, 1, 2, 4, 5 but can't error... */
303 if ((is_ca = X509_check_ca(x)) > 1) {
304 if (is_ca == 4)
305 warnx("%s: RFC 6487: sections 4.8.1 and 4.8.4: "
306 "no basic constraints, but keyCertSign set", fn);
307 else
308 warnx("%s: unexpected legacy certificate", fn);
309 goto out;
310 }
311
312 if (is_ca) {
313 bc = X509_get_ext_d2i(x, NID_basic_constraints, &crit, NULL);
314 if (bc == NULL) {
315 if (crit != -1)
316 warnx("%s: RFC 6487 section 4.8.1: "
317 "error parsing basic constraints", fn);
318 else
319 warnx("%s: RFC 6487 section 4.8.1: "
320 "missing basic constraints", fn);
321 goto out;
322 }
323 if (crit != 1) {
324 warnx("%s: RFC 6487 section 4.8.1: Basic Constraints "
325 "must be marked critical", fn);
326 goto out;
327 }
328 if (bc->pathlen != NULL) {
329 warnx("%s: RFC 6487 section 4.8.1: Path Length "
330 "Constraint must be absent", fn);
331 goto out;
332 }
333
334 if (X509_get_key_usage(x) != (KU_KEY_CERT_SIGN | KU_CRL_SIGN)) {
335 warnx("%s: RFC 6487 section 4.8.4: key usage violation",
336 fn);
337 goto out;
338 }
339
340 if (X509_get_extended_key_usage(x) != UINT32_MAX) {
341 warnx("%s: RFC 6487 section 4.8.5: EKU not allowed",
342 fn);
343 goto out;
344 }
345
346 /*
347 * EXFLAG_SI means that issuer and subject are identical.
348 * EXFLAG_SS is SI plus the AKI is absent or matches the SKI.
349 * Thus, exactly the trust anchors should have EXFLAG_SS set
350 * and we should never see EXFLAG_SI without EXFLAG_SS.
351 */
352 if ((ext_flags & EXFLAG_SS) != 0)
353 purpose = CERT_PURPOSE_TA;
354 else if ((ext_flags & EXFLAG_SI) == 0)
355 purpose = CERT_PURPOSE_CA;
356 else
357 warnx("%s: RFC 6487, section 4.8.3: "
358 "self-issued cert with AKI-SKI mismatch", fn);
359 goto out;
360 }
361
362 if ((ext_flags & EXFLAG_BCONS) != 0) {
363 warnx("%s: Basic Constraints ext in non-CA cert", fn);
364 goto out;
365 }
366
367 if (X509_get_key_usage(x) != KU_DIGITAL_SIGNATURE) {
368 warnx("%s: RFC 6487 section 4.8.4: KU must be digitalSignature",
369 fn);
370 goto out;
371 }
372
373 /*
374 * EKU is only defined for BGPsec Router certs and must be absent from
375 * EE certs.
376 */
377 eku = X509_get_ext_d2i(x, NID_ext_key_usage, &crit, NULL);
378 if (eku == NULL) {
379 if (crit != -1)
380 warnx("%s: error parsing EKU", fn);
381 else
382 purpose = CERT_PURPOSE_EE; /* EKU absent */
383 goto out;
384 }
385 if (crit != 0) {
386 warnx("%s: EKU: extension must not be marked critical", fn);
387 goto out;
388 }
389
390 /*
391 * Per RFC 8209, section 3.1.3.2 the id-kp-bgpsec-router OID must be
392 * present and others are allowed, which we don't need to recognize.
393 * This matches RFC 5280, section 4.2.1.12.
394 */
395 for (i = 0; i < sk_ASN1_OBJECT_num(eku); i++) {
396 if (OBJ_cmp(bgpsec_oid, sk_ASN1_OBJECT_value(eku, i)) == 0) {
397 purpose = CERT_PURPOSE_BGPSEC_ROUTER;
398 break;
399 }
400 }
401
402 out:
403 BASIC_CONSTRAINTS_free(bc);
404 EXTENDED_KEY_USAGE_free(eku);
405 return purpose;
406 }
407
408 /*
409 * Extract Subject Public Key Info (SPKI) from BGPsec X.509 Certificate.
410 * Returns NULL on failure, on success return the SPKI as base64 encoded pubkey
411 */
412 char *
x509_get_pubkey(X509 * x,const char * fn)413 x509_get_pubkey(X509 *x, const char *fn)
414 {
415 EVP_PKEY *pkey;
416 const EC_KEY *eckey;
417 int nid;
418 const char *cname;
419 uint8_t *pubkey = NULL;
420 char *res = NULL;
421 int len;
422
423 pkey = X509_get0_pubkey(x);
424 if (pkey == NULL) {
425 warnx("%s: X509_get0_pubkey failed in %s", fn, __func__);
426 goto out;
427 }
428 if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) {
429 warnx("%s: Expected EVP_PKEY_EC, got %d", fn,
430 EVP_PKEY_base_id(pkey));
431 goto out;
432 }
433
434 eckey = EVP_PKEY_get0_EC_KEY(pkey);
435 if (eckey == NULL) {
436 warnx("%s: Incorrect key type", fn);
437 goto out;
438 }
439
440 nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(eckey));
441 if (nid != NID_X9_62_prime256v1) {
442 if ((cname = EC_curve_nid2nist(nid)) == NULL)
443 cname = nid2str(nid);
444 warnx("%s: Expected P-256, got %s", fn, cname);
445 goto out;
446 }
447
448 if (!EC_KEY_check_key(eckey)) {
449 warnx("%s: EC_KEY_check_key failed in %s", fn, __func__);
450 goto out;
451 }
452
453 len = i2d_PUBKEY(pkey, &pubkey);
454 if (len <= 0) {
455 warnx("%s: i2d_PUBKEY failed in %s", fn, __func__);
456 goto out;
457 }
458
459 if (base64_encode(pubkey, len, &res) == -1)
460 errx(1, "base64_encode failed in %s", __func__);
461
462 out:
463 free(pubkey);
464 return res;
465 }
466
467 /*
468 * Compute the SKI of an RSA public key in an X509_PUBKEY using SHA-1.
469 * Returns allocated hex-encoded SKI on success, NULL on failure.
470 */
471 char *
x509_pubkey_get_ski(X509_PUBKEY * pubkey,const char * fn)472 x509_pubkey_get_ski(X509_PUBKEY *pubkey, const char *fn)
473 {
474 ASN1_OBJECT *obj;
475 const unsigned char *der;
476 int der_len, nid;
477 unsigned char md[EVP_MAX_MD_SIZE];
478 unsigned int md_len = EVP_MAX_MD_SIZE;
479
480 if (!X509_PUBKEY_get0_param(&obj, &der, &der_len, NULL, pubkey)) {
481 warnx("%s: X509_PUBKEY_get0_param failed", fn);
482 return NULL;
483 }
484
485 /* XXX - should allow other keys as well. */
486 if ((nid = OBJ_obj2nid(obj)) != NID_rsaEncryption) {
487 warnx("%s: RFC 7935: wrong signature algorithm %s, want %s",
488 fn, nid2str(nid), LN_rsaEncryption);
489 return NULL;
490 }
491
492 if (!EVP_Digest(der, der_len, md, &md_len, EVP_sha1(), NULL)) {
493 warnx("%s: EVP_Digest failed", fn);
494 return NULL;
495 }
496
497 return hex_encode(md, md_len);
498 }
499
500 /*
501 * Parse the Authority Information Access (AIA) extension
502 * See RFC 6487, section 4.8.7 for details.
503 * Returns NULL on failure, on success returns the AIA URI
504 * (which has to be freed after use).
505 */
506 int
x509_get_aia(X509 * x,const char * fn,char ** out_aia)507 x509_get_aia(X509 *x, const char *fn, char **out_aia)
508 {
509 ACCESS_DESCRIPTION *ad;
510 AUTHORITY_INFO_ACCESS *info;
511 int crit, rc = 0;
512
513 assert(*out_aia == NULL);
514
515 info = X509_get_ext_d2i(x, NID_info_access, &crit, NULL);
516 if (info == NULL) {
517 if (crit != -1) {
518 warnx("%s: RFC 6487 section 4.8.7: error parsing AIA",
519 fn);
520 return 0;
521 }
522 return 1;
523 }
524
525 if (crit != 0) {
526 warnx("%s: RFC 6487 section 4.8.7: "
527 "AIA: extension not non-critical", fn);
528 goto out;
529 }
530
531 if ((X509_get_extension_flags(x) & EXFLAG_SS) != 0) {
532 warnx("%s: RFC 6487 section 4.8.7: AIA must be absent from "
533 "a self-signed certificate", fn);
534 goto out;
535 }
536
537 if (sk_ACCESS_DESCRIPTION_num(info) != 1) {
538 warnx("%s: RFC 6487 section 4.8.7: AIA: "
539 "want 1 element, have %d", fn,
540 sk_ACCESS_DESCRIPTION_num(info));
541 goto out;
542 }
543
544 ad = sk_ACCESS_DESCRIPTION_value(info, 0);
545 if (OBJ_obj2nid(ad->method) != NID_ad_ca_issuers) {
546 warnx("%s: RFC 6487 section 4.8.7: AIA: "
547 "expected caIssuers, have %d", fn, OBJ_obj2nid(ad->method));
548 goto out;
549 }
550
551 if (!x509_location(fn, "AIA: caIssuers", ad->location, out_aia))
552 goto out;
553
554 rc = 1;
555
556 out:
557 AUTHORITY_INFO_ACCESS_free(info);
558 return rc;
559 }
560
561 /*
562 * Parse the Subject Information Access (SIA) extension for an EE cert.
563 * See RFC 6487, section 4.8.8.2 for details.
564 * Returns NULL on failure, on success returns the SIA signedObject URI
565 * (which has to be freed after use).
566 */
567 int
x509_get_sia(X509 * x,const char * fn,char ** out_sia)568 x509_get_sia(X509 *x, const char *fn, char **out_sia)
569 {
570 ACCESS_DESCRIPTION *ad;
571 AUTHORITY_INFO_ACCESS *info;
572 ASN1_OBJECT *oid;
573 int i, crit, rc = 0;
574
575 assert(*out_sia == NULL);
576
577 info = X509_get_ext_d2i(x, NID_sinfo_access, &crit, NULL);
578 if (info == NULL) {
579 if (crit != -1) {
580 warnx("%s: error parsing SIA", fn);
581 return 0;
582 }
583 return 1;
584 }
585
586 if (crit != 0) {
587 warnx("%s: RFC 6487 section 4.8.8: "
588 "SIA: extension not non-critical", fn);
589 goto out;
590 }
591
592 for (i = 0; i < sk_ACCESS_DESCRIPTION_num(info); i++) {
593 char *sia;
594
595 ad = sk_ACCESS_DESCRIPTION_value(info, i);
596 oid = ad->method;
597
598 /*
599 * XXX: RFC 6487 4.8.8.2 states that the accessMethod MUST be
600 * signedObject. However, rpkiNotify accessMethods currently
601 * exist in the wild. Consider removing this special case.
602 * See also https://www.rfc-editor.org/errata/eid7239.
603 */
604 if (OBJ_cmp(oid, notify_oid) == 0) {
605 if (verbose > 1)
606 warnx("%s: RFC 6487 section 4.8.8.2: SIA should"
607 " not contain rpkiNotify accessMethod", fn);
608 continue;
609 }
610 if (OBJ_cmp(oid, signedobj_oid) != 0) {
611 char buf[128];
612
613 OBJ_obj2txt(buf, sizeof(buf), oid, 0);
614 warnx("%s: RFC 6487 section 4.8.8.2: unexpected"
615 " accessMethod: %s", fn, buf);
616 goto out;
617 }
618
619 sia = NULL;
620 if (!x509_location(fn, "SIA: signedObject", ad->location, &sia))
621 goto out;
622
623 if (*out_sia == NULL && strncasecmp(sia, RSYNC_PROTO,
624 RSYNC_PROTO_LEN) == 0) {
625 const char *p = sia + RSYNC_PROTO_LEN;
626 size_t fnlen, plen;
627
628 if (filemode) {
629 *out_sia = sia;
630 continue;
631 }
632
633 fnlen = strlen(fn);
634 plen = strlen(p);
635
636 if (fnlen < plen || strcmp(p, fn + fnlen - plen) != 0) {
637 warnx("%s: mismatch between pathname and SIA "
638 "(%s)", fn, sia);
639 free(sia);
640 goto out;
641 }
642
643 *out_sia = sia;
644 continue;
645 }
646 if (verbose)
647 warnx("%s: RFC 6487 section 4.8.8: SIA: "
648 "ignoring location %s", fn, sia);
649 free(sia);
650 }
651
652 if (*out_sia == NULL) {
653 warnx("%s: RFC 6487 section 4.8.8.2: "
654 "SIA without rsync accessLocation", fn);
655 goto out;
656 }
657
658 rc = 1;
659
660 out:
661 AUTHORITY_INFO_ACCESS_free(info);
662 return rc;
663 }
664
665 /*
666 * Extract the notBefore of a certificate.
667 */
668 int
x509_get_notbefore(X509 * x,const char * fn,time_t * tt)669 x509_get_notbefore(X509 *x, const char *fn, time_t *tt)
670 {
671 const ASN1_TIME *at;
672
673 at = X509_get0_notBefore(x);
674 if (at == NULL) {
675 warnx("%s: X509_get0_notBefore failed", fn);
676 return 0;
677 }
678 if (!x509_get_time(at, tt)) {
679 warnx("%s: ASN1_TIME_to_tm failed", fn);
680 return 0;
681 }
682 return 1;
683 }
684
685 /*
686 * Extract the notAfter from a certificate.
687 */
688 int
x509_get_notafter(X509 * x,const char * fn,time_t * tt)689 x509_get_notafter(X509 *x, const char *fn, time_t *tt)
690 {
691 const ASN1_TIME *at;
692
693 at = X509_get0_notAfter(x);
694 if (at == NULL) {
695 warnx("%s: X509_get0_notafter failed", fn);
696 return 0;
697 }
698 if (!x509_get_time(at, tt)) {
699 warnx("%s: ASN1_TIME_to_tm failed", fn);
700 return 0;
701 }
702 return 1;
703 }
704
705 /*
706 * Check whether all RFC 3779 extensions are set to inherit.
707 * Return 1 if both AS & IP are set to inherit.
708 * Return 0 on failure (such as missing extensions or no inheritance).
709 */
710 int
x509_inherits(X509 * x)711 x509_inherits(X509 *x)
712 {
713 STACK_OF(IPAddressFamily) *addrblk = NULL;
714 ASIdentifiers *asidentifiers = NULL;
715 const IPAddressFamily *af;
716 int crit, i, rc = 0;
717
718 addrblk = X509_get_ext_d2i(x, NID_sbgp_ipAddrBlock, &crit, NULL);
719 if (addrblk == NULL) {
720 if (crit != -1)
721 warnx("error parsing ipAddrBlock");
722 goto out;
723 }
724
725 /*
726 * Check by hand, since X509v3_addr_inherits() success only means that
727 * at least one address family inherits, not all of them.
728 */
729 for (i = 0; i < sk_IPAddressFamily_num(addrblk); i++) {
730 af = sk_IPAddressFamily_value(addrblk, i);
731 if (af->ipAddressChoice->type != IPAddressChoice_inherit)
732 goto out;
733 }
734
735 asidentifiers = X509_get_ext_d2i(x, NID_sbgp_autonomousSysNum, NULL,
736 NULL);
737 if (asidentifiers == NULL) {
738 if (crit != -1)
739 warnx("error parsing asIdentifiers");
740 goto out;
741 }
742
743 /* We need to have AS numbers and don't want RDIs. */
744 if (asidentifiers->asnum == NULL || asidentifiers->rdi != NULL)
745 goto out;
746 if (!X509v3_asid_inherits(asidentifiers))
747 goto out;
748
749 rc = 1;
750 out:
751 ASIdentifiers_free(asidentifiers);
752 sk_IPAddressFamily_pop_free(addrblk, IPAddressFamily_free);
753 return rc;
754 }
755
756 /*
757 * Check whether at least one RFC 3779 extension is set to inherit.
758 * Return 1 if an inherit element is encountered in AS or IP.
759 * Return 0 otherwise.
760 */
761 int
x509_any_inherits(X509 * x)762 x509_any_inherits(X509 *x)
763 {
764 STACK_OF(IPAddressFamily) *addrblk = NULL;
765 ASIdentifiers *asidentifiers = NULL;
766 int crit, rc = 0;
767
768 addrblk = X509_get_ext_d2i(x, NID_sbgp_ipAddrBlock, &crit, NULL);
769 if (addrblk == NULL && crit != -1)
770 warnx("error parsing ipAddrBlock");
771 if (X509v3_addr_inherits(addrblk))
772 rc = 1;
773
774 asidentifiers = X509_get_ext_d2i(x, NID_sbgp_autonomousSysNum, &crit,
775 NULL);
776 if (asidentifiers == NULL && crit != -1)
777 warnx("error parsing asIdentifiers");
778 if (X509v3_asid_inherits(asidentifiers))
779 rc = 1;
780
781 ASIdentifiers_free(asidentifiers);
782 sk_IPAddressFamily_pop_free(addrblk, IPAddressFamily_free);
783 return rc;
784 }
785
786 /*
787 * Parse the very specific subset of information in the CRL distribution
788 * point extension.
789 * See RFC 6487, section 4.8.6 for details.
790 * Returns NULL on failure, the crl URI on success which has to be freed
791 * after use.
792 */
793 int
x509_get_crl(X509 * x,const char * fn,char ** out_crl)794 x509_get_crl(X509 *x, const char *fn, char **out_crl)
795 {
796 CRL_DIST_POINTS *crldp;
797 DIST_POINT *dp;
798 GENERAL_NAMES *names;
799 GENERAL_NAME *name;
800 int i, crit, rc = 0;
801
802 assert(*out_crl == NULL);
803
804 crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, &crit, NULL);
805 if (crldp == NULL) {
806 if (crit != -1) {
807 warnx("%s: RFC 6487 section 4.8.6: failed to parse "
808 "CRL distribution points", fn);
809 return 0;
810 }
811 return 1;
812 }
813
814 if (crit != 0) {
815 warnx("%s: RFC 6487 section 4.8.6: "
816 "CRL distribution point: extension not non-critical", fn);
817 goto out;
818 }
819
820 if (sk_DIST_POINT_num(crldp) != 1) {
821 warnx("%s: RFC 6487 section 4.8.6: CRL: "
822 "want 1 element, have %d", fn,
823 sk_DIST_POINT_num(crldp));
824 goto out;
825 }
826
827 dp = sk_DIST_POINT_value(crldp, 0);
828 if (dp->CRLissuer != NULL) {
829 warnx("%s: RFC 6487 section 4.8.6: CRL CRLIssuer field"
830 " disallowed", fn);
831 goto out;
832 }
833 if (dp->reasons != NULL) {
834 warnx("%s: RFC 6487 section 4.8.6: CRL Reasons field"
835 " disallowed", fn);
836 goto out;
837 }
838 if (dp->distpoint == NULL) {
839 warnx("%s: RFC 6487 section 4.8.6: CRL: "
840 "no distribution point name", fn);
841 goto out;
842 }
843 if (dp->distpoint->dpname != NULL) {
844 warnx("%s: RFC 6487 section 4.8.6: nameRelativeToCRLIssuer"
845 " disallowed", fn);
846 goto out;
847 }
848 /* Need to hardcode the alternative 0 due to missing macros or enum. */
849 if (dp->distpoint->type != 0) {
850 warnx("%s: RFC 6487 section 4.8.6: CRL DistributionPointName:"
851 " expected fullName, have %d", fn, dp->distpoint->type);
852 goto out;
853 }
854
855 names = dp->distpoint->name.fullname;
856 for (i = 0; i < sk_GENERAL_NAME_num(names); i++) {
857 char *crl = NULL;
858
859 name = sk_GENERAL_NAME_value(names, i);
860
861 if (!x509_location(fn, "CRL distribution point", name, &crl))
862 goto out;
863
864 if (*out_crl == NULL && strncasecmp(crl, RSYNC_PROTO,
865 RSYNC_PROTO_LEN) == 0) {
866 *out_crl = crl;
867 continue;
868 }
869 if (verbose)
870 warnx("%s: ignoring CRL distribution point %s",
871 fn, crl);
872 free(crl);
873 }
874
875 if (*out_crl == NULL) {
876 warnx("%s: RFC 6487 section 4.8.6: no rsync URI "
877 "in CRL distributionPoint", fn);
878 goto out;
879 }
880
881 rc = 1;
882
883 out:
884 CRL_DIST_POINTS_free(crldp);
885 return rc;
886 }
887
888 /*
889 * Convert passed ASN1_TIME to time_t *t.
890 * Returns 1 on success and 0 on failure.
891 */
892 int
x509_get_time(const ASN1_TIME * at,time_t * t)893 x509_get_time(const ASN1_TIME *at, time_t *t)
894 {
895 struct tm tm;
896
897 *t = 0;
898 memset(&tm, 0, sizeof(tm));
899 /* Fail instead of silently falling back to the current time. */
900 if (at == NULL)
901 return 0;
902 if (!ASN1_TIME_to_tm(at, &tm))
903 return 0;
904 if ((*t = timegm(&tm)) == -1)
905 errx(1, "timegm failed");
906 return 1;
907 }
908
909 /*
910 * Extract and validate an accessLocation, RFC 6487, 4.8 and RFC 8182, 3.2.
911 * Returns 0 on failure and 1 on success.
912 */
913 int
x509_location(const char * fn,const char * descr,GENERAL_NAME * location,char ** out)914 x509_location(const char *fn, const char *descr, GENERAL_NAME *location,
915 char **out)
916 {
917 ASN1_IA5STRING *uri;
918
919 assert(*out == NULL);
920
921 if (location->type != GEN_URI) {
922 warnx("%s: RFC 6487 section 4.8: %s not URI", fn, descr);
923 return 0;
924 }
925
926 uri = location->d.uniformResourceIdentifier;
927
928 if (!valid_uri(uri->data, uri->length, NULL)) {
929 warnx("%s: RFC 6487 section 4.8: %s bad location", fn, descr);
930 return 0;
931 }
932
933 if ((*out = strndup(uri->data, uri->length)) == NULL)
934 err(1, NULL);
935
936 return 1;
937 }
938
939 /*
940 * Check that subject or issuer only contain commonName and serialNumber.
941 * Return 0 on failure.
942 */
943 int
x509_valid_name(const char * fn,const char * descr,const X509_NAME * xn)944 x509_valid_name(const char *fn, const char *descr, const X509_NAME *xn)
945 {
946 const X509_NAME_ENTRY *ne;
947 const ASN1_OBJECT *ao;
948 const ASN1_STRING *as;
949 int cn = 0, sn = 0;
950 int i, nid;
951
952 for (i = 0; i < X509_NAME_entry_count(xn); i++) {
953 if ((ne = X509_NAME_get_entry(xn, i)) == NULL) {
954 warnx("%s: X509_NAME_get_entry", fn);
955 return 0;
956 }
957 if ((ao = X509_NAME_ENTRY_get_object(ne)) == NULL) {
958 warnx("%s: X509_NAME_ENTRY_get_object", fn);
959 return 0;
960 }
961
962 nid = OBJ_obj2nid(ao);
963 switch (nid) {
964 case NID_commonName:
965 if (cn++ > 0) {
966 warnx("%s: duplicate commonName in %s",
967 fn, descr);
968 return 0;
969 }
970 if ((as = X509_NAME_ENTRY_get_data(ne)) == NULL) {
971 warnx("%s: X509_NAME_ENTRY_get_data failed",
972 fn);
973 return 0;
974 }
975 /*
976 * The following check can be enabled after AFRINIC re-issues CA certs.
977 * https://lists.afrinic.net/pipermail/dbwg/2023-March/000436.html
978 */
979 #if 0
980 /*
981 * XXX - For some reason RFC 8209, section 3.1.1 decided
982 * to allow UTF8String for BGPsec Router Certificates.
983 */
984 if (ASN1_STRING_type(as) != V_ASN1_PRINTABLESTRING) {
985 warnx("%s: RFC 6487 section 4.5: commonName is"
986 " not PrintableString", fn);
987 return 0;
988 }
989 #endif
990 break;
991 case NID_serialNumber:
992 if (sn++ > 0) {
993 warnx("%s: duplicate serialNumber in %s",
994 fn, descr);
995 return 0;
996 }
997 break;
998 case NID_undef:
999 warnx("%s: OBJ_obj2nid failed", fn);
1000 return 0;
1001 default:
1002 warnx("%s: RFC 6487 section 4.5: unexpected attribute"
1003 " %s in %s", fn, nid2str(nid), descr);
1004 return 0;
1005 }
1006 }
1007
1008 if (cn == 0) {
1009 warnx("%s: RFC 6487 section 4.5: %s missing commonName",
1010 fn, descr);
1011 return 0;
1012 }
1013
1014 return 1;
1015 }
1016
1017 /*
1018 * Check ASN1_INTEGER is non-negative and fits in 20 octets.
1019 * Returns allocated BIGNUM if true, NULL otherwise.
1020 */
1021 static BIGNUM *
x509_seqnum_to_bn(const char * fn,const char * descr,const ASN1_INTEGER * i)1022 x509_seqnum_to_bn(const char *fn, const char *descr, const ASN1_INTEGER *i)
1023 {
1024 BIGNUM *bn = NULL;
1025
1026 if ((bn = ASN1_INTEGER_to_BN(i, NULL)) == NULL) {
1027 warnx("%s: %s: ASN1_INTEGER_to_BN error", fn, descr);
1028 goto out;
1029 }
1030
1031 if (BN_is_negative(bn)) {
1032 warnx("%s: %s should be non-negative", fn, descr);
1033 goto out;
1034 }
1035
1036 /* Reject values larger than or equal to 2^159. */
1037 if (BN_num_bytes(bn) > 20 || BN_is_bit_set(bn, 159)) {
1038 warnx("%s: %s should fit in 20 octets", fn, descr);
1039 goto out;
1040 }
1041
1042 return bn;
1043
1044 out:
1045 BN_free(bn);
1046 return NULL;
1047 }
1048
1049 /*
1050 * Convert an ASN1_INTEGER into a hexstring, enforcing that it is non-negative
1051 * and representable by at most 20 octets (RFC 5280, section 4.1.2.2).
1052 * Returned string needs to be freed by the caller.
1053 */
1054 char *
x509_convert_seqnum(const char * fn,const char * descr,const ASN1_INTEGER * i)1055 x509_convert_seqnum(const char *fn, const char *descr, const ASN1_INTEGER *i)
1056 {
1057 BIGNUM *bn = NULL;
1058 char *s = NULL;
1059
1060 if (i == NULL)
1061 goto out;
1062
1063 if ((bn = x509_seqnum_to_bn(fn, descr, i)) == NULL)
1064 goto out;
1065
1066 if ((s = BN_bn2hex(bn)) == NULL)
1067 warnx("%s: %s: BN_bn2hex error", fn, descr);
1068
1069 out:
1070 BN_free(bn);
1071 return s;
1072 }
1073
1074 int
x509_valid_seqnum(const char * fn,const char * descr,const ASN1_INTEGER * i)1075 x509_valid_seqnum(const char *fn, const char *descr, const ASN1_INTEGER *i)
1076 {
1077 BIGNUM *bn;
1078
1079 if ((bn = x509_seqnum_to_bn(fn, descr, i)) == NULL)
1080 return 0;
1081
1082 BN_free(bn);
1083 return 1;
1084 }
1085
1086 /*
1087 * Find the closest expiry moment by walking the chain of authorities.
1088 */
1089 time_t
x509_find_expires(time_t notafter,struct auth * a,struct crl_tree * crlt)1090 x509_find_expires(time_t notafter, struct auth *a, struct crl_tree *crlt)
1091 {
1092 struct crl *crl;
1093 time_t expires;
1094
1095 expires = notafter;
1096
1097 for (; a != NULL; a = a->issuer) {
1098 if (expires > a->cert->notafter)
1099 expires = a->cert->notafter;
1100 crl = crl_get(crlt, a);
1101 if (crl != NULL && expires > crl->nextupdate)
1102 expires = crl->nextupdate;
1103 }
1104
1105 return expires;
1106 }
1107