From 9e039986cd066f0e26560bc4182e5725fc2131db Mon Sep 17 00:00:00 2001 From: Artem Boldariev Date: Mon, 13 Sep 2021 14:00:35 +0300 Subject: [PATCH 01/12] TLS: set some common options both for client and server contexts This commit makes the TLS context manipulation code set some of the common protocol versions regardless of the OpenSSL version in use. --- lib/isc/tls.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/isc/tls.c b/lib/isc/tls.c index ad0cb74168..1f9d7f9319 100644 --- a/lib/isc/tls.c +++ b/lib/isc/tls.c @@ -33,6 +33,9 @@ #include "openssl_shim.h" #include "tls_p.h" +#define COMMON_SSL_OPTIONS \ + (SSL_OP_NO_COMPRESSION | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION) + static isc_once_t init_once = ISC_ONCE_INIT; static isc_once_t shut_once = ISC_ONCE_INIT; static atomic_bool init_done = ATOMIC_VAR_INIT(false); @@ -185,13 +188,13 @@ isc_tlsctx_createclient(isc_tlsctx_t **ctxp) { goto ssl_error; } + SSL_CTX_set_options(ctx, COMMON_SSL_OPTIONS); + #if HAVE_SSL_CTX_SET_MIN_PROTO_VERSION SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); #else - SSL_CTX_set_options( - ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | - SSL_OP_NO_TLSv1_1 | SSL_OP_NO_COMPRESSION | - SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); + SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | + SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1); #endif *ctxp = ctx; @@ -235,6 +238,8 @@ isc_tlsctx_createserver(const char *keyfile, const char *certfile, } RUNTIME_CHECK(ctx != NULL); + SSL_CTX_set_options(ctx, COMMON_SSL_OPTIONS); + #if HAVE_SSL_CTX_SET_MIN_PROTO_VERSION SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); #else From 992f81577011b89fecf67d8672fb4e9743a79487 Mon Sep 17 00:00:00 2001 From: Artem Boldariev Date: Mon, 13 Sep 2021 15:39:36 +0300 Subject: [PATCH 02/12] Add "protocols" options to the "tls" clause This commit adds the ability to specify allowed TLS protocols versions within the "tls" clause. If an unsupported TLS protocol version is specified in a file, the configuration file will not pass verification. Also, this commit adds strict checks for "tls" clauses verification, in particular: - it ensures that loading configuration files containing duplicated "tls" clauses is not allowed; - it ensures that loading configuration files containing "tls" clauses missing "cert-file" or "key-file" is not allowed; - it ensures that loading configuration files containing "tls" clauses named as "ephemeral" or "none" is not allowed. --- bin/named/named.conf.rst | 2 +- bin/named/server.c | 57 +++++-- .../system/checkconf/bad-dot-badprotocol.conf | 20 +++ .../checkconf/bad-dot-duplicatetls.conf | 24 +++ .../system/checkconf/bad-dot-ephemeral.conf | 20 +++ .../system/checkconf/bad-dot-nocert.conf | 30 ++++ bin/tests/system/checkconf/bad-dot-nokey.conf | 30 ++++ bin/tests/system/checkconf/bad-dot-none.conf | 20 +++ .../system/checkconf/good-doh-tlsopts.conf | 32 ++++ .../system/checkconf/good-dot-tlsopts.conf | 20 +++ doc/arm/reference.rst | 8 +- doc/man/named.conf.5in | 2 +- doc/misc/options | 2 +- doc/misc/options.active | 2 +- doc/misc/tls.grammar.rst | 2 +- lib/bind9/check.c | 150 ++++++++++++++++++ lib/isc/include/isc/tls.h | 34 ++++ lib/isc/tls.c | 96 +++++++++++ lib/isccfg/namedconf.c | 12 +- lib/ns/include/ns/listenlist.h | 20 ++- lib/ns/listenlist.c | 23 ++- 21 files changed, 571 insertions(+), 35 deletions(-) create mode 100644 bin/tests/system/checkconf/bad-dot-badprotocol.conf create mode 100644 bin/tests/system/checkconf/bad-dot-duplicatetls.conf create mode 100644 bin/tests/system/checkconf/bad-dot-ephemeral.conf create mode 100644 bin/tests/system/checkconf/bad-dot-nocert.conf create mode 100644 bin/tests/system/checkconf/bad-dot-nokey.conf create mode 100644 bin/tests/system/checkconf/bad-dot-none.conf create mode 100644 bin/tests/system/checkconf/good-doh-tlsopts.conf create mode 100644 bin/tests/system/checkconf/good-dot-tlsopts.conf diff --git a/bin/named/named.conf.rst b/bin/named/named.conf.rst index d805ff65ad..051f9bf3fe 100644 --- a/bin/named/named.conf.rst +++ b/bin/named/named.conf.rst @@ -567,7 +567,7 @@ TLS dh-param quoted_string; // experimental hostname quoted_string; key-file quoted_string; - protocols sslprotos; // experimental + protocols { string; ... }; }; TRUST-ANCHORS diff --git a/bin/named/server.c b/bin/named/server.c index 4183786f63..d73210f38e 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -413,9 +413,9 @@ named_server_reload(isc_task_t *task, isc_event_t *event); #ifdef HAVE_LIBNGHTTP2 static isc_result_t -listenelt_http(const cfg_obj_t *http, bool tls, const char *key, - const char *cert, in_port_t port, isc_mem_t *mctx, - ns_listenelt_t **target); +listenelt_http(const cfg_obj_t *http, bool tls, + const ns_listen_tls_params_t *tls_params, in_port_t port, + isc_mem_t *mctx, ns_listenelt_t **target); #endif static isc_result_t @@ -11026,6 +11026,8 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, const char *key = NULL, *cert = NULL; bool do_tls = false, no_tls = false, http = false; ns_listenelt_t *delt = NULL; + uint32_t tls_protos = 0; + ns_listen_tls_params_t tls_params = { 0 }; REQUIRE(target != NULL && *target == NULL); @@ -11043,6 +11045,7 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, } else { const cfg_obj_t *keyobj = NULL, *certobj = NULL; const cfg_obj_t *tlsmap = NULL; + const cfg_obj_t *tls_proto_list = NULL; do_tls = true; @@ -11059,9 +11062,35 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, CHECK(cfg_map_get(tlsmap, "cert-file", &certobj)); cert = cfg_obj_asstring(certobj); + + if (cfg_map_get(tlsmap, "protocols", &tls_proto_list) == + ISC_R_SUCCESS) { + const cfg_listelt_t *proto = NULL; + INSIST(tls_proto_list != NULL); + for (proto = cfg_list_first(tls_proto_list); + proto != 0; proto = cfg_list_next(proto)) + { + const cfg_obj_t *tls_proto_obj = + cfg_listelt_value(proto); + const char *tls_sver = + cfg_obj_asstring(tls_proto_obj); + const isc_tls_protocol_version_t ver = + isc_tls_protocol_name_to_version( + tls_sver); + + INSIST(ver != + ISC_TLS_PROTO_VER_UNDEFINED); + INSIST(isc_tls_protocol_supported(ver)); + tls_protos |= ver; + } + } } } + tls_params = (ns_listen_tls_params_t){ .key = key, + .cert = cert, + .protocols = tls_protos }; + httpobj = cfg_tuple_get(ltup, "http"); if (httpobj != NULL && cfg_obj_isstring(httpobj)) { const char *httpname = cfg_obj_asstring(httpobj); @@ -11144,14 +11173,14 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, #ifdef HAVE_LIBNGHTTP2 if (http) { - CHECK(listenelt_http(http_server, do_tls, key, cert, port, mctx, - &delt)); + CHECK(listenelt_http(http_server, do_tls, &tls_params, port, + mctx, &delt)); } #endif /* HAVE_LIBNGHTTP2 */ if (!http) { - CHECK(ns_listenelt_create(mctx, port, dscp, NULL, do_tls, key, - cert, &delt)); + CHECK(ns_listenelt_create(mctx, port, dscp, NULL, do_tls, + &tls_params, &delt)); } result = cfg_acl_fromconfig2(cfg_tuple_get(listener, "acl"), config, @@ -11169,9 +11198,9 @@ cleanup: #ifdef HAVE_LIBNGHTTP2 static isc_result_t -listenelt_http(const cfg_obj_t *http, bool tls, const char *key, - const char *cert, in_port_t port, isc_mem_t *mctx, - ns_listenelt_t **target) { +listenelt_http(const cfg_obj_t *http, bool tls, + const ns_listen_tls_params_t *tls_params, in_port_t port, + isc_mem_t *mctx, ns_listenelt_t **target) { isc_result_t result = ISC_R_SUCCESS; ns_listenelt_t *delt = NULL; char **endpoints = NULL; @@ -11184,7 +11213,11 @@ listenelt_http(const cfg_obj_t *http, bool tls, const char *key, isc_quota_t *quota = NULL; REQUIRE(target != NULL && *target == NULL); - REQUIRE((key == NULL) == (cert == NULL)); + + if (tls) { + INSIST(tls_params != NULL); + INSIST((tls_params->key == NULL) == (tls_params->cert == NULL)); + } if (port == 0) { port = tls ? named_g_httpsport : named_g_httpport; @@ -11239,7 +11272,7 @@ listenelt_http(const cfg_obj_t *http, bool tls, const char *key, isc_quota_init(quota, max_clients); } result = ns_listenelt_create_http(mctx, port, named_g_dscp, NULL, tls, - key, cert, endpoints, len, quota, + tls_params, endpoints, len, quota, max_streams, &delt); if (result != ISC_R_SUCCESS) { goto error; diff --git a/bin/tests/system/checkconf/bad-dot-badprotocol.conf b/bin/tests/system/checkconf/bad-dot-badprotocol.conf new file mode 100644 index 0000000000..da3b5edeb1 --- /dev/null +++ b/bin/tests/system/checkconf/bad-dot-badprotocol.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"; + protocols { unknown; TLSv1.2; }; # bad TLS protocol version name +}; + +options { + listen-on port 853 tls local-tls { 10.53.0.1; }; +}; diff --git a/bin/tests/system/checkconf/bad-dot-duplicatetls.conf b/bin/tests/system/checkconf/bad-dot-duplicatetls.conf new file mode 100644 index 0000000000..63f5874e7e --- /dev/null +++ b/bin/tests/system/checkconf/bad-dot-duplicatetls.conf @@ -0,0 +1,24 @@ +/* + * 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"; +}; + +tls local-tls { + key-file "key.pem"; + cert-file "cert.pem"; +}; + +options { + listen-on port 853 tls local-tls { 10.53.0.1; }; +}; diff --git a/bin/tests/system/checkconf/bad-dot-ephemeral.conf b/bin/tests/system/checkconf/bad-dot-ephemeral.conf new file mode 100644 index 0000000000..3f0273036f --- /dev/null +++ b/bin/tests/system/checkconf/bad-dot-ephemeral.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. + */ + +# ephemeral is reserved for internal use +tls ephemeral { + key-file "key.pem"; + cert-file "cert.pem"; +}; + +options { + listen-on port 853 tls ephemeral { 10.53.0.1; }; +}; diff --git a/bin/tests/system/checkconf/bad-dot-nocert.conf b/bin/tests/system/checkconf/bad-dot-nocert.conf new file mode 100644 index 0000000000..20c1eaf837 --- /dev/null +++ b/bin/tests/system/checkconf/bad-dot-nocert.conf @@ -0,0 +1,30 @@ +/* + * 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"; +}; + +http local-http-server { + endpoints { "/dns-query"; }; + listener-clients 100; + streams-per-connection 100; +}; + +options { + listen-on { 10.53.0.1; }; + http-port 80; + https-port 443; + http-listener-clients 100; + http-streams-per-connection 100; + listen-on port 443 tls local-tls http local-http-server { 10.53.0.1; }; + listen-on port 8080 tls none http local-http-server { 10.53.0.1; }; +}; diff --git a/bin/tests/system/checkconf/bad-dot-nokey.conf b/bin/tests/system/checkconf/bad-dot-nokey.conf new file mode 100644 index 0000000000..a6798bafee --- /dev/null +++ b/bin/tests/system/checkconf/bad-dot-nokey.conf @@ -0,0 +1,30 @@ +/* + * 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 { + cert-file "cert.pem"; +}; + +http local-http-server { + endpoints { "/dns-query"; }; + listener-clients 100; + streams-per-connection 100; +}; + +options { + listen-on { 10.53.0.1; }; + http-port 80; + https-port 443; + http-listener-clients 100; + http-streams-per-connection 100; + listen-on port 443 tls local-tls http local-http-server { 10.53.0.1; }; + listen-on port 8080 tls none http local-http-server { 10.53.0.1; }; +}; diff --git a/bin/tests/system/checkconf/bad-dot-none.conf b/bin/tests/system/checkconf/bad-dot-none.conf new file mode 100644 index 0000000000..1eebc253d3 --- /dev/null +++ b/bin/tests/system/checkconf/bad-dot-none.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. + */ + +# none is reserved for internal use +tls none { + key-file "key.pem"; + cert-file "cert.pem"; +}; + +options { + listen-on port 853 tls none { 10.53.0.1; }; +}; diff --git a/bin/tests/system/checkconf/good-doh-tlsopts.conf b/bin/tests/system/checkconf/good-doh-tlsopts.conf new file mode 100644 index 0000000000..90a2f95733 --- /dev/null +++ b/bin/tests/system/checkconf/good-doh-tlsopts.conf @@ -0,0 +1,32 @@ +/* + * 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 { + protocols { TLSv1.2; }; + key-file "key.pem"; + cert-file "cert.pem"; +}; + +http local-http-server { + endpoints { "/dns-query"; }; + listener-clients 100; + streams-per-connection 100; +}; + +options { + listen-on { 10.53.0.1; }; + http-port 80; + https-port 443; + http-listener-clients 100; + http-streams-per-connection 100; + listen-on port 443 tls local-tls http local-http-server { 10.53.0.1; }; + listen-on port 8080 tls none http local-http-server { 10.53.0.1; }; +}; diff --git a/bin/tests/system/checkconf/good-dot-tlsopts.conf b/bin/tests/system/checkconf/good-dot-tlsopts.conf new file mode 100644 index 0000000000..3552eef0aa --- /dev/null +++ b/bin/tests/system/checkconf/good-dot-tlsopts.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 { + protocols { TLSv1.2; }; + key-file "key.pem"; + cert-file "cert.pem"; +}; + +options { + listen-on port 853 tls local-tls { 10.53.0.1; }; +}; diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst index 0a4627bf40..b36db11467 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`` and ``hostname``. + Specifies configuration information for a TLS connection, including a ``key-file``, ``cert-file``, ``ca-file``, ``hostname``, and ``protocols``. ``http`` Specifies configuration information for an HTTP connection, including ``endponts``, ``listener-clients`` and ``streams-per-connection``. @@ -4772,6 +4772,12 @@ The following options can be specified in a ``tls`` statement: ``hostname`` The hostname associated with the certificate. + ``protocols`` + Allowed versions of the TLS protocol. TLS version 1.2 and higher are + supported, depending on the cryptographic library in use. Multiple + versions might be specified (e.g. + ``protocols { TLSv1.2; TLSv1.3; };``). + 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 d22ad8022d..0cce71b677 100644 --- a/doc/man/named.conf.5in +++ b/doc/man/named.conf.5in @@ -658,7 +658,7 @@ tls string { dh\-param quoted_string; // experimental hostname quoted_string; key\-file quoted_string; - protocols sslprotos; // experimental + protocols { string; ... }; }; .ft P .fi diff --git a/doc/misc/options b/doc/misc/options index 7b82fcec62..aa89cd4ed1 100644 --- a/doc/misc/options +++ b/doc/misc/options @@ -463,7 +463,7 @@ tls { dh-param ; // experimental hostname ; key-file ; - protocols ; // experimental + protocols { ; ... }; }; // may occur multiple times trust-anchors { ( static-key | diff --git a/doc/misc/options.active b/doc/misc/options.active index b76a310443..a745dc6327 100644 --- a/doc/misc/options.active +++ b/doc/misc/options.active @@ -460,7 +460,7 @@ tls { dh-param ; // experimental hostname ; key-file ; - protocols ; // experimental + protocols { ; ... }; }; // may occur multiple times trust-anchors { ( static-key | diff --git a/doc/misc/tls.grammar.rst b/doc/misc/tls.grammar.rst index f610a77d59..c0b5a48819 100644 --- a/doc/misc/tls.grammar.rst +++ b/doc/misc/tls.grammar.rst @@ -7,5 +7,5 @@ dh-param ; // experimental hostname ; key-file ; - protocols ; // experimental + protocols { ; ... }; }; diff --git a/lib/bind9/check.c b/lib/bind9/check.c index 88dcc4d73c..d9c14127dd 100644 --- a/lib/bind9/check.c +++ b/lib/bind9/check.c @@ -16,6 +16,8 @@ #include #include +#include + #ifdef HAVE_DNSTAP #include #endif @@ -2116,6 +2118,149 @@ done: } #endif /* HAVE_LIBNGHTTP2 */ +static isc_result_t +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; + uint32_t tls_protos = 0; + isc_symvalue_t symvalue; + + if (strcasecmp(name, "ephemeral") == 0 || strcasecmp(name, "none") == 0) + { + cfg_obj_log(tlsobj, logctx, ISC_LOG_ERROR, + "tls clause name '%s' is reserved for internal use", + name); + result = ISC_R_FAILURE; + } else { + /* Check for duplicates */ + symvalue.as_cpointer = tlsobj; + result = isc_symtab_define(symtab, name, 1, symvalue, + isc_symexists_reject); + if (result == ISC_R_EXISTS) { + const char *file = NULL; + unsigned int line; + + tresult = isc_symtab_lookup(symtab, name, 1, &symvalue); + RUNTIME_CHECK(tresult == ISC_R_SUCCESS); + + line = cfg_obj_line(symvalue.as_cpointer); + file = cfg_obj_file(symvalue.as_cpointer); + if (file == NULL) { + file = ""; + } + + cfg_obj_log(tlsobj, logctx, ISC_LOG_ERROR, + "tls clause '%s' is duplicated: " + "also defined at %s:%u", + name, file, line); + } + } + + if (cfg_map_get(tlsobj, "key-file", &tls_key) != ISC_R_SUCCESS) { + cfg_obj_log(tlsobj, logctx, ISC_LOG_ERROR, + "'key-file' is required in tls clause '%s'", name); + result = ISC_R_FAILURE; + } + + if (cfg_map_get(tlsobj, "cert-file", &tls_cert) != ISC_R_SUCCESS) { + cfg_obj_log(tlsobj, logctx, ISC_LOG_ERROR, + "'cert-file' is required in tls clause '%s'", name); + result = ISC_R_FAILURE; + } + + /* Check protocols are valid */ + tresult = cfg_map_get(tlsobj, "protocols", &tls_proto_list); + if (tresult == ISC_R_SUCCESS) { + const cfg_listelt_t *proto = NULL; + INSIST(tls_proto_list != NULL); + for (proto = cfg_list_first(tls_proto_list); proto != 0; + proto = cfg_list_next(proto)) + { + const cfg_obj_t *tls_proto_obj = + cfg_listelt_value(proto); + const char *tls_sver = cfg_obj_asstring(tls_proto_obj); + const isc_tls_protocol_version_t ver = + isc_tls_protocol_name_to_version(tls_sver); + + if (ver == ISC_TLS_PROTO_VER_UNDEFINED) { + cfg_obj_log(tls_proto_obj, logctx, + ISC_LOG_ERROR, + "'%s' is not a valid " + "TLS protocol version", + tls_sver); + result = ISC_R_FAILURE; + continue; + } else if (!isc_tls_protocol_supported(ver)) { + cfg_obj_log(tls_proto_obj, logctx, + ISC_LOG_ERROR, + "'%s' is not " + "supported by the " + "cryptographic library version in " + "use (%s)", + tls_sver, OPENSSL_VERSION_TEXT); + result = ISC_R_FAILURE; + } + + if ((tls_protos & ver) != 0) { + cfg_obj_log(tls_proto_obj, logctx, + ISC_LOG_WARNING, + "'%s' is specified more than once " + "in '%s'", + tls_sver, name); + result = ISC_R_FAILURE; + } + + tls_protos |= ver; + } + + if (tls_protos == 0) { + cfg_obj_log(tlsobj, logctx, ISC_LOG_ERROR, + "tls '%s' does not contain any valid " + "TLS protocol versions definitions", + name); + result = ISC_R_FAILURE; + } + } + + return (result); +} + +static isc_result_t +bind9_check_tls_definitions(const cfg_obj_t *config, isc_log_t *logctx, + isc_mem_t *mctx) { + isc_result_t result, tresult; + const cfg_obj_t *obj = NULL; + const cfg_listelt_t *elt = NULL; + isc_symtab_t *symtab = NULL; + + result = cfg_map_get(config, "tls", &obj); + if (result != ISC_R_SUCCESS) { + result = ISC_R_SUCCESS; + return (result); + } + + result = isc_symtab_create(mctx, 100, NULL, NULL, false, &symtab); + if (result != ISC_R_SUCCESS) { + return (result); + } + + for (elt = cfg_list_first(obj); elt != NULL; elt = cfg_list_next(elt)) { + const char *name; + obj = cfg_listelt_value(elt); + name = cfg_obj_asstring(cfg_map_getname(obj)); + tresult = bind9_check_tls_defintion(obj, name, logctx, symtab); + if (result == ISC_R_SUCCESS) { + result = tresult; + } + } + + isc_symtab_destroy(&symtab); + + return (result); +} + static isc_result_t get_remotes(const cfg_obj_t *cctx, const char *list, const char *name, const cfg_obj_t **ret) { @@ -5494,6 +5639,11 @@ bind9_check_namedconf(const cfg_obj_t *config, bool check_plugins, } #endif /* HAVE_LIBNGHTTP2 */ + if (bind9_check_tls_definitions(config, logctx, mctx) != ISC_R_SUCCESS) + { + result = ISC_R_FAILURE; + } + (void)cfg_map_get(config, "view", &views); if (views != NULL && options != NULL) { diff --git a/lib/isc/include/isc/tls.h b/lib/isc/include/isc/tls.h index 38c990648b..4520795644 100644 --- a/lib/isc/include/isc/tls.h +++ b/lib/isc/include/isc/tls.h @@ -50,6 +50,40 @@ isc_tlsctx_createclient(isc_tlsctx_t **ctxp); *\li 'ctxp' != NULL and '*ctxp' == NULL. */ +typedef enum isc_tls_protocol_version { + /* these must be the powers of two */ + ISC_TLS_PROTO_VER_1_2 = 1 << 0, + ISC_TLS_PROTO_VER_1_3 = 1 << 1, + ISC_TLS_PROTO_VER_UNDEFINED, +} isc_tls_protocol_version_t; + +void +isc_tlsctx_set_protocols(isc_tlsctx_t *ctx, const uint32_t tls_versions); +/*%< + * Sets the supported TLS protocol versions via the 'tls_versions' bit + * set argument (see `isc_tls_protocol_version_t` enum for the + * expected values). + * + * Requires: + *\li 'ctx' != NULL; + *\li 'tls_versions' != 0. + */ + +bool +isc_tls_protocol_supported(const isc_tls_protocol_version_t tls_ver); +/*%< + * Check in runtime that the specified TLS protocol versions is supported. + */ + +isc_tls_protocol_version_t +isc_tls_protocol_name_to_version(const char *name); +/*%< + * Convert the protocol version string into the version of + * 'isc_tls_protocol_version_t' type. + * Requires: + *\li 'name' != NULL. + */ + isc_tls_t * isc_tls_create(isc_tlsctx_t *ctx); /*%< diff --git a/lib/isc/tls.c b/lib/isc/tls.c index 1f9d7f9319..76fbe28690 100644 --- a/lib/isc/tls.c +++ b/lib/isc/tls.c @@ -10,6 +10,7 @@ */ #include +#include #if HAVE_LIBNGHTTP2 #include #endif /* HAVE_LIBNGHTTP2 */ @@ -364,6 +365,101 @@ ssl_error: return (ISC_R_TLSERROR); } +static long +get_tls_version_disable_bit(const isc_tls_protocol_version_t tls_ver) { + long bit = 0; + + switch (tls_ver) { + case ISC_TLS_PROTO_VER_1_2: +#ifdef SSL_OP_NO_TLSv1_2 + bit = SSL_OP_NO_TLSv1_2; +#else + bit = 0; +#endif + break; + case ISC_TLS_PROTO_VER_1_3: +#ifdef SSL_OP_NO_TLSv1_3 + bit = SSL_OP_NO_TLSv1_3; +#else + bit = 0; +#endif + break; + default: + INSIST(0); + ISC_UNREACHABLE(); + break; + }; + + return (bit); +} + +bool +isc_tls_protocol_supported(const isc_tls_protocol_version_t tls_ver) { + return (get_tls_version_disable_bit(tls_ver) != 0); +} + +isc_tls_protocol_version_t +isc_tls_protocol_name_to_version(const char *name) { + REQUIRE(name != NULL); + + if (strcasecmp(name, "TLSv1.2") == 0) { + return (ISC_TLS_PROTO_VER_1_2); + } else if (strcasecmp(name, "TLSv1.3") == 0) { + return (ISC_TLS_PROTO_VER_1_3); + } + + return (ISC_TLS_PROTO_VER_UNDEFINED); +} + +void +isc_tlsctx_set_protocols(isc_tlsctx_t *ctx, const uint32_t tls_versions) { + REQUIRE(ctx != NULL); + REQUIRE(tls_versions != 0); + long set_options = 0; + long clear_options = 0; + uint32_t versions = tls_versions; + + /* + * The code below might be initially hard to follow because of the + * double negation that OpenSSL enforces. + * + * Taking into account that OpenSSL provides bits to *disable* + * specific protocol versions, like SSL_OP_NO_TLSv1_2, + * SSL_OP_NO_TLSv1_3, etc., the code has the following logic: + * + * If a protocol version is not specified in the bitmask, get the + * bit that disables it and add it to the set of TLS options to + * set ('set_options'). Otherwise, if a protocol version is set, + * add the bit to the set of options to clear ('clear_options'). + */ + + /* TLS protocol versions are defined as powers of two. */ + for (uint32_t tls_ver = ISC_TLS_PROTO_VER_1_2; + tls_ver < ISC_TLS_PROTO_VER_UNDEFINED; tls_ver <<= 1) + { + /* Only supported versions should ever be passed to the + * function. The configuration file was not verified + * properly, if we are trying to enable an unsupported + * TLS version */ + INSIST(isc_tls_protocol_supported(tls_ver)); + if ((tls_versions & tls_ver) == 0) { + set_options |= get_tls_version_disable_bit(tls_ver); + } else { + clear_options |= get_tls_version_disable_bit(tls_ver); + } + versions &= ~(tls_ver); + } + + /* All versions should be processed at this point, thus the value + * must equal zero. If it is not, then some garbage has been + * passed to the function; this situation is worth + * investigation. */ + INSIST(versions == 0); + + (void)SSL_CTX_set_options(ctx, set_options); + (void)SSL_CTX_clear_options(ctx, clear_options); +} + 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 8cd23814d0..1427d4fd5e 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -3875,10 +3875,12 @@ cfg_print_zonegrammar(const unsigned int zonetype, unsigned int flags, /*% * "tls" and related statement syntax. */ -static cfg_type_t cfg_type_sslprotos = { - "sslprotos", cfg_parse_spacelist, cfg_print_spacelist, - cfg_doc_terminal, &cfg_rep_list, &cfg_type_astring -}; +static cfg_type_t cfg_type_tlsprotos = { "tls_protocols", + cfg_parse_bracketed_list, + cfg_print_bracketed_list, + cfg_doc_bracketed_list, + &cfg_rep_list, + &cfg_type_astring }; static cfg_clausedef_t tls_clauses[] = { { "key-file", &cfg_type_qstring, 0 }, @@ -3886,7 +3888,7 @@ static cfg_clausedef_t tls_clauses[] = { { "ca-file", &cfg_type_qstring, 0 }, { "hostname", &cfg_type_qstring, 0 }, { "dh-param", &cfg_type_qstring, CFG_CLAUSEFLAG_EXPERIMENTAL }, - { "protocols", &cfg_type_sslprotos, CFG_CLAUSEFLAG_EXPERIMENTAL }, + { "protocols", &cfg_type_tlsprotos, 0 }, { "ciphers", &cfg_type_astring, CFG_CLAUSEFLAG_EXPERIMENTAL }, { NULL, NULL, 0 } }; diff --git a/lib/ns/include/ns/listenlist.h b/lib/ns/include/ns/listenlist.h index 348b1ca894..ae13f67327 100644 --- a/lib/ns/include/ns/listenlist.h +++ b/lib/ns/include/ns/listenlist.h @@ -59,22 +59,34 @@ struct ns_listenlist { ISC_LIST(ns_listenelt_t) elts; }; +typedef struct ns_listen_tls_params { + const char *key; + const char *cert; + uint32_t protocols; +} ns_listen_tls_params_t; + /*** *** Functions ***/ isc_result_t ns_listenelt_create(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp, - dns_acl_t *acl, bool tls, const char *key, const char *cert, - ns_listenelt_t **target); + dns_acl_t *acl, bool tls, + const ns_listen_tls_params_t *tls_params, + ns_listenelt_t ** target); /*%< * Create a listen-on list element. + * + * Requires: + * \li 'targetp' is a valid pointer to a pointer containing 'NULL'; + * \li 'tls_params' is a valid, non-'NULL' pointer if 'tls' equals 'true'. */ isc_result_t ns_listenelt_create_http(isc_mem_t *mctx, in_port_t http_port, isc_dscp_t dscp, - dns_acl_t *acl, bool tls, const char *key, - const char *cert, char **endpoints, size_t nendpoints, + dns_acl_t *acl, bool tls, + const ns_listen_tls_params_t *tls_params, + char **endpoints, size_t nendpoints, isc_quota_t *quota, const uint32_t max_streams, ns_listenelt_t **target); /*%< diff --git a/lib/ns/listenlist.c b/lib/ns/listenlist.c index 9c445a710a..92ffac7979 100644 --- a/lib/ns/listenlist.c +++ b/lib/ns/listenlist.c @@ -26,19 +26,26 @@ destroy(ns_listenlist_t *list); isc_result_t ns_listenelt_create(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp, - dns_acl_t *acl, bool tls, const char *key, const char *cert, + dns_acl_t *acl, bool tls, + const ns_listen_tls_params_t *tls_params, ns_listenelt_t **target) { ns_listenelt_t *elt = NULL; isc_result_t result = ISC_R_SUCCESS; isc_tlsctx_t *sslctx = NULL; REQUIRE(target != NULL && *target == NULL); + REQUIRE(!tls || tls_params != NULL); if (tls) { - result = isc_tlsctx_createserver(key, cert, &sslctx); + result = isc_tlsctx_createserver(tls_params->key, + tls_params->cert, &sslctx); if (result != ISC_R_SUCCESS) { return (result); } + + if (tls_params->protocols != 0) { + isc_tlsctx_set_protocols(sslctx, tls_params->protocols); + } } elt = isc_mem_get(mctx, sizeof(*elt)); @@ -59,8 +66,9 @@ ns_listenelt_create(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp, isc_result_t ns_listenelt_create_http(isc_mem_t *mctx, in_port_t http_port, isc_dscp_t dscp, - dns_acl_t *acl, bool tls, const char *key, - const char *cert, char **endpoints, size_t nendpoints, + dns_acl_t *acl, bool tls, + const ns_listen_tls_params_t *tls_params, + char **endpoints, size_t nendpoints, isc_quota_t *quota, const uint32_t max_streams, ns_listenelt_t **target) { isc_result_t result; @@ -69,8 +77,8 @@ ns_listenelt_create_http(isc_mem_t *mctx, in_port_t http_port, isc_dscp_t dscp, REQUIRE(endpoints != NULL && *endpoints != NULL); REQUIRE(nendpoints > 0); - result = ns_listenelt_create(mctx, http_port, dscp, acl, tls, key, cert, - target); + result = ns_listenelt_create(mctx, http_port, dscp, acl, tls, + tls_params, target); if (result == ISC_R_SUCCESS) { (*target)->is_http = true; (*target)->http_endpoints = endpoints; @@ -164,8 +172,7 @@ ns_listenlist_default(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp, goto cleanup; } - result = ns_listenelt_create(mctx, port, dscp, acl, false, NULL, NULL, - &elt); + result = ns_listenelt_create(mctx, port, dscp, acl, false, NULL, &elt); if (result != ISC_R_SUCCESS) { goto cleanup_acl; } From f2ae4c8480737936e45fecd926aade97700ee0be Mon Sep 17 00:00:00 2001 From: Artem Boldariev Date: Thu, 16 Sep 2021 14:48:30 +0300 Subject: [PATCH 03/12] DH-parameters loading support This commit adds support for loading DH-parameters (Diffie-Hellman parameters) via the new "dhparam-file" option within "tls" clause. In particular, Diffie-Hellman parameters are needed to enable the range of forward-secrecy enabled cyphers for TLSv1.2, which are getting silently disabled otherwise. --- bin/named/named.conf.rst | 2 +- bin/named/server.c | 13 +++- .../system/checkconf/good-doh-tlsopts.conf | 1 + .../system/checkconf/good-dot-tlsopts.conf | 1 + bin/tests/system/doth/ns2/dhparam3072.pem | 11 ++++ bin/tests/system/doth/ns2/named.conf.in | 1 + doc/arm/reference.rst | 9 ++- doc/man/named.conf.5in | 2 +- doc/misc/options | 2 +- doc/misc/options.active | 2 +- doc/misc/tls.grammar.rst | 2 +- lib/isc/include/isc/tls.h | 11 ++++ lib/isc/tls.c | 66 +++++++++++++++++++ lib/isccfg/namedconf.c | 2 +- lib/ns/include/ns/listenlist.h | 1 + lib/ns/listenlist.c | 9 +++ util/copyrights | 1 + 17 files changed, 126 insertions(+), 10 deletions(-) create mode 100644 bin/tests/system/doth/ns2/dhparam3072.pem diff --git a/bin/named/named.conf.rst b/bin/named/named.conf.rst index 051f9bf3fe..5d2c011f1c 100644 --- a/bin/named/named.conf.rst +++ b/bin/named/named.conf.rst @@ -564,7 +564,7 @@ TLS ca-file quoted_string; cert-file quoted_string; ciphers string; // experimental - dh-param quoted_string; // experimental + dhparam-file quoted_string; hostname quoted_string; key-file quoted_string; protocols { string; ... }; diff --git a/bin/named/server.c b/bin/named/server.c index d73210f38e..aacc18845a 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -11023,7 +11023,7 @@ 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; + const char *key = NULL, *cert = NULL, *dhparam_file = NULL; bool do_tls = false, no_tls = false, http = false; ns_listenelt_t *delt = NULL; uint32_t tls_protos = 0; @@ -11043,7 +11043,8 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, } else if (strcasecmp(tlsname, "ephemeral") == 0) { do_tls = true; } else { - const cfg_obj_t *keyobj = NULL, *certobj = NULL; + const cfg_obj_t *keyobj = NULL, *certobj = NULL, + *dhparam_obj = NULL; const cfg_obj_t *tlsmap = NULL; const cfg_obj_t *tls_proto_list = NULL; @@ -11084,12 +11085,18 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, tls_protos |= ver; } } + + if (cfg_map_get(tlsmap, "dhparam-file", &dhparam_obj) == + ISC_R_SUCCESS) { + dhparam_file = cfg_obj_asstring(dhparam_obj); + } } } tls_params = (ns_listen_tls_params_t){ .key = key, .cert = cert, - .protocols = tls_protos }; + .protocols = tls_protos, + .dhparam_file = dhparam_file }; 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 90a2f95733..4ef244a01e 100644 --- a/bin/tests/system/checkconf/good-doh-tlsopts.conf +++ b/bin/tests/system/checkconf/good-doh-tlsopts.conf @@ -13,6 +13,7 @@ tls local-tls { protocols { TLSv1.2; }; key-file "key.pem"; cert-file "cert.pem"; + dhparam-file "dhparam.pem"; }; 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 3552eef0aa..62d4b8066d 100644 --- a/bin/tests/system/checkconf/good-dot-tlsopts.conf +++ b/bin/tests/system/checkconf/good-dot-tlsopts.conf @@ -13,6 +13,7 @@ tls local-tls { protocols { TLSv1.2; }; key-file "key.pem"; cert-file "cert.pem"; + dhparam-file "dhparam.pem"; }; options { diff --git a/bin/tests/system/doth/ns2/dhparam3072.pem b/bin/tests/system/doth/ns2/dhparam3072.pem new file mode 100644 index 0000000000..9c2e0aa42b --- /dev/null +++ b/bin/tests/system/doth/ns2/dhparam3072.pem @@ -0,0 +1,11 @@ +-----BEGIN DH PARAMETERS----- +MIIBiAKCAYEA5D/Oioe+G+EMf/9RVxmcV4rZAtqZpVTFHcX0ZulvdiQGCQmopm6K +3+0uoU2J6WVMjhna5nHD2NO9miRDI/jIxX9g9k6PedSB4o3fSTtkAnGtUbB8S+Ab +EHtWfd7FTES8P1n16HN7BfPXVbP8zTcK+jO63KdQoxueYoETcrw0Myi9Lm8ri8os +O4oQ+XAH7GzZ60bcYV9jge0XIRUGVnYZDjWMlnwMvZyjLivxKXTC9HPNA6FF1/0H +0LPhsfjdoLNsVHFzfQz7QELMfHbTd0C8y0UMDQw9FqUp0esHZ5gsTlqnDHp2ZHoR +JDfNl4yVO5Gv4HiFJ0NSdggefhESU3FRAOhMmUkctOCxk5hyPqGMsvofOajY2MBp +eCffrKuAU6/dGUeq8inwrZlAMIZ20WyskHmbHnc4DXo2Uo6xSZo3xyEq1ofXXwTZ +vPw4e12so3RJAT2a8UsHf7DG1tH+9ke7HCAJQWxUizRFRsMi1Nl/7ikS4f3zgIbX +GKz9+uk5eS6jAgEC +-----END DH PARAMETERS----- diff --git a/bin/tests/system/doth/ns2/named.conf.in b/bin/tests/system/doth/ns2/named.conf.in index 0a77cf9952..9d747c9f6a 100644 --- a/bin/tests/system/doth/ns2/named.conf.in +++ b/bin/tests/system/doth/ns2/named.conf.in @@ -18,6 +18,7 @@ controls { tls local { key-file "key.pem"; cert-file "cert.pem"; + dhparam-file "dhparam3072.pem"; }; http local { diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst index b36db11467..7b61d2862a 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``, ``hostname``, and ``protocols``. + Specifies configuration information for a TLS connection, including a ``key-file``, ``cert-file``, ``ca-file``, ``dhparam-file``, ``hostname``, and ``protocols``. ``http`` Specifies configuration information for an HTTP connection, including ``endponts``, ``listener-clients`` and ``streams-per-connection``. @@ -4769,6 +4769,13 @@ The following options can be specified in a ``tls`` statement: ``ca-file`` Path to a file containing trusted TLS certificates. + ``dhparam-file`` + Path to a file containing Diffie-Hellman parameters, + which is needed to enable the cipher suites depending on the + Diffie-Hellman ephemeral key exchange (DHE). Having these parameters + specified is essential for enabling perfect forward secrecy capable + ciphers in TLSv1.2. + ``hostname`` The hostname associated with the certificate. diff --git a/doc/man/named.conf.5in b/doc/man/named.conf.5in index 0cce71b677..1c6d7c9075 100644 --- a/doc/man/named.conf.5in +++ b/doc/man/named.conf.5in @@ -655,7 +655,7 @@ tls string { ca\-file quoted_string; cert\-file quoted_string; ciphers string; // experimental - dh\-param quoted_string; // experimental + dhparam\-file quoted_string; hostname quoted_string; key\-file quoted_string; protocols { string; ... }; diff --git a/doc/misc/options b/doc/misc/options index aa89cd4ed1..72b32fb9f4 100644 --- a/doc/misc/options +++ b/doc/misc/options @@ -460,7 +460,7 @@ tls { ca-file ; cert-file ; ciphers ; // experimental - dh-param ; // experimental + dhparam-file ; hostname ; key-file ; protocols { ; ... }; diff --git a/doc/misc/options.active b/doc/misc/options.active index a745dc6327..b2fecd6f69 100644 --- a/doc/misc/options.active +++ b/doc/misc/options.active @@ -457,7 +457,7 @@ tls { ca-file ; cert-file ; ciphers ; // experimental - dh-param ; // experimental + dhparam-file ; hostname ; key-file ; protocols { ; ... }; diff --git a/doc/misc/tls.grammar.rst b/doc/misc/tls.grammar.rst index c0b5a48819..60035e5ae8 100644 --- a/doc/misc/tls.grammar.rst +++ b/doc/misc/tls.grammar.rst @@ -4,7 +4,7 @@ ca-file ; cert-file ; ciphers ; // experimental - dh-param ; // experimental + dhparam-file ; hostname ; key-file ; protocols { ; ... }; diff --git a/lib/isc/include/isc/tls.h b/lib/isc/include/isc/tls.h index 4520795644..594d40bf4d 100644 --- a/lib/isc/include/isc/tls.h +++ b/lib/isc/include/isc/tls.h @@ -84,6 +84,17 @@ isc_tls_protocol_name_to_version(const char *name); *\li 'name' != NULL. */ +bool +isc_tlsctx_load_dhparams(isc_tlsctx_t *ctx, const char *dhparams_file); +/*%< + * Load Diffie-Hellman parameters file and apply it to the given TLS context + * 'ctx'. + * + * Requires: + * \li 'ctx' != NULL; + * \li 'dhaprams_file' 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 76fbe28690..1fc1362a13 100644 --- a/lib/isc/tls.c +++ b/lib/isc/tls.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -460,6 +461,71 @@ isc_tlsctx_set_protocols(isc_tlsctx_t *ctx, const uint32_t tls_versions) { (void)SSL_CTX_clear_options(ctx, clear_options); } +bool +isc_tlsctx_load_dhparams(isc_tlsctx_t *ctx, const char *dhparams_file) { + REQUIRE(ctx != NULL); + REQUIRE(dhparams_file != NULL); + REQUIRE(*dhparams_file != '\0'); + +#ifdef SSL_CTX_set_tmp_dh + /* OpenSSL < 3.0 */ + DH *dh = NULL; + FILE *paramfile; + + paramfile = fopen(dhparams_file, "r"); + + if (paramfile) { + int check = 0; + dh = PEM_read_DHparams(paramfile, NULL, NULL, NULL); + fclose(paramfile); + + if (dh == NULL) { + return (false); + } else if (DH_check(dh, &check) != 1 || check != 0) { + DH_free(dh); + return (false); + } + } else { + return (false); + } + + if (SSL_CTX_set_tmp_dh(ctx, dh) != 1) { + DH_free(dh); + return (false); + } + + DH_free(dh); +#else + /* OpenSSL >= 3.0: SSL_CTX_set_tmp_dh() is deprecated in OpenSSL 3.0 */ + EVP_PKEY *dh = NULL; + BIO *bio = NULL; + + bio = BIO_new_file(dhparams_file, "r"); + if (bio == NULL) { + return (false); + } + + dh = PEM_read_bio_Parameters(bio, NULL); + if (dh == NULL) { + BIO_free(bio); + return (false); + } + + if (SSL_CTX_set0_tmp_dh_pkey(ctx, dh) != 1) { + BIO_free(bio); + EVP_PKEY_free(dh); + return (false); + } + + /* No need to call EVP_PKEY_free(dh) as the "dh" is owned by the + * SSL context at this point. */ + + BIO_free(bio); +#endif + + return (true); +} + 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 1427d4fd5e..63c66da7b0 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -3887,7 +3887,7 @@ static cfg_clausedef_t tls_clauses[] = { { "cert-file", &cfg_type_qstring, 0 }, { "ca-file", &cfg_type_qstring, 0 }, { "hostname", &cfg_type_qstring, 0 }, - { "dh-param", &cfg_type_qstring, CFG_CLAUSEFLAG_EXPERIMENTAL }, + { "dhparam-file", &cfg_type_qstring, 0 }, { "protocols", &cfg_type_tlsprotos, 0 }, { "ciphers", &cfg_type_astring, CFG_CLAUSEFLAG_EXPERIMENTAL }, { NULL, NULL, 0 } diff --git a/lib/ns/include/ns/listenlist.h b/lib/ns/include/ns/listenlist.h index ae13f67327..2fd341318e 100644 --- a/lib/ns/include/ns/listenlist.h +++ b/lib/ns/include/ns/listenlist.h @@ -63,6 +63,7 @@ typedef struct ns_listen_tls_params { const char *key; const char *cert; uint32_t protocols; + const char *dhparam_file; } ns_listen_tls_params_t; /*** diff --git a/lib/ns/listenlist.c b/lib/ns/listenlist.c index 92ffac7979..001821246e 100644 --- a/lib/ns/listenlist.c +++ b/lib/ns/listenlist.c @@ -46,6 +46,15 @@ ns_listenelt_create(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp, if (tls_params->protocols != 0) { isc_tlsctx_set_protocols(sslctx, tls_params->protocols); } + + if (tls_params->dhparam_file != NULL) { + if (!isc_tlsctx_load_dhparams(sslctx, + tls_params->dhparam_file)) + { + isc_tlsctx_free(&sslctx); + return (ISC_R_FAILURE); + } + } } elt = isc_mem_get(mctx, sizeof(*elt)); diff --git a/util/copyrights b/util/copyrights index 2d0d2faf53..0e24a2361d 100644 --- a/util/copyrights +++ b/util/copyrights @@ -276,6 +276,7 @@ ./bin/tests/system/doth/clean.sh SH 2020,2021 ./bin/tests/system/doth/example.axfr.good X 2021 ./bin/tests/system/doth/ns2/cert.pem X 2021 +./bin/tests/system/doth/ns2/dhparam3072.pem X 2021 ./bin/tests/system/doth/ns2/key.pem X 2021 ./bin/tests/system/doth/setup.sh SH 2021 ./bin/tests/system/doth/stress_http_quota.py PYTHON-BIN 2021 From 3b88d783a2eb40c1c597c597942c2c08659b7ffb Mon Sep 17 00:00:00 2001 From: Artem Boldariev Date: Mon, 20 Sep 2021 14:25:59 +0300 Subject: [PATCH 04/12] 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. --- bin/named/named.conf.rst | 2 +- bin/named/server.c | 12 +++++-- .../system/checkconf/bad-dot-badciphers.conf | 20 +++++++++++ .../system/checkconf/good-doh-tlsopts.conf | 1 + .../system/checkconf/good-dot-tlsopts.conf | 1 + doc/arm/reference.rst | 9 ++++- doc/man/named.conf.5in | 2 +- doc/misc/options | 2 +- doc/misc/options.active | 2 +- doc/misc/tls.grammar.rst | 2 +- lib/bind9/check.c | 16 ++++++++- lib/isc/include/isc/tls.h | 19 ++++++++++ lib/isc/tls.c | 36 +++++++++++++++++++ lib/isccfg/namedconf.c | 2 +- lib/ns/include/ns/listenlist.h | 1 + lib/ns/listenlist.c | 4 +++ 16 files changed, 121 insertions(+), 10 deletions(-) create mode 100644 bin/tests/system/checkconf/bad-dot-badciphers.conf diff --git a/bin/named/named.conf.rst b/bin/named/named.conf.rst index 5d2c011f1c..d1818a7ef6 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 aacc18845a..d3e8d802d6 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 0000000000..e4a0abca20 --- /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 4ef244a01e..7583c70cd5 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 62d4b8066d..1a0029d220 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 7b61d2862a..46f24ec536 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 1c6d7c9075..eb7cf4c560 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 72b32fb9f4..1a708a6163 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 b2fecd6f69..91a555f5a5 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 60035e5ae8..17c0c36bac 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 d9c14127dd..84b899953a 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 594d40bf4d..90f185e825 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 1fc1362a13..cec6c5ff43 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 63c66da7b0..ceea97480a 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 2fd341318e..5b8d68edb9 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 001821246e..68aab57cfa 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)); From 16c6e2be066d586ea37e37338550a40634a618f0 Mon Sep 17 00:00:00 2001 From: Artem Boldariev Date: Mon, 20 Sep 2021 16:53:27 +0300 Subject: [PATCH 05/12] Add "prefer-server-ciphers" options to the "tls" clause This commit adds support for enforcing the preference of server ciphers over the client ones. This way, the server attains control over the ciphers priority and, thus, can choose more strong cyphers when a client prioritises less strong ciphers over the more strong ones, which is beneficial when trying to achieve Perfect Forward Secrecy. --- bin/named/named.conf.rst | 1 + bin/named/server.c | 26 +++++++++++++++---- .../system/checkconf/good-doh-tlsopts.conf | 1 + .../system/checkconf/good-dot-tlsopts.conf | 1 + doc/arm/reference.rst | 5 +++- doc/man/named.conf.5in | 1 + doc/misc/options | 1 + doc/misc/options.active | 1 + doc/misc/tls.grammar.rst | 1 + lib/isc/include/isc/tls.h | 10 +++++++ lib/isc/tls.c | 12 +++++++++ lib/isccfg/namedconf.c | 1 + lib/ns/include/ns/listenlist.h | 2 ++ lib/ns/listenlist.c | 5 ++++ 14 files changed, 62 insertions(+), 6 deletions(-) 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)); From c759f25c7be641c0c666fd44d3f75283e99da1f6 Mon Sep 17 00:00:00 2001 From: Artem Boldariev Date: Tue, 21 Sep 2021 14:09:56 +0300 Subject: [PATCH 06/12] Add "session-tickets" options to the "tls" clause This commit adds the ability to enable or disable stateless TLS session resumption tickets (see RFC5077). Having this ability is twofold. Firstly, these tickets are encrypted by the server, and the algorithm might be weaker than the algorithm negotiated during the TLS session establishment (it is in general the case for TLSv1.2, but the generic principle applies to TLSv1.3 as well, despite it having better ciphers for session tickets). Thus, they might compromise Perfect Forward Secrecy. Secondly, disabling it might be necessary if the same TLS key/cert pair is supposed to be used by multiple servers to achieve, e.g., load balancing because the session ticket by default gets generated in runtime, while to achieve successful session resumption ability, in this case, would have required using a shared key. The proper alternative to having the ability to disable stateless TLS session resumption tickets is to implement a proper session tickets key rollover mechanism so that key rotation might be performed often (e.g. once an hour) to not compromise forward secrecy while retaining the associated performance benefits. That is much more work, though. On the other hand, having the ability to disable session tickets allows having a deployable configuration right now in the cases when either forward secrecy is wanted or sharing the TLS key/cert pair between multiple servers is needed (or both). --- bin/named/named.conf.rst | 1 + bin/named/server.c | 12 ++++++++++++ bin/tests/system/checkconf/good-doh-tlsopts.conf | 1 + bin/tests/system/checkconf/good-dot-tlsopts.conf | 1 + doc/arm/reference.rst | 9 ++++++++- doc/man/named.conf.5in | 1 + doc/misc/options | 1 + doc/misc/options.active | 1 + doc/misc/tls.grammar.rst | 1 + lib/isc/include/isc/tls.h | 10 ++++++++++ lib/isc/tls.c | 11 +++++++++++ lib/isccfg/namedconf.c | 1 + lib/ns/include/ns/listenlist.h | 2 ++ lib/ns/listenlist.c | 5 +++++ 14 files changed, 56 insertions(+), 1 deletion(-) diff --git a/bin/named/named.conf.rst b/bin/named/named.conf.rst index ff9e7de0f8..7274c2044a 100644 --- a/bin/named/named.conf.rst +++ b/bin/named/named.conf.rst @@ -569,6 +569,7 @@ TLS key-file quoted_string; prefer-server-ciphers boolean; protocols { string; ... }; + session-tickets boolean; }; TRUST-ANCHORS diff --git a/bin/named/server.c b/bin/named/server.c index 3c3ebd7b48..e9d3bdc59e 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -11027,6 +11027,7 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, *ciphers = NULL; bool tls_prefer_server_ciphers = false, tls_prefer_server_ciphers_set = false; + bool tls_session_tickets = false, tls_session_tickets_set = false; bool do_tls = false, no_tls = false, http = false; ns_listenelt_t *delt = NULL; uint32_t tls_protos = 0; @@ -11052,6 +11053,7 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, const cfg_obj_t *tls_proto_list = NULL; const cfg_obj_t *ciphers_obj = NULL; const cfg_obj_t *prefer_server_ciphers_obj = NULL; + const cfg_obj_t *session_tickets_obj = NULL; do_tls = true; @@ -11109,6 +11111,14 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, prefer_server_ciphers_obj); tls_prefer_server_ciphers_set = true; } + + if (cfg_map_get(tlsmap, "session-tickets", + &session_tickets_obj) == ISC_R_SUCCESS) + { + tls_session_tickets = + cfg_obj_asboolean(session_tickets_obj); + tls_session_tickets_set = true; + } } } @@ -11120,6 +11130,8 @@ listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, .ciphers = ciphers, .prefer_server_ciphers = tls_prefer_server_ciphers, .prefer_server_ciphers_set = tls_prefer_server_ciphers_set, + .session_tickets = tls_session_tickets, + .session_tickets_set = tls_session_tickets_set }; httpobj = cfg_tuple_get(ltup, "http"); diff --git a/bin/tests/system/checkconf/good-doh-tlsopts.conf b/bin/tests/system/checkconf/good-doh-tlsopts.conf index f6cafa342f..0de934bfe4 100644 --- a/bin/tests/system/checkconf/good-doh-tlsopts.conf +++ b/bin/tests/system/checkconf/good-doh-tlsopts.conf @@ -16,6 +16,7 @@ tls local-tls { dhparam-file "dhparam.pem"; ciphers "HIGH:!aNULL:!MD5:!RC4"; prefer-server-ciphers yes; + session-tickets no; }; 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 8912646f65..e68e6211e3 100644 --- a/bin/tests/system/checkconf/good-dot-tlsopts.conf +++ b/bin/tests/system/checkconf/good-dot-tlsopts.conf @@ -16,6 +16,7 @@ tls local-tls { dhparam-file "dhparam.pem"; ciphers "HIGH:!aNULL:!MD5:!RC4"; prefer-server-ciphers yes; + session-tickets no; }; options { diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst index b6a7c14e27..bed3ed0140 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``, ``protocols``, and ``prefer-server-ciphers``. + Specifies configuration information for a TLS connection, including a ``key-file``, ``cert-file``, ``ca-file``, ``dhparam-file``, ``hostname``, ``ciphers``, ``protocols``, ``prefer-server-ciphers``, and ``session-tickets``. ``http`` Specifies configuration information for an HTTP connection, including ``endponts``, ``listener-clients`` and ``streams-per-connection``. @@ -4795,6 +4795,13 @@ The following options can be specified in a ``tls`` statement: ``prefer-server-ciphers`` Specifies that server ciphers should be preferred over client ones. + ``session-tickets`` + Enables or disables session resumption through TLS session tickets, + as defined in RFC5077. Disabling the stateless session tickets + might be required in the cases when forward secrecy is needed, + or the TLS certificate and key pair is planned to be used across + multiple BIND instances. + 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 036d589949..30d73bab2f 100644 --- a/doc/man/named.conf.5in +++ b/doc/man/named.conf.5in @@ -660,6 +660,7 @@ tls string { key\-file quoted_string; prefer\-server\-ciphers boolean; protocols { string; ... }; + session\-tickets boolean; }; .ft P .fi diff --git a/doc/misc/options b/doc/misc/options index da7fcceb31..06fec355af 100644 --- a/doc/misc/options +++ b/doc/misc/options @@ -465,6 +465,7 @@ tls { key-file ; prefer-server-ciphers ; protocols { ; ... }; + session-tickets ; }; // may occur multiple times trust-anchors { ( static-key | diff --git a/doc/misc/options.active b/doc/misc/options.active index f579cc2835..226e77da17 100644 --- a/doc/misc/options.active +++ b/doc/misc/options.active @@ -462,6 +462,7 @@ tls { key-file ; prefer-server-ciphers ; protocols { ; ... }; + session-tickets ; }; // may occur multiple times trust-anchors { ( static-key | diff --git a/doc/misc/tls.grammar.rst b/doc/misc/tls.grammar.rst index 4cb078da94..98f724a6d8 100644 --- a/doc/misc/tls.grammar.rst +++ b/doc/misc/tls.grammar.rst @@ -9,4 +9,5 @@ key-file ; prefer-server-ciphers ; protocols { ; ... }; + session-tickets ; }; diff --git a/lib/isc/include/isc/tls.h b/lib/isc/include/isc/tls.h index 5c32053df3..addc27ba5c 100644 --- a/lib/isc/include/isc/tls.h +++ b/lib/isc/include/isc/tls.h @@ -124,6 +124,16 @@ isc_tlsctx_prefer_server_ciphers(isc_tlsctx_t *ctx, const bool prefer); * \li 'ctx' != NULL. */ +void +isc_tlsctx_session_tickets(isc_tlsctx_t *ctx, const bool use); +/*%< + * Enable/Disable stateless session resumptions tickets on the given + * TLS context 'ctx' (see RFC5077). + * + * 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 f2dcbf187b..94d42b7e17 100644 --- a/lib/isc/tls.c +++ b/lib/isc/tls.c @@ -574,6 +574,17 @@ isc_tlsctx_prefer_server_ciphers(isc_tlsctx_t *ctx, const bool prefer) { } } +void +isc_tlsctx_session_tickets(isc_tlsctx_t *ctx, const bool use) { + REQUIRE(ctx != NULL); + + if (!use) { + (void)SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET); + } else { + (void)SSL_CTX_clear_options(ctx, SSL_OP_NO_TICKET); + } +} + 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 0f8329f26a..7bff17d184 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -3891,6 +3891,7 @@ static cfg_clausedef_t tls_clauses[] = { { "protocols", &cfg_type_tlsprotos, 0 }, { "ciphers", &cfg_type_astring, 0 }, { "prefer-server-ciphers", &cfg_type_boolean, 0 }, + { "session-tickets", &cfg_type_boolean, 0 }, { NULL, NULL, 0 } }; diff --git a/lib/ns/include/ns/listenlist.h b/lib/ns/include/ns/listenlist.h index 207c1f6ab3..8119821b5b 100644 --- a/lib/ns/include/ns/listenlist.h +++ b/lib/ns/include/ns/listenlist.h @@ -67,6 +67,8 @@ typedef struct ns_listen_tls_params { const char *ciphers; bool prefer_server_ciphers; bool prefer_server_ciphers_set; + bool session_tickets; + bool session_tickets_set; } ns_listen_tls_params_t; /*** diff --git a/lib/ns/listenlist.c b/lib/ns/listenlist.c index 600ee64ceb..6aa67dbd2b 100644 --- a/lib/ns/listenlist.c +++ b/lib/ns/listenlist.c @@ -64,6 +64,11 @@ ns_listenelt_create(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp, isc_tlsctx_prefer_server_ciphers( sslctx, tls_params->prefer_server_ciphers); } + + if (tls_params->session_tickets_set) { + isc_tlsctx_session_tickets(sslctx, + tls_params->session_tickets); + } } elt = isc_mem_get(mctx, sizeof(*elt)); From 9c34fa2896ea46ccde4d6bdf972f16a7d4f39dca Mon Sep 17 00:00:00 2001 From: Artem Boldariev Date: Thu, 23 Sep 2021 18:07:42 +0300 Subject: [PATCH 07/12] Mention that "tls" options defaults are outside of our control We have to mention that every option within a "tls" clause has defaults out of our control as some platforms have means for defining encryption policies globally for any application on the system. In order to comply with these policies, we have not to modify TLS contexts settings, unless we have to do so according to the options specified within "tls" clauses. --- doc/arm/reference.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst index bed3ed0140..63beef4cbb 100644 --- a/doc/arm/reference.rst +++ b/doc/arm/reference.rst @@ -4802,6 +4802,13 @@ The following options can be specified in a ``tls`` statement: or the TLS certificate and key pair is planned to be used across multiple BIND instances. +The options described above are used to control different aspects of +TLS functioning. Thus, most of them have no well-defined default +values, as these depend on the cryptographic library version in use +and system-wide cryptographic policy. On the other hand, by specifying +the needed options one could have a uniform configuration deployable +across a range of platforms. + 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 From 17d2b3c8db1deac5be7561f8beecd53a1d00bf57 Mon Sep 17 00:00:00 2001 From: Artem Boldariev Date: Tue, 28 Sep 2021 12:23:20 +0300 Subject: [PATCH 08/12] Modify CHANGES [GL #2795] Mention in the CHANGES file that supported TLS versions can be specified in the configuration file. --- CHANGES | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES b/CHANGES index 7b37b4037a..1ac9a627ac 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +5728. [func] Allow specifying supported TLS protocol + versions within "tls" clauses + (e.g. protocols { TLSv1.2; TLSv1.3; };). [GL #2795] + 5727. [bug] Ignore the missing zones when doing a reload on a catalog zone, and make sure to restore them later on. [GL #2308] From bbf758a6fdc890cd75ba885c3b2381f239f8cbf1 Mon Sep 17 00:00:00 2001 From: Artem Boldariev Date: Tue, 28 Sep 2021 12:49:25 +0300 Subject: [PATCH 09/12] Modify CHANGES [GL #2796] Mention the new "tls" options in the CHANGES file. --- CHANGES | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGES b/CHANGES index 1ac9a627ac..0ee3ee6977 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,18 @@ +5729. [func] Allow finer control over the TLS protocol by + implementing more options within "tls" clauses, namely: + - Diffie-Hellman parameters via + 'dhparam-file "";' + - OpenSSL cipher list string via + 'ciphers "";' + - Server or client ciphers preference via + 'prefer-server-ciphers yes|no;' + - Ability to explicitly enable or disable stateless + TLS session tickets via 'session-tickets yes|no;' + The options are enough to implement perfect forward + secrecy in DNS-over-TLS, DNS-over-HTTPS transports. + Most of these options were no-op before this + change. [GL #2796] + 5728. [func] Allow specifying supported TLS protocol versions within "tls" clauses (e.g. protocols { TLSv1.2; TLSv1.3; };). [GL #2795] From 503a9a56b2a476e1ae72fe9ff5d4849106dfd13b Mon Sep 17 00:00:00 2001 From: Artem Boldariev Date: Tue, 28 Sep 2021 12:59:13 +0300 Subject: [PATCH 10/12] Modify release notes [GL #2795] Mention that it is now possible to specify supported TLS protocol versions. --- doc/notes/notes-current.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/notes/notes-current.rst b/doc/notes/notes-current.rst index 5bd4f71b0b..3dedf1a11d 100644 --- a/doc/notes/notes-current.rst +++ b/doc/notes/notes-current.rst @@ -24,7 +24,8 @@ Known Issues New Features ~~~~~~~~~~~~ -- None. +- Ability to specify supported TLS protocol versions within ``tls`` + clauses (e.g. ``protocols { TLSv1.2; TLSv1.3; };``). :gl:`#2795` Removed Features ~~~~~~~~~~~~~~~~ From 834bb4e52b55f8b22db7dcc9af7715a73d4c58f7 Mon Sep 17 00:00:00 2001 From: Artem Boldariev Date: Tue, 28 Sep 2021 13:13:47 +0300 Subject: [PATCH 11/12] Modify release notes [GL #2796] Mention the new "tls" clause options in the release notes. --- doc/notes/notes-current.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/notes/notes-current.rst b/doc/notes/notes-current.rst index 3dedf1a11d..94a49630be 100644 --- a/doc/notes/notes-current.rst +++ b/doc/notes/notes-current.rst @@ -27,6 +27,15 @@ New Features - Ability to specify supported TLS protocol versions within ``tls`` clauses (e.g. ``protocols { TLSv1.2; TLSv1.3; };``). :gl:`#2795` +- New options within ``tls`` clauses were implemented, namely: + - ``dhparam-file "";`` to specify Diffie-Hellman parameters; + - ``ciphers "";`` to specify OpenSSL ciphers list; + - ``prefer-server-ciphers yes|no;`` to assert server or client ciphers preference; + - ``session-tickets yes|no;`` to explicitly enable or disable stateless TLS session tickets (see RFC5077). + These options allow finer control over TLS protocol features and make it + possible to achieve perfect forward secrecy for DNS-over-TLS and + DNS-over-HTTPS. :gl:`#2796` + Removed Features ~~~~~~~~~~~~~~~~ From 4369d94f68815b90ddaafca517f23d493a71c3c4 Mon Sep 17 00:00:00 2001 From: Artem Boldariev Date: Thu, 30 Sep 2021 11:31:01 +0300 Subject: [PATCH 12/12] Provide an example of forward secrecy enabled TLS configuration This commit adds and example of a perfect forward secrecy enabled TLS configuration intended to be used as a starting point. --- doc/arm/reference.rst | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst index 63beef4cbb..6db12cc859 100644 --- a/doc/arm/reference.rst +++ b/doc/arm/reference.rst @@ -4809,6 +4809,32 @@ and system-wide cryptographic policy. On the other hand, by specifying the needed options one could have a uniform configuration deployable across a range of platforms. +An example of privacy-oriented, perfect forward secrecy enabled +configuration can be found below. It can be used as a +starting point. + +:: + + tls local-tls { + key-file "/path/to/key.pem"; + cert-file "/path/to/fullchain_cert.pem"; + dhparam-file "/path/to/dhparam.pem"; + ciphers "HIGH:!kRSA:!aNULL:!eNULL:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!SHA1:!SHA256:!SHA384"; + prefer-server-ciphers yes; + session-tickets no; + }; + +A Diffie-Hellman parameters file can be generated using e.g. OpenSSL, +like follows: + +:: + openssl dhparam -out /path/to/dhparam.pem <3072_or_4096> + +Ensure that it gets generated on a machine with enough entropy from +external sources (e.g. the computer you work on should be fine, +the remote virtual machine or server might be not). These files do +not contain any sensitive data and can be shared if required. + 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