Home
Got Linux ?

Blah blah blah... Mostly technical thoughts, rants and gibberish


Yubico’s YubiKey (PIV) - How-to

[UPDATED 2022.10.27]

Although we now all are smart cards and OpenSC gurus, thanks to my invaluable wisdom:

Linux smart cards (OpenSC) - How-to

Chances are high having some infatuated IT kiddy bring to our attention that smart cards are things of the past - as we are (!) - and fashionably up-to-date geeks nowaday shove their YubiKey up their USB slot.

Turns out all we’ve learned about OpenSC, PKCS#11, key slots and PIN codes isn’t just there to make us look like fossilized fools but actually rings quite a bell when starting to deal with YubiKeys.

But let’s start from the beginning.

First-thing-first: get yourself a YubiKey! I will actually base this rant on a YubiKey 5C which you can get from:

YubiKey Switzerland subsidiary

Yubico offical website

YubiKey: not just a smart card

YubiKeys are great little crypto cuties that actually provide several interfaces/features through multiple different applets:

YubiKey OTP

YubiKey U2F

YubiKey OATH

YubiKey FIDO2

YubiKey PIV

In this document, we’ll concentrate on that last interface/applet, which makes the YubiKey a close sibling to the smart cards we’ve grown to cherish.

Preparing the key

Let’s first install Yubico’s PIV tool:

apt-get install yubico-piv-tool

NOTE: on Debian/Buster, you may have to pick the package from Sid (hoping the Bug 926551 might be “fixed” before Buster is officially released)

Then check our brand new YubiKey is working correctly:

yubico-piv-tool -a list-readers -a version -a status
# (output for a YubiKey 5C)
Yubico YubiKey OTP+FIDO+CCID 00 00
Application version 5.1.2 found.
CHUID: No data available
CCC: No data available
PIN tries left: 3

(… CCID!?! that also rings a bell!!!…)

Which you can also confirm with OpenSC:

opensc-tool -a
# (output for a YubiKey 5C)
Using reader with a card: Yubico YubiKey OTP+FIDO+CCID 00 00
<hexadecimal fingerprint>

Now, before going any further, one MUST change the Management Key, PIN and PUK codes from their default:

YubiKey PIV setup

# Set the Card Holder Unique ID (CHUID) - REQUIRED for Microsoft Windows
yubico-piv-tool -a set-chuid

# Set the Cardholder Capability Container (CCC) - REQUIRED for Apple Mac OS
yubico-piv-tool -a set-ccc

# Change the PUK code
PUK=<8-digit>
yubico-piv-tool -a change-puk -P 12345678

# Change the PIN code
PIN=<6-digit>
yubico-piv-tool -a change-pin -P 123456

WARNING: Now is not the time to conscientiously store those secrets somewhere you’ll never find them again when dire need comes!

The various key slots

Before proceeding with creating our various certificates, one must understand the purpose and characteristics (PIN-wise) of the key slots provisioned by YubiKey’s PIV applet:

YubiKey PIV slots

Shortly put:

Certification Authority (CA)

We will not be using self-signed certificates. Come on!!!

So, before tearing your hair off, please refer to the OpenSSL Easy primer, which shall in no time make a Certification Authority warlock out of you:

Certification Authority with OpenSSL Easy

Attestation Intermediate Certification Authority (slot F9)

In order to thwart jealousy-spawned claims you’re not actually using a YubiKey to show off your PKI skills, you’ll need an Attestation certificate, signed by the YubiKey itself and bound to (private) keys you’re about to generate.

Yubikey PIV Attestation

Before we do, we need to retrieve your YubiKey-specific Intermediate Certification Authority (ICA):

yubico-piv-tool -s f9 -a read-certificate \
  -o yubikey-piv-attestation-ica.pem

And its issuing Root Certificate Authority (CA):

wget -q https://developers.yubico.com/PIV/Introduction/piv-attestation-ca.pem \
  -O yubikey-piv-root-ica.pem

Authentication token (slot 9A)

The authentication (private) key shall be generated by the YubiKey itself, meaning it can never be recovered by anyone:

