diff --git a/client/attest.go b/client/attest.go index f18e4d03..6cb345e1 100644 --- a/client/attest.go +++ b/client/attest.go @@ -10,6 +10,7 @@ import ( sg "github.com/google/go-sev-guest/client" tg "github.com/google/go-tdx-guest/client" tabi "github.com/google/go-tdx-guest/client/linuxabi" + tpb "github.com/google/go-tdx-guest/proto/tdx" pb "github.com/google/go-tpm-tools/proto/attest" ) @@ -19,9 +20,9 @@ const ( ) // TEEDevice is an interface to add an attestation report from a TEE technology's -// attestation driver. +// attestation driver or quote provider. type TEEDevice interface { - // AddAttestation uses the TEE device's attestation driver to collect an + // AddAttestation uses the TEE device's attestation driver or quote provider to collect an // attestation report, then adds it to the correct field of `attestation`. AddAttestation(attestation *pb.Attestation, options AttestOpts) error // Close finalizes any resources in use by the TEEDevice. @@ -144,10 +145,17 @@ type SevSnpDevice struct { // TdxDevice encapsulates the TDX attestation device to add its attestation quote // to a pb.Attestation. +// Deprecated: TdxDevice is deprecated. It is recommended to use TdxQuoteProvider. type TdxDevice struct { Device tg.Device } +// TdxQuoteProvider encapsulates the TDX attestation device to add its attestation quote +// to a pb.Attestation. +type TdxQuoteProvider struct { + QuoteProvider tg.QuoteProvider +} + // CreateSevSnpDevice opens the SEV-SNP attestation driver and wraps it with behavior // that allows it to add an attestation report to pb.Attestation. func CreateSevSnpDevice() (*SevSnpDevice, error) { @@ -193,6 +201,8 @@ func (d *SevSnpDevice) Close() error { // CreateTdxDevice opens the TDX attestation driver and wraps it with behavior // that allows it to add an attestation quote to pb.Attestation. +// Deprecated: TdxDevice is deprecated, and use of CreateTdxQuoteProvider is +// recommended to create a TEEDevice. func CreateTdxDevice() (*TdxDevice, error) { d, err := tg.OpenDevice() if err != nil { @@ -206,21 +216,15 @@ func CreateTdxDevice() (*TdxDevice, error) { // contents of opts.Nonce. func (d *TdxDevice) AddAttestation(attestation *pb.Attestation, opts AttestOpts) error { var tdxNonce [tabi.TdReportDataSize]byte - if len(opts.TEENonce) == 0 { - copy(tdxNonce[:], opts.Nonce) - } else if len(opts.TEENonce) != tabi.TdReportDataSize { - return fmt.Errorf("the TEENonce size is %d. Intel TDX device requires %d", len(opts.TEENonce), tabi.TdReportDataSize) - } else { - copy(tdxNonce[:], opts.TEENonce) + err := fillTdxNonce(opts, tdxNonce[:]) + if err != nil { + return err } quote, err := tg.GetQuote(d.Device, tdxNonce) if err != nil { return err } - attestation.TeeAttestation = &pb.Attestation_TdxAttestation{ - TdxAttestation: quote, - } - return nil + return setTeeAttestationTdxQuote(quote, attestation) } // Close will free the device handle held by the TdxDevice. Calling more @@ -234,6 +238,73 @@ func (d *TdxDevice) Close() error { return nil } +// CreateTdxQuoteProvider creates the TDX quote provider and wraps it with behavior +// that allows it to add an attestation quote to pb.Attestation. +func CreateTdxQuoteProvider() (*TdxQuoteProvider, error) { + qp, err := tg.GetQuoteProvider() + if err != nil { + return nil, err + } + if qp.IsSupported() != nil { + // TDX quote provider has a fallback mechanism to fetch attestation quote + // via device driver in case ConfigFS is not supported, so checking for TDX + // device availability here. Once Device interface is fully removed from + // subsequent go-tdx-guest versions, then below OpenDevice call should be + // removed as well. + d, err2 := tg.OpenDevice() + if err2 != nil { + return nil, fmt.Errorf("neither TDX device, nor quote provider is supported") + } + d.Close() + } + + return &TdxQuoteProvider{QuoteProvider: qp}, nil +} + +// AddAttestation will get the TDX attestation quote given opts.TEENonce +// and add them to `attestation`. If opts.TEENonce is empty, then uses +// contents of opts.Nonce. +func (qp *TdxQuoteProvider) AddAttestation(attestation *pb.Attestation, opts AttestOpts) error { + var tdxNonce [tabi.TdReportDataSize]byte + err := fillTdxNonce(opts, tdxNonce[:]) + if err != nil { + return err + } + quote, err := tg.GetQuote(qp.QuoteProvider, tdxNonce) + if err != nil { + return err + } + return setTeeAttestationTdxQuote(quote, attestation) +} + +// Close will free resources held by QuoteProvider. +func (qp *TdxQuoteProvider) Close() error { + return nil +} + +func fillTdxNonce(opts AttestOpts, tdxNonce []byte) error { + if len(opts.TEENonce) == 0 { + copy(tdxNonce[:], opts.Nonce) + } else if len(opts.TEENonce) != tabi.TdReportDataSize { + return fmt.Errorf("the TEENonce size is %d. Intel TDX device requires %d", len(opts.TEENonce), tabi.TdReportDataSize) + } else { + copy(tdxNonce[:], opts.TEENonce) + } + return nil +} + +func setTeeAttestationTdxQuote(quote any, attestation *pb.Attestation) error { + switch q := quote.(type) { + case *tpb.QuoteV4: + attestation.TeeAttestation = &pb.Attestation_TdxAttestation{ + TdxAttestation: q, + } + default: + return fmt.Errorf("unsupported quote type: %T", quote) + } + return nil +} + // Does best effort to get a TEE hardware rooted attestation, but won't fail fatally // unless the user provided a TEEDevice object. func getTEEAttestationReport(attestation *pb.Attestation, opts AttestOpts) error { @@ -257,11 +328,11 @@ func getTEEAttestationReport(attestation *pb.Attestation, opts AttestOpts) error } // Try TDX. - if device, err := CreateTdxDevice(); err == nil { + if quoteProvider, err := CreateTdxQuoteProvider(); err == nil { // Don't return errors if the attestation collection fails, since // the user didn't specify a TEEDevice. - device.AddAttestation(attestation, opts) - device.Close() + quoteProvider.AddAttestation(attestation, opts) + quoteProvider.Close() return nil } // Add more devices here. diff --git a/client/attest_test.go b/client/attest_test.go index 8a4c2876..46f55b46 100644 --- a/client/attest_test.go +++ b/client/attest_test.go @@ -369,3 +369,77 @@ func TestTdxDevice(t *testing.T) { }) } } + +func TestTdxQuoteProvider(t *testing.T) { + rwc := test.GetTPM(t) + defer CheckedClose(t, rwc) + + ak, err := AttestationKeyRSA(rwc) + if err != nil { + t.Fatalf("Failed to generate test AK: %v", err) + } + + someNonce := []byte("some nonce") + var someNonce64 [64]byte + copy(someNonce64[:], someNonce) + var nonce64 [64]byte + copy(nonce64[:], []byte("noncey business")) + mockTdxQuoteProvider := tgtestclient.GetMockTdxQuoteProvider([]tgtest.TestCase{ + { + Input: someNonce64, + Quote: tgtestdata.RawQuote, + }, + { + Input: nonce64, + Quote: tgtestdata.RawQuote, + }, + }, t) + + testcases := []struct { + name string + opts AttestOpts + wantReportData [64]byte + wantErr string + }{ + { + name: "Happy case no nonce", + opts: AttestOpts{ + Nonce: someNonce, + TEEDevice: &TdxQuoteProvider{mockTdxQuoteProvider}, + }, + wantReportData: someNonce64, + }, + { + name: "Happy case with nonce", + opts: AttestOpts{ + Nonce: someNonce, + TEEDevice: &TdxQuoteProvider{mockTdxQuoteProvider}, + TEENonce: nonce64[:], + }, + wantReportData: nonce64, + }, + { + name: "TEE nonce without TEE", + opts: AttestOpts{ + Nonce: someNonce, + TEENonce: nonce64[:], + }, + wantErr: "got non-nil TEENonce when TEEDevice is nil", + }, + } + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + att, err := ak.Attest(tc.opts) + if (err == nil && tc.wantErr != "") || (err != nil && !strings.Contains(err.Error(), tc.wantErr)) { + t.Fatalf("Attest(%v) = %v, want %q", tc.opts, err, tc.wantErr) + } + // Successful attestation should include a TDX attestation. + if err == nil { + _, ok := att.GetTeeAttestation().(*pb.Attestation_TdxAttestation) + if !ok { + t.Fatalf("Attestation missing TDX attestation: %v", att.GetTeeAttestation()) + } + } + }) + } +} diff --git a/cmd/attest.go b/cmd/attest.go index 0fad64f6..6e2dfff9 100644 --- a/cmd/attest.go +++ b/cmd/attest.go @@ -88,9 +88,9 @@ hardware and guarantees a fresh quote. } attestOpts.TEENonce = teeNonce case Tdx: - attestOpts.TEEDevice, err = client.CreateTdxDevice() + attestOpts.TEEDevice, err = client.CreateTdxQuoteProvider() if err != nil { - return fmt.Errorf("failed to open %s device: %v", Tdx, err) + return fmt.Errorf("failed to create %s quote provider: %v", Tdx, err) } attestOpts.TEENonce = teeNonce case "": diff --git a/cmd/attest_test.go b/cmd/attest_test.go index 8cc3bcf1..85ce3467 100644 --- a/cmd/attest_test.go +++ b/cmd/attest_test.go @@ -341,12 +341,11 @@ func TestTdxAttestTeeNonceFail(t *testing.T) { } // TEENonce with length less than 64 bytes. - tdxTestDevice := tgtestclient.GetTdxGuest([]tgtest.TestCase{ + mockTdxQuoteProvider := tgtestclient.GetMockTdxQuoteProvider([]tgtest.TestCase{ { Input: [64]byte{1, 2, 3, 4}, }, }, t) - defer tdxTestDevice.Close() ak, err := client.AttestationKeyRSA(rwc) if err != nil { @@ -356,7 +355,7 @@ func TestTdxAttestTeeNonceFail(t *testing.T) { attestopts := client.AttestOpts{ Nonce: []byte{1, 2, 3, 4}, TEENonce: []byte{1, 2, 3, 4}, - TEEDevice: &client.TdxDevice{Device: tdxTestDevice}, + TEEDevice: &client.TdxQuoteProvider{QuoteProvider: mockTdxQuoteProvider}, } _, err = ak.Attest(attestopts) if err == nil { @@ -380,7 +379,7 @@ func TestHardwareAttestationPass(t *testing.T) { teetech string wanterr string }{ - {"TdxPass", "1234", "tdx", "failed to open tdx device"}, + {"TdxPass", "1234", "tdx", "failed to create tdx quote provider"}, {"SevSnpPass", "1234", "sev-snp", "failed to open sev-snp device"}, } for _, op := range tests { diff --git a/cmd/verify_test.go b/cmd/verify_test.go index 5f6c0bdd..3c9db357 100644 --- a/cmd/verify_test.go +++ b/cmd/verify_test.go @@ -123,7 +123,7 @@ func TestHwAttestationPass(t *testing.T) { teetech string wanterr string }{ - {"TdxPass", "1234", "tdx", "failed to open tdx device"}, + {"TdxPass", "1234", "tdx", "failed to create tdx quote provider"}, {"SevSnpPass", "1234", "sev-snp", "failed to open sev-snp device"}, } for _, op := range tests { diff --git a/go.mod b/go.mod index d42314f3..2b3bdaba 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/google/go-attestation v0.5.0 github.com/google/go-cmp v0.5.9 github.com/google/go-sev-guest v0.9.3 - github.com/google/go-tdx-guest v0.2.3-0.20231011100059-4cf02bed9d33 + github.com/google/go-tdx-guest v0.2.3-0.20231222042644-aeefcb0d0eb3 github.com/google/go-tpm v0.9.0 github.com/google/logger v1.1.1 google.golang.org/protobuf v1.31.0 @@ -21,6 +21,6 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/stretchr/testify v1.8.3 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.13.0 // indirect - golang.org/x/sys v0.12.0 // indirect + golang.org/x/crypto v0.17.0 // indirect + golang.org/x/sys v0.15.0 // indirect ) diff --git a/go.sum b/go.sum index 3ce8203c..98158289 100644 --- a/go.sum +++ b/go.sum @@ -312,6 +312,8 @@ github.com/google/go-sev-guest v0.9.3 h1:GOJ+EipURdeWFl/YYdgcCxyPeMgQUWlI056iFkB github.com/google/go-sev-guest v0.9.3/go.mod h1:hc1R4R6f8+NcJwITs0L90fYWTsBpd1Ix+Gur15sqHDs= github.com/google/go-tdx-guest v0.2.3-0.20231011100059-4cf02bed9d33 h1:lRlUusuieEuqljjihCXb+Mr73VNitOYPJYWXzJKtBWs= github.com/google/go-tdx-guest v0.2.3-0.20231011100059-4cf02bed9d33/go.mod h1:84ut3oago/BqPXD4ppiGXdkZNW3WFPkcyAO4my2hXdY= +github.com/google/go-tdx-guest v0.2.3-0.20231222042644-aeefcb0d0eb3 h1:0EpD00z41G8EjJsHmO54BoUb3izF8/hgUzAzmlo6mCk= +github.com/google/go-tdx-guest v0.2.3-0.20231222042644-aeefcb0d0eb3/go.mod h1:Iut2YE9wI7DbuNY9hFcExiUH5oeayMkHNgh/JpByzHQ= github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU= github.com/google/go-tspi v0.3.0 h1:ADtq8RKfP+jrTyIWIZDIYcKOMecRqNJFOew2IT0Inus= @@ -765,6 +767,7 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -959,6 +962,7 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/go.work.sum b/go.work.sum index 90f9abdc..dd39ee00 100644 --- a/go.work.sum +++ b/go.work.sum @@ -193,21 +193,21 @@ cloud.google.com/go/webrisk v1.9.2/go.mod h1:pY9kfDgAqxUpDBOrG4w8deLfhvJmejKB0qd cloud.google.com/go/websecurityscanner v1.6.2/go.mod h1:7YgjuU5tun7Eg2kpKgGnDuEOXWIrh8x8lWrJT4zfmas= cloud.google.com/go/workflows v1.12.1/go.mod h1:5A95OhD/edtOhQd/O741NSfIMezNTbCwLM1P1tBRGHM= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= -github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU= -github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e h1:BWhy2j3IXJhjCbC68FptL43tDKIq8FladmaTs3Xs7Z8= github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= +github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU= +github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= +github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e h1:BWhy2j3IXJhjCbC68FptL43tDKIq8FladmaTs3Xs7Z8= github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-pkcs11 v0.2.1-0.20230907215043-c6f79328ddf9/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY= +github.com/google/go-sev-guest v0.8.0/go.mod h1:hc1R4R6f8+NcJwITs0L90fYWTsBpd1Ix+Gur15sqHDs= github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -218,6 +218,7 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= @@ -238,12 +239,15 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= diff --git a/server/verify_tdx.go b/server/verify_tdx.go index 8867e4ed..6cf4c33d 100644 --- a/server/verify_tdx.go +++ b/server/verify_tdx.go @@ -1,7 +1,6 @@ package server import ( - tpb "github.com/google/go-tdx-guest/proto/tdx" tv "github.com/google/go-tdx-guest/verify" ) @@ -18,8 +17,11 @@ func TdxDefaultOptions() *VerifyTdxOpts { } } -// VerifyTdxAttestation checks that the TDX attestation quote is valid -func VerifyTdxAttestation(attestation *tpb.QuoteV4, opts *VerifyTdxOpts) error { +// VerifyTdxAttestation checks that the TDX attestation quote is valid. The TEE-specific attestation +// quote is extracted from the Attestation protobuf. At a granular level, this quote is fetched via +// go-tdx-guest's GetQuote client API. +// Supported quote formats - QuoteV4. +func VerifyTdxAttestation(tdxAttestationQuote any, opts *VerifyTdxOpts) error { // Check that the quote contains valid signature and certificates. Do not check revocations. - return tv.TdxQuote(attestation, opts.Verification) + return tv.TdxQuote(tdxAttestationQuote, opts.Verification) } diff --git a/server/verify_test.go b/server/verify_test.go index 2de92944..88043d9a 100644 --- a/server/verify_test.go +++ b/server/verify_test.go @@ -361,17 +361,15 @@ func TestVerifyBasicAttestationWithTdx(t *testing.T) { nonce := []byte("super secret nonce") var nonce64 [64]byte copy(nonce64[:], nonce) - tdxTestDevice := tgtestclient.GetTdxGuest([]tgtest.TestCase{ + mockTdxQuoteProvider := tgtestclient.GetMockTdxQuoteProvider([]tgtest.TestCase{ { Input: nonce64, Quote: tgtestdata.RawQuote, }, }, t) - - defer tdxTestDevice.Close() attestation, err := ak.Attest(client.AttestOpts{ Nonce: nonce, - TEEDevice: &client.TdxDevice{Device: tdxTestDevice}, + TEEDevice: &client.TdxQuoteProvider{QuoteProvider: mockTdxQuoteProvider}, TEENonce: nonce64[:], }) @@ -1144,54 +1142,49 @@ func TestVerifyAttestationWithTdx(t *testing.T) { altNonce := []byte("alternate secret nonce") var nonce64 [64]byte copy(nonce64[:], altNonce) - tdxTestDevice := tgtestclient.GetTdxGuest([]tgtest.TestCase{ + mockTdxQuoteProvider := tgtestclient.GetMockTdxQuoteProvider([]tgtest.TestCase{ { Input: nonce64, Quote: tgtestdata.RawQuote, }, }, t) - defer tdxTestDevice.Close() attestation, err := ak.Attest(client.AttestOpts{ Nonce: nonce, - TEEDevice: &client.TdxDevice{Device: tdxTestDevice}, + TEEDevice: &client.TdxQuoteProvider{QuoteProvider: mockTdxQuoteProvider}, TEENonce: nonce64[:], }) if err != nil { t.Fatalf("failed to attest: %v", err) } - alterQuote1 := make([]byte, len(tgtestdata.RawQuote)) copy(alterQuote1[:], tgtestdata.RawQuote) alterQuote1[0x1E] = 0x32 - tdxTestDevice1 := tgtestclient.GetTdxGuest([]tgtest.TestCase{ + mockTdxQuoteProvider1 := tgtestclient.GetMockTdxQuoteProvider([]tgtest.TestCase{ { Input: nonce64, Quote: alterQuote1, }, }, t) - defer tdxTestDevice1.Close() attestation1, err := ak.Attest(client.AttestOpts{ Nonce: nonce, - TEEDevice: &client.TdxDevice{Device: tdxTestDevice1}, + TEEDevice: &client.TdxQuoteProvider{QuoteProvider: mockTdxQuoteProvider1}, TEENonce: nonce64[:], }) if err != nil { t.Fatalf("failed to attest: %v", err) } - alterQuote2 := make([]byte, len(tgtestdata.RawQuote)) copy(alterQuote2[:], tgtestdata.RawQuote) alterQuote1[0x1024] = 0x32 - tdxTestDevice2 := tgtestclient.GetTdxGuest([]tgtest.TestCase{ + mockTdxQuoteProvider2 := tgtestclient.GetMockTdxQuoteProvider([]tgtest.TestCase{ { Input: nonce64, Quote: alterQuote1, }, }, t) - defer tdxTestDevice1.Close() attestation2, err := ak.Attest(client.AttestOpts{ Nonce: nonce, - TEEDevice: &client.TdxDevice{Device: tdxTestDevice2}, + TEEDevice: &client.TdxQuoteProvider{QuoteProvider: mockTdxQuoteProvider2}, TEENonce: nonce64[:], }) if err != nil {