piv

package
v0.0.0-...-91fa366 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 8, 2024 License: Apache-2.0 Imports: 26 Imported by: 0

Documentation

Overview

Package piv implements management functionality for the YubiKey PIV applet.

Index

Constants

View Source
const (
	// SignatureKey is at  offset 0.
	// 6E.73.C1.
	SignatureKey KeyType = 0

	// DecryptionKey is at  offset 1.
	// 6E.73.C2 .
	DecryptionKey KeyType = 1

	// AuthenticationKey is at offset 2.
	// 6E.73.C3 .
	AuthenticationKey KeyType = 2
	KeyTypeLast               = AuthenticationKey

	// AttestKey is specific to yubikeys.
	AttestKey KeyType = 3

	KeyTypeUnknown = 0xFF

	KeyTypeSize = int((KeyTypeLast + 1) * 2)
)
View Source
const (
	AsymmetricGenerateKey = 0 // 0x80
	AsymmetricReadKey     = 1 // 0x81
)
View Source
const (
	// SecureMessaging
	// https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.4.pdf Page 32.
	// 4.4.3.7 Extended Capabilities.
	// byte 1.
	SecureMessaging               = 0x80 // byte 1, bit8
	GetChallenge                  = 0x40 // byte 1, bit7
	KeyImport                     = 0x20 // byte 1, bit6
	PWStatusChangeable            = 0x10 // byte 1, bit5
	PrivateUseDOs                 = 0x08 // byte 1, bit4
	AlgorithmAttributesChangeable = 0x04 // byte 1, bit3
	PSODECENCwithAES              = 0x02 // byte 1, bit2
	KDFSupported                  = 0x01 // byte 1, bit1

	// MSECommandNotSupported
	// https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.4.pdf Page 33.
	// 4.4.3.7 Extended Capabilities.
	// byte 10 (0xA) MSE command for key numbers 2 (DEC) and 3 (AUT).
	MSECommandNotSupported = 0x00
	MSECommandSupported    = 0x01
)
View Source
const (
	FormfactorUSBAKeychain          = 0x1
	FormfactorUSBANano              = 0x2
	FormfactorUSBCKeychain          = 0x3
	FormfactorUSBCNano              = 0x4
	FormfactorUSBCLightningKeychain = 0x5

	FormfactorUSBAKeychainFIPS          = 0x81
	FormfactorUSBANanoFIPS              = 0x82
	FormfactorUSBCKeychainFIPS          = 0x83
	FormfactorUSBCNanoFIPS              = 0x84
	FormfactorUSBCLightningKeychainFIPS = 0x85
)

Formfactors recognized by this package. See the reference for more information: https://developers.yubico.com/yubikey-manager/Config_Reference.html#_form_factor

View Source
const (
	NameNotSet = "[not set]"
)

Variables

View Source
var (
	ErrTooShort            = errors.New("error data too short")
	ErrNoSuchTag           = errors.New("error no such tag found")
	ErrNoSuchAlgorithm     = errors.New("unable to get key algorithm")
	ErrUnknownKeyOrigin    = errors.New("unknown key origin")
	ErrUnknownKeyType      = errors.New("unknown key type")
	ErrKeyNotPresent       = errors.New("key not present")
	ErrNoPublicKeyModulus  = errors.New("crypto/rsa: missing public modulus")
	ErrNoPublicKeyExponent = errors.New("crypto/rsa: missing public exponent")
	ErrPublicExponentSmall = errors.New("crypto/rsa: public exponent too small")
	ErrPublicExponentLarge = errors.New("crypto/rsa: public exponent too large")
)
View Source
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

View Source
var (
	ErrApduMismatch       = errors.New("src != expected ")
	ErrApduBadInstruction = errors.New("src.instruction != expected.instruction ")
	ErrApduBadParam       = errors.New("src.param != expected.param ")
	ErrApduBadData        = errors.New("src.data != expected.data ")
)
View Source
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,
	}

	// DebugOpen can be set if you have an issue during the open calls and want to dump those apdu's.
	DebugOpen = false
)
View Source
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

func Cards() ([]string, error)

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

func ExportRsaPublicKeyAsPemStr

func ExportRsaPublicKeyAsPemStr(publicKey *rsa.PublicKey) (string, error)

func ParseCardHolderName

func ParseCardHolderName(name []byte) string

func ReadOrGenerateString

func ReadOrGenerateString(readOrGenerate int) string

func UpperCaseHexString

func UpperCaseHexString(d []byte) string

UpperCaseHexString is the same as hex.EncodeToString but all uppercase.

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 AsymmetricKeyType

type AsymmetricKeyType byte

AsymmetricKeyType is for determining the type of asymmetric key to create. CRT fields for generating key pairs. https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.4.pdf Page 74 7.2.14 GENERATE ASYMMETRIC KEY PAIR.

const (
	AsymmetricDigitalSignature AsymmetricKeyType = iota
	AsymmetricConfidentiality
	AsymmetricAuthentication
	AsymmetricDigitalSignatureExt
	AsymmetricConfidentialityExt
	AsymmetricAuthenticationExt
	AsymmetricKeyTypeLast = AsymmetricAuthenticationExt
)

func (AsymmetricKeyType) KeyType

func (k AsymmetricKeyType) KeyType() KeyType

func (AsymmetricKeyType) String

func (k AsymmetricKeyType) String() string

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).

func (AuthErr) Error

func (v AuthErr) Error() string

type Client

type Client struct {
	SCConstruct SCConstructor
	// contains filtered or unexported fields
}

func (Client) Cards

func (c Client) Cards() ([]string, error)

func (Client) Open

func (c Client) Open(card string) (*YubiKey, error)

func (*Client) OpenGPG

func (c *Client) OpenGPG(card string) (*GPGYubiKey, error)

OpenGPG connects to a YubiKey OpenGPG smart card.

type ClientInterface

type ClientInterface interface {
	OpenGPG(card string) (*GPGYubiKey, error)
	Cards() ([]string, error)
	Open(card string) (*YubiKey, error)
}

ClientInterface wraps client.

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 (and FIPS variants for these).

func (Formfactor) String

func (f Formfactor) String() string

String returns the human-readable description for the given form-factor value, or a fallback value for any other, unknown form-factor.

type GPGYubiKey

type GPGYubiKey struct {
	// contains filtered or unexported fields
}

func NewTestGpgYubikey

func NewTestGpgYubikey(gpgData *GpgData, trace bool, origins map[KeyType]KeyOrigin) *GPGYubiKey

NewTestGpgYubikey is for testing.

func OpenGPG

func OpenGPG(card string) (*GPGYubiKey, error)

OpenGPG connects to a YubiKey OpenGPG smart card.

func (*GPGYubiKey) AppletVersion

func (yk *GPGYubiKey) AppletVersion() (string, error)

AppletVersion returns the version of the applet.

func (*GPGYubiKey) AuthPIN

func (yk *GPGYubiKey) AuthPIN(pin []byte) error

AuthPIN attempts to authenticate against the card with the provided PIN. The PIN is required to use and modify certain slots.

After a specific number of authentication attempts with an invalid PIN, usually 3, the PIN will become block and refuse further attempts. At that point the PUK must be used to unblock the PIN.

Use DefaultPIN if the PIN hasn't been set. FIXME: this only makes calls against PW2, might have to check PW1 and PW3 for some use cases.

func (*GPGYubiKey) CardHolder

func (yk *GPGYubiKey) CardHolder() (string, error)

CardHolder returns the Cardholder of the key.

func (*GPGYubiKey) Close

func (yk *GPGYubiKey) Close() error

func (*GPGYubiKey) Decrypt

func (yk *GPGYubiKey) Decrypt(data []byte) ([]byte, error)

func (*GPGYubiKey) DisableDebug

func (yk *GPGYubiKey) DisableDebug()

func (*GPGYubiKey) DisableTrace

func (yk *GPGYubiKey) DisableTrace()

