From c0f6ff402d244346e726952a1deff12df0f727e7 Mon Sep 17 00:00:00 2001
From: Joe Orton <jorton@redhat.com>
Date: Mon, 26 Jul 2021 12:23:24 +0100
Subject: [PATCH 01/12] Merge r1519264 from trunk:

add some log messages and AP_DEBUG_ASSERTs for functions that should never be
called

Submitted by: sf
---
 modules/ssl/ssl_engine_io.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c
index 8fad43ef427..b17626ad841 100644
--- a/modules/ssl/ssl_engine_io.c
+++ b/modules/ssl/ssl_engine_io.c
@@ -194,6 +194,10 @@ static int bio_filter_destroy(BIO *bio)
 static int bio_filter_out_read(BIO *bio, char *out, int outl)
 {
     /* this is never called */
+    bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr);
+    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, outctx->c,
+                  "BUG: %s() should not be called", "bio_filter_out_read");
+    AP_DEBUG_ASSERT(0);
     return -1;
 }
 
@@ -293,12 +297,20 @@ static long bio_filter_out_ctrl(BIO *bio, int cmd, long num, void *ptr)
 static int bio_filter_out_gets(BIO *bio, char *buf, int size)
 {
     /* this is never called */
+    bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr);
+    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, outctx->c,
+                  "BUG: %s() should not be called", "bio_filter_out_gets");
+    AP_DEBUG_ASSERT(0);
     return -1;
 }
 
 static int bio_filter_out_puts(BIO *bio, const char *str)
 {
     /* this is never called */
+    bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr);
+    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, outctx->c,
+                  "BUG: %s() should not be called", "bio_filter_out_puts");
+    AP_DEBUG_ASSERT(0);
     return -1;
 }
 
@@ -533,21 +545,37 @@ static int bio_filter_in_read(BIO *bio, char *in, int inlen)
 
 static int bio_filter_in_write(BIO *bio, const char *in, int inl)
 {
+    bio_filter_in_ctx_t *inctx = (bio_filter_in_ctx_t *)(bio->ptr);
+    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, inctx->f->c,
+                  "BUG: %s() should not be called", "bio_filter_in_write");
+    AP_DEBUG_ASSERT(0);
     return -1;
 }
 
 static int bio_filter_in_puts(BIO *bio, const char *str)
 {
+    bio_filter_in_ctx_t *inctx = (bio_filter_in_ctx_t *)(bio->ptr);
+    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, inctx->f->c,
+                  "BUG: %s() should not be called", "bio_filter_in_puts");
+    AP_DEBUG_ASSERT(0);
     return -1;
 }
 
 static int bio_filter_in_gets(BIO *bio, char *buf, int size)
 {
+    bio_filter_in_ctx_t *inctx = (bio_filter_in_ctx_t *)(bio->ptr);
+    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, inctx->f->c,
+                  "BUG: %s() should not be called", "bio_filter_in_gets");
+    AP_DEBUG_ASSERT(0);
     return -1;
 }
 
 static long bio_filter_in_ctrl(BIO *bio, int cmd, long num, void *ptr)
 {
+    bio_filter_in_ctx_t *inctx = (bio_filter_in_ctx_t *)(bio->ptr);
+    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, inctx->f->c,
+                  "BUG: %s() should not be called", "bio_filter_in_ctrl");
+    AP_DEBUG_ASSERT(0);
     return -1;
 }
 

From 3751831fc063faefcd0960d6588d0d3add3d9d4f Mon Sep 17 00:00:00 2001
From: Joe Orton <jorton@redhat.com>
Date: Mon, 26 Jul 2021 12:24:24 +0100
Subject: [PATCH 02/12] Merge r1876934 from trunk:

mod_ssl: add compatibility with OpenSSL 3.0.0

Wrappers around deprecated API:
* X509_STORE_load_locations() => modssl_X509_STORE_load_locations(),
* CTX_load_verify_locations() => modssl_CTX_load_verify_locations(),
* ERR_peek_error_line_data()  => modssl_ERR_peek_error_data(),
* DH_bits(dh)                 => BN_num_bits(DH_get0_p(dh)).

Provide a compatible version of ssl_callback_SessionTicket() which does not
use the deprecated HMAC_CTX and HMAC_Init_ex(), replaced by EVP_MAC_CTX and
EVP_MAC_CTX_set_params() respectively. This requires adapting struct
modssl_ticket_key_t to replace hmac_secret[] with OSSL_PARAM mac_params[],
created once at load time still.
The callback is registered by SSL_CTX_set_tlsext_ticket_key_evp_cb() instead
of SSL_CTX_set_tlsext_ticket_key_cb().

Since BIO_eof() may now be called openssl-3 state machine, the never-called
assertion in bio_filter_in_ctrl() does not hold anymore, and we have to
handle BIO_CTRL_EOF. For any other cmd, we continue to AP_DEBUG_ASSERT(0) and
log an error, yet the return value is changed from -1 to 0 which is the usual
unhandled value.

Note that OpenSSL 3.0.0 is still in alpha stage as of now, the API shouldn't
change though, neither breakage to 1.x.x API.

