Bug#960023: SSHFP stops working with libc6 2.31 [AD bit stripped]

Iain Lane laney at debian.org
Fri May 8 13:32:21 BST 2020


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                                  [ iain at orangesquash.org.uk ]
Debian Developer                                   [ laney at debian.org ]
Ubuntu Developer                                   [ laney at ubuntu.com ]
-------------- next part --------------
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


More information about the Pkg-systemd-maintainers mailing list