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;