]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: ssl/cli: support crt-list filters
authorWilliam Lallemand <wlallemand@haproxy.com>
Wed, 4 Dec 2019 14:39:35 +0000 (15:39 +0100)
committerWilliam Lallemand <wlallemand@haproxy.org>
Thu, 5 Mar 2020 10:27:53 +0000 (11:27 +0100)
Generate a list of the previous filters when updating a certificate
which use filters in crt-list. Then pass this list to the function
generating the sni_ctx during the commit.

This feature allows the update of the crt-list certificates which uses
the filters with "set ssl cert".

This function could be probably replaced by creating a new
ckch_inst_new_load_store() function which take the previous sni_ctx list as
an argument instead of the char **sni_filter, avoiding the
allocation/copy during runtime for each filter. But since are still
handling the multi-cert bundles, it's better this way to avoid code
duplication.

include/types/ssl_sock.h
src/ssl_sock.c

index feca100046a05f09134de86eacdb688be75841cf..bb64e49723411bb3f9250855ab6d876e295f08de 100644 (file)
@@ -111,7 +111,6 @@ struct cert_key_and_chain {
 struct ckch_store {
        struct cert_key_and_chain *ckch;
        unsigned int multi:1;  /* is it a multi-cert bundle ? */
-       unsigned int filters:1;/* one of the instances is using filters, TODO:remove this flag once filters are supported */
        struct list ckch_inst; /* list of ckch_inst which uses this ckch_node */
        struct ebmb_node node;
        char path[0];
index 2688117e5985cf7c5dc5c6c7ff720679a2de4d66..86894cb4401d192cec4c255116e413be897784d6 100644 (file)
@@ -3895,6 +3895,84 @@ end:
        return NULL;
 }
 
+
+/*
+ * Free a sni filters array generated by ckch_inst_sni_ctx_to_sni_filters()
+ */
+static inline void free_sni_filters(char **sni_filter, int fcount)
+{
+       int i;
+
+       if (sni_filter) {
+               for (i = 0; i < fcount; i++) {
+                       if (sni_filter[i]) {
+                               free(sni_filter[i]);
+                               sni_filter[i] = NULL;
+                       }
+               }
+               free(sni_filter);
+       }
+}
+
+/*
+ * Fill <*sni_filter> with an allocated array of ptr to the existing filters,
+ * The caller should free <*sni_filter>.
+ * Fill <*fcount> with the number of filters
+ * Return an ERR_* code.
+ */
+static int ckch_inst_sni_ctx_to_sni_filters(const struct ckch_inst *ckchi, char ***sni_filter, int *fcount, char **err)
+{
+       struct sni_ctx *sc0;
+       int errcode = 0;
+       int i = 0;
+       char **tmp_filter;
+       int tmp_fcount = 0;
+
+       list_for_each_entry(sc0, &ckchi->sni_ctx, by_ckch_inst) {
+               tmp_fcount++;
+       }
+
+       if (!tmp_fcount)
+               goto end;
+
+       tmp_filter = malloc(sizeof(*tmp_filter) * tmp_fcount);
+       if (!tmp_filter) {
+               errcode |= ERR_FATAL|ERR_ALERT;
+               goto error;
+       }
+
+       list_for_each_entry(sc0, &ckchi->sni_ctx, by_ckch_inst) {
+               size_t len = strlen((char *)sc0->name.key);
+
+               /* we need to alloc and copy to insert a '!' or/and a '*' */
+               tmp_filter[i] = calloc(1, len + sc0->neg + sc0->wild + 1);
+               if (!tmp_filter[i]) {
+                       errcode |= ERR_FATAL|ERR_ALERT;
+                       goto error;
+               }
+
+               if (sc0->neg)
+                       *tmp_filter[i] = '!';
+               if (sc0->wild)
+                       *(tmp_filter[i] + sc0->neg) = '*';
+
+               memcpy(tmp_filter[i] + sc0->neg + sc0->wild, (char *)sc0->name.key, len + 1);
+               i++;
+       }
+end:
+       *sni_filter = tmp_filter;
+       *fcount = tmp_fcount;
+
+       return errcode;
+error:
+       memprintf(err, "%sUnable to generate filters!",
+                 err && *err ? *err : "");
+       free_sni_filters(tmp_filter, tmp_fcount);
+
+       return errcode;
+}
+
+
 #if HA_OPENSSL_VERSION_NUMBER >= 0x1000200fL
 
 /*
@@ -3949,10 +4027,6 @@ static int ckch_inst_new_load_multi_store(const char *path, struct ckch_store *c
 
        certs_and_keys = ckchs->ckch;
 
-       /* at least one of the instances is using filters during the config
-        * parsing, that's ok to inherit this during loading on CLI */
-       ckchs->filters |= !!fcount;
-
        /* Process each ckch and update keytypes for each CN/SAN
         * for example, if CN/SAN www.a.com is associated with
         * certs with keytype 0 and 2, then at the end of the loop,
@@ -4193,10 +4267,6 @@ static int ckch_inst_new_load_store(const char *path, struct ckch_store *ckchs,
 
        ckch = ckchs->ckch;
 
-       /* at least one of the instances is using filters during the config
-        * parsing, that's ok to inherit this during loading on CLI */
-       ckchs->filters |= !!fcount;
-
        ctx = SSL_CTX_new(SSLv23_server_method());
        if (!ctx) {
                memprintf(err, "%sunable to allocate SSL context for cert '%s'.\n",
@@ -10924,6 +10994,8 @@ static int cli_io_handler_commit_cert(struct appctx *appctx)
                                /* walk through the old ckch_inst and creates new ckch_inst using the updated ckchs */
                                list_for_each_entry_from(ckchi, &old_ckchs->ckch_inst, by_ckchs) {
                                        struct ckch_inst *new_inst;
+                                       char **sni_filter = NULL;
+                                       int fcount = 0;
 
                                        /* it takes a lot of CPU to creates SSL_CTXs, so we yield every 10 CKCH instances */
                                        if (y >= 10) {
@@ -10932,10 +11004,17 @@ static int cli_io_handler_commit_cert(struct appctx *appctx)
                                                goto yield;
                                        }
 
+                                       errcode |= ckch_inst_sni_ctx_to_sni_filters(ckchi, &sni_filter, &fcount, &err);
+                                       if (errcode & ERR_CODE)
+                                               goto error;
+
                                        if (new_ckchs->multi)
-                                               errcode |= ckch_inst_new_load_multi_store(new_ckchs->path, new_ckchs, ckchi->bind_conf, ckchi->ssl_conf, NULL, 0, &new_inst, &err);
+                                               errcode |= ckch_inst_new_load_multi_store(new_ckchs->path, new_ckchs, ckchi->bind_conf, ckchi->ssl_conf, sni_filter, fcount, &new_inst, &err);
                                        else
-                                               errcode |= ckch_inst_new_load_store(new_ckchs->path, new_ckchs, ckchi->bind_conf, ckchi->ssl_conf, NULL, 0, &new_inst, &err);
+                                               errcode |= ckch_inst_new_load_store(new_ckchs->path, new_ckchs, ckchi->bind_conf, ckchi->ssl_conf, sni_filter, fcount, &new_inst, &err);
+
+                                       free_sni_filters(sni_filter, fcount);
+                                       sni_filter = NULL;
 
                                        if (errcode & ERR_CODE)
                                                goto error;
@@ -11103,7 +11182,6 @@ error:
        return cli_dynerr(appctx, err);
 }
 
-
 /*
  * Parsing function of `set ssl cert`, it updates or creates a temporary ckch.
  */
@@ -11266,14 +11344,6 @@ static int cli_parse_set_cert(char **args, char *payload, struct appctx *appctx,
 
        old_ckchs = appctx->ctx.ssl.old_ckchs;
 
-       /* TODO: handle filters */
-       if (old_ckchs->filters) {
-               memprintf(&err, "%sCertificates used in crt-list with filters are not supported!\n",
-                         err ? err : "");
-               errcode |= ERR_ALERT | ERR_FATAL;
-               goto end;
-       }
-
        /* duplicate the ckch store */
        new_ckchs = ckchs_dup(old_ckchs);
        if (!new_ckchs) {