diff --git a/.gitignore b/.gitignore index 5ef31f9f5d5..dc48d1d5b2b 100644 --- a/.gitignore +++ b/.gitignore @@ -32,4 +32,8 @@ policyControllerImagerefs sgetImagerefs policyImagerefs +bundle +signature +certificate + **verify-experimental* diff --git a/cmd/cosign/cli/options/signblob.go b/cmd/cosign/cli/options/signblob.go index 3d458bc4852..1385b9ac26d 100644 --- a/cmd/cosign/cli/options/signblob.go +++ b/cmd/cosign/cli/options/signblob.go @@ -34,6 +34,7 @@ type SignBlobOptions struct { Registry RegistryOptions BundlePath string SkipConfirmation bool + TlogUpload bool } var _ Interface = (*SignBlobOptions)(nil) @@ -70,4 +71,7 @@ func (o *SignBlobOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().BoolVarP(&o.SkipConfirmation, "yes", "y", false, "skip confirmation prompts for non-destructive operations") + + cmd.Flags().BoolVar(&o.TlogUpload, "tlog-upload", false, + "whether or not to upload to the tlog") } diff --git a/cmd/cosign/cli/sign/sign.go b/cmd/cosign/cli/sign/sign.go index 3400d72911a..79eb2fbed8c 100644 --- a/cmd/cosign/cli/sign/sign.go +++ b/cmd/cosign/cli/sign/sign.go @@ -76,6 +76,11 @@ func ShouldUploadToTlog(ctx context.Context, ko options.KeyOpts, ref name.Refere return true } + // We don't need to validate the ref, just return true + if ref == nil { + return true + } + // Check if the image is public (no auth in Get) if _, err := remote.Get(ref, remote.WithContext(ctx)); err != nil { fmt.Fprintf(os.Stderr, "%q appears to be a private repository, please confirm uploading to the transparency log at %q [Y/N]: ", ref.Context().String(), ko.RekorURL) diff --git a/cmd/cosign/cli/sign/sign_blob.go b/cmd/cosign/cli/sign/sign_blob.go index 446959af3d2..aaf5d14b264 100644 --- a/cmd/cosign/cli/sign/sign_blob.go +++ b/cmd/cosign/cli/sign/sign_blob.go @@ -34,7 +34,7 @@ import ( ) // nolint -func SignBlobCmd(ro *options.RootOptions, ko options.KeyOpts, regOpts options.RegistryOptions, payloadPath string, b64 bool, outputSignature string, outputCertificate string) ([]byte, error) { +func SignBlobCmd(ro *options.RootOptions, ko options.KeyOpts, regOpts options.RegistryOptions, payloadPath string, b64 bool, outputSignature string, outputCertificate string, tlogUpload bool) ([]byte, error) { var payload []byte var err error var rekorBytes []byte @@ -65,7 +65,7 @@ func SignBlobCmd(ro *options.RootOptions, ko options.KeyOpts, regOpts options.Re signedPayload := cosign.LocalSignedPayload{} - if options.EnableExperimental() { + if ShouldUploadToTlog(ctx, ko, nil, ko.SkipConfirmation, tlogUpload) { rekorBytes, err = sv.Bytes(ctx) if err != nil { return nil, err diff --git a/cmd/cosign/cli/signblob.go b/cmd/cosign/cli/signblob.go index 816062fa440..fe45d2f3503 100644 --- a/cmd/cosign/cli/signblob.go +++ b/cmd/cosign/cli/signblob.go @@ -36,7 +36,7 @@ func SignBlob() *cobra.Command { Example: ` cosign sign-blob --key | # sign a blob with Google sign-in (experimental) - COSIGN_EXPERIMENTAL=1 cosign --timeout 90s sign-blob + cosign sign-blob --output-signature --output-certificate # sign a blob with a local key pair file cosign sign-blob --key cosign.key @@ -55,11 +55,8 @@ func SignBlob() *cobra.Command { Args: cobra.MinimumNArgs(1), PersistentPreRun: options.BindViper, PreRunE: func(cmd *cobra.Command, args []string) error { - // A key file is required unless we're in experimental mode! - if !options.EnableExperimental() { - if !options.OneOf(o.Key, o.SecurityKey.Use) { - return &options.KeyParseError{} - } + if options.NOf(o.Key, o.SecurityKey.Use) > 1 { + return &options.KeyParseError{} } return nil }, @@ -91,7 +88,7 @@ func SignBlob() *cobra.Command { fmt.Fprintln(os.Stderr, "WARNING: the '--output' flag is deprecated and will be removed in the future. Use '--output-signature'") o.OutputSignature = o.Output } - if _, err := sign.SignBlobCmd(ro, ko, o.Registry, blob, o.Base64Output, o.OutputSignature, o.OutputCertificate); err != nil { + if _, err := sign.SignBlobCmd(ro, ko, o.Registry, blob, o.Base64Output, o.OutputSignature, o.OutputCertificate, o.TlogUpload); err != nil { return fmt.Errorf("signing %s: %w", blob, err) } } diff --git a/cmd/cosign/cli/verify.go b/cmd/cosign/cli/verify.go index 4999d7fb54e..d41753de4a3 100644 --- a/cmd/cosign/cli/verify.go +++ b/cmd/cosign/cli/verify.go @@ -264,7 +264,7 @@ The blob may be specified as a path to a file or - for stdin.`, cosign verify-blob --key gitlab://[PROJECT_ID] --signature $sig # Verify a signature against a certificate - COSIGN_EXPERIMENTAL=1 cosign verify-blob --certificate --signature $sig + cosign verify-blob --certificate --signature $sig `, Args: cobra.ExactArgs(1), diff --git a/cmd/cosign/cli/verify/verify.go b/cmd/cosign/cli/verify/verify.go index 5135edfb6f1..8571c3c409b 100644 --- a/cmd/cosign/cli/verify/verify.go +++ b/cmd/cosign/cli/verify/verify.go @@ -118,7 +118,7 @@ func (c *VerifyCommand) Exec(ctx context.Context, images []string) (err error) { co.ClaimVerifier = cosign.SimpleClaimVerifier } - if c.keylessVerification() { + if keylessVerification(c.KeyRef, c.Sk) { if c.RekorURL != "" { rekorClient, err := rekor.NewClient(c.RekorURL) if err != nil { @@ -408,11 +408,11 @@ func loadCertChainFromFileOrURL(path string) ([]*x509.Certificate, error) { return certs, nil } -func (c *VerifyCommand) keylessVerification() bool { - if c.KeyRef != "" { +func keylessVerification(keyRef string, sk bool) bool { + if keyRef != "" { return false } - if c.Sk { + if sk { return false } return true diff --git a/cmd/cosign/cli/verify/verify_blob.go b/cmd/cosign/cli/verify/verify_blob.go index e5745c5f464..4284aeaf983 100644 --- a/cmd/cosign/cli/verify/verify_blob.go +++ b/cmd/cosign/cli/verify/verify_blob.go @@ -91,8 +91,8 @@ func (c *VerifyBlobCmd) Exec(ctx context.Context, blobRef string) error { var bundle *bundle.RekorBundle // Require a certificate/key OR a local bundle file that has the cert. - if !options.OneOf(c.KeyRef, c.Sk, c.CertRef) && c.BundlePath == "" { - return &options.PubKeyParseError{} + if options.NOf(c.KeyRef, c.Sk) > 1 { + return &options.KeyParseError{} } sig, err := signatures(c.SigRef, c.BundlePath) @@ -117,7 +117,7 @@ func (c *VerifyBlobCmd) Exec(ctx context.Context, blobRef string) error { IgnoreSCT: c.IgnoreSCT, Offline: c.Offline, } - if options.EnableExperimental() { + if keylessVerification(c.KeyRef, c.Sk) { if c.RekorURL != "" { rekorClient, err := rekor.NewClient(c.RekorURL) if err != nil { @@ -125,8 +125,6 @@ func (c *VerifyBlobCmd) Exec(ctx context.Context, blobRef string) error { } co.RekorClient = rekorClient } - } - if options.EnableExperimental() { co.RootCerts, err = fulcio.GetRoots() if err != nil { return fmt.Errorf("getting Fulcio roots: %w", err) @@ -242,6 +240,8 @@ func (c *VerifyBlobCmd) Exec(ctx context.Context, blobRef string) error { return fmt.Errorf("loading verifier from bundle: %w", err) } bundle = b.Bundle + default: + return fmt.Errorf("please provide a cert to verify against via --certificate or a bundle via --bundle") } // Performs all blob verification. diff --git a/doc/cosign_sign-blob.md b/doc/cosign_sign-blob.md index 855fa824c9a..fb7065f8d87 100644 --- a/doc/cosign_sign-blob.md +++ b/doc/cosign_sign-blob.md @@ -12,7 +12,7 @@ cosign sign-blob [flags] cosign sign-blob --key | # sign a blob with Google sign-in (experimental) - COSIGN_EXPERIMENTAL=1 cosign --timeout 90s sign-blob + cosign sign-blob --output-signature --output-certificate # sign a blob with a local key pair file cosign sign-blob --key cosign.key @@ -56,6 +56,7 @@ cosign sign-blob [flags] --rekor-url string [EXPERIMENTAL] address of rekor STL server (default "https://rekor.sigstore.dev") --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) + --tlog-upload whether or not to upload to the tlog -y, --yes skip confirmation prompts for non-destructive operations ``` diff --git a/doc/cosign_verify-blob.md b/doc/cosign_verify-blob.md index a96feb58c1f..6a3bb23712a 100644 --- a/doc/cosign_verify-blob.md +++ b/doc/cosign_verify-blob.md @@ -51,7 +51,7 @@ cosign verify-blob [flags] cosign verify-blob --key gitlab://[PROJECT_ID] --signature $sig # Verify a signature against a certificate - COSIGN_EXPERIMENTAL=1 cosign verify-blob --certificate --signature $sig + cosign verify-blob --certificate --signature $sig ``` diff --git a/test/e2e_test.go b/test/e2e_test.go index 24d5c886841..1eccfcd10ed 100644 --- a/test/e2e_test.go +++ b/test/e2e_test.go @@ -693,7 +693,7 @@ func TestSignBlob(t *testing.T) { KeyRef: privKeyPath1, PassFunc: passFunc, } - sig, err := sign.SignBlobCmd(ro, ko, options.RegistryOptions{}, bp, true, "", "") + sig, err := sign.SignBlobCmd(ro, ko, options.RegistryOptions{}, bp, true, "", "", false) if err != nil { t.Fatal(err) } @@ -738,7 +738,7 @@ func TestSignBlobBundle(t *testing.T) { BundlePath: bundlePath, RekorURL: rekorURL, } - if _, err := sign.SignBlobCmd(ro, ko, options.RegistryOptions{}, bp, true, "", ""); err != nil { + if _, err := sign.SignBlobCmd(ro, ko, options.RegistryOptions{}, bp, true, "", "", false); err != nil { t.Fatal(err) } // Now verify should work @@ -746,7 +746,7 @@ func TestSignBlobBundle(t *testing.T) { // Now we turn on the tlog and sign again defer setenv(t, env.VariableExperimental.String(), "1")() - if _, err := sign.SignBlobCmd(ro, ko, options.RegistryOptions{}, bp, true, "", ""); err != nil { + if _, err := sign.SignBlobCmd(ro, ko, options.RegistryOptions{}, bp, true, "", "", false); err != nil { t.Fatal(err) }