func (*GPGYubiKey) EnableDebug

func (yk *GPGYubiKey) EnableDebug()

func (*GPGYubiKey) EnableTrace

func (yk *GPGYubiKey) EnableTrace()

func (*GPGYubiKey) GPGData

func (yk *GPGYubiKey) GPGData() (*GpgData, error)

GPGData returns the GpgData if it was opened in GPG mode.

func (*GPGYubiKey) GenerateKey

func (yk *GPGYubiKey) GenerateKey(keyType AsymmetricKeyType) (*rsa.PublicKey, error)

GenerateKey generates key on the yubikey and returns the public key portion. https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.4.pdf Page 74. 7.2.14 GENERATE ASYMMETRIC KEY PAIR.

func (*GPGYubiKey) GetAttestationCert

func (yk *GPGYubiKey) GetAttestationCert(keyType KeyType) ([]byte, error)

func (*GPGYubiKey) ReadPublicKey

func (yk *GPGYubiKey) ReadPublicKey(keyType AsymmetricKeyType) (*rsa.PublicKey, error)

ReadPublicKey returns the public Key stored in the yubikey. https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.4.pdf Page 74. 7.2.14 GENERATE ASYMMETRIC KEY PAIR.

func (*GPGYubiKey) ReadPublicKeyWithOrigin

func (yk *GPGYubiKey) ReadPublicKeyWithOrigin(keyType AsymmetricKeyType, requestedOrigin KeyOrigin) (*rsa.PublicKey, error)

ReadPublicKeyWithOrigin returns the public Key stored in the yubikey only if it originates from the requested place. Origin is Generated or Imported. https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.4.pdf Page 74. 7.2.14 GENERATE ASYMMETRIC KEY PAIR.

func (*GPGYubiKey) Serial

func (yk *GPGYubiKey) Serial() (uint32, error)

Serial returns the YubiKey's serial number. this is odd. ykman list will show hex output of this. if you are comparing to ykman list, you want to use: fmt.Sprintf("%X%02X%02X%02X", (serial & 0xff000000) >> 24), (serial & 0x00ff0000) >> 16), (serial & 0x0000ff00) >> 8), (serial & 0x000000ff)).

func (*GPGYubiKey) SerialString

func (yk *GPGYubiKey) SerialString() (string, error)

SerialString returns the YubiKey's serial number.

func (*GPGYubiKey) String

func (yk *GPGYubiKey) String() string

func (*GPGYubiKey) Version

func (yk *GPGYubiKey) Version() (string, error)

Version returns the version of the key.

type GpgData

type GpgData struct {

	// SecureMessagingAlgorithm the type of secure messaging supported.
	// https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.4.pdf Page 33
	// 4.4.3.7 Extended Capabilities.
	// byte 1 SecureMessagingSupported.
	SecureMessagingSupported bool
	// GetChallengeSupported Support for GET CHALLENGE
	// The maximum supported length of a challenge can be found in MaximumChallengeLength.
	GetChallengeSupported bool
	// Support for Key Import
	KeyImportSupported bool
	// PWStatusChangeable PW Status changeable (DO C4 available for PUT DATA)
	PWStatusChangeable bool
	// PrivateUseDOsSupported Support for Private use DOs (0101-0104)
	PrivateUseDOsSupported bool
	// AlgorithmAttributesChangeable Algorithm attributes changeable with PUT DATA
	AlgorithmAttributesChangeable bool
	// SupportsPSODecryptionEncryptionWithAES PSO:DEC/ENC with AES
	SupportsPSODecryptionEncryptionWithAES bool
	// KDF-DO (F9) and related functionality avail- able
	KDFSupported bool

	// PinBlock2Supported
	// https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.4.pdf Page 33.
	// 4.4.3.7 Extended Capabilities.
	// byte 9 PIN block 2 format.
	PinBlock2Supported bool

	// MSECommandSupported
	// https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.4.pdf Page 33.
	// 4.4.3.7 Extended Capabilities.
	// byte 10 (0xA) MSE command for key numbers 2 (DEC) and 3 (AUT).
	MSECommandSupported bool

	// SerialInt is an integer of the serial number.
	SerialInt uint32
	// Serial is a hex string of the serial number as displayed by ykman list.
	Serial      string
	LongName    string
	CardHolder  string
	Rid         string
	Application string
	Version     string
	// https://developers.yubico.com/ykneo-openpgp/SecurityAdvisory%202015-04-14.html
	AppletVersion                       string
	Manufacturer                        string
	Reader                              string
	SecureMessaging                     SecureMessagingAlgorithm
	MaximumChallengeLength              uint16
	MaximumCardholderCertificatesLength uint16
	MaximumSpecialDOsLength             uint16
	// contains filtered or unexported fields
}

