commit ef68f40: [Rework] Rework SSL caching

Vsevolod Stakhov vsevolod at highsecure.ru
Tue Feb 18 13:21:07 UTC 2020


Author: Vsevolod Stakhov
Date: 2020-02-18 12:49:54 +0000
URL: https://github.com/rspamd/rspamd/commit/ef68f4073a524bd1552d63c365a78888ea6969e0

[Rework] Rework SSL caching

---
 src/libserver/cfg_utils.c |  31 ++--------
 src/libserver/ssl_util.c  | 145 ++++++++++++++++++++++++++++++++++++----------
 src/libserver/ssl_util.h  |   2 +
 3 files changed, 120 insertions(+), 58 deletions(-)

diff --git a/src/libserver/cfg_utils.c b/src/libserver/cfg_utils.c
index b74759229..bcebb9f93 100644
--- a/src/libserver/cfg_utils.c
+++ b/src/libserver/cfg_utils.c
@@ -2755,7 +2755,6 @@ gboolean
 rspamd_config_libs (struct rspamd_external_libs_ctx *ctx,
 					struct rspamd_config *cfg)
 {
-	static const char secure_ciphers[] = "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4";
 	size_t r;
 	gboolean ret = TRUE;
 
@@ -2830,30 +2829,8 @@ rspamd_config_libs (struct rspamd_external_libs_ctx *ctx,
 #endif
 		}
 
-		if (cfg->ssl_ca_path) {
-			if (SSL_CTX_load_verify_locations (ctx->ssl_ctx, 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->ssl_ctx);
-		}
-
-		if (cfg->ssl_ciphers) {
-			if (SSL_CTX_set_cipher_list (ctx->ssl_ctx, 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),
-						secure_ciphers);
-				/* Default settings */
-				SSL_CTX_set_cipher_list (ctx->ssl_ctx, secure_ciphers);
-			}
-		}
+		rspamd_ssl_ctx_config (cfg, ctx->ssl_ctx);
+		rspamd_ssl_ctx_config (cfg, ctx->ssl_ctx_noverify);
 
 		/* Init decompression */
 		ctx->in_zstream = ZSTD_createDStream ();
@@ -2942,8 +2919,8 @@ rspamd_deinit_libs (struct rspamd_external_libs_ctx *ctx)
 #ifdef HAVE_OPENSSL
 		EVP_cleanup ();
 		ERR_free_strings ();
-		SSL_CTX_free (ctx->ssl_ctx);
-		SSL_CTX_free (ctx->ssl_ctx_noverify);
+		rspamd_ssl_ctx_free (ctx->ssl_ctx);
+		rspamd_ssl_ctx_free (ctx->ssl_ctx_noverify);
 #endif
 		rspamd_inet_library_destroy ();
 		rspamd_free_zstd_dictionary (ctx->in_dict);
diff --git a/src/libserver/ssl_util.c b/src/libserver/ssl_util.c
index a094eaf45..5a1abdeef 100644
--- a/src/libserver/ssl_util.c
+++ b/src/libserver/ssl_util.c
@@ -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);
 }
\ No newline at end of file
diff --git a/src/libserver/ssl_util.h b/src/libserver/ssl_util.h
index 9118c3e8c..f3593387f 100644
--- a/src/libserver/ssl_util.h
+++ b/src/libserver/ssl_util.h
@@ -96,6 +96,8 @@ void rspamd_ssl_connection_free (struct rspamd_ssl_connection *conn);
 
 gpointer rspamd_init_ssl_ctx (void);
 gpointer rspamd_init_ssl_ctx_noverify (void);
+void rspamd_ssl_ctx_config (struct rspamd_config *cfg, gpointer ssl_ctx);
+void rspamd_ssl_ctx_free (gpointer ssl_ctx);
 void rspamd_openssl_maybe_init (void);
 
 #ifdef  __cplusplus


More information about the Commits mailing list