diff --git a/doc/configuration.txt b/doc/configuration.txt index e01e21960..6f78d7723 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -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 * See also: "crt", section 5.1 about bind options and section 5.2 about server options. +ssl-security-level + 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 diff --git a/include/haproxy/openssl-compat.h b/include/haproxy/openssl-compat.h index 48160e832..7cd21a8fd 100644 --- a/include/haproxy/openssl-compat.h +++ b/include/haproxy/openssl-compat.h @@ -118,6 +118,16 @@ #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 diff --git a/include/haproxy/ssl_sock-t.h b/include/haproxy/ssl_sock-t.h index fdf41a7a9..2d8f8157e 100644 --- a/include/haproxy/ssl_sock-t.h +++ b/include/haproxy/ssl_sock-t.h @@ -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 { diff --git a/src/cfgparse-ssl.c b/src/cfgparse-ssl.c index 3f728258d..23b515d23 100644 --- a/src/cfgparse-ssl.c +++ b/src/cfgparse-ssl.c @@ -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 diff --git a/src/quic_ssl.c b/src/quic_ssl.c index d7f112d99..51a96c2a3 100644 --- a/src/quic_ssl.c +++ b/src/quic_ssl.c @@ -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); diff --git a/src/ssl_gencert.c b/src/ssl_gencert.c index 95195d133..44dc82c74 100644 --- a/src/ssl_gencert.c +++ b/src/ssl_gencert.c @@ -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)) diff --git a/src/ssl_sock.c b/src/ssl_sock.c index bd2031c73..85998ae4e 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -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; }