]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add "ciphers" options to the "tls" clause
authorArtem Boldariev <artem@boldariev.com>
Mon, 20 Sep 2021 11:25:59 +0000 (14:25 +0300)
committerArtem Boldariev <artem@boldariev.com>
Fri, 1 Oct 2021 12:50:43 +0000 (15:50 +0300)
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.

16 files changed:
bin/named/named.conf.rst
bin/named/server.c
bin/tests/system/checkconf/bad-dot-badciphers.conf [new file with mode: 0644]
bin/tests/system/checkconf/good-doh-tlsopts.conf
bin/tests/system/checkconf/good-dot-tlsopts.conf
doc/arm/reference.rst
doc/man/named.conf.5in
doc/misc/options
doc/misc/options.active
doc/misc/tls.grammar.rst
lib/bind9/check.c
lib/isc/include/isc/tls.h
lib/isc/tls.c
lib/isccfg/namedconf.c
lib/ns/include/ns/listenlist.h
lib/ns/listenlist.c

index 5d2c011f1cab65bc151f9ec891ac243ad270add7..d1818a7ef6ba0443861950e0e3a5c4cc447f4754 100644 (file)
@@ -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;
index aacc18845a738726427fa0bfde2861b092b19bd5..d3e8d802d6218adfc20461af8cb850e2af77f872 100644 (file)
@@ -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 (file)
index 0000000..e4a0abc
--- /dev/null
@@ -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; };
+};
index 4ef244a01e945d35c7004a3f7d2fd4b328aaa640..7583c70cd503f14bf5586ce12d5fec7de884fdc5 100644 (file)
@@ -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 {
index 62d4b8066d5f6a7794dbaadca8f54dc594972872..1a0029d22013464dd260fa4daace4da3d20af746 100644 (file)
@@ -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 {
index 7b61d2862a7fad6ad75ed46dee487a53fd930ce5..46f24ec5366b2995962059e2ff13ad18891b41fb 100644 (file)
@@ -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
index 1c6d7c90757d8030d53570fd70b56d8dbf0105df..eb7cf4c5606f890426760f572b004d5ff8af2fab 100644 (file)
@@ -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;
index 72b32fb9f40d31cb1bf769a4a6d9c21b9d8f500c..1a708a616360700235072ec2f06627778058bb5d 100644 (file)
@@ -459,7 +459,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>;
index b2fecd6f69ec17ef9080ca313bf1108d2973b53e..91a555f5a52a0481e41c77f1469bb95b5b889005 100644 (file)
@@ -456,7 +456,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>;
index 60035e5ae8438a5a89d92eca20069df838bcc8ba..17c0c36bac11a9ca214dfedc434294a35dcd73fc 100644 (file)
@@ -3,7 +3,7 @@
   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>;
index d9c14127dd1f17830b285f382c485cdfdba7ffb2..84b899953a37b2ccfd11902dcb8c47c9c62bb3d6 100644 (file)
@@ -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);
 }
 
index 594d40bf4d7b329121bea6664a4643d480f75a3a..90f185e825c95dfec0724e650b405d03e9b09a55 100644 (file)
@@ -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);
 /*%<
index 1fc1362a13d2a7e93578aeb1ccea045d04ae0175..cec6c5ff43365ec7c443012ab13379daf1ab6d29 100644 (file)
@@ -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;
index 63c66da7b00c1d66c6fe5e9ea06d2dac89451acd..ceea97480a60ae3ccf7bda2b7fe3f7f7b68e8182 100644 (file)
@@ -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 }
 };
 
index 2fd341318e83fa2f17fa2a019a0f2973aeb77b2e..5b8d68edb9e920c1e956530a183e3d3962303cfe 100644 (file)
@@ -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;
 
 /***
index 001821246e0ef195c2b6960d39fc14e768021d09..68aab57cfa39650c8ce8d48cf33290cac650e6a6 100644 (file)
@@ -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));