← scratchings

YubiKey Cheat Sheet

Reference for ykman, sc_auth, yubico-piv-tool, and SSH/PKCS#11.


0. Prerequisites (macOS / Homebrew)

# Core CLI tools
brew install ykman                     # Yubico's main CLI (PIV, FIDO, OATH, OpenPGP, OTP)
brew install yubico-piv-tool           # Lower-level PIV CLI; also provides libykcs11.dylib for SSH

# Optional GUI
brew install --cask yubico-authenticator   # Replaces the deprecated YubiKey Manager GUI

# Only if you need it (note: can shadow native macOS PIV — see §4 troubleshooting)
brew install opensc                    # Provides opensc-pkcs11.so as alternative PKCS#11 lib

sc_auth, security, system_profiler, and openssl ship with macOS — no install needed.


1. ykman — overview & global

Command Purpose
ykman info Serial, firmware, applet status
ykman list Connected keys (multi-key setups)
ykman --device <serial> ... Target a specific key
ykman config usb Show enabled USB applets
ykman config usb -e FIDO2 / -d FIDO2 Enable / disable applet over USB
ykman config nfc Show / change enabled NFC applets

2. ykman piv — smart card (X.509)

Inventory

Command Purpose
ykman piv info Slots populated, PIN/PUK retries, mgmt key info
ykman piv keys info <slot> Key metadata for slot
ykman piv certificates export <slot> - Dump cert to stdout (PEM)

Access (PIN / PUK / mgmt key)

Command Purpose
ykman piv access change-pin Change user PIN (default 123456)
ykman piv access change-puk Change PUK (default 12345678)
ykman piv access unblock-pin Reset blocked PIN using PUK
ykman piv access change-management-key --protect --generate Random mgmt key, stored under PIN
ykman piv access set-retries N M Set PIN / PUK retry counts

Keys & certificates

Command Purpose
ykman piv keys generate <slot> --algorithm ECCP256 pub.pem Generate keypair on card
ykman piv certificates generate <slot> --subject "CN=foo" pub.pem Self-signed cert from on-card key
ykman piv certificates request <slot> --subject "CN=foo" pub.pem csr.pem Generate CSR
ykman piv certificates import <slot> cert.pem Import external cert
ykman piv keys import <slot> key.pem Import external private key (loses HW-gen guarantee)
ykman piv certificates delete <slot> Delete cert from slot
ykman piv reset Wipe entire PIV applet

Standard slot purposes

Slot Purpose Notes
9a PIV Authentication macOS login, SSH
9c Digital Signature Touch always required
9d Key Management Encryption / key agreement
9e Card Authentication No PIN required
82–95 Retired key management Historical decryption keys
f9 Attestation Yubico-signed attestation cert

3. ykman — other applets

FIDO2 / WebAuthn

Command Purpose
ykman fido info PIN status, credential count
ykman fido access change-pin Set / change FIDO2 PIN
ykman fido credentials list Discoverable (resident) credentials only
ykman fido credentials delete <id> Delete a resident credential
ykman fido reset Wipe FIDO2 — all credentials lost

OATH (TOTP / HOTP)

Command Purpose
ykman oath info Account count, password status
ykman oath accounts list List account names
ykman oath accounts code [name] Show current code(s)
ykman oath accounts add <name> <secret> Add from base32 secret
ykman oath accounts uri "otpauth://..." Add from otpauth URI
ykman oath accounts delete <name> Remove account
ykman oath access change Set / change OATH password

OpenPGP

Command Purpose
ykman openpgp info Keys present, PIN retries, touch policies
ykman openpgp access change-pin Change User PIN (default 123456)
ykman openpgp access change-admin-pin Change Admin PIN (default 12345678)
ykman openpgp keys set-touch <key> <policy> off / on / fixed / cached / cached-fixed
ykman openpgp reset Wipe OpenPGP applet

OTP (legacy 2-slot)

Command Purpose
ykman otp info Slot configuration status
ykman otp static <slot> Program static password
ykman otp chalresp <slot> <key> Program HMAC-SHA1 challenge-response
ykman otp delete <slot> Wipe a slot
ykman otp swap Swap slots 1 and 2

4. sc_auth — macOS smart card pairing

Native macOS CLI. Write operations require sudo.

