OpenSSH Key Storage

Dan Kaminsky dan at doxpara.com
Fri Feb 1 19:18:39 EST 2002


> I have had a brief discussion with Damien Miller (below) about storing
> host port values in the known_hosts file so as to track multiple ssh
> sessions (with independant keys) that run on a single host but accept
> connections on different ports.  If it were possible to state that a
> given key for a remote host belonged to that host's ssh session on port
> 23 and that another key belonged to that same host but the session
> available on port 22, it would take away some of the grief in managing
> such connections.
>
> I am presently using host aliases in the options file to handle this as
> Damien suggested but explaining this to my clients is difficult when SSH
> (commercial) has this seemingly simple feature built in.

Would you name your web servers after the IP addresses they were on?  Ever
seen an https host named https://443.foobar.com?

Of course not.  How you got there is not where you are, when it comes to
computer networks.  (Yes, this is another divergence from the human
experience.  When teleporters become a reality, this may very well change.)

Look.  Just because a daemon exists on a host doesn't mean it's necessarily
that host's daemon, especially if it's not on the standard port, even more
especially if that port is less than 1024.  Port forwarding is a *really
useful thing*.  To wit:

Take two hosts, a client and a server, that cannot establish outgoing
sessions with eachother but may each send traffic to some broker over tcp/22
(or any other port).  The server SSH's into the broker and reates a remote
port forward from remote's 2022 to 127.0.0.1:22.  Then the client SSH's into
the broker and creates a local port forward on 3022 to be forwarded to the
broker's 127.0.0.1:2022.  Now, the client may SSH into the server by
connecting to 127.0.0.1:2022, and by using the HostKeyAlias, will verify the
identity of the server.  This looks something like this:

server$  ssh user at broker -R2022:127.0.0.1:22
client$ ssh user at broker -L3022:127.0.0.1:2022
[new window]
client$ ssh -o HostKeyAlias=server -p 2022 user at 127.0.0.1

The reason I'm documenting this entire process is simple:  The key the
client receives from 127.0.0.1:2022 is the one of the server.  It's not "the
broker on port 3022".  It's not "localhost on port 2022".  It's not even
"the server, oh on port 22."  It's _the_ _server_.  That's its identity.

Now, it is certainly possible for multiple SSH daemons to be actually be run
on the same machine.  If they have identical keys, that's fine -- perhaps a
newer revision of sshd_config is being tested on an alternate port, perhaps
a backup sshd is live in case the primary one crashes, or perhaps it's the
same actual daemon listening on multiple ports to assist in firewall
piercing(like when sshd is told to listen on port 443).  We don't care how
we got that correctly hostkeyed SSH daemon, we just care we got it.

But, ah, if the keys are different, the question is WHY.  We have to presume
that a host that is not providing its correct keying material in fact
cannot.  Any user can run an sshd on port 2022 just as easily as he can type
ssh user at host -R2022:127.0.0.1:22.  What separates his
SSH-1.99-OpenSSH_3.0.1p1 from the real one isn't the route taken by the
client but the key offered by the daemon.  If he's offering a different key,
he's effectively a different host, perhaps with some of the same services
available but presumptively not an identical amount of trust to the
legitimate identity.

A daemon that cannot offer its correct host key is for all intents and
purposes a different host, and needs to be treated as such.  Don't get me
wrong -- it can be really, really useful to create a separate sshd with
highly restricted permissions, able only to administer the restricted level
it lives at and even with a buffer overflow go no farther.  We can do this
by executing something like:

server# su -l webuser -c "/usr/sbin/sshd -p 2022 -f /etc/sshd_config -h
/home/webuser/sshd_user/userkey1 -h /home/webuser/sshd_user/userkey2"

That fits fine in a rc.local script, or could even be directly executed over
ssh or command line as the user.  But the client *needs to know* that this
account is of a different identity -- it's not a root owned key that's being
hosted, but some restricted other identity host key.  So we rename it.

client$ ssh user at server -o HostKeyAlias="webserver" -p 2022

It's a different host we're trusting.  It's a different server we're
trusting.  If the processes are accidentally running on the same machine,
who cares.  You don't trust IPs and you don't trust ports.  Try, and you
find yourself accepting keys you should -- after all, it's the right host,
who cares if the network itself is redirecting the port -- and being unable
to update your network infrastructure at will.

If the Windows SSH daemons behave as you describe, there's probably some
damaging hacks against them via corrupted ssh:// URLs.

This all being said -- I actively dislike HostKeyAlias syntax and find it
unwieldy.  Cryptographically correct it may be, but we can -- and should --
do better.  Bug me privately if you want to see what I was up to with this;
suffice it to say, it's an uglier problem than I expected(as I found out at
Defcon when I was trying to explain it to a crowd.  That was pretty
embarassing.)

--Dan





More information about the openssh-unix-dev mailing list