mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-03 13:59:27 -04:00
Merge branch 'artem/tls-protocols-conf' into 'main'
Resolve #2795, #2796: implement TLS configuration options to make it possible to specify supported TLS versions and implement perfect forward secrecy for DoH and DoT Closes #2796 and #2795 See merge request isc-projects/bind9!5444
This commit is contained in:
commit
39584a5226
27 changed files with 995 additions and 54 deletions
19
CHANGES
19
CHANGES
|
|
@ -1,3 +1,22 @@
|
|||
5729. [func] Allow finer control over the TLS protocol by
|
||||
implementing more options within "tls" clauses, namely:
|
||||
- Diffie-Hellman parameters via
|
||||
'dhparam-file "<path_to_file>";'
|
||||
- OpenSSL cipher list string via
|
||||
'ciphers "<cipher_list>";'
|
||||
- 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]
|
||||
|
||||
5727. [bug] Ignore the missing zones when doing a reload on a
|
||||
catalog zone, and make sure to restore them later on.
|
||||
[GL #2308]
|
||||
|
|
|
|||
|
|
@ -563,11 +563,13 @@ TLS
|
|||
tls string {
|
||||
ca-file quoted_string;
|
||||
cert-file quoted_string;
|
||||
ciphers string; // experimental
|
||||
dh-param quoted_string; // experimental
|
||||
ciphers string;
|
||||
dhparam-file quoted_string;
|
||||
hostname quoted_string;
|
||||
key-file quoted_string;
|
||||
protocols sslprotos; // experimental
|
||||
prefer-server-ciphers boolean;
|
||||
protocols { string; ... };
|
||||
session-tickets boolean;
|
||||
};
|
||||
|
||||
TRUST-ANCHORS
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -11023,9 +11023,15 @@ 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,
|
||||
*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;
|
||||
ns_listen_tls_params_t tls_params = { 0 };
|
||||
|
||||
REQUIRE(target != NULL && *target == NULL);
|
||||
|
||||
|
|
@ -11041,8 +11047,13 @@ 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;
|
||||
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;
|
||||
|
||||
|
|
@ -11059,9 +11070,70 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg_map_get(tlsmap, "dhparam-file", &dhparam_obj) ==
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
.session_tickets = tls_session_tickets,
|
||||
.session_tickets_set = tls_session_tickets_set
|
||||
};
|
||||
|
||||
httpobj = cfg_tuple_get(ltup, "http");
|
||||
if (httpobj != NULL && cfg_obj_isstring(httpobj)) {
|
||||
const char *httpname = cfg_obj_asstring(httpobj);
|
||||
|
|
@ -11144,14 +11216,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 +11241,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 +11256,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 +11315,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;
|
||||
|
|
|
|||
20
bin/tests/system/checkconf/bad-dot-badciphers.conf
Normal file
20
bin/tests/system/checkconf/bad-dot-badciphers.conf
Normal file
|
|
@ -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; };
|
||||
};
|
||||
20
bin/tests/system/checkconf/bad-dot-badprotocol.conf
Normal file
20
bin/tests/system/checkconf/bad-dot-badprotocol.conf
Normal file
|
|
@ -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; };
|
||||
};
|
||||
24
bin/tests/system/checkconf/bad-dot-duplicatetls.conf
Normal file
24
bin/tests/system/checkconf/bad-dot-duplicatetls.conf
Normal file
|
|
@ -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; };
|
||||
};
|
||||
20
bin/tests/system/checkconf/bad-dot-ephemeral.conf
Normal file
20
bin/tests/system/checkconf/bad-dot-ephemeral.conf
Normal file
|
|
@ -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; };
|
||||
};
|
||||
30
bin/tests/system/checkconf/bad-dot-nocert.conf
Normal file
30
bin/tests/system/checkconf/bad-dot-nocert.conf
Normal file
|
|
@ -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; };
|
||||
};
|
||||
30
bin/tests/system/checkconf/bad-dot-nokey.conf
Normal file
30
bin/tests/system/checkconf/bad-dot-nokey.conf
Normal file
|
|
@ -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; };
|
||||
};
|
||||
20
bin/tests/system/checkconf/bad-dot-none.conf
Normal file
20
bin/tests/system/checkconf/bad-dot-none.conf
Normal file
|
|
@ -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; };
|
||||
};
|
||||
36
bin/tests/system/checkconf/good-doh-tlsopts.conf
Normal file
36
bin/tests/system/checkconf/good-doh-tlsopts.conf
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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";
|
||||
dhparam-file "dhparam.pem";
|
||||
ciphers "HIGH:!aNULL:!MD5:!RC4";
|
||||
prefer-server-ciphers yes;
|
||||
session-tickets no;
|
||||
};
|
||||
|
||||
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; };
|
||||
};
|
||||
24
bin/tests/system/checkconf/good-dot-tlsopts.conf
Normal file
24
bin/tests/system/checkconf/good-dot-tlsopts.conf
Normal file
|
|
@ -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 {
|
||||
protocols { TLSv1.2; };
|
||||
key-file "key.pem";
|
||||
cert-file "cert.pem";
|
||||
dhparam-file "dhparam.pem";
|
||||
ciphers "HIGH:!aNULL:!MD5:!RC4";
|
||||
prefer-server-ciphers yes;
|
||||
session-tickets no;
|
||||
};
|
||||
|
||||
options {
|
||||
listen-on port 853 tls local-tls { 10.53.0.1; };
|
||||
};
|
||||
11
bin/tests/system/doth/ns2/dhparam3072.pem
Normal file
11
bin/tests/system/doth/ns2/dhparam3072.pem
Normal file
|
|
@ -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-----
|
||||
|
|
@ -18,6 +18,7 @@ controls {
|
|||
tls local {
|
||||
key-file "key.pem";
|
||||
cert-file "cert.pem";
|
||||
dhparam-file "dhparam3072.pem";
|
||||
};
|
||||
|
||||
http local {
|
||||
|
|
|
|||
|
|
@ -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``, ``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``.
|
||||
|
|
@ -4769,9 +4769,72 @@ 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.
|
||||
|
||||
``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; };``).
|
||||
|
||||
``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).
|
||||
|
||||
``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.
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -654,11 +654,13 @@ statistics\-channels {
|
|||
tls string {
|
||||
ca\-file quoted_string;
|
||||
cert\-file quoted_string;
|
||||
ciphers string; // experimental
|
||||
dh\-param quoted_string; // experimental
|
||||
ciphers string;
|
||||
dhparam\-file quoted_string;
|
||||
hostname quoted_string;
|
||||
key\-file quoted_string;
|
||||
protocols sslprotos; // experimental
|
||||
prefer\-server\-ciphers boolean;
|
||||
protocols { string; ... };
|
||||
session\-tickets boolean;
|
||||
};
|
||||
.ft P
|
||||
.fi
|
||||
|
|
|
|||
|
|
@ -459,11 +459,13 @@ statistics-channels {
|
|||
tls <string> {
|
||||
ca-file <quoted_string>;
|
||||
cert-file <quoted_string>;
|
||||
ciphers <string>; // experimental
|
||||
dh-param <quoted_string>; // experimental
|
||||
ciphers <string>;
|
||||
dhparam-file <quoted_string>;
|
||||
hostname <quoted_string>;
|
||||
key-file <quoted_string>;
|
||||
protocols <sslprotos>; // experimental
|
||||
prefer-server-ciphers <boolean>;
|
||||
protocols { <string>; ... };
|
||||
session-tickets <boolean>;
|
||||
}; // may occur multiple times
|
||||
|
||||
trust-anchors { <string> ( static-key |
|
||||
|
|
|
|||
|
|
@ -456,11 +456,13 @@ statistics-channels {
|
|||
tls <string> {
|
||||
ca-file <quoted_string>;
|
||||
cert-file <quoted_string>;
|
||||
ciphers <string>; // experimental
|
||||
dh-param <quoted_string>; // experimental
|
||||
ciphers <string>;
|
||||
dhparam-file <quoted_string>;
|
||||
hostname <quoted_string>;
|
||||
key-file <quoted_string>;
|
||||
protocols <sslprotos>; // experimental
|
||||
prefer-server-ciphers <boolean>;
|
||||
protocols { <string>; ... };
|
||||
session-tickets <boolean>;
|
||||
}; // may occur multiple times
|
||||
|
||||
trust-anchors { <string> ( static-key |
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@
|
|||
tls <string> {
|
||||
ca-file <quoted_string>;
|
||||
cert-file <quoted_string>;
|
||||
ciphers <string>; // experimental
|
||||
dh-param <quoted_string>; // experimental
|
||||
ciphers <string>;
|
||||
dhparam-file <quoted_string>;
|
||||
hostname <quoted_string>;
|
||||
key-file <quoted_string>;
|
||||
protocols <sslprotos>; // experimental
|
||||
prefer-server-ciphers <boolean>;
|
||||
protocols { <string>; ... };
|
||||
session-tickets <boolean>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -24,7 +24,17 @@ Known Issues
|
|||
New Features
|
||||
~~~~~~~~~~~~
|
||||
|
||||
- None.
|
||||
- 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 "<path_to_file>";`` to specify Diffie-Hellman parameters;
|
||||
- ``ciphers "<cipher_list>";`` 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
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <openssl/opensslv.h>
|
||||
|
||||
#ifdef HAVE_DNSTAP
|
||||
#include <fstrm.h>
|
||||
#endif
|
||||
|
|
@ -2116,6 +2118,163 @@ 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, *tls_ciphers = 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 = "<unknown 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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 +5653,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) {
|
||||
|
|
|
|||
|
|
@ -50,6 +50,90 @@ 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.
|
||||
*/
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
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);
|
||||
/*%<
|
||||
|
|
|
|||
234
lib/isc/tls.c
234
lib/isc/tls.c
|
|
@ -10,12 +10,14 @@
|
|||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#if HAVE_LIBNGHTTP2
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#endif /* HAVE_LIBNGHTTP2 */
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/rand.h>
|
||||
|
|
@ -33,6 +35,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 +190,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 +240,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
|
||||
|
|
@ -359,6 +366,225 @@ 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -3875,19 +3875,23 @@ 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 },
|
||||
{ "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 },
|
||||
{ "protocols", &cfg_type_sslprotos, CFG_CLAUSEFLAG_EXPERIMENTAL },
|
||||
{ "ciphers", &cfg_type_astring, CFG_CLAUSEFLAG_EXPERIMENTAL },
|
||||
{ "dhparam-file", &cfg_type_qstring, 0 },
|
||||
{ "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 }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -59,22 +59,40 @@ struct ns_listenlist {
|
|||
ISC_LIST(ns_listenelt_t) elts;
|
||||
};
|
||||
|
||||
typedef struct ns_listen_tls_params {
|
||||
const char *key;
|
||||
const char *cert;
|
||||
uint32_t protocols;
|
||||
const char *dhparam_file;
|
||||
const char *ciphers;
|
||||
bool prefer_server_ciphers;
|
||||
bool prefer_server_ciphers_set;
|
||||
bool session_tickets;
|
||||
bool session_tickets_set;
|
||||
} 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);
|
||||
/*%<
|
||||
|
|
|
|||
|
|
@ -26,19 +26,49 @@ 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);
|
||||
}
|
||||
|
||||
if (tls_params->dhparam_file != NULL) {
|
||||
if (!isc_tlsctx_load_dhparams(sslctx,
|
||||
tls_params->dhparam_file))
|
||||
{
|
||||
isc_tlsctx_free(&sslctx);
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (tls_params->session_tickets_set) {
|
||||
isc_tlsctx_session_tickets(sslctx,
|
||||
tls_params->session_tickets);
|
||||
}
|
||||
}
|
||||
|
||||
elt = isc_mem_get(mctx, sizeof(*elt));
|
||||
|
|
@ -59,8 +89,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 +100,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 +195,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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue