summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJörg Thalheim <joerg@thalheim.io>2020-03-03 23:31:25 +0000
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2020-12-10 18:05:15 +0100
commitff26d281aec0877b43269f18c6282cd79a7f5529 (patch)
treeb87462b385d1ff479c62e50cabd49873e2496376
parente9bac3752edaa6b364def3c1f8b79ce246de2783 (diff)
downloadsystemd-ff26d281aec0877b43269f18c6282cd79a7f5529.tar.gz
systemd-resolved: use hostname for certificate validation in DoTv245.9
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)
-rw-r--r--man/resolved.conf.xml19
-rw-r--r--src/resolve/resolved-dnstls-gnutls.c20
-rw-r--r--src/resolve/resolved-dnstls-openssl.c15
3 files changed, 34 insertions, 20 deletions
diff --git a/man/resolved.conf.xml b/man/resolved.conf.xml
index 0f70ced5b5..37161ebcbc 100644
--- a/man/resolved.conf.xml
+++ b/man/resolved.conf.xml
@@ -193,11 +193,17 @@
<varlistentry>
<term><varname>DNSOverTLS=</varname></term>
<listitem>
- <para>Takes a boolean argument or <literal>opportunistic</literal>.
- 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 <literal>opportunistic</literal>
+ <para>Takes a boolean argument or <literal>opportunistic</literal>. 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 <varname>DNS=</varname>
+ by using the format format <literal>address#server_name</literal> 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.</para>
+
+ <para>When set to <literal>opportunistic</literal>
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"
@@ -214,9 +220,6 @@
resolver is not capable of authenticating the server, so it is
vulnerable to "man-in-the-middle" attacks.</para>
- <para>Server Name Indication (SNI) can be used when opening a TLS connection.
- Entries in <varname>DNS=</varname> should be in format <literal>address#server_name</literal>.</para>
-
<para>In addition to this global DNSOverTLS setting
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
also maintains per-link DNSOverTLS settings. For system DNS
diff --git a/src/resolve/resolved-dnstls-gnutls.c b/src/resolve/resolved-dnstls-gnutls.c
index 2a4a95989c..e5dd00692c 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);
}
if (server->server_name) {
diff --git a/src/resolve/resolved-dnstls-openssl.c b/src/resolve/resolved-dnstls-openssl.c
index 8f58efacbd..7763cbcb5a 100644
--- a/src/resolve/resolved-dnstls-openssl.c
+++ b/src/resolve/resolved-dnstls-openssl.c
@@ -6,6 +6,7 @@
#include <openssl/bio.h>
#include <openssl/err.h>
+#include <openssl/x509v3.h>
#include "io-util.h"
#include "resolved-dns-stream.h"
@@ -80,13 +81,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)) == 0)
- 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;
+ }
}
if (server->server_name) {