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
#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)
/*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)
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;
}
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) {
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;
}
# 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
*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;
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)
#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;
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)
{
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)
{
"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,
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);
EVP_PKEY_set1_DH(pkey, dh);
DH_free(dh);
}
+#endif
BIO_free(bio);
*pkey_r = pkey;
return pkey == NULL ? -1 : 0;
}
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",
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
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),