]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-dcrypt, lib-ssl-iostream: Share OpenSSL init/deinit code.
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Mon, 20 Jun 2016 09:58:08 +0000 (12:58 +0300)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Mon, 20 Jun 2016 17:50:21 +0000 (20:50 +0300)
src/Makefile.am
src/lib-dcrypt/Makefile.am
src/lib-dcrypt/dcrypt-openssl.c
src/lib-ssl-iostream/Makefile.am
src/lib-ssl-iostream/dovecot-openssl-common.c [new file with mode: 0644]
src/lib-ssl-iostream/dovecot-openssl-common.h [new file with mode: 0644]
src/lib-ssl-iostream/iostream-openssl-context.c

index 086b7c8fb5bb927921d69dd753452146c66aaaf4..dd76173d8a46afafb179b3e63151efc675c8d340 100644 (file)
@@ -9,11 +9,11 @@ LIBDOVECOT_SUBDIRS = \
        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 \
index c7618f0dc5c033d97faff6709bd9ca7a8099be66..af25c10b53a75ab0377073e28defbd9eff571f30 100644 (file)
@@ -3,7 +3,8 @@ pkglib_LTLIBRARIES =
 
 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 \
@@ -16,7 +17,8 @@ libdcrypt_la_CFLAGS = $(AM_CPPFLAGS) \
 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)
index af230ee0282da72a4658d4b848959ae5b0749796..e7cfbb5374de1890f1a6b920f30f4eea27731f59 100644 (file)
@@ -6,6 +6,7 @@
 #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>
@@ -2059,14 +2060,11 @@ static struct dcrypt_vfs dcrypt_openssl_vfs = {
 
 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();
 }
index 7b4ff2c309777912b6a36438d26ee51c527a5250..769de87b283147cf81b688bf2fd7ae61bd1b48bf 100644 (file)
@@ -10,8 +10,13 @@ AM_CPPFLAGS = \
 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 \
@@ -25,6 +30,9 @@ libssl_iostream_la_SOURCES = \
        iostream-ssl.c \
        $(ssl_sources)
 
+noinst_HEADERS = \
+       dovecot-openssl-common.h
+
 headers = \
        iostream-openssl.h \
        iostream-ssl.h \
diff --git a/src/lib-ssl-iostream/dovecot-openssl-common.c b/src/lib-ssl-iostream/dovecot-openssl-common.c
new file mode 100644 (file)
index 0000000..7e622fb
--- /dev/null
@@ -0,0 +1,81 @@
+/* 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;
+}
diff --git a/src/lib-ssl-iostream/dovecot-openssl-common.h b/src/lib-ssl-iostream/dovecot-openssl-common.h
new file mode 100644 (file)
index 0000000..31854d3
--- /dev/null
@@ -0,0 +1,16 @@
+#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
index b976a0c03cdfa08070028729dfe16f2987dbf535..2b6199df91dd727b1d3e73e25bf8599a13046785 100644 (file)
@@ -3,14 +3,13 @@
 #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
@@ -22,7 +21,6 @@ struct ssl_iostream_password_context {
 };
 
 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,
@@ -542,52 +540,36 @@ void openssl_iostream_context_deinit(struct ssl_iostream_context *ctx)
 
 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;
 }