Setting Up Yubikey ECDSA SSH Keys
I’ve been using 1Password’s ssh
agent for a while, but I wanted to revisit ssh
keys on my iPhone. Prompt 3 came out recently and supported Yubi hardware keys, so after two days of yak shaving:
Yubikey Prep
Reset your Yubikey’s PIV module. This does not impact any YubiOTP, FIDO, U2F, or other parts of the Yubikey you might be using.
1ykman piv reset
Your Yubikey has three “PIN” like things for PIV functions: the access PIN which you will use every day; the PIN-Unlocking Key (PUK); and the Management Key. My mnemonic is “oh PUK!” is what you’ll say when you accidentally lock your PIN.
By default, the Yubi will only let you make three mistakes before locking. It’s not a terrible idea to increase both, because typing a secret on an iPhone screen can be difficult. 8 for the PIN and 10 for the PUK seems sane:
1ykman piv access set-retries 8 10
Enter 123456
(the default after the piv reset
).
Change your management key next - this will store the new management key on the Yubikey, protected by the PIN:
1ykman piv access change-management-key --touch --generate --protect
(press enter at the prompt, enter 123456
for the PIN)
Change the PUK. You do not need to keep it to digits; it’s easier to type a 6-8 character word.
1ykman piv access change-puk
(enter 12345678
as the old PUK)
Change the PIN. Again, use a short word or similar. If you get an error, it’s too short or too long.
1ykman piv change-pin
(enter 123456
as the old PIN).
Key Generation and Conversion
Create an ssh
ecsda keypair. If you already have a key deployed to servers hither and yon, you can convert it instead.
1ssh-keygen -t ecdsa -b 384 # my key doesn't support ed25519, but newer Yubis may
By default that will be named ~/.ssh/id_ecdsa
, but you can name it something else, just fix it below.
ykman
won’t import a file in OPENSSH PRIVATE KEY
form, so we need to first convert it to generic PEM
form, and then to a named-curve
format that ykman
expects:
1ssh-keygen -p -f ~/.ssh/id_ecdsa -m PEM # you could skip this with ssh-keygen -m PEM
2openssl ec -in ~/.ssh/id_ecdsa -param_enc named_curve -out ~/for-ykman.pem -AES-128-CBC
Now we can (finally!) import the key to our Yubikey
1ykman piv keys import --pin-policy once --touch-policy cached 9a ~/for-ykman.pem
Enter your PIN and touch the key when prompted. I’m not at all sure what pin-policy once
is supposed to do, because I have to re-enter my PIN every time I use it. cached
means you don’t need to re-tap the button within about 15 seconds, which can be helpful if you have some kind of nutty sftp client.
N.B.: Many Yubikey/SSH tutorials tell you that you also need to generate a certificate for the key as well. My experience so far has been that’s not been necessary with relatively new versions of OpenSSH, Prompt 3, and perhaps because it’s an ecdsa key. If I run into a situation where I need to create a certificate I will update this post.
Okay, now what?
Copy the contents of the ~/.ssh/id_ecdsa.pub
file into the authorized_keys
file on the servers you’re trying to reach, same as any other SSH key.
Prompt 3 on all platforms will work “out of the box” if you set it to use Yubikey PIV. I found it less fiddly to plug it into my iPhone than using NFC, but both work.
For macOS, you’ll need a PKCS11 provider. Apple ships one in ssh-keychain
but sadly this version doesn’t support ECDSA keys (FB13663068
), only RSA - and my Yubikey only supports up to RSA2048.* That’s okay: Yubikey publishes a provider in the Yubico PIV Tool
download (alternate: brew install yubico-piv-tool
and change the path below). I’ve heard that OpenSC also has a PKCS11 provider, but the Yubico dylib worked fine for me.
You’ll want to tell Sonoma’s ssh how to use this by adding the PKCS11Provider
directive to your ~/.ssh/config
, such as this:
Host *
PKCS11Provider /usr/local/lib/libykcs11.dylib
Once that’s done, you should be able to ssh server
. You’ll need to enter the PIN and then touch the key to activate - it will just hang until you do.
*
Firmware 5.7 and later Yubikeys support RSA4096 and I don’t know if ssh-keychain
supports RSA4096, even if the key does.
Why not use FIDO2?
FIDO2 sk
type keys are probably The Future, as it’s a bit less fiddly than this, but there’s no way to make them work on iPadOS: the OS only allows NFC reading of the FIDO2 key, and no iPads have NFC readers. Since I wanted the ability to ssh
from my iPad, this was a nonstarter.