]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Constify various functions that were non const due to extension cache
authorBob Beck <beck@openssl.org>
Tue, 17 Feb 2026 21:28:01 +0000 (14:28 -0700)
committerNeil Horman <nhorman@openssl.org>
Mon, 23 Feb 2026 16:34:16 +0000 (11:34 -0500)
for https://github.com/openssl/openssl/issues/30052

This is a blatent cheat. While I can get pretty close to getting
around cheating by cacheing extensions as X509 objects are created it's
too fragile at the moment. In a future with a better not-copying all
the things X509, we would endeavour to not need this.

In the meantime, in the interest of getting the public API ready to
do that, we instead make a blatent cheat in the internal function of

int ossl_x509v3_cache_extensions(const X509 *x);

Which in a future world we can work to make go away.

And then the public API all changes to const.

long X509_get_pathlen(const X509 *x);
int X509_check_ca(const X509 *x);
int X509_check_purpose(const X509 *x, int id, int ca);
long X509_get_proxy_pathlen(const X509 *x);
uint32_t X509_get_extension_flags(const X509 *x);
uint32_t X509_get_key_usage(const X509 *x);
uint32_t X509_get_extended_key_usage(const X509 *x);
onst ASN1_OCTET_STRING *X509_get0_subject_key_id(const X509 *x);
const ASN1_OCTET_STRING *X509_get0_authority_key_id(const X509 *x);
const GENERAL_NAMES *X509_get0_authority_issuer(const X509 *x);
const ASN1_INTEGER *X509_get0_authority_serial(const X509 *x);

Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Norbert Pocs <norbertp@openssl.org>
Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
Reviewed-by: Neil Horman <nhorman@openssl.org>
MergeDate: Mon Feb 23 16:34:29 2026
(Merged from https://github.com/openssl/openssl/pull/30055)

CHANGES.md
crypto/x509/v3_purp.c
doc/man3/X509_check_ca.pod
doc/man3/X509_get_extension_flags.pod
include/crypto/x509.h
include/openssl/x509.h.in
include/openssl/x509v3.h.in

index 147e13149dfbf96b451ddace048cf6eb54045254..7d1ec712217a9a73b54b9d437e6873a6a902fbc4 100644 (file)
@@ -252,6 +252,14 @@ OpenSSL 4.0
 
    *Ryan Hooper*
 
+ * Constify Various X509 functions:
+   X509_get_pathlen X509_check_ca X509_check_purpose X509_get_proxy_pathlen
+   X509_get_extension_flags X509_get_key_usage X509_get_extended_key_usage
+   X509_get0_subject_key_id X509_get0_authority_key_id X509_get0_authority_issuer
+   X509_get0_authority_serial.
+
+   * Bob Beck *
+
  * Fixed CRLs with invalid `ASN1_TIME` in invalidityDate extensions,
    where verification incorrectly succeeded. Enforced proper
    handling of `ASN1_TIME` validation results so that any CRL
index a1eb58193621acdfe1248730527b73461af53813..016fd5a60623d011c45e148f89bd076b64bad801 100644 (file)
@@ -79,12 +79,6 @@ static int xp_cmp(const X509_PURPOSE *const *a, const X509_PURPOSE *const *b)
     return (*a)->purpose - (*b)->purpose;
 }
 
