dovecot-openssl-common.c revision b91659702c83b8f144e369ad5fa82724242c210c
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2016-2017 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
803d5e00922fd90af4bb5d529eed7af37ea8174aTimo Sirainen#ifdef HAVE_SSL_NEW_MEM_FUNCS
c281d6630970d51a0e017366be9d86a061303d4bAki Tuomistatic void *dovecot_openssl_malloc(size_t size, const char *u0 ATTR_UNUSED, int u1 ATTR_UNUSED)
c281d6630970d51a0e017366be9d86a061303d4bAki Tuomi#else
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainenstatic void *dovecot_openssl_malloc(size_t size)
c281d6630970d51a0e017366be9d86a061303d4bAki Tuomi#endif
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
803d5e00922fd90af4bb5d529eed7af37ea8174aTimo Sirainen#ifdef HAVE_SSL_NEW_MEM_FUNCS
c281d6630970d51a0e017366be9d86a061303d4bAki Tuomistatic void *dovecot_openssl_realloc(void *ptr, size_t size, const char *u0 ATTR_UNUSED, int u1 ATTR_UNUSED)
c281d6630970d51a0e017366be9d86a061303d4bAki Tuomi#else
864e580b625a632c0e5a7b0591ffd0e707f276f4Timo Sirainenstatic void *dovecot_openssl_realloc(void *ptr, size_t size)
c281d6630970d51a0e017366be9d86a061303d4bAki Tuomi#endif
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
803d5e00922fd90af4bb5d529eed7af37ea8174aTimo Sirainen#ifdef HAVE_SSL_NEW_MEM_FUNCS
c281d6630970d51a0e017366be9d86a061303d4bAki Tuomistatic void dovecot_openssl_free(void *ptr, const char *u0 ATTR_UNUSED, int u1 ATTR_UNUSED)
c281d6630970d51a0e017366be9d86a061303d4bAki Tuomi#else
c281d6630970d51a0e017366be9d86a061303d4bAki Tuomistatic void dovecot_openssl_free(void *ptr)
c281d6630970d51a0e017366be9d86a061303d4bAki Tuomi#endif
c281d6630970d51a0e017366be9d86a061303d4bAki Tuomi{
c281d6630970d51a0e017366be9d86a061303d4bAki Tuomi free(ptr);
c281d6630970d51a0e017366be9d86a061303d4bAki Tuomi}
c281d6630970d51a0e017366be9d86a061303d4bAki Tuomi
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,
c281d6630970d51a0e017366be9d86a061303d4bAki Tuomi dovecot_openssl_realloc, dovecot_openssl_free) == 0) {
20b857d3114dd228a7066193c88c45519c252343Timo Sirainen /*i_warning("CRYPTO_set_mem_functions() was called too late");*/
20b857d3114dd228a7066193c88c45519c252343Timo Sirainen }
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();
c281d6630970d51a0e017366be9d86a061303d4bAki Tuomi#if OPENSSL_VERSION_NUMBER < 0x10000000L
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen ERR_remove_state(0);
c281d6630970d51a0e017366be9d86a061303d4bAki Tuomi#elif OPENSSL_VERSION_NUMBER < 0x10100000L
c281d6630970d51a0e017366be9d86a061303d4bAki Tuomi ERR_remove_thread_state(NULL);
c281d6630970d51a0e017366be9d86a061303d4bAki Tuomi#endif
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen ERR_free_strings();
b91659702c83b8f144e369ad5fa82724242c210cTimo Sirainen#ifdef HAVE_OPENSSL_CLEANUP
b4884ca2e67bb794786419d9e7b6140842b03bccApollon Oikonomopoulos OPENSSL_cleanup();
b4884ca2e67bb794786419d9e7b6140842b03bccApollon Oikonomopoulos#endif
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}