Skip to content

Commit fc354ca

Browse files
committed
Add --ca-roots flag for 'cosign verify'
Add --ca-roots command-line flag for 'cosign verify' to enable verifying cosign signatures using PEM bundles of CA roots. Whether to also add --ca-intermediates flag is TBD. Unit tests will be added in the next commit(s). Fixes sigstore#3462. Signed-off-by: Dmitry S <dsavints@gmail.com>
1 parent 6a97d53 commit fc354ca

10 files changed

+84
-49
lines changed

cmd/cosign/cli/options/certificate.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ type CertVerifyOptions struct {
3333
CertGithubWorkflowName string
3434
CertGithubWorkflowRepository string
3535
CertGithubWorkflowRef string
36-
CertBundle string
36+
CARoots string
3737
CertChain string
3838
SCT string
3939
IgnoreSCT bool
@@ -76,18 +76,18 @@ func (o *CertVerifyOptions) AddFlags(cmd *cobra.Command) {
7676
cmd.Flags().StringVar(&o.CertGithubWorkflowRef, "certificate-github-workflow-ref", "",
7777
"contains the ref claim from the GitHub OIDC Identity token that contains the git ref that the workflow run was based upon.")
7878
// -- Cert extensions end --
79-
cmd.Flags().StringVar(&o.CertBundle, "certificate-bundle", "",
79+
cmd.Flags().StringVar(&o.CARoots, "ca-roots", "",
8080
"path to a bundle file of CA certificates in PEM format which will be needed "+
8181
"when building the certificate chains for the signing certificate. Conflicts with --certificate-chain.")
82-
_ = cmd.Flags().SetAnnotation("certificate-bundle", cobra.BashCompFilenameExt, []string{"cert"})
82+
_ = cmd.Flags().SetAnnotation("ca-roots", cobra.BashCompFilenameExt, []string{"cert"})
8383

8484
cmd.Flags().StringVar(&o.CertChain, "certificate-chain", "",
8585
"path to a list of CA certificates in PEM format which will be needed "+
8686
"when building the certificate chain for the signing certificate. "+
8787
"Must start with the parent intermediate CA certificate of the "+
88-
"signing certificate and end with the root certificate. Conflicts with --certificate-bundle.")
88+
"signing certificate and end with the root certificate. Conflicts with --ca-roots.")
8989
_ = cmd.Flags().SetAnnotation("certificate-chain", cobra.BashCompFilenameExt, []string{"cert"})
90-
cmd.MarkFlagsMutuallyExclusive("certificate-bundle", "certificate-chain")
90+
cmd.MarkFlagsMutuallyExclusive("ca-roots", "certificate-chain")
9191

9292
cmd.Flags().StringVar(&o.SCT, "sct", "",
9393
"path to a detached Signed Certificate Timestamp, formatted as a RFC6962 AddChainResponse struct. "+

cmd/cosign/cli/verify.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ against the transparency log.`,
115115
CertGithubWorkflowName: o.CertVerify.CertGithubWorkflowName,
116116
CertGithubWorkflowRepository: o.CertVerify.CertGithubWorkflowRepository,
117117
CertGithubWorkflowRef: o.CertVerify.CertGithubWorkflowRef,
118-
CertBundle: o.CertVerify.CertBundle,
118+
CARoots: o.CertVerify.CARoots,
119119
CertChain: o.CertVerify.CertChain,
120120
IgnoreSCT: o.CertVerify.IgnoreSCT,
121121
SCTRef: o.CertVerify.SCT,

cmd/cosign/cli/verify/verify.go

+56-31
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ type VerifyCommand struct {
5959
CertGithubWorkflowName string
6060
CertGithubWorkflowRepository string
6161
CertGithubWorkflowRef string
62-
CertBundle string
62+
CARoots string
6363
CertChain string
6464
CertOidcProvider string
6565
IgnoreSCT bool
@@ -174,29 +174,47 @@ func (c *VerifyCommand) Exec(ctx context.Context, images []string) (err error) {
174174
}
175175
}
176176
if keylessVerification(c.KeyRef, c.Sk) {
177-
if c.CertChain != "" {
178-
chain, err := loadCertChainFromFileOrURL(c.CertChain)
179-
if err != nil {
180-
return err
181-
}
182-
co.RootCerts = x509.NewCertPool()
183-
co.RootCerts.AddCert(chain[len(chain)-1])
184-
if len(chain) > 1 {
185-
co.IntermediateCerts = x509.NewCertPool()
186-
for _, cert := range chain[:len(chain)-1] {
187-
co.IntermediateCerts.AddCert(cert)
177+
switch {
178+
case c.CertChain != "":
179+
{
180+
chain, err := loadCertChainFromFileOrURL(c.CertChain)
181+
if err != nil {
182+
return err
183+
}
184+
co.RootCerts = x509.NewCertPool()
185+
co.RootCerts.AddCert(chain[len(chain)-1])
186+
if len(chain) > 1 {
187+
co.IntermediateCerts = x509.NewCertPool()
188+
for _, cert := range chain[:len(chain)-1] {
189+
co.IntermediateCerts.AddCert(cert)
190+
}
188191
}
189192
}
190-
} else {
191-
// This performs an online fetch of the Fulcio roots. This is needed
192-
// for verifying keyless certificates (both online and offline).
193-
co.RootCerts, err = fulcio.GetRoots()
194-
if err != nil {
195-
return fmt.Errorf("getting Fulcio roots: %w", err)
193+
case c.CARoots != "":
194+
{
195+
caRoots, err := loadCertChainFromFileOrURL(c.CARoots)
196+
if err != nil {
197+
return err
198+
}
199+
co.RootCerts = x509.NewCertPool()
200+
if len(caRoots) > 0 {
201+
for _, cert := range caRoots {
202+
co.RootCerts.AddCert(cert)
203+
}
204+
}
196205
}
197-
co.IntermediateCerts, err = fulcio.GetIntermediates()
198-
if err != nil {
199-
return fmt.Errorf("getting Fulcio intermediates: %w", err)
206+
default:
207+
{
208+
// This performs an online fetch of the Fulcio roots. This is needed
209+
// for verifying keyless certificates (both online and offline).
210+
co.RootCerts, err = fulcio.GetRoots()
211+
if err != nil {
212+
return fmt.Errorf("getting Fulcio roots: %w", err)
213+
}
214+
co.IntermediateCerts, err = fulcio.GetIntermediates()
215+
if err != nil {
216+
return fmt.Errorf("getting Fulcio intermediates: %w", err)
217+
}
200218
}
201219
}
202220
}
@@ -238,8 +256,8 @@ func (c *VerifyCommand) Exec(ctx context.Context, images []string) (err error) {
238256
if err != nil {
239257
return err
240258
}
241-
if c.CertChain == "" {
242-
// If no certChain is passed, the Fulcio root certificate will be used
259+
if c.CertChain == "" && c.CARoots == "" {
260+
// If no certChain and no CARoots are passed, the Fulcio root certificate will be used
243261
co.RootCerts, err = fulcio.GetRoots()
244262
if err != nil {
245263
return fmt.Errorf("getting Fulcio roots: %w", err)
@@ -253,14 +271,21 @@ func (c *VerifyCommand) Exec(ctx context.Context, images []string) (err error) {
253271
return err
254272
}
255273
} else {
256-
// Verify certificate with chain
257-
chain, err := loadCertChainFromFileOrURL(c.CertChain)
258-
if err != nil {
259-
return err
260-
}
261-
pubKey, err = cosign.ValidateAndUnpackCertWithChain(cert, chain, co)
262-
if err != nil {
263-
return err
274+
if c.CARoots == "" {
275+
// Verify certificate with chain
276+
chain, err := loadCertChainFromFileOrURL(c.CertChain)
277+
if err != nil {
278+
return err
279+
}
280+
pubKey, err = cosign.ValidateAndUnpackCertWithChain(cert, chain, co)
281+
if err != nil {
282+
return err
283+
}
284+
} else {
285+
pubKey, err = cosign.ValidateAndUnpackCertWithCertPools(cert, co)
286+
if err != nil {
287+
return err
288+
}
264289
}
265290
}
266291
if c.SCTRef != "" {

doc/cosign_dockerfile_verify.md

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

doc/cosign_manifest_verify.md

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

doc/cosign_verify-attestation.md

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

doc/cosign_verify-blob-attestation.md

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

doc/cosign_verify-blob.md

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)