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';
> 
> 


Reply via email to