yubico-piv-tool -s 9a -a generate \
  -A RSA2048 -H SHA256 \
  -o yubikey-s9a-pub.pem

Which we’ll straight-away attest as being YubiKey-bound:

yubico-piv-tool -s 9a -a attest \
  -o yubikey-s9a-attestation-cert.pem

Then, let’s generate the corresponding Certificate Signing Request (CSR):

USERNAME='<username>'
yubico-piv-tool -s 9a -a verify-pin -a request-certificate \
  -S "/C=Country/ST=State/L=City/O=Example Org./OU=example.org/CN=${USERNAME}/"
  -i yubikey-s9a-pub.pem -o yubikey-s9a-req.pem

NOTE: Make sure to specify a subject/DN (-S) that matches your Certicate Authority requirements (Country, STate, Locality, Organization name, etc.).

Once you receive the signed certificate - yubikey-s9a-cert.pem - back from your Certificate Authority, import it into the YubiKey:

yubico-piv-tool -s 9a -a import-certificate \
  -i yubikey-s9a-cert.pem

And test everything works as expected:

pkcs11-tool \
  --module /usr/lib/x86_64-linux-gnu/onepin-opensc-pkcs11.so \
  --test --login --token-label "${USERNAME}"

As for the corresponding SSH authorized key:

ssh-keygen -D /usr/lib/x86_64-linux-gnu/onepin-opensc-pkcs11.so -e

There you go!

Thwart jealousy-spawned critics

Now, should jealous morons dare pretend you don’t actually know how to use a YubiKey, just throw your Yubico-signed attestation in their face, let them verify it:

openssl verify \
  -CAfile yubikey-piv-root-ica.pem \
  -untrusted yubikey-piv-attestation-ica.pem \
  yubikey-s9a-attestation-cert.pem

and check it matches your request or certificate (modulus):

openssl x509 -noout -modulus \
  -in yubikey-s9a-attestation-cert.pem

openssl req -noout -modulus \
  -in yubikey-s9a-req.pem

openssl x509 -noout -modulus \
  -in yubikey-s9a-cert.pem

(prout!)

Qualified digital signature

Before we carry on, a word about what a qualified certificate is and what it means when dealing with smart cards/tokens.

Generally speaking, a qualified certificate is “a certificate whose primary purpose is to identify a person with a high level of assurance”, as stated in RFC 3739:

RFC 3739

In Switzerland, a qualified digital signature - based on a qualified certificate - is recognized as a legally valid signature - like the hand- written signature - in regards with the law (Loi sur la signature électronique, SCSE, RS 943.03) and its dependencies:

SCSE, RS 943.03

PTA-SCSE, RS 943.032.1

PTA-SCSE, RS 943.032.1, Annex

In addition, Trust Service Providers (TSP) issuing qualified certificates shall comply with ETSI technical requirements 319 411 (1+2) and 319 412 (2):

ETSI 319 411 1

ETSI 319 411 2

ETSI 319 412 2

In the end, and shortly put, it means the technical constraints on qualified certificates are:

  1. it MUST be delivered to living individuals only

  2. the subject (DN) of the certificate MUST uniquely identify the individual as registered by authorities (e.g. as in your ID card or passport)

  3. the certificate MUST NOT be used for any other purpose than digital signature (iow. it may not be used for encryption)

  4. the private key SHALL be under the sole control of the subject; iow. the private key may not be in possession of the TSP/CA

  5. private key access MUST be blocked after (max) 4 unsuccessful attempts

  6. a blocked private key MUST NOT be unblocked without the TSP/CA verifying the identity of the holder of the certificate (iow. it can not be unblocked by a PUK)

All of it leading to a better understanding of why the YubiKey’s PIV applet might differentiate slot 9C (signature, PIN always asked) from slot 9D (encryption, PIN aksed once).

Given we nerds are no TSPs - would you trust me? I certainly don’t trust you! - and our next purpose is to issue a personal certificate for (both) e-mail signature and encryption, we’ll skip slot 9C (reserve it for its intended purpose, although we could re-purpose it) and use slot 9D for encryption and (non-qualified) signature.

