diff --git a/config.go b/config.go index 73276df..d64cb63 100644 --- a/config.go +++ b/config.go @@ -61,6 +61,9 @@ type Verifier struct { // Supports '*' and '?' in the pattern string. Image string `yaml:"image,omitempty"` + // AttestationPresent is a boolean to specify whether an attestation is expected to be present + AttestationPresent bool `yaml:"attestationPresent,omitempty"` + // Options defines verification options Options *CheckOptions `yaml:"options,omitempty"` } @@ -89,5 +92,5 @@ type CheckOptions struct { Key string `yaml:"key,omitempty"` // RekorURL is the address of a rekor STL server - RekorURL string `yaml:"rekorURL,omitempty"` + RekorURL string `yaml:"rekor_url,omitempty"` } diff --git a/provider.go b/provider.go index 50f6a7e..5ec86c1 100644 --- a/provider.go +++ b/provider.go @@ -31,6 +31,7 @@ import ( "github.com/sigstore/cosign/cmd/cosign/cli/rekor" "github.com/sigstore/cosign/pkg/cosign" "github.com/sigstore/cosign/pkg/cosign/pkcs11key" + "github.com/sigstore/cosign/pkg/oci" sigs "github.com/sigstore/cosign/pkg/signature" ) @@ -91,9 +92,11 @@ func validate(cfg *Config) func(w http.ResponseWriter, req *http.Request) { Key: key, } fmt.Println("verify signature for:", key) - if err := verifyImageSignatures(ctx, key, cfg.Verifiers); err != nil { + metadata, err := verifyImageSignatures(ctx, key, cfg.Verifiers) + if err != nil { result.Error = err.Error() } + result.Value = metadata results = append(results, result) } @@ -101,7 +104,12 @@ func validate(cfg *Config) func(w http.ResponseWriter, req *http.Request) { } } -func verifyImageSignatures(ctx context.Context, key string, verifiers []Verifier) error { +type CheckedMetadata struct { + ImageSignatures []oci.Signature `json:"imageSignatures"` + AttestationSignatures []oci.Signature `json:"attestationSignatures"` +} + +func verifyImageSignatures(ctx context.Context, key string, verifiers []Verifier) (*CheckedMetadata, error) { for _, o := range verifiers { if !wildcard.Match(o.Image, key) { continue @@ -110,7 +118,7 @@ func verifyImageSignatures(ctx context.Context, key string, verifiers []Verifier ro := options.RegistryOptions{} ociremoteOpts, err := ro.ClientOpts(ctx) if err != nil { - return err + return nil, err } co := &cosign.CheckOpts{ RegistryClientOpts: ociremoteOpts, @@ -119,14 +127,14 @@ func verifyImageSignatures(ctx context.Context, key string, verifiers []Verifier if o.Options.RekorURL != "" { rekorClient, err := rekor.NewClient(o.Options.RekorURL) if err != nil { - return fmt.Errorf("rekor.NewClient: %v", err) + return nil, fmt.Errorf("rekor.NewClient: %v", err) } co.RekorClient = rekorClient } if o.Options.Key != "" { pubKey, err := sigs.PublicKeyFromKeyRef(ctx, o.Options.Key) if err != nil { - return fmt.Errorf("PublicKeyFromKeyRef: %v", err) + return nil, fmt.Errorf("PublicKeyFromKeyRef: %v", err) } pkcs11Key, ok := pubKey.(*pkcs11key.Key) if ok { @@ -137,29 +145,50 @@ func verifyImageSignatures(ctx context.Context, key string, verifiers []Verifier ref, err := name.ParseReference(key) if err != nil { - return fmt.Errorf("ParseReference: %v", err) + return nil, fmt.Errorf("ParseReference: %v", err) } + var metadata *CheckedMetadata + checkedSignatures, bundleVerified, err := cosign.VerifyImageSignatures(ctx, ref, co) if err != nil { - return fmt.Errorf("VerifyImageSignatures: %v", err) + return nil, fmt.Errorf("VerifyImageSignatures: %v", err) } if co.RekorClient != nil && !bundleVerified { - return fmt.Errorf("no valid signatures found for %s: %v", key, err) + return nil, fmt.Errorf("no valid signatures found for %s: %v", key, err) } if len(checkedSignatures) == 0 { - return fmt.Errorf("no valid signatures found for %s", key) + return nil, fmt.Errorf("no valid signatures found for %s", key) } - fmt.Println("signature verified for:", key) + metadata.ImageSignatures = checkedSignatures + + fmt.Println("signature verified for: ", key) fmt.Printf("%d number of valid signatures found for %s, found signatures: %v\n", len(checkedSignatures), key, checkedSignatures) - return nil + if o.AttestationPresent { + fmt.Println("Verifying Attestations for image: ", key) + + checkedAttestations, bundleVerified, err := cosign.VerifyImageAttestations(ctx, ref, co) + if err != nil { + return nil, fmt.Errorf("VerifyImageAttestations: %v", err) + } + if co.RekorClient != nil && !bundleVerified { + return nil, fmt.Errorf("no valid attestations found for: %s", key) + } + + metadata.AttestationSignatures = checkedAttestations + + fmt.Println("attestation verified for: ", key) + fmt.Printf("%d number of valid attestations found for %s, found attestations: %v\n", len(checkedAttestations), key, checkedAttestations) + } + + return metadata, nil } - return fmt.Errorf("no verifier found for: %s", key) + return nil, fmt.Errorf("no verifier found for: %s", key) } // sendResponse sends back the response to Gatekeeper.