mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-06 15:17:01 +02:00
MINOR: ssl: add the section parser for 'crt-store'
'crt-store' is a new section useful to define the struct ckch_store. The "load" keyword in the "crt-store" section allows to define which files you want to load for a specific certificate definition. Ex: crt-store load crt "site1.crt" key "site1.key" load crt "site2.crt" key "site2.key" frontend in bind *:443 ssl crt "site1.crt" crt "site2.crt" This is part of the certificate loading which was discussed in #785.
This commit is contained in:
parent
aaa72e06e5
commit
00eb44864b
@ -36,6 +36,7 @@ struct acl_cond;
|
||||
#define CFG_USERLIST 3
|
||||
#define CFG_PEERS 4
|
||||
#define CFG_CRTLIST 5
|
||||
#define CFG_CRTSTORE 6
|
||||
|
||||
/* various keyword modifiers */
|
||||
enum kw_mod {
|
||||
|
@ -58,6 +58,15 @@ struct ckch_data {
|
||||
int ocsp_update_mode;
|
||||
};
|
||||
|
||||
/* configuration for the ckch_store */
|
||||
struct ckch_conf {
|
||||
char *crt;
|
||||
char *key;
|
||||
char *ocsp;
|
||||
char *issuer;
|
||||
char *sctl;
|
||||
};
|
||||
|
||||
/*
|
||||
* this is used to store 1 to SSL_SOCK_NUM_KEYTYPES cert_key_and_chain and
|
||||
* metadata.
|
||||
@ -71,6 +80,7 @@ struct ckch_store {
|
||||
struct ckch_data *data;
|
||||
struct list ckch_inst; /* list of ckch_inst which uses this ckch_node */
|
||||
struct list crtlist_entry; /* list of entries which use this store */
|
||||
struct ckch_conf conf;
|
||||
struct ebmb_node node;
|
||||
char path[VAR_ARRAY];
|
||||
};
|
||||
@ -157,5 +167,21 @@ struct cert_exts {
|
||||
/* add a parsing callback */
|
||||
};
|
||||
|
||||
/* argument types */
|
||||
enum parse_type_t {
|
||||
PARSE_TYPE_INT = 0,
|
||||
PARSE_TYPE_STR, /* string which is strdup() */
|
||||
PARSE_TYPE_ONOFF, /* "on" or "off" keyword */
|
||||
};
|
||||
|
||||
struct ckch_conf_kws {
|
||||
const char *name;
|
||||
size_t offset;
|
||||
enum parse_type_t type;
|
||||
int (*func)(const char *path, char *buf, struct ckch_data *d, char **err);
|
||||
};
|
||||
|
||||
extern struct ckch_conf_kws ckch_conf_kws[];
|
||||
|
||||
#endif /* USE_OPENSSL */
|
||||
#endif /* _HAPROXY_SSL_CKCH_T_H */
|
||||
|
@ -43,6 +43,7 @@ struct ckch_store *ckchs_dup(const struct ckch_store *src);
|
||||
struct ckch_store *ckch_store_new(const char *filename);
|
||||
void ckch_store_free(struct ckch_store *store);
|
||||
void ckch_store_replace(struct ckch_store *old_ckchs, struct ckch_store *new_ckchs);
|
||||
int ckch_store_load_files(struct ckch_conf *f, struct ckch_store *c, char **err);
|
||||
|
||||
/* ckch_inst functions */
|
||||
void ckch_inst_free(struct ckch_inst *inst);
|
||||
|
234
src/ssl_ckch.c
234
src/ssl_ckch.c
@ -28,6 +28,7 @@
|
||||
|
||||
#include <haproxy/applet.h>
|
||||
#include <haproxy/base64.h>
|
||||
#include <haproxy/cfgparse.h>
|
||||
#include <haproxy/channel.h>
|
||||
#include <haproxy/cli.h>
|
||||
#include <haproxy/errors.h>
|
||||
@ -911,6 +912,13 @@ void ckch_store_free(struct ckch_store *store)
|
||||
ssl_sock_free_cert_key_and_chain_contents(store->data);
|
||||
ha_free(&store->data);
|
||||
|
||||
/* free the ckch_conf content */
|
||||
free(store->conf.crt);
|
||||
free(store->conf.key);
|
||||
free(store->conf.ocsp);
|
||||
free(store->conf.issuer);
|
||||
free(store->conf.sctl);
|
||||
|
||||
free(store);
|
||||
}
|
||||
|
||||
@ -3988,3 +3996,229 @@ static struct cli_kw_list cli_kws = {{ },{
|
||||
|
||||
INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
|
||||
|
||||
struct ckch_conf_kws ckch_conf_kws[] = {
|
||||
{ "crt", offsetof(struct ckch_conf, crt), PARSE_TYPE_STR, ssl_sock_load_pem_into_ckch },
|
||||
{ "key", offsetof(struct ckch_conf, key), PARSE_TYPE_STR, ssl_sock_load_key_into_ckch },
|
||||
{ "ocsp", offsetof(struct ckch_conf, ocsp), PARSE_TYPE_STR, ssl_sock_load_ocsp_response_from_file },
|
||||
{ "issuer", offsetof(struct ckch_conf, issuer), PARSE_TYPE_STR, ssl_sock_load_issuer_file_into_ckch },
|
||||
{ "sctl", offsetof(struct ckch_conf, sctl), PARSE_TYPE_STR, ssl_sock_load_sctl_from_file },
|
||||
{ NULL, 0, PARSE_TYPE_STR, NULL }
|
||||
};
|
||||
|
||||
/* crt-store does not try to find files, but use the stored filename */
|
||||
int ckch_store_load_files(struct ckch_conf *f, struct ckch_store *c, char **err)
|
||||
{
|
||||
int i;
|
||||
int err_code = 0;
|
||||
int rc = 0;
|
||||
struct ckch_data *d = c->data;
|
||||
|
||||
/* crt */
|
||||
if (!f->crt) {
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; ckch_conf_kws[i].name; i++) {
|
||||
if (*(char **)((intptr_t)f + (ptrdiff_t)ckch_conf_kws[i].offset)) {
|
||||
if (!ckch_conf_kws[i].func)
|
||||
continue;
|
||||
rc = ckch_conf_kws[i].func(*(char **)((intptr_t)f + (ptrdiff_t)ckch_conf_kws[i].offset), NULL, d, err);
|
||||
if (rc) {
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
memprintf(err, "%s '%s' cannot be read or parsed.",
|
||||
err && *err ? *err : "", *(char **)((intptr_t)f + (ptrdiff_t)ckch_conf_kws[i].offset));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (err_code & ERR_FATAL)
|
||||
ssl_sock_free_cert_key_and_chain_contents(d);
|
||||
ERR_clear_error();
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
static int crtstore_parse_load(char **args, int section_type, struct proxy *curpx, const struct proxy *defpx,
|
||||
const char *file, int linenum, char **err)
|
||||
{
|
||||
int i;
|
||||
int err_code = 0;
|
||||
int cur_arg = 0;
|
||||
struct ckch_conf f = {};
|
||||
struct ckch_store *c = NULL;
|
||||
|
||||
cur_arg++; /* skip "load" */
|
||||
|
||||
while (*(args[cur_arg])) {
|
||||
int found = 0;
|
||||
|
||||
for (i = 0; ckch_conf_kws[i].name != NULL; i++) {
|
||||
if (strcmp(ckch_conf_kws[i].name, args[cur_arg]) == 0) {
|
||||
void *target;
|
||||
found = 1;
|
||||
target = (char **)((intptr_t)&f + (ptrdiff_t)ckch_conf_kws[i].offset);
|
||||
|
||||
if (ckch_conf_kws[i].type == PARSE_TYPE_STR) {
|
||||
char **t = target;
|
||||
|
||||
*t = strdup(args[cur_arg + 1]);
|
||||
if (!*t)
|
||||
goto alloc_error;
|
||||
} else if (ckch_conf_kws[i].type == PARSE_TYPE_INT) {
|
||||
int *t = target;
|
||||
char *stop;
|
||||
|
||||
*t = strtol(args[cur_arg + 1], &stop, 10);
|
||||
if (*stop != '\0') {
|
||||
memprintf(err, "parsing [%s:%d] : cannot parse '%s' value '%s', an integer is expected.\n",
|
||||
file, linenum, args[cur_arg], args[cur_arg + 1]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
} else if (ckch_conf_kws[i].type == PARSE_TYPE_ONOFF) {
|
||||
int *t = target;
|
||||
|
||||
if (strcmp(args[cur_arg + 1], "on") == 0) {
|
||||
*t = 1;
|
||||
} else if (strcmp(args[cur_arg + 1], "off") == 0) {
|
||||
*t = 0;
|
||||
} else {
|
||||
memprintf(err, "parsing [%s:%d] : cannot parse '%s' value '%s', 'on' or 'off' is expected.\n",
|
||||
file, linenum, args[cur_arg], args[cur_arg + 1]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if (!found) {
|
||||
memprintf(err,"parsing [%s:%d] : '%s %s' in section 'crt-store': unknown keyword '%s'.",
|
||||
file, linenum, args[0], args[cur_arg],args[cur_arg]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
cur_arg += 2;
|
||||
}
|
||||
|
||||
if (!f.crt) {
|
||||
memprintf(err,"parsing [%s:%d] : '%s' in section 'crt-store': mandatory 'crt' parameter not found.",
|
||||
file, linenum, args[0]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* process and insert the ckch_store */
|
||||
c = ckch_store_new(f.crt);
|
||||
if (!c)
|
||||
goto alloc_error;
|
||||
|
||||
err_code |= ckch_store_load_files(&f, c, err);
|
||||
if (err_code & ERR_FATAL)
|
||||
goto out;
|
||||
|
||||
c->conf = f;
|
||||
|
||||
if (ebst_insert(&ckchs_tree, &c->node) != &c->node) {
|
||||
memprintf(err,"parsing [%s:%d] : '%s' in section 'crt-store': store '%s' was already defined.",
|
||||
file, linenum, args[0], c->path);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
/* free ckch_conf content */
|
||||
if (err_code & ERR_FATAL)
|
||||
ckch_store_free(c);
|
||||
return err_code;
|
||||
|
||||
alloc_error:
|
||||
ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
|
||||
err_code |= ERR_ALERT | ERR_ABORT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse "crt-store" section and create corresponding ckch_stores.
|
||||
*
|
||||
* The function returns 0 in success case, otherwise, it returns error
|
||||
* flags.
|
||||
*/
|
||||
static int cfg_parse_crtstore(const char *file, int linenum, char **args, int kwm)
|
||||
{
|
||||
struct cfg_kw_list *kwl;
|
||||
const char *best;
|
||||
int index;
|
||||
int rc = 0;
|
||||
int err_code = 0;
|
||||
char *errmsg = NULL;
|
||||
|
||||
if (strcmp(args[0], "crt-store") == 0) { /* new crt-store section */
|
||||
if (*args[1]) {
|
||||
ha_alert("parsing [%s:%d] : 'crt-store' section does not support an argument.\n", file, linenum);
|
||||
err_code |= ERR_ALERT | ERR_FATAL | ERR_ABORT;
|
||||
goto out;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
list_for_each_entry(kwl, &cfg_keywords.list, list) {
|
||||
for (index = 0; kwl->kw[index].kw != NULL; index++) {
|
||||
if (kwl->kw[index].section != CFG_CRTSTORE)
|
||||
continue;
|
||||
if (strcmp(kwl->kw[index].kw, args[0]) == 0) {
|
||||
if (check_kw_experimental(&kwl->kw[index], file, linenum, &errmsg)) {
|
||||
ha_alert("%s\n", errmsg);
|
||||
err_code |= ERR_ALERT | ERR_FATAL | ERR_ABORT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* prepare error message just in case */
|
||||
rc = kwl->kw[index].parse(args, CFG_CRTSTORE, NULL, NULL, file, linenum, &errmsg);
|
||||
if (rc & ERR_ALERT) {
|
||||
ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg);
|
||||
err_code |= rc;
|
||||
goto out;
|
||||
}
|
||||
else if (rc & ERR_WARN) {
|
||||
ha_warning("parsing [%s:%d] : %s\n", file, linenum, errmsg);
|
||||
err_code |= rc;
|
||||
goto out;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
best = cfg_find_best_match(args[0], &cfg_keywords.list, CFG_CRTSTORE, NULL);
|
||||
if (best)
|
||||
ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section; did you mean '%s' maybe ?\n", file, linenum, args[0], cursection, best);
|
||||
else
|
||||
ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], cursection);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
|
||||
out:
|
||||
if (err_code & ERR_FATAL)
|
||||
err_code |= ERR_ABORT;
|
||||
free(errmsg);
|
||||
return err_code;
|
||||
|
||||
alloc_error:
|
||||
ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
|
||||
err_code |= ERR_ALERT | ERR_ABORT;
|
||||
goto out;
|
||||
|
||||
}
|
||||
|
||||
REGISTER_CONFIG_SECTION("crt-store", cfg_parse_crtstore, NULL);
|
||||
|
||||
static struct cfg_kw_list cfg_kws = {ILH, {
|
||||
{ CFG_CRTSTORE, "load", crtstore_parse_load },
|
||||
{ 0, NULL, NULL },
|
||||
}};
|
||||
INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
|
||||
|
Loading…
Reference in New Issue
Block a user