Skip to content
This repository has been archived by the owner on Apr 9, 2024. It is now read-only.

Allow provenance-less endorsement generation #237

Merged
merged 13 commits into from
Jul 17, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion cmd/verifier/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -46,7 +47,7 @@ func main() {

provenanceVerifier := verification.ProvenanceIRVerifier{
Got: provenanceIR,
Want: &verification.ReferenceValues{},
Want: &prover.ProvenanceReferenceValues{},
}

if err := provenanceVerifier.Verify(); err != nil {
Expand Down
24 changes: 24 additions & 0 deletions docs/development-guidelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI this is mostly solved by bazel and / or nix. Especially since the instructions here refer to latest, which will stop working at some point.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. We used to use bazel in this repo, and it caused a lot of problems. I think this is fine for now.


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
```
4 changes: 2 additions & 2 deletions golangci-linters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ linters:
- noctx
- nolintlint
- nonamedreturns
- nosnakecase
# - nosnakecase

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The template kept these as commented out. I think this is for convenience to be able to enable or disable them easily.

- nosprintfhostport
# Might be nice to enable it later.
# - paralleltest
Expand Down Expand Up @@ -160,7 +160,7 @@ linters:
# - noctx
# - nolintlint
# - nonamedreturns
# - nosnakecase
- nosnakecase
# - nosprintfhostport
- paralleltest
# - prealloc
Expand Down
55 changes: 39 additions & 16 deletions internal/endorser/endorser.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having two different packages with the same name but in different locations in the same repo seems problematic. Maybe one of them should be renamed at some point

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, but I cannot think of a better name. I don't like long names with underscore in them.
Do you have any suggestions?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed the other verification into verifier. The only files in it now are verifier.go and verifier_test.go so I think that makes sense.

)

// ParsedProvenance contains a provenance in the internal ProvenanceIR format,
Expand All @@ -43,26 +44,35 @@ 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 *verification.ReferenceValues, 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
// 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A design question: might it happen, that I accidentially endorse something if I forget to add a provenance? Do we want to make this more explict? E.g., make GenerateEndorsement private but expose two methods GenerateEndorsementWithProvenance and GenerateEndorsementWithoutProvenance?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is being handled by the VerificationOptions. It requires explicitly setting skip provenance verification. If that is not set, at least one provenance is required.

So I'd say those accidents are unlikely.

// 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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just checking: Don't you get from oneof in the proto definition that exactly one of verOpt is not nil?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. I think this is a shortcoming of Go. I was able to create an instance where both options are null, so I had to add this check.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, thanks! I'd have expected...

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)
}

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 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(referenceValues *verification.ReferenceValues, 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.GetSkipProvenanceVerification() == nil {
return nil, fmt.Errorf("at least one provenance file must be provided")
}

Expand All @@ -73,22 +83,35 @@ func verifyAndSummarizeProvenances(referenceValues *verification.ReferenceValues
provenancesData = append(provenancesData, p.SourceMetadata)
}

errs := multierr.Append(verifyConsistency(provenanceIRs), verifyProvenances(referenceValues, provenanceIRs))
var errs error
if len(provenanceIRs) > 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am trying to understand what happens if we have multiple provenances but SkipProvenanceVerification.

IIUC the control flow lands here, but then GetReferenceProvenance would be nil? Is this okay with verifyProvenances?

On a higher level: What do we expect to happen then?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We expect the provenances to be consistent, but they are not verified against a set of reference values. Added tests to cover these scenarios.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, sounds good!

Just to double check: In the GetReferenceProvenance case, verifyProvenances will get nil for GetReferenceProvenance.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Yes. verifyProvenances is called with a nil. Added a check to immediately return if the input ProvenanceReferenceValues is nil.

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))
}
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,
}

return &verifiedProvenances, nil
}

// 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.ProvenanceReferenceValues, provenances []model.ProvenanceIR) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a comment what happens if prover.ProvenanceReferenceValues == nil?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

var errs error
for index := range provenances {
provenanceVerifier := verification.ProvenanceIRVerifier{
Expand Down
149 changes: 111 additions & 38 deletions internal/endorser/endorser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,19 @@ 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"
binaryHash = "d059c38cea82047ad316a1c6c6fbd13ecf7a0abdcc375463920bd25bf5c142cc"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
binaryHash = "d059c38cea82047ad316a1c6c6fbd13ecf7a0abdcc375463920bd25bf5c142cc"
binaryDigestSha256 = "d059c38cea82047ad316a1c6c6fbd13ecf7a0abdcc375463920bd25bf5c142cc"

for consistency

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

binaryName = "oak_functions_freestanding_bin"
errorBinaryDigest = "does not match the given binary digest"
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{
Expand All @@ -50,12 +52,12 @@ func TestGenerateEndorsement_SingleValidEndorsement(t *testing.T) {
t.Fatalf("Could not load provenances: %v", err)
}

referenceValues, err := verification.LoadReferenceValuesFromFile("../../testdata/reference_values.toml")
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(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)
}
Expand All @@ -69,7 +71,67 @@ 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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if you give provenances and also set SkipProvenanceVerification?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a few tests and updated the documentation on GenerateEndorsement. It generates an endorsement with the given provenances as evidence, if the provenances are consistent and match the given subject.

Let me know if you expect some other behavior.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm... I am not sure I would expect "unverified provenances" as evidence, but actually: why not?

However, is it clear afterwards if the provenances were verified? Or does that not really matter?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are not totally unverified. But they are not verified against a set of reference values. Actually this is similar to providing verification options with an empty ReferenceProvenance. Except that the latter enforces having some provenances. Clarified this, and renamed SkipVerification to EndorseProvenanceLess to be clear that we are not skipping the entire verification logic.

However, is it clear afterwards if the provenances were verified? Or does that not really matter?

Currently we don't include the verification options in the endorsement, but I think it is a good idea to include it. As an extension. Created #238.

verOpts := &prover.VerificationOptions{
// 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)
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)

// 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) {
tempPath1, err := copyToTemp("../../testdata/slsa_v02_provenance.json")
if err != nil {
t.Fatalf("Could not load provenance: %v", err)
Expand All @@ -83,11 +145,12 @@ 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},
verOpts := &prover.VerificationOptions{
Option: &prover.VerificationOptions_ReferenceProvenance{
ReferenceProvenance: &prover.ProvenanceReferenceValues{},
},
}
provenanceSet, err := verifyAndSummarizeProvenances(&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)
}
Expand All @@ -114,12 +177,14 @@ func TestLoadAndVerifyProvenances_ConsistentNotVerified(t *testing.T) {
if err != nil {
t.Fatalf("Could not load provenances: %v", err)
}
referenceValues := verification.ReferenceValues{
BinarySHA256Digests: []string{binaryHash + "_diff"},
verOpts := &prover.VerificationOptions{
Option: &prover.VerificationOptions_ReferenceProvenance{
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)
}
Expand All @@ -140,15 +205,16 @@ func TestLoadAndVerify_InconsistentVerified(t *testing.T) {
if err != nil {
t.Fatalf("Could not load provenances: %v", err)
}
referenceValues := verification.ReferenceValues{
BinarySHA256Digests: []string{"e8e05d1d09af8952919bf6ab38e0cc5a6414ee2b5e21f4765b12421c5db0037e", binaryHash},
verOpt := prover.VerificationOptions{
Option: &prover.VerificationOptions_ReferenceProvenance{
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)
}
}

Expand All @@ -167,18 +233,19 @@ func TestLoadAndVerify_InconsistentNotVerified(t *testing.T) {
if err != nil {
t.Fatalf("Could not load provenances: %v", err)
}
referenceValues := verification.ReferenceValues{
BinarySHA256Digests: []string{binaryHash + "_diff"},
verOpt := &prover.VerificationOptions{
Option: &prover.VerificationOptions_ReferenceProvenance{
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)
}
}

Expand All @@ -192,23 +259,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")
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(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)
}
Expand All @@ -234,3 +295,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
}
Loading