So for a while, I did use simple-tpm-pkcs11 for my work ssh key, and it was working well (back in 2014/2015). Someone would need to have access to both the unlocked disk (there is a encrypted blob there) and the motherboard for getting any access. The problem appeared in 2017 while I was traveling around Europe, when the frame of my laptop screen began to crack, and that I had to potentially send it to repair. Suddenly, I realized that I wasn’t sure to get back the same motherboard if it got fried, and even if I did waited for new laptop, that I would have issue when switching.
So I switched to using a smartcard in summer 2017, with a spare yubikey I had. It took me a while to just change my ssh keys everywhere (I listed around 30 to 40 systems). I already used yubikey for the 2FA auth at work, so this was quite easy to just also use my key for testing. I decided to generate my ssh key directly on the hardware to prevent possible leaks, but this turned out to be also a bad idea. Yubikey did receive lots of criticism for switching from free software code that could be uploaded to code that was burned in the silicon in the microcontroller back in 2016 (https://lwn.net/Articles/687676/). While I do care about free software, this was a tradeoff I was willing to make for the form factor, and my understanding is that they didn’t really had much choice anyway given the current industry (with NDA all over the place, etc).
But then, the almost impossible did happen, and this attack got published: https://lwn.net/Articles/738896/
So I switched again ssh keys (the process this time was much faster, since I did had my list from summer), and now, my current setup is to have 2 yubikey nano, 1 holding 1 ssh key, the other one holding 2 keys ( same key as first + a backup key in case the first has a issue). The first yubikey is on my laptop, the 2nd is a backup in case I lose the first. I upload the 2 keys everywhere, so if I lose the first, I can still connect, and I can remove the lost key without losing access. And I do have a clear text version of the 2 ssh keys on a encrypted usb stick safely stored in case I need to replicate one. And 1 spare key to replace the one that would be lost.
My biggest issue in the past was that the ssh-agent of seahorse didn’t support adding pkcs11 smartcard, and I wasn’t even sure where to start to add that, as I lost myself in the several layer of crypto stack (for people who never seen the diagram: https://assets.flameeyes.eu/2011/04/nss-pkcs11 ). Now, this is solved on recent GNOME so I can just do:
ssh-add -s /usr/lib64/opensc-pkcs11.so
Then it ask for the PIN and I can use it in my agent.
On my Silverblue laptop , I need to layer opensc and that work. As for the initial setup, my first script:
#!/bin/bash
PUBLIC=$(mktemp --suffix=.pem)
CERT=$(mktemp --suffix=.pem)
SLOT=${SLOT:-9a}
ALGO=${ALGO:-RSA2048}
yubico-piv-tool -s $SLOT -a generate -A $ALGO -o $PUBLIC
yubico-piv-tool -s $SLOT -a verify-pin -P 123456 -a selfsign-certificate \
-S "/CN=SSH key of $USER, slot $SLOT/" -i $PUBLIC -o $CERT
yubico-piv-tool -s $SLOT -a import-certificate -i $CERT
echo "the current key is:"
ssh-keygen -D /usr/lib64/opensc-pkcs11.so
This do generate the certificate on the key itself.
My production script still has a reminder to not use that due to ROCA. Depending on the version of the key you have, you might go for more than RSA 2048, but I think openssh do not support ECDSA keys on pkcs11, despites patch floating. Openssh in Fedora is patched for that: https://fedoramagazine.org/fedora-28-better-smart-card-support-openssh/, but that’s not a risk I am willing to try in case I need to use the key on another laptop (something I consider more likely than a crypto breaktrough regarding RSA factoring). Not to mention there is still old stuff around that do not support ECDSA, as one of my coworker did painfully found out (and let’s not throw quantum crypto out there, as I kinda think people panic for nothing at the moment: https://security.stackexchange.com/questions/33069/why-is-ecc-more-vulnerable-than-rsa-in-a-post-quantum-world ).
My current script is generating offline so I can keep a backup copy:
#!/bin/bash
set -e
if [ $# == 1 ]; then
DIR=$1
else
DIR=$(mktemp --directory ${XDG_RUNTIME_DIR}/ssh_yubi_XXXXXXXXXX)
fi
# hardcoded, since that's the max we can store on a smartcard for now
SIZE=2048
PREFIX=${PREFIX:-SSH}
echo "Working in $DIR"
SLOT=${SLOT:-9a}
KEY_PREFIX=newkey
NEW_KEYFILE=$DIR/$KEY_PREFIX
cd $DIR
if [ ! -f "$DIR/$KEY_PREFIX" ]; then
ssh-keygen -N "" -b $SIZE -q -f $DIR/$KEY_PREFIX
fi
openssl rsa -in $DIR/$KEY_PREFIX -out $DIR/${KEY_PREFIX}.pem -outform pem
yubico-piv-tool -s $SLOT -a import-key -i $DIR/${KEY_PREFIX}.pem
ssh-keygen -e -f $DIR/${KEY_PREFIX}.pub -m PKCS8 > $DIR/${KEY_PREFIX}.pkcs8
yubico-piv-tool -a verify -P 123456 -a selfsign-certificate -s $SLOT -S "/CN=${PREFIX} key of $USER, slot $SLOT/" -i $DIR/${KEY_PREFIX}.pkcs8 -o ${SLOT}-cert.pem
yubico-piv-tool -a verify -P 123456 -a import-certificate -s $SLOT -i ${SLOT}-cert.pem
yubico-piv-tool -a status
echo "the current key is:"
ssh-keygen -D /usr/lib64/opensc-pkcs11.so
I can also use it to flash a 2nd key. I did a script because I wanted to do lots of test before deploying. New yubikey can generate bigger keys (new one do RSA 4096, afaik), but since I already own 5 of them (2 for ssh keys, 1 for 2FA, and 2 empty spare in case I lose one of the used one), maybe I should stop buying more.
If you go that road, do not forget also to change the management pin, listed as 123456 here. You can do it after, and can’t remove it anyway (I tried, that’s hardcoded in the ssh source and I wasn’t willing to go deal with the OpenBSD crowd on that so I didn’t even tried). Changing it would help in case of theft, but since most theft are done for the monetary value of the hardware more than the key, maybe you shouldn’t sweat too much on it.
My code came from a few ressources that I did bookmark that could help:
http://blog.rchapman.org/posts/Import_an_existing_ssh_key_into_Yubikey_NEO_applet/
https://developers.yubico.com/PIV/Guides/SSH_with_PIV_and_PKCS11.html
There is a ton of doc out there, most being IMHO overly complicated since they usually deal with the GPG side, and kinda never explain the tradeoff made, have varying level of sophistication, and sometime requires to be updated.
That’s kinda overkill for ssh IMHO, and this doesn’t really help people to realize that they could use a yubikey and just make sure their ssh keys do not fall in the wrong hands, because access to servers is a bigger target than personal GPG signatures by one or two order of magnitude.
Now, there is still issues, mostly around integration. For example, if I unplug the key, it should remove itself from the agent, but I have no way to do that easily (I did took a look at udev events, but nope). I need to load the key in the agent and type my pin on a console, while I would love to get it on first use (there is some option to do that for regular key, it doesn’t work for pkcs11). I do not think the agent lock itself when I lock my screen. And the agent itself is open to any software I run, which is kinda not optimal, even if I guess I can write a SELinux policy for that (but the risk are too low for me to bother in practice).