From ea5407eca1a0ac1aec7302910c42072e5a8856dd Mon Sep 17 00:00:00 2001 From: Dionna Amalie Glaze Date: Thu, 15 Dec 2022 15:21:56 -0800 Subject: [PATCH] Update to go-sev-guest v0.4.0 (#271) This adds the ability for the test to run with a real sev-guest device, not just a fake. Signed-off-by: Dionna Glaze Signed-off-by: Dionna Glaze --- client/attest_test.go | 9 +++--- go.mod | 5 ++-- go.sum | 5 ++-- server/verify_sev.go | 21 +++++++++----- server/verify_test.go | 64 ++++++++++++++++++++++++------------------- 5 files changed, 60 insertions(+), 44 deletions(-) diff --git a/client/attest_test.go b/client/attest_test.go index 637f2b94..9217caa4 100644 --- a/client/attest_test.go +++ b/client/attest_test.go @@ -13,6 +13,7 @@ import ( "time" sgtest "github.com/google/go-sev-guest/testing" + testclient "github.com/google/go-sev-guest/testing/client" "github.com/google/go-tpm-tools/internal/test" pb "github.com/google/go-tpm-tools/proto/attest" ) @@ -223,7 +224,7 @@ func TestSevSnpDevice(t *testing.T) { copy(someNonce64[:], someNonce) var nonce64 [64]byte copy(nonce64[:], []byte("noncey business")) - sevTestDevice, err := sgtest.TcDevice([]sgtest.TestCase{ + sevTestDevice, _, _, _ := testclient.GetSevGuest([]sgtest.TestCase{ { Input: someNonce64, Output: sgtest.TestRawReport(someNonce64), @@ -232,10 +233,8 @@ func TestSevSnpDevice(t *testing.T) { Input: nonce64, Output: sgtest.TestRawReport(nonce64), }, - }, &sgtest.DeviceOptions{Now: time.Now()}) - if err != nil { - t.Fatalf("failed to create test device: %v", err) - } + }, &sgtest.DeviceOptions{Now: time.Now()}, t) + defer sevTestDevice.Close() testcases := []struct { name string diff --git a/go.mod b/go.mod index 7fc15e57..5513539d 100644 --- a/go.mod +++ b/go.mod @@ -6,15 +6,16 @@ go 1.19 require ( github.com/google/go-attestation v0.4.4-0.20220404204839-8820d49b18d9 github.com/google/go-cmp v0.5.7 - github.com/google/go-sev-guest v0.2.6 + github.com/google/go-sev-guest v0.4.1 github.com/google/go-tpm v0.3.3 + github.com/google/logger v1.1.1 google.golang.org/protobuf v1.28.0 ) require ( + github.com/golang/protobuf v1.5.2 // indirect github.com/google/certificate-transparency-go v1.1.2 // indirect github.com/google/go-tspi v0.2.1-0.20190423175329-115dea689aad // indirect - github.com/google/logger v1.1.1 // indirect github.com/google/uuid v1.1.2 // indirect github.com/pborman/uuid v1.2.0 // indirect github.com/pkg/errors v0.9.1 // indirect diff --git a/go.sum b/go.sum index 76e179ad..eb560df5 100644 --- a/go.sum +++ b/go.sum @@ -286,6 +286,7 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -320,8 +321,8 @@ github.com/google/go-licenses v0.0.0-20210329231322-ce1d9163b77d/go.mod h1:+TYOm github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE= github.com/google/go-replayers/httpreplay v0.1.0/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no= -github.com/google/go-sev-guest v0.2.6 h1:IH3neBTmwVXLX1OfYzI3vbUM8psEJ47y1xnwhsFDXcY= -github.com/google/go-sev-guest v0.2.6/go.mod h1:OMtBJPoT3rJO9HkA+ufUz4v/C71QJM4gf0IMz8dchPw= +github.com/google/go-sev-guest v0.4.1 h1:IjxtGAvzR+zSyAqMc1FWfYKCg1cwPkBly9+Xog3YMZc= +github.com/google/go-sev-guest v0.4.1/go.mod h1:UEi9uwoPbLdKGl1QHaq1G8pfCbQ4QP0swWX4J0k6r+Q= github.com/google/go-tpm v0.1.2-0.20190725015402-ae6dd98980d4/go.mod h1:H9HbmUG2YgV/PHITkO7p6wxEEj/v5nlsVWIwumwH2NI= github.com/google/go-tpm v0.3.0/go.mod h1:iVLWvrPp/bHeEkxTFi9WG6K9w0iy2yIszHwZGHPbzAw= github.com/google/go-tpm v0.3.2/go.mod h1:j71sMBTfp3X5jPHz852ZOfQMUOf65Gb/Th8pRmp7fvg= diff --git a/server/verify_sev.go b/server/verify_sev.go index 3280c9ef..e2079daa 100644 --- a/server/verify_sev.go +++ b/server/verify_sev.go @@ -5,6 +5,7 @@ import ( spb "github.com/google/go-sev-guest/proto/sevsnp" "github.com/google/go-sev-guest/validate" sv "github.com/google/go-sev-guest/verify" + "github.com/google/go-sev-guest/verify/trust" ) // VerifySnpOpts allows for customizing the functionality of VerifyAttestation's SEV-SNP verification. @@ -15,21 +16,27 @@ type VerifySnpOpts struct { // to verify a versioned chip endorsement key (VCEK) that signs attestation reports. // If nil, falls back on go-sev-guest's embedded root certs. Maps a product name // to an array of allowed roots. - TrustedRoots map[string][]*sv.AMDRootCerts + TrustedRoots map[string][]*trust.AMDRootCerts // Allow the debug bit to be set (should only be used for testing). AllowDebugTestOnly bool + // Getter is the object that will fetch files from URLs. + Getter trust.HTTPSGetter } // VerifySevSnpAttestation checks that the SEV-SNP attestation report matches expectations for the // product. func VerifySevSnpAttestation(attestation *spb.Attestation, opts *VerifySnpOpts) error { - // Check that the fields of the report are acceptable. - if err := validate.SnpAttestation(attestation, &validate.Options{ - ReportData: opts.ReportData[:], - GuestPolicy: sabi.SnpPolicy{Debug: opts.AllowDebugTestOnly}, + // Check that the report is signed by a valid AMD key. Do not check revocations. This must be + // done before validation to ensure the certificates are filled in by the verify library. + if err := sv.SnpAttestation(attestation, &sv.Options{ + TrustedRoots: opts.TrustedRoots, + Getter: opts.Getter, }); err != nil { return err } - // Check that the report is signed by a valid AMD key. Do not check revocations. - return sv.SnpAttestation(attestation, &sv.Options{TrustedRoots: opts.TrustedRoots}) + // Check that the fields of the report are acceptable. + return validate.SnpAttestation(attestation, &validate.Options{ + ReportData: opts.ReportData[:], + GuestPolicy: sabi.SnpPolicy{Debug: opts.AllowDebugTestOnly}, + }) } diff --git a/server/verify_test.go b/server/verify_test.go index 4bd3b1ba..7e88ef4f 100644 --- a/server/verify_test.go +++ b/server/verify_test.go @@ -12,13 +12,14 @@ import ( "fmt" "hash" "io" + "os" "strings" "testing" "time" "github.com/google/go-cmp/cmp" sgtest "github.com/google/go-sev-guest/testing" - "github.com/google/go-sev-guest/verify" + testclient "github.com/google/go-sev-guest/testing/client" "github.com/google/go-tpm-tools/cel" "github.com/google/go-tpm-tools/client" "github.com/google/go-tpm-tools/internal" @@ -26,6 +27,7 @@ import ( attestpb "github.com/google/go-tpm-tools/proto/attest" "github.com/google/go-tpm/tpm2" "github.com/google/go-tpm/tpmutil" + "github.com/google/logger" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/testing/protocmp" ) @@ -59,6 +61,11 @@ func extendPCRsRandomly(rwc io.ReadWriteCloser, selpcr tpm2.PCRSelection) error return nil } +func TestMain(m *testing.M) { + logger.Init("TestLog", false, false, os.Stderr) + os.Exit(m.Run()) +} + func TestVerifyHappyCases(t *testing.T) { rwc := test.GetTPM(t) defer client.CheckedClose(t, rwc) @@ -206,12 +213,26 @@ func TestVerifyBasicAttestation(t *testing.T) { } defer ak.Close() + // When running on hardware, ak.Attest will collect an attestation report regardless of + // AttestOpts. We test the default behavior here by not passing in a device. + sevTestDevice, goodSnpRoot, _, kdsGetter := testclient.GetSevGuest(nil, &sgtest.DeviceOptions{}, t) + defer sevTestDevice.Close() + nonce := []byte("super secret nonce") - attestation, err := ak.Attest(client.AttestOpts{Nonce: nonce}) + var nonce64 [64]byte + copy(nonce64[:], nonce) + attestation, err := ak.Attest(client.AttestOpts{ + Nonce: nonce, + }) if err != nil { t.Fatalf("failed to attest: %v", err) } + teeopts := &VerifySnpOpts{ + Getter: kdsGetter, + ReportData: nonce64, + TrustedRoots: goodSnpRoot, + } if _, err := VerifyAttestation(attestation, VerifyOpts{ Nonce: nonce, TrustedAKs: []crypto.PublicKey{ak.PublicKey()}, @@ -222,12 +243,14 @@ func TestVerifyBasicAttestation(t *testing.T) { if _, err := VerifyAttestation(attestation, VerifyOpts{ Nonce: append(nonce, 0), TrustedAKs: []crypto.PublicKey{ak.PublicKey()}, + TEEOpts: teeopts, }); err == nil { t.Error("using the wrong nonce should make verification fail") } if _, err := VerifyAttestation(attestation, VerifyOpts{ - Nonce: nonce, + Nonce: nonce, + TEEOpts: teeopts, }); err == nil { t.Error("using no trusted AKs should make verification fail") } @@ -239,6 +262,7 @@ func TestVerifyBasicAttestation(t *testing.T) { if _, err := VerifyAttestation(attestation, VerifyOpts{ Nonce: nonce, TrustedAKs: []crypto.PublicKey{priv.Public()}, + TEEOpts: teeopts, }); err == nil { t.Error("using a random trusted AKs should make verification fail") } @@ -940,15 +964,13 @@ func TestVerifyAttestationWithSevSnp(t *testing.T) { nonce := []byte("super secret nonce") var nonce64 [64]byte copy(nonce64[:], []byte("alternate secret nonce")) - sevTestDevice, err := sgtest.TcDevice([]sgtest.TestCase{ + sevTestDevice, goodSnpRoot, badSnpRoot, kdsGetter := testclient.GetSevGuest([]sgtest.TestCase{ { Input: nonce64, Output: sgtest.TestRawReport(nonce64), }, - }, &sgtest.DeviceOptions{Now: time.Now()}) - if err != nil { - t.Fatalf("failed to create test device: %v", err) - } + }, &sgtest.DeviceOptions{Now: time.Now()}, t) + defer sevTestDevice.Close() attestation, err := ak.Attest(client.AttestOpts{ Nonce: nonce, TEEDevice: &client.SevSnpDevice{Device: sevTestDevice}, @@ -958,15 +980,6 @@ func TestVerifyAttestationWithSevSnp(t *testing.T) { t.Fatalf("failed to attest: %v", err) } - goodSnpRoot := map[string][]*verify.AMDRootCerts{ - "Milan": { - { - Product: "Milan", - AskX509: sevTestDevice.Signer.Ask, - ArkX509: sevTestDevice.Signer.Ark, - }, - }, - } tcs := []struct { name string opts VerifyOpts @@ -978,6 +991,7 @@ func TestVerifyAttestationWithSevSnp(t *testing.T) { Nonce: nonce, TrustedAKs: []crypto.PublicKey{ak.PublicKey()}, TEEOpts: &VerifySnpOpts{ + Getter: kdsGetter, ReportData: nonce64, TrustedRoots: goodSnpRoot, AllowDebugTestOnly: true, @@ -990,6 +1004,7 @@ func TestVerifyAttestationWithSevSnp(t *testing.T) { Nonce: nonce, TrustedAKs: []crypto.PublicKey{ak.PublicKey()}, TEEOpts: &VerifySnpOpts{ + Getter: kdsGetter, ReportData: func() [64]byte { var badNonce [64]byte copy(badNonce[:], []byte("soooo baaad")) @@ -1007,17 +1022,9 @@ func TestVerifyAttestationWithSevSnp(t *testing.T) { Nonce: nonce, TrustedAKs: []crypto.PublicKey{ak.PublicKey()}, TEEOpts: &VerifySnpOpts{ - ReportData: nonce64, - TrustedRoots: map[string][]*verify.AMDRootCerts{ - "Milan": { - { - Product: "Milan", - // Backwards, oops - AskX509: sevTestDevice.Signer.Ark, - ArkX509: sevTestDevice.Signer.Ask, - }, - }, - }, + Getter: kdsGetter, + ReportData: nonce64, + TrustedRoots: badSnpRoot, AllowDebugTestOnly: true, }, }, @@ -1029,6 +1036,7 @@ func TestVerifyAttestationWithSevSnp(t *testing.T) { Nonce: nonce, TrustedAKs: []crypto.PublicKey{ak.PublicKey()}, TEEOpts: &VerifySnpOpts{ + Getter: kdsGetter, ReportData: nonce64, TrustedRoots: goodSnpRoot, },