-
Notifications
You must be signed in to change notification settings - Fork 9
Allow provenance-less endorsement generation #237
Changes from all commits
446f030
8865be5
303fa54
5e0eb9b
62c6d0e
a1fcaa7
726084f
d3f2a6e
fc1288f
95f0cc3
31a9063
5102936
38ce654
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -65,7 +65,7 @@ linters: | |
- noctx | ||
- nolintlint | ||
- nonamedreturns | ||
- nosnakecase | ||
# - nosnakecase | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
@@ -160,7 +160,7 @@ linters: | |
# - noctx | ||
# - nolintlint | ||
# - nonamedreturns | ||
# - nosnakecase | ||
- nosnakecase | ||
# - nosprintfhostport | ||
- paralleltest | ||
# - prealloc | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,9 +29,10 @@ 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" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Renamed the other |
||
) | ||
|
||
// ParsedProvenance contains a provenance in the internal ProvenanceIR format, | ||
|
@@ -43,26 +44,40 @@ 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 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") | ||
} | ||
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 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). | ||
func verifyAndSummarizeProvenances(referenceValues *verification.ReferenceValues, provenances []ParsedProvenance) (*claims.VerifiedProvenanceSet, error) { | ||
if len(provenances) == 0 { | ||
// (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") | ||
} | ||
|
||
|
@@ -73,25 +88,44 @@ 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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 IIUC the control flow lands here, but then On a higher level: What do we expect to happen then? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, sounds good! Just to double check: In the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch. Yes. |
||
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 { | ||
// 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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe add a comment what happens if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
var errs error | ||
if referenceValues == nil { | ||
return nil | ||
} | ||
for index := range provenances { | ||
provenanceVerifier := verification.ProvenanceIRVerifier{ | ||
provenanceVerifier := verifier.ProvenanceIRVerifier{ | ||
Got: &provenances[index], | ||
Want: referenceValues, | ||
} | ||
|
There was a problem hiding this comment.
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.There was a problem hiding this comment.
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.