Commit 792a760ac2 for openssl.org

commit 792a760ac2e7ab64d7ff4597e48bb94e2520dfdb
Author: Neil Horman <nhorman@openssl.org>
Date:   Wed Feb 18 10:31:50 2026 -0500

    Constify X509_check_issued and friends

    Constify this funcitons X509 parameter, as it generally doesn't modify
    the structure, save for the caching information that it computes.

    Note: As the caching opertions in ossl_x509v3_cache_extensions modify
    X509 data all over the place, this change centralizes those updates,
    which is something of an increase in complexity, but it does allow us to
    reduce the critical section of the write lock there which (hopefully)
    will make other accesses that take that lock a bit faster.

    Reviewed-by: Tomas Mraz <tomas@openssl.org>
    Reviewed-by: Norbert Pocs <norbertp@openssl.org>
    MergeDate: Thu Feb 26 14:58:30 2026
    (Merged from https://github.com/openssl/openssl/pull/30067)

diff --git a/crypto/x509/v3_purp.c b/crypto/x509/v3_purp.c
index 535dce409f..ffdc7cb5eb 100644
--- a/crypto/x509/v3_purp.c
+++ b/crypto/x509/v3_purp.c
@@ -386,16 +386,16 @@ static int setup_dp(const X509 *x, DIST_POINT *dp)
 }

 /* Return 1 on success, 0 if x is invalid, -1 on (internal) error. */
-static int setup_crldp(X509 *x)
+static int setup_crldp(const X509 *x, STACK_OF(DIST_POINT) **tmp_crldp)
 {
     int i;

-    x->crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, &i, NULL);
-    if (x->crldp == NULL && i != -1)
+    *tmp_crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, &i, NULL);
+    if (*tmp_crldp == NULL && i != -1)
         return 0;

