Skip to content

Commit

Permalink
Drop support for versions of Go lower than 1.20
Browse files Browse the repository at this point in the history
This commit removes the code to support Go 1.16 to 1.19, requiring now
Go 1.20. With this requirement we can remove the build tags.

It also renames the X25519 SharedKey to ECDH.
  • Loading branch information
maraino authored and ericchiang committed Oct 3, 2024
1 parent 2c985a1 commit 12c06a0
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 328 deletions.
2 changes: 1 addition & 1 deletion v2/go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module github.com/go-piv/piv-go/v2

go 1.16
go 1.20
93 changes: 85 additions & 8 deletions v2/piv/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -1006,9 +1006,13 @@ func (yk *YubiKey) PrivateKey(slot Slot, public crypto.PublicKey, auth KeyAuth)
return &keyEd25519{yk, slot, pub, auth, pp}, nil
case *rsa.PublicKey:
return &keyRSA{yk, slot, pub, auth, pp}, nil
case *ecdh.PublicKey:
if crv := pub.Curve(); crv != ecdh.X25519() {
return nil, fmt.Errorf("unsupported ecdh curve: %v", crv)
}
return &X25519PrivateKey{yk, slot, pub, auth, pp}, nil
default:
// Add support for X25519 keys using build tags
return yk.tryX25519PrivateKey(slot, public, auth, pp)
return nil, fmt.Errorf("unsupported public key type: %T", public)
}
}

Expand Down Expand Up @@ -1087,13 +1091,17 @@ func (yk *YubiKey) SetPrivateKeyInsecure(key []byte, slot Slot, private crypto.P
privateKey := make([]byte, elemLen)
copy(privateKey, priv[:32])
params = append(params, privateKey)
default:
// Add support for X25519 keys using build tags
var err error
params, paramTag, elemLen, err = yk.tryX22519PrivateKeyInsecure(private)
if err != nil {
return err
case *ecdh.PrivateKey:
if crv := priv.Curve(); crv != ecdh.X25519() {
return fmt.Errorf("unsupported ecdh curve: %v", crv)
}
paramTag = 0x08
elemLen = 32

// seed
params = append(params, priv.Bytes())
default:
return fmt.Errorf("unsupported private key type: %T", private)
}

elemLenASN1 := marshalASN1Length(uint64(elemLen))
Expand Down Expand Up @@ -1250,6 +1258,33 @@ func (k *ECDSAPrivateKey) ECDH(peer *ecdh.PublicKey) ([]byte, error) {
})
}

// X25519PrivateKey is a crypto.PrivateKey implementation for X25519 keys. It
// implements the method ECDH to perform Diffie-Hellman key agreements.
//
// Keys returned by YubiKey.PrivateKey() may be type asserted to
// *X25519PrivateKey, if the slot contains an X25519 key.
type X25519PrivateKey struct {
yk *YubiKey
slot Slot
pub *ecdh.PublicKey
auth KeyAuth
pp PINPolicy
}

func (k *X25519PrivateKey) Public() crypto.PublicKey {
return k.pub
}

// ECDH performs an ECDH exchange and returns the shared secret.
//
// Peer's public key must use the same algorithm as the key in this slot, or an
// error will be returned.
func (k *X25519PrivateKey) ECDH(peer *ecdh.PublicKey) ([]byte, error) {
return k.auth.do(k.yk, k.pp, func(tx *scTx) ([]byte, error) {
return ykECDHX25519(tx, k.slot, k.pub, peer)
})
}

type keyEd25519 struct {
yk *YubiKey
slot Slot
Expand Down Expand Up @@ -1335,6 +1370,38 @@ func ykSignECDSA(tx *scTx, slot Slot, pub *ecdsa.PublicKey, digest []byte) ([]by
return rs, nil
}

func ykECDHX25519(tx *scTx, slot Slot, pub *ecdh.PublicKey, peer *ecdh.PublicKey) ([]byte, error) {
if crv := pub.Curve(); crv != ecdh.X25519() {
return nil, fmt.Errorf("unsupported ecdh curve: %v", crv)
}
if pub.Curve() != peer.Curve() {
return nil, errMismatchingAlgorithms
}
cmd := apdu{
instruction: insAuthenticate,
param1: algX25519,
param2: byte(slot.Key),
data: marshalASN1(0x7c,
append([]byte{0x82, 0x00},
marshalASN1(0x85, peer.Bytes())...)),
}
resp, err := tx.Transmit(cmd)
if err != nil {
return nil, fmt.Errorf("command failed: %w", err)
}

sig, _, err := unmarshalASN1(resp, 1, 0x1c) // 0x7c
if err != nil {
return nil, fmt.Errorf("unmarshal response: %v", err)
}
sharedSecret, _, err := unmarshalASN1(sig, 2, 0x02) // 0x82
if err != nil {
return nil, fmt.Errorf("unmarshal response signature: %v", err)
}

return sharedSecret, nil
}

// This function only works on SoloKeys prototypes and other PIV devices that choose
// to implement Ed25519 signatures under alg 0x22.
func skSignEd25519(tx *scTx, slot Slot, pub ed25519.PublicKey, digest []byte) ([]byte, error) {
Expand Down Expand Up @@ -1432,6 +1499,16 @@ func decodeRSAPublic(b []byte) (*rsa.PublicKey, error) {
return &rsa.PublicKey{N: &n, E: int(e.Int64())}, nil
}

func decodeX25519Public(b []byte) (*ecdh.PublicKey, error) {
// Adaptation of
// https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-73-4.pdf#page=95
p, _, err := unmarshalASN1(b, 2, 0x06)
if err != nil {
return nil, fmt.Errorf("unmarshal points: %v", err)
}
return ecdh.X25519().NewPublicKey(p)
}

func rsaAlg(pub *rsa.PublicKey) (byte, error) {
size := pub.N.BitLen()
switch size {
Expand Down
115 changes: 0 additions & 115 deletions v2/piv/key_go120.go

This file was deleted.

120 changes: 0 additions & 120 deletions v2/piv/key_go120_test.go

This file was deleted.

Loading

0 comments on commit 12c06a0

Please sign in to comment.