]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: ssl: allow to change the OpenSSL security level from global section
authorWilliam Lallemand <wlallemand@haproxy.com>
Tue, 12 Mar 2024 15:22:34 +0000 (16:22 +0100)
committerWilliam Lallemand <wlallemand@haproxy.com>
Tue, 12 Mar 2024 16:37:11 +0000 (17:37 +0100)
The new "ssl-security-level" option allows one to change the OpenSSL
security level without having to change the openssl.cnf global file of
your distribution. This directives applies on every SSL_CTX context.

People sometimes change their security level directly in the ciphers
directive, however there are some cases when the security level change
is not applied in the right order (for example when applying a DH
param).

Before this patch, it was to possible to trick by using a specific
openssl.cnf file and start haproxy this way:

    OPENSSL_CONF=./openssl.cnf ./haproxy -f bug-2468.cfg

Values for the security level can be found there:

https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_security_level.html

This was discussed in github issue #2468.

doc/configuration.txt
include/haproxy/openssl-compat.h
include/haproxy/ssl_sock-t.h
src/cfgparse-ssl.c
src/quic_ssl.c
src/ssl_gencert.c
src/ssl_sock.c

index e01e21960e16c563b1033ef7777f3644de26138e..6f78d77238ea44ba716248cbd05334744e3e4980 100644 (file)
@@ -1311,6 +1311,7 @@ The following keywords are supported in the "global" section :
    - ssl-propquery
    - ssl-provider
    - ssl-provider-path
+   - ssl-security-level
    - ssl-server-verify
    - ssl-skip-self-issued-ca
    - stats
@@ -2588,6 +2589,17 @@ ssl-load-extra-files <none|all|bundle|sctl|ocsp|issuer|key>*
   See also: "crt", section 5.1 about bind options and section 5.2 about server
   options.
 
+ssl-security-level <number>
+  This directive allows to chose the OpenSSL security level as described in
+  https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_security_level.html
+  The security level will be applied to every SSL contextes in HAProxy.
+  Only a value between 0 and 5 is supported.
+
+  The default value depends on your OpenSSL version, distribution and how was
+  compiled the library.
+
+  This directive requires at least OpenSSL 1.1.1.
+
 ssl-server-verify [none|required]
   The default behavior for SSL verify on servers side. If specified to 'none',
   servers certificates are not verified. The default is 'required' except if
index 48160e832621395a458e4529b3239739ce40f023..7cd21a8fd36c50fa0d5400ee9888334800399e4b 100644 (file)
 #define HAVE_SSL_0RTT_QUIC
 #endif
 
+
+#if defined(SSL_CTX_set_security_level) || HA_OPENSSL_VERSION_NUMBER >= 0x1010100fL
+#define HAVE_SSL_SET_SECURITY_LEVEL
+#endif
+
+#if !defined(HAVE_SSL_SET_SECURITY_LEVEL)
+/* define a nope function for set_security_level */
+#define SSL_CTX_set_security_level(ctx, level) ({})
+#endif
+
 #if (HA_OPENSSL_VERSION_NUMBER >= 0x3000000fL)
 #define HAVE_OSSL_PARAM
 #define MAC_CTX EVP_MAC_CTX
@@ -309,6 +319,11 @@ static inline int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
 
 #endif
 
+
+#if (HA_OPENSSL_VERSION_NUMBER < 0x10101000L)
+#endif
+
+
 #if (HA_OPENSSL_VERSION_NUMBER < 0x3000000fL)
 #if defined(SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB)
 #define SSL_CTX_set_tlsext_ticket_key_evp_cb SSL_CTX_set_tlsext_ticket_key_cb
