MEDIUM: ssl: add bind-option "strict-sni"
This new option ensures that there is no possible fallback to a default
certificate if the client does not provide an SNI which is explicitly
handled by a certificate.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index c88592a..30647a9 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -7241,6 +7241,12 @@
appear in clear text, so that ACLs and HTTP processing will only have access
to deciphered contents.
+strict-sni
+ This setting is only available when support for OpenSSL was built in. The
+ SSL/TLS negotiation is allow only if the client provided an SNI which match
+ a certificate. The default certificate is not used.
+ See the "crt" option for more information.
+
tfo
Is an optional keyword which is supported only on Linux kernels >= 3.6. It
enables TCP Fast Open on the listening socket, which means that clients which
diff --git a/include/types/listener.h b/include/types/listener.h
index d5d91f4..2f584e3 100644
--- a/include/types/listener.h
+++ b/include/types/listener.h
@@ -127,6 +127,7 @@
SSL_CTX *default_ctx; /* SSL context of first/default certificate */
char *npn_str; /* NPN protocol string */
int npn_len; /* NPN protocol string length */
+ int strict_sni; /* refuse negotiation if sni doesn't match a certificate */
struct eb_root sni_ctx; /* sni_ctx tree of all known certs full-names sorted by name */
struct eb_root sni_w_ctx; /* sni_ctx tree of all known certs wildcards sorted by name */
#endif
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 87eff2b..f814276 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -178,8 +178,12 @@
(void)al; /* shut gcc stupid warning */
servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
- if (!servername)
- return SSL_TLSEXT_ERR_NOACK;
+ if (!servername) {
+ if (s->strict_sni)
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ else
+ return SSL_TLSEXT_ERR_NOACK;
+ }
for (i = 0; i < trash.size; i++) {
if (!servername[i])
@@ -193,13 +197,20 @@
/* lookup in full qualified names */
node = ebst_lookup(&s->sni_ctx, trash.str);
if (!node) {
- if (!wildp)
- return SSL_TLSEXT_ERR_ALERT_WARNING;
-
+ if (!wildp) {
+ if (s->strict_sni)
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ else
+ return SSL_TLSEXT_ERR_ALERT_WARNING;
+ }
/* lookup in full wildcards names */
node = ebst_lookup(&s->sni_w_ctx, wildp);
- if (!node)
- return SSL_TLSEXT_ERR_ALERT_WARNING;
+ if (!node) {
+ if (s->strict_sni)
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ else
+ return SSL_TLSEXT_ERR_ALERT_WARNING;
+ }
}
/* switch ctx */
@@ -2569,6 +2580,13 @@
return 0;
}
+/* parse the "strict-sni" bind keyword */
+static int bind_parse_strict_sni(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+{
+ conf->strict_sni = 1;
+ return 0;
+}
+
/* parse the "verify" bind keyword */
static int bind_parse_verify(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
{
@@ -2888,6 +2906,7 @@
{ "no-tlsv12", bind_parse_no_tlsv12, 0 }, /* disable TLSv12 */
{ "no-tls-tickets", bind_parse_no_tls_tickets, 0 }, /* disable session resumption tickets */
{ "ssl", bind_parse_ssl, 0 }, /* enable SSL processing */
+ { "strict-sni", bind_parse_strict_sni, 0 }, /* refuse negotiation if sni doesn't match a certificate */
{ "verify", bind_parse_verify, 1 }, /* set SSL verify method */
{ "npn", bind_parse_npn, 1 }, /* set NPN supported protocols */
{ NULL, NULL, 0 },