bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen#include "lib.h"
98c2cac72e2032f223050a4edd229993c1d5c1f0Aki Tuomi#include "randgen.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 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
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 }
04b6c66afd1aa12ff9bded2747a543dde39d6f9cTimo Sirainen /* OBJ_cleanup() is called automatically by EVP_cleanup() in
04b6c66afd1aa12ff9bded2747a543dde39d6f9cTimo Sirainen newer versions. Doesn't hurt to call it anyway. */
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen OBJ_cleanup();
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();
e93dc99f2b89533c4bc6af9d0d2852f83f0d5b9aTimo Sirainen#ifdef HAVE_OPENSSL_AUTO_THREAD_DEINIT
e93dc99f2b89533c4bc6af9d0d2852f83f0d5b9aTimo Sirainen /* no cleanup needed */
e93dc99f2b89533c4bc6af9d0d2852f83f0d5b9aTimo Sirainen#elif defined(HAVE_OPENSSL_ERR_REMOVE_THREAD_STATE)
e93dc99f2b89533c4bc6af9d0d2852f83f0d5b9aTimo Sirainen /* This was marked as deprecated in v1.1. */
c281d6630970d51a0e017366be9d86a061303d4bAki Tuomi ERR_remove_thread_state(NULL);
e93dc99f2b89533c4bc6af9d0d2852f83f0d5b9aTimo Sirainen#else
e93dc99f2b89533c4bc6af9d0d2852f83f0d5b9aTimo Sirainen /* This was deprecated by ERR_remove_thread_state(NULL) in v1.0.0. */
e93dc99f2b89533c4bc6af9d0d2852f83f0d5b9aTimo Sirainen ERR_remove_state(0);
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}