GpgData holds data about the GPG functionality of the card.

func (*GpgData) Algorithm

func (g *GpgData) Algorithm(keyType KeyType) (string, error)

Algorithm returns the Algorithm of the key at index.

def keyalg(card, n):
   ka = card.tv[f'6E.73.C{n+1}']
   if 1 <= ka[0] <= 3:		# RSA
	   return f'RSA {ka[1]*256+ka[2]}'
   else:
	   return f'Alg={ka[0]:<4d}'

func (*GpgData) Copy

func (g *GpgData) Copy(src *GpgData)

func (*GpgData) Date

func (g *GpgData) Date(keyType KeyType) (time.Time, error)

Date returns the Date of the key at index.

def keydate(card, n):
   kd = card.tv['6E.73.CD'][n*4:n*4+4]
   timestamp = (kd[0]<<24)|(kd[1]<<16)|(kd[2]<<8)|kd[3]
   return datetime.fromtimestamp(timestamp)		# TODO fix time zone

func (*GpgData) DumpTLV

func (g *GpgData) DumpTLV() string

func (*GpgData) Fingerprint

func (g *GpgData) Fingerprint(keyType KeyType) (string, error)

Fingerprint returns the Fingerprint of the key at index.

def keyfingerprint(card, n):
   kf = card.tv['6E.73.C5'][n*20:n*20+20]
   return ''.join(f'{x:02X}' for x in kf)

func (*GpgData) GetAppletVersion

func (g *GpgData) GetAppletVersion() string

GetAppletVersion returns the version of the applet.

func (*GpgData) GetCardHolder

func (g *GpgData) GetCardHolder() string

GetCardHolder returns the Cardholder of the key.

func (*GpgData) GetTag

func (g *GpgData) GetTag(key string, expectedLen int) ([]byte, error)

GetTag will get the results from a tag. if expectedLen is >0 it will verify the length.

func (*GpgData) GetVersion

func (g *GpgData) GetVersion() string

GetVersion returns the version of the key.

func (*GpgData) HasTag

func (g *GpgData) HasTag(key string) (int, bool)

HasTag will check if a tag exists and return the length.

func (*GpgData) ID

func (g *GpgData) ID(keyType KeyType) (string, error)

ID returns the ID of the key at index. ID is the last 8 bytes of the fingerprint.

def keyid(card, n):
   kf = card.tv['6E.73.C5'][n*20:n*20+20]
   return ''.join(f'{x:02X}' for x in kf[-8:])

func (*GpgData) Origin

func (g *GpgData) Origin(keyType KeyType) (KeyOrigin, error)

Origin returns the Origin of the key at index.

def keyorigin(card, n):
   if '6E.73.DE' in card.tv:
	   return (['empty    ','generated','imported '])[card.tv['6E.73.DE'][2*n+1]]
   else:
	   return ''

func (*GpgData) String

func (g *GpgData) String() (string, error)

String makes a GpgData struct readable.

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/areese/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 KeyInfo

type KeyInfo struct {
	Algorithm   Algorithm
	PINPolicy   PINPolicy
	TouchPolicy TouchPolicy
	Origin      Origin
	PublicKey   crypto.PublicKey
}

KeyInfo holds unprotected metadata about a key slot.

type KeyOrigin

type KeyOrigin byte

