ssl-proxy-openssl.c revision efe78d3ba24fc866af1c79b9223dc0809ba26cad
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2002-2016 Dovecot authors, see the included COPYING file */
9fd2181788a61500641c66aec0f8c746b19bf830Timo Sirainen#if !defined(OPENSSL_NO_ECDH) && OPENSSL_VERSION_NUMBER >= 0x10000000L
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen#ifndef SSL_CTRL_SET_TLSEXT_HOSTNAME /* FIXME: this may be unnecessary.. */
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen const struct master_service_ssl_settings *ssl_set;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen struct io *io_ssl_read, *io_ssl_write, *io_plain_read, *io_plain_write;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen const char *key;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen const char *ca;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen const char *dh;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenstatic unsigned int ssl_proxy_count;
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainenstatic void plain_read(struct ssl_proxy *proxy);
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainenstatic void ssl_write(struct ssl_proxy *proxy);
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainenstatic void ssl_proxy_unref(struct ssl_proxy *proxy);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenssl_server_context_init(const struct login_settings *login_set,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen const struct master_service_ssl_settings *ssl_set);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic void ssl_server_context_deinit(struct ssl_server_context **_ctx);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic void ssl_proxy_ctx_set_crypto_params(SSL_CTX *ssl_ctx,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen const struct master_service_ssl_settings *set);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen#if defined(HAVE_ECDH) && !defined(SSL_CTRL_SET_ECDH_AUTO)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenstatic int ssl_proxy_ctx_get_pkey_ec_curve_name(const struct master_service_ssl_settings *set);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenstatic void ssl_proxy_destroy_failed(struct ssl_proxy *proxy)
a26b7e87b4157cfa800f9bcd8c4c044462d21268Timo Sirainenstatic unsigned int ssl_server_context_hash(const struct ssl_server_context *ctx)
a26b7e87b4157cfa800f9bcd8c4c044462d21268Timo Sirainen unsigned int i, g, h = 0;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen /* checking for different certs is typically good enough,
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen and it should be enough to check only the first few bytes. */
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen for (i = 0; i < 16 && ctx->cert[i] != '\0'; i++) {
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen if ((g = h & 0xf0000000UL) != 0) {
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen h = h ^ (g >> 24);
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainenstatic int ssl_server_context_cmp(const struct ssl_server_context *ctx1,
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen if (null_strcmp(ctx1->cipher_list, ctx2->cipher_list) != 0)
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen if (null_strcmp(ctx1->protocols, ctx2->protocols) != 0)
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen return ctx1->verify_client_cert == ctx2->verify_client_cert ? 0 : 1;
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainenstatic void ssl_free_parameters(struct ssl_parameters *params)
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainenstatic void ssl_set_io(struct ssl_proxy *proxy, enum ssl_io_action action)
013a8a91c83c6ea24bc75322b81235f19e26fa8fTimo Sirainen proxy->io_ssl_read = io_add(proxy->fd_ssl, IO_READ,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen proxy->io_ssl_write = io_add(proxy->fd_ssl, IO_WRITE,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic void plain_block_input(struct ssl_proxy *proxy, bool block)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen proxy->io_plain_read = io_add(proxy->fd_plain, IO_READ,
f9142439f2b5e86065af7420e80fe52835227dc8Timo Sirainenstatic void plain_read(struct ssl_proxy *proxy)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (proxy->sslout_size == sizeof(proxy->sslout_buf)) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* buffer full, block input until it's written */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen while (proxy->sslout_size < sizeof(proxy->sslout_buf) &&
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainenstatic void plain_write(struct ssl_proxy *proxy)
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen ret = net_transmit(proxy->fd_plain, proxy->plainout_buf,
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen memmove(proxy->plainout_buf, proxy->plainout_buf + ret,
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainenstatic void ssl_handle_error(struct ssl_proxy *proxy, int ret,
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen /* eat up the error queue */
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen else if (ret != 0)
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen errstr = t_strdup_printf("%s syscall failed: %s",
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen /* clean connection closing */
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen if (ERR_GET_REASON(ERR_peek_error()) == ERR_R_MALLOC_FAILURE) {
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen "You may need to increase service %s { vsz_limit }",
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen errstr = t_strdup_printf("%s failed: unknown failure %d (%s)",
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainenstatic void ssl_handshake(struct ssl_proxy *proxy)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ssl_handle_error(proxy, ret, "SSL_connect()");
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen if (proxy->handshake_callback(proxy->handshake_context) < 0)
d2d5871fa9e7226df694ff7a4be511167b35b305Timo Sirainen while (proxy->plainout_size < sizeof(proxy->plainout_buf) &&
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen ret = SSL_write(proxy->ssl, proxy->sslout_buf, proxy->sslout_size);
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen memmove(proxy->sslout_buf, proxy->sslout_buf + ret,
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen if (proxy->plainout_size == sizeof(proxy->plainout_buf))
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainenssl_proxy_alloc_common(SSL_CTX *ssl_ctx, int fd, const struct ip_addr *ip,
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen pool_t set_pool, const struct login_settings *login_set,
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen const struct master_service_ssl_settings *ssl_set,
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen i_error("SSL support not enabled in configuration");
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen i_error("SSL_new() failed: %s", openssl_iostream_error());
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen i_error("SSL_set_fd() failed: %s", openssl_iostream_error());
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfd) < 0) {
static struct ssl_server_context *
return ctx;
int ret;
if (ret < 0)
return ret;
char *name;
int len;
return NULL;
if (len < 0)
const char *comp_str;
return NULL;
BN_free(e);
return rsa;
case SSL_AD_CLOSE_NOTIFY:
} else if (ret == 0) {
int ctxerr;
if (preverify_ok == 0)
if (preverify_ok != 0) {
void *userdata)
unsigned int ssl_proxy_get_count(void)
return ssl_proxy_count;
bool load_xnames)
#ifdef SSL_OP_NO_COMPRESSION
#ifdef SSL_OP_NO_TICKET
#ifdef SSL_MODE_RELEASE_BUFFERS
return xnames;
int nid;
const char *curve_name;
#ifdef HAVE_ECDH
#ifdef SSL_CTRL_SET_ECDH_AUTO
char *dup_password;
return pkey;
static DH *
return dh;
const char *password;
int nid = 0;
const char *password;
return nid;
X509 *x;
int ret = 0;
if (x == NULL)
goto end;
if (ERR_peek_error() != 0)
ret = 0;
if (ret != 0) {
unsigned long err;
ret = 0;
goto end;
end:
return ret;
#ifdef HAVE_SSL_GET_SERVERNAME
const char *host;
void **other_sets;
&other_sets);
static struct ssl_server_context *
#ifdef HAVE_SSL_GET_SERVERNAME
return ctx;
void ssl_proxy_init(void)
unsigned char buf;
ssl_proxy_count = 0;
void ssl_proxy_deinit(void)
if (!ssl_initialized)
EVP_cleanup();