MINOR: ssl: Add 'ssl-provider' global option

When HAProxy is linked to an OpenSSLv3 library, this option can be used
to load a provider during init. You can specify multiple ssl-provider
options, which will be loaded in the order they appear. This does not
prevent OpenSSL from parsing its own configuration file in which some
other providers might be specified.
A linked list of the providers loaded from the configuration file is
kept so that all those providers can be unloaded during cleanup. The
providers loaded directly by OpenSSL will be freed by OpenSSL.
This commit is contained in:
Remi Tricot-Le Breton 2022-05-16 16:24:33 +02:00 committed by William Lallemand
parent e80976526c
commit 1746a388c5
4 changed files with 97 additions and 0 deletions

View File

@ -1051,6 +1051,7 @@ The following keywords are supported in the "global" section :
- ssl-default-server-options
- ssl-dh-param-file
- ssl-propquery
- ssl-provider
- ssl-server-verify
- ssl-skip-self-issued-ca
- unix-bind
@ -2072,6 +2073,25 @@ ssl-propquery <query>
foo provider by default, and to fallback on the default provider's one if it
was not found.
ssl-provider <name>
This setting is only available when support for OpenSSL was built in and when
OpenSSL's version is at least 3.0. It allows to load a provider during init.
If loading is successful, any capabilities provided by the loaded provider
might be used by HAProxy. Multiple 'ssl-provider' options can be specified in
a configuration file. The providers will be loaded in their order of
appearance.
Please note that loading a provider explicitely prevents OpenSSL from loading
the 'default' provider automatically. OpenSSL also allows to define the
providers that should be loaded directly in its configuration file
(openssl.cnf for instance) so it is not necessary to use this 'ssl-provider'
option to load providers. The "show ssl providers" CLI command can be used to
show all the providers that were successfully loaded.
The default search path of OpenSSL provider can be found in the output of the
"openssl version -a" command. If the provider is in another directory, you
can set the OPENSSL_MODULES environment variable, which takes the directory
where your provider can be found.
See also "ssl-propquery".
ssl-load-extra-del-ext
This setting allows to configure the way HAProxy does the lookup for the
extra SSL files. By default HAProxy adds a new extension to the filename.

View File

@ -53,6 +53,7 @@ extern int ssl_keylog_index;
extern int ssl_client_sni_index;
extern struct pool_head *pool_head_ssl_keylog;
extern struct pool_head *pool_head_ssl_keylog_str;
extern struct list openssl_providers;
int ssl_sock_prep_ctx_and_inst(struct bind_conf *bind_conf, struct ssl_bind_conf *ssl_conf,
SSL_CTX *ctx, struct ckch_inst *ckch_inst, char **err);
@ -100,6 +101,9 @@ int ssl_sock_load_global_dh_param_from_file(const char *filename);
void ssl_free_dh(void);
#endif
void ssl_free_engines(void);
#ifdef HAVE_SSL_PROVIDERS
void ssl_unload_providers(void);
#endif
#ifdef HAVE_SSL_CLIENT_HELLO_CB
int ssl_sock_switchctx_err_cbk(SSL *ssl, int *al, void *priv);
#ifdef OPENSSL_IS_BORINGSSL
@ -126,6 +130,9 @@ void ssl_free_global_issuers(void);
int ssl_initialize_random(void);
int ssl_sock_load_cert_list_file(char *file, int dir, struct bind_conf *bind_conf, struct proxy *curproxy, char **err);
int ssl_init_single_engine(const char *engine_id, const char *def_algorithms);
#ifdef HAVE_SSL_PROVIDERS
int ssl_init_provider(const char *provider_name);
#endif
#if ((defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB && !defined OPENSSL_NO_OCSP) && !defined OPENSSL_IS_BORINGSSL)
int ssl_get_ocspresponse_detail(unsigned char *ocsp_certid, struct buffer *out);
int ssl_ocsp_response_print(struct buffer *ocsp_response, struct buffer *out);

