{"id":25161508,"url":"https://github.com/cunicu/go-piv","last_synced_at":"2025-07-10T16:05:19.752Z","repository":{"id":199145182,"uuid":"702164483","full_name":"cunicu/go-piv","owner":"cunicu","description":"A Go implementation of the PIV standards for smart card certificate management","archived":false,"fork":false,"pushed_at":"2024-12-23T06:40:50.000Z","size":516,"stargazers_count":3,"open_issues_count":5,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2024-12-23T07:28:50.016Z","etag":null,"topics":["go","golang","piv","smart-card"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"go-piv/piv-go","license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cunicu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-10-08T17:22:17.000Z","updated_at":"2024-12-23T06:40:28.000Z","dependencies_parsed_at":"2023-12-04T02:30:32.162Z","dependency_job_id":"f483c26a-f393-4a5b-9d0e-20405374acd7","html_url":"https://github.com/cunicu/go-piv","commit_stats":null,"previous_names":["cunicu/go-piv"],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cunicu%2Fgo-piv","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cunicu%2Fgo-piv/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cunicu%2Fgo-piv/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cunicu%2Fgo-piv/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cunicu","download_url":"https://codeload.github.com/cunicu/go-piv/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":237897685,"owners_count":19383727,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","golang","piv","smart-card"],"created_at":"2025-02-09T02:35:21.996Z","updated_at":"2025-02-09T02:35:24.448Z","avatar_url":"https://github.com/cunicu.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!--\n  SPDX-FileCopyrightText: 2020 Google LLC\n  SPDX-FileCopyrightText: 2023-2024 Steffen Vogel \u003cpost@steffenvogel.de\u003e\n  SPDX-License-Identifier: Apache-2.0\n--\u003e\n\n# go-piv: A Go implementation of the PIV standards for smart card certificate management\n\n[![GitHub build](https://img.shields.io/github/actions/workflow/status/cunicu/go-piv/build.yaml?style=flat-square)](https://github.com/cunicu/go-piv/actions)\n[![goreportcard](https://goreportcard.com/badge/github.com/cunicu/go-piv?style=flat-square)](https://goreportcard.com/report/github.com/cunicu/go-piv)\n[![Codecov](https://img.shields.io/codecov/c/github/cunicu/go-piv?token=ou12ZLpDEr\u0026style=flat-square)](https://app.codecov.io/gh/cunicu/go-piv)\n[![License](https://img.shields.io/github/license/cunicu/go-piv?style=flat-square)](https://github.com/cunicu/go-piv/blob/main/LICENSE)\n![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/cunicu/go-piv?style=flat-square)\n[![Go Reference](https://pkg.go.dev/badge/github.com/cunicu/go-piv.svg)](https://pkg.go.dev/github.com/cunicu/go-piv)\n\nYubiKeys provide an applet implementing the [PIV standards](https://csrc.nist.gov/projects/piv/piv-standards-and-supporting-documentation) for managing certificates on a smart card.\nThis applet is a simpler alternative to GPG for managing asymmetric keys on a YubiKey.\n\nThis package is an alternative to Paul Tagliamonte's [go-ykpiv](https://github.com/paultag/go-ykpiv),\na wrapper for YubiKey's `ykpiv.h` C library. This package aims to provide:\n\n* Better error messages\n* Idiomatic Go APIs\n* Modern features such as PIN protected management keys\n\nThis package is a fork from [`github.com/go-piv/piv-go`](https://github.com/go-piv/piv-go) with the following changes:\n\n* Replacement of in-repo PCSC bindings with [`github.com/ebfe/scard`](https://github.com/ebfe/scard).\n* Improved CI tests, linting and repository structure.\n* Made repository [REUSE](https://reuse.software) compliant.\n* Removal of Google's CLA.\n\n## Examples\n\n* [Signing](#signing)\n* [PINs](#pins)\n* [Certificates](#certificates)\n* [Attestation](#attestation)\n\n### Signing\n\nThe piv-go package can be used to generate keys and store certificates on a\nYubiKey. This uses a management key to generate new keys on the applet, and a\nPIN for signing operations. The package provides default PIN values. If the PIV\ncredentials on the YubiKey haven't been modified, the follow code generates a\nnew EC key on the smart card, and provides a signing interface:\n\n```go\n// List all smart cards connected to the system.\ncards, err := piv.Cards()\nif err != nil {\n    // ...\n}\n\n// Find a YubiKey and open the reader.\nvar c *piv.Card\nfor _, card := range cards {\n    if strings.Contains(strings.ToLower(card), \"yubikey\") {\n        if c, err = piv.Open(card); err != nil {\n            // ...\n        }\n        break\n    }\n}\n\nif c == nil {\n    // ...\n}\n\n// Generate a private key on the YubiKey.\nkey := piv.Key{\n    Algorithm:   piv.AlgorithmEC256,\n    PINPolicy:   piv.PINPolicyAlways,\n    TouchPolicy: piv.TouchPolicyAlways,\n}\n\npub, err := c.GenerateKey(piv.DefaultManagementKey, piv.SlotAuthentication, key)\nif err != nil {\n    // ...\n}\n\nauth := piv.KeyAuth{PIN: piv.DefaultPIN}\npriv, err := c.PrivateKey(piv.SlotAuthentication, pub, auth)\nif err != nil {\n    // ...\n}\n// Use private key to sign or decrypt.\n```\n\n### PINs\n\nThe PIV applet has three unique credentials:\n\n* Management key (3DES key) used to generate new keys on the YubiKey.\n* PIN (up to 8 digits, usually 6) used to access signing operations.\n* PUK (up to 8 digits) used to unblock the PIN. Usually set once and thrown\n  away or managed by an administrator.\n\npiv-go implements PIN protected management keys to store the management key on\nthe YubiKey. This allows users to only provide a PIN and still access management\ncapabilities.\n\nThe following code generates new, random credentials for a YubiKey:\n\n```go\nnewPINInt, err := rand.Int(rand.Reader, big.NewInt(1_000_000))\nif err != nil {\n    // ...\n}\n\nnewPUKInt, err := rand.Int(rand.Reader, big.NewInt(100_000_000))\nif err != nil {\n    // ...\n}\n\nvar newKey ManagementKey\nif _, err := io.ReadFull(rand.Reader, newKey[:]); err != nil {\n    // ...\n}\n\n// Format with leading zeros.\nnewPIN := fmt.Sprintf(\"%06d\", newPINInt)\nnewPUK := fmt.Sprintf(\"%08d\", newPUKInt)\n\n// Set all values to a new value.\nif err := c.SetManagementKey(piv.DefaultManagementKey, newKey); err != nil {\n    // ...\n}\n\nif err := c.SetPUK(piv.DefaultPUK, newPUK); err != nil {\n    // ...\n}\n\nif err := c.SetPIN(piv.DefaultPIN, newPIN); err != nil {\n    // ...\n}\n\n// Store management key on the YubiKey.\nm := piv.Metadata{ManagementKey: \u0026newKey}\nif err := c.SetMetadata(newKey, m); err != nil {\n    // ...\n}\n\nfmt.Println(\"Credentials set. Your PIN is: %s\", newPIN)\n```\n\nThe user can use the PIN later to fetch the management key:\n\n```go\nm, err := c.Metadata(pin)\nif err != nil {\n    // ...\n}\n\nif m.ManagementKey == nil {\n    // ...\n}\n\nkey := *m.ManagementKey\n```\n\n### Certificates\n\nThe PIV applet can also store X.509 certificates on the YubiKey:\n\n```go\ncert, err := x509.ParseCertificate(certDER)\nif err != nil {\n    // ...\n}\n\nif err := c.SetCertificate(managementKey, piv.SlotAuthentication, cert); err != nil {\n    // ...\n}\n```\n\nThe certificate can later be used in combination with the private key. For\nexample, to serve TLS traffic:\n\n```go\ncert, err := c.Certificate(piv.SlotAuthentication)\nif err != nil {\n    // ...\n}\n\npriv, err := c.PrivateKey(piv.SlotAuthentication, cert.PublicKey, auth)\nif err != nil {\n    // ...\n}\n\ns := \u0026http.Server{\n    TLSConfig: \u0026tls.Config{\n        Certificates: []tls.Certificate{\n            {\n                Certificate: [][]byte{cert.Raw},\n                PrivateKey:  priv,\n            },\n        },\n    },\n    Handler: myHandler,\n}\n```\n\n### Attestation\n\nYubiKeys can attest that a particular key was generated on the smart card, and\nthat it was set with specific PIN and touch policies. The client generates a\nkey, then asks the YubiKey to sign an attestation certificate:\n\n```go\n// Get the YubiKey's attestation certificate, which is signed by Yubico.\nyubiKeyAttestationCert, err := c.AttestationCertificate()\nif err != nil {\n    // ...\n}\n\n// Generate a key on the YubiKey and generate an attestation certificate for\n// that key. This will be signed by the YubiKey's attestation certificate.\nkey := piv.Key{\n    Algorithm:   piv.AlgorithmEC256,\n    PINPolicy:   piv.PINPolicyAlways,\n    TouchPolicy: piv.TouchPolicyAlways,\n}\nif _, err := c.GenerateKey(managementKey, piv.SlotAuthentication, key); err != nil {\n    // ...\n}\nslotAttestationCertificate, err := c.Attest(piv.SlotAuthentication)\nif err != nil {\n    // ...\n}\n\n// Send certificates to server.\n```\n\nA CA can then verify the attestation, proving a key was generated on the card\nand enforce policy:\n\n```go\n// Server receives both certificates, then proves a key was generated on the\n// YubiKey.\na, err := piv.Verify(yubiKeyAttestationCert, slotAttestationCertificate)\nif err != nil {\n    // ...\n}\nif a.TouchPolicy != piv.TouchPolicyAlways {\n    // ...\n}\n\n// Record YubiKey's serial number and public key.\npub := slotAttestationCertificate.PublicKey\nserial := a.Serial\n```\n\n## Installation\n\nOn MacOS, piv-go doesn't require any additional packages.\n\nTo build on Linux, piv-go requires PCSC lite.\nTo install on Debian-based distributions, run:\n\n### Debian, Ubuntu\n\n```shell\nsudo apt-get install libpcsclite-dev\n```\n\n### RHEL, Fedora, Rocky Linux\n\n```shell\nsudo yum install pcsc-lite-devel\n```\n\n### FreeBSD\n\n```shell\nsudo pkg install pcsc-lite\n```\n\n### Windows\n\nNo prerequisites are needed. The default driver by Microsoft supports all functionalities\nwhich get tested by unit tests. However if you run into problems try the official\n[YubiKey Smart Card Minidriver](https://www.yubico.com/products/services-software/download/smart-card-drivers-tools/).\nYubico states on their website the driver adds [_additional smart functionality_](https://www.yubico.com/authentication-standards/smart-card/).\n\nPlease notice the following:\n\n\u003e Windows support is best effort due to lack of test hardware. This means the maintainers will take patches for Windows, but if you encounter a bug or the build is broken, you may be asked to fix it.\n\n## Non-YubiKey smart cards\n\nNon-YubiKey smart cards that implement the PIV standard are not officially supported due to a lack of test hardware. However, PRs that fix integrations with other smart cards are welcome, and piv-go will attempt to not break that support.  \n\n## Testing\n\nTests automatically find connected available YubiKeys, but won't modify the\nsmart card without the `TEST_DANGEROUS_WIPE_REAL_CARD=1` environment variable is set. To let the tests modify your\nYubiKey's PIV applet, run:\n\n```shell\nTEST_DANGEROUS_WIPE_REAL_CARD=1 go test -v ./piv\n```\n\nLonger tests can be skipped with the `--test.short` flag.\n\n```shell\nTEST_DANGEROUS_WIPE_REAL_CARD=1  go test -v --short ./piv\n```\n\n## Why?\n\nYubiKey's C PIV library, ykpiv, is brittle. The error messages aren't terrific,\nand while it has debug options, plumbing them through isn't idiomatic or\nconvenient.\n\nykpiv wraps PC/SC APIs available on Windows, Mac, and Linux. There's no\nrequirement for it to be written in any particular langauge. As an alternative\nto [pault.ag/go/ykpiv][go-ykpiv] this package re-implements ykpiv in Go instead\nof calling it.\n\n## Authors\n\ngo-piv has been forked from [go-piv/piv-go](https://github.com/go-piv/piv-go) at commit [8c3a0ff](https://github.com/go-piv/piv-go/commit/8c3a0ffe023df2a9e11cb82a2e3292ae285549a2)\n\n* Eric Chiang ([@ericchiang](https://github.com/ericchiang))\n* Steffen Vogel ([@stv0g](https://github.com/stv0g))\n\n## Contact\n\nPlease have a look at the contact page: [cunicu.li/docs/contact](https://cunicu.li/docs/contact).\n\n## License\n\ngo-piv is licensed under the [Apache 2.0](./LICENSE) license.\n\n* SPDX-FileCopyrightText: 2020 Google LLC\n* SPDX-FileCopyrightText: 2023-2024 Steffen Vogel \u003cpost@steffenvogel.de\u003e\n* SPDX-License-Identifier: Apache-2.0\n\n[go-ykpiv]: https://github.com/paultag/go-ykpiv\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcunicu%2Fgo-piv","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcunicu%2Fgo-piv","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcunicu%2Fgo-piv/lists"}