Skip to content

Commit

Permalink
feat: update unit test
Browse files Browse the repository at this point in the history
Signed-off-by: Juncheng Zhu <[email protected]>
  • Loading branch information
junczhu committed Feb 14, 2025
1 parent 414a753 commit f0aaace
Show file tree
Hide file tree
Showing 5 changed files with 367 additions and 12 deletions.
40 changes: 40 additions & 0 deletions cosign/certoptions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
Copyright The Ratify Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cosign

import (
"crypto/x509"

"github.com/sigstore/cosign/v2/cmd/cosign/cli/fulcio"
)

type CertOptions interface {
// GetRoots retrieves the root certificate for the given subject.
GetRoots() (*x509.CertPool, error)

// GetIntermediate retrieves the intermediate certificate for the given subject.
GetIntermediates() (*x509.CertPool, error)
}

type DefaultCertOptions struct{}

func (d *DefaultCertOptions) GetRoots() (*x509.CertPool, error) {
return fulcio.GetRoots()
}

func (d *DefaultCertOptions) GetIntermediates() (*x509.CertPool, error) {
return fulcio.GetIntermediates()
}
38 changes: 38 additions & 0 deletions cosign/certoptions_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
Copyright The Ratify Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cosign

import (
"testing"
)

func TestDefaultCertOptions_GetRoots(t *testing.T) {
d := &DefaultCertOptions{}

_, err := d.GetRoots()
if err != nil {
t.Fatalf("expected no error from GetRoots, got %v", err)
}
}

func TestDefaultCertOptions_GetIntermediates(t *testing.T) {
d := &DefaultCertOptions{}

_, err := d.GetIntermediates()
if err != nil {
t.Fatalf("expected no error from GetIntermediates, got %v", err)
}
}
2 changes: 1 addition & 1 deletion cosign/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/ratify-project/ratify-verifier-go/cosign
go 1.22.0

require (
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.1.0
github.com/ratify-project/ratify-go v0.0.0-20250121002110-2815af359901
github.com/sigstore/cosign/v2 v2.2.4
Expand Down Expand Up @@ -123,7 +124,6 @@ require (
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
Expand Down
52 changes: 43 additions & 9 deletions cosign/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ package cosign
import (
"context"
"crypto"
"encoding/json"
"fmt"

ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/ratify-project/ratify-go"
"github.com/sigstore/cosign/v2/cmd/cosign/cli/fulcio"
"github.com/sigstore/cosign/v2/pkg/cosign"
"github.com/sigstore/cosign/v2/pkg/cosign/bundle"
"github.com/sigstore/cosign/v2/pkg/oci/static"
"github.com/sigstore/sigstore/pkg/signature"
"oras.land/oras-go/v2/registry"
Expand Down Expand Up @@ -91,8 +92,8 @@ func (v *Verifier) Verify(ctx context.Context, opts *ratify.VerifyOptions) (*rat
if err != nil {
return nil, fmt.Errorf("failed to parse subject reference: %w", err)
}

err = updateRepoSigVerifierKeys(opts.Subject, v.CheckOpts, v.keysMap)
// Use the Fulcio root certificate for keyless verification
err = updateCheckOpts(opts.Subject, v.CheckOpts, v.keysMap, &DefaultCertOptions{})
if err != nil {
return nil, fmt.Errorf("failed to update signature verifier keys: %w", err)
}
Expand All @@ -106,11 +107,15 @@ func (v *Verifier) Verify(ctx context.Context, opts *ratify.VerifyOptions) (*rat
}

for _, signatureDesc := range signatureLayers {
staticOpts, err := staticLayerOpts(signatureDesc)
if err != nil {
return nil, fmt.Errorf("failed to parse Cosign signature %w", err)
}
signatureBlob, err := opts.Store.FetchBlobContent(ctx, subjectRef.Repository, signatureDesc)
if err != nil {
return nil, fmt.Errorf("failed to fetch signature blob: %w", err)
}
sig, err := static.NewSignature(signatureBlob, signatureDesc.Annotations[static.SignatureAnnotationKey])
sig, err := static.NewSignature(signatureBlob, signatureDesc.Annotations[static.SignatureAnnotationKey], staticOpts...)
if err != nil {
return nil, fmt.Errorf("failed to validate the cosign signature: %w", err)
}
Expand Down Expand Up @@ -144,22 +149,25 @@ func getSignatureBlobDesc(ctx context.Context, store ratify.Store, artifactRef r
return signatureLayers, nil
}

// updateRepoSigVerifierKeys updates the signature verifier keys for the given repository.
func updateRepoSigVerifierKeys(repo string, opts *cosign.CheckOpts, keysMap map[string]crypto.PublicKey) error {
// updateCheckOpts updates the signature verifierOpts by verifyOpts.
func updateCheckOpts(repo string, opts *cosign.CheckOpts, keysMap map[string]crypto.PublicKey, certOpt CertOptions) error {
if opts.RekorClient == nil {
opts.IgnoreTlog = true
}

hashType := crypto.SHA256
key, exists := keysMap[repo]
if !exists {
// Use the Fulcio root certificate for keyless verification
// TODO: support passing certChain and no CARoots
opts.SigVerifier = nil
roots, err := fulcio.GetRoots()
roots, err := certOpt.GetRoots()
if err != nil || roots == nil {
return err
}
opts.RootCerts = roots
opts.IgnoreSCT = true

opts.IntermediateCerts, err = fulcio.GetIntermediates()
opts.IntermediateCerts, err = certOpt.GetIntermediates()
if err != nil {
return err
}
Expand All @@ -172,3 +180,29 @@ func updateRepoSigVerifierKeys(repo string, opts *cosign.CheckOpts, keysMap map[
opts.SigVerifier = verifier
return nil
}

// staticLayerOpts builds the cosign options for static layer signatures.
//
// Parameters:
// - desc: The OCI descriptor of the signature layer.
//
// Returns:
// - A slice of static.Option containing the options for the static layer signature.
// - An error if there is an issue with unmarshalling the bundle or other processing.
func staticLayerOpts(desc ocispec.Descriptor) ([]static.Option, error) {
options := []static.Option{
static.WithAnnotations(desc.Annotations),
}
if cert, chain := desc.Annotations[static.CertificateAnnotationKey], desc.Annotations[static.ChainAnnotationKey]; cert != "" && chain != "" {
options = append(options, static.WithCertChain([]byte(cert), []byte(chain)))
}
var rekorBundle bundle.RekorBundle = bundle.RekorBundle{}
if val, ok := desc.Annotations[static.BundleAnnotationKey]; ok {
if err := json.Unmarshal([]byte(val), &rekorBundle); err != nil {
return nil, fmt.Errorf("failed to unmarshal rekor bundle: %w", err)
}
options = append(options, static.WithBundle(&rekorBundle))
}

return options, nil
}
Loading

0 comments on commit f0aaace

Please sign in to comment.