View File

@ -200,6 +200,26 @@ static int ssl_parse_global_ssl_propquery(char **args, int section_type, struct
return ret;
}
/* parse the "ssl-provider" keyword in global section.
* Returns <0 on alert, >0 on warning, 0 on success.
*/
static int ssl_parse_global_ssl_provider(char **args, int section_type, struct proxy *curpx,
const struct proxy *defpx, const char *file, int line,
char **err)
{
int ret = -1;
if (*(args[1]) == 0) {
memprintf(err, "global statement '%s' expects a valid engine provider name as an argument.", args[0]);
return ret;
}
if (ssl_init_provider(args[1]) == 0)
ret = 0;
return ret;
}
#endif
/* parse the "ssl-default-bind-ciphers" / "ssl-default-server-ciphers" keywords
@ -1960,6 +1980,7 @@ static struct cfg_kw_list cfg_kws = {ILH, {
#endif
#ifdef HAVE_SSL_PROVIDERS
{ CFG_GLOBAL, "ssl-propquery", ssl_parse_global_ssl_propquery },
{ CFG_GLOBAL, "ssl-provider", ssl_parse_global_ssl_provider },
#endif
{ CFG_GLOBAL, "ssl-skip-self-issued-ca", ssl_parse_skip_self_issued_ca },
{ CFG_GLOBAL, "tune.ssl.cachesize", ssl_parse_global_int },

View File

@ -481,6 +481,14 @@ struct ssl_engine_list {
};
#endif
#ifdef HAVE_SSL_PROVIDERS
struct list openssl_providers = LIST_HEAD_INIT(openssl_providers);
struct ssl_provider_list {
struct list list;
OSSL_PROVIDER *provider;
};
#endif
#ifndef OPENSSL_NO_DH
static int ssl_dh_ptr_index = -1;
static HASSL_DH *global_dh = NULL;
@ -698,6 +706,33 @@ int ssl_init_single_engine(const char *engine_id, const char *def_algorithms)
}
#endif
#ifdef HAVE_SSL_PROVIDERS
int ssl_init_provider(const char *provider_name)
{
int err_code = ERR_ABORT;
struct ssl_provider_list *prov = NULL;
prov = calloc(1, sizeof(*prov));
if (!prov) {
ha_alert("ssl-provider %s: memory allocation failure\n", provider_name);
goto error;
}
if ((prov->provider = OSSL_PROVIDER_load(NULL, provider_name)) == NULL) {
ha_alert("ssl-provider %s: unknown provider\n", provider_name);
goto error;
}
LIST_INSERT(&openssl_providers, &prov->list);
return 0;
error:
ha_free(&prov);
return err_code;
}
#endif /* HAVE_SSL_PROVIDERS */
#ifdef SSL_MODE_ASYNC
/*
* openssl async fd handler
@ -8024,6 +8059,9 @@ static void __ssl_sock_init(void)
#if defined(USE_ENGINE) && !defined(OPENSSL_NO_ENGINE)
hap_register_post_deinit(ssl_free_engines);
#endif
#ifdef HAVE_SSL_PROVIDERS
hap_register_post_deinit(ssl_unload_providers);
#endif
#if HA_OPENSSL_VERSION_NUMBER < 0x3000000fL
/* Load SSL string for the verbose & debug mode. */
ERR_load_SSL_strings();
@ -8128,6 +8166,17 @@ void ssl_free_engines(void) {
}
#endif
#ifdef HAVE_SSL_PROVIDERS
void ssl_unload_providers(void) {
struct ssl_provider_list *prov, *provb;
list_for_each_entry_safe(prov, provb, &openssl_providers, list) {
OSSL_PROVIDER_unload(prov->provider);
LIST_DELETE(&prov->list);
free(prov);
}
}
#endif
#ifndef OPENSSL_NO_DH
void ssl_free_dh(void) {
if (local_dh_1024) {