This patch adds the global 'ssl-engine' keyword. First arg is an engine
identifier followed by a list of default_algorithms the engine will
operate.
If the openssl version is too old, an error is reported when the option
is used.
---
doc/configuration.txt | 16 ++++++
include/common/mini-clist.h | 7 +++
src/ssl_sock.c | 119 +++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 141 insertions(+), 1 deletion(-)
diff --git a/doc/configuration.txt b/doc/configuration.txt
index c2ede71..ecd1769 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -589,6 +589,7 @@ The following keywords are supported in the "global"
section :
- spread-checks
- server-state-base
- server-state-file
+ - ssl-engine
- tune.buffers.limit
- tune.buffers.reserve
- tune.bufsize
@@ -1240,6 +1241,21 @@ spread-checks <0..50, in percent>
and +/- 50%. A value between 2 and 5 seems to show good results. The
default value remains at 0.
+ssl-engine <name> [algo <comma-seperated list of algorithms>]
+ Sets the OpenSSL engine to <name>. List of valid values for <name> may be
+ obtained using the command "openssl engine". This statement may be used
+ multiple times, it will simply enable multiple crypto engines. Referencing an
+ unsupported engine will prevent haproxy from starting. Note that many engines
+ will lead to lower HTTPS performance than pure software with recent
+ processors. The optional command "algo" sets the default algorithms an ENGINE
+ will supply using the OPENSSL function ENGINE_set_default_string(). A value
+ of "ALL" uses the engine for all cryptographic operations. If no list of
+ algo is specified then the value of "ALL" is used. A comma-seperated list
+ of different algorithms may be specified, including: RSA, DSA, DH, EC, RAND,
+ CIPHERS, DIGESTS, PKEY, PKEY_CRYPTO, PKEY_ASN1. This is the same format that
+ openssl configuration file uses:
+ https://www.openssl.org/docs/man1.0.2/apps/config.html
+
tune.buffers.limit <number>
Sets a hard limit on the number of buffers which may be allocated per
process.
The default value is zero which means unlimited. The minimum non-zero value
diff --git a/include/common/mini-clist.h b/include/common/mini-clist.h
index da24b33..7000927 100644
--- a/include/common/mini-clist.h
+++ b/include/common/mini-clist.h
@@ -61,6 +61,13 @@ struct cond_wordlist {
char *s;
};
+/* this is the same as above with the additional pointer to an argument. */
+struct arg1_wordlist {
+ struct list list;
+ void *arg1;
+ char *word;
+};
+
/* First undefine some macros which happen to also be defined on OpenBSD,
* in sys/queue.h, used by sys/event.h
*/
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 232a497..b173d77 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -52,6 +52,7 @@
#ifndef OPENSSL_NO_DH
#include <openssl/dh.h>
#endif
+#include <openssl/engine.h>
#include <import/lru.h>
#include <import/xxhash.h>
@@ -168,6 +169,9 @@ static struct {
struct list tlskeys_reference = LIST_HEAD_INIT(tlskeys_reference);
#endif
+struct list openssl_engines = LIST_HEAD_INIT(openssl_engines);
+static unsigned int openssl_engines_initialized;
+
#ifndef OPENSSL_NO_DH
static int ssl_dh_ptr_index = -1;
static DH *global_dh = NULL;
@@ -262,6 +266,55 @@ struct ocsp_cbk_arg {
};
};
+static int ssl_init_single_engine(const char *engine_id, const char
*def_algorithms)
+{
+ int err_code = ERR_ABORT;
+ ENGINE *engine;
+
+ /* grab the structural reference to the engine */
+ engine = ENGINE_by_id(engine_id);
+ if (engine == NULL) {
+ Alert("ssl-engine %s: failed to get structural reference\n",
engine_id);
+ goto fail_get;
+ }
+
+ if (!ENGINE_init(engine)) {
+ /* the engine couldn't initialise, release it */
+ Alert("ssl-engine %s: failed to initialize\n", engine_id);
+ goto fail_init;
+ }
+
+ if (ENGINE_set_default_string(engine, def_algorithms) == 0) {
+ Alert("ssl-engine %s: failed on ENGINE_set_default_string\n",
engine_id);
+ goto fail_set_method;
+ }
+ err_code = 0;
+
+fail_set_method:
+ /* release the functional reference from ENGINE_init() */
+ ENGINE_finish(engine);
+
+fail_init:
+ /* release the structural reference from ENGINE_by_id() */
+ ENGINE_free(engine);
+
+fail_get:
+ return err_code;
+}
+
+static int ssl_init_engines(void)
+{
+ int err_code = 0;
+ struct arg1_wordlist *wl, *wlb;
+
+ list_for_each_entry_safe(wl, wlb, &openssl_engines, list) {
+ err_code = ssl_init_single_engine(wl->word, wl->arg1);
+ if (err_code == ERR_ABORT)
+ break;
+ }
+ return err_code;
+}
+
/*
* This function returns the number of seconds elapsed
* since the Epoch, 1970-01-01 00:00:00 +0000 (UTC) and the
@@ -2329,7 +2382,6 @@ static int ssl_sock_load_cert_chain_file(SSL_CTX *ctx,
const char *file, struct
if (BIO_read_filename(in, file) <= 0)
goto end;
-
passwd_cb = SSL_CTX_get_default_passwd_cb(ctx);
passwd_cb_userdata = SSL_CTX_get_default_passwd_cb_userdata(ctx);
@@ -2513,6 +2565,12 @@ int ssl_sock_load_cert(char *path, struct bind_conf
*bind_conf, char **err)
int j;
#endif
+ if (!openssl_engines_initialized) {
+ if (ssl_init_engines())
+ return 1;
+ openssl_engines_initialized = 1;
+ }
+
if (stat(path, &buf) == 0) {
dir = opendir(path);
if (!dir)
@@ -2654,6 +2712,12 @@ int ssl_sock_load_cert_list_file(char *file, struct
bind_conf *bind_conf, struct
return 1;
}
+ if (!openssl_engines_initialized) {
+ if (ssl_init_engines())
+ return 1;
+ openssl_engines_initialized = 1;
+ }
+
while (fgets(thisline, sizeof(thisline), f) != NULL) {
int arg, newarg, cur_arg, i, ssl_b = 0, ssl_e = 0;
char *end;
@@ -6375,6 +6439,48 @@ static int ssl_parse_global_ca_crt_base(char **args, int
section_type, struct pr
return 0;
}
+/* parse the "ssl-engine" keyword in global section.
+ * Returns <0 on alert, >0 on warning, 0 on success.
+ */
+static int ssl_parse_global_ssl_engine(char **args, int section_type, struct
proxy *curpx,
+ struct proxy *defpx, const char *file,
int line,
+ char **err)
+{
+ char *algo;
+ struct arg1_wordlist *wl;
+
+ if (*(args[1]) == 0) {
+ memprintf(err, "global statement '%s' expects a valid engine
name as an argument.", args[0]);
+ return -1;
+ }
+
+ if (*(args[2]) == 0) {
+ memprintf(err, "statement '%s' expects algorithm names as an
argument.", args[0]);
+ /* if no list of algorithms is given, it defaults to ALL */
+ algo = strdup("ALL");
+ goto add_engine;
+ }
+
+ /* otherwise the expected format is ssl-engine <engine_name> algo <list
of algo> */
+ if (strcmp(args[2], "algo") != 0) {
+ memprintf(err, "global statement '%s' expects to have algo
keyword.", args[0]);
+ return -1;
+ }
+
+ if (*(args[3]) == 0) {
+ memprintf(err, "global statement '%s' expects algorithm names
as an argument.", args[0]);
+ return -1;
+ }
+ algo = strdup(args[3]);
+
+add_engine:
+ wl = calloc(1, sizeof(*wl));
+ wl->word = strdup(args[1]);
+ wl->arg1 = algo;
+ LIST_ADD(&openssl_engines, &wl->list);
+ return 0;
+}
+
/* parse the "ssl-default-bind-ciphers" / "ssl-default-server-ciphers" keywords
* in global section. Returns <0 on alert, >0 on warning, 0 on success.
*/
@@ -6948,6 +7054,7 @@ static struct cfg_kw_list cfg_kws = {ILH, {
#ifndef OPENSSL_NO_DH
{ CFG_GLOBAL, "ssl-dh-param-file", ssl_parse_global_dh_param_file },
#endif
+ { CFG_GLOBAL, "ssl-engine", ssl_parse_global_ssl_engine },
{ CFG_GLOBAL, "tune.ssl.cachesize", ssl_parse_global_int },
#ifndef OPENSSL_NO_DH
{ CFG_GLOBAL, "tune.ssl.default-dh-param", ssl_parse_global_default_dh
},
@@ -7015,6 +7122,7 @@ static void __ssl_sock_init(void)
srv_register_keywords(&srv_kws);
cfg_register_keywords(&cfg_kws);
cli_register_kw(&cli_kws);
+ ENGINE_load_builtin_engines();
#if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
hap_register_post_check(tlskeys_finalize_config);
#endif
@@ -7067,6 +7175,7 @@ static void __ssl_sock_init(void)
__attribute__((destructor))
static void __ssl_sock_deinit(void)
{
+ struct arg1_wordlist *wl, *wlb;
#if (defined SSL_CTRL_SET_TLSEXT_HOSTNAME && !defined
SSL_NO_GENERATE_CERTIFICATES)
lru64_destroy(ssl_ctx_lru_tree);
#endif
@@ -7093,6 +7202,14 @@ static void __ssl_sock_deinit(void)
}
#endif
+ /* free up engine list */
+ list_for_each_entry_safe(wl, wlb, &openssl_engines, list) {
+ free(wl->arg1);
+ free(wl->word);
+ LIST_DEL(&wl->list);
+ free(wl);
+ }
+
ERR_remove_state(0);
ERR_free_strings();
--
1.9.1