From c49f14597ad1bf732d80286f716cf3d1149bcde2 Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Tue, 3 Mar 2026 15:32:11 +0000 Subject: [PATCH 1/8] CI: Update to test OpenSSL 4.0.0 explicitly. --- .github/workflows/linux.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 5da65e26d9e..081978b652b 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -316,12 +316,11 @@ jobs: APU_CONFIG="--without-crypto" pkgs: subversion # ------------------------------------------------------------------------- - - name: OpenSSL ECH branch + - name: OpenSSL 4.0 config: --enable-mods-shared=most --enable-maintainer-mode --disable-md --disable-http2 --disable-ldap --disable-crypto notest-cflags: -Werror -O2 env: | - TEST_OPENSSL3=ech2 - TEST_OPENSSL3_BRANCH=feature/ech + TEST_OPENSSL3=4.0.0 OPENSSL_CONFIG=no-engine APR_VERSION=1.7.6 APU_VERSION=1.6.3 From 85c15dcb2cc0bcaa3aca65cfe2ea3bfb84f0e97e Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Tue, 3 Mar 2026 15:46:10 +0000 Subject: [PATCH 2/8] * modules/ssl/ssl_engine_kernel.c (ssl_hook_UserCheck): Change name to const X509_NAME *. (ssl_callback_proxy_cert): Change ca_name, issuer, and ca_issuer to const X509_NAME *. * modules/ssl/ssl_engine_log.c (ssl_log_cert_error): Change cert parameter to const X509 *. Use X509_get0_serialNumber, X509_get0_notBefore, and X509_get0_notAfter instead of non-const variants. (ssl_log_xerror, ssl_log_cxerror, ssl_log_rxerror): Change cert parameter to const X509 *. * modules/ssl/ssl_engine_vars.c (ssl_var_lookup_ssl_cert_dn): Change xsname parameter to const X509_NAME *. (ssl_var_lookup_ssl_cert_dn_oneline): Change xsname parameter to const X509_NAME *. (ssl_var_lookup_ssl_cert): Change xsname to const X509_NAME *. (ssl_var_lookup_ssl_cert_rfc4523_cea): Change issuer to const X509_NAME *. * modules/ssl/ssl_private.h (ssl_log_xerror, ssl_log_cxerror, ssl_log_rxerror): Update declarations to use const X509 *. * modules/ssl/ssl_util_ssl.c (modssl_X509_NAME_to_string): Change dn parameter to const X509_NAME *. (getIDs): Change subj to const X509_NAME *. * modules/ssl/ssl_util_ssl.h (modssl_X509_NAME_to_string): Update declaration to use const X509_NAME *. * support/ab.c (ssl_print_cert_info): Change dn to const X509_NAME *. --- modules/ssl/ssl_engine_kernel.c | 4 ++-- modules/ssl/ssl_engine_log.c | 14 +++++++------- modules/ssl/ssl_engine_vars.c | 12 ++++++------ modules/ssl/ssl_private.h | 6 +++--- modules/ssl/ssl_util_ssl.c | 4 ++-- modules/ssl/ssl_util_ssl.h | 2 +- support/ab.c | 2 +- 7 files changed, 22 insertions(+), 22 deletions(-) diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c index 569cb26c4d5..cb88f0112c6 100644 --- a/modules/ssl/ssl_engine_kernel.c +++ b/modules/ssl/ssl_engine_kernel.c @@ -1263,7 +1263,7 @@ int ssl_hook_UserCheck(request_rec *r) } if (!sslconn->client_dn) { - X509_NAME *name = X509_get_subject_name(sslconn->client_cert); + const X509_NAME *name = X509_get_subject_name(sslconn->client_cert); char *cp = X509_NAME_oneline(name, NULL, 0); sslconn->client_dn = apr_pstrdup(r->connection->pool, cp); OPENSSL_free(cp); @@ -1817,7 +1817,7 @@ int ssl_callback_proxy_cert(SSL *ssl, X509 **x509, EVP_PKEY **pkey) server_rec *s = mySrvFromConn(c); SSLSrvConfigRec *sc = mySrvConfig(s); SSLDirConfigRec *dc = myDirConfigFromConn(c); - X509_NAME *ca_name, *issuer, *ca_issuer; + const X509_NAME *ca_name, *issuer, *ca_issuer; X509_INFO *info; X509 *ca_cert; STACK_OF(X509_NAME) *ca_list; diff --git a/modules/ssl/ssl_engine_log.c b/modules/ssl/ssl_engine_log.c index 6bca827d50f..2c145692bbe 100644 --- a/modules/ssl/ssl_engine_log.c +++ b/modules/ssl/ssl_engine_log.c @@ -126,7 +126,7 @@ void ssl_log_ssl_error(const char *file, int line, int level, server_rec *s) static void ssl_log_cert_error(const char *file, int line, int level, apr_status_t rv, const server_rec *s, const conn_rec *c, const request_rec *r, - apr_pool_t *p, X509 *cert, const char *format, + apr_pool_t *p, const X509 *cert, const char *format, va_list ap) { char buf[HUGE_STRING_LEN]; @@ -167,14 +167,14 @@ static void ssl_log_cert_error(const char *file, int line, int level, } BIO_puts(bio, " / serial: "); - if (i2a_ASN1_INTEGER(bio, X509_get_serialNumber(cert)) == -1) + if (i2a_ASN1_INTEGER(bio, X509_get0_serialNumber(cert)) == -1) BIO_puts(bio, "(ERROR)"); BIO_puts(bio, " / notbefore: "); - ASN1_TIME_print(bio, X509_get_notBefore(cert)); + ASN1_TIME_print(bio, X509_get0_notBefore(cert)); BIO_puts(bio, " / notafter: "); - ASN1_TIME_print(bio, X509_get_notAfter(cert)); + ASN1_TIME_print(bio, X509_get0_notAfter(cert)); BIO_puts(bio, "]"); @@ -212,7 +212,7 @@ static void ssl_log_cert_error(const char *file, int line, int level, * in the other cases we use the connection and request pool, respectively). */ void ssl_log_xerror(const char *file, int line, int level, apr_status_t rv, - apr_pool_t *ptemp, server_rec *s, X509 *cert, + apr_pool_t *ptemp, server_rec *s, const X509 *cert, const char *fmt, ...) { if (APLOG_IS_LEVEL(s,level)) { @@ -225,7 +225,7 @@ void ssl_log_xerror(const char *file, int line, int level, apr_status_t rv, } void ssl_log_cxerror(const char *file, int line, int level, apr_status_t rv, - conn_rec *c, X509 *cert, const char *fmt, ...) + conn_rec *c, const X509 *cert, const char *fmt, ...) { if (APLOG_IS_LEVEL(mySrvFromConn(c),level)) { va_list ap; @@ -237,7 +237,7 @@ void ssl_log_cxerror(const char *file, int line, int level, apr_status_t rv, } void ssl_log_rxerror(const char *file, int line, int level, apr_status_t rv, - request_rec *r, X509 *cert, const char *fmt, ...) + request_rec *r, const X509 *cert, const char *fmt, ...) { if (APLOG_R_IS_LEVEL(r,level)) { va_list ap; diff --git a/modules/ssl/ssl_engine_vars.c b/modules/ssl/ssl_engine_vars.c index 3f9bea18b37..45dc6fd0b97 100644 --- a/modules/ssl/ssl_engine_vars.c +++ b/modules/ssl/ssl_engine_vars.c @@ -41,7 +41,7 @@ static const char *ssl_var_lookup_ssl(apr_pool_t *p, const SSLConnRec *sslconn, request_rec *r, const char *var); static const char *ssl_var_lookup_ssl_cert(apr_pool_t *p, request_rec *r, X509 *xs, const char *var); -static const char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, const char *var); +static const char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, const X509_NAME *xsname, const char *var); static const char *ssl_var_lookup_ssl_cert_san(apr_pool_t *p, X509 *xs, const char *var); static const char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_TIME *tm); static const char *ssl_var_lookup_ssl_cert_remain(apr_pool_t *p, ASN1_TIME *tm); @@ -598,7 +598,7 @@ static const char *ssl_var_lookup_ssl(apr_pool_t *p, const SSLConnRec *sslconn, } static const char *ssl_var_lookup_ssl_cert_dn_oneline(apr_pool_t *p, request_rec *r, - X509_NAME *xsname) + const X509_NAME *xsname) { char *result = NULL; SSLDirConfigRec *dc; @@ -629,7 +629,7 @@ static const char *ssl_var_lookup_ssl_cert(apr_pool_t *p, request_rec *r, X509 * const char *var) { const char *result; - X509_NAME *xsname; + const X509_NAME *xsname; int nid; result = NULL; @@ -727,8 +727,8 @@ static const struct { { NULL, 0, 0 } }; -static const char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, - const char *var) +static const char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, const X509_NAME *xsname, + const char *var) { const char *ptr; const char *result; @@ -929,7 +929,7 @@ static const char *ssl_var_lookup_ssl_cert_rfc4523_cea(apr_pool_t *p, SSL *ssl) serialNumber = X509_get_serialNumber(xs); if (serialNumber) { - X509_NAME *issuer = X509_get_issuer_name(xs); + const X509_NAME *issuer = X509_get_issuer_name(xs); if (issuer) { BIGNUM *bn = ASN1_INTEGER_to_BN(serialNumber, NULL); if((decimal = BN_bn2dec(bn)) == NULL) { diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h index fcaf76310ba..24d442dbeb9 100644 --- a/modules/ssl/ssl_private.h +++ b/modules/ssl/ssl_private.h @@ -1212,16 +1212,16 @@ void ssl_log_ssl_error(const char *, int, int, server_rec *); * counterparts. */ void ssl_log_xerror(const char *file, int line, int level, apr_status_t rv, apr_pool_t *p, server_rec *s, - X509 *cert, const char *format, ...) + const X509 *cert, const char *format, ...) __attribute__((format(printf,8,9))); void ssl_log_cxerror(const char *file, int line, int level, - apr_status_t rv, conn_rec *c, X509 *cert, + apr_status_t rv, conn_rec *c, const X509 *cert, const char *format, ...) __attribute__((format(printf,7,8))); void ssl_log_rxerror(const char *file, int line, int level, - apr_status_t rv, request_rec *r, X509 *cert, + apr_status_t rv, request_rec *r, const X509 *cert, const char *format, ...) __attribute__((format(printf,7,8))); diff --git a/modules/ssl/ssl_util_ssl.c b/modules/ssl/ssl_util_ssl.c index a4c312b7fb3..566f4d0f7a2 100644 --- a/modules/ssl/ssl_util_ssl.c +++ b/modules/ssl/ssl_util_ssl.c @@ -236,7 +236,7 @@ char *modssl_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne, * convert an X509_NAME to an RFC 2253 formatted string, optionally truncated * to maxlen characters (specify a maxlen of 0 for no length limit) */ -char *modssl_X509_NAME_to_string(apr_pool_t *p, X509_NAME *dn, int maxlen) +char *modssl_X509_NAME_to_string(apr_pool_t *p, const X509_NAME *dn, int maxlen) { char *result = NULL; BIO *bio; @@ -373,7 +373,7 @@ BOOL modssl_X509_getSAN(apr_pool_t *p, X509 *x509, int type, const char *onf, /* return an array of (RFC 6125 coined) DNS-IDs and CN-IDs in a certificate */ static BOOL getIDs(apr_pool_t *p, X509 *x509, apr_array_header_t **ids) { - X509_NAME *subj; + const X509_NAME *subj; int i = -1; /* First, the DNS-IDs (dNSName entries in the subjectAltName extension) */ diff --git a/modules/ssl/ssl_util_ssl.h b/modules/ssl/ssl_util_ssl.h index 443c1b7ee73..006151bc1ca 100644 --- a/modules/ssl/ssl_util_ssl.h +++ b/modules/ssl/ssl_util_ssl.h @@ -73,7 +73,7 @@ int modssl_smart_shutdown(SSL *ssl); BOOL modssl_X509_getBC(X509 *, int *, int *); char *modssl_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne, int raw); -char *modssl_X509_NAME_to_string(apr_pool_t *, X509_NAME *, int); +char *modssl_X509_NAME_to_string(apr_pool_t *, const X509_NAME *, int); BOOL modssl_X509_getSAN(apr_pool_t *, X509 *, int, const char *, int, apr_array_header_t **); BOOL modssl_X509_match_name(apr_pool_t *, X509 *, const char *, BOOL, server_rec *); char *modssl_SSL_SESSION_id2sz(IDCONST unsigned char *, int, char *, int); diff --git a/support/ab.c b/support/ab.c index e02cd6841fb..e3101a632e6 100644 --- a/support/ab.c +++ b/support/ab.c @@ -799,7 +799,7 @@ static int ssl_print_connection_info(BIO *bio, SSL *ssl) static void ssl_print_cert_info(BIO *bio, X509 *cert) { - X509_NAME *dn; + const X509_NAME *dn; EVP_PKEY *pk; char buf[1024]; From c7d6c6b1ce1c77f93815136b4907ca6e63540b0a Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Wed, 29 Apr 2026 15:54:35 +0100 Subject: [PATCH 3/8] mod_ssl: use ASN1_STRING accessor API in dump_extn_value: * modules/ssl/ssl_engine_vars.c (dump_extn_value): Use ASN1_STRING_get0_data() and ASN1_STRING_length() rather than directly dereferencing the ASN1_OCTET_STRING structure, which is opaque in OpenSSL 4.0. * modules/ssl/ssl_private.h: Add compat macros for ASN1_STRING_get0_data and ASN1_STRING_length for pre-1.1 API. Co-Authored-By: Claude Opus 4.6 --- modules/ssl/ssl_engine_vars.c | 8 ++++---- modules/ssl/ssl_private.h | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/modules/ssl/ssl_engine_vars.c b/modules/ssl/ssl_engine_vars.c index 45dc6fd0b97..59fa89293c6 100644 --- a/modules/ssl/ssl_engine_vars.c +++ b/modules/ssl/ssl_engine_vars.c @@ -1244,17 +1244,17 @@ void modssl_var_extract_san_entries(apr_table_t *t, SSL *ssl, apr_pool_t *p) * success and writes the string to the given bio. */ static int dump_extn_value(BIO *bio, ASN1_OCTET_STRING *str) { - const unsigned char *pp = str->data; + const unsigned char *pp = ASN1_STRING_get0_data(str); ASN1_STRING *ret = ASN1_STRING_new(); int rv = 0; - if(!ret) { - return rv; + if (!ret) { + return rv; } /* This allows UTF8String, IA5String, VisibleString, or BMPString; * conversion to UTF-8 is forced. */ - if (d2i_DISPLAYTEXT(&ret, &pp, str->length)) { + if (d2i_DISPLAYTEXT(&ret, &pp, ASN1_STRING_length(str))) { ASN1_STRING_print_ex(bio, ret, ASN1_STRFLGS_UTF8_CONVERT); rv = 1; } diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h index 24d442dbeb9..3131b341c8e 100644 --- a/modules/ssl/ssl_private.h +++ b/modules/ssl/ssl_private.h @@ -282,6 +282,8 @@ #define DH_bits(x) (BN_num_bits(x->p)) #define X509_up_ref(x) (CRYPTO_add(&(x)->references, +1, CRYPTO_LOCK_X509)) #define EVP_PKEY_up_ref(pk) (CRYPTO_add(&(pk)->references, +1, CRYPTO_LOCK_EVP_PKEY)) +#define ASN1_STRING_get0_data(x) ((x)->data) +#define ASN1_STRING_length(x) ((int)(x)->length) #else void init_bio_methods(void); void free_bio_methods(void); From 8c7f4d393828cdf4c2e2882a0d17dc9193b317f7 Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Wed, 29 Apr 2026 16:26:33 +0100 Subject: [PATCH 4/8] mod_ssl: constify ASN1_TIME pointers, use X509_get0_not{Before,After}: * modules/ssl/ssl_engine_vars.c (ssl_var_lookup_ssl_cert_valid, ssl_var_lookup_ssl_cert_remain): Constify ASN1_TIME * parameter. (ssl_var_lookup_ssl_cert): Use X509_get0_notBefore() and X509_get0_notAfter() which return const pointers. (ssl_var_lookup_ssl_cert_remain): Use ASN1_TIME_check() directly rather than INVALID_ASN1_TIME macro which dereferences the ASN1_TIME structure. (dump_extn_value): Constify ASN1_OCTET_STRING * parameter. * modules/ssl/ssl_private.h: Add compat macros for X509_get0_before and X509_get0_after for pre-1.1 API. Co-Authored-By: Claude Opus 4.6 --- modules/ssl/ssl_engine_vars.c | 18 +++++++++--------- modules/ssl/ssl_private.h | 2 ++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/modules/ssl/ssl_engine_vars.c b/modules/ssl/ssl_engine_vars.c index 59fa89293c6..451280b6345 100644 --- a/modules/ssl/ssl_engine_vars.c +++ b/modules/ssl/ssl_engine_vars.c @@ -43,8 +43,8 @@ static const char *ssl_var_lookup_ssl(apr_pool_t *p, const SSLConnRec *sslconn, static const char *ssl_var_lookup_ssl_cert(apr_pool_t *p, request_rec *r, X509 *xs, const char *var); static const char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, const X509_NAME *xsname, const char *var); static const char *ssl_var_lookup_ssl_cert_san(apr_pool_t *p, X509 *xs, const char *var); -static const char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_TIME *tm); -static const char *ssl_var_lookup_ssl_cert_remain(apr_pool_t *p, ASN1_TIME *tm); +static const char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, const ASN1_TIME *tm); +static const char *ssl_var_lookup_ssl_cert_remain(apr_pool_t *p, const ASN1_TIME *tm); static const char *ssl_var_lookup_ssl_cert_serial(apr_pool_t *p, X509 *xs); static const char *ssl_var_lookup_ssl_cert_chain(apr_pool_t *p, STACK_OF(X509) *sk, const char *var, int pem); static const char *ssl_var_lookup_ssl_cert_rfc4523_cea(apr_pool_t *p, SSL *ssl); @@ -641,13 +641,13 @@ static const char *ssl_var_lookup_ssl_cert(apr_pool_t *p, request_rec *r, X509 * result = ssl_var_lookup_ssl_cert_serial(p, xs); } else if (strcEQ(var, "V_START")) { - result = ssl_var_lookup_ssl_cert_valid(p, X509_get_notBefore(xs)); + result = ssl_var_lookup_ssl_cert_valid(p, X509_get0_notBefore(xs)); } else if (strcEQ(var, "V_END")) { - result = ssl_var_lookup_ssl_cert_valid(p, X509_get_notAfter(xs)); + result = ssl_var_lookup_ssl_cert_valid(p, X509_get0_notAfter(xs)); } else if (strcEQ(var, "V_REMAIN")) { - result = ssl_var_lookup_ssl_cert_remain(p, X509_get_notAfter(xs)); + result = ssl_var_lookup_ssl_cert_remain(p, X509_get0_notAfter(xs)); } else if (*var && strcEQ(var+1, "_DN")) { if (*var == 'S') @@ -816,7 +816,7 @@ static const char *ssl_var_lookup_ssl_cert_san(apr_pool_t *p, X509 *xs, const ch return NULL; } -static const char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_TIME *tm) +static const char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, const ASN1_TIME *tm) { BIO* bio; @@ -837,12 +837,12 @@ static const char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_TIME *tm) /* Return a string giving the number of days remaining until 'tm', or * "0" if this can't be determined. */ -static const char *ssl_var_lookup_ssl_cert_remain(apr_pool_t *p, ASN1_TIME *tm) +static const char *ssl_var_lookup_ssl_cert_remain(apr_pool_t *p, const ASN1_TIME *tm) { #if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER) int diff; - if (INVALID_ASN1_TIME(tm) || ASN1_TIME_diff(&diff, NULL, NULL, tm) != 1) { + if (ASN1_TIME_check(tm) != 1 || ASN1_TIME_diff(&diff, NULL, NULL, tm) != 1) { return "0"; } #else @@ -1242,7 +1242,7 @@ void modssl_var_extract_san_entries(apr_table_t *t, SSL *ssl, apr_pool_t *p) * parse the extension type as a primitive string. This will fail for * any structured extension type per the docs. Returns non-zero on * success and writes the string to the given bio. */ -static int dump_extn_value(BIO *bio, ASN1_OCTET_STRING *str) +static int dump_extn_value(BIO *bio, const ASN1_OCTET_STRING *str) { const unsigned char *pp = ASN1_STRING_get0_data(str); ASN1_STRING *ret = ASN1_STRING_new(); diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h index 3131b341c8e..097c3b05829 100644 --- a/modules/ssl/ssl_private.h +++ b/modules/ssl/ssl_private.h @@ -284,6 +284,8 @@ #define EVP_PKEY_up_ref(pk) (CRYPTO_add(&(pk)->references, +1, CRYPTO_LOCK_EVP_PKEY)) #define ASN1_STRING_get0_data(x) ((x)->data) #define ASN1_STRING_length(x) ((int)(x)->length) +#define X509_get0_before(x) X509_get_before(x) +#define X509_get0_after(x) X509_get_after(x) #else void init_bio_methods(void); void free_bio_methods(void); From c8ef912bbe32dbca15185bd6be3853d7c8646988 Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Wed, 29 Apr 2026 17:09:27 +0100 Subject: [PATCH 5/8] mod_ssl: constify X509_NAME_ENTRY and X509_EXTENSION pointers: * modules/ssl/ssl_engine_vars.c (ssl_var_lookup_ssl_cert_dn, extract_dn): Constify X509_NAME_ENTRY * variables, constify X509_NAME * parameter of extract_dn, drop unnecessary casts on X509_NAME_ENTRY_get_object() calls. (ssl_ext_list): Use MODSSL_X509_EXT_CONST for X509_EXTENSION * since X509_EXTENSION accessors are only constified in OpenSSL 4. * modules/ssl/ssl_util_ssl.c, modules/ssl/ssl_util_ssl.h (modssl_X509_NAME_ENTRY_to_string): Constify X509_NAME_ENTRY * parameter. * modules/ssl/ssl_private.h: Add MODSSL_X509_EXT_CONST, defined as const for OpenSSL 4+ and empty otherwise. Co-Authored-By: Claude Opus 4.6 --- modules/ssl/ssl_engine_vars.c | 12 ++++++------ modules/ssl/ssl_private.h | 6 ++++++ modules/ssl/ssl_util_ssl.c | 2 +- modules/ssl/ssl_util_ssl.h | 2 +- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/modules/ssl/ssl_engine_vars.c b/modules/ssl/ssl_engine_vars.c index 451280b6345..6c45b65d400 100644 --- a/modules/ssl/ssl_engine_vars.c +++ b/modules/ssl/ssl_engine_vars.c @@ -732,7 +732,7 @@ static const char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, const X509_NAME *xs { const char *ptr; const char *result; - X509_NAME_ENTRY *xsne; + const X509_NAME_ENTRY *xsne; int i, j, n, idx = 0, raw = 0; apr_size_t varlen; @@ -759,7 +759,7 @@ static const char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, const X509_NAME *xs for (j = 0; j < X509_NAME_entry_count(xsname); j++) { xsne = X509_NAME_get_entry(xsname, j); - n =OBJ_obj2nid((ASN1_OBJECT *)X509_NAME_ENTRY_get_object(xsne)); + n = OBJ_obj2nid(X509_NAME_ENTRY_get_object(xsne)); if (n == ssl_var_lookup_ssl_cert_dn_rec[i].nid && idx-- == 0) { result = modssl_X509_NAME_ENTRY_to_string(p, xsne, raw); @@ -1112,9 +1112,9 @@ static const char *ssl_var_lookup_ssl_version(const char *var) /* Add each RDN in 'xn' to the table 't' where the NID is present in * 'nids', using key prefix 'pfx'. */ static void extract_dn(apr_table_t *t, apr_hash_t *nids, const char *pfx, - X509_NAME *xn, apr_pool_t *p) + const X509_NAME *xn, apr_pool_t *p) { - X509_NAME_ENTRY *xsne; + const X509_NAME_ENTRY *xsne; apr_hash_t *count; int i, nid; @@ -1129,7 +1129,7 @@ static void extract_dn(apr_table_t *t, apr_hash_t *nids, const char *pfx, /* Retrieve the nid, and check whether this is one of the nids * which are to be extracted. */ - nid = OBJ_obj2nid((ASN1_OBJECT *)X509_NAME_ENTRY_get_object(xsne)); + nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(xsne)); tag = apr_hash_get(nids, &nid, sizeof nid); if (tag) { @@ -1301,7 +1301,7 @@ apr_array_header_t *ssl_ext_list(apr_pool_t *p, conn_rec *c, int peer, */ array = apr_array_make(p, count, sizeof(char *)); for (j = 0; j < count; j++) { - X509_EXTENSION *ext = X509_get_ext(xs, j); + MODSSL_X509_EXT_CONST X509_EXTENSION *ext = X509_get_ext(xs, j); if (OBJ_cmp(X509_EXTENSION_get_object(ext), oid) == 0) { BIO *bio = BIO_new(BIO_s_mem()); diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h index 097c3b05829..442b8b17ae4 100644 --- a/modules/ssl/ssl_private.h +++ b/modules/ssl/ssl_private.h @@ -155,6 +155,12 @@ #define MODSSL_SSL_METHOD_CONST #endif +#if OPENSSL_VERSION_NUMBER >= 0x40000000L +#define MODSSL_X509_EXT_CONST const +#else +#define MODSSL_X509_EXT_CONST +#endif + #if defined(LIBRESSL_VERSION_NUMBER) /* Missing from LibreSSL */ #if LIBRESSL_VERSION_NUMBER < 0x2060000f diff --git a/modules/ssl/ssl_util_ssl.c b/modules/ssl/ssl_util_ssl.c index 566f4d0f7a2..81ce8e5e63a 100644 --- a/modules/ssl/ssl_util_ssl.c +++ b/modules/ssl/ssl_util_ssl.c @@ -224,7 +224,7 @@ static char *asn1_string_convert(apr_pool_t *p, ASN1_STRING *asn1str, int raw) #define asn1_string_to_utf8(p, a) asn1_string_convert(p, a, 0) /* convert a NAME_ENTRY to UTF8 string */ -char *modssl_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne, +char *modssl_X509_NAME_ENTRY_to_string(apr_pool_t *p, const X509_NAME_ENTRY *xsne, int raw) { char *result = asn1_string_convert(p, X509_NAME_ENTRY_get_data(xsne), raw); diff --git a/modules/ssl/ssl_util_ssl.h b/modules/ssl/ssl_util_ssl.h index 006151bc1ca..2631ee03693 100644 --- a/modules/ssl/ssl_util_ssl.h +++ b/modules/ssl/ssl_util_ssl.h @@ -71,7 +71,7 @@ EVP_PKEY *modssl_read_privatekey(const char *filename, pem_password_cb *cb, vo int modssl_smart_shutdown(SSL *ssl); BOOL modssl_X509_getBC(X509 *, int *, int *); -char *modssl_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne, +char *modssl_X509_NAME_ENTRY_to_string(apr_pool_t *p, const X509_NAME_ENTRY *xsne, int raw); char *modssl_X509_NAME_to_string(apr_pool_t *, const X509_NAME *, int); BOOL modssl_X509_getSAN(apr_pool_t *, X509 *, int, const char *, int, apr_array_header_t **); From 6829f4cfd4dff98003b33c1ab40ad470c3e5cdf3 Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Wed, 29 Apr 2026 18:38:23 +0100 Subject: [PATCH 6/8] * modules/ssl/ssl_util_ssl.c (asn1_string_convert): Constify ASN1_STRING * argument. --- modules/ssl/ssl_util_ssl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ssl/ssl_util_ssl.c b/modules/ssl/ssl_util_ssl.c index 81ce8e5e63a..12995b3f651 100644 --- a/modules/ssl/ssl_util_ssl.c +++ b/modules/ssl/ssl_util_ssl.c @@ -206,7 +206,7 @@ char *modssl_bio_free_read(apr_pool_t *p, BIO *bio) /* Convert ASN.1 string to a pool-allocated char * string, escaping * control characters. If raw is zero, convert to UTF-8, otherwise * unchanged from the character set. */ -static char *asn1_string_convert(apr_pool_t *p, ASN1_STRING *asn1str, int raw) +static char *asn1_string_convert(apr_pool_t *p, const ASN1_STRING *asn1str, int raw) { BIO *bio; int flags = ASN1_STRFLGS_ESC_CTRL; From 11e45668a40693f0127337f8814290bd7fcd5757 Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Wed, 29 Apr 2026 19:06:02 +0100 Subject: [PATCH 7/8] * modules/ssl/ssl_engine_ocsp.c (extract_responder_uri): Use modssl_ASN1_STRING_convert instead of directly accessing ASN1_STRING data pointer. * modules/ssl/ssl_util_ssl.c (modssl_ASN1_STRING_convert): Rename from asn1_string_convert and export function. (asn1_string_to_utf8): Update to use modssl_ASN1_STRING_convert. (modssl_X509_NAME_ENTRY_to_string): Update to use modssl_ASN1_STRING_convert. * modules/ssl/ssl_util_ssl.h (modssl_ASN1_STRING_convert): Declare new function. --- modules/ssl/ssl_engine_ocsp.c | 4 ++-- modules/ssl/ssl_util_ssl.c | 6 +++--- modules/ssl/ssl_util_ssl.h | 6 ++++++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/modules/ssl/ssl_engine_ocsp.c b/modules/ssl/ssl_engine_ocsp.c index 5e045125585..539ed103eae 100644 --- a/modules/ssl/ssl_engine_ocsp.c +++ b/modules/ssl/ssl_engine_ocsp.c @@ -38,8 +38,8 @@ static const char *extract_responder_uri(X509 *cert, apr_pool_t *pool) /* Name found in extension, and is a URI: */ if (OBJ_obj2nid(value->method) == NID_ad_OCSP && value->location->type == GEN_URI) { - result = apr_pstrdup(pool, - (char *)value->location->d.uniformResourceIdentifier->data); + const ASN1_STRING *uri = value->location->d.uniformResourceIdentifier; + result = modssl_ASN1_STRING_convert(pool, uri, 0); } } diff --git a/modules/ssl/ssl_util_ssl.c b/modules/ssl/ssl_util_ssl.c index 12995b3f651..ae5d796eb65 100644 --- a/modules/ssl/ssl_util_ssl.c +++ b/modules/ssl/ssl_util_ssl.c @@ -206,7 +206,7 @@ char *modssl_bio_free_read(apr_pool_t *p, BIO *bio) /* Convert ASN.1 string to a pool-allocated char * string, escaping * control characters. If raw is zero, convert to UTF-8, otherwise * unchanged from the character set. */ -static char *asn1_string_convert(apr_pool_t *p, const ASN1_STRING *asn1str, int raw) +char *modssl_ASN1_STRING_convert(apr_pool_t *p, const ASN1_STRING *asn1str, int raw) { BIO *bio; int flags = ASN1_STRFLGS_ESC_CTRL; @@ -221,13 +221,13 @@ static char *asn1_string_convert(apr_pool_t *p, const ASN1_STRING *asn1str, int return modssl_bio_free_read(p, bio); } -#define asn1_string_to_utf8(p, a) asn1_string_convert(p, a, 0) +#define asn1_string_to_utf8(p, a) modssl_ASN1_STRING_convert(p, a, 0) /* convert a NAME_ENTRY to UTF8 string */ char *modssl_X509_NAME_ENTRY_to_string(apr_pool_t *p, const X509_NAME_ENTRY *xsne, int raw) { - char *result = asn1_string_convert(p, X509_NAME_ENTRY_get_data(xsne), raw); + char *result = modssl_ASN1_STRING_convert(p, X509_NAME_ENTRY_get_data(xsne), raw); ap_xlate_proto_from_ascii(result, len); return result; } diff --git a/modules/ssl/ssl_util_ssl.h b/modules/ssl/ssl_util_ssl.h index 2631ee03693..f5ed3c23aac 100644 --- a/modules/ssl/ssl_util_ssl.h +++ b/modules/ssl/ssl_util_ssl.h @@ -78,6 +78,12 @@ BOOL modssl_X509_getSAN(apr_pool_t *, X509 *, int, const char *, int, apr BOOL modssl_X509_match_name(apr_pool_t *, X509 *, const char *, BOOL, server_rec *); char *modssl_SSL_SESSION_id2sz(IDCONST unsigned char *, int, char *, int); +/* Convert ASN.1 string to a pool-allocated char * string, escaping + * control characters. If raw is zero, convert to UTF-8, otherwise + * unchanged from the character set. */ +char *modssl_ASN1_STRING_convert(apr_pool_t *p, const ASN1_STRING *asn1str, + int raw); + /* Reads the remaining data in BIO, if not empty, and copies it into a * pool-allocated string. If empty, returns NULL. BIO_free(bio) is * called for both cases. */ From 76111f829a24369f73ad034bdd3b681e1d10929e Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Wed, 29 Apr 2026 19:44:36 +0100 Subject: [PATCH 8/8] CI: No longer disable deprecated-declaration warnings for OpenSSL 3.4 -Werror build. --- .github/workflows/linux.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 081978b652b..9f21b654f9a 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -287,7 +287,7 @@ jobs: # ------------------------------------------------------------------------- - name: OpenSSL 3.4 -Werror config: --enable-mods-shared=most --enable-maintainer-mode --disable-md --disable-http2 --disable-ldap --disable-crypto - notest-cflags: -Werror -O2 -Wno-deprecated-declarations + notest-cflags: -Werror -O2 env: | TEST_OPENSSL3=3.4.4 APR_VERSION=1.7.6