MEDIUM: ssl/crtlist: "crt" keyword in frontend
This patch implements the "crt" keywords in frontend, declaring an implicit crt-list named after the frontend. The patch is split in two steps: The first step is the crt keyword parser, which parses crt lines and fill a "cfg_crt_node" struct containing a ssl_bind_conf and a ckch_conf which are put in a list to be used later. After parsing the frontend section, as a 2nd step, a post_section_parser is called, it will create a crt-list named after the frontend and will fill it with certificates from the list of cfg_crt_node. Once created this crt-list will be loaded in every "ssl" bind lines that didn't declare any crt or crt-list. Example: listen https bind :443 ssl crt foobar.pem crt test1.net.crt key test1.net.key Implements part of #2854
This commit is contained in:
parent
5316923f6b
commit
af32dc61f4
@ -30,6 +30,8 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <import/ebsttree.h>
|
||||
|
||||
#include <haproxy/api.h>
|
||||
#include <haproxy/base64.h>
|
||||
#include <haproxy/cfgparse.h>
|
||||
@ -40,7 +42,9 @@
|
||||
#include <haproxy/ssl_utils.h>
|
||||
#include <haproxy/tools.h>
|
||||
#include <haproxy/ssl_ckch.h>
|
||||
#include <haproxy/ssl_crtlist.h>
|
||||
#include <haproxy/ssl_ocsp.h>
|
||||
#include <haproxy/ssl_sock.h>
|
||||
|
||||
|
||||
/****************** Global Section Parsing ********************************************/
|
||||
@ -2153,7 +2157,205 @@ static int ssl_parse_skip_self_issued_ca(char **args, int section_type, struct p
|
||||
#endif
|
||||
}
|
||||
|
||||
struct cfg_crt_node {
|
||||
int linenum;
|
||||
char *filename;
|
||||
struct ssl_bind_conf *ssl_conf;
|
||||
struct ckch_conf *ckch_conf;
|
||||
struct list list;
|
||||
};
|
||||
|
||||
/* list used for inline crt-list initialization */
|
||||
static struct list cur_crtlist = LIST_HEAD_INIT(cur_crtlist);
|
||||
/*
|
||||
* Parse a "crt" line in a frontend.
|
||||
*/
|
||||
static int proxy_parse_crt(char **args, int section_type, struct proxy *curpx,
|
||||
const struct proxy *defpx, const char *file, int linenum,
|
||||
char **err)
|
||||
{
|
||||
int cfgerr = 0;
|
||||
struct ssl_bind_conf *ssl_conf = NULL;
|
||||
struct ckch_conf *ckch_conf = NULL;
|
||||
struct cfg_crt_node *cfg_crt_node = NULL;
|
||||
int cur_arg = 2;
|
||||
int i;
|
||||
|
||||
if (!*args[1]) {
|
||||
memprintf(err, "parsing [%s:%d] : '%s' : expects a certificate name", file, linenum, args[0]);
|
||||
goto error;
|
||||
}
|
||||
|
||||
cfg_crt_node = calloc(1, sizeof *cfg_crt_node);
|
||||
if (!cfg_crt_node) {
|
||||
memprintf(err, "not enough memory!");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ckch_conf = calloc(1, sizeof *ckch_conf);
|
||||
if (!ckch_conf) {
|
||||
memprintf(err, "not enough memory!");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ckch_conf->crt = strdup(args[1]);
|
||||
if (!ckch_conf->crt) {
|
||||
memprintf(err, "not enough memory!");
|
||||
goto error;
|
||||
}
|
||||
|
||||
while (*args[cur_arg]) {
|
||||
int found = 0;
|
||||
|
||||
/* first look for crt-list keywords */
|
||||
for (i = 0; ssl_crtlist_kws[i].kw != NULL; i++) {
|
||||
if (strcmp(ssl_crtlist_kws[i].kw, args[cur_arg]) == 0) {
|
||||
|
||||
if (!ssl_conf)
|
||||
ssl_conf = calloc(1, sizeof *ssl_conf);
|
||||
if (!ssl_conf) {
|
||||
memprintf(err, "not enough memory!");
|
||||
goto error;
|
||||
}
|
||||
|
||||
cfgerr |= ssl_crtlist_kws[i].parse(args, cur_arg, NULL, ssl_conf, 0, err);
|
||||
if (cfgerr & ERR_CODE)
|
||||
goto error;
|
||||
cur_arg += 1 + ssl_crtlist_kws[i].skip;
|
||||
found = 1;
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
||||
/* then look for ckch_conf keywords */
|
||||
cfgerr |= ckch_conf_parse(args, cur_arg, ckch_conf, &found, file, linenum, err);
|
||||
if (cfgerr & ERR_CODE)
|
||||
goto error;
|
||||
if (found) {
|
||||
cur_arg += 2; /* skip 2 words if the keyword was found */
|
||||
ckch_conf->used = CKCH_CONF_SET_CRTLIST; /* if they are options they must be used everywhere */
|
||||
goto next;
|
||||
}
|
||||
|
||||
next:
|
||||
if (!found) {
|
||||
memprintf(err, "unknown crt keyword '%s'", args[cur_arg]);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
cfg_crt_node->ssl_conf = ssl_conf;
|
||||
cfg_crt_node->ckch_conf = ckch_conf;
|
||||
LIST_INSERT(&cur_crtlist, &cfg_crt_node->list);
|
||||
|
||||
return 0;
|
||||
error:
|
||||
ckch_conf_clean(ckch_conf);
|
||||
ha_free(&ckch_conf);
|
||||
ssl_sock_free_ssl_conf(ssl_conf);
|
||||
ha_free(&ssl_conf);
|
||||
ha_free(&cfg_crt_node);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* After parsing the crt keywords in a frontend/listen section, create the corresponding crt-list and initialize the
|
||||
* certificates
|
||||
*/
|
||||
|
||||
static int post_section_frontend_crt_init()
|
||||
{
|
||||
struct crtlist *newlist = NULL;
|
||||
struct crtlist_entry *entry = NULL;
|
||||
int err_code = 0;
|
||||
struct cfg_crt_node *n, *r;
|
||||
struct bind_conf *b;
|
||||
char *crtlist_name = NULL;
|
||||
char *err = NULL;
|
||||
|
||||
list_for_each_entry_safe(n, r, &cur_crtlist, list) {
|
||||
|
||||
/* create a new crt-list with the frontend name or a specified name */
|
||||
if (!crtlist_name)
|
||||
memprintf(&crtlist_name, "@%s", curproxy->id);
|
||||
if (!crtlist_name) {
|
||||
memprintf(&err, "Not enough memory!");
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!newlist)
|
||||
newlist = crtlist_new(crtlist_name, 0);
|
||||
if (!newlist) {
|
||||
memprintf(&err, "Not enough memory!");
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
entry = crtlist_entry_new();
|
||||
if (entry == NULL) {
|
||||
memprintf(&err, "Not enough memory!");
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* must set the ssl_conf in case of duplication of the crtlist_entry */
|
||||
entry->ssl_conf = n->ssl_conf;
|
||||
|
||||
err_code |= crtlist_load_crt(n->ckch_conf->crt, n->ckch_conf, newlist, entry, n->filename, n->linenum, &err);
|
||||
if (err_code & ERR_CODE)
|
||||
goto error;
|
||||
|
||||
LIST_DELETE(&n->list);
|
||||
/* n->ssl_conf is reused so we don't free them here */
|
||||
free(n->ckch_conf);
|
||||
free(n);
|
||||
}
|
||||
|
||||
if (newlist) {
|
||||
|
||||
if (ebst_insert(&crtlists_tree, &newlist->node) != &newlist->node) {
|
||||
memprintf(&err, "Couldn't create the crt-list '%s', this name is already used by another crt-list!", crtlist_name);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* look for "ssl" bind lines without any crt nor crt-line */
|
||||
list_for_each_entry(b, &curproxy->conf.bind, by_fe) {
|
||||
if (b->options & BC_O_USE_SSL) {
|
||||
if (eb_is_empty(&b->sni_ctx) && eb_is_empty(&b->sni_w_ctx)) {
|
||||
err_code |= ssl_sock_load_cert_list_file(crtlist_name, 0, b, curproxy, &err);
|
||||
if (err_code & ERR_CODE)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err_code;
|
||||
error:
|
||||
|
||||
if (err)
|
||||
ha_alert("%s.\n", err);
|
||||
free(err);
|
||||
|
||||
list_for_each_entry_safe(n, r, &cur_crtlist, list) {
|
||||
ckch_conf_clean(n->ckch_conf);
|
||||
ha_free(&n->ckch_conf);
|
||||
ssl_sock_free_ssl_conf(n->ssl_conf);
|
||||
ha_free(&n->ssl_conf);
|
||||
LIST_DELETE(&n->list);
|
||||
ha_free(&n);
|
||||
}
|
||||
|
||||
ha_free(&crtlist_name);
|
||||
crtlist_entry_free(entry);
|
||||
crtlist_free(newlist);
|
||||
return err_code;
|
||||
}
|
||||
|
||||
REGISTER_CONFIG_POST_SECTION("listen", post_section_frontend_crt_init);
|
||||
REGISTER_CONFIG_POST_SECTION("frontend", post_section_frontend_crt_init);
|
||||
|
||||
|
||||
/* Note: must not be declared <const> as its list will be overwritten.
|
||||
@ -2343,6 +2545,9 @@ static struct cfg_kw_list cfg_kws = {ILH, {
|
||||
{ CFG_GLOBAL, "ssl-default-server-ciphersuites", ssl_parse_global_ciphersuites },
|
||||
{ CFG_GLOBAL, "ssl-load-extra-files", ssl_parse_global_extra_files },
|
||||
{ CFG_GLOBAL, "ssl-load-extra-del-ext", ssl_parse_global_extra_noext },
|
||||
|
||||
{ CFG_LISTEN, "crt", proxy_parse_crt },
|
||||
|
||||
{ 0, NULL, NULL },
|
||||
}};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user