]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: ssl/crtlist: loading crt-store keywords from a crt-list
authorWilliam Lallemand <wlallemand@haproxy.com>
Wed, 10 Apr 2024 15:21:50 +0000 (17:21 +0200)
committerWilliam Lallemand <wlallemand@haproxy.com>
Fri, 17 May 2024 15:35:51 +0000 (17:35 +0200)
This patch allows the usage of "crt-store" keywords from a "crt-list".

The crtstore_parse_load() function was splitted into 2 functions, so the
keywords parsing is done in ckch_conf_parse().

With this patch, crt are loaded with ckch_store_new_load_files_conf() or
ckch_store_new_load_files_path() depending on weither or not there is a
"crt-store" keyword.

More checks need to be done on "crt" bind keywords to ensure that
keywords are compatible.

This patch does not introduce the feature on the CLI.

include/haproxy/ssl_ckch-t.h
include/haproxy/ssl_ckch.h
include/haproxy/ssl_crtlist.h
src/ssl_ckch.c
src/ssl_crtlist.c

index 6951126e2f56bc9a4086b79814fa6997a3ad2ce2..cb945ff277132b953df34431f1dd0b9b005ce9ec 100644 (file)
@@ -60,6 +60,7 @@ struct ckch_data {
 
 /* configuration for the ckch_store */
 struct ckch_conf {
+       int used;
        char *crt;
        char *key;
        char *ocsp;
index 1bb82a2d518a9620db4a957e04ab59dbe6acd497..41183791ce4cfce51ae840c9ae6de1affe9960bd 100644 (file)
@@ -46,6 +46,7 @@ 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);
 
+int ckch_conf_parse(char **args, int cur_arg, struct ckch_conf *f, int *found, const char *file, int linenum, char **err);
 /* ckch_inst functions */
 void ckch_inst_free(struct ckch_inst *inst);
 struct ckch_inst *ckch_inst_new();
index 961cfc385e830a64b0ae698bcb9d39b08b7b9d01..f81ee9ea011e78c44f2406ad8b7608e1b21ae91f 100644 (file)
@@ -38,7 +38,7 @@ void crtlist_free(struct crtlist *crtlist);
 struct crtlist *crtlist_new(const char *filename, int unique);
 
 /* file loading */
-int crtlist_parse_line(char *line, char **crt_path, struct crtlist_entry *entry, const char *file, int linenum, int from_cli, char **err);
+int crtlist_parse_line(char *line, char **crt_path, struct crtlist_entry *entry, struct ckch_conf *conf, const char *file, int linenum, int from_cli, char **err);
 int crtlist_parse_file(char *file, struct bind_conf *bind_conf, struct proxy *curproxy, struct crtlist **crtlist, char **err);
 int crtlist_load_cert_dir(char *path, struct bind_conf *bind_conf, struct crtlist **crtlist, char **err);
 
index f6e2e9a5b00a74182867119906f0d1ab7f5f8fce..b7b881a0183bf0b376d9dec5e2ae98cf19af9998 100644 (file)
@@ -4127,7 +4127,60 @@ static int crtstore_parse_path_base(char **args, int section_type, struct proxy
                free(current_keybase);
                current_keybase = strdup(args[1]);
        }
+out:
+       return err_code;
+}
+
 
+/* parse ckch_conf keywords for crt-list */
+int ckch_conf_parse(char **args, int cur_arg, struct ckch_conf *f, int *found, const char *file, int linenum, char **err)
+{
+       int i;
+       int err_code = 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) {
+                                       ha_alert("parsing [%s:%d]: out of memory.\n", file, linenum);
+                                       err_code |= ERR_ALERT | ERR_ABORT;
+                                       goto out;
+                               }
+                       } 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;
+               }
+       }
 out:
        return err_code;
 }
@@ -4137,7 +4190,6 @@ static char current_crtstore_name[PATH_MAX] = {};
 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 = {};
