BUILD: ssl: make X509_NAME usage OpenSSL 4.0 ready

Starting with OpenSSL 4.0, X509_get_subject_name(), X509_get_issuer_name(),
and X509_CRL_get_issuer() return a const-qualified X509_NAME pointer.
Similarly, X509_NAME_get_entry() returns a const X509_NAME_ENTRY *, and
X509_NAME_ENTRY_get_data() returns a const ASN1_STRING *.

Introduce the __X509_NAME_CONST__ macro (defined to 'const' for OpenSSL
>= 4.0.0, empty for WolfSSL and older OpenSSL version which lacks const
on these APIs) and use it to qualify X509_NAME * variables and the
parameters of the three DN helper functions ssl_sock_get_dn_entry(),
ssl_sock_get_dn_formatted(), and ssl_sock_get_dn_oneline(). This avoids
both const-qualifier warnings on OpenSSL 4.0 and discarded-qualifier
warnings on WolfSSL, without needing explicit casts at call sites.

In ssl_sock.c (ssl_get_client_ca_file) and ssl_gencert.c
(ssl_sock_do_create_cert), a __X509_NAME_CONST__ X509_NAME * variable was
being reused to store the result of X509_NAME_dup() and then passed to
mutating functions (X509_NAME_add_entry_by_txt, X509_NAME_free). Introduce
separate X509_NAME * variables (xn_dup, subject) to hold the mutable
duplicate.

Original patch from Alexandr Nedvedicky <sashan@openssl.org>:
https://www.mail-archive.com/haproxy@formilux.org/msg46696.html
This commit is contained in:
William Lallemand 2026-03-11 15:03:36 +01:00
parent e82f03dd88
commit 73732abfb2
8 changed files with 47 additions and 39 deletions

View file

