Documentation ¶
Overview ¶
Package piv implements management functionality for the YubiKey PIV applet.
Index ¶
- Constants
- Variables
- func Cards() ([]string, error)
- type Algorithm
- type Attestation
- type AuthErr
- type CardID
- type ECDSAPrivateKey
- type Formfactor
- type Key
- type KeyAuth
- type Metadata
- type PINPolicy
- type Slot
- type TouchPolicy
- type Version
- type YubiKey
- func (yk *YubiKey) Attest(slot Slot) (*x509.Certificate, error)
- func (yk *YubiKey) AttestationCertificate() (*x509.Certificate, error)
- func (yk *YubiKey) CardID() (*CardID, error)
- func (yk *YubiKey) Certificate(slot Slot) (*x509.Certificate, error)
- func (yk *YubiKey) Close() error
- func (yk *YubiKey) GenerateKey(key [24]byte, slot Slot, opts Key) (crypto.PublicKey, error)
- func (yk *YubiKey) Metadata(pin string) (*Metadata, error)
- func (yk *YubiKey) PrivateKey(slot Slot, public crypto.PublicKey, auth KeyAuth) (crypto.PrivateKey, error)
- func (yk *YubiKey) Reset() error
- func (yk *YubiKey) Retries() (int, error)
- func (yk *YubiKey) Serial() (uint32, error)
- func (yk *YubiKey) SetCardID(key [24]byte, id *CardID) error
- func (yk *YubiKey) SetCertificate(key [24]byte, slot Slot, cert *x509.Certificate) error
- func (yk *YubiKey) SetManagementKey(oldKey, newKey [24]byte) error
- func (yk *YubiKey) SetMetadata(key [24]byte, m *Metadata) error
- func (yk *YubiKey) SetPIN(oldPIN, newPIN string) error
- func (yk *YubiKey) SetPUK(oldPUK, newPUK string) error
- func (yk *YubiKey) SetPrivateKeyInsecure(key [24]byte, slot Slot, private crypto.PrivateKey, policy Key) error
- func (yk *YubiKey) Unblock(puk, newPIN string) error
- func (yk *YubiKey) Version() Version
- Bugs
Constants ¶
const ( FormfactorUSBAKeychain = iota + 1 FormfactorUSBANano FormfactorUSBCKeychain FormfactorUSBCNano FormfactorUSBCLightningKeychain )
Formfactors recognized by this package.
Variables ¶
var ( SlotAuthentication = Slot{0x9a, 0x5fc105} SlotSignature = Slot{0x9c, 0x5fc10a} SlotCardAuthentication = Slot{0x9e, 0x5fc101} SlotKeyManagement = Slot{0x9d, 0x5fc10b} )
Slot combinations pre-defined by this package.
Object IDs are specified in NIST 800-73-4 section 4.3: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-73-4.pdf#page=30
Key IDs are specified in NIST 800-73-4 section 5.1: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-73-4.pdf#page=32
var ( // DefaultPIN for the PIV applet. The PIN is used to change the Management Key, // and slots can optionally require it to perform signing operations. DefaultPIN = "123456" // DefaultPUK for the PIV applet. The PUK is only used to reset the PIN when // the card's PIN retries have been exhausted. DefaultPUK = "12345678" // DefaultManagementKey for the PIV applet. The Management Key is a Triple-DES // key required for slot actions such as generating keys, setting certificates, // and signing. DefaultManagementKey = [24]byte{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, } )
var ErrNotFound = errors.New("data object or application not found")
ErrNotFound is returned when the requested object on the smart card is not found.
Functions ¶
func Cards ¶
Cards lists all smart cards available via PC/SC interface. Card names are strings describing the key, such as "Yubico Yubikey NEO OTP+U2F+CCID 00 00".
Card names depend on the operating system and what port a card is plugged into. To uniquely identify a card, use its serial number.
See: https://ludovicrousseau.blogspot.com/2010/05/what-is-in-pcsc-reader-name.html
Types ¶
type Algorithm ¶
type Algorithm int
Algorithm represents a specific algorithm and bit size supported by the PIV specification.
const ( AlgorithmEC256 Algorithm = iota + 1 AlgorithmEC384 AlgorithmEd25519 AlgorithmRSA1024 AlgorithmRSA2048 )
Algorithms supported by this package. Note that not all cards will support every algorithm.
AlgorithmEd25519 is currently only implemented by SoloKeys.
For algorithm discovery, see: https://github.com/ericchiang/piv-go/issues/1
type Attestation ¶
type Attestation struct { // Version of the YubiKey's firmware. Version Version // Serial is the YubiKey's serial number. Serial uint32 // Formfactor indicates the physical type of the YubiKey. // // Formfactor may be empty Formfactor(0) for some YubiKeys. Formfactor Formfactor // PINPolicy set on the slot. PINPolicy PINPolicy // TouchPolicy set on the slot. TouchPolicy TouchPolicy // Slot is the inferred slot the attested key resides in based on the // common name in the attestation. If the slot cannot be determined, // this field will be an empty struct. Slot Slot }
Attestation returns additional information about a key attested to be generated on a card. See https://developers.yubico.com/PIV/Introduction/PIV_attestation.html for more information.
func Verify ¶
func Verify(attestationCert, slotCert *x509.Certificate) (*Attestation, error)
Verify proves that a key was generated on a YubiKey. It ensures the slot and YubiKey certificate chains up to the Yubico CA, parsing additional information out of the slot certificate, such as the touch and PIN policies of a key.
type AuthErr ¶
type AuthErr struct { // Retries is the number of retries remaining if this error resulted from a retriable // authentication attempt. If the authentication method is blocked or does not support // retries, this will be 0. Retries int }
AuthErr is an error indicating an authentication error occurred (wrong PIN or blocked).
type CardID ¶
type CardID struct { GUID [16]byte // contains filtered or unexported fields }
CardID is the Card Holder Unique Identifier with settable GUID Raw contains the whole object GUID contains the Card Universally Unique Identifier.
type ECDSAPrivateKey ¶
type ECDSAPrivateKey struct {
// contains filtered or unexported fields
}
ECDSAPrivateKey is a crypto.PrivateKey implementation for ECDSA keys. It implements crypto.Signer and the method SharedKey performs Diffie-Hellman key agreements.
Keys returned by YubiKey.PrivateKey() may be type asserted to *ECDSAPrivateKey, if the slot contains an ECDSA key.
func (*ECDSAPrivateKey) Public ¶
func (k *ECDSAPrivateKey) Public() crypto.PublicKey
Public returns the public key associated with this private key.
func (*ECDSAPrivateKey) SharedKey ¶
func (k *ECDSAPrivateKey) SharedKey(peer *ecdsa.PublicKey) ([]byte, error)
SharedKey performs a Diffie-Hellman key agreement with the peer to produce a shared secret key.
Peer's public key must use the same algorithm as the key in this slot, or an error will be returned.
Length of the result depends on the types and sizes of the keys used for the operation. Callers should use a cryptographic key derivation function to extract the amount of bytes they need.
func (*ECDSAPrivateKey) Sign ¶
func (k *ECDSAPrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error)
Sign implements crypto.Signer.
type Formfactor ¶
type Formfactor int
Formfactor enumerates the physical set of forms a key can take. USB-A vs. USB-C and Keychain vs. Nano.
type Key ¶
type Key struct { // Algorithm to use when generating the key. Algorithm Algorithm // PINPolicy for the key. // // BUG(ericchiang): some older YubiKeys (third generation) will silently // drop this value. If PINPolicyNever or PINPolicyOnce is supplied but the // key still requires a PIN every time, you may be using a buggy key and // should supply PINPolicyAlways. See https://github.com/go-piv/piv-go/issues/60 PINPolicy PINPolicy // TouchPolicy for the key. TouchPolicy TouchPolicy }
Key is used for key generation and holds different options for the key.
While keys can have default PIN and touch policies, this package currently doesn't support this option, and all fields must be provided.
type KeyAuth ¶
type KeyAuth struct { // PIN, if provided, is a static PIN used to authenticate against the key. // If provided, PINPrompt is ignored. PIN string // PINPrompt can be used to interactively request the PIN from the user. The // method is only called when needed. For example, if a key specifies // PINPolicyOnce, PINPrompt will only be called once per YubiKey struct. PINPrompt func() (pin string, err error) // PINPolicy can be used to specify the PIN caching strategy for the slot. If // not provided, this will be inferred from the attestation certificate. // // This field is required on older (<4.3.0) YubiKeys when using PINPrompt, // as well as for keys imported to the card. PINPolicy PINPolicy }
KeyAuth is used to authenticate against the YubiKey on each signing and decryption request.
type Metadata ¶
type Metadata struct { // ManagementKey is the management key stored directly on the YubiKey. ManagementKey *[24]byte // contains filtered or unexported fields }
Metadata holds protected metadata. This is primarily used by YubiKey manager to implement PIN protect management keys, storing management keys on the card guarded by the PIN.
type PINPolicy ¶
type PINPolicy int
PINPolicy represents PIN requirements when signing or decrypting with an asymmetric key in a given slot.
PIN policies supported by this package.
BUG(ericchiang): Caching for PINPolicyOnce isn't supported on YubiKey versions older than 4.3.0 due to issues with verifying if a PIN is needed. If specified, a PIN will be required for every operation.
type Slot ¶
type Slot struct { // Key is a reference for a key type. // // See: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-73-4.pdf#page=32 Key uint32 // Object is a reference for data object. // // See: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-73-4.pdf#page=30 Object uint32 }
Slot is a private key and certificate combination managed by the security key.
func RetiredKeyManagementSlot ¶
RetiredKeyManagementSlot provides access to "retired" slots. Slots meant for old Key Management keys that have been rotated. YubiKeys 4 and later support values between 0x82 and 0x95 (inclusive).
slot, ok := RetiredKeyManagementSlot(0x82) if !ok { // unrecognized slot } pub, err := yk.GenerateKey(managementKey, slot, key)
type TouchPolicy ¶
type TouchPolicy int
TouchPolicy represents proof-of-presence requirements when signing or decrypting with asymmetric key in a given slot.
const ( TouchPolicyNever TouchPolicy = iota + 1 TouchPolicyAlways TouchPolicyCached )
Touch policies supported by this package.
type YubiKey ¶
type YubiKey struct {
// contains filtered or unexported fields
}
YubiKey is an exclusive open connection to a YubiKey smart card. While open, no other process can query the given card.
To release the connection, call the Close method.
func (*YubiKey) Attest ¶
func (yk *YubiKey) Attest(slot Slot) (*x509.Certificate, error)
Attest generates a certificate for a key, signed by the YubiKey's attestation certificate. This can be used to prove a key was generate on a specific YubiKey.
This method is only supported for YubiKey versions >= 4.3.0. https://developers.yubico.com/PIV/Introduction/PIV_attestation.html
Certificates returned by this method MUST NOT be used for anything other than attestion or determining the slots public key. For example, the certificate is NOT suitable for TLS.
If the slot doesn't have a key, the returned error wraps ErrNotFound.
func (*YubiKey) AttestationCertificate ¶
func (yk *YubiKey) AttestationCertificate() (*x509.Certificate, error)
AttestationCertificate returns the YubiKey's attestation certificate, which is unique to the key and signed by Yubico.
func (*YubiKey) CardID ¶
CardID returns the card CHUID with the GUID extracted If the CHUID is not set, the returned error wraps ErrNotFound.
func (*YubiKey) Certificate ¶
func (yk *YubiKey) Certificate(slot Slot) (*x509.Certificate, error)
Certificate returns the certifiate object stored in a given slot.
If a certificate hasn't been set in the provided slot, the returned error wraps ErrNotFound.
func (*YubiKey) GenerateKey ¶
GenerateKey generates an asymmetric key on the card, returning the key's public key.
func (*YubiKey) Metadata ¶
Metadata returns protected data stored on the card. This can be used to retrieve PIN protected management keys.
func (*YubiKey) PrivateKey ¶
func (yk *YubiKey) PrivateKey(slot Slot, public crypto.PublicKey, auth KeyAuth) (crypto.PrivateKey, error)
PrivateKey is used to access signing and decryption options for the key stored in the slot. The returned key implements crypto.Signer and/or crypto.Decrypter depending on the key type.
If the public key hasn't been stored externally, it can be provided by fetching the slot's attestation certificate:
cert, err := yk.Attest(slot) if err != nil { // ... } priv, err := yk.PrivateKey(slot, cert.PublicKey, auth)
func (*YubiKey) Reset ¶
Reset resets the YubiKey PIV applet to its factory settings, wiping all slots and resetting the PIN, PUK, and Management Key to their default values. This does NOT affect data on other applets, such as GPG or U2F.
func (*YubiKey) Retries ¶
Retries returns the number of attempts remaining to enter the correct PIN.
func (*YubiKey) SetCertificate ¶
SetCertificate stores a certificate object in the provided slot. Setting a certificate isn't required to use the associated key for signing or decryption.
func (*YubiKey) SetManagementKey ¶
SetManagementKey updates the management key to a new key. Management keys are triple-des keys, however padding isn't verified. To generate a new key, generate 24 random bytes.
var newKey [24]byte if _, err := io.ReadFull(rand.Reader, newKey[:]); err != nil { // ... } if err := yk.SetManagementKey(piv.DefaultManagementKey, newKey); err != nil { // ... }
func (*YubiKey) SetMetadata ¶
SetMetadata sets PIN protected metadata on the key. This is primarily to store the management key on the smart card instead of managing the PIN and management key seperately.
func (*YubiKey) SetPIN ¶
SetPIN updates the PIN to a new value. For compatibility, PINs should be 1-8 numeric characters.
To generate a new PIN, use the crypto/rand package.
// Generate a 6 character PIN. newPINInt, err := rand.Int(rand.Reader, bit.NewInt(1_000_000)) if err != nil { // ... } // Format with leading zeros. newPIN := fmt.Sprintf("%06d", newPINInt) if err := yk.SetPIN(piv.DefaultPIN, newPIN); err != nil { // ... }
func (*YubiKey) SetPUK ¶
SetPUK updates the PUK to a new value. For compatibility, PUKs should be 1-8 numeric characters.
To generate a new PUK, use the crypto/rand package.
// Generate a 8 character PUK. newPUKInt, err := rand.Int(rand.Reader, bit.NewInt(100_000_000)) if err != nil { // ... } // Format with leading zeros. newPUK := fmt.Sprintf("%08d", newPUKInt) if err := yk.SetPIN(piv.DefaultPUK, newPUK); err != nil { // ... }
func (*YubiKey) SetPrivateKeyInsecure ¶
func (yk *YubiKey) SetPrivateKeyInsecure(key [24]byte, slot Slot, private crypto.PrivateKey, policy Key) error
SetPrivateKeyInsecure is an insecure method which imports a private key into the slot. Users should almost always use GeneratePrivateKey() instead.
Importing a private key breaks functionality provided by this package, including AttestationCertificate() and Attest(). There are no stability guarantees for other methods for imported private keys.
Keys generated outside of the YubiKey should not be considered hardware-backed, as there's no way to prove the key wasn't copied, exfiltrated, or replaced with malicious material before being imported.
func (*YubiKey) Version ¶
Version returns the version as reported by the PIV applet. For newer YubiKeys (>=4.0.0) this corresponds to the version of the YubiKey itself.
Older YubiKeys return values that aren't directly related to the YubiKey version. For example, 3rd generation YubiKeys report 1.0.X.
Notes ¶
Bugs ¶
Caching for PINPolicyOnce isn't supported on YubiKey versions older than 4.3.0 due to issues with verifying if a PIN is needed. If specified, a PIN will be required for every operation.
some older YubiKeys (third generation) will silently drop this value. If PINPolicyNever or PINPolicyOnce is supplied but the key still requires a PIN every time, you may be using a buggy key and should supply PINPolicyAlways. See https://github.com/go-piv/piv-go/issues/60