Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.22
FROM golang:1.25
# We need OpenSSL headers to build the simulator
RUN apt-get update && apt-get install -y \
libssl-dev \
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/google/go-tpm

go 1.22
go 1.25.0

require (
github.com/google/go-cmp v0.5.9
Expand Down
19 changes: 11 additions & 8 deletions legacy/tpm2/encoding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ package tpm2
import (
"bytes"
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/ecdh"
"crypto/rand"
"encoding/hex"
"reflect"
Expand Down Expand Up @@ -402,7 +401,11 @@ func TestEncodeTPMLPCRSelection(t *testing.T) {
}

func TestECCParamsEncodeDecode(t *testing.T) {
pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
pk, err := ecdh.P256().GenerateKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
X, Y, err := ECCBytes(pk.PublicKey())
if err != nil {
t.Fatal(err)
}
Expand All @@ -412,7 +415,7 @@ func TestECCParamsEncodeDecode(t *testing.T) {
Hash: AlgSHA1,
},
CurveID: CurveNISTP256,
Point: ECPoint{XRaw: pk.PublicKey.X.Bytes(), YRaw: pk.PublicKey.Y.Bytes()},
Point: ECPoint{XRaw: X, YRaw: Y},
}

buf, err := params.encode()
Expand All @@ -424,11 +427,11 @@ func TestECCParamsEncodeDecode(t *testing.T) {
t.Fatalf("decodeECCParams: %v", err)
}

if params.Point.X().Cmp(pk.PublicKey.X) != 0 {
t.Fatalf("the deserialized X(big.Int) from ECCParams didn't match the X(Int) generated by ecdsa. got: %+v\nwant: %+v", params.Point.X(), pk.PublicKey.X)
if !bytes.Equal(params.Point.X().Bytes(), X) {
t.Fatalf("the deserialized X(bytes[]) from ECCParams didn't match the X(bytes[]) generated by ecdsa. got: %+v\nwant: %+v", params.Point.XRaw, X)
}
if params.Point.Y().Cmp(pk.PublicKey.Y) != 0 {
t.Fatalf("the deserialized Y(big.Int) from ECCParams didn't match the Y(Int) generated by ecdsa. got: %+v\nwant: %+v", params.Point.Y(), pk.PublicKey.Y)
if !bytes.Equal(params.Point.Y().Bytes(), Y) {
t.Fatalf("the deserialized Y(bytes[]) from ECCParams didn't match the Y(bytes[]) generated by ecdsa. got: %+v\nwant: %+v", params.Point.YRaw, Y)
}
if params.Point.X().Cmp(got.Point.X()) != 0 {
t.Fatalf("the deserialized X(big.Int) from ECCParams after encode/decode didn't match the X(big.Int) before. got: %+v\nwant: %+v", got.Point.X(), params.Point.X())
Expand Down
48 changes: 43 additions & 5 deletions legacy/tpm2/structures.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package tpm2
import (
"bytes"
"crypto"
"crypto/ecdh"
"crypto/ecdsa"
"crypto/rsa"
"encoding/binary"
Expand Down Expand Up @@ -113,11 +114,16 @@ func (p Public) Key() (crypto.PublicKey, error) {
if !ok {
return nil, fmt.Errorf("can't map TPM EC curve ID 0x%x to Go elliptic.Curve value", p.ECCParameters.CurveID)
}
pubKey = &ecdsa.PublicKey{
X: p.ECCParameters.Point.X(),
Y: p.ECCParameters.Point.Y(),
Curve: curve,
}

// Create a buffer with the uncompressed ECC public key
data := make([]byte, 0, len(p.ECCParameters.Point.XRaw)+len(p.ECCParameters.Point.YRaw)+1)
// 0x04 denotes an uncompressed ECC key
// https://datatracker.ietf.org/doc/rfc5480/
data = append(data, 0x04)
data = append(data, p.ECCParameters.Point.XRaw...)
data = append(data, p.ECCParameters.Point.YRaw...)

return ecdsa.ParseUncompressedPublicKey(curve, data)
default:
return nil, fmt.Errorf("unsupported public key type 0x%x", p.Type)
}
Expand Down Expand Up @@ -265,6 +271,38 @@ func decodeRSAParams(in *bytes.Buffer) (*RSAParams, error) {
return &params, nil
}

// Code from tpm2/crypto.go
func elementLength(c ecdh.Curve) (int, error) {
switch c {
case ecdh.P256():
// crypto/internal/nistec/fiat.p256ElementLen
return 32, nil
case ecdh.P384():
// crypto/internal/nistec/fiat.p384ElementLen
return 48, nil
case ecdh.P521():
// crypto/internal/nistec/fiat.p521ElementLen
return 66, nil
default:
return 0, fmt.Errorf("unknown element length for curve: %v", c)
}
}

// ECCBytes returns an uncompressed ECC Point
func ECCBytes(pubKey *ecdh.PublicKey) ([]byte, []byte, error) {
b := pubKey.Bytes()
// 0x04 denotes an uncompressed ECC key
// https://datatracker.ietf.org/doc/rfc5480/
if len(b) == 0 || b[0] != 0x04 {
return nil, nil, fmt.Errorf("could not decode %x as an uncompressed point", b)
}
size, err := elementLength(pubKey.Curve())
if err != nil {
return nil, nil, fmt.Errorf("ECCPoint: %w", err)
}
return b[1 : size+1], b[size+1:], nil
}

// ECCParams represents parameters of an ECC key pair:
// both the TPMS_ECC_PARMS and the TPMS_ECC_POINT.
//
Expand Down
48 changes: 39 additions & 9 deletions legacy/tpm2/test/tpm2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,14 @@ func TestLoadExternalPublicKey(t *testing.T) {
if err != nil {
t.Fatal(err)
}
ecdhKey, err := pk.ECDH()
if err != nil {
t.Fatal(err)
}
X, Y, err := ECCBytes(ecdhKey.PublicKey())
if err != nil {
t.Fatal(err)
}
public := Public{
Type: AlgECC,
NameAlg: AlgSHA1,
Expand All @@ -596,12 +604,12 @@ func TestLoadExternalPublicKey(t *testing.T) {
Hash: AlgSHA1,
},
CurveID: CurveNISTP256,
Point: ECPoint{XRaw: pk.PublicKey.X.Bytes(), YRaw: pk.PublicKey.Y.Bytes()},
Point: ECPoint{XRaw: X, YRaw: Y},
},
}
private := Private{
Type: AlgECC,
Sensitive: pk.D.Bytes(),
Sensitive: ecdhKey.Bytes(),
}
run(t, public, private)
})
Expand Down Expand Up @@ -813,6 +821,14 @@ func TestCertifyExternalKey(t *testing.T) {
if err != nil {
t.Fatal(err)
}
ecdhPK, err := pk.ECDH()
if err != nil {
t.Fatal(err)
}
X, Y, err := ECCBytes(ecdhPK.PublicKey())
if err != nil {
t.Fatal(err)
}
public := Public{
Type: AlgECC,
NameAlg: AlgSHA1,
Expand All @@ -823,12 +839,12 @@ func TestCertifyExternalKey(t *testing.T) {
Hash: AlgSHA1,
},
CurveID: CurveNISTP256,
Point: ECPoint{XRaw: pk.PublicKey.X.Bytes(), YRaw: pk.PublicKey.Y.Bytes()},
Point: ECPoint{XRaw: X, YRaw: Y},
},
}
private := Private{
Type: AlgECC,
Sensitive: pk.D.Bytes(),
Sensitive: ecdhPK.Bytes(),
}
run(t, public, private)
})
Expand Down Expand Up @@ -1463,17 +1479,26 @@ func TestCreateAndCertifyCreationECC(t *testing.T) {
t.Logf("Public: %v", p)
}

var pkEcdsa ecdsa.PublicKey
var hsh hash.Hash
pkEcdsa = ecdsa.PublicKey{Curve: elliptic.P256(), X: p.ECCParameters.Point.X(), Y: p.ECCParameters.Point.Y()}
pk, err := p.Key()
if err != nil {
t.Fatal(err)
}

// Convert to ecdsa.PublicKey
pkEcdsa, ok := pk.(*ecdsa.PublicKey)
if !ok {
t.Fatalf("Failed getting *ecdsa.PublicKey")
}

signHash, err := p.ECCParameters.Sign.Hash.Hash()
if err != nil {
t.Fatalf("Hash failed: %v", err)
}
hsh = signHash.New()
hsh.Write(attestation)

if !ecdsa.Verify(&pkEcdsa, hsh.Sum(nil), signature.ECC.R, signature.ECC.S) {
if !ecdsa.Verify(pkEcdsa, hsh.Sum(nil), signature.ECC.R, signature.ECC.S) {
t.Fatalf("Verify failed")
}
}
Expand Down Expand Up @@ -1771,6 +1796,11 @@ func TestReadPublicKey(t *testing.T) {
if err != nil {
t.Fatal(err)
}
ecdhPK, err := pk.ECDH()
if err != nil {
t.Fatal(err)
}
X, Y, err := ECCBytes(ecdhPK.PublicKey())
public := Public{
Type: AlgECC,
NameAlg: AlgSHA1,
Expand All @@ -1781,12 +1811,12 @@ func TestReadPublicKey(t *testing.T) {
Hash: AlgSHA1,
},
CurveID: CurveNISTP256,
Point: ECPoint{XRaw: pk.PublicKey.X.Bytes(), YRaw: pk.PublicKey.Y.Bytes()},
Point: ECPoint{XRaw: X, YRaw: Y},
},
}
private := Private{
Type: AlgECC,
Sensitive: pk.D.Bytes(),
Sensitive: ecdhPK.Bytes(),
}
run(t, public, private, &pk.PublicKey)
})
Expand Down
42 changes: 27 additions & 15 deletions tpm2/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,11 @@ func Priv(public TPMTPublic, sensitive TPMTSensitive) (crypto.PrivateKey, error)
return nil, fmt.Errorf("failed to retrieve the ECC")
}