@ -394,6 +394,12 @@ static inline unsigned long ERR_peek_error_func(const char **func)
#define __OPENSSL_110_CONST__
#endif
#if (HA_OPENSSL_VERSION_NUMBER >= 0x40000000L) && (!defined(USE_OPENSSL_WOLFSSL))
#define __X509_NAME_CONST__ const
#else
#define __X509_NAME_CONST__
#endif
/* ERR_remove_state() was deprecated in 1.0.0 in favor of
* ERR_remove_thread_state(), which was in turn deprecated in
* 1.1.0 and does nothing anymore. Let's simply silently kill

View file

@ -34,10 +34,10 @@ int cert_get_pkey_algo(X509 *crt, struct buffer *out);
int ssl_sock_get_serial(X509 *crt, struct buffer *out);
int ssl_sock_crt2der(X509 *crt, struct buffer *out);
int ssl_sock_get_time(ASN1_TIME *tm, struct buffer *out);
int ssl_sock_get_dn_entry(X509_NAME *a, const struct buffer *entry, int pos,
int ssl_sock_get_dn_entry(__X509_NAME_CONST__ X509_NAME *a, const struct buffer *entry, int pos,
struct buffer *out);
int ssl_sock_get_dn_formatted(X509_NAME *a, const struct buffer *format, struct buffer *out);
int ssl_sock_get_dn_oneline(X509_NAME *a, struct buffer *out);
int ssl_sock_get_dn_formatted(__X509_NAME_CONST__ X509_NAME *a, const struct buffer *format, struct buffer *out);
int ssl_sock_get_dn_oneline(__X509_NAME_CONST__ X509_NAME *a, struct buffer *out);
X509* ssl_sock_get_peer_certificate(SSL *ssl);
X509* ssl_sock_get_verified_chain_root(SSL *ssl);
unsigned int openssl_version_parser(const char *version);

View file

@ -2126,7 +2126,7 @@ static int show_cert_detail(X509 *cert, STACK_OF(X509) *chain, struct issuer_cha
int i;
int write = -1;
unsigned int len = 0;
X509_NAME *name = NULL;
__X509_NAME_CONST__ X509_NAME *name = NULL;
if (!tmp)
return -1;
@ -4412,7 +4412,7 @@ static int show_crl_detail(X509_CRL *crl, struct buffer *out)
BIO *bio = NULL;
struct buffer *tmp = alloc_trash_chunk();
long version;
X509_NAME *issuer;
__X509_NAME_CONST__ X509_NAME *issuer;
int write = -1;
#ifndef USE_OPENSSL_WOLFSSL
STACK_OF(X509_REVOKED) *rev = NULL;

View file

@ -92,7 +92,8 @@ static SSL_CTX *ssl_sock_do_create_cert(const char *servername, struct bind_conf
EVP_PKEY *pkey = NULL;
SSL *tmp_ssl = NULL;
CONF *ctmp = NULL;
X509_NAME *name;
__X509_NAME_CONST__ X509_NAME *name;
X509_NAME *subject = NULL;
const EVP_MD *digest;
X509V3_CTX ctx;
unsigned int i;
@ -140,21 +141,21 @@ static SSL_CTX *ssl_sock_do_create_cert(const char *servername, struct bind_conf
goto mkcert_error;
/* Set the subject name using the same, but the CN */
name = X509_NAME_dup(name);
subject = X509_NAME_dup(name);
if (strlen(servername) <= 64) {
if (X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
if (X509_NAME_add_entry_by_txt(subject, "CN", MBSTRING_ASC,
(const unsigned char *)servername,
-1, -1, 0) != 1) {
X509_NAME_free(name);
X509_NAME_free(subject);
goto mkcert_error;
}
}
if (X509_set_subject_name(newcrt, name) != 1) {
X509_NAME_free(name);
if (X509_set_subject_name(newcrt, subject) != 1) {
X509_NAME_free(subject);
goto mkcert_error;
}
X509_NAME_free(name);
X509_NAME_free(subject);
/* Add x509v3 extensions as specified */
ctmp = NCONF_new(NULL);

View file

@ -779,7 +779,7 @@ static int
smp_fetch_ssl_r_dn(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
X509 *crt = NULL;
X509_NAME *name;
__X509_NAME_CONST__ X509_NAME *name;
int ret = 0;
struct buffer *smp_trash;
struct connection *conn;
@ -1113,7 +1113,7 @@ smp_fetch_ssl_x_i_dn(const struct arg *args, struct sample *smp, const char *kw,
int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
int conn_server = (kw[4] == 's') ? 1 : 0;
X509 *crt = NULL;
X509_NAME *name;
__X509_NAME_CONST__ X509_NAME *name;
int ret = 0;
struct buffer *smp_trash;
struct connection *conn;
@ -1309,7 +1309,7 @@ smp_fetch_ssl_x_s_dn(const struct arg *args, struct sample *smp, const char *kw,
int cert_peer = (kw[4] == 'c' || kw[4] == 's') ? 1 : 0;
int conn_server = (kw[4] == 's') ? 1 : 0;
X509 *crt = NULL;
X509_NAME *name;
__X509_NAME_CONST__ X509_NAME *name;
int ret = 0;
struct buffer *smp_trash;
struct connection *conn;

View file

@ -691,7 +691,8 @@ static STACK_OF(X509_NAME)* ssl_get_client_ca_file(char *path)
STACK_OF(X509_OBJECT) *objs;
STACK_OF(X509_NAME) *skn;
X509 *x;
X509_NAME *xn;
__X509_NAME_CONST__ X509_NAME *xn;
X509_NAME *xn_dup;
skn = sk_X509_NAME_new_null();
/* take x509 from cafile_tree */
@ -716,19 +717,19 @@ static STACK_OF(X509_NAME)* ssl_get_client_ca_file(char *path)
if (ca_name)
continue;
ca_name = calloc(1, sizeof *ca_name);
xn = X509_NAME_dup(xn);
xn_dup = X509_NAME_dup(xn);
if (!ca_name ||
!xn ||
!sk_X509_NAME_push(skn, xn)) {
!xn_dup ||
!sk_X509_NAME_push(skn, xn_dup)) {
free(ca_name);
X509_NAME_free(xn);
X509_NAME_free(xn_dup);
sk_X509_NAME_pop_free(skn, X509_NAME_free);
sk_X509_NAME_free(skn);
skn = NULL;
break;
}
ca_name->node.key = key;
ca_name->xname = xn;
ca_name->xname = xn_dup;
eb64_insert(&ca_name_tree, &ca_name->node);
}
sk_X509_OBJECT_popX_free(objs, X509_OBJECT_free);
@ -3151,7 +3152,7 @@ int ckch_inst_new_load_store(const char *path, struct ckch_store *ckchs, struct
SSL_CTX *ctx;
int i;
int order = 0;
X509_NAME *xname;
__X509_NAME_CONST__ X509_NAME *xname;
char *str;
EVP_PKEY *pkey;
struct pkey_info kinfo = { .sig = TLSEXT_signature_anonymous, .bits = 0 };
@ -3243,8 +3244,8 @@ int ckch_inst_new_load_store(const char *path, struct ckch_store *ckchs, struct
xname = X509_get_subject_name(data->cert);
i = -1;
while ((i = X509_NAME_get_index_by_NID(xname, NID_commonName, i)) != -1) {
X509_NAME_ENTRY *entry = X509_NAME_get_entry(xname, i);
ASN1_STRING *value;
__X509_NAME_CONST__ X509_NAME_ENTRY *entry = X509_NAME_get_entry(xname, i);
__X509_NAME_CONST__ ASN1_STRING *value;
value = X509_NAME_ENTRY_get_data(entry);
if (ASN1_STRING_to_UTF8((unsigned char **)&str, value) >= 0) {
@ -4897,7 +4898,7 @@ static int ssl_sock_srv_verifycbk(int ok, X509_STORE_CTX *ctx)
X509 *cert;
STACK_OF(GENERAL_NAME) *alt_names;
int i;
X509_NAME *cert_subject;
__X509_NAME_CONST__ X509_NAME *cert_subject;
char *str;
if (ok == 0)
@ -4963,8 +4964,8 @@ static int ssl_sock_srv_verifycbk(int ok, X509_STORE_CTX *ctx)
cert_subject = X509_get_subject_name(cert);
i = -1;
while (!ok && (i = X509_NAME_get_index_by_NID(cert_subject, NID_commonName, i)) != -1) {
X509_NAME_ENTRY *entry = X509_NAME_get_entry(cert_subject, i);
ASN1_STRING *value;
__X509_NAME_CONST__ X509_NAME_ENTRY *entry = X509_NAME_get_entry(cert_subject, i);
__X509_NAME_CONST__ ASN1_STRING *value;
value = X509_NAME_ENTRY_get_data(entry);
if (ASN1_STRING_to_UTF8((unsigned char **)&str, value) >= 0) {
ok = ssl_sock_srv_hostcheck(str, servername);
@ -7637,7 +7638,7 @@ int ssl_sock_get_remote_common_name(struct connection *conn,
{
struct ssl_sock_ctx *ctx = conn_get_ssl_sock_ctx(conn);
X509 *crt = NULL;
X509_NAME *name;
__X509_NAME_CONST__ X509_NAME *name;
const char find_cn[] = "CN";
const struct buffer find_cn_chunk = {
.area = (char *)&find_cn,
@ -7737,7 +7738,7 @@ int ssl_sock_get_alpn(const struct connection *conn, void *xprt_ctx, const char
int ssl_load_global_issuer_from_BIO(BIO *in, char *fp, char **err)
{
X509 *ca;
X509_NAME *name = NULL;
__X509_NAME_CONST__ X509_NAME *name = NULL;
ASN1_OCTET_STRING *skid = NULL;
STACK_OF(X509) *chain = NULL;
struct issuer_chain *issuer;

View file

@ -140,7 +140,7 @@ static void ssl_trace(enum trace_level level, uint64_t mask, const struct trace_
X509 *crt = SSL_get_certificate(ssl);
if (crt) {
X509_NAME *name = X509_get_subject_name(crt);
__X509_NAME_CONST__ X509_NAME *name = X509_get_subject_name(crt);
if (name)
chunk_appendf(&trace_buf, " subject=\"%s\"",
X509_NAME_oneline(name, 0, 0));

View file

@ -187,12 +187,12 @@ int ssl_sock_get_time(ASN1_TIME *tm, struct buffer *out)
/* Extract an entry from a X509_NAME and copy its value to an output chunk.
* Returns 1 if entry found, 0 if entry not found, or -1 if output not large enough.
*/
int ssl_sock_get_dn_entry(X509_NAME *a, const struct buffer *entry, int pos,
int ssl_sock_get_dn_entry(__X509_NAME_CONST__ X509_NAME *a, const struct buffer *entry, int pos,
struct buffer *out)
{
X509_NAME_ENTRY *ne;
ASN1_OBJECT *obj;
ASN1_STRING *data;
__X509_NAME_CONST__ X509_NAME_ENTRY *ne;
__X509_NAME_CONST__ ASN1_OBJECT *obj;
__X509_NAME_CONST__ ASN1_STRING *data;
const unsigned char *data_ptr;
int data_len;
int i, j, n;
@ -249,7 +249,7 @@ int ssl_sock_get_dn_entry(X509_NAME *a, const struct buffer *entry, int pos,
* Currently supports rfc2253 for returning LDAP V3 DNs.
* Returns 1 if dn entries exist, 0 if no dn entry was found.
*/
int ssl_sock_get_dn_formatted(X509_NAME *a, const struct buffer *format, struct buffer *out)
int ssl_sock_get_dn_formatted(__X509_NAME_CONST__ X509_NAME *a, const struct buffer *format, struct buffer *out)
{
BIO *bio = NULL;
int ret = 0;
@ -279,11 +279,11 @@ out:
/* Extract and format full DN from a X509_NAME and copy result into a chunk
* Returns 1 if dn entries exits, 0 if no dn entry found or -1 if output is not large enough.
*/
int ssl_sock_get_dn_oneline(X509_NAME *a, struct buffer *out)
int ssl_sock_get_dn_oneline(__X509_NAME_CONST__ X509_NAME *a, struct buffer *out)
{
X509_NAME_ENTRY *ne;
ASN1_OBJECT *obj;
ASN1_STRING *data;
__X509_NAME_CONST__ X509_NAME_ENTRY *ne;
__X509_NAME_CONST__ ASN1_OBJECT *obj;
__X509_NAME_CONST__ ASN1_STRING *data;
const unsigned char *data_ptr;
int data_len;
int i, n, ln;