Commit ae8d50f211 for openssl.org
commit ae8d50f211231c8aa9fcb3bd0a6c38604dbd6de4
Author: Bob Beck <beck@openssl.org>
Date: Mon Mar 2 11:46:39 2026 -0700
Make X509_up_ref and X509_free take const X509 *
Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Saša NedvÄ›dický <sashan@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
MergeDate: Wed Mar 4 16:43:39 2026
(Merged from https://github.com/openssl/openssl/pull/30235)
diff --git a/crypto/x509/x509_set.c b/crypto/x509/x509_set.c
index cd196ff4ca..3551fb6514 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(X509 *x)
+int X509_up_ref(const X509 *x)
{
int i;
- if (CRYPTO_UP_REF(&x->references, &i) <= 0)
+ if (CRYPTO_UP_REF(&((X509 *)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 08435a4517..701937b4c6 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(X509)
+IMPLEMENT_ASN1_FUNCTIONS_CONSTFREE(X509)
IMPLEMENT_ASN1_DUP_FUNCTION(X509)
/*
diff --git a/doc/man3/X509_new.pod b/doc/man3/X509_new.pod
index 264767e834..d8dd1179cc 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(X509 *a);
- int X509_up_ref(X509 *a);
+ void X509_free(const X509 *a);
+ int X509_up_ref(const 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 37d5d4c187..8fc148f9be 100644
--- a/doc/man7/ossl-guide-migration.pod
+++ b/doc/man7/ossl-guide-migration.pod
@@ -169,6 +169,8 @@ 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 ca8bbc2517..aff58e0577 100644
--- a/include/openssl/asn1t.h.in
+++ b/include/openssl/asn1t.h.in
@@ -775,6 +775,8 @@ 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) \
@@ -806,10 +808,24 @@ 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 42c3ec95ff..f81dd58888 100644
--- a/include/openssl/safestack.h.in
+++ b/include/openssl/safestack.h.in
@@ -35,50 +35,6 @@ 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 b5a104a3aa..84d65269cc 100644
--- a/include/openssl/x509.h.in
+++ b/include/openssl/x509.h.in
@@ -571,7 +571,11 @@ DECLARE_ASN1_FUNCTIONS(X509_NAME)
int X509_NAME_set(X509_NAME **xn, const X509_NAME *name);
DECLARE_ASN1_FUNCTIONS(X509_CINF)
-DECLARE_ASN1_FUNCTIONS(X509)
+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);
X509 *X509_new_ex(OSSL_LIB_CTX *libctx, const char *propq);
DECLARE_ASN1_FUNCTIONS(X509_CERT_AUX)
@@ -672,7 +676,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(X509 *x);
+int X509_up_ref(const 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 6b83d53b62..b694a335c5 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4495,11 +4495,6 @@ 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:
@@ -5714,3 +5709,8 @@ OSSL_ENCODER_CTX_ctrl_string ? 4_0_0 EXIST::FUNCTION:
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:
+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 0c7c129705..9ef5a338af 100644
--- a/util/perl/OpenSSL/stackhash.pm
+++ b/util/perl/OpenSSL/stackhash.pm
@@ -10,7 +10,6 @@ package OpenSSL::stackhash;
use strict;
use warnings;
-
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(generate_stack_macros generate_const_stack_macros
@@ -23,9 +22,51 @@ 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;
-SKM_DEFINE_STACK_OF_INTERNAL(${nametype}, ${realtype}, ${plaintype})
+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;
+}
#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))