From 656233715e1e9810c43f05b12e13f8829ea4cad2 Mon Sep 17 00:00:00 2001 From: Emmanuel Hocdet Date: Thu, 24 Jan 2013 17:17:15 +0100 Subject: [PATCH] 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. --- doc/configuration.txt | 6 ++++++ include/types/listener.h | 1 + src/ssl_sock.c | 33 ++++++++++++++++++++++++++------- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/doc/configuration.txt b/doc/configuration.txt index c88592a72..30647a982 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -7241,6 +7241,12 @@ ssl 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 d5d91f43f..2f584e3f2 100644 --- a/include/types/listener.h +++ b/include/types/listener.h @@ -127,6 +127,7 @@ struct bind_conf { 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 87eff2b7c..f81427606 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -178,8 +178,12 @@ static int ssl_sock_switchctx_cbk(SSL *ssl, int *al, struct bind_conf *s) (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 @@ static int ssl_sock_switchctx_cbk(SSL *ssl, int *al, struct bind_conf *s) /* 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 @@ static int bind_parse_ssl(char **args, int cur_arg, struct proxy *px, struct bin 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 @@ static struct bind_kw_list bind_kws = { "SSL", { }, { { "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 },