D := new(big.Int).SetBytes(d.Buffer)

ecdsaKey := &ecdsa.PrivateKey{
PublicKey: *publicKey,
D: D,
privateKey, err = ecdsa.ParseRawPrivateKey(publicKey.Curve, d.Buffer)
if err != nil {
return nil, fmt.Errorf("failed parsing ECC private key: %v", err)
}

privateKey = ecdsaKey
default:
return nil, fmt.Errorf("unsupported public key type: %v", public.Type)
}
Expand Down Expand Up @@ -145,18 +142,19 @@ func ECDSAPub(parms *TPMSECCParms, pub *TPMSECCPoint) (*ecdsa.PublicKey, error)
return nil, fmt.Errorf("unknown curve: %v", parms.CurveID)
}

pubKey := ecdsa.PublicKey{
Curve: c,
X: big.NewInt(0).SetBytes(pub.X.Buffer),
Y: big.NewInt(0).SetBytes(pub.Y.Buffer),
}
// Create a buffer with the uncompressed ECC public key
data := make([]byte, 0, len(pub.X.Buffer)+len(pub.Y.Buffer)+1)
// 0x04 denotes an uncompressed ECC key
// https://datatracker.ietf.org/doc/rfc5480/
data = append(data, 0x04)
data = append(data, pub.X.Buffer...)
data = append(data, pub.Y.Buffer...)

