]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: ssl: add support for ciphersuites option for TLSv1.3
authorDirkjan Bussink <d.bussink@gmail.com>
Fri, 14 Sep 2018 09:14:21 +0000 (11:14 +0200)
committerWilly Tarreau <w@1wt.eu>
Mon, 8 Oct 2018 17:20:13 +0000 (19:20 +0200)
OpenSSL released support for TLSv1.3. It also added a separate function
SSL_CTX_set_ciphersuites that is used to set the ciphers used in the
TLS 1.3 handshake. This change adds support for that new configuration
option by adding a ciphersuites configuration variable that works
essentially the same as the existing ciphers setting.

Note that it should likely be backported to 1.8 in order to ease usage
of the now released openssl-1.1.1.

doc/configuration.txt
include/common/defaults.h
include/types/listener.h
include/types/server.h
src/server.c
src/ssl_sock.c

index d890b0b0504053533a5206da340a1a7137e47a96..7c6684b94208c140a8493a81c33830215958e912 100644 (file)
@@ -583,8 +583,10 @@ The following keywords are supported in the "global" section :
    - setenv
    - stats
    - ssl-default-bind-ciphers
+   - ssl-default-bind-ciphersuites
    - ssl-default-bind-options
    - ssl-default-server-ciphers
+   - ssl-default-server-ciphersuites
    - ssl-default-server-options
    - ssl-dh-param-file
    - ssl-server-verify
@@ -988,11 +990,25 @@ setenv <name> <value>
 ssl-default-bind-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 ("cipher suite")
-  that are negotiated during the SSL/TLS handshake for all "bind" lines which
-  do not explicitly define theirs. The format of the string is defined in
-  "man 1 ciphers" from OpenSSL man pages, and can be for instance a string such
-  as "AES:ALL:!aNULL:!eNULL:+RC4:@STRENGTH" (without quotes). Please check the
-  "bind" keyword for more information.
+  that are negotiated during the SSL/TLS handshake except for TLSv1.3 for all
+  "bind" lines which do not explicitly define theirs. The format of the string
+  is defined in "man 1 ciphers" from OpenSSL man pages, and can be for instance
+  a string such as "AES:ALL:!aNULL:!eNULL:+RC4:@STRENGTH" (without quotes). For
+  TLSv1.3 cipher configuration, please check the "ssl-default-bind-ciphersuites"
+  keyword. Please check the "bind" keyword for more information.
+
+ssl-default-bind-ciphersuites <ciphersuites>
+  This setting is only available when support for OpenSSL was built in and
+  OpenSSL 1.1.1 or later was used to build HAProxy. It sets the default string
+  describing the list of cipher algorithms ("cipher suite") that are negotiated
+  during the TLSv1.3 handshake for all "bind" lines which do not explicitly define
+  theirs. The format of the string is defined in
+  "man 1 ciphers" from OpenSSL man pages under the section "ciphersuites", and can
+  be for instance a string such as
+  "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256"
+  (without quotes). For cipher configuration for TLSv1.2 and earlier, please check
+  the "ssl-default-bind-ciphers" keyword. Please check the "bind" keyword for more
+  information.
 
 ssl-default-bind-options [<option>]...
   This setting is only available when support for OpenSSL was built in. It sets
@@ -1006,10 +1022,21 @@ ssl-default-bind-options [<option>]...
 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
