]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: ssl: Add 'ssl-provider' global option
authorRemi Tricot-Le Breton <rlebreton@haproxy.com>
Mon, 16 May 2022 14:24:33 +0000 (16:24 +0200)
committerWilliam Lallemand <wlallemand@haproxy.org>
Tue, 17 May 2022 08:56:05 +0000 (10:56 +0200)
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.

doc/configuration.txt
include/haproxy/ssl_sock.h
src/cfgparse-ssl.c
src/ssl_sock.c

index 7632291c20eb34458a23d4bb3e05c7df51899ad6..8198181b032bfca3699f63aee94ae30c4f71ac8a 100644 (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.
index cd1c2d4029462d18ef5d03249eb9a39190a923db..8d1ce50b7e2d1666ea221b82f3ec753ac7451bd7 100644 (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);
index 513cfd6a7ed7bca2172792766466af346248120a..326cc210ccabddad6821096ec245eec53da49d65 100644 (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 },
index 6ffdf4d94637efef84ee00de29be5d7110f5c7a8..a27949d5f1959d0a7bf419280b317660a4793ceb 100644 (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 @@ fail_get:
 }
 #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) {