attest: Support certification by ECC AKs.
Some checks failed
CodeQL / Analyze (go) (push) Has been cancelled
Test / test-linux (1.22.x) (push) Has been cancelled
Test / test-linux-tpm12 (1.22.x) (push) Has been cancelled
Test / test-macos (1.22.x) (push) Has been cancelled
Test / test-windows (1.22.x) (push) Has been cancelled

This commit is contained in:
Evgeny Shatokhin
2025-01-06 16:26:38 +11:00
committed by Brandon Weeks
parent 1b202b12e8
commit c7aee80c5d
3 changed files with 94 additions and 29 deletions

View File

@ -17,6 +17,7 @@ package attest
import ( import (
"bytes" "bytes"
"crypto" "crypto"
"crypto/ecdsa"
"crypto/rand" "crypto/rand"
"crypto/rsa" "crypto/rsa"
"errors" "errors"
@ -164,11 +165,6 @@ func (p *CertificationParameters) Verify(opts VerifyOpts) error {
} }
// Check the signature over the attestation data verifies correctly. // Check the signature over the attestation data verifies correctly.
// TODO: Support ECC certifying keys
pk, ok := opts.Public.(*rsa.PublicKey)
if !ok {
return fmt.Errorf("only RSA verification keys are supported")
}
if !opts.Hash.Available() { if !opts.Hash.Available() {
return fmt.Errorf("hash function is unavailable") return fmt.Errorf("hash function is unavailable")
} }
@ -184,9 +180,18 @@ func (p *CertificationParameters) Verify(opts VerifyOpts) error {
return fmt.Errorf("DecodeSignature() failed: %v", err) return fmt.Errorf("DecodeSignature() failed: %v", err)
} }
switch pk := opts.Public.(type) {
case *rsa.PublicKey:
if err := rsa.VerifyPKCS1v15(pk, opts.Hash, hsh.Sum(nil), sig.RSA.Signature); err != nil { if err := rsa.VerifyPKCS1v15(pk, opts.Hash, hsh.Sum(nil), sig.RSA.Signature); err != nil {
return fmt.Errorf("could not verify attestation: %v", err) return fmt.Errorf("could not verify attestation: %v", err)
} }
case *ecdsa.PublicKey:
if ok := ecdsa.Verify(pk, hsh.Sum(nil), sig.ECC.R, sig.ECC.S); !ok {
return fmt.Errorf("could not verify ECC attestation")
}
default:
return fmt.Errorf("unsupported public key type: %T", pub)
}
return nil return nil
} }

View File

