piv-agent is currently going through a heavy refactor: I am removing GnuPG support.
This is for several reasons, including:
- It is terribly complex, and its agent protocol moreso. The agent protocol is also poorly documented.
- Supporting it requires maintenance and several additional dependencies, including one that I had to fork.
- It has well-documented technical problems.
- I don't use it anymore.
To that end, I am planning the following release schedule for piv-agent:
- ✅
v1.xwill be released. It will supportagevia a plugin, in addition to SSH and GPG. - ✅
v2.xwill be released shortly afterv1.x, with GPG support totally removed. Active development will only occur onv2.x. - ⏳
v1.xwill be maintained for a short period (6 months). This is so that anyone else usingpiv-agenthas a chance to migrate away from GPG, or find another solution. - ⏳ When
v1.xmaintenance ends,v2.xcan be considered stable(ish).
Please test v2.x if you can, but be aware there may be breakage. In particular, the age plugin support is experimental: until this warning is removed, the identity format is unstable.
Discussion of this plan and updates happens here.
piv-agentis an SSH and age plugin agent providing simple integration of PIV hardware (e.g. a Yubikey) withssh, andageworkflows such asgitsigning andpassagepassword storage.piv-agentoriginated as a reimplementation of yubikey-agent because I needed some extra features, and also to gain a better understanding of the PIV applet on security key hardware.piv-agentmakes heavy use of the Go standard library and supplementarycryptopackages, as well aspiv-goandpcsclite. Thanks for the great software!
DISCLAIMER
I make no assertion about the security or otherwise of this software and I am not a cryptographer. If you are, please take a look at the code and send PRs or issues. 💚
piv-agent has a hard dependency on Linux and systemd.
At this time no other OS stack is supported.
- implements
ssh-agentfunctionality - classic cryptographic keys are generated on the hardware security key, rather than on your laptop
- secret keys never touch your hard drive
- implements an age plugin:
age-plugin-piv-agent - ML-KEM key seeds that are used in the
ageplugin are sealed by your TPM using systemd credentials- secret key seeds never touch your hard drive unencrypted
- support for multiple hardware security keys
- support for multiple slots in those keys
- support for multiple touch policies
- uses systemd socket activation
- as a result, automatically drop the transaction on the security key and cached passphrases after some period of disuse
- provides "fall-back" to traditional SSH key files
This agent should require no interaction and in general do the right thing when security keys are plugged/unplugged, laptop is power cycled, etc.
It is highly opinionated:
- Only supports 256-bit ECC keys (P-256) on hardware tokens for SSH
- Only supports ed25519 SSH keys on disk (
~/.ssh/id_ed25519) - Only supports the mlkem768p256tag identity/recipient type for age
- Requires socket activation
It tries to strike a balance between security and usability:
- Takes a persistent transaction on the hardware token, effectively caching the PIN.
- Caches passphrases for on-disk keys (i.e.
~/.ssh/id_ed25519) in memory, so these only need to be provided once after the agent starts. - After a period of inactivity it exits, dropping both the transaction and the passphrase. Socket activation restarts it automatically as required.
Tested with:
- YubiKey 5C, firmware versions 5.2.4, 5.7.1.
If you have tested another device or firmware version with piv-agent successfully, please send a PR adding it to this list.
| Supported | Not Supported |
|---|---|
| ✅ | ❌ |
| Security Key | Keyfile | |
|---|---|---|
| ecdsa-sha2-nistp256 | ✅ | ❌ |
| ssh-ed25519 | ❌ | ✅ |
piv-agent, and its age plugin age-plugin-piv-agent only support the mlkem768p256tag identity/recipient type.
Please see the documentation.
Install build dependencies:
# debian/ubuntu
sudo apt install libpcsclite-dev
make
This D-Bus variable is required for pinentry to use a graphical prompt:
go build ./cmd/piv-agent && systemd-socket-activate -l /tmp/piv-agent.sock -E DBUS_SESSION_BUS_ADDRESS ./piv-agent serve --debug
Then in another terminal:
export SSH_AUTH_SOCK=/tmp/piv-agent.sock
ssh ...
cd docs && make serve