diff --git a/include/haproxy/ssl_ckch.h b/include/haproxy/ssl_ckch.h
index 94c53b301..00ba2bf18 100644
--- a/include/haproxy/ssl_ckch.h
+++ b/include/haproxy/ssl_ckch.h
@@ -72,5 +72,14 @@ int __ssl_store_load_locations_file(char *path, int
create_if_none, enum cafile_
 extern struct cert_exts cert_exts[];
 extern int (*ssl_commit_crlfile_cb)(const char *path, X509_STORE *ctx,
char **err);

+struct ckch_data_cache {
+ struct ckch_data_cache *next;
+ struct ckch_data *key;
+ uint8_t *data;
+ int len;
+};
+
+struct ckch_data_cache *ckch_data_get(void *key);
+
 #endif /* USE_OPENSSL */
 #endif /* _HAPROXY_SSL_CRTLIST_H */
diff --git a/src/ssl_ckch.c b/src/ssl_ckch.c
index add42b69e..f659014ba 100644
--- a/src/ssl_ckch.c
+++ b/src/ssl_ckch.c
@@ -516,11 +516,63 @@ int ssl_sock_load_files_into_ckch(const char *path,
struct ckch_data *data, char
  *
  *  Return 0 on success or != 0 on failure
  */
+
+struct ckch_data_cache *cache[31] = {0};
+
+/*
+ * 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(void *key, uint8_t *data, int len)
+{
+ int idx = (unsigned long)key % 31;
+ struct ckch_data_cache *prev, *cur, *last = NULL;
+
+ ha_notice("caching ckch_data:%p len:%d\n", key, len);
+
+ for(prev = cache[idx]; prev != NULL;) {
+ last = prev;
+ prev = prev->next;
+ }
+
+ cur = malloc(sizeof(struct ckch_data_cache));
+ memset(cur, 0, sizeof(struct ckch_data_cache));
+ if (last == NULL)
+ cache[idx] = cur;
+ else
+ last = cur;
+ cur->key = key;
+ cur->data = malloc(len);
+ memcpy(cur->data, data, len);
+ cur->len = len;
+}
+
+struct ckch_data_cache *ckch_data_get(void *key)
+{
+ int idx = (unsigned long)key % 31;
+ struct ckch_data_cache *prev;
+
+ for(prev = cache[idx]; prev != NULL; prev = prev->next) {
+ if (prev->key == key)
+ return prev;
+ }
+
+ return NULL;
+}
+
 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 (buf) {
  /* reading from a buffer */
@@ -538,14 +590,25 @@ 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 (key == NULL) {
  memprintf(err, "%sunable to load private key from file '%s'.\n",
           err && *err ? *err : "", path);
  goto end;
+ } else {
+ ckch_data_put(data, (uint8_t*)src, len);
  }

  ret = 0;
@@ -581,6 +644,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 +670,23 @@ 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 */
+ if(key && global.mode&MODE_MWORKER) {
+ ckch_data_put(data, (uint8_t *)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..64bd7ac04 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -2009,10 +2009,77 @@ 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 */
 };

+/* cache SSL_CTX* to ckch_data
+ * so we can recreate private key
+ */
+struct ssl_ctx_cache {
+ void *key;
+ struct ckch_data_cache *value;
+ struct ssl_ctx_cache *next;
+ EVP_PKEY *pkey;
+};
+static struct ssl_ctx_cache *ctx_cache[31];
+
+void ssl_ctx_put(void *key, void *data)
+{
+ int idx = (unsigned long)key % 31;
+ struct ssl_ctx_cache *prev, *cur, *last = NULL;
+
+ ha_notice("ssl_ctx_cache key = %p value = %p\n", key, data);
+
+ for(prev = ctx_cache[idx]; prev != NULL;) {
+ last = prev;
+ prev = prev->next;
+ }
+
+ cur = malloc(sizeof(struct ssl_ctx_cache));
+       memset(cur, 0, sizeof(struct ssl_ctx_cache));
+ if (last == NULL)
+ ctx_cache[idx] = cur;
+ else
+ last->next = cur;
+ cur->next = NULL;
+ cur->key = key;
+ cur->value = data;
+}
+
+struct ssl_ctx_cache *ssl_ctx_get(void *key)
+{
+ int idx = (unsigned long)key % 31;
+ struct ssl_ctx_cache *prev;
+
+ for(prev = ctx_cache[idx]; prev != NULL; prev = prev->next) {
+ if (prev->key == key) {
+ ha_notice("ssl_ctx_cache found key = %p value = %p\n", key, prev->value);
+ return prev;
+ }
+ }
+
+ return NULL;
+}
+
 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(ctx))) {
+ if (value->pkey == NULL) {
+ in = BIO_new_mem_buf(value->value->data, value->value->len);
+ if ((value->pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL))) {
+ SSL_CTX_use_PrivateKey(ctx, value->pkey);
+ ha_notice("loaded private key PID=%d SSL_CTX*=%p\n", getpid(), ctx);
+ }
+ else {
+ value->pkey = (EVP_PKEY*)-1L;
+ ha_notice("unable to realize private key from memory buffer\n");
+ }
+ }
+ }
+
  SSL_set_SSL_CTX(ssl, ctx);
 }

@@ -3323,11 +3390,16 @@ static int ssl_sock_load_cert_chain(const char
*path, const struct ckch_data *da
 static int ssl_sock_put_ckch_into_ctx(const char *path, struct ckch_data
*data, SSL_CTX *ctx, char **err)
 {
  int errcode = 0;
+ struct ckch_data_cache *value;
  STACK_OF(X509) *find_chain = NULL;

  ERR_clear_error();

- if (SSL_CTX_use_PrivateKey(ctx, data->key) <= 0) {
+ if(global.mode&MODE_MWORKER && (value = ckch_data_get(data))) {
+ ssl_ctx_put(ctx, value);
+ }
+
+ if (!(global.mode&MODE_MWORKER) && SSL_CTX_use_PrivateKey(ctx, data->key)
<= 0) {
  int ret;

  ret = ERR_get_error();

Reply via email to