Command Purpose
sc_auth identities List paired & unpaired identities visible to system
sudo sc_auth pair -u <user> -h <hash> Pair cert (use 9a hash, not 9d)
sudo sc_auth unpair -u <user> -h <hash> Unpair specific cert
sudo sc_auth unpair -u <user> Unpair all certs for user
sc_auth list -u <user> Show paired hashes for user
sc_auth pairing_ui -s status Is the auto-pair popup enabled?
sc_auth pairing_ui -s disable Suppress the popup
sc_auth verifypin Test PIN entry against the card

Get the 9a public-key hash directly from the card:

ykman piv certificates export 9a - | openssl x509 -pubkey -noout | \
  openssl pkey -pubin -outform DER | openssl dgst -sha1

Related macOS helpers: | Command | Purpose | |---|---| | security list-smartcards | Tokens visible to keychain | | system_profiler SPSmartCardsDataType | Detailed card / cert info | | sudo killall -HUP scardservicesd | Kick smart card daemon |


5. yubico-piv-tool — older / lower-level PIV tool

Equivalent to ykman piv with finer control. Useful when you need scriptable non-interactive flows or options ykman doesn't expose.

Command Purpose
yubico-piv-tool -a status Slot inventory
yubico-piv-tool -a verify-pin -P <pin> Verify PIN
yubico-piv-tool -a change-pin -P <old> -N <new> Change PIN
yubico-piv-tool -a change-puk -P <old> -N <new> Change PUK
yubico-piv-tool -a set-mgm-key -n <hex> Set mgmt key
yubico-piv-tool -a generate -s 9a -A ECCP256 -o pub.pem Generate keypair
yubico-piv-tool -a selfsign -s 9a -S "/CN=foo/" -i pub.pem -o cert.pem Self-sign
yubico-piv-tool -a request-certificate -s 9a -S "/CN=foo/" -i pub.pem -o csr.pem CSR
yubico-piv-tool -a import-certificate -s 9a -i cert.pem Import cert
yubico-piv-tool -a import-key -s 9a -i key.pem Import private key
yubico-piv-tool -a read-certificate -s 9a Dump cert (PEM)
yubico-piv-tool -a delete-certificate -s 9a Delete cert
yubico-piv-tool -a attest -s 9a Attestation cert for slot
yubico-piv-tool -a reset Wipe PIV (only after PIN + PUK both blocked)

Common flags: -a action · -s slot · -A algorithm (RSA1024 / RSA2048 / ECCP256 / ECCP384) · -P PIN · -k mgmt key (hex; omit for default) · -r reader name (multi-card).


6. SSH with YubiKey (PKCS#11)

Library paths (macOS / Homebrew)

On Apple Silicon brew --prefix is /opt/homebrew; on Intel it's /usr/local.

Display the public key (for authorized_keys)

Via PKCS#11 (all keys on the card, in OpenSSH format):

ssh-keygen -D $(brew --prefix)/lib/libykcs11.dylib

Output is one OpenSSH pubkey per slot. The 9a entry is what you want for login auth — copy that line into the target server's ~/.ssh/authorized_keys.

Pin it to slot 9a only (skip 9c/9d/9e noise):

ssh-keygen -D $(brew --prefix)/lib/libykcs11.dylib | head -1

Directly from the cert (no PKCS#11 lib needed):

ykman piv certificates export 9a - | ssh-keygen -i -m PKCS8 -f /dev/stdin

Add a comment so you can identify the key on the server:

echo "$(ssh-keygen -D $(brew --prefix)/lib/libykcs11.dylib | head -1) yubikey-$(ykman info | awk '/Serial/ {print $NF}')"

Push it to a server in one shot:

ssh-keygen -D $(brew --prefix)/lib/libykcs11.dylib | head -1 | \
  ssh user@host 'cat >> ~/.ssh/authorized_keys'

One-shot connection test

ssh -I $(brew --prefix)/lib/libykcs11.dylib user@host

~/.ssh/config — global

Host *
    PKCS11Provider /opt/homebrew/lib/libykcs11.dylib
    AddKeysToAgent yes
    IdentitiesOnly yes

~/.ssh/config — scoped

Host *.tripoli.systems
    PKCS11Provider /opt/homebrew/lib/libykcs11.dylib
    IdentitiesOnly yes
    User odd

Host github.com
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes

ssh-agent (per session)

ssh-add -s /opt/homebrew/lib/libykcs11.dylib   # load YubiKey into agent
ssh-add -e /opt/homebrew/lib/libykcs11.dylib   # remove it
ssh-add -L                                      # list loaded keys

7. Common workflows

First-time PIV setup for macOS login

ykman piv access change-pin
ykman piv access change-puk
ykman piv access change-management-key --protect --generate

ykman piv keys generate 9a --algorithm ECCP256 /tmp/9a.pub
ykman piv certificates generate 9a --subject "CN=$(whoami) PIV Auth" /tmp/9a.pub

ykman piv keys generate 9d --algorithm ECCP256 /tmp/9d.pub
ykman piv certificates generate 9d --subject "CN=$(whoami) Key Mgmt" /tmp/9d.pub

HASH=$(ykman piv certificates export 9a - | openssl x509 -pubkey -noout | \
       openssl pkey -pubin -outform DER | openssl dgst -sha1 | awk '{print $NF}')

sudo sc_auth pair -u "$(whoami)" -h "$HASH"
rm /tmp/9a.pub /tmp/9d.pub

Backup key (mirror configuration)

Repeat the entire PIV setup on a second YubiKey, then pair its own 9a hash with sc_auth pair. Each key holds independent keypairs; both pairings coexist for the same user.

Recover from blocked PIN

ykman piv access unblock-pin     # uses PUK
# If PUK is also blocked:
ykman piv reset                  # wipes PIV applet — redo setup

Inspect current pairing state

sc_auth list -u "$(whoami)"
sc_auth identities
security list-smartcards

8. Default secrets (change immediately)

Applet Field Default
PIV PIN 123456
PIV PUK 12345678
PIV Management Key 010203040506070801020304050607080102030405060708
OpenPGP User PIN 123456
OpenPGP Admin PIN 12345678
FIDO2 PIN (unset; set on first use)

9. Multi-account GitHub with one YubiKey

GitHub treats SSH auth keys as globally unique — the same pubkey can't be added to two accounts. Other YubiKey features have no such restriction.

Per-feature behavior

Feature Multiple accounts? Notes
WebAuthn 2FA Register the same key on each account
Passkeys One discoverable slot per account (~25 on YubiKey 5)
SSH authentication ✗ shared key Pubkey must be unique per account
SSH commit signing Same signing key allowed across accounts
GPG commit signing Same signing key allowed across accounts

application= lets one physical YubiKey hold independent SSH keys. The string must start with ssh:.

ssh-keygen -t ed25519-sk -O resident -O application=ssh:github-personal \
  -f ~/.ssh/id_personal_sk

ssh-keygen -t ed25519-sk -O resident -O application=ssh:github-work \
  -f ~/.ssh/id_work_sk

-O resident stores them on the key so you can recover with ssh-keygen -K on a fresh machine.

Add ~/.ssh/id_personal_sk.pub to your personal account, id_work_sk.pub to work. Then:

Host github-personal
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_personal_sk
    IdentitiesOnly yes

Host github-work
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_work_sk
    IdentitiesOnly yes

Clone with git@github-personal:me/repo.git or git@github-work:org/repo.git.

Option B — Distinct PIV slots

If you're already using PIV for macOS login, reuse that infrastructure. Avoid slot 9c for SSH — its spec-mandated "always" PIN policy means re-entering the PIN per operation. Retired slots 82–95 are a better fit.

# Personal — slot 9a (already in use for macOS login)
# Work — use a retired slot
ykman piv keys generate 82 --algorithm ECCP256 \
  --pin-policy ONCE --touch-policy CACHED /tmp/82.pub
ykman piv certificates generate 82 --subject "CN=github-work" /tmp/82.pub

Extract each pubkey and pin it per host. Save them to disk first, since PKCS#11 keys aren't files:

ssh-keygen -D $(brew --prefix)/lib/libykcs11.dylib > ~/.ssh/yk-all.pub
# Identify which line is which slot by subject CN, then split into per-account .pub files

Then in ~/.ssh/config:

Host github-personal
    HostName github.com
    User git
    PKCS11Provider /opt/homebrew/lib/libykcs11.dylib
    IdentityFile ~/.ssh/yk-9a.pub
    IdentitiesOnly yes

Host github-work
    HostName github.com
    User git
    PKCS11Provider /opt/homebrew/lib/libykcs11.dylib
    IdentityFile ~/.ssh/yk-82.pub
    IdentitiesOnly yes

Without IdentitiesOnly yes + IdentityFile, the SSH client offers every slot on the card — wastes auth attempts and may pick the wrong account.