From a717cc551203da34bf2a58546de4b0d69f548662 Mon Sep 17 00:00:00 2001 From: asraa Date: Wed, 8 Jun 2022 15:35:59 -0500 Subject: [PATCH] feat: add an option to print provenance (#87) * add an option to print provenance Signed-off-by: Asra Ali fix Signed-off-by: Asra Ali * print provenaace Signed-off-by: Asra Ali --- README.md | 24 +++++++++--------- main.go | 62 ++++++++++++++++++++++++----------------------- main_test.go | 2 +- pkg/provenance.go | 9 ++++++- 4 files changed, 53 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 0c5a5c0..a510195 100644 --- a/README.md +++ b/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 diff --git a/main.go b/main.go index 7e24ece..239aa82 100644 --- a/main.go +++ b/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() diff --git a/main_test.go b/main_test.go index d591d73..6bef09f 100644 --- a/main_test.go +++ b/main_test.go @@ -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) diff --git a/pkg/provenance.go b/pkg/provenance.go index a0d2ea3..08c3f37 100644 --- a/pkg/provenance.go +++ b/pkg/provenance.go @@ -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 }