Kyh's blog

Kyh's random blog of stuff

SSHFP DNS Records

So it turns out there’s several RFCs for adding SSH fingerprints to DNS records. They would be RFCs 4255 and 6594

What is this useful for?

Well, if you’re sshing into a box from a new location and don’t remember your SSH fingerprints (Was it the RSA/DSA/ECDSA one!?), your SSHFP record(s) will let you verify them. This also prevents MITM attacks upon first connections by verifying “out of band” over DNS. Of course, someone can come along and also MITM your DNS lookups, but that’s what DNSSEC is for.

Openssh seems to have support for SSHFP records since forever (I couldn’t find what version) via the VerifyHostKeyDNS option. Versions of openssh 5.7p1+ have support for ECDSA keys, but only added RFC6594 support (ECDSA and SHA256 hashed fingerprints) in 6.1p1. So if you have ECDSA keys, you’ll need to upgrade to 6.1p1 if you want the ssh client to verify the ECDSA fingerprints. (Type 3)

In order to have openssh verify the SSHFP records, you need to use ssh -o verifyhostkeydns=yes or add the VerifyHostKeyDNS option to your .ssh/config.

Adding SSHFP records are as simple as doing a “` ssh-keygen -r hostname ““ on the machine you want to generate the records for and copy/pasting the output into your zone file.

You’ll get output like:

1
2
3
4
5
6
hostname IN SSHFP 1 1 f14c4f33571ffbf90c9d5f15129cc9c041059f41
hostname IN SSHFP 1 2 3cf2edc60ab732743b085b6f069933e2a173c7c8e3bff5f8670a36a9deb3c4df
hostname IN SSHFP 2 1 b3a4503cae6a4d6735628e4e1039b4fc792ecb2c
hostname IN SSHFP 2 2 2e82993087a7cd7f4ed848ce3f189bc306ff60b152c73a8b50b08fe9256d4dcb
hostname IN SSHFP 3 1 d5a2e79a08bf51455a1d693e53742359eb3d4e01
hostname IN SSHFP 3 2 6196ea891b455633bbb0f81f60f4c9b0d55fa5bc8d5eec11d6d6d1e6caf954d9

The first 3 columns being self-explanatory. The fourth column is the type of key (1 = RSA, 2 = DSA, 3 = ECDSA), fifth column is 1 = SHA1, 2 = SHA256 and the last column being the SHA1 or SHA256 hash of the public key. (un-based64ed, as it’s stored in ssh_hostkey.pub base64 encoded)

You can check your SSHFP records by doing a dig +short SSHFP example.org

Now, annoyingly openssh doesn’t do any kind of DNSSEC validation on its own, so it’s only checking the AD (authenticated data) bit on the response from the DNS resolver. Unfortunatley if you’re not running a local or remote validating resolver that you trust the network path to, an attacker can still change/strip the AD bit from the response between you and the resolver.

They can do this because it’s the resolver that verifies the DNSSEC records and simply returns a bit saying “Yes, this record is signed and valid”.

Another hurdle is that doing DNSSEC lookups almost always results in DNS packets that are larger than 512 bytes. (If you run a firewall and you block TCP DNS or UDP DNS packets larger than 512 bytes, you’re an asshole. Stop it).

This is where EDNS-0 (Extension mechanisms for DNS) comes in. You have to set your resolver options (RES_OPTIONS) to explicitly enable edns0 support. In Linux, this is “export RES_OPTIONS=edns0”.

What if you don’t have a validating resolver? Well, you could install unbound + dnssec-trigger but that’s a pain in the arse, so lets use a trick @isomer told me. We’re going to use googles public DNS resolvers, since they validate DNSSEC records now.

1
2
3
4
5
sudo unshare --mount bash
echo "nameserver 8.8.8.8" >newresolv.conf
mount --bind newresolv.conf /etc/resolv.conf
export RES_OPTIONS=edns0
ssh -v  -p 1000 -o VerifyHostKeyDNS=yes user@yourdomain.tld

(You can use test at kyhwana.org if you’d like to see some actual valid SSHFP records.)

What the above does is run a bash shell with the mount namespace “unshared” from the rest of the system, so we can go ahead and bind newresolv.conf with the google DNS resolver IPs to /etc/resolv.conf, this only affects the bash shell we’ve started. We then tell our resolver to use EDNS0 and then ssh to the host with verbose mode turned on, where we should see: debug1: found 6 secure fingerprints in DNS debug1: matching host key fingerprint found in DNS indicating that it’s found the SSHFP fingerprints and that they’re signed correctly!

Huzzah, you can now securely connect to a host that you’ve connected to before and know that you’re not being MITMed! (Assuming our DNS packets aren’t being interferred with between us and googles DNS)