mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 23:56:57 +02:00
MINOR: ssl: deduplicate ca-file
Typically server line like: 'server-template srv 1-1000 *:443 ssl ca-file ca-certificates.crt' load ca-certificates.crt 1000 times and stay duplicated in memory. Same case for bind line: ca-file is loaded for each certificate. Same 'ca-file' can be load one time only and stay deduplicated in memory. As a corollary, this will prevent file access for ca-file when updating a certificate via CLI.
This commit is contained in:
parent
cefbbd9811
commit
d4f9a60ee2
@ -136,6 +136,20 @@ static inline STACK_OF(X509) *X509_chain_up_ref(STACK_OF(X509) *chain)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef OPENSSL_IS_BORINGSSL
|
||||||
|
/*
|
||||||
|
* Functions missing in BoringSSL
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline X509_CRL *X509_OBJECT_get0_X509_CRL(const X509_OBJECT *a)
|
||||||
|
{
|
||||||
|
if (a == NULL || a->type != X509_LU_CRL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return a->data.crl;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if (HA_OPENSSL_VERSION_NUMBER < 0x1010000fL) && (LIBRESSL_VERSION_NUMBER < 0x2070000fL)
|
#if (HA_OPENSSL_VERSION_NUMBER < 0x1010000fL) && (LIBRESSL_VERSION_NUMBER < 0x2070000fL)
|
||||||
/*
|
/*
|
||||||
* Functions introduced in OpenSSL 1.1.0 and in LibreSSL 2.7.0
|
* Functions introduced in OpenSSL 1.1.0 and in LibreSSL 2.7.0
|
||||||
|
100
src/ssl_sock.c
100
src/ssl_sock.c
@ -363,6 +363,86 @@ static struct {
|
|||||||
char *path;
|
char *path;
|
||||||
} ckchs_transaction;
|
} ckchs_transaction;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* deduplicate cafile
|
||||||
|
*/
|
||||||
|
struct cafile_entry {
|
||||||
|
X509_STORE *ca_store;
|
||||||
|
struct ebmb_node node;
|
||||||
|
char path[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct eb_root cafile_tree = EB_ROOT_UNIQUE;
|
||||||
|
|
||||||
|
static X509_STORE* ssl_store_get0_locations_file(char *path)
|
||||||
|
{
|
||||||
|
struct ebmb_node *eb;
|
||||||
|
|
||||||
|
eb = ebst_lookup(&cafile_tree, path);
|
||||||
|
if (eb) {
|
||||||
|
struct cafile_entry *ca_e;
|
||||||
|
ca_e = ebmb_entry(eb, struct cafile_entry, node);
|
||||||
|
return ca_e->ca_store;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ssl_store_load_locations_file(char *path)
|
||||||
|
{
|
||||||
|
if (ssl_store_get0_locations_file(path) == NULL) {
|
||||||
|
struct cafile_entry *ca_e;
|
||||||
|
X509_STORE *store = X509_STORE_new();
|
||||||
|
if (X509_STORE_load_locations(store, path, NULL)) {
|
||||||
|
int pathlen;
|
||||||
|
pathlen = strlen(path);
|
||||||
|
ca_e = calloc(1, sizeof(*ca_e) + pathlen + 1);
|
||||||
|
if (ca_e) {
|
||||||
|
memcpy(ca_e->path, path, pathlen + 1);
|
||||||
|
ca_e->ca_store = store;
|
||||||
|
ebst_insert(&cafile_tree, &ca_e->node);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
X509_STORE_free(store);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* mimic what X509_STORE_load_locations do with store_ctx */
|
||||||
|
static int ssl_set_cert_crl_file(X509_STORE *store_ctx, char *path)
|
||||||
|
{
|
||||||
|
X509_STORE *store;
|
||||||
|
store = ssl_store_get0_locations_file(path);
|
||||||
|
if (store_ctx && store) {
|
||||||
|
int i;
|
||||||
|
X509_OBJECT *obj;
|
||||||
|
STACK_OF(X509_OBJECT) *objs = X509_STORE_get0_objects(store);
|
||||||
|
for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
|
||||||
|
obj = sk_X509_OBJECT_value(objs, i);
|
||||||
|
switch (X509_OBJECT_get_type(obj)) {
|
||||||
|
case X509_LU_X509:
|
||||||
|
X509_STORE_add_cert(store_ctx, X509_OBJECT_get0_X509(obj));
|
||||||
|
break;
|
||||||
|
case X509_LU_CRL:
|
||||||
|
X509_STORE_add_crl(store_ctx, X509_OBJECT_get0_X509_CRL(obj));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SSL_CTX_load_verify_locations substitute, internaly call X509_STORE_load_locations */
|
||||||
|
static int ssl_set_verify_locations_file(SSL_CTX *ctx, char *path)
|
||||||
|
{
|
||||||
|
X509_STORE *store_ctx = SSL_CTX_get_cert_store(ctx);
|
||||||
|
return ssl_set_cert_crl_file(store_ctx, path);
|
||||||
|
}
|
||||||
|
|
||||||
/* This memory pool is used for capturing clienthello parameters. */
|
/* This memory pool is used for capturing clienthello parameters. */
|
||||||
struct ssl_capture {
|
struct ssl_capture {
|
||||||
unsigned long long int xxh64;
|
unsigned long long int xxh64;
|
||||||
@ -4872,9 +4952,9 @@ int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, struct ssl_bind_conf *ssl_
|
|||||||
char *ca_file = (ssl_conf && ssl_conf->ca_file) ? ssl_conf->ca_file : bind_conf->ssl_conf.ca_file;
|
char *ca_file = (ssl_conf && ssl_conf->ca_file) ? ssl_conf->ca_file : bind_conf->ssl_conf.ca_file;
|
||||||
char *crl_file = (ssl_conf && ssl_conf->crl_file) ? ssl_conf->crl_file : bind_conf->ssl_conf.crl_file;
|
char *crl_file = (ssl_conf && ssl_conf->crl_file) ? ssl_conf->crl_file : bind_conf->ssl_conf.crl_file;
|
||||||
if (ca_file) {
|
if (ca_file) {
|
||||||
/* load CAfile to verify */
|
/* set CAfile to verify */
|
||||||
if (!SSL_CTX_load_verify_locations(ctx, ca_file, NULL)) {
|
if (!ssl_set_verify_locations_file(ctx, ca_file)) {
|
||||||
memprintf(err, "%sProxy '%s': unable to load CA file '%s' for bind '%s' at [%s:%d].\n",
|
memprintf(err, "%sProxy '%s': unable to set CA file '%s' for bind '%s' at [%s:%d].\n",
|
||||||
err && *err ? *err : "", curproxy->id, ca_file, bind_conf->arg, bind_conf->file, bind_conf->line);
|
err && *err ? *err : "", curproxy->id, ca_file, bind_conf->arg, bind_conf->file, bind_conf->line);
|
||||||
cfgerr |= ERR_ALERT | ERR_FATAL;
|
cfgerr |= ERR_ALERT | ERR_FATAL;
|
||||||
}
|
}
|
||||||
@ -5372,9 +5452,9 @@ int ssl_sock_prepare_srv_ctx(struct server *srv)
|
|||||||
(srv->ssl_ctx.verify_host || (verify & SSL_VERIFY_PEER)) ? ssl_sock_srv_verifycbk : NULL);
|
(srv->ssl_ctx.verify_host || (verify & SSL_VERIFY_PEER)) ? ssl_sock_srv_verifycbk : NULL);
|
||||||
if (verify & SSL_VERIFY_PEER) {
|
if (verify & SSL_VERIFY_PEER) {
|
||||||
if (srv->ssl_ctx.ca_file) {
|
if (srv->ssl_ctx.ca_file) {
|
||||||
/* load CAfile to verify */
|
/* set CAfile to verify */
|
||||||
if (!SSL_CTX_load_verify_locations(srv->ssl_ctx.ctx, srv->ssl_ctx.ca_file, NULL)) {
|
if (!ssl_set_verify_locations_file(srv->ssl_ctx.ctx, srv->ssl_ctx.ca_file)) {
|
||||||
ha_alert("Proxy '%s', server '%s' [%s:%d] unable to load CA file '%s'.\n",
|
ha_alert("Proxy '%s', server '%s' [%s:%d] unable to set CA file '%s'.\n",
|
||||||
curproxy->id, srv->id,
|
curproxy->id, srv->id,
|
||||||
srv->conf.file, srv->conf.line, srv->ssl_ctx.ca_file);
|
srv->conf.file, srv->conf.line, srv->ssl_ctx.ca_file);
|
||||||
cfgerr++;
|
cfgerr++;
|
||||||
@ -8324,6 +8404,10 @@ static int ssl_bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, st
|
|||||||
else
|
else
|
||||||
memprintf(&conf->ca_file, "%s", args[cur_arg + 1]);
|
memprintf(&conf->ca_file, "%s", args[cur_arg + 1]);
|
||||||
|
|
||||||
|
if (!ssl_store_load_locations_file(conf->ca_file)) {
|
||||||
|
memprintf(err, "'%s' : unable to load %s", args[cur_arg], conf->ca_file);
|
||||||
|
return ERR_ALERT | ERR_FATAL;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
static int bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
|
static int bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
|
||||||
@ -9081,6 +9165,10 @@ static int srv_parse_ca_file(char **args, int *cur_arg, struct proxy *px, struct
|
|||||||
else
|
else
|
||||||
memprintf(&newsrv->ssl_ctx.ca_file, "%s", args[*cur_arg + 1]);
|
memprintf(&newsrv->ssl_ctx.ca_file, "%s", args[*cur_arg + 1]);
|
||||||
|
|
||||||
|
if (!ssl_store_load_locations_file(newsrv->ssl_ctx.ca_file)) {
|
||||||
|
memprintf(err, "'%s' : unable to load %s", args[*cur_arg], newsrv->ssl_ctx.ca_file);
|
||||||
|
return ERR_ALERT | ERR_FATAL;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user