-/*
- * As much as I'd like to make X509_check_purpose use a "const" X509* I really
- * can't because it does recalculate hashes and do other non-const things.
- * If id == -1 it just calls x509v3_cache_extensions() for its side-effect.
- * Returns 1 on success, 0 if x does not allow purpose, -1 on (internal) error.
- */
 int X509_check_purpose(const X509 *x, int id, int non_leaf)
 {
     int idx;
@@ -440,8 +434,13 @@ static int check_sig_alg_match(const EVP_PKEY *issuer_key, const X509 *subject)
  * x->sha1_hash is filled in, or else EXFLAG_NO_FINGERPRINT is set in x->flags.
  * X509_SIG_INFO_VALID is set in x->flags if x->siginf was filled successfully.
  * Set EXFLAG_INVALID and return 0 in case the certificate is invalid.
+ *
+ * This is usually called by side-effect on objects, and forces us to keep
+ * mutable X509 objects around. We should really make this go away.
+ * In the interest of being able to do so, this function explicitly takes
+ * a const argument and casts away const.
  */
-int ossl_x509v3_cache_extensions(X509 *x)
+int ossl_x509v3_cache_extensions(const X509 *const_x)
 {
     BASIC_CONSTRAINTS *bs;
     PROXY_CERT_INFO_EXTENSION *pci;
@@ -450,6 +449,16 @@ int ossl_x509v3_cache_extensions(X509 *x)
     EXTENDED_KEY_USAGE *extusage;
     int i;
     int res;
+    X509 *x;
+
+    /*
+     * XXX deliberately cast away const - this is so the
+     * public API may be made const even though we are lying
+     * about it for the moment. This will enable us
+     * to move to where we do not have to cast this away
+     * in the future
+     */
+    x = (X509 *)const_x;
 
 #ifdef tsan_ld_acq
     /* Fast lock-free check, see end of the function for details. */
@@ -733,7 +742,7 @@ void X509_set_proxy_pathlen(X509 *x, long l)
     x->ex_pcpathlen = l;
 }
 
-int X509_check_ca(X509 *x)
+int X509_check_ca(const X509 *x)
 {
     /* Note 0 normally means "not a CA" - but in this case means error. */
     if (!ossl_x509v3_cache_extensions(x))
@@ -1077,14 +1086,14 @@ int X509_check_akid(const X509 *issuer, const AUTHORITY_KEYID *akid)
     return X509_V_OK;
 }
 
-uint32_t X509_get_extension_flags(X509 *x)
+uint32_t X509_get_extension_flags(const X509 *x)
 {
     /* Call for side-effect of computing hash and caching extensions */
     X509_check_purpose(x, -1, 0);
     return x->ex_flags;
 }
 
-uint32_t X509_get_key_usage(X509 *x)
+uint32_t X509_get_key_usage(const X509 *x)
 {
     /* Call for side-effect of computing hash and caching extensions */
     if (X509_check_purpose(x, -1, 0) != 1)
@@ -1092,7 +1101,7 @@ uint32_t X509_get_key_usage(X509 *x)
     return (x->ex_flags & EXFLAG_KUSAGE) != 0 ? x->ex_kusage : UINT32_MAX;
 }
 
-uint32_t X509_get_extended_key_usage(X509 *x)
+uint32_t X509_get_extended_key_usage(const X509 *x)
 {
     /* Call for side-effect of computing hash and caching extensions */
     if (X509_check_purpose(x, -1, 0) != 1)
@@ -1100,7 +1109,7 @@ uint32_t X509_get_extended_key_usage(X509 *x)
     return (x->ex_flags & EXFLAG_XKUSAGE) != 0 ? x->ex_xkusage : UINT32_MAX;
 }
 
-const ASN1_OCTET_STRING *X509_get0_subject_key_id(X509 *x)
+const ASN1_OCTET_STRING *X509_get0_subject_key_id(const X509 *x)
 {
     /* Call for side-effect of computing hash and caching extensions */
     if (X509_check_purpose(x, -1, 0) != 1)
@@ -1108,7 +1117,7 @@ const ASN1_OCTET_STRING *X509_get0_subject_key_id(X509 *x)
     return x->skid;
 }
 
-const ASN1_OCTET_STRING *X509_get0_authority_key_id(X509 *x)
+const ASN1_OCTET_STRING *X509_get0_authority_key_id(const X509 *x)
 {
     /* Call for side-effect of computing hash and caching extensions */
     if (X509_check_purpose(x, -1, 0) != 1)
@@ -1116,7 +1125,7 @@ const ASN1_OCTET_STRING *X509_get0_authority_key_id(X509 *x)
     return (x->akid != NULL ? x->akid->keyid : NULL);
 }
 
-const GENERAL_NAMES *X509_get0_authority_issuer(X509 *x)
+const GENERAL_NAMES *X509_get0_authority_issuer(const X509 *x)
 {
     /* Call for side-effect of computing hash and caching extensions */
     if (X509_check_purpose(x, -1, 0) != 1)
@@ -1124,7 +1133,7 @@ const GENERAL_NAMES *X509_get0_authority_issuer(X509 *x)
     return (x->akid != NULL ? x->akid->issuer : NULL);
 }
 
-const ASN1_INTEGER *X509_get0_authority_serial(X509 *x)
+const ASN1_INTEGER *X509_get0_authority_serial(const X509 *x)
 {
     /* Call for side-effect of computing hash and caching extensions */
     if (X509_check_purpose(x, -1, 0) != 1)
@@ -1132,7 +1141,7 @@ const ASN1_INTEGER *X509_get0_authority_serial(X509 *x)
     return (x->akid != NULL ? x->akid->serial : NULL);
 }
 
-long X509_get_pathlen(X509 *x)
+long X509_get_pathlen(const X509 *x)
 {
     /* Called for side effect of caching extensions */
     if (X509_check_purpose(x, -1, 0) != 1
@@ -1141,7 +1150,7 @@ long X509_get_pathlen(X509 *x)
     return x->ex_pathlen;
 }
 
-long X509_get_proxy_pathlen(X509 *x)
+long X509_get_proxy_pathlen(const X509 *x)
 {
     /* Called for side effect of caching extensions */
     if (X509_check_purpose(x, -1, 0) != 1
index 91eba44f4100c4ce06406cf2d1fc7e53ec7e94e0..496eff2cb7dc9410a67ac51d365716087c49142f 100644 (file)
@@ -8,7 +8,7 @@ X509_check_ca - check if given certificate is CA certificate
 
  #include <openssl/x509v3.h>
 
- int X509_check_ca(X509 *cert);
+ int X509_check_ca(const X509 *cert);
 
 =head1 DESCRIPTION
 
index 054eab5a26c84674d28c7d55b8fe0fb227e98fde..c2a5ac0e7f0762fd84499ab07430c736bd5ed37c 100644 (file)
@@ -18,17 +18,17 @@ X509_get_proxy_pathlen - retrieve certificate extension data
 
  #include <openssl/x509v3.h>
 
- long X509_get_pathlen(X509 *x);
- uint32_t X509_get_extension_flags(X509 *x);
- uint32_t X509_get_key_usage(X509 *x);
- uint32_t X509_get_extended_key_usage(X509 *x);
- const ASN1_OCTET_STRING *X509_get0_subject_key_id(X509 *x);
- const ASN1_OCTET_STRING *X509_get0_authority_key_id(X509 *x);
- const GENERAL_NAMES *X509_get0_authority_issuer(X509 *x);
- const ASN1_INTEGER *X509_get0_authority_serial(X509 *x);
+ long X509_get_pathlen(const X509 *x);
+ uint32_t X509_get_extension_flags(const X509 *x);
+ uint32_t X509_get_key_usage(const X509 *x);
+ uint32_t X509_get_extended_key_usage(const X509 *x);
+ const ASN1_OCTET_STRING *X509_get0_subject_key_id(const X509 *x);
+ const ASN1_OCTET_STRING *X509_get0_authority_key_id(const X509 *x);
+ const GENERAL_NAMES *X509_get0_authority_issuer(const X509 *x);
+ const ASN1_INTEGER *X509_get0_authority_serial(const X509 *x);
  void X509_set_proxy_flag(X509 *x);
  void X509_set_proxy_pathlen(int l);
- long X509_get_proxy_pathlen(X509 *x);
+ long X509_get_proxy_pathlen(const X509 *x);
 
 =head1 DESCRIPTION
 
index ff073e247952ca12a6d1aafd1d861e2e423ef9aa..a2f3a24391376a1a91b39089a53df9f5d31b2ad2 100644 (file)
@@ -313,7 +313,7 @@ struct x509_object_st {
 int ossl_a2i_ipadd(unsigned char *ipout, const char *ipasc);
 int ossl_x509_set1_time(int *modified, ASN1_TIME **ptm, const ASN1_TIME *tm);
 int ossl_x509_print_ex_brief(BIO *bio, X509 *cert, unsigned long neg_cflags);
-int ossl_x509v3_cache_extensions(X509 *x);
+int ossl_x509v3_cache_extensions(const X509 *x);
 int ossl_x509_init_sig_info(X509 *x);
 
 int ossl_x509_set0_libctx(X509 *x, OSSL_LIB_CTX *libctx, const char *propq);
index 2f13b025bf94f4a5ee43f4588f0fdcfebbac8e4a..1846c9b688e6d90d7b35c970678ac9cd0b546e8f 100644 (file)
@@ -530,7 +530,7 @@ int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey);
 EVP_PKEY *X509_PUBKEY_get0(const X509_PUBKEY *key);
 EVP_PKEY *X509_PUBKEY_get(const X509_PUBKEY *key);
 int X509_get_pubkey_parameters(EVP_PKEY *pkey, STACK_OF(X509) *chain);
-long X509_get_pathlen(X509 *x);
+long X509_get_pathlen(const X509 *x);
 DECLARE_ASN1_ENCODE_FUNCTIONS_only(EVP_PKEY, PUBKEY)
 EVP_PKEY *d2i_PUBKEY_ex(EVP_PKEY **a, const unsigned char **pp, long length,
     OSSL_LIB_CTX *libctx, const char *propq);
index de75440060041fb30109583902fcf28759ad68d5..1cc66047dd31ea9e1a8f4416675f0c411da5ab3d 100644 (file)
@@ -744,22 +744,22 @@ int X509V3_extensions_print(BIO *out, const char *title,
     const STACK_OF(X509_EXTENSION) *exts,
     unsigned long flag, int indent);
 
-int X509_check_ca(X509 *x);
+int X509_check_ca(const X509 *x);
 int X509_check_purpose(const X509 *x, int id, int ca);
 int X509_supported_extension(X509_EXTENSION *ex);
 int X509_check_issued(X509 *issuer, X509 *subject);
 int X509_check_akid(const X509 *issuer, const AUTHORITY_KEYID *akid);
 void X509_set_proxy_flag(X509 *x);
 void X509_set_proxy_pathlen(X509 *x, long l);
-long X509_get_proxy_pathlen(X509 *x);
-
-uint32_t X509_get_extension_flags(X509 *x);
-uint32_t X509_get_key_usage(X509 *x);
-uint32_t X509_get_extended_key_usage(X509 *x);
-const ASN1_OCTET_STRING *X509_get0_subject_key_id(X509 *x);
-const ASN1_OCTET_STRING *X509_get0_authority_key_id(X509 *x);
-const GENERAL_NAMES *X509_get0_authority_issuer(X509 *x);
-const ASN1_INTEGER *X509_get0_authority_serial(X509 *x);
+long X509_get_proxy_pathlen(const X509 *x);
+
+uint32_t X509_get_extension_flags(const X509 *x);
+uint32_t X509_get_key_usage(const X509 *x);
+uint32_t X509_get_extended_key_usage(const X509 *x);
+const ASN1_OCTET_STRING *X509_get0_subject_key_id(const X509 *x);
+const ASN1_OCTET_STRING *X509_get0_authority_key_id(const X509 *x);
+const GENERAL_NAMES *X509_get0_authority_issuer(const X509 *x);
+const ASN1_INTEGER *X509_get0_authority_serial(const X509 *x);
 
 int X509_PURPOSE_get_count(void);
 int X509_PURPOSE_get_unused_id(OSSL_LIB_CTX *libctx);