index fdf41a7a96c8df0b7848c69f5f688558150dcade..2d8f8157e1b802d6291ab881999d156bd8dd5124 100644 (file)
@@ -303,6 +303,7 @@ struct global_ssl {
        int keylog; /* activate keylog  */
        int extra_files; /* which files not defined in the configuration file are we looking for */
        int extra_files_noext; /* whether we remove the extension when looking up a extra file */
+       int security_level;    /* configure the openssl security level */
 
 #ifndef OPENSSL_NO_OCSP
        struct {
index 3f728258dd141fa4561b7a1881abf05b51a9a5ef..23b515d23e5533c15568378044c0c73ee26c0c4f 100644 (file)
@@ -2120,6 +2120,39 @@ static int ssl_parse_global_ca_crt_base(char **args, int section_type, struct pr
        return 0;
 }
 
+/* parse the "ssl-security-level" keyword in global section.  */
+static int ssl_parse_security_level(char **args, int section_type, struct proxy *curpx,
+                                        const struct proxy *defpx, const char *file, int linenum,
+                                        char **err)
+{
+#ifndef HAVE_SSL_SET_SECURITY_LEVEL
+       memprintf(err, "global statement '%s' requires at least OpenSSL 1.1.1.", args[0]);
+       return -1;
+#else
+       char *endptr;
+
+       if (!*args[1]) {
+               ha_alert("parsing [%s:%d] : '%s' : missing value\n", file, linenum, args[0]);
+               return -1;
+       }
+
+       global_ssl.security_level = strtol(args[1], &endptr, 10);
+       if (*endptr != '\0') {
+               ha_alert("parsing [%s:%d] : '%s' : expects an integer argument, found '%s'\n",
+                        file, linenum, args[0], args[1]);
+               return -1;
+       }
+
+       if (global_ssl.security_level < 0 || global_ssl.security_level > 5) {
+               ha_alert("parsing [%s:%d] : '%s' : expects a value between 0 and 5\n",
+                        file, linenum, args[0]);
+               return -1;
+       }
+#endif
+
+       return 0;
+}
+
 /* parse the "ssl-skip-self-issued-ca" keyword in global section.  */
 static int ssl_parse_skip_self_issued_ca(char **args, int section_type, struct proxy *curpx,
                                         const struct proxy *defpx, const char *file, int line,
@@ -2343,6 +2376,7 @@ static struct cfg_kw_list cfg_kws = {ILH, {
        { CFG_GLOBAL, "ssl-provider",  ssl_parse_global_ssl_provider },
        { CFG_GLOBAL, "ssl-provider-path",  ssl_parse_global_ssl_provider_path },
 #endif
+       { CFG_GLOBAL, "ssl-security-level", ssl_parse_security_level },
        { CFG_GLOBAL, "ssl-skip-self-issued-ca", ssl_parse_skip_self_issued_ca },
        { CFG_GLOBAL, "tune.ssl.cachesize", ssl_parse_global_int },
 #ifndef OPENSSL_NO_DH
index d7f112d992d62f50621716b3467c7a63d8601180..51a96c2a315fbd0f694076350e03d659064ceb2a 100644 (file)
@@ -441,6 +441,8 @@ int ssl_quic_initial_ctx(struct bind_conf *bind_conf)
        ctx = SSL_CTX_new(TLS_server_method());
        bind_conf->initial_ctx = ctx;
 
+       if (global_ssl.security_level > -1)
+               SSL_CTX_set_security_level(ctx, global_ssl.security_level);
        SSL_CTX_set_options(ctx, options);
        SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
        SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION);
index 95195d1338939f78d10d78b539832a55a173530f..44dc82c742868851dc5365e6ce40004e4314317f 100644 (file)
@@ -201,6 +201,10 @@ static SSL_CTX *ssl_sock_do_create_cert(const char *servername, struct bind_conf
        /* Create and set the new SSL_CTX */
        if (!(ssl_ctx = SSL_CTX_new(SSLv23_server_method())))
                goto mkcert_error;
+
+       if (global_ssl.security_level > -1)
+               SSL_CTX_set_security_level(ssl_ctx, global_ssl.security_level);
+
        if (!SSL_CTX_use_PrivateKey(ssl_ctx, pkey))
                goto mkcert_error;
        if (!SSL_CTX_use_certificate(ssl_ctx, newcrt))
index bd2031c73871da5fde85329dd84938fc5a59b977..85998ae4ee87b7509d66ad2f97f934d4ee1dcf36 100644 (file)
@@ -136,6 +136,7 @@ struct global_ssl global_ssl = {
 #ifdef HAVE_SSL_KEYLOG
        .keylog = 0,
 #endif
+       .security_level = -1,
 #ifndef OPENSSL_NO_OCSP
        .ocsp_update.delay_max = SSL_OCSP_UPDATE_DELAY_MAX,
        .ocsp_update.delay_min = SSL_OCSP_UPDATE_DELAY_MIN,
@@ -3458,6 +3459,9 @@ int ckch_inst_new_load_store(const char *path, struct ckch_store *ckchs, struct
                goto error;
        }
 
+       if (global_ssl.security_level > -1)
+               SSL_CTX_set_security_level(ctx, global_ssl.security_level);
+
        errcode |= ssl_sock_put_ckch_into_ctx(path, data, ctx, err);
        if (errcode & ERR_CODE)
                goto error;
@@ -3612,6 +3616,9 @@ int ckch_inst_new_load_srv_store(const char *path, struct ckch_store *ckchs,
                goto error;
        }
 
+       if (global_ssl.security_level > -1)
+               SSL_CTX_set_security_level(ctx, global_ssl.security_level);
+
        errcode |= ssl_sock_put_srv_ckch_into_ctx(path, data, ctx, err);
        if (errcode & ERR_CODE)
                goto error;
@@ -3959,6 +3966,9 @@ ssl_sock_initial_ctx(struct bind_conf *bind_conf)
        ctx = SSL_CTX_new(SSLv23_server_method());
        bind_conf->initial_ctx = ctx;
 
+       if (global_ssl.security_level > -1)
+               SSL_CTX_set_security_level(ctx, global_ssl.security_level);
+
        if (conf_ssl_methods->flags && (conf_ssl_methods->min || conf_ssl_methods->max))
                ha_warning("Proxy '%s': no-sslv3/no-tlsv1x are ignored for bind '%s' at [%s:%d]. "
                           "Use only 'ssl-min-ver' and 'ssl-max-ver' to fix.\n",
@@ -4955,6 +4965,8 @@ int ssl_sock_prepare_srv_ctx(struct server *srv)
                        cfgerr++;
                        return cfgerr;
                }
+               if (global_ssl.security_level > -1)
+                       SSL_CTX_set_security_level(ctx, global_ssl.security_level);
 
                srv->ssl_ctx.ctx = ctx;
        }