(have a look at wiki page if you don't want to read the blog post :)
If you are into PKI, chances are that you have also had the opportunity to work with HSM or smart-card devices. Once you go down that route, you will find yourself trying to get all kinds of crazy things to use crypto devices, either in order to protect access to private keys or to increase system performance when it comes down to crypto operations.
My entry point into crypto devices were HSMs in combination with X.509 infrastructure, which was followed by working with smart-cards. This involved both card personalisation and using the cards with various end user applications (web browsers, mail clients, more exotic things like Kerberos, login processes etc).
These smart-cards commonly come with a specialised firmware that implements PKCS#11 interface - a C-level API standardising access to crypto operations on a smart-card. There are some other interfaces as well, but PKCS#11 is one of the best options when it comes down to cross-platform support in end user applications.
Unfortunately, the PKCS#11 is a fairly high-level standard that does not deal with how the PKCS#11 library (that provides the API) itself communicates with the smart-card. This results in most vendors having their own implementations which are tied-in to their own smart-cards.
What is possibly a bit less known is that OpenPGP has its own way of handling crypto devices - the OpenPGP card standard. OpenPGP cards come with identical low-level interface, making it possible to use same middleware to work with different card vendors (not many card vendors out there, though :). Most commonly, if not even exclusively, the cards are used in conjunction with GnuPG.
First time I started playing around with OpenPGP cards was back in 2013, when I ordered a couple of them from Kernel Concepts. I ended-up setting-up new set of private keys using two cards. One card ended-up with the master certification key (for signing my own and other people's keys), while the other had authentication, signing, and encryption sub-keys (for everyday use).
Around that time I was still sporting on regular basis a nice little Acer Aspire One netbook (still live and kicking, although underpowered). As is common, I have set-up the LUKS encryption to protect my data. Partitions required a password to be entered in order to unlock them during boot.
Some time after getting more used to the OpenPGP card usage, I thought it would be cool to protect the LUKS-encrypted disk using the OpenPGP card itself. Essentially, the idea was to create a random key, add it to the LUKS devices, and use the OpenPGP card for providing the key during boot.
There was a couple of ways to do this, one involving storage of unlock key on the OpenPGP card itself (as user data), and having the key protected via PIN. Unfortunately, I could not get this to work.
The next logical step was to figure out if I could encrypt the key using my OpenPGP card, and have the card decrypt the key during the boot. In turn, decrypted key would be passed on to cryptsetup in order to unlock the partitions.
After some reading of existing material on topic (mainly on using GnuPG soft keys for the purpose), and a bit of trial and error, I managed to get the whole set-up working. The process required a custom initrd that included both the GnuPG keyring and the necessary GnuPG binaries (and other apps) for using the OpenPGP card.
The next step I took was to move my boot partition outside of the netbook, and onto a dedicated boot device. This would allow me to keep my trusted boot device with me during most/all times. Since I also needed to have a card-reader, I ended-up getting a nice little device called +iD - a foldable smart card reader which also sports a MicroSD card reader.
This has allowed me to plug-in a single device into the machine, boot my specially-prepared initrd from it, and decrypt the LUKS unlock key using OpenPGP card I inserted into the same device.
This has worked rather well for me under Debian Squeeze and Debian Wheezy, but since Debian Jessie came out, I did not have chance/will to mess around with it to create same type of set-up. This was partially due to being unsure on what changes would be required due to switch to systemd, especially since I saw a couple of entries out there that stated it was not possible to use scripts for providing LUSK unlock key anymore.
After I bought a new laptop a couple of weeks ago, I figured I should try to recreate the same results in Debian Jessie before putting the machine to regular use.
Starting off with an existing guide I found on the Internet, which revolved around using GnuPG with soft keys, I ended-up adding bits and pieces necessary for handling decryption using the OpenPGP cards.
Luckily, it did not take too much effort to sort things out. The systemd did not cause any issues for me, and it became much easier to figure out boot issues by interrupting the boot process just before the mount phase. By simply passing break=premount kernel option during boot, you will get a nice shell access in the initrd environment, just prior to the file-systems being mounted. This made testing and troubleshooting much, much easier. I ended-up including strace to the initrd image, and running it within the restricted environment to figure out what exact errors I was getting, and what files were missing.
There was a couple of tricky points to sort-out:
Did you know initrd does not have come with bash? I didn't, so first time I got locked-out due to script failing to execute :)
I could not get the stock pinentry application to work. I ended-up pulling in the pinentry-curses package into the mix to fix this (although... maybe it was some other issue that was messing with me, described below).
After the pinentry-curses got added, it turned out that initrd is missing some terminal capability information. An additional file had to be added.
The scdaemon, used by GnuPG for accessing the OpenPGP card, spewed out debug messages during PIN entry. This was a bit annoying, so I decided to redirect its log to /dev/null.
Unfortunately, GnuPG can sometimes get confused with what is the GnuPG home directory, even when using the --homedir option. I believe this happens when it tries to spawn the gpg-agent. This was easy to fix by setting the GNUPGHOME environment variable instead.
I did find myself getting locked-out repeatedly. After some trial and error, I ended-up adding the following snippet at the top of decrypt script (this lets you provide regular password at start in case something is wonky with GnuPG/card):
echo "Enter password: " >&2 read password if [ -n "$password" ]; then echo -n "$password" exit fi
The full guide has been added to Majic Wiki, and includes full step-by-step instructions. If you happen to have any questions/suggestions, feel free to drop me a comment here. Just a word of warning - please make sure you have backups before trying any of this out ;)
If you want to play around in safe environment, try using a VM instead first. I had good experiences using VirtualBox, with two disks (second disk being pretty small and used as a "fake" USB device - don't even try booting from USB stick with VirtualBox, trust me).