|
|
@@ -16,7 +16,9 @@ |
|
|
|
|
|
|
|
#include "config.h" |
|
|
|
#include "libutil/util.h" |
|
|
|
#include "libutil/hash.h" |
|
|
|
#include "libserver/logger.h" |
|
|
|
#include "libserver/cfg_file.h" |
|
|
|
#include "ssl_util.h" |
|
|
|
#include "unix-std.h" |
|
|
|
#include "cryptobox.h" |
|
|
@@ -44,12 +46,18 @@ enum rspamd_ssl_shutdown { |
|
|
|
ssl_shut_unclean, |
|
|
|
}; |
|
|
|
|
|
|
|
struct rspamd_ssl_ctx { |
|
|
|
SSL_CTX *s; |
|
|
|
rspamd_lru_hash_t *sessions; |
|
|
|
}; |
|
|
|
|
|
|
|
struct rspamd_ssl_connection { |
|
|
|
gint fd; |
|
|
|
enum rspamd_ssl_state state; |
|
|
|
enum rspamd_ssl_shutdown shut; |
|
|
|
gboolean verify_peer; |
|
|
|
SSL *ssl; |
|
|
|
struct rspamd_ssl_ctx *ssl_ctx; |
|
|
|
gchar *hostname; |
|
|
|
struct rspamd_io_ev *ev; |
|
|
|
struct rspamd_io_ev *shut_ev; |
|
|
@@ -419,6 +427,8 @@ rspamd_tls_set_error (gint retcode, const gchar *stage, GError **err) |
|
|
|
static void |
|
|
|
rspamd_ssl_connection_dtor (struct rspamd_ssl_connection *conn) |
|
|
|
{ |
|
|
|
msg_debug_ssl ("closing SSL connection %p; %d sessions in the cache", |
|
|
|
conn->ssl, rspamd_lru_hash_size (conn->ssl_ctx->sessions)); |
|
|
|
SSL_free (conn->ssl); |
|
|
|
|
|
|
|
if (conn->hostname) { |
|
|
@@ -618,23 +628,24 @@ struct rspamd_ssl_connection * |
|
|
|
rspamd_ssl_connection_new (gpointer ssl_ctx, struct ev_loop *ev_base, |
|
|
|
gboolean verify_peer, const gchar *log_tag) |
|
|
|
{ |
|
|
|
struct rspamd_ssl_connection *c; |
|
|
|
struct rspamd_ssl_connection *conn; |
|
|
|
struct rspamd_ssl_ctx *ctx = (struct rspamd_ssl_ctx *)ssl_ctx; |
|
|
|
|
|
|
|
g_assert (ssl_ctx != NULL); |
|
|
|
c = g_malloc0 (sizeof (*c)); |
|
|
|
c->ssl = SSL_new (ssl_ctx); |
|
|
|
c->event_loop = ev_base; |
|
|
|
c->verify_peer = verify_peer; |
|
|
|
conn = g_malloc0 (sizeof (*conn)); |
|
|
|
conn->ssl_ctx = ctx; |
|
|
|
conn->event_loop = ev_base; |
|
|
|
conn->verify_peer = verify_peer; |
|
|
|
|
|
|
|
if (log_tag) { |
|
|
|
rspamd_strlcpy (c->log_tag, log_tag, sizeof (log_tag)); |
|
|
|
rspamd_strlcpy (conn->log_tag, log_tag, sizeof (log_tag)); |
|
|
|
} |
|
|
|
else { |
|
|
|
rspamd_random_hex (c->log_tag, sizeof (log_tag) - 1); |
|
|
|
c->log_tag[sizeof (log_tag) - 1] = '\0'; |
|
|
|
rspamd_random_hex (conn->log_tag, sizeof (log_tag) - 1); |
|
|
|
conn->log_tag[sizeof (log_tag) - 1] = '\0'; |
|
|
|
} |
|
|
|
|
|
|
|
return c; |
|
|
|
return conn; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@@ -648,6 +659,11 @@ rspamd_ssl_connect_fd (struct rspamd_ssl_connection *conn, gint fd, |
|
|
|
|
|
|
|
g_assert (conn != NULL); |
|
|
|
|
|
|
|
conn->ssl = SSL_new (conn->ssl_ctx->s); |
|
|
|
SSL_set_app_data (conn->ssl, conn); |
|
|
|
msg_debug_ssl ("new ssl connection %p; session reused=%s", |
|
|
|
conn->ssl, SSL_session_reused (conn->ssl) ? "true" : "false"); |
|
|
|
|
|
|
|
if (conn->state != ssl_conn_reset) { |
|
|
|
return FALSE; |
|
|
|
} |
|
|
@@ -927,18 +943,32 @@ rspamd_ssl_connection_free (struct rspamd_ssl_connection *conn) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
gpointer |
|
|
|
rspamd_init_ssl_ctx (void) |
|
|
|
static int |
|
|
|
rspamd_ssl_new_client_session (SSL *ssl, SSL_SESSION *sess) |
|
|
|
{ |
|
|
|
struct rspamd_ssl_ctx *ctx; |
|
|
|
struct rspamd_ssl_connection *conn; |
|
|
|
|
|
|
|
conn = SSL_get_app_data (ssl); |
|
|
|
|
|
|
|
msg_debug_ssl ("hui: got new session from %p", conn); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static struct rspamd_ssl_ctx * |
|
|
|
rspamd_init_ssl_ctx_common (void) |
|
|
|
{ |
|
|
|
struct rspamd_ssl_ctx *ret; |
|
|
|
SSL_CTX *ssl_ctx; |
|
|
|
gint ssl_options; |
|
|
|
static const guint client_cache_size = 1024; |
|
|
|
|
|
|
|
rspamd_openssl_maybe_init (); |
|
|
|
|
|
|
|
ssl_ctx = SSL_CTX_new (SSLv23_method ()); |
|
|
|
SSL_CTX_set_verify (ssl_ctx, SSL_VERIFY_PEER, NULL); |
|
|
|
SSL_CTX_set_verify_depth (ssl_ctx, 4); |
|
|
|
ret = g_malloc0 (sizeof (*ret)); |
|
|
|
ssl_options = SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3; |
|
|
|
ssl_ctx = SSL_CTX_new (SSLv23_method ()); |
|
|
|
|
|
|
|
#ifdef SSL_OP_NO_COMPRESSION |
|
|
|
ssl_options |= SSL_OP_NO_COMPRESSION; |
|
|
@@ -948,30 +978,42 @@ rspamd_init_ssl_ctx (void) |
|
|
|
|
|
|
|
SSL_CTX_set_options (ssl_ctx, ssl_options); |
|
|
|
|
|
|
|
return ssl_ctx; |
|
|
|
#ifdef TLS1_3_VERSION |
|
|
|
SSL_CTX_set_min_proto_version (ssl_ctx, 0); |
|
|
|
SSL_CTX_set_max_proto_version (ssl_ctx, TLS1_3_VERSION); |
|
|
|
#endif |
|
|
|
|
|
|
|
#ifdef SSL_SESS_CACHE_CLIENT |
|
|
|
SSL_CTX_set_session_cache_mode (ssl_ctx, SSL_SESS_CACHE_CLIENT |
|
|
|
| SSL_SESS_CACHE_NO_INTERNAL_STORE); |
|
|
|
#endif |
|
|
|
|
|
|
|
ret->s = ssl_ctx; |
|
|
|
ret->sessions = rspamd_lru_hash_new_full (client_cache_size, |
|
|
|
g_free, (GDestroyNotify)SSL_SESSION_free, rspamd_str_hash, |
|
|
|
rspamd_str_equal); |
|
|
|
SSL_CTX_set_app_data (ssl_ctx, ret); |
|
|
|
SSL_CTX_sess_set_new_cb (ssl_ctx, rspamd_ssl_new_client_session); |
|
|
|
|
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
gpointer rspamd_init_ssl_ctx_noverify (void) |
|
|
|
gpointer |
|
|
|
rspamd_init_ssl_ctx (void) |
|
|
|
{ |
|
|
|
SSL_CTX *ssl_ctx_noverify; |
|
|
|
gint ssl_options; |
|
|
|
struct rspamd_ssl_ctx *ssl_ctx = rspamd_init_ssl_ctx_common (); |
|
|
|
|
|
|
|
rspamd_openssl_maybe_init (); |
|
|
|
SSL_CTX_set_verify (ssl_ctx->s, SSL_VERIFY_PEER, NULL); |
|
|
|
SSL_CTX_set_verify_depth (ssl_ctx->s, 4); |
|
|
|
|
|
|
|
ssl_options = SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3; |
|
|
|
return ssl_ctx; |
|
|
|
} |
|
|
|
|
|
|
|
#ifdef SSL_OP_NO_COMPRESSION |
|
|
|
ssl_options |= SSL_OP_NO_COMPRESSION; |
|
|
|
#elif OPENSSL_VERSION_NUMBER >= 0x00908000L |
|
|
|
sk_SSL_COMP_zero (SSL_COMP_get_compression_methods ()); |
|
|
|
#endif |
|
|
|
gpointer rspamd_init_ssl_ctx_noverify (void) |
|
|
|
{ |
|
|
|
struct rspamd_ssl_ctx *ssl_ctx_noverify = rspamd_init_ssl_ctx_common (); |
|
|
|
|
|
|
|
ssl_ctx_noverify = SSL_CTX_new (SSLv23_method ()); |
|
|
|
SSL_CTX_set_verify (ssl_ctx_noverify, SSL_VERIFY_NONE, NULL); |
|
|
|
SSL_CTX_set_options (ssl_ctx_noverify, ssl_options); |
|
|
|
#ifdef SSL_SESS_CACHE_BOTH |
|
|
|
SSL_CTX_set_session_cache_mode (ssl_ctx_noverify, SSL_SESS_CACHE_BOTH); |
|
|
|
#endif |
|
|
|
SSL_CTX_set_verify (ssl_ctx_noverify->s, SSL_VERIFY_NONE, NULL); |
|
|
|
|
|
|
|
return ssl_ctx_noverify; |
|
|
|
} |
|
|
@@ -1012,4 +1054,45 @@ rspamd_openssl_maybe_init (void) |
|
|
|
|
|
|
|
openssl_initialized = TRUE; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void |
|
|
|
rspamd_ssl_ctx_config (struct rspamd_config *cfg, gpointer ssl_ctx) |
|
|
|
{ |
|
|
|
struct rspamd_ssl_ctx *ctx = (struct rspamd_ssl_ctx *)ssl_ctx; |
|
|
|
static const char default_secure_ciphers[] = "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4"; |
|
|
|
|
|
|
|
if (cfg->ssl_ca_path) { |
|
|
|
if (SSL_CTX_load_verify_locations (ctx->s, cfg->ssl_ca_path, |
|
|
|
NULL) != 1) { |
|
|
|
msg_err_config ("cannot load CA certs from %s: %s", |
|
|
|
cfg->ssl_ca_path, |
|
|
|
ERR_error_string (ERR_get_error (), NULL)); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
msg_debug_config ("ssl_ca_path is not set, using default CA path"); |
|
|
|
SSL_CTX_set_default_verify_paths (ctx->s); |
|
|
|
} |
|
|
|
|
|
|
|
if (cfg->ssl_ciphers) { |
|
|
|
if (SSL_CTX_set_cipher_list (ctx->s, cfg->ssl_ciphers) != 1) { |
|
|
|
msg_err_config ( |
|
|
|
"cannot set ciphers set to %s: %s; fallback to %s", |
|
|
|
cfg->ssl_ciphers, |
|
|
|
ERR_error_string (ERR_get_error (), NULL), |
|
|
|
default_secure_ciphers); |
|
|
|
/* Default settings */ |
|
|
|
SSL_CTX_set_cipher_list (ctx->s, default_secure_ciphers); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void |
|
|
|
rspamd_ssl_ctx_free (gpointer ssl_ctx) |
|
|
|
{ |
|
|
|
struct rspamd_ssl_ctx *ctx = (struct rspamd_ssl_ctx *)ssl_ctx; |
|
|
|
|
|
|
|
rspamd_lru_hash_destroy (ctx->sessions); |
|
|
|
SSL_CTX_free (ctx->s); |
|
|
|
} |