Monthly Archives: November 2015

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 ' (' 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 IN SSHFP 1 1 d6a64454a9a559ec35f59994c2e5f8376ff86ac8 IN SSHFP 1 2 99d78eff62823561bab2661a72250f1e8344c1c6a4e8903f0d5d8ebce6d819b7 IN SSHFP 2 1 9572024308e542074768bbfd6a3ff8b30e940ce2 IN SSHFP 2 2 ab63e4ebe5ba0b9eb12a9735a533cfdf5e2807bac852e8b019dedfb630841896 IN SSHFP 3 1 fe1160646ac00872d269ebd7ddaa07cb83d7d6af 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

RFC 4255

WPA2 Enterprise with hostapd

After setting up my wireless FreeBSD router I wanted to secure my wireless network with WPA2 Enterprise.

I’ve had a really hard time finding any good documentation on hostapd, but I finally got it to work. So why would you use WPA2 Enterprise, isnt Personal good enough? Well, the problem is these days that anyone can set up a wireless network with the same name as yours. If you connect to this fake network beliving you are connected to your own someone have full access to everything you send and receive. WPA2 Enterprise fixes this because the access point also has to prove its identity by providing a valid SSL Certificate. If this certificate changes you will be notified right away.

So, how do you set it up in hostapd? Well, its not that complex at all, the problem is that you cant find any documentation on it.


Here is my configuration for WPA2 Enterprise. This uses hostapds own internal RAIDUS-server but you could as well use FreeRADIUS or some other RADIUS server out there, but then you’ll have to figure out how to configure that in hostapd. 😀


wpa_pairwise=TKIP CCMP

# Path for EAP server user database


"peter@domain.tld" PEAP [ver=0]
"peter@domain.tld" MSCHAPV2 "passphrase" [2]

You can also set up it to require client certificate to connect to make it even more “secure”. It all depends on how you handle your certificates and passwords.

#"peter@domain.tld" PEAP [ver=0]
"peter@domain.tld" TLS

I use free host and client certificates from but if you want to set up your own CA you can find and excellent article here
I have found some “documentation” in the form of well commented configurationfiles.

Secure wireless FreeBSD router

One of my hobby projects is to build a “fully fledged” wireless  FreeBSD router. To do this I got a Soekris 6501-50 which has four gigabit ports and two mini PCIe slots.

For storage I have a small 30GB miniPCIe SSD (OCZ-NOCTI). I have two wireless cards installed one dual band 3x3MIMO minipcie card from COMPEX (When FreeBSD gets up to speed with 802.11ac I will upgrade to a WLE900VX) and for legacy 2.4Ghz I use a TPLINK TL-WN781ND. These two cards are then used for two virtual interfaces each, one for my primary wlan and one for my guest wlan.

One important part of the wireless part of the router is the antennas. For a long time I used three consumer antennas (ALLNET ALL19003) for 5GHz use for my COMPEX card, but when I moved to a new apartment and switched to 5GHz I didnt get good speeds everywhere in the apartment. This got me thinking about a ceiling antenna. But I found it very hard to find one in consmer stores, so I turned to Ebay. I found a decently cheap Laird S2451DBT 6port antenna which is now mounted in the ceiling at a central point of the apartment.

To do packet filtering I use the OpenBSD derived pf(4) which has been in FreeBSD for a long time now.

Wireless networks
Like I told you in earlier I have two physical cards and two networks (ssid). One primary and one guest networks with tighter rules but less strict authentication.

The firt step here is to find a card supported by FreeBSD, but also have support for hostap mode, obviously mine does. To get it to run WPA2 Personal on a specific channel the configuration is very easy


Lately I started to use the more secure WPA2 Enterprise and you can read about my configuration here

Other networks
My internet provider is Telia and I have something they call Triple Play.. (Internet, TV and Tele in the same cable). In order to get this to work you should use their Thompson router that has som magic for splitting up your one incoming fiber into three different networks. After some reading on the interwebs I found out this is really just tagged vlans and I can split them myself without any problem. “Internet” comes untagged and the IPTV traffic comes in on tag 845, so I just create a vlan interface with my external interface as parent and then bridge this interface to one of my internal interfaces on the Soekris. (and of coruse connect the IPTV-box to this port). You can read more about this configuration here (swedish)

