From: Artem Boldariev Date: Mon, 20 Sep 2021 11:25:59 +0000 (+0300) Subject: Add "ciphers" options to the "tls" clause X-Git-Tag: v9.17.19~17^2~8 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3b88d783a2eb40c1c597c597942c2c08659b7ffb;p=thirdparty%2Fbind9.git Add "ciphers" options to the "tls" clause This commit adds support for setting TLS cipher list string in the format specified in the OpenSSL documentation (https://www.openssl.org/docs/man1.1.1/man1/ciphers.html). The syntax of the cipher list is verified so that specifying the wrong string will prevent the configuration from being loaded. --- diff --git a/bin/named/named.conf.rst b/bin/named/named.conf.rst index 5d2c011f1ca..d1818a7ef6b 100644 --- a/bin/named/named.conf.rst +++ b/bin/named/named.conf.rst @@ -563,7 +563,7 @@ TLS tls string { ca-file quoted_string; cert-file quoted_string; - ciphers string; // experimental + ciphers string; dhparam-file quoted_string; hostname quoted_string; key-file quoted_string; diff --git a/bin/named/server.c b/bin/named/server.c index aacc18845a7..d3e8d802d62 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -11023,7 +11023,8 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, const cfg_obj_t *http_server = NULL; in_port_t port = 0; isc_dscp_t dscp = -1; - const char *key = NULL, *cert = NULL, *dhparam_file = NULL; + const char *key = NULL, *cert = NULL, *dhparam_file = NULL, + *ciphers = NULL; bool do_tls = false, no_tls = false, http = false; ns_listenelt_t *delt = NULL; uint32_t tls_protos = 0; @@ -11047,6 +11048,7 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, *dhparam_obj = NULL; const cfg_obj_t *tlsmap = NULL; const cfg_obj_t *tls_proto_list = NULL; + const cfg_obj_t *ciphers_obj = NULL; do_tls = true; @@ -11090,13 +11092,19 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, ISC_R_SUCCESS) { dhparam_file = cfg_obj_asstring(dhparam_obj); } + + if (cfg_map_get(tlsmap, "ciphers", &ciphers_obj) == + ISC_R_SUCCESS) { + ciphers = cfg_obj_asstring(ciphers_obj); + } } } tls_params = (ns_listen_tls_params_t){ .key = key, .cert = cert, .protocols = tls_protos, - .dhparam_file = dhparam_file }; + .dhparam_file = dhparam_file, + .ciphers = ciphers }; httpobj = cfg_tuple_get(ltup, "http"); if (httpobj != NULL && cfg_obj_isstring(httpobj)) { diff --git a/bin/tests/system/checkconf/bad-dot-badciphers.conf b/bin/tests/system/checkconf/bad-dot-badciphers.conf new file mode 100644 index 00000000000..e4a0abca20b --- /dev/null +++ b/bin/tests/system/checkconf/bad-dot-badciphers.conf @@ -0,0 +1,20 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +tls local-tls { + key-file "key.pem"; + cert-file "cert.pem"; + ciphers "$bad:ciphers"; +}; + +options { + listen-on port 853 tls local-tls { 10.53.0.1; }; +}; diff --git a/bin/tests/system/checkconf/good-doh-tlsopts.conf b/bin/tests/system/checkconf/good-doh-tlsopts.conf index 4ef244a01e9..7583c70cd50 100644 --- a/bin/tests/system/checkconf/good-doh-tlsopts.conf +++ b/bin/tests/system/checkconf/good-doh-tlsopts.conf @@ -14,6 +14,7 @@ tls local-tls { key-file "key.pem"; cert-file "cert.pem"; dhparam-file "dhparam.pem"; + ciphers "HIGH:!aNULL:!MD5:!RC4"; }; 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 62d4b8066d5..1a0029d2201 100644 --- a/bin/tests/system/checkconf/good-dot-tlsopts.conf +++ b/bin/tests/system/checkconf/good-dot-tlsopts.conf @@ -14,6 +14,7 @@ tls local-tls { key-file "key.pem"; cert-file "cert.pem"; dhparam-file "dhparam.pem"; + ciphers "HIGH:!aNULL:!MD5:!RC4"; }; options { diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst index 7b61d2862a7..46f24ec5366 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``, and ``protocols``. + Specifies configuration information for a TLS connection, including a ``key-file``, ``cert-file``, ``ca-file``, ``dhparam-file``, ``hostname``, ``ciphers``, and ``protocols``. ``http`` Specifies configuration information for an HTTP connection, including ``endponts``, ``listener-clients`` and ``streams-per-connection``. @@ -4785,6 +4785,13 @@ The following options can be specified in a ``tls`` statement: versions might be specified (e.g. ``protocols { TLSv1.2; TLSv1.3; };``). + ``ciphers`` + Cipher list which defines allowed ciphers, such as + ``HIGH:!aNULL:!MD5:!SHA1:!SHA256:!SHA384``. The string must be + formed according to the rules specified in the OpenSSL documentation + (see https://www.openssl.org/docs/man1.1.1/man1/ciphers.html + for details). + 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 1c6d7c90757..eb7cf4c5606 100644 --- a/doc/man/named.conf.5in +++ b/doc/man/named.conf.5in @@ -654,7 +654,7 @@ statistics\-channels { tls string { ca\-file quoted_string; cert\-file quoted_string; - ciphers string; // experimental + ciphers string; dhparam\-file quoted_string; hostname quoted_string; key\-file quoted_string; diff --git a/doc/misc/options b/doc/misc/options index 72b32fb9f40..1a708a61636 100644 --- a/doc/misc/options +++ b/doc/misc/options @@ -459,7 +459,7 @@ statistics-channels { tls { ca-file ; cert-file ; - ciphers ; // experimental + ciphers ; dhparam-file ; hostname ; key-file ; diff --git a/doc/misc/options.active b/doc/misc/options.active index b2fecd6f69e..91a555f5a52 100644 --- a/doc/misc/options.active +++ b/doc/misc/options.active @@ -456,7 +456,7 @@ statistics-channels { tls { ca-file ; cert-file ; - ciphers ; // experimental + ciphers ; dhparam-file ; hostname ; key-file ; diff --git a/doc/misc/tls.grammar.rst b/doc/misc/tls.grammar.rst index 60035e5ae84..17c0c36bac1 100644 --- a/doc/misc/tls.grammar.rst +++ b/doc/misc/tls.grammar.rst @@ -3,7 +3,7 @@ tls { ca-file ; cert-file ; - ciphers ; // experimental + ciphers ; dhparam-file ; hostname ; key-file ; diff --git a/lib/bind9/check.c b/lib/bind9/check.c index d9c14127dd1..84b899953a3 100644 --- a/lib/bind9/check.c +++ b/lib/bind9/check.c @@ -2123,7 +2123,7 @@ bind9_check_tls_defintion(const cfg_obj_t *tlsobj, const char *name, isc_log_t *logctx, isc_symtab_t *symtab) { isc_result_t result, tresult; const cfg_obj_t *tls_proto_list = NULL, *tls_key = NULL, - *tls_cert = NULL; + *tls_cert = NULL, *tls_ciphers = NULL; uint32_t tls_protos = 0; isc_symvalue_t symvalue; @@ -2224,6 +2224,20 @@ bind9_check_tls_defintion(const cfg_obj_t *tlsobj, const char *name, } } + /* Check cipher list string is valid */ + tresult = cfg_map_get(tlsobj, "ciphers", &tls_ciphers); + if (tresult == ISC_R_SUCCESS) { + const char *ciphers = cfg_obj_asstring(tls_ciphers); + if (!isc_tls_cipherlist_valid(ciphers)) { + cfg_obj_log(tls_ciphers, logctx, ISC_LOG_ERROR, + "'ciphers' in the 'tls' clause '%s' is " + "not a " + "valid cipher list string", + name); + result = ISC_R_FAILURE; + } + } + return (result); } diff --git a/lib/isc/include/isc/tls.h b/lib/isc/include/isc/tls.h index 594d40bf4d7..90f185e825c 100644 --- a/lib/isc/include/isc/tls.h +++ b/lib/isc/include/isc/tls.h @@ -95,6 +95,25 @@ isc_tlsctx_load_dhparams(isc_tlsctx_t *ctx, const char *dhparams_file); * \li 'dhaprams_file' a valid pointer to a non empty string. */ +bool +isc_tls_cipherlist_valid(const char *cipherlist); +/*%< + * Check if cipher list string is valid. + * + * Requires: + * \li 'cipherlist' a valid pointer to a non empty string. + */ + +void +isc_tlsctx_set_cipherlist(isc_tlsctx_t *ctx, const char *cipherlist); +/*%< + * Set cipher list string for on the given TLS context 'ctx'. + * + * Requires: + * \li 'ctx' != NULL; + * \li 'cipherlist' a valid pointer to a non empty string. + */ + isc_tls_t * isc_tls_create(isc_tlsctx_t *ctx); /*%< diff --git a/lib/isc/tls.c b/lib/isc/tls.c index 1fc1362a13d..cec6c5ff433 100644 --- a/lib/isc/tls.c +++ b/lib/isc/tls.c @@ -526,6 +526,42 @@ isc_tlsctx_load_dhparams(isc_tlsctx_t *ctx, const char *dhparams_file) { return (true); } +bool +isc_tls_cipherlist_valid(const char *cipherlist) { + isc_tlsctx_t *tmp_ctx = NULL; + const SSL_METHOD *method = NULL; + bool result; + REQUIRE(cipherlist != NULL); + + if (*cipherlist == '\0') { + return (false); + } + + method = TLS_server_method(); + if (method == NULL) { + return (false); + } + tmp_ctx = SSL_CTX_new(method); + if (tmp_ctx == NULL) { + return (false); + } + + result = SSL_CTX_set_cipher_list(tmp_ctx, cipherlist) == 1; + + isc_tlsctx_free(&tmp_ctx); + + return (result); +} + +void +isc_tlsctx_set_cipherlist(isc_tlsctx_t *ctx, const char *cipherlist) { + REQUIRE(ctx != NULL); + REQUIRE(cipherlist != NULL); + REQUIRE(*cipherlist != '\0'); + + RUNTIME_CHECK(SSL_CTX_set_cipher_list(ctx, cipherlist) == 1); +} + 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 63c66da7b00..ceea97480a6 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -3889,7 +3889,7 @@ static cfg_clausedef_t tls_clauses[] = { { "hostname", &cfg_type_qstring, 0 }, { "dhparam-file", &cfg_type_qstring, 0 }, { "protocols", &cfg_type_tlsprotos, 0 }, - { "ciphers", &cfg_type_astring, CFG_CLAUSEFLAG_EXPERIMENTAL }, + { "ciphers", &cfg_type_astring, 0 }, { NULL, NULL, 0 } }; diff --git a/lib/ns/include/ns/listenlist.h b/lib/ns/include/ns/listenlist.h index 2fd341318e8..5b8d68edb9e 100644 --- a/lib/ns/include/ns/listenlist.h +++ b/lib/ns/include/ns/listenlist.h @@ -64,6 +64,7 @@ typedef struct ns_listen_tls_params { const char *cert; uint32_t protocols; const char *dhparam_file; + const char *ciphers; } ns_listen_tls_params_t; /*** diff --git a/lib/ns/listenlist.c b/lib/ns/listenlist.c index 001821246e0..68aab57cfa3 100644 --- a/lib/ns/listenlist.c +++ b/lib/ns/listenlist.c @@ -55,6 +55,10 @@ ns_listenelt_create(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp, return (ISC_R_FAILURE); } } + + if (tls_params->ciphers != NULL) { + isc_tlsctx_set_cipherlist(sslctx, tls_params->ciphers); + } } elt = isc_mem_get(mctx, sizeof(*elt));