From bd80cf4fd2c2a6cef329ec502365c6ef5daa231b Mon Sep 17 00:00:00 2001 From: Dmitry S Date: Tue, 2 Jul 2024 20:12:29 +0200 Subject: [PATCH] add handling of keyless verification for all verify commands Copy the handling of non-Fulcio keys from the verify to all other verify commands (verify-attestation, verify-blob, verify-blob-attestations). Fix #3759. Signed-off-by: Dmitry S --- cmd/cosign/cli/verify.go | 2 + cmd/cosign/cli/verify/verify_attestation.go | 60 ++++++++++++++++--- cmd/cosign/cli/verify/verify_blob.go | 44 ++++++++++++-- .../cli/verify/verify_blob_attestation.go | 44 ++++++++++++-- 4 files changed, 133 insertions(+), 17 deletions(-) diff --git a/cmd/cosign/cli/verify.go b/cmd/cosign/cli/verify.go index a2540923082f..50b81a4176a5 100644 --- a/cmd/cosign/cli/verify.go +++ b/cmd/cosign/cli/verify.go @@ -228,6 +228,8 @@ against the transparency log.`, CertGithubWorkflowName: o.CertVerify.CertGithubWorkflowName, CertGithubWorkflowRepository: o.CertVerify.CertGithubWorkflowRepository, CertGithubWorkflowRef: o.CertVerify.CertGithubWorkflowRef, + CAIntermediates: o.CertVerify.CAIntermediates, + CARoots: o.CertVerify.CARoots, IgnoreSCT: o.CertVerify.IgnoreSCT, SCTRef: o.CertVerify.SCT, KeyRef: o.Key, diff --git a/cmd/cosign/cli/verify/verify_attestation.go b/cmd/cosign/cli/verify/verify_attestation.go index 09fcc7185169..2a6909490847 100644 --- a/cmd/cosign/cli/verify/verify_attestation.go +++ b/cmd/cosign/cli/verify/verify_attestation.go @@ -17,6 +17,7 @@ package verify import ( "context" + "crypto/x509" "errors" "flag" "fmt" @@ -52,6 +53,8 @@ type VerifyAttestationCommand struct { CertGithubWorkflowName string CertGithubWorkflowRepository string CertGithubWorkflowRef string + CAIntermediates string + CARoots string CertChain string IgnoreSCT bool SCTRef string @@ -156,15 +159,54 @@ 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) + switch { + case c.CertChain != "": + chain, err := loadCertChainFromFileOrURL(c.CertChain) + if err != nil { + return err + } + co.RootCerts = x509.NewCertPool() + co.RootCerts.AddCert(chain[len(chain)-1]) + if len(chain) > 1 { + co.IntermediateCerts = x509.NewCertPool() + for _, cert := range chain[:len(chain)-1] { + co.IntermediateCerts.AddCert(cert) + } + } + case c.CARoots != "": + caRoots, err := loadCertChainFromFileOrURL(c.CARoots) + if err != nil { + return err + } + co.RootCerts = x509.NewCertPool() + if len(caRoots) > 0 { + for _, cert := range caRoots { + co.RootCerts.AddCert(cert) + } + } + if c.CAIntermediates != "" { + caIntermediates, err := loadCertChainFromFileOrURL(c.CAIntermediates) + if err != nil { + return err + } + if len(caIntermediates) > 0 { + co.IntermediateCerts = x509.NewCertPool() + for _, cert := range caIntermediates { + co.IntermediateCerts.AddCert(cert) + } + } + } + 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). + 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) + } } } diff --git a/cmd/cosign/cli/verify/verify_blob.go b/cmd/cosign/cli/verify/verify_blob.go index c58146ca0d15..1ce148bda1b7 100644 --- a/cmd/cosign/cli/verify/verify_blob.go +++ b/cmd/cosign/cli/verify/verify_blob.go @@ -152,10 +152,46 @@ func (c *VerifyBlobCmd) Exec(ctx context.Context, blobRef string) error { } } 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 == "" { + switch { + case c.CertChain != "": + chain, err := loadCertChainFromFileOrURL(c.CertChain) + if err != nil { + return err + } + co.RootCerts = x509.NewCertPool() + co.RootCerts.AddCert(chain[len(chain)-1]) + if len(chain) > 1 { + co.IntermediateCerts = x509.NewCertPool() + for _, cert := range chain[:len(chain)-1] { + co.IntermediateCerts.AddCert(cert) + } + } + case c.CARoots != "": + caRoots, err := loadCertChainFromFileOrURL(c.CARoots) + if err != nil { + return err + } + co.RootCerts = x509.NewCertPool() + if len(caRoots) > 0 { + for _, cert := range caRoots { + co.RootCerts.AddCert(cert) + } + } + if c.CAIntermediates != "" { + caIntermediates, err := loadCertChainFromFileOrURL(c.CAIntermediates) + if err != nil { + return err + } + if len(caIntermediates) > 0 { + co.IntermediateCerts = x509.NewCertPool() + for _, cert := range caIntermediates { + co.IntermediateCerts.AddCert(cert) + } + } + } + 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). co.RootCerts, err = fulcio.GetRoots() if err != nil { return fmt.Errorf("getting Fulcio roots: %w", err) diff --git a/cmd/cosign/cli/verify/verify_blob_attestation.go b/cmd/cosign/cli/verify/verify_blob_attestation.go index 4c29501ce098..30f9ddb3cd20 100644 --- a/cmd/cosign/cli/verify/verify_blob_attestation.go +++ b/cmd/cosign/cli/verify/verify_blob_attestation.go @@ -170,10 +170,46 @@ 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 == "" { + switch { + case c.CertChain != "": + chain, err := loadCertChainFromFileOrURL(c.CertChain) + if err != nil { + return err + } + co.RootCerts = x509.NewCertPool() + co.RootCerts.AddCert(chain[len(chain)-1]) + if len(chain) > 1 { + co.IntermediateCerts = x509.NewCertPool() + for _, cert := range chain[:len(chain)-1] { + co.IntermediateCerts.AddCert(cert) + } + } + case c.CARoots != "": + caRoots, err := loadCertChainFromFileOrURL(c.CARoots) + if err != nil { + return err + } + co.RootCerts = x509.NewCertPool() + if len(caRoots) > 0 { + for _, cert := range caRoots { + co.RootCerts.AddCert(cert) + } + } + if c.CAIntermediates != "" { + caIntermediates, err := loadCertChainFromFileOrURL(c.CAIntermediates) + if err != nil { + return err + } + if len(caIntermediates) > 0 { + co.IntermediateCerts = x509.NewCertPool() + for _, cert := range caIntermediates { + co.IntermediateCerts.AddCert(cert) + } + } + } + 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). co.RootCerts, err = fulcio.GetRoots() if err != nil { return fmt.Errorf("getting Fulcio roots: %w", err)