mirror of
https://github.com/slsa-framework/slsa-verifier.git
synced 2026-05-13 20:16:41 +00:00
feat: add an option to print provenance (#87)
* add an option to print provenance Signed-off-by: Asra Ali <asraa@google.com> fix Signed-off-by: Asra Ali <asraa@google.com> * print provenaace Signed-off-by: Asra Ali <asraa@google.com>
This commit is contained in:
24
README.md
24
README.md
@@ -61,6 +61,8 @@ $ go run . --help
|
||||
path to an artifact to verify
|
||||
-branch string
|
||||
expected branch the binary was compiled from (default "main")
|
||||
-print-provenance
|
||||
output the verified provenance
|
||||
-provenance string
|
||||
path to a provenance file
|
||||
-source string
|
||||
@@ -74,22 +76,20 @@ $ go run . --help
|
||||
### Example
|
||||
|
||||
```bash
|
||||
$ go run . --artifact-path ~/Downloads/binary-linux-amd64 --provenance ~/Downloads/binary-linux-amd64.intoto.jsonl --source github.com/origin/repo
|
||||
|
||||
Verified against tlog entry 1544571
|
||||
verified SLSA provenance produced at
|
||||
$ go run . -artifact-path ~/Downloads/slsa-verifier-linux-amd64 -provenance ~/Downloads/slsa-verifier-linux-amd64.intoto.jsonl -source github.com/slsa-framework/slsa-verifier -tag v1.0.0
|
||||
Verified signature against tlog entry index 2592016 at URL: https://rekor.sigstore.dev/api/v1/log/entries/d77621eaf1de74592546f773192f49ed995e8b12f2e5eeed02057ae32b24aa95
|
||||
Signing certificate information:
|
||||
{
|
||||
"caller": "origin/repo",
|
||||
"commit": "0dfcd24824432c4ce587f79c918eef8fc2c44d7b",
|
||||
"job_workflow_ref": "/slsa-framework/slsa-github-generator/blob/main/.github/workflows/builder_go_slsa3.yml",
|
||||
"trigger": "workflow_dispatch",
|
||||
"issuer": "https://token.actions.githubusercontent.com"
|
||||
"caller": "slsa-framework/slsa-verifier",
|
||||
"commit": "c1b6db643d6134285dc929206fdcfa3712a877eb",
|
||||
"job_workflow_ref": "/slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@refs/tags/v0.0.1",
|
||||
"trigger": "push",
|
||||
"issuer": "https://token.actions.githubusercontent.com"
|
||||
}
|
||||
{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://slsa.dev/provenance/v0.2","subject":[{"name":"binary-linux-amd64","digest":{"sha256":"723ccb85318bc8b1a9dd29340612ce1268cd3418d70f68e775edbdc16d1d9158"}}],"predicate":{...}}
|
||||
successfully verified SLSA provenance
|
||||
PASSED: Verified SLSA provenance
|
||||
```
|
||||
|
||||
The verified in-toto statement is written to stdout and can be used to pipe into policy engines.
|
||||
The verified in-toto statement may be written to stdout with the `--print-provenance` flag to pipe into policy engines.
|
||||
|
||||
## Technical design
|
||||
|
||||
|
||||
62
main.go
62
main.go
@@ -17,12 +17,13 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
provenancePath string
|
||||
artifactPath string
|
||||
source string
|
||||
branch string
|
||||
tag string
|
||||
versiontag string
|
||||
provenancePath string
|
||||
artifactPath string
|
||||
source string
|
||||
branch string
|
||||
tag string
|
||||
versiontag string
|
||||
printProvenance bool
|
||||
)
|
||||
|
||||
var defaultRekorAddr = "https://rekor.sigstore.dev"
|
||||
@@ -30,68 +31,63 @@ var defaultRekorAddr = "https://rekor.sigstore.dev"
|
||||
func verify(ctx context.Context,
|
||||
provenance []byte, artifactHash, source, branch string,
|
||||
tag, versiontag *string,
|
||||
) error {
|
||||
) ([]byte, error) {
|
||||
rClient, err := rekor.NewClient(defaultRekorAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
/* Verify signature on the intoto attestation. */
|
||||
env, cert, err := pkg.VerifyProvenanceSignature(ctx, rClient, provenance, artifactHash)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
/* Verify properties of the signing identity. */
|
||||
// Get the workflow info given the certificate information.
|
||||
workflowInfo, err := pkg.GetWorkflowInfoFromCertificate(cert)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b, err := json.MarshalIndent(workflowInfo, "", "\t")
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "verified signature on SLSA provenance produced at \n %s\n", b)
|
||||
fmt.Fprintf(os.Stderr, "Signing certificate information:\n %s\n", b)
|
||||
|
||||
/* Verify properties of the SLSA provenance. */
|
||||
// Verify the workflow identity.
|
||||
if err := pkg.VerifyWorkflowIdentity(workflowInfo, source); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Unpack and verify info in the provenance, including the Subject Digest.
|
||||
if err := pkg.VerifyProvenance(env, artifactHash); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Verify the branch.
|
||||
if err := pkg.VerifyBranch(env, branch); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Verify the tag.
|
||||
if tag != nil {
|
||||
if err := pkg.VerifyTag(env, *tag); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Verify the versioned tag.
|
||||
if versiontag != nil {
|
||||
if err := pkg.VerifyVersionedTag(env, *versiontag); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Print verified provenance to stdout.
|
||||
pyld, err := base64.StdEncoding.DecodeString(env.Payload)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: %s", pkg.ErrorInvalidDssePayload, "decoding payload")
|
||||
}
|
||||
fmt.Fprintf(os.Stdout, "%s\n", string(pyld))
|
||||
return nil
|
||||
// Return verified provenance.
|
||||
return base64.StdEncoding.DecodeString(env.Payload)
|
||||
}
|
||||
|
||||
func main() {
|
||||
@@ -101,6 +97,7 @@ func main() {
|
||||
flag.StringVar(&branch, "branch", "main", "expected branch the binary was compiled from")
|
||||
flag.StringVar(&tag, "tag", "", "[optional] expected tag the binary was compiled from")
|
||||
flag.StringVar(&versiontag, "versioned-tag", "", "[optional] expected version the binary was compiled from. Uses semantic version to match the tag")
|
||||
flag.BoolVar(&printProvenance, "print-provenance", false, "print the verified provenance to std out")
|
||||
flag.Parse()
|
||||
|
||||
if provenancePath == "" || artifactPath == "" || source == "" {
|
||||
@@ -122,13 +119,18 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if err := runVerify(artifactPath, provenancePath, source, branch,
|
||||
ptag, pversiontag); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "verification failed: %v\n", err)
|
||||
verifiedProvenance, err := runVerify(artifactPath, provenancePath, source, branch,
|
||||
ptag, pversiontag)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "FAILED: SLSA verification failed: %v\n", err)
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
fmt.Fprintf(os.Stderr, "successfully verified SLSA provenance\n")
|
||||
fmt.Fprintf(os.Stderr, "PASSED: Verified SLSA provenance\n")
|
||||
|
||||
if printProvenance {
|
||||
fmt.Fprintf(os.Stdout, "%s\n", string(verifiedProvenance))
|
||||
}
|
||||
}
|
||||
|
||||
func isFlagPassed(name string) bool {
|
||||
@@ -143,7 +145,7 @@ func isFlagPassed(name string) bool {
|
||||
|
||||
func runVerify(artifactPath, provenancePath, source, branch string,
|
||||
ptag, pversiontag *string,
|
||||
) error {
|
||||
) ([]byte, error) {
|
||||
f, err := os.Open(artifactPath)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
@@ -152,7 +154,7 @@ func runVerify(artifactPath, provenancePath, source, branch string,
|
||||
|
||||
provenance, err := os.ReadFile(provenancePath)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
h := sha256.New()
|
||||
|
||||
@@ -345,7 +345,7 @@ func Test_runVerify(t *testing.T) {
|
||||
artifactPath = filepath.Clean(fmt.Sprintf("./testdata/%v/%s", v, tt.artifact))
|
||||
provenancePath = fmt.Sprintf("%s.intoto.jsonl", artifactPath)
|
||||
|
||||
err := runVerify(artifactPath,
|
||||
_, err := runVerify(artifactPath,
|
||||
provenancePath,
|
||||
tt.source, branch,
|
||||
tt.ptag, tt.pversiontag)
|
||||
|
||||
@@ -359,8 +359,15 @@ func FindSigningCertificate(ctx context.Context, uuids []string, dssePayload dss
|
||||
if err := cosign.CheckExpiry(cert, it); err != nil {
|
||||
continue
|
||||
}
|
||||
uuid, err := cosign.ComputeLeafHash(entry)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error computing leaf hash for tlog entry at index: %d\n", *entry.LogIndex)
|
||||
continue
|
||||
}
|
||||
|
||||
// success!
|
||||
fmt.Fprintf(os.Stderr, "Verified against tlog entry %d\n", *entry.LogIndex)
|
||||
url := fmt.Sprintf("%v/%v/%v", defaultRekorAddr, "api/v1/log/entries", hex.EncodeToString(uuid))
|
||||
fmt.Fprintf(os.Stderr, "Verified signature against tlog entry index %d at URL: %s\n", *entry.LogIndex, url)
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user