Hello Sashan, We did receive the notice of our OpenSSL 4.0 job breaking today indeed, so your patch is very welcome! :-)
Unfortunately its breaking the OpenSSL 1.0.2 jobs and WolfSSL 5.7.0 jobs, so we might need to split a bit more the code: https://github.com/haproxy/haproxy/actions/runs/22412311345/job/64888830549 https://github.com/haproxy/haproxy/actions/runs/22412311345/job/64888830607 I'll take a look at this tomorrow. Thanks! On Wed, Feb 25, 2026 at 08:10:53PM +0100, Alexandr Nedvedicky wrote: > Subject: make HA-proxy OpenSSL 4.0 ready > Hello, > > patch below updates HA-proxy, so it builds with OpenSSL 4.0. > The OpenSSL 4.0 alpha version is going to be released within > few weeks. > > The diff below has been compile tested so far. It builds > with OpenSSL master as well as OpenSSL 3.5. > > more details on changes can be found here: > > OpenSSL 4.0 makes ASN1_STRING (et. al.) opaque. > [ https://github.com/openssl/openssl/pull/29862 ] > > Starting OpenSSL 4.0 X509_get_subject_name() (et. al.) > rturns const objects now. > [ https://github.com/openssl/openssl/pull/29468 ] > > thanks and > regards > sashan > > --------8<---------------8<---------------8<------------------8<-------- > diff --git a/include/haproxy/ssl_utils.h b/include/haproxy/ssl_utils.h > index d6649fa9b..d4751c5fc 100644 > --- a/include/haproxy/ssl_utils.h > +++ b/include/haproxy/ssl_utils.h > @@ -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(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(const X509_NAME *a, const struct buffer > *format, struct buffer *out); > +int ssl_sock_get_dn_oneline(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); > diff --git a/src/ssl_sample.c b/src/ssl_sample.c > index 5a3783a73..072bd0346 100644 > --- a/src/ssl_sample.c > +++ b/src/ssl_sample.c > @@ -774,7 +774,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; > + const X509_NAME *name; > int ret = 0; > struct buffer *smp_trash; > struct connection *conn; > @@ -1108,7 +1108,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; > + const X509_NAME *name; > int ret = 0; > struct buffer *smp_trash; > struct connection *conn; > diff --git a/src/ssl_utils.c b/src/ssl_utils.c > index eadcec24b..029ae73d0 100644 > --- a/src/ssl_utils.c > +++ b/src/ssl_utils.c > @@ -74,11 +74,12 @@ int ssl_sock_get_serial(X509 *crt, struct buffer *out) > if (!serial) > return 0; > > - if (out->size < serial->length) > + if (out->size < ASN1_STRING_length(serial)) > return -1; > > - memcpy(out->area, serial->data, serial->length); > - out->data = serial->length; > + out->data = ASN1_STRING_length(serial); > + memcpy(out->area, ASN1_STRING_get0_data(serial), out->data); > + > return 1; > } > > @@ -110,32 +111,34 @@ int ssl_sock_crt2der(X509 *crt, struct buffer *out) > */ > int ssl_sock_get_time(ASN1_TIME *tm, struct buffer *out) > { > - if (tm->type == V_ASN1_GENERALIZEDTIME) { > - ASN1_GENERALIZEDTIME *gentm = (ASN1_GENERALIZEDTIME *)tm; > + const unsigned char *data; > + > + if (ASN1_STRING_type(tm) == V_ASN1_GENERALIZEDTIME) { > + data = ASN1_STRING_get0_data(tm); > > - if (gentm->length < 12) > + if (ASN1_STRING_length(tm) < 12) > return 0; > - if (gentm->data[0] != 0x32 || gentm->data[1] != 0x30) > + if (data[0] != 0x32 || data[1] != 0x30) > return 0; > - if (out->size < gentm->length-2) > + if (out->size < ASN1_STRING_length(tm) - 2) > return -1; > > - memcpy(out->area, gentm->data+2, gentm->length-2); > - out->data = gentm->length-2; > + out->data = ASN1_STRING_length(tm) - 2; > + memcpy(out->area, data + 2, out->data); > return 1; > } > else if (tm->type == V_ASN1_UTCTIME) { > - ASN1_UTCTIME *utctm = (ASN1_UTCTIME *)tm; > + data = ASN1_STRING_get0_data(tm); > > - if (utctm->length < 10) > + if (ASN1_STRING_length(tm) < 10) > return 0; > - if (utctm->data[0] >= 0x35) > + if (data[0] >= 0x35) > return 0; > - if (out->size < utctm->length) > + if (out->size < ASN1_STRING_length(tm)) > return -1; > > - memcpy(out->area, utctm->data, utctm->length); > - out->data = utctm->length; > + out->data = ASN1_STRING_length(tm); > + memcpy(out->area, data, out->data); > return 1; > } > > @@ -145,7 +148,7 @@ 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(const X509_NAME *a, const struct buffer *entry, > int pos, > struct buffer *out) > { > X509_NAME_ENTRY *ne; > @@ -207,7 +210,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(const X509_NAME *a, const struct buffer > *format, struct buffer *out) > { > BIO *bio = NULL; > int ret = 0; > @@ -237,7 +240,7 @@ int ssl_sock_get_dn_formatted(X509_NAME *a, const struct > buffer *format, struct > /* 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(const X509_NAME *a, struct buffer *out) > { > X509_NAME_ENTRY *ne; > ASN1_OBJECT *obj; > @@ -629,16 +632,16 @@ INITCALL0(STG_REGISTER, init_x509_v_err_tab); > long asn1_generalizedtime_to_epoch(ASN1_GENERALIZEDTIME *d) > { > long epoch; > - char *p, *end; > + const unsigned char *p, *end; > const unsigned short month_offset[12] = { > 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 > }; > unsigned long year, month; > > - if (!d || (d->type != V_ASN1_GENERALIZEDTIME)) return -1; > + if (!d || (ASN1_STRING_type(d) != V_ASN1_GENERALIZEDTIME)) return -1; > > - p = (char *)d->data; > - end = p + d->length; > + p = ASN1_STRING_get0_data(d); > + end = p + ASN1_STRING_length(d); > > if (end - p < 4) return -1; > year = 1000 * (p[0] - '0') + 100 * (p[1] - '0') + 10 * (p[2] - '0') + > p[3] - '0'; > >

