Skip to content

Commit

Permalink
Add dynamic support for AES128/192/256 management keys, including set…
Browse files Browse the repository at this point in the history
…ting them. Prefer AES192 over 3DES when possible.

Update supportsVersion to use *version and bytes instead of Version and ints to eliminate a lot of unnecessary calls to .Version()
  • Loading branch information
Quantu authored and ericchiang committed Jul 9, 2024
1 parent df01a03 commit 6b1bedd
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 80 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ if err != nil {
The PIV applet has three unique credentials:

* Management key (3DES key) used to generate new keys on the YubiKey.
* YubiKey firmware 5.4.0+ adds support for AES128/192/256 keys
* PIN (up to 8 digits, usually 6) used to access signing operations.
* PUK (up to 8 digits) used to unblock the PIN. Usually set once and thrown
away or managed by an administrator.
Expand Down Expand Up @@ -103,7 +104,7 @@ newPIN := fmt.Sprintf("%06d", newPINInt)
newPUK := fmt.Sprintf("%08d", newPUKInt)

// Set all values to a new value.
if err := yk.SetManagementKey(piv.DefaultManagementKey, newKey); err != nil {
if err := yk.SetManagementKey(piv.DefaultManagementKey, newKey[:]); err != nil {
// ...
}
if err := yk.SetPUK(piv.DefaultPUK, newPUK); err != nil {
Expand All @@ -113,8 +114,8 @@ if err := yk.SetPIN(piv.DefaultPIN, newPIN); err != nil {
// ...
}
// Store management key on the YubiKey.
m := piv.Metadata{ManagementKey: &newKey}
if err := yk.SetMetadata(newKey, m); err != nil {
m := piv.Metadata{ManagementKey: &newKey[:]}
if err := yk.SetMetadata(newKey[:], m); err != nil {
// ...
}

Expand Down
14 changes: 7 additions & 7 deletions v2/piv/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -743,8 +743,8 @@ func marshalASN1(tag byte, data []byte) []byte {
// 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 (yk *YubiKey) SetCertificate(key [24]byte, slot Slot, cert *x509.Certificate) error {
if err := ykAuthenticate(yk.tx, key, yk.rand); err != nil {
func (yk *YubiKey) SetCertificate(key []byte, slot Slot, cert *x509.Certificate) error {
if err := ykAuthenticate(yk.tx, key, yk.rand, yk.version); err != nil {
return fmt.Errorf("authenticating with management key: %w", err)
}
return ykStoreCertificate(yk.tx, slot, cert)
Expand Down Expand Up @@ -797,8 +797,8 @@ type Key struct {

// GenerateKey generates an asymmetric key on the card, returning the key's
// public key.
func (yk *YubiKey) GenerateKey(key [24]byte, slot Slot, opts Key) (crypto.PublicKey, error) {
if err := ykAuthenticate(yk.tx, key, yk.rand); err != nil {
func (yk *YubiKey) GenerateKey(key []byte, slot Slot, opts Key) (crypto.PublicKey, error) {
if err := ykAuthenticate(yk.tx, key, yk.rand, yk.version); err != nil {
return nil, fmt.Errorf("authenticating with management key: %w", err)
}
return ykGenerateKey(yk.tx, slot, opts)
Expand Down Expand Up @@ -926,7 +926,7 @@ func (k KeyAuth) do(yk *YubiKey, pp PINPolicy, f func(tx *scTx) ([]byte, error))
}

func pinPolicy(yk *YubiKey, slot Slot) (PINPolicy, error) {
if supportsVersion(yk.Version(), 5, 3, 0) {
if supportsVersion(yk.version, 5, 3, 0) {
info, err := yk.KeyInfo(slot)
if err != nil {
return 0, fmt.Errorf("get key info: %v", err)
Expand Down Expand Up @@ -1005,7 +1005,7 @@ func (yk *YubiKey) PrivateKey(slot Slot, public crypto.PublicKey, auth KeyAuth)
// 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 (yk *YubiKey) SetPrivateKeyInsecure(key [24]byte, slot Slot, private crypto.PrivateKey, policy Key) error {
func (yk *YubiKey) SetPrivateKeyInsecure(key []byte, slot Slot, private crypto.PrivateKey, policy Key) error {
// Reference implementation
// https://github.com/Yubico/yubico-piv-tool/blob/671a5740ef09d6c5d9d33f6e5575450750b58bde/lib/ykpiv.c#L1812

Expand Down Expand Up @@ -1073,7 +1073,7 @@ func (yk *YubiKey) SetPrivateKeyInsecure(key [24]byte, slot Slot, private crypto
tags = append(tags, param...)
}

if err := ykAuthenticate(yk.tx, key, yk.rand); err != nil {
if err := ykAuthenticate(yk.tx, key, yk.rand, yk.version); err != nil {
return fmt.Errorf("authenticating with management key: %w", err)
}

Expand Down
2 changes: 1 addition & 1 deletion v2/piv/key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ func TestPINPrompt(t *testing.T) {
}

func supportsAttestation(yk *YubiKey) bool {
return supportsVersion(yk.Version(), 4, 3, 0)
return supportsVersion(yk.version, 4, 3, 0)
}

func TestSlots(t *testing.T) {
Expand Down
Loading

0 comments on commit 6b1bedd

Please sign in to comment.