summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2021-11-18 17:46:43 +0000
committerLaurent Bercot <ska@appnovation.com>2021-11-18 17:46:43 +0000
commit46e49260b35a2a39bbb92f44ceb598ab2db94d6a (patch)
treeeccdc2482d5c19c0d51d0d1d45f3070cdf9272ae
parent069e3184359c76f8bb4aa3e7c62a69d571b478ac (diff)
downloads6-networking-46e49260b35a2a39bbb92f44ceb598ab2db94d6a.tar.xz
Allow SNI wildcarding for *.example.com
Signed-off-by: Laurent Bercot <ska@appnovation.com>
-rw-r--r--doc/s6-tlsd-io.html11
-rw-r--r--src/sbearssl/sbearssl_sni_policy_vtable.c32
2 files changed, 38 insertions, 5 deletions
diff --git a/doc/s6-tlsd-io.html b/doc/s6-tlsd-io.html
index b2a4a1e..f21d487 100644
--- a/doc/s6-tlsd-io.html
+++ b/doc/s6-tlsd-io.html
@@ -129,6 +129,17 @@ entirely ignored.
</p>
<p>
+ You can wildcard the first level of a SNI domain: you can point
+to a valid certificate for <tt><em>foo</em>.example.com</tt> for all
+values of <em>foo</em> via a variable called <tt>CERTFILE:*.example.com</tt>
+(and have the corresponding <tt>KEYFILE:*.example.com</tt>). Only the
+first level can be wildcarded, and this does not work for top-level
+domains (you cannot hold a certificate for <tt>*.com</tt>). Note: if you are
+using a shell to handle your environment variables, be careful to
+properly quote them so that it does not attempt to expand the asterisks.
+</p>
+
+<p>
If you are using client certificates, <tt>s6-tlsd-io</tt>
also requires either one of the following variables to be set:
</p>
diff --git a/src/sbearssl/sbearssl_sni_policy_vtable.c b/src/sbearssl/sbearssl_sni_policy_vtable.c
index 0f3de6e..a1d878a 100644
--- a/src/sbearssl/sbearssl_sni_policy_vtable.c
+++ b/src/sbearssl/sbearssl_sni_policy_vtable.c
@@ -49,14 +49,36 @@ static int choose (br_ssl_server_policy_class const **pctx, br_ssl_server_contex
sbearssl_sni_policy_node *node ;
char const *servername = br_ssl_engine_get_server_name(&sc->eng) ;
- /* Get the node corresponding to the ServerName sent by the client. "" for no SNI. */
+ /*
+ Get the node corresponding to the ServerName sent by the client.
+ If servername is foo.bar.baz, try:
+ 1. foo.bar.baz
+ 2. *.bar.baz (don't do this for TLDs, we don't want *.com)
+ 3. empty string (i.e. default certificate)
+ If no SNI, only try the empty string.
+ */
{
- uint32_t n ;
- if (!avltree_search(&pol->map, servername, &n))
+ uint32_t n = avltree_totalsize(&pol->map) ;
+ if (servername)
{
- if (!servername[0]) return 0 ;
- if (!avltree_search(&pol->map, "", &n)) return 0 ;
+ if (!avltree_search(&pol->map, servername, &n))
+ {
+ char const *sub1 = strchr(servername, '.') ;
+ if (sub1 && sub1[1])
+ {
+ char const *sub2 = strchr(sub1 + 1, '.') ;
+ if (sub2 && sub2[1])
+ {
+ size_t len = strlen(sub1) ;
+ char tmp[len + 2] ;
+ tmp[0] = '*' ;
+ memcpy(tmp + 1, sub1, len + 1) ;
+ avltree_search(&pol->map, tmp, &n) ;
+ }
+ }
+ }
}
+ if (n == avltree_totalsize(&pol->map) && !avltree_search(&pol->map, "", &n)) return 0 ;
avltree_free(&pol->map) ;
node = genalloc_s(sbearssl_sni_policy_node, &pol->mapga) + n ;
}