Package: ssh,systemd Severity: normal Hey
I've just been playing with SSHFP as a way of verifying SSH host keys (VerifyHostKeyDNS=yes) when I can trust my local DNS resolver. I was trying on Ubuntu 20.04 and I could just *not* get it to work. It was considering the response to be untrusted. I'll spare you all of the tedious details of the many things I tried, but it comes down to this. As of 2.31, glibc's stub resolver is stripping the AD (authenticated data) bit from resposes that it receives from its upstream name servers. This is documented in the release notes for 2.31: * The DNS stub resolver will optionally send the AD (authenticated data) bit in queries if the trust-ad option is set via the options directive in /etc/resolv.conf (or if RES_TRUSTAD is set in _res.options). In this mode, the AD bit, as provided by the name server, is available to applications which call res_search and related functions. In the default mode, the AD bit is not set in queries, and it is automatically cleared in responses, indicating a lack of DNSSEC validation. (Therefore, the name servers and the network path to them are treated as untrusted.) and a couple of relevant links https://gnutoolchain-gerrit.osci.io/r/c/glibc/+/461 https://bugzilla.redhat.com/show_bug.cgi?id=1164339#c15 I'm filing this on *both* SSH and systemd, since I think either or both are places that might want to consider being altered to account for this and I'd be interested in the maintainers' opinions. openssh ======= In Debian we are patching ssh to unconditionally send EDNS0, even if not specified in /etc/resolve.conf, in an effort to support this feature. Sending TRUSTAD too is arguably in keeping with the spirit of this patch. I tried this in the attached patch and it works. systemd ======= systemd-resolved similarly adds 'options edns0' to resolv.conf files it generates for its stub resolver. It could be extended (untested) to add the 'trust-ad' option. Counterargument =============== I'm not very well-read here yet, but it seems like this is done because AD can be faked by malicious resolvers, and so the argument is that it's not safe to trust it unless you know you're in a trusted environment. In that light, perhaps what ssh and systemd are doing (adding edns0 to make the AD bit be sent automatically) is working against upstream glibc's goal, and so we shouldn't do this for users without their opt-in? This is where I'd appreciate the input of wiser heads. If this type of argument is accepted, it would be good to provide a simple way to turn trust-ad on so that people can do it when they are on trusted networks. (Maybe even with higher-level support from something like network-manager too.) Cheers, -- Iain Lane [ i...@orangesquash.org.uk ] Debian Developer [ la...@debian.org ] Ubuntu Developer [ la...@ubuntu.com ]
diff -Nru openssh-8.2p1/debian/patches/dnssec-sshfp.patch openssh-8.2p1/debian/patches/dnssec-sshfp.patch --- openssh-8.2p1/debian/patches/dnssec-sshfp.patch 2020-02-26 10:55:07.000000000 +0000 +++ openssh-8.2p1/debian/patches/dnssec-sshfp.patch 2020-05-03 20:00:01.000000000 +0100 @@ -17,11 +17,11 @@ openbsd-compat/getrrsetbyname.h | 3 +++ 3 files changed, 21 insertions(+), 6 deletions(-) -diff --git a/dns.c b/dns.c -index e4f9bf830..9c9fe6413 100644 +Index: b/dns.c +=================================================================== --- a/dns.c +++ b/dns.c -@@ -210,6 +210,7 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address, +@@ -210,6 +210,7 @@ { u_int counter; int result; @@ -29,7 +29,7 @@ struct rrsetinfo *fingerprints = NULL; u_int8_t hostkey_algorithm; -@@ -233,8 +234,19 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address, +@@ -233,8 +234,19 @@ return -1; } @@ -50,11 +50,11 @@ if (result) { verbose("DNS lookup error: %s", dns_result_totext(result)); return -1; -diff --git a/openbsd-compat/getrrsetbyname.c b/openbsd-compat/getrrsetbyname.c -index dc6fe0533..e061a290a 100644 +Index: b/openbsd-compat/getrrsetbyname.c +=================================================================== --- a/openbsd-compat/getrrsetbyname.c +++ b/openbsd-compat/getrrsetbyname.c -@@ -209,8 +209,8 @@ getrrsetbyname(const char *hostname, unsigned int rdclass, +@@ -209,8 +209,8 @@ goto fail; } @@ -65,7 +65,7 @@ result = ERRSET_INVAL; goto fail; } -@@ -226,9 +226,9 @@ getrrsetbyname(const char *hostname, unsigned int rdclass, +@@ -226,9 +226,9 @@ #endif /* DEBUG */ #ifdef RES_USE_DNSSEC @@ -74,15 +74,25 @@ - _resp->options |= RES_USE_DNSSEC; + /* turn on DNSSEC if required */ + if (flags & RRSET_FORCE_EDNS0) -+ _resp->options |= (RES_USE_EDNS0|RES_USE_DNSSEC); ++ _resp->options |= (RES_USE_EDNS0|RES_USE_DNSSEC|RES_TRUSTAD); #endif /* RES_USE_DNSEC */ /* make query */ -diff --git a/openbsd-compat/getrrsetbyname.h b/openbsd-compat/getrrsetbyname.h -index 1283f5506..dbbc85a2a 100644 +Index: b/openbsd-compat/getrrsetbyname.h +=================================================================== --- a/openbsd-compat/getrrsetbyname.h +++ b/openbsd-compat/getrrsetbyname.h -@@ -72,6 +72,9 @@ +@@ -66,12 +66,19 @@ + #define T_RRSIG 46 + #endif + ++#ifndef RES_TRUSTAD ++#define RES_TRUSTAD 0x04000000 /* Request AD bit, keep it in responses. */ ++#endif ++ + /* + * Flags for getrrsetbyname() + */ #ifndef RRSET_VALIDATED # define RRSET_VALIDATED 1 #endif