I have a directory full of ssh private keys, and I'd like to check what keys are accepted on what server without logging in. How can I do that without adding the ssh-keys to my authentication client with ssh-add or logging in on the server? How does ssh know what keys it should try to authenticate with? Does the server send the fingerprints of the keys it can use or does the client send all it's fingerprints and the server then checks them?

  • Do you just have the private part locally or also the public part? I guess you could compare the public part to lines in authorized_keys of the remote system. – Ulrich Schwarz Dec 8 '15 at 11:10

You can use something like:


HOSTS=( localhost hosta hostb )

probekey ()
    for privkey in $KEYPATH
    if [[ "$(file $privkey)" =~ "private" ]]
        #echo "Probing key $privkey for host $1"
            ssh -i "${privkey}" -o "IdentitiesOnly yes" -o "PreferredAuthentications publickey" -o "ControlMaster no" "$1" exit 2>/dev/null
            if [ "$?" == "0" ]
            echo "Key ${privkey} matches for host $1"

for HOST in ${HOSTS[@]}
    probekey $HOST

What this script basically does is iterating through an array of hosts ($HOSTS) and performs the probekey function. The function iterates through the list of files in $KEYPATH, checks if the file type contains private (for RSA or DSA private key files) and if that matches it starts a ssh connection to the host using that particular key. If the connection was succesfull the returncode is 0 and a message is printed.

This is not an exact answer to the question because it does login to the host (when a key matches) and performs the exit command to directly logout again.

| improve this answer | |
  • How does ssh know what keys it should try to authenticate with? Does the server send the fingerprints of the keys it can use or does the client send all it's fingerprints? – redfast00 Dec 8 '15 at 11:52
  • 1
    Suppose you stand in front of a door with a keychain containing for instance 10 keys. You don't know which key will open the door so you will try them one by one. If the door opens you know it matches. Close the door, walk to the next door and try all the keys from the keychain again. This script acts very similar. It will try every key from the keychain (directory containing keys) and tries them one by one. If the door opens (you get logged in) close the door (logout) and print a message. If all keys are tried, walk to the next door (host) and start over again, probing all the keys. – Lambert Dec 8 '15 at 11:59
  • Yeah, but if the door sends what number of key (suppose keys are numbered) it can use, it becomes way easier. Your solution works, but is a bruteforce attempt. – redfast00 Dec 8 '15 at 12:01
  • I don't exactly understand what you are trying to say but I don't think that it is a good idea for a ssh service to offer all the public keys to a new session. The numbering of keys does not matter. If you offer a public key to the ssh server it will match the key against the configured keys in ~/.ssh/authorized_keys{2} for the user. – Lambert Dec 8 '15 at 12:14
  • I meant it symbolicaly: number means fingerprint. – redfast00 Dec 8 '15 at 17:21

You cannot check what keys are accepted on the server without logging in. The only way to know whether a key is accepted is to attempt to log in with it.

If there was a way to list what keys are accepted for an account, this would be a violation of privacy and would make breaches easier in some circumstances. SSH doesn't even tell you whether the account name is valid: a denied login is a denied login, whether it's because the account name is not known or because the authentication data is invalid. Doing otherwise would at least breach privacy by exposing who has an account on the machine. It would also make brute force attacks against accounts with weak passwords easier, and harder to detect in logs and in anti-intrusion systems, since the attacker could concentrate on existing accounts.

It's up to the SSH client to choose which key(s) it tries sending to the server. With OpenSSH, this can be configured with the IdentityFile configuration option (-i command line option), and by selecting keys to be loaded into ssh-agent or specifying the IdentitiesOnly configuration option. The server sends a challenge (a randomly generated string) to the client. The client must reply with the challenge cryptographically signed with a private key, together with the corresponding public key¹. The server verifies that the signature is a valid signature of the challenge with that key, and that the combination of the requested user name and the public key is valid. (Typically that last part means that there is a line with this public key in the user's ~/.ssh/authorized_keys file.) The client is allowed several tries (after a few the server will give up and close the connection).

If you've forgotten which of your keys is valid for which server, the simplest way is to log in to the server and check the ~/.ssh/authorized_keys file there. If the only way you know to log into that server is to try every key until one succeeds, then you'll have to do that (which of course will tell you what key you can use, so you don't need to read ~/.ssh/authorized_keys). If you have to make a lot of attempts on the same account, be prepared for the server to close the connection before you've finished; wait a few seconds and try again.

For future reference, if you have many different keys, maintain a .ssh/config that has the proper IdentityFile directive for each host.

¹ I'm simplifying the actual protocol, retaining only what is necessary here.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.