Publish ssh public host key fingerprints in DNS (SSHFP)

This article describes a solution to the problem where people answers ‘yes’ on the question if they are sure they want to continue connection to a new/unknown SSH server. The solution is to publish SSHFP records in DNS.

Have you ever blindly answered yes to something like this?

The authenticity of host 'framkant.org (52.16.239.146)' can't be established.
ECDSA key fingerprint is 42:f9:b3:40:17:61:89:e4:80:cf:d5:ae:bb:bb:7d:75.
+--[ECDSA  256]---+
|   ....o+o       |
|  .  oooo.       |
|   o .=..        |
|    oo o.        |
|      o.S        |
|      .o o  . E  |
|       ..  . .   |
|      ..  .      |
|      ++..       |
+-----------------+
Are you sure you want to continue connecting (yes/no)? 

Well, dont. Of course its very important to know WHERE you are connecting. In a directed attack the attacker could have set up a server of their own to fool you to reveal important passwords or other information. But most people dont think to much about this and just answers yes to get rid of the message.

The problem is, HOW do you distribute the correct fingerprint and check it? In a datacenter there are many was to do this (configuration orchestration, ldap and so on) but to end users and home computers this is a probem. Of coruse you could post your fingerprints on a webpage secured with https, but the chances a user would really sit down and compare the numbers are slim.

The solution is DNSSEC. When your zone is signed and the chain of trust is complete a client can really trust the correctness of the information present in the DNS tree. Publishing your ssh host key fingerprints here sounds like a great idea. The new record type SSHFP solves this problem and the good news is that OpenSSH have support since a few years back. Its even so simple that ssh-keygen can generate the new records for you:

> ssh-keygen -r framkant.org
framkant.org IN SSHFP 1 1 d6a64454a9a559ec35f59994c2e5f8376ff86ac8
framkant.org IN SSHFP 1 2 99d78eff62823561bab2661a72250f1e8344c1c6a4e8903f0d5d8ebce6d819b7
framkant.org IN SSHFP 2 1 9572024308e542074768bbfd6a3ff8b30e940ce2
framkant.org IN SSHFP 2 2 ab63e4ebe5ba0b9eb12a9735a533cfdf5e2807bac852e8b019dedfb630841896
framkant.org IN SSHFP 3 1 fe1160646ac00872d269ebd7ddaa07cb83d7d6af
framkant.org IN SSHFP 3 2 6580debbe37b4a2f32eed78aec2e2f943de6559f24f2b6d7671e78a0ca469728

The first digit represent the key type and the second represent the hash used. You can read more about this in RFC 4255. If your zone is signed by DNSSEC and the chain of trust is complete you will see something like this when connecting to a server with SSHFP records attached to it.

debug1: Server host key: ECDSA 42:f9:b3:40:17:61:89:e4:80:cf:d5:ae:bb:bb:7d:75
debug1: found 6 secure fingerprints in DNS
debug1: matching host key fingerprint found in DNS
debug1: ssh_ecdsa_verify: signature correct

OpenSSH uses two different methods to find out if the records are secured by DNSSEC. If compiled with ldns-support it will perform the DNSSEC-validation itself. If not, it will trust the resolvers in resolv.conf to do the validation. The resolver will set a special bit, the AD-bit (Authenticated Data) if dnssec validates. If the AD-bit is set on the response from the resolver ssh will assume that the records can be trusted.

If you want ssh to always try to use information found in DNS add this to your ~/.ssh/config

Host *
    VerifyHostKeyDNS yes

References
RFC 4255

Running OpenDNSSEC

During the years there have been several vulnerabilities found in the DNS protocol making it possible to fool clients in different ways. Maybe the most well known is called dns cache poisoning. To resolve some of these problems people came up with DNSSEC. DNSSEC is a way to cryptographically prove the authenticity of a DNS response by validating signatures all the way up to the root zone. You can read more about it on wikipedia.