-  negotiated during the SSL/TLS handshake with the server, for all "server"
-  lines which do not explicitly define theirs. The format of the string is
-  defined in "man 1 ciphers". Please check the "server" keyword for more
-  information.
+  negotiated during the SSL/TLS handshake except for TLSv1.3 with the server,
+  for all "server" lines which do not explicitly define theirs. The format of
+  the string is defined in "man 1 ciphers". For TLSv1.3 cipher configuration,
+  please check the "ssl-default-server-ciphersuites" keyword. Please check the
+  "server" keyword for more information.
+
+ssl-default-server-ciphersuites <ciphersuites>
+  This setting is only available when support for OpenSSL was built in and
+  OpenSSL 1.1.1 or later was used to build HAProxy. It sets the default
+  string describing the list of cipher algorithms that are negotiated during
+  the TLSv1.3 handshake with the server, for all "server" lines which do not
+  explicitly define theirs. The format of the string is defined in
+  "man 1 ciphers" under the "ciphersuites" section. For cipher configuration for
+  TLSv1.2 and earlier, please check the "ssl-default-server-ciphers" keyword.
+  Please check the "server" keyword for more information.
 
 ssl-default-server-options [<option>]...
   This setting is only available when support for OpenSSL was built in. It sets
@@ -10618,13 +10645,26 @@ ca-sign-pass <passphrase>
 ciphers <ciphers>
   This setting is only available when support for OpenSSL was built in. It sets
   the string describing the list of cipher algorithms ("cipher suite") that are
