From 8437e622be7fa57e029fbbf5079119fd1a6bf7d3 Mon Sep 17 00:00:00 2001 From: Canaan Silberberg Date: Fri, 1 Sep 2023 17:54:24 -0400 Subject: [PATCH 1/4] Add SLSA 1.0 attestation support to cosign Signed-off-by: Canaan Silberberg --- cmd/cosign/cli/attest/attest_blob_test.go | 254 ++++++++++++---------- cmd/cosign/cli/options/predicate.go | 9 +- doc/cosign_attest-blob.md | 2 +- doc/cosign_attest.md | 2 +- doc/cosign_verify-attestation.md | 2 +- doc/cosign_verify-blob-attestation.md | 2 +- pkg/cosign/attestation/attestation.go | 27 ++- 7 files changed, 171 insertions(+), 127 deletions(-) diff --git a/cmd/cosign/cli/attest/attest_blob_test.go b/cmd/cosign/cli/attest/attest_blob_test.go index 1f40a9e5d5d..df2df7eff01 100644 --- a/cmd/cosign/cli/attest/attest_blob_test.go +++ b/cmd/cosign/cli/attest/attest_blob_test.go @@ -71,6 +71,16 @@ func writeFile(t *testing.T, td string, blob string, name string) string { return blobPath } +func makeSLSA02PredicateFile(t *testing.T, td string) string { + predicate := `{ "buildType": "x", "builder": { "id": "2" }, "recipe": {} }` + return writeFile(t, td, predicate, "predicate02.json") +} + +func makeSLSA1PredicateFile(t *testing.T, td string) string { + predicate := `{ "buildDefinition": {}, "runDetails": {} }` + return writeFile(t, td, predicate, "predicate1.json") +} + // TestAttestBlobCmdWithCert verifies the AttestBlobCmd checks // that the cmd correctly matches the signing key with the cert // provided. @@ -99,73 +109,79 @@ func TestAttestBlobCmdLocalKeyAndCert(t *testing.T) { chainRef := writeFile(t, td, string(pemChain), "chain.pem") blob := writeFile(t, td, "foo", "foo.txt") - predicate := `{ "buildType": "x", "builder": { "id": "2" }, "recipe": {} }` - predicateType := "slsaprovenance" - predicatePath := writeFile(t, td, predicate, "predicate.json") - ctx := context.Background() - for _, tc := range []struct { - name string - keyref string - certref string - certchainref string - errString string - }{ - { - name: "no cert", - keyref: keyRef, - }, - { - name: "cert matches key", - keyref: keyRef, - certref: certRef, - }, - { - name: "fail: cert no match key", - keyref: keyRef, - certref: subCertPem, - errString: "public key in certificate does not match the provided public key", - }, - { - name: "cert chain matches key", - keyref: keyRef, - certref: certRef, - certchainref: chainRef, - }, - { - name: "cert chain partial", - keyref: keyRef, - certref: certRef, - certchainref: subCertPem, - }, - { - name: "fail: cert chain bad", - keyref: keyRef, - certref: certRef, - certchainref: otherRootPem, - errString: "unable to validate certificate chain", - }, - } { - t.Run(tc.name, func(t *testing.T) { - at := AttestBlobCommand{ - KeyOpts: options.KeyOpts{KeyRef: tc.keyref}, - CertPath: tc.certref, - CertChainPath: tc.certchainref, - PredicatePath: predicatePath, - PredicateType: predicateType, - } - err := at.Exec(ctx, blob) - if err != nil { - if tc.errString == "" { - t.Fatalf("unexpected error %v", err) - } - if !strings.Contains(err.Error(), tc.errString) { - t.Fatalf("expected error %v got %v", tc.errString, err) - } - return - } - if tc.errString != "" { - t.Fatalf("expected error %v", tc.errString) + predicates := map[string]string{} + predicates["slsaprovenance"] = makeSLSA02PredicateFile(t, td) + predicates["slsaprovenance1"] = makeSLSA1PredicateFile(t, td) + + for predicateType, predicatePath := range predicates { + t.Run(predicateType, func(t *testing.T) { + + ctx := context.Background() + for _, tc := range []struct { + name string + keyref string + certref string + certchainref string + errString string + }{ + { + name: "no cert", + keyref: keyRef, + }, + { + name: "cert matches key", + keyref: keyRef, + certref: certRef, + }, + { + name: "fail: cert no match key", + keyref: keyRef, + certref: subCertPem, + errString: "public key in certificate does not match the provided public key", + }, + { + name: "cert chain matches key", + keyref: keyRef, + certref: certRef, + certchainref: chainRef, + }, + { + name: "cert chain partial", + keyref: keyRef, + certref: certRef, + certchainref: subCertPem, + }, + { + name: "fail: cert chain bad", + keyref: keyRef, + certref: certRef, + certchainref: otherRootPem, + errString: "unable to validate certificate chain", + }, + } { + t.Run(tc.name, func(t *testing.T) { + at := AttestBlobCommand{ + KeyOpts: options.KeyOpts{KeyRef: tc.keyref}, + CertPath: tc.certref, + CertChainPath: tc.certchainref, + PredicatePath: predicatePath, + PredicateType: predicateType, + } + err := at.Exec(ctx, blob) + if err != nil { + if tc.errString == "" { + t.Fatalf("unexpected error %v", err) + } + if !strings.Contains(err.Error(), tc.errString) { + t.Fatalf("expected error %v got %v", tc.errString, err) + } + return + } + if tc.errString != "" { + t.Fatalf("expected error %v", tc.errString) + } + }) } }) } @@ -185,59 +201,65 @@ func TestAttestBlob(t *testing.T) { blobPath := writeFile(t, td, string(blob), "foo.txt") digest, _, _ := signature.ComputeDigestForSigning(bytes.NewReader(blob), crypto.SHA256, []crypto.Hash{crypto.SHA256, crypto.SHA384}) blobDigest := strings.ToLower(hex.EncodeToString(digest)) - predicate := `{ "buildType": "x", "builder": { "id": "2" }, "recipe": {} }` - predicateType := "slsaprovenance" - predicatePath := writeFile(t, td, predicate, "predicate.json") - - dssePath := filepath.Join(td, "dsse.intoto.jsonl") - at := AttestBlobCommand{ - KeyOpts: options.KeyOpts{KeyRef: keyRef}, - PredicatePath: predicatePath, - PredicateType: predicateType, - OutputSignature: dssePath, - } - err := at.Exec(ctx, blobPath) - if err != nil { - t.Fatal(err) - } - // Load the attestation. - dsseBytes, _ := os.ReadFile(dssePath) - env := &ssldsse.Envelope{} - if err := json.Unmarshal(dsseBytes, env); err != nil { - t.Fatal(err) - } + predicates := map[string]string{} + predicates["slsaprovenance"] = makeSLSA02PredicateFile(t, td) + predicates["slsaprovenance1"] = makeSLSA1PredicateFile(t, td) - if len(env.Signatures) != 1 { - t.Fatalf("expected 1 signature, got %d", len(env.Signatures)) - } + for predicateType, predicatePath := range predicates { + t.Run(predicateType, func(t *testing.T) { - // Verify the subject digest - decodedPredicate, err := base64.StdEncoding.DecodeString(env.Payload) - if err != nil { - t.Fatalf("decoding dsse payload: %v", err) - } - var statement in_toto.Statement - if err := json.Unmarshal(decodedPredicate, &statement); err != nil { - t.Fatalf("decoding predicate: %v", err) - } - if statement.Subject == nil || len(statement.Subject) != 1 { - t.Fatalf("expected one subject in intoto statement") - } - if statement.Subject[0].Digest["sha256"] != blobDigest { - t.Fatalf("expected matching digest") - } - if statement.PredicateType != options.PredicateTypeMap[predicateType] { - t.Fatalf("expected matching predicate type") - } + dssePath := filepath.Join(td, "dsse.intoto.jsonl") + at := AttestBlobCommand{ + KeyOpts: options.KeyOpts{KeyRef: keyRef}, + PredicatePath: predicatePath, + PredicateType: predicateType, + OutputSignature: dssePath, + } + err := at.Exec(ctx, blobPath) + if err != nil { + t.Fatal(err) + } - // Load a verifier and DSSE verify - verifier, _ := signature.LoadVerifierFromPEMFile(pubKeyRef, crypto.SHA256) - dssev, err := ssldsse.NewEnvelopeVerifier(&dsse.VerifierAdapter{SignatureVerifier: verifier}) - if err != nil { - t.Fatalf("new envelope verifier: %v", err) - } - if _, err := dssev.Verify(ctx, env); err != nil { - t.Fatalf("dsse verify: %v", err) + // Load the attestation. + dsseBytes, _ := os.ReadFile(dssePath) + env := &ssldsse.Envelope{} + if err := json.Unmarshal(dsseBytes, env); err != nil { + t.Fatal(err) + } + + if len(env.Signatures) != 1 { + t.Fatalf("expected 1 signature, got %d", len(env.Signatures)) + } + + // Verify the subject digest + decodedPredicate, err := base64.StdEncoding.DecodeString(env.Payload) + if err != nil { + t.Fatalf("decoding dsse payload: %v", err) + } + var statement in_toto.Statement + if err := json.Unmarshal(decodedPredicate, &statement); err != nil { + t.Fatalf("decoding predicate: %v", err) + } + if statement.Subject == nil || len(statement.Subject) != 1 { + t.Fatalf("expected one subject in intoto statement") + } + if statement.Subject[0].Digest["sha256"] != blobDigest { + t.Fatalf("expected matching digest") + } + if statement.PredicateType != options.PredicateTypeMap[predicateType] { + t.Fatalf("expected matching predicate type") + } + + // Load a verifier and DSSE verify + verifier, _ := signature.LoadVerifierFromPEMFile(pubKeyRef, crypto.SHA256) + dssev, err := ssldsse.NewEnvelopeVerifier(&dsse.VerifierAdapter{SignatureVerifier: verifier}) + if err != nil { + t.Fatalf("new envelope verifier: %v", err) + } + if _, err := dssev.Verify(ctx, env); err != nil { + t.Fatalf("dsse verify: %v", err) + } + }) } } diff --git a/cmd/cosign/cli/options/predicate.go b/cmd/cosign/cli/options/predicate.go index 707a38cae4a..8694f6ba1d9 100644 --- a/cmd/cosign/cli/options/predicate.go +++ b/cmd/cosign/cli/options/predicate.go @@ -19,7 +19,8 @@ import ( "fmt" "net/url" - slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2" + slsa02 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2" + slsa1 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1" "github.com/in-toto/in-toto-golang/in_toto" "github.com/spf13/cobra" @@ -30,6 +31,7 @@ import ( const ( PredicateCustom = "custom" PredicateSLSA = "slsaprovenance" + PredicateSLSA1 = "slsaprovenance1" PredicateSPDX = "spdx" PredicateSPDXJSON = "spdxjson" PredicateCycloneDX = "cyclonedx" @@ -40,7 +42,8 @@ const ( // PredicateTypeMap is the mapping between the predicate `type` option to predicate URI. var PredicateTypeMap = map[string]string{ PredicateCustom: attestation.CosignCustomProvenanceV01, - PredicateSLSA: slsa.PredicateSLSAProvenance, + PredicateSLSA: slsa02.PredicateSLSAProvenance, + PredicateSLSA1: slsa1.PredicateSLSAProvenance, PredicateSPDX: in_toto.PredicateSPDX, PredicateSPDXJSON: in_toto.PredicateSPDX, PredicateCycloneDX: in_toto.PredicateCycloneDX, @@ -58,7 +61,7 @@ var _ Interface = (*PredicateOptions)(nil) // AddFlags implements Interface func (o *PredicateOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().StringVar(&o.Type, "type", "custom", - "specify a predicate type (slsaprovenance|link|spdx|spdxjson|cyclonedx|vuln|custom) or an URI") + "specify a predicate type (slsaprovenance|slsaprovenance1|link|spdx|spdxjson|cyclonedx|vuln|custom) or an URI") } // ParsePredicateType parses the predicate `type` flag passed into a predicate URI, or validates `type` is a valid URI. diff --git a/doc/cosign_attest-blob.md b/doc/cosign_attest-blob.md index e620f4e3a4f..1273ad0009b 100644 --- a/doc/cosign_attest-blob.md +++ b/doc/cosign_attest-blob.md @@ -58,7 +58,7 @@ cosign attest-blob [flags] --slot string security key slot to use for generated key (default: signature) (authentication|signature|card-authentication|key-management) --timestamp-server-url string url to the Timestamp RFC3161 server, default none. Must be the path to the API to request timestamp responses, e.g. https://freetsa.org/tsr --tlog-upload whether or not to upload to the tlog (default true) - --type string specify a predicate type (slsaprovenance|link|spdx|spdxjson|cyclonedx|vuln|custom) or an URI (default "custom") + --type string specify a predicate type (slsaprovenance|slsaprovenance1|link|spdx|spdxjson|cyclonedx|vuln|custom) or an URI (default "custom") -y, --yes skip confirmation prompts for non-destructive operations ``` diff --git a/doc/cosign_attest.md b/doc/cosign_attest.md index bf7c25e468a..f035fffb447 100644 --- a/doc/cosign_attest.md +++ b/doc/cosign_attest.md @@ -68,7 +68,7 @@ cosign attest [flags] --slot string security key slot to use for generated key (default: signature) (authentication|signature|card-authentication|key-management) --timestamp-server-url string url to the Timestamp RFC3161 server, default none. Must be the path to the API to request timestamp responses, e.g. https://freetsa.org/tsr --tlog-upload whether or not to upload to the tlog (default true) - --type string specify a predicate type (slsaprovenance|link|spdx|spdxjson|cyclonedx|vuln|custom) or an URI (default "custom") + --type string specify a predicate type (slsaprovenance|slsaprovenance1|link|spdx|spdxjson|cyclonedx|vuln|custom) or an URI (default "custom") -y, --yes skip confirmation prompts for non-destructive operations ``` diff --git a/doc/cosign_verify-attestation.md b/doc/cosign_verify-attestation.md index 61725949d53..42e76576424 100644 --- a/doc/cosign_verify-attestation.md +++ b/doc/cosign_verify-attestation.md @@ -86,7 +86,7 @@ cosign verify-attestation [flags] --sk whether to use a hardware security key --slot string security key slot to use for generated key (default: signature) (authentication|signature|card-authentication|key-management) --timestamp-certificate-chain string path to PEM-encoded certificate chain file for the RFC3161 timestamp authority. Must contain the root CA certificate. Optionally may contain intermediate CA certificates, and may contain the leaf TSA certificate if not present in the timestamp - --type string specify a predicate type (slsaprovenance|link|spdx|spdxjson|cyclonedx|vuln|custom) or an URI (default "custom") + --type string specify a predicate type (slsaprovenance|slsaprovenance1|link|spdx|spdxjson|cyclonedx|vuln|custom) or an URI (default "custom") ``` ### Options inherited from parent commands diff --git a/doc/cosign_verify-blob-attestation.md b/doc/cosign_verify-blob-attestation.md index fc2b8cf809d..cac53e15bad 100644 --- a/doc/cosign_verify-blob-attestation.md +++ b/doc/cosign_verify-blob-attestation.md @@ -54,7 +54,7 @@ cosign verify-blob-attestation [flags] --sk whether to use a hardware security key --slot string security key slot to use for generated key (default: signature) (authentication|signature|card-authentication|key-management) --timestamp-certificate-chain string path to PEM-encoded certificate chain file for the RFC3161 timestamp authority. Must contain the root CA certificate. Optionally may contain intermediate CA certificates, and may contain the leaf TSA certificate if not present in the timestamp - --type string specify a predicate type (slsaprovenance|link|spdx|spdxjson|cyclonedx|vuln|custom) or an URI (default "custom") + --type string specify a predicate type (slsaprovenance|slsaprovenance1|link|spdx|spdxjson|cyclonedx|vuln|custom) or an URI (default "custom") ``` ### Options inherited from parent commands diff --git a/pkg/cosign/attestation/attestation.go b/pkg/cosign/attestation/attestation.go index 52a2008043f..7d9e50bb666 100644 --- a/pkg/cosign/attestation/attestation.go +++ b/pkg/cosign/attestation/attestation.go @@ -23,7 +23,8 @@ import ( "strings" "time" - slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2" + slsa02 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2" + slsa1 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1" "github.com/in-toto/in-toto-golang/in_toto" ) @@ -99,7 +100,7 @@ type GenerateOpts struct { } // GenerateStatement returns an in-toto statement based on the provided -// predicate type (custom|slsaprovenance|spdx|spdxjson|cyclonedx|link). +// predicate type (custom|slsaprovenance|slsaprovenance1.0|spdx|spdxjson|cyclonedx|link). func GenerateStatement(opts GenerateOpts) (interface{}, error) { predicate, err := io.ReadAll(opts.Predicate) if err != nil { @@ -109,6 +110,8 @@ func GenerateStatement(opts GenerateOpts) (interface{}, error) { switch opts.Type { case "slsaprovenance": return generateSLSAProvenanceStatement(predicate, opts.Digest, opts.Repo) + case "slsaprovenance1": + return generateSLSAProvenanceStatementSLSA1(predicate, opts.Digest, opts.Repo) case "spdx": return generateSPDXStatement(predicate, opts.Digest, opts.Repo, false) case "spdxjson": @@ -199,7 +202,7 @@ func generateCustomPredicate(rawPayload []byte, customType, timestamp string) (i } func generateSLSAProvenanceStatement(rawPayload []byte, digest string, repo string) (interface{}, error) { - var predicate slsa.ProvenancePredicate + var predicate slsa02.ProvenancePredicate err := checkRequiredJSONFields(rawPayload, reflect.TypeOf(predicate)) if err != nil { return nil, fmt.Errorf("provenance predicate: %w", err) @@ -209,7 +212,23 @@ func generateSLSAProvenanceStatement(rawPayload []byte, digest string, repo stri return "", fmt.Errorf("unmarshal Provenance predicate: %w", err) } return in_toto.ProvenanceStatement{ - StatementHeader: generateStatementHeader(digest, repo, slsa.PredicateSLSAProvenance), + StatementHeader: generateStatementHeader(digest, repo, slsa02.PredicateSLSAProvenance), + Predicate: predicate, + }, nil +} + +func generateSLSAProvenanceStatementSLSA1(rawPayload []byte, digest string, repo string) (interface{}, error) { + var predicate slsa1.ProvenancePredicate + err := checkRequiredJSONFields(rawPayload, reflect.TypeOf(predicate)) + if err != nil { + return nil, fmt.Errorf("provenance predicate: %w", err) + } + err = json.Unmarshal(rawPayload, &predicate) + if err != nil { + return "", fmt.Errorf("unmarshal Provenance predicate: %w", err) + } + return in_toto.ProvenanceStatementSLSA1{ + StatementHeader: generateStatementHeader(digest, repo, slsa1.PredicateSLSAProvenance), Predicate: predicate, }, nil } From 3c374b92b5450dd64fb9fe08f35794c8ba9b5261 Mon Sep 17 00:00:00 2001 From: Canaan Silberberg Date: Tue, 5 Sep 2023 11:44:54 -0400 Subject: [PATCH 2/4] fix leading whitspace Signed-off-by: Canaan Silberberg --- cmd/cosign/cli/attest/attest_blob_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmd/cosign/cli/attest/attest_blob_test.go b/cmd/cosign/cli/attest/attest_blob_test.go index df2df7eff01..a62b0eaea2d 100644 --- a/cmd/cosign/cli/attest/attest_blob_test.go +++ b/cmd/cosign/cli/attest/attest_blob_test.go @@ -116,7 +116,6 @@ func TestAttestBlobCmdLocalKeyAndCert(t *testing.T) { for predicateType, predicatePath := range predicates { t.Run(predicateType, func(t *testing.T) { - ctx := context.Background() for _, tc := range []struct { name string @@ -208,7 +207,6 @@ func TestAttestBlob(t *testing.T) { for predicateType, predicatePath := range predicates { t.Run(predicateType, func(t *testing.T) { - dssePath := filepath.Join(td, "dsse.intoto.jsonl") at := AttestBlobCommand{ KeyOpts: options.KeyOpts{KeyRef: keyRef}, From 700ae028ef6ea275b6f87b417033ed8e709ae7ef Mon Sep 17 00:00:00 2001 From: Canaan Silberberg Date: Wed, 6 Sep 2023 14:07:29 -0400 Subject: [PATCH 3/4] fix 1.0 typo Signed-off-by: Canaan Silberberg --- pkg/cosign/attestation/attestation.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cosign/attestation/attestation.go b/pkg/cosign/attestation/attestation.go index 7d9e50bb666..a61090bfc47 100644 --- a/pkg/cosign/attestation/attestation.go +++ b/pkg/cosign/attestation/attestation.go @@ -100,7 +100,7 @@ type GenerateOpts struct { } // GenerateStatement returns an in-toto statement based on the provided -// predicate type (custom|slsaprovenance|slsaprovenance1.0|spdx|spdxjson|cyclonedx|link). +// predicate type (custom|slsaprovenance|slsaprovenance1|spdx|spdxjson|cyclonedx|link). func GenerateStatement(opts GenerateOpts) (interface{}, error) { predicate, err := io.ReadAll(opts.Predicate) if err != nil { From 1ac71d77e6a7c0fbef09a33e1903b561b606cb28 Mon Sep 17 00:00:00 2001 From: Canaan Silberberg Date: Wed, 6 Sep 2023 14:16:57 -0400 Subject: [PATCH 4/4] add slsaprovenance02 type Signed-off-by: Canaan Silberberg --- cmd/cosign/cli/options/predicate.go | 4 +++- doc/cosign_attest-blob.md | 2 +- doc/cosign_attest.md | 2 +- doc/cosign_verify-attestation.md | 2 +- doc/cosign_verify-blob-attestation.md | 2 +- pkg/cosign/attestation/attestation.go | 8 +++++--- 6 files changed, 12 insertions(+), 8 deletions(-) diff --git a/cmd/cosign/cli/options/predicate.go b/cmd/cosign/cli/options/predicate.go index 8694f6ba1d9..0c68e279b7a 100644 --- a/cmd/cosign/cli/options/predicate.go +++ b/cmd/cosign/cli/options/predicate.go @@ -31,6 +31,7 @@ import ( const ( PredicateCustom = "custom" PredicateSLSA = "slsaprovenance" + PredicateSLSA02 = "slsaprovenance02" PredicateSLSA1 = "slsaprovenance1" PredicateSPDX = "spdx" PredicateSPDXJSON = "spdxjson" @@ -43,6 +44,7 @@ const ( var PredicateTypeMap = map[string]string{ PredicateCustom: attestation.CosignCustomProvenanceV01, PredicateSLSA: slsa02.PredicateSLSAProvenance, + PredicateSLSA02: slsa02.PredicateSLSAProvenance, PredicateSLSA1: slsa1.PredicateSLSAProvenance, PredicateSPDX: in_toto.PredicateSPDX, PredicateSPDXJSON: in_toto.PredicateSPDX, @@ -61,7 +63,7 @@ var _ Interface = (*PredicateOptions)(nil) // AddFlags implements Interface func (o *PredicateOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().StringVar(&o.Type, "type", "custom", - "specify a predicate type (slsaprovenance|slsaprovenance1|link|spdx|spdxjson|cyclonedx|vuln|custom) or an URI") + "specify a predicate type (slsaprovenance|slsaprovenance02|slsaprovenance1|link|spdx|spdxjson|cyclonedx|vuln|custom) or an URI") } // ParsePredicateType parses the predicate `type` flag passed into a predicate URI, or validates `type` is a valid URI. diff --git a/doc/cosign_attest-blob.md b/doc/cosign_attest-blob.md index 1273ad0009b..e6d95e11202 100644 --- a/doc/cosign_attest-blob.md +++ b/doc/cosign_attest-blob.md @@ -58,7 +58,7 @@ cosign attest-blob [flags] --slot string security key slot to use for generated key (default: signature) (authentication|signature|card-authentication|key-management) --timestamp-server-url string url to the Timestamp RFC3161 server, default none. Must be the path to the API to request timestamp responses, e.g. https://freetsa.org/tsr --tlog-upload whether or not to upload to the tlog (default true) - --type string specify a predicate type (slsaprovenance|slsaprovenance1|link|spdx|spdxjson|cyclonedx|vuln|custom) or an URI (default "custom") + --type string specify a predicate type (slsaprovenance|slsaprovenance02|slsaprovenance1|link|spdx|spdxjson|cyclonedx|vuln|custom) or an URI (default "custom") -y, --yes skip confirmation prompts for non-destructive operations ``` diff --git a/doc/cosign_attest.md b/doc/cosign_attest.md index f035fffb447..a613bcf5401 100644 --- a/doc/cosign_attest.md +++ b/doc/cosign_attest.md @@ -68,7 +68,7 @@ cosign attest [flags] --slot string security key slot to use for generated key (default: signature) (authentication|signature|card-authentication|key-management) --timestamp-server-url string url to the Timestamp RFC3161 server, default none. Must be the path to the API to request timestamp responses, e.g. https://freetsa.org/tsr --tlog-upload whether or not to upload to the tlog (default true) - --type string specify a predicate type (slsaprovenance|slsaprovenance1|link|spdx|spdxjson|cyclonedx|vuln|custom) or an URI (default "custom") + --type string specify a predicate type (slsaprovenance|slsaprovenance02|slsaprovenance1|link|spdx|spdxjson|cyclonedx|vuln|custom) or an URI (default "custom") -y, --yes skip confirmation prompts for non-destructive operations ``` diff --git a/doc/cosign_verify-attestation.md b/doc/cosign_verify-attestation.md index 42e76576424..f30a071f1b0 100644 --- a/doc/cosign_verify-attestation.md +++ b/doc/cosign_verify-attestation.md @@ -86,7 +86,7 @@ cosign verify-attestation [flags] --sk whether to use a hardware security key --slot string security key slot to use for generated key (default: signature) (authentication|signature|card-authentication|key-management) --timestamp-certificate-chain string path to PEM-encoded certificate chain file for the RFC3161 timestamp authority. Must contain the root CA certificate. Optionally may contain intermediate CA certificates, and may contain the leaf TSA certificate if not present in the timestamp - --type string specify a predicate type (slsaprovenance|slsaprovenance1|link|spdx|spdxjson|cyclonedx|vuln|custom) or an URI (default "custom") + --type string specify a predicate type (slsaprovenance|slsaprovenance02|slsaprovenance1|link|spdx|spdxjson|cyclonedx|vuln|custom) or an URI (default "custom") ``` ### Options inherited from parent commands diff --git a/doc/cosign_verify-blob-attestation.md b/doc/cosign_verify-blob-attestation.md index cac53e15bad..526e61890c7 100644 --- a/doc/cosign_verify-blob-attestation.md +++ b/doc/cosign_verify-blob-attestation.md @@ -54,7 +54,7 @@ cosign verify-blob-attestation [flags] --sk whether to use a hardware security key --slot string security key slot to use for generated key (default: signature) (authentication|signature|card-authentication|key-management) --timestamp-certificate-chain string path to PEM-encoded certificate chain file for the RFC3161 timestamp authority. Must contain the root CA certificate. Optionally may contain intermediate CA certificates, and may contain the leaf TSA certificate if not present in the timestamp - --type string specify a predicate type (slsaprovenance|slsaprovenance1|link|spdx|spdxjson|cyclonedx|vuln|custom) or an URI (default "custom") + --type string specify a predicate type (slsaprovenance|slsaprovenance02|slsaprovenance1|link|spdx|spdxjson|cyclonedx|vuln|custom) or an URI (default "custom") ``` ### Options inherited from parent commands diff --git a/pkg/cosign/attestation/attestation.go b/pkg/cosign/attestation/attestation.go index a61090bfc47..5c454c1b84e 100644 --- a/pkg/cosign/attestation/attestation.go +++ b/pkg/cosign/attestation/attestation.go @@ -100,7 +100,7 @@ type GenerateOpts struct { } // GenerateStatement returns an in-toto statement based on the provided -// predicate type (custom|slsaprovenance|slsaprovenance1|spdx|spdxjson|cyclonedx|link). +// predicate type (custom|slsaprovenance|slsaprovenance02|slsaprovenance1|spdx|spdxjson|cyclonedx|link). func GenerateStatement(opts GenerateOpts) (interface{}, error) { predicate, err := io.ReadAll(opts.Predicate) if err != nil { @@ -109,7 +109,9 @@ func GenerateStatement(opts GenerateOpts) (interface{}, error) { switch opts.Type { case "slsaprovenance": - return generateSLSAProvenanceStatement(predicate, opts.Digest, opts.Repo) + return generateSLSAProvenanceStatementSLSA02(predicate, opts.Digest, opts.Repo) + case "slsaprovenance02": + return generateSLSAProvenanceStatementSLSA02(predicate, opts.Digest, opts.Repo) case "slsaprovenance1": return generateSLSAProvenanceStatementSLSA1(predicate, opts.Digest, opts.Repo) case "spdx": @@ -201,7 +203,7 @@ func generateCustomPredicate(rawPayload []byte, customType, timestamp string) (i return result, nil } -func generateSLSAProvenanceStatement(rawPayload []byte, digest string, repo string) (interface{}, error) { +func generateSLSAProvenanceStatementSLSA02(rawPayload []byte, digest string, repo string) (interface{}, error) { var predicate slsa02.ProvenancePredicate err := checkRequiredJSONFields(rawPayload, reflect.TypeOf(predicate)) if err != nil {