Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 45 additions & 25 deletions cmd/aaop/aaop.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"os/signal"
"path"
"path/filepath"
"strings"
"syscall"
"time"

Expand All @@ -34,7 +35,7 @@ import (
var (
noPGI = flag.Bool("no-public-good", false, "disable public good sigstore instance")
certsDir = flag.String("certs", "", "Directory to where TLS certs are stored")
trustDomain = flag.String("trust-domain", "", "trust domain to use")
trustDomains = flag.String("trust-domain", "", "comma separated trust domains to use")
tufRepo = flag.String("tuf-repo", "", "URL to TUF repository")
tufRoot = flag.String("tuf-root", "", "Path to a root.json used to initialize TUF repository")
ns = flag.String("namespace", "", "namespace the pod runs in")
Expand Down Expand Up @@ -66,17 +67,20 @@ func main() {
var kc *authn.KeyChainProvider
var v provider.Verifier
var err error
var tds []string

flag.Parse()

tds = strings.Split(*trustDomains, ",")

if *tufRepo != "" && *tufRoot != "" {
if v, err = loadCustomVerifier(*tufRepo,
*tufRoot,
*trustDomain); err != nil {
tds); err != nil {
Comment thread
kommendorkapten marked this conversation as resolved.
log.Fatal(err)
}
} else {
if v, err = loadVerifiers(!*noPGI, *trustDomain); err != nil {
if v, err = loadVerifiers(!*noPGI, tds); err != nil {
log.Fatal(err)
}
}
Expand Down Expand Up @@ -185,9 +189,11 @@ func run(ctx context.Context, srv *http.Server, cf string, kf string) error {
// loadCustomVerifier loads a user provided TUF root.
// Currently only verificatoin options with RFC3161 signed timestamps
Comment thread
kommendorkapten marked this conversation as resolved.
// are supported.
func loadCustomVerifier(repo, root, td string) (provider.Verifier, error) {
func loadCustomVerifier(repo, root string, tds []string) (provider.Verifier, error) {
var mv = verifier.Multi{
V: []*verifier.Verifier{},
}
var rb []byte
var v *verifier.Verifier
var vo = []verify.VerifierOption{
verify.WithSignedTimestamps(1),
}
Expand All @@ -197,49 +203,63 @@ func loadCustomVerifier(repo, root, td string) (provider.Verifier, error) {
return nil, fmt.Errorf("failed to load verifier: %w", err)
}

if v, err = verifier.New(rb, repo, td, vo); err != nil {
return nil, fmt.Errorf("failed to create verifier: %w", err)
for _, td := range tds {
var v *verifier.Verifier

if v, err = verifier.New(rb, repo, td, vo); err != nil {
return nil, fmt.Errorf("failed to create verifier: %w", err)
}

mv.V = append(mv.V, v)

slog.Info("loaded verifier",
"tuf_repo", repo,
"trust_domain", td)
}

return v, nil
if len(mv.V) == 0 {
return nil, errors.New("no trust root provided")
}

return &mv, nil
}

// loadVerifiers returns the default verifiers. If pgi is true and tr is
// the empty string, pgi and gh verifiers are returned.
// if the provided trust domain is set, only gh verifier is returend,
Comment thread
kommendorkapten marked this conversation as resolved.
// with the set trust domain.
func loadVerifiers(pgi bool, td string) (provider.Verifier, error) {
func loadVerifiers(pgi bool, tds []string) (provider.Verifier, error) {
var mv = verifier.Multi{
V: map[string]*verifier.Verifier{},
V: []*verifier.Verifier{},
}
var v *verifier.Verifier
var err error
var dotcom bool

// only load PGI if no tenant's trust domain is selected
if td == "" || td == DotcomTrustDomain {
dotcom = true
if len(tds) == 0 {
tds = append(tds, DotcomTrustDomain)
}

if pgi && dotcom {
if pgi {
if v, err = verifier.PGIVerifier(); err != nil {
return nil, fmt.Errorf("failed to load PGI verifier: %w", err)
}
mv.V[verifier.PublicGoodIssuer] = v
mv.V = append(mv.V, v)
slog.Info("loaded verifier",
"instance", "public good Sigstore")
}

if v, err = verifier.GHVerifier(td); err != nil {
return nil, fmt.Errorf("failed to load GitHub verifier: %w", err)
}
mv.V[verifier.GitHubIssuer] = v
if td == "" {
td = "dotcom"
for _, td := range tds {
var v *verifier.Verifier

if v, err = verifier.GHVerifier(td); err != nil {
return nil, fmt.Errorf("failed to load GitHub verifier: %w", err)
}
mv.V = append(mv.V, v)

slog.Info("loaded verifier",
"instance", "GitHub Sigstore",
"trust_domain", td)
}
slog.Info("loaded verifier",
"instance", "GitHub Sigstore",
"trust_domain", td)

return &mv, nil
}
Expand Down
8 changes: 3 additions & 5 deletions cmd/cver/cver.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ var (
)

func main() {
var mv = &verifier.Multi{
V: map[string]*verifier.Verifier{},
}
var mv = &verifier.Multi{}
var v *verifier.Verifier
var res []*verify.VerificationResult
var ref name.Reference
Expand All @@ -41,12 +39,12 @@ func main() {
log.Print(err)
}

mv.V[verifier.PublicGoodIssuer] = v
mv.V = append(mv.V, v)

if v, err = verifier.GHVerifier(""); err != nil {
log.Print(err)
}
mv.V[verifier.GitHubIssuer] = v
mv.V = append(mv.V, v)

if ref, err = name.ParseReference(*img); err != nil {
log.Print(err)
Expand Down
70 changes: 20 additions & 50 deletions pkg/verifier/multi.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package verifier

import (
"crypto/x509"
"fmt"
"log/slog"

"github.com/google/go-containerregistry/pkg/v1"
Expand All @@ -19,50 +17,43 @@ const (
GitHubIssuer = "GitHub, Inc."
)

// Multi is a Verifier that knows about multiple trust roots and inspects
// the bundle to select the correct trust root for each provided bundle.
// Multi is a Verifier that knows about multiple trust roots.
// During verification each trust root are tried until a successful
// verification is reached.
type Multi struct {
V map[string]*Verifier
V []*Verifier
}

// NewMulti initializes the multi verifier with a map of Issuer org to
// a Verifier.
Comment thread
kommendorkapten marked this conversation as resolved.
func NewMulti(v map[string]*Verifier) *Multi {
func NewMulti(v []*Verifier) *Multi {
var m = make([]*Verifier, len(v))

copy(m, v)
return &Multi{
V: v,
V: m,
}
}

// Verify iterates over each bundle and selects the correct verifier
// based on the certificate's issuer. Bundles with unknown certificate
// issuers are ignored.
// Verify iterates over each bundle, and verifies the bundle against
// all known trust roots. If a successful verification occurs, no other
// trust roots are tried.
func (m *Multi) Verify(bundles []*bundle.Bundle, h *v1.Hash) ([]*verify.VerificationResult, error) {
var res = []*verify.VerificationResult{}
var err error

for _, b := range bundles {
var r *verify.VerificationResult
var v *Verifier
var iss string
var err error

if iss, err = getIssuer(b); err != nil {
slog.Error("failed to extract issuer from bundle",
"image_digest", h.Hex,
"error", err)
continue
}

if v = m.V[iss]; v == nil {
slog.Error("unknown issuer",
"image_digest", h.Hex,
"issuer", iss)
// No configured verifier for this issuer
continue
for _, v := range m.V {
if r, err = v.VerifyOne(b, h); err == nil {
Comment thread
kommendorkapten marked this conversation as resolved.
res = append(res, r)
// skip rest of verifiers if verified
break
}
}

if r, err = v.VerifyOne(b, h); err == nil {
res = append(res, r)
} else {
if r == nil {
subjects, subjectsErr := bundleSubjects(b)
attrs := []any{
"image_digest", h.Hex,
Expand All @@ -80,24 +71,3 @@ func (m *Multi) Verify(bundles []*bundle.Bundle, h *v1.Hash) ([]*verify.Verifica

return res, nil
}

// getIssuer extracts the certificate from the bundle and returns the
// organization name that issued the certificate.
func getIssuer(b *bundle.Bundle) (string, error) {
var vc verify.VerificationContent
var c *x509.Certificate
var err error

if vc, err = b.VerificationContent(); err != nil {
return "", err
}
if c = vc.Certificate(); c == nil {
return "", err
}

if len(c.Issuer.Organization) != 1 {
return "", fmt.Errorf("expected 1 issuer, found %d", len(c.Issuer.Organization))
}

return c.Issuer.Organization[0], nil
}
10 changes: 2 additions & 8 deletions pkg/verifier/multi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,7 @@ func TestMultiVerifier(t *testing.T) {
require.NoError(t, err)
assert.NotNil(t, gh)

var mv = NewMulti(map[string]*Verifier{
PublicGoodIssuer: pgi,
GitHubIssuer: gh,
})
var mv = NewMulti([]*Verifier{pgi, gh})

var b = &bundle.Bundle{}
err = b.UnmarshalJSON([]byte(okBundle))
Expand All @@ -76,10 +73,7 @@ func TestMultiVerifierWrongHash(t *testing.T) {
require.NoError(t, err)
assert.NotNil(t, gh)

var mv = NewMulti(map[string]*Verifier{
PublicGoodIssuer: pgi,
GitHubIssuer: gh,
})
var mv = NewMulti([]*Verifier{pgi, gh})

var b = &bundle.Bundle{}
err = b.UnmarshalJSON([]byte(okBundle))
Expand Down