dovecot-openssl-common.c revision f3904862b2f1f869ffad80ad556f2019b9b2121a
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen/* Copyright (c) 2016 Dovecot authors, see the included COPYING file */
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen#include "lib.h"
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen#include "dovecot-openssl-common.h"
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen#include <openssl/ssl.h>
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen#include <openssl/engine.h>
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen#include <openssl/rand.h>
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainenstatic int openssl_init_refcount = 0;
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainenstatic ENGINE *dovecot_openssl_engine;
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainenstatic void *dovecot_openssl_malloc(size_t size)
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen{
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen /* this may be performance critical, so don't use
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen i_malloc() or calloc() */
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen void *mem = malloc(size);
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen if (mem == NULL) {
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen i_fatal_status(FATAL_OUTOFMEM,
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen "OpenSSL: malloc(%"PRIuSIZE_T"): Out of memory", size);
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen }
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen return mem;
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen}
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainenstatic void *dovecot_openssl_realloc(void *ptr, size_t size)
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen{
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen void *mem = realloc(ptr, size);
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen if (mem == NULL) {
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen i_fatal_status(FATAL_OUTOFMEM,
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen "OpenSSL: realloc(%"PRIuSIZE_T"): Out of memory", size);
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen }
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen return mem;
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen}
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainenvoid dovecot_openssl_common_global_ref(void)
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen{
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen unsigned char buf;
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen if (openssl_init_refcount++ > 0)
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen return;
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen /* use our own memory allocation functions that will die instead of
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen returning NULL. this avoids random failures on out-of-memory
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen conditions. */
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen if (CRYPTO_set_mem_functions(dovecot_openssl_malloc,
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen dovecot_openssl_realloc, free) == 0)
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen i_warning("CRYPTO_set_mem_functions() was called too late");
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainen
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen SSL_library_init();
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen SSL_load_error_strings();
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen OpenSSL_add_all_algorithms();
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen /* PRNG initialization might want to use /dev/urandom, make sure it
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen does it before chrooting. We might not have enough entropy at
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen the first try, so this function may fail. It's still been
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen initialized though. */
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen (void)RAND_bytes(&buf, 1);
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen}
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainenbool dovecot_openssl_common_global_unref(void)
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen{
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen i_assert(openssl_init_refcount > 0);
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen if (--openssl_init_refcount > 0)
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen return TRUE;
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen if (dovecot_openssl_engine != NULL) {
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen ENGINE_finish(dovecot_openssl_engine);
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen dovecot_openssl_engine = NULL;
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen }
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen#if OPENSSL_VERSION_NUMBER < 0x10001000L
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen OBJ_cleanup();
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen#endif
f3904862b2f1f869ffad80ad556f2019b9b2121aTimo Sirainen#ifdef HAVE_SSL_COMP_FREE_COMPRESSION_METHODS
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen SSL_COMP_free_compression_methods();
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen#endif
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen ENGINE_cleanup();
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen EVP_cleanup();
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen CRYPTO_cleanup_all_ex_data();
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen ERR_remove_state(0);
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen ERR_free_strings();
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen return FALSE;
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen}
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainenint dovecot_openssl_common_global_set_engine(const char *engine,
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen const char **error_r)
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen{
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen if (dovecot_openssl_engine != NULL)
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen return 1;
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen ENGINE_load_builtin_engines();
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen dovecot_openssl_engine = ENGINE_by_id(engine);
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen if (dovecot_openssl_engine == NULL) {
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen *error_r = t_strdup_printf("Unknown engine '%s'", engine);
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen return 0;
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen }
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen if (ENGINE_init(dovecot_openssl_engine) == 0) {
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen *error_r = t_strdup_printf("ENGINE_init(%s) failed", engine);
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen ENGINE_free(dovecot_openssl_engine);
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen dovecot_openssl_engine = NULL;
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen return -1;
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen }
123d1cb83e666b485df755467df64edc456d56dbTimo Sirainen if (ENGINE_set_default(dovecot_openssl_engine, ENGINE_METHOD_ALL) == 0) {
123d1cb83e666b485df755467df64edc456d56dbTimo Sirainen *error_r = t_strdup_printf("ENGINE_set_default(%s) failed", engine);
123d1cb83e666b485df755467df64edc456d56dbTimo Sirainen ENGINE_free(dovecot_openssl_engine);
123d1cb83e666b485df755467df64edc456d56dbTimo Sirainen dovecot_openssl_engine = NULL;
123d1cb83e666b485df755467df64edc456d56dbTimo Sirainen return -1;
123d1cb83e666b485df755467df64edc456d56dbTimo Sirainen }
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen return 1;
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen}