]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Rework] Rework SSL caching
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Tue, 18 Feb 2020 12:49:54 +0000 (12:49 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Tue, 18 Feb 2020 12:49:54 +0000 (12:49 +0000)
src/libserver/cfg_utils.c
src/libserver/ssl_util.c
src/libserver/ssl_util.h

index b7475922913b119793946a0a82808293dbbff10c..bcebb9f937b15024ae17ec68d67c7776db3d9e29 100644 (file)
@@ -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);
index a094eaf4527e5bf73e165dd5dd7a37de9d232b6d..5a1abdeef6aaeca6dbf1cf4683cfa4157d4e3fa1 100644 (file)
@@ -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
index 9118c3e8cd645027e926387b6cc91a4b70651373..f3593387f55b716c923496dcd12f2210506c1c1c 100644 (file)
@@ -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