KeyOrigin is for determining the Origin of a key. https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.4.pdf Page 24 4.4.1 DOs for GET DATA. Application Related Data. 6E.73.DE == Key Information.

const (
	KeyNotPresent      KeyOrigin = 0
	KeyGeneratedByCard KeyOrigin = 1
	KeyImportedToCard  KeyOrigin = 2
	KeyOriginLast                = KeyImportedToCard
	// KeyOriginAny allows a key of any origin.
	KeyOriginAny = 3
)

func (KeyOrigin) String

func (k KeyOrigin) String() string

type KeyType

type KeyType byte

KeyType is for indexing the keys from a yubikey. https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.4.pdf Page 24 4.4.1 DOs for GET DATA. Application Related Data. 6E.73.DE == Key Information.

func KeyTypeFromString

func KeyTypeFromString(s string) KeyType

func (KeyType) Offset

func (k KeyType) Offset() int

func (KeyType) String

func (k KeyType) String() string

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 Origin

type Origin int

Origin represents whether a key was generated on the hardware, or has been imported into it.

const (
	OriginGenerated Origin = iota + 1
	OriginImported
)

Origins supported by this package.

type PCSCConstructor

type PCSCConstructor struct{}

func (*PCSCConstructor) NewSCContext

func (p *PCSCConstructor) NewSCContext() (SCContext, error)

nolint:ireturn

func (*PCSCConstructor) String

func (p *PCSCConstructor) String() string

type PCSCContext

type PCSCContext struct {
	// contains filtered or unexported fields
}

func (*PCSCContext) Close

func (p *PCSCContext) Close() error

func (*PCSCContext) Connect

func (p *PCSCContext) Connect(reader string) (SCHandle, error)

nolint:ireturn

func (*PCSCContext) ListReaders

func (p *PCSCContext) ListReaders() ([]string, error)

func (*PCSCContext) String

func (p *PCSCContext) String() string

type PCSCHandle

type PCSCHandle struct {
	// contains filtered or unexported fields
}

func (*PCSCHandle) Begin

func (p *PCSCHandle) Begin() (SCTx, error)

nolint:ireturn

func (*PCSCHandle) Close

func (p *PCSCHandle) Close() error

func (*PCSCHandle) String

func (p *PCSCHandle) String() string

type PCSCTx

type PCSCTx struct {
	// contains filtered or unexported fields
}

func (*PCSCTx) Close

func (p *PCSCTx) Close() error

func (*PCSCTx) DisableDebug

func (p *PCSCTx) DisableDebug()

func (*PCSCTx) EnableDebug

func (p *PCSCTx) EnableDebug()

func (*PCSCTx) IsDebugEnabled

func (p *PCSCTx) IsDebugEnabled() bool

func (*PCSCTx) String

func (p *PCSCTx) String() string

func (*PCSCTx) Transmit

func (p *PCSCTx) Transmit(d apdu) ([]byte, error)

func (*PCSCTx) TransmitBytes

func (p *PCSCTx) TransmitBytes(req []byte) (more bool, b []byte, err error)

type PINPolicy

type PINPolicy int

PINPolicy represents PIN requirements when signing or decrypting with an asymmetric key in a given slot.

const (
	PINPolicyNever PINPolicy = iota + 1
	PINPolicyOnce
	PINPolicyAlways
)

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 SCConstructor

type SCConstructor interface {
	NewSCContext() (SCContext, error)
}

SCConstructor is a constructor for SCContext.

type SCContext

type SCContext interface {
	Close() error
	Connect(reader string) (SCHandle, error)
	ListReaders() ([]string, error)
}

SCContext wraps scContext.

type SCHandle

type SCHandle interface {
	Begin() (SCTx, error)
	Close() error
}

SCHandle wraps scHandle.

type SCTx

type SCTx interface {
	Close() error
	DisableDebug()
	EnableDebug()
	Transmit(d apdu) ([]byte, error)
	TransmitBytes(req []byte) (more bool, b []byte, err error)
	IsDebugEnabled() bool
}

