Skip to content

Commit

Permalink
add handling of keyless verification for all verify commands
Browse files Browse the repository at this point in the history
Copy the handling of non-Fulcio keys from the verify
to all other verify commands (verify-attestation,
verify-blob, verify-blob-attestations).

Fix sigstore#3759.

Signed-off-by: Dmitry S. <[email protected]>
  • Loading branch information
dmitris committed Jul 9, 2024
1 parent 811dba8 commit ee2dc8f
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 45 deletions.
18 changes: 15 additions & 3 deletions cmd/cosign/cli/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,14 @@ against the transparency log.`,
CheckClaims: o.CheckClaims,
KeyRef: o.Key,
CertRef: o.CertVerify.Cert,
CertChain: o.CertVerify.CertChain,
CAIntermediates: o.CertVerify.CAIntermediates,
CARoots: o.CertVerify.CARoots,
CertGithubWorkflowTrigger: o.CertVerify.CertGithubWorkflowTrigger,
CertGithubWorkflowSha: o.CertVerify.CertGithubWorkflowSha,
CertGithubWorkflowName: o.CertVerify.CertGithubWorkflowName,
CertGithubWorkflowRepository: o.CertVerify.CertGithubWorkflowRepository,
CertGithubWorkflowRef: o.CertVerify.CertGithubWorkflowRef,
CAIntermediates: o.CertVerify.CAIntermediates,
CARoots: o.CertVerify.CARoots,
CertChain: o.CertVerify.CertChain,
IgnoreSCT: o.CertVerify.IgnoreSCT,
SCTRef: o.CertVerify.SCT,
Sk: o.SecurityKey.Use,
Expand Down Expand Up @@ -223,6 +223,8 @@ against the transparency log.`,
CertVerifyOptions: o.CertVerify,
CertRef: o.CertVerify.Cert,
CertChain: o.CertVerify.CertChain,
CAIntermediates: o.CertVerify.CAIntermediates,
CARoots: o.CertVerify.CARoots,
CertGithubWorkflowTrigger: o.CertVerify.CertGithubWorkflowTrigger,
CertGithubWorkflowSha: o.CertVerify.CertGithubWorkflowSha,
CertGithubWorkflowName: o.CertVerify.CertGithubWorkflowName,
Expand Down Expand Up @@ -281,6 +283,12 @@ The blob may be specified as a path to a file or - for stdin.`,
# Verify a simple blob and message
cosign verify-blob --key cosign.pub (--signature <sig path>|<sig url> msg)
# Verify a signature with certificate and CA certificate chain
cosign verify-blob --certificate cert.pem --certificate-chain certchain.pem --signature $sig <blob>
# Verify a signature with CA roots and optional intermediate certificates
cosign verify-blob --certificate cert.pem --ca-roots caroots.pem [--ca-intermediates caintermediates.pem] --signature $sig <blob>
# Verify a signature from an environment variable
cosign verify-blob --key cosign.pub --signature $sig msg
Expand Down Expand Up @@ -333,6 +341,8 @@ The blob may be specified as a path to a file or - for stdin.`,
CertVerifyOptions: o.CertVerify,
CertRef: o.CertVerify.Cert,
CertChain: o.CertVerify.CertChain,
CARoots: o.CertVerify.CARoots,
CAIntermediates: o.CertVerify.CAIntermediates,
SigRef: o.Signature,
CertGithubWorkflowTrigger: o.CertVerify.CertGithubWorkflowTrigger,
CertGithubWorkflowSHA: o.CertVerify.CertGithubWorkflowSha,
Expand Down Expand Up @@ -402,6 +412,8 @@ The blob may be specified as a path to a file.`,
CertVerifyOptions: o.CertVerify,
CertRef: o.CertVerify.Cert,
CertChain: o.CertVerify.CertChain,
CARoots: o.CertVerify.CARoots,
CAIntermediates: o.CertVerify.CAIntermediates,
CertGithubWorkflowTrigger: o.CertVerify.CertGithubWorkflowTrigger,
CertGithubWorkflowSHA: o.CertVerify.CertGithubWorkflowSha,
CertGithubWorkflowName: o.CertVerify.CertGithubWorkflowName,
Expand Down
9 changes: 6 additions & 3 deletions cmd/cosign/cli/verify/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ func (c *VerifyCommand) Exec(ctx context.Context, images []string) (err error) {
return err
}
}

keyRef := c.KeyRef
certRef := c.CertRef

Expand Down Expand Up @@ -511,15 +512,14 @@ func shouldVerifySCT(ignoreSCT bool, keyRef string, sk bool) bool {
return true
}

// loadCertsKeylessVerification loads certificates for the verification of keyless signatures
// for the verify command.
// loadCertsKeylessVerification loads certificates provided as a certificate chain or CA roots + CA intermediate
// certificate files. If both certChain and caRootsFile are empty strings, the Fulcio roots are loaded.
//
// TODO - mention additionally verify-attestation, verify-blob, verify-blob-attestation
// commands when they are extended to call this function.
//
// The co *cosign.CheckOpts is both input and output parameter - it gets updated
// with the root and intermediate certificates needed for verification.
// If both certChain and caRootsFile are empty strings, the Fulcio roots are loaded.
func loadCertsKeylessVerification(certChainFile string,
caRootsFile string,
caIntermediatesFile string,
Expand All @@ -539,6 +539,7 @@ func loadCertsKeylessVerification(certChainFile string,
co.IntermediateCerts.AddCert(cert)
}
}

case caRootsFile != "":
caRoots, err := loadCertChainFromFileOrURL(caRootsFile)
if err != nil {
Expand All @@ -562,6 +563,7 @@ func loadCertsKeylessVerification(certChainFile string,
}
}
}

default:
// This performs an online fetch of the Fulcio roots from a TUF repository.
// This is needed for verifying keyless certificates (both online and offline).
Expand All @@ -574,5 +576,6 @@ func loadCertsKeylessVerification(certChainFile string,
return fmt.Errorf("getting Fulcio intermediates: %w", err)
}
}

return nil
}
13 changes: 4 additions & 9 deletions cmd/cosign/cli/verify/verify_attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ type VerifyAttestationCommand struct {
CertGithubWorkflowName string
CertGithubWorkflowRepository string
CertGithubWorkflowRef string
CAIntermediates string
CARoots string
CertChain string
IgnoreSCT bool
SCTRef string
Expand Down Expand Up @@ -156,15 +158,8 @@ func (c *VerifyAttestationCommand) Exec(ctx context.Context, images []string) (e
}

if keylessVerification(c.KeyRef, c.Sk) {
// This performs an online fetch of the Fulcio roots. This is needed
// for verifying keyless certificates (both online and offline).
co.RootCerts, err = fulcio.GetRoots()
if err != nil {
return fmt.Errorf("getting Fulcio roots: %w", err)
}
co.IntermediateCerts, err = fulcio.GetIntermediates()
if err != nil {
return fmt.Errorf("getting Fulcio intermediates: %w", err)
if err := loadCertsKeylessVerification(c.CertChain, c.CARoots, c.CAIntermediates, co); err != nil {
return err
}
}

Expand Down
23 changes: 9 additions & 14 deletions cmd/cosign/cli/verify/verify_blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import (
"os"
"path/filepath"

"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"
"github.com/sigstore/cosign/v2/internal/ui"
Expand All @@ -53,6 +52,8 @@ type VerifyBlobCmd struct {
options.KeyOpts
options.CertVerifyOptions
CertRef string
CAIntermediates string
CARoots string
CertChain string
SigRef string
CertGithubWorkflowTrigger string
Expand Down Expand Up @@ -151,19 +152,10 @@ func (c *VerifyBlobCmd) Exec(ctx context.Context, blobRef string) error {
return fmt.Errorf("getting Rekor public keys: %w", err)
}
}

if keylessVerification(c.KeyRef, c.Sk) {
// Use default TUF roots if a cert chain is not provided.
// This performs an online fetch of the Fulcio roots. This is needed
// for verifying keyless certificates (both online and offline).
if c.CertChain == "" {
co.RootCerts, err = fulcio.GetRoots()
if err != nil {
return fmt.Errorf("getting Fulcio roots: %w", err)
}
co.IntermediateCerts, err = fulcio.GetIntermediates()
if err != nil {
return fmt.Errorf("getting Fulcio intermediates: %w", err)
}
if err := loadCertsKeylessVerification(c.CertChain, c.CARoots, c.CAIntermediates, co); err != nil {
return err
}
}

Expand Down Expand Up @@ -249,7 +241,8 @@ func (c *VerifyBlobCmd) Exec(ctx context.Context, blobRef string) error {
}
// Set a cert chain if provided.
var chainPEM []byte
if c.CertChain != "" {
switch {
case c.CertChain != "":
chain, err := loadCertChainFromFileOrURL(c.CertChain)
if err != nil {
return err
Expand All @@ -269,6 +262,8 @@ func (c *VerifyBlobCmd) Exec(ctx context.Context, blobRef string) error {
if err != nil {
return err
}
case c.CARoots != "":
// TODO insert CA roots + intermediates into the signature options for verification
}

// Gather the cert for the signature and add the cert along with the
Expand Down
22 changes: 7 additions & 15 deletions cmd/cosign/cli/verify/verify_blob_attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import (
"path/filepath"

v1 "github.com/google/go-containerregistry/pkg/v1"
"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"
internal "github.com/sigstore/cosign/v2/internal/pkg/cosign"
Expand All @@ -52,8 +51,10 @@ type VerifyBlobAttestationCommand struct {
options.KeyOpts
options.CertVerifyOptions

CertRef string
CertChain string
CertRef string
CertChain string
CAIntermediates string
CARoots string

CertGithubWorkflowTrigger string
CertGithubWorkflowSHA string
Expand Down Expand Up @@ -170,20 +171,11 @@ func (c *VerifyBlobAttestationCommand) Exec(ctx context.Context, artifactPath st
}
}
if keylessVerification(c.KeyRef, c.Sk) {
// Use default TUF roots if a cert chain is not provided.
// This performs an online fetch of the Fulcio roots. This is needed
// for verifying keyless certificates (both online and offline).
if c.CertChain == "" {
co.RootCerts, err = fulcio.GetRoots()
if err != nil {
return fmt.Errorf("getting Fulcio roots: %w", err)
}
co.IntermediateCerts, err = fulcio.GetIntermediates()
if err != nil {
return fmt.Errorf("getting Fulcio intermediates: %w", err)
}
if err := loadCertsKeylessVerification(c.CertChain, c.CARoots, c.CAIntermediates, co); err != nil {
return err
}
}

// Ignore Signed Certificate Timestamp if the flag is set or a key is provided
if shouldVerifySCT(c.IgnoreSCT, c.KeyRef, c.Sk) {
co.CTLogPubKeys, err = cosign.GetCTLogPubs(ctx)
Expand Down
2 changes: 1 addition & 1 deletion cmd/cosign/cli/verify/verify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ func TestVerifyCertMissingIssuer(t *testing.T) {
}
}

func TestLoadCertsKeylessVerification(t *testing.T) {
func TestLoadCerts(t *testing.T) {
certs := getTestCerts(t)
certChainFile := makeCertChainFile(t, certs.RootCertPEM, certs.SubCertPEM, certs.LeafCertPEM)
rootsFile, intermediatesFile := makeRootsIntermediatesFiles(t, certs.RootCertPEM, certs.SubCertPEM)
Expand Down
6 changes: 6 additions & 0 deletions doc/cosign_verify-blob.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions pkg/oci/static/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ type options struct {
RFC3161Timestamp *bundle.RFC3161Timestamp
Cert []byte
Chain []byte
RootCerts []byte
IntermediateCerts [][]byte
Annotations map[string]string
RecordCreationTimestamp bool
}
Expand Down Expand Up @@ -114,6 +116,14 @@ func WithCertChain(cert, chain []byte) Option {
}
}

// Wr sets the CA root and intermediates certificates for this signature.
func WithRootsIntermediates(roots []byte, intermediates [][]byte) Option {
return func(o *options) {
o.RootCerts = roots
o.IntermediateCerts = intermediates
}
}

// WithRecordCreationTimestamp sets the feature flag to honor the creation timestamp to time of running
func WithRecordCreationTimestamp(rct bool) Option {
return func(o *options) {
Expand Down

0 comments on commit ee2dc8f

Please sign in to comment.