MINOR: ssl: Add "renegotiate" server option

This "renegotiate" option can be set on SSL backends to allow secure
renegotiation. It is mostly useful with SSL libraries that disable
secure regotiation by default (such as BoringSSL or AWS-LC).
The "no-renegotiate" one can be used the other way around, to disable
secure renegotation that could be allowed by default.
Those two options can be set via "ssl-default-server-options" as well.
This commit is contained in:
Remi Tricot-Le Breton 2025-05-28 11:24:38 +02:00 committed by William Lallemand
parent 6b74633069
commit e04aba2fa3
6 changed files with 75 additions and 1 deletions

View File

@ -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 <prefix>
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 <count>
May be used in the following contexts: tcp, http, log

View File

@ -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 */

View File

@ -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,

View File

@ -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 */

View File

@ -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);

View File

@ -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