Reference for ykman, sc_auth, yubico-piv-tool, and SSH/PKCS#11.
# 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.
| 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 |
| 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) |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
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 |
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).
$(brew --prefix)/lib/libykcs11.dylib$(brew --prefix)/lib/opensc-pkcs11.soOn Apple Silicon brew --prefix is /opt/homebrew; on Intel it's /usr/local.
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'
ssh -I $(brew --prefix)/lib/libykcs11.dylib user@host
Host *
PKCS11Provider /opt/homebrew/lib/libykcs11.dylib
AddKeysToAgent yes
IdentitiesOnly yes
Host *.tripoli.systems
PKCS11Provider /opt/homebrew/lib/libykcs11.dylib
IdentitiesOnly yes
User odd
Host github.com
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
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
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
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.
ykman piv access unblock-pin # uses PUK
# If PUK is also blocked:
ykman piv reset # wipes PIV applet — redo setup
sc_auth list -u "$(whoami)"
sc_auth identities
security list-smartcards
| 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) |
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.
| 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.
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.