diff --git a/bin/named/named.conf.rst b/bin/named/named.conf.rst index d1818a7ef6..ff9e7de0f8 100644 --- a/bin/named/named.conf.rst +++ b/bin/named/named.conf.rst @@ -567,6 +567,7 @@ TLS dhparam-file quoted_string; hostname quoted_string; key-file quoted_string; + prefer-server-ciphers boolean; protocols { string; ... }; }; diff --git a/bin/named/server.c b/bin/named/server.c index d3e8d802d6..3c3ebd7b48 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -11025,6 +11025,8 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, isc_dscp_t dscp = -1; const char *key = NULL, *cert = NULL, *dhparam_file = NULL, *ciphers = NULL; + bool tls_prefer_server_ciphers = false, + tls_prefer_server_ciphers_set = false; bool do_tls = false, no_tls = false, http = false; ns_listenelt_t *delt = NULL; uint32_t tls_protos = 0; @@ -11049,6 +11051,7 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, const cfg_obj_t *tlsmap = NULL; const cfg_obj_t *tls_proto_list = NULL; const cfg_obj_t *ciphers_obj = NULL; + const cfg_obj_t *prefer_server_ciphers_obj = NULL; do_tls = true; @@ -11097,14 +11100,27 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, ISC_R_SUCCESS) { ciphers = cfg_obj_asstring(ciphers_obj); } + + if (cfg_map_get(tlsmap, "prefer-server-ciphers", + &prefer_server_ciphers_obj) == + ISC_R_SUCCESS) + { + tls_prefer_server_ciphers = cfg_obj_asboolean( + prefer_server_ciphers_obj); + tls_prefer_server_ciphers_set = true; + } } } - tls_params = (ns_listen_tls_params_t){ .key = key, - .cert = cert, - .protocols = tls_protos, - .dhparam_file = dhparam_file, - .ciphers = ciphers }; + tls_params = (ns_listen_tls_params_t){ + .key = key, + .cert = cert, + .protocols = tls_protos, + .dhparam_file = dhparam_file, + .ciphers = ciphers, + .prefer_server_ciphers = tls_prefer_server_ciphers, + .prefer_server_ciphers_set = tls_prefer_server_ciphers_set, + }; httpobj = cfg_tuple_get(ltup, "http"); if (httpobj != NULL && cfg_obj_isstring(httpobj)) { diff --git a/bin/tests/system/checkconf/good-doh-tlsopts.conf b/bin/tests/system/checkconf/good-doh-tlsopts.conf index 7583c70cd5..f6cafa342f 100644 --- a/bin/tests/system/checkconf/good-doh-tlsopts.conf +++ b/bin/tests/system/checkconf/good-doh-tlsopts.conf @@ -15,6 +15,7 @@ tls local-tls { cert-file "cert.pem"; dhparam-file "dhparam.pem"; ciphers "HIGH:!aNULL:!MD5:!RC4"; + prefer-server-ciphers yes; }; http local-http-server { diff --git a/bin/tests/system/checkconf/good-dot-tlsopts.conf b/bin/tests/system/checkconf/good-dot-tlsopts.conf index 1a0029d220..8912646f65 100644 --- a/bin/tests/system/checkconf/good-dot-tlsopts.conf +++ b/bin/tests/system/checkconf/good-dot-tlsopts.conf @@ -15,6 +15,7 @@ tls local-tls { cert-file "cert.pem"; dhparam-file "dhparam.pem"; ciphers "HIGH:!aNULL:!MD5:!RC4"; + prefer-server-ciphers yes; }; options { diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst index 46f24ec536..b6a7c14e27 100644 --- a/doc/arm/reference.rst +++ b/doc/arm/reference.rst @@ -293,7 +293,7 @@ The following statements are supported: Declares communication channels to get access to ``named`` statistics. ``tls`` - Specifies configuration information for a TLS connection, including a ``key-file``, ``cert-file``, ``ca-file``, ``dhparam-file``, ``hostname``, ``ciphers``, and ``protocols``. + Specifies configuration information for a TLS connection, including a ``key-file``, ``cert-file``, ``ca-file``, ``dhparam-file``, ``hostname``, ``ciphers``, ``protocols``, and ``prefer-server-ciphers``. ``http`` Specifies configuration information for an HTTP connection, including ``endponts``, ``listener-clients`` and ``streams-per-connection``. @@ -4792,6 +4792,9 @@ The following options can be specified in a ``tls`` statement: (see https://www.openssl.org/docs/man1.1.1/man1/ciphers.html for details). + ``prefer-server-ciphers`` + Specifies that server ciphers should be preferred over client ones. + There are two built-in TLS connection configurations: ``ephemeral``, uses a temporary key and certificate created for the current ``named`` session only, and ``none``, which can be used when setting up an HTTP diff --git a/doc/man/named.conf.5in b/doc/man/named.conf.5in index eb7cf4c560..036d589949 100644 --- a/doc/man/named.conf.5in +++ b/doc/man/named.conf.5in @@ -658,6 +658,7 @@ tls string { dhparam\-file quoted_string; hostname quoted_string; key\-file quoted_string; + prefer\-server\-ciphers boolean; protocols { string; ... }; }; .ft P diff --git a/doc/misc/options b/doc/misc/options index 1a708a6163..da7fcceb31 100644 --- a/doc/misc/options +++ b/doc/misc/options @@ -463,6 +463,7 @@ tls { dhparam-file ; hostname ; key-file ; + prefer-server-ciphers ; protocols { ; ... }; }; // may occur multiple times diff --git a/doc/misc/options.active b/doc/misc/options.active index 91a555f5a5..f579cc2835 100644 --- a/doc/misc/options.active +++ b/doc/misc/options.active @@ -460,6 +460,7 @@ tls { dhparam-file ; hostname ; key-file ; + prefer-server-ciphers ; protocols { ; ... }; }; // may occur multiple times diff --git a/doc/misc/tls.grammar.rst b/doc/misc/tls.grammar.rst index 17c0c36bac..4cb078da94 100644 --- a/doc/misc/tls.grammar.rst +++ b/doc/misc/tls.grammar.rst @@ -7,5 +7,6 @@ dhparam-file ; hostname ; key-file ; + prefer-server-ciphers ; protocols { ; ... }; }; diff --git a/lib/isc/include/isc/tls.h b/lib/isc/include/isc/tls.h index 90f185e825..5c32053df3 100644 --- a/lib/isc/include/isc/tls.h +++ b/lib/isc/include/isc/tls.h @@ -114,6 +114,16 @@ isc_tlsctx_set_cipherlist(isc_tlsctx_t *ctx, const char *cipherlist); * \li 'cipherlist' a valid pointer to a non empty string. */ +void +isc_tlsctx_prefer_server_ciphers(isc_tlsctx_t *ctx, const bool prefer); +/*%< + * Make the given TLS context 'ctx' to prefer or to not prefer + * server side ciphers during the ciphers negotiation. + * + * Requires: + * \li 'ctx' != NULL. + */ + isc_tls_t * isc_tls_create(isc_tlsctx_t *ctx); /*%< diff --git a/lib/isc/tls.c b/lib/isc/tls.c index cec6c5ff43..f2dcbf187b 100644 --- a/lib/isc/tls.c +++ b/lib/isc/tls.c @@ -562,6 +562,18 @@ isc_tlsctx_set_cipherlist(isc_tlsctx_t *ctx, const char *cipherlist) { RUNTIME_CHECK(SSL_CTX_set_cipher_list(ctx, cipherlist) == 1); } +void +isc_tlsctx_prefer_server_ciphers(isc_tlsctx_t *ctx, const bool prefer) { + REQUIRE(ctx != NULL); + + if (prefer) { + (void)SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); + } else { + (void)SSL_CTX_clear_options(ctx, + SSL_OP_CIPHER_SERVER_PREFERENCE); + } +} + isc_tls_t * isc_tls_create(isc_tlsctx_t *ctx) { isc_tls_t *newctx = NULL; diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index ceea97480a..0f8329f26a 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -3890,6 +3890,7 @@ static cfg_clausedef_t tls_clauses[] = { { "dhparam-file", &cfg_type_qstring, 0 }, { "protocols", &cfg_type_tlsprotos, 0 }, { "ciphers", &cfg_type_astring, 0 }, + { "prefer-server-ciphers", &cfg_type_boolean, 0 }, { NULL, NULL, 0 } }; diff --git a/lib/ns/include/ns/listenlist.h b/lib/ns/include/ns/listenlist.h index 5b8d68edb9..207c1f6ab3 100644 --- a/lib/ns/include/ns/listenlist.h +++ b/lib/ns/include/ns/listenlist.h @@ -65,6 +65,8 @@ typedef struct ns_listen_tls_params { uint32_t protocols; const char *dhparam_file; const char *ciphers; + bool prefer_server_ciphers; + bool prefer_server_ciphers_set; } ns_listen_tls_params_t; /*** diff --git a/lib/ns/listenlist.c b/lib/ns/listenlist.c index 68aab57cfa..600ee64ceb 100644 --- a/lib/ns/listenlist.c +++ b/lib/ns/listenlist.c @@ -59,6 +59,11 @@ ns_listenelt_create(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp, if (tls_params->ciphers != NULL) { isc_tlsctx_set_cipherlist(sslctx, tls_params->ciphers); } + + if (tls_params->prefer_server_ciphers_set) { + isc_tlsctx_prefer_server_ciphers( + sslctx, tls_params->prefer_server_ciphers); + } } elt = isc_mem_get(mctx, sizeof(*elt));