This is gross but it works. I use this stunt to avoid storing cryptographic keys in customized OpenWRT firmware images.
Importing keys to card¶
Readying Card For Use¶
Follow instructions at
https://developers.yubico.com/yubico-piv-tool/YubiKey_PIV_introduction.html
to use yubico-piv-tool
to personalize the PIV application (set admin
keys, PUK, and PIN). That amounts to:
dd if=/dev/random bs=24 count=1 | hexdump -v -e '/1 "%02X"' > mgmt.key.hex
yubico-piv-tool -a set-mgm-key -n `cat mgmt.key.hex`
yubico-piv-tool -k `cat mgmt.key.hex` -a change-pin -P 123456 -N $NEW_PIN
yubico-piv-tool -k `cat mgmt.key.hex` -a change-puk -P 12345678 -N $NEW_PUK
Keep the management key only on the high side machine; the PIN will doubtless need to be on the low-side machine and the PUK may merit being on a midlingly-secure piece of paper.
Importing Keys¶
I used slots 9a and 9d. The others claim to have some special features
associated with them, but may be viable. (In particular, with a modern
Yubikey and yubico-piv-tool
program, 82-95 may be of interest, though I
have not been able to test this.)
Import the key and certificate to the slot of your choosing This is perhaps most easily done from a PKCS#12 file containing both key and certificate:
yubico-piv-tool -k `cat mgmt.key.hex` -s 9a -a import-key -a import-cert -K PKCS12 -i ${FILE}.p12
Note that the Yubikey has only 2005 bytes of storage for PKCS#11 material, which limits the number of keys that can exist on the device. I am not sure if the certificate has to be present for the key to be useful.
Check the Card¶
Use pkcs11-tool
to verify that the card is configured as you expect:
Show objects on card:
pkcs11-tool -O
Read object to stdout from card by name:
pkcs11-tool -r -y cert -a 'Certificate for Key Management'
OpenVPN¶
Testing¶
Check that openvpn --show-pkcs11-ids /usr/lib/pkcs11/opensc-pkcs11.so
sees your key(s).
Caveats¶
It is necessary to tell OpenVPN not to
fork()
, as somewhere in OpenSC / pcsc-lite cannot deal with its clients forking. Thankfully, OpenVPN only forks to run scripts andip
androute
, which are not mandatory features for me. If they are for you, it is likely that things will have to be patched (ick; I’m sorry). In any case, use these directives in the config fileifconfig-noexec route-noexec
and avoid the use of
up
,down
, etc.While you can (and I do) use two OpenVPN servers using two different keys on the same card, this is apparently far more fragile than it should be. Using
--show-pkcs11-ids
, for example, will work but will cause all running daemons to be unable to do any more signatures ever, requiring restarts of the daemons. Don’t do that, especially not remotely.The use of OpenSC PKCS#11 is incompatible with GnuPG’s scdaemon, which locks the card exclusively. This is incredibly annoying, meaning that although the card has both PIV and OpenPGP support, only one is usable at a time. I suppose the pain is less than the cost of another card.
Configuration¶
Then, tell OpenVPN about OpenSC:
pkcs11-providers /usr/lib/pkcs11/opensc-pkcs11.so
And use the output from --show-pkcs11-ids
above to derive the
appropriate pkcs11-id
line. For me, that looks like
pkcs11-id 'piv_II/PKCS\x2315\x20emulated/1e06775fbfccbb86/PIV_II\x20\x28PIV\x20Card\x20Holder\x20pin\x29/01'
You may wish to use --management-query-passwords
, too, so that OpenVPN
asks on its management interface for the card’s PIN. Alternatively, I have
a (gross) patch
which adds an option
(--pkcs11-pinfile
) for reading the PIN in from a file. Thanks to Ondra
Medek in https://openvpn.net/archive/openvpn-devel/2005-12/msg00014.html for
pointing out what needed to change.