SCTx wraps scTx.

type SecureMessagingAlgorithm

type SecureMessagingAlgorithm byte

SecureMessagingAlgorithm the type of secure messaging supported. https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.4.pdf Page 33 4.4.3.7 Extended Capabilities.

const (
	// NoSecureMessaging No secure messaging or proprietary implementation.
	NoSecureMessaging SecureMessagingAlgorithm = 0
	// AES128bit AES 128 bit.
	AES128bit SecureMessagingAlgorithm = 1
	// AES256bit AES 256 bit.
	AES256bit SecureMessagingAlgorithm = 2
	// SCP11b SCP11b.
	SCP11b SecureMessagingAlgorithm = 3

	SecureMessagingAlgorithmLast = SCP11b
)

func (SecureMessagingAlgorithm) String

func (s SecureMessagingAlgorithm) String() string

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

func RetiredKeyManagementSlot(key uint32) (Slot, bool)

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)

https://developers.yubico.com/PIV/Introduction/Certificate_slots.html#_slot_82_95_retired_key_management

func (Slot) String

func (s Slot) String() string

String returns the two-character hex representation of the slot.

type TestSCConstructor

type TestSCConstructor struct {
	Ctx     TestSCContext
	OpenErr error
}

func (*TestSCConstructor) NewSCContext

func (p *TestSCConstructor) NewSCContext() (SCContext, error)

nolint:ireturn

func (*TestSCConstructor) String

func (p *TestSCConstructor) String() string

type TestSCContext

type TestSCContext struct {
	CloseErr error

	ConnectFunc    func(string) (SCHandle, error)
	Handle         SCHandle
	ConnectErr     error
	ListReadersErr error
	Readers        []string
}

func (*TestSCContext) Close

func (p *TestSCContext) Close() error

func (*TestSCContext) Connect

func (p *TestSCContext) Connect(reader string) (SCHandle, error)

nolint:ireturn

func (*TestSCContext) ListReaders

func (p *TestSCContext) ListReaders() ([]string, error)

func (*TestSCContext) SimpleConnect

func (p *TestSCContext) SimpleConnect(reader string) (SCHandle, error)

nolint:ireturn

func (*TestSCContext) String

func (p *TestSCContext) String() string

type TestSCHandle

type TestSCHandle struct {
	BeginErr error
	Ctx      SCTx
	CloseErr error
}

func (*TestSCHandle) Begin

func (p *TestSCHandle) Begin() (SCTx, error)

nolint:ireturn

func (*TestSCHandle) Close

func (p *TestSCHandle) Close() error

func (*TestSCHandle) String

func (p *TestSCHandle) String() string

type TestSCTx

type TestSCTx struct {
	CurrentAPDUIndex  int
	APDUList          []apdu
	ResponseList      [][]byte
	CloseErr          error
	TransmitData      []byte
	TransmitErr       []error
	TransmitBytesMore bool
	TransmitBytesData []byte
	TransmitBytesErr  error
}

func (*TestSCTx) Close

func (p *TestSCTx) Close() error

func (*TestSCTx) DisableDebug

func (p *TestSCTx) DisableDebug()

func (*TestSCTx) EnableDebug

func (p *TestSCTx) EnableDebug()

func (*TestSCTx) IsDebugEnabled

func (p *TestSCTx) IsDebugEnabled() bool

func (*TestSCTx) String

func (p *TestSCTx) String() string

func (*TestSCTx) Transmit

func (p *TestSCTx) Transmit(d apdu) ([]byte, error)

func (*TestSCTx) TransmitBytes

func (p *TestSCTx) TransmitBytes(req []byte) (more bool, b []byte, err error)

func (*TestSCTx) VerifyAPDU

func (p *TestSCTx) VerifyAPDU(d apdu) ([]byte, error)

VerifyAPDU is to ensure that the apdu's are sent in an expected order.

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 Verifier

