Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support keyless verification for verify-blob-attestation #2525

Merged
merged 2 commits into from
Jan 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions cmd/cosign/cli/options/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ type VerifyBlobOptions struct {
SecurityKey SecurityKeyOptions
CertVerify CertVerifyOptions
Rekor RekorOptions
Registry RegistryOptions
CommonVerifyOptions CommonVerifyOptions

RFC3161TimestampPath string
Expand All @@ -154,7 +153,6 @@ func (o *VerifyBlobOptions) AddFlags(cmd *cobra.Command) {
o.SecurityKey.AddFlags(cmd)
o.Rekor.AddFlags(cmd)
o.CertVerify.AddFlags(cmd)
o.Registry.AddFlags(cmd)
o.CommonVerifyOptions.AddFlags(cmd)

cmd.Flags().StringVar(&o.Key, "key", "",
Expand Down Expand Up @@ -190,18 +188,41 @@ func (o *VerifyDockerfileOptions) AddFlags(cmd *cobra.Command) {
type VerifyBlobAttestationOptions struct {
Key string
SignaturePath string
BundlePath string

PredicateOptions
CheckClaims bool

SecurityKey SecurityKeyOptions
CertVerify CertVerifyOptions
Rekor RekorOptions
CommonVerifyOptions CommonVerifyOptions

RFC3161TimestampPath string
}

var _ Interface = (*VerifyBlobOptions)(nil)

// AddFlags implements Interface
func (o *VerifyBlobAttestationOptions) AddFlags(cmd *cobra.Command) {
o.PredicateOptions.AddFlags(cmd)
o.SecurityKey.AddFlags(cmd)
o.Rekor.AddFlags(cmd)
o.CertVerify.AddFlags(cmd)
o.CommonVerifyOptions.AddFlags(cmd)

cmd.Flags().StringVar(&o.Key, "key", "",
"path to the public key file, KMS URI or Kubernetes Secret")

cmd.Flags().StringVar(&o.SignaturePath, "signature", "",
"path to base64-encoded signature over attestation in DSSE format")

cmd.Flags().StringVar(&o.BundlePath, "bundle", "",
"path to bundle FILE")

cmd.Flags().BoolVar(&o.CheckClaims, "check-claims", true,
"whether to check the claims found")

cmd.Flags().StringVar(&o.RFC3161TimestampPath, "rfc3161-timestamp", "",
asraa marked this conversation as resolved.
Show resolved Hide resolved
"path to RFC3161 timestamp FILE")
}
28 changes: 25 additions & 3 deletions cmd/cosign/cli/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -329,10 +329,32 @@ The blob may be specified as a path to a file.`,
Args: cobra.ExactArgs(1),
PersistentPreRun: options.BindViper,
RunE: func(cmd *cobra.Command, args []string) error {
ko := options.KeyOpts{
KeyRef: o.Key,
Sk: o.SecurityKey.Use,
Slot: o.SecurityKey.Slot,
RekorURL: o.Rekor.URL,
BundlePath: o.BundlePath,
RFC3161TimestampPath: o.RFC3161TimestampPath,
TSACertChainPath: o.CommonVerifyOptions.TSACertChainPath,
}
v := verify.VerifyBlobAttestationCommand{
KeyRef: o.Key,
PredicateType: o.PredicateOptions.Type,
SignaturePath: o.SignaturePath,
KeyOpts: ko,
PredicateType: o.PredicateOptions.Type,
CheckClaims: o.CheckClaims,
SignaturePath: o.SignaturePath,
CertVerifyOptions: o.CertVerify,
CertRef: o.CertVerify.Cert,
CertChain: o.CertVerify.CertChain,
CertGithubWorkflowTrigger: o.CertVerify.CertGithubWorkflowTrigger,
CertGithubWorkflowSHA: o.CertVerify.CertGithubWorkflowSha,
CertGithubWorkflowName: o.CertVerify.CertGithubWorkflowName,
CertGithubWorkflowRepository: o.CertVerify.CertGithubWorkflowRepository,
CertGithubWorkflowRef: o.CertVerify.CertGithubWorkflowRef,
IgnoreSCT: o.CertVerify.IgnoreSCT,
SCTRef: o.CertVerify.SCT,
Offline: o.CommonVerifyOptions.Offline,
SkipTlogVerify: o.CommonVerifyOptions.SkipTlogVerify,
}
if len(args) != 1 {
return fmt.Errorf("no path to blob passed in, run `cosign verify-blob-attestation -h` for more help")
Expand Down
45 changes: 6 additions & 39 deletions cmd/cosign/cli/verify/verify_blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import (
"os"
"path/filepath"

ssldsse "github.com/secure-systems-lab/go-securesystemslib/dsse"
"github.com/sigstore/cosign/v2/cmd/cosign/cli/fulcio"
"github.com/sigstore/cosign/v2/cmd/cosign/cli/options"
"github.com/sigstore/cosign/v2/cmd/cosign/cli/rekor"
Expand All @@ -40,7 +39,6 @@ import (
"github.com/sigstore/cosign/v2/pkg/oci/static"
sigs "github.com/sigstore/cosign/v2/pkg/signature"

ctypes "github.com/sigstore/cosign/v2/pkg/types"
"github.com/sigstore/sigstore/pkg/cryptoutils"
)

Expand Down Expand Up @@ -288,30 +286,12 @@ func (c *VerifyBlobCmd) Exec(ctx context.Context, blobRef string) error {
}
}

// Use the DSSE verifier if the payload is a DSSE with the In-Toto format.
// TODO: This verifier only supports verification of a single signer/signature on
// the envelope. Either have the verifier validate that only one signature exists,
// or use a multi-signature verifier.
if isIntotoDSSE(blobBytes) {
// co.SigVerifier = dsse.WrapVerifier(co.SigVerifier)
signature, err := static.NewAttestation(blobBytes, opts...)
if err != nil {
return err
}
// We have no artifact the attestation is tied to, so we can't do any claim
// verification.
// TODO: Add an option to support this to populate the v1.Hash for a claim.
if _, err = cosign.VerifyBlobAttestation(ctx, signature, co); err != nil {
return err
}
} else {
signature, err := static.NewSignature(blobBytes, sig, opts...)
if err != nil {
return err
}
if _, err = cosign.VerifyBlobSignature(ctx, signature, co); err != nil {
return err
}
signature, err := static.NewSignature(blobBytes, sig, opts...)
if err != nil {
return err
}
if _, err = cosign.VerifyBlobSignature(ctx, signature, co); err != nil {
return err
}

fmt.Fprintln(os.Stderr, "Verified OK")
Expand Down Expand Up @@ -361,16 +341,3 @@ func payloadBytes(blobRef string) ([]byte, error) {
}
return blobBytes, nil
}

// isIntotoDSSE checks whether a payload is a Dead Simple Signing Envelope with the In-Toto format.
func isIntotoDSSE(blobBytes []byte) bool {
DSSEenvelope := ssldsse.Envelope{}
if err := json.Unmarshal(blobBytes, &DSSEenvelope); err != nil {
return false
}
if DSSEenvelope.PayloadType != ctypes.IntotoPayloadType {
return false
}

return true
}
Loading