]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-ssl-iostream: Fix compability with OpenSSL 3.0
authorAki Tuomi <aki.tuomi@open-xchange.com>
Mon, 24 Oct 2022 11:05:46 +0000 (14:05 +0300)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Thu, 3 Nov 2022 07:40:40 +0000 (07:40 +0000)
src/lib-ssl-iostream/Makefile.am
src/lib-ssl-iostream/dovecot-openssl-common.c
src/lib-ssl-iostream/iostream-openssl-common.c
src/lib-ssl-iostream/iostream-openssl-context.c
src/lib-ssl-iostream/iostream-openssl.c

index 83a22309951470455834b5c95d78ef86ea691ed1..fb998846155108b03443a8d80eea44630d837683 100644 (file)
@@ -5,7 +5,8 @@ NOPLUGIN_LDFLAGS =
 AM_CPPFLAGS = \
        -I$(top_srcdir)/src/lib \
        -I$(top_srcdir)/src/lib-test \
-       -DMODULE_DIR=\""$(moduledir)"\"
+       -DMODULE_DIR=\""$(moduledir)"\" \
+       $(SSL_CFLAGS)
 
 module_LTLIBRARIES = libssl_iostream_openssl.la
 
index 72ef119e8063f401835d61f09c10fefd7a30febb..49e8f707c5b374e70db8db2a05cc49ab2d6916df 100644 (file)
@@ -3,13 +3,23 @@
 #include "lib.h"
 #include "randgen.h"
 #include "dovecot-openssl-common.h"
+#include "iostream-openssl.h"
 
 #include <openssl/ssl.h>
-#include <openssl/engine.h>
+#include <openssl/err.h>
+#ifdef HAVE_OSSL_PROVIDER_try_load
+#  include <openssl/provider.h>
+#else
+#  include <openssl/engine.h>
+#endif
 #include <openssl/rand.h>
 
 static int openssl_init_refcount = 0;
-static ENGINE *dovecot_openssl_engine;
+#ifdef HAVE_OSSL_PROVIDER_try_load
+static OSSL_PROVIDER *dovecot_openssl_engine = NULL;
+#else
+static ENGINE *dovecot_openssl_engine = NULL;
+#endif
 
 #ifdef HAVE_SSL_NEW_MEM_FUNCS
 static void *dovecot_openssl_malloc(size_t size, const char *u0 ATTR_UNUSED, int u1 ATTR_UNUSED)
@@ -63,9 +73,13 @@ void dovecot_openssl_common_global_ref(void)
                /*i_warning("CRYPTO_set_mem_functions() was called too late");*/
        }
 
+#ifdef HAVE_OPENSSL_init_ssl
+       OPENSSL_init_ssl(0, NULL);
+#else
        SSL_library_init();
        SSL_load_error_strings();
        OpenSSL_add_all_algorithms();
+#endif
 }
 
 bool dovecot_openssl_common_global_unref(void)
@@ -76,30 +90,35 @@ bool dovecot_openssl_common_global_unref(void)
                return TRUE;
 
        if (dovecot_openssl_engine != NULL) {
+#ifdef HAVE_OSSL_PROVIDER_try_load
+               OSSL_PROVIDER_unload(dovecot_openssl_engine);
+#else
                ENGINE_finish(dovecot_openssl_engine);
+#endif
                dovecot_openssl_engine = NULL;
        }
+#ifdef HAVE_OPENSSL_cleanup
+       OPENSSL_cleanup();
+#else
        /* OBJ_cleanup() is called automatically by EVP_cleanup() in
           newer versions. Doesn't hurt to call it anyway. */
        OBJ_cleanup();
-#if !defined(OPENSSL_NO_COMP)
+#  if !defined(OPENSSL_NO_COMP)
        SSL_COMP_free_compression_methods();
-#endif
+#  endif
        ENGINE_cleanup();
        EVP_cleanup();
        CRYPTO_cleanup_all_ex_data();
-#ifdef HAVE_OPENSSL_thread_stop
+#  ifdef HAVE_OPENSSL_thread_stop
        /* no cleanup needed */
-#elif defined(HAVE_ERR_remove_thread_state)
+#  elif defined(HAVE_ERR_remove_thread_state)
        /* This was marked as deprecated in v1.1. */
        ERR_remove_thread_state(NULL);