type Verifier struct {
	// Root certificates to use to validate challenges. If nil, this defaults to Yubico's
	// CA bundle.
	//
	// https://developers.yubico.com/PIV/Introduction/PIV_attestation.html
	// https://developers.yubico.com/PIV/Introduction/piv-attestation-ca.pem
	// https://developers.yubico.com/U2F/yubico-u2f-ca-certs.txt
	Roots *x509.CertPool
}

Verifier allows specifying options when verifying attestations produced by YubiKeys.

func (*Verifier) Verify

func (v *Verifier) Verify(attestationCert, slotCert *x509.Certificate) (*Attestation, error)

Verify proves that a key was generated on a YubiKey.

As opposed to the package level Verify, it uses any options enabled on the Verifier.

type Version

type Version struct {
	Major int
	Minor int
	Patch int
}

Version encodes a major, minor, and patch version.

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 Open

func Open(card string) (*YubiKey, error)

Open connects to a YubiKey PIV smart card.

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) Certificate

func (yk *YubiKey) Certificate(slot Slot) (*x509.Certificate, error)

Certificate returns the certificate object stored in a given slot.

If a certificate hasn't been set in the provided slot, the returned error wraps ErrNotFound.

func (*YubiKey) Close

func (yk *YubiKey) Close() error

Close releases the connection to the smart card.

func (*YubiKey) DisableDebug

func (yk *YubiKey) DisableDebug()

DisableDebug will stop dumping the contents of every apdu to console.

func (*YubiKey) EnableDebug

func (yk *YubiKey) EnableDebug()

EnableDebug will cause the contents of every apdu to be dumped to console until DisableDebug is called.

func (*YubiKey) GenerateKey

func (yk *YubiKey) GenerateKey(key [24]byte, slot Slot, opts Key) (crypto.PublicKey, error)

GenerateKey generates an asymmetric key on the card, returning the key's public key.

func (*YubiKey) KeyInfo

func (yk *YubiKey) KeyInfo(slot Slot) (KeyInfo, error)

KeyInfo returns public information about the given key slot. It is only supported by YubiKeys with a version >= 5.3.0.

func (*YubiKey) Metadata

func (yk *YubiKey) Metadata(pin string) (*Metadata, error)

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

func (yk *YubiKey) Reset() error

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

func (yk *YubiKey) Retries() (int, error)

Retries returns the number of attempts remaining to enter the correct PIN.

func (*YubiKey) Serial

func (yk *YubiKey) Serial() (uint32, error)

Serial returns the YubiKey's serial number.

func (*YubiKey) SetCertificate

func (yk *YubiKey) SetCertificate(key [24]byte, slot Slot, cert *x509.Certificate) error

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

func (yk *YubiKey) SetManagementKey(oldKey, newKey [24]byte) error

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

func (yk *YubiKey) SetMetadata(key [24]byte, m *Metadata) error

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 separately.

func (*YubiKey) SetPIN

func (yk *YubiKey) SetPIN(oldPIN, newPIN string) error

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

func (yk *YubiKey) SetPUK(oldPUK, newPUK string) error

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 an 8 character PUK.
newPUKInt, err := rand.Int(rand.Reader, big.NewInt(100_000_000))
if err != nil {
	// ...
}
// Format with leading zeros.
newPUK := fmt.Sprintf("%08d", newPUKInt)
if err := yk.SetPUK(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) String

func (yk *YubiKey) String() string

func (*YubiKey) Unblock

func (yk *YubiKey) Unblock(puk, newPIN string) error

Unblock unblocks the PIN, setting it to a new value.

func (*YubiKey) VerifyPIN

func (yk *YubiKey) VerifyPIN(pin string) error

VerifyPIN attempts to authenticate against the card with the provided PIN.

PIN authentication for other operations are handled separately, and VerifyPIN does not need to be called before those methods.

After a specific number of authentication attempts with an invalid PIN, usually 3, the PIN will become block and refuse further attempts. At that point the PUK must be used to unblock the PIN.

Use DefaultPIN if the PIN hasn't been set.

func (*YubiKey) Version

func (yk *YubiKey) Version() 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/areese/piv-go/issues/60

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL