macOS Sierra SSH "Permission Denied"

keychain-mac-tuto If you used DSA keys to log in to your SSH server and have upgraded your client machine to macOS Sierra (or OSX Sierra if you like), you probably ran into this problem:

[sourcecode language="text" gutter="false"] client$ ssh -p 8123 george@10.0.0.10 -i ~/.ssh/id_dsa Permission denied (publickey). [/sourcecode]

The answer to this problem is replacing the DSA key with an RSA key, but how do you do on the server when your only means for connecting is the OSX client machine you just upgraded? Here's how:

First, create a new 4096 bit RSA keypair on the local machine (don't delete your DSA keys yet!). Don't use anything less than 4096 bits, and protect it with a lengthy passphrase. This key will replace the DSA key later on.

[sourcecode language="text" gutter="false"] client$ ssh-keygen -b 4096 -t rsa -f ~/.ssh/id_rsa Generating public/private rsa key pair. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in id_rsa. Your public key has been saved in id_rsa.pub. The key fingerprint is: SHA256:OA3Vx8qb4kKRWYs8qsq5/EywaLLdwZdlCIITFPnRtt8 george@macbook.local The key's randomart image is: +---[RSA 4096]----+ |ooo . .. . | | + . o .. . o | |o o +.o= o o | | . o oB=. o | | . .=oS o | |. o.. ..Eo | |oo oo.o. . | |=o=. o. . | |o+o. . | +----[SHA256]-----+ [/sourcecode]

Don't worry about that long passphrase, Sierra now stores that in your Keychain. Now, log into your server by temporarily enabling ssh-dss public key support on the ssh command line, like so:

[sourcecode language="text" gutter="false"] client$ ssh -p 8123 george@10.0.0.10 -i ~/.ssh/id_dsa
-o PubkeyAcceptedKeyTypes=+ssh-dss [/sourcecode]

If all went well, you should now be connected to your server, but with your old DSA key. The DSA support was disabled in Sierra because it is no longer considered to be a safe option as it is based on the discrete logarithm problem and the key is required to be just 1024 bits long.

What we need to do now is remove the DSA public key from the server and add the newly created RSA key. Start your editor with:

[sourcecode language="text" gutter="false"] server$ vim ~/.ssh/authorized_keys [/sourcecode]

Find the old DSA public key, remove it. Add the contents of the id_rsa.pub on your client machine to this file on the server. Save the file with <esc>:wq<enter>.

Now exit the server and reconnect with your new RSA key from the client:

[sourcecode language="text" gutter="false"] server$ exit client$ ssh -p 8123 george@10.0.0.10 -i ~/.ssh/id_rsa [/sourcecode]

You should now see the welcome message from the server and the command prompt. Please note that the -i option is here for clarity; if your key is in ~/.ssh/id_rsa it will be used as default identity.

If everything worked, please delete the id_dsa key to prevent confusion. All operations should now be back to normal (but safer).

Bonus 1: Tab-completion for SSH If you are tired of typing the long ssh commands and remembering ip addresses and key files, create a file called ~/.ssh/config and give it the following contents:

[sourcecode language="text" gutter="false"]

My Super secret server

Host secret-server HostName 10.0.0.1 Port 8123 User george IdentityFile ~/.ssh/id_rsa [/sourcecode]

After saving the file, you can use tab completion after the ssh command, and you will notice that the following command will work:

[sourcecode language="text" gutter="false"] client$ ssh secret-server [/sourcecode]

Bonus 2: Per-server identity With the powers of the config file mentioned earlier, there is no longer a reason to have one key file or one userid per server. Suppose somebody accidentally gets a hold of a key file, or someone figures out a way to find a key for a bunch of packets between two machines. This would mean immediate compromise of all machines. Because there is no extra effort in using multiple keys, I use a new private key for each server. My ~/.ssh/config file looks similar to this:

[sourcecode language="text" gutter="false"]

My Super secret server

Host secret-server HostName 10.0.0.1 Port 8123 User george IdentityFile ~/.ssh/id_george_secret_rsa

The DMZ firewall

Host dmz-firewall HostName 10.0.0.21 Port 8623 User jack IdentityFile ~/.ssh/id_jack_dmz_fw_rsa [/sourcecode]

Because just like passwords, I never use the same private key twice.