-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
"SSHFP Records on Windows Server"
by Colin Cogle
Published September 24, 2022.
ABSTRACT
SSHFP records are a vital part of securing SSH. However, Microsoft's DNS Server
doesn't give us an easy way to add them. Here's how.
A REVIEW OF SSH FINGERPRINTS
SSH servers all have fingerprints to identify themselves. These little hashes
of the host's public key are exchanged with clients, and remembered in a Trust
On First Use (TOFU) security model.
The authenticity of host 'yourserver.local (2001:db8::1)' can't be established.
ED25519 key fingerprint is SHA256:1z0nm0KwN5cnOSA9HQ0VzjUR9VaPUd+/tB5FtTB1NdQ=.
No matching host key fingerprint found in DNS.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])?
> Figure 1: The default OpenSSH warning when connecting to an unknown server.
Now, let's be honest. SSH is an incredibly high-value target, but how many of
us have actually taken the time to manually verify an SSH key? Raise your hands.
Yeah, I'm not raising mine, either.
TOFU is a decent security model, because it protects all connections to the
server -- except for the very first one.
You might have noticed that there is a line up there that reads, "No matching
host key fingerprint found in DNS". Longtime Linux system administrators might
know about the SSHFP DNS record, defined way back in RFC 4255. Adding one to a
standard DNS server such as BIND is as simple as making the records and copying
them into your zone file.
$ ssh-keygen -r myservername | tee ssh-keys.txt
myservername IN SSHFP 1 2 d73d279b42b037972739203d1d0d15ce3511f5568f51dfbfb41
myservername IN SSHFP 3 2 95941914e0c29ca8a104bf4b6c8890c7c172f7ce610bc331ea6
myservername IN SSHFP 4 2 6c0461c9809836eb61b0e3a07b31a99522452a7e28499a39aa8
$ ssh-keys.txt >> /etc/bind9/myzonefile.dns
> Figure 2: SSHFP records can be generated with the ssh-keygen command, and
> appended to your zone file. None of this is new. (I'm using tee so we have
> something to look at.)
If you're lucky enough to be using the BIND9 DNS server, congratulations! Your
work is done. However, f this was all I was writing about, it wouldn't make
for a useful article.
MICROSOFT IN THE MIX
However, some of us administer Windows networks, which sometimes means that Act-
ive Directory Domain Services is in the mix; and, if that be true, then one
would be foolish not to use the Microsoft DNS Server alongside that. Though it
lags far behind BIND9 in terms of feature and resource record support, it does
provide a GUI (albeit dated) and a robust PowerShell module.
While it does not support SSHFP records natively, the DNS Server included with
all versions of Windows Server will at least accept, store, and serve SSHFP re-
cords. The problem, though, is how to get them saved, as neither the GUI nor
the PowerShell cmdlets will let you input one. (Neither will dnscmd, but that
thing is deprecated, anyway.)
You might be wondering, though. What is the point of storing SSHFP records when
you have a Windows-centric network? Simple: you gain the same benefits.
* If you have macOS or Linux machines on your network, they likely have SSH
servers running.
* Your firewall, switches, and VMware hosts might have SSH daemons running,
too. Even if they only run some of the time, you can still have DNS-level
protection.
* Notably, the OpenSSH Server is an installable feature in Windows 10 and 11,
Windows Server 2019, and Windows Server 2022; with backports available for
downlevel versions:
https://github.com/PowerShell/Win32-OpenSSH (This may
also be the replacement for PowerShell Remoting, if WinRM ever becomes dep-
recated.)
HERE'S HOW
1. CHECK YOUR DNS SERVER
You will need to be running Windows Server 2012, or later. While this should
work with any version of the Microsoft DNS Server, both the RFC -- and common
sense -- strongly recommend you use DNSSEC to secure these records.
If you're running Windows Server 2008 R2 or older, stop right here and evaluate
your personal and professional life decisions. Not only has been out of exten-
ded support for quite a long time, but its DNSSEC implementation is rudimentary
at best.
2. GATHER YOUR FINGERPRINTS
You will need to gather the SSH fingerprints for all of your hosts. You can log
on and run `ssh-keygen -r` to generate them interactively, or for things like
printers and other network devices, a tool like `ssh-keyscan` can read them re-
motely.
3. DOWNLOAD THE BIND9 TOOLS
If you have a macOS or Linux machine with the `nsupdate` tool on there, you can
skip this section. Otherwise, download the BIND9 Tools for Windows to obtain a
copy of `nsupdate.exe`, which will allow us to spit arbitrary DNS records into
our zone.
Set-Location $env:Temp
Invoke-WebRequest -OutFile 'BIND.zip' `
-Uri '
https://downloads.isc.org/isc/bind9/9.16.32/BIND9.16.32.x64.zip'
Expand-Archive -Path 'BIND.zip'
> Figure 3: You can also use PowerShell to download and install the BIND9
> Tools. This is useful if you want to script this, or if you're lucky
> enough to be running a headless version of Windows Server.
4. CREATE THE NSUPDATE COMMAND
The nsupdate tool has its own syntax. You can copy and paste the hostnames and
fingerprints that you've gathered from across your network, and combine them
into one big Notepad document.
You can also use PowerShell to turn your `ssh-keygen -r` output into a file that
can be used by nsupdate:
# Edit this next line with the name of your DNS zone!
$MyDomainName = 'example.com'
$sshfp = ''
Get-Content 'Output of ssh-keygen -r.txt' | ForEach-Object -ScriptBlock `
{
# Each line of the input file will need to be modified to add some more
# items. It must be prefixed with "update add" and have a TTL inserted
# after the hostname (even though the DNS zone will likely override it).
$x = $_ -Split "[\t\s]"
$sshfp += "update add $($x[0]).$MyDomainName 3600 $($x[1..5]).`r`n"
}
# Prepare the NSUpdate command.
$NSUpdateCommand = "server $DNSServer
zone $MyDomainName
$sshfp
send"
> Figure 4: This PowerShell code can be used to convert `ssh-keygen -r`
> output into something `nsupdate` can understand.
5. RELAXING ZONE SECURITY (FOR A FEW SECONDS)
Security-conscious people might be thinking that using freeware to inject random
DNS records is a very bad thing, and they are correct. Fortunately, by default,
Windows-hosted zones default to only allowing secure dynamic updates (authenti-
cated by Kerberos). To accomplish our goal, we will need to temporarily relax
security rules.
Set your zone update settings to allow secure and non-secure updates, but don't
forget to change it back later. You can point and click, or use PowerShell.
1. In the DNS snap-in, right-click your zone and choose Properties.
2. Under Dynamic Updates, choose "Secure and Nonsecure".
3. Click OK.
Or, run this:
Set-DnsServerPrimaryZone -Name example.com -DynamicUpdate NonsecureAndSecure
> Figure 5: Same thing as the three-step, but in PowerShell.
Now, don't linger, since we've left our zone open to exploit.
6. NSUPDATE-ING
Now for the coup de grĂ¢ce. You can copy and paste the contents of your file di-
rectly into nsupdate.exe. Alternatively, if you've been following along with my
PowerShell commands, you can simply do this:
$NSUpdateCommand | .\nsupdate.exe
> Figure 6: Send the last code block's work into nsupdate.exe.
Before you celebrate, we need to restore safety and sanity; either skip back a
section and undo your changes, or run this PowerShell command:
Set-DnsServerPrimaryZone -Name 'example.com' -DynamicUpdate 'Secure'
> Figure 7: Please do not leave gaping security holes in your
> infrastructure.
7. VERIFYING YOUR WORK
Once this is done, you will see some unknown records listed in your list of DNS
entries. They show up as an unknown type because the DNS Server service is an
afterthought to Microsoft. (Don't even get me started on TLSA.)
Unfortunately, because Microsoft's DNS Server service lags so far behind the
curve, you will not be able to edit or properly view the record. Just be happy
we got this far. You can, though, double-click on it and view the raw binary
data, for what that's worth (in Server 2016 and newer).
LET'S TRY IT
Now that your SSHFP DNS records are live (and hopefully secured), let's try con-
necting again. If your records are present and correct, you will see output like
this:
The authenticity of host 'yourserver.local (2001:db8::1)' can't be established.
ED25519 key fingerprint is SHA256:1z0nm0KwN5cnOSA9HQ0VzjUR9VaPUd+/tB5FtTB1NdQ=.
Matching host key fingerprint found in DNS.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])?
> Figure 10: There we go! Now the host key is verified.
It's a bit of a roundabout method, unfortunately. It would be great if Micro-
soft's DNS Server gave us an easier way to add and modify SSHFP records (and
DANE/TLSA records, for that matter). However, this will work and this will help
you secure your internal environment.
Finally, save this text file. This isn't a shameless plug, but a warning that,
as you replace devices or regenerate SSH host keys, you will need to regenerate
your SSHFP records.
=== WORKS CONSULTED ===
Microsoft Corporation. "Step-by-Step: Demonstrate DNSSEC in a Test Lab",
"Windows Server 2012 R2 and Windows Server 2012". 31 August 2016,
learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-
2012-R2-and-2012/hh831411(v=ws.11). Accessed 22 September 2022.
Moonesamy, S., "Using Ed25519 in SSHFP Resource Records", RFC 7479,
DOI 10.17487/RFC7479, March 2015, <
https://www.rfc-editor.org/info/rfc7479>.
Accessed 24 September 2022.
Schlyter, Jakob and Wesley Griffin, "Using DNS to Securely Publish Secure Shell
(SSH) Key Fingerprints", RFC 4255, DOI 10.17487/RFC4255, January 2006,
<
https://www.rfc-editor.org/info/rfc4255>. Accessed 22 September 2022.
Sury, O., "Use of the SHA-256 Algorithm with RSA, Digital Signature Algorithm
(DSA), and Elliptic Curve DSA (ECDSA) in SSHFP Resource Records", RFC 6594,
DOI 10.17487/RFC6594, April 2012, <
https://www.rfc-editor.org/info/rfc6594>.
Accessed 24 September 2022.
===============================================================================
"SSHFP Records on Windows Server" by Colin Cogle is licensed under Creative
Commons Attribution-ShareAlike 4.0 International CC-BY-SA. You can find
this article online at:
https://colincogle.name/sshfp
===============================================================================
-----BEGIN PGP SIGNATURE-----
iHUEARYIAB0WIQQ7NZ6ap/Bjr/sGU4FSrfh98PoTfwUCYy/LbQAKCRBSrfh98PoT
f5G3AQDjDRr+FtcKtjpXo1i8yU/VtoTGoRQX2b0jxKJ5FI+TngEA253uRJa4ow8Z
KzC/mfzC9NwgvFscdwhn9cPgKOjGNQE=
=9TZz
-----END PGP SIGNATURE-----