From 446f030547667c5010caa97ea31cf826c9ce9a97 Mon Sep 17 00:00:00 2001 From: Razieh Behjati Date: Fri, 7 Jul 2023 22:51:43 +0100 Subject: [PATCH 01/13] Replace ReferenceValues with proto and allow no provenance verification --- cmd/verifier/main.go | 3 +- docs/development-guidelines.md | 24 + internal/endorser/endorser.go | 7 +- internal/endorser/endorser_test.go | 56 ++- internal/verification/reference.go | 50 -- internal/verification/reference_test.go | 38 -- internal/verification/verifier.go | 87 ++-- internal/verification/verifier_test.go | 130 ++++-- .../provenance_verification.pb.go | 441 ++++++++++++++++++ proto/provenance_verification.proto | 45 ++ testdata/different_reference_values.textproto | 17 + testdata/different_reference_values.toml | 4 - testdata/reference_values.textproto | 19 + testdata/reference_values.toml | 5 - 14 files changed, 734 insertions(+), 192 deletions(-) delete mode 100644 internal/verification/reference.go delete mode 100644 internal/verification/reference_test.go create mode 100644 pkg/proto/verification/provenance_verification.pb.go create mode 100644 proto/provenance_verification.proto create mode 100644 testdata/different_reference_values.textproto delete mode 100644 testdata/different_reference_values.toml create mode 100644 testdata/reference_values.textproto delete mode 100644 testdata/reference_values.toml diff --git a/cmd/verifier/main.go b/cmd/verifier/main.go index 5afb42fc..6d772c20 100644 --- a/cmd/verifier/main.go +++ b/cmd/verifier/main.go @@ -22,6 +22,7 @@ import ( "github.com/project-oak/transparent-release/internal/model" "github.com/project-oak/transparent-release/internal/verification" + prover "github.com/project-oak/transparent-release/pkg/proto/verification" ) func main() { @@ -46,7 +47,7 @@ func main() { provenanceVerifier := verification.ProvenanceIRVerifier{ Got: provenanceIR, - Want: &verification.ReferenceValues{}, + Want: &prover.VerificationOptions{}, } if err := provenanceVerifier.Verify(); err != nil { diff --git a/docs/development-guidelines.md b/docs/development-guidelines.md index 73854884..253a7fd8 100644 --- a/docs/development-guidelines.md +++ b/docs/development-guidelines.md @@ -23,3 +23,27 @@ You need to have: - Format files: `./scripts/formatting.sh` - Check linting: `./scripts/linting.sh` - Additional checks: `go vet ./...` + +## Using protocol buffers + +See instructions for compiling protocol buffers in the +[original guide](https://protobuf.dev/getting-started/gotutorial/#compiling-protocol-buffers). Here +is a summary: + +1. If you haven’t installed the compiler, [download the package](https://protobuf.dev/downloads) and + follow the instructions in the README. + +2. Run the following command to install the Go protocol buffers plugin: + +```bash +go install google.golang.org/protobuf/cmd/protoc-gen-go@latest +``` + +3. Run the compiler to generate the go code. Specify the source directory (where your application’s + source code lives – the current directory is used if you don’t provide a value), the destination + directory (where you want the generated code to go; often the same as $SRC_DIR), and the path to + your .proto: + +```bash +protoc -I=$SRC_DIR --go_out=$DST_DIR $SRC_DIR/provenance_verification.proto +``` diff --git a/internal/endorser/endorser.go b/internal/endorser/endorser.go index 1fd77034..b81b7687 100644 --- a/internal/endorser/endorser.go +++ b/internal/endorser/endorser.go @@ -32,6 +32,7 @@ import ( "github.com/project-oak/transparent-release/internal/verification" "github.com/project-oak/transparent-release/pkg/claims" "github.com/project-oak/transparent-release/pkg/intoto" + prover "github.com/project-oak/transparent-release/pkg/proto/verification" ) // ParsedProvenance contains a provenance in the internal ProvenanceIR format, @@ -47,7 +48,7 @@ type ParsedProvenance struct { // the given provenances as evidence and reference values to verify them. At least one provenance // must be provided. The endorsement statement is generated only if the provenance statements are // valid. -func GenerateEndorsement(referenceValues *verification.ReferenceValues, validityDuration claims.ClaimValidity, provenances []ParsedProvenance) (*intoto.Statement, error) { +func GenerateEndorsement(referenceValues *prover.VerificationOptions, validityDuration claims.ClaimValidity, provenances []ParsedProvenance) (*intoto.Statement, error) { verifiedProvenances, err := verifyAndSummarizeProvenances(referenceValues, provenances) if err != nil { return nil, fmt.Errorf("could not verify and summarize provenances: %v", err) @@ -61,7 +62,7 @@ func GenerateEndorsement(referenceValues *verification.ReferenceValues, validity // (1) The list of provenances is empty, // (2) Any of the provenances is invalid (see verifyProvenances for details on validity), // (3) Provenances do not match (e.g., have different binary names). -func verifyAndSummarizeProvenances(referenceValues *verification.ReferenceValues, provenances []ParsedProvenance) (*claims.VerifiedProvenanceSet, error) { +func verifyAndSummarizeProvenances(referenceValues *prover.VerificationOptions, provenances []ParsedProvenance) (*claims.VerifiedProvenanceSet, error) { if len(provenances) == 0 { return nil, fmt.Errorf("at least one provenance file must be provided") } @@ -88,7 +89,7 @@ func verifyAndSummarizeProvenances(referenceValues *verification.ReferenceValues } // verifyProvenances verifies the given list of provenances. An error is returned if verification fails for one of them. -func verifyProvenances(referenceValues *verification.ReferenceValues, provenances []model.ProvenanceIR) error { +func verifyProvenances(referenceValues *prover.VerificationOptions, provenances []model.ProvenanceIR) error { var errs error for index := range provenances { provenanceVerifier := verification.ProvenanceIRVerifier{ diff --git a/internal/endorser/endorser_test.go b/internal/endorser/endorser_test.go index fe92fed9..db9c4234 100644 --- a/internal/endorser/endorser_test.go +++ b/internal/endorser/endorser_test.go @@ -22,14 +22,15 @@ import ( "time" "github.com/project-oak/transparent-release/internal/testutil" - "github.com/project-oak/transparent-release/internal/verification" "github.com/project-oak/transparent-release/pkg/claims" + prover "github.com/project-oak/transparent-release/pkg/proto/verification" + "google.golang.org/protobuf/encoding/prototext" ) const ( binaryHash = "d059c38cea82047ad316a1c6c6fbd13ecf7a0abdcc375463920bd25bf5c142cc" binaryName = "oak_functions_freestanding_bin" - errorBinaryDigest = "do not contain the actual binary SHA256 digest" + errorBinaryDigest = "do not contain the actual SHA256 digest" ) func TestGenerateEndorsement_SingleValidEndorsement(t *testing.T) { @@ -50,7 +51,7 @@ func TestGenerateEndorsement_SingleValidEndorsement(t *testing.T) { t.Fatalf("Could not load provenances: %v", err) } - referenceValues, err := verification.LoadReferenceValuesFromFile("../../testdata/reference_values.toml") + referenceValues, err := loadTextprotoVerificationOptions("../../testdata/reference_values.textproto") if err != nil { t.Fatalf("Could not load reference values: %v", err) } @@ -83,9 +84,13 @@ func TestLoadAndVerifyProvenances_MultipleValidEndorsement(t *testing.T) { t.Fatalf("Could not load provenances: %v", err) } - referenceValues := verification.ReferenceValues{ - // Make sure we pick the correct binary hash if there are several reference values. - BinarySHA256Digests: []string{binaryHash + "_diff", binaryHash}, + referenceValues := prover.VerificationOptions{ + ReferenceProvenance: &prover.ProvenanceReferenceValues{ + // Make sure we pick the correct binary hash if there are several reference values. + ReferenceBinaryDigests: &prover.Digests{ + Digests: map[string]*prover.StringAllowList{"sha256": &prover.StringAllowList{Values: []string{binaryHash + "_diff", binaryHash}}}, + }, + }, } provenanceSet, err := verifyAndSummarizeProvenances(&referenceValues, provenances) if err != nil { @@ -114,8 +119,12 @@ func TestLoadAndVerifyProvenances_ConsistentNotVerified(t *testing.T) { if err != nil { t.Fatalf("Could not load provenances: %v", err) } - referenceValues := verification.ReferenceValues{ - BinarySHA256Digests: []string{binaryHash + "_diff"}, + referenceValues := prover.VerificationOptions{ + ReferenceProvenance: &prover.ProvenanceReferenceValues{ + ReferenceBinaryDigests: &prover.Digests{ + Digests: map[string]*prover.StringAllowList{"sha256": &prover.StringAllowList{Values: []string{binaryHash + "_diff"}}}, + }, + }, } // Provenances do not contain the given reference binary SHA256 digest value, but are consistent. @@ -140,8 +149,12 @@ func TestLoadAndVerify_InconsistentVerified(t *testing.T) { if err != nil { t.Fatalf("Could not load provenances: %v", err) } - referenceValues := verification.ReferenceValues{ - BinarySHA256Digests: []string{"e8e05d1d09af8952919bf6ab38e0cc5a6414ee2b5e21f4765b12421c5db0037e", binaryHash}, + referenceValues := prover.VerificationOptions{ + ReferenceProvenance: &prover.ProvenanceReferenceValues{ + ReferenceBinaryDigests: &prover.Digests{ + Digests: map[string]*prover.StringAllowList{"sha256": &prover.StringAllowList{Values: []string{"e8e05d1d09af8952919bf6ab38e0cc5a6414ee2b5e21f4765b12421c5db0037e", binaryHash}}}, + }, + }, } // Provenances each contain a (different) given reference binary SHA256 digest value, but are inconsistent. @@ -167,8 +180,12 @@ func TestLoadAndVerify_InconsistentNotVerified(t *testing.T) { if err != nil { t.Fatalf("Could not load provenances: %v", err) } - referenceValues := verification.ReferenceValues{ - BinarySHA256Digests: []string{binaryHash + "_diff"}, + referenceValues := prover.VerificationOptions{ + ReferenceProvenance: &prover.ProvenanceReferenceValues{ + ReferenceBinaryDigests: &prover.Digests{ + Digests: map[string]*prover.StringAllowList{"sha256": &prover.StringAllowList{Values: []string{binaryHash + "_diff"}}}, + }, + }, } _, err = verifyAndSummarizeProvenances(&referenceValues, provenances) @@ -192,7 +209,8 @@ func TestLoadAndVerifyProvenances_NotVerified(t *testing.T) { if err != nil { t.Fatalf("Could not load provenances: %v", err) } - referenceValues, err := verification.LoadReferenceValuesFromFile("../../testdata/different_reference_values.toml") + // referenceValues, err := verification.LoadReferenceValuesFromFile("../../testdata/different_reference_values.toml") + referenceValues, err := loadTextprotoVerificationOptions("../../testdata/different_reference_values.textproto") if err != nil { t.Fatalf("Could not load reference values: %v", err) } @@ -234,3 +252,15 @@ func copyToTemp(path string) (string, error) { return tmpfile.Name(), nil } + +func loadTextprotoVerificationOptions(path string) (*prover.VerificationOptions, error) { + bytes, err := os.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("reading provenance verification options from %q: %v", path, err) + } + var opt prover.VerificationOptions + if err := prototext.Unmarshal(bytes, &opt); err != nil { + return nil, fmt.Errorf("unmarshal bytes to VerificationOptions: %v", err) + } + return &opt, nil +} diff --git a/internal/verification/reference.go b/internal/verification/reference.go deleted file mode 100644 index adef45ea..00000000 --- a/internal/verification/reference.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2023 The Project Oak Authors -// -// 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 verification - -import ( - "fmt" - - "github.com/pelletier/go-toml" -) - -// ReferenceValues specify expected values to verify provenances against. -type ReferenceValues struct { - // Allow list of binary digests. - BinarySHA256Digests []string `toml:"binary_sha256_digests"` - // If true, expect that the provenance has a non-empty build command. - WantBuildCmds bool `toml:"want_build_cmds"` - // Allow list of builder image digests that are trusted for building the binary. - BuilderImageSHA256Digests []string `toml:"builder_image_sha256_digests"` - // The URI of the repo holding the resources the binary is built from. - RepoURI string `toml:"repo_uri"` - // Allow list of builders trusted to build the binary. - TrustedBuilders []string `toml:"trusted_builders"` -} - -// LoadReferenceValuesFromFile loads reference values from a toml file in the given path and returns an instance of ReferenceValues. -func LoadReferenceValuesFromFile(path string) (*ReferenceValues, error) { - tomlTree, err := toml.LoadFile(path) - if err != nil { - return nil, fmt.Errorf("couldn't load toml file: %v", err) - } - - referenceValues := ReferenceValues{} - if err := tomlTree.Unmarshal(&referenceValues); err != nil { - return nil, fmt.Errorf("couldn't unmarshal toml file: %v", err) - } - - return &referenceValues, nil -} diff --git a/internal/verification/reference_test.go b/internal/verification/reference_test.go deleted file mode 100644 index 8fa0b852..00000000 --- a/internal/verification/reference_test.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2023 The Project Oak Authors -// -// 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 verification - -import ( - "path/filepath" - "testing" - - "github.com/project-oak/transparent-release/internal/testutil" -) - -const ( - testdataPath = "../../testdata/" -) - -func TestParseReferenceValues(t *testing.T) { - path := filepath.Join(testdataPath, "reference_values.toml") - referenceValues, err := LoadReferenceValuesFromFile(path) - if err != nil { - t.Fatalf("couldn't load reference values file: %v", err) - } - - testutil.AssertEq(t, "binary digests[0]", referenceValues.BinarySHA256Digests[0], "d059c38cea82047ad316a1c6c6fbd13ecf7a0abdcc375463920bd25bf5c142cc") - testutil.AssertEq(t, "want build cmd", referenceValues.WantBuildCmds, false) - testutil.AssertEq(t, "builder image digests[0]", referenceValues.BuilderImageSHA256Digests[0], "9e2ba52487d945504d250de186cb4fe2e3ba023ed2921dd6ac8b97ed43e76af9") -} diff --git a/internal/verification/verifier.go b/internal/verification/verifier.go index 2e59258d..7b7c7140 100644 --- a/internal/verification/verifier.go +++ b/internal/verification/verifier.go @@ -19,6 +19,7 @@ import ( "fmt" "github.com/project-oak/transparent-release/internal/model" + prover "github.com/project-oak/transparent-release/pkg/proto/verification" "go.uber.org/multierr" ) @@ -26,12 +27,16 @@ import ( // all non-empty fields in got using fields in the reference values. Empty fields will not be verified. type ProvenanceIRVerifier struct { Got *model.ProvenanceIR - Want *ReferenceValues + Want *prover.VerificationOptions } // Verify verifies an instance of ProvenanceIRVerifier by comparing its Got and Want fields. // Verify checks fields, which (i) are set in Got, i.e., GotHasX is true, and (ii) are set in Want. func (v *ProvenanceIRVerifier) Verify() error { + if v.Want.GetReferenceProvenance() == nil { + return nil + } + var errs error if err := v.verifyBinarySHA256Digest(); err != nil { @@ -60,26 +65,20 @@ func (v *ProvenanceIRVerifier) Verify() error { // verifyBinarySHA256Digest verifies that the binary SHA256 Got in this // verifier is among the Wanted digests. func (v *ProvenanceIRVerifier) verifyBinarySHA256Digest() error { - if v.Want.BinarySHA256Digests == nil { - return nil - } - + referenceDigests := v.Want.GetReferenceProvenance().GetReferenceBinaryDigests() gotBinarySHA256Digest := v.Got.BinarySHA256Digest() - for _, wantBinarySHA256Digest := range v.Want.BinarySHA256Digests { - if wantBinarySHA256Digest == gotBinarySHA256Digest { - return nil - } + if err := verifySHA256Digest(gotBinarySHA256Digest, referenceDigests); err != nil { + return fmt.Errorf("verifying binary SHA356 digest: %v", err) } - return fmt.Errorf("the reference binary SHA256 digests (%v) do not contain the actual binary SHA256 digest (%v)", - v.Want.BinarySHA256Digests, - gotBinarySHA256Digest) + return nil } // verifyBuildCmd verifies the build cmd. Returns an error if a build command is // needed in the Want reference values, but is not present in the Got provenance. func (v *ProvenanceIRVerifier) verifyBuildCmd() error { - if v.Got.HasBuildCmd() && v.Want.WantBuildCmds { + mustHaveBuildCommand := v.Want.GetReferenceProvenance().GetMustHaveBuildCommand() + if mustHaveBuildCommand && v.Got.HasBuildCmd() { if buildCmd, err := v.Got.BuildCmd(); err != nil || len(buildCmd) == 0 { return fmt.Errorf("no build cmd found") } @@ -90,59 +89,83 @@ func (v *ProvenanceIRVerifier) verifyBuildCmd() error { // verifyBuilderImageDigest verifies that the builder image digest in the Got // provenance matches a builder image digest in the Want reference values. func (v *ProvenanceIRVerifier) verifyBuilderImageDigest() error { - if !v.Got.HasBuilderImageSHA256Digest() || v.Want.BuilderImageSHA256Digests == nil { + if !v.Got.HasBuilderImageSHA256Digest() { + // A valid provenance that is missing a builder image digest passes the + // verification. return nil } + referenceDigests := v.Want.GetReferenceProvenance().GetReferenceBuilderImageDigests() gotBuilderImageDigest, err := v.Got.BuilderImageSHA256Digest() - if err != nil { + if err != nil && referenceDigests != nil { return fmt.Errorf("no builder image digest set") } - for _, wantBuilderImageSHA256Digest := range v.Want.BuilderImageSHA256Digests { - if wantBuilderImageSHA256Digest == gotBuilderImageDigest { - return nil - } + if err := verifySHA256Digest(gotBuilderImageDigest, referenceDigests); err != nil { + return fmt.Errorf("verifying builder image SHA356 digest: %v", err) } - - return fmt.Errorf("the reference builder image digests (%v) do not contain the actual builder image digest (%v)", - v.Want.BuilderImageSHA256Digests, - gotBuilderImageDigest) + return nil } // verifyRepoURI verifies that the Git URI in the Got provenance // is the same as the repo URI in the Want reference values. func (v *ProvenanceIRVerifier) verifyRepoURI() error { - var errs error - - if !v.Got.HasRepoURI() || v.Want.RepoURI == "" { + referenceRepoURI := v.Want.GetReferenceProvenance().GetReferenceRepo_URI() + if referenceRepoURI == "" { return nil } - if v.Got.RepoURI() != v.Want.RepoURI { - multierr.AppendInto(&errs, fmt.Errorf("the URI from the provenance (%v) is different from the repo URI (%v)", v.Got.RepoURI(), v.Want.RepoURI)) + if !v.Got.HasRepoURI() { + return fmt.Errorf("no repo URI in the provenance, but want (%v)", referenceRepoURI) } - return errs + if v.Got.RepoURI() != referenceRepoURI { + return fmt.Errorf("the repo URI from the provenance (%v) is different from the repo URI (%v)", v.Got.RepoURI(), referenceRepoURI) + } + + return nil } // verifyTrustedBuilder verifies that the given trusted builder matches a trusted builder in the reference values. func (v *ProvenanceIRVerifier) verifyTrustedBuilder() error { - if !v.Got.HasTrustedBuilder() || v.Want.TrustedBuilders == nil { + referenceRepoURI := v.Want.GetReferenceProvenance().GetReferenceBuilders() + if referenceRepoURI == nil { return nil } + gotTrustedBuilder, err := v.Got.TrustedBuilder() if err != nil { return fmt.Errorf("no trusted builder set") } - for _, wantTrustedBuilder := range v.Want.TrustedBuilders { + for _, wantTrustedBuilder := range referenceRepoURI.GetValues() { if wantTrustedBuilder == gotTrustedBuilder { return nil } } return fmt.Errorf("the reference trusted builders (%v) do not contain the actual trusted builder (%v)", - v.Want.TrustedBuilders, + referenceRepoURI.GetValues(), gotTrustedBuilder) } + +// verifySHA256Digest verifies that a given SHA256 is among the given digests. +func verifySHA256Digest(got string, want *prover.Digests) error { + if want == nil { + return nil + } + + sha256Digests, ok := want.GetDigests()["sha256"] + if !ok { + return nil + } + + for _, wantBinarySHA256Digest := range sha256Digests.GetValues() { + if wantBinarySHA256Digest == got { + return nil + } + } + return fmt.Errorf("the reference SHA256 digests (%v) do not contain the actual SHA256 digest (%v)", + sha256Digests.GetValues(), + got) +} diff --git a/internal/verification/verifier_test.go b/internal/verification/verifier_test.go index ae3a0b3e..4e78cd39 100644 --- a/internal/verification/verifier_test.go +++ b/internal/verification/verifier_test.go @@ -21,6 +21,7 @@ import ( "github.com/project-oak/transparent-release/internal/model" slsav02 "github.com/project-oak/transparent-release/pkg/intoto/slsa_provenance/v0.2" + prover "github.com/project-oak/transparent-release/pkg/proto/verification" ) const ( @@ -32,12 +33,8 @@ func TestVerify_HasNoValues(t *testing.T) { // There are no optional fields set apart from the binary digest and the build type. got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName) - want := ReferenceValues{ - // We ask for all the optional values in the reference values. - WantBuildCmds: true, - BuilderImageSHA256Digests: []string{"builder_image_digest"}, - RepoURI: "some_repo_uri", - TrustedBuilders: []string{"some_trusted_builder"}, + want := prover.VerificationOptions{ + ReferenceProvenance: &prover.ProvenanceReferenceValues{}, } verifier := ProvenanceIRVerifier{ @@ -46,7 +43,6 @@ func TestVerify_HasNoValues(t *testing.T) { } // We don't expect any verification to happen. - if err := verifier.Verify(); err != nil { t.Fatalf("verify failed, got %v", err) } @@ -55,8 +51,10 @@ func TestVerify_HasNoValues(t *testing.T) { func TestVerify_NeedsCanHaveHasBuildCmd(t *testing.T) { got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithBuildCmd([]string{"build cmd"})) - want := ReferenceValues{ - WantBuildCmds: true, + want := prover.VerificationOptions{ + ReferenceProvenance: &prover.ProvenanceReferenceValues{ + MustHaveBuildCommand: true, + }, } verifier := ProvenanceIRVerifier{ @@ -73,8 +71,10 @@ func TestVerify_NeedsCannotHaveDoesNotHaveBuildCmd(t *testing.T) { // No buildCmd is set in the provenance. got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName) - want := ReferenceValues{ - WantBuildCmds: true, + want := prover.VerificationOptions{ + ReferenceProvenance: &prover.ProvenanceReferenceValues{ + MustHaveBuildCommand: true, + }, } verifier := ProvenanceIRVerifier{ @@ -91,8 +91,10 @@ func TestVerify_NeedsCannotHaveHasEmptyBuildCmd(t *testing.T) { // The build command is empty. got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithBuildCmd([]string{})) // And the reference values ask for a build cmd. - want := ReferenceValues{ - WantBuildCmds: true, + want := prover.VerificationOptions{ + ReferenceProvenance: &prover.ProvenanceReferenceValues{ + MustHaveBuildCommand: true, + }, } verifier := ProvenanceIRVerifier{ @@ -110,8 +112,10 @@ func TestVerify_DoesNotNeedCannotHaveHasEmptyBuildCmd(t *testing.T) { // The build command is empty. got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithBuildCmd([]string{})) // But the reference values do not ask for a build cmd. - want := ReferenceValues{ - WantBuildCmds: false, + want := prover.VerificationOptions{ + ReferenceProvenance: &prover.ProvenanceReferenceValues{ + MustHaveBuildCommand: false, + }, } verifier := ProvenanceIRVerifier{ @@ -128,8 +132,12 @@ func TestVerify_DoesNotNeedCannotHaveHasEmptyBuildCmd(t *testing.T) { func TestVerify_NeedsHasBuilderImageDigest(t *testing.T) { builderDigest := "9e2ba52487d945504d250de186cb4fe2e3ba023ed2921dd6ac8b97ed43e76af9" got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithBuilderImageSHA256Digest(builderDigest)) - want := ReferenceValues{ - BuilderImageSHA256Digests: []string{"some_other_digest", builderDigest}, + want := prover.VerificationOptions{ + ReferenceProvenance: &prover.ProvenanceReferenceValues{ + ReferenceBuilderImageDigests: &prover.Digests{ + Digests: map[string]*prover.StringAllowList{"sha256": &prover.StringAllowList{Values: []string{"some_other_digest", builderDigest}}}, + }, + }, } verifier := ProvenanceIRVerifier{ @@ -145,8 +153,12 @@ func TestVerify_NeedsHasBuilderImageDigest(t *testing.T) { func TestVerify_NeedsDoesNotHaveBuilderImageDigest(t *testing.T) { builderDigest := "9e2ba52487d945504d250de186cb4fe2e3ba023ed2921dd6ac8b97ed43e76af9" got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithBuilderImageSHA256Digest(builderDigest)) - want := ReferenceValues{ - BuilderImageSHA256Digests: []string{"some_other_digest", "and_some_other"}, + want := prover.VerificationOptions{ + ReferenceProvenance: &prover.ProvenanceReferenceValues{ + ReferenceBuilderImageDigests: &prover.Digests{ + Digests: map[string]*prover.StringAllowList{"sha256": &prover.StringAllowList{Values: []string{"some_other_digest", "and_some_other"}}}, + }, + }, } verifier := ProvenanceIRVerifier{ @@ -154,8 +166,8 @@ func TestVerify_NeedsDoesNotHaveBuilderImageDigest(t *testing.T) { Want: &want, } - wantErr := fmt.Sprintf("the reference builder image digests (%v) do not contain the actual builder image digest (%v)", - want.BuilderImageSHA256Digests, + wantErr := fmt.Sprintf("the reference SHA256 digests (%v) do not contain the actual SHA256 digest (%v)", + want.GetReferenceProvenance().GetReferenceBuilderImageDigests().GetDigests()["sha256"].GetValues(), builderDigest) if err := verifier.Verify(); err == nil || !strings.Contains(err.Error(), wantErr) { t.Fatalf("got %q, want error message containing %q,", err, wantErr) @@ -164,8 +176,12 @@ func TestVerify_NeedsDoesNotHaveBuilderImageDigest(t *testing.T) { func TestVerify_NeedsHasEmptyBuilderImageDigest(t *testing.T) { got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithBuilderImageSHA256Digest("")) - want := ReferenceValues{ - BuilderImageSHA256Digests: []string{"some_digest"}, + want := prover.VerificationOptions{ + ReferenceProvenance: &prover.ProvenanceReferenceValues{ + ReferenceBuilderImageDigests: &prover.Digests{ + Digests: map[string]*prover.StringAllowList{"sha256": &prover.StringAllowList{Values: []string{"some_digest"}}}, + }, + }, } verifier := ProvenanceIRVerifier{ @@ -173,8 +189,8 @@ func TestVerify_NeedsHasEmptyBuilderImageDigest(t *testing.T) { Want: &want, } - wantErr := fmt.Sprintf("the reference builder image digests (%v) do not contain the actual builder image digest (%v)", - want.BuilderImageSHA256Digests, + wantErr := fmt.Sprintf("the reference SHA256 digests (%v) do not contain the actual SHA256 digest (%v)", + want.GetReferenceProvenance().GetReferenceBuilderImageDigests().GetDigests()["sha256"].GetValues(), "") if err := verifier.Verify(); err == nil || !strings.Contains(err.Error(), wantErr) { t.Fatalf("got %q, want error message containing %q,", err, wantErr) @@ -184,8 +200,9 @@ func TestVerify_NeedsHasEmptyBuilderImageDigest(t *testing.T) { func TestVerify_DoesNotNeedHasEmptyBuilderImageDigest(t *testing.T) { builderImageSHA256Digest := "" got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithBuilderImageSHA256Digest(builderImageSHA256Digest)) - want := ReferenceValues{ + want := prover.VerificationOptions{ // We do not check for the builder image digest. + ReferenceProvenance: &prover.ProvenanceReferenceValues{}, } verifier := ProvenanceIRVerifier{ @@ -201,8 +218,10 @@ func TestVerify_DoesNotNeedHasEmptyBuilderImageDigest(t *testing.T) { func TestVerify_HasWantedRepoURI(t *testing.T) { got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithRepoURI("https://github.com/project-oak/transparent-release")) - want := ReferenceValues{ - RepoURI: "https://github.com/project-oak/transparent-release", + want := prover.VerificationOptions{ + ReferenceProvenance: &prover.ProvenanceReferenceValues{ + ReferenceRepo_URI: "https://github.com/project-oak/transparent-release", + }, } verifier := ProvenanceIRVerifier{ @@ -221,8 +240,10 @@ func TestVerify_HasWrongRepoURI(t *testing.T) { got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithRepoURI(wrongURI)) - want := ReferenceValues{ - RepoURI: "github.com/project-oak/transparent-release", + want := prover.VerificationOptions{ + ReferenceProvenance: &prover.ProvenanceReferenceValues{ + ReferenceRepo_URI: "github.com/project-oak/transparent-release", + }, } verifier := ProvenanceIRVerifier{ @@ -230,9 +251,9 @@ func TestVerify_HasWrongRepoURI(t *testing.T) { Want: &want, } - wantErr := fmt.Sprintf("the URI from the provenance (%v) is different from the repo URI (%v)", + wantErr := fmt.Sprintf("the repo URI from the provenance (%v) is different from the repo URI (%v)", wrongURI, - want.RepoURI, + want.GetReferenceProvenance().GetReferenceRepo_URI(), ) if err := verifier.Verify(); err == nil || !strings.Contains(err.Error(), wantErr) { t.Fatalf("got %q, want error message containing %q,", err, wantErr) @@ -242,8 +263,10 @@ func TestVerify_HasWrongRepoURI(t *testing.T) { func TestVerify_HasNoRepoURIs(t *testing.T) { // We have no repo URIs in the provenance. got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName) - want := ReferenceValues{ - RepoURI: "github.com/project-oak/transparent-release", + want := prover.VerificationOptions{ + ReferenceProvenance: &prover.ProvenanceReferenceValues{ + ReferenceRepo_URI: "github.com/project-oak/transparent-release", + }, } verifier := ProvenanceIRVerifier{ @@ -251,9 +274,11 @@ func TestVerify_HasNoRepoURIs(t *testing.T) { Want: &want, } - // verfy succeeds because there are no references to any repo URI to match against - if err := verifier.Verify(); err != nil { - t.Fatalf("verify failed, got %v", err) + wantErr := fmt.Sprintf("no repo URI in the provenance, but want (%v)", + want.GetReferenceProvenance().GetReferenceRepo_URI(), + ) + if err := verifier.Verify(); err == nil || !strings.Contains(err.Error(), wantErr) { + t.Fatalf("got %q, want error message containing %q,", err, wantErr) } } @@ -261,8 +286,12 @@ func TestVerify_NeedsHasTrustedBuilder(t *testing.T) { trustedBuilder := "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@refs/tags/v1.2.0" got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithTrustedBuilder(trustedBuilder)) - want := ReferenceValues{ - TrustedBuilders: []string{trustedBuilder}, + want := prover.VerificationOptions{ + ReferenceProvenance: &prover.ProvenanceReferenceValues{ + ReferenceBuilders: &prover.StringAllowList{ + Values: []string{trustedBuilder}, + }, + }, } verifier := ProvenanceIRVerifier{ @@ -279,8 +308,12 @@ func TestVerify_NeedsDoesNotHaveTrustedBuilder(t *testing.T) { trustedBuilder := "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@refs/tags/v1.2.0" got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithTrustedBuilder(trustedBuilder)) - want := ReferenceValues{ - TrustedBuilders: []string{"other_" + trustedBuilder, "another_" + trustedBuilder}, + want := prover.VerificationOptions{ + ReferenceProvenance: &prover.ProvenanceReferenceValues{ + ReferenceBuilders: &prover.StringAllowList{ + Values: []string{"other_" + trustedBuilder, "another_" + trustedBuilder}, + }, + }, } verifier := ProvenanceIRVerifier{ @@ -289,7 +322,7 @@ func TestVerify_NeedsDoesNotHaveTrustedBuilder(t *testing.T) { } wantErr := fmt.Sprintf("the reference trusted builders (%v) do not contain the actual trusted builder (%v)", - want.TrustedBuilders, + want.GetReferenceProvenance().GetReferenceBuilders().GetValues(), trustedBuilder) if err := verifier.Verify(); err == nil || !strings.Contains(err.Error(), wantErr) { t.Fatalf("got %q, want error message containing %q,", err, wantErr) @@ -299,8 +332,12 @@ func TestVerify_NeedsDoesNotHaveTrustedBuilder(t *testing.T) { func TestVerify_NeedsHasEmptyTrustedBuilder(t *testing.T) { got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithTrustedBuilder("")) - want := ReferenceValues{ - TrustedBuilders: []string{"other_trusted_builder", "another_trusted_builder"}, + want := prover.VerificationOptions{ + ReferenceProvenance: &prover.ProvenanceReferenceValues{ + ReferenceBuilders: &prover.StringAllowList{ + Values: []string{"other_trusted_builder", "another_trusted_builder"}, + }, + }, } verifier := ProvenanceIRVerifier{ @@ -309,7 +346,7 @@ func TestVerify_NeedsHasEmptyTrustedBuilder(t *testing.T) { } wantErr := fmt.Sprintf("the reference trusted builders (%v) do not contain the actual trusted builder (%v)", - want.TrustedBuilders, + want.GetReferenceProvenance().GetReferenceBuilders().GetValues(), "") if err := verifier.Verify(); err == nil || !strings.Contains(err.Error(), wantErr) { t.Fatalf("got %q, want error message containing %q,", err, wantErr) @@ -319,8 +356,9 @@ func TestVerify_NeedsHasEmptyTrustedBuilder(t *testing.T) { func TestVerify_DoesNotNeedHasEmptyTrustedBuilder(t *testing.T) { got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithTrustedBuilder("")) - want := ReferenceValues{ + want := prover.VerificationOptions{ // We do not check the trusted builder. + ReferenceProvenance: &prover.ProvenanceReferenceValues{}, } verifier := ProvenanceIRVerifier{ diff --git a/pkg/proto/verification/provenance_verification.pb.go b/pkg/proto/verification/provenance_verification.pb.go new file mode 100644 index 00000000..b1a78aa3 --- /dev/null +++ b/pkg/proto/verification/provenance_verification.pb.go @@ -0,0 +1,441 @@ +// Copyright 2023 The Project Oak Authors +// +// 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 main contains a command-line tool for verifying SLSA provenances. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc v3.21.12 +// source: proto/provenance_verification.proto + +package verification + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type VerificationOptions struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ReferenceProvenance *ProvenanceReferenceValues `protobuf:"bytes,1,opt,name=reference_provenance,json=referenceProvenance,proto3,oneof" json:"reference_provenance,omitempty"` +} + +func (x *VerificationOptions) Reset() { + *x = VerificationOptions{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_provenance_verification_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VerificationOptions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerificationOptions) ProtoMessage() {} + +func (x *VerificationOptions) ProtoReflect() protoreflect.Message { + mi := &file_proto_provenance_verification_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VerificationOptions.ProtoReflect.Descriptor instead. +func (*VerificationOptions) Descriptor() ([]byte, []int) { + return file_proto_provenance_verification_proto_rawDescGZIP(), []int{0} +} + +func (x *VerificationOptions) GetReferenceProvenance() *ProvenanceReferenceValues { + if x != nil { + return x.ReferenceProvenance + } + return nil +} + +type ProvenanceReferenceValues struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + MustHaveBuildCommand bool `protobuf:"varint,1,opt,name=must_have_build_command,json=mustHaveBuildCommand,proto3" json:"must_have_build_command,omitempty"` + ReferenceBinaryDigests *Digests `protobuf:"bytes,2,opt,name=reference_binary_digests,json=referenceBinaryDigests,proto3,oneof" json:"reference_binary_digests,omitempty"` + ReferenceBuilderImageDigests *Digests `protobuf:"bytes,3,opt,name=reference_builder_image_digests,json=referenceBuilderImageDigests,proto3,oneof" json:"reference_builder_image_digests,omitempty"` + ReferenceRepo_URI string `protobuf:"bytes,4,opt,name=reference_repo_URI,json=referenceRepoURI,proto3" json:"reference_repo_URI,omitempty"` + ReferenceBuilders *StringAllowList `protobuf:"bytes,5,opt,name=reference_builders,json=referenceBuilders,proto3,oneof" json:"reference_builders,omitempty"` +} + +func (x *ProvenanceReferenceValues) Reset() { + *x = ProvenanceReferenceValues{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_provenance_verification_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ProvenanceReferenceValues) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProvenanceReferenceValues) ProtoMessage() {} + +func (x *ProvenanceReferenceValues) ProtoReflect() protoreflect.Message { + mi := &file_proto_provenance_verification_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProvenanceReferenceValues.ProtoReflect.Descriptor instead. +func (*ProvenanceReferenceValues) Descriptor() ([]byte, []int) { + return file_proto_provenance_verification_proto_rawDescGZIP(), []int{1} +} + +func (x *ProvenanceReferenceValues) GetMustHaveBuildCommand() bool { + if x != nil { + return x.MustHaveBuildCommand + } + return false +} + +func (x *ProvenanceReferenceValues) GetReferenceBinaryDigests() *Digests { + if x != nil { + return x.ReferenceBinaryDigests + } + return nil +} + +func (x *ProvenanceReferenceValues) GetReferenceBuilderImageDigests() *Digests { + if x != nil { + return x.ReferenceBuilderImageDigests + } + return nil +} + +func (x *ProvenanceReferenceValues) GetReferenceRepo_URI() string { + if x != nil { + return x.ReferenceRepo_URI + } + return "" +} + +func (x *ProvenanceReferenceValues) GetReferenceBuilders() *StringAllowList { + if x != nil { + return x.ReferenceBuilders + } + return nil +} + +// Represents an allow listed map of digests. +type Digests struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Keys are cryptographic hash algorithms (e.g., sha256). + // Values are acceptable digests. + Digests map[string]*StringAllowList `protobuf:"bytes,1,rep,name=digests,proto3" json:"digests,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *Digests) Reset() { + *x = Digests{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_provenance_verification_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Digests) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Digests) ProtoMessage() {} + +func (x *Digests) ProtoReflect() protoreflect.Message { + mi := &file_proto_provenance_verification_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Digests.ProtoReflect.Descriptor instead. +func (*Digests) Descriptor() ([]byte, []int) { + return file_proto_provenance_verification_proto_rawDescGZIP(), []int{2} +} + +func (x *Digests) GetDigests() map[string]*StringAllowList { + if x != nil { + return x.Digests + } + return nil +} + +// Represents an allow list of values. +type StringAllowList struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Values []string `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` +} + +func (x *StringAllowList) Reset() { + *x = StringAllowList{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_provenance_verification_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StringAllowList) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StringAllowList) ProtoMessage() {} + +func (x *StringAllowList) ProtoReflect() protoreflect.Message { + mi := &file_proto_provenance_verification_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StringAllowList.ProtoReflect.Descriptor instead. +func (*StringAllowList) Descriptor() ([]byte, []int) { + return file_proto_provenance_verification_proto_rawDescGZIP(), []int{3} +} + +func (x *StringAllowList) GetValues() []string { + if x != nil { + return x.Values + } + return nil +} + +var File_proto_provenance_verification_proto protoreflect.FileDescriptor + +var file_proto_provenance_verification_proto_rawDesc = []byte{ + 0x0a, 0x23, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, + 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1a, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, + 0x31, 0x22, 0x9d, 0x01, 0x0a, 0x13, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x6d, 0x0a, 0x14, 0x72, 0x65, 0x66, + 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x52, + 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x48, 0x00, + 0x52, 0x13, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x65, + 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x88, 0x01, 0x01, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x72, 0x65, 0x66, + 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, + 0x65, 0x22, 0x8e, 0x04, 0x0a, 0x19, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, + 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, + 0x35, 0x0a, 0x17, 0x6d, 0x75, 0x73, 0x74, 0x5f, 0x68, 0x61, 0x76, 0x65, 0x5f, 0x62, 0x75, 0x69, + 0x6c, 0x64, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x14, 0x6d, 0x75, 0x73, 0x74, 0x48, 0x61, 0x76, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, + 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x62, 0x0a, 0x18, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, + 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, + 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, + 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x48, 0x00, 0x52, + 0x16, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x79, + 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x88, 0x01, 0x01, 0x12, 0x6f, 0x0a, 0x1f, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x5f, + 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x48, 0x01, 0x52, 0x1c, 0x72, 0x65, 0x66, 0x65, + 0x72, 0x65, 0x6e, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x49, 0x6d, 0x61, 0x67, + 0x65, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x88, 0x01, 0x01, 0x12, 0x2c, 0x0a, 0x12, 0x72, + 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x5f, 0x55, 0x52, + 0x49, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, + 0x63, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x55, 0x52, 0x49, 0x12, 0x5f, 0x0a, 0x12, 0x72, 0x65, 0x66, + 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x4c, 0x69, + 0x73, 0x74, 0x48, 0x02, 0x52, 0x11, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x42, + 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x88, 0x01, 0x01, 0x42, 0x1b, 0x0a, 0x19, 0x5f, 0x72, + 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x5f, + 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x42, 0x22, 0x0a, 0x20, 0x5f, 0x72, 0x65, 0x66, 0x65, + 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x6d, + 0x61, 0x67, 0x65, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x42, 0x15, 0x0a, 0x13, 0x5f, + 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, + 0x72, 0x73, 0x22, 0xbe, 0x01, 0x0a, 0x07, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x12, 0x4a, + 0x0a, 0x07, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x30, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, + 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x67, + 0x65, 0x73, 0x74, 0x73, 0x2e, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x07, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x1a, 0x67, 0x0a, 0x0c, 0x44, 0x69, + 0x67, 0x65, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x41, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x65, + 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, + 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x41, + 0x6c, 0x6c, 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x22, 0x29, 0x0a, 0x0f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x41, 0x6c, 0x6c, + 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x42, 0x14, + 0x5a, 0x12, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_proto_provenance_verification_proto_rawDescOnce sync.Once + file_proto_provenance_verification_proto_rawDescData = file_proto_provenance_verification_proto_rawDesc +) + +func file_proto_provenance_verification_proto_rawDescGZIP() []byte { + file_proto_provenance_verification_proto_rawDescOnce.Do(func() { + file_proto_provenance_verification_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_provenance_verification_proto_rawDescData) + }) + return file_proto_provenance_verification_proto_rawDescData +} + +var file_proto_provenance_verification_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_proto_provenance_verification_proto_goTypes = []interface{}{ + (*VerificationOptions)(nil), // 0: verification.provenance.v1.VerificationOptions + (*ProvenanceReferenceValues)(nil), // 1: verification.provenance.v1.ProvenanceReferenceValues + (*Digests)(nil), // 2: verification.provenance.v1.Digests + (*StringAllowList)(nil), // 3: verification.provenance.v1.StringAllowList + nil, // 4: verification.provenance.v1.Digests.DigestsEntry +} +var file_proto_provenance_verification_proto_depIdxs = []int32{ + 1, // 0: verification.provenance.v1.VerificationOptions.reference_provenance:type_name -> verification.provenance.v1.ProvenanceReferenceValues + 2, // 1: verification.provenance.v1.ProvenanceReferenceValues.reference_binary_digests:type_name -> verification.provenance.v1.Digests + 2, // 2: verification.provenance.v1.ProvenanceReferenceValues.reference_builder_image_digests:type_name -> verification.provenance.v1.Digests + 3, // 3: verification.provenance.v1.ProvenanceReferenceValues.reference_builders:type_name -> verification.provenance.v1.StringAllowList + 4, // 4: verification.provenance.v1.Digests.digests:type_name -> verification.provenance.v1.Digests.DigestsEntry + 3, // 5: verification.provenance.v1.Digests.DigestsEntry.value:type_name -> verification.provenance.v1.StringAllowList + 6, // [6:6] is the sub-list for method output_type + 6, // [6:6] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name +} + +func init() { file_proto_provenance_verification_proto_init() } +func file_proto_provenance_verification_proto_init() { + if File_proto_provenance_verification_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_proto_provenance_verification_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VerificationOptions); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_provenance_verification_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ProvenanceReferenceValues); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_provenance_verification_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Digests); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_provenance_verification_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StringAllowList); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_proto_provenance_verification_proto_msgTypes[0].OneofWrappers = []interface{}{} + file_proto_provenance_verification_proto_msgTypes[1].OneofWrappers = []interface{}{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_proto_provenance_verification_proto_rawDesc, + NumEnums: 0, + NumMessages: 5, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_proto_provenance_verification_proto_goTypes, + DependencyIndexes: file_proto_provenance_verification_proto_depIdxs, + MessageInfos: file_proto_provenance_verification_proto_msgTypes, + }.Build() + File_proto_provenance_verification_proto = out.File + file_proto_provenance_verification_proto_rawDesc = nil + file_proto_provenance_verification_proto_goTypes = nil + file_proto_provenance_verification_proto_depIdxs = nil +} diff --git a/proto/provenance_verification.proto b/proto/provenance_verification.proto new file mode 100644 index 00000000..3667449a --- /dev/null +++ b/proto/provenance_verification.proto @@ -0,0 +1,45 @@ +// Copyright 2023 The Project Oak Authors +// +// 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 main contains a command-line tool for verifying SLSA provenances. + +syntax = "proto3"; + +package verification.provenance.v1; + +option go_package = "proto/verification"; + +message VerificationOptions { + optional ProvenanceReferenceValues reference_provenance = 1; +} + +message ProvenanceReferenceValues { + bool must_have_build_command = 1; + optional Digests reference_binary_digests = 2; + optional Digests reference_builder_image_digests = 3; + string reference_repo_URI = 4; + optional StringAllowList reference_builders = 5; +} + +// Represents an allow listed map of digests. +message Digests { + // Keys are cryptographic hash algorithms (e.g., sha256). + // Values are acceptable digests. + map digests = 1; +} + +// Represents an allow list of values. +message StringAllowList { + repeated string values = 1; +} diff --git a/testdata/different_reference_values.textproto b/testdata/different_reference_values.textproto new file mode 100644 index 00000000..1b6ca1ec --- /dev/null +++ b/testdata/different_reference_values.textproto @@ -0,0 +1,17 @@ +reference_provenance: { + must_have_build_command: true + reference_binary_digests: { + digests: { + key: "sha256" + value: { values: ["a_different_digest"]} + } + } + reference_builder_image_digests: { + digests: { + key: "sha256" + value: { values: ["another_different_digest"]} + } + } + reference_repo_URI: "some_different_repo" +} + \ No newline at end of file diff --git a/testdata/different_reference_values.toml b/testdata/different_reference_values.toml deleted file mode 100644 index 43551b23..00000000 --- a/testdata/different_reference_values.toml +++ /dev/null @@ -1,4 +0,0 @@ -binary_sha256_digests = ["a_different_digest"] -want_build_cmds = true -builder_image_sha256_digests = ["another_different_digest"] -repo_uri = "some_different_repo" diff --git a/testdata/reference_values.textproto b/testdata/reference_values.textproto new file mode 100644 index 00000000..d1dcc156 --- /dev/null +++ b/testdata/reference_values.textproto @@ -0,0 +1,19 @@ +reference_provenance: { + must_have_build_command: false + reference_binary_digests: { + digests: { + key: "sha256" + value: { values: ["d059c38cea82047ad316a1c6c6fbd13ecf7a0abdcc375463920bd25bf5c142cc"]} + } + } + reference_builder_image_digests: { + digests: { + key: "sha256" + value: { values: ["9e2ba52487d945504d250de186cb4fe2e3ba023ed2921dd6ac8b97ed43e76af9"]} + } + } + reference_repo_URI: "git+https://github.com/project-oak/oak@refs/heads/main" + reference_builders: { + values: ["https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@refs/tags/v1.2.0"] + } +} diff --git a/testdata/reference_values.toml b/testdata/reference_values.toml deleted file mode 100644 index 33ee7848..00000000 --- a/testdata/reference_values.toml +++ /dev/null @@ -1,5 +0,0 @@ -binary_sha256_digests = ["d059c38cea82047ad316a1c6c6fbd13ecf7a0abdcc375463920bd25bf5c142cc"] -want_build_cmds = false -builder_image_sha256_digests = ["9e2ba52487d945504d250de186cb4fe2e3ba023ed2921dd6ac8b97ed43e76af9"] -repo_uri = "git+https://github.com/project-oak/oak@refs/heads/main" -trusted_builders = ["https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@refs/tags/v1.2.0"] From 8865be5bdafd4a10b19fdcefa2c93da7fc778ab5 Mon Sep 17 00:00:00 2001 From: Razieh Behjati Date: Fri, 7 Jul 2023 23:09:36 +0100 Subject: [PATCH 02/13] Fix linting --- internal/endorser/endorser_test.go | 8 ++++---- internal/verification/verifier.go | 2 +- internal/verification/verifier_test.go | 16 ++++++++-------- .../verification/provenance_verification.pb.go | 12 ++++++------ proto/provenance_verification.proto | 2 +- testdata/different_reference_values.textproto | 2 +- testdata/reference_values.textproto | 2 +- 7 files changed, 22 insertions(+), 22 deletions(-) diff --git a/internal/endorser/endorser_test.go b/internal/endorser/endorser_test.go index db9c4234..dc7cc155 100644 --- a/internal/endorser/endorser_test.go +++ b/internal/endorser/endorser_test.go @@ -88,7 +88,7 @@ func TestLoadAndVerifyProvenances_MultipleValidEndorsement(t *testing.T) { ReferenceProvenance: &prover.ProvenanceReferenceValues{ // Make sure we pick the correct binary hash if there are several reference values. ReferenceBinaryDigests: &prover.Digests{ - Digests: map[string]*prover.StringAllowList{"sha256": &prover.StringAllowList{Values: []string{binaryHash + "_diff", binaryHash}}}, + Digests: map[string]*prover.StringAllowList{"sha256": {Values: []string{binaryHash + "_diff", binaryHash}}}, }, }, } @@ -122,7 +122,7 @@ func TestLoadAndVerifyProvenances_ConsistentNotVerified(t *testing.T) { referenceValues := prover.VerificationOptions{ ReferenceProvenance: &prover.ProvenanceReferenceValues{ ReferenceBinaryDigests: &prover.Digests{ - Digests: map[string]*prover.StringAllowList{"sha256": &prover.StringAllowList{Values: []string{binaryHash + "_diff"}}}, + Digests: map[string]*prover.StringAllowList{"sha256": {Values: []string{binaryHash + "_diff"}}}, }, }, } @@ -152,7 +152,7 @@ func TestLoadAndVerify_InconsistentVerified(t *testing.T) { referenceValues := prover.VerificationOptions{ ReferenceProvenance: &prover.ProvenanceReferenceValues{ ReferenceBinaryDigests: &prover.Digests{ - Digests: map[string]*prover.StringAllowList{"sha256": &prover.StringAllowList{Values: []string{"e8e05d1d09af8952919bf6ab38e0cc5a6414ee2b5e21f4765b12421c5db0037e", binaryHash}}}, + Digests: map[string]*prover.StringAllowList{"sha256": {Values: []string{"e8e05d1d09af8952919bf6ab38e0cc5a6414ee2b5e21f4765b12421c5db0037e", binaryHash}}}, }, }, } @@ -183,7 +183,7 @@ func TestLoadAndVerify_InconsistentNotVerified(t *testing.T) { referenceValues := prover.VerificationOptions{ ReferenceProvenance: &prover.ProvenanceReferenceValues{ ReferenceBinaryDigests: &prover.Digests{ - Digests: map[string]*prover.StringAllowList{"sha256": &prover.StringAllowList{Values: []string{binaryHash + "_diff"}}}, + Digests: map[string]*prover.StringAllowList{"sha256": {Values: []string{binaryHash + "_diff"}}}, }, }, } diff --git a/internal/verification/verifier.go b/internal/verification/verifier.go index 7b7c7140..d1f737b7 100644 --- a/internal/verification/verifier.go +++ b/internal/verification/verifier.go @@ -110,7 +110,7 @@ func (v *ProvenanceIRVerifier) verifyBuilderImageDigest() error { // verifyRepoURI verifies that the Git URI in the Got provenance // is the same as the repo URI in the Want reference values. func (v *ProvenanceIRVerifier) verifyRepoURI() error { - referenceRepoURI := v.Want.GetReferenceProvenance().GetReferenceRepo_URI() + referenceRepoURI := v.Want.GetReferenceProvenance().GetReferenceRepoUri() if referenceRepoURI == "" { return nil } diff --git a/internal/verification/verifier_test.go b/internal/verification/verifier_test.go index 4e78cd39..2b1f0f22 100644 --- a/internal/verification/verifier_test.go +++ b/internal/verification/verifier_test.go @@ -135,7 +135,7 @@ func TestVerify_NeedsHasBuilderImageDigest(t *testing.T) { want := prover.VerificationOptions{ ReferenceProvenance: &prover.ProvenanceReferenceValues{ ReferenceBuilderImageDigests: &prover.Digests{ - Digests: map[string]*prover.StringAllowList{"sha256": &prover.StringAllowList{Values: []string{"some_other_digest", builderDigest}}}, + Digests: map[string]*prover.StringAllowList{"sha256": {Values: []string{"some_other_digest", builderDigest}}}, }, }, } @@ -156,7 +156,7 @@ func TestVerify_NeedsDoesNotHaveBuilderImageDigest(t *testing.T) { want := prover.VerificationOptions{ ReferenceProvenance: &prover.ProvenanceReferenceValues{ ReferenceBuilderImageDigests: &prover.Digests{ - Digests: map[string]*prover.StringAllowList{"sha256": &prover.StringAllowList{Values: []string{"some_other_digest", "and_some_other"}}}, + Digests: map[string]*prover.StringAllowList{"sha256": {Values: []string{"some_other_digest", "and_some_other"}}}, }, }, } @@ -179,7 +179,7 @@ func TestVerify_NeedsHasEmptyBuilderImageDigest(t *testing.T) { want := prover.VerificationOptions{ ReferenceProvenance: &prover.ProvenanceReferenceValues{ ReferenceBuilderImageDigests: &prover.Digests{ - Digests: map[string]*prover.StringAllowList{"sha256": &prover.StringAllowList{Values: []string{"some_digest"}}}, + Digests: map[string]*prover.StringAllowList{"sha256": {Values: []string{"some_digest"}}}, }, }, } @@ -220,7 +220,7 @@ func TestVerify_HasWantedRepoURI(t *testing.T) { model.WithRepoURI("https://github.com/project-oak/transparent-release")) want := prover.VerificationOptions{ ReferenceProvenance: &prover.ProvenanceReferenceValues{ - ReferenceRepo_URI: "https://github.com/project-oak/transparent-release", + ReferenceRepoUri: "https://github.com/project-oak/transparent-release", }, } @@ -242,7 +242,7 @@ func TestVerify_HasWrongRepoURI(t *testing.T) { model.WithRepoURI(wrongURI)) want := prover.VerificationOptions{ ReferenceProvenance: &prover.ProvenanceReferenceValues{ - ReferenceRepo_URI: "github.com/project-oak/transparent-release", + ReferenceRepoUri: "github.com/project-oak/transparent-release", }, } @@ -253,7 +253,7 @@ func TestVerify_HasWrongRepoURI(t *testing.T) { wantErr := fmt.Sprintf("the repo URI from the provenance (%v) is different from the repo URI (%v)", wrongURI, - want.GetReferenceProvenance().GetReferenceRepo_URI(), + want.GetReferenceProvenance().GetReferenceRepoUri(), ) if err := verifier.Verify(); err == nil || !strings.Contains(err.Error(), wantErr) { t.Fatalf("got %q, want error message containing %q,", err, wantErr) @@ -265,7 +265,7 @@ func TestVerify_HasNoRepoURIs(t *testing.T) { got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName) want := prover.VerificationOptions{ ReferenceProvenance: &prover.ProvenanceReferenceValues{ - ReferenceRepo_URI: "github.com/project-oak/transparent-release", + ReferenceRepoUri: "github.com/project-oak/transparent-release", }, } @@ -275,7 +275,7 @@ func TestVerify_HasNoRepoURIs(t *testing.T) { } wantErr := fmt.Sprintf("no repo URI in the provenance, but want (%v)", - want.GetReferenceProvenance().GetReferenceRepo_URI(), + want.GetReferenceProvenance().GetReferenceRepoUri(), ) if err := verifier.Verify(); err == nil || !strings.Contains(err.Error(), wantErr) { t.Fatalf("got %q, want error message containing %q,", err, wantErr) diff --git a/pkg/proto/verification/provenance_verification.pb.go b/pkg/proto/verification/provenance_verification.pb.go index b1a78aa3..a6f25a9e 100644 --- a/pkg/proto/verification/provenance_verification.pb.go +++ b/pkg/proto/verification/provenance_verification.pb.go @@ -91,7 +91,7 @@ type ProvenanceReferenceValues struct { MustHaveBuildCommand bool `protobuf:"varint,1,opt,name=must_have_build_command,json=mustHaveBuildCommand,proto3" json:"must_have_build_command,omitempty"` ReferenceBinaryDigests *Digests `protobuf:"bytes,2,opt,name=reference_binary_digests,json=referenceBinaryDigests,proto3,oneof" json:"reference_binary_digests,omitempty"` ReferenceBuilderImageDigests *Digests `protobuf:"bytes,3,opt,name=reference_builder_image_digests,json=referenceBuilderImageDigests,proto3,oneof" json:"reference_builder_image_digests,omitempty"` - ReferenceRepo_URI string `protobuf:"bytes,4,opt,name=reference_repo_URI,json=referenceRepoURI,proto3" json:"reference_repo_URI,omitempty"` + ReferenceRepoUri string `protobuf:"bytes,4,opt,name=reference_repo_uri,json=referenceRepoUri,proto3" json:"reference_repo_uri,omitempty"` ReferenceBuilders *StringAllowList `protobuf:"bytes,5,opt,name=reference_builders,json=referenceBuilders,proto3,oneof" json:"reference_builders,omitempty"` } @@ -148,9 +148,9 @@ func (x *ProvenanceReferenceValues) GetReferenceBuilderImageDigests() *Digests { return nil } -func (x *ProvenanceReferenceValues) GetReferenceRepo_URI() string { +func (x *ProvenanceReferenceValues) GetReferenceRepoUri() string { if x != nil { - return x.ReferenceRepo_URI + return x.ReferenceRepoUri } return "" } @@ -296,9 +296,9 @@ var file_proto_provenance_verification_proto_rawDesc = []byte{ 0x2e, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x48, 0x01, 0x52, 0x1c, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x88, 0x01, 0x01, 0x12, 0x2c, 0x0a, 0x12, 0x72, - 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x5f, 0x55, 0x52, - 0x49, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, - 0x63, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x55, 0x52, 0x49, 0x12, 0x5f, 0x0a, 0x12, 0x72, 0x65, 0x66, + 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x5f, 0x75, 0x72, + 0x69, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, + 0x63, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x55, 0x72, 0x69, 0x12, 0x5f, 0x0a, 0x12, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, diff --git a/proto/provenance_verification.proto b/proto/provenance_verification.proto index 3667449a..546fcf15 100644 --- a/proto/provenance_verification.proto +++ b/proto/provenance_verification.proto @@ -28,7 +28,7 @@ message ProvenanceReferenceValues { bool must_have_build_command = 1; optional Digests reference_binary_digests = 2; optional Digests reference_builder_image_digests = 3; - string reference_repo_URI = 4; + string reference_repo_uri = 4; optional StringAllowList reference_builders = 5; } diff --git a/testdata/different_reference_values.textproto b/testdata/different_reference_values.textproto index 1b6ca1ec..f43d61e3 100644 --- a/testdata/different_reference_values.textproto +++ b/testdata/different_reference_values.textproto @@ -12,6 +12,6 @@ reference_provenance: { value: { values: ["another_different_digest"]} } } - reference_repo_URI: "some_different_repo" + reference_repo_uri: "some_different_repo" } \ No newline at end of file diff --git a/testdata/reference_values.textproto b/testdata/reference_values.textproto index d1dcc156..ee78d3bb 100644 --- a/testdata/reference_values.textproto +++ b/testdata/reference_values.textproto @@ -12,7 +12,7 @@ reference_provenance: { value: { values: ["9e2ba52487d945504d250de186cb4fe2e3ba023ed2921dd6ac8b97ed43e76af9"]} } } - reference_repo_URI: "git+https://github.com/project-oak/oak@refs/heads/main" + reference_repo_uri: "git+https://github.com/project-oak/oak@refs/heads/main" reference_builders: { values: ["https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@refs/tags/v1.2.0"] } From 303fa5486dac684b732af625f950d7aeaac274e3 Mon Sep 17 00:00:00 2001 From: Razieh Behjati Date: Wed, 12 Jul 2023 15:40:35 +0100 Subject: [PATCH 03/13] Add test for provenance-less endorsement --- pkg/claims/endorsement.go | 2 +- pkg/claims/endorsement_test.go | 19 +++++++++++++++++++ proto/provenance_verification.proto | 1 + 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/pkg/claims/endorsement.go b/pkg/claims/endorsement.go index ffc24f2c..4f482bdc 100644 --- a/pkg/claims/endorsement.go +++ b/pkg/claims/endorsement.go @@ -33,7 +33,7 @@ type VerifiedProvenanceSet struct { BinaryName string // SHA256 digest of the binary that all validated provenances agree on. BinaryDigest string - // Provenances contains metadata about provenances + // Provenances is a possibly empty list of provenance metadata objects. Provenances []ProvenanceData } diff --git a/pkg/claims/endorsement_test.go b/pkg/claims/endorsement_test.go index ce9fcc76..d9ff357a 100644 --- a/pkg/claims/endorsement_test.go +++ b/pkg/claims/endorsement_test.go @@ -68,6 +68,25 @@ func TestNotAfterBeforeNotBeforeEndorsement(t *testing.T) { } } +func TestGenerateProvenanceLessEndorsement(t *testing.T) { + newNotBefore := time.Now().AddDate(0, 0, 1) + newNotAfter := time.Now().AddDate(0, 0, 3) + + validity := ClaimValidity{ + NotBefore: &newNotBefore, + NotAfter: &newNotAfter, + } + + provenances := VerifiedProvenanceSet{ + BinaryName: "SomeBinary", + BinaryDigest: "813841dda3818d616aa3e706e49d0286dc825c5dbad4a75cfb37b91ba412238b", + } + endorsement := GenerateEndorsementStatement(validity, provenances) + if err := validateClaim(*endorsement); err != nil { + t.Fatalf("Invalid endorsement: %v", err) + } +} + // Helper function for creating new test cases from the hard-coded one. func tweakValidity(t *testing.T, daysAddedToNotBefore, daysAddedToNotAfter int) []byte { examplePath := "../../schema/claim/v1/example.json" diff --git a/proto/provenance_verification.proto b/proto/provenance_verification.proto index 546fcf15..f3ae3695 100644 --- a/proto/provenance_verification.proto +++ b/proto/provenance_verification.proto @@ -21,6 +21,7 @@ package verification.provenance.v1; option go_package = "proto/verification"; message VerificationOptions { + // The absence of a reference provenance indicates that provenance verification can be skipped. optional ProvenanceReferenceValues reference_provenance = 1; } From 5e0eb9b4afb3100616cd5df3b3223bd5c17b9a4a Mon Sep 17 00:00:00 2001 From: Razieh Behjati Date: Wed, 12 Jul 2023 16:37:43 +0100 Subject: [PATCH 04/13] Simplify verifier, and explicitly pass binary name and digest to GenerateEndorsement --- cmd/verifier/main.go | 2 +- internal/endorser/endorser.go | 49 ++++--- internal/endorser/endorser_test.go | 75 ++++------- internal/verification/verifier.go | 40 ++---- internal/verification/verifier_test.go | 127 +++++++----------- .../provenance_verification.pb.go | 110 +++++++-------- proto/provenance_verification.proto | 1 - testdata/different_reference_values.textproto | 8 +- testdata/reference_values.textproto | 6 - 9 files changed, 162 insertions(+), 256 deletions(-) diff --git a/cmd/verifier/main.go b/cmd/verifier/main.go index 6d772c20..8323736d 100644 --- a/cmd/verifier/main.go +++ b/cmd/verifier/main.go @@ -47,7 +47,7 @@ func main() { provenanceVerifier := verification.ProvenanceIRVerifier{ Got: provenanceIR, - Want: &prover.VerificationOptions{}, + Want: &prover.ProvenanceReferenceValues{}, } if err := provenanceVerifier.Verify(); err != nil { diff --git a/internal/endorser/endorser.go b/internal/endorser/endorser.go index b81b7687..6e87b12b 100644 --- a/internal/endorser/endorser.go +++ b/internal/endorser/endorser.go @@ -44,12 +44,15 @@ type ParsedProvenance struct { SourceMetadata claims.ProvenanceData } -// GenerateEndorsement generates an endorsement statement for the given validity duration, using -// the given provenances as evidence and reference values to verify them. At least one provenance -// must be provided. The endorsement statement is generated only if the provenance statements are -// valid. -func GenerateEndorsement(referenceValues *prover.VerificationOptions, validityDuration claims.ClaimValidity, provenances []ParsedProvenance) (*intoto.Statement, error) { - verifiedProvenances, err := verifyAndSummarizeProvenances(referenceValues, provenances) +// GenerateEndorsement generates an endorsement statement for the given binary +// and the given validity duration, using the given provenances as evidence and +// reference values to verify them. If more than one provenance statements are +// provided the endorsement statement is generated only if the provenance +// statements are valid. If no provenances are provided, a provenance-less +// endorsement is generated, if the input verification options does not contain +// a reference provenance. +func GenerateEndorsement(binaryName, binaryDigest string, verOpt *prover.VerificationOptions, validityDuration claims.ClaimValidity, provenances []ParsedProvenance) (*intoto.Statement, error) { + verifiedProvenances, err := verifyAndSummarizeProvenances(binaryName, binaryDigest, verOpt, provenances) if err != nil { return nil, fmt.Errorf("could not verify and summarize provenances: %v", err) } @@ -57,13 +60,15 @@ func GenerateEndorsement(referenceValues *prover.VerificationOptions, validityDu return claims.GenerateEndorsementStatement(validityDuration, *verifiedProvenances), nil } -// Returns an instance of claims.VerifiedProvenanceSet, containing metadata about a set of verified -// provenances, or an error. An error is returned if any of the following conditions is met: -// (1) The list of provenances is empty, -// (2) Any of the provenances is invalid (see verifyProvenances for details on validity), +// Returns an instance of claims.VerifiedProvenanceSet, containing metadata +// about a set of verified provenances, or an error. An error is returned if +// any of the following conditions is met: +// (1) The list of provenances is empty, but verification options contains a +// nonempty provenance reference. +// (2) Any of the provenances is invalid (see verifyProvenances for details), // (3) Provenances do not match (e.g., have different binary names). -func verifyAndSummarizeProvenances(referenceValues *prover.VerificationOptions, provenances []ParsedProvenance) (*claims.VerifiedProvenanceSet, error) { - if len(provenances) == 0 { +func verifyAndSummarizeProvenances(binaryName, binaryDigest string, verOpt *prover.VerificationOptions, provenances []ParsedProvenance) (*claims.VerifiedProvenanceSet, error) { + if len(provenances) == 0 && verOpt.GetReferenceProvenance() != nil { return nil, fmt.Errorf("at least one provenance file must be provided") } @@ -74,14 +79,26 @@ func verifyAndSummarizeProvenances(referenceValues *prover.VerificationOptions, provenancesData = append(provenancesData, p.SourceMetadata) } - errs := multierr.Append(verifyConsistency(provenanceIRs), verifyProvenances(referenceValues, provenanceIRs)) + errs := multierr.Append(verifyConsistency(provenanceIRs), verifyProvenances(verOpt.GetReferenceProvenance(), provenanceIRs)) + + if len(provenanceIRs) > 0 { + if provenanceIRs[0].BinarySHA256Digest() != binaryDigest { + errs = multierr.Append(errs, fmt.Errorf("the binary digest in the provenance (%q) does not match the given binary digest (%q)", + provenanceIRs[0].BinarySHA256Digest(), binaryDigest)) + } + if provenanceIRs[0].BinaryName() != binaryName { + errs = multierr.Append(errs, fmt.Errorf("the binary name in the provenance (%q) does not match the given binary name (%q)", + provenanceIRs[0].BinaryName(), binaryName)) + } + } + if errs != nil { return nil, fmt.Errorf("failed while verifying of provenances: %v", errs) } verifiedProvenances := claims.VerifiedProvenanceSet{ - BinaryDigest: provenanceIRs[0].BinarySHA256Digest(), - BinaryName: provenanceIRs[0].BinaryName(), + BinaryDigest: binaryDigest, + BinaryName: binaryName, Provenances: provenancesData, } @@ -89,7 +106,7 @@ func verifyAndSummarizeProvenances(referenceValues *prover.VerificationOptions, } // verifyProvenances verifies the given list of provenances. An error is returned if verification fails for one of them. -func verifyProvenances(referenceValues *prover.VerificationOptions, provenances []model.ProvenanceIR) error { +func verifyProvenances(referenceValues *prover.ProvenanceReferenceValues, provenances []model.ProvenanceIR) error { var errs error for index := range provenances { provenanceVerifier := verification.ProvenanceIRVerifier{ diff --git a/internal/endorser/endorser_test.go b/internal/endorser/endorser_test.go index dc7cc155..0f5cc161 100644 --- a/internal/endorser/endorser_test.go +++ b/internal/endorser/endorser_test.go @@ -28,9 +28,10 @@ import ( ) const ( - binaryHash = "d059c38cea82047ad316a1c6c6fbd13ecf7a0abdcc375463920bd25bf5c142cc" - binaryName = "oak_functions_freestanding_bin" - errorBinaryDigest = "do not contain the actual SHA256 digest" + binaryHash = "d059c38cea82047ad316a1c6c6fbd13ecf7a0abdcc375463920bd25bf5c142cc" + binaryName = "oak_functions_freestanding_bin" + errorBinaryDigest = "does not match the given binary digest" + errorInconsistentProvenances = "provenances are not consistent" ) func TestGenerateEndorsement_SingleValidEndorsement(t *testing.T) { @@ -51,12 +52,12 @@ func TestGenerateEndorsement_SingleValidEndorsement(t *testing.T) { t.Fatalf("Could not load provenances: %v", err) } - referenceValues, err := loadTextprotoVerificationOptions("../../testdata/reference_values.textproto") + verOpt, err := loadTextprotoVerificationOptions("../../testdata/reference_values.textproto") if err != nil { t.Fatalf("Could not load reference values: %v", err) } - statement, err := GenerateEndorsement(referenceValues, validity, provenances) + statement, err := GenerateEndorsement(binaryName, binaryHash, verOpt, validity, provenances) if err != nil { t.Fatalf("Could not generate endorsement from %q: %v", provenances[0].SourceMetadata.URI, err) } @@ -85,14 +86,9 @@ func TestLoadAndVerifyProvenances_MultipleValidEndorsement(t *testing.T) { } referenceValues := prover.VerificationOptions{ - ReferenceProvenance: &prover.ProvenanceReferenceValues{ - // Make sure we pick the correct binary hash if there are several reference values. - ReferenceBinaryDigests: &prover.Digests{ - Digests: map[string]*prover.StringAllowList{"sha256": {Values: []string{binaryHash + "_diff", binaryHash}}}, - }, - }, - } - provenanceSet, err := verifyAndSummarizeProvenances(&referenceValues, provenances) + ReferenceProvenance: &prover.ProvenanceReferenceValues{}, + } + provenanceSet, err := verifyAndSummarizeProvenances(binaryName, binaryHash, &referenceValues, provenances) if err != nil { t.Fatalf("Could not generate endorsement from %q: %v", provenances[0].SourceMetadata.URI, err) } @@ -119,16 +115,12 @@ func TestLoadAndVerifyProvenances_ConsistentNotVerified(t *testing.T) { if err != nil { t.Fatalf("Could not load provenances: %v", err) } - referenceValues := prover.VerificationOptions{ - ReferenceProvenance: &prover.ProvenanceReferenceValues{ - ReferenceBinaryDigests: &prover.Digests{ - Digests: map[string]*prover.StringAllowList{"sha256": {Values: []string{binaryHash + "_diff"}}}, - }, - }, + verOpts := prover.VerificationOptions{ + ReferenceProvenance: &prover.ProvenanceReferenceValues{}, } // Provenances do not contain the given reference binary SHA256 digest value, but are consistent. - _, err = verifyAndSummarizeProvenances(&referenceValues, provenances) + _, err = verifyAndSummarizeProvenances(binaryName, binaryHash+"_diff", &verOpts, provenances) if err == nil || !strings.Contains(err.Error(), errorBinaryDigest) { t.Fatalf("got %q, want error message containing %q,", err, errorBinaryDigest) } @@ -149,19 +141,14 @@ func TestLoadAndVerify_InconsistentVerified(t *testing.T) { if err != nil { t.Fatalf("Could not load provenances: %v", err) } - referenceValues := prover.VerificationOptions{ - ReferenceProvenance: &prover.ProvenanceReferenceValues{ - ReferenceBinaryDigests: &prover.Digests{ - Digests: map[string]*prover.StringAllowList{"sha256": {Values: []string{"e8e05d1d09af8952919bf6ab38e0cc5a6414ee2b5e21f4765b12421c5db0037e", binaryHash}}}, - }, - }, + verOpt := prover.VerificationOptions{ + ReferenceProvenance: &prover.ProvenanceReferenceValues{}, } // Provenances each contain a (different) given reference binary SHA256 digest value, but are inconsistent. - _, err = verifyAndSummarizeProvenances(&referenceValues, provenances) - want := "provenances are not consistent" - if err == nil || !strings.Contains(err.Error(), want) { - t.Fatalf("got %q, want error message containing %q,", err, want) + _, err = verifyAndSummarizeProvenances(binaryName, binaryHash, &verOpt, provenances) + if err == nil || !strings.Contains(err.Error(), errorInconsistentProvenances) { + t.Fatalf("got %q, want error message containing %q,", err, errorInconsistentProvenances) } } @@ -180,22 +167,17 @@ func TestLoadAndVerify_InconsistentNotVerified(t *testing.T) { if err != nil { t.Fatalf("Could not load provenances: %v", err) } - referenceValues := prover.VerificationOptions{ - ReferenceProvenance: &prover.ProvenanceReferenceValues{ - ReferenceBinaryDigests: &prover.Digests{ - Digests: map[string]*prover.StringAllowList{"sha256": {Values: []string{binaryHash + "_diff"}}}, - }, - }, + verOpt := prover.VerificationOptions{ + ReferenceProvenance: &prover.ProvenanceReferenceValues{}, } - _, err = verifyAndSummarizeProvenances(&referenceValues, provenances) + _, err = verifyAndSummarizeProvenances(binaryName, binaryHash+"_diff", &verOpt, provenances) if err == nil || !strings.Contains(err.Error(), errorBinaryDigest) { t.Fatalf("got %q, want error message containing %q,", err, errorBinaryDigest) } - want2 := "provenances are not consistent" - if err == nil || !strings.Contains(err.Error(), want2) { - t.Fatalf("got %q, want error message containing %q,", err, want2) + if err == nil || !strings.Contains(err.Error(), errorInconsistentProvenances) { + t.Fatalf("got %q, want error message containing %q,", err, errorInconsistentProvenances) } } @@ -209,24 +191,17 @@ func TestLoadAndVerifyProvenances_NotVerified(t *testing.T) { if err != nil { t.Fatalf("Could not load provenances: %v", err) } - // referenceValues, err := verification.LoadReferenceValuesFromFile("../../testdata/different_reference_values.toml") - referenceValues, err := loadTextprotoVerificationOptions("../../testdata/different_reference_values.textproto") + verOpts, err := loadTextprotoVerificationOptions("../../testdata/different_reference_values.textproto") if err != nil { t.Fatalf("Could not load reference values: %v", err) } - _, err = verifyAndSummarizeProvenances(referenceValues, provenances) - + _, err = verifyAndSummarizeProvenances(binaryName, "a_different_digest", verOpts, provenances) if err == nil || !strings.Contains(err.Error(), errorBinaryDigest) { t.Fatalf("got %q, want error message containing %q,", err, errorBinaryDigest) } - want := "failed to verify binary SHA256 digest" - if err == nil || !strings.Contains(err.Error(), want) { - t.Fatalf("got %q, want error message containing %q,", err, want) - } - - want = "is different from the repo URI" + want := "is different from the repo URI" if err == nil || !strings.Contains(err.Error(), want) { t.Fatalf("got %q, want error message containing %q,", err, want) } diff --git a/internal/verification/verifier.go b/internal/verification/verifier.go index d1f737b7..9b3ce33d 100644 --- a/internal/verification/verifier.go +++ b/internal/verification/verifier.go @@ -27,22 +27,14 @@ import ( // all non-empty fields in got using fields in the reference values. Empty fields will not be verified. type ProvenanceIRVerifier struct { Got *model.ProvenanceIR - Want *prover.VerificationOptions + Want *prover.ProvenanceReferenceValues } // Verify verifies an instance of ProvenanceIRVerifier by comparing its Got and Want fields. // Verify checks fields, which (i) are set in Got, i.e., GotHasX is true, and (ii) are set in Want. func (v *ProvenanceIRVerifier) Verify() error { - if v.Want.GetReferenceProvenance() == nil { - return nil - } - var errs error - if err := v.verifyBinarySHA256Digest(); err != nil { - multierr.AppendInto(&errs, fmt.Errorf("failed to verify binary SHA256 digest: %v", err)) - } - // Verify HasBuildCmd. multierr.AppendInto(&errs, v.verifyBuildCmd()) @@ -62,22 +54,10 @@ func (v *ProvenanceIRVerifier) Verify() error { return errs } -// verifyBinarySHA256Digest verifies that the binary SHA256 Got in this -// verifier is among the Wanted digests. -func (v *ProvenanceIRVerifier) verifyBinarySHA256Digest() error { - referenceDigests := v.Want.GetReferenceProvenance().GetReferenceBinaryDigests() - gotBinarySHA256Digest := v.Got.BinarySHA256Digest() - - if err := verifySHA256Digest(gotBinarySHA256Digest, referenceDigests); err != nil { - return fmt.Errorf("verifying binary SHA356 digest: %v", err) - } - return nil -} - // verifyBuildCmd verifies the build cmd. Returns an error if a build command is // needed in the Want reference values, but is not present in the Got provenance. func (v *ProvenanceIRVerifier) verifyBuildCmd() error { - mustHaveBuildCommand := v.Want.GetReferenceProvenance().GetMustHaveBuildCommand() + mustHaveBuildCommand := v.Want.GetMustHaveBuildCommand() if mustHaveBuildCommand && v.Got.HasBuildCmd() { if buildCmd, err := v.Got.BuildCmd(); err != nil || len(buildCmd) == 0 { return fmt.Errorf("no build cmd found") @@ -89,15 +69,15 @@ func (v *ProvenanceIRVerifier) verifyBuildCmd() error { // verifyBuilderImageDigest verifies that the builder image digest in the Got // provenance matches a builder image digest in the Want reference values. func (v *ProvenanceIRVerifier) verifyBuilderImageDigest() error { - if !v.Got.HasBuilderImageSHA256Digest() { + referenceDigests := v.Want.GetReferenceBuilderImageDigests() + if !v.Got.HasBuilderImageSHA256Digest() || referenceDigests == nil { // A valid provenance that is missing a builder image digest passes the // verification. return nil } - referenceDigests := v.Want.GetReferenceProvenance().GetReferenceBuilderImageDigests() gotBuilderImageDigest, err := v.Got.BuilderImageSHA256Digest() - if err != nil && referenceDigests != nil { + if err != nil { return fmt.Errorf("no builder image digest set") } @@ -110,7 +90,7 @@ func (v *ProvenanceIRVerifier) verifyBuilderImageDigest() error { // verifyRepoURI verifies that the Git URI in the Got provenance // is the same as the repo URI in the Want reference values. func (v *ProvenanceIRVerifier) verifyRepoURI() error { - referenceRepoURI := v.Want.GetReferenceProvenance().GetReferenceRepoUri() + referenceRepoURI := v.Want.GetReferenceRepoUri() if referenceRepoURI == "" { return nil } @@ -128,8 +108,8 @@ func (v *ProvenanceIRVerifier) verifyRepoURI() error { // verifyTrustedBuilder verifies that the given trusted builder matches a trusted builder in the reference values. func (v *ProvenanceIRVerifier) verifyTrustedBuilder() error { - referenceRepoURI := v.Want.GetReferenceProvenance().GetReferenceBuilders() - if referenceRepoURI == nil { + referenceBuilders := v.Want.GetReferenceBuilders() + if referenceBuilders == nil { return nil } @@ -138,14 +118,14 @@ func (v *ProvenanceIRVerifier) verifyTrustedBuilder() error { return fmt.Errorf("no trusted builder set") } - for _, wantTrustedBuilder := range referenceRepoURI.GetValues() { + for _, wantTrustedBuilder := range referenceBuilders.GetValues() { if wantTrustedBuilder == gotTrustedBuilder { return nil } } return fmt.Errorf("the reference trusted builders (%v) do not contain the actual trusted builder (%v)", - referenceRepoURI.GetValues(), + referenceBuilders.GetValues(), gotTrustedBuilder) } diff --git a/internal/verification/verifier_test.go b/internal/verification/verifier_test.go index 2b1f0f22..9c68256c 100644 --- a/internal/verification/verifier_test.go +++ b/internal/verification/verifier_test.go @@ -33,13 +33,9 @@ func TestVerify_HasNoValues(t *testing.T) { // There are no optional fields set apart from the binary digest and the build type. got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName) - want := prover.VerificationOptions{ - ReferenceProvenance: &prover.ProvenanceReferenceValues{}, - } - verifier := ProvenanceIRVerifier{ Got: got, - Want: &want, + Want: &prover.ProvenanceReferenceValues{}, } // We don't expect any verification to happen. @@ -51,10 +47,8 @@ func TestVerify_HasNoValues(t *testing.T) { func TestVerify_NeedsCanHaveHasBuildCmd(t *testing.T) { got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithBuildCmd([]string{"build cmd"})) - want := prover.VerificationOptions{ - ReferenceProvenance: &prover.ProvenanceReferenceValues{ - MustHaveBuildCommand: true, - }, + want := prover.ProvenanceReferenceValues{ + MustHaveBuildCommand: true, } verifier := ProvenanceIRVerifier{ @@ -71,10 +65,8 @@ func TestVerify_NeedsCannotHaveDoesNotHaveBuildCmd(t *testing.T) { // No buildCmd is set in the provenance. got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName) - want := prover.VerificationOptions{ - ReferenceProvenance: &prover.ProvenanceReferenceValues{ - MustHaveBuildCommand: true, - }, + want := prover.ProvenanceReferenceValues{ + MustHaveBuildCommand: true, } verifier := ProvenanceIRVerifier{ @@ -91,10 +83,8 @@ func TestVerify_NeedsCannotHaveHasEmptyBuildCmd(t *testing.T) { // The build command is empty. got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithBuildCmd([]string{})) // And the reference values ask for a build cmd. - want := prover.VerificationOptions{ - ReferenceProvenance: &prover.ProvenanceReferenceValues{ - MustHaveBuildCommand: true, - }, + want := prover.ProvenanceReferenceValues{ + MustHaveBuildCommand: true, } verifier := ProvenanceIRVerifier{ @@ -112,10 +102,8 @@ func TestVerify_DoesNotNeedCannotHaveHasEmptyBuildCmd(t *testing.T) { // The build command is empty. got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithBuildCmd([]string{})) // But the reference values do not ask for a build cmd. - want := prover.VerificationOptions{ - ReferenceProvenance: &prover.ProvenanceReferenceValues{ - MustHaveBuildCommand: false, - }, + want := prover.ProvenanceReferenceValues{ + MustHaveBuildCommand: false, } verifier := ProvenanceIRVerifier{ @@ -132,11 +120,9 @@ func TestVerify_DoesNotNeedCannotHaveHasEmptyBuildCmd(t *testing.T) { func TestVerify_NeedsHasBuilderImageDigest(t *testing.T) { builderDigest := "9e2ba52487d945504d250de186cb4fe2e3ba023ed2921dd6ac8b97ed43e76af9" got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithBuilderImageSHA256Digest(builderDigest)) - want := prover.VerificationOptions{ - ReferenceProvenance: &prover.ProvenanceReferenceValues{ - ReferenceBuilderImageDigests: &prover.Digests{ - Digests: map[string]*prover.StringAllowList{"sha256": {Values: []string{"some_other_digest", builderDigest}}}, - }, + want := prover.ProvenanceReferenceValues{ + ReferenceBuilderImageDigests: &prover.Digests{ + Digests: map[string]*prover.StringAllowList{"sha256": {Values: []string{"some_other_digest", builderDigest}}}, }, } @@ -153,11 +139,9 @@ func TestVerify_NeedsHasBuilderImageDigest(t *testing.T) { func TestVerify_NeedsDoesNotHaveBuilderImageDigest(t *testing.T) { builderDigest := "9e2ba52487d945504d250de186cb4fe2e3ba023ed2921dd6ac8b97ed43e76af9" got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithBuilderImageSHA256Digest(builderDigest)) - want := prover.VerificationOptions{ - ReferenceProvenance: &prover.ProvenanceReferenceValues{ - ReferenceBuilderImageDigests: &prover.Digests{ - Digests: map[string]*prover.StringAllowList{"sha256": {Values: []string{"some_other_digest", "and_some_other"}}}, - }, + want := prover.ProvenanceReferenceValues{ + ReferenceBuilderImageDigests: &prover.Digests{ + Digests: map[string]*prover.StringAllowList{"sha256": {Values: []string{"some_other_digest", "and_some_other"}}}, }, } @@ -167,7 +151,7 @@ func TestVerify_NeedsDoesNotHaveBuilderImageDigest(t *testing.T) { } wantErr := fmt.Sprintf("the reference SHA256 digests (%v) do not contain the actual SHA256 digest (%v)", - want.GetReferenceProvenance().GetReferenceBuilderImageDigests().GetDigests()["sha256"].GetValues(), + want.GetReferenceBuilderImageDigests().GetDigests()["sha256"].GetValues(), builderDigest) if err := verifier.Verify(); err == nil || !strings.Contains(err.Error(), wantErr) { t.Fatalf("got %q, want error message containing %q,", err, wantErr) @@ -176,11 +160,9 @@ func TestVerify_NeedsDoesNotHaveBuilderImageDigest(t *testing.T) { func TestVerify_NeedsHasEmptyBuilderImageDigest(t *testing.T) { got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithBuilderImageSHA256Digest("")) - want := prover.VerificationOptions{ - ReferenceProvenance: &prover.ProvenanceReferenceValues{ - ReferenceBuilderImageDigests: &prover.Digests{ - Digests: map[string]*prover.StringAllowList{"sha256": {Values: []string{"some_digest"}}}, - }, + want := prover.ProvenanceReferenceValues{ + ReferenceBuilderImageDigests: &prover.Digests{ + Digests: map[string]*prover.StringAllowList{"sha256": {Values: []string{"some_digest"}}}, }, } @@ -190,7 +172,7 @@ func TestVerify_NeedsHasEmptyBuilderImageDigest(t *testing.T) { } wantErr := fmt.Sprintf("the reference SHA256 digests (%v) do not contain the actual SHA256 digest (%v)", - want.GetReferenceProvenance().GetReferenceBuilderImageDigests().GetDigests()["sha256"].GetValues(), + want.GetReferenceBuilderImageDigests().GetDigests()["sha256"].GetValues(), "") if err := verifier.Verify(); err == nil || !strings.Contains(err.Error(), wantErr) { t.Fatalf("got %q, want error message containing %q,", err, wantErr) @@ -200,14 +182,11 @@ func TestVerify_NeedsHasEmptyBuilderImageDigest(t *testing.T) { func TestVerify_DoesNotNeedHasEmptyBuilderImageDigest(t *testing.T) { builderImageSHA256Digest := "" got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithBuilderImageSHA256Digest(builderImageSHA256Digest)) - want := prover.VerificationOptions{ - // We do not check for the builder image digest. - ReferenceProvenance: &prover.ProvenanceReferenceValues{}, - } verifier := ProvenanceIRVerifier{ - Got: got, - Want: &want, + Got: got, + // We do not check for the builder image digest. + Want: &prover.ProvenanceReferenceValues{}, } if err := verifier.Verify(); err != nil { @@ -218,10 +197,8 @@ func TestVerify_DoesNotNeedHasEmptyBuilderImageDigest(t *testing.T) { func TestVerify_HasWantedRepoURI(t *testing.T) { got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithRepoURI("https://github.com/project-oak/transparent-release")) - want := prover.VerificationOptions{ - ReferenceProvenance: &prover.ProvenanceReferenceValues{ - ReferenceRepoUri: "https://github.com/project-oak/transparent-release", - }, + want := prover.ProvenanceReferenceValues{ + ReferenceRepoUri: "https://github.com/project-oak/transparent-release", } verifier := ProvenanceIRVerifier{ @@ -240,10 +217,8 @@ func TestVerify_HasWrongRepoURI(t *testing.T) { got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithRepoURI(wrongURI)) - want := prover.VerificationOptions{ - ReferenceProvenance: &prover.ProvenanceReferenceValues{ - ReferenceRepoUri: "github.com/project-oak/transparent-release", - }, + want := prover.ProvenanceReferenceValues{ + ReferenceRepoUri: "github.com/project-oak/transparent-release", } verifier := ProvenanceIRVerifier{ @@ -253,7 +228,7 @@ func TestVerify_HasWrongRepoURI(t *testing.T) { wantErr := fmt.Sprintf("the repo URI from the provenance (%v) is different from the repo URI (%v)", wrongURI, - want.GetReferenceProvenance().GetReferenceRepoUri(), + want.GetReferenceRepoUri(), ) if err := verifier.Verify(); err == nil || !strings.Contains(err.Error(), wantErr) { t.Fatalf("got %q, want error message containing %q,", err, wantErr) @@ -263,10 +238,8 @@ func TestVerify_HasWrongRepoURI(t *testing.T) { func TestVerify_HasNoRepoURIs(t *testing.T) { // We have no repo URIs in the provenance. got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName) - want := prover.VerificationOptions{ - ReferenceProvenance: &prover.ProvenanceReferenceValues{ - ReferenceRepoUri: "github.com/project-oak/transparent-release", - }, + want := prover.ProvenanceReferenceValues{ + ReferenceRepoUri: "github.com/project-oak/transparent-release", } verifier := ProvenanceIRVerifier{ @@ -275,7 +248,7 @@ func TestVerify_HasNoRepoURIs(t *testing.T) { } wantErr := fmt.Sprintf("no repo URI in the provenance, but want (%v)", - want.GetReferenceProvenance().GetReferenceRepoUri(), + want.GetReferenceRepoUri(), ) if err := verifier.Verify(); err == nil || !strings.Contains(err.Error(), wantErr) { t.Fatalf("got %q, want error message containing %q,", err, wantErr) @@ -286,11 +259,9 @@ func TestVerify_NeedsHasTrustedBuilder(t *testing.T) { trustedBuilder := "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@refs/tags/v1.2.0" got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithTrustedBuilder(trustedBuilder)) - want := prover.VerificationOptions{ - ReferenceProvenance: &prover.ProvenanceReferenceValues{ - ReferenceBuilders: &prover.StringAllowList{ - Values: []string{trustedBuilder}, - }, + want := prover.ProvenanceReferenceValues{ + ReferenceBuilders: &prover.StringAllowList{ + Values: []string{trustedBuilder}, }, } @@ -308,11 +279,9 @@ func TestVerify_NeedsDoesNotHaveTrustedBuilder(t *testing.T) { trustedBuilder := "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@refs/tags/v1.2.0" got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithTrustedBuilder(trustedBuilder)) - want := prover.VerificationOptions{ - ReferenceProvenance: &prover.ProvenanceReferenceValues{ - ReferenceBuilders: &prover.StringAllowList{ - Values: []string{"other_" + trustedBuilder, "another_" + trustedBuilder}, - }, + want := prover.ProvenanceReferenceValues{ + ReferenceBuilders: &prover.StringAllowList{ + Values: []string{"other_" + trustedBuilder, "another_" + trustedBuilder}, }, } @@ -322,7 +291,7 @@ func TestVerify_NeedsDoesNotHaveTrustedBuilder(t *testing.T) { } wantErr := fmt.Sprintf("the reference trusted builders (%v) do not contain the actual trusted builder (%v)", - want.GetReferenceProvenance().GetReferenceBuilders().GetValues(), + want.GetReferenceBuilders().GetValues(), trustedBuilder) if err := verifier.Verify(); err == nil || !strings.Contains(err.Error(), wantErr) { t.Fatalf("got %q, want error message containing %q,", err, wantErr) @@ -332,11 +301,9 @@ func TestVerify_NeedsDoesNotHaveTrustedBuilder(t *testing.T) { func TestVerify_NeedsHasEmptyTrustedBuilder(t *testing.T) { got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithTrustedBuilder("")) - want := prover.VerificationOptions{ - ReferenceProvenance: &prover.ProvenanceReferenceValues{ - ReferenceBuilders: &prover.StringAllowList{ - Values: []string{"other_trusted_builder", "another_trusted_builder"}, - }, + want := prover.ProvenanceReferenceValues{ + ReferenceBuilders: &prover.StringAllowList{ + Values: []string{"other_trusted_builder", "another_trusted_builder"}, }, } @@ -346,7 +313,7 @@ func TestVerify_NeedsHasEmptyTrustedBuilder(t *testing.T) { } wantErr := fmt.Sprintf("the reference trusted builders (%v) do not contain the actual trusted builder (%v)", - want.GetReferenceProvenance().GetReferenceBuilders().GetValues(), + want.GetReferenceBuilders().GetValues(), "") if err := verifier.Verify(); err == nil || !strings.Contains(err.Error(), wantErr) { t.Fatalf("got %q, want error message containing %q,", err, wantErr) @@ -356,14 +323,10 @@ func TestVerify_NeedsHasEmptyTrustedBuilder(t *testing.T) { func TestVerify_DoesNotNeedHasEmptyTrustedBuilder(t *testing.T) { got := model.NewProvenanceIR(binarySHA256Digest, slsav02.GenericSLSABuildType, binaryName, model.WithTrustedBuilder("")) - want := prover.VerificationOptions{ - // We do not check the trusted builder. - ReferenceProvenance: &prover.ProvenanceReferenceValues{}, - } - verifier := ProvenanceIRVerifier{ - Got: got, - Want: &want, + Got: got, + // We do not check the trusted builder. + Want: &prover.ProvenanceReferenceValues{}, } if err := verifier.Verify(); err != nil { diff --git a/pkg/proto/verification/provenance_verification.pb.go b/pkg/proto/verification/provenance_verification.pb.go index a6f25a9e..a663af56 100644 --- a/pkg/proto/verification/provenance_verification.pb.go +++ b/pkg/proto/verification/provenance_verification.pb.go @@ -41,6 +41,7 @@ type VerificationOptions struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // The absence of a reference provenance indicates that provenance verification can be skipped. ReferenceProvenance *ProvenanceReferenceValues `protobuf:"bytes,1,opt,name=reference_provenance,json=referenceProvenance,proto3,oneof" json:"reference_provenance,omitempty"` } @@ -89,7 +90,6 @@ type ProvenanceReferenceValues struct { unknownFields protoimpl.UnknownFields MustHaveBuildCommand bool `protobuf:"varint,1,opt,name=must_have_build_command,json=mustHaveBuildCommand,proto3" json:"must_have_build_command,omitempty"` - ReferenceBinaryDigests *Digests `protobuf:"bytes,2,opt,name=reference_binary_digests,json=referenceBinaryDigests,proto3,oneof" json:"reference_binary_digests,omitempty"` ReferenceBuilderImageDigests *Digests `protobuf:"bytes,3,opt,name=reference_builder_image_digests,json=referenceBuilderImageDigests,proto3,oneof" json:"reference_builder_image_digests,omitempty"` ReferenceRepoUri string `protobuf:"bytes,4,opt,name=reference_repo_uri,json=referenceRepoUri,proto3" json:"reference_repo_uri,omitempty"` ReferenceBuilders *StringAllowList `protobuf:"bytes,5,opt,name=reference_builders,json=referenceBuilders,proto3,oneof" json:"reference_builders,omitempty"` @@ -134,13 +134,6 @@ func (x *ProvenanceReferenceValues) GetMustHaveBuildCommand() bool { return false } -func (x *ProvenanceReferenceValues) GetReferenceBinaryDigests() *Digests { - if x != nil { - return x.ReferenceBinaryDigests - } - return nil -} - func (x *ProvenanceReferenceValues) GetReferenceBuilderImageDigests() *Digests { if x != nil { return x.ReferenceBuilderImageDigests @@ -277,56 +270,48 @@ var file_proto_provenance_verification_proto_rawDesc = []byte{ 0x52, 0x13, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x88, 0x01, 0x01, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, - 0x65, 0x22, 0x8e, 0x04, 0x0a, 0x19, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, + 0x65, 0x22, 0x8d, 0x03, 0x0a, 0x19, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x35, 0x0a, 0x17, 0x6d, 0x75, 0x73, 0x74, 0x5f, 0x68, 0x61, 0x76, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x6d, 0x75, 0x73, 0x74, 0x48, 0x61, 0x76, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, - 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x62, 0x0a, 0x18, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, - 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, - 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, - 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x48, 0x00, 0x52, - 0x16, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x79, - 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x88, 0x01, 0x01, 0x12, 0x6f, 0x0a, 0x1f, 0x72, 0x65, - 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x5f, - 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x48, 0x01, 0x52, 0x1c, 0x72, 0x65, 0x66, 0x65, - 0x72, 0x65, 0x6e, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x49, 0x6d, 0x61, 0x67, - 0x65, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x88, 0x01, 0x01, 0x12, 0x2c, 0x0a, 0x12, 0x72, - 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x5f, 0x75, 0x72, - 0x69, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, - 0x63, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x55, 0x72, 0x69, 0x12, 0x5f, 0x0a, 0x12, 0x72, 0x65, 0x66, - 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x4c, 0x69, - 0x73, 0x74, 0x48, 0x02, 0x52, 0x11, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x42, - 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x88, 0x01, 0x01, 0x42, 0x1b, 0x0a, 0x19, 0x5f, 0x72, - 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x5f, - 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x42, 0x22, 0x0a, 0x20, 0x5f, 0x72, 0x65, 0x66, 0x65, - 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x6d, - 0x61, 0x67, 0x65, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x42, 0x15, 0x0a, 0x13, 0x5f, - 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, - 0x72, 0x73, 0x22, 0xbe, 0x01, 0x0a, 0x07, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x12, 0x4a, - 0x0a, 0x07, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x30, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, + 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x6f, 0x0a, 0x1f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, + 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x6d, 0x61, 0x67, + 0x65, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x23, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x67, - 0x65, 0x73, 0x74, 0x73, 0x2e, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x07, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x1a, 0x67, 0x0a, 0x0c, 0x44, 0x69, - 0x67, 0x65, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x41, 0x0a, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x65, - 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, - 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x41, - 0x6c, 0x6c, 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, - 0x02, 0x38, 0x01, 0x22, 0x29, 0x0a, 0x0f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x41, 0x6c, 0x6c, - 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x42, 0x14, - 0x5a, 0x12, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x73, 0x74, 0x73, 0x48, 0x00, 0x52, 0x1c, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, + 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x44, 0x69, 0x67, + 0x65, 0x73, 0x74, 0x73, 0x88, 0x01, 0x01, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x65, 0x66, 0x65, 0x72, + 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x10, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, + 0x70, 0x6f, 0x55, 0x72, 0x69, 0x12, 0x5f, 0x0a, 0x12, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, + 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x01, + 0x52, 0x11, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, + 0x65, 0x72, 0x73, 0x88, 0x01, 0x01, 0x42, 0x22, 0x0a, 0x20, 0x5f, 0x72, 0x65, 0x66, 0x65, 0x72, + 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x6d, 0x61, + 0x67, 0x65, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x72, + 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, + 0x73, 0x22, 0xbe, 0x01, 0x0a, 0x07, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x12, 0x4a, 0x0a, + 0x07, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, + 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, + 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x67, 0x65, + 0x73, 0x74, 0x73, 0x2e, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x07, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x1a, 0x67, 0x0a, 0x0c, 0x44, 0x69, 0x67, + 0x65, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x41, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x65, 0x72, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, + 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x41, 0x6c, + 0x6c, 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x22, 0x29, 0x0a, 0x0f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x41, 0x6c, 0x6c, 0x6f, + 0x77, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x42, 0x14, 0x5a, + 0x12, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -351,16 +336,15 @@ var file_proto_provenance_verification_proto_goTypes = []interface{}{ } var file_proto_provenance_verification_proto_depIdxs = []int32{ 1, // 0: verification.provenance.v1.VerificationOptions.reference_provenance:type_name -> verification.provenance.v1.ProvenanceReferenceValues - 2, // 1: verification.provenance.v1.ProvenanceReferenceValues.reference_binary_digests:type_name -> verification.provenance.v1.Digests - 2, // 2: verification.provenance.v1.ProvenanceReferenceValues.reference_builder_image_digests:type_name -> verification.provenance.v1.Digests - 3, // 3: verification.provenance.v1.ProvenanceReferenceValues.reference_builders:type_name -> verification.provenance.v1.StringAllowList - 4, // 4: verification.provenance.v1.Digests.digests:type_name -> verification.provenance.v1.Digests.DigestsEntry - 3, // 5: verification.provenance.v1.Digests.DigestsEntry.value:type_name -> verification.provenance.v1.StringAllowList - 6, // [6:6] is the sub-list for method output_type - 6, // [6:6] is the sub-list for method input_type - 6, // [6:6] is the sub-list for extension type_name - 6, // [6:6] is the sub-list for extension extendee - 0, // [0:6] is the sub-list for field type_name + 2, // 1: verification.provenance.v1.ProvenanceReferenceValues.reference_builder_image_digests:type_name -> verification.provenance.v1.Digests + 3, // 2: verification.provenance.v1.ProvenanceReferenceValues.reference_builders:type_name -> verification.provenance.v1.StringAllowList + 4, // 3: verification.provenance.v1.Digests.digests:type_name -> verification.provenance.v1.Digests.DigestsEntry + 3, // 4: verification.provenance.v1.Digests.DigestsEntry.value:type_name -> verification.provenance.v1.StringAllowList + 5, // [5:5] is the sub-list for method output_type + 5, // [5:5] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name } func init() { file_proto_provenance_verification_proto_init() } diff --git a/proto/provenance_verification.proto b/proto/provenance_verification.proto index f3ae3695..a2af2e32 100644 --- a/proto/provenance_verification.proto +++ b/proto/provenance_verification.proto @@ -27,7 +27,6 @@ message VerificationOptions { message ProvenanceReferenceValues { bool must_have_build_command = 1; - optional Digests reference_binary_digests = 2; optional Digests reference_builder_image_digests = 3; string reference_repo_uri = 4; optional StringAllowList reference_builders = 5; diff --git a/testdata/different_reference_values.textproto b/testdata/different_reference_values.textproto index f43d61e3..2ee225ad 100644 --- a/testdata/different_reference_values.textproto +++ b/testdata/different_reference_values.textproto @@ -1,11 +1,5 @@ reference_provenance: { must_have_build_command: true - reference_binary_digests: { - digests: { - key: "sha256" - value: { values: ["a_different_digest"]} - } - } reference_builder_image_digests: { digests: { key: "sha256" @@ -14,4 +8,4 @@ reference_provenance: { } reference_repo_uri: "some_different_repo" } - \ No newline at end of file + \ No newline at end of file diff --git a/testdata/reference_values.textproto b/testdata/reference_values.textproto index ee78d3bb..5168b5de 100644 --- a/testdata/reference_values.textproto +++ b/testdata/reference_values.textproto @@ -1,11 +1,5 @@ reference_provenance: { must_have_build_command: false - reference_binary_digests: { - digests: { - key: "sha256" - value: { values: ["d059c38cea82047ad316a1c6c6fbd13ecf7a0abdcc375463920bd25bf5c142cc"]} - } - } reference_builder_image_digests: { digests: { key: "sha256" From 62c6d0e378991dc8c8ef1cdfe0c5a070d74145e6 Mon Sep 17 00:00:00 2001 From: Razieh Behjati Date: Wed, 12 Jul 2023 17:38:49 +0100 Subject: [PATCH 05/13] Add test for provenance-less endorsement generation --- internal/endorser/endorser.go | 5 ++-- internal/endorser/endorser_test.go | 40 ++++++++++++++++++++++++------ 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/internal/endorser/endorser.go b/internal/endorser/endorser.go index 6e87b12b..d9ecf842 100644 --- a/internal/endorser/endorser.go +++ b/internal/endorser/endorser.go @@ -79,9 +79,10 @@ func verifyAndSummarizeProvenances(binaryName, binaryDigest string, verOpt *prov provenancesData = append(provenancesData, p.SourceMetadata) } - errs := multierr.Append(verifyConsistency(provenanceIRs), verifyProvenances(verOpt.GetReferenceProvenance(), provenanceIRs)) - + var errs error if len(provenanceIRs) > 0 { + errs = multierr.Append(verifyConsistency(provenanceIRs), verifyProvenances(verOpt.GetReferenceProvenance(), provenanceIRs)) + if provenanceIRs[0].BinarySHA256Digest() != binaryDigest { errs = multierr.Append(errs, fmt.Errorf("the binary digest in the provenance (%q) does not match the given binary digest (%q)", provenanceIRs[0].BinarySHA256Digest(), binaryDigest)) diff --git a/internal/endorser/endorser_test.go b/internal/endorser/endorser_test.go index 0f5cc161..801af479 100644 --- a/internal/endorser/endorser_test.go +++ b/internal/endorser/endorser_test.go @@ -34,7 +34,7 @@ const ( errorInconsistentProvenances = "provenances are not consistent" ) -func TestGenerateEndorsement_SingleValidEndorsement(t *testing.T) { +func TestGenerateEndorsement_SingleValidProvenance(t *testing.T) { tomorrow := time.Now().AddDate(0, 0, 1) nextWeek := time.Now().AddDate(0, 0, 7) validity := claims.ClaimValidity{ @@ -71,7 +71,31 @@ func TestGenerateEndorsement_SingleValidEndorsement(t *testing.T) { testutil.AssertEq(t, "notAfter date", predicate.Validity.NotAfter, &nextWeek) } -func TestLoadAndVerifyProvenances_MultipleValidEndorsement(t *testing.T) { +func TestGenerateEndorsement_NoProvenance(t *testing.T) { + verOpts := &prover.VerificationOptions{ + // No ProvenanceReferenceValues to allow provenance-less endorsement generation. + } + tomorrow := time.Now().AddDate(0, 0, 1) + nextWeek := time.Now().AddDate(0, 0, 7) + validity := claims.ClaimValidity{ + NotBefore: &tomorrow, + NotAfter: &nextWeek, + } + statement, err := GenerateEndorsement(binaryName, binaryHash, verOpts, validity, []ParsedProvenance{}) + if err != nil { + t.Fatalf("Could not generate provenance-less endorsement: %v", err) + } + + testutil.AssertEq(t, "binary hash", statement.Subject[0].Digest["sha256"], binaryHash) + testutil.AssertEq(t, "binary name", statement.Subject[0].Name, binaryName) + + predicate := statement.Predicate.(claims.ClaimPredicate) + + testutil.AssertEq(t, "notBefore date", predicate.Validity.NotBefore, &tomorrow) + testutil.AssertEq(t, "notAfter date", predicate.Validity.NotAfter, &nextWeek) +} + +func TestLoadAndVerifyProvenances_MultipleValidProvenances(t *testing.T) { tempPath1, err := copyToTemp("../../testdata/slsa_v02_provenance.json") if err != nil { t.Fatalf("Could not load provenance: %v", err) @@ -85,10 +109,10 @@ func TestLoadAndVerifyProvenances_MultipleValidEndorsement(t *testing.T) { t.Fatalf("Could not load provenances: %v", err) } - referenceValues := prover.VerificationOptions{ + verOpts := &prover.VerificationOptions{ ReferenceProvenance: &prover.ProvenanceReferenceValues{}, } - provenanceSet, err := verifyAndSummarizeProvenances(binaryName, binaryHash, &referenceValues, provenances) + provenanceSet, err := verifyAndSummarizeProvenances(binaryName, binaryHash, verOpts, provenances) if err != nil { t.Fatalf("Could not generate endorsement from %q: %v", provenances[0].SourceMetadata.URI, err) } @@ -115,12 +139,12 @@ func TestLoadAndVerifyProvenances_ConsistentNotVerified(t *testing.T) { if err != nil { t.Fatalf("Could not load provenances: %v", err) } - verOpts := prover.VerificationOptions{ + verOpts := &prover.VerificationOptions{ ReferenceProvenance: &prover.ProvenanceReferenceValues{}, } // Provenances do not contain the given reference binary SHA256 digest value, but are consistent. - _, err = verifyAndSummarizeProvenances(binaryName, binaryHash+"_diff", &verOpts, provenances) + _, err = verifyAndSummarizeProvenances(binaryName, binaryHash+"_diff", verOpts, provenances) if err == nil || !strings.Contains(err.Error(), errorBinaryDigest) { t.Fatalf("got %q, want error message containing %q,", err, errorBinaryDigest) } @@ -167,11 +191,11 @@ func TestLoadAndVerify_InconsistentNotVerified(t *testing.T) { if err != nil { t.Fatalf("Could not load provenances: %v", err) } - verOpt := prover.VerificationOptions{ + verOpt := &prover.VerificationOptions{ ReferenceProvenance: &prover.ProvenanceReferenceValues{}, } - _, err = verifyAndSummarizeProvenances(binaryName, binaryHash+"_diff", &verOpt, provenances) + _, err = verifyAndSummarizeProvenances(binaryName, binaryHash+"_diff", verOpt, provenances) if err == nil || !strings.Contains(err.Error(), errorBinaryDigest) { t.Fatalf("got %q, want error message containing %q,", err, errorBinaryDigest) } From a1fcaa7cc70119a3065539278de51d245b4cf625 Mon Sep 17 00:00:00 2001 From: Razieh Behjati Date: Thu, 13 Jul 2023 18:55:36 +0100 Subject: [PATCH 06/13] Make skip verification an explicit field in the proto --- internal/endorser/endorser.go | 18 +- internal/endorser/endorser_test.go | 58 +++- .../provenance_verification.pb.go | 268 ++++++++++++------ proto/provenance_verification.proto | 17 +- testdata/different_reference_values.textproto | 1 - 5 files changed, 255 insertions(+), 107 deletions(-) diff --git a/internal/endorser/endorser.go b/internal/endorser/endorser.go index d9ecf842..1d9cb5dd 100644 --- a/internal/endorser/endorser.go +++ b/internal/endorser/endorser.go @@ -46,12 +46,16 @@ type ParsedProvenance struct { // GenerateEndorsement generates an endorsement statement for the given binary // and the given validity duration, using the given provenances as evidence and -// reference values to verify them. If more than one provenance statements are -// provided the endorsement statement is generated only if the provenance -// statements are valid. If no provenances are provided, a provenance-less -// endorsement is generated, if the input verification options does not contain +// VerificationOptions to verify them. If more than one provenance statements +// are provided the endorsement statement is generated only if the provenance +// statements are consistent and valid according to the input +// VerificationOptions. If no provenances are provided, a provenance-less +// endorsement is generated, if the input VerificationOptions does not contain // a reference provenance. func GenerateEndorsement(binaryName, binaryDigest string, verOpt *prover.VerificationOptions, validityDuration claims.ClaimValidity, provenances []ParsedProvenance) (*intoto.Statement, error) { + if (verOpt.GetSkipProvenanceVerification() == nil) && (verOpt.GetReferenceProvenance() == nil) { + return nil, fmt.Errorf("invalid VerificationOptions: exactly one of SkipProvenanceVerification and ReferenceProvenance must be set") + } verifiedProvenances, err := verifyAndSummarizeProvenances(binaryName, binaryDigest, verOpt, provenances) if err != nil { return nil, fmt.Errorf("could not verify and summarize provenances: %v", err) @@ -63,12 +67,12 @@ func GenerateEndorsement(binaryName, binaryDigest string, verOpt *prover.Verific // Returns an instance of claims.VerifiedProvenanceSet, containing metadata // about a set of verified provenances, or an error. An error is returned if // any of the following conditions is met: -// (1) The list of provenances is empty, but verification options contains a -// nonempty provenance reference. +// (1) The list of provenances is empty, but VerificationOptions does not have +// its SkipProvenanceVerification field set. // (2) Any of the provenances is invalid (see verifyProvenances for details), // (3) Provenances do not match (e.g., have different binary names). func verifyAndSummarizeProvenances(binaryName, binaryDigest string, verOpt *prover.VerificationOptions, provenances []ParsedProvenance) (*claims.VerifiedProvenanceSet, error) { - if len(provenances) == 0 && verOpt.GetReferenceProvenance() != nil { + if len(provenances) == 0 && verOpt.GetSkipProvenanceVerification() == nil { return nil, fmt.Errorf("at least one provenance file must be provided") } diff --git a/internal/endorser/endorser_test.go b/internal/endorser/endorser_test.go index 801af479..da52de50 100644 --- a/internal/endorser/endorser_test.go +++ b/internal/endorser/endorser_test.go @@ -54,7 +54,7 @@ func TestGenerateEndorsement_SingleValidProvenance(t *testing.T) { verOpt, err := loadTextprotoVerificationOptions("../../testdata/reference_values.textproto") if err != nil { - t.Fatalf("Could not load reference values: %v", err) + t.Fatalf("Could not load verification options: %v", err) } statement, err := GenerateEndorsement(binaryName, binaryHash, verOpt, validity, provenances) @@ -73,7 +73,10 @@ func TestGenerateEndorsement_SingleValidProvenance(t *testing.T) { func TestGenerateEndorsement_NoProvenance(t *testing.T) { verOpts := &prover.VerificationOptions{ - // No ProvenanceReferenceValues to allow provenance-less endorsement generation. + // Skip verification to allow provenance-less endorsement generation. + Option: &prover.VerificationOptions_SkipProvenanceVerification{ + SkipProvenanceVerification: &prover.SkipVerification{}, + }, } tomorrow := time.Now().AddDate(0, 0, 1) nextWeek := time.Now().AddDate(0, 0, 7) @@ -93,6 +96,39 @@ func TestGenerateEndorsement_NoProvenance(t *testing.T) { testutil.AssertEq(t, "notBefore date", predicate.Validity.NotBefore, &tomorrow) testutil.AssertEq(t, "notAfter date", predicate.Validity.NotAfter, &nextWeek) + + // Repeat the same with verification options loaded from file. + verOpts, err = loadTextprotoVerificationOptions("../../testdata/skip_verification.textproto") + if err != nil { + t.Fatalf("Could not load verification options: %v", err) + } + statement, err = GenerateEndorsement(binaryName, binaryHash, verOpts, validity, []ParsedProvenance{}) + if err != nil { + t.Fatalf("Could not generate provenance-less endorsement: %v", err) + } + + testutil.AssertEq(t, "binary hash", statement.Subject[0].Digest["sha256"], binaryHash) + testutil.AssertEq(t, "binary name", statement.Subject[0].Name, binaryName) + + predicate = statement.Predicate.(claims.ClaimPredicate) + + testutil.AssertEq(t, "notBefore date", predicate.Validity.NotBefore, &tomorrow) + testutil.AssertEq(t, "notAfter date", predicate.Validity.NotAfter, &nextWeek) +} + +func TestGenerateEndorsement_InvalidVerificationOptions(t *testing.T) { + tomorrow := time.Now().AddDate(0, 0, 1) + nextWeek := time.Now().AddDate(0, 0, 7) + validity := claims.ClaimValidity{ + NotBefore: &tomorrow, + NotAfter: &nextWeek, + } + + verOpts := &prover.VerificationOptions{} + _, err := GenerateEndorsement(binaryName, binaryHash, verOpts, validity, []ParsedProvenance{}) + if err == nil || !strings.Contains(err.Error(), "invalid VerificationOptions") { + t.Fatalf("got %q, want error message containing %q,", err, "invalid VerificationOptions:") + } } func TestLoadAndVerifyProvenances_MultipleValidProvenances(t *testing.T) { @@ -110,7 +146,9 @@ func TestLoadAndVerifyProvenances_MultipleValidProvenances(t *testing.T) { } verOpts := &prover.VerificationOptions{ - ReferenceProvenance: &prover.ProvenanceReferenceValues{}, + Option: &prover.VerificationOptions_ReferenceProvenance{ + ReferenceProvenance: &prover.ProvenanceReferenceValues{}, + }, } provenanceSet, err := verifyAndSummarizeProvenances(binaryName, binaryHash, verOpts, provenances) if err != nil { @@ -140,7 +178,9 @@ func TestLoadAndVerifyProvenances_ConsistentNotVerified(t *testing.T) { t.Fatalf("Could not load provenances: %v", err) } verOpts := &prover.VerificationOptions{ - ReferenceProvenance: &prover.ProvenanceReferenceValues{}, + Option: &prover.VerificationOptions_ReferenceProvenance{ + ReferenceProvenance: &prover.ProvenanceReferenceValues{}, + }, } // Provenances do not contain the given reference binary SHA256 digest value, but are consistent. @@ -166,7 +206,9 @@ func TestLoadAndVerify_InconsistentVerified(t *testing.T) { t.Fatalf("Could not load provenances: %v", err) } verOpt := prover.VerificationOptions{ - ReferenceProvenance: &prover.ProvenanceReferenceValues{}, + Option: &prover.VerificationOptions_ReferenceProvenance{ + ReferenceProvenance: &prover.ProvenanceReferenceValues{}, + }, } // Provenances each contain a (different) given reference binary SHA256 digest value, but are inconsistent. @@ -192,7 +234,9 @@ func TestLoadAndVerify_InconsistentNotVerified(t *testing.T) { t.Fatalf("Could not load provenances: %v", err) } verOpt := &prover.VerificationOptions{ - ReferenceProvenance: &prover.ProvenanceReferenceValues{}, + Option: &prover.VerificationOptions_ReferenceProvenance{ + ReferenceProvenance: &prover.ProvenanceReferenceValues{}, + }, } _, err = verifyAndSummarizeProvenances(binaryName, binaryHash+"_diff", verOpt, provenances) @@ -217,7 +261,7 @@ func TestLoadAndVerifyProvenances_NotVerified(t *testing.T) { } verOpts, err := loadTextprotoVerificationOptions("../../testdata/different_reference_values.textproto") if err != nil { - t.Fatalf("Could not load reference values: %v", err) + t.Fatalf("Could not load verification options: %v", err) } _, err = verifyAndSummarizeProvenances(binaryName, "a_different_digest", verOpts, provenances) diff --git a/pkg/proto/verification/provenance_verification.pb.go b/pkg/proto/verification/provenance_verification.pb.go index a663af56..8ef17f8c 100644 --- a/pkg/proto/verification/provenance_verification.pb.go +++ b/pkg/proto/verification/provenance_verification.pb.go @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package main contains a command-line tool for verifying SLSA provenances. - // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.31.0 @@ -41,8 +39,11 @@ type VerificationOptions struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // The absence of a reference provenance indicates that provenance verification can be skipped. - ReferenceProvenance *ProvenanceReferenceValues `protobuf:"bytes,1,opt,name=reference_provenance,json=referenceProvenance,proto3,oneof" json:"reference_provenance,omitempty"` + // Types that are assignable to Option: + // + // *VerificationOptions_SkipProvenanceVerification + // *VerificationOptions_ReferenceProvenance + Option isVerificationOptions_Option `protobuf_oneof:"option"` } func (x *VerificationOptions) Reset() { @@ -77,13 +78,83 @@ func (*VerificationOptions) Descriptor() ([]byte, []int) { return file_proto_provenance_verification_proto_rawDescGZIP(), []int{0} } +func (m *VerificationOptions) GetOption() isVerificationOptions_Option { + if m != nil { + return m.Option + } + return nil +} + +func (x *VerificationOptions) GetSkipProvenanceVerification() *SkipVerification { + if x, ok := x.GetOption().(*VerificationOptions_SkipProvenanceVerification); ok { + return x.SkipProvenanceVerification + } + return nil +} + func (x *VerificationOptions) GetReferenceProvenance() *ProvenanceReferenceValues { - if x != nil { + if x, ok := x.GetOption().(*VerificationOptions_ReferenceProvenance); ok { return x.ReferenceProvenance } return nil } +type isVerificationOptions_Option interface { + isVerificationOptions_Option() +} + +type VerificationOptions_SkipProvenanceVerification struct { + SkipProvenanceVerification *SkipVerification `protobuf:"bytes,1,opt,name=skip_provenance_verification,json=skipProvenanceVerification,proto3,oneof"` +} + +type VerificationOptions_ReferenceProvenance struct { + ReferenceProvenance *ProvenanceReferenceValues `protobuf:"bytes,2,opt,name=reference_provenance,json=referenceProvenance,proto3,oneof"` +} + +func (*VerificationOptions_SkipProvenanceVerification) isVerificationOptions_Option() {} + +func (*VerificationOptions_ReferenceProvenance) isVerificationOptions_Option() {} + +// A singleton value to indicate that verification can be skipped. +type SkipVerification struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *SkipVerification) Reset() { + *x = SkipVerification{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_provenance_verification_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SkipVerification) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SkipVerification) ProtoMessage() {} + +func (x *SkipVerification) ProtoReflect() protoreflect.Message { + mi := &file_proto_provenance_verification_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SkipVerification.ProtoReflect.Descriptor instead. +func (*SkipVerification) Descriptor() ([]byte, []int) { + return file_proto_provenance_verification_proto_rawDescGZIP(), []int{1} +} + +// A collection of reference values for verifying provenance statements. type ProvenanceReferenceValues struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -98,7 +169,7 @@ type ProvenanceReferenceValues struct { func (x *ProvenanceReferenceValues) Reset() { *x = ProvenanceReferenceValues{} if protoimpl.UnsafeEnabled { - mi := &file_proto_provenance_verification_proto_msgTypes[1] + mi := &file_proto_provenance_verification_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -111,7 +182,7 @@ func (x *ProvenanceReferenceValues) String() string { func (*ProvenanceReferenceValues) ProtoMessage() {} func (x *ProvenanceReferenceValues) ProtoReflect() protoreflect.Message { - mi := &file_proto_provenance_verification_proto_msgTypes[1] + mi := &file_proto_provenance_verification_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -124,7 +195,7 @@ func (x *ProvenanceReferenceValues) ProtoReflect() protoreflect.Message { // Deprecated: Use ProvenanceReferenceValues.ProtoReflect.Descriptor instead. func (*ProvenanceReferenceValues) Descriptor() ([]byte, []int) { - return file_proto_provenance_verification_proto_rawDescGZIP(), []int{1} + return file_proto_provenance_verification_proto_rawDescGZIP(), []int{2} } func (x *ProvenanceReferenceValues) GetMustHaveBuildCommand() bool { @@ -155,7 +226,8 @@ func (x *ProvenanceReferenceValues) GetReferenceBuilders() *StringAllowList { return nil } -// Represents an allow listed map of digests. +// An allow list of digests, represented as a mapping from cryptographic hash +// function names, to their allow listed values. type Digests struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -169,7 +241,7 @@ type Digests struct { func (x *Digests) Reset() { *x = Digests{} if protoimpl.UnsafeEnabled { - mi := &file_proto_provenance_verification_proto_msgTypes[2] + mi := &file_proto_provenance_verification_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -182,7 +254,7 @@ func (x *Digests) String() string { func (*Digests) ProtoMessage() {} func (x *Digests) ProtoReflect() protoreflect.Message { - mi := &file_proto_provenance_verification_proto_msgTypes[2] + mi := &file_proto_provenance_verification_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -195,7 +267,7 @@ func (x *Digests) ProtoReflect() protoreflect.Message { // Deprecated: Use Digests.ProtoReflect.Descriptor instead. func (*Digests) Descriptor() ([]byte, []int) { - return file_proto_provenance_verification_proto_rawDescGZIP(), []int{2} + return file_proto_provenance_verification_proto_rawDescGZIP(), []int{3} } func (x *Digests) GetDigests() map[string]*StringAllowList { @@ -205,7 +277,7 @@ func (x *Digests) GetDigests() map[string]*StringAllowList { return nil } -// Represents an allow list of values. +// An allow list of string values. type StringAllowList struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -217,7 +289,7 @@ type StringAllowList struct { func (x *StringAllowList) Reset() { *x = StringAllowList{} if protoimpl.UnsafeEnabled { - mi := &file_proto_provenance_verification_proto_msgTypes[3] + mi := &file_proto_provenance_verification_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -230,7 +302,7 @@ func (x *StringAllowList) String() string { func (*StringAllowList) ProtoMessage() {} func (x *StringAllowList) ProtoReflect() protoreflect.Message { - mi := &file_proto_provenance_verification_proto_msgTypes[3] + mi := &file_proto_provenance_verification_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -243,7 +315,7 @@ func (x *StringAllowList) ProtoReflect() protoreflect.Message { // Deprecated: Use StringAllowList.ProtoReflect.Descriptor instead. func (*StringAllowList) Descriptor() ([]byte, []int) { - return file_proto_provenance_verification_proto_rawDescGZIP(), []int{3} + return file_proto_provenance_verification_proto_rawDescGZIP(), []int{4} } func (x *StringAllowList) GetValues() []string { @@ -260,58 +332,65 @@ var file_proto_provenance_verification_proto_rawDesc = []byte{ 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1a, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, - 0x31, 0x22, 0x9d, 0x01, 0x0a, 0x13, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x6d, 0x0a, 0x14, 0x72, 0x65, 0x66, - 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x52, - 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x48, 0x00, - 0x52, 0x13, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x65, - 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x88, 0x01, 0x01, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x72, 0x65, 0x66, - 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, - 0x65, 0x22, 0x8d, 0x03, 0x0a, 0x19, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, - 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, - 0x35, 0x0a, 0x17, 0x6d, 0x75, 0x73, 0x74, 0x5f, 0x68, 0x61, 0x76, 0x65, 0x5f, 0x62, 0x75, 0x69, - 0x6c, 0x64, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x14, 0x6d, 0x75, 0x73, 0x74, 0x48, 0x61, 0x76, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, - 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x6f, 0x0a, 0x1f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, - 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x6d, 0x61, 0x67, - 0x65, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x23, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, - 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x67, - 0x65, 0x73, 0x74, 0x73, 0x48, 0x00, 0x52, 0x1c, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, - 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x44, 0x69, 0x67, - 0x65, 0x73, 0x74, 0x73, 0x88, 0x01, 0x01, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x65, 0x66, 0x65, 0x72, - 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x10, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, - 0x70, 0x6f, 0x55, 0x72, 0x69, 0x12, 0x5f, 0x0a, 0x12, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, - 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, - 0x74, 0x72, 0x69, 0x6e, 0x67, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x01, - 0x52, 0x11, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, - 0x65, 0x72, 0x73, 0x88, 0x01, 0x01, 0x42, 0x22, 0x0a, 0x20, 0x5f, 0x72, 0x65, 0x66, 0x65, 0x72, - 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x6d, 0x61, - 0x67, 0x65, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x72, + 0x31, 0x22, 0xfd, 0x01, 0x0a, 0x13, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x70, 0x0a, 0x1c, 0x73, 0x6b, 0x69, + 0x70, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2c, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, + 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x6b, 0x69, + 0x70, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, + 0x1a, 0x73, 0x6b, 0x69, 0x70, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x56, + 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x6a, 0x0a, 0x14, 0x72, + 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, + 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x76, 0x65, 0x72, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, + 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, + 0x65, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, + 0x48, 0x00, 0x52, 0x13, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x50, 0x72, 0x6f, + 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x6f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x22, 0x12, 0x0a, 0x10, 0x53, 0x6b, 0x69, 0x70, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x8d, 0x03, 0x0a, 0x19, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x6e, + 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x73, 0x12, 0x35, 0x0a, 0x17, 0x6d, 0x75, 0x73, 0x74, 0x5f, 0x68, 0x61, 0x76, 0x65, + 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x6d, 0x75, 0x73, 0x74, 0x48, 0x61, 0x76, 0x65, 0x42, 0x75, + 0x69, 0x6c, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x6f, 0x0a, 0x1f, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x5f, + 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x48, 0x00, 0x52, 0x1c, 0x72, 0x65, 0x66, 0x65, + 0x72, 0x65, 0x6e, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x49, 0x6d, 0x61, 0x67, + 0x65, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x88, 0x01, 0x01, 0x12, 0x2c, 0x0a, 0x12, 0x72, + 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x5f, 0x75, 0x72, + 0x69, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, + 0x63, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x55, 0x72, 0x69, 0x12, 0x5f, 0x0a, 0x12, 0x72, 0x65, 0x66, + 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x4c, 0x69, + 0x73, 0x74, 0x48, 0x01, 0x52, 0x11, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x42, + 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x88, 0x01, 0x01, 0x42, 0x22, 0x0a, 0x20, 0x5f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, - 0x73, 0x22, 0xbe, 0x01, 0x0a, 0x07, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x12, 0x4a, 0x0a, - 0x07, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, + 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x42, 0x15, + 0x0a, 0x13, 0x5f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, + 0x6c, 0x64, 0x65, 0x72, 0x73, 0x22, 0xbe, 0x01, 0x0a, 0x07, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, + 0x73, 0x12, 0x4a, 0x0a, 0x07, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x1a, 0x67, 0x0a, + 0x0c, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x41, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x67, 0x65, - 0x73, 0x74, 0x73, 0x2e, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x07, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x1a, 0x67, 0x0a, 0x0c, 0x44, 0x69, 0x67, - 0x65, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x41, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x65, 0x72, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, - 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x41, 0x6c, - 0x6c, 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, - 0x38, 0x01, 0x22, 0x29, 0x0a, 0x0f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x41, 0x6c, 0x6c, 0x6f, - 0x77, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x42, 0x14, 0x5a, - 0x12, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x29, 0x0a, 0x0f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x73, 0x42, 0x14, 0x5a, 0x12, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x65, 0x72, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -326,25 +405,27 @@ func file_proto_provenance_verification_proto_rawDescGZIP() []byte { return file_proto_provenance_verification_proto_rawDescData } -var file_proto_provenance_verification_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_proto_provenance_verification_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_proto_provenance_verification_proto_goTypes = []interface{}{ (*VerificationOptions)(nil), // 0: verification.provenance.v1.VerificationOptions - (*ProvenanceReferenceValues)(nil), // 1: verification.provenance.v1.ProvenanceReferenceValues - (*Digests)(nil), // 2: verification.provenance.v1.Digests - (*StringAllowList)(nil), // 3: verification.provenance.v1.StringAllowList - nil, // 4: verification.provenance.v1.Digests.DigestsEntry + (*SkipVerification)(nil), // 1: verification.provenance.v1.SkipVerification + (*ProvenanceReferenceValues)(nil), // 2: verification.provenance.v1.ProvenanceReferenceValues + (*Digests)(nil), // 3: verification.provenance.v1.Digests + (*StringAllowList)(nil), // 4: verification.provenance.v1.StringAllowList + nil, // 5: verification.provenance.v1.Digests.DigestsEntry } var file_proto_provenance_verification_proto_depIdxs = []int32{ - 1, // 0: verification.provenance.v1.VerificationOptions.reference_provenance:type_name -> verification.provenance.v1.ProvenanceReferenceValues - 2, // 1: verification.provenance.v1.ProvenanceReferenceValues.reference_builder_image_digests:type_name -> verification.provenance.v1.Digests - 3, // 2: verification.provenance.v1.ProvenanceReferenceValues.reference_builders:type_name -> verification.provenance.v1.StringAllowList - 4, // 3: verification.provenance.v1.Digests.digests:type_name -> verification.provenance.v1.Digests.DigestsEntry - 3, // 4: verification.provenance.v1.Digests.DigestsEntry.value:type_name -> verification.provenance.v1.StringAllowList - 5, // [5:5] is the sub-list for method output_type - 5, // [5:5] is the sub-list for method input_type - 5, // [5:5] is the sub-list for extension type_name - 5, // [5:5] is the sub-list for extension extendee - 0, // [0:5] is the sub-list for field type_name + 1, // 0: verification.provenance.v1.VerificationOptions.skip_provenance_verification:type_name -> verification.provenance.v1.SkipVerification + 2, // 1: verification.provenance.v1.VerificationOptions.reference_provenance:type_name -> verification.provenance.v1.ProvenanceReferenceValues + 3, // 2: verification.provenance.v1.ProvenanceReferenceValues.reference_builder_image_digests:type_name -> verification.provenance.v1.Digests + 4, // 3: verification.provenance.v1.ProvenanceReferenceValues.reference_builders:type_name -> verification.provenance.v1.StringAllowList + 5, // 4: verification.provenance.v1.Digests.digests:type_name -> verification.provenance.v1.Digests.DigestsEntry + 4, // 5: verification.provenance.v1.Digests.DigestsEntry.value:type_name -> verification.provenance.v1.StringAllowList + 6, // [6:6] is the sub-list for method output_type + 6, // [6:6] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name } func init() { file_proto_provenance_verification_proto_init() } @@ -366,7 +447,7 @@ func file_proto_provenance_verification_proto_init() { } } file_proto_provenance_verification_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ProvenanceReferenceValues); i { + switch v := v.(*SkipVerification); i { case 0: return &v.state case 1: @@ -378,7 +459,7 @@ func file_proto_provenance_verification_proto_init() { } } file_proto_provenance_verification_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Digests); i { + switch v := v.(*ProvenanceReferenceValues); i { case 0: return &v.state case 1: @@ -390,6 +471,18 @@ func file_proto_provenance_verification_proto_init() { } } file_proto_provenance_verification_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Digests); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_provenance_verification_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*StringAllowList); i { case 0: return &v.state @@ -402,15 +495,18 @@ func file_proto_provenance_verification_proto_init() { } } } - file_proto_provenance_verification_proto_msgTypes[0].OneofWrappers = []interface{}{} - file_proto_provenance_verification_proto_msgTypes[1].OneofWrappers = []interface{}{} + file_proto_provenance_verification_proto_msgTypes[0].OneofWrappers = []interface{}{ + (*VerificationOptions_SkipProvenanceVerification)(nil), + (*VerificationOptions_ReferenceProvenance)(nil), + } + file_proto_provenance_verification_proto_msgTypes[2].OneofWrappers = []interface{}{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proto_provenance_verification_proto_rawDesc, NumEnums: 0, - NumMessages: 5, + NumMessages: 6, NumExtensions: 0, NumServices: 0, }, diff --git a/proto/provenance_verification.proto b/proto/provenance_verification.proto index a2af2e32..3cea150b 100644 --- a/proto/provenance_verification.proto +++ b/proto/provenance_verification.proto @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package main contains a command-line tool for verifying SLSA provenances. - syntax = "proto3"; package verification.provenance.v1; @@ -21,10 +19,16 @@ package verification.provenance.v1; option go_package = "proto/verification"; message VerificationOptions { - // The absence of a reference provenance indicates that provenance verification can be skipped. - optional ProvenanceReferenceValues reference_provenance = 1; + oneof option { + SkipVerification skip_provenance_verification = 1; + ProvenanceReferenceValues reference_provenance = 2; + } } +// A singleton value to indicate that verification can be skipped. +message SkipVerification{} + +// A collection of reference values for verifying provenance statements. message ProvenanceReferenceValues { bool must_have_build_command = 1; optional Digests reference_builder_image_digests = 3; @@ -32,14 +36,15 @@ message ProvenanceReferenceValues { optional StringAllowList reference_builders = 5; } -// Represents an allow listed map of digests. +// An allow list of digests, represented as a mapping from cryptographic hash +// function names, to their allow listed values. message Digests { // Keys are cryptographic hash algorithms (e.g., sha256). // Values are acceptable digests. map digests = 1; } -// Represents an allow list of values. +// An allow list of string values. message StringAllowList { repeated string values = 1; } diff --git a/testdata/different_reference_values.textproto b/testdata/different_reference_values.textproto index 2ee225ad..ad9d20d2 100644 --- a/testdata/different_reference_values.textproto +++ b/testdata/different_reference_values.textproto @@ -1,5 +1,4 @@ reference_provenance: { - must_have_build_command: true reference_builder_image_digests: { digests: { key: "sha256" From 726084f78f7c5215fcf479409f2f8b90a41c921b Mon Sep 17 00:00:00 2001 From: Razieh Behjati Date: Fri, 14 Jul 2023 09:16:10 +0100 Subject: [PATCH 07/13] Add missing test file, and disable nosnakecase lint errors --- golangci-linters.yaml | 4 ++-- testdata/skip_verification.textproto | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 testdata/skip_verification.textproto diff --git a/golangci-linters.yaml b/golangci-linters.yaml index c92adba8..d7f6021a 100644 --- a/golangci-linters.yaml +++ b/golangci-linters.yaml @@ -65,7 +65,7 @@ linters: - noctx - nolintlint - nonamedreturns - - nosnakecase + # - nosnakecase - nosprintfhostport # Might be nice to enable it later. # - paralleltest @@ -160,7 +160,7 @@ linters: # - noctx # - nolintlint # - nonamedreturns - # - nosnakecase + - nosnakecase # - nosprintfhostport - paralleltest # - prealloc diff --git a/testdata/skip_verification.textproto b/testdata/skip_verification.textproto new file mode 100644 index 00000000..713746e8 --- /dev/null +++ b/testdata/skip_verification.textproto @@ -0,0 +1 @@ +skip_provenance_verification{} \ No newline at end of file From d3f2a6e158e2d1da64242643b77b44c0ee4f65a4 Mon Sep 17 00:00:00 2001 From: Razieh Behjati Date: Fri, 14 Jul 2023 09:18:00 +0100 Subject: [PATCH 08/13] Remove superficial optionals from proto definition --- .../provenance_verification.pb.go | 69 +++++++++---------- proto/provenance_verification.proto | 4 +- 2 files changed, 34 insertions(+), 39 deletions(-) diff --git a/pkg/proto/verification/provenance_verification.pb.go b/pkg/proto/verification/provenance_verification.pb.go index 8ef17f8c..08589966 100644 --- a/pkg/proto/verification/provenance_verification.pb.go +++ b/pkg/proto/verification/provenance_verification.pb.go @@ -161,9 +161,9 @@ type ProvenanceReferenceValues struct { unknownFields protoimpl.UnknownFields MustHaveBuildCommand bool `protobuf:"varint,1,opt,name=must_have_build_command,json=mustHaveBuildCommand,proto3" json:"must_have_build_command,omitempty"` - ReferenceBuilderImageDigests *Digests `protobuf:"bytes,3,opt,name=reference_builder_image_digests,json=referenceBuilderImageDigests,proto3,oneof" json:"reference_builder_image_digests,omitempty"` + ReferenceBuilderImageDigests *Digests `protobuf:"bytes,3,opt,name=reference_builder_image_digests,json=referenceBuilderImageDigests,proto3" json:"reference_builder_image_digests,omitempty"` ReferenceRepoUri string `protobuf:"bytes,4,opt,name=reference_repo_uri,json=referenceRepoUri,proto3" json:"reference_repo_uri,omitempty"` - ReferenceBuilders *StringAllowList `protobuf:"bytes,5,opt,name=reference_builders,json=referenceBuilders,proto3,oneof" json:"reference_builders,omitempty"` + ReferenceBuilders *StringAllowList `protobuf:"bytes,5,opt,name=reference_builders,json=referenceBuilders,proto3" json:"reference_builders,omitempty"` } func (x *ProvenanceReferenceValues) Reset() { @@ -349,48 +349,44 @@ var file_proto_provenance_verification_proto_rawDesc = []byte{ 0x48, 0x00, 0x52, 0x13, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x12, 0x0a, 0x10, 0x53, 0x6b, 0x69, 0x70, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x8d, 0x03, 0x0a, 0x19, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x6e, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xc8, 0x02, 0x0a, 0x19, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x35, 0x0a, 0x17, 0x6d, 0x75, 0x73, 0x74, 0x5f, 0x68, 0x61, 0x76, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x6d, 0x75, 0x73, 0x74, 0x48, 0x61, 0x76, 0x65, 0x42, 0x75, - 0x69, 0x6c, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x6f, 0x0a, 0x1f, 0x72, 0x65, + 0x69, 0x6c, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x6a, 0x0a, 0x1f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x48, 0x00, 0x52, 0x1c, 0x72, 0x65, 0x66, 0x65, - 0x72, 0x65, 0x6e, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x49, 0x6d, 0x61, 0x67, - 0x65, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x88, 0x01, 0x01, 0x12, 0x2c, 0x0a, 0x12, 0x72, - 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x5f, 0x75, 0x72, - 0x69, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, - 0x63, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x55, 0x72, 0x69, 0x12, 0x5f, 0x0a, 0x12, 0x72, 0x65, 0x66, - 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x4c, 0x69, - 0x73, 0x74, 0x48, 0x01, 0x52, 0x11, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x42, - 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x88, 0x01, 0x01, 0x42, 0x22, 0x0a, 0x20, 0x5f, 0x72, - 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, - 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x42, 0x15, - 0x0a, 0x13, 0x5f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, - 0x6c, 0x64, 0x65, 0x72, 0x73, 0x22, 0xbe, 0x01, 0x0a, 0x07, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, - 0x73, 0x12, 0x4a, 0x0a, 0x07, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x1a, 0x67, 0x0a, - 0x0c, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, - 0x41, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, - 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x72, 0x69, - 0x6e, 0x67, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x29, 0x0a, 0x0f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, - 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x73, 0x42, 0x14, 0x5a, 0x12, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x65, 0x72, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x2e, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x52, 0x1c, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, + 0x6e, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x44, + 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, + 0x6e, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x10, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x70, + 0x6f, 0x55, 0x72, 0x69, 0x12, 0x5a, 0x0a, 0x12, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, + 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2b, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x11, 0x72, + 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x73, + 0x22, 0xbe, 0x01, 0x0a, 0x07, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x12, 0x4a, 0x0a, 0x07, + 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, + 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x67, 0x65, 0x73, + 0x74, 0x73, 0x2e, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x07, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x1a, 0x67, 0x0a, 0x0c, 0x44, 0x69, 0x67, 0x65, + 0x73, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x41, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x65, 0x72, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, + 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x41, 0x6c, 0x6c, + 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x22, 0x29, 0x0a, 0x0f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x41, 0x6c, 0x6c, 0x6f, 0x77, + 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x42, 0x14, 0x5a, 0x12, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -499,7 +495,6 @@ func file_proto_provenance_verification_proto_init() { (*VerificationOptions_SkipProvenanceVerification)(nil), (*VerificationOptions_ReferenceProvenance)(nil), } - file_proto_provenance_verification_proto_msgTypes[2].OneofWrappers = []interface{}{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ diff --git a/proto/provenance_verification.proto b/proto/provenance_verification.proto index 3cea150b..298a4ad5 100644 --- a/proto/provenance_verification.proto +++ b/proto/provenance_verification.proto @@ -31,9 +31,9 @@ message SkipVerification{} // A collection of reference values for verifying provenance statements. message ProvenanceReferenceValues { bool must_have_build_command = 1; - optional Digests reference_builder_image_digests = 3; + Digests reference_builder_image_digests = 3; string reference_repo_uri = 4; - optional StringAllowList reference_builders = 5; + StringAllowList reference_builders = 5; } // An allow list of digests, represented as a mapping from cryptographic hash From fc1288f1b674a4fbc0dd18208a5ae3589ed9a697 Mon Sep 17 00:00:00 2001 From: Razieh Behjati Date: Mon, 17 Jul 2023 12:09:47 +0100 Subject: [PATCH 09/13] Add more tests --- internal/endorser/endorser.go | 9 ++- internal/endorser/endorser_test.go | 110 ++++++++++++++++++++++++++++ proto/provenance_verification.proto | 3 +- 3 files changed, 118 insertions(+), 4 deletions(-) diff --git a/internal/endorser/endorser.go b/internal/endorser/endorser.go index 1d9cb5dd..8059c955 100644 --- a/internal/endorser/endorser.go +++ b/internal/endorser/endorser.go @@ -48,10 +48,13 @@ type ParsedProvenance struct { // and the given validity duration, using the given provenances as evidence and // VerificationOptions to verify them. If more than one provenance statements // are provided the endorsement statement is generated only if the provenance -// statements are consistent and valid according to the input -// VerificationOptions. If no provenances are provided, a provenance-less +// statements are consistent. If VerificationOptions contains a +// ReferenceProvenance, the input provenances must as well be valid according +// to the reference values provided in it to pass the verification. If the +// verification is passed, the input provenances are included as evidence in +// the generated endorsement. If no provenances are provided, a provenance-less // endorsement is generated, if the input VerificationOptions does not contain -// a reference provenance. +// a ReferenceProvenance. func GenerateEndorsement(binaryName, binaryDigest string, verOpt *prover.VerificationOptions, validityDuration claims.ClaimValidity, provenances []ParsedProvenance) (*intoto.Statement, error) { if (verOpt.GetSkipProvenanceVerification() == nil) && (verOpt.GetReferenceProvenance() == nil) { return nil, fmt.Errorf("invalid VerificationOptions: exactly one of SkipProvenanceVerification and ReferenceProvenance must be set") diff --git a/internal/endorser/endorser_test.go b/internal/endorser/endorser_test.go index da52de50..68ed2547 100644 --- a/internal/endorser/endorser_test.go +++ b/internal/endorser/endorser_test.go @@ -116,6 +116,116 @@ func TestGenerateEndorsement_NoProvenance(t *testing.T) { testutil.AssertEq(t, "notAfter date", predicate.Validity.NotAfter, &nextWeek) } +func TestGenerateEndorsement_SingleProvenance_SkipVerification(t *testing.T) { + verOpts := &prover.VerificationOptions{ + // Skip verification against reference values. + Option: &prover.VerificationOptions_SkipProvenanceVerification{ + SkipProvenanceVerification: &prover.SkipVerification{}, + }, + } + tomorrow := time.Now().AddDate(0, 0, 1) + nextWeek := time.Now().AddDate(0, 0, 7) + validity := claims.ClaimValidity{ + NotBefore: &tomorrow, + NotAfter: &nextWeek, + } + + tempPath, err := copyToTemp("../../testdata/slsa_v02_provenance.json") + if err != nil { + t.Fatalf("Could not load provenance: %v", err) + } + tempURI := "file://" + tempPath + provenances, err := LoadProvenances([]string{tempURI}) + if err != nil { + t.Fatalf("Could not load provenances: %v", err) + } + + statement, err := GenerateEndorsement(binaryName, binaryHash, verOpts, validity, provenances) + if err != nil { + t.Fatalf("Could not generate provenance-less endorsement: %v", err) + } + + testutil.AssertEq(t, "binary hash", statement.Subject[0].Digest["sha256"], binaryHash) + testutil.AssertEq(t, "binary name", statement.Subject[0].Name, binaryName) + + predicate := statement.Predicate.(claims.ClaimPredicate) + + testutil.AssertEq(t, "notBefore date", predicate.Validity.NotBefore, &tomorrow) + testutil.AssertEq(t, "notAfter date", predicate.Validity.NotAfter, &nextWeek) + testutil.AssertEq(t, "evidence length", len(predicate.Evidence), 1) +} + +func TestGenerateEndorsement_SingleInvalidProvenance_SkipVerification(t *testing.T) { + verOpts := &prover.VerificationOptions{ + // Skip verification against reference values. + Option: &prover.VerificationOptions_SkipProvenanceVerification{ + SkipProvenanceVerification: &prover.SkipVerification{}, + }, + } + tomorrow := time.Now().AddDate(0, 0, 1) + nextWeek := time.Now().AddDate(0, 0, 7) + validity := claims.ClaimValidity{ + NotBefore: &tomorrow, + NotAfter: &nextWeek, + } + + tempPath, err := copyToTemp("../../testdata/slsa_v02_provenance.json") + if err != nil { + t.Fatalf("Could not load provenance: %v", err) + } + tempURI := "file://" + tempPath + provenances, err := LoadProvenances([]string{tempURI}) + if err != nil { + t.Fatalf("Could not load provenances: %v", err) + } + + _, err = GenerateEndorsement(binaryName+"_diff", binaryHash, verOpts, validity, provenances) + if err == nil || !strings.Contains(err.Error(), "does not match the given binary name") { + t.Fatalf("got %q, want error message containing %q,", err, "does not match the given binary name") + } +} + +func TestLoadAndVerifyProvenances_MultipleValidProvenances_SkipVerification(t *testing.T) { + tempPath1, err := copyToTemp("../../testdata/slsa_v02_provenance.json") + if err != nil { + t.Fatalf("Could not load provenance: %v", err) + } + tempPath2, err := copyToTemp("../../testdata/slsa_v02_provenance.json") + if err != nil { + t.Fatalf("Could not load provenance: %v", err) + } + provenances, err := LoadProvenances([]string{"file://" + tempPath1, "file://" + tempPath2}) + if err != nil { + t.Fatalf("Could not load provenances: %v", err) + } + tomorrow := time.Now().AddDate(0, 0, 1) + nextWeek := time.Now().AddDate(0, 0, 7) + validity := claims.ClaimValidity{ + NotBefore: &tomorrow, + NotAfter: &nextWeek, + } + + verOpts := &prover.VerificationOptions{ + // Skip verification. + Option: &prover.VerificationOptions_SkipProvenanceVerification{ + SkipProvenanceVerification: &prover.SkipVerification{}, + }, + } + statement, err := GenerateEndorsement(binaryName, binaryHash, verOpts, validity, provenances) + if err != nil { + t.Fatalf("Could not generate provenance-less endorsement: %v", err) + } + + testutil.AssertEq(t, "binary hash", statement.Subject[0].Digest["sha256"], binaryHash) + testutil.AssertEq(t, "binary name", statement.Subject[0].Name, binaryName) + + predicate := statement.Predicate.(claims.ClaimPredicate) + + testutil.AssertEq(t, "notBefore date", predicate.Validity.NotBefore, &tomorrow) + testutil.AssertEq(t, "notAfter date", predicate.Validity.NotAfter, &nextWeek) + testutil.AssertEq(t, "evidence length", len(predicate.Evidence), 2) +} + func TestGenerateEndorsement_InvalidVerificationOptions(t *testing.T) { tomorrow := time.Now().AddDate(0, 0, 1) nextWeek := time.Now().AddDate(0, 0, 7) diff --git a/proto/provenance_verification.proto b/proto/provenance_verification.proto index 298a4ad5..19adecb5 100644 --- a/proto/provenance_verification.proto +++ b/proto/provenance_verification.proto @@ -20,12 +20,13 @@ option go_package = "proto/verification"; message VerificationOptions { oneof option { + // If this is set, and no provenances are provided, the verification does not result in any errors. SkipVerification skip_provenance_verification = 1; ProvenanceReferenceValues reference_provenance = 2; } } -// A singleton value to indicate that verification can be skipped. +// A singleton value to indicate that verification against reference values can be skipped. message SkipVerification{} // A collection of reference values for verifying provenance statements. From 95f0cc39d43d5ccf0a1e5f929262dbbb41aa170b Mon Sep 17 00:00:00 2001 From: Razieh Behjati Date: Mon, 17 Jul 2023 12:25:40 +0100 Subject: [PATCH 10/13] Fixes after review --- internal/endorser/endorser_test.go | 36 ++++++++++++++-------------- testdata/skip_verification.textproto | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/internal/endorser/endorser_test.go b/internal/endorser/endorser_test.go index 68ed2547..2ba0a10b 100644 --- a/internal/endorser/endorser_test.go +++ b/internal/endorser/endorser_test.go @@ -28,7 +28,7 @@ import ( ) const ( - binaryHash = "d059c38cea82047ad316a1c6c6fbd13ecf7a0abdcc375463920bd25bf5c142cc" + binaryDigestSha256 = "d059c38cea82047ad316a1c6c6fbd13ecf7a0abdcc375463920bd25bf5c142cc" binaryName = "oak_functions_freestanding_bin" errorBinaryDigest = "does not match the given binary digest" errorInconsistentProvenances = "provenances are not consistent" @@ -57,12 +57,12 @@ func TestGenerateEndorsement_SingleValidProvenance(t *testing.T) { t.Fatalf("Could not load verification options: %v", err) } - statement, err := GenerateEndorsement(binaryName, binaryHash, verOpt, validity, provenances) + statement, err := GenerateEndorsement(binaryName, binaryDigestSha256, verOpt, validity, provenances) if err != nil { t.Fatalf("Could not generate endorsement from %q: %v", provenances[0].SourceMetadata.URI, err) } - testutil.AssertEq(t, "binary hash", statement.Subject[0].Digest["sha256"], binaryHash) + testutil.AssertEq(t, "binary hash", statement.Subject[0].Digest["sha256"], binaryDigestSha256) testutil.AssertEq(t, "binary name", statement.Subject[0].Name, binaryName) predicate := statement.Predicate.(claims.ClaimPredicate) @@ -84,12 +84,12 @@ func TestGenerateEndorsement_NoProvenance(t *testing.T) { NotBefore: &tomorrow, NotAfter: &nextWeek, } - statement, err := GenerateEndorsement(binaryName, binaryHash, verOpts, validity, []ParsedProvenance{}) + statement, err := GenerateEndorsement(binaryName, binaryDigestSha256, verOpts, validity, []ParsedProvenance{}) if err != nil { t.Fatalf("Could not generate provenance-less endorsement: %v", err) } - testutil.AssertEq(t, "binary hash", statement.Subject[0].Digest["sha256"], binaryHash) + testutil.AssertEq(t, "binary hash", statement.Subject[0].Digest["sha256"], binaryDigestSha256) testutil.AssertEq(t, "binary name", statement.Subject[0].Name, binaryName) predicate := statement.Predicate.(claims.ClaimPredicate) @@ -102,12 +102,12 @@ func TestGenerateEndorsement_NoProvenance(t *testing.T) { if err != nil { t.Fatalf("Could not load verification options: %v", err) } - statement, err = GenerateEndorsement(binaryName, binaryHash, verOpts, validity, []ParsedProvenance{}) + statement, err = GenerateEndorsement(binaryName, binaryDigestSha256, verOpts, validity, []ParsedProvenance{}) if err != nil { t.Fatalf("Could not generate provenance-less endorsement: %v", err) } - testutil.AssertEq(t, "binary hash", statement.Subject[0].Digest["sha256"], binaryHash) + testutil.AssertEq(t, "binary hash", statement.Subject[0].Digest["sha256"], binaryDigestSha256) testutil.AssertEq(t, "binary name", statement.Subject[0].Name, binaryName) predicate = statement.Predicate.(claims.ClaimPredicate) @@ -140,12 +140,12 @@ func TestGenerateEndorsement_SingleProvenance_SkipVerification(t *testing.T) { t.Fatalf("Could not load provenances: %v", err) } - statement, err := GenerateEndorsement(binaryName, binaryHash, verOpts, validity, provenances) + statement, err := GenerateEndorsement(binaryName, binaryDigestSha256, verOpts, validity, provenances) if err != nil { t.Fatalf("Could not generate provenance-less endorsement: %v", err) } - testutil.AssertEq(t, "binary hash", statement.Subject[0].Digest["sha256"], binaryHash) + testutil.AssertEq(t, "binary hash", statement.Subject[0].Digest["sha256"], binaryDigestSha256) testutil.AssertEq(t, "binary name", statement.Subject[0].Name, binaryName) predicate := statement.Predicate.(claims.ClaimPredicate) @@ -179,7 +179,7 @@ func TestGenerateEndorsement_SingleInvalidProvenance_SkipVerification(t *testing t.Fatalf("Could not load provenances: %v", err) } - _, err = GenerateEndorsement(binaryName+"_diff", binaryHash, verOpts, validity, provenances) + _, err = GenerateEndorsement(binaryName+"_diff", binaryDigestSha256, verOpts, validity, provenances) if err == nil || !strings.Contains(err.Error(), "does not match the given binary name") { t.Fatalf("got %q, want error message containing %q,", err, "does not match the given binary name") } @@ -211,12 +211,12 @@ func TestLoadAndVerifyProvenances_MultipleValidProvenances_SkipVerification(t *t SkipProvenanceVerification: &prover.SkipVerification{}, }, } - statement, err := GenerateEndorsement(binaryName, binaryHash, verOpts, validity, provenances) + statement, err := GenerateEndorsement(binaryName, binaryDigestSha256, verOpts, validity, provenances) if err != nil { t.Fatalf("Could not generate provenance-less endorsement: %v", err) } - testutil.AssertEq(t, "binary hash", statement.Subject[0].Digest["sha256"], binaryHash) + testutil.AssertEq(t, "binary hash", statement.Subject[0].Digest["sha256"], binaryDigestSha256) testutil.AssertEq(t, "binary name", statement.Subject[0].Name, binaryName) predicate := statement.Predicate.(claims.ClaimPredicate) @@ -235,7 +235,7 @@ func TestGenerateEndorsement_InvalidVerificationOptions(t *testing.T) { } verOpts := &prover.VerificationOptions{} - _, err := GenerateEndorsement(binaryName, binaryHash, verOpts, validity, []ParsedProvenance{}) + _, err := GenerateEndorsement(binaryName, binaryDigestSha256, verOpts, validity, []ParsedProvenance{}) if err == nil || !strings.Contains(err.Error(), "invalid VerificationOptions") { t.Fatalf("got %q, want error message containing %q,", err, "invalid VerificationOptions:") } @@ -260,13 +260,13 @@ func TestLoadAndVerifyProvenances_MultipleValidProvenances(t *testing.T) { ReferenceProvenance: &prover.ProvenanceReferenceValues{}, }, } - provenanceSet, err := verifyAndSummarizeProvenances(binaryName, binaryHash, verOpts, provenances) + provenanceSet, err := verifyAndSummarizeProvenances(binaryName, binaryDigestSha256, verOpts, provenances) if err != nil { t.Fatalf("Could not generate endorsement from %q: %v", provenances[0].SourceMetadata.URI, err) } testutil.AssertEq(t, "binary name", provenanceSet.BinaryName, binaryName) - testutil.AssertEq(t, "binary hash", provenanceSet.BinaryDigest, binaryHash) + testutil.AssertEq(t, "binary hash", provenanceSet.BinaryDigest, binaryDigestSha256) } func TestLoadProvenances_FailingSingleRemoteProvenanceEndorsement(t *testing.T) { @@ -294,7 +294,7 @@ func TestLoadAndVerifyProvenances_ConsistentNotVerified(t *testing.T) { } // Provenances do not contain the given reference binary SHA256 digest value, but are consistent. - _, err = verifyAndSummarizeProvenances(binaryName, binaryHash+"_diff", verOpts, provenances) + _, err = verifyAndSummarizeProvenances(binaryName, binaryDigestSha256+"_diff", verOpts, provenances) if err == nil || !strings.Contains(err.Error(), errorBinaryDigest) { t.Fatalf("got %q, want error message containing %q,", err, errorBinaryDigest) } @@ -322,7 +322,7 @@ func TestLoadAndVerify_InconsistentVerified(t *testing.T) { } // Provenances each contain a (different) given reference binary SHA256 digest value, but are inconsistent. - _, err = verifyAndSummarizeProvenances(binaryName, binaryHash, &verOpt, provenances) + _, err = verifyAndSummarizeProvenances(binaryName, binaryDigestSha256, &verOpt, provenances) if err == nil || !strings.Contains(err.Error(), errorInconsistentProvenances) { t.Fatalf("got %q, want error message containing %q,", err, errorInconsistentProvenances) } @@ -349,7 +349,7 @@ func TestLoadAndVerify_InconsistentNotVerified(t *testing.T) { }, } - _, err = verifyAndSummarizeProvenances(binaryName, binaryHash+"_diff", verOpt, provenances) + _, err = verifyAndSummarizeProvenances(binaryName, binaryDigestSha256+"_diff", verOpt, provenances) if err == nil || !strings.Contains(err.Error(), errorBinaryDigest) { t.Fatalf("got %q, want error message containing %q,", err, errorBinaryDigest) } diff --git a/testdata/skip_verification.textproto b/testdata/skip_verification.textproto index 713746e8..958c870e 100644 --- a/testdata/skip_verification.textproto +++ b/testdata/skip_verification.textproto @@ -1 +1 @@ -skip_provenance_verification{} \ No newline at end of file +skip_provenance_verification{} From 31a9063f5334990545396c9c25cb1c15947ca7b7 Mon Sep 17 00:00:00 2001 From: Razieh Behjati Date: Mon, 17 Jul 2023 13:31:00 +0100 Subject: [PATCH 11/13] Rename package internal/verification to internal/verifier --- cmd/verifier/main.go | 4 ++-- internal/endorser/endorser.go | 4 ++-- internal/{verification => verifier}/verifier.go | 2 +- internal/{verification => verifier}/verifier_test.go | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) rename internal/{verification => verifier}/verifier.go (99%) rename internal/{verification => verifier}/verifier_test.go (99%) diff --git a/cmd/verifier/main.go b/cmd/verifier/main.go index 8323736d..7febd355 100644 --- a/cmd/verifier/main.go +++ b/cmd/verifier/main.go @@ -21,7 +21,7 @@ import ( "os" "github.com/project-oak/transparent-release/internal/model" - "github.com/project-oak/transparent-release/internal/verification" + "github.com/project-oak/transparent-release/internal/verifier" prover "github.com/project-oak/transparent-release/pkg/proto/verification" ) @@ -45,7 +45,7 @@ func main() { log.Fatalf("couldn't map from %s to internal representation: %v", validatedProvenance, err) } - provenanceVerifier := verification.ProvenanceIRVerifier{ + provenanceVerifier := verifier.ProvenanceIRVerifier{ Got: provenanceIR, Want: &prover.ProvenanceReferenceValues{}, } diff --git a/internal/endorser/endorser.go b/internal/endorser/endorser.go index 8059c955..c2526205 100644 --- a/internal/endorser/endorser.go +++ b/internal/endorser/endorser.go @@ -29,7 +29,7 @@ import ( "go.uber.org/multierr" "github.com/project-oak/transparent-release/internal/model" - "github.com/project-oak/transparent-release/internal/verification" + "github.com/project-oak/transparent-release/internal/verifier" "github.com/project-oak/transparent-release/pkg/claims" "github.com/project-oak/transparent-release/pkg/intoto" prover "github.com/project-oak/transparent-release/pkg/proto/verification" @@ -117,7 +117,7 @@ func verifyAndSummarizeProvenances(binaryName, binaryDigest string, verOpt *prov func verifyProvenances(referenceValues *prover.ProvenanceReferenceValues, provenances []model.ProvenanceIR) error { var errs error for index := range provenances { - provenanceVerifier := verification.ProvenanceIRVerifier{ + provenanceVerifier := verifier.ProvenanceIRVerifier{ Got: &provenances[index], Want: referenceValues, } diff --git a/internal/verification/verifier.go b/internal/verifier/verifier.go similarity index 99% rename from internal/verification/verifier.go rename to internal/verifier/verifier.go index 9b3ce33d..65e88630 100644 --- a/internal/verification/verifier.go +++ b/internal/verifier/verifier.go @@ -13,7 +13,7 @@ // limitations under the License. // Package verification provides a function for verifying a SLSA provenance file. -package verification +package verifier import ( "fmt" diff --git a/internal/verification/verifier_test.go b/internal/verifier/verifier_test.go similarity index 99% rename from internal/verification/verifier_test.go rename to internal/verifier/verifier_test.go index 9c68256c..6ecb7f14 100644 --- a/internal/verification/verifier_test.go +++ b/internal/verifier/verifier_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package verification +package verifier import ( "fmt" From 51029365a1ecf80cf557bc065bb46656d4320bca Mon Sep 17 00:00:00 2001 From: Razieh Behjati Date: Mon, 17 Jul 2023 17:32:56 +0100 Subject: [PATCH 12/13] Rename SkipVerification to EndorseProvenanceLess --- internal/endorser/endorser.go | 14 +- internal/endorser/endorser_test.go | 229 +++++------------- internal/verifier/verifier.go | 1 - .../provenance_verification.pb.go | 80 +++--- proto/provenance_verification.proto | 11 +- testdata/different_reference_values.textproto | 1 - testdata/skip_verification.textproto | 2 +- 7 files changed, 125 insertions(+), 213 deletions(-) diff --git a/internal/endorser/endorser.go b/internal/endorser/endorser.go index c2526205..e8f6d0cc 100644 --- a/internal/endorser/endorser.go +++ b/internal/endorser/endorser.go @@ -56,8 +56,8 @@ type ParsedProvenance struct { // endorsement is generated, if the input VerificationOptions does not contain // a ReferenceProvenance. func GenerateEndorsement(binaryName, binaryDigest string, verOpt *prover.VerificationOptions, validityDuration claims.ClaimValidity, provenances []ParsedProvenance) (*intoto.Statement, error) { - if (verOpt.GetSkipProvenanceVerification() == nil) && (verOpt.GetReferenceProvenance() == nil) { - return nil, fmt.Errorf("invalid VerificationOptions: exactly one of SkipProvenanceVerification and ReferenceProvenance must be set") + if (verOpt.GetEndorseProvenanceLess() == nil) && (verOpt.GetReferenceProvenance() == nil) { + return nil, fmt.Errorf("invalid VerificationOptions: exactly one of EndorseProvenanceLess and ReferenceProvenance must be set") } verifiedProvenances, err := verifyAndSummarizeProvenances(binaryName, binaryDigest, verOpt, provenances) if err != nil { @@ -75,7 +75,7 @@ func GenerateEndorsement(binaryName, binaryDigest string, verOpt *prover.Verific // (2) Any of the provenances is invalid (see verifyProvenances for details), // (3) Provenances do not match (e.g., have different binary names). func verifyAndSummarizeProvenances(binaryName, binaryDigest string, verOpt *prover.VerificationOptions, provenances []ParsedProvenance) (*claims.VerifiedProvenanceSet, error) { - if len(provenances) == 0 && verOpt.GetSkipProvenanceVerification() == nil { + if len(provenances) == 0 && verOpt.GetEndorseProvenanceLess() == nil { return nil, fmt.Errorf("at least one provenance file must be provided") } @@ -113,9 +113,15 @@ func verifyAndSummarizeProvenances(binaryName, binaryDigest string, verOpt *prov return &verifiedProvenances, nil } -// verifyProvenances verifies the given list of provenances. An error is returned if verification fails for one of them. +// verifyProvenances verifies the given list of provenances against the given +// ProvenanceReferenceValues. An error is returned if verification fails for +// one of them. No verification is performed if the provided +// ProvenanceReferenceValues is nil. func verifyProvenances(referenceValues *prover.ProvenanceReferenceValues, provenances []model.ProvenanceIR) error { var errs error + if referenceValues == nil { + return nil + } for index := range provenances { provenanceVerifier := verifier.ProvenanceIRVerifier{ Got: &provenances[index], diff --git a/internal/endorser/endorser_test.go b/internal/endorser/endorser_test.go index 2ba0a10b..6c7e9bc9 100644 --- a/internal/endorser/endorser_test.go +++ b/internal/endorser/endorser_test.go @@ -34,23 +34,34 @@ const ( errorInconsistentProvenances = "provenances are not consistent" ) -func TestGenerateEndorsement_SingleValidProvenance(t *testing.T) { +func createClaimValidity(days int) claims.ClaimValidity { tomorrow := time.Now().AddDate(0, 0, 1) - nextWeek := time.Now().AddDate(0, 0, 7) - validity := claims.ClaimValidity{ + nextWeek := time.Now().AddDate(0, 0, days) + return claims.ClaimValidity{ NotBefore: &tomorrow, NotAfter: &nextWeek, } +} - tempPath, err := copyToTemp("../../testdata/slsa_v02_provenance.json") - if err != nil { - t.Fatalf("Could not load provenance: %v", err) +func createProvenanceList(t *testing.T, paths []string) []ParsedProvenance { + tempURIs := make([]string, 0, len(paths)) + for _, p := range paths { + tempPath, err := copyToTemp(p) + if err != nil { + t.Fatalf("Could not load provenance: %v", err) + } + tempURIs = append(tempURIs, "file://"+tempPath) } - tempURI := "file://" + tempPath - provenances, err := LoadProvenances([]string{tempURI}) + provenances, err := LoadProvenances(tempURIs) if err != nil { t.Fatalf("Could not load provenances: %v", err) } + return provenances +} + +func TestGenerateEndorsement_SingleValidProvenance(t *testing.T) { + provenances := createProvenanceList(t, []string{"../../testdata/slsa_v02_provenance.json"}) + validity := createClaimValidity(7) verOpt, err := loadTextprotoVerificationOptions("../../testdata/reference_values.textproto") if err != nil { @@ -67,24 +78,18 @@ func TestGenerateEndorsement_SingleValidProvenance(t *testing.T) { predicate := statement.Predicate.(claims.ClaimPredicate) - testutil.AssertEq(t, "notBefore date", predicate.Validity.NotBefore, &tomorrow) - testutil.AssertEq(t, "notAfter date", predicate.Validity.NotAfter, &nextWeek) + testutil.AssertEq(t, "notBefore date", predicate.Validity.NotBefore, validity.NotBefore) + testutil.AssertEq(t, "notAfter date", predicate.Validity.NotAfter, validity.NotAfter) } -func TestGenerateEndorsement_NoProvenance(t *testing.T) { +func TestGenerateEndorsement_NoProvenance_EndorseProvenanceLess(t *testing.T) { verOpts := &prover.VerificationOptions{ // Skip verification to allow provenance-less endorsement generation. - Option: &prover.VerificationOptions_SkipProvenanceVerification{ - SkipProvenanceVerification: &prover.SkipVerification{}, + Option: &prover.VerificationOptions_EndorseProvenanceLess{ + EndorseProvenanceLess: &prover.EndorseProvenanceLess{}, }, } - tomorrow := time.Now().AddDate(0, 0, 1) - nextWeek := time.Now().AddDate(0, 0, 7) - validity := claims.ClaimValidity{ - NotBefore: &tomorrow, - NotAfter: &nextWeek, - } - statement, err := GenerateEndorsement(binaryName, binaryDigestSha256, verOpts, validity, []ParsedProvenance{}) + statement, err := GenerateEndorsement(binaryName, binaryDigestSha256, verOpts, createClaimValidity(7), []ParsedProvenance{}) if err != nil { t.Fatalf("Could not generate provenance-less endorsement: %v", err) } @@ -92,55 +97,30 @@ func TestGenerateEndorsement_NoProvenance(t *testing.T) { testutil.AssertEq(t, "binary hash", statement.Subject[0].Digest["sha256"], binaryDigestSha256) testutil.AssertEq(t, "binary name", statement.Subject[0].Name, binaryName) - predicate := statement.Predicate.(claims.ClaimPredicate) - - testutil.AssertEq(t, "notBefore date", predicate.Validity.NotBefore, &tomorrow) - testutil.AssertEq(t, "notAfter date", predicate.Validity.NotAfter, &nextWeek) - // Repeat the same with verification options loaded from file. verOpts, err = loadTextprotoVerificationOptions("../../testdata/skip_verification.textproto") if err != nil { t.Fatalf("Could not load verification options: %v", err) } - statement, err = GenerateEndorsement(binaryName, binaryDigestSha256, verOpts, validity, []ParsedProvenance{}) + statement, err = GenerateEndorsement(binaryName, binaryDigestSha256, verOpts, createClaimValidity(7), []ParsedProvenance{}) if err != nil { t.Fatalf("Could not generate provenance-less endorsement: %v", err) } testutil.AssertEq(t, "binary hash", statement.Subject[0].Digest["sha256"], binaryDigestSha256) testutil.AssertEq(t, "binary name", statement.Subject[0].Name, binaryName) - - predicate = statement.Predicate.(claims.ClaimPredicate) - - testutil.AssertEq(t, "notBefore date", predicate.Validity.NotBefore, &tomorrow) - testutil.AssertEq(t, "notAfter date", predicate.Validity.NotAfter, &nextWeek) } -func TestGenerateEndorsement_SingleProvenance_SkipVerification(t *testing.T) { +func TestGenerateEndorsement_SingleProvenance_EndorseProvenanceLess(t *testing.T) { verOpts := &prover.VerificationOptions{ // Skip verification against reference values. - Option: &prover.VerificationOptions_SkipProvenanceVerification{ - SkipProvenanceVerification: &prover.SkipVerification{}, + Option: &prover.VerificationOptions_EndorseProvenanceLess{ + EndorseProvenanceLess: &prover.EndorseProvenanceLess{}, }, } - tomorrow := time.Now().AddDate(0, 0, 1) - nextWeek := time.Now().AddDate(0, 0, 7) - validity := claims.ClaimValidity{ - NotBefore: &tomorrow, - NotAfter: &nextWeek, - } - - tempPath, err := copyToTemp("../../testdata/slsa_v02_provenance.json") - if err != nil { - t.Fatalf("Could not load provenance: %v", err) - } - tempURI := "file://" + tempPath - provenances, err := LoadProvenances([]string{tempURI}) - if err != nil { - t.Fatalf("Could not load provenances: %v", err) - } + provenances := createProvenanceList(t, []string{"../../testdata/slsa_v02_provenance.json"}) - statement, err := GenerateEndorsement(binaryName, binaryDigestSha256, verOpts, validity, provenances) + statement, err := GenerateEndorsement(binaryName, binaryDigestSha256, verOpts, createClaimValidity(7), provenances) if err != nil { t.Fatalf("Could not generate provenance-less endorsement: %v", err) } @@ -149,69 +129,33 @@ func TestGenerateEndorsement_SingleProvenance_SkipVerification(t *testing.T) { testutil.AssertEq(t, "binary name", statement.Subject[0].Name, binaryName) predicate := statement.Predicate.(claims.ClaimPredicate) - - testutil.AssertEq(t, "notBefore date", predicate.Validity.NotBefore, &tomorrow) - testutil.AssertEq(t, "notAfter date", predicate.Validity.NotAfter, &nextWeek) testutil.AssertEq(t, "evidence length", len(predicate.Evidence), 1) } -func TestGenerateEndorsement_SingleInvalidProvenance_SkipVerification(t *testing.T) { +func TestGenerateEndorsement_SingleInvalidProvenance_EndorseProvenanceLess(t *testing.T) { verOpts := &prover.VerificationOptions{ // Skip verification against reference values. - Option: &prover.VerificationOptions_SkipProvenanceVerification{ - SkipProvenanceVerification: &prover.SkipVerification{}, + Option: &prover.VerificationOptions_EndorseProvenanceLess{ + EndorseProvenanceLess: &prover.EndorseProvenanceLess{}, }, } - tomorrow := time.Now().AddDate(0, 0, 1) - nextWeek := time.Now().AddDate(0, 0, 7) - validity := claims.ClaimValidity{ - NotBefore: &tomorrow, - NotAfter: &nextWeek, - } - tempPath, err := copyToTemp("../../testdata/slsa_v02_provenance.json") - if err != nil { - t.Fatalf("Could not load provenance: %v", err) - } - tempURI := "file://" + tempPath - provenances, err := LoadProvenances([]string{tempURI}) - if err != nil { - t.Fatalf("Could not load provenances: %v", err) - } + provenances := createProvenanceList(t, []string{"../../testdata/slsa_v02_provenance.json"}) - _, err = GenerateEndorsement(binaryName+"_diff", binaryDigestSha256, verOpts, validity, provenances) + _, err := GenerateEndorsement(binaryName+"_diff", binaryDigestSha256, verOpts, createClaimValidity(7), provenances) if err == nil || !strings.Contains(err.Error(), "does not match the given binary name") { t.Fatalf("got %q, want error message containing %q,", err, "does not match the given binary name") } } -func TestLoadAndVerifyProvenances_MultipleValidProvenances_SkipVerification(t *testing.T) { - tempPath1, err := copyToTemp("../../testdata/slsa_v02_provenance.json") - if err != nil { - t.Fatalf("Could not load provenance: %v", err) - } - tempPath2, err := copyToTemp("../../testdata/slsa_v02_provenance.json") - if err != nil { - t.Fatalf("Could not load provenance: %v", err) - } - provenances, err := LoadProvenances([]string{"file://" + tempPath1, "file://" + tempPath2}) - if err != nil { - t.Fatalf("Could not load provenances: %v", err) - } - tomorrow := time.Now().AddDate(0, 0, 1) - nextWeek := time.Now().AddDate(0, 0, 7) - validity := claims.ClaimValidity{ - NotBefore: &tomorrow, - NotAfter: &nextWeek, - } - +func TestLoadAndVerifyProvenances_MultipleValidProvenances_EndorseProvenanceLess(t *testing.T) { + provenances := createProvenanceList(t, []string{"../../testdata/slsa_v02_provenance.json", "../../testdata/slsa_v02_provenance.json"}) verOpts := &prover.VerificationOptions{ - // Skip verification. - Option: &prover.VerificationOptions_SkipProvenanceVerification{ - SkipProvenanceVerification: &prover.SkipVerification{}, + Option: &prover.VerificationOptions_EndorseProvenanceLess{ + EndorseProvenanceLess: &prover.EndorseProvenanceLess{}, }, } - statement, err := GenerateEndorsement(binaryName, binaryDigestSha256, verOpts, validity, provenances) + statement, err := GenerateEndorsement(binaryName, binaryDigestSha256, verOpts, createClaimValidity(7), provenances) if err != nil { t.Fatalf("Could not generate provenance-less endorsement: %v", err) } @@ -220,40 +164,35 @@ func TestLoadAndVerifyProvenances_MultipleValidProvenances_SkipVerification(t *t testutil.AssertEq(t, "binary name", statement.Subject[0].Name, binaryName) predicate := statement.Predicate.(claims.ClaimPredicate) - - testutil.AssertEq(t, "notBefore date", predicate.Validity.NotBefore, &tomorrow) - testutil.AssertEq(t, "notAfter date", predicate.Validity.NotAfter, &nextWeek) testutil.AssertEq(t, "evidence length", len(predicate.Evidence), 2) } -func TestGenerateEndorsement_InvalidVerificationOptions(t *testing.T) { - tomorrow := time.Now().AddDate(0, 0, 1) - nextWeek := time.Now().AddDate(0, 0, 7) - validity := claims.ClaimValidity{ - NotBefore: &tomorrow, - NotAfter: &nextWeek, +func TestLoadAndVerify_MultipleInconsistentProvenances_EndorseProvenanceLess(t *testing.T) { + provenances := createProvenanceList(t, []string{"../../testdata/slsa_v02_provenance.json", "../../testdata/different_slsa_v02_provenance.json"}) + + verOpts := &prover.VerificationOptions{ + Option: &prover.VerificationOptions_EndorseProvenanceLess{ + EndorseProvenanceLess: &prover.EndorseProvenanceLess{}, + }, + } + + // Provenances each contain a (different) given reference binary SHA256 digest value, but are inconsistent. + _, err := GenerateEndorsement(binaryName, binaryDigestSha256, verOpts, createClaimValidity(3), provenances) + if err == nil || !strings.Contains(err.Error(), errorInconsistentProvenances) { + t.Fatalf("got %q, want error message containing %q,", err, errorInconsistentProvenances) } +} +func TestGenerateEndorsement_InvalidVerificationOptions(t *testing.T) { verOpts := &prover.VerificationOptions{} - _, err := GenerateEndorsement(binaryName, binaryDigestSha256, verOpts, validity, []ParsedProvenance{}) + _, err := GenerateEndorsement(binaryName, binaryDigestSha256, verOpts, createClaimValidity(7), []ParsedProvenance{}) if err == nil || !strings.Contains(err.Error(), "invalid VerificationOptions") { t.Fatalf("got %q, want error message containing %q,", err, "invalid VerificationOptions:") } } func TestLoadAndVerifyProvenances_MultipleValidProvenances(t *testing.T) { - tempPath1, err := copyToTemp("../../testdata/slsa_v02_provenance.json") - if err != nil { - t.Fatalf("Could not load provenance: %v", err) - } - tempPath2, err := copyToTemp("../../testdata/slsa_v02_provenance.json") - if err != nil { - t.Fatalf("Could not load provenance: %v", err) - } - provenances, err := LoadProvenances([]string{"file://" + tempPath1, "file://" + tempPath2}) - if err != nil { - t.Fatalf("Could not load provenances: %v", err) - } + provenances := createProvenanceList(t, []string{"../../testdata/slsa_v02_provenance.json", "../../testdata/slsa_v02_provenance.json"}) verOpts := &prover.VerificationOptions{ Option: &prover.VerificationOptions_ReferenceProvenance{ @@ -278,15 +217,8 @@ func TestLoadProvenances_FailingSingleRemoteProvenanceEndorsement(t *testing.T) } func TestLoadAndVerifyProvenances_ConsistentNotVerified(t *testing.T) { - tempPath1, err := copyToTemp("../../testdata/slsa_v02_provenance.json") - if err != nil { - t.Fatalf("Could not load provenance: %v", err) - } + provenances := createProvenanceList(t, []string{"../../testdata/slsa_v02_provenance.json", "../../testdata/slsa_v02_provenance.json"}) - provenances, err := LoadProvenances([]string{"file://" + tempPath1, "file://" + tempPath1}) - if err != nil { - t.Fatalf("Could not load provenances: %v", err) - } verOpts := &prover.VerificationOptions{ Option: &prover.VerificationOptions_ReferenceProvenance{ ReferenceProvenance: &prover.ProvenanceReferenceValues{}, @@ -294,27 +226,15 @@ func TestLoadAndVerifyProvenances_ConsistentNotVerified(t *testing.T) { } // Provenances do not contain the given reference binary SHA256 digest value, but are consistent. - _, err = verifyAndSummarizeProvenances(binaryName, binaryDigestSha256+"_diff", verOpts, provenances) + _, err := verifyAndSummarizeProvenances(binaryName, binaryDigestSha256+"_diff", verOpts, provenances) if err == nil || !strings.Contains(err.Error(), errorBinaryDigest) { t.Fatalf("got %q, want error message containing %q,", err, errorBinaryDigest) } } func TestLoadAndVerify_InconsistentVerified(t *testing.T) { - tempPath1, err := copyToTemp("../../testdata/slsa_v02_provenance.json") - if err != nil { - t.Fatalf("Could not load provenance: %v", err) - } - - tempPath2, err := copyToTemp("../../testdata/different_slsa_v02_provenance.json") - if err != nil { - t.Fatalf("Could not load provenance: %v", err) - } + provenances := createProvenanceList(t, []string{"../../testdata/slsa_v02_provenance.json", "../../testdata/different_slsa_v02_provenance.json"}) - provenances, err := LoadProvenances([]string{"file://" + tempPath1, "file://" + tempPath2}) - if err != nil { - t.Fatalf("Could not load provenances: %v", err) - } verOpt := prover.VerificationOptions{ Option: &prover.VerificationOptions_ReferenceProvenance{ ReferenceProvenance: &prover.ProvenanceReferenceValues{}, @@ -322,34 +242,22 @@ func TestLoadAndVerify_InconsistentVerified(t *testing.T) { } // Provenances each contain a (different) given reference binary SHA256 digest value, but are inconsistent. - _, err = verifyAndSummarizeProvenances(binaryName, binaryDigestSha256, &verOpt, provenances) + _, err := verifyAndSummarizeProvenances(binaryName, binaryDigestSha256, &verOpt, provenances) if err == nil || !strings.Contains(err.Error(), errorInconsistentProvenances) { t.Fatalf("got %q, want error message containing %q,", err, errorInconsistentProvenances) } } func TestLoadAndVerify_InconsistentNotVerified(t *testing.T) { - tempPath1, err := copyToTemp("../../testdata/slsa_v02_provenance.json") - if err != nil { - t.Fatalf("Could not load provenance: %v", err) - } + provenances := createProvenanceList(t, []string{"../../testdata/slsa_v02_provenance.json", "../../testdata/different_slsa_v02_provenance.json"}) - tempPath2, err := copyToTemp("../../testdata/different_slsa_v02_provenance.json") - if err != nil { - t.Fatalf("Could not load provenance: %v", err) - } - - provenances, err := LoadProvenances([]string{"file://" + tempPath1, "file://" + tempPath2}) - if err != nil { - t.Fatalf("Could not load provenances: %v", err) - } verOpt := &prover.VerificationOptions{ Option: &prover.VerificationOptions_ReferenceProvenance{ ReferenceProvenance: &prover.ProvenanceReferenceValues{}, }, } - _, err = verifyAndSummarizeProvenances(binaryName, binaryDigestSha256+"_diff", verOpt, provenances) + _, err := verifyAndSummarizeProvenances(binaryName, binaryDigestSha256+"_diff", verOpt, provenances) if err == nil || !strings.Contains(err.Error(), errorBinaryDigest) { t.Fatalf("got %q, want error message containing %q,", err, errorBinaryDigest) } @@ -360,15 +268,8 @@ func TestLoadAndVerify_InconsistentNotVerified(t *testing.T) { } func TestLoadAndVerifyProvenances_NotVerified(t *testing.T) { - tempPath1, err := copyToTemp("../../testdata/slsa_v02_provenance.json") - if err != nil { - t.Fatalf("Could not load provenance: %v", err) - } + provenances := createProvenanceList(t, []string{"../../testdata/slsa_v02_provenance.json"}) - provenances, err := LoadProvenances([]string{"file://" + tempPath1}) - if err != nil { - t.Fatalf("Could not load provenances: %v", err) - } verOpts, err := loadTextprotoVerificationOptions("../../testdata/different_reference_values.textproto") if err != nil { t.Fatalf("Could not load verification options: %v", err) diff --git a/internal/verifier/verifier.go b/internal/verifier/verifier.go index 65e88630..6857ca2f 100644 --- a/internal/verifier/verifier.go +++ b/internal/verifier/verifier.go @@ -34,7 +34,6 @@ type ProvenanceIRVerifier struct { // Verify checks fields, which (i) are set in Got, i.e., GotHasX is true, and (ii) are set in Want. func (v *ProvenanceIRVerifier) Verify() error { var errs error - // Verify HasBuildCmd. multierr.AppendInto(&errs, v.verifyBuildCmd()) diff --git a/pkg/proto/verification/provenance_verification.pb.go b/pkg/proto/verification/provenance_verification.pb.go index 08589966..6c5df13d 100644 --- a/pkg/proto/verification/provenance_verification.pb.go +++ b/pkg/proto/verification/provenance_verification.pb.go @@ -34,6 +34,7 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// Options for verifying provenances when generating an endorsement statement. type VerificationOptions struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -41,7 +42,7 @@ type VerificationOptions struct { // Types that are assignable to Option: // - // *VerificationOptions_SkipProvenanceVerification + // *VerificationOptions_EndorseProvenanceLess // *VerificationOptions_ReferenceProvenance Option isVerificationOptions_Option `protobuf_oneof:"option"` } @@ -85,9 +86,9 @@ func (m *VerificationOptions) GetOption() isVerificationOptions_Option { return nil } -func (x *VerificationOptions) GetSkipProvenanceVerification() *SkipVerification { - if x, ok := x.GetOption().(*VerificationOptions_SkipProvenanceVerification); ok { - return x.SkipProvenanceVerification +func (x *VerificationOptions) GetEndorseProvenanceLess() *EndorseProvenanceLess { + if x, ok := x.GetOption().(*VerificationOptions_EndorseProvenanceLess); ok { + return x.EndorseProvenanceLess } return nil } @@ -103,27 +104,30 @@ type isVerificationOptions_Option interface { isVerificationOptions_Option() } -type VerificationOptions_SkipProvenanceVerification struct { - SkipProvenanceVerification *SkipVerification `protobuf:"bytes,1,opt,name=skip_provenance_verification,json=skipProvenanceVerification,proto3,oneof"` +type VerificationOptions_EndorseProvenanceLess struct { + // Allows generating endorsements without any provenances as evidence. + // If one or more provenances are provided, the presence of this value + // is the same as having an empty reference provenance. + EndorseProvenanceLess *EndorseProvenanceLess `protobuf:"bytes,1,opt,name=endorse_provenance_less,json=endorseProvenanceLess,proto3,oneof"` } type VerificationOptions_ReferenceProvenance struct { ReferenceProvenance *ProvenanceReferenceValues `protobuf:"bytes,2,opt,name=reference_provenance,json=referenceProvenance,proto3,oneof"` } -func (*VerificationOptions_SkipProvenanceVerification) isVerificationOptions_Option() {} +func (*VerificationOptions_EndorseProvenanceLess) isVerificationOptions_Option() {} func (*VerificationOptions_ReferenceProvenance) isVerificationOptions_Option() {} -// A singleton value to indicate that verification can be skipped. -type SkipVerification struct { +// A singleton value to allow provenance-less endorsement generation. +type EndorseProvenanceLess struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields } -func (x *SkipVerification) Reset() { - *x = SkipVerification{} +func (x *EndorseProvenanceLess) Reset() { + *x = EndorseProvenanceLess{} if protoimpl.UnsafeEnabled { mi := &file_proto_provenance_verification_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -131,13 +135,13 @@ func (x *SkipVerification) Reset() { } } -func (x *SkipVerification) String() string { +func (x *EndorseProvenanceLess) String() string { return protoimpl.X.MessageStringOf(x) } -func (*SkipVerification) ProtoMessage() {} +func (*EndorseProvenanceLess) ProtoMessage() {} -func (x *SkipVerification) ProtoReflect() protoreflect.Message { +func (x *EndorseProvenanceLess) ProtoReflect() protoreflect.Message { mi := &file_proto_provenance_verification_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -149,8 +153,8 @@ func (x *SkipVerification) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use SkipVerification.ProtoReflect.Descriptor instead. -func (*SkipVerification) Descriptor() ([]byte, []int) { +// Deprecated: Use EndorseProvenanceLess.ProtoReflect.Descriptor instead. +func (*EndorseProvenanceLess) Descriptor() ([]byte, []int) { return file_proto_provenance_verification_proto_rawDescGZIP(), []int{1} } @@ -332,24 +336,24 @@ var file_proto_provenance_verification_proto_rawDesc = []byte{ 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1a, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, - 0x31, 0x22, 0xfd, 0x01, 0x0a, 0x13, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x70, 0x0a, 0x1c, 0x73, 0x6b, 0x69, - 0x70, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2c, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, - 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x6b, 0x69, - 0x70, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, - 0x1a, 0x73, 0x6b, 0x69, 0x70, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x56, - 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x6a, 0x0a, 0x14, 0x72, - 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, - 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x76, 0x65, 0x72, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, - 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, - 0x65, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, - 0x48, 0x00, 0x52, 0x13, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x50, 0x72, 0x6f, - 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x6f, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x22, 0x12, 0x0a, 0x10, 0x53, 0x6b, 0x69, 0x70, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xc8, 0x02, 0x0a, 0x19, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x6e, + 0x31, 0x22, 0xf8, 0x01, 0x0a, 0x13, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x6b, 0x0a, 0x17, 0x65, 0x6e, 0x64, + 0x6f, 0x72, 0x73, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x5f, + 0x6c, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x76, 0x65, 0x72, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, + 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x64, 0x6f, 0x72, 0x73, 0x65, 0x50, + 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x4c, 0x65, 0x73, 0x73, 0x48, 0x00, 0x52, + 0x15, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x73, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, + 0x63, 0x65, 0x4c, 0x65, 0x73, 0x73, 0x12, 0x6a, 0x0a, 0x14, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, + 0x6e, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x66, 0x65, + 0x72, 0x65, 0x6e, 0x63, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x48, 0x00, 0x52, 0x13, 0x72, + 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, + 0x63, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x17, 0x0a, 0x15, + 0x45, 0x6e, 0x64, 0x6f, 0x72, 0x73, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, + 0x65, 0x4c, 0x65, 0x73, 0x73, 0x22, 0xc8, 0x02, 0x0a, 0x19, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x35, 0x0a, 0x17, 0x6d, 0x75, 0x73, 0x74, 0x5f, 0x68, 0x61, 0x76, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x01, @@ -404,14 +408,14 @@ func file_proto_provenance_verification_proto_rawDescGZIP() []byte { var file_proto_provenance_verification_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_proto_provenance_verification_proto_goTypes = []interface{}{ (*VerificationOptions)(nil), // 0: verification.provenance.v1.VerificationOptions - (*SkipVerification)(nil), // 1: verification.provenance.v1.SkipVerification + (*EndorseProvenanceLess)(nil), // 1: verification.provenance.v1.EndorseProvenanceLess (*ProvenanceReferenceValues)(nil), // 2: verification.provenance.v1.ProvenanceReferenceValues (*Digests)(nil), // 3: verification.provenance.v1.Digests (*StringAllowList)(nil), // 4: verification.provenance.v1.StringAllowList nil, // 5: verification.provenance.v1.Digests.DigestsEntry } var file_proto_provenance_verification_proto_depIdxs = []int32{ - 1, // 0: verification.provenance.v1.VerificationOptions.skip_provenance_verification:type_name -> verification.provenance.v1.SkipVerification + 1, // 0: verification.provenance.v1.VerificationOptions.endorse_provenance_less:type_name -> verification.provenance.v1.EndorseProvenanceLess 2, // 1: verification.provenance.v1.VerificationOptions.reference_provenance:type_name -> verification.provenance.v1.ProvenanceReferenceValues 3, // 2: verification.provenance.v1.ProvenanceReferenceValues.reference_builder_image_digests:type_name -> verification.provenance.v1.Digests 4, // 3: verification.provenance.v1.ProvenanceReferenceValues.reference_builders:type_name -> verification.provenance.v1.StringAllowList @@ -443,7 +447,7 @@ func file_proto_provenance_verification_proto_init() { } } file_proto_provenance_verification_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SkipVerification); i { + switch v := v.(*EndorseProvenanceLess); i { case 0: return &v.state case 1: @@ -492,7 +496,7 @@ func file_proto_provenance_verification_proto_init() { } } file_proto_provenance_verification_proto_msgTypes[0].OneofWrappers = []interface{}{ - (*VerificationOptions_SkipProvenanceVerification)(nil), + (*VerificationOptions_EndorseProvenanceLess)(nil), (*VerificationOptions_ReferenceProvenance)(nil), } type x struct{} diff --git a/proto/provenance_verification.proto b/proto/provenance_verification.proto index 19adecb5..9aee362b 100644 --- a/proto/provenance_verification.proto +++ b/proto/provenance_verification.proto @@ -18,16 +18,19 @@ package verification.provenance.v1; option go_package = "proto/verification"; +// Options for verifying provenances when generating an endorsement statement. message VerificationOptions { oneof option { - // If this is set, and no provenances are provided, the verification does not result in any errors. - SkipVerification skip_provenance_verification = 1; + // Allows generating endorsements without any provenances as evidence. + // If one or more provenances are provided, the presence of this value + // is the same as having an empty reference provenance. + EndorseProvenanceLess endorse_provenance_less = 1; ProvenanceReferenceValues reference_provenance = 2; } } -// A singleton value to indicate that verification against reference values can be skipped. -message SkipVerification{} +// A singleton value to allow provenance-less endorsement generation. +message EndorseProvenanceLess{} // A collection of reference values for verifying provenance statements. message ProvenanceReferenceValues { diff --git a/testdata/different_reference_values.textproto b/testdata/different_reference_values.textproto index ad9d20d2..f83ccb01 100644 --- a/testdata/different_reference_values.textproto +++ b/testdata/different_reference_values.textproto @@ -7,4 +7,3 @@ reference_provenance: { } reference_repo_uri: "some_different_repo" } - \ No newline at end of file diff --git a/testdata/skip_verification.textproto b/testdata/skip_verification.textproto index 958c870e..a9d21bc6 100644 --- a/testdata/skip_verification.textproto +++ b/testdata/skip_verification.textproto @@ -1 +1 @@ -skip_provenance_verification{} +endorse_provenance_less{} From 38ce6547e5fe3c09576fe34a9c2bc4571e1ec380 Mon Sep 17 00:00:00 2001 From: Razieh Behjati Date: Mon, 17 Jul 2023 18:53:04 +0100 Subject: [PATCH 13/13] cleanup --- internal/endorser/endorser.go | 22 ++++++------ internal/endorser/endorser_test.go | 54 ++++++++++++++---------------- internal/verifier/verifier.go | 5 ++- 3 files changed, 40 insertions(+), 41 deletions(-) diff --git a/internal/endorser/endorser.go b/internal/endorser/endorser.go index e8f6d0cc..855ed0c9 100644 --- a/internal/endorser/endorser.go +++ b/internal/endorser/endorser.go @@ -46,15 +46,16 @@ type ParsedProvenance struct { // GenerateEndorsement generates an endorsement statement for the given binary // and the given validity duration, using the given provenances as evidence and -// VerificationOptions to verify them. If more than one provenance statements -// are provided the endorsement statement is generated only if the provenance -// statements are consistent. If VerificationOptions contains a -// ReferenceProvenance, the input provenances must as well be valid according -// to the reference values provided in it to pass the verification. If the -// verification is passed, the input provenances are included as evidence in -// the generated endorsement. If no provenances are provided, a provenance-less -// endorsement is generated, if the input VerificationOptions does not contain -// a ReferenceProvenance. +// VerificationOptions to verify them. If one or more provenance statements +// are provided, an endorsement statement is generated only if the +// provenance(s) are valid with respect to the ReferenceProvenance in +// VerificationOptions, if it contains one. If more than one provenance are +// provided, they are in addition checked to be consistent (i.e., that they have +// the same subject). If these conditions hold, the input provenances are +// included as evidence in the generated endorsement. If no provenances are +// provided, a provenance-less endorsement is generated, only if the input +// VerificationOptions has the EndorseProvenanceLess field set. An error is +// returned in all other cases. func GenerateEndorsement(binaryName, binaryDigest string, verOpt *prover.VerificationOptions, validityDuration claims.ClaimValidity, provenances []ParsedProvenance) (*intoto.Statement, error) { if (verOpt.GetEndorseProvenanceLess() == nil) && (verOpt.GetReferenceProvenance() == nil) { return nil, fmt.Errorf("invalid VerificationOptions: exactly one of EndorseProvenanceLess and ReferenceProvenance must be set") @@ -71,9 +72,10 @@ func GenerateEndorsement(binaryName, binaryDigest string, verOpt *prover.Verific // about a set of verified provenances, or an error. An error is returned if // any of the following conditions is met: // (1) The list of provenances is empty, but VerificationOptions does not have -// its SkipProvenanceVerification field set. +// its EndorseProvenanceLess field set. // (2) Any of the provenances is invalid (see verifyProvenances for details), // (3) Provenances do not match (e.g., have different binary names). +// (4) Provenances match but don't match the input binary name or digest. func verifyAndSummarizeProvenances(binaryName, binaryDigest string, verOpt *prover.VerificationOptions, provenances []ParsedProvenance) (*claims.VerifiedProvenanceSet, error) { if len(provenances) == 0 && verOpt.GetEndorseProvenanceLess() == nil { return nil, fmt.Errorf("at least one provenance file must be provided") diff --git a/internal/endorser/endorser_test.go b/internal/endorser/endorser_test.go index 6c7e9bc9..7956c718 100644 --- a/internal/endorser/endorser_test.go +++ b/internal/endorser/endorser_test.go @@ -59,32 +59,17 @@ func createProvenanceList(t *testing.T, paths []string) []ParsedProvenance { return provenances } -func TestGenerateEndorsement_SingleValidProvenance(t *testing.T) { - provenances := createProvenanceList(t, []string{"../../testdata/slsa_v02_provenance.json"}) - validity := createClaimValidity(7) - - verOpt, err := loadTextprotoVerificationOptions("../../testdata/reference_values.textproto") - if err != nil { - t.Fatalf("Could not load verification options: %v", err) - } - - statement, err := GenerateEndorsement(binaryName, binaryDigestSha256, verOpt, validity, provenances) - if err != nil { - t.Fatalf("Could not generate endorsement from %q: %v", provenances[0].SourceMetadata.URI, err) +func TestGenerateEndorsement_InvalidVerificationOptions(t *testing.T) { + verOpts := &prover.VerificationOptions{} + _, err := GenerateEndorsement(binaryName, binaryDigestSha256, verOpts, createClaimValidity(7), []ParsedProvenance{}) + if err == nil || !strings.Contains(err.Error(), "invalid VerificationOptions") { + t.Fatalf("got %q, want error message containing %q,", err, "invalid VerificationOptions:") } - - testutil.AssertEq(t, "binary hash", statement.Subject[0].Digest["sha256"], binaryDigestSha256) - testutil.AssertEq(t, "binary name", statement.Subject[0].Name, binaryName) - - predicate := statement.Predicate.(claims.ClaimPredicate) - - testutil.AssertEq(t, "notBefore date", predicate.Validity.NotBefore, validity.NotBefore) - testutil.AssertEq(t, "notAfter date", predicate.Validity.NotAfter, validity.NotAfter) } func TestGenerateEndorsement_NoProvenance_EndorseProvenanceLess(t *testing.T) { verOpts := &prover.VerificationOptions{ - // Skip verification to allow provenance-less endorsement generation. + // Allow provenance-less endorsement generation. Option: &prover.VerificationOptions_EndorseProvenanceLess{ EndorseProvenanceLess: &prover.EndorseProvenanceLess{}, }, @@ -113,7 +98,6 @@ func TestGenerateEndorsement_NoProvenance_EndorseProvenanceLess(t *testing.T) { func TestGenerateEndorsement_SingleProvenance_EndorseProvenanceLess(t *testing.T) { verOpts := &prover.VerificationOptions{ - // Skip verification against reference values. Option: &prover.VerificationOptions_EndorseProvenanceLess{ EndorseProvenanceLess: &prover.EndorseProvenanceLess{}, }, @@ -134,7 +118,6 @@ func TestGenerateEndorsement_SingleProvenance_EndorseProvenanceLess(t *testing.T func TestGenerateEndorsement_SingleInvalidProvenance_EndorseProvenanceLess(t *testing.T) { verOpts := &prover.VerificationOptions{ - // Skip verification against reference values. Option: &prover.VerificationOptions_EndorseProvenanceLess{ EndorseProvenanceLess: &prover.EndorseProvenanceLess{}, }, @@ -183,12 +166,27 @@ func TestLoadAndVerify_MultipleInconsistentProvenances_EndorseProvenanceLess(t * } } -func TestGenerateEndorsement_InvalidVerificationOptions(t *testing.T) { - verOpts := &prover.VerificationOptions{} - _, err := GenerateEndorsement(binaryName, binaryDigestSha256, verOpts, createClaimValidity(7), []ParsedProvenance{}) - if err == nil || !strings.Contains(err.Error(), "invalid VerificationOptions") { - t.Fatalf("got %q, want error message containing %q,", err, "invalid VerificationOptions:") +func TestGenerateEndorsement_SingleValidProvenance(t *testing.T) { + provenances := createProvenanceList(t, []string{"../../testdata/slsa_v02_provenance.json"}) + validity := createClaimValidity(7) + + verOpt, err := loadTextprotoVerificationOptions("../../testdata/reference_values.textproto") + if err != nil { + t.Fatalf("Could not load verification options: %v", err) } + + statement, err := GenerateEndorsement(binaryName, binaryDigestSha256, verOpt, validity, provenances) + if err != nil { + t.Fatalf("Could not generate endorsement from %q: %v", provenances[0].SourceMetadata.URI, err) + } + + testutil.AssertEq(t, "binary hash", statement.Subject[0].Digest["sha256"], binaryDigestSha256) + testutil.AssertEq(t, "binary name", statement.Subject[0].Name, binaryName) + + predicate := statement.Predicate.(claims.ClaimPredicate) + + testutil.AssertEq(t, "notBefore date", predicate.Validity.NotBefore, validity.NotBefore) + testutil.AssertEq(t, "notAfter date", predicate.Validity.NotAfter, validity.NotAfter) } func TestLoadAndVerifyProvenances_MultipleValidProvenances(t *testing.T) { diff --git a/internal/verifier/verifier.go b/internal/verifier/verifier.go index 6857ca2f..bd986c86 100644 --- a/internal/verifier/verifier.go +++ b/internal/verifier/verifier.go @@ -56,8 +56,7 @@ func (v *ProvenanceIRVerifier) Verify() error { // verifyBuildCmd verifies the build cmd. Returns an error if a build command is // needed in the Want reference values, but is not present in the Got provenance. func (v *ProvenanceIRVerifier) verifyBuildCmd() error { - mustHaveBuildCommand := v.Want.GetMustHaveBuildCommand() - if mustHaveBuildCommand && v.Got.HasBuildCmd() { + if v.Want.GetMustHaveBuildCommand() && v.Got.HasBuildCmd() { if buildCmd, err := v.Got.BuildCmd(); err != nil || len(buildCmd) == 0 { return fmt.Errorf("no build cmd found") } @@ -81,7 +80,7 @@ func (v *ProvenanceIRVerifier) verifyBuilderImageDigest() error { } if err := verifySHA256Digest(gotBuilderImageDigest, referenceDigests); err != nil { - return fmt.Errorf("verifying builder image SHA356 digest: %v", err) + return fmt.Errorf("verifying builder image SHA256 digest: %v", err) } return nil }