SSH Public Key: More Important Than It Seems to Be

Once my colleague asked me to help her with SSH public key authentication. The symptoms are very common: you add your id_rsa.pub to authorized_keys, try to login and… ssh asks you for password.

Usually it’s enough to check permissions for ~/.ssh (700), ~/.ssh/id_rsa (600), and turn off SElinux 🙂 However, this time it didn’t help me: ssh was persistently asking for password.

I decided to fix the problem as fast as I can, so, I checked that ~/.ssh/id_rsa.pub was really added to authorized_keys… no, it wasn’t! Here the story begins: the correct id_rsa.pub resided in current directory and it was added to authorized_keys indeed. My colleague has generated a new keypair and replaced only ~/.ssh/id_rsa leaving the previous garbage ~/.ssh/id_rsa.pub.

Well, as we know, private key is enough for passwordless authentication. Really, when I removed that misleading ~/.ssh/id_rsa.pub file, public key authentication succeeded.

I will summarize now:

If public key file exists, it must correspond to its private counterpart. Otherwise, ssh will misuse it and passwordless authentication will fail. So, be careful when you change user’s identity file!

Let us investigate it. This is SSH client debug output if public key file exists…

[guest@mynode ~]$ ssh -v victim@localhost -i .ssh/id_rsa
OpenSSH_5.3p1, OpenSSL 1.0.0-fips 29 Mar 2010
debug1: Reading configuration data /etc/ssh/ssh_config
...
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey,password
debug1: Next authentication method: publickey
debug1: Offering public key: .ssh/id_rsa
debug1: Server accepts key: pkalg ssh-rsa blen 277
debug1: read PEM private key done: type RSA
debug1: Authentication succeeded (publickey).
debug1: channel 0: new [client-session]
debug1: Requesting no-more-sessions@openssh.com
debug1: Entering interactive session.
debug1: Sending environment.
debug1: Sending env LANG = en_US.UTF-8

…and if it is missed:

[guest@mynode ~]$ ssh -v victim@localhost -i .ssh/id_rsa
OpenSSH_5.3p1, OpenSSL 1.0.0-fips 29 Mar 2010
debug1: Reading configuration data /etc/ssh/ssh_config
..
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey,password
debug1: Next authentication method: publickey
debug1: Trying private key: .ssh/id_rsa
debug1: read PEM private key done: type RSA
debug1: Authentication succeeded (publickey).
debug1: channel 0: new [client-session]
debug1: Requesting no-more-sessions@openssh.com
debug1: Entering interactive session.
debug1: Sending environment.
debug1: Sending env LANG = en_US.UTF-8

Reading OpenSSH code, we can guess why SSH loves public keys and uses them if they are available.

openssh-5.9p1/sshconnect2.c:
int
userauth_pubkey(Authctxt *authctxt)
{
        Identity *id;
        int sent = 0;

        while ((id = TAILQ_FIRST(&authctxt->keys))) {
                if (id->tried++)
                        return (0);
                /* move key to the end of the queue */
                TAILQ_REMOVE(&authctxt->keys, id, next);
                TAILQ_INSERT_TAIL(&authctxt->keys, id, next);
                /*
                 * send a test message if we have the public key. for
                 * encrypted keys we cannot do this and have to load the
                 * private key instead
                 */
                if (id->key && id->key->type != KEY_RSA1) {
                        debug("Offering %s public key: %s", key_type(id->key),
                            id->filename);
                        sent = send_pubkey_test(authctxt, id);
                } else if (id->key == NULL) {
                        debug("Trying private key: %s", id->filename);
                        id->key = load_identity_file(id->filename);
                        if (id->key != NULL) {
                                id->isprivate = 1;
                                sent = sign_and_send_pubkey(authctxt, id);
                                key_free(id->key);
                                id->key = NULL;
                        }
                }
                if (sent)
                        return (sent);
        }
        return (0);
}

SSH client notifies server that we have a public key. If the server allows this key, the client will try to load private key that can be protected with a passphrase and therefore require extra user input.

So, we found a new proof that OpenSSH was developed with usability in mind.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s