-#elif defined(HAVE_ERR_remove_state)
+#  elif defined(HAVE_ERR_remove_state)
        /* This was deprecated by ERR_remove_thread_state(NULL) in v1.0.0. */
        ERR_remove_state(0);
-#endif
+#  endif
        ERR_free_strings();
-#ifdef HAVE_OPENSSL_cleanup
-       OPENSSL_cleanup();
 #endif
        return FALSE;
 }
@@ -110,6 +129,7 @@ int dovecot_openssl_common_global_set_engine(const char *engine,
        if (dovecot_openssl_engine != NULL)
                return 1;
 
+#ifdef HAVE_ENGINE_by_id
        ENGINE_load_builtin_engines();
        dovecot_openssl_engine = ENGINE_by_id(engine);
        if (dovecot_openssl_engine == NULL) {
@@ -128,5 +148,15 @@ int dovecot_openssl_common_global_set_engine(const char *engine,
                dovecot_openssl_engine = NULL;
                return -1;
        }
+#elif defined(HAVE_OSSL_PROVIDER_try_load)
+       if ((dovecot_openssl_engine = OSSL_PROVIDER_try_load(NULL, engine, 1)) == NULL) {
+               *error_r = t_strdup_printf("Cannot load '%s': %s", engine,
+                                          openssl_iostream_error());
+               return 0;
+       }
+       return 1;
+#else
+       *error_r = t_strdup_printf("Cannot load '%s': No engine/provider support available", engine);
+#endif
        return 1;
 }
index f532d11df0f131609274cfb40a0e0fc3c4b481ae..3ffa1ef39446d9fcd92eae7acb52cfccdb8394bb 100644 (file)
 #  define TLS_MAX_VERSION 0
 #endif
 
+#ifdef HAVE_ERR_get_error_all
+# define openssl_get_error_data(data, flags) \
+       ERR_get_error_all(NULL, NULL, NULL, data, flags)
+#else
+# define openssl_get_error_data(data, flags) \
+       ERR_get_error_line_data(NULL, NULL, data, flags)
+#endif
+
 /* openssl_min_protocol_to_options() scans this array for name and returns
    version and opt. opt is used with SSL_set_options() and version is used with
    SSL_set_min_proto_version(). Using either method should enable the same
@@ -69,7 +77,11 @@ bool openssl_cert_match_name(SSL *ssl, const char *verify_name,
 
        *reason_r = NULL;
 
+#ifdef HAVE_SSL_get1_peer_certificate
+       cert = SSL_get1_peer_certificate(ssl);
+#else
        cert = SSL_get_peer_certificate(ssl);
+#endif
        i_assert(cert != NULL);
 
        char *peername;
@@ -120,7 +132,7 @@ const char *openssl_iostream_error(void)
        const char *data, *final_error;
        int flags;
 
-       while ((err = ERR_get_error_line_data(NULL, NULL, &data, &flags)) != 0) {
+       while ((err = openssl_get_error_data(&data, &flags)) != 0) {
                if (ERR_GET_REASON(err) == ERR_R_MALLOC_FAILURE)
                        i_fatal_status(FATAL_OUTOFMEM, "OpenSSL malloc() failed");
                if (ERR_peek_error() == 0)
index f0a5ad6625f0e4182436b03e8a94eef1ce89d811..80c3af812e263bf8c19f48cf312ac9b538fd0992 100644 (file)
 #include <openssl/ssl.h>
 #include <openssl/err.h>
 
+#ifndef HAVE_EVP_PKEY_get0_DH
+#  define EVP_PKEY_get0_DH(x) ((x)->pkey.dh)
+#endif
+
 struct ssl_iostream_password_context {
        const char *password;
        const char *error;
@@ -22,6 +26,7 @@ struct ssl_iostream_password_context {
 static bool ssl_global_initialized = FALSE;
 int dovecot_ssl_extdata_index;
 
+#ifdef HAVE_SSL_CTX_set_tmp_rsa_callback
 static RSA *ssl_gen_rsa_key(SSL *ssl ATTR_UNUSED,
                            int is_export ATTR_UNUSED, int keylength)
 {
@@ -40,7 +45,9 @@ static RSA *ssl_gen_rsa_key(SSL *ssl ATTR_UNUSED,
                RSA_free(rsa);
        return NULL;
 }
+#endif
 
+#ifdef HAVE_SSL_CTX_set_tmp_dh_callback
 static DH *ssl_tmp_dh_callback(SSL *ssl,
                               int is_export ATTR_UNUSED, int keylength ATTR_UNUSED)
 {
@@ -51,6 +58,7 @@ static DH *ssl_tmp_dh_callback(SSL *ssl,
                "but no DH parameters provided. Set ssl_dh=</path/to/dh.pem");
        return NULL;
 }
+#endif
 
 static int
 pem_password_callback(char *buf, int size, int rwflag ATTR_UNUSED,
@@ -127,6 +135,12 @@ int openssl_iostream_load_dh(const struct ssl_iostream_settings *set,
                return -1;
        }
 
+#ifdef HAVE_PEM_read_bio_Parameters
+       if ((pkey = PEM_read_bio_Parameters(bio, &pkey)) == NULL) {
+               *error_r = t_strdup_printf("Couldn't parse DH parameters: %s",
+                                          openssl_iostream_error());
+       }
+#else
        DH *dh = NULL;
        dh = PEM_read_bio_DHparams(bio, &dh, NULL, NULL);
 
@@ -138,6 +152,7 @@ int openssl_iostream_load_dh(const struct ssl_iostream_settings *set,
                EVP_PKEY_set1_DH(pkey, dh);
                DH_free(dh);
        }
+#endif
        BIO_free(bio);
        *pkey_r = pkey;
        return pkey == NULL ? -1 : 0;
@@ -175,8 +190,12 @@ ssl_iostream_ctx_use_dh(struct ssl_iostream_context *ctx,
        }
        if (openssl_iostream_load_dh(set, &pkey_dh, error_r) < 0)
                return -1;
+#ifdef HAVE_SSL_CTX_set0_tmp_dh_pkey
+       if (SSL_CTX_set0_tmp_dh_pkey(ctx->ssl_ctx, pkey_dh) == 0)
+#else
        DH *dh = EVP_PKEY_get0_DH(pkey_dh);
        if (SSL_CTX_set_tmp_dh(ctx->ssl_ctx, dh) == 0)
+#endif
        {
                 *error_r = t_strdup_printf(
                        "Can't load DH parameters (ssl_dh setting): %s",
@@ -498,10 +517,14 @@ ssl_proxy_ctx_set_crypto_params(SSL_CTX *ssl_ctx,
                                const struct ssl_iostream_settings *set ATTR_UNUSED,
                                const char **error_r ATTR_UNUSED)
 {
+#ifdef HAVE_SSL_CTX_set_tmp_rsa_callback
        if (SSL_CTX_need_tmp_RSA(ssl_ctx) != 0)
                SSL_CTX_set_tmp_rsa_callback(ssl_ctx, ssl_gen_rsa_key);
+#endif
+#ifdef HAVE_SSL_CTX_set_tmp_dh_callback
        if (set->dh == NULL || *set->dh == '\0')
                SSL_CTX_set_tmp_dh_callback(ssl_ctx, ssl_tmp_dh_callback);
+#endif
 #ifndef OPENSSL_NO_ECDH
        /* In the non-recommended situation where ECDH cipher suites are being
           used instead of ECDHE, do not reuse the same ECDH key pair for
index 825967bdb093115fa7b5b3341bb5b4dc049cbbbc..7237f90703903143675c9da19a3c625cca8bc4dd 100644 (file)
@@ -802,7 +802,11 @@ openssl_iostream_get_peer_name(struct ssl_iostream *ssl_io)
        if (!ssl_iostream_has_valid_client_cert(ssl_io))
                return NULL;
 
+#ifdef HAVE_SSL_get1_peer_certificate
+       x509 = SSL_get1_peer_certificate(ssl_io->ssl);
+#else
        x509 = SSL_get_peer_certificate(ssl_io->ssl);
+#endif
        i_assert(x509 != NULL);
 
        len = X509_NAME_get_text_by_NID(X509_get_subject_name(x509),