-    for (i = 0; i < sk_DIST_POINT_num(x->crldp); i++) {
-        int res = setup_dp(x, sk_DIST_POINT_value(x->crldp, i));
+    for (i = 0; i < sk_DIST_POINT_num(*tmp_crldp); i++) {
+        int res = setup_dp(x, sk_DIST_POINT_value(*tmp_crldp, i));

         if (res < 1)
             return res;
@@ -449,45 +449,55 @@ int ossl_x509v3_cache_extensions(const X509 *const_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;
+    uint32_t tmp_ex_flags;
+    unsigned char tmp_sha1_hash[SHA_DIGEST_LENGTH];
+    long tmp_ex_pathlen;
+    long tmp_ex_pcpathlen;
+    uint32_t tmp_ex_kusage;
+    uint32_t tmp_ex_xkusage;
+    uint32_t tmp_ex_nscert;
+    ASN1_OCTET_STRING *tmp_skid;
+    AUTHORITY_KEYID *tmp_akid;
+    STACK_OF(GENERAL_NAME) *tmp_altname;
+    NAME_CONSTRAINTS *tmp_nc;
+    STACK_OF(DIST_POINT) *tmp_crldp = NULL;
+    STACK_OF(IPAddressFamily) *tmp_rfc3779_addr;
+    struct ASIdentifiers_st *tmp_rfc3779_asid;
+    X509_SIG_INFO tmp_siginf;

 #ifdef tsan_ld_acq
     /* Fast lock-free check, see end of the function for details. */
-    if (tsan_ld_acq((TSAN_QUALIFIER int *)&x->ex_cached))
-        return (x->ex_flags & EXFLAG_INVALID) == 0;
+    if (tsan_ld_acq((TSAN_QUALIFIER int *)&const_x->ex_cached))
+        return (const_x->ex_flags & EXFLAG_INVALID) == 0;
 #endif

-    if (!CRYPTO_THREAD_write_lock(x->lock))
+    if (!CRYPTO_THREAD_read_lock(const_x->lock))
         return 0;
-    if ((x->ex_flags & EXFLAG_SET) != 0) { /* Cert has already been processed */
-        CRYPTO_THREAD_unlock(x->lock);
-        return (x->ex_flags & EXFLAG_INVALID) == 0;
+    tmp_ex_flags = const_x->ex_flags;
+    tmp_ex_pcpathlen = const_x->ex_pcpathlen;
+    tmp_ex_kusage = const_x->ex_kusage;
+    tmp_ex_nscert = const_x->ex_nscert;
+
+    if ((tmp_ex_flags & EXFLAG_SET) != 0) { /* Cert has already been processed */
+        CRYPTO_THREAD_unlock(const_x->lock);
+        return (tmp_ex_flags & EXFLAG_INVALID) == 0;
     }

     ERR_set_mark();

     /* Cache the SHA1 digest of the cert */
-    if (!X509_digest(x, EVP_sha1(), x->sha1_hash, NULL))
-        x->ex_flags |= EXFLAG_NO_FINGERPRINT;
+    if (!X509_digest(const_x, EVP_sha1(), tmp_sha1_hash, NULL))
+        tmp_ex_flags |= EXFLAG_NO_FINGERPRINT;

     /* V1 should mean no extensions ... */
-    if (X509_get_version(x) == X509_VERSION_1)
-        x->ex_flags |= EXFLAG_V1;
+    if (X509_get_version(const_x) == X509_VERSION_1)
+        tmp_ex_flags |= EXFLAG_V1;

     /* Handle basic constraints */
-    x->ex_pathlen = -1;
-    if ((bs = X509_get_ext_d2i(x, NID_basic_constraints, &i, NULL)) != NULL) {
+    tmp_ex_pathlen = -1;
+    if ((bs = X509_get_ext_d2i(const_x, NID_basic_constraints, &i, NULL)) != NULL) {
         if (bs->ca)
-            x->ex_flags |= EXFLAG_CA;
+            tmp_ex_flags |= EXFLAG_CA;
         if (bs->pathlen != NULL) {
             /*
              * The error case !bs->ca is checked by check_chain()
@@ -495,86 +505,86 @@ int ossl_x509v3_cache_extensions(const X509 *const_x)
              */
             if (bs->pathlen->type == V_ASN1_NEG_INTEGER) {
                 ERR_raise(ERR_LIB_X509V3, X509V3_R_NEGATIVE_PATHLEN);
-                x->ex_flags |= EXFLAG_INVALID;
+                tmp_ex_flags |= EXFLAG_INVALID;
             } else {
-                x->ex_pathlen = ASN1_INTEGER_get(bs->pathlen);
+                tmp_ex_pathlen = ASN1_INTEGER_get(bs->pathlen);
             }
         }
         BASIC_CONSTRAINTS_free(bs);
-        x->ex_flags |= EXFLAG_BCONS;
+        tmp_ex_flags |= EXFLAG_BCONS;
     } else if (i != -1) {
-        x->ex_flags |= EXFLAG_INVALID;
+        tmp_ex_flags |= EXFLAG_INVALID;
     }

     /* Handle proxy certificates */
-    if ((pci = X509_get_ext_d2i(x, NID_proxyCertInfo, &i, NULL)) != NULL) {
-        if ((x->ex_flags & EXFLAG_CA) != 0
-            || X509_get_ext_by_NID(x, NID_subject_alt_name, -1) >= 0
-            || X509_get_ext_by_NID(x, NID_issuer_alt_name, -1) >= 0) {
-            x->ex_flags |= EXFLAG_INVALID;
+    if ((pci = X509_get_ext_d2i(const_x, NID_proxyCertInfo, &i, NULL)) != NULL) {
+        if ((tmp_ex_flags & EXFLAG_CA) != 0
+            || X509_get_ext_by_NID(const_x, NID_subject_alt_name, -1) >= 0
+            || X509_get_ext_by_NID(const_x, NID_issuer_alt_name, -1) >= 0) {
+            tmp_ex_flags |= EXFLAG_INVALID;
         }
         if (pci->pcPathLengthConstraint != NULL)
-            x->ex_pcpathlen = ASN1_INTEGER_get(pci->pcPathLengthConstraint);
+            tmp_ex_pcpathlen = ASN1_INTEGER_get(pci->pcPathLengthConstraint);
         else
-            x->ex_pcpathlen = -1;
+            tmp_ex_pcpathlen = -1;
         PROXY_CERT_INFO_EXTENSION_free(pci);
-        x->ex_flags |= EXFLAG_PROXY;
+        tmp_ex_flags |= EXFLAG_PROXY;
     } else if (i != -1) {
-        x->ex_flags |= EXFLAG_INVALID;
+        tmp_ex_flags |= EXFLAG_INVALID;
     }

     /* Handle (basic) key usage */
-    if ((usage = X509_get_ext_d2i(x, NID_key_usage, &i, NULL)) != NULL) {
-        x->ex_kusage = 0;
+    if ((usage = X509_get_ext_d2i(const_x, NID_key_usage, &i, NULL)) != NULL) {
+        tmp_ex_kusage = 0;
         if (usage->length > 0) {
-            x->ex_kusage = usage->data[0];
+            tmp_ex_kusage = usage->data[0];
             if (usage->length > 1)
-                x->ex_kusage |= usage->data[1] << 8;
+                tmp_ex_kusage |= usage->data[1] << 8;
         }
-        x->ex_flags |= EXFLAG_KUSAGE;
+        tmp_ex_flags |= EXFLAG_KUSAGE;
         ASN1_BIT_STRING_free(usage);
         /* Check for empty key usage according to RFC 5280 section 4.2.1.3 */
-        if (x->ex_kusage == 0) {
+        if (tmp_ex_kusage == 0) {
             ERR_raise(ERR_LIB_X509V3, X509V3_R_EMPTY_KEY_USAGE);
-            x->ex_flags |= EXFLAG_INVALID;
+            tmp_ex_flags |= EXFLAG_INVALID;
         }
     } else if (i != -1) {
-        x->ex_flags |= EXFLAG_INVALID;
+        tmp_ex_flags |= EXFLAG_INVALID;
     }

     /* Handle extended key usage */
-    x->ex_xkusage = 0;
-    if ((extusage = X509_get_ext_d2i(x, NID_ext_key_usage, &i, NULL)) != NULL) {
-        x->ex_flags |= EXFLAG_XKUSAGE;
+    tmp_ex_xkusage = 0;
+    if ((extusage = X509_get_ext_d2i(const_x, NID_ext_key_usage, &i, NULL)) != NULL) {
+        tmp_ex_flags |= EXFLAG_XKUSAGE;
         for (i = 0; i < sk_ASN1_OBJECT_num(extusage); i++) {
             switch (OBJ_obj2nid(sk_ASN1_OBJECT_value(extusage, i))) {
             case NID_server_auth:
-                x->ex_xkusage |= XKU_SSL_SERVER;
+                tmp_ex_xkusage |= XKU_SSL_SERVER;
                 break;
             case NID_client_auth:
-                x->ex_xkusage |= XKU_SSL_CLIENT;
+                tmp_ex_xkusage |= XKU_SSL_CLIENT;
                 break;
             case NID_email_protect:
-                x->ex_xkusage |= XKU_SMIME;
+                tmp_ex_xkusage |= XKU_SMIME;
                 break;
             case NID_code_sign:
-                x->ex_xkusage |= XKU_CODE_SIGN;
+                tmp_ex_xkusage |= XKU_CODE_SIGN;
                 break;
             case NID_ms_sgc:
             case NID_ns_sgc:
-                x->ex_xkusage |= XKU_SGC;
+                tmp_ex_xkusage |= XKU_SGC;
                 break;
             case NID_OCSP_sign:
-                x->ex_xkusage |= XKU_OCSP_SIGN;
+                tmp_ex_xkusage |= XKU_OCSP_SIGN;
                 break;
             case NID_time_stamp:
-                x->ex_xkusage |= XKU_TIMESTAMP;
+                tmp_ex_xkusage |= XKU_TIMESTAMP;
                 break;
             case NID_dvcs:
-                x->ex_xkusage |= XKU_DVCS;
+                tmp_ex_xkusage |= XKU_DVCS;
                 break;
             case NID_anyExtendedKeyUsage:
-                x->ex_xkusage |= XKU_ANYEKU;
+                tmp_ex_xkusage |= XKU_ANYEKU;
                 break;
             default:
                 /* Ignore unknown extended key usage */
@@ -583,85 +593,85 @@ int ossl_x509v3_cache_extensions(const X509 *const_x)
         }
         sk_ASN1_OBJECT_pop_free(extusage, ASN1_OBJECT_free);
     } else if (i != -1) {
-        x->ex_flags |= EXFLAG_INVALID;
+        tmp_ex_flags |= EXFLAG_INVALID;
     }

     /* Handle legacy Netscape extension */
-    if ((ns = X509_get_ext_d2i(x, NID_netscape_cert_type, &i, NULL)) != NULL) {
+    if ((ns = X509_get_ext_d2i(const_x, NID_netscape_cert_type, &i, NULL)) != NULL) {
         if (ns->length > 0)
-            x->ex_nscert = ns->data[0];
+            tmp_ex_nscert = ns->data[0];
         else
-            x->ex_nscert = 0;
-        x->ex_flags |= EXFLAG_NSCERT;
+            tmp_ex_nscert = 0;
+        tmp_ex_flags |= EXFLAG_NSCERT;
         ASN1_BIT_STRING_free(ns);
     } else if (i != -1) {
-        x->ex_flags |= EXFLAG_INVALID;
+        tmp_ex_flags |= EXFLAG_INVALID;
     }

     /* Handle subject key identifier and issuer/authority key identifier */
-    x->skid = X509_get_ext_d2i(x, NID_subject_key_identifier, &i, NULL);
-    if (x->skid == NULL && i != -1)
-        x->ex_flags |= EXFLAG_INVALID;
+    tmp_skid = X509_get_ext_d2i(const_x, NID_subject_key_identifier, &i, NULL);
+    if (tmp_skid == NULL && i != -1)
+        tmp_ex_flags |= EXFLAG_INVALID;

-    x->akid = X509_get_ext_d2i(x, NID_authority_key_identifier, &i, NULL);
-    if (x->akid == NULL && i != -1)
-        x->ex_flags |= EXFLAG_INVALID;
+    tmp_akid = X509_get_ext_d2i(const_x, NID_authority_key_identifier, &i, NULL);
+    if (tmp_akid == NULL && i != -1)
+        tmp_ex_flags |= EXFLAG_INVALID;

     /* Check if subject name matches issuer */
-    if (X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x)) == 0) {
-        x->ex_flags |= EXFLAG_SI; /* Cert is self-issued */
-        if (X509_check_akid(x, x->akid) == X509_V_OK /* SKID matches AKID */
+    if (X509_NAME_cmp(X509_get_subject_name(const_x), X509_get_issuer_name(const_x)) == 0) {
+        tmp_ex_flags |= EXFLAG_SI; /* Cert is self-issued */
+        if (X509_check_akid(const_x, tmp_akid) == X509_V_OK /* SKID matches AKID */
             /* .. and the signature alg matches the PUBKEY alg: */
-            && check_sig_alg_match(X509_get0_pubkey(x), x) == X509_V_OK)
-            x->ex_flags |= EXFLAG_SS; /* indicate self-signed */
+            && check_sig_alg_match(X509_get0_pubkey(const_x), const_x) == X509_V_OK)
+            tmp_ex_flags |= EXFLAG_SS; /* indicate self-signed */
         /* This is very related to ossl_x509_likely_issued(x, x) == X509_V_OK */
     }

     /* Handle subject alternative names and various other extensions */
-    x->altname = X509_get_ext_d2i(x, NID_subject_alt_name, &i, NULL);
-    if (x->altname == NULL && i != -1)
-        x->ex_flags |= EXFLAG_INVALID;
-    x->nc = X509_get_ext_d2i(x, NID_name_constraints, &i, NULL);
-    if (x->nc == NULL && i != -1)
-        x->ex_flags |= EXFLAG_INVALID;
+    tmp_altname = X509_get_ext_d2i(const_x, NID_subject_alt_name, &i, NULL);
+    if (tmp_altname == NULL && i != -1)
+        tmp_ex_flags |= EXFLAG_INVALID;
+    tmp_nc = X509_get_ext_d2i(const_x, NID_name_constraints, &i, NULL);
+    if (tmp_nc == NULL && i != -1)
+        tmp_ex_flags |= EXFLAG_INVALID;

     /* Handle CRL distribution point entries */
-    res = setup_crldp(x);
+    res = setup_crldp(const_x, &tmp_crldp);
     if (res == 0)
-        x->ex_flags |= EXFLAG_INVALID;
+        tmp_ex_flags |= EXFLAG_INVALID;

 #ifndef OPENSSL_NO_RFC3779
-    x->rfc3779_addr = X509_get_ext_d2i(x, NID_sbgp_ipAddrBlock, &i, NULL);
-    if (x->rfc3779_addr == NULL && i != -1)
-        x->ex_flags |= EXFLAG_INVALID;
-    x->rfc3779_asid = X509_get_ext_d2i(x, NID_sbgp_autonomousSysNum, &i, NULL);
-    if (x->rfc3779_asid == NULL && i != -1)
-        x->ex_flags |= EXFLAG_INVALID;
+    tmp_rfc3779_addr = X509_get_ext_d2i(const_x, NID_sbgp_ipAddrBlock, &i, NULL);
+    if (tmp_rfc3779_addr == NULL && i != -1)
+        tmp_ex_flags |= EXFLAG_INVALID;
+    tmp_rfc3779_asid = X509_get_ext_d2i(const_x, NID_sbgp_autonomousSysNum, &i, NULL);
+    if (tmp_rfc3779_asid == NULL && i != -1)
+        tmp_ex_flags |= EXFLAG_INVALID;
 #endif
-    for (i = 0; i < X509_get_ext_count(x); i++) {
-        const X509_EXTENSION *ex = X509_get_ext(x, i);
+    for (i = 0; i < X509_get_ext_count(const_x); i++) {
+        const X509_EXTENSION *ex = X509_get_ext(const_x, i);
         int nid = OBJ_obj2nid(X509_EXTENSION_get_object(ex));

         if (nid == NID_freshest_crl)
-            x->ex_flags |= EXFLAG_FRESHEST;
+            tmp_ex_flags |= EXFLAG_FRESHEST;
         if (!X509_EXTENSION_get_critical(ex))
             continue;
         if (!X509_supported_extension(ex)) {
-            x->ex_flags |= EXFLAG_CRITICAL;
+            tmp_ex_flags |= EXFLAG_CRITICAL;
             break;
         }
         switch (nid) {
         case NID_basic_constraints:
-            x->ex_flags |= EXFLAG_BCONS_CRITICAL;
+            tmp_ex_flags |= EXFLAG_BCONS_CRITICAL;
             break;
         case NID_authority_key_identifier:
-            x->ex_flags |= EXFLAG_AKID_CRITICAL;
+            tmp_ex_flags |= EXFLAG_AKID_CRITICAL;
             break;
         case NID_subject_key_identifier:
-            x->ex_flags |= EXFLAG_SKID_CRITICAL;
+            tmp_ex_flags |= EXFLAG_SKID_CRITICAL;
             break;
         case NID_subject_alt_name:
-            x->ex_flags |= EXFLAG_SAN_CRITICAL;
+            tmp_ex_flags |= EXFLAG_SAN_CRITICAL;
             break;
         default:
             break;
@@ -669,26 +679,58 @@ int ossl_x509v3_cache_extensions(const X509 *const_x)
     }

     /* Set x->siginf, ignoring errors due to unsupported algos */
-    (void)ossl_x509_init_sig_info(x);
+    (void)ossl_x509_init_sig_info(const_x, &tmp_siginf);
+
+    tmp_ex_flags |= EXFLAG_SET; /* Indicate that cert has been processed */
+    ERR_pop_to_mark();
+
+    CRYPTO_THREAD_unlock(const_x->lock);
+    /*
+     * Now that we've done all the compute intensive work under read lock
+     * do all the updating under a write lock
+     */
+    if (!CRYPTO_THREAD_write_lock(const_x->lock))
+        return 0;
+    ((X509 *)const_x)->ex_flags = tmp_ex_flags;
+    ((X509 *)const_x)->ex_pathlen = tmp_ex_pathlen;
+    ((X509 *)const_x)->ex_pcpathlen = tmp_ex_pcpathlen;
+    if (!(tmp_ex_flags & EXFLAG_NO_FINGERPRINT))
+        memcpy(((X509 *)const_x)->sha1_hash, tmp_sha1_hash, SHA_DIGEST_LENGTH);
+    if (tmp_ex_flags & EXFLAG_KUSAGE)
+        ((X509 *)const_x)->ex_kusage = tmp_ex_kusage;
+    ((X509 *)const_x)->ex_xkusage = tmp_ex_xkusage;
+    if (tmp_ex_flags & EXFLAG_NSCERT)
+        ((X509 *)const_x)->ex_nscert = tmp_ex_nscert;
+    ASN1_OCTET_STRING_free(((X509 *)const_x)->skid);
+    ((X509 *)const_x)->skid = tmp_skid;
+    AUTHORITY_KEYID_free(((X509 *)const_x)->akid);
+    ((X509 *)const_x)->akid = tmp_akid;
+    sk_GENERAL_NAME_pop_free(((X509 *)const_x)->altname, GENERAL_NAME_free);
+    ((X509 *)const_x)->altname = tmp_altname;
+    NAME_CONSTRAINTS_free(((X509 *)const_x)->nc);
+    ((X509 *)const_x)->nc = tmp_nc;
+    sk_DIST_POINT_pop_free(((X509 *)const_x)->crldp, DIST_POINT_free);
+    ((X509 *)const_x)->crldp = tmp_crldp;
+    sk_IPAddressFamily_pop_free(((X509 *)const_x)->rfc3779_addr, IPAddressFamily_free);
+    ((X509 *)const_x)->rfc3779_addr = tmp_rfc3779_addr;
+    ASIdentifiers_free(((X509 *)const_x)->rfc3779_asid);
+    ((X509 *)const_x)->rfc3779_asid = tmp_rfc3779_asid;
+    ((X509 *)const_x)->siginf = tmp_siginf;

-    x->ex_flags |= EXFLAG_SET; /* Indicate that cert has been processed */
 #ifdef tsan_st_rel
-    tsan_st_rel((TSAN_QUALIFIER int *)&x->ex_cached, 1);
+    tsan_st_rel((TSAN_QUALIFIER int *)&const_x->ex_cached, 1);
     /*
      * Above store triggers fast lock-free check in the beginning of the
      * function. But one has to ensure that the structure is "stable", i.e.
      * all stores are visible on all processors. Hence the release fence.
      */
 #endif
-    ERR_pop_to_mark();
-
-    if ((x->ex_flags & EXFLAG_INVALID) == 0) {
-        CRYPTO_THREAD_unlock(x->lock);
-        return 1;
+    CRYPTO_THREAD_unlock(const_x->lock);
+    if (tmp_ex_flags & EXFLAG_INVALID) {
+        ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_CERTIFICATE);
+        return 0;
     }
-    CRYPTO_THREAD_unlock(x->lock);
-    ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_CERTIFICATE);
-    return 0;
+    return 1;
 }

 /*-
@@ -1000,7 +1042,7 @@ static int no_check_purpose(const X509_PURPOSE *xp, const X509 *x,
  * Returns 0 for OK, or positive for reason for mismatch
  * where reason codes match those for X509_verify_cert().
  */
-int X509_check_issued(X509 *issuer, X509 *subject)
+int X509_check_issued(const X509 *issuer, const X509 *subject)
 {
     int ret;

@@ -1010,7 +1052,7 @@ int X509_check_issued(X509 *issuer, X509 *subject)
 }

 /* do the checks 1., 2., and 3. as described above for X509_check_issued() */
-int ossl_x509_likely_issued(X509 *issuer, X509 *subject)
+int ossl_x509_likely_issued(const X509 *issuer, const X509 *subject)
 {
     int ret;

diff --git a/crypto/x509/x509_local.h b/crypto/x509/x509_local.h
index 1966ace95a..44260a23b7 100644
--- a/crypto/x509/x509_local.h
+++ b/crypto/x509/x509_local.h
@@ -183,7 +183,7 @@ DEFINE_STACK_OF(BY_DIR_ENTRY)
 typedef STACK_OF(X509_NAME_ENTRY) STACK_OF_X509_NAME_ENTRY;
 DEFINE_STACK_OF(STACK_OF_X509_NAME_ENTRY)

-int ossl_x509_likely_issued(X509 *issuer, X509 *subject);
+int ossl_x509_likely_issued(const X509 *issuer, const X509 *subject);
 int ossl_x509_signing_allowed(const X509 *issuer, const X509 *subject);
 int ossl_x509_store_ctx_get_by_subject(const X509_STORE_CTX *ctx, X509_LOOKUP_TYPE type,
     const X509_NAME *name, X509_OBJECT *ret);
diff --git a/crypto/x509/x509_set.c b/crypto/x509/x509_set.c
index ce7a77550b..cd196ff4ca 100644
--- a/crypto/x509/x509_set.c
+++ b/crypto/x509/x509_set.c
@@ -298,8 +298,8 @@ static int x509_sig_info_init(X509_SIG_INFO *siginf, const X509_ALGOR *alg,
 }

 /* Returns 1 on success, 0 on failure */
-int ossl_x509_init_sig_info(X509 *x)
+int ossl_x509_init_sig_info(const X509 *x, X509_SIG_INFO *info)
 {
-    return x509_sig_info_init(&x->siginf, &x->sig_alg, &x->signature,
+    return x509_sig_info_init(info, &x->sig_alg, &x->signature,
         X509_PUBKEY_get0(x->cert_info.key));
 }
diff --git a/doc/man3/X509_check_issued.pod b/doc/man3/X509_check_issued.pod
index b83bc1396b..eddbb19868 100644
--- a/doc/man3/X509_check_issued.pod
+++ b/doc/man3/X509_check_issued.pod
@@ -9,7 +9,7 @@ certificate

  #include <openssl/x509v3.h>

- int X509_check_issued(X509 *issuer, X509 *subject);
+ int X509_check_issued(const X509 *issuer, const X509 *subject);


 =head1 DESCRIPTION
@@ -34,6 +34,10 @@ or some B<X509_V_ERR*> constant to indicate an error.
 L<X509_verify_cert(3)>, L<X509_verify(3)>, L<X509_check_ca(3)>,
 L<openssl-verify(1)>, L<X509_self_signed(3)>

+=head1 HISTORY
+
+X509_check_issued() has had its arguments altered to be const in OpenSSL 4.0.
+
 =head1 COPYRIGHT

 Copyright 2015-2021 The OpenSSL Project Authors. All Rights Reserved.
diff --git a/include/crypto/x509.h b/include/crypto/x509.h
index 8ddeb1afac..dffbac9d58 100644
--- a/include/crypto/x509.h
+++ b/include/crypto/x509.h
@@ -317,7 +317,7 @@ 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, const X509 *cert, unsigned long neg_cflags);
 int ossl_x509v3_cache_extensions(const X509 *x);
-int ossl_x509_init_sig_info(X509 *x);
+int ossl_x509_init_sig_info(const X509 *x, X509_SIG_INFO *info);

 int ossl_x509_set0_libctx(X509 *x, OSSL_LIB_CTX *libctx, const char *propq);
 int ossl_x509_crl_set0_libctx(X509_CRL *x, OSSL_LIB_CTX *libctx,
diff --git a/include/openssl/x509v3.h.in b/include/openssl/x509v3.h.in
index ca1d0a7b4d..99df8ac8ea 100644
--- a/include/openssl/x509v3.h.in
+++ b/include/openssl/x509v3.h.in
@@ -747,7 +747,7 @@ int X509V3_extensions_print(BIO *out, const char *title,
 int X509_check_ca(const X509 *x);
 int X509_check_purpose(const X509 *x, int id, int ca);
 int X509_supported_extension(const X509_EXTENSION *ex);
-int X509_check_issued(X509 *issuer, X509 *subject);
+int X509_check_issued(const X509 *issuer, const 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);