Submitted by: ylavic
---
 modules/ssl/ssl_engine_init.c   | 76 ++++++++++++++++++++++++++-------
 modules/ssl/ssl_engine_io.c     | 17 ++++++--
 modules/ssl/ssl_engine_kernel.c | 22 ++++++++--
 modules/ssl/ssl_engine_log.c    | 12 +++++-
 modules/ssl/ssl_private.h       | 19 ++++++++-
 5 files changed, 120 insertions(+), 26 deletions(-)

diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
index cb1ea12a2d7..352363f7e9f 100644
--- a/modules/ssl/ssl_engine_init.c
+++ b/modules/ssl/ssl_engine_init.c
@@ -871,6 +871,23 @@ static void ssl_init_ctx_callbacks(server_rec *s,
 #endif
 }
 
+static APR_INLINE
+int modssl_CTX_load_verify_locations(SSL_CTX *ctx,
+                                     const char *file,
+                                     const char *path)
+{
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+    if (!SSL_CTX_load_verify_locations(ctx, file, path))
+        return 0;
+#else
+    if (file && !SSL_CTX_load_verify_file(ctx, file))
+        return 0;
+    if (path && !SSL_CTX_load_verify_dir(ctx, path))
+        return 0;
+#endif
+    return 1;
+}
+
 static apr_status_t ssl_init_ctx_verify(server_rec *s,
                                         apr_pool_t *p,
                                         apr_pool_t *ptemp,
@@ -911,10 +928,8 @@ static apr_status_t ssl_init_ctx_verify(server_rec *s,
         ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s,
                      "Configuring client authentication");
 
-        if (!SSL_CTX_load_verify_locations(ctx,
-                                           mctx->auth.ca_cert_file,
-                                           mctx->auth.ca_cert_path))
-        {
+        if (!modssl_CTX_load_verify_locations(ctx, mctx->auth.ca_cert_file,
+                                                   mctx->auth.ca_cert_path)) {
             ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01895)
                     "Unable to configure verify locations "
                     "for client authentication");
@@ -999,6 +1014,23 @@ static apr_status_t ssl_init_ctx_cipher_suite(server_rec *s,
     return APR_SUCCESS;
 }
 
+static APR_INLINE
+int modssl_X509_STORE_load_locations(X509_STORE *store,
+                                     const char *file,
+                                     const char *path)
+{
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+    if (!X509_STORE_load_locations(store, file, path))
+        return 0;
+#else
+    if (file && !X509_STORE_load_file(store, file))
+        return 0;
+    if (path && !X509_STORE_load_path(store, path))
+        return 0;
+#endif
+    return 1;
+}
+
 static apr_status_t ssl_init_ctx_crl(server_rec *s,
                                      apr_pool_t *p,
                                      apr_pool_t *ptemp,
@@ -1037,8 +1069,8 @@ static apr_status_t ssl_init_ctx_crl(server_rec *s,
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01900)
                  "Configuring certificate revocation facility");
 
-    if (!store || !X509_STORE_load_locations(store, mctx->crl_file,
-                                             mctx->crl_path)) {
+    if (!store || modssl_X509_STORE_load_locations(store, mctx->crl_file,
+                                                          mctx->crl_path)) {
         ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01901)
                      "Host %s: unable to configure X.509 CRL storage "
                      "for certificate revocation", mctx->sc->vhost_id);
@@ -1277,7 +1309,7 @@ static apr_status_t ssl_init_server_certs(server_rec *s,
     const char *vhost_id = mctx->sc->vhost_id, *key_id, *certfile, *keyfile;
     int i;
     X509 *cert;
-    DH *dhparams;
+    DH *dh;
 #ifdef HAVE_ECC
     EC_GROUP *ecparams = NULL;
     int nid;
@@ -1462,12 +1494,12 @@ static apr_status_t ssl_init_server_certs(server_rec *s,
      */
     certfile = APR_ARRAY_IDX(mctx->pks->cert_files, 0, const char *);
     if (certfile && !modssl_is_engine_id(certfile)
-        && (dhparams = ssl_dh_GetParamFromFile(certfile))) {
-        SSL_CTX_set_tmp_dh(mctx->ssl_ctx, dhparams);
+        && (dh = ssl_dh_GetParamFromFile(certfile))) {
+        SSL_CTX_set_tmp_dh(mctx->ssl_ctx, dh);
         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02540)
                      "Custom DH parameters (%d bits) for %s loaded from %s",
-                     DH_bits(dhparams), vhost_id, certfile);
-        DH_free(dhparams);
+                     BN_num_bits(DH_get0_p(dh)), vhost_id, certfile);
+        DH_free(dh);
     }
 
 #ifdef HAVE_ECC
@@ -1518,6 +1550,7 @@ static apr_status_t ssl_init_ticket_key(server_rec *s,
     char buf[TLSEXT_TICKET_KEY_LEN];
     char *path;
     modssl_ticket_key_t *ticket_key = mctx->ticket_key;
+    int res;
 
     if (!ticket_key->file_path) {
         return APR_SUCCESS;
@@ -1545,11 +1578,22 @@ static apr_status_t ssl_init_ticket_key(server_rec *s,
     }
 
     memcpy(ticket_key->key_name, buf, 16);
-    memcpy(ticket_key->hmac_secret, buf + 16, 16);
     memcpy(ticket_key->aes_key, buf + 32, 16);
-
-    if (!SSL_CTX_set_tlsext_ticket_key_cb(mctx->ssl_ctx,
-                                          ssl_callback_SessionTicket)) {
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+    memcpy(ticket_key->hmac_secret, buf + 16, 16);
+    res = SSL_CTX_set_tlsext_ticket_key_cb(mctx->ssl_ctx,
+                                           ssl_callback_SessionTicket);
+#else
+    ticket_key->mac_params[0] =
+        OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, buf + 16, 16);
+    ticket_key->mac_params[1] =
+        OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, "sha256", 0);
+    ticket_key->mac_params[2] =
+        OSSL_PARAM_construct_end();
+    res = SSL_CTX_set_tlsext_ticket_key_evp_cb(mctx->ssl_ctx,
+                                               ssl_callback_SessionTicket);
+#endif
+    if (!res) {
         ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01913)
                      "Unable to initialize TLS session ticket key callback "
                      "(incompatible OpenSSL version?)");
@@ -1680,7 +1724,7 @@ static apr_status_t ssl_init_proxy_certs(server_rec *s,
         return ssl_die(s);
     }
 
-    X509_STORE_load_locations(store, pkp->ca_cert_file, NULL);
+    modssl_X509_STORE_load_locations(store, pkp->ca_cert_file, NULL);
 
     for (n = 0; n < ncerts; n++) {
         int i;
diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c
index b17626ad841..3fa457824b4 100644
--- a/modules/ssl/ssl_engine_io.c
+++ b/modules/ssl/ssl_engine_io.c
@@ -572,11 +572,20 @@ static int bio_filter_in_gets(BIO *bio, char *buf, int size)
 
 static long bio_filter_in_ctrl(BIO *bio, int cmd, long num, void *ptr)
 {
-    bio_filter_in_ctx_t *inctx = (bio_filter_in_ctx_t *)(bio->ptr);
+    bio_filter_in_ctx_t *inctx = (bio_filter_in_ctx_t *)BIO_get_data(bio);
+    switch (cmd) {
+#ifdef BIO_CTRL_EOF
+    case BIO_CTRL_EOF:
+        return inctx->rc == APR_EOF;
+#endif
+    default:
+        break;
+    }
     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, inctx->f->c,
-                  "BUG: %s() should not be called", "bio_filter_in_ctrl");
+                  "BUG: bio_filter_in_ctrl() should not be called with cmd=%i",
+                  cmd);
     AP_DEBUG_ASSERT(0);
-    return -1;
+    return 0;
 }
 
 #if MODSSL_USE_OPENSSL_PRE_1_1_API
@@ -601,7 +610,7 @@ static BIO_METHOD bio_filter_in_method = {
     bio_filter_in_read,
     bio_filter_in_puts,         /* puts is never called */
     bio_filter_in_gets,         /* gets is never called */
-    bio_filter_in_ctrl,         /* ctrl is never called */
+    bio_filter_in_ctrl,         /* ctrl is called for EOF check */
     bio_filter_create,
     bio_filter_destroy,
     NULL
diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c
index 5211a0db348..09a440061bf 100644
--- a/modules/ssl/ssl_engine_kernel.c
+++ b/modules/ssl/ssl_engine_kernel.c
@@ -2614,7 +2614,11 @@ int ssl_callback_SessionTicket(SSL *ssl,
                                unsigned char *keyname,
                                unsigned char *iv,
                                EVP_CIPHER_CTX *cipher_ctx,
-                               HMAC_CTX *hctx,
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+                               HMAC_CTX *hmac_ctx,
+#else
+                               EVP_MAC_CTX *mac_ctx,
+#endif
                                int mode)
 {
     conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
@@ -2640,7 +2644,13 @@ int ssl_callback_SessionTicket(SSL *ssl,
         }
         EVP_EncryptInit_ex(cipher_ctx, EVP_aes_128_cbc(), NULL,
                            ticket_key->aes_key, iv);
-        HMAC_Init_ex(hctx, ticket_key->hmac_secret, 16, tlsext_tick_md(), NULL);
+
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+        HMAC_Init_ex(hmac_ctx, ticket_key->hmac_secret, 16,
+                     tlsext_tick_md(), NULL);
+#else
+        EVP_MAC_CTX_set_params(mac_ctx, ticket_key->mac_params);
+#endif
 
         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(02289)
                       "TLS session ticket key for %s successfully set, "
@@ -2661,7 +2671,13 @@ int ssl_callback_SessionTicket(SSL *ssl,
 
         EVP_DecryptInit_ex(cipher_ctx, EVP_aes_128_cbc(), NULL,
                            ticket_key->aes_key, iv);
-        HMAC_Init_ex(hctx, ticket_key->hmac_secret, 16, tlsext_tick_md(), NULL);
+
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+        HMAC_Init_ex(hmac_ctx, ticket_key->hmac_secret, 16,
+                     tlsext_tick_md(), NULL);
+#else
+        EVP_MAC_CTX_set_params(mac_ctx, ticket_key->mac_params);
+#endif
 
         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(02290)
                       "TLS session ticket key for %s successfully set, "
diff --git a/modules/ssl/ssl_engine_log.c b/modules/ssl/ssl_engine_log.c
index 7dbbbdb55e0..3b3ceacf0a5 100644
--- a/modules/ssl/ssl_engine_log.c
+++ b/modules/ssl/ssl_engine_log.c
@@ -78,6 +78,16 @@ apr_status_t ssl_die(server_rec *s)
     return APR_EGENERAL;
 }
 
+static APR_INLINE
+unsigned long modssl_ERR_peek_error_data(const char **data, int *flags)
+{
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+    return ERR_peek_error_line_data(NULL, NULL, data, flags);
+#else
+    return ERR_peek_error_data(data, flags);
+#endif
+}
+
 /*
  * Prints the SSL library error information.
  */
@@ -87,7 +97,7 @@ void ssl_log_ssl_error(const char *file, int line, int level, server_rec *s)
     const char *data;
     int flags;
 
-    while ((e = ERR_peek_error_line_data(NULL, NULL, &data, &flags))) {
+    while ((e = modssl_ERR_peek_error_data(&data, &flags))) {
         const char *annotation;
         char err[256];
 
diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h
index c19427063d6..a13250493c7 100644
--- a/modules/ssl/ssl_private.h
+++ b/modules/ssl/ssl_private.h
@@ -89,6 +89,9 @@
 /* must be defined before including ssl.h */
 #define OPENSSL_NO_SSL_INTERN
 #endif
+#if OPENSSL_VERSION_NUMBER >= 0x30000000
+#include <openssl/core_names.h>
+#endif
 #include <openssl/ssl.h>
 #include <openssl/err.h>
 #include <openssl/x509.h>
@@ -681,7 +684,11 @@ typedef struct {
 typedef struct {
     const char *file_path;
     unsigned char key_name[16];
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
     unsigned char hmac_secret[16];
+#else
+    OSSL_PARAM mac_params[3];
+#endif
     unsigned char aes_key[16];
 } modssl_ticket_key_t;
 #endif
@@ -945,8 +952,16 @@ int          ssl_callback_ServerNameIndication(SSL *, int *, modssl_ctx_t *);
 int          ssl_callback_ClientHello(SSL *, int *, void *);
 #endif
 #ifdef HAVE_TLS_SESSION_TICKETS
-int         ssl_callback_SessionTicket(SSL *, unsigned char *, unsigned char *,
-                                       EVP_CIPHER_CTX *, HMAC_CTX *, int);
+int ssl_callback_SessionTicket(SSL *ssl,
+                               unsigned char *keyname,
+                               unsigned char *iv,
+                               EVP_CIPHER_CTX *cipher_ctx,
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+                               HMAC_CTX *hmac_ctx,
+#else
+                               EVP_MAC_CTX *mac_ctx,
+#endif
+                               int mode);
 #endif
 
 #ifdef HAVE_TLS_ALPN

From 2d03cad3a1f42e155b43d512372f209675f21540 Mon Sep 17 00:00:00 2001
From: Joe Orton <jorton@redhat.com>
Date: Mon, 26 Jul 2021 12:24:27 +0100
Subject: [PATCH 03/12] Merge r1876938 from trunk:

mod_ssl: follow up to r1876934: wrap DH_bits()

DH_get0_p() seems to be undefined for some openssl versions, so it can't
be used to implement DH_bits() generically.

Add new a modssl_DH_bits() wrapper to call DH_bits() for openssl < 3,
and BN_num_bits(DH_get0_p(dh)) otherwise.

Submitted by: ylavic
---
 modules/ssl/ssl_engine_init.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
index 352363f7e9f..d8365127d00 100644
--- a/modules/ssl/ssl_engine_init.c
+++ b/modules/ssl/ssl_engine_init.c
@@ -1299,6 +1299,15 @@ static int ssl_no_passwd_prompt_cb(char *buf, int size, int rwflag,
    return 0;
 }
 
+static APR_INLINE int modssl_DH_bits(DH *dh)
+{
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+    return DH_bits(dh);
+#else
+    return BN_num_bits(DH_get0_p(dh));
+#endif
+}
+
 static apr_status_t ssl_init_server_certs(server_rec *s,
                                           apr_pool_t *p,
                                           apr_pool_t *ptemp,
@@ -1498,7 +1507,7 @@ static apr_status_t ssl_init_server_certs(server_rec *s,
         SSL_CTX_set_tmp_dh(mctx->ssl_ctx, dh);
         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02540)
                      "Custom DH parameters (%d bits) for %s loaded from %s",
-                     BN_num_bits(DH_get0_p(dh)), vhost_id, certfile);
+                     modssl_DH_bits(dh), vhost_id, certfile);
         DH_free(dh);
     }
 

From a45ea8ea6eaa88620ee978ef6f4928c3266814a0 Mon Sep 17 00:00:00 2001
From: Joe Orton <jorton@redhat.com>
Date: Mon, 26 Jul 2021 12:24:46 +0100
Subject: [PATCH 04/12] Merge r1891138 from trunk:

* modules/ssl/ssl_engine_init.c (ssl_init_server_certs): Fix use of
  encrypted private keys with OpenSSL 3.0.

* test/travis_run_linux.sh: For TEST_SSL, test loading encrypted
  private keys.

Github: closes #{197}

Submitted by: jorton
---
 modules/ssl/ssl_engine_init.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
index d8365127d00..bab4982ad8b 100644
--- a/modules/ssl/ssl_engine_init.c
+++ b/modules/ssl/ssl_engine_init.c
@@ -1308,6 +1308,22 @@ static APR_INLINE int modssl_DH_bits(DH *dh)
 #endif
 }
 
+/* SSL_CTX_use_PrivateKey_file() can fail either because the private
+ * key was encrypted, or due to a mismatch between an already-loaded
+ * cert and the key - a common misconfiguration - from calling
+ * X509_check_private_key().  This macro is passed the last error code
+ * off the OpenSSL stack and evaluates to true only for the first
+ * case.  With OpenSSL < 3 the second case is identifiable by the
+ * function code, but function codes are not used from 3.0. */
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+#define CHECK_PRIVKEY_ERROR(ec) (ERR_GET_FUNC(ec) != X509_F_X509_CHECK_PRIVATE_KEY)
+#else
+#define CHECK_PRIVKEY_ERROR(ec) (ERR_GET_LIB != ERR_LIB_X509            \
+                                 || (ERR_GET_REASON(ec) != X509_R_KEY_TYPE_MISMATCH \
+                                     && ERR_GET_REASON(ec) != X509_R_KEY_VALUES_MISMATCH \
+                                     && ERR_GET_REASON(ec) != X509_R_UNKNOWN_KEY_TYPE))
+#endif
+
 static apr_status_t ssl_init_server_certs(server_rec *s,
                                           apr_pool_t *p,
                                           apr_pool_t *ptemp,
@@ -1413,8 +1429,7 @@ static apr_status_t ssl_init_server_certs(server_rec *s,
         }
         else if ((SSL_CTX_use_PrivateKey_file(mctx->ssl_ctx, keyfile,
                                               SSL_FILETYPE_PEM) < 1)
-                 && (ERR_GET_FUNC(ERR_peek_last_error())
-                     != X509_F_X509_CHECK_PRIVATE_KEY)) {
+                 && CHECK_PRIVKEY_ERROR(ERR_peek_last_error())) {
             ssl_asn1_t *asn1;
             const unsigned char *ptr;
 

From f4f39a9d5f8a88aa3af256c99b38a9e19f3635b1 Mon Sep 17 00:00:00 2001
From: Joe Orton <jorton@redhat.com>
Date: Mon, 26 Jul 2021 12:25:36 +0100
Subject: [PATCH 05/12] Merge r1890067 from trunk:

mod_ssl: Switch to using OpenSSL's automatic internal DH parameter
generation from OpenSSL 1.1.0 and later.  The
SSL_set_tmp_dh_callback() API is deprecated from OpenSSL 3.0 onwards.
Should not be a user-visible change (except mod_ssl gets smaller).

* modules/ssl/ssl_private.h,
  modules/ssl/ssl_engine_kernel.c,
  modules/ssl/ssl_engine_init.c (ssl_init_ctx_callbacks):
  Drop internal DH parameter generation and callback for OpenSSL 1.1+,
  use SSL_CTX_set_dh_auto(, 1) instead.

Github: closes #188
Reviewed by: rpluem

Submitted by: jorton
---
 modules/ssl/ssl_engine_init.c   | 14 ++++++++++----
 modules/ssl/ssl_engine_kernel.c |  2 ++
 modules/ssl/ssl_private.h       |  2 ++
 3 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
index bab4982ad8b..2893e66903a 100644
--- a/modules/ssl/ssl_engine_init.c
+++ b/modules/ssl/ssl_engine_init.c
@@ -91,7 +91,6 @@ static int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
 
     return 1;
 }
-#endif
 
 /*
  * Grab well-defined DH parameters from OpenSSL, see the BN_get_rfc*
@@ -171,6 +170,7 @@ DH *modssl_get_dh_params(unsigned keylen)
         
     return NULL; /* impossible to reach. */
 }
+#endif
 
 static void ssl_add_version_components(apr_pool_t *ptemp, apr_pool_t *pconf,
                                        server_rec *s)
@@ -440,8 +440,9 @@ apr_status_t ssl_init_Module(apr_pool_t *p, apr_pool_t *plog,
 
     modssl_init_app_data2_idx(); /* for modssl_get_app_data2() at request time */
 
+#if MODSSL_USE_OPENSSL_PRE_1_1_API
     init_dh_params();
-#if !MODSSL_USE_OPENSSL_PRE_1_1_API
+#else
     init_bio_methods();
 #endif
 
@@ -862,7 +863,11 @@ static void ssl_init_ctx_callbacks(server_rec *s,
 {
     SSL_CTX *ctx = mctx->ssl_ctx;
 
+#if MODSSL_USE_OPENSSL_PRE_1_1_API
     SSL_CTX_set_tmp_dh_callback(ctx,  ssl_callback_TmpDH);
+#else
+    SSL_CTX_set_dh_auto(ctx, 1);
+#endif
 
     SSL_CTX_set_info_callback(ctx, ssl_callback_Info);
 
@@ -2345,10 +2350,11 @@ apr_status_t ssl_init_ModuleKill(void *data)
 
     }
 
-#if !MODSSL_USE_OPENSSL_PRE_1_1_API
+#if MODSSL_USE_OPENSSL_PRE_1_1_API
+    free_dh_params();
+#else
     free_bio_methods();
 #endif
-    free_dh_params();
 
     return APR_SUCCESS;
 }
diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c
index 09a440061bf..591f6ae29c1 100644
--- a/modules/ssl/ssl_engine_kernel.c
+++ b/modules/ssl/ssl_engine_kernel.c
@@ -1685,6 +1685,7 @@ const authz_provider ssl_authz_provider_verify_client =
 **  _________________________________________________________________
 */
 
+#if MODSSL_USE_OPENSSL_PRE_1_1_API
 /*
  * Hand out standard DH parameters, based on the authentication strength
  */
@@ -1730,6 +1731,7 @@ DH *ssl_callback_TmpDH(SSL *ssl, int export, int keylen)
 
     return modssl_get_dh_params(keylen);
 }
+#endif
 
 /*
  * This OpenSSL callback function is called when OpenSSL
diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h
index a13250493c7..77c9fc6e2a2 100644
--- a/modules/ssl/ssl_private.h
+++ b/modules/ssl/ssl_private.h
@@ -1139,10 +1139,12 @@ void ssl_init_ocsp_certificates(server_rec *s, modssl_ctx_t *mctx);
 
 #endif
 
+#if MODSSL_USE_OPENSSL_PRE_1_1_API
 /* Retrieve DH parameters for given key length.  Return value should
  * be treated as unmutable, since it is stored in process-global
  * memory. */
 DH *modssl_get_dh_params(unsigned keylen);
+#endif
 
 /* Returns non-zero if the request was made over SSL/TLS.  If sslconn
  * is non-NULL and the request is using SSL/TLS, sets *sslconn to the

From 3d53c7216030ccace0211f647f15419dc1aebc0a Mon Sep 17 00:00:00 2001
From: Joe Orton <jorton@redhat.com>
Date: Mon, 26 Jul 2021 12:29:32 +0100
Subject: [PATCH 06/12] Merge r1890076 from trunk:

fix build with LibreSSL [Yann Ylavic]
Github issue #188

Submitted by: gbechis
---
 modules/ssl/ssl_private.h | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h
index 77c9fc6e2a2..a329d99a031 100644
--- a/modules/ssl/ssl_private.h
+++ b/modules/ssl/ssl_private.h
@@ -137,13 +137,12 @@
         SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MIN_PROTO_VERSION, version, NULL)
 #define SSL_CTX_set_max_proto_version(ctx, version) \
         SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MAX_PROTO_VERSION, version, NULL)
-#elif LIBRESSL_VERSION_NUMBER < 0x2070000f
+#endif /* LIBRESSL_VERSION_NUMBER < 0x2060000f */
 /* LibreSSL before 2.7 declares OPENSSL_VERSION_NUMBER == 2.0 but does not
  * include most changes from OpenSSL >= 1.1 (new functions, macros, 
  * deprecations, ...), so we have to work around this...
  */
-#define MODSSL_USE_OPENSSL_PRE_1_1_API (1)
-#endif /* LIBRESSL_VERSION_NUMBER < 0x2060000f */
+#define MODSSL_USE_OPENSSL_PRE_1_1_API (LIBRESSL_VERSION_NUMBER < 0x2070000f)
 #else /* defined(LIBRESSL_VERSION_NUMBER) */
 #define MODSSL_USE_OPENSSL_PRE_1_1_API (OPENSSL_VERSION_NUMBER < 0x10100000L)
 #endif

From 57ac9ae89c79fb89a7182409921dada7f184fe7f Mon Sep 17 00:00:00 2001
From: Joe Orton <jorton@redhat.com>
Date: Mon, 26 Jul 2021 14:15:28 +0100
Subject: [PATCH 07/12] Merge r1737657 from trunk:

Support for OpenSSL 1.1.0:
- BIO was made opaque after OpenSSL 1.1.0pre4.

Submitted by: rjung
---
 modules/ssl/ssl_engine_io.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c
index 3fa457824b4..79b9a701004 100644
--- a/modules/ssl/ssl_engine_io.c
+++ b/modules/ssl/ssl_engine_io.c
@@ -194,7 +194,7 @@ static int bio_filter_destroy(BIO *bio)
 static int bio_filter_out_read(BIO *bio, char *out, int outl)
 {
     /* this is never called */
-    bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr);
+    bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)BIO_get_data(bio);
     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, outctx->c,
                   "BUG: %s() should not be called", "bio_filter_out_read");
     AP_DEBUG_ASSERT(0);
