From 3f9d9289ee8730a81a0464539f4e1ba2d23d0ce9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Tue, 3 Mar 2020 23:31:25 +0000 Subject: [PATCH] systemd-resolved: use hostname for certificate validation in DoT Widely accepted certificates for IP addresses are expensive and only affordable for larger organizations. Therefore if the user provides the hostname in the DNS= option, we should use it instead of the IP address. (cherry picked from commit eec394f10bbfcc3d2fc8504ad8ff5be44231abd5) CVE: CVE-2018-21029 Upstream-Status: Backport [ff26d281aec0877b43269f18c6282cd79a7f5529] Signed-off-by: Marek Vasut --- man/resolved.conf.xml | 16 +++++++++++----- src/resolve/resolved-dnstls-gnutls.c | 20 ++++++++++++-------- src/resolve/resolved-dnstls-openssl.c | 15 +++++++++++---- 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/man/resolved.conf.xml b/man/resolved.conf.xml index 818000145b..37161ebcbc 100644 --- a/man/resolved.conf.xml +++ b/man/resolved.conf.xml @@ -193,11 +193,17 @@ DNSOverTLS= - Takes a boolean argument or opportunistic. - If true all connections to the server will be encrypted. Note that - this mode requires a DNS server that supports DNS-over-TLS and has - a valid certificate for it's IP. If the DNS server does not support - DNS-over-TLS all DNS requests will fail. When set to opportunistic + Takes a boolean argument or opportunistic. If + true all connections to the server will be encrypted. Note that this + mode requires a DNS server that supports DNS-over-TLS and has a valid + certificate. If the hostname was specified in DNS= + by using the format format address#server_name it + is used to validate its certificate and also to enable Server Name + Indication (SNI) when opening a TLS connection. Otherwise + the certificate is checked against the server's IP. + If the DNS server does not support DNS-over-TLS all DNS requests will fail. + + When set to opportunistic DNS request are attempted to send encrypted with DNS-over-TLS. If the DNS server does not support TLS, DNS-over-TLS is disabled. Note that this mode makes DNS-over-TLS vulnerable to "downgrade" diff --git a/src/resolve/resolved-dnstls-gnutls.c b/src/resolve/resolved-dnstls-gnutls.c index ed0a31e8bf..c7215723a7 100644 --- a/src/resolve/resolved-dnstls-gnutls.c +++ b/src/resolve/resolved-dnstls-gnutls.c @@ -56,15 +56,19 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) { } if (server->manager->dns_over_tls_mode == DNS_OVER_TLS_YES) { - stream->dnstls_data.validation.type = GNUTLS_DT_IP_ADDRESS; - if (server->family == AF_INET) { - stream->dnstls_data.validation.data = (unsigned char*) &server->address.in.s_addr; - stream->dnstls_data.validation.size = 4; - } else { - stream->dnstls_data.validation.data = server->address.in6.s6_addr; - stream->dnstls_data.validation.size = 16; + if (server->server_name) + gnutls_session_set_verify_cert(gs, server->server_name, 0); + else { + stream->dnstls_data.validation.type = GNUTLS_DT_IP_ADDRESS; + if (server->family == AF_INET) { + stream->dnstls_data.validation.data = (unsigned char*) &server->address.in.s_addr; + stream->dnstls_data.validation.size = 4; + } else { + stream->dnstls_data.validation.data = server->address.in6.s6_addr; + stream->dnstls_data.validation.size = 16; + } + gnutls_session_set_verify_cert2(gs, &stream->dnstls_data.validation, 1, 0); } - gnutls_session_set_verify_cert2(gs, &stream->dnstls_data.validation, 1, 0); } gnutls_handshake_set_timeout(gs, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); diff --git a/src/resolve/resolved-dnstls-openssl.c b/src/resolve/resolved-dnstls-openssl.c index 85e202ff74..007aedaa5b 100644 --- a/src/resolve/resolved-dnstls-openssl.c +++ b/src/resolve/resolved-dnstls-openssl.c @@ -6,6 +6,7 @@ #include #include +#include #include "io-util.h" #include "resolved-dns-stream.h" @@ -78,13 +79,19 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) { if (server->manager->dns_over_tls_mode == DNS_OVER_TLS_YES) { X509_VERIFY_PARAM *v; - const unsigned char *ip; SSL_set_verify(s, SSL_VERIFY_PEER, NULL); v = SSL_get0_param(s); - ip = server->family == AF_INET ? (const unsigned char*) &server->address.in.s_addr : server->address.in6.s6_addr; - if (!X509_VERIFY_PARAM_set1_ip(v, ip, FAMILY_ADDRESS_SIZE(server->family))) - return -ECONNREFUSED; + if (server->server_name) { + X509_VERIFY_PARAM_set_hostflags(v, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); + if (X509_VERIFY_PARAM_set1_host(v, server->server_name, 0) == 0) + return -ECONNREFUSED; + } else { + const unsigned char *ip; + ip = server->family == AF_INET ? (const unsigned char*) &server->address.in.s_addr : server->address.in6.s6_addr; + if (X509_VERIFY_PARAM_set1_ip(v, ip, FAMILY_ADDRESS_SIZE(server->family)) == 0) + return -ECONNREFUSED; + } } ERR_clear_error(); -- 2.40.1