Both YubiKey and GnuPG are able to do many things. The difference one might point out is, that GnuPG probably does neither of them particularly well, resembling a Swiss army knife. No matter how well either of the tools handles tasks it is able to perform, both tools had became a de-facto standard in their respective fields.

Given that the sphere of influence of both these tools overlap on multiple fronts, and due to the complexity of GnuPG, it is inevitable that there would be both wrong ways to use them together as well as right ones.

To start on the safer side of the above range, there is a really nice YubiKey guide covering much of the use cases a mighty YubiKey offers, dedicating most of the guide's length to specifically the GnuPG functionality. For YubiKey, the guide hardly omits anything really important one might encounter.

The story is sadly quite different for the OpenPGP smartcard, a form factor security token that fits into my wallet. In fact, YubiKey swallowed this smartcard entirely, offering every single piece of it's functionality as drop-in replacement, while adding a ton other features on top of it. Ignoring all the other security features, just an addition of the NFC is a plus. The fact that a YubiKey can do everything a OpenPGP smartcard can is a reason why is it possible to follow a guide for YubiKey, while working with a OpenPGP smartcard. Or so I thought.

Key Derivation Function

Before we get further, I have to explain one key concept briefly: Key Derivation Function. Simplifying, KDF is a function that turns one key into other one in a reproducible manner. If you ever wondered about where password hashing came from, KDF is the culprit. There are two other important properties of the process.

First, reversing the function (obtaining the original key from the derived one) should be practically impossible. This condition is getting challenged all the time with newer and better hardware and a sheer amount of data available. Hence why for instance the usage of MD5 is actively discouraged.

Second important property for a subset of Key Derivation Functions is that it should take considerable amount of time to provide a result. For a KDF where such a property is desirable, an input parameter called iterations is provided. The higher the iterations count, the longer the user has to wait when using a KDF legitimately (this should still be barely perceptible), but also the exponentially longer time would an attacker need to generate a hash tables with this function, thus reducing some attack surface.

KDF and OpenPGP standard

To understand why is KDF important for a OpenPGP smartcard and a YubiKey at the same time is that OpenPGP standard defines multiple PIN passwords for operation, most importantly a normal PIN and an admin PIN. These PINs were stored in a device as a plaintext up until OpenPGP smartcard version 3.3 and YubiKey version 5.2.

Storing a password in a plaintext is not a good idea. Sending a plaintext password over any communication channel is also not a good idea. The guys defining an OpenPGP standard understood that and came with a solution, that is a common practice elsewhere. Simplifying again, instead of a plaintext, store hashes of the PINs on the device and make the client, in this case a GnuPG software, calculate the hashed PIN before sending it over to the device, where it gets compared. The guys decided to call this process by its scientific name, thus KDF.

There are at least two good reasons to enable this feature on all your OpenPGP smartcards and YubiKeys when working with GnuPG. Reducing the possibility of MITM attacks and making it even harder for an attacker to do something nasty with your device before you revoke your certificates.

The speed of an adoption

So enabling KDF seems like a no-brainer. As is usually the case with any software whatsoever, more features lead to more bugs. This case is no different. There are many mentions that enabling not only solved some problems, but created a few others. Some got resolved and adopted in time.

Other problems [got resolved] but did not get adopted widely, as is the case of the GnuPG 2.3 branch, which is marked as a development branch, paving a way for a stable 2.4 branch. Due to changes introduced in GnuPG 2.3, which I won't go into at this time, many distributions stick with the 2.2 branch.

Debian's gnupg package currently sits at 2.2.27. Arch went with 2.3.1 briefly but then rolled back. Artix community noticed and got confused in the process.

OpenPGP smartcard and GnuPG 2.2

I am still not sure how come that enabling KDF as a very first step right after a factory reset works on a YubiKey even with a GnuPG as low as 2.2.27 and at the same time, it fails on GnuPG smartcard 3.4 with a following error:

gpg/card> passwd
gpg: OpenPGP card no. XXXX detected

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? 1
Error changing the PIN: Bad PIN

Choosing a selection 3 to change the admin pin fails with the same message:

Error changing the PIN: Bad PIN

The reason for this is that while the KDF gets enabled with the kdf-setup admin command, the passwords do not get rehashed and so the comparison is broken as now the hash is compared with the plaintext, or something along the lines. The only way out of this I found is a smartcard factory reset.

KDF with GnuPG 2.3.1

The good part is that the above problem is resolved in the GnuPG 2.3.0. The bad part is, as already stated, this version is not really too available from the official repositories on the distributions I readily interact with.

Another good bit is, that once the KDF is enabled on the GnuPG smartcard with the GnuPG 2.3.1 (maybe even with 2.3.0, but I did not test), it can interact with GnuPG 2.2.27 and higher without a Bad PIN problem.

So the only thing needed is get GnuPG 2.3.1 running and enabling KDF on the GnuPG with that. I found a surefire way to do this on Arch by building and installing a GnuPG 2.3.1 package from this commit, as it even was a one point in the official repositories, before being pulled down as described earlier.

In case there is a conflict with gpgme which Depends on gnupg>=2, you can modify the PKGBUILD as follows:

- provides=(${pkgname%-git})
+ provides=(${pkgname%-git}=2)

Worked for me.

Running GnuPG 2.3.1 on Arch

With the GnuPG 2.3.1 (or newer) installed, proceed by editing card settings:

gpg --edit-card

However, you should be greeted with the following:

gpg: WARNING: server 'gpg-agent' is older than us (2.2.32 < 2.3.1)
gpg: Note: Outdated servers may lack important security fixes.
gpg: Note: Use the command "gpgconf --kill all" to restart them.
gpg: WARNING: server 'scdaemon' is older than us (2.2.32 < 2.3.1)
gpg: Note: Outdated servers may lack important security fixes.
gpg: Note: Use the command "gpgconf --kill all" to restart them.

This is the reason why I believe it is not trivial to use GnuPG version that is not readily available from the repositories, unless you really know what you are doing. If the only thing needed was updated version of gpg, things would be only marginally harder than running make followed ./bin/gpg --edit-card. To make it all really work, we need to also update scdaemon and, obviously an gpg-agent. Other distributions than Arch might probably get by by building gnupg from source and adjusting ./configure parameters before running make install.

However, with the Arch package installed, the required executable files are already in place, they only need to be loaded into memory and the greeting above shows exactly how to do that:

gpgconf --kill all

Sadly, trying to edit the card now, we are out of luck:

gpg: selecting card failed: No such device
gpg: OpenPGP card not available: No such device

gpg/card>

The solution is officially documented and confirmed elsewhere:

echo "disable-ccid" >> ~/.gnupg/scdaemon.conf

The rest is easy. Enable KDF on the smartcard and confirm by changing PIN. Changing PIN should work now. Restore the scdaemon.conf file and roll back the official GnuPG version to not mess up your package manager package verification process:

sudo pacman -S gnupg

You can now follow the YubiKey guide even with a GnuPG 2.2 branch exactly as it is, only skipping the kdf-setup part, as KDF is already properly activated on the smartcard. Enjoy!