I’ve been wanting to play with ECDSA ssh keys for a while (If memory
serves, it became available in early 2011).
I hoped that 10.7 (Lion)
would support it (the man pages confused things because they talk about
generating and using ECDSA keys, but the utilities don’t actually do
it). Then I hoped that 10.8 (Mountain Lion) would support. I finally
gave up and installed my own version of OpenSSH through
Homebrew. After a bit of googling, and some trial and
error, here are the steps I arrived at successfully.
We need to add the
tap to Homebrew. This is essentially an extra repo, but all the recipes
in it, duplicate things that are installed by default in the system.
We also want to bring in a new OpenSSL with extra optimizations, which is
easy with Homebrew. As a last bit to this step, we will ensure that the new
ssh-agent is launchd and
brew install openssh --with-brewed-openssl --with-keychain-support
We need to fix the launchd plist if we want to use the new agent
(which we do, because how else would you manage all your ssh keys?). The
overview is to simply replace ‘/usr/bin/ssh-agent’ with
launchctl stop org.openbsd.ssh-agent
launchctl unload -w /System/Library/LaunchAgents/org.openbsd.ssh-agent.plist
sudo vi /System/Library/LaunchAgents/org.openbsd.ssh-agent.plist
launchctl load -w -S Aqua /System/Library/LaunchAgents/org.openbsd.ssh-agent.plist
Updating the environment
The SSH_AUTH_SOCK environment variable needs to be updated for new
or existing terminal sessions. The slacker way is to logout or restart.
Just export the variable, or setenv if you (t)csh. (ba,z)sh:
export SSH_AUTH_SOCK=$(launchctl getenv SSH_AUTH_SOCK)
setenv SSH_AUTH_SOCK "`launchctl getenv SSH_AUTH_SOCK"
Generating an ECDSA key
Now we can finally generate our ECDSA key and add your new key to
[louisk@iPwn louisk ]$ ssh-keygen -t ecdsa
Generating public/private ecdsa key pair.
Enter file in which to save the key (/Users/louisk/.ssh/id_ecdsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/louisk/.ssh/id_ecdsa.
Your public key has been saved in /Users/louisk/.ssh/id_ecdsa.pub.
The key fingerprint is:
The key's randomart image is:
| . . .. |
| + + .. |
| . = oo.. |
|. o . o..o.. |
| = B S.o. |
|o o E .. |
| . o |
| . |
[louisk@iPwn louisk ]$
[louisk@iPwn louisk ]$ ssh-add .ssh/id_ecdsa
Enter passphrase for .ssh/id_ecdsa:
Identity added: .ssh/id_ecdsa (.ssh/id_ecdsa)
[louisk@iPwn louisk ]$ ssh-add -l
521 b3:0c:26:1a:58:23:87:5c:fc:b0:db:51:9a:92:55:ae .ssh/id_ecdsa (ECDSA)
[louisk@iPwn louisk ]$
Testing the key
Don’t forget to copy your new key (by default: id_ecdsa.pub) to your
~/.ssh/authorized_keys on your remote hosts. You should now be able to
login to a host using an ECDSA key exchange. Evidence of success can be
seen by looking at the verbose output from ssh (logging in to a Juniper
[louisk@mpro louisk 177 ]$ ssh -v 198.18.0.2
OpenSSH_6.4, OpenSSL 1.0.1f 6 Jan 2014
debug1: Reading configuration data /Users/louisk/.ssh/config
debug1: /Users/louisk/.ssh/config line 59: Applying options for *
debug1: Reading configuration data /usr/local/etc/ssh/ssh_config
debug1: Connecting to 198.18.0.2 [198.18.0.2] port 22.
debug1: Connection established.
debug1: identity file /Users/louisk/.ssh/id_ecdsa type 3
debug1: identity file /Users/louisk/.ssh/id_ecdsa-cert type -1
debug1: Enabling compatibility mode for protocol 2.0
debug1: Local version string SSH-2.0-OpenSSH_6.4
debug1: Remote protocol version 2.0, remote software version OpenSSH_6.1
debug1: match: OpenSSH_6.1 pat OpenSSH*
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: server->client aes128-ctr hmac-md5 none
debug1: kex: client->server aes128-ctr hmac-md5 none
debug1: sending SSH2_MSG_KEX_ECDH_INIT
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
debug1: Server host key: ECDSA 2e:5a:65:f0:bc:42:d2:22:e6:7d:71:65:0c:4f:b0:06
debug1: Host '198.18.0.2' is known and matches the ECDSA host key.
debug1: Found key in /Users/louisk/.ssh/known_hosts:196
debug1: ssh_ecdsa_verify: signature correct
debug1: SSH2_MSG_NEWKEYS sent
debug1: expecting SSH2_MSG_NEWKEYS
debug1: SSH2_MSG_NEWKEYS received
debug1: Roaming not allowed by server
debug1: SSH2_MSG_SERVICE_REQUEST sent
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey,password,keyboard-interactive
debug1: Next authentication method: publickey
debug1: Offering ECDSA public key: /Users/louisk/.ssh/id_ecdsa
debug1: Server accepts key: pkalg ecdsa-sha2-nistp521 blen 172
debug1: Authentication succeeded (publickey).
Authenticated to 198.18.0.2 ([198.18.0.2]:22).
debug1: channel 0: new [client-session]
debug1: Requesting firstname.lastname@example.org
debug1: Entering interactive session.
debug1: Requesting authentication agent forwarding.
--- JUNOS 13.2X50-D15.3 built 2013-09-22 23:13:21 UTC
debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
debug1: client_input_channel_req: channel 0 rtype email@example.com reply 0
debug1: channel 0: free: client-session, nchannels 1
Connection to 198.18.0.2 closed.
Transferred: sent 3416, received 2240 bytes, in 7.2 seconds
Bytes per second: sent 473.1, received 310.2
debug1: Exit status 0
[louisk@mpro louisk 178 ]$
Its probably worth noting that if you don’t put “/usr/local/bin” ahead
of “/usr/bin” in your shell “$PATH”, things won’t work the way you
want. All you have to do is add “/usr/local/bin” first, then everything
Update for Yosemite
UPDATE: This works fine with OS X Yosemite 10.10
Update for El Capitan
UPDATE: In order to make the plist changes, you will need to disable
rootless. Please see this article on
rootless and boot-args
ssh-agent (from homebrew) is not working currently. This may (or may not) get fixed for the