@@ -4151,65 +4203,31 @@ static int crtstore_parse_load(char **args, int section_type, struct proxy *curp
        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 (strcmp("alias", args[cur_arg]) == 0) {
-                                       int rv;
-
-                                       if (*args[cur_arg + 1] == '/') {
-                                               memprintf(err, "parsing [%s:%d] : cannot parse '%s' value '%s', '/' is forbidden as the first character.\n",
-                                                         file, linenum, args[cur_arg], args[cur_arg + 1]);
-                                               err_code |= ERR_ALERT | ERR_FATAL;
-                                               goto out;
-                                       }
+               if (strcmp("alias", args[cur_arg]) == 0) {
+                       int rv;
 
-                                       rv = snprintf(alias_name, sizeof(alias_name), "@%s/%s", current_crtstore_name, args[cur_arg + 1]);
-                                       if (rv >= sizeof(alias_name)) {
-                                               memprintf(err, "parsing [%s:%d] : cannot parse '%s' value '%s', too long, max len is %zd.\n",
-                                                         file, linenum, args[cur_arg], args[cur_arg + 1], sizeof(alias_name));
-                                               err_code |= ERR_ALERT | ERR_FATAL;
-                                               goto out;
-                                       }
-                                       final_name = alias_name;
-                               } else 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 (*args[cur_arg + 1] == '/') {
+                               memprintf(err, "parsing [%s:%d] : cannot parse '%s' value '%s', '/' is forbidden as the first character.\n",
+                                         file, linenum, args[cur_arg], args[cur_arg + 1]);
+                               err_code |= ERR_ALERT | ERR_FATAL;
+                               goto out;
                        }
 
+                       rv = snprintf(alias_name, sizeof(alias_name), "@%s/%s", current_crtstore_name, args[cur_arg + 1]);
+                       if (rv >= sizeof(alias_name)) {
+                               memprintf(err, "parsing [%s:%d] : cannot parse '%s' value '%s', too long, max len is %zd.\n",
+                                         file, linenum, args[cur_arg], args[cur_arg + 1], sizeof(alias_name));
+                               err_code |= ERR_ALERT | ERR_FATAL;
+                               goto out;
+                       }
+                       final_name = alias_name;
+                       found = 1;
+               } else {
+                       err_code |= ckch_conf_parse(args, cur_arg, &f, &found, file, linenum, err);
+                       if (err_code & ERR_FATAL)
+                       goto out;
                }
+
                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]);
index 528db099d9b0e948a65ebe546d72c1f8cb0a13f5..fc9bfb70e63c899ab0f275fdb669ca50a0ea03c8 100644 (file)
@@ -356,7 +356,7 @@ struct crtlist *crtlist_new(const char *filename, int unique)
  *  <crt_path> is a ptr in <line>
  *  Return an error code
  */
