From ddb97c7acb36669bd2a7fc2f187906c0db877e09 Mon Sep 17 00:00:00 2001 From: overweight Date: Thu, 28 Jan 2021 22:26:52 -0800 Subject: [PATCH] fix cve-2018-21029 --- ...-in-resolved.conf-man-page-with-rega.patch | 37 ++ ...mplement-SNI-when-using-DNS-over-TLS.patch | 330 ++++++++++++++++++ ...-resolve-error-handling-improvements.patch | 80 +++++ ...or-IP-in-certificate-when-using-DoT-.patch | 51 +++ ...nection-failures-with-TLS-1.3-and-Gn.patch | 34 ++ ...-at-least-version-3.6.0-of-GnuTLS-fo.patch | 58 +++ ...-use-hostname-for-certificate-valida.patch | 124 +++++++ systemd.spec | 15 +- 8 files changed, 728 insertions(+), 1 deletion(-) create mode 100644 backport-CVE-2018-21029-Be-more-specific-in-resolved.conf-man-page-with-rega.patch create mode 100644 backport-CVE-2018-21029-Implement-SNI-when-using-DNS-over-TLS.patch create mode 100644 backport-CVE-2018-21029-resolve-error-handling-improvements.patch create mode 100644 backport-CVE-2018-21029-resolved-check-for-IP-in-certificate-when-using-DoT-.patch create mode 100644 backport-CVE-2018-21029-resolved-fix-connection-failures-with-TLS-1.3-and-Gn.patch create mode 100644 backport-CVE-2018-21029-resolved-require-at-least-version-3.6.0-of-GnuTLS-fo.patch create mode 100644 backport-CVE-2018-21029-systemd-resolved-use-hostname-for-certificate-valida.patch diff --git a/backport-CVE-2018-21029-Be-more-specific-in-resolved.conf-man-page-with-rega.patch b/backport-CVE-2018-21029-Be-more-specific-in-resolved.conf-man-page-with-rega.patch new file mode 100644 index 0000000..95167a5 --- /dev/null +++ b/backport-CVE-2018-21029-Be-more-specific-in-resolved.conf-man-page-with-rega.patch @@ -0,0 +1,37 @@ +From 2f2b28ab35e80855042c69e324feaf7418636aa2 Mon Sep 17 00:00:00 2001 +From: Riccardo Schirone +Date: Wed, 13 Nov 2019 17:37:15 +0100 +Subject: [PATCH] Be more specific in resolved.conf man page with regard to + DNSOverTLS + +DNSOverTLS in strict mode (value yes) does check the server, as it is said in +the first few lines of the option documentation. The check is not performed in +"opportunistic" mode, however, as that is allowed by RFC 7858, section "4.1. +Opportunistic Privacy Profile". + +> With such a discovered DNS server, the client might or might not validate the +> resolver. These choices maximize availability and performance, but they leave +> the client vulnerable to on-path attacks that remove privacy. +--- + man/resolved.conf.xml | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/man/resolved.conf.xml b/man/resolved.conf.xml +index 213be1d7b2..818000145b 100644 +--- a/man/resolved.conf.xml ++++ b/man/resolved.conf.xml +@@ -210,8 +210,9 @@ + send for setting up an encrypted connection, and thus results + in a small DNS look-up time penalty. + +- Note as the resolver is not capable of authenticating +- the server, it is vulnerable for "man-in-the-middle" attacks. ++ Note that in opportunistic mode the ++ resolver is not capable of authenticating the server, so it is ++ vulnerable to "man-in-the-middle" attacks. + + In addition to this global DNSOverTLS setting + systemd-networkd.service8 +-- +2.26.2 + diff --git a/backport-CVE-2018-21029-Implement-SNI-when-using-DNS-over-TLS.patch b/backport-CVE-2018-21029-Implement-SNI-when-using-DNS-over-TLS.patch new file mode 100644 index 0000000..a864bca --- /dev/null +++ b/backport-CVE-2018-21029-Implement-SNI-when-using-DNS-over-TLS.patch @@ -0,0 +1,330 @@ +From 2e22a54f4e085496088b77085f38b66532da59fb Mon Sep 17 00:00:00 2001 +From: Guilhem Lettron +Date: Sat, 30 Nov 2019 03:51:40 +0100 +Subject: [PATCH] Implement SNI when using DNS-over-TLS + +Some DNS providers need SNI to identify client. + +This can be used by adding #name to a DNS. +Example: +[Resolve] +DNS=192.168.1.1#example.com +--- + man/resolved.conf.xml | 3 +++ + src/resolve/meson.build | 8 ++++++ + src/resolve/resolved-conf.c | 6 +++-- + src/resolve/resolved-dns-server.c | 12 ++++++++- + src/resolve/resolved-dns-server.h | 5 +++- + src/resolve/resolved-dnstls-gnutls.c | 6 +++++ + src/resolve/resolved-dnstls-openssl.c | 11 ++++++++ + src/resolve/resolved-link-bus.c | 2 +- + src/resolve/resolved-link.c | 2 +- + src/resolve/resolved-util.c | 36 +++++++++++++++++++++++++++ + src/resolve/resolved-util.h | 6 +++++ + src/resolve/test-resolved-util.c | 32 ++++++++++++++++++++++++ + 12 files changed, 123 insertions(+), 6 deletions(-) + create mode 100644 src/resolve/resolved-util.c + create mode 100644 src/resolve/resolved-util.h + create mode 100644 src/resolve/test-resolved-util.c + +diff --git a/man/resolved.conf.xml b/man/resolved.conf.xml +index 818000145b..0f70ced5b5 100644 +--- a/man/resolved.conf.xml ++++ b/man/resolved.conf.xml +@@ -214,6 +214,9 @@ + resolver is not capable of authenticating the server, so it is + vulnerable to "man-in-the-middle" attacks. + ++ Server Name Indication (SNI) can be used when opening a TLS connection. ++ Entries in DNS= should be in format address#server_name. ++ + In addition to this global DNSOverTLS setting + systemd-networkd.service8 + also maintains per-link DNSOverTLS settings. For system DNS +diff --git a/src/resolve/meson.build b/src/resolve/meson.build +index 92b67b6333..c4d8d4e5d9 100644 +--- a/src/resolve/meson.build ++++ b/src/resolve/meson.build +@@ -64,6 +64,8 @@ systemd_resolved_sources = files(''' + resolved-etc-hosts.h + resolved-etc-hosts.c + resolved-dnstls.h ++ resolved-util.c ++ resolved-util.h + '''.split()) + + resolvectl_sources = files(''' +@@ -228,4 +230,10 @@ tests += [ + [], + [], + 'ENABLE_RESOLVE', 'manual'], ++ ++ [['src/resolve/test-resolved-util.c', ++ 'src/resolve/resolved-util.c', ++ 'src/resolve/resolved-util.h'], ++ [], ++ []], + ] +diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c +index a46c45385b..ca5b8e7918 100644 +--- a/src/resolve/resolved-conf.c ++++ b/src/resolve/resolved-conf.c +@@ -8,6 +8,7 @@ + #include "parse-util.h" + #include "resolved-conf.h" + #include "resolved-dnssd.h" ++#include "resolved-util.h" + #include "specifier.h" + #include "string-table.h" + #include "string-util.h" +@@ -27,11 +28,12 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons + union in_addr_union address; + int family, r, ifindex = 0; + DnsServer *s; ++ _cleanup_free_ char *server_name = NULL; + + assert(m); + assert(word); + +- r = in_addr_ifindex_from_string_auto(word, &family, &address, &ifindex); ++ r = in_addr_ifindex_name_from_string_auto(word, &family, &address, &ifindex, &server_name); + if (r < 0) + return r; + +@@ -52,7 +54,7 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons + return 0; + } + +- return dns_server_new(m, NULL, type, NULL, family, &address, ifindex); ++ return dns_server_new(m, NULL, type, NULL, family, &address, ifindex, server_name); + } + + int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, const char *string) { +diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c +index 9f2c97314f..4b0599ab9c 100644 +--- a/src/resolve/resolved-dns-server.c ++++ b/src/resolve/resolved-dns-server.c +@@ -25,8 +25,10 @@ int dns_server_new( + Link *l, + int family, + const union in_addr_union *in_addr, +- int ifindex) { ++ int ifindex, ++ const char *server_name) { + ++ _cleanup_free_ char *name = NULL; + DnsServer *s; + + assert(m); +@@ -44,6 +46,12 @@ int dns_server_new( + return -E2BIG; + } + ++ if (server_name) { ++ name = strdup(server_name); ++ if (!name) ++ return -ENOMEM; ++ } ++ + s = new(DnsServer, 1); + if (!s) + return -ENOMEM; +@@ -55,6 +63,7 @@ int dns_server_new( + .family = family, + .address = *in_addr, + .ifindex = ifindex, ++ .server_name = TAKE_PTR(name), + }; + + dns_server_reset_features(s); +@@ -107,6 +116,7 @@ static DnsServer* dns_server_free(DnsServer *s) { + #endif + + free(s->server_string); ++ free(s->server_name); + return mfree(s); + } + +diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h +index 54339355aa..889c80a205 100644 +--- a/src/resolve/resolved-dns-server.h ++++ b/src/resolve/resolved-dns-server.h +@@ -53,6 +53,8 @@ struct DnsServer { + + char *server_string; + ++ char *server_name; ++ + /* The long-lived stream towards this server. */ + DnsStream *stream; + +@@ -94,7 +96,8 @@ int dns_server_new( + Link *link, + int family, + const union in_addr_union *address, +- int ifindex); ++ int ifindex, ++ const char *server_string); + + DnsServer* dns_server_ref(DnsServer *s); + DnsServer* dns_server_unref(DnsServer *s); +diff --git a/src/resolve/resolved-dnstls-gnutls.c b/src/resolve/resolved-dnstls-gnutls.c +index ed0a31e8bf..aad3bb4481 100644 +--- a/src/resolve/resolved-dnstls-gnutls.c ++++ b/src/resolve/resolved-dnstls-gnutls.c +@@ -67,6 +67,12 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) { + gnutls_session_set_verify_cert2(gs, &stream->dnstls_data.validation, 1, 0); + } + ++ if (server->server_name) { ++ r = gnutls_server_name_set(gs, GNUTLS_NAME_DNS, server->server_name, strlen(server->server_name)); ++ if (r < 0) ++ return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to set server name: %s", gnutls_strerror(r)); ++ } ++ + gnutls_handshake_set_timeout(gs, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); + + gnutls_transport_set_ptr2(gs, (gnutls_transport_ptr_t) (long) stream->fd, stream); +diff --git a/src/resolve/resolved-dnstls-openssl.c b/src/resolve/resolved-dnstls-openssl.c +index 85e202ff74..ce0a437371 100644 +--- a/src/resolve/resolved-dnstls-openssl.c ++++ b/src/resolve/resolved-dnstls-openssl.c +@@ -87,6 +87,17 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) { + return -ECONNREFUSED; + } + ++ if (server->server_name) { ++ r = SSL_set_tlsext_host_name(s, server->server_name); ++ if (r <= 0) { ++ char errbuf[256]; ++ ++ error = ERR_get_error(); ++ ERR_error_string_n(error, errbuf, sizeof(errbuf)); ++ return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to set server name: %s", errbuf); ++ } ++ } ++ + ERR_clear_error(); + stream->dnstls_data.handshake = SSL_do_handshake(s); + if (stream->dnstls_data.handshake <= 0) { +diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c +index 8a2768b1e2..dae8435b45 100644 +--- a/src/resolve/resolved-link-bus.c ++++ b/src/resolve/resolved-link-bus.c +@@ -284,7 +284,7 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_ + if (s) + dns_server_move_back_and_unmark(s); + else { +- r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i].family, &dns[i].address, 0); ++ r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i].family, &dns[i].address, 0, NULL); + if (r < 0) + goto clear; + } +diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c +index 96ebb4d23d..f19fc2f3aa 100644 +--- a/src/resolve/resolved-link.c ++++ b/src/resolve/resolved-link.c +@@ -269,7 +269,7 @@ static int link_update_dns_server_one(Link *l, const char *name) { + return 0; + } + +- return dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, 0); ++ return dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, 0, NULL); + } + + static int link_update_dns_servers(Link *l) { +diff --git a/src/resolve/resolved-util.c b/src/resolve/resolved-util.c +new file mode 100644 +index 0000000000..2f18f8c19d +--- /dev/null ++++ b/src/resolve/resolved-util.c +@@ -0,0 +1,36 @@ ++/* SPDX-License-Identifier: LGPL-2.1+ */ ++ ++#include "alloc-util.h" ++#include "in-addr-util.h" ++#include "macro.h" ++#include "resolved-util.h" ++ ++int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name) { ++ _cleanup_free_ char *buf = NULL, *name = NULL; ++ const char *m; ++ int r; ++ ++ assert(s); ++ ++ m = strchr(s, '#'); ++ if (m) { ++ name = strdup(m+1); ++ if (!name) ++ return -ENOMEM; ++ ++ buf = strndup(s, m - s); ++ if (!buf) ++ return -ENOMEM; ++ ++ s = buf; ++ } ++ ++ r = in_addr_ifindex_from_string_auto(s, family, ret, ifindex); ++ if (r < 0) ++ return r; ++ ++ if (server_name) ++ *server_name = TAKE_PTR(name); ++ ++ return r; ++} +diff --git a/src/resolve/resolved-util.h b/src/resolve/resolved-util.h +new file mode 100644 +index 0000000000..10ebbc0874 +--- /dev/null ++++ b/src/resolve/resolved-util.h +@@ -0,0 +1,6 @@ ++/* SPDX-License-Identifier: LGPL-2.1+ */ ++#pragma once ++ ++#include "in-addr-util.h" ++ ++int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name); +diff --git a/src/resolve/test-resolved-util.c b/src/resolve/test-resolved-util.c +new file mode 100644 +index 0000000000..35bd73c4f6 +--- /dev/null ++++ b/src/resolve/test-resolved-util.c +@@ -0,0 +1,32 @@ ++/* SPDX-License-Identifier: LGPL-2.1+ */ ++ ++#include "log.h" ++#include "resolved-util.h" ++#include "string-util.h" ++#include "tests.h" ++ ++ ++static void test_in_addr_ifindex_name_from_string_auto_one(const char *a, const char *expected) { ++ int family, ifindex; ++ union in_addr_union ua; ++ _cleanup_free_ char *server_name = NULL; ++ ++ assert_se(in_addr_ifindex_name_from_string_auto(a, &family, &ua, &ifindex, &server_name) >= 0); ++ assert_se(streq_ptr(server_name, expected)); ++} ++ ++static void test_in_addr_ifindex_name_from_string_auto(void) { ++ log_info("/* %s */", __func__); ++ ++ test_in_addr_ifindex_name_from_string_auto_one("192.168.0.1", NULL); ++ test_in_addr_ifindex_name_from_string_auto_one("192.168.0.1#test.com", "test.com"); ++ test_in_addr_ifindex_name_from_string_auto_one("fe80::18%19", NULL); ++ test_in_addr_ifindex_name_from_string_auto_one("fe80::18%19#another.test.com", "another.test.com"); ++} ++ ++int main(int argc, char **argv) { ++ test_setup_logging(LOG_DEBUG); ++ ++ test_in_addr_ifindex_name_from_string_auto(); ++ return 0; ++} +-- +2.26.2 + diff --git a/backport-CVE-2018-21029-resolve-error-handling-improvements.patch b/backport-CVE-2018-21029-resolve-error-handling-improvements.patch new file mode 100644 index 0000000..c04f6d6 --- /dev/null +++ b/backport-CVE-2018-21029-resolve-error-handling-improvements.patch @@ -0,0 +1,80 @@ +From df70539f9fe01a16d0f561ad9c6f5d7a955039c0 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Mon, 10 Feb 2020 14:50:03 +0900 +Subject: [PATCH] resolve: error handling improvements + +--- + src/resolve/resolved-dnstls-openssl.c | 27 ++++++++++++++++++--------- + 1 file changed, 18 insertions(+), 9 deletions(-) + +diff --git a/src/resolve/resolved-dnstls-openssl.c b/src/resolve/resolved-dnstls-openssl.c +index ce0a437371..8f58efacbd 100644 +--- a/src/resolve/resolved-dnstls-openssl.c ++++ b/src/resolve/resolved-dnstls-openssl.c +@@ -73,7 +73,9 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) { + return -ENOMEM; + + SSL_set_connect_state(s); +- SSL_set_session(s, server->dnstls_data.session); ++ r = SSL_set_session(s, server->dnstls_data.session); ++ if (r == 0) ++ return -EIO; + SSL_set_bio(s, TAKE_PTR(rb), TAKE_PTR(wb)); + + if (server->manager->dns_over_tls_mode == DNS_OVER_TLS_YES) { +@@ -83,7 +85,7 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) { + 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))) ++ if (X509_VERIFY_PARAM_set1_ip(v, ip, FAMILY_ADDRESS_SIZE(server->family)) == 0) + return -ECONNREFUSED; + } + +@@ -106,8 +108,8 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) { + char errbuf[256]; + + ERR_error_string_n(error, errbuf, sizeof(errbuf)); +- log_debug("Failed to invoke SSL_do_handshake: %s", errbuf); +- return -ECONNREFUSED; ++ return log_debug_errno(SYNTHETIC_ERRNO(ECONNREFUSED), ++ "Failed to invoke SSL_do_handshake: %s", errbuf); + } + } + +@@ -368,20 +370,27 @@ void dnstls_server_free(DnsServer *server) { + + int dnstls_manager_init(Manager *manager) { + int r; ++ + assert(manager); + + ERR_load_crypto_strings(); + SSL_load_error_strings(); +- manager->dnstls_data.ctx = SSL_CTX_new(TLS_client_method()); + ++ manager->dnstls_data.ctx = SSL_CTX_new(TLS_client_method()); + if (!manager->dnstls_data.ctx) + return -ENOMEM; + +- SSL_CTX_set_min_proto_version(manager->dnstls_data.ctx, TLS1_2_VERSION); +- SSL_CTX_set_options(manager->dnstls_data.ctx, SSL_OP_NO_COMPRESSION); ++ r = SSL_CTX_set_min_proto_version(manager->dnstls_data.ctx, TLS1_2_VERSION); ++ if (r == 0) ++ return -EIO; ++ ++ (void) SSL_CTX_set_options(manager->dnstls_data.ctx, SSL_OP_NO_COMPRESSION); ++ + r = SSL_CTX_set_default_verify_paths(manager->dnstls_data.ctx); +- if (r < 0) +- log_warning("Failed to load system trust store: %s", ERR_error_string(ERR_get_error(), NULL)); ++ if (r == 0) ++ return log_warning_errno(SYNTHETIC_ERRNO(EIO), ++ "Failed to load system trust store: %s", ++ ERR_error_string(ERR_get_error(), NULL)); + + return 0; + } +-- +2.26.2 + diff --git a/backport-CVE-2018-21029-resolved-check-for-IP-in-certificate-when-using-DoT-.patch b/backport-CVE-2018-21029-resolved-check-for-IP-in-certificate-when-using-DoT-.patch new file mode 100644 index 0000000..74b9b80 --- /dev/null +++ b/backport-CVE-2018-21029-resolved-check-for-IP-in-certificate-when-using-DoT-.patch @@ -0,0 +1,51 @@ +From 7f2f4faced3fda47e6b76ab73cde747cc20cf8b8 Mon Sep 17 00:00:00 2001 +From: Iwan Timmer +Date: Tue, 29 Oct 2019 20:32:18 +0100 +Subject: [PATCH] resolved: check for IP in certificate when using DoT with + GnuTLS + +Validate the IP address in the certificate for DNS-over-TLS in strict mode when GnuTLS is used. As this is not yet the case in contrast to the documentation. +--- + src/resolve/resolved-dnstls-gnutls.c | 13 +++++++++++-- + src/resolve/resolved-dnstls-gnutls.h | 1 + + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/src/resolve/resolved-dnstls-gnutls.c b/src/resolve/resolved-dnstls-gnutls.c +index ea276d2c20..9e5e60fcce 100644 +--- a/src/resolve/resolved-dnstls-gnutls.c ++++ b/src/resolve/resolved-dnstls-gnutls.c +@@ -55,8 +55,17 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) { + server->dnstls_data.session_data.size = 0; + } + +- if (server->manager->dns_over_tls_mode == DNS_OVER_TLS_YES) +- gnutls_session_set_verify_cert(gs, NULL, 0); ++ 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; ++ } ++ 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-gnutls.h b/src/resolve/resolved-dnstls-gnutls.h +index af52f04fdf..d4da2017c3 100644 +--- a/src/resolve/resolved-dnstls-gnutls.h ++++ b/src/resolve/resolved-dnstls-gnutls.h +@@ -18,6 +18,7 @@ struct DnsTlsServerData { + + struct DnsTlsStreamData { + gnutls_session_t session; ++ gnutls_typed_vdata_st validation; + int handshake; + bool shutdown; + }; +-- +2.26.2 + diff --git a/backport-CVE-2018-21029-resolved-fix-connection-failures-with-TLS-1.3-and-Gn.patch b/backport-CVE-2018-21029-resolved-fix-connection-failures-with-TLS-1.3-and-Gn.patch new file mode 100644 index 0000000..38431f0 --- /dev/null +++ b/backport-CVE-2018-21029-resolved-fix-connection-failures-with-TLS-1.3-and-Gn.patch @@ -0,0 +1,34 @@ +From 68805580209cfaa50b2400d1a2e6c66500001395 Mon Sep 17 00:00:00 2001 +From: Peter Wu +Date: Sun, 20 Oct 2019 18:10:31 +0100 +Subject: [PATCH] resolved: fix connection failures with TLS 1.3 and GnuTLS + +Prefer TLS 1.3 before TLS 1.2 for DNS-over-TLS support, otherwise +servers compliant with RFC 8446 might end up agreeing TLS 1.2 plus a +downgrade signal which is not expected by GnuTLS clients. This manifests +in the following error: + + Failed to invoke gnutls_handshake: An illegal parameter has been received. + +Fixes: #13528 +Fixes: v242-962-g9c0624dcdb ("resolved: support TLS 1.3 when using GnuTLS for DNS-over-TLS") +--- + src/resolve/resolved-dnstls-gnutls.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/resolve/resolved-dnstls-gnutls.c b/src/resolve/resolved-dnstls-gnutls.c +index 06d635fcc4..7ad9662073 100644 +--- a/src/resolve/resolved-dnstls-gnutls.c ++++ b/src/resolve/resolved-dnstls-gnutls.c +@@ -10,7 +10,7 @@ + #include "resolved-dnstls.h" + + #if GNUTLS_VERSION_NUMBER >= 0x030600 +-#define PRIORTY_STRING "NORMAL:-VERS-ALL:+VERS-TLS1.2:+VERS-TLS1.3" ++#define PRIORTY_STRING "NORMAL:-VERS-ALL:+VERS-TLS1.3:+VERS-TLS1.2" + #else + #define PRIORTY_STRING "NORMAL:-VERS-ALL:+VERS-TLS1.2" + #endif +-- +2.26.2 + diff --git a/backport-CVE-2018-21029-resolved-require-at-least-version-3.6.0-of-GnuTLS-fo.patch b/backport-CVE-2018-21029-resolved-require-at-least-version-3.6.0-of-GnuTLS-fo.patch new file mode 100644 index 0000000..32124be --- /dev/null +++ b/backport-CVE-2018-21029-resolved-require-at-least-version-3.6.0-of-GnuTLS-fo.patch @@ -0,0 +1,58 @@ +From 38e053c58fa139e0f546f327b5d8ce3db7cf1647 Mon Sep 17 00:00:00 2001 +From: Iwan Timmer +Date: Tue, 29 Oct 2019 20:26:05 +0100 +Subject: [PATCH] resolved: require at least version 3.6.0 of GnuTLS for + DNS-over-TLS + +Increase the required version to ensure TLS 1.3 is always supported when using GnuTLS for DNS-over-TLS and allow further changes to use recent API additions. +--- + README | 2 +- + meson.build | 2 +- + src/resolve/resolved-dnstls-gnutls.c | 4 ---- + 3 files changed, 2 insertions(+), 6 deletions(-) + +diff --git a/README b/README +index 8aa16fe8c9..8dbf94b49c 100644 +--- a/README ++++ b/README +@@ -155,7 +155,7 @@ REQUIREMENTS: + libmicrohttpd (optional) + libpython (optional) + libidn2 or libidn (optional) +- gnutls >= 3.1.4 (optional, >= 3.5.3 is required to support DNS-over-TLS with gnutls) ++ gnutls >= 3.1.4 (optional, >= 3.6.0 is required to support DNS-over-TLS with gnutls) + openssl >= 1.1.0 (optional, required to support DNS-over-TLS with openssl) + elfutils >= 158 (optional) + polkit (optional) +diff --git a/meson.build b/meson.build +index 0001504d53..a7a9222582 100644 +--- a/meson.build ++++ b/meson.build +@@ -1199,7 +1199,7 @@ if dns_over_tls != 'false' + if dns_over_tls == 'openssl' + have_gnutls = false + else +- have_gnutls = (conf.get('HAVE_GNUTLS') == 1 and libgnutls.version().version_compare('>= 3.5.3')) ++ have_gnutls = (conf.get('HAVE_GNUTLS') == 1 and libgnutls.version().version_compare('>= 3.6.0')) + if dns_over_tls == 'gnutls' and not have_gnutls + error('DNS-over-TLS support was requested with gnutls, but dependencies are not available') + endif +diff --git a/src/resolve/resolved-dnstls-gnutls.c b/src/resolve/resolved-dnstls-gnutls.c +index 7ad9662073..ea276d2c20 100644 +--- a/src/resolve/resolved-dnstls-gnutls.c ++++ b/src/resolve/resolved-dnstls-gnutls.c +@@ -9,11 +9,7 @@ + #include "resolved-dns-stream.h" + #include "resolved-dnstls.h" + +-#if GNUTLS_VERSION_NUMBER >= 0x030600 + #define PRIORTY_STRING "NORMAL:-VERS-ALL:+VERS-TLS1.3:+VERS-TLS1.2" +-#else +-#define PRIORTY_STRING "NORMAL:-VERS-ALL:+VERS-TLS1.2" +-#endif + DEFINE_TRIVIAL_CLEANUP_FUNC(gnutls_session_t, gnutls_deinit); + + static ssize_t dnstls_stream_writev(gnutls_transport_ptr_t p, const giovec_t *iov, int iovcnt) { +-- +2.26.2 + diff --git a/backport-CVE-2018-21029-systemd-resolved-use-hostname-for-certificate-valida.patch b/backport-CVE-2018-21029-systemd-resolved-use-hostname-for-certificate-valida.patch new file mode 100644 index 0000000..f69880f --- /dev/null +++ b/backport-CVE-2018-21029-systemd-resolved-use-hostname-for-certificate-valida.patch @@ -0,0 +1,124 @@ +From eec394f10bbfcc3d2fc8504ad8ff5be44231abd5 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. +--- + man/resolved.conf.xml | 19 +++++++++++-------- + src/resolve/resolved-dnstls-gnutls.c | 20 ++++++++++++-------- + src/resolve/resolved-dnstls-openssl.c | 15 +++++++++++---- + 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 @@ + + 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" +@@ -214,9 +220,6 @@ + resolver is not capable of authenticating the server, so it is + vulnerable to "man-in-the-middle" attacks. + +- Server Name Indication (SNI) can be used when opening a TLS connection. +- Entries in DNS= should be in format address#server_name. +- + In addition to this global DNSOverTLS setting + systemd-networkd.service8 + 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 aad3bb4481..ef90a7d5ae 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 + #include ++#include + + #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) { +-- +2.26.2 + diff --git a/systemd.spec b/systemd.spec index 8cdc2be..e6de2d9 100644 --- a/systemd.spec +++ b/systemd.spec @@ -16,7 +16,7 @@ Name: systemd Url: https://www.freedesktop.org/wiki/Software/systemd Version: 243 -Release: 73 +Release: 74 License: MIT and LGPLv2+ and GPLv2+ Summary: System and Service Manager @@ -287,6 +287,14 @@ Patch0237: backport-bus-use-bus_log_parse_error-to-print-message.patch Patch0238: backport-busctl-avoid-asserting-on-NULL-message.patch Patch0239: backport-sd-journal-check-sd-event-state-before-setting-up-po.patch +Patch0240: backport-CVE-2018-21029-resolved-check-for-IP-in-certificate-when-using-DoT-.patch +Patch0241: backport-CVE-2018-21029-resolved-fix-connection-failures-with-TLS-1.3-and-Gn.patch +Patch0242: backport-CVE-2018-21029-resolved-require-at-least-version-3.6.0-of-GnuTLS-fo.patch +Patch0243: backport-CVE-2018-21029-Be-more-specific-in-resolved.conf-man-page-with-rega.patch +Patch0244: backport-CVE-2018-21029-Implement-SNI-when-using-DNS-over-TLS.patch +Patch0245: backport-CVE-2018-21029-resolve-error-handling-improvements.patch +Patch0246: backport-CVE-2018-21029-systemd-resolved-use-hostname-for-certificate-valida.patch + #openEuler Patch9002: 1509-fix-journal-file-descriptors-leak-problems.patch Patch9003: 1602-activation-service-must-be-restarted-when-reactivated.patch @@ -1791,6 +1799,11 @@ fi %exclude /usr/share/man/man3/* %changelog +* Tue Mar 26 2024 wangyuhang - 243-74 +- Type:cve +- ID:CVE-2018-21029 +- SUG:NA + * Wed Feb 28 2024 huyubiao - 243-73 - Type:bugfix - CVE:NA -- Gitee