From 23e8ed6ea6668ec79064083c36cecbfbb4d87079 Mon Sep 17 00:00:00 2001 From: William Lallemand Date: Mon, 24 Nov 2025 21:44:46 +0100 Subject: [PATCH] MEDIUM: ssl: porting to X509_STORE_get1_objects() for OpenSSL 4.0 OpenSSL 4.0 is deprecating X509_STORE_get0_objects(). Every occurence of X509_STORE_get0_objects() was first replaced by X509_STORE_get1_objects(). This changes the ref count of the STACK_OF(X509_OBJECT) everywhere, and need it to be sk_X509_OBJECT_pop_free(objs, X509_OBJECT_free) each time. X509_STORE_get1_objects() is not available in AWS-LC, OpenSSL < 3.2, LibreSSL and WolfSSL, so we need to still be compatible with get0. To achieve this, 2 macros were added X509_STORE_getX_objects() and sk_X509_OBJECT_popX_free(), these macros will use either the get0 or the get1 macro depending on their availability. In the case of get0, sk_X509_OBJECT_popX_free() will just do nothing instead of trying to free. Don't backport that unless really needed if we want to be compatible with OpenSSL 4.0. It changes all the refcounts. --- include/haproxy/openssl-compat.h | 8 ++++++++ src/ssl_ckch.c | 29 +++++++++++++++++++---------- src/ssl_sock.c | 6 ++++-- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/include/haproxy/openssl-compat.h b/include/haproxy/openssl-compat.h index fcd1ca247..fc788aa76 100644 --- a/include/haproxy/openssl-compat.h +++ b/include/haproxy/openssl-compat.h @@ -380,6 +380,14 @@ static inline unsigned long ERR_peek_error_func(const char **func) #endif +#if (HA_OPENSSL_VERSION_NUMBER >= 0x40000000L) && !defined(OPENSSL_IS_AWSLC) && !defined(LIBRESSL_VERSION_NUMBER) && !defined(USE_OPENSSL_WOLFSSL) +# define X509_STORE_getX_objects(x) X509_STORE_get1_objects(x) +# define sk_X509_OBJECT_popX_free(x, y) sk_X509_OBJECT_pop_free(x,y) +#else +# define X509_STORE_getX_objects(x) X509_STORE_get0_objects(x) +# define sk_X509_OBJECT_popX_free(x, y) ({}) +#endif + #if (HA_OPENSSL_VERSION_NUMBER >= 0x1010000fL) || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x2070200fL) #define __OPENSSL_110_CONST__ const #else diff --git a/src/ssl_ckch.c b/src/ssl_ckch.c index eb2e9cc84..7753fb718 100644 --- a/src/ssl_ckch.c +++ b/src/ssl_ckch.c @@ -1345,7 +1345,7 @@ struct cafile_entry *ssl_store_dup_cafile_entry(struct cafile_entry *src) { struct cafile_entry *dst = NULL; X509_STORE *store = NULL; - STACK_OF(X509_OBJECT) *objs; + STACK_OF(X509_OBJECT) *objs = NULL; int i; if (!src) @@ -1357,7 +1357,7 @@ struct cafile_entry *ssl_store_dup_cafile_entry(struct cafile_entry *src) if (!store) goto err; - objs = X509_STORE_get0_objects(src->ca_store); + objs = X509_STORE_getX_objects(src->ca_store); for (i = 0; i < sk_X509_OBJECT_num(objs); i++) { X509 *cert; X509_CRL *crl; @@ -1385,10 +1385,11 @@ struct cafile_entry *ssl_store_dup_cafile_entry(struct cafile_entry *src) } } dst = ssl_store_create_cafile_entry(src->path, store, src->type); - + sk_X509_OBJECT_popX_free(objs, X509_OBJECT_free); return dst; err: + sk_X509_OBJECT_popX_free(objs, X509_OBJECT_free); X509_STORE_free(store); ha_free(&dst); @@ -1496,13 +1497,13 @@ end: */ int __ssl_store_load_locations_file(char *path, int create_if_none, enum cafile_type type, int shuterror) { + STACK_OF(X509_OBJECT) *objs = NULL; X509_STORE *store = ssl_store_get0_locations_file(path); /* If this function is called by the CLI, we should not call the * X509_STORE_load_locations function because it performs forbidden disk * accesses. */ if (!store && create_if_none) { - STACK_OF(X509_OBJECT) *objs; int cert_count = 0; struct stat buf; struct cafile_entry *ca_e; @@ -1607,7 +1608,7 @@ scandir_err: } } - objs = X509_STORE_get0_objects(store); + objs = X509_STORE_getX_objects(store); cert_count = sk_X509_OBJECT_num(objs); if (cert_count == 0) { if (!shuterror) @@ -1621,9 +1622,11 @@ scandir_err: } ebst_insert(&cafile_tree, &ca_e->node); } + sk_X509_OBJECT_popX_free(objs, X509_OBJECT_free); return (store != NULL); err: + sk_X509_OBJECT_popX_free(objs, X509_OBJECT_free); X509_STORE_free(store); store = NULL; return 0; @@ -3794,7 +3797,7 @@ static int cli_io_handler_show_cafile_detail(struct appctx *appctx) struct buffer *out = alloc_trash_chunk(); int i = 0; X509 *cert; - STACK_OF(X509_OBJECT) *objs; + STACK_OF(X509_OBJECT) *objs = NULL; int retval = 0; int ca_index = ctx->ca_index; int show_all = ctx->show_all; @@ -3820,7 +3823,7 @@ static int cli_io_handler_show_cafile_detail(struct appctx *appctx) if (!cafile_entry->ca_store) goto end; - objs = X509_STORE_get0_objects(cafile_entry->ca_store); + objs = X509_STORE_getX_objects(cafile_entry->ca_store); for (i = ca_index; i < sk_X509_OBJECT_num(objs); i++) { cert = X509_OBJECT_get0_X509(sk_X509_OBJECT_value(objs, i)); @@ -3843,13 +3846,16 @@ static int cli_io_handler_show_cafile_detail(struct appctx *appctx) } end: + sk_X509_OBJECT_popX_free(objs, X509_OBJECT_free); free_trash_chunk(out); return 1; /* end, don't come back */ end_no_putchk: + sk_X509_OBJECT_popX_free(objs, X509_OBJECT_free); free_trash_chunk(out); return 1; yield: + sk_X509_OBJECT_popX_free(objs, X509_OBJECT_free); /* save the current state */ ctx->ca_index = i; free_trash_chunk(out); @@ -3952,9 +3958,10 @@ static int get_certificate_count(struct cafile_entry *cafile_entry) STACK_OF(X509_OBJECT) *objs; if (cafile_entry && cafile_entry->ca_store) { - objs = X509_STORE_get0_objects(cafile_entry->ca_store); + objs = X509_STORE_getX_objects(cafile_entry->ca_store); if (objs) cert_count = sk_X509_OBJECT_num(objs); + sk_X509_OBJECT_popX_free(objs, X509_OBJECT_free); } return cert_count; } @@ -4484,7 +4491,7 @@ static int cli_io_handler_show_crlfile_detail(struct appctx *appctx) struct buffer *out = alloc_trash_chunk(); int i; X509_CRL *crl; - STACK_OF(X509_OBJECT) *objs; + STACK_OF(X509_OBJECT) *objs = NULL; int retval = 0; int index = ctx->index; @@ -4509,7 +4516,7 @@ static int cli_io_handler_show_crlfile_detail(struct appctx *appctx) if (!cafile_entry->ca_store) goto end; - objs = X509_STORE_get0_objects(cafile_entry->ca_store); + objs = X509_STORE_getX_objects(cafile_entry->ca_store); for (i = 0; i < sk_X509_OBJECT_num(objs); i++) { crl = X509_OBJECT_get0_X509_CRL(sk_X509_OBJECT_value(objs, i)); if (!crl) @@ -4532,9 +4539,11 @@ end: goto yield; end_no_putchk: + sk_X509_OBJECT_popX_free(objs, X509_OBJECT_free); free_trash_chunk(out); return 1; yield: + sk_X509_OBJECT_popX_free(objs, X509_OBJECT_free); free_trash_chunk(out); return 0; /* should come back */ } diff --git a/src/ssl_sock.c b/src/ssl_sock.c index ea161a2ba..3540038a2 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -630,7 +630,7 @@ static int ssl_set_cert_crl_file(X509_STORE *store_ctx, char *path) if (store_ctx && store) { int i; X509_OBJECT *obj; - STACK_OF(X509_OBJECT) *objs = X509_STORE_get0_objects(store); + STACK_OF(X509_OBJECT) *objs = X509_STORE_getX_objects(store); for (i = 0; i < sk_X509_OBJECT_num(objs); i++) { obj = sk_X509_OBJECT_value(objs, i); switch (X509_OBJECT_get_type(obj)) { @@ -644,6 +644,7 @@ static int ssl_set_cert_crl_file(X509_STORE *store_ctx, char *path) break; } } + sk_X509_OBJECT_popX_free(objs, X509_OBJECT_free); return 1; } return 0; @@ -687,7 +688,7 @@ static STACK_OF(X509_NAME)* ssl_get_client_ca_file(char *path) skn = sk_X509_NAME_new_null(); /* take x509 from cafile_tree */ - objs = X509_STORE_get0_objects(ca_e->ca_store); + objs = X509_STORE_getX_objects(ca_e->ca_store); for (i = 0; i < sk_X509_OBJECT_num(objs); i++) { x = X509_OBJECT_get0_X509(sk_X509_OBJECT_value(objs, i)); if (!x) @@ -723,6 +724,7 @@ static STACK_OF(X509_NAME)* ssl_get_client_ca_file(char *path) ca_name->xname = xn; eb64_insert(&ca_name_tree, &ca_name->node); } + sk_X509_OBJECT_popX_free(objs, X509_OBJECT_free); ca_e->ca_list = skn; /* remove temporary ca_name tree */ node = eb64_first(&ca_name_tree); -- 2.47.3