Jim Zajkowski

Setting Up Yubikey ECDSA SSH Keys

Feb 28, 2024

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.