MINOR: ssl: allow to change the server signature algorithm
This patch introduces the "sigalgs" keyword for the bind line, which
allows to configure the list of server signature algorithms negociated
during the handshake. Also available as "ssl-default-bind-sigalgs" in
the default section.
This patch was originally written by Bruno Henc.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 9d4aa3c24..0111b61 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -1097,6 +1097,7 @@
- ssl-default-bind-ciphersuites
- ssl-default-bind-curves
- ssl-default-bind-options
+ - ssl-default-bind-sigalgs
- ssl-default-server-ciphers
- ssl-default-server-ciphersuites
- ssl-default-server-options
@@ -2183,6 +2184,22 @@
global
ssl-default-bind-options ssl-min-ver TLSv1.0 no-tls-tickets
+ssl-default-bind-sigalgs <sigalgs>
+ This setting is only available when support for OpenSSL was built in. It
+ sets the default string describing the list of signature algorithms that
+ are negotiated during the TLSv1.2 and TLSv1.3 handshake for all "bind" lines
+ which do not explicitly define theirs. The format of the string is a
+ colon-delimited list of signature algorithms. Each signature algorithm can
+ use one of two forms: TLS1.3 signature scheme names ("rsa_pss_rsae_sha256")
+ or the public key algorithm + digest form ("ECDSA+SHA256"). A list
+ can contain both forms. For more information on the format,
+ see SSL_CTX_set1_sigalgs(3). A list of signature algorithms is also
+ available in RFC8446 section 4.2.3 and in OpenSSL in the ssl/t1_lib.c file.
+ This setting is not applicable to TLSv1.1 and earlier versions of the
+ protocol as the signature algorithms aren't separately negotiated in these
+ versions. It is not recommended to change this setting unless compatibility
+ with a middlebox is required.
+
ssl-default-server-ciphers <ciphers>
This setting is only available when support for OpenSSL was built in. It
sets the default string describing the list of cipher algorithms that are
@@ -15330,6 +15347,14 @@
warning will be emitted if this happens since the resulting number of
listeners will not be the expected one.
+sigalgs <sigalgs>
+ This setting is only available when support for OpenSSL was built in. It sets
+ the string describing the list of signature algorithms that are negotiated
+ during the TLSv1.2 and TLSv1.3 handshake. The format of the string is defined
+ in "man 3 SSL_CTX_set1_sigalgs" from the OpenSSL man pages. It is not
+ recommended to use this setting unless compatibility with a middlebox is
+ required.
+
ssl
This setting is only available when support for OpenSSL was built in. It
enables SSL deciphering on connections instantiated from this listener. A
diff --git a/include/haproxy/listener-t.h b/include/haproxy/listener-t.h
index 92aa9cf..ff5b30d 100644
--- a/include/haproxy/listener-t.h
+++ b/include/haproxy/listener-t.h
@@ -143,6 +143,7 @@
char *ciphersuites; /* TLS 1.3 cipher suite to use if non-null */
char *curves; /* curves suite to use for ECDHE */
char *ecdhe; /* named curve to use for ECDHE */
+ char *sigalgs; /* Signature algorithms */
struct tls_version_filter ssl_methods_cfg; /* original ssl methods found in configuration */
struct tls_version_filter ssl_methods; /* actual ssl methods used at runtime */
#endif
diff --git a/include/haproxy/openssl-compat.h b/include/haproxy/openssl-compat.h
index d1fa7ba..b857e10 100644
--- a/include/haproxy/openssl-compat.h
+++ b/include/haproxy/openssl-compat.h
@@ -520,5 +520,9 @@
#define SSL_CTX_set1_curves_list SSL_CTX_set1_curves_list
#endif
+#if !defined(SSL_CTX_set1_sigalgs_list) && defined(SSL_CTRL_SET_SIGALGS_LIST)
+#define SSL_CTX_set1_sigalgs_list SSL_CTX_set1_sigalgs_list
+#endif
+
#endif /* USE_OPENSSL */
#endif /* _HAPROXY_OPENSSL_COMPAT_H */
diff --git a/include/haproxy/ssl_sock-t.h b/include/haproxy/ssl_sock-t.h
index 022c574..b4d3502 100644
--- a/include/haproxy/ssl_sock-t.h
+++ b/include/haproxy/ssl_sock-t.h
@@ -279,6 +279,9 @@
#if defined(SSL_CTX_set1_curves_list)
char *listen_default_curves;
#endif
+#if defined(SSL_CTX_set1_sigalgs_list)
+ char *listen_default_sigalgs;
+#endif
int listen_default_ssloptions;
int connect_default_ssloptions;
struct tls_version_filter listen_default_sslmethods;
diff --git a/src/cfgparse-ssl.c b/src/cfgparse-ssl.c
index 43ac3df..48e1450 100644
--- a/src/cfgparse-ssl.c
+++ b/src/cfgparse-ssl.c
@@ -316,6 +316,34 @@
return 0;
}
#endif
+
+#if defined(SSL_CTX_set1_sigalgs_list)
+/*
+ * parse the "ssl-default-bind-sigalgs" keyword in a global section.
+ * Returns <0 on alert, >0 on warning, 0 on success.
+ */
+static int ssl_parse_global_sigalgs(char **args, int section_type, struct proxy *curpx,
+ const struct proxy *defpx, const char *file, int line,
+ char **err)
+{
+ char **target;
+
+ target = &global_ssl.listen_default_sigalgs;
+
+ if (too_many_args(1, args, err, NULL))
+ return -1;
+
+ if (*(args[1]) == 0) {
+ memprintf(err, "global statement '%s' expects a curves suite as an arguments.", args[0]);
+ return -1;
+ }
+
+ free(*target);
+ *target = strdup(args[1]);
+ return 0;
+}
+#endif
+
/* parse various global tune.ssl settings consisting in positive integers.
* Returns <0 on alert, >0 on warning, 0 on success.
*/
@@ -798,6 +826,27 @@
return ssl_bind_parse_curves(args, cur_arg, px, &conf->ssl_conf, 0, err);
}
+/* parse the "sigalgs" bind keyword */
+static int ssl_bind_parse_sigalgs(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err)
+{
+#if defined(SSL_CTX_set1_sigalgs_list)
+ if (!*args[cur_arg + 1]) {
+ memprintf(err, "'%s' : missing signature algorithm list", args[cur_arg]);
+ return ERR_ALERT | ERR_FATAL;
+ }
+ conf->sigalgs = strdup(args[cur_arg + 1]);
+ return 0;
+#else
+ memprintf(err, "'%s' : library does not support setting signature algorithms", args[cur_arg]);
+ return ERR_ALERT | ERR_FATAL;
+#endif
+}
+static int bind_parse_sigalgs(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+{
+ return ssl_bind_parse_sigalgs(args, cur_arg, px, &conf->ssl_conf, 0, err);
+}
+
+
/* parse the "ecdhe" bind keyword keyword */
static int ssl_bind_parse_ecdhe(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err)
{
@@ -1153,6 +1202,10 @@
if (global_ssl.listen_default_curves && !conf->ssl_conf.curves)
conf->ssl_conf.curves = strdup(global_ssl.listen_default_curves);
#endif
+#if defined(SSL_CTX_set1_sigalgs_list)
+ if (global_ssl.listen_default_sigalgs && !conf->ssl_conf.sigalgs)
+ conf->ssl_conf.sigalgs = strdup(global_ssl.listen_default_sigalgs);
+#endif
#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
if (global_ssl.listen_default_ciphersuites && !conf->ssl_conf.ciphersuites)
conf->ssl_conf.ciphersuites = strdup(global_ssl.listen_default_ciphersuites);
@@ -2009,6 +2062,7 @@
{ "no-alpn", ssl_bind_parse_no_alpn, 0 }, /* disable sending ALPN */
{ "no-ca-names", ssl_bind_parse_no_ca_names, 0 }, /* do not send ca names to clients (ca_file related) */
{ "npn", ssl_bind_parse_npn, 1 }, /* set NPN supported protocols */
+ { "sigalgs", ssl_bind_parse_sigalgs, 1 }, /* set SSL signature algorithms */
{ "ssl-min-ver", ssl_bind_parse_tls_method_minmax,1 }, /* minimum version */
{ "ssl-max-ver", ssl_bind_parse_tls_method_minmax,1 }, /* maximum version */
{ "verify", ssl_bind_parse_verify, 1 }, /* set SSL verify method */
@@ -2050,6 +2104,7 @@
{ "no-tlsv12", bind_parse_tls_method_options, 0 }, /* disable TLSv12 */
{ "no-tlsv13", bind_parse_tls_method_options, 0 }, /* disable TLSv13 */
{ "no-tls-tickets", bind_parse_no_tls_tickets, 0 }, /* disable session resumption tickets */
+ { "sigalgs", bind_parse_sigalgs, 1 }, /* set SSL signature algorithms */
{ "ssl", bind_parse_ssl, 0 }, /* enable SSL processing */
{ "ssl-min-ver", bind_parse_tls_method_minmax, 1 }, /* minimum version */
{ "ssl-max-ver", bind_parse_tls_method_minmax, 1 }, /* maximum version */
@@ -2152,6 +2207,9 @@
#if defined(SSL_CTX_set1_curves_list)
{ CFG_GLOBAL, "ssl-default-bind-curves", ssl_parse_global_curves },
#endif
+#if defined(SSL_CTX_set1_sigalgs_list)
+ { CFG_GLOBAL, "ssl-default-bind-sigalgs", ssl_parse_global_sigalgs },
+#endif
#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
{ CFG_GLOBAL, "ssl-default-bind-ciphersuites", ssl_parse_global_ciphersuites },
{ CFG_GLOBAL, "ssl-default-server-ciphersuites", ssl_parse_global_ciphersuites },
diff --git a/src/ssl_crtlist.c b/src/ssl_crtlist.c
index 741e6ae..3d3ae40 100644
--- a/src/ssl_crtlist.c
+++ b/src/ssl_crtlist.c
@@ -74,6 +74,9 @@
#endif
ha_free(&conf->curves);
ha_free(&conf->ecdhe);
+#if defined(SSL_CTX_set1_sigalgs_list)
+ ha_free(&conf->sigalgs);
+#endif
}
}
@@ -151,6 +154,13 @@
dst->ssl_methods.min = src->ssl_methods.min;
dst->ssl_methods.max = src->ssl_methods.max;
+#if defined(SSL_CTX_set1_sigalgs_list)
+ if (src->sigalgs) {
+ dst->sigalgs = strdup(src->sigalgs);
+ if (!dst->sigalgs)
+ goto error;
+ }
+#endif
return dst;
error:
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index a32ff41..b44b5ce 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -4570,6 +4570,9 @@
#endif
const char *conf_curves = NULL;
X509_STORE *store = SSL_CTX_get_cert_store(ctx);
+#if defined(SSL_CTX_set1_sigalgs_list)
+ const char *conf_sigalgs = NULL;
+#endif
if (ssl_conf) {
struct tls_version_filter *conf_ssl_methods = &ssl_conf->ssl_methods;
@@ -4771,6 +4774,17 @@
#endif /* defined(SSL_CTX_set_tmp_ecdh) && !defined(OPENSSL_NO_ECDH) */
#endif /* HA_OPENSSL_VERSION_NUMBER >= 0x10101000L */
}
+
+#if defined(SSL_CTX_set1_sigalgs_list)
+ conf_sigalgs = (ssl_conf && ssl_conf->sigalgs) ? ssl_conf->sigalgs : bind_conf->ssl_conf.sigalgs;
+ if (conf_sigalgs) {
+ if (!SSL_CTX_set1_sigalgs_list(ctx, conf_sigalgs)) {
+ memprintf(err, "%sProxy '%s': unable to set SSL Signature Algorithm list to '%s' for bind '%s' at [%s:%d].\n",
+ err && *err ? *err : "", curproxy->id, conf_sigalgs, bind_conf->arg, bind_conf->file, bind_conf->line);
+ cfgerr |= ERR_ALERT | ERR_FATAL;
+ }
+ }
+#endif
return cfgerr;
}