MINOR: ssl: support strict-sni in ssl-default-bind-options
Several users already reported that it would be nice to support strict-sni in ssl-default-bind-options. However, in order to support it, we also need an option to disable it. This patch moves the setting of the option from the strict_sni field to a flag in the ssl_options field so that it can be inherited from the default bind options, and adds a new "no-strict-sni" directive to allow to disable it on a specific "bind" line. The test file "del_ssl_crt-list.vtc" which already tests both options was updated to make use of the default option and the no- variant to confirm everything continues to work.
This commit is contained in:
parent
7244f16ac4
commit
3494775a1f
@ -16794,6 +16794,13 @@ no-sslv3
|
|||||||
global statement "ssl-default-bind-options". Use "ssl-min-ver" and
|
global statement "ssl-default-bind-options". Use "ssl-min-ver" and
|
||||||
"ssl-max-ver" instead.
|
"ssl-max-ver" instead.
|
||||||
|
|
||||||
|
no-strict-sni
|
||||||
|
This setting is only available when support for OpenSSL was built in. It
|
||||||
|
disables strict-sni enforcement from a previous "strict-sni" directive. It
|
||||||
|
may be needed in order to selectively disable strict-sni usage on a "bind"
|
||||||
|
line when it was already globally enforced via "ssl-default-bind-options".
|
||||||
|
See also the "strict-sni" bind option.
|
||||||
|
|
||||||
no-tls-tickets
|
no-tls-tickets
|
||||||
This setting is only available when support for OpenSSL was built in. It
|
This setting is only available when support for OpenSSL was built in. It
|
||||||
disables the stateless session resumption (RFC 5077 TLS Ticket
|
disables the stateless session resumption (RFC 5077 TLS Ticket
|
||||||
@ -17007,9 +17014,10 @@ strict-sni
|
|||||||
SSL/TLS negotiation is allowed only if the client provided an SNI that matches
|
SSL/TLS negotiation is allowed only if the client provided an SNI that matches
|
||||||
a certificate. The default certificate is not used. This option also allows
|
a certificate. The default certificate is not used. This option also allows
|
||||||
starting without any certificate on a bind line, so an empty directory could
|
starting without any certificate on a bind line, so an empty directory could
|
||||||
be used and filled later from the stats socket.
|
be used and filled later from the stats socket. This option is also available
|
||||||
See the "crt" option for more information. See "add ssl crt-list" command in
|
on global statement "ssl-default-bind-options", and may be selectively
|
||||||
the management guide.
|
disabled on a "bind" line using "no-strict-sni". See the "crt" option for
|
||||||
|
more information. See "add ssl crt-list" command in the management guide.
|
||||||
|
|
||||||
tcp-ut <delay>
|
tcp-ut <delay>
|
||||||
Sets the TCP User Timeout for all incoming connections instantiated from this
|
Sets the TCP User Timeout for all incoming connections instantiated from this
|
||||||
|
@ -121,6 +121,7 @@ enum li_status {
|
|||||||
#define BC_SSL_O_NONE 0x0000
|
#define BC_SSL_O_NONE 0x0000
|
||||||
#define BC_SSL_O_NO_TLS_TICKETS 0x0100 /* disable session resumption tickets */
|
#define BC_SSL_O_NO_TLS_TICKETS 0x0100 /* disable session resumption tickets */
|
||||||
#define BC_SSL_O_PREF_CLIE_CIPH 0x0200 /* prefer client ciphers */
|
#define BC_SSL_O_PREF_CLIE_CIPH 0x0200 /* prefer client ciphers */
|
||||||
|
#define BC_SSL_O_STRICT_SNI 0x0400 /* refuse negotiation if sni doesn't match a certificate */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct tls_version_filter {
|
struct tls_version_filter {
|
||||||
@ -169,7 +170,6 @@ struct bind_conf {
|
|||||||
unsigned long long ca_ignerr_bitfield[IGNERR_BF_SIZE]; /* ignored verify errors in handshake if depth > 0 */
|
unsigned long long ca_ignerr_bitfield[IGNERR_BF_SIZE]; /* ignored verify errors in handshake if depth > 0 */
|
||||||
unsigned long long crt_ignerr_bitfield[IGNERR_BF_SIZE]; /* ignored verify errors in handshake if depth == 0 */
|
unsigned long long crt_ignerr_bitfield[IGNERR_BF_SIZE]; /* ignored verify errors in handshake if depth == 0 */
|
||||||
void *initial_ctx; /* SSL context for initial negotiation */
|
void *initial_ctx; /* SSL context for initial negotiation */
|
||||||
int strict_sni; /* refuse negotiation if sni doesn't match a certificate */
|
|
||||||
int ssl_options; /* ssl options */
|
int ssl_options; /* ssl options */
|
||||||
struct eb_root sni_ctx; /* sni_ctx tree of all known certs full-names sorted by name */
|
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 */
|
struct eb_root sni_w_ctx; /* sni_ctx tree of all known certs wildcards sorted by name */
|
||||||
|
@ -26,6 +26,7 @@ haproxy h1 -conf {
|
|||||||
tune.ssl.capture-buffer-size 1
|
tune.ssl.capture-buffer-size 1
|
||||||
crt-base ${testdir}
|
crt-base ${testdir}
|
||||||
stats socket "${tmpdir}/h1/stats" level admin
|
stats socket "${tmpdir}/h1/stats" level admin
|
||||||
|
ssl-default-bind-options strict-sni
|
||||||
|
|
||||||
defaults
|
defaults
|
||||||
mode http
|
mode http
|
||||||
@ -47,13 +48,14 @@ haproxy h1 -conf {
|
|||||||
server s3 "${tmpdir}/first-ssl.sock" ssl verify none sni str(record2.bug940.domain.tld)
|
server s3 "${tmpdir}/first-ssl.sock" ssl verify none sni str(record2.bug940.domain.tld)
|
||||||
|
|
||||||
listen first-ssl-fe
|
listen first-ssl-fe
|
||||||
|
# note: strict-sni is enforced from ssl-default-bind-options above
|
||||||
mode http
|
mode http
|
||||||
bind "${tmpdir}/first-ssl.sock" ssl strict-sni crt-list ${testdir}/simple.crt-list
|
bind "${tmpdir}/first-ssl.sock" ssl crt-list ${testdir}/simple.crt-list
|
||||||
server s1 ${s1_addr}:${s1_port}
|
server s1 ${s1_addr}:${s1_port}
|
||||||
|
|
||||||
listen second-ssl-fe
|
listen second-ssl-fe
|
||||||
mode http
|
mode http
|
||||||
bind "${tmpdir}/second-ssl.sock" ssl crt-list ${testdir}/localhost.crt-list
|
bind "${tmpdir}/second-ssl.sock" ssl no-strict-sni crt-list ${testdir}/localhost.crt-list
|
||||||
server s1 ${s1_addr}:${s1_port}
|
server s1 ${s1_addr}:${s1_port}
|
||||||
} -start
|
} -start
|
||||||
|
|
||||||
|
@ -1307,10 +1307,13 @@ static int bind_parse_generate_certs(char **args, int cur_arg, struct proxy *px,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parse the "strict-sni" bind keyword */
|
/* parse the "strict-sni" and "no-strict-sni" bind keywords */
|
||||||
static int bind_parse_strict_sni(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
|
static int bind_parse_strict_sni(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
|
||||||
{
|
{
|
||||||
conf->strict_sni = 1;
|
if (strncmp(args[cur_arg], "no-", 3) != 0)
|
||||||
|
conf->ssl_options |= BC_SSL_O_STRICT_SNI;
|
||||||
|
else
|
||||||
|
conf->ssl_options &= ~BC_SSL_O_STRICT_SNI;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2029,6 +2032,10 @@ static int ssl_parse_default_bind_options(char **args, int section_type, struct
|
|||||||
global_ssl.listen_default_ssloptions |= BC_SSL_O_NO_TLS_TICKETS;
|
global_ssl.listen_default_ssloptions |= BC_SSL_O_NO_TLS_TICKETS;
|
||||||
else if (strcmp(args[i], "prefer-client-ciphers") == 0)
|
else if (strcmp(args[i], "prefer-client-ciphers") == 0)
|
||||||
global_ssl.listen_default_ssloptions |= BC_SSL_O_PREF_CLIE_CIPH;
|
global_ssl.listen_default_ssloptions |= BC_SSL_O_PREF_CLIE_CIPH;
|
||||||
|
else if (strcmp(args[i], "strict-sni") == 0)
|
||||||
|
global_ssl.listen_default_ssloptions |= BC_SSL_O_STRICT_SNI;
|
||||||
|
else if (strcmp(args[i], "no-strict-sni") == 0)
|
||||||
|
global_ssl.listen_default_ssloptions &= ~BC_SSL_O_STRICT_SNI;
|
||||||
else if (strcmp(args[i], "ssl-min-ver") == 0 || strcmp(args[i], "ssl-max-ver") == 0) {
|
else if (strcmp(args[i], "ssl-min-ver") == 0 || strcmp(args[i], "ssl-max-ver") == 0) {
|
||||||
if (!parse_tls_method_minmax(args, i, &global_ssl.listen_default_sslmethods, err))
|
if (!parse_tls_method_minmax(args, i, &global_ssl.listen_default_sslmethods, err))
|
||||||
i++;
|
i++;
|
||||||
@ -2446,6 +2453,7 @@ static struct bind_kw_list bind_kws = { "SSL", { }, {
|
|||||||
{ "no-alpn", bind_parse_no_alpn, 0 }, /* disable sending ALPN */
|
{ "no-alpn", bind_parse_no_alpn, 0 }, /* disable sending ALPN */
|
||||||
{ "no-ca-names", bind_parse_no_ca_names, 0 }, /* do not send ca names to clients (ca_file related) */
|
{ "no-ca-names", bind_parse_no_ca_names, 0 }, /* do not send ca names to clients (ca_file related) */
|
||||||
{ "no-sslv3", bind_parse_tls_method_options, 0 }, /* disable SSLv3 */
|
{ "no-sslv3", bind_parse_tls_method_options, 0 }, /* disable SSLv3 */
|
||||||
|
{ "no-strict-sni", bind_parse_strict_sni, 0 }, /* do not refuse negotiation if sni doesn't match a certificate */
|
||||||
{ "no-tlsv10", bind_parse_tls_method_options, 0 }, /* disable TLSv10 */
|
{ "no-tlsv10", bind_parse_tls_method_options, 0 }, /* disable TLSv10 */
|
||||||
{ "no-tlsv11", bind_parse_tls_method_options, 0 }, /* disable TLSv11 */
|
{ "no-tlsv11", bind_parse_tls_method_options, 0 }, /* disable TLSv11 */
|
||||||
{ "no-tlsv12", bind_parse_tls_method_options, 0 }, /* disable TLSv12 */
|
{ "no-tlsv12", bind_parse_tls_method_options, 0 }, /* disable TLSv12 */
|
||||||
|
@ -274,7 +274,7 @@ int ssl_sock_switchctx_cbk(SSL *ssl, int *al, void *arg)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* no servername field is not compatible with strict-sni */
|
/* no servername field is not compatible with strict-sni */
|
||||||
if (s->strict_sni) {
|
if (s->ssl_options & BC_SSL_O_STRICT_SNI) {
|
||||||
TRACE_ERROR("No server_name provided and 'strict-sni' enabled", SSL_EV_CONN_SWITCHCTX_CB|SSL_EV_CONN_ERR, conn);
|
TRACE_ERROR("No server_name provided and 'strict-sni' enabled", SSL_EV_CONN_SWITCHCTX_CB|SSL_EV_CONN_ERR, conn);
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
@ -435,7 +435,7 @@ sni_lookup:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!s->strict_sni && !default_lookup) {
|
if (!(s->ssl_options & BC_SSL_O_STRICT_SNI) && !default_lookup) {
|
||||||
/* we didn't find a SNI, and we didn't look for a default
|
/* we didn't find a SNI, and we didn't look for a default
|
||||||
* look again to find a matching default cert */
|
* look again to find a matching default cert */
|
||||||
servername = "";
|
servername = "";
|
||||||
@ -541,7 +541,7 @@ int ssl_sock_switchctx_cbk(SSL *ssl, int *al, void *priv)
|
|||||||
return SSL_TLSEXT_ERR_OK;
|
return SSL_TLSEXT_ERR_OK;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (s->strict_sni) {
|
if (s->ssl_options & BC_SSL_O_STRICT_SNI) {
|
||||||
TRACE_ERROR("No server_name provided and 'strict-sni' enabled", SSL_EV_CONN_SWITCHCTX_CB|SSL_EV_CONN_ERR);
|
TRACE_ERROR("No server_name provided and 'strict-sni' enabled", SSL_EV_CONN_SWITCHCTX_CB|SSL_EV_CONN_ERR);
|
||||||
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
return SSL_TLSEXT_ERR_ALERT_FATAL;
|
||||||
}
|
}
|
||||||
@ -598,7 +598,7 @@ sni_lookup:
|
|||||||
#endif
|
#endif
|
||||||
HA_RWLOCK_RDUNLOCK(SNI_LOCK, &s->sni_lock);
|
HA_RWLOCK_RDUNLOCK(SNI_LOCK, &s->sni_lock);
|
||||||
|
|
||||||
if (!s->strict_sni && !default_lookup) {
|
if (!(s->ssl_options & BC_SSL_O_STRICT_SNI) && !default_lookup) {
|
||||||
/* we didn't find a SNI, and we didn't look for a default
|
/* we didn't find a SNI, and we didn't look for a default
|
||||||
* look again to find a matching default cert */
|
* look again to find a matching default cert */
|
||||||
servername = "";
|
servername = "";
|
||||||
@ -644,7 +644,7 @@ int ssl_sock_switchctx_wolfSSL_cbk(WOLFSSL* ssl, void* arg)
|
|||||||
|
|
||||||
servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
|
servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
|
||||||
if (!servername) {
|
if (!servername) {
|
||||||
if (s->strict_sni)
|
if (s->ssl_options & BC_SSL_O_STRICT_SNI)
|
||||||
goto abort;
|
goto abort;
|
||||||
|
|
||||||
/* without servername extension, look for the defaults which is
|
/* without servername extension, look for the defaults which is
|
||||||
@ -720,7 +720,7 @@ sni_lookup:
|
|||||||
}
|
}
|
||||||
|
|
||||||
HA_RWLOCK_RDUNLOCK(SNI_LOCK, &s->sni_lock);
|
HA_RWLOCK_RDUNLOCK(SNI_LOCK, &s->sni_lock);
|
||||||
if (!s->strict_sni && !default_lookup) {
|
if (!(s->ssl_options & BC_SSL_O_STRICT_SNI) && !default_lookup) {
|
||||||
/* we didn't find a SNI, and we didn't look for a default
|
/* we didn't find a SNI, and we didn't look for a default
|
||||||
* look again to find a matching default cert */
|
* look again to find a matching default cert */
|
||||||
servername = "";
|
servername = "";
|
||||||
|
@ -1577,7 +1577,7 @@ static int cli_parse_del_crtlist(char **args, char *payload, struct appctx *appc
|
|||||||
/* Iterate over all the instances in order to see if any of them is a
|
/* Iterate over all the instances in order to see if any of them is a
|
||||||
* default instance. If this is the case, the entry won't be suppressed. */
|
* default instance. If this is the case, the entry won't be suppressed. */
|
||||||
list_for_each_entry_safe(inst, inst_s, &entry->ckch_inst, by_crtlist_entry) {
|
list_for_each_entry_safe(inst, inst_s, &entry->ckch_inst, by_crtlist_entry) {
|
||||||
if (inst->is_default && !inst->bind_conf->strict_sni) {
|
if (inst->is_default && !(inst->bind_conf->ssl_options & BC_SSL_O_STRICT_SNI)) {
|
||||||
if (!error_message_dumped) {
|
if (!error_message_dumped) {
|
||||||
memprintf(&err, "certificate '%s' cannot be deleted, it is used as default certificate by the following frontends:\n", cert_path);
|
memprintf(&err, "certificate '%s' cannot be deleted, it is used as default certificate by the following frontends:\n", cert_path);
|
||||||
error_message_dumped = 1;
|
error_message_dumped = 1;
|
||||||
|
@ -4776,7 +4776,7 @@ int ssl_sock_prepare_bind_conf(struct bind_conf *bind_conf)
|
|||||||
|
|
||||||
/* check if we have certificates */
|
/* check if we have certificates */
|
||||||
if (eb_is_empty(&bind_conf->sni_ctx) && eb_is_empty(&bind_conf->sni_w_ctx)) {
|
if (eb_is_empty(&bind_conf->sni_ctx) && eb_is_empty(&bind_conf->sni_w_ctx)) {
|
||||||
if (bind_conf->strict_sni && !(bind_conf->options & BC_O_GENERATE_CERTS)) {
|
if ((bind_conf->ssl_options & BC_SSL_O_STRICT_SNI) && !(bind_conf->options & BC_O_GENERATE_CERTS)) {
|
||||||
ha_warning("Proxy '%s': no SSL certificate specified for bind '%s' at [%s:%d], ssl connections will fail (use 'crt').\n",
|
ha_warning("Proxy '%s': no SSL certificate specified for bind '%s' at [%s:%d], ssl connections will fail (use 'crt').\n",
|
||||||
px->id, bind_conf->arg, bind_conf->file, bind_conf->line);
|
px->id, bind_conf->arg, bind_conf->file, bind_conf->line);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user