piv-go is a Go module and CLI for working with PIV (Personal Identity Verification) smart cards over PC/SC. It provides a layered library for ISO 7816 and PIV operations, vendor-aware adapters for common tokens, and a task-oriented piv command-line interface.
The repository is intended for developers and operators who need to inspect tokens, read and manage certificates, verify or rotate credentials, generate keys, and run targeted diagnostics without dropping to raw APDU tooling unless they choose to.
- Go packages for ISO 7816 APDU/TLV handling, PIV commands, PC/SC transport, emulator flows, and vendor adapters.
- A
pivCLI for reader discovery, token inspection, certificate and key operations, credential workflows, and diagnostics. - Built-in vendor adapters for SafeNet/eToken and YubiKey PIV tokens.
- Emulator-backed tests for core library and CLI flows.
pcsc/implements the PC/SC transport layer and isolates directscardcalls.iso7816/implements APDU encoding, response parsing, status handling, and BER-TLV utilities.piv/implements the PIV protocol client and high-level token operations.adapters/contains vendor-neutral helpers and vendor-specific adapters.emulator/contains emulator-backed support used in tests and diagnostics.cmd/piv/contains the public CLI.
Additional public documentation:
- Go 1.25 or newer.
- A PC/SC runtime and a compatible reader driver.
- A PIV-capable token for real device operations.
Platform notes:
- macOS: the PC/SC framework is available as part of the operating system.
- Linux: install
pcsc-lite, the development headers (libpcsclite-devon Debian/Ubuntu), andpkg-configbefore building. - Windows: install the vendor reader driver and ensure the Smart Card service is enabled.
The transport layer depends on github.com/ebfe/scard, so missing PC/SC headers or runtime services will break builds or runtime discovery even if the Go toolchain is installed correctly.
go build ./...
go test ./...
go vet ./...Run the CLI directly from the module root:
go run ./cmd/piv --helpDiscover readers and detect whether a token is PIV-ready:
go run ./cmd/piv devicesInspect the selected token:
go run ./cmd/piv info --reader "YubiKey 5C NFC"
go run ./cmd/piv slot list --reader "YubiKey 5C NFC"Export public artifacts:
go run ./cmd/piv cert export auth --reader "YubiKey 5C NFC" --out auth-cert.pem
go run ./cmd/piv key public auth --reader "YubiKey 5C NFC" --out auth-pub.pemRun safe diagnostics before attempting a mutation:
go run ./cmd/piv doctor --reader "YubiKey 5C NFC" --with-selectUse machine-readable output when automating:
go run ./cmd/piv info --reader "YubiKey 5C NFC" --jsonSee docs/CLI.md for the full command map, output conventions, and destructive-operation guidance.
package main
import (
"fmt"
"log"
"github.com/PeculiarVentures/piv-go/pcsc"
"github.com/PeculiarVentures/piv-go/piv"
)
func main() {
ctx, err := pcsc.NewContext()
if err != nil {
log.Fatal(err)
}
defer ctx.Release()
card, err := ctx.Connect("YubiKey 5C NFC")
if err != nil {
log.Fatal(err)
}
defer card.Close()
client := piv.NewClient(card)
if err := client.Select(); err != nil {
log.Fatal(err)
}
certDER, err := client.GetCertificate(piv.SlotAuthentication)
if err != nil {
log.Fatal(err)
}
fmt.Printf("authentication certificate is %d bytes\n", len(certDER))
}When building signing flows, prefer resolving key metadata and deriving the
authorization policy before calling Sign(...). This keeps VERIFY PIN
handling explicit at the application layer. The following fragment assumes you
already resolved an adapter runtime, prepared the digest, and obtained the PIN
value from your own application logic:
metadata, err := adapters.ResolveKeyMetadata(runtime, piv.SlotSignature)
if err != nil {
log.Fatal(err)
}
policy := adapters.DeriveSignAuthorization(metadata)
if policy.RequiresPIN() || !policy.IsKnown() {
if err := runtime.Session.Client.VerifyPIN(pin); err != nil {
log.Fatal(err)
}
}
signature, err := runtime.Session.Client.Sign(piv.AlgECCP256, piv.SlotSignature, digest)
if err != nil {
log.Fatal(err)
}
fmt.Printf("signature length: %d\n", len(signature))- Real hardware operations can be destructive. Review
setup,mgm,key delete,key generate, andcert deletecommands before using them on a live token. - SafeNet and YubiKey support includes vendor-specific handling for factory-default credentials and reset flows. Treat those defaults as onboarding aids for uninitialized devices, not as acceptable production settings.
- APDU tracing can capture credential material and token metadata. If you use
--traceor store debug output, keep it out of shell history, issue trackers, and public archives. - The emulator is useful for tests and smoke validation, but it is not a full replacement for vendor firmware behavior.
This project is licensed under the Apache License 2.0. See LICENSE.