Hi,

The attached patch adds the ssl_sni_check converter which returns true
if the sample input string matches a loaded certificate's CN/SAN.

This can be useful to check for example if a host header matches a
loaded certificate CN/SAN before doing a redirect:

frontent fe_main 
  bind 127.0.0.1:80
  bind 127.0.0.1:443 ssl crt /etc/haproxy/ssl/
  http-request redirect scheme https if !{ ssl_fc } { hdr(host),ssl_sni_check() 
}


This converter may be even more useful when certificates will be
added/removed at runtime.

++

-- 
Moemen MHEDHBI
>From 14ed628ab9badbb06c45bab324eb00f998de49af Mon Sep 17 00:00:00 2001
From: Moemen MHEDHBI <mmhed...@haproxy.com>
Date: Sun, 23 Dec 2018 20:50:04 +0100
Subject: [PATCH] MINOR: sample: add ssl_sni_check converter

This adds the ssl_sni_check converter. The converter returns
true if the sample input string matches a loaded certificate's CN/SAN.
Lookup can be done through certificates of a specified bind line (by
<name>) otherwise the search will include all bind lines of the current
proxy.
---
 doc/configuration.txt |  6 ++++++
 src/ssl_sock.c        | 43 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 49 insertions(+)

diff --git a/doc/configuration.txt b/doc/configuration.txt
index 6ca63d64a..0be043e73 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -13651,6 +13651,12 @@ sha1
   Converts a binary input sample to a SHA1 digest. The result is a binary
   sample with length of 20 bytes.
 
+ssl_sni_check(<name>)
+  Returns true if the sample input string matches a loaded certificate's CN/SAN.
+  Otherwise false is returned. When <name> is provided the lookup is done only
+  through the certificates of the  bind line named <name>, if not all bind 
+  lines of the current frontend will be searched.
+
 strcmp(<var>)
   Compares the contents of <var> with the input value of type string. Returns
   the result as a signed integer compatible with strcmp(3): 0 if both strings
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 282b85ddd..b24d78978 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -7276,6 +7276,41 @@ smp_fetch_ssl_c_verify(const struct arg *args, struct sample *smp, const char *k
 	return 1;
 }
 
+/* boolean, returns true if input string matches a loaded certificate's CN/SAN. */
+/* The lookup is done only for the bind named <name> if the param is prvided. */
+static int smp_conv_ssl_sni_check(const struct arg *args, struct sample *smp, void *private)
+{
+	struct proxy *px = smp->px;
+	struct listener *l;
+	struct ebmb_node *node = NULL;
+	char *wildp = NULL;
+	int i;
+
+	for (i = 0; i < trash.size && i < smp->data.u.str.data; i++) {
+		trash.area[i] = tolower(smp->data.u.str.area[i]);
+		if (!wildp && (trash.area[i] == '.'))
+			wildp = &trash.area[i];
+	}
+	trash.area[i] = 0;
+
+	list_for_each_entry(l, &px->conf.listeners, by_fe) {
+		if ( args->type == ARGT_STR && l->name && (strcmp(args->data.str.area, l->name) != 0))
+			continue;
+		/* lookup in full qualified names */
+		node = ebst_lookup(&l->bind_conf->sni_ctx, trash.area);
+		/* lookup in wildcards names */
+		if (!node && wildp)
+			node = ebst_lookup(&l->bind_conf->sni_w_ctx, wildp);
+		if (node != NULL)
+			break;
+	}
+
+	smp->data.type = SMP_T_BOOL;
+	smp->data.u.sint = !!node;
+	smp->flags = SMP_F_VOL_TEST;
+	return 1;
+}
+
 /* parse the "ca-file" bind keyword */
 static int ssl_bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
 {
@@ -9047,6 +9082,14 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
 
 INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
 
+/* Note: must not be declared <const> as its list will be overwritten */
+static struct sample_conv_kw_list sample_conv_kws = {ILH, {
+	{ "ssl_sni_check", smp_conv_ssl_sni_check, ARG1(0,STR), NULL, SMP_T_STR, SMP_T_BOOL },
+	{ /* END */ },
+}};
+
+INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
+
 /* Note: must not be declared <const> as its list will be overwritten.
  * Please take care of keeping this list alphabetically sorted.
  */
-- 
2.19.2

Reply via email to