lib-auth \
lib-master \
lib-charset \
+ lib-ssl-iostream \
lib-dcrypt \
lib-dns \
lib-dict \
lib-sasl \
- lib-ssl-iostream \
lib-stats \
lib-http \
lib-fs \
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
- -I$(top_srcdir)/src/lib-test
+ -I$(top_srcdir)/src/lib-test \
+ -I$(top_srcdir)/src/lib-ssl-iostream
libdcrypt_la_SOURCES = \
dcrypt.c \
if BUILD_OPENSSL
pkglib_LTLIBRARIES += libdcrypt_openssl.la
libdcrypt_openssl_la_SOURCES = dcrypt-openssl.c dcrypt.c
-libdcrypt_openssl_la_LDFLAGS = -module -avoid-version -shared $(SSL_LIBS) ../lib/liblib.la
+libdcrypt_openssl_la_LDFLAGS = -module -avoid-version -shared ../lib-ssl-iostream/libdovecot_openssl_common.la ../lib/liblib.la
+libdcrypt_openssl_la_DEPENDENCIES = ../lib-ssl-iostream/libdovecot_openssl_common.la ../lib/liblib.la
libdcrypt_openssl_la_CFLAGS = $(AM_CPPFLAGS) \
-DDCRYPT_MODULE_DIR=\"$(pkglibdir)\"
$(SSL_CFLAGS)
#include "randgen.h"
#include "array.h"
#include "module-dir.h"
+#include "dovecot-openssl-common.h"
#include <openssl/evp.h>
#include <openssl/sha.h>
#include <openssl/err.h>
void dcrypt_openssl_init(struct module *module ATTR_UNUSED)
{
- OpenSSL_add_all_algorithms();
- ERR_load_crypto_strings();
+ dovecot_openssl_common_global_ref();
dcrypt_set_vfs(&dcrypt_openssl_vfs);
}
void dcrypt_openssl_deinit(void)
{
-#if OPENSSL_API_COMPAT < 0x10100000L
- OBJ_cleanup();
-#endif
+ dovecot_openssl_common_global_unref();
}
if BUILD_OPENSSL
module_LTLIBRARIES = libssl_iostream_openssl.la
+noinst_LTLIBRARIES += libdovecot_openssl_common.la
+libdovecot_openssl_common_la_LIBADD = $(SSL_LIBS)
+libdovecot_openssl_common_la_SOURCES = \
+ dovecot-openssl-common.c
+
libssl_iostream_openssl_la_LDFLAGS = -module -avoid-version
-libssl_iostream_openssl_la_LIBADD = $(SSL_LIBS)
+libssl_iostream_openssl_la_LIBADD = libdovecot_openssl_common.la
libssl_iostream_openssl_la_SOURCES = \
iostream-openssl.c \
iostream-openssl-common.c \
iostream-ssl.c \
$(ssl_sources)
+noinst_HEADERS = \
+ dovecot-openssl-common.h
+
headers = \
iostream-openssl.h \
iostream-ssl.h \
--- /dev/null
+/* Copyright (c) 2016 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "dovecot-openssl-common.h"
+
+#include <openssl/ssl.h>
+#include <openssl/engine.h>
+#include <openssl/rand.h>
+
+static int openssl_init_refcount = 0;
+static ENGINE *dovecot_openssl_engine;
+
+void dovecot_openssl_common_global_ref(void)
+{
+ unsigned char buf;
+
+ if (openssl_init_refcount++ > 0)
+ return;
+
+ SSL_library_init();
+ SSL_load_error_strings();
+ OpenSSL_add_all_algorithms();
+
+ /* PRNG initialization might want to use /dev/urandom, make sure it
+ does it before chrooting. We might not have enough entropy at
+ the first try, so this function may fail. It's still been
+ initialized though. */
+ (void)RAND_bytes(&buf, 1);
+}
+
+bool dovecot_openssl_common_global_unref(void)
+{
+ i_assert(openssl_init_refcount > 0);
+
+ if (--openssl_init_refcount > 0)
+ return TRUE;
+
+ if (dovecot_openssl_engine != NULL) {
+ ENGINE_finish(dovecot_openssl_engine);
+ dovecot_openssl_engine = NULL;
+ }
+#if OPENSSL_VERSION_NUMBER < 0x10001000L
+ OBJ_cleanup();
+#endif
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+ SSL_COMP_free_compression_methods();
+#endif
+ ENGINE_cleanup();
+ EVP_cleanup();
+ CRYPTO_cleanup_all_ex_data();
+ ERR_remove_state(0);
+ ERR_free_strings();
+ return FALSE;
+}
+
+int dovecot_openssl_common_global_set_engine(const char *engine,
+ const char **error_r)
+{
+ if (dovecot_openssl_engine != NULL)
+ return 1;
+
+ ENGINE_load_builtin_engines();
+ dovecot_openssl_engine = ENGINE_by_id(engine);
+ if (dovecot_openssl_engine == NULL) {
+ *error_r = t_strdup_printf("Unknown engine '%s'", engine);
+ return 0;
+ }
+ if (ENGINE_init(dovecot_openssl_engine) == 0) {
+ *error_r = t_strdup_printf("ENGINE_init(%s) failed", engine);
+ ENGINE_free(dovecot_openssl_engine);
+ dovecot_openssl_engine = NULL;
+ return -1;
+ }
+ if (ENGINE_set_default_RSA(dovecot_openssl_engine) == 0)
+ i_unreached();
+ if (ENGINE_set_default_DSA(dovecot_openssl_engine) == 0)
+ i_unreached();
+ if (ENGINE_set_default_ciphers(dovecot_openssl_engine) == 0)
+ i_unreached();
+ return 1;
+}
--- /dev/null
+#ifndef DOVECOT_OPENSSL_COMMON_H
+#define DOVECOT_OPENSSL_COMMON_H
+
+/* Initialize OpenSSL if this is the first instance.
+ Increase initialization reference count. */
+void dovecot_openssl_common_global_ref(void);
+/* Deinitialize OpenSSL if this is the last instance. Returns TRUE if there
+ are more instances left. */
+bool dovecot_openssl_common_global_unref(void);
+
+/* Set OpenSSL engine if it's not already set. Returns 1 on success, 0 if engine
+ is unknown, -1 on other error. error_r is set on 0/-1. */
+int dovecot_openssl_common_global_set_engine(const char *engine,
+ const char **error_r);
+
+#endif
#include "lib.h"
#include "safe-memset.h"
#include "iostream-openssl.h"
+#include "dovecot-openssl-common.h"
#include <openssl/crypto.h>
#include <openssl/x509.h>
-#include <openssl/engine.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
-#include <openssl/rand.h>
#if !defined(OPENSSL_NO_ECDH) && OPENSSL_VERSION_NUMBER >= 0x10000000L
# define HAVE_ECDH
};
static bool ssl_global_initialized = FALSE;
-static ENGINE *ssl_iostream_engine;
int dovecot_ssl_extdata_index;
static int ssl_iostream_init_global(const struct ssl_iostream_settings *set,
void openssl_iostream_global_deinit(void)
{
- if (ssl_iostream_engine != NULL)
- ENGINE_finish(ssl_iostream_engine);
- ENGINE_cleanup();
- EVP_cleanup();
- CRYPTO_cleanup_all_ex_data();
- ERR_remove_state(0);
- ERR_free_strings();
+ dovecot_openssl_common_global_unref();
}
static int ssl_iostream_init_global(const struct ssl_iostream_settings *set,
const char **error_r)
{
static char dovecot[] = "dovecot";
- unsigned char buf;
+ const char *error;
if (ssl_global_initialized)
return 0;
ssl_global_initialized = TRUE;
- SSL_library_init();
- SSL_load_error_strings();
- OpenSSL_add_all_algorithms();
+ dovecot_openssl_common_global_ref();
dovecot_ssl_extdata_index =
SSL_get_ex_new_index(0, dovecot, NULL, NULL, NULL);
- /* PRNG initialization might want to use /dev/urandom, make sure it
- does it before chrooting. We might not have enough entropy at
- the first try, so this function may fail. It's still been
- initialized though. */
- (void)RAND_bytes(&buf, 1);
-
if (set->crypto_device != NULL && *set->crypto_device != '\0') {
- ENGINE_load_builtin_engines();
- ssl_iostream_engine = ENGINE_by_id(set->crypto_device);
- if (ssl_iostream_engine == NULL) {
- *error_r = t_strdup_printf(
+ switch (dovecot_openssl_common_global_set_engine(set->crypto_device, &error)) {
+ case 0:
+ error = t_strdup_printf(
"Unknown ssl_crypto_device: %s",
set->crypto_device);
+ /* fall through */
+ case -1:
+ *error_r = error;
/* we'll deinit at exit in any case */
return -1;
}
- ENGINE_init(ssl_iostream_engine);
- ENGINE_set_default_RSA(ssl_iostream_engine);
- ENGINE_set_default_DSA(ssl_iostream_engine);
- ENGINE_set_default_ciphers(ssl_iostream_engine);
}
return 0;
}