]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: ssl: allow to change the server signature algorithm
authorWilliam Lallemand <wlallemand@haproxy.org>
Thu, 4 May 2023 13:33:55 +0000 (15:33 +0200)
committerWilliam Lallemand <wlallemand@haproxy.org>
Thu, 4 May 2023 20:43:18 +0000 (22:43 +0200)
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.

doc/configuration.txt
include/haproxy/listener-t.h
include/haproxy/openssl-compat.h
include/haproxy/ssl_sock-t.h
src/cfgparse-ssl.c
src/ssl_crtlist.c
src/ssl_sock.c

index 9d4aa3c24793d987c6f338c1691bda9dee11cefd..0111b6125aa8fe61c6f5c3025b26589a31f15495 100644 (file)
@@ -1097,6 +1097,7 @@ The following keywords are supported in the "global" section :
    - 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 @@ ssl-default-bind-options [<option>]...
         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 @@ shards <number> | by-thread | by-group
   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
index 92aa9cf5f3a88690b8c1ae67e884952a373c5625..ff5b30da720f281abbd1932078667a296f92276f 100644 (file)
@@ -143,6 +143,7 @@ struct ssl_bind_conf {
        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
index d1fa7baac5d514c115e99d2e18ae7bc324c15d4f..b857e108c168bbd02186de48f98fe1c989f39d46 100644 (file)
@@ -520,5 +520,9 @@ static inline unsigned long ERR_peek_error_func(const char **func)
 #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 */
index 022c5748711536adc1f1ba6fe823093739284a8d..b4d350215e7245a04f2bb627d4630268b6ecaab4 100644 (file)
@@ -278,6 +278,9 @@ struct global_ssl {
 #endif
 #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;
index 43ac3dfdc87d3296748d051362dba32d3e033592..48e14508902d672e61de550b955d7185fd5dae5b 100644 (file)
@@ -316,6 +316,34 @@ static int ssl_parse_global_curves(char **args, int section_type, struct proxy *
        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 @@ static int bind_parse_curves(char **args, int cur_arg, struct proxy *px, struct
        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 @@ static int bind_parse_ssl(char **args, int cur_arg, struct proxy *px, struct bin
        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 @@ struct ssl_crtlist_kw ssl_crtlist_kws[] = {
        { "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 @@ static struct bind_kw_list bind_kws = { "SSL", { }, {
        { "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 @@ static struct cfg_kw_list cfg_kws = {ILH, {
 #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 },
index 741e6aed6e91009ffb7526a328dea3b93487162a..3d3ae407e3efc284654df5613911c6a05d2f1c65 100644 (file)
@@ -74,6 +74,9 @@ void ssl_sock_free_ssl_conf(struct ssl_bind_conf *conf)
 #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 @@ struct ssl_bind_conf *crtlist_dup_ssl_conf(struct ssl_bind_conf *src)
        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:
index a32ff413e64a7b6d76f93c1c702ce523c5093ec8..b44b5ce9283e805dc89e7bc8dc284fc58c9f5c21 100644 (file)
@@ -4570,6 +4570,9 @@ static int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, struct ssl_bind_con
 #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;
@@ -4772,6 +4775,17 @@ static int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, struct ssl_bind_con
 #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;
 }