attest: Support creation of ECC AK.

This commit is contained in:
Evgeny Shatokhin 2025-01-03 15:28:59 +11:00 committed by Brandon Weeks
parent 183ad1d5ad
commit 1b202b12e8
5 changed files with 128 additions and 52 deletions

View File

@ -194,6 +194,9 @@ type AKConfig struct {
// If nil, the default SRK (i.e. RSA with handle 0x81000001) is assumed.
// Supported only by TPM 2.0 on Linux.
Parent *ParentKeyConfig
// If not specified, the default algorithm (RSA) is assumed.
Algorithm Algorithm
}
// EncryptedCredential represents encrypted parameters which must be activated

View File

@ -67,33 +67,56 @@ func TestSimTPM20Info(t *testing.T) {
func TestSimTPM20AKCreateAndLoad(t *testing.T) {
sim, tpm := setupSimulatedTPM(t)
defer sim.Close()
for _, test := range []struct {
name string
opts *AKConfig
}{
{
name: "NoConfig",
opts: nil,
},
{
name: "EmptyConfig",
opts: &AKConfig{},
},
{
name: "RSA",
opts: &AKConfig{Algorithm: RSA},
},
{
name: "ECDSA",
opts: &AKConfig{Algorithm: ECDSA},
},
} {
t.Run(test.name, func(t *testing.T) {
ak, err := tpm.NewAK(test.opts)
if err != nil {
t.Fatalf("NewAK() failed: %v", err)
}
ak, err := tpm.NewAK(nil)
if err != nil {
t.Fatalf("NewAK() failed: %v", err)
}
enc, err := ak.Marshal()
if err != nil {
ak.Close(tpm)
t.Fatalf("ak.Marshal() failed: %v", err)
}
if err := ak.Close(tpm); err != nil {
t.Fatalf("ak.Close() failed: %v", err)
}
enc, err := ak.Marshal()
if err != nil {
ak.Close(tpm)
t.Fatalf("ak.Marshal() failed: %v", err)
}
if err := ak.Close(tpm); err != nil {
t.Fatalf("ak.Close() failed: %v", err)
}
loaded, err := tpm.LoadAK(enc)
if err != nil {
t.Fatalf("LoadAK() failed: %v", err)
}
defer loaded.Close(tpm)
loaded, err := tpm.LoadAK(enc)
if err != nil {
t.Fatalf("LoadKey() failed: %v", err)
}
defer loaded.Close(tpm)
k1, k2 := ak.ak.(*wrappedKey20), loaded.ak.(*wrappedKey20)
k1, k2 := ak.ak.(*wrappedKey20), loaded.ak.(*wrappedKey20)
if !bytes.Equal(k1.public, k2.public) {
t.Error("Original & loaded AK public blobs did not match.")
t.Logf("Original = %v", k1.public)
t.Logf("Loaded = %v", k2.public)
if !bytes.Equal(k1.public, k2.public) {
t.Error("Original & loaded AK public blobs did not match.")
t.Logf("Original = %v", k1.public)
t.Logf("Loaded = %v", k2.public)
}
})
}
}

View File

@ -83,38 +83,62 @@ func TestAKCreateAndLoad(t *testing.T) {
if !*testLocal {
t.SkipNow()
}
tpm, err := OpenTPM(nil)
if err != nil {
t.Fatalf("OpenTPM() failed: %v", err)
}
defer tpm.Close()
for _, test := range []struct {
name string
opts *AKConfig
}{
{
name: "NoConfig",
opts: nil,
},
{
name: "EmptyConfig",
opts: &AKConfig{},
},
{
name: "RSA",
opts: &AKConfig{Algorithm: RSA},
},
{
name: "ECDSA",
opts: &AKConfig{Algorithm: ECDSA},
},
} {
t.Run(test.name, func(t *testing.T) {
tpm, err := OpenTPM(nil)
if err != nil {
t.Fatalf("OpenTPM() failed: %v", err)
}
defer tpm.Close()
ak, err := tpm.NewAK(nil)
if err != nil {
t.Fatalf("NewAK() failed: %v", err)
}
ak, err := tpm.NewAK(test.opts)
if err != nil {
t.Fatalf("NewAK() failed: %v", err)
}
enc, err := ak.Marshal()
if err != nil {
ak.Close(tpm)
t.Fatalf("ak.Marshal() failed: %v", err)
}
if err := ak.Close(tpm); err != nil {
t.Fatalf("ak.Close() failed: %v", err)
}
enc, err := ak.Marshal()
if err != nil {
ak.Close(tpm)
t.Fatalf("ak.Marshal() failed: %v", err)
}
if err := ak.Close(tpm); err != nil {
t.Fatalf("ak.Close() failed: %v", err)
}
loaded, err := tpm.LoadAK(enc)
if err != nil {
t.Fatalf("LoadKey() failed: %v", err)
}
defer loaded.Close(tpm)
loaded, err := tpm.LoadAK(enc)
if err != nil {
t.Fatalf("LoadAK() failed: %v", err)
}
defer loaded.Close(tpm)
k1, k2 := ak.ak.(*wrappedKey20), loaded.ak.(*wrappedKey20)
k1, k2 := ak.ak.(*wrappedKey20), loaded.ak.(*wrappedKey20)
if !bytes.Equal(k1.public, k2.public) {
t.Error("Original & loaded AK public blobs did not match.")
t.Logf("Original = %v", k1.public)
t.Logf("Loaded = %v", k2.public)
if !bytes.Equal(k1.public, k2.public) {
t.Error("Original & loaded AK public blobs did not match.")
t.Logf("Original = %v", k1.public)
t.Logf("Loaded = %v", k2.public)
}
})
}
}

View File

@ -48,7 +48,7 @@ const (
)
var (
akTemplate = tpm2.Public{
akTemplateRSA = tpm2.Public{
Type: tpm2.AlgRSA,
NameAlg: tpm2.AlgSHA256,
Attributes: tpm2.FlagSignerDefault | tpm2.FlagNoDA,
@ -60,6 +60,22 @@ var (
KeyBits: 2048,
},
}
akTemplateECC = tpm2.Public{
Type: tpm2.AlgECC,
NameAlg: tpm2.AlgSHA256,
Attributes: tpm2.FlagSignerDefault | tpm2.FlagNoDA,
ECCParameters: &tpm2.ECCParams{
Sign: &tpm2.SigScheme{
Alg: tpm2.AlgECDSA,
Hash: tpm2.AlgSHA256,
},
CurveID: tpm2.CurveNISTP256,
Point: tpm2.ECPoint{
XRaw: make([]byte, 32),
YRaw: make([]byte, 32),
},
},
}
defaultRSASRKTemplate = tpm2.Public{
Type: tpm2.AlgRSA,
NameAlg: tpm2.AlgSHA256,

View File

@ -246,6 +246,16 @@ func (t *wrappedTPM20) newAK(opts *AKConfig) (*AK, error) {
return nil, fmt.Errorf("failed to get SRK handle: %v", err)
}
var akTemplate tpm2.Public
var sigScheme *tpm2.SigScheme
// The default is RSA.
if opts != nil && opts.Algorithm == ECDSA {
akTemplate = akTemplateECC
sigScheme = akTemplateECC.ECCParameters.Sign
} else {
akTemplate = akTemplateRSA
sigScheme = akTemplateRSA.RSAParameters.Sign
}
blob, pub, creationData, creationHash, tix, err := tpm2.CreateKey(t.rwc, srk, tpm2.PCRSelection{}, "", "", akTemplate)
if err != nil {
return nil, fmt.Errorf("CreateKeyEx() failed: %v", err)
@ -262,7 +272,7 @@ func (t *wrappedTPM20) newAK(opts *AKConfig) (*AK, error) {
}()
// We can only certify the creation immediately afterwards, so we cache the result.
attestation, sig, err := tpm2.CertifyCreation(t.rwc, "", keyHandle, keyHandle, nil, creationHash, tpm2.SigScheme{Alg: tpm2.AlgRSASSA, Hash: tpm2.AlgSHA256, Count: 0}, tix)
attestation, sig, err := tpm2.CertifyCreation(t.rwc, "", keyHandle, keyHandle, nil, creationHash, *sigScheme, tix)
if err != nil {
return nil, fmt.Errorf("CertifyCreation failed: %v", err)
}