This page describes some of the ways in which SSH key-based authentication may fail, and some of the steps you can take to solve your problems. Key authentication failure is probably the single most common problem new users of SSH experience, and answering these questions repeatedly is exhausting....
This overview describes the basic concepts of public key authentication for those who don't know much about it yet.
Public key authentication involves the use of cryptography to prove that you possess certain credentials, without actually revealing those credentials to the other party. Specifically, the client holds a private key, which may or may not be encrypted with a pass phrase. The server holds the public key. The client and server use a Zero-knowledge proof method, in which the client proves that it holds the private key, but does not actually transmit the private key.
Setting it up requires a few steps. First, a key pair (private and public keys) is generated on the client system. Then, the public key is copied to the server, (appended) to the file ~username/.ssh/authorized_keys (a simple text file). This file tells the sshd program on the server that the holder of the private key which matches the public key is allowed to login as "username".
The public key is not secret information, and does not need to be protected. If someone copies your public key to their own authorized_keys file, this only hurts them, not you -- it allows you to login to their system.
The private key is secret information, and should be protected as such. The private key is normally encrypted using a pass phrase, which must be entered in the client system before the private key can be used. The private key's pass phrase has nothing to do with the server's password (if the server has such a thing). The two should not be confused.
Most of the commands shown on this page assume that you are using OpenSSH. There are equivalents in other implementations; they may sometimes have different names (for example, ssh-keygen2 or puttygen). When in doubt, consult your documentation.
For starters, please read man ssh-keygen (or its equivalent) on your system. This describes the basic process of generating a key pair, and then putting the public key onto the server.
SSH has two protocols for communications, which are cleverly called "protocol 1" and "protocol 2". Protocol 1 is considered obsolete, and should not be used. Nevertheless, until quite recently, the default setting for ssh-keygen in OpenSSH was to generate a protocol-1 keypair. So, you should always explicitly specify which type of keypair you want to generate.
Protocol 2 offers two different algorithms for public key authentication: RSA and DSA. RSA was encumbered by patents a few years ago (those patents have now expired). DSA was developed as an alternative during the period when RSA was encumbered. Both are considered "secure", and you may use either one:
ssh-keygen -t rsa # or ssh-keygen -t dsa
Note that keypair generation is usually done on the client so that the private key never needs to be transmitted anywhere.
You'll be prompted for the location of your keypair (just hit Enter to accept the defaults), and the passphrase. If you use a passphrase, the private key will be encrypted. Every time the SSH client needs to read the private key, it will need to use your passphrase to open it -- either by prompting you for it, or by getting it from ssh-agent. This provides you with some security against theft of the private key. If you don't use a passphrase, then anyone who obtains your private key (for example, from a backup of your home directory) will be able to use it. (Setting up ssh-agent is not covered here.)
When ssh-keygen is done, you will have two files:
$HOME/.ssh/id_rsa # Private key $HOME/.ssh/id_rsa.pub # Public key
If you generated a DSA keypair, or if you're using a different implementation, the names will differ. Your private key should be kept secret. If you used a passphrase, it is also encrypted. The public key should be copied to the server where sshd can read it.
Now, before you do that, you need to realize that there are two different formats in which the public key may be stored: OpenSSH format, or SECSH format. You may need to convert the public key to whichever format the sshd implementation on your server knows how to read. If you generated the keypair using OpenSSH, then (obviously) your public key will be in OpenSSH format. If the sshd on your server is OpenSSH (which you can determine by using telnet server.hostname 22 and reading the banner), then your key does not need conversion.
If your server is running an implementation that uses the SECSH format, then you'll need to convert your public key to that format. ssh-keygen has flags for doing that; read the man page to see how. Likewise, if you generated your keypair using PuTTY (or something else that uses the SECSH format), and your server runs OpenSSH, then you'll need to convert your public key to OpenSSH format.
Once the key is in the correct format, it should be placed into the file (not directory) named $HOME/.ssh/authorized_keys on the server. If you have connected to this server before, or if you've used the ssh client on this server before, then the $HOME/.ssh directory should already exist; and then all you'll need to do is concatenate your public key to the end of the authorized_keys file.
(Some people like to use the ssh-copy-id program to copy their public key into the authorized_keys file on a server. See man ssh-copy-id for instructions, if your version of SSH has it.)
If you try to connect to the server, and you are still prompted for a password, then the server may have refused to honor your key. If this is the case, there are a few things you should check.
The first is to make sure you understood whether you were actually being prompted for a password (by the server), or a pass phrase (by the client). If the client needs a pass phrase to decrypt the private key, this is quite different from the server rejecting the key and falling back to password authentication.
This is an example of the client asking for a pass phrase:
cyclops:~$ ssh golem Enter passphrase for key '/home/greg/.ssh/id_rsa':
This is an example of the server asking for a password:
imadev:~$ ssh vandev wooledg@vandev's password:
Second, please note that the authorized_keys file uses the American spelling, not the British spelling. If you put the key into authorised_keys it will not work.
Third, make sure that you copied the public key to the server, and not the private key.
If it's not one of those, then you need to check the Permissions on everything. OpenSSH will refuse to honor your public key if it's in a place where other users might be able to write their own public keys. (If another user can write to your authorized_keys file, then she can put her own key there, and then login as you.)
This is the part that many people mess up. Not only do you have to ensure that the authorized_keys file itself has no group- or world-write permission; but you also must make sure that every directory in the full path to that file is similarly free of group- or world-write permissions. For example:
wooledg@hostname:~$ echo $HOME /home/wooledg wooledg@hostname:~$ ls -ld / /home /home/wooledg /home/wooledg/.ssh drwxr-xr-x 21 root root 4096 2007-07-03 08:57 / drwxrwsr-x 3 root staff 4096 2006-07-20 14:32 /home drwxr-sr-x 25 wooledg wooledg 4096 2007-07-17 17:00 /home/wooledg drwx--S--- 2 wooledg wooledg 4096 2006-07-20 14:40 /home/wooledg/.ssh ^ | +-- Group write permission.
In many implementations, the presence of the group-write permission bit on the /home directory would cause sshd to reject an authorized_keys file in this user's .ssh directory. (There are some configuration settings that can change that, but it's typically easier and better to fix permissions on too-loose directories rather than removing SSH's safety precautions.)
(Somewhere around OpenSSH 3.0 -- exact version number unknown -- the permissions on directories "above" the user's home directory stopped being checked. So, the liberal permissions on /home would not cause a problem in sufficiently new versions of OpenSSH. Still, it doesn't hurt to fix them.)
If none of the tips in the Troubleshooting section fixed the problem, then it may be time to dig deeper. First of all, it is imperative to note that the server will not tell the client why a key is rejected. This is intentional, to prevent leaking information to an attacker. Therefore, no amount of ssh -vvvv will be of any use whatsoever. The rejection of a key cannot be diagnosed from the client side at all.
A key rejection can sometimes be diagnosed from the server side, however. You will most likely need superuser (root) privileges to do so. Start by looking for a place where sshd is already logging information; often, this may be the /var/log/auth.log file, or some similar file. See if a reason for rejection is stated there. If not, or if no such file exists yet, then you may wish to start up a second instance of sshd on an alternative port:
server# sshd -p 2200 -d
Keep that window open, as the debugging information is written to standard output. Then on the client, connect to the alternative port:
client$ ssh -p 2200 username@server
If the key is rejected, a reason for the rejection should be revealed on the server.
For the impatient who just skimmed this to the bottom, let's recap:
The private key lives on the client. The public key is created on the client and gets copied to the server. Make sure you don't mix this up.
The authorized_keys file on the server must be spelled correctly.
The Permissions on every directory in the path to authorized_keys starting from root must not be group- or world-writable.