@@ -297,7 +297,7 @@ static long bio_filter_out_ctrl(BIO *bio, int cmd, long num, void *ptr)
 static int bio_filter_out_gets(BIO *bio, char *buf, int size)
 {
     /* this is never called */
-    bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr);
+    bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)BIO_get_data(bio);
     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, outctx->c,
                   "BUG: %s() should not be called", "bio_filter_out_gets");
     AP_DEBUG_ASSERT(0);
@@ -307,7 +307,7 @@ static int bio_filter_out_gets(BIO *bio, char *buf, int size)
 static int bio_filter_out_puts(BIO *bio, const char *str)
 {
     /* this is never called */
-    bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr);
+    bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)BIO_get_data(bio);
     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, outctx->c,
                   "BUG: %s() should not be called", "bio_filter_out_puts");
     AP_DEBUG_ASSERT(0);
@@ -545,7 +545,7 @@ static int bio_filter_in_read(BIO *bio, char *in, int inlen)
 
 static int bio_filter_in_write(BIO *bio, const char *in, int inl)
 {
-    bio_filter_in_ctx_t *inctx = (bio_filter_in_ctx_t *)(bio->ptr);
+    bio_filter_in_ctx_t *inctx = (bio_filter_in_ctx_t *)BIO_get_data(bio);
     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, inctx->f->c,
                   "BUG: %s() should not be called", "bio_filter_in_write");
     AP_DEBUG_ASSERT(0);