This article is an attempt to describe how to implement DNSSEC on your own authoritative name servers. The first and most important step before you even begin to think about implementing DNSSEC is to find out if your registrar supports publishing DS records in the parent zone. If this is not the case your chain of trust will be broken and dnssec will fail.

Installing
OpenDNSSEC uses a PKCS#11 enabled backend to store cryptographic material (Hardware Security Module). These could be very expensive, so they also provide a software version of a HSM. This way you can start using OpenDNSSEC without having to pay thousands of dollars on crypto hardware. I’ve been looking into a quite affordable HSM for my (very small) needs. http://www.smartcard-hsm.com

We start by installing the software from packages

# pkg install opendnssec
[...]
# pkg install softhsm
[...]

Configuration
We start by setting up the SoftHSM. It comes default with this configuration which will work just fine for us.

# SoftHSM configuration file
#
# Format:
# :
#
# The given paths are just an indication to SoftHSM on where it should
# store the information for each token.

0:/var/lib/softhsm/slot0.db

We then need to initialize the HSM by running

# softhsm --init-token --slot 0 --label "OpenDNSSEC"
The SO PIN must have a length between 4 and 255 characters.
Enter SO PIN: 
The user PIN must have a length between 4 and 255 characters.
Enter user PIN: 
The token has been initialized.

You will later use the SO PIN to reset/reinit the HSM and the user PIN will be used to access your keys.

Now we can start looking at OpenDNSSEC. First make sure that /usr/local/etc/opendnssec/conf.xml looks reasonable (it does for most people). Just make sure the repository section matches information you gave to OpenHSM.

Then we have a quick look at the kasp.xml “Key and Signature Policy”. This file specifies at which intervals you want to renew the cryptographic keys in you setup. You have have two types of keys for every domain you handle within OpenDNSSEC. KSK and ZSK. The KSK is the “Key Signing Key”. If you are familiar with Certificate authorities this is sort of the Root CA. Its the signature this of key you pass upwards to the parent in the chain of trust. The ZSK is the “Zone Signing Key” and its used to sign the Records in the zone. In the CA anology this is a Intermidiate CA. The purpose of using two keys is to give the opportunity to store the KSK more securely (even offline) when its not used. If you store your keys very securley you can extend the lifetime of the KSK without any problems. The lifetime of your KSK defines how often you need to talk to your registrar and publish new fingerprints in the parent zone. OpenDNSSEC will manage ZSK key rollover for you.

Now we can start opendnssec and begin to have some zones signed. First of all we need to create the databases needed

# ods-ksmutil setup
*WARNING* This will erase all data in the database; are you sure? [y/N] y

Then we can start the opendnssec daemons.

# sh /usr/local/etc/rc.d/opendnssec onestart
Starting enforcer...
OpenDNSSEC ods-enforcerd started (version 1.4.8.2), pid 42305
Starting signer engine...
OpenDNSSEC signer engine version 1.4.8.2
Engine running.

To have it start at boot put opendnssec_start=”YES” in /etc/rc.conf.

Key management
I run OpenDNSSEC and my DNS-server (nsd) on the same machine so I sign the zones and put them in a folder that nsd can reach. It is also possible to send your zones with zone transfers if you are having a separate machine for OpenDNSSEC. Anyway, this is how you add a new zone to OpenDNSSEC and then tell it to sign it.

# ods-ksmutil zone add --zone framkant.org --input /usr/local/etc/nsd/chroot/zones/framkant.org --output /usr/local/etc/nsd/chroot/zones/signed/framkant.org
zonelist filename set to /usr/local/etc/opendnssec/zonelist.xml.
Imported zone: framkant.org
# ods-ksmutil update zonelist
zonelist filename set to /usr/local/etc/opendnssec/zonelist.xml.
kasp filename set to /usr/local/etc/opendnssec/kasp.xml.
Zone framkant.org found; policy set to default
Notifying enforcer of new database...
# ods-signer sign framkant.org
Zone framkant.org scheduled for immediate re-sign.

An here is the before and after:
Unsigned:

