Commit 3298dadd88 for openssl.org

commit 3298dadd88c5454cd49f70e68af60e731a4f65c5
Author: Bob Beck <beck@openssl.org>
Date:   Thu Mar 5 09:28:52 2026 -0700

    Revert "Make X509_up_ref and X509_free take const X509 *"

    This reverts commit ae8d50f211231c8aa9fcb3bd0a6c38604dbd6de4.

    Fixes:  https://github.com/openssl/project/issues/1893

    messing with free is a bridge too far

    Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
    Reviewed-by: Tomas Mraz <tomas@openssl.org>
    Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
    Reviewed-by: Neil Horman <nhorman@openssl.org>
    MergeDate: Fri Mar  6 17:50:22 2026
    (Merged from https://github.com/openssl/openssl/pull/30273)

diff --git a/crypto/x509/x509_set.c b/crypto/x509/x509_set.c
index 3551fb6514..cd196ff4ca 100644
--- a/crypto/x509/x509_set.c
+++ b/crypto/x509/x509_set.c
@@ -113,11 +113,11 @@ int X509_set_pubkey(X509 *x, EVP_PKEY *pkey)
     return 1;
 }

-int X509_up_ref(const X509 *x)
+int X509_up_ref(X509 *x)
 {
     int i;

-    if (CRYPTO_UP_REF(&((X509 *)x)->references, &i) <= 0)
+    if (CRYPTO_UP_REF(&x->references, &i) <= 0)
         return 0;

     REF_PRINT_COUNT("X509", i, x);
diff --git a/crypto/x509/x_x509.c b/crypto/x509/x_x509.c
index 701937b4c6..08435a4517 100644
--- a/crypto/x509/x_x509.c
+++ b/crypto/x509/x_x509.c
@@ -129,7 +129,7 @@ ASN1_SEQUENCE_ref(X509, x509_cb) = {
     ASN1_EMBED(X509, signature, ASN1_BIT_STRING)
 } ASN1_SEQUENCE_END_ref(X509, X509)

-IMPLEMENT_ASN1_FUNCTIONS_CONSTFREE(X509)
+IMPLEMENT_ASN1_FUNCTIONS(X509)
 IMPLEMENT_ASN1_DUP_FUNCTION(X509)

 /*
diff --git a/doc/man3/X509_new.pod b/doc/man3/X509_new.pod
index d8dd1179cc..264767e834 100644
--- a/doc/man3/X509_new.pod
+++ b/doc/man3/X509_new.pod
@@ -14,8 +14,8 @@ OSSL_STACK_OF_X509_free

  X509 *X509_new(void);
  X509 *X509_new_ex(OSSL_LIB_CTX *libctx, const char *propq);
- void X509_free(const X509 *a);
- int X509_up_ref(const X509 *a);
+ void X509_free(X509 *a);
+ int X509_up_ref(X509 *a);
  STACK_OF(X509) *X509_chain_up_ref(STACK_OF(X509) *x);
  void OSSL_STACK_OF_X509_free(STACK_OF(X509) *certs);

diff --git a/doc/man7/ossl-guide-migration.pod b/doc/man7/ossl-guide-migration.pod
index 8fc148f9be..37d5d4c187 100644
--- a/doc/man7/ossl-guide-migration.pod
+++ b/doc/man7/ossl-guide-migration.pod
@@ -169,8 +169,6 @@ X509_to_X509_REQ
 X509_TRUST_add
 X509v3_addr_validate_resource_set
 X509v3_asid_validate_resource_set
-X509_up_ref
-X509_free

 The following two functions we "un-constified" As they were documented as returning
 an explicitly mutable pointer from within an B<X509> object:
diff --git a/include/openssl/asn1t.h.in b/include/openssl/asn1t.h.in
index aff58e0577..ca8bbc2517 100644
--- a/include/openssl/asn1t.h.in
+++ b/include/openssl/asn1t.h.in
@@ -775,8 +775,6 @@ typedef struct ASN1_STREAM_ARG_st {

 #define IMPLEMENT_ASN1_FUNCTIONS(stname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, stname, stname)

-#define IMPLEMENT_ASN1_FUNCTIONS_CONSTFREE(stname) IMPLEMENT_ASN1_FUNCTIONS_fname_constfree(stname, stname, stname)
-
 #define IMPLEMENT_ASN1_FUNCTIONS_name(stname, itname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, itname)

 #define IMPLEMENT_ASN1_FUNCTIONS_ENCODE_name(stname, itname) \
@@ -808,24 +806,10 @@ typedef struct ASN1_STREAM_ARG_st {
         ASN1_item_free((ASN1_VALUE *)a, ASN1_ITEM_rptr(itname));    \
     }

-#define IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname_constfree(stname, itname, fname) \
-    stname *fname##_new(void)                                                 \
-    {                                                                         \
-        return (stname *)ASN1_item_new(ASN1_ITEM_rptr(itname));               \
-    }                                                                         \
-    void fname##_free(const stname *a)                                        \
-    {                                                                         \
-        ASN1_item_free((ASN1_VALUE *)a, ASN1_ITEM_rptr(itname));              \
-    }
-
 #define IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, fname)    \
     IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname) \
     IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname)

-#define IMPLEMENT_ASN1_FUNCTIONS_fname_constfree(stname, itname, fname) \
-    IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname)        \
-    IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname_constfree(stname, itname, fname)
-
 #define IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname)                       \
     stname *d2i_##fname(stname **a, const unsigned char **in, long len)                    \
     {                                                                                      \
diff --git a/include/openssl/safestack.h.in b/include/openssl/safestack.h.in
index f81dd58888..42c3ec95ff 100644
--- a/include/openssl/safestack.h.in
+++ b/include/openssl/safestack.h.in
@@ -35,6 +35,50 @@ extern "C" {

 #define STACK_OF(type) struct stack_st_##type

+/* Helper macro for internal use */
+#define SKM_DEFINE_STACK_OF_INTERNAL(t1, t2, t3)                                                                         \
+    STACK_OF(t1);                                                                                                        \
+    typedef int (*sk_##t1##_compfunc)(const t3 *const *a, const t3 *const *b);                                           \
+    typedef void (*sk_##t1##_freefunc)(t3 * a);                                                                          \
+    typedef t3 *(*sk_##t1##_copyfunc)(const t3 *a);                                                                      \
+    static ossl_inline void sk_##t1##_freefunc_thunk(OPENSSL_sk_freefunc freefunc_arg, void *ptr)                        \
+    {                                                                                                                    \
+        sk_##t1##_freefunc freefunc = (sk_##t1##_freefunc)freefunc_arg;                                                  \
+        freefunc((t3 *)ptr);                                                                                             \
+    }                                                                                                                    \
+    static ossl_inline int sk_##t1##_cmpfunc_thunk(int (*cmp)(const void *, const void *), const void *a, const void *b) \
+    {                                                                                                                    \
+        int (*realcmp)(const t3 *const *a, const t3 *const *b) = (int (*)(const t3 *const *a, const t3 *const *b))(cmp); \
+        const t3 *const *at = (const t3 *const *)a;                                                                      \
+        const t3 *const *bt = (const t3 *const *)b;                                                                      \
+                                                                                                                         \
+        return realcmp(at, bt);                                                                                          \
+    }                                                                                                                    \
+    static ossl_unused ossl_inline t2 *ossl_check_##t1##_type(t2 *ptr)                                                   \
+    {                                                                                                                    \
+        return ptr;                                                                                                      \
+    }                                                                                                                    \
+    static ossl_unused ossl_inline const OPENSSL_STACK *ossl_check_const_##t1##_sk_type(const STACK_OF(t1) *sk)          \
+    {                                                                                                                    \
+        return (const OPENSSL_STACK *)sk;                                                                                \
+    }                                                                                                                    \
+    static ossl_unused ossl_inline OPENSSL_STACK *ossl_check_##t1##_sk_type(STACK_OF(t1) *sk)                            \
+    {                                                                                                                    \
+        return (OPENSSL_STACK *)sk;                                                                                      \
+    }                                                                                                                    \
+    static ossl_unused ossl_inline OPENSSL_sk_compfunc ossl_check_##t1##_compfunc_type(sk_##t1##_compfunc cmp)           \
+    {                                                                                                                    \
+        return (OPENSSL_sk_compfunc)cmp;                                                                                 \
+    }                                                                                                                    \
+    static ossl_unused ossl_inline OPENSSL_sk_copyfunc ossl_check_##t1##_copyfunc_type(sk_##t1##_copyfunc cpy)           \
+    {                                                                                                                    \
+        return (OPENSSL_sk_copyfunc)cpy;                                                                                 \
+    }                                                                                                                    \
+    static ossl_unused ossl_inline OPENSSL_sk_freefunc ossl_check_##t1##_freefunc_type(sk_##t1##_freefunc fr)            \
+    {                                                                                                                    \
+        return (OPENSSL_sk_freefunc)fr;                                                                                  \
+    }
+
 #define SKM_DEFINE_STACK_OF(t1, t2, t3)                                                                                    \
     STACK_OF(t1);                                                                                                          \
     typedef int (*sk_##t1##_compfunc)(const t3 *const *a, const t3 *const *b);                                             \
diff --git a/include/openssl/x509.h.in b/include/openssl/x509.h.in
index 578df3fa6c..6cd76829d1 100644
--- a/include/openssl/x509.h.in
+++ b/include/openssl/x509.h.in
@@ -571,11 +571,7 @@ DECLARE_ASN1_FUNCTIONS(X509_NAME)
 int X509_NAME_set(X509_NAME **xn, const X509_NAME *name);

 DECLARE_ASN1_FUNCTIONS(X509_CINF)
-X509 *X509_new(void);
-void X509_free(const X509 *a);
-X509 *d2i_X509(X509 **a, const unsigned char **in, long len);
-int i2d_X509(const X509 *a, unsigned char **out);
-const ASN1_ITEM *X509_it(void);
+DECLARE_ASN1_FUNCTIONS(X509)
 X509 *X509_new_ex(OSSL_LIB_CTX *libctx, const char *propq);
 DECLARE_ASN1_FUNCTIONS(X509_CERT_AUX)

@@ -676,7 +672,7 @@ int X509_set1_notBefore(X509 *x, const ASN1_TIME *tm);
 const ASN1_TIME *X509_get0_notAfter(const X509 *x);
 ASN1_TIME *X509_getm_notAfter(X509 *x);
 int X509_set1_notAfter(X509 *x, const ASN1_TIME *tm);
-int X509_up_ref(const X509 *x);
+int X509_up_ref(X509 *x);
 int X509_get_signature_type(const X509 *x);

 #ifndef OPENSSL_NO_DEPRECATED_1_1_0
diff --git a/util/libcrypto.num b/util/libcrypto.num
index b8dcd55a86..8cbf49ac77 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4495,6 +4495,11 @@ i2d_X509_CINF                           ?	4_0_0	EXIST::FUNCTION:
 X509_CINF_free                          ?	4_0_0	EXIST::FUNCTION:
 X509_CINF_new                           ?	4_0_0	EXIST::FUNCTION:
 X509_CINF_it                            ?	4_0_0	EXIST::FUNCTION:
+d2i_X509                                ?	4_0_0	EXIST::FUNCTION:
+i2d_X509                                ?	4_0_0	EXIST::FUNCTION:
+X509_free                               ?	4_0_0	EXIST::FUNCTION:
+X509_new                                ?	4_0_0	EXIST::FUNCTION:
+X509_it                                 ?	4_0_0	EXIST::FUNCTION:
 X509_new_ex                             ?	4_0_0	EXIST::FUNCTION:
 d2i_X509_CERT_AUX                       ?	4_0_0	EXIST::FUNCTION:
 i2d_X509_CERT_AUX                       ?	4_0_0	EXIST::FUNCTION:
@@ -5710,8 +5715,3 @@ OPENSSL_sk_set_cmp_thunks               ?	4_0_0	EXIST::FUNCTION:
 ASN1_BIT_STRING_set1                    ?	4_0_0	EXIST::FUNCTION:
 OSSL_ESS_check_signing_certs_ex         ?	4_0_0	EXIST::FUNCTION:
 X509v3_delete_extension                 ?	4_0_0	EXIST::FUNCTION:
-X509_new                                ?	4_0_0	EXIST::FUNCTION:
-X509_free                               ?	4_0_0	EXIST::FUNCTION:
-d2i_X509                                ?	4_0_0	EXIST::FUNCTION:
-i2d_X509                                ?	4_0_0	EXIST::FUNCTION:
-X509_it                                 ?	4_0_0	EXIST::FUNCTION:
diff --git a/util/perl/OpenSSL/stackhash.pm b/util/perl/OpenSSL/stackhash.pm
index 9ef5a338af..0c7c129705 100644
--- a/util/perl/OpenSSL/stackhash.pm
+++ b/util/perl/OpenSSL/stackhash.pm
@@ -10,6 +10,7 @@ package OpenSSL::stackhash;

 use strict;
 use warnings;
+
 require Exporter;
 our @ISA = qw(Exporter);
 our @EXPORT_OK = qw(generate_stack_macros generate_const_stack_macros
@@ -22,51 +23,9 @@ sub generate_stack_macros_int {
     my $nametype = shift;
     my $realtype = shift;
     my $plaintype = shift;
-    my $const_free = "";
-    if ($nametype eq "X509") {
-	$const_free = "const ";
-    }
+
     my $macros = <<END_MACROS;
-STACK_OF(${nametype});
-typedef int (*sk_${nametype}_compfunc)(const ${plaintype} *const *a, const ${plaintype} *const *b);
-typedef void (*sk_${nametype}_freefunc)(${const_free}${plaintype} *a);
-typedef ${plaintype} *(*sk_${nametype}_copyfunc)(const ${plaintype} *a);
-static ossl_inline void sk_${nametype}_freefunc_thunk(OPENSSL_sk_freefunc freefunc_arg, void *ptr)
-{
-    sk_${nametype}_freefunc freefunc = (sk_${nametype}_freefunc)freefunc_arg;
-    freefunc((${const_free}${plaintype} *)ptr);
-}
-static ossl_inline int sk_${nametype}_cmpfunc_thunk(int (*cmp)(const void *, const void *), const void *a, const void *b)
-{
-    int (*realcmp)(const ${plaintype} *const *a, const ${plaintype} *const *b) = (int (*)(const ${plaintype} *const *a, const ${plaintype} *const *b))(cmp);
-    const ${plaintype} *const *at = (const ${plaintype} *const *)a;
-    const ${plaintype} *const *bt = (const ${plaintype} *const *)b;
-    return realcmp(at, bt);
-}
-static ossl_unused ossl_inline ${realtype} *ossl_check_${nametype}_type(${realtype} *ptr)
-{
-    return ptr;
-}
-static ossl_unused ossl_inline const OPENSSL_STACK *ossl_check_const_${nametype}_sk_type(const STACK_OF(${nametype}) *sk)
-{
-    return (const OPENSSL_STACK *)sk;
-}
-static ossl_unused ossl_inline OPENSSL_STACK *ossl_check_${nametype}_sk_type(STACK_OF(${nametype}) *sk)
-{
-    return (OPENSSL_STACK *)sk;
-}
-static ossl_unused ossl_inline OPENSSL_sk_compfunc ossl_check_${nametype}_compfunc_type(sk_${nametype}_compfunc cmp)
-{
-    return (OPENSSL_sk_compfunc)cmp;
-}
-static ossl_unused ossl_inline OPENSSL_sk_copyfunc ossl_check_${nametype}_copyfunc_type(sk_${nametype}_copyfunc cpy)
-{
-    return (OPENSSL_sk_copyfunc)cpy;
-}
-static ossl_unused ossl_inline OPENSSL_sk_freefunc ossl_check_${nametype}_freefunc_type(sk_${nametype}_freefunc fr)
-{
-    return (OPENSSL_sk_freefunc)fr;
-}
+SKM_DEFINE_STACK_OF_INTERNAL(${nametype}, ${realtype}, ${plaintype})
 #define sk_${nametype}_num(sk) OPENSSL_sk_num(ossl_check_const_${nametype}_sk_type(sk))
 #define sk_${nametype}_value(sk, idx) ((${realtype} *)OPENSSL_sk_value(ossl_check_const_${nametype}_sk_type(sk), (idx)))
 #define sk_${nametype}_new(cmp) ((STACK_OF(${nametype}) *)OPENSSL_sk_set_cmp_thunks(OPENSSL_sk_new(ossl_check_${nametype}_compfunc_type(cmp)), sk_${nametype}_cmpfunc_thunk))