diff options
Diffstat (limited to 'usr.sbin/rpki-client/x509.c')
-rw-r--r-- | usr.sbin/rpki-client/x509.c | 49 |
1 files changed, 40 insertions, 9 deletions
diff --git a/usr.sbin/rpki-client/x509.c b/usr.sbin/rpki-client/x509.c index 3c0517c89ab..908778c1e82 100644 --- a/usr.sbin/rpki-client/x509.c +++ b/usr.sbin/rpki-client/x509.c @@ -1,4 +1,4 @@ -/* $OpenBSD: x509.c,v 1.95 2024/06/08 13:28:35 tb Exp $ */ +/* $OpenBSD: x509.c,v 1.96 2024/06/08 13:31:38 tb Exp $ */ /* * Copyright (c) 2022 Theo Buehler <tb@openbsd.org> * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org> @@ -266,18 +266,34 @@ x509_get_ski(X509 *x, const char *fn, char **ski) } /* - * Check the certificate's purpose: CA or BGPsec Router. - * Return a member of enum cert_purpose. + * Check the cert's purpose: the cA bit in basic constraints distinguishes + * between TA/CA and EE/BGPsec router. TAs are self-signed, CAs not self-issued, + * EEs have no extended key usage, BGPsec router have id-kp-bgpsec-router OID. */ enum cert_purpose x509_get_purpose(X509 *x, const char *fn) { BASIC_CONSTRAINTS *bc = NULL; EXTENDED_KEY_USAGE *eku = NULL; - int crit; + int crit, ext_flags, is_ca; enum cert_purpose purpose = CERT_PURPOSE_INVALID; - if (X509_check_ca(x) == 1) { + if (!x509_cache_extensions(x, fn)) + goto out; + + ext_flags = X509_get_extension_flags(x); + + /* This weird API can return 0, 1, 2, 4, 5 but can't error... */ + if ((is_ca = X509_check_ca(x)) > 1) { + if (is_ca == 4) + warnx("%s: RFC 6487: sections 4.8.1 and 4.8.4: " + "no basic constraints, but keyCertSign set", fn); + else + warnx("%s: unexpected legacy certificate", fn); + goto out; + } + + if (is_ca) { bc = X509_get_ext_d2i(x, NID_basic_constraints, &crit, NULL); if (bc == NULL) { if (crit != -1) @@ -298,22 +314,37 @@ x509_get_purpose(X509 *x, const char *fn) "Constraint must be absent", fn); goto out; } - purpose = CERT_PURPOSE_CA; - /* XXX - we may want to check EXFLAG_SI and add a TA purpose. */ + /* + * EXFLAG_SI means that issuer and subject are identical. + * EXFLAG_SS is SI plus the AKI is absent or matches the SKI. + * Thus, exactly the trust anchors should have EXFLAG_SS set + * and we should never see EXFLAG_SI without EXFLAG_SS. + */ + if ((ext_flags & EXFLAG_SS) != 0) + purpose = CERT_PURPOSE_TA; + else if ((ext_flags & EXFLAG_SI) == 0) + purpose = CERT_PURPOSE_CA; + else + warnx("%s: RFC 6487, section 4.8.3: " + "self-issued cert with AKI-SKI mismatch", fn); goto out; } - if (X509_get_extension_flags(x) & EXFLAG_BCONS) { + if ((ext_flags & EXFLAG_BCONS) != 0) { warnx("%s: Basic Constraints ext in non-CA cert", fn); goto out; } + /* + * EKU is only defined for BGPsec Router certs and must be absent from + * EE certs. + */ eku = X509_get_ext_d2i(x, NID_ext_key_usage, &crit, NULL); if (eku == NULL) { if (crit != -1) warnx("%s: error parsing EKU", fn); else - warnx("%s: EKU: extension missing", fn); + purpose = CERT_PURPOSE_EE; /* EKU absent */ goto out; } if (crit != 0) { |