diff --git a/doc/configuration.txt b/doc/configuration.txt index c21bae921..8083edb88 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -18007,6 +18007,21 @@ no-check-ssl It may also be used as "default-server" setting to reset any previous "default-server" "check-ssl" setting. +no-renegotiate + May be used in the following contexts: tcp, http, log + + This setting is only available when support for OpenSSL was built in. It + disables the renegotiation mechanisms, be it the legacy unsafe one or the + more recent "secure renegotation" one (RFC 5746 TLS Renegotiation Indication + Extension) for the given SSL backend. This option is also available on global + statement "ssl-default-server-options". + Renegotiation is not posible anymore in TLS 1.3. + If neither "renegotiate" nor "no-renegotiate" is specified, the SSL library's + default behavior is kept. + Note that for instance OpenSSL library enables secure renegotiation by + default while BoringSSL and AWS-LC disable it. + See also "renegotiate". + no-send-proxy May be used in the following contexts: tcp, http @@ -18335,6 +18350,21 @@ redir Example : server srv1 192.168.1.1:80 redir http://image1.mydomain.com check +renegotiate + May be used in the following contexts: tcp, http, log + + This option enables the secure renegotiation mechanism (RFC 5746 TLS + Renegotiation Indication Extension) for a given SSL backend. It does not mean + that renegotiation requests will be sent by the SSL client, it only allows + backends to renegotiate when servers request it. It still requires that the + underlying SSL library actually supports renegotiation. + This option is also available on global statement "ssl-default-server-options". + Renegotiation is not posible anymore in TLS 1.3. + If neither "renegotiate" nor "no-renegotiate" is specified, the SSL library's + default behavior is kept. + Note that for instance OpenSSL library enables secure renegotiation by + default while BoringSSL and AWS-LC disable it. + rise May be used in the following contexts: tcp, http, log diff --git a/include/haproxy/server-t.h b/include/haproxy/server-t.h index dc238ec25..ed39d2e0a 100644 --- a/include/haproxy/server-t.h +++ b/include/haproxy/server-t.h @@ -304,6 +304,13 @@ struct srv_pp_tlv_list { unsigned char type; }; +/* Renegotiate mode */ +enum renegotiate_mode { + SSL_RENEGOTIATE_DFLT = 0, /* Use the SSL library's default behavior */ + SSL_RENEGOTIATE_OFF, /* Disable secure renegotiation */ + SSL_RENEGOTIATE_ON /* Enable secure renegotiation */ +}; + struct proxy; struct server { /* mostly config or admin stuff, doesn't change often */ @@ -477,6 +484,7 @@ struct server { int npn_len; /* NPN protocol string length */ char *alpn_str; /* ALPN protocol string */ int alpn_len; /* ALPN protocol string length */ + int renegotiate; /* Renegotiate mode (SSL_RENEGOTIATE_ flag) */ } ssl_ctx; struct resolv_srvrq *srvrq; /* Pointer representing the DNS SRV requeest, if any */ struct list srv_rec_item; /* to attach server to a srv record item */ diff --git a/include/haproxy/ssl_sock-t.h b/include/haproxy/ssl_sock-t.h index 44055492b..75d7eee19 100644 --- a/include/haproxy/ssl_sock-t.h +++ b/include/haproxy/ssl_sock-t.h @@ -320,6 +320,8 @@ struct global_ssl { #ifdef HAVE_ACME int acme_scheduler; #endif + + int renegotiate; /* Renegotiate mode (SSL_RENEGOTIATE_ flag) */ }; /* The order here matters for picking a default context, diff --git a/src/cfgparse-ssl.c b/src/cfgparse-ssl.c index 44171b67d..deebbf503 100644 --- a/src/cfgparse-ssl.c +++ b/src/cfgparse-ssl.c @@ -1630,6 +1630,19 @@ static int srv_parse_check_sni(char **args, int *cur_arg, struct proxy *px, stru } +/* parse the "renegotiate" server keyword */ +static int srv_parse_renegotiate(char **args, int *cur_arg, struct proxy *px, + struct server *newsrv, char **err) +{ + + if (strncmp(*args, "no-", 3) == 0) + newsrv->ssl_ctx.renegotiate = SSL_RENEGOTIATE_OFF; + else + newsrv->ssl_ctx.renegotiate = SSL_RENEGOTIATE_ON; + + return 0; +} + /* common function to init ssl_ctx */ static int ssl_sock_init_srv(struct server *s) { @@ -1675,6 +1688,9 @@ static int ssl_sock_init_srv(struct server *s) } #endif + if (global_ssl.renegotiate && !s->ssl_ctx.renegotiate) + s->ssl_ctx.renegotiate = global_ssl.renegotiate; + return 0; } @@ -2079,6 +2095,9 @@ static int ssl_parse_default_server_options(char **args, int section_type, struc return -1; } } + else if (strcmp(args[i], "renegotiate") == 0 || strcmp(args[i], "no-renegotiate") == 0) { + global_ssl.renegotiate = (*args[i] == 'n') ? SSL_RENEGOTIATE_OFF : SSL_RENEGOTIATE_ON; + } else if (parse_tls_method_options(args[i], &global_ssl.connect_default_sslmethods, err)) { memprintf(err, "unknown option '%s' on global statement '%s'.", args[i], args[0]); return -1; @@ -2505,6 +2524,7 @@ static struct srv_kw_list srv_kws = { "SSL", { }, { { "force-tlsv12", srv_parse_tls_method_options, 0, 1, 1 }, /* force TLSv12 */ { "force-tlsv13", srv_parse_tls_method_options, 0, 1, 1 }, /* force TLSv13 */ { "no-check-ssl", srv_parse_no_check_ssl, 0, 1, 0 }, /* disable SSL for health checks */ + { "no-renegotiate", srv_parse_renegotiate, 0, 1, 1 }, /* Disable renegotiation */ { "no-send-proxy-v2-ssl", srv_parse_no_send_proxy_ssl, 0, 1, 0 }, /* do not send PROXY protocol header v2 with SSL info */ { "no-send-proxy-v2-ssl-cn", srv_parse_no_send_proxy_cn, 0, 1, 0 }, /* do not send PROXY protocol header v2 with CN */ { "no-ssl", srv_parse_no_ssl, 0, 1, 0 }, /* disable SSL processing */ @@ -2516,6 +2536,7 @@ static struct srv_kw_list srv_kws = { "SSL", { }, { { "no-tlsv13", srv_parse_tls_method_options, 0, 0, 1 }, /* disable TLSv13 */ { "no-tls-tickets", srv_parse_no_tls_tickets, 0, 1, 1 }, /* disable session resumption tickets */ { "npn", srv_parse_npn, 1, 1, 1 }, /* Set NPN supported protocols */ + { "renegotiate", srv_parse_renegotiate, 0, 1, 1 }, /* Allow secure renegotiation */ { "send-proxy-v2-ssl", srv_parse_send_proxy_ssl, 0, 1, 1 }, /* send PROXY protocol header v2 with SSL info */ { "send-proxy-v2-ssl-cn", srv_parse_send_proxy_cn, 0, 1, 1 }, /* send PROXY protocol header v2 with CN */ { "sigalgs", srv_parse_sigalgs, 1, 1, 1 }, /* signature algorithms */ diff --git a/src/server.c b/src/server.c index fc886c917..50ff2a32c 100644 --- a/src/server.c +++ b/src/server.c @@ -2718,7 +2718,7 @@ static void srv_ssl_settings_cpy(struct server *srv, const struct server *src) srv->ssl_ctx.client_crt = strdup(src->ssl_ctx.client_crt); srv->ssl_ctx.verify = src->ssl_ctx.verify; - + srv->ssl_ctx.renegotiate = src->ssl_ctx.renegotiate; if (src->ssl_ctx.verify_host != NULL) srv->ssl_ctx.verify_host = strdup(src->ssl_ctx.verify_host); diff --git a/src/ssl_sock.c b/src/ssl_sock.c index c897bbf18..b4983dba3 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -148,6 +148,7 @@ struct global_ssl global_ssl = { #ifdef HAVE_ACME .acme_scheduler = 1, #endif + .renegotiate = SSL_RENEGOTIATE_DFLT, }; @@ -4532,6 +4533,12 @@ static int ssl_sock_prepare_srv_ssl_ctx(const struct server *srv, SSL_CTX *ctx) if (srv->ssl_ctx.options & SRV_SSL_O_NO_TLS_TICKETS) options |= SSL_OP_NO_TICKET; + + if (srv->ssl_ctx.renegotiate == SSL_RENEGOTIATE_OFF) + options |= SSL_OP_NO_RENEGOTIATION; + else if (srv->ssl_ctx.renegotiate == SSL_RENEGOTIATE_ON) + options &= ~SSL_OP_NO_RENEGOTIATION; + SSL_CTX_set_options(ctx, options); #ifdef SSL_MODE_ASYNC @@ -5099,6 +5106,12 @@ static int ssl_sock_init(struct connection *conn, void **xprt_ctx) goto err; SSL_set_connect_state(ctx->ssl); + +#if defined(OPENSSL_IS_AWSLC) || defined(OPENSSL_IS_BORINGSSL) + if (srv->ssl_ctx.renegotiate == SSL_RENEGOTIATE_ON) + SSL_set_renegotiate_mode(ctx->ssl, ssl_renegotiate_freely); +#endif + HA_RWLOCK_RDLOCK(SSL_SERVER_LOCK, &srv->ssl_ctx.lock); if (srv->ssl_ctx.reused_sess[tid].ptr) { /* let's recreate a session from (ptr,size) and assign