This is how the interfaces are configured


OpenSSH with ECDSA keys on yubikey/smart card

In one of the latest versions of OpenSSH it is now possible to store ECDSA keys on smart cards. If you managed to use ssh with your RSA keys on the yubikey its fairly simple to go to ECDSA. The only thing you need is a late snapshot of OpenSSH portable and a patch.

# fetch
# tar zxf openssh-SNAP-20151124.tar.gz
# cd openssh 
# fetch "" -o ecdsa.patch
# patch -s < ecdsa.patch
# ./configure
# gmake

Now you should be able to use get public keys from the smart card on your yubikey. Make sure pcscd is running then fetch the key with your newly compiled ssh-keygen.

# ./ssh-keygen -D /usr/local/lib/
C_GetAttributeValue failed: 18
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBAJGTLvC9BHSNPAfOw3s4lEix3zKLBKRgZlQ9kSxyttSG8XZ/NIoxm+ZYGbkYxji1kN7brMff21mgXGUzfxp58M=


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.

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.

We start by installing the software from packages

# pkg install opendnssec
# pkg install softhsm

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.


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, pid 42305
Starting signer engine...
OpenDNSSEC signer engine version
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 --input /usr/local/etc/nsd/chroot/zones/ --output /usr/local/etc/nsd/chroot/zones/signed/
zonelist filename set to /usr/local/etc/opendnssec/zonelist.xml.
Imported zone:
# 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 found; policy set to default
Notifying enforcer of new database...
# ods-signer sign
Zone scheduled for immediate re-sign.

An here is the before and after:

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

		MX	10
		MX	20
@		A
		AAAA	2001:470:6c08::1

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