@@ -554,7 +554,7 @@ static int bio_filter_in_write(BIO *bio, const char *in, int inl)
 
 static int bio_filter_in_puts(BIO *bio, const char *str)
 {
-    bio_filter_in_ctx_t *inctx = (bio_filter_in_ctx_t *)(bio->ptr);
+    bio_filter_in_ctx_t *inctx = (bio_filter_in_ctx_t *)BIO_get_data(bio);
     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, inctx->f->c,
                   "BUG: %s() should not be called", "bio_filter_in_puts");
     AP_DEBUG_ASSERT(0);
@@ -563,7 +563,7 @@ static int bio_filter_in_puts(BIO *bio, const char *str)
 
 static int bio_filter_in_gets(BIO *bio, char *buf, int size)
 {
-    bio_filter_in_ctx_t *inctx = (bio_filter_in_ctx_t *)(bio->ptr);
+    bio_filter_in_ctx_t *inctx = (bio_filter_in_ctx_t *)BIO_get_data(bio);
     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, inctx->f->c,
                   "BUG: %s() should not be called", "bio_filter_in_gets");
     AP_DEBUG_ASSERT(0);

From 4e8c252f999eb8d75d921dc4e2d0dd63cfdca54d Mon Sep 17 00:00:00 2001
From: Joe Orton <jorton@redhat.com>
Date: Wed, 28 Jul 2021 12:28:59 +0100
Subject: [PATCH 08/12] Merge r1876936 from trunk:

