From da94f9169094ee933f959c9b389ceb806ec71801 Mon Sep 17 00:00:00 2001 From: Dionna Glaze Date: Fri, 2 Feb 2024 17:37:10 +0000 Subject: [PATCH 1/3] Add Apache license preambles to new files Missed these in PR#105. Signed-off-by: Dionna Glaze --- tools/lib/report/report.go | 14 ++++++++++++++ tools/show/main.go | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/tools/lib/report/report.go b/tools/lib/report/report.go index a512e25..7daae7a 100644 --- a/tools/lib/report/report.go +++ b/tools/lib/report/report.go @@ -1,3 +1,17 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Package report provides functions for reading and writing attestation reports of various formats. package report diff --git a/tools/show/main.go b/tools/show/main.go index aa6950b..48c28f5 100644 --- a/tools/show/main.go +++ b/tools/show/main.go @@ -1,3 +1,17 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // show reads an attestation report and outputs it in a preferred format. package main From 5349ff7682ac5c1c2efdecd8aab43152e489080e Mon Sep 17 00:00:00 2001 From: Dionna Glaze Date: Fri, 2 Feb 2024 17:38:50 +0000 Subject: [PATCH 2/3] Rename GetAttestation to ReadAttestation Internal naming guidelines say to avoid "Get" unless meant for http GET requests. Signed-off-by: Dionna Glaze --- tools/check/check.go | 2 +- tools/lib/report/report.go | 4 ++-- tools/show/main.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/check/check.go b/tools/check/check.go index e774821..19d3751 100644 --- a/tools/check/check.go +++ b/tools/check/check.go @@ -476,7 +476,7 @@ func main() { die(errors.New("cannot specify both -check_crl=true and -network=false")) } - attestation, err := report.GetAttestation(*infile, *inform) + attestation, err := report.ReadAttestation(*infile, *inform) if err != nil { die(err) } diff --git a/tools/lib/report/report.go b/tools/lib/report/report.go index 7daae7a..36c1ca8 100644 --- a/tools/lib/report/report.go +++ b/tools/lib/report/report.go @@ -87,8 +87,8 @@ func ParseAttestation(b []byte, inform string) (*spb.Attestation, error) { return nil, errors.New("internal error") } -// GetAttestation reads an attestation report from a file. -func GetAttestation(infile, inform string) (*spb.Attestation, error) { +// ReadAttestation reads an attestation report from a file. +func ReadAttestation(infile, inform string) (*spb.Attestation, error) { var in io.Reader var f *os.File if infile == "-" { diff --git a/tools/show/main.go b/tools/show/main.go index 48c28f5..21a2989 100644 --- a/tools/show/main.go +++ b/tools/show/main.go @@ -36,7 +36,7 @@ func main() { logger.Init("", false, false, os.Stderr) flag.Parse() - attestation, err := report.GetAttestation(*infile, *inform) + attestation, err := report.ReadAttestation(*infile, *inform) if err != nil { logger.Fatal(err) } From ac86ea4ffcedc600a03e698349c135f6b6441ab0 Mon Sep 17 00:00:00 2001 From: Dionna Glaze Date: Sat, 3 Feb 2024 04:00:59 +0000 Subject: [PATCH 3/3] Add tools/lib/report tests Get some test coverage and fix the bug this found. Signed-off-by: Dionna Glaze --- tools/lib/report/report.go | 4 +- tools/lib/report/report_test.go | 197 ++++++++++++++++++++++++++++++++ 2 files changed, 198 insertions(+), 3 deletions(-) create mode 100644 tools/lib/report/report_test.go diff --git a/tools/lib/report/report.go b/tools/lib/report/report.go index 36c1ca8..3ba99f8 100644 --- a/tools/lib/report/report.go +++ b/tools/lib/report/report.go @@ -16,7 +16,6 @@ package report import ( - "errors" "fmt" "io" "os" @@ -80,11 +79,10 @@ func ParseAttestation(b []byte, inform string) (*spb.Attestation, error) { return nil, fmt.Errorf("could not parse as textproto: %v", multierr.Append(aerr, rerr)) } } + return result, nil default: return nil, fmt.Errorf("unknown inform: %q", inform) } - // This should be impossible. - return nil, errors.New("internal error") } // ReadAttestation reads an attestation report from a file. diff --git a/tools/lib/report/report_test.go b/tools/lib/report/report_test.go new file mode 100644 index 0000000..8746502 --- /dev/null +++ b/tools/lib/report/report_test.go @@ -0,0 +1,197 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package report + +import ( + "bytes" + "fmt" + "os" + "path" + "sync" + "testing" + "time" + + "github.com/google/go-sev-guest/abi" + "github.com/google/go-sev-guest/client" + spb "github.com/google/go-sev-guest/proto/sevsnp" + test "github.com/google/go-sev-guest/testing" + "google.golang.org/protobuf/encoding/prototext" + "google.golang.org/protobuf/proto" +) + +var qp client.QuoteProvider +var mu sync.Once + +type reports struct { + attestation *spb.Attestation + bincerts []byte + binreport []byte + protocerts []byte + protoreport []byte + textcerts []byte + textreport []byte +} + +var input *reports + +func initDevice() { + now := time.Date(2022, time.May, 3, 9, 0, 0, 0, time.UTC) + tests := test.TestCases() + ones32 := make([]byte, 32) + for i := range ones32 { + ones32[i] = 1 + } + opts := &test.DeviceOptions{Now: now} + tcqp, err := test.TcQuoteProvider(tests, opts) + if err != nil { + panic(fmt.Sprintf("failed to create test device: %v", err)) + } + qp = tcqp + + var zeros [abi.ReportDataSize]byte + bincerts, err := qp.GetRawQuote(zeros) + if err != nil { + panic(fmt.Errorf("mock failed to quote: %v", err)) + } + if len(bincerts) < abi.ReportSize+abi.CertTableEntrySize { + panic("mock failed to return cert table") + } + binreport := bincerts[:abi.ReportSize] + attestation, err := ParseAttestation(bincerts, "bin") + if err != nil { + panic(fmt.Errorf("marshal failure: %v", err)) + } + protocerts, err := proto.Marshal(attestation) + if err != nil { + panic(fmt.Errorf("marshal failure: %v", err)) + } + protoreport, err := proto.Marshal(attestation.Report) + if err != nil { + panic(fmt.Errorf("marshal failure: %v", err)) + } + textcerts, err := prototext.MarshalOptions{Multiline: true, Indent: " "}.Marshal(attestation) + if err != nil { + panic(fmt.Errorf("marshal failure: %v", err)) + } + textreport, err := prototext.MarshalOptions{Multiline: true, Indent: " "}.Marshal(attestation.Report) + if err != nil { + panic(fmt.Errorf("marshal failure: %v", err)) + } + input = &reports{ + attestation: attestation, + bincerts: bincerts, + binreport: binreport, + protocerts: protocerts, + protoreport: protoreport, + textcerts: textcerts, + textreport: textreport, + } +} + +func TestParseAttestation(t *testing.T) { + mu.Do(initDevice) + type testcase struct { + input []byte + inform string + } + good := []testcase{ + {input.bincerts, "bin"}, + {input.binreport, "bin"}, + {input.protocerts, "proto"}, + {input.protoreport, "proto"}, + {input.textcerts, "textproto"}, + {input.textreport, "textproto"}, + } + bad := []testcase{ + {input.bincerts, "proto"}, + {input.textcerts, "bin"}, + {input.protoreport, "textproto"}, + } + for _, tc := range good { + if _, err := ParseAttestation(tc.input, tc.inform); err != nil { + t.Fatalf("ParseAttestation(_, %q) = _, %v. Expect nil", tc.inform, err) + } + } + for _, tc := range bad { + if _, err := ParseAttestation(tc.input, tc.inform); err == nil { + t.Fatalf("ParseAttestation(_, %q) = _, nil. Expected an error", tc.inform) + } + } +} + +func TestReadAttestation(t *testing.T) { + mu.Do(initDevice) + type testcase struct { + input []byte + inform string + } + good := []testcase{ + {input.bincerts, "bin"}, + {input.binreport, "bin"}, + {input.protocerts, "proto"}, + {input.protoreport, "proto"}, + {input.textcerts, "textproto"}, + {input.textreport, "textproto"}, + } + bad := []testcase{ + {input.bincerts, "proto"}, + {input.textcerts, "bin"}, + {input.protoreport, "textproto"}, + } + for _, tc := range good { + p := path.Join(t.TempDir(), "input") + if err := os.WriteFile(p, tc.input, 0644); err != nil { + t.Fatalf("Could not write test file %q: %v", p, err) + } + if _, err := ReadAttestation(p, tc.inform); err != nil { + t.Fatalf("ParseAttestation(_, %q) = _, %v. Expect nil", tc.inform, err) + } + } + for _, tc := range bad { + p := path.Join(t.TempDir(), "input") + if err := os.WriteFile(p, tc.input, 0644); err != nil { + t.Fatalf("Could not write test file %q: %v", p, err) + } + if _, err := ReadAttestation(p, tc.inform); err == nil { + t.Fatalf("ReadAttestation(_, %q) = _, nil. Expected an error", tc.inform) + } + } +} + +func TestTransform(t *testing.T) { + mu.Do(initDevice) + binout, err := Transform(input.attestation, "bin") + if err != nil { + t.Fatalf("Transform(_, \"bin\") = _, %v. Expect nil.", err) + } + if !bytes.Equal(binout, input.bincerts) { + t.Fatalf("Transform(_, \"bin\") = %v, nil. Expect %v.", binout, input.bincerts) + } + protoout, err := Transform(input.attestation, "proto") + if err != nil { + t.Fatalf("Transform(_, \"proto\") = _, %v. Expect nil.", err) + } + if !bytes.Equal(protoout, input.protocerts) { + t.Fatalf("Transform(_, \"proto\") = %v, nil. Expect %v.", protoout, input.protocerts) + } + textout, err := Transform(input.attestation, "textproto") + if err != nil { + t.Fatalf("Transform(_, \"textproto\") = _, %v. Expect nil.", err) + } + if !bytes.Equal(textout, input.textcerts) { + t.Fatalf("Transform(_, \"textproto\") = %v, nil. Expect %v.", string(textout), string(input.textcerts)) + } + +}