Skip to content

Commit 40fc15f

Browse files
authored
add --ca-roots and --ca-intermediates flags to 'cosign verify' (#3464)
* add --certificate-bundle flag to 'cosign verify' Related to issue #3462. Current commit adds the flag to verify the CLI options. The new flag doesn't have any effect yet (will add in follow-up PRs). Signed-off-by: Dmitry S <[email protected]> * 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]> * add functional tests for --ca-roots flag Signed-off-by: Dmitry S <[email protected]> * setup-crane action for e2e_test_pkcs11.sh Signed-off-by: Dmitry S <[email protected]> * rebase on trunk Signed-off-by: Dmitry Savintsev <[email protected]> * transform gencert subpackage to helper function Signed-off-by: Dmitry S <[email protected]> * use the trunk version of workflows/e2e-tests.yml Signed-off-by: Dmitry S <[email protected]> * correct certificate generation for e2e tests Signed-off-by: Dmitry S <[email protected]> * refactor test cert/keys generation and corresponding test Signed-off-by: Dmitry S <[email protected]> * add license header Signed-off-by: Dmitry S <[email protected]> * remove test shell scripts Signed-off-by: Dmitry S <[email protected]> * remove unused certFile param to verifyCertBundle Signed-off-by: Dmitry S <[email protected]> * remove duplicate test functions Signed-off-by: Dmitry S <[email protected]> --------- Signed-off-by: Dmitry S <[email protected]> Signed-off-by: Dmitry Savintsev <[email protected]>
1 parent 7c20052 commit 40fc15f

12 files changed

+847
-14
lines changed

cmd/cosign/cli/options/certificate.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ type CertVerifyOptions struct {
3333
CertGithubWorkflowName string
3434
CertGithubWorkflowRepository string
3535
CertGithubWorkflowRef string
36+
CAIntermediates string
37+
CARoots string
3638
CertChain string
3739
SCT string
3840
IgnoreSCT bool
@@ -75,12 +77,25 @@ func (o *CertVerifyOptions) AddFlags(cmd *cobra.Command) {
7577
cmd.Flags().StringVar(&o.CertGithubWorkflowRef, "certificate-github-workflow-ref", "",
7678
"contains the ref claim from the GitHub OIDC Identity token that contains the git ref that the workflow run was based upon.")
7779
// -- Cert extensions end --
80+
cmd.Flags().StringVar(&o.CAIntermediates, "ca-intermediates", "",
81+
"path to a file of intermediate CA certificates in PEM format which will be needed "+
82+
"when building the certificate chains for the signing certificate. "+
83+
"The flag is optional and must be used together with --ca-roots, conflicts with "+
84+
"--certificate-chain.")
85+
_ = cmd.Flags().SetAnnotation("ca-intermediates", cobra.BashCompFilenameExt, []string{"cert"})
86+
cmd.Flags().StringVar(&o.CARoots, "ca-roots", "",
87+
"path to a bundle file of CA certificates in PEM format which will be needed "+
88+
"when building the certificate chains for the signing certificate. Conflicts with --certificate-chain.")
89+
_ = cmd.Flags().SetAnnotation("ca-roots", cobra.BashCompFilenameExt, []string{"cert"})
90+
7891
cmd.Flags().StringVar(&o.CertChain, "certificate-chain", "",
7992
"path to a list of CA certificates in PEM format which will be needed "+
8093
"when building the certificate chain for the signing certificate. "+
8194
"Must start with the parent intermediate CA certificate of the "+
82-
"signing certificate and end with the root certificate")
95+
"signing certificate and end with the root certificate. Conflicts with --ca-roots and --ca-intermediates.")
8396
_ = cmd.Flags().SetAnnotation("certificate-chain", cobra.BashCompFilenameExt, []string{"cert"})
97+
cmd.MarkFlagsMutuallyExclusive("ca-roots", "certificate-chain")
98+
cmd.MarkFlagsMutuallyExclusive("ca-intermediates", "certificate-chain")
8499

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

cmd/cosign/cli/verify.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ against the transparency log.`,
6262
# verify image with local certificate and certificate chain
6363
cosign verify --cert cosign.crt --cert-chain chain.crt <IMAGE>
6464
65+
# verify image with local certificate and certificate bundles of CA roots
66+
# and (optionally) CA intermediates
67+
cosign verify --cert cosign.crt --ca-roots ca-roots.pem --ca-intermediates ca-intermediates.pem <IMAGE>
68+
6569
# verify image using keyless verification with the given certificate
6670
# chain and identity parameters, without Fulcio roots (for BYO PKI):
6771
cosign verify --cert-chain chain.crt --certificate-oidc-issuer https://issuer.example.com --certificate-identity [email protected] <IMAGE>
@@ -115,6 +119,8 @@ against the transparency log.`,
115119
CertGithubWorkflowName: o.CertVerify.CertGithubWorkflowName,
116120
CertGithubWorkflowRepository: o.CertVerify.CertGithubWorkflowRepository,
117121
CertGithubWorkflowRef: o.CertVerify.CertGithubWorkflowRef,
122+
CAIntermediates: o.CertVerify.CAIntermediates,
123+
CARoots: o.CertVerify.CARoots,
118124
CertChain: o.CertVerify.CertChain,
119125
IgnoreSCT: o.CertVerify.IgnoreSCT,
120126
SCTRef: o.CertVerify.SCT,

cmd/cosign/cli/verify/verify.go

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ type VerifyCommand struct {
5959
CertGithubWorkflowName string
6060
CertGithubWorkflowRepository string
6161
CertGithubWorkflowRef string
62+
CAIntermediates string
63+
CARoots string
6264
CertChain string
6365
CertOidcProvider string
6466
IgnoreSCT bool
@@ -173,7 +175,8 @@ func (c *VerifyCommand) Exec(ctx context.Context, images []string) (err error) {
173175
}
174176
}
175177
if keylessVerification(c.KeyRef, c.Sk) {
176-
if c.CertChain != "" {
178+
switch {
179+
case c.CertChain != "":
177180
chain, err := loadCertChainFromFileOrURL(c.CertChain)
178181
if err != nil {
179182
return err
@@ -186,9 +189,32 @@ func (c *VerifyCommand) Exec(ctx context.Context, images []string) (err error) {
186189
co.IntermediateCerts.AddCert(cert)
187190
}
188191
}
189-
} else {
190-
// This performs an online fetch of the Fulcio roots. This is needed
191-
// for verifying keyless certificates (both online and offline).
192+
case c.CARoots != "":
193+
caRoots, err := loadCertChainFromFileOrURL(c.CARoots)
194+
if err != nil {
195+
return err
196+
}
197+
co.RootCerts = x509.NewCertPool()
198+
if len(caRoots) > 0 {
199+
for _, cert := range caRoots {
200+
co.RootCerts.AddCert(cert)
201+
}
202+
}
203+
if c.CAIntermediates != "" {
204+
caIntermediates, err := loadCertChainFromFileOrURL(c.CAIntermediates)
205+
if err != nil {
206+
return err
207+
}
208+
if len(caIntermediates) > 0 {
209+
co.IntermediateCerts = x509.NewCertPool()
210+
for _, cert := range caIntermediates {
211+
co.IntermediateCerts.AddCert(cert)
212+
}
213+
}
214+
}
215+
default:
216+
// This performs an online fetch of the Fulcio roots from a TUF repository.
217+
// This is needed for verifying keyless certificates (both online and offline).
192218
co.RootCerts, err = fulcio.GetRoots()
193219
if err != nil {
194220
return fmt.Errorf("getting Fulcio roots: %w", err)
@@ -237,8 +263,9 @@ func (c *VerifyCommand) Exec(ctx context.Context, images []string) (err error) {
237263
if err != nil {
238264
return err
239265
}
240-
if c.CertChain == "" {
241-
// If no certChain is passed, the Fulcio root certificate will be used
266+
switch {
267+
case c.CertChain == "" && co.RootCerts == nil:
268+
// If no certChain and no CARoots are passed, the Fulcio root certificate will be used
242269
co.RootCerts, err = fulcio.GetRoots()
243270
if err != nil {
244271
return fmt.Errorf("getting Fulcio roots: %w", err)
@@ -251,7 +278,7 @@ func (c *VerifyCommand) Exec(ctx context.Context, images []string) (err error) {
251278
if err != nil {
252279
return err
253280
}
254-
} else {
281+
case c.CertChain != "":
255282
// Verify certificate with chain
256283
chain, err := loadCertChainFromFileOrURL(c.CertChain)
257284
if err != nil {
@@ -261,14 +288,26 @@ func (c *VerifyCommand) Exec(ctx context.Context, images []string) (err error) {
261288
if err != nil {
262289
return err
263290
}
291+
case co.RootCerts != nil:
292+
// Verify certificate with root (and if given, intermediate) certificate
293+
pubKey, err = cosign.ValidateAndUnpackCert(cert, co)
294+
if err != nil {
295+
return err
296+
}
297+
default:
298+
return errors.New("no certificate chain provided to verify certificate")
264299
}
300+
265301
if c.SCTRef != "" {
266302
sct, err := os.ReadFile(filepath.Clean(c.SCTRef))
267303
if err != nil {
268304
return fmt.Errorf("reading sct from file: %w", err)
269305
}
270306
co.SCT = sct
271307
}
308+
default:
309+
// Do nothing. Neither keyRef, c.Sk, nor certRef were set - can happen for example when using Fulcio and TSA.
310+
// For an example see the TestAttachWithRFC3161Timestamp test in test/e2e_test.go.
272311
}
273312
co.SigVerifier = pubKey
274313

doc/cosign_dockerfile_verify.md

Lines changed: 3 additions & 1 deletion
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: 3 additions & 1 deletion
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: 3 additions & 1 deletion
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: 3 additions & 1 deletion
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: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)