$TTL 300
@ SOA ns3.jails.se. peter.jails.se. (
				2015032501
				3H	; Refresh after three hours
				1H	; Retry after one hour
				1W	; Expire after one week
				1D )	; Minimum one day TTL

		NS	ns3.jails.se.
		NS	mx3.jails.se.
		MX	10 mail.jails.se.
		MX	20 mx3.jails.se.
		
@		A	52.16.239.146
		AAAA	2001:470:6c08::1


www		A	52.16.239.146
		AAAA	2001:470:6c08::1

Signed:

framkant.org.	3600	IN	SOA	ns3.jails.se. peter.jails.se. 2015032504 10800 3600 604800 3600
framkant.org.	3600	IN	RRSIG	SOA 8 2 3600 20151214230507 20151130173240 26386 framkant.org. iheuqDSSeLdoXJpYOI9ICFSDETnxXbls5K8YnnLBqeQOqgvxNRESWqy1rgAtnReFHnijcMpwly3ttFGUVtd9C4x3dQwMSbgwe9mXY0Tp/ojDdXG0UQLUXHgys0jFen1Go+c3r97lRH8RblIDVu5D5tVynO8+fN9FKzy29ZWfcbc=
framkant.org.	3600	IN	DNSKEY	257 3 8 AwEAAdbN+hOWIvhXB/M4R6KUPPALZA+DUcsW/jEl/Q/1BNi2ff9JZECgNi+2sv1nTdZ+6nOchKNP8UoZ41X4d82MQsO+mGIZeXW5Cb0Riqk7+B7EQWd6jH/pXs9/wNBRQHCNGk1NsyHQNgGxdAq3w99oeIaEbiI+4r/fnwjqKpg3boMyWZlNW30XcJMObXu57hO3S6f09I/+r+7d1bH8FbPBI1VWqiDPgQqjMOkJHrroJ3QWNr8qqSJSsxe2Zb9rTmkx6htrS2XQT2v1kvTT3iBO/Vf+JNbSNYOX4BnR5otgwr9I9OteLDFW4NGn5JNm3Q+kvrLAjByGyOsq0hI3TbvXp20= ;{id = 60509 (ksk), size = 2048b}
framkant.org.	3600	IN	DNSKEY	256 3 8 AwEAAfNwi9djf7sYUVQpqScBOBMqjFD9GqHeI11Y/62SWINheq8+sQ8H/yN2H3eqmW9+ffBVNU8VTCVcdLOwkPGEF5Q1lE7hIbHGLunCAUo5OC8yFhuEtXNFoYo/EuGGbgUmcgYLNKIu8+RxzL5VO9dV7FTUy60tnCsYi/tKDGBP376p ;{id = 26386 (zsk), size = 1024b}
framkant.org.	3600	IN	RRSIG	DNSKEY 8 2 3600 20151214194904 20151130173136 60509 framkant.org. G6+/6njI1NSCvWIeOhyvFo/+v1uSSFRx2Art3bv7Gw2nSJA2aMiu1ZVaIw7uGf75xdWr6lSj6ndb61UmTl+N6ccdbTU80HxwPmBA/fVZpGIAJrQ8psLgx8uDY3AxCfZdEq3YM0JzPewLnKGUaoVFsTzoWNNw2NRYqUuRiBnlebibcci70vaI0QpyRlXfSJ4DWls3H0isk0BWdukcpYEKNx4hl6GsRDCpNRoNs27TXgHnAcv7YV1528gyrgbw63DT6yyyL49nlN+TEV5aiDlNsjnkYJqgy869xfMROAw0VScHderqnixW4LlAGX0QYuPuOoK2dPx874i7xH7JhOoTbQ==
framkant.org.	0	IN	NSEC3PARAM	1 0 5 c2d153cf47fb60fa 
framkant.org.	0	IN	RRSIG	NSEC3PARAM 8 2 0 20151214120059 20151130173136 26386 framkant.org. DlSk0ye1kcP7g0z6QJy0QYpB75ZPpWhbypyRJ3a+L0BaL4cY/cdRS9SACxmhXu/kEkrmadJ/IcfDMhMHOj9D0uY+8ksbKfVhpAX237sFp18V8rsH0zkOPjMjD1O4c30N+isLVdnaPX3OyIRxqRFrRL2XH4kMOR9c8uBpBtin/MU=
framkant.org.	300	IN	NS	ns3.jails.se.
framkant.org.	300	IN	NS	mx3.jails.se.
framkant.org.	300	IN	RRSIG	NS 8 2 300 20151214130253 20151130173136 26386 framkant.org. X9V2dv2+tyWoom6SC5zwkgkMj0buTu/wvGO/ClE7KveJ3YwmG/kPH0z37sS6GWK+j1MzNTzDepcUdxxghO/shDZvSz/7WAtvuHVPWfo2lg+iGG7nxCmYqcmq7Vo2+GZCU5TRjivsCDxen9w+e8+AuZtpuTkEppTQMbEIq+qNGyw=
framkant.org.	300	IN	MX	10 mail.jails.se.
framkant.org.	300	IN	MX	20 mx3.jails.se.
framkant.org.	300	IN	RRSIG	MX 8 2 300 20151215000707 20151130173136 26386 framkant.org. Yw1eRGRESXu1bGh/RNhqJNFpjv+MsDzoyxoPOTNTZiBr+OmlCq6p8M6QgfEPIipmg0VzrHJjzEFfpb4WQmPTKKehH/nEoevKLAogPjbozucr+lgjAXh3AoXr15OYF9dyJilyuTLQ3TyyWDAOxSHtnHy5w704ibaIyGoeKniTf3k=
framkant.org.	300	IN	A	52.16.239.146
framkant.org.	300	IN	RRSIG	A 8 2 300 20151214104407 20151130173136 26386 framkant.org. zmVjO5Rh1R+lpIUdIvsyTCmhGt2qL1wHUIOlZJbBkiiVpdE051MhRTShRjU79LQ5a+SlBeE5jjVeRrAXhTAb6KhNzZ5j5JaTjPYXzqxe//ddpMYEDzGhmuO1zkfUjtKCFhxgk92lFqimHXJFTj3nXdgbmqvK1io7aqYWCRvKxt4=
framkant.org.	300	IN	AAAA	2001:470:6c08::1
framkant.org.	300	IN	RRSIG	AAAA 8 2 300 20151214075539 20151130173136 26386 framkant.org. ymUD9mz9uQ6on0SF8TSFbb5xU100mJZuZeJafub1YkeolsxmcyXP0HQl0c20QFHWWp7qX4L7rY7QKIgc9aeaMkskrT9BEmwFoTB/MMu9nrweZyyAUdnnrD06mJ6BumBM0ZWBt6qHLe4tiPh8YVqCCjhFBo+SUvDOfelg3k/QAkY=
rl1jo83jomo43daiudaavkfofbmtkks2.framkant.org.	3600	IN	NSEC3	1 0 5 c2d153cf47fb60fa  h0gt9jkpqemi2oumlejri2lvo60uc2qt A NS SOA MX AAAA RRSIG DNSKEY NSEC3PARAM 
rl1jo83jomo43daiudaavkfofbmtkks2.framkant.org.	3600	IN	RRSIG	NSEC3 8 3 3600 20151214151238 20151130173240 26386 framkant.org. 6iNFSodcFOSydizrXrduzAsTPkZB+wqqr0IrdqEL+YcoM1aefmHfX3l5Kems01KCihozii5O23oprGXw0niYk4ESvXjYH0pOK/J6KWes9PirDQj0P8w//FiX9I7jYL4YkfAqf+pKU1vx2mVDT5ATD2Dkty4GX7eKg4h7qDvgSUM=
www.framkant.org.	300	IN	A	52.16.239.146
www.framkant.org.	300	IN	RRSIG	A 8 3 300 20151214080233 20151130173136 26386 framkant.org. TqG3vzzO3vIPVLZpWHh5Sh6ijNBr61u+7jEMlpl/kfj7S5wvmMgUkWl+hmNaokgrDvrEahpCdTQ0yjSmWl+m5aVFlV17x0x5lJN+Fcx+SuOqqdkHkYKDyTShWdyfDRj9rAQxThbrhvOz3+6gfTJ1HMeGBXIkLMzf1MEojHDlhEg=
www.framkant.org.	300	IN	AAAA	2001:470:6c08::1
www.framkant.org.	300	IN	RRSIG	AAAA 8 3 300 20151214134021 20151130173136 26386 framkant.org. reaA1ca5Jly76YPU+Nfq6CEwgqx7/T2xYh7IzfJ4aZ034vF7djYJFvNMvKMF5wuX7hbP44B3lQk/mnYlzmuVsKGYIwNvU+4+ggIsahgdCItasFOLdJln3oY7f+ch/o6XljE9JKusWFYT2GcPLCsr73PcEIF3QkdXDgXZzSDuZBc=
h0gt9jkpqemi2oumlejri2lvo60uc2qt.framkant.org.	3600	IN	NSEC3	1 0 5 c2d153cf47fb60fa  rl1jo83jomo43daiudaavkfofbmtkks2 A AAAA RRSIG 
h0gt9jkpqemi2oumlejri2lvo60uc2qt.framkant.org.	3600	IN	RRSIG	NSEC3 8 3 3600 20151215051041 20151130173240 26386 framkant.org. lbAGEJm+kCHy68wZ9YqbAFuESnabPvL5TwA0MnwtliUa+lB5DEI2/DIPa+QS7sekjWUxmve2FQoQC+0gFbCP9gOFle8bTwZsAf7ZtZJeVuzEI/HcisNbJk5bV/E/p6xyIBwUDKbcdPh1vhmyDXkhSOZ0o16vLbPgZwuBKtk8J2s=

