Yubikey PIV / Smartcard
PIV, Personal Identity Verification, is a standard defined by NIST (SP 800-73) for smartcard-based cryptography. The Yubikey 5 implements PIV alongside OpenPGP, giving it two separate cryptographic identities that coexist on the same hardware. Where the OpenPGP interface was covered in the GPG section and is used for email, file encryption, and SSH via the GPG agent, PIV uses the PKCS#11 interface and is better suited to X.509 certificate operations, client certificate authentication, and integration with systems that speak standard smartcard protocols.
In the context of this series, PIV is primarily used for two things: loading TLS client certificates onto the Yubikey for HTTPS mutual authentication, and as an alternative SSH authentication path via PKCS#11 for systems that do not use the GPG agent approach.
PIV slots
The PIV interface provides four main certificate slots, each with a defined purpose:
| Slot | Name | Purpose |
|---|---|---|
| 9A | Authentication | Client authentication, SSH |
| 9C | Digital Signature | Document signing |
| 9D | Key Management | Encryption, key exchange |
| 9E | Card Authentication | Physical access, secondary auth |
Each slot holds one key pair and one certificate. For this setup, slot 9A is the most relevant: it is where the client authentication certificate lives, used for SSH via PKCS#11 and for mutual TLS authentication with self-hosted services.
Prerequisites
Install the required packages:
sudo apt install yubikey-manager opensc libpcsclite1 pcscd
opensc provides the PKCS#11 module and smartcard utilities. yubikey-manager provides ykman, the command line tool used throughout this page. Verify pcscd is running:
sudo systemctl enable --now pcscd
Insert the Yubikey and verify it is detected:
ykman info
The output should show the Yubikey model, firmware version, and list PIV as an enabled application.
Default credentials
A factory Yubikey has the following PIV defaults. Change all of them before use:
| Credential | Default value |
|---|---|
| PIN | 123456 |
| PUK | 12345678 |
| Management key (firmware < 5.7) | 010203040506070801020304050607080102030405060708 (3DES) |
| Management key (firmware ≥ 5.7) | 010203040506070801020304050607080102030405060708 (AES-192) |
Three incorrect PIN entries blocks the PIN. Three incorrect PUK entries blocks the PUK permanently. Three incorrect management key entries resets the PIV application entirely, destroying all keys and certificates. Store all three in KeePassXC before proceeding.
Check your firmware version:
ykman info | grep "Firmware"
Firmware 5.7.0 and above uses AES-192 for the management key. Earlier firmware uses 3DES. The setup commands differ slightly between the two.
Initial PIV configuration
Generate a new management key
The management key protects administrative operations on the PIV application. It must be changed from the default before the Yubikey goes into use.
For firmware 5.7+:
# Generate a random AES-192 management key
MGMT_KEY=$(python3 -c "import secrets; print(secrets.token_hex(24))")
echo "Management key: $MGMT_KEY"
# Set the new management key
ykman piv access change-management-key \
--management-key 010203040506070801020304050607080102030405060708 \
--new-management-key $MGMT_KEY \
--algorithm AES192
For firmware below 5.7:
# Generate a random 3DES management key (48 hex chars)
MGMT_KEY=$(export LC_CTYPE=C; dd if=/dev/urandom 2>/dev/null | \
tr -d '[:lower:]' | tr -cd '[:xdigit:]' | fold -w48 | head -1)
echo "Management key: $MGMT_KEY"
ykman piv access change-management-key \
--management-key 010203040506070801020304050607080102030405060708 \
--new-management-key $MGMT_KEY
Copy the management key to KeePassXC immediately.
Set PIN and PUK
Change the PIN to a 6-8 character value. Numeric-only PINs work everywhere, alphanumeric PINs work on most systems but may cause issues with some PKCS#11 applications. Numeric is safer for maximum compatibility.
ykman piv access change-pin --pin 123456 --new-pin <your-new-pin>
ykman piv access change-puk --puk 12345678 --new-puk <your-new-puk>
Store both in KeePassXC. The PIN is what you enter when using the Yubikey for PIV operations. The PUK is what you use to unblock the PIN if it becomes blocked.
Enable PIN protection for the management key (optional)
For convenience, you can configure the Yubikey to protect the management key with the PIN rather than requiring the full management key string for administrative operations. This is less secure but more practical for setups where you regularly modify PIV configuration:
ykman piv access set-pin-retries --pin-retries 5 --puk-retries 3 \
--management-key $MGMT_KEY --pin <your-pin>
Generating keys and certificates
Slot 9A: Authentication certificate
Generate a key in slot 9A and create a self-signed certificate for it. For client certificate authentication against your own services, a self-signed certificate is sufficient since your own CA will be signing the certificates used in production. This self-signed certificate is a placeholder that allows the slot to be used immediately.
# Generate the key
ykman piv keys generate \
--algorithm ECCP384 \
--pin-policy once \
--touch-policy always \
9A /tmp/9a-public.pem
# Create a self-signed certificate
ykman piv certificates generate \
--subject "CN=Your Name,OU=Authentication" \
9A /tmp/9a-public.pem
The --pin-policy once setting requires the PIN once per session rather than for every operation. --touch-policy always requires a physical touch for every cryptographic operation using this slot. Both are the recommended settings for an authentication certificate.
Clean up the temporary public key file:
rm /tmp/9a-public.pem
Verify the certificate is loaded:
ykman piv info
Slot 9A should now show the certificate details.
Importing a CA-signed certificate
Once your CA (covered in the CA section of this series) has issued a client certificate, import it into slot 9A to replace the self-signed one. You need the certificate file but not the private key, since the key was generated on the card and never left it.
ykman piv certificates import 9A /path/to/signed-client.cert.pem
Using PIV for SSH via PKCS#11
PIV slot 9A can be used for SSH authentication via the PKCS#11 interface, as an alternative to the GPG agent approach covered earlier. This is useful for systems where you want SSH authentication tied to the PIV certificate rather than the GPG authentication subkey, or for SSH clients that do not integrate with the GPG agent.
First, find the OpenSC PKCS#11 module path:
dpkg -L opensc | grep pkcs11
It is typically at /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so.
Extract the SSH public key from the PIV certificate:
ssh-keygen -D /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so
This outputs the SSH public key corresponding to the certificate in slot 9A. Copy this to authorized_keys on the target server.
To connect using PIV authentication:
ssh -I /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so user@server
Or add it to ~/.ssh/config for permanent use with specific hosts:
Host server.yourdomain.net
PKCS11Provider /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so
SSH will prompt for the PIV PIN and require a touch (if touch policy is enabled) for each connection.
Preventing KDE from enforcing smartcard login
The source material this series draws on includes commands to disable GNOME’s automatic smartcard-only login enforcement. On Kubuntu with KDE Plasma and SDDM, this behaviour is not the default and the GNOME commands do not apply.
However, if you install opensc and pcscd, some configurations may trigger KDE or SDDM to offer smartcard login as an option. If the login screen starts behaving unexpectedly after installing these packages, check the SDDM configuration:
cat /etc/sddm.conf
And verify that no third-party PAM configuration has added smartcard requirements to the SDDM PAM stack:
cat /etc/pam.d/sddm
If you see references to pam_pkcs11.so that you did not add intentionally, remove them.
Managing PIV with Kleopatra
Kleopatra, covered in the GPG Tools section, also handles PIV smartcard operations. Insert the Yubikey and open Kleopatra. Navigate to Tools > Manage Smartcards to view the PIV slots, check certificate status, and perform basic management operations through the GUI rather than the command line.
Kleopatra is particularly useful for viewing what is currently loaded on the card without having to remember ykman piv info syntax.
Checking PIV status
At any point, check the full PIV status of the card:
ykman piv info
This shows all four slots, whether keys and certificates are present, the PIN and PUK retry counters, and the management key algorithm.
To inspect a specific certificate in detail:
ykman piv certificates export 9A - | openssl x509 -noout -text
The PIV PIN and the OpenPGP PIN are separate credentials on the same Yubikey. Changing one does not affect the other. Three incorrect attempts for either blocks that specific interface. Keep both in KeePassXC and do not confuse them.