mod_ssl: follow up to r1876934: fix !modssl_X509_STORE_load_locations() logic.

Submitted by: ylavic
---
 modules/ssl/ssl_engine_init.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
index 2893e66903a..c97ab51cb88 100644
--- a/modules/ssl/ssl_engine_init.c
+++ b/modules/ssl/ssl_engine_init.c
@@ -1074,8 +1074,8 @@ static apr_status_t ssl_init_ctx_crl(server_rec *s,
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01900)
                  "Configuring certificate revocation facility");
 
-    if (!store || modssl_X509_STORE_load_locations(store, mctx->crl_file,
-                                                          mctx->crl_path)) {
+    if (!store || !modssl_X509_STORE_load_locations(store, mctx->crl_file,
+                                                           mctx->crl_path)) {
         ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01901)
                      "Host %s: unable to configure X.509 CRL storage "
                      "for certificate revocation", mctx->sc->vhost_id);

From 2b89f72cd9ff7b1c113676f6e112f439916e2993 Mon Sep 17 00:00:00 2001
From: Joe Orton <jorton@redhat.com>
Date: Mon, 4 Oct 2021 14:26:49 +0100
Subject: [PATCH 09/12] Merge r1893876 from trunk:

* modules/ssl/ssl_engine_init.c (ssl_init_server_certs): For OpenSSL
  1.1+, disable auto DH parameter selection if parameters have been
  manually configured.  This fixes a regression in r1890067 after
  which manually configured parameters are ignored.

Submitted by: jorton
---
 modules/ssl/ssl_engine_init.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
index c97ab51cb88..e477c5857a9 100644
--- a/modules/ssl/ssl_engine_init.c
+++ b/modules/ssl/ssl_engine_init.c
@@ -1524,7 +1524,14 @@ static apr_status_t ssl_init_server_certs(server_rec *s,
     certfile = APR_ARRAY_IDX(mctx->pks->cert_files, 0, const char *);
     if (certfile && !modssl_is_engine_id(certfile)
         && (dh = ssl_dh_GetParamFromFile(certfile))) {
+        /* ### This should be replaced with SSL_CTX_set0_tmp_dh_pkey()
+         * for OpenSSL 3.0+. */
         SSL_CTX_set_tmp_dh(mctx->ssl_ctx, dh);
+#if !MODSSL_USE_OPENSSL_PRE_1_1_API
+        /* OpenSSL ignores manually configured DH params if automatic
+         * selection if enabled, so disable auto selection here. */
+        SSL_CTX_set_dh_auto(mctx->ssl_ctx, 0);
+#endif
         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02540)
                      "Custom DH parameters (%d bits) for %s loaded from %s",
                      modssl_DH_bits(dh), vhost_id, certfile);

From 9bcbc67a6f9832d66332da61733da0378fb191b3 Mon Sep 17 00:00:00 2001
From: Joe Orton <jorton@redhat.com>
Date: Tue, 12 Oct 2021 13:48:55 +0100
Subject: [PATCH 10/12] Merge r1893964 from trunk:

