From f9dac40baff6fbe0f2a0aaa874b23db6a7ae0758 Mon Sep 17 00:00:00 2001 From: Rob Best Date: Mon, 17 Jan 2022 09:13:02 +0000 Subject: [PATCH] Export function to verify individual signature Calling the existing VerifyImageSignatures function multiple times for the same image with different verifiers will download the OCI manifest multiple times. This is inefficient and slow. Exporting a function that verifies a single signature allows the decoupling of the OCI manifest fetch and verification stages. Signed-off-by: Rob Best --- pkg/cosign/verify.go | 99 +++++++++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 47 deletions(-) diff --git a/pkg/cosign/verify.go b/pkg/cosign/verify.go index cb397579687..17ed3811230 100644 --- a/pkg/cosign/verify.go +++ b/pkg/cosign/verify.go @@ -321,53 +321,9 @@ func verifySignatures(ctx context.Context, sigs oci.Signatures, h v1.Hash, co *C validationErrs := []string{} for _, sig := range sl { - if err := func(sig oci.Signature) error { - verifier := co.SigVerifier - if verifier == nil { - // If we don't have a public key to check against, we can try a root cert. - cert, err := sig.Cert() - if err != nil { - return err - } - if cert == nil { - return errors.New("no certificate found on signature") - } - verifier, err = ValidateAndUnpackCert(cert, co) - if err != nil { - return err - } - } - - if err := verifyOCISignature(ctx, verifier, sig); err != nil { - return err - } - - // We can't check annotations without claims, both require unmarshalling the payload. - if co.ClaimVerifier != nil { - if err := co.ClaimVerifier(sig, h, co.Annotations); err != nil { - return err - } - } - - verified, err := VerifyBundle(ctx, sig) - if err != nil && co.RekorClient == nil { - return errors.Wrap(err, "unable to verify bundle") - } - bundleVerified = bundleVerified || verified - - if !verified && co.RekorClient != nil { - if co.SigVerifier != nil { - pub, err := co.SigVerifier.PublicKey(co.PKOpts...) - if err != nil { - return err - } - return tlogValidatePublicKey(ctx, co.RekorClient, pub, sig) - } - - return tlogValidateCertificate(ctx, co.RekorClient, sig) - } - return nil - }(sig); err != nil { + verified, err := VerifyImageSignature(ctx, sig, h, co) + bundleVerified = bundleVerified || verified + if err != nil { validationErrs = append(validationErrs, err.Error()) continue } @@ -381,6 +337,55 @@ func verifySignatures(ctx context.Context, sigs oci.Signatures, h v1.Hash, co *C return checkedSignatures, bundleVerified, nil } +// VerifyImageSignature verifies a signature +func VerifyImageSignature(ctx context.Context, sig oci.Signature, h v1.Hash, co *CheckOpts) (bundleVerified bool, err error) { + verifier := co.SigVerifier + if verifier == nil { + // If we don't have a public key to check against, we can try a root cert. + cert, err := sig.Cert() + if err != nil { + return bundleVerified, err + } + if cert == nil { + return bundleVerified, errors.New("no certificate found on signature") + } + verifier, err = ValidateAndUnpackCert(cert, co) + if err != nil { + return bundleVerified, err + } + } + + if err := verifyOCISignature(ctx, verifier, sig); err != nil { + return bundleVerified, err + } + + // We can't check annotations without claims, both require unmarshalling the payload. + if co.ClaimVerifier != nil { + if err := co.ClaimVerifier(sig, h, co.Annotations); err != nil { + return bundleVerified, err + } + } + + bundleVerified, err = VerifyBundle(ctx, sig) + if err != nil && co.RekorClient == nil { + return false, errors.Wrap(err, "unable to verify bundle") + } + + if !bundleVerified && co.RekorClient != nil { + if co.SigVerifier != nil { + pub, err := co.SigVerifier.PublicKey(co.PKOpts...) + if err != nil { + return bundleVerified, err + } + return bundleVerified, tlogValidatePublicKey(ctx, co.RekorClient, pub, sig) + } + + return bundleVerified, tlogValidateCertificate(ctx, co.RekorClient, sig) + } + + return bundleVerified, nil +} + func loadSignatureFromFile(sigRef string, signedImgRef name.Reference, co *CheckOpts) (oci.Signatures, error) { var b64sig string targetSig, err := blob.LoadFileOrURL(sigRef)