Post Scriptum: actually, a YubiKey may never be used to store a qualified certificate since the TSP/CA has no mean to enforce point 6. above (unless it sends you the YubiKey without its Management Key and PUK code). On the other hand, it may be OK to store a regulated certificate (which requirements are lesser than for qualified ones). [TODO: check/document this]

Signature and encryption token (slot 9D)

Since we already covered how to have the YubiKey generate (and saveguard) the private key, let’s now use an externally generated key pair and certificate. (but that’s up to you; personally, I’d rather stick with the former approach)

We’ll just assume that your Certificate Authority’s policies are to use your name and e-mail as address as component’s of your certificate’s subject (DN):

commonName=<firstname> <surname>
emailAddress=<firstname>.<surname>@example.org

First, let’s import the private key:

yubico-piv-tool -s 9d -a import-key \
  -i yubikey-s9d-key.pem

And then the certificate:

yubico-piv-tool -s 9d -a import-certificate \
  -i yubikey-s9d-cert.pem

Or, if you have a PKCS#12 (private key + certificate) package handy:

yubico-piv-tool -s 9d -a import-key -a import-certificate \
  -K PKCS12 -i yubikey-s9d-key+cert.p12

And to test everything works as expected:

TOKEN_LABEL='...'  # as reported by pkcs11-tool -L
pkcs11-tool \
  --module /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so \
  --test --login --token-label "${TOKEN_LABEL}"
# Watch for both 'PIV AUTH' and 'KEY MAN' keys test
# (for keys reported by pkcs11-tool -O)

And that’s it!

Using the Retired Key slots

The YubiKey provides 20 additional slots, numbered 82 to 95 and normally intended for Retired Key Management but which can be used similarly as the standard ones (9A to 9E).

YubiKey PIV slots

In order for those slots to appear as PKCS#11 objects, the Key History Object must be initialized with the proper value, as per NIST 800-73-4 specifications (§3.3.3 and Appendix A, Table 19):

echo -n C10114C20100FE00 | yubico-piv-tool -a write-object --id 0x5FC10C -i -

NIST 800-73-4

Those slots can then be used for any operation, including signing (which is a slight deviation from the NIST requirements), which can come handy if one needs several slots to securely store the various Issuing CAs (ICAs) one may have as part of one’s own Public Key Infrastructure (PKI).

Locking the YubiKey management

Most actions taken above - especially those modifying its content - can be administratively restricted by setting the YubiKey Management Key:

MKEY=$(dd if=/dev/urandom 2>/dev/null | tr -d '[:lower:]' | tr -cd '[:xdigit:]' | fold -w48 | head -1)
echo ${MKEY}
yubico-piv-tool -a set-mgm-key

Once this is done, one will need to use the -k option to have the tool prompt for the Management Key:

yubico-piv-tool -k ...

This is something that is not stricly required but which some IT department might do to ensure users don’t mess with their YubiKey.

YubiKey PIV administration access

Usage

As for how to use your brand new gadget, just refer to our previous smart card (PKCS#11) how-to:

Smart Card / PKCS#11 How-to

KeePassXC

Should you want to use your YubiKey as challenge-response source for KeePassXC, reprogram its slot 2 for HMAC-SHA1 challenge-response:

# Generate 20-bytes HMAC key
dd status=none if=/dev/urandom bs=20 count=1 | xxd -p -c 40

# Program the YubiKey
ykpersonalize -2 \
  -a \
  -ochal-resp -ochal-hmac -ohmac-lt64 \
  -oserial-api-visible \
  -oallow-update

Once reprogrammed, KeePassXC will automatically detect the YubiKey as source for challenge-response master key (along optional password and key file).

CRITICAL: make sure to keep a copy of the configured HMAC key (-a) somewhere safe!

NOTE: this does not affect any of the PIV-configuration covered above.

Gotchas

Kudos to Yubico

Have you noticed what an excellent documentation Yubico provides to us geeks? Thanks guys!