From: Theo Buehler Subject: rpki-client: const shuffling for openssl 4 To: tech@openbsd.org Date: Sat, 28 Mar 2026 10:21:15 +0100 OpenSSL 4 went on a const sprinkling spree which requires us to think about how we can compile cleanly with various versions of the libs so we can catch more serious warnings. We can adapt the xissuer in print.c to be const. It hasn't been const because X509_get_issuer_name() isn't const correct. cert.c is a bit tricky even if it only parses things and hence doesn't modify libcrypto objects it doesn't own. There are two pieces to the puzzle. In cert_check_spki() the pubkey is a libcrypto-internal pointer hanging off cert->x509, which is then passed to the very const-incorrect getter X509_PUBKEY_get0_param(): that's a piece of art which hands back pointers to things deeper down in the x509 - some of them const, some non-const. OpenSSL 3 made its X509_PUBKEY argument const, but their X509_ALGOR ** still isn't. I don't believe they thought about it in #11894 as they had a _cmp() vs _eq() bikeshed to sort out. Our choices are to cast the pubkey coming from X509_get_X509_PUBKEY() or the one passed to X509_PUBKEY_get0_param(). Since the latter call is tricky I chose the former. Of course I saved the best for last: The individual extension handlers don't take a const X509_EXTENSION * mainly because each of them calls X509V3_EXT_d2i() which should have been const but isn't. We could cast away const in all nine of its callers, which might be the least evil approach if we can live with a it of churn. That works out nicely except that we also need to cast the ext passed to X509_EXTENSION_get_object(). Happy to go this way if you prefer that. As an aside, a single wrapper function that allows casting away const only once seems a bad idea: /* * Decode extension data from DER. It's the caller's responsibility to * assign the return value to the correct pointer type and to free it. */ static void * cert_yolo_decode_extension_data(const X509_EXTENSION *ext) { /* XXX - const correct only in OpenSSL 4. */ return X509V3_EXT_d2i((X509_EXTENSION *)ext); } I don't see how to add belts and suspenders to make this interface less terrible and trappy. Yet another approach is the below: cast away const from X509_get_ext(). "grep -w ext cert.c" will show you that ext is only passed to X509V3_EXT_d2i() and X509_EXTENSION_get_object() already mentioned above and to X509_EXTENSION_get_critical() which is already const correct. Index: cert.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v diff -u -p -r1.224 cert.c --- cert.c 3 Feb 2026 16:21:37 -0000 1.224 +++ cert.c 27 Mar 2026 20:04:04 -0000 @@ -354,8 +354,12 @@ cert_check_spki(const char *fn, struct c const void *pval = NULL; int rc = 0; - /* Should be called _get0_. It returns a pointer owned by cert->x509. */ - if ((pubkey = X509_get_X509_PUBKEY(cert->x509)) == NULL) { + /* + * Should be called _get0_. It returns a pointer owned by cert->x509. + * XXX - cast away const for OpenSSL 4. + */ + pubkey = (X509_PUBKEY *)X509_get_X509_PUBKEY(cert->x509); + if (pubkey == NULL) { warnx("%s: RFC 6487, 4.7: certificate without SPKI", fn); goto out; } @@ -1499,7 +1503,7 @@ cert_parse_extensions(const char *fn, st { X509 *x = cert->x509; X509_EXTENSION *ext; - ASN1_OBJECT *obj; + const ASN1_OBJECT *obj; int extsz, i, nid; int bc, ski, aki, ku, eku, crldp, aia, sia, cp, ip, as; @@ -1515,7 +1519,8 @@ cert_parse_extensions(const char *fn, st } for (i = 0; i < extsz; i++) { - ext = X509_get_ext(x, i); + /* XXX - cast away const for OpenSSL 4. */ + ext = (X509_EXTENSION *)X509_get_ext(x, i); assert(ext != NULL); obj = X509_EXTENSION_get_object(ext); assert(obj != NULL); Index: print.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/print.c,v diff -u -p -r1.74 print.c --- print.c 20 Jan 2026 16:49:03 -0000 1.74 +++ print.c 27 Mar 2026 19:36:55 -0000 @@ -378,7 +378,7 @@ crl_print(const struct crl *p) { STACK_OF(X509_REVOKED) *revlist; X509_REVOKED *rev; - X509_NAME *xissuer; + const X509_NAME *xissuer; int i; char *issuer, *serial; time_t t;