* modules/ssl/ssl_engine_init.c (ssl_init_ctx_callbacks,
  ssl_init_server_certs): Flip logic for enabling/disabling DH auto
  parameter selection for OpenSSL 1.1+ to be simpler and consistent
  with auto ECDH curve selection.
---
 modules/ssl/ssl_engine_init.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
index e477c5857a9..3f32ed2ab3b 100644
--- a/modules/ssl/ssl_engine_init.c
+++ b/modules/ssl/ssl_engine_init.c
@@ -864,9 +864,9 @@ static void ssl_init_ctx_callbacks(server_rec *s,
     SSL_CTX *ctx = mctx->ssl_ctx;
 
 #if MODSSL_USE_OPENSSL_PRE_1_1_API
+    /* Note that for OpenSSL>=1.1, auto selection is enabled via
+     * SSL_CTX_set_dh_auto(,1) if no parameter is configured. */
     SSL_CTX_set_tmp_dh_callback(ctx,  ssl_callback_TmpDH);
-#else
-    SSL_CTX_set_dh_auto(ctx, 1);
 #endif
 
     SSL_CTX_set_info_callback(ctx, ssl_callback_Info);
@@ -1527,16 +1527,18 @@ static apr_status_t ssl_init_server_certs(server_rec *s,
         /* ### This should be replaced with SSL_CTX_set0_tmp_dh_pkey()
          * for OpenSSL 3.0+. */
         SSL_CTX_set_tmp_dh(mctx->ssl_ctx, dh);
-#if !MODSSL_USE_OPENSSL_PRE_1_1_API
-        /* OpenSSL ignores manually configured DH params if automatic
-         * selection if enabled, so disable auto selection here. */
-        SSL_CTX_set_dh_auto(mctx->ssl_ctx, 0);
-#endif
         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02540)
                      "Custom DH parameters (%d bits) for %s loaded from %s",
                      modssl_DH_bits(dh), vhost_id, certfile);
         DH_free(dh);
     }
+#if !MODSSL_USE_OPENSSL_PRE_1_1_API
+    else {
+        /* If no parameter is manually configured, enable auto
+         * selection. */
+        SSL_CTX_set_dh_auto(mctx->ssl_ctx, 1);
+    }
+#endif
 
 #ifdef HAVE_ECC
     /*

From 24c3475cefd740368385f29afb9247e0d723e1fd Mon Sep 17 00:00:00 2001
From: Joe Orton <jorton@redhat.com>
Date: Fri, 10 Dec 2021 14:10:34 +0000
Subject: [PATCH 11/12] Merge r1894716 from trunk:

  * mod_ssl: fix in CHECK_PRIVKEY_ERROR for openssl 3.0

Submitted by: icing
---
 modules/ssl/ssl_engine_init.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
index 3f32ed2ab3b..43119046a94 100644
--- a/modules/ssl/ssl_engine_init.c
+++ b/modules/ssl/ssl_engine_init.c
@@ -1323,7 +1323,7 @@ static APR_INLINE int modssl_DH_bits(DH *dh)
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
 #define CHECK_PRIVKEY_ERROR(ec) (ERR_GET_FUNC(ec) != X509_F_X509_CHECK_PRIVATE_KEY)
 #else
-#define CHECK_PRIVKEY_ERROR(ec) (ERR_GET_LIB != ERR_LIB_X509            \
+#define CHECK_PRIVKEY_ERROR(ec) (ERR_GET_LIB(ec) != ERR_LIB_X509            \
                                  || (ERR_GET_REASON(ec) != X509_R_KEY_TYPE_MISMATCH \
                                      && ERR_GET_REASON(ec) != X509_R_KEY_VALUES_MISMATCH \
                                      && ERR_GET_REASON(ec) != X509_R_UNKNOWN_KEY_TYPE))

From fd7b7c4ce42a59a6d17a4bb490492edf7f948318 Mon Sep 17 00:00:00 2001
From: Joe Orton <jorton@redhat.com>
Date: Fri, 10 Dec 2021 14:50:50 +0000
Subject: [PATCH 12/12] Merge r1895774 from trunk:

* modules/ssl/ssl_engine_io.c (bio_filter_in_ctrl): Remove debugging
  assert for unexpected control commands, matching bio_filter_out_ctrl
  which also ignores such invocations.  Fixes core dumps in debug
  builds with OpenSSL 3.0.0 which triggers this via the
  BIO_get_ktls_recv() call on the SSL bio, aka
    BIO_ctrl(b, BIO_CTRL_GET_KTLS_RECV, ...);

See: https://github.com/openssl/openssl/blob/105af0ad923a665ca5fee296b52dbf34b524a2aa/ssl/record/rec_layer_s3.c#L274

Submitted by: jorton
---
 modules/ssl/ssl_engine_io.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c
index 79b9a701004..f14fc9b0aae 100644
--- a/modules/ssl/ssl_engine_io.c
+++ b/modules/ssl/ssl_engine_io.c
@@ -584,7 +584,6 @@ static long bio_filter_in_ctrl(BIO *bio, int cmd, long num, void *ptr)
     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, inctx->f->c,
                   "BUG: bio_filter_in_ctrl() should not be called with cmd=%i",
                   cmd);
-    AP_DEBUG_ASSERT(0);
     return 0;
 }
 
