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;

Reply via email to