Skip to content

Commit 3943fef

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 #3462. Signed-off-by: Dmitry S <[email protected]>
1 parent bec7b4c commit 3943fef

File tree

10 files changed

+83
-48
lines changed

10 files changed

+83
-48
lines changed

cmd/cosign/cli/options/certificate.go

Lines changed: 4 additions & 4 deletions
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,7 +76,7 @@ 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.")
8282
_ = cmd.Flags().SetAnnotation("certificate-bundle", cobra.BashCompFilenameExt, []string{"cert"})
@@ -85,9 +85,9 @@ func (o *CertVerifyOptions) AddFlags(cmd *cobra.Command) {
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 56 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ type VerifyCommand struct {
6060
CertGithubWorkflowName string
6161
CertGithubWorkflowRepository string
6262
CertGithubWorkflowRef string
63-
CertBundle string
63+
CARoots string
6464
CertChain string
6565
CertOidcProvider string
6666
IgnoreSCT bool
@@ -178,29 +178,47 @@ func (c *VerifyCommand) Exec(ctx context.Context, images []string) (err error) {
178178
}
179179
}
180180
if keylessVerification(c.KeyRef, c.Sk) {
181-
if c.CertChain != "" {
182-
chain, err := loadCertChainFromFileOrURL(c.CertChain)
183-
if err != nil {
184-
return err
185-
}
186-
co.RootCerts = x509.NewCertPool()
187-
co.RootCerts.AddCert(chain[len(chain)-1])
188-
if len(chain) > 1 {
189-
co.IntermediateCerts = x509.NewCertPool()
190-
for _, cert := range chain[:len(chain)-1] {
191-
co.IntermediateCerts.AddCert(cert)
181+
switch {
182+
case c.CertChain != "":
183+
{
184+
chain, err := loadCertChainFromFileOrURL(c.CertChain)
185+
if err != nil {
186+
return err
187+
}
188+
co.RootCerts = x509.NewCertPool()
189+
co.RootCerts.AddCert(chain[len(chain)-1])
190+
if len(chain) > 1 {
191+
co.IntermediateCerts = x509.NewCertPool()
192+
for _, cert := range chain[:len(chain)-1] {
193+
co.IntermediateCerts.AddCert(cert)
194+
}
192195
}
193196
}
194-
} else {
195-
// This performs an online fetch of the Fulcio roots. This is needed
196-
// for verifying keyless certificates (both online and offline).
197-
co.RootCerts, err = fulcio.GetRoots()
198-
if err != nil {
199-
return fmt.Errorf("getting Fulcio roots: %w", err)
197+
case c.CARoots != "":
198+
{
199+
caRoots, err := loadCertChainFromFileOrURL(c.CARoots)
200+
if err != nil {
201+
return err
202+
}
203+
co.RootCerts = x509.NewCertPool()
204+
if len(caRoots) > 0 {
205+
for _, cert := range caRoots {
206+
co.RootCerts.AddCert(cert)
207+
}
208+
}
200209
}
201-
co.IntermediateCerts, err = fulcio.GetIntermediates()
202-
if err != nil {
203-
return fmt.Errorf("getting Fulcio intermediates: %w", err)
210+
default:
211+
{
212+
// This performs an online fetch of the Fulcio roots. This is needed
213+
// for verifying keyless certificates (both online and offline).
214+
co.RootCerts, err = fulcio.GetRoots()
215+
if err != nil {
216+
return fmt.Errorf("getting Fulcio roots: %w", err)
217+
}
218+
co.IntermediateCerts, err = fulcio.GetIntermediates()
219+
if err != nil {
220+
return fmt.Errorf("getting Fulcio intermediates: %w", err)
221+
}
204222
}
205223
}
206224
}
@@ -242,8 +260,8 @@ func (c *VerifyCommand) Exec(ctx context.Context, images []string) (err error) {
242260
if err != nil {
243261
return err
244262
}
245-
if c.CertChain == "" {
246-
// If no certChain is passed, the Fulcio root certificate will be used
263+
if c.CertChain == "" && c.CARoots == "" {
264+
// If no certChain and no CARoots are passed, the Fulcio root certificate will be used
247265
co.RootCerts, err = fulcio.GetRoots()
248266
if err != nil {
249267
return fmt.Errorf("getting Fulcio roots: %w", err)
@@ -257,14 +275,21 @@ func (c *VerifyCommand) Exec(ctx context.Context, images []string) (err error) {
257275
return err
258276
}
259277
} else {
260-
// Verify certificate with chain
261-
chain, err := loadCertChainFromFileOrURL(c.CertChain)
262-
if err != nil {
263-
return err
264-
}
265-
pubKey, err = cosign.ValidateAndUnpackCertWithChain(cert, chain, co)
266-
if err != nil {
267-
return err
278+
if c.CARoots == "" {
279+
// Verify certificate with chain
280+
chain, err := loadCertChainFromFileOrURL(c.CertChain)
281+
if err != nil {
282+
return err
283+
}
284+
pubKey, err = cosign.ValidateAndUnpackCertWithChain(cert, chain, co)
285+
if err != nil {
286+
return err
287+
}
288+
} else {
289+
pubKey, err = cosign.ValidateAndUnpackCertWithCertPools(cert, co)
290+
if err != nil {
291+
return err
292+
}
268293
}
269294
}
270295
if c.SCTRef != "" {

doc/cosign_dockerfile_verify.md

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

doc/cosign_manifest_verify.md

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

doc/cosign_verify-attestation.md

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

doc/cosign_verify-blob-attestation.md

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

doc/cosign_verify-blob.md

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)