From b6ae2aafde4373c6959a9937878189b75936a009 Mon Sep 17 00:00:00 2001 From: William Lallemand Date: Fri, 5 May 2023 00:05:46 +0200 Subject: [PATCH] MINOR: ssl: allow to change the signature algorithm for client authentication This commit introduces the keyword "client-sigalgs" for the bind line, which does the same as "sigalgs" but for the client authentication. "ssl-default-bind-client-sigalgs" allows to set the default parameter for all the bind lines. This patch should fix issue #2081. --- doc/configuration.txt | 23 ++++++++++++++++ include/haproxy/listener-t.h | 1 + include/haproxy/ssl_sock-t.h | 3 +++ src/cfgparse-ssl.c | 52 ++++++++++++++++++++++++++++++++++++ src/ssl_crtlist.c | 10 +++++++ src/ssl_sock.c | 14 ++++++++++ 6 files changed, 103 insertions(+) diff --git a/doc/configuration.txt b/doc/configuration.txt index 0111b6125a..7926b72efa 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -1095,6 +1095,7 @@ The following keywords are supported in the "global" section : - setenv - ssl-default-bind-ciphers - ssl-default-bind-ciphersuites + - ssl-default-bind-client-sigalgs - ssl-default-bind-curves - ssl-default-bind-options - ssl-default-bind-sigalgs @@ -2168,6 +2169,21 @@ ssl-default-bind-ciphersuites "ssl-default-bind-ciphers" keyword. Please check the "bind" keyword for more information. +ssl-default-bind-client-sigalgs + This setting is only available when support for OpenSSL was built in. It sets + the default string describing the list of signature algorithms related to + client authentication 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_client_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-bind-curves This setting is only available when support for OpenSSL was built in. It sets the default string describing the list of elliptic curves algorithms ("curve @@ -14809,6 +14825,13 @@ ciphersuites OpenSSL man pages under the "ciphersuites" section. For cipher configuration for TLSv1.2 and earlier, please check the "ciphers" keyword. +client-sigalgs + This setting is only available when support for OpenSSL was built in. It sets + the string describing the list of signature algorithms related to client + authentication that are negotiated . The format of the string is defined in + "man 3 SSL_CTX_set1_client_sigalgs" from the OpenSSL man pages. It is not + recommended to use this setting if no specific usecase was identified. + crl-file This setting is only available when support for OpenSSL was built in. It designates a PEM file from which to load certificate revocation list used diff --git a/include/haproxy/listener-t.h b/include/haproxy/listener-t.h index ff5b30da72..7384739be1 100644 --- a/include/haproxy/listener-t.h +++ b/include/haproxy/listener-t.h @@ -144,6 +144,7 @@ struct ssl_bind_conf { char *curves; /* curves suite to use for ECDHE */ char *ecdhe; /* named curve to use for ECDHE */ char *sigalgs; /* Signature algorithms */ + char *client_sigalgs; /* Client 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/ssl_sock-t.h b/include/haproxy/ssl_sock-t.h index b4d350215e..0b94a0eab4 100644 --- a/include/haproxy/ssl_sock-t.h +++ b/include/haproxy/ssl_sock-t.h @@ -281,6 +281,9 @@ struct global_ssl { #endif #if defined(SSL_CTX_set1_sigalgs_list) char *listen_default_sigalgs; +#endif +#if defined(SSL_CTX_set1_sigalgs_list) + char *listen_default_client_sigalgs; #endif int listen_default_ssloptions; int connect_default_ssloptions; diff --git a/src/cfgparse-ssl.c b/src/cfgparse-ssl.c index 48e1450890..42d7f404b7 100644 --- a/src/cfgparse-ssl.c +++ b/src/cfgparse-ssl.c @@ -344,6 +344,33 @@ static int ssl_parse_global_sigalgs(char **args, int section_type, struct proxy } #endif +#if defined(SSL_CTX_set1_client_sigalgs_list) +/* + * parse the "ssl-default-bind-client-sigalgs" keyword in a global section. + * Returns <0 on alert, >0 on warning, 0 on success. + */ +static int ssl_parse_global_client_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_client_sigalgs; + + if (too_many_args(1, args, err, NULL)) + return -1; + + if (*(args[1]) == 0) { + memprintf(err, "global statement '%s' expects signature algorithms 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. */ @@ -846,6 +873,26 @@ static int bind_parse_sigalgs(char **args, int cur_arg, struct proxy *px, struct return ssl_bind_parse_sigalgs(args, cur_arg, px, &conf->ssl_conf, 0, err); } +/* parse the "client-sigalgs" bind keyword */ +static int ssl_bind_parse_client_sigalgs(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, int from_cli, char **err) +{ +#if defined(SSL_CTX_set1_client_sigalgs_list) + if (!*args[cur_arg + 1]) { + memprintf(err, "'%s' : missing signature algorithm list", args[cur_arg]); + return ERR_ALERT | ERR_FATAL; + } + conf->client_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_client_sigalgs(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) +{ + return ssl_bind_parse_client_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) @@ -2056,6 +2103,7 @@ struct ssl_crtlist_kw ssl_crtlist_kws[] = { #ifdef HAVE_SSL_CTX_SET_CIPHERSUITES { "ciphersuites", ssl_bind_parse_ciphersuites, 1 }, /* set TLS 1.3 cipher suite */ #endif + { "client-sigalgs", ssl_bind_parse_client_sigalgs, 1 }, /* set SSL client signature algorithms */ { "crl-file", ssl_bind_parse_crl_file, 1 }, /* set certificate revocation list file use on client cert verify */ { "curves", ssl_bind_parse_curves, 1 }, /* set SSL curve suite */ { "ecdhe", ssl_bind_parse_ecdhe, 1 }, /* defines named curve for elliptic curve Diffie-Hellman */ @@ -2084,6 +2132,7 @@ static struct bind_kw_list bind_kws = { "SSL", { }, { #ifdef HAVE_SSL_CTX_SET_CIPHERSUITES { "ciphersuites", bind_parse_ciphersuites, 1 }, /* set TLS 1.3 cipher suite */ #endif + { "client-sigalgs", bind_parse_client_sigalgs, 1 }, /* set SSL client signature algorithms */ { "crl-file", bind_parse_crl_file, 1 }, /* set certificate revocation list file use on client cert verify */ { "crt", bind_parse_crt, 1 }, /* load SSL certificates from this location */ { "crt-ignore-err", bind_parse_ignore_err, 1 }, /* set error IDs to ignore on verify depth == 0 */ @@ -2210,6 +2259,9 @@ static struct cfg_kw_list cfg_kws = {ILH, { #if defined(SSL_CTX_set1_sigalgs_list) { CFG_GLOBAL, "ssl-default-bind-sigalgs", ssl_parse_global_sigalgs }, #endif +#if defined(SSL_CTX_set1_client_sigalgs_list) + { CFG_GLOBAL, "ssl-default-bind-client-sigalgs", ssl_parse_global_client_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 3d3ae407e3..9ea5ea0e12 100644 --- a/src/ssl_crtlist.c +++ b/src/ssl_crtlist.c @@ -76,6 +76,9 @@ void ssl_sock_free_ssl_conf(struct ssl_bind_conf *conf) ha_free(&conf->ecdhe); #if defined(SSL_CTX_set1_sigalgs_list) ha_free(&conf->sigalgs); +#endif +#if defined(SSL_CTX_set1_client_sigalgs_list) + ha_free(&conf->client_sigalgs); #endif } } @@ -160,6 +163,13 @@ struct ssl_bind_conf *crtlist_dup_ssl_conf(struct ssl_bind_conf *src) if (!dst->sigalgs) goto error; } +#endif +#if defined(SSL_CTX_set1_client_sigalgs_list) + if (src->client_sigalgs) { + dst->client_sigalgs = strdup(src->client_sigalgs); + if (!dst->client_sigalgs) + goto error; + } #endif return dst; diff --git a/src/ssl_sock.c b/src/ssl_sock.c index b44b5ce928..79ac2d66f4 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -4573,6 +4573,9 @@ static int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, struct ssl_bind_con #if defined(SSL_CTX_set1_sigalgs_list) const char *conf_sigalgs = NULL; #endif +#if defined(SSL_CTX_set1_client_sigalgs_list) + const char *conf_client_sigalgs = NULL; +#endif if (ssl_conf) { struct tls_version_filter *conf_ssl_methods = &ssl_conf->ssl_methods; @@ -4786,6 +4789,17 @@ static int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, struct ssl_bind_con } #endif +#if defined(SSL_CTX_set1_client_sigalgs_list) + conf_client_sigalgs = (ssl_conf && ssl_conf->client_sigalgs) ? ssl_conf->client_sigalgs : bind_conf->ssl_conf.client_sigalgs; + if (conf_client_sigalgs) { + if (!SSL_CTX_set1_client_sigalgs_list(ctx, conf_client_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_client_sigalgs, bind_conf->arg, bind_conf->file, bind_conf->line); + cfgerr |= ERR_ALERT | ERR_FATAL; + } + } +#endif + return cfgerr; } -- 2.39.5