To handle your created keys you can use ods-ksmutil

# ods-ksmutil key list --verbose
SQLite database set to: /usr/local/var/opendnssec/kasp.db
Keys:
Zone:                           Keytype:      State:    Date of next transition (to):  Size:   Algorithm:  CKA_ID:                           Repository:                       Keytag:
framkant.org                    KSK           publish   2015-12-01 09:31:35 (ready)    2048    8           adcfe72699de3bb9afe511d67a112580  SoftHSM                           60509
framkant.org                    ZSK           active    2016-02-28 19:31:35 (retire)   1024    8           fcf02532b68b64f7f0dbccf85be3677f  SoftHSM                           26386

Now you need to publish a fingerprint of you key in the parent zone. Please refer to your registrar on how to do this. In sweden at least .SE, binero and loopia have support for this. To get the DS record you can use:

ods-ksmutil key export --ds --zone framkant.org
;active KSK DS record (SHA1):
framkant.org.	3600	IN	DS	65041 8 1 766dee3e0d5cac1c19529d4474eb828d72a91d24
;active KSK DS record (SHA256):
framkant.org.	3600	IN	DS	65041 8 2 a5aba22e70dcc7ad0ee9d31210f87b4f8e99bf6222463eb9c53f3d7a46143129

This is the information you need to send to your registrar. When you can see the DS-record in the parent zone

# drill DS framkant.org @b2.org.afilias-nst.org
;; ->>HEADER<

it is time to tell OpenDNSSEC that the keys are in place and its time to mark the KSK as active.

# ods-ksmutil key ds-seen --zone framkant.org --keytag 60509

Now you are up and running, and if all goes well it will work just fine for one year, until you will need to change the DS records present at the tld. Please refer to the OpenDNSSEC documentation for more information.

Reference:
https://wiki.opendnssec.org/display/DOCS/OpenDNSSEC+Documentation+Home
https://wiki.opendnssec.org/display/SoftHSMDOCS/SoftHSM+Documentation+v1.3