-int crtlist_parse_line(char *line, char **crt_path, struct crtlist_entry *entry, const char *file, int linenum, int from_cli, char **err)
+int crtlist_parse_line(char *line, char **crt_path, struct crtlist_entry *entry, struct ckch_conf *cc, const char *file, int linenum, int from_cli, char **err)
 {
        int cfgerr = 0;
        int arg, newarg, cur_arg, i, ssl_b = 0, ssl_e = 0;
@@ -443,6 +443,7 @@ int crtlist_parse_line(char *line, char **crt_path, struct crtlist_entry *entry,
        cur_arg = ssl_b ? ssl_b : 1;
        while (cur_arg < ssl_e) {
                newarg = 0;
+               /* look for ssl_conf 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)
@@ -462,9 +463,20 @@ int crtlist_parse_line(char *line, char **crt_path, struct crtlist_entry *entry,
                                        goto error;
                                }
                                cur_arg += 1 + ssl_crtlist_kws[i].skip;
-                               break;
+                               goto out;
                        }
                }
+               if (cc) {
+                       /* look for ckch_conf keywords */
+                       cfgerr |= ckch_conf_parse(args, cur_arg, cc, &newarg, file, linenum, err);
+                       if (cfgerr & ERR_FATAL)
+                               goto error;
+
+                       cc->used = 1;
+                       if (newarg) /* skip 2 words if the keyword was found */
+                               cur_arg += 2;
+               }
+out:
                if (!cfgerr && !newarg) {
                        memprintf(err, "parsing [%s:%d]: unknown ssl keyword %s",
                                  file, linenum, args[cur_arg]);
@@ -523,6 +535,7 @@ int crtlist_parse_file(char *file, struct bind_conf *bind_conf, struct proxy *cu
                char *crt_path;
                char path[MAXPATHLEN+1];
                struct ckch_store *ckchs;
+               struct ckch_conf cc = {};
                int found = 0;
 
                if (missing_lf != -1) {
@@ -564,7 +577,7 @@ int crtlist_parse_file(char *file, struct bind_conf *bind_conf, struct proxy *cu
                        goto error;
                }
 
-               cfgerr |= crtlist_parse_line(thisline, &crt_path, entry, file, linenum, 0, err);
+               cfgerr |= crtlist_parse_line(thisline, &crt_path, entry, &cc, file, linenum, 0, err);
                if (cfgerr & ERR_CODE)
                        goto error;
 
@@ -591,13 +604,20 @@ int crtlist_parse_file(char *file, struct bind_conf *bind_conf, struct proxy *cu
                if (ckchs == NULL) {
                        if (stat(crt_path, &buf) == 0) {
                                found++;
-
-                               ckchs = ckch_store_new_load_files_path(crt_path, err);
+                               if (cc.used) {
+                                       free(cc.crt);
+                                       cc.crt = strdup(crt_path);
+                                       ckchs = ckch_store_new_load_files_conf(crt_path, &cc, err);
+                               } else {
+                                       ckchs = ckch_store_new_load_files_path(crt_path, err);
+                               }
                                if (ckchs == NULL) {
                                        cfgerr |= ERR_ALERT | ERR_FATAL;
                                        goto error;
                                }
 
+                               ckchs->conf = cc;
+
                                entry->node.key = ckchs;
                                entry->crtlist = newlist;
                                if (entry->ssl_conf)
@@ -618,6 +638,7 @@ int crtlist_parse_file(char *file, struct bind_conf *bind_conf, struct proxy *cu
                                char fp[MAXPATHLEN+1] = {0};
                                int n = 0;
                                struct crtlist_entry *entry_dup = entry; /* use the previous created entry */
+
                                for (n = 0; n < SSL_SOCK_NUM_KEYTYPES; n++) {
                                        struct stat buf;
                                        int ret;
@@ -629,6 +650,12 @@ int crtlist_parse_file(char *file, struct bind_conf *bind_conf, struct proxy *cu
                                        ckchs = ckchs_lookup(fp);
                                        if (!ckchs) {
                                                if (stat(fp, &buf) == 0) {
+
+                                                       if (cc.used) {
+                                                               memprintf(err, "%sCan't load '%s'. Using crt-store keyword is not compatible with multi certificates bundle.\n",
+                                                                         err && *err ? *err : "", crt_path);
+                                                               cfgerr |= ERR_ALERT | ERR_FATAL;
+                                                       }
                                                        ckchs = ckch_store_new_load_files_path(fp, err);
                                                        if (!ckchs) {
                                                                cfgerr |= ERR_ALERT | ERR_FATAL;
@@ -719,6 +746,8 @@ int crtlist_parse_file(char *file, struct bind_conf *bind_conf, struct proxy *cu
 error:
        crtlist_entry_free(entry);
 
+       /* FIXME: free cc */
+
        fclose(f);
        crtlist_free(newlist);
        return cfgerr;
@@ -1307,7 +1336,8 @@ static int cli_parse_add_crtlist(char **args, char *payload, struct appctx *appc
                        goto error;
                }
                /* cert_path is filled here */
-               cfgerr |= crtlist_parse_line(payload, &cert_path, entry, "CLI", 1, 1, &err);
+               cfgerr |= crtlist_parse_line(payload, &cert_path, entry, NULL, "CLI", 1, 1, &err);
+               /* FIXME: handle the ckch_conf */
                if (cfgerr & ERR_CODE)
                        goto error;
        } else {