OpenSSH, ECDSA, and OS X

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.

Homebrew dupes

We need to add the dupes 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.

1brew tap homebrew/dupes

Compile/install OpenSSH

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 keychain compatible.

1brew install openssh --with-brewed-openssl --with-keychain-support

Tweaking launchd

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 ‘/usr/local/bin/ssh-agent’.

1	launchctl stop org.openbsd.ssh-agent
2	launchctl unload -w /System/Library/LaunchAgents/org.openbsd.ssh-agent.plist
3	sudo vi /System/Library/LaunchAgents/org.openbsd.ssh-agent.plist
4	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:

1	export SSH_AUTH_SOCK=$(launchctl getenv SSH_AUTH_SOCK)

(t)csh:

1	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 your ssh-agent(1)

 1[louisk@iPwn louisk ]$ ssh-keygen -t ecdsa
 2Generating public/private ecdsa key pair.
 3Enter file in which to save the key (/Users/louisk/.ssh/id_ecdsa): 
 4Enter passphrase (empty for no passphrase):
 5Enter same passphrase again:
 6Your identification has been saved in /Users/louisk/.ssh/id_ecdsa.
 7Your public key has been saved in /Users/louisk/.ssh/id_ecdsa.pub.
 8The key fingerprint is:
 9b5:06:56:e9:0b:c0:ce:21:6c:2b:f3:88:19:df:bc:61 louisk@iPwn
10The key's randomart image is:
11+---[ECDSA 256]---+
12|   . .    ..     |
13|    + +  ..      |
14|   . = oo..      |
15|. o . o..o..     |
16| = B    S.o.     |
17|o o E    ..      |
18|   . o           |
19|    .            |
20|                 |
21+-----------------+
22[louisk@iPwn louisk ]$
1[louisk@iPwn louisk ]$ ssh-add .ssh/id_ecdsa
2Enter passphrase for .ssh/id_ecdsa:
3Identity added: .ssh/id_ecdsa (.ssh/id_ecdsa)
4[louisk@iPwn louisk ]$ ssh-add -l
5521 b3:0c:26:1a:58:23:87:5c:fc:b0:db:51:9a:92:55:ae .ssh/id_ecdsa (ECDSA)
6[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 switch).

 1	[louisk@mpro louisk 177 ]$ ssh -v 198.18.0.2
 2	OpenSSH_6.4, OpenSSL 1.0.1f 6 Jan 2014
 3	debug1: Reading configuration data /Users/louisk/.ssh/config
 4	debug1: /Users/louisk/.ssh/config line 59: Applying options for *
 5	debug1: Reading configuration data /usr/local/etc/ssh/ssh_config
 6	debug1: Connecting to 198.18.0.2 [198.18.0.2] port 22.
 7	debug1: Connection established.
 8	debug1: identity file /Users/louisk/.ssh/id_ecdsa type 3
 9	debug1: identity file /Users/louisk/.ssh/id_ecdsa-cert type -1
10	debug1: Enabling compatibility mode for protocol 2.0
11	debug1: Local version string SSH-2.0-OpenSSH_6.4
12	debug1: Remote protocol version 2.0, remote software version OpenSSH_6.1
13	debug1: match: OpenSSH_6.1 pat OpenSSH*
14	debug1: SSH2_MSG_KEXINIT sent
15	debug1: SSH2_MSG_KEXINIT received
16	debug1: kex: server->client aes128-ctr hmac-md5 none
17	debug1: kex: client->server aes128-ctr hmac-md5 none
18	debug1: sending SSH2_MSG_KEX_ECDH_INIT
19	debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
20	debug1: Server host key: ECDSA 2e:5a:65:f0:bc:42:d2:22:e6:7d:71:65:0c:4f:b0:06
21	debug1: Host '198.18.0.2' is known and matches the ECDSA host key.
22	debug1: Found key in /Users/louisk/.ssh/known_hosts:196
23	debug1: ssh_ecdsa_verify: signature correct
24	debug1: SSH2_MSG_NEWKEYS sent
25	debug1: expecting SSH2_MSG_NEWKEYS
26	debug1: SSH2_MSG_NEWKEYS received
27	debug1: Roaming not allowed by server
28	debug1: SSH2_MSG_SERVICE_REQUEST sent
29	debug1: SSH2_MSG_SERVICE_ACCEPT received
30	debug1: Authentications that can continue: publickey,password,keyboard-interactive
31	debug1: Next authentication method: publickey
32	debug1: Offering ECDSA public key: /Users/louisk/.ssh/id_ecdsa
33	debug1: Server accepts key: pkalg ecdsa-sha2-nistp521 blen 172
34	debug1: Authentication succeeded (publickey).
35	Authenticated to 198.18.0.2 ([198.18.0.2]:22).
36	debug1: channel 0: new [client-session]
37	debug1: Requesting no-more-sessions@openssh.com
38	debug1: Entering interactive session.
39	debug1: Requesting authentication agent forwarding.
40	--- JUNOS 13.2X50-D15.3 built 2013-09-22 23:13:21 UTC
41	{master:0}
42	louisk@switch0.cmhome> exit
43
44	debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
45	debug1: client_input_channel_req: channel 0 rtype eow@openssh.com reply 0
46	debug1: channel 0: free: client-session, nchannels 1
47	Connection to 198.18.0.2 closed.
48	Transferred: sent 3416, received 2240 bytes, in 7.2 seconds
49	Bytes per second: sent 473.1, received 310.2
50	debug1: Exit status 0
51	[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 works fine.

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 release.

Copyright

Comments