Some funky libcrypto business ahead.

X509 API functions such as X509_check_ca() or X509_get_extension_flags()
cache X509v3 extensions internally if they're not already cached. They
make decisions based on (or report some of) the cached values. Although
it's unlikely, this caching may fail halfway through. The result is
fairly random in the case of X509_check_ca() (which can't report an
error itself) - in LibreSSL it would actually return 1 due to a bug I
fixed yesterday. Every use of X509_get_extension_flags() on a cert for
which we don't know that the extensions are cached already should also
check the EXFLAG_INVALID, which is annoying.

An old workaround that used to be used in libssl is to call
X509_check_purpose(x, -1, -1), which is effectively a wrapper around
x509v3_cache_extensions() that allows error checking. This way, the
reported values by the affected API functions are reliable. I suggest to
do this once we get our hands on a cert, so this issue is out of the
way.

Caching of extensions will happen sooner or later anyway, at the latest
within X509_verify_cert(). In LibreSSL this also ensures that the
RFC 3779 extensions are in canonical form before we inspect them which
I think is a good thing.

Index: cert.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
retrieving revision 1.77
diff -u -p -r1.77 cert.c
--- cert.c      11 May 2022 09:40:00 -0000      1.77
+++ cert.c      11 May 2022 13:16:19 -0000
@@ -597,6 +597,12 @@ cert_parse_pre(const char *fn, const uns
                goto out;
        }
 
+       /* Cache X509v3 extensions, see X509_check_ca(3). */
+       if (X509_check_purpose(x, -1, -1) <= 0) {
+               cryptowarnx("%s: could not cache X509v3 extensions", p.fn);
+               goto out;
+       }
+
        /* Look for X509v3 extensions. */
 
        if ((extsz = X509_get_ext_count(x)) < 0)
Index: cms.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/cms.c,v
retrieving revision 1.16
diff -u -p -r1.16 cms.c
--- cms.c       28 Mar 2022 13:04:01 -0000      1.16
+++ cms.c       11 May 2022 13:19:14 -0000
@@ -224,6 +224,12 @@ cms_parse_validate(X509 **xp, const char
        }
        *xp = X509_dup(sk_X509_value(certs, 0));
 
+       /* Cache X509v3 extensions, see X509_check_ca(3). */
+       if (X509_check_purpose(*xp, -1, -1) <= 0) {
+               cryptowarnx("%s: could not cache X509v3 extensions", fn);
+               goto out;
+       }
+
        if (CMS_SignerInfo_get0_signer_id(si, &kid, NULL, NULL) != 1 ||
            kid == NULL) {
                warnx("%s: RFC 6488: could not extract SKI from SID", fn);

Reply via email to