-  negotiated during the SSL/TLS handshake. The format of the string is defined
-  in "man 1 ciphers" from OpenSSL man pages, and can be for instance a string
-  such as "AES:ALL:!aNULL:!eNULL:+RC4:@STRENGTH" (without quotes).
-  Depending on the compatibility and security requirements, the list of suitable
-  ciphers depends on a variety of variables. For background information and
-  recommendations see e. g. (https://wiki.mozilla.org/Security/Server_Side_TLS)
-  and (https://mozilla.github.io/server-side-tls/ssl-config-generator/).
+  negotiated during the SSL/TLS handshake except for TLSv1.3. The format of the
+  string is defined in "man 1 ciphers" from OpenSSL man pages, and can be for
+  instance a string such as "AES:ALL:!aNULL:!eNULL:+RC4:@STRENGTH" (without
+  quotes). Depending on the compatibility and security requirements, the list
+  of suitable ciphers depends on a variety of variables. For background
+  information and recommendations see e.g.
+  (https://wiki.mozilla.org/Security/Server_Side_TLS) and
+  (https://mozilla.github.io/server-side-tls/ssl-config-generator/). For TLSv1.3
+  cipher configuration, please check the "ciphersuites" keyword.
+
+ciphersuites <ciphersuites>
+  This setting is only available when support for OpenSSL was built in and
+  OpenSSL 1.1.1 or later was used to build HAProxy. It sets the string describing
+  the list of cipher algorithms ("cipher suite") that are negotiated during the
+  TLSv1.3 handshake. The format of the string is defined in "man 1 ciphers" from
+  OpenSSL man pages under the "ciphersuites" section, and can be for instance a
+  string such as
+  "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256"
+  (without quotes). For cipher configuration for TLSv1.2 and earlier, please check
+  the "ciphers" keyword.
 
 crl-file <crlfile>
   This setting is only available when support for OpenSSL was built in. It
@@ -11347,8 +11387,9 @@ check-ssl
   this option.
 
 ciphers <ciphers>
-  This option sets the string describing the list of cipher algorithms that is
-  is negotiated during the SSL/TLS handshake with the server. The format of the
+  This setting is only available when support for OpenSSL was built in. This
+  option sets the string describing the list of cipher algorithms that is
+  negotiated during the SSL/TLS handshake with the server. The format of the
   string is defined in "man 1 ciphers". When SSL is used to communicate with
   servers on the local network, it is common to see a weaker set of algorithms
   than what is used over the internet. Doing so reduces CPU usage on both the
@@ -11356,6 +11397,13 @@ ciphers <ciphers>
   Some algorithms such as RC4-SHA1 are reasonably cheap. If no security at all
   is needed and just connectivity, using DES can be appropriate.
 
+ciphersuites <ciphersuites>
+  This setting is only available when support for OpenSSL was built in and
+  OpenSSL 1.1.1 or later was used to build HAProxy. This option sets the string
+  describing the list of cipher algorithms that is negotiated during the TLS
+  1.3 handshake with the server. The format of the string is defined in
+  "man 1 ciphers" under the "ciphersuites" section.
+
 cookie <value>
   The "cookie" parameter sets the cookie value assigned to the server to
   <value>. This value will be checked in incoming requests, and the first
index f5c74dbfe5ce9086788dfab98a301ecc55dd720e..b2c2583540a353d16094bd2ab0ec3b46d3cf5001 100644 (file)
 #define CONNECT_DEFAULT_CIPHERS NULL
 #endif
 
+/* ciphers used as defaults on TLS 1.3 connect */
+#ifndef CONNECT_DEFAULT_CIPHERSUITES
+#define CONNECT_DEFAULT_CIPHERSUITES NULL
+#endif
+
 /* ciphers used as defaults on listeners */
 #ifndef LISTEN_DEFAULT_CIPHERS
 #define LISTEN_DEFAULT_CIPHERS NULL
 #endif
 
+/* cipher suites used as defaults on TLS 1.3 listeners */
+#ifndef LISTEN_DEFAULT_CIPHERSUITES
+#define LISTEN_DEFAULT_CIPHERSUITES NULL
+#endif
+
 /* named curve used as defaults for ECDHE ciphers */
 #ifndef ECDHE_DEFAULT_CURVE
 #define ECDHE_DEFAULT_CURVE "prime256v1"
index 816d1117b340c889d828dcc42922b27d5d1c88ce..50f1936842094b42f5178781f8ea11183e4fe7a0 100644 (file)
@@ -129,6 +129,9 @@ struct ssl_bind_conf {
        char *ca_file;             /* CAfile to use on verify */
        char *crl_file;            /* CRLfile to use on verify */
        char *ciphers;             /* cipher suite to use if non-null */
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
+       char *ciphersuites;        /* TLS 1.3 cipher suite to use if non-null */
+#endif
        char *curves;              /* curves suite to use for ECDHE */
        char *ecdhe;               /* named curve to use for ECDHE */
        struct tls_version_filter ssl_methods; /* ssl methods */
index 8adc29baf674612256949ec8bcea42be57d392d8..a2e11c30e1c3fb8c1f5d228c9710b5146e3c13b6 100644 (file)
@@ -288,6 +288,9 @@ struct server {
                        int allocated_size;
                } * reused_sess;
                char *ciphers;                  /* cipher suite to use if non-null */
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
+               char *ciphersuites;                     /* TLS 1.3 cipher suite to use if non-null */
+#endif
                int options;                    /* ssl options */
                int verify;                     /* verify method (set of SSL_VERIFY_* flags) */
                struct tls_version_filter methods;      /* ssl methods */
index e6944c2e1cb3fa6ba1ba8949fba5e065cf742130..c817c39169ed619243280f5a54c5774600619443 100644 (file)
@@ -1480,6 +1480,10 @@ static void srv_ssl_settings_cpy(struct server *srv, struct server *src)
                srv->ssl_ctx.verify_host = strdup(src->ssl_ctx.verify_host);
        if (src->ssl_ctx.ciphers != NULL)
                srv->ssl_ctx.ciphers = strdup(src->ssl_ctx.ciphers);
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
+       if (src->ssl_ctx.ciphersuites != NULL)
+               srv->ssl_ctx.ciphersuites = strdup(src->ssl_ctx.ciphersuites);
+#endif
        if (src->sni_expr != NULL)
                srv->sni_expr = strdup(src->sni_expr);
 }
index c11acb3b719504fa958a237a06de19adaeb23c19..07e039f9d61678e1ab51bc979523c0655fd8f585 100644 (file)
@@ -171,6 +171,10 @@ static struct {
 
        char *listen_default_ciphers;
        char *connect_default_ciphers;
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
+       char *listen_default_ciphersuites;
+       char *connect_default_ciphersuites;
+#endif
        int listen_default_ssloptions;
        int connect_default_ssloptions;
        struct tls_version_filter listen_default_sslmethods;
@@ -188,6 +192,14 @@ static struct {
 #endif
 #ifdef CONNECT_DEFAULT_CIPHERS
        .connect_default_ciphers = CONNECT_DEFAULT_CIPHERS,
+#endif
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
+#ifdef LISTEN_DEFAULT_CIPHERSUITES
+       .listen_default_ciphersuites = LISTEN_DEFAULT_CIPHERSUITES,
+#endif
+#ifdef CONNECT_DEFAULT_CIPHERSUITES
+       .connect_default_ciphersuites = CONNECT_DEFAULT_CIPHERSUITES,
+#endif
 #endif
        .listen_default_ssloptions = BC_SSL_O_NONE,
        .connect_default_ssloptions = SRV_SSL_O_NONE,
@@ -3548,6 +3560,10 @@ void ssl_sock_free_ssl_conf(struct ssl_bind_conf *conf)
                conf->crl_file = NULL;
                free(conf->ciphers);
                conf->ciphers = NULL;
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
+               free(conf->ciphersuites);
+               conf->ciphersuites = NULL;
+#endif
                free(conf->curves);
                conf->curves = NULL;
                free(conf->ecdhe);
@@ -4082,6 +4098,9 @@ int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, struct ssl_bind_conf *ssl_
        int verify = SSL_VERIFY_NONE;
        struct ssl_bind_conf __maybe_unused *ssl_conf_cur;
        const char *conf_ciphers;
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
+       const char *conf_ciphersuites;
+#endif
        const char *conf_curves = NULL;
 
        if (ssl_conf) {
@@ -4181,6 +4200,16 @@ int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, struct ssl_bind_conf *ssl_
                cfgerr++;
        }
 
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
+       conf_ciphersuites = (ssl_conf && ssl_conf->ciphersuites) ? ssl_conf->ciphersuites : bind_conf->ssl_conf.ciphersuites;
+       if (conf_ciphersuites &&
+           !SSL_CTX_set_ciphersuites(ctx, conf_ciphersuites)) {
+               ha_alert("Proxy '%s': unable to set TLS 1.3 cipher suites to '%s' for bind '%s' at [%s:%d].\n",
+                        curproxy->id, conf_ciphersuites, bind_conf->arg, bind_conf->file, bind_conf->line);
+               cfgerr++;
+       }
+#endif
+
 #ifndef OPENSSL_NO_DH
        /* If tune.ssl.default-dh-param has not been set,
           neither has ssl-default-dh-file and no static DH
@@ -4663,6 +4692,16 @@ int ssl_sock_prepare_srv_ctx(struct server *srv)
                cfgerr++;
        }
 
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
+       if (srv->ssl_ctx.ciphersuites &&
+               !SSL_CTX_set_cipher_list(srv->ssl_ctx.ctx, srv->ssl_ctx.ciphersuites)) {
+               ha_alert("Proxy '%s', server '%s' [%s:%d] : unable to set TLS 1.3 cipher suites to '%s'.\n",
+                        curproxy->id, srv->id,
+                        srv->conf.file, srv->conf.line, srv->ssl_ctx.ciphersuites);
+               cfgerr++;
+       }
+#endif
+
        return cfgerr;
 }
 
@@ -7243,6 +7282,26 @@ static int bind_parse_ciphers(char **args, int cur_arg, struct proxy *px, struct
 {
        return ssl_bind_parse_ciphers(args, cur_arg, px, &conf->ssl_conf, err);
 }
+
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
+/* parse the "ciphersuites" bind keyword */
+static int ssl_bind_parse_ciphersuites(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
+{
+       if (!*args[cur_arg + 1]) {
+               memprintf(err, "'%s' : missing cipher suite", args[cur_arg]);
+               return ERR_ALERT | ERR_FATAL;
+       }
+
+       free(conf->ciphersuites);
+       conf->ciphersuites = strdup(args[cur_arg + 1]);
+       return 0;
+}
+static int bind_parse_ciphersuites(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+{
+       return ssl_bind_parse_ciphersuites(args, cur_arg, px, &conf->ssl_conf, err);
+}
+#endif
+
 /* parse the "crt" bind keyword */
 static int bind_parse_crt(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
 {
@@ -7634,6 +7693,10 @@ static int bind_parse_ssl(char **args, int cur_arg, struct proxy *px, struct bin
 
        if (global_ssl.listen_default_ciphers && !conf->ssl_conf.ciphers)
                conf->ssl_conf.ciphers = strdup(global_ssl.listen_default_ciphers);
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
+       if (global_ssl.listen_default_ciphersuites && !conf->ssl_conf.ciphersuites)
+               conf->ssl_conf.ciphersuites = strdup(global_ssl.listen_default_ciphersuites);
+#endif
        conf->ssl_options |= global_ssl.listen_default_ssloptions;
        conf->ssl_conf.ssl_methods.flags |= global_ssl.listen_default_sslmethods.flags;
        if (!conf->ssl_conf.ssl_methods.min)
@@ -7831,6 +7894,10 @@ static int srv_parse_check_ssl(char **args, int *cur_arg, struct proxy *px, stru
        newsrv->check.use_ssl = 1;
        if (global_ssl.connect_default_ciphers && !newsrv->ssl_ctx.ciphers)
                newsrv->ssl_ctx.ciphers = strdup(global_ssl.connect_default_ciphers);
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
+       if (global_ssl.connect_default_ciphersuites && !newsrv->ssl_ctx.ciphersuites)
+               newsrv->ssl_ctx.ciphersuites = strdup(global_ssl.connect_default_ciphersuites);
+#endif
        newsrv->ssl_ctx.options |= global_ssl.connect_default_ssloptions;
        newsrv->ssl_ctx.methods.flags |= global_ssl.connect_default_sslmethods.flags;
        if (!newsrv->ssl_ctx.methods.min)
@@ -7854,6 +7921,21 @@ static int srv_parse_ciphers(char **args, int *cur_arg, struct proxy *px, struct
        return 0;
 }
 
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
+/* parse the "ciphersuites" server keyword */
+static int srv_parse_ciphersuites(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
+{
+       if (!*args[*cur_arg + 1]) {
+               memprintf(err, "'%s' : missing cipher suite", args[*cur_arg]);
+               return ERR_ALERT | ERR_FATAL;
+       }
+
+       free(newsrv->ssl_ctx.ciphersuites);
+       newsrv->ssl_ctx.ciphersuites = strdup(args[*cur_arg + 1]);
+       return 0;
+}
+#endif
+
 /* parse the "crl-file" server keyword */
 static int srv_parse_crl_file(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
 {
@@ -7995,6 +8077,10 @@ static int srv_parse_ssl(char **args, int *cur_arg, struct proxy *px, struct ser
        newsrv->use_ssl = 1;
        if (global_ssl.connect_default_ciphers && !newsrv->ssl_ctx.ciphers)
                newsrv->ssl_ctx.ciphers = strdup(global_ssl.connect_default_ciphers);
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
+       if (global_ssl.connect_default_ciphersuites && !newsrv->ssl_ctx.ciphersuites)
+               newsrv->ssl_ctx.ciphersuites = strdup(global_ssl.connect_default_ciphersuites);
+#endif
        return 0;
 }
 
@@ -8234,6 +8320,32 @@ static int ssl_parse_global_ciphers(char **args, int section_type, struct proxy
        return 0;
 }
 
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
+/* parse the "ssl-default-bind-ciphersuites" / "ssl-default-server-ciphersuites" keywords
+ * in global section. Returns <0 on alert, >0 on warning, 0 on success.
+ */
+static int ssl_parse_global_ciphersuites(char **args, int section_type, struct proxy *curpx,
+                                    struct proxy *defpx, const char *file, int line,
+                                    char **err)
+{
+       char **target;
+
+       target = (args[0][12] == 'b') ? &global_ssl.listen_default_ciphersuites : &global_ssl.connect_default_ciphersuites;
+
+       if (too_many_args(1, args, err, NULL))
+               return -1;
+
+       if (*(args[1]) == 0) {
+               memprintf(err, "global statement '%s' expects a cipher suite as an argument.", 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.
  */
@@ -8773,6 +8885,9 @@ static struct ssl_bind_kw ssl_bind_kws[] = {
        { "alpn",                  ssl_bind_parse_alpn,             1 }, /* set ALPN supported protocols */
        { "ca-file",               ssl_bind_parse_ca_file,          1 }, /* set CAfile to process verify on client cert */
        { "ciphers",               ssl_bind_parse_ciphers,          1 }, /* set SSL cipher suite */
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
+       { "ciphersuites",          ssl_bind_parse_ciphersuites,     1 }, /* set TLS 1.3 cipher suite */
+#endif
        { "crl-file",              ssl_bind_parse_crl_file,         1 }, /* set certificat 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 */
@@ -8792,6 +8907,9 @@ static struct bind_kw_list bind_kws = { "SSL", { }, {
        { "ca-sign-file",          bind_parse_ca_sign_file,       1 }, /* set CAFile used to generate and sign server certs */
        { "ca-sign-pass",          bind_parse_ca_sign_pass,       1 }, /* set CAKey passphrase */
        { "ciphers",               bind_parse_ciphers,            1 }, /* set SSL cipher suite */
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
+       { "ciphersuites",          bind_parse_ciphersuites,       1 }, /* set TLS 1.3 cipher suite */
+#endif
        { "crl-file",              bind_parse_crl_file,           1 }, /* set certificat 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 ingore on verify depth == 0 */
@@ -8835,6 +8953,9 @@ static struct srv_kw_list srv_kws = { "SSL", { }, {
        { "check-sni",               srv_parse_check_sni,          1, 1 }, /* set SNI */
        { "check-ssl",               srv_parse_check_ssl,          0, 1 }, /* enable SSL for health checks */
        { "ciphers",                 srv_parse_ciphers,            1, 1 }, /* select the cipher suite */
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
+       { "ciphersuites",            srv_parse_ciphersuites,       1, 1 }, /* select the cipher suite */
+#endif
        { "crl-file",                srv_parse_crl_file,           1, 1 }, /* set certificate revocation list file use on server cert verify */
        { "crt",                     srv_parse_crt,                1, 1 }, /* set client certificate */
        { "force-sslv3",             srv_parse_tls_method_options, 0, 1 }, /* force SSLv3 */
@@ -8890,6 +9011,10 @@ static struct cfg_kw_list cfg_kws = {ILH, {
        { CFG_GLOBAL, "tune.ssl.capture-cipherlist-size", ssl_parse_global_capture_cipherlist },
        { CFG_GLOBAL, "ssl-default-bind-ciphers", ssl_parse_global_ciphers },
        { CFG_GLOBAL, "ssl-default-server-ciphers", ssl_parse_global_ciphers },
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
+       { CFG_GLOBAL, "ssl-default-bind-ciphersuites", ssl_parse_global_ciphersuites },
+       { CFG_GLOBAL, "ssl-default-server-ciphersuites", ssl_parse_global_ciphersuites },
+#endif
        { 0, NULL, NULL },
 }};
 
@@ -8971,6 +9096,12 @@ static void __ssl_sock_init(void)
                global_ssl.listen_default_ciphers = strdup(global_ssl.listen_default_ciphers);
        if (global_ssl.connect_default_ciphers)
                global_ssl.connect_default_ciphers = strdup(global_ssl.connect_default_ciphers);
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
+       if (global_ssl.listen_default_ciphersuites)
+               global_ssl.listen_default_ciphersuites = strdup(global_ssl.listen_default_ciphersuites);
+       if (global_ssl.connect_default_ciphersuites)
+               global_ssl.connect_default_ciphersuites = strdup(global_ssl.connect_default_ciphersuites);
+#endif
 
        xprt_register(XPRT_SSL, &ssl_sock);
        SSL_library_init();