diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2021-11-18 17:46:43 +0000 |
---|---|---|
committer | Laurent Bercot <ska@appnovation.com> | 2021-11-18 17:46:43 +0000 |
commit | 46e49260b35a2a39bbb92f44ceb598ab2db94d6a (patch) | |
tree | eccdc2482d5c19c0d51d0d1d45f3070cdf9272ae | |
parent | 069e3184359c76f8bb4aa3e7c62a69d571b478ac (diff) | |
download | s6-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.html | 11 | ||||
-rw-r--r-- | src/sbearssl/sbearssl_sni_policy_vtable.c | 32 |
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 ; } |