Home
Got Linux ?

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


Yubico’s YubiKey (PIV) - How-to

[UPDATED 2019.07.05]

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

# Change the 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

# Set the Card Holder Unique ID (CHUID)
yubico-piv-tool -k -a set-chuid

# 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

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 -k -s 9a -a generate \
  -A RSA2048 -H SHA256 \
  -o yubikey-s9a-pub.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 -k -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/libykcs11.so \
  --test --login --token-label "${USERNAME}"

As for the corresponding SSH authorized key:

ssh-keygen -D /usr/lib/x86_64-linux-gnu/libykcs11.so -e

There you go!

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 -k -s 9d -a import-key \
  -i yubikey-s9d-key.pem

And then the certificate:

yubico-piv-tool -k -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 -k -s 9d -a import-key -a import-certificate \
  -K PKCS12 -i yubikey-s9d-key+cert.p12

And that’s it!

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

Gotchas

Kudos to Yubico

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