Signed:	3600	IN	SOA 2015032504 10800 3600 604800 3600	3600	IN	RRSIG	SOA 8 2 3600 20151214230507 20151130173240 26386 iheuqDSSeLdoXJpYOI9ICFSDETnxXbls5K8YnnLBqeQOqgvxNRESWqy1rgAtnReFHnijcMpwly3ttFGUVtd9C4x3dQwMSbgwe9mXY0Tp/ojDdXG0UQLUXHgys0jFen1Go+c3r97lRH8RblIDVu5D5tVynO8+fN9FKzy29ZWfcbc=	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}	3600	IN	DNSKEY	256 3 8 AwEAAfNwi9djf7sYUVQpqScBOBMqjFD9GqHeI11Y/62SWINheq8+sQ8H/yN2H3eqmW9+ffBVNU8VTCVcdLOwkPGEF5Q1lE7hIbHGLunCAUo5OC8yFhuEtXNFoYo/EuGGbgUmcgYLNKIu8+RxzL5VO9dV7FTUy60tnCsYi/tKDGBP376p ;{id = 26386 (zsk), size = 1024b}	3600	IN	RRSIG	DNSKEY 8 2 3600 20151214194904 20151130173136 60509 G6+/6njI1NSCvWIeOhyvFo/+v1uSSFRx2Art3bv7Gw2nSJA2aMiu1ZVaIw7uGf75xdWr6lSj6ndb61UmTl+N6ccdbTU80HxwPmBA/fVZpGIAJrQ8psLgx8uDY3AxCfZdEq3YM0JzPewLnKGUaoVFsTzoWNNw2NRYqUuRiBnlebibcci70vaI0QpyRlXfSJ4DWls3H0isk0BWdukcpYEKNx4hl6GsRDCpNRoNs27TXgHnAcv7YV1528gyrgbw63DT6yyyL49nlN+TEV5aiDlNsjnkYJqgy869xfMROAw0VScHderqnixW4LlAGX0QYuPuOoK2dPx874i7xH7JhOoTbQ==	0	IN	NSEC3PARAM	1 0 5 c2d153cf47fb60fa	0	IN	RRSIG	NSEC3PARAM 8 2 0 20151214120059 20151130173136 26386 DlSk0ye1kcP7g0z6QJy0QYpB75ZPpWhbypyRJ3a+L0BaL4cY/cdRS9SACxmhXu/kEkrmadJ/IcfDMhMHOj9D0uY+8ksbKfVhpAX237sFp18V8rsH0zkOPjMjD1O4c30N+isLVdnaPX3OyIRxqRFrRL2XH4kMOR9c8uBpBtin/MU=	300	IN	NS	300	IN	NS	300	IN	RRSIG	NS 8 2 300 20151214130253 20151130173136 26386 X9V2dv2+tyWoom6SC5zwkgkMj0buTu/wvGO/ClE7KveJ3YwmG/kPH0z37sS6GWK+j1MzNTzDepcUdxxghO/shDZvSz/7WAtvuHVPWfo2lg+iGG7nxCmYqcmq7Vo2+GZCU5TRjivsCDxen9w+e8+AuZtpuTkEppTQMbEIq+qNGyw=	300	IN	MX	10	300	IN	MX	20	300	IN	RRSIG	MX 8 2 300 20151215000707 20151130173136 26386 Yw1eRGRESXu1bGh/RNhqJNFpjv+MsDzoyxoPOTNTZiBr+OmlCq6p8M6QgfEPIipmg0VzrHJjzEFfpb4WQmPTKKehH/nEoevKLAogPjbozucr+lgjAXh3AoXr15OYF9dyJilyuTLQ3TyyWDAOxSHtnHy5w704ibaIyGoeKniTf3k=	300	IN	A	300	IN	RRSIG	A 8 2 300 20151214104407 20151130173136 26386 zmVjO5Rh1R+lpIUdIvsyTCmhGt2qL1wHUIOlZJbBkiiVpdE051MhRTShRjU79LQ5a+SlBeE5jjVeRrAXhTAb6KhNzZ5j5JaTjPYXzqxe//ddpMYEDzGhmuO1zkfUjtKCFhxgk92lFqimHXJFTj3nXdgbmqvK1io7aqYWCRvKxt4=	300	IN	AAAA	2001:470:6c08::1	300	IN	RRSIG	AAAA 8 2 300 20151214075539 20151130173136 26386 ymUD9mz9uQ6on0SF8TSFbb5xU100mJZuZeJafub1YkeolsxmcyXP0HQl0c20QFHWWp7qX4L7rY7QKIgc9aeaMkskrT9BEmwFoTB/MMu9nrweZyyAUdnnrD06mJ6BumBM0ZWBt6qHLe4tiPh8YVqCCjhFBo+SUvDOfelg3k/QAkY=	3600	IN	NSEC3	1 0 5 c2d153cf47fb60fa  h0gt9jkpqemi2oumlejri2lvo60uc2qt A NS SOA MX AAAA RRSIG DNSKEY NSEC3PARAM	3600	IN	RRSIG	NSEC3 8 3 3600 20151214151238 20151130173240 26386 6iNFSodcFOSydizrXrduzAsTPkZB+wqqr0IrdqEL+YcoM1aefmHfX3l5Kems01KCihozii5O23oprGXw0niYk4ESvXjYH0pOK/J6KWes9PirDQj0P8w//FiX9I7jYL4YkfAqf+pKU1vx2mVDT5ATD2Dkty4GX7eKg4h7qDvgSUM=	300	IN	A	300	IN	RRSIG	A 8 3 300 20151214080233 20151130173136 26386 TqG3vzzO3vIPVLZpWHh5Sh6ijNBr61u+7jEMlpl/kfj7S5wvmMgUkWl+hmNaokgrDvrEahpCdTQ0yjSmWl+m5aVFlV17x0x5lJN+Fcx+SuOqqdkHkYKDyTShWdyfDRj9rAQxThbrhvOz3+6gfTJ1HMeGBXIkLMzf1MEojHDlhEg=	300	IN	AAAA	2001:470:6c08::1	300	IN	RRSIG	AAAA 8 3 300 20151214134021 20151130173136 26386 reaA1ca5Jly76YPU+Nfq6CEwgqx7/T2xYh7IzfJ4aZ034vF7djYJFvNMvKMF5wuX7hbP44B3lQk/mnYlzmuVsKGYIwNvU+4+ggIsahgdCItasFOLdJln3oY7f+ch/o6XljE9JKusWFYT2GcPLCsr73PcEIF3QkdXDgXZzSDuZBc=	3600	IN	NSEC3	1 0 5 c2d153cf47fb60fa  rl1jo83jomo43daiudaavkfofbmtkks2 A AAAA RRSIG	3600	IN	RRSIG	NSEC3 8 3 3600 20151215051041 20151130173240 26386 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
Zone:                           Keytype:      State:    Date of next transition (to):  Size:   Algorithm:  CKA_ID:                           Repository:                       Keytag:                    KSK           publish   2015-12-01 09:31:35 (ready)    2048    8           adcfe72699de3bb9afe511d67a112580  SoftHSM                           60509                    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
;active KSK DS record (SHA1):	3600	IN	DS	65041 8 1 766dee3e0d5cac1c19529d4474eb828d72a91d24
;active KSK DS record (SHA256):	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
;; ->>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 --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.


