BUG/MEDIUM: ssl: crt-list negative filters don't work
authorWilliam Lallemand <wlallemand@haproxy.com>
Mon, 17 Aug 2020 12:31:19 +0000 (14:31 +0200)
committerWilliam Lallemand <wlallemand@haproxy.org>
Wed, 30 Sep 2020 06:39:35 +0000 (08:39 +0200)
The negative filters which are supposed to exclude a SNI from a
wildcard, never worked. Indeed the negative filters were skipped in the
code.

To fix the issue, this patch looks for negative filters that are on the
same line as a the wildcard that just matched.

This patch should fix issue #818. It must be backported in 2.2.  The
problem also exists in versions > 1.8 but the infrastructure required to
fix this was only introduced in 2.1.  In older versions we should
probably change the documentation to state that negative filters are
useless.

(cherry picked from commit 30f9e095f5ed695348f3041ef183f25739c2ace1)
Signed-off-by: William Lallemand <wlallemand@haproxy.org>

src/ssl_sock.c

index 5c1f054..8bc3518 100644 (file)
@@ -2362,13 +2362,31 @@ static int ssl_sock_switchctx_cbk(SSL *ssl, int *al, void *arg)
        for (i = 0; i < 2; i++) {
                if (i == 0)     /* lookup in full qualified names */
                        node = ebst_lookup(&s->sni_ctx, trash.area);
-               else if (i == 1 && wildp) /* lookup in wildcards names */
+               else if (i == 1 && wildp)  /* lookup in wildcards names */
                        node = ebst_lookup(&s->sni_w_ctx, wildp);
                else
                        break;
+
                for (n = node; n; n = ebmb_next_dup(n)) {
+
                        /* lookup a not neg filter */
                        if (!container_of(n, struct sni_ctx, name)->neg) {
+                               struct sni_ctx *sni, *sni_tmp;
+                               int skip = 0;
+
+                               if (i == 1 && wildp) { /* wildcard */
+                                       /* If this is a wildcard, look for an exclusion on the same crt-list line */
+                                       sni = container_of(n, struct sni_ctx, name);
+                                       list_for_each_entry(sni_tmp, &sni->ckch_inst->sni_ctx, by_ckch_inst) {
+                                               if (sni_tmp->neg && (!strcmp((const char *)sni_tmp->name.key, trash.area))) {
+                                                       skip = 1;
+                                                       break;
+                                               }
+                                       }
+                                       if (skip)
+                                               continue;
+                               }
+
                                switch(container_of(n, struct sni_ctx, name)->kinfo.sig) {
                                case TLSEXT_signature_ecdsa:
                                        if (!node_ecdsa)