return &pubKey, nil
return ecdsa.ParseUncompressedPublicKey(c, data)
}

// ECDHPub converts a TPM ECC public key into one recognized by the ecdh package
func ECDHPub(parms *TPMSECCParms, pub *TPMSECCPoint) (*ecdh.PublicKey, error) {

pubKey, err := ECDSAPub(parms, pub)
if err != nil {
return nil, err
Expand All @@ -166,14 +164,28 @@ func ECDHPub(parms *TPMSECCParms, pub *TPMSECCPoint) (*ecdh.PublicKey, error) {
}

// ECCPoint returns an uncompressed ECC Point
// Deprecated: [big.Int] is being deprecated in the ECC libraries. Use ECCBytes instead.
func ECCPoint(pubKey *ecdh.PublicKey) (*big.Int, *big.Int, error) {
x, y, err := ECCBytes(pubKey)
if err != nil {
return nil, nil, err
}
return big.NewInt(0).SetBytes(x), big.NewInt(0).SetBytes(y), nil
}

// ECCPoints returns an uncompressed ECC Point
func ECCBytes(pubKey *ecdh.PublicKey) ([]byte, []byte, error) {
b := pubKey.Bytes()
// 0x04 denotes an uncompressed ECC key
// https://datatracker.ietf.org/doc/rfc5480/
if len(b) == 0 || b[0] != 0x04 {
return nil, nil, fmt.Errorf("could not decode %x as an uncompressed point", b)
}
size, err := elementLength(pubKey.Curve())
if err != nil {
return nil, nil, fmt.Errorf("ECCPoint: %w", err)
}
return big.NewInt(0).SetBytes(b[1 : size+1]),
big.NewInt(0).SetBytes(b[size+1:]), nil
return b[1 : size+1], b[size+1:], nil
}

func elementLength(c ecdh.Curve) (int, error) {
Expand Down
14 changes: 9 additions & 5 deletions tpm2/crypto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ func TestPriv(t *testing.T) {

rsaKey, _ := rsa.GenerateKey(rand.Reader, 2048)
ecdsaKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
ecdhKey, _ := ecdsaKey.ECDH()
eccPointX, eccPointY, _ := ECCBytes(ecdhKey.PublicKey())

seed := make([]byte, crypto.SHA256.New().Size())
rand.Read(seed)
Expand Down Expand Up @@ -119,7 +121,7 @@ func TestPriv(t *testing.T) {
},
Sensitive: NewTPMUSensitiveComposite(
TPMAlgECC,
&TPM2BECCParameter{Buffer: ecdsaKey.D.FillBytes(make([]byte, len(ecdsaKey.D.Bytes())))},
&TPM2BECCParameter{Buffer: ecdhKey.Bytes()},
),
},
public: TPMTPublic{
Expand Down Expand Up @@ -157,10 +159,10 @@ func TestPriv(t *testing.T) {
TPMAlgECC,
&TPMSECCPoint{
X: TPM2BECCParameter{
Buffer: ecdsaKey.X.Bytes(),
Buffer: eccPointX,
},
Y: TPM2BECCParameter{
Buffer: ecdsaKey.Y.Bytes(),
Buffer: eccPointY,
},
},
),
Expand Down Expand Up @@ -236,6 +238,8 @@ func TestPub(t *testing.T) {

rsaKey, _ := rsa.GenerateKey(rand.Reader, 2048)
ecdsaKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
ecdhKey, _ := ecdsaKey.ECDH()
X, Y, _ := ECCBytes(ecdhKey.PublicKey())

tests := map[string]struct {
public TPMTPublic
Expand Down Expand Up @@ -321,10 +325,10 @@ func TestPub(t *testing.T) {
TPMAlgECC,
&TPMSECCPoint{
X: TPM2BECCParameter{
Buffer: ecdsaKey.X.Bytes(),
Buffer: X,
},
Y: TPM2BECCParameter{
Buffer: ecdsaKey.Y.Bytes(),
Buffer: Y,
},
},
),
Expand Down
Loading