I have two machines running OpenBSD v6.9. Let's be original and call them client and server.
I generated the SSHFP records on the server with :
ssh-keygen -r host.domain.tld
In the DNS zone, I added the SSHFP record with this line :
host IN SSHFP 1 2 02323a6fb8a12eba9288930ce2513fc94970e5575996ebede1ee352bd039c531
host IN SSHFP 4 2 3eef5929fe85038b2e2a7de70897175e7b0d68328b41ef6466a2fa06f9a8bb49
sshd is configured to use only Ed25519 host key but I also keep RSA host key in case on futur need.
The DNS zone is signed with DNSSEC and everything is validated by "https://dnsviz.net/" and "https://dnssec-debugger.verisignlabs.com/".
On the client, there is an Unbound resolver with DNSSEC validator :
dig host.domain.tld -t SSHFP
; <<>> dig 9.10.8-P1 <<>> host.domain.tld -t SSHFP
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 9525
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;host.domain.tld. IN SSHFP
;; ANSWER SECTION:
host.domain.tld. 3600 IN SSHFP 4 2 3eef5929fe85038b2e2a7de70897175e7b0d68328b41ef6466a2fa06 f9a8bb49
host.domain.tld. 3600 IN SSHFP 1 2 02323a6fb8a12eba9288930ce2513fc94970e5575996ebede1ee352b d039c531
;; Query time: 182 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Mon May 17 17:15:46 CEST 2021
;; MSG SIZE rcvd: 137
It is not mentioned above but if I add +dnssec to the query, the RRSIG SSHFP is displayed.
And the SSH client config file :
Host host.domain.tld
AddressFamily inet
HostName host.domain.tld
Port 22
Protocol 2
User username
CheckHostIP yes
PasswordAuthentication no
ChallengeResponseAuthentication no
PubkeyAuthentication yes
VerifyHostKeyDNS yes
IdentityFile ~/.ssh/id_ed25519_host.domain.tld
But, when I try to connect from the client to the server, it seems that SSHFP does not work :
ssh host.domain.tld
The authenticity of host 'host.domain.tld (server_ip_address)' can't be established.
ED25519 key fingerprint is SHA256:Pu9ZKf6FA4suKn3nCJcXXnsNaDKLQe9kZqL6Bvmou0k.
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])?
According to Internet guides, I should not be asked to accept the key.
So, to summarize :
- SSHFP record generated on the server,
- SSHFP record added to the DNS zone,
- DNS zone signed with DNSSEC,
- client able to query SSHFP records and validate DNSSEC,
- SSH config file with the option "VerifyHostKeyDNS",
- and it is not working.
Here is the detail of the connexion :
ssh -v host.domain.tld
OpenSSH_8.6, LibreSSL 3.3.2
debug1: Reading configuration data /home/username/.ssh/config
debug1: /home/username/.ssh/config line 2: Applying options for host.domain.tld
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: Connecting to host.domain.tld [server_ip_address] port 22.
debug1: Connection established.
debug1: identity file /home/username/.ssh/id_ed25519_host.domain.tld type 3
debug1: identity file /home/username/.ssh/id_ed25519_host.domain.tld-cert type -1
debug1: Local version string SSH-2.0-OpenSSH_8.6
debug1: Remote protocol version 2.0, remote software version OpenSSH_8.6
debug1: compat_banner: match: OpenSSH_8.6 pat OpenSSH* compat 0x04000000
debug1: Authenticating to host.domain.tld:22 as 'username'
debug1: load_hostkeys: fopen /home/username/.ssh/known_hosts2: No such file or directory
debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts: No such file or directory
debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts2: No such file or directory
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: algorithm: [email protected]
debug1: kex: host key algorithm: ssh-ed25519
debug1: kex: server->client cipher: [email protected] MAC: <implicit> compression: none
debug1: kex: client->server cipher: [email protected] MAC: <implicit> compression: none
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
debug1: SSH2_MSG_KEX_ECDH_REPLY received
debug1: Server host key: ssh-ed25519 SHA256:Pu9ZKf6FA4suKn3nCJcXXnsNaDKLQe9kZqL6Bvmou0k
debug1: found 2 insecure fingerprints in DNS
debug1: matching host key fingerprint found in DNS
debug1: load_hostkeys: fopen /home/username/.ssh/known_hosts2: No such file or directory
debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts: No such file or directory
debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts2: No such file or directory
debug1: load_hostkeys: fopen /home/username/.ssh/known_hosts2: No such file or directory
debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts: No such file or directory
debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts2: No such file or directory
debug1: hostkeys_find_by_key_hostfile: hostkeys file /home/username/.ssh/known_hosts2 does not exist
debug1: hostkeys_find_by_key_hostfile: hostkeys file /etc/ssh/ssh_known_hosts does not exist
debug1: hostkeys_find_by_key_hostfile: hostkeys file /etc/ssh/ssh_known_hosts2 does not exist
The authenticity of host 'host.domain.tld (server_ip_address)' can't be established.
ED25519 key fingerprint is SHA256:Pu9ZKf6FA4suKn3nCJcXXnsNaDKLQe9kZqL6Bvmou0k.
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])?
Do you have any idea of the problem ?
Thanks in advance.
OpenSSH v6.9 is very, very, very old. Latest is OpenSSH v9.0. I took a look at
dns.c
of the V_6_9 branch of OpenSSH repository. The key thing to note in your debug output is:Means that DNSSEC lookup of
host.domain.tld
is not a valid DNS record (totally insecured), despite generally having found two(2) distinctSSHFP
resource records (secured or not).This also means that
devl host.domain.tld.
would not put out in the first line the expected message of:While the scope of DNSSEC troubleshooting is vast and wide, a solution is not easily had within this post.
I suggest that you plug in your
domain.tld
into one of the two excellent online DNSSEC troubleshooters and go from there:Of course, as a last resort, there is
[dnssec]
tag on ServerFault (yet another StackExchange group) and your fav. search engine, but it is quicker to tap an in-house DNSSEC expert for your needs.Security Consideration
Of course, you do do have DNSSEC up and running?
Protection of SSHFP is only assured by a properly signed resource record by DNSSEC but, But ... BUT most people (and many ISPs) do not instruct their DNS resolver to only return back a valid DNS record as determined by DNSSEC; having mentioned that, the possibility of SSHFP being hijacked remains.
The problem here is not the confidentiality of the public key (it isn’t confidential).
The problem we have is the integrity of that DNS record holding this public key. While the SSHFP key data is correct in your problem statement, the bug is more of “lack of clarity” yet the logic remains defensively correct.
That is the end for this Original Question post. But I shall outline even some more security caveats.
More Caveats
If not distributed securely (via DNSSEC), such SSHFP DNS records can quite easily be tampered with or replaced with another key. So, DNSSEC must be 'enforced' before even trusting and using
SSHFP
.If a faked SSH CA server has the wrong public key configured (whose private key is in the hands of someone else), the client ends up by trusting that someone else.
Caution: Improper use of SSHFP records can have serious security consequences; follow these rules to avoid creating security vulnerabilities:
VerifyHostKeysDNS yes
unless the current resolver(s) properly validate DNSSEC-approved queries or use a valid DNSSEC-capable resolver list that I made using a simpledelv domain.tld.
command as a test for its DNSSEC-capability.; fully validated
check.delv ssh.domain.tld.
and check that first line for; fully validated
output or make DNSSEC mandatory via/etc/resolv.conf
(more of this later).Not following these rules could allow adversaries to create spoofed-SSHFP records for their SSH server(s) to impersonate yours, making SSH connections to the servers insecure and vulnerable to attacks.
You can avoid the "always perform
delv ssh.domain.tld
for; fully validated
) by having your host'sglibc
library perform this at resolve time (via resolver(3) but NOT the gethostbyname(3) function call). If you must require absolute DNSSEC-verified DNS queries for all your DNS needs, you could insert the following into your/etc/resolv.conf
(only if you have glibc v2.38 or later):File:
/etc/resolv.conf
Once this gets DNSSEC-secured, there are a couple of steps required to troubleshoot the mechanism of
SSHFP
DNS record and SSH clients.Validating SSHFP Setup
The seven(7) steps are listed in order to try as (do not do next step until the prior has passed).
Ping
host.domain.tld
, get an ICMP response.Execute
delv host.domain.tld.
and ensure that the first output line shows; fully validated
; please note the period (.
) added at end of your hostname.Exercise proper
EDNS(0)
using this EDNS(0) online tester against your server in question.Get the SSH fingerprint from your SSH server in question to start the comparison; execute
ssh-keyscan -D host.domain.tld.
(note the-D
option).which outputs:
SSHFP
record usingdelv host.domain.tld. SSHFP
.generates the following output:
SSHFP
DNS record says. The algorithm (1-6) and hash ID (1 or 2) must both match as well.The algorithm ID to name that must match are: 1=RSA, 2=DSA, 3=ECDSA, 4=Ed25519, 6=Ed448.
The hash ID to name that must match are: 1=SHA1, 2=SHA256.
ssh -oVerifyHostKeyDNS=yes -oStrictHostKeyChecking=yes host.domain.tld.
If this step works, integrate both options into your SSH client config file.If the fingerprints do not match, it is always invariably the DNS record that needs updating.
WARNING Appeared
With newer OpenSSH, you might even get the following pesky prompt during an initial SSH login:
may outputs the following:
The key thing to note in the above output is the following line:
It means exactly what it means.
The
VerifyHostKeyDNS yes
in your local SSH client config is what controls that output; the config being either in$USER/.ssh/config
or in/etc/ssh/ssh_config
.The above decision is based on a simple comparison between:
SSHFP
zone data of thishost.domain.tld
host.domain.tld
providing the public keyThis message covers 99.999% of the following potential scenario.
sshd
is not using the same pubkey, possibly due to:ssh-keygen
(most common)sshd -c <config_file>
)AuthorizedKeyFile
had been changeFingerprintHash
) setting had been changedPubkeyAcceptedKeyTypes
had been changedCASignatureAlgorithms
had been changedTrustedCAUserKeys
had been changedThe other 0.001% of the time is broken down in one of the many not so common scenarios:
ssh_config
/$HOME/.ssh/config
has used a different port number (rare but has maliciously happened)sshd
daemon got its start through SysV init (service XXXX start
orsystemd start XXXX.service
orsystem start XXXX.timer
or furtively via crond/atd job or evenrc.local
) and is using its own SSH server public key.sshd
executable. This requires file validation by package tools (of your distro in ascertaining that it’s checksum value, modification time, file path, security context, and attributes of not only thesshd
executable file but its referenced libraries (seeldd/usr/sbin/sshd
) are all computed and set correctly.At any rate, once you've eliminated the remaining 0.001%, it is a simple matter of:
SSHFP
DNS record (ssh-keyscan -r host.domain.tld
); save the output to an editor bufferdomain.tld
(dig domain.tld. soa
and note theMNAME
portion of SOA record data).MNAME
authoritative nameserver ofhost.domain.tld
/etc/named.conf
; newer Bind v9.11+ shows default config vianamed -V
)domain.tld
zone. (ISC Bind9 isfile /var/lib/bind/db.domain.tld
)db.domain.tld
file.SSHFP
DNS records from the editor buffer that you saved in the first step.Might want to put that period (
.
) symbol directly at the end of the host name for each of theseSSHFP
data records (that was generated byssh-keyscan
before closing that zone database file; such that:Enjoy!
Source: