Apologies for the badly pasted diff
Richard
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();