@ -31,13 +31,19 @@ import (
"github.com/google/go-tpm/legacy/tpm2" "github.com/google/go-tpm/legacy/tpm2"
) )
func TestSimTPM20CertificationParameters(t *testing.T) { func TestSimTPM20CertificationParametersRSA(t *testing.T) {
sim, tpm := setupSimulatedTPM(t) sim, tpm := setupSimulatedTPM(t)
defer sim.Close() defer sim.Close()
testCertificationParameters(t, tpm) testCertificationParameters(t, tpm, RSA)
} }
func TestTPM20CertificationParameters(t *testing.T) { func TestSimTPM20CertificationParametersECC(t *testing.T) {
sim, tpm := setupSimulatedTPM(t)
defer sim.Close()
testCertificationParameters(t, tpm, ECDSA)
}
func TestTPM20CertificationParametersRSA(t *testing.T) {
if !*testLocal { if !*testLocal {
t.SkipNow() t.SkipNow()
} }
@ -46,11 +52,23 @@ func TestTPM20CertificationParameters(t *testing.T) {
t.Fatalf("OpenTPM() failed: %v", err) t.Fatalf("OpenTPM() failed: %v", err)
} }
defer tpm.Close() defer tpm.Close()
testCertificationParameters(t, tpm) testCertificationParameters(t, tpm, RSA)
} }
func testCertificationParameters(t *testing.T, tpm *TPM) { func TestTPM20CertificationParametersECC(t *testing.T) {
ak, err := tpm.NewAK(nil) if !*testLocal {
t.SkipNow()
}
tpm, err := OpenTPM(nil)
if err != nil {
t.Fatalf("OpenTPM() failed: %v", err)
}
defer tpm.Close()
testCertificationParameters(t, tpm, ECDSA)
}
func testCertificationParameters(t *testing.T, tpm *TPM, akAlg Algorithm) {
ak, err := tpm.NewAK(&AKConfig{Algorithm: akAlg})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -59,12 +77,12 @@ func testCertificationParameters(t *testing.T, tpm *TPM) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if pub.Type != tpm2.AlgRSA {
t.Fatal("non-RSA verifying key")
}
pk := &rsa.PublicKey{E: int(pub.RSAParameters.Exponent()), N: pub.RSAParameters.Modulus()} pk, err := pub.Key()
hash, err := pub.RSAParameters.Sign.Hash.Hash() if err != nil {
t.Fatal(err)
}
hash, err := pub.NameAlg.Hash()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -170,13 +188,19 @@ func testCertificationParameters(t *testing.T, tpm *TPM) {
} }
} }
func TestSimTPM20KeyCertification(t *testing.T) { func TestSimTPM20KeyCertificationRSA(t *testing.T) {
sim, tpm := setupSimulatedTPM(t) sim, tpm := setupSimulatedTPM(t)
defer sim.Close() defer sim.Close()
testKeyCertification(t, tpm) testKeyCertification(t, tpm, RSA)
} }
func TestTPM20KeyCertification(t *testing.T) { func TestSimTPM20KeyCertificationECC(t *testing.T) {
sim, tpm := setupSimulatedTPM(t)
defer sim.Close()
testKeyCertification(t, tpm, ECDSA)
}
func TestTPM20KeyCertificationRSA(t *testing.T) {
if !*testLocal { if !*testLocal {
t.SkipNow() t.SkipNow()
} }
@ -185,11 +209,23 @@ func TestTPM20KeyCertification(t *testing.T) {
t.Fatalf("OpenTPM() failed: %v", err) t.Fatalf("OpenTPM() failed: %v", err)
} }
defer tpm.Close() defer tpm.Close()
testKeyCertification(t, tpm) testKeyCertification(t, tpm, RSA)
} }
func testKeyCertification(t *testing.T, tpm *TPM) { func TestTPM20KeyCertificationECC(t *testing.T) {
ak, err := tpm.NewAK(nil) if !*testLocal {
t.SkipNow()
}
tpm, err := OpenTPM(nil)
if err != nil {
t.Fatalf("OpenTPM() failed: %v", err)
}
defer tpm.Close()
testKeyCertification(t, tpm, ECDSA)
}
func testKeyCertification(t *testing.T, tpm *TPM, akAlg Algorithm) {
ak, err := tpm.NewAK(&AKConfig{Algorithm: akAlg})
if err != nil { if err != nil {
t.Fatalf("NewAK() failed: %v", err) t.Fatalf("NewAK() failed: %v", err)
} }
@ -198,8 +234,11 @@ func testKeyCertification(t *testing.T, tpm *TPM) {
if err != nil { if err != nil {
t.Fatalf("DecodePublic() failed: %v", err) t.Fatalf("DecodePublic() failed: %v", err)
} }
pk := &rsa.PublicKey{E: int(pub.RSAParameters.Exponent()), N: pub.RSAParameters.Modulus()} pk, err := pub.Key()
hash, err := pub.RSAParameters.Sign.Hash.Hash() if err != nil {
t.Fatalf("pub.Key() failed: %v", err)
}
hash, err := pub.NameAlg.Hash()
if err != nil { if err != nil {
t.Fatalf("cannot access AK's hash function: %v", err) t.Fatalf("cannot access AK's hash function: %v", err)
} }

View File

@ -566,6 +566,27 @@ func (k *wrappedKey20) activateCredential(tb tpmBase, in EncryptedCredential, ek
}, k.hnd, ekHnd, credential, secret) }, k.hnd, ekHnd, credential, secret)
} }
func sigSchemeFromPublicKey(pub []byte) (tpm2.SigScheme, error) {
tpmPub, err := tpm2.DecodePublic(pub)
if err != nil {
return tpm2.SigScheme{}, fmt.Errorf("decode public key: %v", err)
}
switch tpmPub.Type {
case tpm2.AlgRSA:
return tpm2.SigScheme{
Alg: tpm2.AlgRSASSA,
Hash: tpm2.AlgSHA256,
}, nil
case tpm2.AlgECC:
return tpm2.SigScheme{
Alg: tpm2.AlgECDSA,
Hash: tpm2.AlgSHA256,
}, nil
default:
return tpm2.SigScheme{}, fmt.Errorf("public key of alg 0x%x not supported", tpmPub.Type)
}
}
func (k *wrappedKey20) certify(tb tpmBase, handle interface{}) (*CertificationParameters, error) { func (k *wrappedKey20) certify(tb tpmBase, handle interface{}) (*CertificationParameters, error) {
t, ok := tb.(*wrappedTPM20) t, ok := tb.(*wrappedTPM20)
if !ok { if !ok {
@ -575,9 +596,9 @@ func (k *wrappedKey20) certify(tb tpmBase, handle interface{}) (*CertificationPa
if !ok { if !ok {
return nil, fmt.Errorf("expected tpmutil.Handle, got %T", handle) return nil, fmt.Errorf("expected tpmutil.Handle, got %T", handle)
} }
scheme := tpm2.SigScheme{ scheme, err := sigSchemeFromPublicKey(k.public)
Alg: tpm2.AlgRSASSA, if err != nil {
Hash: tpm2.AlgSHA256, return nil, fmt.Errorf("get signature scheme: %v", err)
} }
return certify(t.rwc, hnd, k.hnd, scheme) return certify(t.rwc, hnd, k.hnd, scheme)
} }