Diff attached.
Regards
Richard
diff --git a/include/haproxy/ssl_ckch-t.h b/include/haproxy/ssl_ckch-t.h
index 0002b84d9..2470c45b2 100644
--- a/include/haproxy/ssl_ckch-t.h
+++ b/include/haproxy/ssl_ckch-t.h
@@ -56,6 +56,13 @@ struct ckch_data {
X509 *ocsp_issuer;
OCSP_CERTID *ocsp_cid;
int ocsp_update_mode;
+#if defined(USE_ENGINE) && !defined(OPENSSL_NO_ENGINE)
+ char *engine;
+ char *private_key;
+#endif
+ int len;
+ char *pem_data;
+ EVP_PKEY *worker_key;
};
/*
diff --git a/src/ssl_ckch.c b/src/ssl_ckch.c
index b69caacb3..0f6ab6a0a 100644
--- a/src/ssl_ckch.c
+++ b/src/ssl_ckch.c
@@ -516,11 +516,45 @@ int ssl_sock_load_files_into_ckch(const char *path, struct ckch_data *data, char
*
* Return 0 on success or != 0 on failure
*/
+
+/*
+ * This caches the BIO data in case the private key i
+ *
+ * to be instantiated in the child process (used for HSM keys)
+ *
+ * The key ckch_data* and the value is ckch_data_cache*
+ *
+ */
+static void ckch_data_put(struct ckch_data *cur, char *data, int len)
+{
+ cur->pem_data = malloc(len);
+ memcpy(cur->pem_data, data, len);
+ cur->len = len;
+}
+
+#if defined(USE_ENGINE) && !defined(OPENSSL_NO_ENGINE)
+static void engine_data_put(struct ckch_data *cur, char *engine, char *private_key)
+{
+ cur->engine = strdup(engine);
+ cur->private_key = strdup(private_key);
+ cur->len = -1;
+}
+#endif
+
int ssl_sock_load_key_into_ckch(const char *path, char *buf, struct ckch_data *data , char **err)
{
BIO *in = NULL;
int ret = 1;
EVP_PKEY *key = NULL;
+ static char src[16384];
+ char *src_temp;
+ int len;
+ int filetype = 0;
+#if defined(USE_ENGINE) && !defined(OPENSSL_NO_ENGINE)
+ CONF *conf = NULL;
+ BIO *conf_in = NULL;
+ ENGINE *eng;
+#endif
if (buf) {
/* reading from a buffer */
@@ -538,16 +572,67 @@ int ssl_sock_load_key_into_ckch(const char *path, char *buf, struct ckch_data *d
if (BIO_read_filename(in, path) <= 0)
goto end;
+ filetype = 1;
}
/* Read Private Key */
+ if(filetype) {
+ len = BIO_read(in, src, sizeof(src));
+ BIO_reset(in);
+ } else {
+ len = BIO_get_mem_data(in, &src_temp);
+ memcpy(src, src_temp, len);
+ }
+
key = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);
+#if OPENSSL_VERSION_NUMBER >= 0x030000000UL
+ data->len = 0;
+ if(key && global.mode&MODE_MWORKER) {
+ ckch_data_put(data, src, len);
+ }
+#endif
+ if(key)
+ goto ok;
+#if defined(USE_ENGINE) && !defined(OPENSSL_NO_ENGINE)
+ /* ENGINE should be loaded in global config */
+ conf = NCONF_new(NCONF_default());
+ if (conf == NULL)
+ goto end;
+ conf_in = BIO_new_mem_buf(src, len);
+ if (conf_in == NULL)
+ goto end;
+ ret = NCONF_load_bio(conf, conf_in, NULL);
+ if (ret<=0)
+ goto end;
+ char *eng_id = NCONF_get_string(conf, NULL, "engine");
+ char *private_key = NCONF_get_string(conf, NULL, "private_key");
+
+ ha_notice("ENGINE private_key = %s\n", private_key);
+ ha_notice("ENGINE engine_id = %s\n", eng_id);
+
+ eng = ENGINE_by_id(eng_id);
+ if (eng == NULL)
+ goto end;
+ else
+ fprintf(stderr, "ENGINE %s is successfully loaded!\n", eng_id);
+ key = ENGINE_load_private_key(eng, private_key, NULL, NULL);
+ if (key)
+ fprintf(stderr, "private key %s is successfully loaded!\n", private_key);
+
+ data->len = 0;
+ if(key && global.mode&MODE_MWORKER) {
+ ha_notice("storing key = %p engine_id = %s private_key = %s\n",
+ data, eng_id, private_key);
+ engine_data_put(data, eng_id, private_key);
+ }
+#endif
if (key == NULL) {
memprintf(err, "%sunable to load private key from file '%s'.\n",
err && *err ? *err : "", path);
goto end;
}
+ok:
ret = 0;
SWAP(data->key, key);
@@ -560,6 +645,12 @@ int ssl_sock_load_key_into_ckch(const char *path, char *buf, struct ckch_data *d
if (key)
EVP_PKEY_free(key);
+#if defined(USE_ENGINE) && !defined(OPENSSL_NO_ENGINE)
+ if (conf)
+ NCONF_free(conf);
+ if (conf_in)
+ BIO_free(conf_in);
+#endif
return ret;
}
@@ -581,6 +672,10 @@ int ssl_sock_load_pem_into_ckch(const char *path, char *buf, struct ckch_data *d
EVP_PKEY *key = NULL;
HASSL_DH *dh = NULL;
STACK_OF(X509) *chain = NULL;
+ int filetype = 0;
+ int len;
+ static char src[16384];
+ char *src_temp;
if (buf) {
/* reading from a buffer */
@@ -603,11 +698,24 @@ int ssl_sock_load_pem_into_ckch(const char *path, char *buf, struct ckch_data *d
err && *err ? *err : "", path);
goto end;
}
+ filetype = 1;
}
/* Read Private Key */
+ if(filetype) {
+ len = BIO_read(in, src, sizeof(src));
+ BIO_reset(in);
+ } else {
+ len = BIO_get_mem_data(in, &src_temp);
+ memcpy(src, src_temp, len);
+ }
+
key = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);
/* no need to check for errors here, because the private key could be loaded later */
+ data->len = 0;
+ if(key && global.mode&MODE_MWORKER) {
+ ckch_data_put(data, src, len);
+ }
#ifndef OPENSSL_NO_DH
/* Seek back to beginning of file */
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 824bdaa72..5034745c8 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -2009,10 +2009,45 @@ struct methodVersions methodVersions[] = {
{SSL_OP_NO_TLSv1_3, MC_SSL_O_NO_TLSV13, ctx_set_TLSv13_func, ssl_set_TLSv13_func, "TLSv1.3"}, /* CONF_TLSV13 */
};
+struct ssl_ctx_cache {
+ EVP_PKEY *worker_key;
+ struct ckch_data *data;
+};
+
static void ssl_sock_switchctx_set(SSL *ssl, SSL_CTX *ctx)
{
+ struct ssl_ctx_cache *value = NULL;
+ BIO *in;
+
SSL_set_verify(ssl, SSL_CTX_get_verify_mode(ctx), ssl_sock_bind_verifycbk);
SSL_set_client_CA_list(ssl, SSL_dup_CA_list(SSL_CTX_get_client_CA_list(ctx)));
+
+ if ((value = SSL_CTX_get_app_data(ctx))) {
+ if (value->worker_key == NULL) {
+#if defined(USE_ENGINE) && !defined(OPENSSL_NO_ENGINE)
+ ENGINE *eng = ENGINE_by_id(value->data->engine);
+ value->worker_key = ENGINE_load_private_key(eng, value->data->private_key, NULL, NULL);
+ if (value->worker_key) {
+ SSL_CTX_use_PrivateKey(ctx, value->worker_key);
+ ha_notice("loaded private key PID=%d SSL_CTX*=%p\n", getpid(), ctx);
+ } else {
+ value->worker_key = (EVP_PKEY*)-1L;
+ ha_notice("unable to realize private key from ENGINE\n");
+ }
+#else
+ in = BIO_new_mem_buf(value->data->pem_data, value->data->len);
+ if ((value->worker_key = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL))) {
+ SSL_CTX_use_PrivateKey(ctx, value->worker_key);
+ ha_notice("loaded private key PID=%d SSL_CTX*=%p\n", getpid(), ctx);
+ }
+ else {
+ value->worker_key = (EVP_PKEY*)-1L;
+ ha_notice("unable to realize private key from memory buffer\n");
+ }
+#endif
+ }
+ }
+
SSL_set_SSL_CTX(ssl, ctx);
}
@@ -3327,7 +3362,11 @@ static int ssl_sock_put_ckch_into_ctx(const char *path, struct ckch_data *data,
ERR_clear_error();
- if (SSL_CTX_use_PrivateKey(ctx, data->key) <= 0) {
+ if(global.mode&MODE_MWORKER && !data->len) {
+ SSL_CTX_use_PrivateKey(ctx, data->key);
+ }
+
+ if (!(global.mode&MODE_MWORKER) && SSL_CTX_use_PrivateKey(ctx, data->key) <= 0) {
int ret;
ret = ERR_get_error();
@@ -3447,6 +3486,7 @@ int ckch_inst_new_load_store(const char *path, struct ckch_store *ckchs, struct
X509_NAME *xname;
char *str;
EVP_PKEY *pkey;
+ struct ssl_ctx_cache *ctx_cache;
struct pkey_info kinfo = { .sig = TLSEXT_signature_anonymous, .bits = 0 };
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
STACK_OF(GENERAL_NAME) *names;
@@ -3473,6 +3513,15 @@ int ckch_inst_new_load_store(const char *path, struct ckch_store *ckchs, struct
if (global_ssl.security_level > -1)
SSL_CTX_set_security_level(ctx, global_ssl.security_level);
+ if(global.mode && data->len) {
+ ha_notice("storing SSL_CTX* = %p, data = %p, data->len = %d\n",
+ ctx, data, data->len);
+ ctx_cache = malloc(sizeof(struct ssl_ctx_cache));
+ ctx_cache->worker_key = NULL;
+ ctx_cache->data = data;
+ SSL_CTX_set_app_data(ctx, ctx_cache);
+ }
+
errcode |= ssl_sock_put_ckch_into_ctx(path, data, ctx, err);
if (errcode & ERR_CODE)
goto error;