From da2d86b8d98f124070a6edece84bf5e33d4a1754 Mon Sep 17 00:00:00 2001 From: Zach Steindler Date: Tue, 23 Jul 2024 17:05:24 -0400 Subject: [PATCH 1/4] Add new bundle support to `verify-blob` and `verify-blob-attestation` Part of #3139 Signed-off-by: Zach Steindler --- cmd/cosign/cli/options/verify.go | 30 +++- cmd/cosign/cli/verify.go | 6 + cmd/cosign/cli/verify/verify_blob.go | 15 +- .../cli/verify/verify_blob_attestation.go | 9 + .../verify/verify_blob_attestation_test.go | 65 +++++++ cmd/cosign/cli/verify/verify_blob_test.go | 66 +++++++ cmd/cosign/cli/verify/verify_bundle.go | 163 ++++++++++++++++++ doc/cosign_verify-blob-attestation.md | 2 + doc/cosign_verify-blob.md | 2 + go.mod | 4 +- go.sum | 15 +- 11 files changed, 365 insertions(+), 12 deletions(-) create mode 100644 cmd/cosign/cli/verify/verify_bundle.go diff --git a/cmd/cosign/cli/options/verify.go b/cmd/cosign/cli/options/verify.go index 49ade7539df..3cdbb0e8a62 100644 --- a/cmd/cosign/cli/options/verify.go +++ b/cmd/cosign/cli/options/verify.go @@ -158,9 +158,11 @@ func (o *VerifyAttestationOptions) AddFlags(cmd *cobra.Command) { // VerifyBlobOptions is the top level wrapper for the `verify blob` command. type VerifyBlobOptions struct { - Key string - Signature string - BundlePath string + Key string + Signature string + BundlePath string + NewBundleFormat bool + TrustedRootPath string SecurityKey SecurityKeyOptions CertVerify CertVerifyOptions @@ -188,6 +190,13 @@ func (o *VerifyBlobOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().StringVar(&o.BundlePath, "bundle", "", "path to bundle FILE") + // TODO: have this default to true as a breaking change + cmd.Flags().BoolVar(&o.NewBundleFormat, "new-bundle-format", false, + "output bundle in new format that contains all verification material") + + cmd.Flags().StringVar(&o.TrustedRootPath, "trusted-root", "", + "path to trusted root FILE") + cmd.Flags().StringVar(&o.RFC3161TimestampPath, "rfc3161-timestamp", "", "path to RFC3161 timestamp FILE") } @@ -210,9 +219,11 @@ func (o *VerifyDockerfileOptions) AddFlags(cmd *cobra.Command) { // VerifyBlobAttestationOptions is the top level wrapper for the `verify-blob-attestation` command. type VerifyBlobAttestationOptions struct { - Key string - SignaturePath string - BundlePath string + Key string + SignaturePath string + BundlePath string + NewBundleFormat bool + TrustedRootPath string PredicateOptions CheckClaims bool @@ -244,6 +255,13 @@ func (o *VerifyBlobAttestationOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().StringVar(&o.BundlePath, "bundle", "", "path to bundle FILE") + // TODO: have this default to true as a breaking change + cmd.Flags().BoolVar(&o.NewBundleFormat, "new-bundle-format", false, + "output bundle in new format that contains all verification material") + + cmd.Flags().StringVar(&o.TrustedRootPath, "trusted-root", "", + "path to trusted root FILE") + cmd.Flags().BoolVar(&o.CheckClaims, "check-claims", true, "if true, verifies the provided blob's sha256 digest exists as an in-toto subject within the attestation. If false, only the DSSE envelope is verified.") diff --git a/cmd/cosign/cli/verify.go b/cmd/cosign/cli/verify.go index c574b8a0f80..703898523b7 100644 --- a/cmd/cosign/cli/verify.go +++ b/cmd/cosign/cli/verify.go @@ -333,6 +333,7 @@ The blob may be specified as a path to a file or - for stdin.`, Slot: o.SecurityKey.Slot, RekorURL: o.Rekor.URL, BundlePath: o.BundlePath, + NewBundleFormat: o.NewBundleFormat, RFC3161TimestampPath: o.RFC3161TimestampPath, TSACertChainPath: o.CommonVerifyOptions.TSACertChainPath, } @@ -344,6 +345,7 @@ The blob may be specified as a path to a file or - for stdin.`, CARoots: o.CertVerify.CARoots, CAIntermediates: o.CertVerify.CAIntermediates, SigRef: o.Signature, + TrustedRootPath: o.TrustedRootPath, CertGithubWorkflowTrigger: o.CertVerify.CertGithubWorkflowTrigger, CertGithubWorkflowSHA: o.CertVerify.CertGithubWorkflowSha, CertGithubWorkflowName: o.CertVerify.CertGithubWorkflowName, @@ -353,6 +355,7 @@ The blob may be specified as a path to a file or - for stdin.`, SCTRef: o.CertVerify.SCT, Offline: o.CommonVerifyOptions.Offline, IgnoreTlog: o.CommonVerifyOptions.IgnoreTlog, + UseSignedTimestamps: o.CommonVerifyOptions.UseSignedTimestamps, } ctx, cancel := context.WithTimeout(cmd.Context(), ro.Timeout) @@ -401,6 +404,7 @@ The blob may be specified as a path to a file.`, Slot: o.SecurityKey.Slot, RekorURL: o.Rekor.URL, BundlePath: o.BundlePath, + NewBundleFormat: o.NewBundleFormat, RFC3161TimestampPath: o.RFC3161TimestampPath, TSACertChainPath: o.CommonVerifyOptions.TSACertChainPath, } @@ -410,6 +414,7 @@ The blob may be specified as a path to a file.`, CheckClaims: o.CheckClaims, SignaturePath: o.SignaturePath, CertVerifyOptions: o.CertVerify, + TrustedRootPath: o.TrustedRootPath, CertRef: o.CertVerify.Cert, CertChain: o.CertVerify.CertChain, CARoots: o.CertVerify.CARoots, @@ -423,6 +428,7 @@ The blob may be specified as a path to a file.`, SCTRef: o.CertVerify.SCT, Offline: o.CommonVerifyOptions.Offline, IgnoreTlog: o.CommonVerifyOptions.IgnoreTlog, + UseSignedTimestamps: o.CommonVerifyOptions.UseSignedTimestamps, } // We only use the blob if we are checking claims. if len(args) == 0 && o.CheckClaims { diff --git a/cmd/cosign/cli/verify/verify_blob.go b/cmd/cosign/cli/verify/verify_blob.go index c9e622897e4..b1574bf2ae2 100644 --- a/cmd/cosign/cli/verify/verify_blob.go +++ b/cmd/cosign/cli/verify/verify_blob.go @@ -56,6 +56,7 @@ type VerifyBlobCmd struct { CARoots string CertChain string SigRef string + TrustedRootPath string CertGithubWorkflowTrigger string CertGithubWorkflowSHA string CertGithubWorkflowName string @@ -81,9 +82,6 @@ func (c *VerifyBlobCmd) loadTSACertificates(ctx context.Context) (*cosign.TSACer // nolint func (c *VerifyBlobCmd) Exec(ctx context.Context, blobRef string) error { - var cert *x509.Certificate - opts := make([]static.Option, 0) - // Require a certificate/key OR a local bundle file that has the cert. if options.NOf(c.KeyRef, c.CertRef, c.Sk, c.BundlePath) == 0 { return fmt.Errorf("provide a key with --key or --sk, a certificate to verify against with --certificate, or a bundle with --bundle") @@ -94,6 +92,17 @@ func (c *VerifyBlobCmd) Exec(ctx context.Context, blobRef string) error { return &options.PubKeyParseError{} } + if c.KeyOpts.NewBundleFormat { + err := verifyNewBundle(ctx, c.BundlePath, c.TrustedRootPath, c.KeyRef, c.Slot, c.CertVerifyOptions.CertOidcIssuer, c.CertVerifyOptions.CertOidcIssuerRegexp, c.CertVerifyOptions.CertIdentity, c.CertVerifyOptions.CertIdentityRegexp, c.CertGithubWorkflowTrigger, c.CertGithubWorkflowSHA, c.CertGithubWorkflowName, c.CertGithubWorkflowRepository, c.CertGithubWorkflowRef, blobRef, c.Sk, c.IgnoreTlog, c.UseSignedTimestamps, c.IgnoreSCT) + if err == nil { + ui.Infof(ctx, "Verified OK") + } + return err + } + + var cert *x509.Certificate + opts := make([]static.Option, 0) + var identities []cosign.Identity var err error if c.KeyRef == "" { diff --git a/cmd/cosign/cli/verify/verify_blob_attestation.go b/cmd/cosign/cli/verify/verify_blob_attestation.go index 63988432588..b8bec7b1756 100644 --- a/cmd/cosign/cli/verify/verify_blob_attestation.go +++ b/cmd/cosign/cli/verify/verify_blob_attestation.go @@ -55,6 +55,7 @@ type VerifyBlobAttestationCommand struct { CertChain string CAIntermediates string CARoots string + TrustedRootPath string CertGithubWorkflowTrigger string CertGithubWorkflowSHA string @@ -91,6 +92,14 @@ func (c *VerifyBlobAttestationCommand) Exec(ctx context.Context, artifactPath st return &options.KeyParseError{} } + if c.KeyOpts.NewBundleFormat { + err = verifyNewBundle(ctx, c.BundlePath, c.TrustedRootPath, c.KeyRef, c.Slot, c.CertVerifyOptions.CertOidcIssuer, c.CertVerifyOptions.CertOidcIssuerRegexp, c.CertVerifyOptions.CertIdentity, c.CertVerifyOptions.CertIdentityRegexp, c.CertGithubWorkflowTrigger, c.CertGithubWorkflowSHA, c.CertGithubWorkflowName, c.CertGithubWorkflowRepository, c.CertGithubWorkflowRef, artifactPath, c.Sk, c.IgnoreTlog, c.UseSignedTimestamps, c.IgnoreSCT) + if err == nil { + fmt.Fprintln(os.Stderr, "Verified OK") + } + return err + } + var identities []cosign.Identity if c.KeyRef == "" { identities, err = c.Identities() diff --git a/cmd/cosign/cli/verify/verify_blob_attestation_test.go b/cmd/cosign/cli/verify/verify_blob_attestation_test.go index 2d87efeb451..58121544420 100644 --- a/cmd/cosign/cli/verify/verify_blob_attestation_test.go +++ b/cmd/cosign/cli/verify/verify_blob_attestation_test.go @@ -18,9 +18,15 @@ import ( "context" "encoding/base64" "os" + "path/filepath" "testing" + protobundle "github.com/sigstore/protobuf-specs/gen/pb-go/bundle/v1" + protodsse "github.com/sigstore/protobuf-specs/gen/pb-go/dsse" + "google.golang.org/protobuf/encoding/protojson" + "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v2/pkg/cosign/bundle" ) const pubkey = `-----BEGIN PUBLIC KEY----- @@ -53,6 +59,7 @@ func TestVerifyBlobAttestation(t *testing.T) { tests := []struct { description string blobPath string + bundlePath string signature string predicateType string env map[string]string @@ -107,6 +114,17 @@ func TestVerifyBlobAttestation(t *testing.T) { blobPath: hugeBlobPath, env: map[string]string{"COSIGN_MAX_ATTACHMENT_SIZE": "128"}, shouldErr: true, + }, { + description: "verify new bundle with public key", + // From blobSLSAProvenanceSignature + bundlePath: makeLocalAttestNewBundle(t, "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL3Nsc2EuZGV2L3Byb3ZlbmFuY2UvdjAuMiIsInN1YmplY3QiOlt7Im5hbWUiOiJibG9iIiwiZGlnZXN0Ijp7InNoYTI1NiI6IjY1ODc4MWNkNGVkOWJjYTYwZGFjZDA5ZjdiYjkxNGJiNTE1MDJlOGI1ZDYxOWY1N2YzOWExZDY1MjU5NmNjMjQifX1dLCJwcmVkaWNhdGUiOnsiYnVpbGRlciI6eyJpZCI6IjIifSwiYnVpbGRUeXBlIjoieCIsImludm9jYXRpb24iOnsiY29uZmlnU291cmNlIjp7fX19fQ==", "application/vnd.in-toto+json", "MEUCIA8KjZqkrt90fzBojSwwtj3Bqb41E6ruxQk97TLnpzdYAiEAzOAjOTzyvTHqbpFDAn6zhrg6EZv7kxK5faRoVGYMh2c="), + blobPath: blobPath, + }, { + description: "verify new bundle with public key - bad sig", + // From blobSLSAProvenanceSignature + bundlePath: makeLocalAttestNewBundle(t, "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL3Nsc2EuZGV2L3Byb3ZlbmFuY2UvdjAuMiIsInN1YmplY3QiOlt7Im5hbWUiOiJibG9iIiwiZGlnZXN0Ijp7InNoYTI1NiI6IjY1ODc4MWNkNGVkOWJjYTYwZGFjZDA5ZjdiYjkxNGJiNTE1MDJlOGI1ZDYxOWY1N2YzOWExZDY1MjU5NmNjMjQifX1dLCJwcmVkaWNhdGUiOnsiYnVpbGRlciI6eyJpZCI6IjIifSwiYnVpbGRUeXBlIjoieCIsImludm9jYXRpb24iOnsiY29uZmlnU291cmNlIjp7fX19fQ==", "application/vnd.in-toto+json", "c29tZXRoaW5nCg=="), + blobPath: blobPath, + shouldErr: true, }, } @@ -128,6 +146,11 @@ func TestVerifyBlobAttestation(t *testing.T) { CheckClaims: true, PredicateType: test.predicateType, } + if test.bundlePath != "" { + cmd.KeyOpts.BundlePath = test.bundlePath + cmd.KeyOpts.NewBundleFormat = true + cmd.TrustedRootPath = writeTrustedRootFile(t, td, "{\"mediaType\":\"application/vnd.dev.sigstore.trustedroot+json;version=0.1\"}") + } err = cmd.Exec(ctx, test.blobPath) if (err != nil) != test.shouldErr { @@ -191,3 +214,45 @@ func TestVerifyBlobAttestationNoCheckClaims(t *testing.T) { }) } } + +func makeLocalAttestNewBundle(t *testing.T, payload, payloadType, sig string) string { + b, err := bundle.MakeProtobufBundle("hint", []byte{}, nil, []byte{}) + if err != nil { + t.Fatal(err) + } + + decodedPayload, err := base64.StdEncoding.DecodeString(payload) + if err != nil { + t.Fatal(err) + } + + decodedSig, err := base64.StdEncoding.DecodeString(sig) + if err != nil { + t.Fatal(err) + } + + b.Content = &protobundle.Bundle_DsseEnvelope{ + DsseEnvelope: &protodsse.Envelope{ + Payload: decodedPayload, + PayloadType: payloadType, + Signatures: []*protodsse.Signature{ + { + Sig: decodedSig, + }, + }, + }, + } + + contents, err := protojson.Marshal(b) + if err != nil { + t.Fatal(err) + } + + // write bundle to disk + td := t.TempDir() + bundlePath := filepath.Join(td, "bundle.sigstore.json") + if err := os.WriteFile(bundlePath, contents, 0644); err != nil { + t.Fatal(err) + } + return bundlePath +} diff --git a/cmd/cosign/cli/verify/verify_blob_test.go b/cmd/cosign/cli/verify/verify_blob_test.go index 1b8b3a3429d..8dd77c81af9 100644 --- a/cmd/cosign/cli/verify/verify_blob_test.go +++ b/cmd/cosign/cli/verify/verify_blob_test.go @@ -45,6 +45,8 @@ import ( sigs "github.com/sigstore/cosign/v2/pkg/signature" ctypes "github.com/sigstore/cosign/v2/pkg/types" "github.com/sigstore/cosign/v2/test" + protobundle "github.com/sigstore/protobuf-specs/gen/pb-go/bundle/v1" + protocommon "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" "github.com/sigstore/rekor/pkg/generated/models" "github.com/sigstore/rekor/pkg/pki" "github.com/sigstore/rekor/pkg/types" @@ -57,6 +59,7 @@ import ( "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore/pkg/signature/dsse" signatureoptions "github.com/sigstore/sigstore/pkg/signature/options" + "google.golang.org/protobuf/encoding/protojson" ) func TestSignaturesRef(t *testing.T) { @@ -235,6 +238,7 @@ func TestVerifyBlob(t *testing.T) { key []byte cert *x509.Certificate bundlePath string + newBundle bool // The rekor entry response when Rekor is enabled rekorEntry []*models.LogEntry skipTlogVerify bool @@ -320,6 +324,26 @@ func TestVerifyBlob(t *testing.T) { pubKeyBytes, true), shouldErr: true, }, + { + name: "valid signature with public key - new bundle", + blob: blobBytes, + signature: blobSignature, + key: pubKeyBytes, + bundlePath: makeLocalNewBundle(t, []byte(blobSignature), sha256.Sum256(blobBytes)), + newBundle: true, + skipTlogVerify: true, + shouldErr: false, + }, + { + name: "invalid signature with public key - new bundle", + blob: blobBytes, + signature: otherSignature, + key: pubKeyBytes, + bundlePath: makeLocalNewBundle(t, []byte(blobSignature), sha256.Sum256(blobBytes)), + newBundle: true, + skipTlogVerify: true, + shouldErr: false, + }, { name: "invalid signature with public key", blob: blobBytes, @@ -563,6 +587,7 @@ func TestVerifyBlob(t *testing.T) { cmd := VerifyBlobCmd{ KeyOpts: options.KeyOpts{ BundlePath: tt.bundlePath, + NewBundleFormat: tt.newBundle, RekorURL: testServer.URL, RFC3161TimestampPath: tt.tsPath, TSACertChainPath: tt.tsChainPath, @@ -592,6 +617,9 @@ func TestVerifyBlob(t *testing.T) { keyPath := writeBlobFile(t, td, string(tt.key), "key.pem") cmd.KeyRef = keyPath } + if tt.newBundle { + cmd.TrustedRootPath = writeTrustedRootFile(t, td, "{\"mediaType\":\"application/vnd.dev.sigstore.trustedroot+json;version=0.1\"}") + } err := cmd.Exec(context.Background(), blobPath) if (err != nil) != tt.shouldErr { @@ -757,6 +785,36 @@ func makeLocalBundleWithoutRekorBundle(t *testing.T, sig []byte, svBytes []byte) return bundlePath } +func makeLocalNewBundle(t *testing.T, sig []byte, digest [32]byte) string { + b, err := bundle.MakeProtobufBundle("hint", []byte{}, nil, []byte{}) + if err != nil { + t.Fatal(err) + } + + b.Content = &protobundle.Bundle_MessageSignature{ + MessageSignature: &protocommon.MessageSignature{ + MessageDigest: &protocommon.HashOutput{ + Algorithm: protocommon.HashAlgorithm_SHA2_256, + Digest: digest[:], + }, + Signature: sig, + }, + } + + contents, err := protojson.Marshal(b) + if err != nil { + t.Fatal(err) + } + + // write bundle to disk + td := t.TempDir() + bundlePath := filepath.Join(td, "bundle.sigstore.json") + if err := os.WriteFile(bundlePath, contents, 0644); err != nil { + t.Fatal(err) + } + return bundlePath +} + func TestVerifyBlobCmdWithBundle(t *testing.T) { keyless := newKeylessStack(t) defer os.RemoveAll(keyless.td) @@ -1574,3 +1632,11 @@ func writeTimestampFile(t *testing.T, td string, ts *bundle.RFC3161Timestamp, na } return path } + +func writeTrustedRootFile(t *testing.T, td, contents string) string { + path := filepath.Join(td, "trusted_root.json") + if err := os.WriteFile(path, []byte(contents), 0644); err != nil { + t.Fatal(err) + } + return path +} diff --git a/cmd/cosign/cli/verify/verify_bundle.go b/cmd/cosign/cli/verify/verify_bundle.go new file mode 100644 index 00000000000..1d5289e22ad --- /dev/null +++ b/cmd/cosign/cli/verify/verify_bundle.go @@ -0,0 +1,163 @@ +// +// Copyright 2024 The Sigstore Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package verify + +import ( + "bytes" + "context" + "fmt" + "time" + + sgbundle "github.com/sigstore/sigstore-go/pkg/bundle" + "github.com/sigstore/sigstore-go/pkg/fulcio/certificate" + "github.com/sigstore/sigstore-go/pkg/root" + "github.com/sigstore/sigstore-go/pkg/verify" + + "github.com/sigstore/cosign/v2/pkg/cosign/pivkey" + sigs "github.com/sigstore/cosign/v2/pkg/signature" +) + +type verifyTrustedMaterial struct { + root.TrustedMaterial + keyTrustedMaterial root.TrustedMaterial +} + +func (v *verifyTrustedMaterial) PublicKeyVerifier(hint string) (root.TimeConstrainedVerifier, error) { + return v.keyTrustedMaterial.PublicKeyVerifier(hint) +} + +func verifyNewBundle(ctx context.Context, bundlePath, trustedRootPath, keyRef, slot, certOIDCIssuer, certOIDCIssuerRegex, certIdentity, certIdentityRegexp, githubWorkflowTrigger, githubWorkflowSHA, githubWorkflowName, githubWorkflowRepository, githubWorkflowRef, artifactRef string, sk, ignoreTlog, useSignedTimestamps, ignoreSCT bool) error { + if certOIDCIssuerRegex != "" { + return fmt.Errorf("--new-bundle-format does not support --certificate-oidc-issuer-regexp") + } + + bundle, err := sgbundle.LoadJSONFromPath(bundlePath) + if err != nil { + return err + } + + var trustedroot *root.TrustedRoot + + if trustedRootPath == "" { + // Assume we're using public good instance; fetch via TUF + trustedroot, err = root.FetchTrustedRoot() + if err != nil { + return err + } + } else { + trustedroot, err = root.NewTrustedRootFromPath(trustedRootPath) + if err != nil { + return err + } + } + + trustedmaterial := &verifyTrustedMaterial{TrustedMaterial: trustedroot} + + // See if we need to wrap trusted root with provided key + if keyRef != "" { + signatureVerifier, err := sigs.PublicKeyFromKeyRef(ctx, keyRef) + if err != nil { + return err + } + + newExpiringKey := root.NewExpiringKey(signatureVerifier, time.Time{}, time.Time{}) + trustedmaterial.keyTrustedMaterial = root.NewTrustedPublicKeyMaterial(func(_ string) (root.TimeConstrainedVerifier, error) { + return newExpiringKey, nil + }) + } else if sk { + s, err := pivkey.GetKeyWithSlot(slot) + if err != nil { + return fmt.Errorf("opening piv token: %w", err) + } + defer s.Close() + signatureVerifier, err := s.Verifier() + if err != nil { + return fmt.Errorf("loading public key from token: %w", err) + } + + newExpiringKey := root.NewExpiringKey(signatureVerifier, time.Time{}, time.Time{}) + trustedmaterial.keyTrustedMaterial = root.NewTrustedPublicKeyMaterial(func(_ string) (root.TimeConstrainedVerifier, error) { + return newExpiringKey, nil + }) + } + + identityPolicies := []verify.PolicyOption{} + + verificationMaterial := bundle.GetVerificationMaterial() + + if verificationMaterial == nil { + return fmt.Errorf("No verification material in bundle") + } + + if verificationMaterial.GetPublicKey() != nil { + identityPolicies = append(identityPolicies, verify.WithKey()) + } else { + sanMatcher, err := verify.NewSANMatcher(certIdentity, certIdentityRegexp) + if err != nil { + return err + } + + extensions := certificate.Extensions{ + Issuer: certOIDCIssuer, + GithubWorkflowTrigger: githubWorkflowTrigger, + GithubWorkflowSHA: githubWorkflowSHA, + GithubWorkflowName: githubWorkflowName, + GithubWorkflowRepository: githubWorkflowRepository, + GithubWorkflowRef: githubWorkflowRef, + } + + certIdentity, err := verify.NewCertificateIdentity(sanMatcher, extensions) + if err != nil { + return err + } + + identityPolicies = append(identityPolicies, verify.WithCertificateIdentity(certIdentity)) + } + + // Make some educated guesses about verification policy + verifierConfig := []verify.VerifierOption{} + + if len(trustedroot.RekorLogs()) > 0 && !ignoreTlog { + verifierConfig = append(verifierConfig, verify.WithTransparencyLog(1), verify.WithObserverTimestamps(1)) + } + + if len(trustedroot.TimestampingAuthorities()) > 0 && useSignedTimestamps { + verifierConfig = append(verifierConfig, verify.WithSignedTimestamps(1)) + } + + if !ignoreSCT { + verifierConfig = append(verifierConfig, verify.WithSignedCertificateTimestamps(1)) + } + + if ignoreTlog && !useSignedTimestamps { + verifierConfig = append(verifierConfig, verify.WithoutAnyObserverTimestampsUnsafe()) + } + + // Perform verification + payload, err := payloadBytes(artifactRef) + if err != nil { + return err + } + buf := bytes.NewBuffer(payload) + + sev, err := verify.NewSignedEntityVerifier(trustedmaterial, verifierConfig...) + if err != nil { + return err + } + + _, err = sev.Verify(bundle, verify.NewPolicy(verify.WithArtifact(buf), identityPolicies...)) + return err +} diff --git a/doc/cosign_verify-blob-attestation.md b/doc/cosign_verify-blob-attestation.md index f9d199ec45d..a7c293359d6 100644 --- a/doc/cosign_verify-blob-attestation.md +++ b/doc/cosign_verify-blob-attestation.md @@ -49,6 +49,7 @@ cosign verify-blob-attestation [flags] --insecure-ignore-tlog ignore transparency log verification, to be used when an artifact signature has not been uploaded to the transparency log. Artifacts cannot be publicly verified when not included in a log --key string path to the public key file, KMS URI or Kubernetes Secret --max-workers int the amount of maximum workers for parallel executions (default 10) + --new-bundle-format output bundle in new format that contains all verification material --offline only allow offline verification --private-infrastructure skip transparency log verification when verifying artifacts in a privately deployed infrastructure --rekor-url string address of rekor STL server (default "https://rekor.sigstore.dev") @@ -58,6 +59,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 + --trusted-root string path to trusted root FILE --type string specify a predicate type (slsaprovenance|slsaprovenance02|slsaprovenance1|link|spdx|spdxjson|cyclonedx|vuln|openvex|custom) or an URI (default "custom") --use-signed-timestamps use signed timestamps if available ``` diff --git a/doc/cosign_verify-blob.md b/doc/cosign_verify-blob.md index f04ec98387d..92655cccbed 100644 --- a/doc/cosign_verify-blob.md +++ b/doc/cosign_verify-blob.md @@ -84,6 +84,7 @@ cosign verify-blob [flags] --insecure-ignore-tlog ignore transparency log verification, to be used when an artifact signature has not been uploaded to the transparency log. Artifacts cannot be publicly verified when not included in a log --key string path to the public key file, KMS URI or Kubernetes Secret --max-workers int the amount of maximum workers for parallel executions (default 10) + --new-bundle-format output bundle in new format that contains all verification material --offline only allow offline verification --private-infrastructure skip transparency log verification when verifying artifacts in a privately deployed infrastructure --rekor-url string address of rekor STL server (default "https://rekor.sigstore.dev") @@ -93,6 +94,7 @@ cosign verify-blob [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 + --trusted-root string path to trusted root FILE --use-signed-timestamps use signed timestamps if available ``` diff --git a/go.mod b/go.mod index 243677bc1bc..b1d59f71b8f 100644 --- a/go.mod +++ b/go.mod @@ -32,9 +32,10 @@ require ( github.com/pkg/errors v0.9.1 github.com/secure-systems-lab/go-securesystemslib v0.8.0 github.com/sigstore/fulcio v1.5.1 - github.com/sigstore/protobuf-specs v0.3.0 + github.com/sigstore/protobuf-specs v0.3.2 github.com/sigstore/rekor v1.3.6 github.com/sigstore/sigstore v1.8.7 + github.com/sigstore/sigstore-go v0.4.1-0.20240717174219-8554eb6de5ac github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.7 github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.7 github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.7 @@ -240,6 +241,7 @@ require ( github.com/tchap/go-patricia/v2 v2.3.1 // indirect github.com/thales-e-security/pool v0.0.2 // indirect github.com/theupdateframework/go-tuf v0.7.0 // indirect + github.com/theupdateframework/go-tuf/v2 v2.0.0-20240701122707-5abb6219c8d9 // indirect github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect github.com/tjfoc/gmsm v1.4.1 // indirect github.com/urfave/negroni v1.0.0 // indirect diff --git a/go.sum b/go.sum index 1962c60ca87..718eec0dd1b 100644 --- a/go.sum +++ b/go.sum @@ -318,6 +318,8 @@ github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7 github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-rod/rod v0.116.1 h1:BDMZY3qm/14SmvHBV7DoFUhXeJ2MbUYgumQ88b+v2WE= github.com/go-rod/rod v0.116.1/go.mod h1:3Ash9fYwznqz9S1uLQgQRStur4fCXjoxxGW+ym6TYjU= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= @@ -432,6 +434,9 @@ github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25L github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-sockaddr v1.0.5 h1:dvk7TIXCZpmfOlM+9mlcrWmWjw/wlKT+VDq2wMvfPJU= github.com/hashicorp/go-sockaddr v1.0.5/go.mod h1:uoUUmtwU7n9Dv3O4SNLeFvg0SxQ3lyjsj6+CCykpaxI= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= github.com/hashicorp/vault/api v1.14.0 h1:Ah3CFLixD5jmjusOgm8grfN9M0d+Y8fVR2SW0K6pJLU= @@ -599,16 +604,20 @@ github.com/secure-systems-lab/go-securesystemslib v0.8.0 h1:mr5An6X45Kb2nddcFlbm github.com/secure-systems-lab/go-securesystemslib v0.8.0/go.mod h1:UH2VZVuJfCYR8WgMlCU1uFsOUU+KeyrTWcSS73NBOzU= github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c= github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI= github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE= github.com/sigstore/fulcio v1.5.1 h1:Iasy1zfNjaq8BV4S8o6pXspLDU28PQC2z07GmOu9zpM= github.com/sigstore/fulcio v1.5.1/go.mod h1:W1A/UHrTopy1IBZPMtHmxg7GPYAu+vt5dRXM3W6yjPo= -github.com/sigstore/protobuf-specs v0.3.0 h1:E49qS++llp4psM+3NNVEb+C4AD422bT9VkOQIPrNLpA= -github.com/sigstore/protobuf-specs v0.3.0/go.mod h1:ynKzXpqr3dUj2Xk9O/5ZUhjnpi0F53DNi5AdH6pS3jc= +github.com/sigstore/protobuf-specs v0.3.2 h1:nCVARCN+fHjlNCk3ThNXwrZRqIommIeNKWwQvORuRQo= +github.com/sigstore/protobuf-specs v0.3.2/go.mod h1:RZ0uOdJR4OB3tLQeAyWoJFbNCBFrPQdcokntde4zRBA= github.com/sigstore/rekor v1.3.6 h1:QvpMMJVWAp69a3CHzdrLelqEqpTM3ByQRt5B5Kspbi8= github.com/sigstore/rekor v1.3.6/go.mod h1:JDTSNNMdQ/PxdsS49DJkJ+pRJCO/83nbR5p3aZQteXc= github.com/sigstore/sigstore v1.8.7 h1:L7/zKauHTg0d0Hukx7qlR4nifh6T6O6UIt9JBwAmTIg= github.com/sigstore/sigstore v1.8.7/go.mod h1:MPiQ/NIV034Fc3Kk2IX9/XmBQdK60wfmpvgK9Z1UjRA= +github.com/sigstore/sigstore-go v0.4.1-0.20240717174219-8554eb6de5ac h1:mmxLGVL45EZKNfB6p0wCPTxv4/ne4U4UbquDwMrQhXk= +github.com/sigstore/sigstore-go v0.4.1-0.20240717174219-8554eb6de5ac/go.mod h1:ZPJJCwEBIl3ofcA/p/EawAA/I0WMU93DWZhHf98wbak= github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.7 h1:SoahswHQm2JhO8h3KTAeX8IZeE7mSR2Lc53ay5choes= github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.7/go.mod h1:TOVOPOqldrrz4dP7x4/0DFQTs9QSXZUoHu21+JHmixA= github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.7 h1:jcdKxc5bvwfL7+ZbeCszaN/qsBd6180fGAHxeX5Ckm0= @@ -669,6 +678,8 @@ github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gt github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU= github.com/theupdateframework/go-tuf v0.7.0 h1:CqbQFrWo1ae3/I0UCblSbczevCCbS31Qvs5LdxRWqRI= github.com/theupdateframework/go-tuf v0.7.0/go.mod h1:uEB7WSY+7ZIugK6R1hiBMBjQftaFzn7ZCDJcp1tCUug= +github.com/theupdateframework/go-tuf/v2 v2.0.0-20240701122707-5abb6219c8d9 h1:AH/4455EGJqYHx6KcrWJ9Bv/h9xae+SP5EGgmmbQBSA= +github.com/theupdateframework/go-tuf/v2 v2.0.0-20240701122707-5abb6219c8d9/go.mod h1:baB22nBHeHBCeuGZcIlctNq4P61PcOdyARlplg5xmLA= github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0= github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs= github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= From cd8d985bfcdc52dcfbfa94883846f6ea946004c8 Mon Sep 17 00:00:00 2001 From: Zach Steindler Date: Tue, 23 Jul 2024 17:21:02 -0400 Subject: [PATCH 2/4] fix error message Signed-off-by: Zach Steindler --- cmd/cosign/cli/verify/verify_bundle.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/cosign/cli/verify/verify_bundle.go b/cmd/cosign/cli/verify/verify_bundle.go index 1d5289e22ad..24372d8df96 100644 --- a/cmd/cosign/cli/verify/verify_bundle.go +++ b/cmd/cosign/cli/verify/verify_bundle.go @@ -99,7 +99,7 @@ func verifyNewBundle(ctx context.Context, bundlePath, trustedRootPath, keyRef, s verificationMaterial := bundle.GetVerificationMaterial() if verificationMaterial == nil { - return fmt.Errorf("No verification material in bundle") + return fmt.Errorf("no verification material in bundle") } if verificationMaterial.GetPublicKey() != nil { From cad0ddef34e686d5cb3e34d72fcf0273a3199360 Mon Sep 17 00:00:00 2001 From: Zach Steindler Date: Thu, 25 Jul 2024 10:26:08 -0400 Subject: [PATCH 3/4] Use sigstore-go v0.5.1 for cert issuer regex support Signed-off-by: Zach Steindler --- cmd/cosign/cli/verify/verify_bundle.go | 12 ++++++------ go.mod | 4 ++-- go.sum | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/cmd/cosign/cli/verify/verify_bundle.go b/cmd/cosign/cli/verify/verify_bundle.go index 24372d8df96..b0e0b30b160 100644 --- a/cmd/cosign/cli/verify/verify_bundle.go +++ b/cmd/cosign/cli/verify/verify_bundle.go @@ -40,10 +40,6 @@ func (v *verifyTrustedMaterial) PublicKeyVerifier(hint string) (root.TimeConstra } func verifyNewBundle(ctx context.Context, bundlePath, trustedRootPath, keyRef, slot, certOIDCIssuer, certOIDCIssuerRegex, certIdentity, certIdentityRegexp, githubWorkflowTrigger, githubWorkflowSHA, githubWorkflowName, githubWorkflowRepository, githubWorkflowRef, artifactRef string, sk, ignoreTlog, useSignedTimestamps, ignoreSCT bool) error { - if certOIDCIssuerRegex != "" { - return fmt.Errorf("--new-bundle-format does not support --certificate-oidc-issuer-regexp") - } - bundle, err := sgbundle.LoadJSONFromPath(bundlePath) if err != nil { return err @@ -110,8 +106,12 @@ func verifyNewBundle(ctx context.Context, bundlePath, trustedRootPath, keyRef, s return err } + issuerMatcher, err := verify.NewIssuerMatcher(certOIDCIssuer, certOIDCIssuerRegex) + if err != nil { + return err + } + extensions := certificate.Extensions{ - Issuer: certOIDCIssuer, GithubWorkflowTrigger: githubWorkflowTrigger, GithubWorkflowSHA: githubWorkflowSHA, GithubWorkflowName: githubWorkflowName, @@ -119,7 +119,7 @@ func verifyNewBundle(ctx context.Context, bundlePath, trustedRootPath, keyRef, s GithubWorkflowRef: githubWorkflowRef, } - certIdentity, err := verify.NewCertificateIdentity(sanMatcher, extensions) + certIdentity, err := verify.NewCertificateIdentity(sanMatcher, issuerMatcher, extensions) if err != nil { return err } diff --git a/go.mod b/go.mod index b1d59f71b8f..0daf8d127c7 100644 --- a/go.mod +++ b/go.mod @@ -35,7 +35,7 @@ require ( github.com/sigstore/protobuf-specs v0.3.2 github.com/sigstore/rekor v1.3.6 github.com/sigstore/sigstore v1.8.7 - github.com/sigstore/sigstore-go v0.4.1-0.20240717174219-8554eb6de5ac + github.com/sigstore/sigstore-go v0.5.1 github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.7 github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.7 github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.7 @@ -241,7 +241,7 @@ require ( github.com/tchap/go-patricia/v2 v2.3.1 // indirect github.com/thales-e-security/pool v0.0.2 // indirect github.com/theupdateframework/go-tuf v0.7.0 // indirect - github.com/theupdateframework/go-tuf/v2 v2.0.0-20240701122707-5abb6219c8d9 // indirect + github.com/theupdateframework/go-tuf/v2 v2.0.0 // indirect github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect github.com/tjfoc/gmsm v1.4.1 // indirect github.com/urfave/negroni v1.0.0 // indirect diff --git a/go.sum b/go.sum index 718eec0dd1b..66a1d3ec914 100644 --- a/go.sum +++ b/go.sum @@ -616,8 +616,8 @@ github.com/sigstore/rekor v1.3.6 h1:QvpMMJVWAp69a3CHzdrLelqEqpTM3ByQRt5B5Kspbi8= github.com/sigstore/rekor v1.3.6/go.mod h1:JDTSNNMdQ/PxdsS49DJkJ+pRJCO/83nbR5p3aZQteXc= github.com/sigstore/sigstore v1.8.7 h1:L7/zKauHTg0d0Hukx7qlR4nifh6T6O6UIt9JBwAmTIg= github.com/sigstore/sigstore v1.8.7/go.mod h1:MPiQ/NIV034Fc3Kk2IX9/XmBQdK60wfmpvgK9Z1UjRA= -github.com/sigstore/sigstore-go v0.4.1-0.20240717174219-8554eb6de5ac h1:mmxLGVL45EZKNfB6p0wCPTxv4/ne4U4UbquDwMrQhXk= -github.com/sigstore/sigstore-go v0.4.1-0.20240717174219-8554eb6de5ac/go.mod h1:ZPJJCwEBIl3ofcA/p/EawAA/I0WMU93DWZhHf98wbak= +github.com/sigstore/sigstore-go v0.5.1 h1:5IhKvtjlQBeLnjKkzMELNG4tIBf+xXQkDzhLV77+/8Y= +github.com/sigstore/sigstore-go v0.5.1/go.mod h1:TuOfV7THHqiDaUHuJ5+QN23RP/YoKmsbwJpY+aaYPN0= github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.7 h1:SoahswHQm2JhO8h3KTAeX8IZeE7mSR2Lc53ay5choes= github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.7/go.mod h1:TOVOPOqldrrz4dP7x4/0DFQTs9QSXZUoHu21+JHmixA= github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.7 h1:jcdKxc5bvwfL7+ZbeCszaN/qsBd6180fGAHxeX5Ckm0= @@ -678,8 +678,8 @@ github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gt github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU= github.com/theupdateframework/go-tuf v0.7.0 h1:CqbQFrWo1ae3/I0UCblSbczevCCbS31Qvs5LdxRWqRI= github.com/theupdateframework/go-tuf v0.7.0/go.mod h1:uEB7WSY+7ZIugK6R1hiBMBjQftaFzn7ZCDJcp1tCUug= -github.com/theupdateframework/go-tuf/v2 v2.0.0-20240701122707-5abb6219c8d9 h1:AH/4455EGJqYHx6KcrWJ9Bv/h9xae+SP5EGgmmbQBSA= -github.com/theupdateframework/go-tuf/v2 v2.0.0-20240701122707-5abb6219c8d9/go.mod h1:baB22nBHeHBCeuGZcIlctNq4P61PcOdyARlplg5xmLA= +github.com/theupdateframework/go-tuf/v2 v2.0.0 h1:rD8d9RotYBprZVgC+9oyTZ5MmawepnTSTqoDuxjWgbs= +github.com/theupdateframework/go-tuf/v2 v2.0.0/go.mod h1:baB22nBHeHBCeuGZcIlctNq4P61PcOdyARlplg5xmLA= github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0= github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs= github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= From c3c07dc7c1cab7297188d5a3dd91349de709095e Mon Sep 17 00:00:00 2001 From: Zach Steindler Date: Fri, 26 Jul 2024 10:36:32 -0400 Subject: [PATCH 4/4] Use more specific `WithIntegratedTimestamps` with tlog verification Signed-off-by: Zach Steindler --- cmd/cosign/cli/verify/verify_bundle.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/cosign/cli/verify/verify_bundle.go b/cmd/cosign/cli/verify/verify_bundle.go index b0e0b30b160..01921be7ffb 100644 --- a/cmd/cosign/cli/verify/verify_bundle.go +++ b/cmd/cosign/cli/verify/verify_bundle.go @@ -131,7 +131,7 @@ func verifyNewBundle(ctx context.Context, bundlePath, trustedRootPath, keyRef, s verifierConfig := []verify.VerifierOption{} if len(trustedroot.RekorLogs()) > 0 && !ignoreTlog { - verifierConfig = append(verifierConfig, verify.WithTransparencyLog(1), verify.WithObserverTimestamps(1)) + verifierConfig = append(verifierConfig, verify.WithTransparencyLog(1), verify.WithIntegratedTimestamps(1)) } if len(trustedroot.TimestampingAuthorities()) > 0 && useSignedTimestamps {