Using Smart Card enabled yubikey for ssh authentication

This guide will try to show you how to use yubikey for ssh authentication

I recently found out that the yubikey neo had a built in smart card. Also, a few days ago Yubico released their fourth version of the yubikey introducing built in smart card as a standard feature. Me, having very little knowledge and experience with smart cards bought one just to play around with and I quickly found out that the card could be used to securely store encryption keys and certificates.

I use SSH alot both at home and at work, so this was the natural place to start. There is a short guide on how to use the yubikey with ssh on the yubikey developer site but this only covers the yubikey-part. This article will show you how to get things working in FreeBSD. But it will also skip the steps needed to configure the yubikey to have the smart card enabled, and how to generate keys and so on (yubikey software needed)

First if all you need to install a few packages.

# pkg install pcsc-lite
# pkg install opensc
# pkg install libccid

Then there i alot of stuff you can fiddle with using the pkcs11-tool, pkcs15-tool commands. But to get going you can just start the pcscd daemon manually and insert the yubikey into your computer.

# pcscd -f -d

If you have correctly generated a key (and certificate) on the yubikey in one of the slots you should now be able to run

$ ssh-keygen -D /usr/local/lib/
C_GetAttributeValue failed: 18
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCOvhEqFq9Ualp1iYiNs0JFs3MgvGU+By/VvyW4qkymW+w/MmHAaHl+/UFnE+kgXChdYHaGEVxxGi6dQlSq+1ZKAWPJsOEbkysK6cgjgvP21gVNjL62TlQz+QfGF82mv0hfSGXQrZQR7VDs+6xJOe3S/0i1HvnnRTdR2v9QSJzd2EWNLmUcPy7+4x4rEB11G0oPt+Xyx60WaleJctwJHHhJS/jqHdvuf7HO6MS/EQn2NTnwIjChlmm2kUT7obnev/r6uEwz87NubnYJUrYImRDMafjS9taq8l7y33ydT00QHEI76kmrSSi7hTfmxUgStQWuQ2mq10YEVd8kZ2sqmC3N

To show the public part of your keys residing on the smart card. If this command was successful you can also add the keys to your ssh-agent using

$ ssh-add -s /usr/local/lib/
Enter passphrase for PKCS#11: 
Card added: /usr/local/lib/

and then you can list the keys with

$ssh-add -l
2048 8c:c9:99:1f:1b:98:42:af:9b:9b:93:e6:5b:ff:2a:94 /usr/local/lib/ (RSA)

To remove the card from the agent use

$ ssh-add -e /usr/local/lib/
Card removed: /usr/local/lib/

To connect somewhere using the keys on the smart card without the agent you can just use

$ ssh -I /usr/local/lib/ user@host.tld

There will probably be more guides in the future on how to use this further.


You can now use ECDSA keys stored on yubikey with OpenSSH.