summaryrefslogtreecommitdiff
path: root/vendor/github.com/spiffe/go-spiffe/v2/bundle
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/spiffe/go-spiffe/v2/bundle')
-rw-r--r--vendor/github.com/spiffe/go-spiffe/v2/bundle/jwtbundle/bundle.go200
-rw-r--r--vendor/github.com/spiffe/go-spiffe/v2/bundle/jwtbundle/doc.go43
-rw-r--r--vendor/github.com/spiffe/go-spiffe/v2/bundle/jwtbundle/set.go105
-rw-r--r--vendor/github.com/spiffe/go-spiffe/v2/bundle/jwtbundle/source.go12
-rw-r--r--vendor/github.com/spiffe/go-spiffe/v2/bundle/spiffebundle/bundle.go485
-rw-r--r--vendor/github.com/spiffe/go-spiffe/v2/bundle/spiffebundle/doc.go59
-rw-r--r--vendor/github.com/spiffe/go-spiffe/v2/bundle/spiffebundle/set.go135
-rw-r--r--vendor/github.com/spiffe/go-spiffe/v2/bundle/spiffebundle/source.go10
-rw-r--r--vendor/github.com/spiffe/go-spiffe/v2/bundle/x509bundle/bundle.go202
-rw-r--r--vendor/github.com/spiffe/go-spiffe/v2/bundle/x509bundle/doc.go42
-rw-r--r--vendor/github.com/spiffe/go-spiffe/v2/bundle/x509bundle/set.go105
-rw-r--r--vendor/github.com/spiffe/go-spiffe/v2/bundle/x509bundle/source.go12
12 files changed, 1410 insertions, 0 deletions
diff --git a/vendor/github.com/spiffe/go-spiffe/v2/bundle/jwtbundle/bundle.go b/vendor/github.com/spiffe/go-spiffe/v2/bundle/jwtbundle/bundle.go
new file mode 100644
index 0000000..ebd3cac
--- /dev/null
+++ b/vendor/github.com/spiffe/go-spiffe/v2/bundle/jwtbundle/bundle.go
@@ -0,0 +1,200 @@
+package jwtbundle
+
+import (
+ "crypto"
+ "encoding/json"
+ "errors"
+ "io"
+ "os"
+ "sync"
+
+ "github.com/go-jose/go-jose/v4"
+ "github.com/spiffe/go-spiffe/v2/internal/jwtutil"
+ "github.com/spiffe/go-spiffe/v2/spiffeid"
+ "github.com/zeebo/errs"
+)
+
+var jwtbundleErr = errs.Class("jwtbundle")
+
+// Bundle is a collection of trusted JWT authorities for a trust domain.
+type Bundle struct {
+ trustDomain spiffeid.TrustDomain
+
+ mtx sync.RWMutex
+ jwtAuthorities map[string]crypto.PublicKey
+}
+
+// New creates a new bundle.
+func New(trustDomain spiffeid.TrustDomain) *Bundle {
+ return &Bundle{
+ trustDomain: trustDomain,
+ jwtAuthorities: make(map[string]crypto.PublicKey),
+ }
+}
+
+// FromJWTAuthorities creates a new bundle from JWT authorities
+func FromJWTAuthorities(trustDomain spiffeid.TrustDomain, jwtAuthorities map[string]crypto.PublicKey) *Bundle {
+ return &Bundle{
+ trustDomain: trustDomain,
+ jwtAuthorities: jwtutil.CopyJWTAuthorities(jwtAuthorities),
+ }
+}
+
+// Load loads a bundle from a file on disk. The file must contain a standard RFC 7517 JWKS document.
+func Load(trustDomain spiffeid.TrustDomain, path string) (*Bundle, error) {
+ bundleBytes, err := os.ReadFile(path)
+ if err != nil {
+ return nil, jwtbundleErr.New("unable to read JWT bundle: %w", err)
+ }
+
+ return Parse(trustDomain, bundleBytes)
+}
+
+// Read decodes a bundle from a reader. The contents must contain a standard RFC 7517 JWKS document.
+func Read(trustDomain spiffeid.TrustDomain, r io.Reader) (*Bundle, error) {
+ b, err := io.ReadAll(r)
+ if err != nil {
+ return nil, jwtbundleErr.New("unable to read: %v", err)
+ }
+
+ return Parse(trustDomain, b)
+}
+
+// Parse parses a bundle from bytes. The data must be a standard RFC 7517 JWKS document.
+func Parse(trustDomain spiffeid.TrustDomain, bundleBytes []byte) (*Bundle, error) {
+ jwks := new(jose.JSONWebKeySet)
+ if err := json.Unmarshal(bundleBytes, jwks); err != nil {
+ return nil, jwtbundleErr.New("unable to parse JWKS: %v", err)
+ }
+
+ bundle := New(trustDomain)
+ for i, key := range jwks.Keys {
+ if err := bundle.AddJWTAuthority(key.KeyID, key.Key); err != nil {
+ return nil, jwtbundleErr.New("error adding authority %d of JWKS: %v", i, errors.Unwrap(err))
+ }
+ }
+
+ return bundle, nil
+}
+
+// TrustDomain returns the trust domain that the bundle belongs to.
+func (b *Bundle) TrustDomain() spiffeid.TrustDomain {
+ return b.trustDomain
+}
+
+// JWTAuthorities returns the JWT authorities in the bundle, keyed by key ID.
+func (b *Bundle) JWTAuthorities() map[string]crypto.PublicKey {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+
+ return jwtutil.CopyJWTAuthorities(b.jwtAuthorities)
+}
+
+// FindJWTAuthority finds the JWT authority with the given key ID from the bundle. If the authority
+// is found, it is returned and the boolean is true. Otherwise, the returned
+// value is nil and the boolean is false.
+func (b *Bundle) FindJWTAuthority(keyID string) (crypto.PublicKey, bool) {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+
+ if jwtAuthority, ok := b.jwtAuthorities[keyID]; ok {
+ return jwtAuthority, true
+ }
+ return nil, false
+}
+
+// HasJWTAuthority returns true if the bundle has a JWT authority with the given key ID.
+func (b *Bundle) HasJWTAuthority(keyID string) bool {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+
+ _, ok := b.jwtAuthorities[keyID]
+ return ok
+}
+
+// AddJWTAuthority adds a JWT authority to the bundle. If a JWT authority already exists
+// under the given key ID, it is replaced. A key ID must be specified.
+func (b *Bundle) AddJWTAuthority(keyID string, jwtAuthority crypto.PublicKey) error {
+ if keyID == "" {
+ return jwtbundleErr.New("keyID cannot be empty")
+ }
+
+ b.mtx.Lock()
+ defer b.mtx.Unlock()
+
+ b.jwtAuthorities[keyID] = jwtAuthority
+ return nil
+}
+
+// RemoveJWTAuthority removes the JWT authority identified by the key ID from the bundle.
+func (b *Bundle) RemoveJWTAuthority(keyID string) {
+ b.mtx.Lock()
+ defer b.mtx.Unlock()
+
+ delete(b.jwtAuthorities, keyID)
+}
+
+// SetJWTAuthorities sets the JWT authorities in the bundle.
+func (b *Bundle) SetJWTAuthorities(jwtAuthorities map[string]crypto.PublicKey) {
+ b.mtx.Lock()
+ defer b.mtx.Unlock()
+
+ b.jwtAuthorities = jwtutil.CopyJWTAuthorities(jwtAuthorities)
+}
+
+// Empty returns true if the bundle has no JWT authorities.
+func (b *Bundle) Empty() bool {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+
+ return len(b.jwtAuthorities) == 0
+}
+
+// Marshal marshals the JWT bundle into a standard RFC 7517 JWKS document. The
+// JWKS does not contain any SPIFFE-specific parameters.
+func (b *Bundle) Marshal() ([]byte, error) {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+
+ jwks := jose.JSONWebKeySet{}
+ for keyID, jwtAuthority := range b.jwtAuthorities {
+ jwks.Keys = append(jwks.Keys, jose.JSONWebKey{
+ Key: jwtAuthority,
+ KeyID: keyID,
+ })
+ }
+
+ return json.Marshal(jwks)
+}
+
+// Clone clones the bundle.
+func (b *Bundle) Clone() *Bundle {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+
+ return FromJWTAuthorities(b.trustDomain, b.jwtAuthorities)
+}
+
+// Equal compares the bundle for equality against the given bundle.
+func (b *Bundle) Equal(other *Bundle) bool {
+ if b == nil || other == nil {
+ return b == other
+ }
+
+ return b.trustDomain == other.trustDomain &&
+ jwtutil.JWTAuthoritiesEqual(b.jwtAuthorities, other.jwtAuthorities)
+}
+
+// GetJWTBundleForTrustDomain returns the JWT bundle for the given trust
+// domain. It implements the Source interface. An error will be returned if
+// the trust domain does not match that of the bundle.
+func (b *Bundle) GetJWTBundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*Bundle, error) {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+
+ if b.trustDomain != trustDomain {
+ return nil, jwtbundleErr.New("no JWT bundle for trust domain %q", trustDomain)
+ }
+
+ return b, nil
+}
diff --git a/vendor/github.com/spiffe/go-spiffe/v2/bundle/jwtbundle/doc.go b/vendor/github.com/spiffe/go-spiffe/v2/bundle/jwtbundle/doc.go
new file mode 100644
index 0000000..394878e
--- /dev/null
+++ b/vendor/github.com/spiffe/go-spiffe/v2/bundle/jwtbundle/doc.go
@@ -0,0 +1,43 @@
+// Package jwtbundle provides JWT bundle related functionality.
+//
+// A bundle represents a collection of JWT authorities, i.e., those that
+// are used to authenticate SPIFFE JWT-SVIDs.
+//
+// You can create a new bundle for a specific trust domain:
+//
+// td := spiffeid.RequireTrustDomainFromString("example.org")
+// bundle := jwtbundle.New(td)
+//
+// Or you can load it from disk:
+//
+// td := spiffeid.RequireTrustDomainFromString("example.org")
+// bundle := jwtbundle.Load(td, "bundle.jwks")
+//
+// The bundle can be initialized with JWT authorities:
+//
+// td := spiffeid.RequireTrustDomainFromString("example.org")
+// var jwtAuthorities map[string]crypto.PublicKey = ...
+// bundle := jwtbundle.FromJWTAuthorities(td, jwtAuthorities)
+//
+// In addition, you can add JWT authorities to the bundle:
+//
+// var keyID string = ...
+// var publicKey crypto.PublicKey = ...
+// bundle.AddJWTAuthority(keyID, publicKey)
+//
+// Bundles can be organized into a set, keyed by trust domain:
+//
+// set := jwtbundle.NewSet()
+// set.Add(bundle)
+//
+// A Source is source of JWT bundles for a trust domain. Both the Bundle
+// and Set types implement Source:
+//
+// // Initialize the source from a bundle or set
+// var source jwtbundle.Source = bundle
+// // ... or ...
+// var source jwtbundle.Source = set
+//
+// // Use the source to query for bundles by trust domain
+// bundle, err := source.GetJWTBundleForTrustDomain(td)
+package jwtbundle
diff --git a/vendor/github.com/spiffe/go-spiffe/v2/bundle/jwtbundle/set.go b/vendor/github.com/spiffe/go-spiffe/v2/bundle/jwtbundle/set.go
new file mode 100644
index 0000000..048dd0d
--- /dev/null
+++ b/vendor/github.com/spiffe/go-spiffe/v2/bundle/jwtbundle/set.go
@@ -0,0 +1,105 @@
+package jwtbundle
+
+import (
+ "sort"
+ "sync"
+
+ "github.com/spiffe/go-spiffe/v2/spiffeid"
+)
+
+// Set is a set of bundles, keyed by trust domain.
+type Set struct {
+ mtx sync.RWMutex
+ bundles map[spiffeid.TrustDomain]*Bundle
+}
+
+// NewSet creates a new set initialized with the given bundles.
+func NewSet(bundles ...*Bundle) *Set {
+ bundlesMap := make(map[spiffeid.TrustDomain]*Bundle)
+
+ for _, b := range bundles {
+ if b != nil {
+ bundlesMap[b.trustDomain] = b
+ }
+ }
+
+ return &Set{
+ bundles: bundlesMap,
+ }
+}
+
+// Add adds a new bundle into the set. If a bundle already exists for the
+// trust domain, the existing bundle is replaced.
+func (s *Set) Add(bundle *Bundle) {
+ s.mtx.Lock()
+ defer s.mtx.Unlock()
+
+ if bundle != nil {
+ s.bundles[bundle.trustDomain] = bundle
+ }
+}
+
+// Remove removes the bundle for the given trust domain.
+func (s *Set) Remove(trustDomain spiffeid.TrustDomain) {
+ s.mtx.Lock()
+ defer s.mtx.Unlock()
+
+ delete(s.bundles, trustDomain)
+}
+
+// Has returns true if there is a bundle for the given trust domain.
+func (s *Set) Has(trustDomain spiffeid.TrustDomain) bool {
+ s.mtx.RLock()
+ defer s.mtx.RUnlock()
+
+ _, ok := s.bundles[trustDomain]
+ return ok
+}
+
+// Get returns a bundle for the given trust domain. If the bundle is in the set
+// it is returned and the boolean is true. Otherwise, the returned value is
+// nil and the boolean is false.
+func (s *Set) Get(trustDomain spiffeid.TrustDomain) (*Bundle, bool) {
+ s.mtx.RLock()
+ defer s.mtx.RUnlock()
+
+ bundle, ok := s.bundles[trustDomain]
+ return bundle, ok
+}
+
+// Bundles returns the bundles in the set sorted by trust domain.
+func (s *Set) Bundles() []*Bundle {
+ s.mtx.RLock()
+ defer s.mtx.RUnlock()
+
+ out := make([]*Bundle, 0, len(s.bundles))
+ for _, bundle := range s.bundles {
+ out = append(out, bundle)
+ }
+ sort.Slice(out, func(a, b int) bool {
+ return out[a].TrustDomain().Compare(out[b].TrustDomain()) < 0
+ })
+ return out
+}
+
+// Len returns the number of bundles in the set.
+func (s *Set) Len() int {
+ s.mtx.RLock()
+ defer s.mtx.RUnlock()
+
+ return len(s.bundles)
+}
+
+// GetJWTBundleForTrustDomain returns the JWT bundle for the given trust
+// domain. It implements the Source interface.
+func (s *Set) GetJWTBundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*Bundle, error) {
+ s.mtx.RLock()
+ defer s.mtx.RUnlock()
+
+ bundle, ok := s.bundles[trustDomain]
+ if !ok {
+ return nil, jwtbundleErr.New("no JWT bundle for trust domain %q", trustDomain)
+ }
+
+ return bundle, nil
+}
diff --git a/vendor/github.com/spiffe/go-spiffe/v2/bundle/jwtbundle/source.go b/vendor/github.com/spiffe/go-spiffe/v2/bundle/jwtbundle/source.go
new file mode 100644
index 0000000..224cd9f
--- /dev/null
+++ b/vendor/github.com/spiffe/go-spiffe/v2/bundle/jwtbundle/source.go
@@ -0,0 +1,12 @@
+package jwtbundle
+
+import (
+ "github.com/spiffe/go-spiffe/v2/spiffeid"
+)
+
+// Source represents a source of JWT bundles keyed by trust domain.
+type Source interface {
+ // GetJWTBundleForTrustDomain returns the JWT bundle for the given trust
+ // domain.
+ GetJWTBundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*Bundle, error)
+}
diff --git a/vendor/github.com/spiffe/go-spiffe/v2/bundle/spiffebundle/bundle.go b/vendor/github.com/spiffe/go-spiffe/v2/bundle/spiffebundle/bundle.go
new file mode 100644
index 0000000..13b103e
--- /dev/null
+++ b/vendor/github.com/spiffe/go-spiffe/v2/bundle/spiffebundle/bundle.go
@@ -0,0 +1,485 @@
+package spiffebundle
+
+import (
+ "crypto"
+ "crypto/x509"
+ "encoding/json"
+ "errors"
+ "io"
+ "os"
+ "sync"
+ "time"
+
+ "github.com/go-jose/go-jose/v4"
+ "github.com/spiffe/go-spiffe/v2/bundle/jwtbundle"
+ "github.com/spiffe/go-spiffe/v2/bundle/x509bundle"
+ "github.com/spiffe/go-spiffe/v2/internal/jwtutil"
+ "github.com/spiffe/go-spiffe/v2/internal/x509util"
+ "github.com/spiffe/go-spiffe/v2/spiffeid"
+ "github.com/zeebo/errs"
+)
+
+const (
+ x509SVIDUse = "x509-svid"
+ jwtSVIDUse = "jwt-svid"
+)
+
+var spiffebundleErr = errs.Class("spiffebundle")
+
+type bundleDoc struct {
+ jose.JSONWebKeySet
+ SequenceNumber *uint64 `json:"spiffe_sequence,omitempty"`
+ RefreshHint *int64 `json:"spiffe_refresh_hint,omitempty"`
+}
+
+// Bundle is a collection of trusted public key material for a trust domain,
+// conforming to the SPIFFE Bundle Format as part of the SPIFFE Trust Domain
+// and Bundle specification:
+// https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE_Trust_Domain_and_Bundle.md
+type Bundle struct {
+ trustDomain spiffeid.TrustDomain
+
+ mtx sync.RWMutex
+ refreshHint *time.Duration
+ sequenceNumber *uint64
+ jwtAuthorities map[string]crypto.PublicKey
+ x509Authorities []*x509.Certificate
+}
+
+// New creates a new bundle.
+func New(trustDomain spiffeid.TrustDomain) *Bundle {
+ return &Bundle{
+ trustDomain: trustDomain,
+ jwtAuthorities: make(map[string]crypto.PublicKey),
+ }
+}
+
+// Load loads a bundle from a file on disk. The file must contain a JWKS
+// document following the SPIFFE Trust Domain and Bundle specification.
+func Load(trustDomain spiffeid.TrustDomain, path string) (*Bundle, error) {
+ bundleBytes, err := os.ReadFile(path)
+ if err != nil {
+ return nil, spiffebundleErr.New("unable to read SPIFFE bundle: %w", err)
+ }
+
+ return Parse(trustDomain, bundleBytes)
+}
+
+// Read decodes a bundle from a reader. The contents must contain a JWKS
+// document following the SPIFFE Trust Domain and Bundle specification.
+func Read(trustDomain spiffeid.TrustDomain, r io.Reader) (*Bundle, error) {
+ b, err := io.ReadAll(r)
+ if err != nil {
+ return nil, spiffebundleErr.New("unable to read: %v", err)
+ }
+
+ return Parse(trustDomain, b)
+}
+
+// Parse parses a bundle from bytes. The data must be a JWKS document following
+// the SPIFFE Trust Domain and Bundle specification.
+func Parse(trustDomain spiffeid.TrustDomain, bundleBytes []byte) (*Bundle, error) {
+ jwks := &bundleDoc{}
+ if err := json.Unmarshal(bundleBytes, jwks); err != nil {
+ return nil, spiffebundleErr.New("unable to parse JWKS: %v", err)
+ }
+
+ bundle := New(trustDomain)
+ if jwks.RefreshHint != nil {
+ bundle.SetRefreshHint(time.Second * time.Duration(*jwks.RefreshHint))
+ }
+ if jwks.SequenceNumber != nil {
+ bundle.SetSequenceNumber(*jwks.SequenceNumber)
+ }
+
+ if jwks.Keys == nil {
+ // The parameter keys MUST be present.
+ // https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE_Trust_Domain_and_Bundle.md#413-keys
+ return nil, spiffebundleErr.New("no authorities found")
+ }
+ for i, key := range jwks.Keys {
+ switch key.Use {
+ // Two SVID types are supported: x509-svid and jwt-svid.
+ case x509SVIDUse:
+ if len(key.Certificates) != 1 {
+ return nil, spiffebundleErr.New("expected a single certificate in %s entry %d; got %d", x509SVIDUse, i, len(key.Certificates))
+ }
+ bundle.AddX509Authority(key.Certificates[0])
+ case jwtSVIDUse:
+ if err := bundle.AddJWTAuthority(key.KeyID, key.Key); err != nil {
+ return nil, spiffebundleErr.New("error adding authority %d of JWKS: %v", i, errors.Unwrap(err))
+ }
+ }
+ }
+
+ return bundle, nil
+}
+
+// FromX509Bundle creates a bundle from an X.509 bundle.
+// The function panics in case of a nil X.509 bundle.
+func FromX509Bundle(x509Bundle *x509bundle.Bundle) *Bundle {
+ bundle := New(x509Bundle.TrustDomain())
+ bundle.x509Authorities = x509Bundle.X509Authorities()
+ return bundle
+}
+
+// FromJWTBundle creates a bundle from a JWT bundle.
+// The function panics in case of a nil JWT bundle.
+func FromJWTBundle(jwtBundle *jwtbundle.Bundle) *Bundle {
+ bundle := New(jwtBundle.TrustDomain())
+ bundle.jwtAuthorities = jwtBundle.JWTAuthorities()
+ return bundle
+}
+
+// FromX509Authorities creates a bundle from X.509 certificates.
+func FromX509Authorities(trustDomain spiffeid.TrustDomain, x509Authorities []*x509.Certificate) *Bundle {
+ bundle := New(trustDomain)
+ bundle.x509Authorities = x509util.CopyX509Authorities(x509Authorities)
+ return bundle
+}
+
+// FromJWTAuthorities creates a new bundle from JWT authorities.
+func FromJWTAuthorities(trustDomain spiffeid.TrustDomain, jwtAuthorities map[string]crypto.PublicKey) *Bundle {
+ bundle := New(trustDomain)
+ bundle.jwtAuthorities = jwtutil.CopyJWTAuthorities(jwtAuthorities)
+ return bundle
+}
+
+// TrustDomain returns the trust domain that the bundle belongs to.
+func (b *Bundle) TrustDomain() spiffeid.TrustDomain {
+ return b.trustDomain
+}
+
+// X509Authorities returns the X.509 authorities in the bundle.
+func (b *Bundle) X509Authorities() []*x509.Certificate {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+
+ return x509util.CopyX509Authorities(b.x509Authorities)
+}
+
+// AddX509Authority adds an X.509 authority to the bundle. If the authority already
+// exists in the bundle, the contents of the bundle will remain unchanged.
+func (b *Bundle) AddX509Authority(x509Authority *x509.Certificate) {
+ b.mtx.Lock()
+ defer b.mtx.Unlock()
+
+ for _, r := range b.x509Authorities {
+ if r.Equal(x509Authority) {
+ return
+ }
+ }
+
+ b.x509Authorities = append(b.x509Authorities, x509Authority)
+}
+
+// RemoveX509Authority removes an X.509 authority from the bundle.
+func (b *Bundle) RemoveX509Authority(x509Authority *x509.Certificate) {
+ b.mtx.Lock()
+ defer b.mtx.Unlock()
+
+ for i, r := range b.x509Authorities {
+ if r.Equal(x509Authority) {
+ b.x509Authorities = append(b.x509Authorities[:i], b.x509Authorities[i+1:]...)
+ return
+ }
+ }
+}
+
+// HasX509Authority checks if the given X.509 authority exists in the bundle.
+func (b *Bundle) HasX509Authority(x509Authority *x509.Certificate) bool {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+
+ for _, r := range b.x509Authorities {
+ if r.Equal(x509Authority) {
+ return true
+ }
+ }
+ return false
+}
+
+// SetX509Authorities sets the X.509 authorities in the bundle.
+func (b *Bundle) SetX509Authorities(authorities []*x509.Certificate) {
+ b.mtx.Lock()
+ defer b.mtx.Unlock()
+
+ b.x509Authorities = x509util.CopyX509Authorities(authorities)
+}
+
+// JWTAuthorities returns the JWT authorities in the bundle, keyed by key ID.
+func (b *Bundle) JWTAuthorities() map[string]crypto.PublicKey {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+
+ return jwtutil.CopyJWTAuthorities(b.jwtAuthorities)
+}
+
+// FindJWTAuthority finds the JWT authority with the given key ID from the bundle. If the authority
+// is found, it is returned and the boolean is true. Otherwise, the returned
+// value is nil and the boolean is false.
+func (b *Bundle) FindJWTAuthority(keyID string) (crypto.PublicKey, bool) {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+
+ jwtAuthority, ok := b.jwtAuthorities[keyID]
+ return jwtAuthority, ok
+}
+
+// HasJWTAuthority returns true if the bundle has a JWT authority with the given key ID.
+func (b *Bundle) HasJWTAuthority(keyID string) bool {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+
+ _, ok := b.jwtAuthorities[keyID]
+ return ok
+}
+
+// AddJWTAuthority adds a JWT authority to the bundle. If a JWT authority already exists
+// under the given key ID, it is replaced. A key ID must be specified.
+func (b *Bundle) AddJWTAuthority(keyID string, jwtAuthority crypto.PublicKey) error {
+ if keyID == "" {
+ return spiffebundleErr.New("keyID cannot be empty")
+ }
+
+ b.mtx.Lock()
+ defer b.mtx.Unlock()
+
+ b.jwtAuthorities[keyID] = jwtAuthority
+ return nil
+}
+
+// RemoveJWTAuthority removes the JWT authority identified by the key ID from the bundle.
+func (b *Bundle) RemoveJWTAuthority(keyID string) {
+ b.mtx.Lock()
+ defer b.mtx.Unlock()
+
+ delete(b.jwtAuthorities, keyID)
+}
+
+// SetJWTAuthorities sets the JWT authorities in the bundle.
+func (b *Bundle) SetJWTAuthorities(jwtAuthorities map[string]crypto.PublicKey) {
+ b.mtx.Lock()
+ defer b.mtx.Unlock()
+
+ b.jwtAuthorities = jwtutil.CopyJWTAuthorities(jwtAuthorities)
+}
+
+// Empty returns true if the bundle has no X.509 and JWT authorities.
+func (b *Bundle) Empty() bool {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+
+ return len(b.x509Authorities) == 0 && len(b.jwtAuthorities) == 0
+}
+
+// RefreshHint returns the refresh hint. If the refresh hint is set in
+// the bundle, it is returned and the boolean is true. Otherwise, the returned
+// value is zero and the boolean is false.
+func (b *Bundle) RefreshHint() (refreshHint time.Duration, ok bool) {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+
+ if b.refreshHint != nil {
+ return *b.refreshHint, true
+ }
+ return 0, false
+}
+
+// SetRefreshHint sets the refresh hint. The refresh hint value will be
+// truncated to time.Second.
+func (b *Bundle) SetRefreshHint(refreshHint time.Duration) {
+ b.mtx.Lock()
+ defer b.mtx.Unlock()
+
+ b.refreshHint = &refreshHint
+}
+
+// ClearRefreshHint clears the refresh hint.
+func (b *Bundle) ClearRefreshHint() {
+ b.mtx.Lock()
+ defer b.mtx.Unlock()
+
+ b.refreshHint = nil
+}
+
+// SequenceNumber returns the sequence number. If the sequence number is set in
+// the bundle, it is returned and the boolean is true. Otherwise, the returned
+// value is zero and the boolean is false.
+func (b *Bundle) SequenceNumber() (uint64, bool) {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+
+ if b.sequenceNumber != nil {
+ return *b.sequenceNumber, true
+ }
+ return 0, false
+}
+
+// SetSequenceNumber sets the sequence number.
+func (b *Bundle) SetSequenceNumber(sequenceNumber uint64) {
+ b.mtx.Lock()
+ defer b.mtx.Unlock()
+
+ b.sequenceNumber = &sequenceNumber
+}
+
+// ClearSequenceNumber clears the sequence number.
+func (b *Bundle) ClearSequenceNumber() {
+ b.mtx.Lock()
+ defer b.mtx.Unlock()
+
+ b.sequenceNumber = nil
+}
+
+// Marshal marshals the bundle according to the SPIFFE Trust Domain and Bundle
+// specification. The trust domain is not marshaled as part of the bundle and
+// must be conveyed separately. See the specification for details.
+func (b *Bundle) Marshal() ([]byte, error) {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+
+ jwks := bundleDoc{}
+ if b.refreshHint != nil {
+ tr := int64((*b.refreshHint + (time.Second - 1)) / time.Second)
+ jwks.RefreshHint = &tr
+ }
+ jwks.SequenceNumber = b.sequenceNumber
+ for _, x509Authority := range b.x509Authorities {
+ jwks.Keys = append(jwks.Keys, jose.JSONWebKey{
+ Key: x509Authority.PublicKey,
+ Certificates: []*x509.Certificate{x509Authority},
+ Use: x509SVIDUse,
+ })
+ }
+
+ for keyID, jwtAuthority := range b.jwtAuthorities {
+ jwks.Keys = append(jwks.Keys, jose.JSONWebKey{
+ Key: jwtAuthority,
+ KeyID: keyID,
+ Use: jwtSVIDUse,
+ })
+ }
+
+ return json.Marshal(jwks)
+}
+
+// Clone clones the bundle.
+func (b *Bundle) Clone() *Bundle {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+
+ return &Bundle{
+ trustDomain: b.trustDomain,
+ refreshHint: copyRefreshHint(b.refreshHint),
+ sequenceNumber: copySequenceNumber(b.sequenceNumber),
+ x509Authorities: x509util.CopyX509Authorities(b.x509Authorities),
+ jwtAuthorities: jwtutil.CopyJWTAuthorities(b.jwtAuthorities),
+ }
+}
+
+// X509Bundle returns an X.509 bundle containing the X.509 authorities in the SPIFFE
+// bundle.
+func (b *Bundle) X509Bundle() *x509bundle.Bundle {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+
+ // FromX509Authorities makes a copy, so we can pass our internal slice directly.
+ return x509bundle.FromX509Authorities(b.trustDomain, b.x509Authorities)
+}
+
+// JWTBundle returns a JWT bundle containing the JWT authorities in the SPIFFE bundle.
+func (b *Bundle) JWTBundle() *jwtbundle.Bundle {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+
+ // FromJWTBundle makes a copy, so we can pass our internal slice directly.
+ return jwtbundle.FromJWTAuthorities(b.trustDomain, b.jwtAuthorities)
+}
+
+// GetBundleForTrustDomain returns the SPIFFE bundle for the given trust
+// domain. It implements the Source interface. An error will be returned if the
+// trust domain does not match that of the bundle.
+func (b *Bundle) GetBundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*Bundle, error) {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+
+ if b.trustDomain != trustDomain {
+ return nil, spiffebundleErr.New("no SPIFFE bundle for trust domain %q", trustDomain)
+ }
+
+ return b, nil
+}
+
+// GetX509BundleForTrustDomain returns the X.509 bundle for the given trust
+// domain. It implements the x509bundle.Source interface. An error will be
+// returned if the trust domain does not match that of the bundle.
+func (b *Bundle) GetX509BundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*x509bundle.Bundle, error) {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+
+ if b.trustDomain != trustDomain {
+ return nil, spiffebundleErr.New("no X.509 bundle for trust domain %q", trustDomain)
+ }
+
+ return b.X509Bundle(), nil
+}
+
+// GetJWTBundleForTrustDomain returns the JWT bundle of the given trust domain.
+// It implements the jwtbundle.Source interface. An error will be returned if
+// the trust domain does not match that of the bundle.
+func (b *Bundle) GetJWTBundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*jwtbundle.Bundle, error) {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+
+ if b.trustDomain != trustDomain {
+ return nil, spiffebundleErr.New("no JWT bundle for trust domain %q", trustDomain)
+ }
+
+ return b.JWTBundle(), nil
+}
+
+// Equal compares the bundle for equality against the given bundle.
+func (b *Bundle) Equal(other *Bundle) bool {
+ if b == nil || other == nil {
+ return b == other
+ }
+
+ return b.trustDomain == other.trustDomain &&
+ refreshHintEqual(b.refreshHint, other.refreshHint) &&
+ sequenceNumberEqual(b.sequenceNumber, other.sequenceNumber) &&
+ jwtutil.JWTAuthoritiesEqual(b.jwtAuthorities, other.jwtAuthorities) &&
+ x509util.CertsEqual(b.x509Authorities, other.x509Authorities)
+}
+
+func refreshHintEqual(a, b *time.Duration) bool {
+ if a == nil || b == nil {
+ return a == b
+ }
+
+ return *a == *b
+}
+
+func sequenceNumberEqual(a, b *uint64) bool {
+ if a == nil || b == nil {
+ return a == b
+ }
+
+ return *a == *b
+}
+
+func copyRefreshHint(refreshHint *time.Duration) *time.Duration {
+ if refreshHint == nil {
+ return nil
+ }
+ copied := *refreshHint
+ return &copied
+}
+
+func copySequenceNumber(sequenceNumber *uint64) *uint64 {
+ if sequenceNumber == nil {
+ return nil
+ }
+ copied := *sequenceNumber
+ return &copied
+}
diff --git a/vendor/github.com/spiffe/go-spiffe/v2/bundle/spiffebundle/doc.go b/vendor/github.com/spiffe/go-spiffe/v2/bundle/spiffebundle/doc.go
new file mode 100644
index 0000000..db9dcde
--- /dev/null
+++ b/vendor/github.com/spiffe/go-spiffe/v2/bundle/spiffebundle/doc.go
@@ -0,0 +1,59 @@
+// Package spiffebundle provides SPIFFE bundle related functionality.
+//
+// A bundle represents a SPIFFE bundle, a collection authorities for
+// authenticating SVIDs.
+//
+// You can create a new bundle for a specific trust domain:
+//
+// td := spiffeid.RequireTrustDomainFromString("example.org")
+// bundle := spiffebundle.New(td)
+//
+// Or you can load it from disk:
+//
+// td := spiffeid.RequireTrustDomainFromString("example.org")
+// bundle := spiffebundle.Load(td, "bundle.json")
+//
+// The bundle can be initialized with X.509 or JWT authorities:
+//
+// td := spiffeid.RequireTrustDomainFromString("example.org")
+//
+// var x509Authorities []*x509.Certificate = ...
+// bundle := spiffebundle.FromX509Authorities(td, x509Authorities)
+// // ... or ...
+// var jwtAuthorities map[string]crypto.PublicKey = ...
+// bundle := spiffebundle.FromJWTAuthorities(td, jwtAuthorities)
+//
+// In addition, you can add authorities to the bundle:
+//
+// var x509CA *x509.Certificate = ...
+// bundle.AddX509Authority(x509CA)
+// var keyID string = ...
+// var publicKey crypto.PublicKey = ...
+// bundle.AddJWTAuthority(keyID, publicKey)
+//
+// Bundles can be organized into a set, keyed by trust domain:
+//
+// set := spiffebundle.NewSet()
+// set.Add(bundle)
+//
+// A Source is source of bundles for a trust domain. Both the
+// Bundle and Set types implement Source:
+//
+// // Initialize the source from a bundle or set
+// var source spiffebundle.Source = bundle
+// // ... or ...
+// var source spiffebundle.Source = set
+//
+// // Use the source to query for X.509 bundles by trust domain
+// bundle, err := source.GetBundleForTrustDomain(td)
+//
+// Additionally the Bundle and Set types also implement the x509bundle.Source and jwtbundle.Source interfaces:
+//
+// // As an x509bundle.Source...
+// var source x509bundle.Source = bundle // or set
+// x509Bundle, err := source.GetX509BundleForTrustDomain(td)
+//
+// // As a jwtbundle.Source...
+// var source jwtbundle.Source = bundle // or set
+// jwtBundle, err := source.GetJWTBundleForTrustDomain(td)
+package spiffebundle
diff --git a/vendor/github.com/spiffe/go-spiffe/v2/bundle/spiffebundle/set.go b/vendor/github.com/spiffe/go-spiffe/v2/bundle/spiffebundle/set.go
new file mode 100644
index 0000000..2738135
--- /dev/null
+++ b/vendor/github.com/spiffe/go-spiffe/v2/bundle/spiffebundle/set.go
@@ -0,0 +1,135 @@
+package spiffebundle
+
+import (
+ "sort"
+ "sync"
+
+ "github.com/spiffe/go-spiffe/v2/bundle/jwtbundle"
+ "github.com/spiffe/go-spiffe/v2/bundle/x509bundle"
+ "github.com/spiffe/go-spiffe/v2/spiffeid"
+)
+
+// Set is a set of bundles, keyed by trust domain.
+type Set struct {
+ mtx sync.RWMutex
+ bundles map[spiffeid.TrustDomain]*Bundle
+}
+
+// NewSet creates a new set initialized with the given bundles.
+func NewSet(bundles ...*Bundle) *Set {
+ bundlesMap := make(map[spiffeid.TrustDomain]*Bundle)
+
+ for _, b := range bundles {
+ if b != nil {
+ bundlesMap[b.trustDomain] = b
+ }
+ }
+
+ return &Set{
+ bundles: bundlesMap,
+ }
+}
+
+// Add adds a new bundle into the set. If a bundle already exists for the
+// trust domain, the existing bundle is replaced.
+func (s *Set) Add(bundle *Bundle) {
+ s.mtx.Lock()
+ defer s.mtx.Unlock()
+
+ if bundle != nil {
+ s.bundles[bundle.trustDomain] = bundle
+ }
+}
+
+// Remove removes the bundle for the given trust domain.
+func (s *Set) Remove(trustDomain spiffeid.TrustDomain) {
+ s.mtx.Lock()
+ defer s.mtx.Unlock()
+
+ delete(s.bundles, trustDomain)
+}
+
+// Has returns true if there is a bundle for the given trust domain.
+func (s *Set) Has(trustDomain spiffeid.TrustDomain) bool {
+ s.mtx.RLock()
+ defer s.mtx.RUnlock()
+
+ _, ok := s.bundles[trustDomain]
+ return ok
+}
+
+// Get returns a bundle for the given trust domain. If the bundle is in the set
+// it is returned and the boolean is true. Otherwise, the returned value is
+// nil and the boolean is false.
+func (s *Set) Get(trustDomain spiffeid.TrustDomain) (*Bundle, bool) {
+ s.mtx.RLock()
+ defer s.mtx.RUnlock()
+
+ bundle, ok := s.bundles[trustDomain]
+ return bundle, ok
+}
+
+// Bundles returns the bundles in the set sorted by trust domain.
+func (s *Set) Bundles() []*Bundle {
+ s.mtx.RLock()
+ defer s.mtx.RUnlock()
+
+ out := make([]*Bundle, 0, len(s.bundles))
+ for _, bundle := range s.bundles {
+ out = append(out, bundle)
+ }
+ sort.Slice(out, func(a, b int) bool {
+ return out[a].TrustDomain().Compare(out[b].TrustDomain()) < 0
+ })
+ return out
+}
+
+// Len returns the number of bundles in the set.
+func (s *Set) Len() int {
+ s.mtx.RLock()
+ defer s.mtx.RUnlock()
+
+ return len(s.bundles)
+}
+
+// GetBundleForTrustDomain returns the SPIFFE bundle for the given trust
+// domain. It implements the Source interface.
+func (s *Set) GetBundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*Bundle, error) {
+ s.mtx.RLock()
+ defer s.mtx.RUnlock()
+
+ bundle, ok := s.bundles[trustDomain]
+ if !ok {
+ return nil, spiffebundleErr.New("no SPIFFE bundle for trust domain %q", trustDomain)
+ }
+
+ return bundle, nil
+}
+
+// GetX509BundleForTrustDomain returns the X.509 bundle for the given trust
+// domain. It implements the x509bundle.Source interface.
+func (s *Set) GetX509BundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*x509bundle.Bundle, error) {
+ s.mtx.RLock()
+ defer s.mtx.RUnlock()
+
+ bundle, ok := s.bundles[trustDomain]
+ if !ok {
+ return nil, spiffebundleErr.New("no X.509 bundle for trust domain %q", trustDomain)
+ }
+
+ return bundle.X509Bundle(), nil
+}
+
+// GetJWTBundleForTrustDomain returns the JWT bundle for the given trust
+// domain. It implements the jwtbundle.Source interface.
+func (s *Set) GetJWTBundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*jwtbundle.Bundle, error) {
+ s.mtx.RLock()
+ defer s.mtx.RUnlock()
+
+ bundle, ok := s.bundles[trustDomain]
+ if !ok {
+ return nil, spiffebundleErr.New("no JWT bundle for trust domain %q", trustDomain)
+ }
+
+ return bundle.JWTBundle(), nil
+}
diff --git a/vendor/github.com/spiffe/go-spiffe/v2/bundle/spiffebundle/source.go b/vendor/github.com/spiffe/go-spiffe/v2/bundle/spiffebundle/source.go
new file mode 100644
index 0000000..f4d3712
--- /dev/null
+++ b/vendor/github.com/spiffe/go-spiffe/v2/bundle/spiffebundle/source.go
@@ -0,0 +1,10 @@
+package spiffebundle
+
+import "github.com/spiffe/go-spiffe/v2/spiffeid"
+
+// Source represents a source of SPIFFE bundles keyed by trust domain.
+type Source interface {
+ // GetBundleForTrustDomain returns the SPIFFE bundle for the given trust
+ // domain.
+ GetBundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*Bundle, error)
+}
diff --git a/vendor/github.com/spiffe/go-spiffe/v2/bundle/x509bundle/bundle.go b/vendor/github.com/spiffe/go-spiffe/v2/bundle/x509bundle/bundle.go
new file mode 100644
index 0000000..a70bb62
--- /dev/null
+++ b/vendor/github.com/spiffe/go-spiffe/v2/bundle/x509bundle/bundle.go
@@ -0,0 +1,202 @@
+package x509bundle
+
+import (
+ "crypto/x509"
+ "io"
+ "os"
+ "sync"
+
+ "github.com/spiffe/go-spiffe/v2/internal/pemutil"
+ "github.com/spiffe/go-spiffe/v2/internal/x509util"
+ "github.com/spiffe/go-spiffe/v2/spiffeid"
+ "github.com/zeebo/errs"
+)
+
+var x509bundleErr = errs.Class("x509bundle")
+
+// Bundle is a collection of trusted X.509 authorities for a trust domain.
+type Bundle struct {
+ trustDomain spiffeid.TrustDomain
+
+ mtx sync.RWMutex
+ x509Authorities []*x509.Certificate
+}
+
+// New creates a new bundle.
+func New(trustDomain spiffeid.TrustDomain) *Bundle {
+ return &Bundle{
+ trustDomain: trustDomain,
+ }
+}
+
+// FromX509Authorities creates a bundle from X.509 certificates.
+func FromX509Authorities(trustDomain spiffeid.TrustDomain, authorities []*x509.Certificate) *Bundle {
+ return &Bundle{
+ trustDomain: trustDomain,
+ x509Authorities: x509util.CopyX509Authorities(authorities),
+ }
+}
+
+// Load loads a bundle from a file on disk. The file must contain PEM-encoded
+// certificate blocks.
+func Load(trustDomain spiffeid.TrustDomain, path string) (*Bundle, error) {
+ fileBytes, err := os.ReadFile(path)
+ if err != nil {
+ return nil, x509bundleErr.New("unable to load X.509 bundle file: %w", err)
+ }
+
+ return Parse(trustDomain, fileBytes)
+}
+
+// Read decodes a bundle from a reader. The contents must be PEM-encoded
+// certificate blocks.
+func Read(trustDomain spiffeid.TrustDomain, r io.Reader) (*Bundle, error) {
+ b, err := io.ReadAll(r)
+ if err != nil {
+ return nil, x509bundleErr.New("unable to read X.509 bundle: %v", err)
+ }
+
+ return Parse(trustDomain, b)
+}
+
+// Parse parses a bundle from bytes. The data must be PEM-encoded certificate
+// blocks.
+func Parse(trustDomain spiffeid.TrustDomain, b []byte) (*Bundle, error) {
+ bundle := New(trustDomain)
+ if len(b) == 0 {
+ return bundle, nil
+ }
+
+ certs, err := pemutil.ParseCertificates(b)
+ if err != nil {
+ return nil, x509bundleErr.New("cannot parse certificate: %v", err)
+ }
+ for _, cert := range certs {
+ bundle.AddX509Authority(cert)
+ }
+ return bundle, nil
+}
+
+// ParseRaw parses a bundle from bytes. The certificate must be ASN.1 DER (concatenated
+// with no intermediate padding if there are more than one certificate)
+func ParseRaw(trustDomain spiffeid.TrustDomain, b []byte) (*Bundle, error) {
+ bundle := New(trustDomain)
+ if len(b) == 0 {
+ return bundle, nil
+ }
+
+ certs, err := x509.ParseCertificates(b)
+ if err != nil {
+ return nil, x509bundleErr.New("cannot parse certificate: %v", err)
+ }
+ for _, cert := range certs {
+ bundle.AddX509Authority(cert)
+ }
+ return bundle, nil
+}
+
+// TrustDomain returns the trust domain that the bundle belongs to.
+func (b *Bundle) TrustDomain() spiffeid.TrustDomain {
+ return b.trustDomain
+}
+
+// X509Authorities returns the X.509 x509Authorities in the bundle.
+func (b *Bundle) X509Authorities() []*x509.Certificate {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+ return x509util.CopyX509Authorities(b.x509Authorities)
+}
+
+// AddX509Authority adds an X.509 authority to the bundle. If the authority already
+// exists in the bundle, the contents of the bundle will remain unchanged.
+func (b *Bundle) AddX509Authority(x509Authority *x509.Certificate) {
+ b.mtx.Lock()
+ defer b.mtx.Unlock()
+
+ for _, r := range b.x509Authorities {
+ if r.Equal(x509Authority) {
+ return
+ }
+ }
+
+ b.x509Authorities = append(b.x509Authorities, x509Authority)
+}
+
+// RemoveX509Authority removes an X.509 authority from the bundle.
+func (b *Bundle) RemoveX509Authority(x509Authority *x509.Certificate) {
+ b.mtx.Lock()
+ defer b.mtx.Unlock()
+
+ for i, r := range b.x509Authorities {
+ if r.Equal(x509Authority) {
+ // remove element from slice
+ b.x509Authorities = append(b.x509Authorities[:i], b.x509Authorities[i+1:]...)
+ return
+ }
+ }
+}
+
+// HasX509Authority checks if the given X.509 authority exists in the bundle.
+func (b *Bundle) HasX509Authority(x509Authority *x509.Certificate) bool {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+
+ for _, r := range b.x509Authorities {
+ if r.Equal(x509Authority) {
+ return true
+ }
+ }
+ return false
+}
+
+// SetX509Authorities sets the X.509 authorities in the bundle.
+func (b *Bundle) SetX509Authorities(x509Authorities []*x509.Certificate) {
+ b.mtx.Lock()
+ defer b.mtx.Unlock()
+
+ b.x509Authorities = x509util.CopyX509Authorities(x509Authorities)
+}
+
+// Empty returns true if the bundle has no X.509 x509Authorities.
+func (b *Bundle) Empty() bool {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+
+ return len(b.x509Authorities) == 0
+}
+
+// Marshal marshals the X.509 bundle into PEM-encoded certificate blocks.
+func (b *Bundle) Marshal() ([]byte, error) {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+ return pemutil.EncodeCertificates(b.x509Authorities), nil
+}
+
+// Equal compares the bundle for equality against the given bundle.
+func (b *Bundle) Equal(other *Bundle) bool {
+ if b == nil || other == nil {
+ return b == other
+ }
+
+ return b.trustDomain == other.trustDomain &&
+ x509util.CertsEqual(b.x509Authorities, other.x509Authorities)
+}
+
+// Clone clones the bundle.
+func (b *Bundle) Clone() *Bundle {
+ b.mtx.RLock()
+ defer b.mtx.RUnlock()
+
+ return FromX509Authorities(b.trustDomain, b.x509Authorities)
+}
+
+// GetX509BundleForTrustDomain returns the X.509 bundle for the given trust
+// domain. It implements the Source interface. An error will be
+// returned if the trust domain does not match that of the bundle.
+func (b *Bundle) GetX509BundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*Bundle, error) {
+ if b.trustDomain != trustDomain {
+ return nil, x509bundleErr.New("no X.509 bundle found for trust domain: %q", trustDomain)
+ }
+
+ return b, nil
+}
diff --git a/vendor/github.com/spiffe/go-spiffe/v2/bundle/x509bundle/doc.go b/vendor/github.com/spiffe/go-spiffe/v2/bundle/x509bundle/doc.go
new file mode 100644
index 0000000..889554f
--- /dev/null
+++ b/vendor/github.com/spiffe/go-spiffe/v2/bundle/x509bundle/doc.go
@@ -0,0 +1,42 @@
+// Package x509bundle provides X.509 bundle related functionality.
+//
+// A bundle represents a collection of X.509 authorities, i.e., those that
+// are used to authenticate SPIFFE X509-SVIDs.
+//
+// You can create a new bundle for a specific trust domain:
+//
+// td := spiffeid.RequireTrustDomainFromString("example.org")
+// bundle := x509bundle.New(td)
+//
+// Or you can load it from disk:
+//
+// td := spiffeid.RequireTrustDomainFromString("example.org")
+// bundle := x509bundle.Load(td, "bundle.pem")
+//
+// The bundle can be initialized with X.509 authorities:
+//
+// td := spiffeid.RequireTrustDomainFromString("example.org")
+// var x509Authorities []*x509.Certificate = ...
+// bundle := x509bundle.FromX509Authorities(td, x509Authorities)
+//
+// In addition, you can add X.509 authorities to the bundle:
+//
+// var x509CA *x509.Certificate = ...
+// bundle.AddX509Authority(x509CA)
+//
+// Bundles can be organized into a set, keyed by trust domain:
+//
+// set := x509bundle.NewSet()
+// set.Add(bundle)
+//
+// A Source is source of X.509 bundles for a trust domain. Both the Bundle
+// and Set types implement Source:
+//
+// // Initialize the source from a bundle or set
+// var source x509bundle.Source = bundle
+// // ... or ...
+// var source x509bundle.Source = set
+//
+// // Use the source to query for bundles by trust domain
+// bundle, err := source.GetX509BundleForTrustDomain(td)
+package x509bundle
diff --git a/vendor/github.com/spiffe/go-spiffe/v2/bundle/x509bundle/set.go b/vendor/github.com/spiffe/go-spiffe/v2/bundle/x509bundle/set.go
new file mode 100644
index 0000000..522e249
--- /dev/null
+++ b/vendor/github.com/spiffe/go-spiffe/v2/bundle/x509bundle/set.go
@@ -0,0 +1,105 @@
+package x509bundle
+
+import (
+ "sort"
+ "sync"
+
+ "github.com/spiffe/go-spiffe/v2/spiffeid"
+)
+
+// Set is a set of bundles, keyed by trust domain.
+type Set struct {
+ mtx sync.RWMutex
+ bundles map[spiffeid.TrustDomain]*Bundle
+}
+
+// NewSet creates a new set initialized with the given bundles.
+func NewSet(bundles ...*Bundle) *Set {
+ bundlesMap := make(map[spiffeid.TrustDomain]*Bundle)
+
+ for _, b := range bundles {
+ if b != nil {
+ bundlesMap[b.trustDomain] = b
+ }
+ }
+
+ return &Set{
+ bundles: bundlesMap,
+ }
+}
+
+// Add adds a new bundle into the set. If a bundle already exists for the
+// trust domain, the existing bundle is replaced.
+func (s *Set) Add(bundle *Bundle) {
+ s.mtx.Lock()
+ defer s.mtx.Unlock()
+
+ if bundle != nil {
+ s.bundles[bundle.trustDomain] = bundle
+ }
+}
+
+// Remove removes the bundle for the given trust domain.
+func (s *Set) Remove(trustDomain spiffeid.TrustDomain) {
+ s.mtx.Lock()
+ defer s.mtx.Unlock()
+
+ delete(s.bundles, trustDomain)
+}
+
+// Has returns true if there is a bundle for the given trust domain.
+func (s *Set) Has(trustDomain spiffeid.TrustDomain) bool {
+ s.mtx.RLock()
+ defer s.mtx.RUnlock()
+
+ _, ok := s.bundles[trustDomain]
+ return ok
+}
+
+// Get returns a bundle for the given trust domain. If the bundle is in the set
+// it is returned and the boolean is true. Otherwise, the returned value is
+// nil and the boolean is false.
+func (s *Set) Get(trustDomain spiffeid.TrustDomain) (*Bundle, bool) {
+ s.mtx.RLock()
+ defer s.mtx.RUnlock()
+
+ bundle, ok := s.bundles[trustDomain]
+ return bundle, ok
+}
+
+// Bundles returns the bundles in the set sorted by trust domain.
+func (s *Set) Bundles() []*Bundle {
+ s.mtx.RLock()
+ defer s.mtx.RUnlock()
+
+ out := make([]*Bundle, 0, len(s.bundles))
+ for _, bundle := range s.bundles {
+ out = append(out, bundle)
+ }
+ sort.Slice(out, func(a, b int) bool {
+ return out[a].TrustDomain().Compare(out[b].TrustDomain()) < 0
+ })
+ return out
+}
+
+// Len returns the number of bundles in the set.
+func (s *Set) Len() int {
+ s.mtx.RLock()
+ defer s.mtx.RUnlock()
+
+ return len(s.bundles)
+}
+
+// GetX509BundleForTrustDomain returns the X.509 bundle for the given trust
+// domain. It implements the Source interface.
+func (s *Set) GetX509BundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*Bundle, error) {
+ s.mtx.RLock()
+ defer s.mtx.RUnlock()
+
+ bundle, ok := s.bundles[trustDomain]
+ if !ok {
+ return nil, x509bundleErr.New("no X.509 bundle for trust domain %q", trustDomain)
+ }
+
+ return bundle, nil
+}
diff --git a/vendor/github.com/spiffe/go-spiffe/v2/bundle/x509bundle/source.go b/vendor/github.com/spiffe/go-spiffe/v2/bundle/x509bundle/source.go
new file mode 100644
index 0000000..2244635
--- /dev/null
+++ b/vendor/github.com/spiffe/go-spiffe/v2/bundle/x509bundle/source.go
@@ -0,0 +1,12 @@
+package x509bundle
+
+import (
+ "github.com/spiffe/go-spiffe/v2/spiffeid"
+)
+
+// Source represents a source of X.509 bundles keyed by trust domain.
+type Source interface {
+ // GetX509BundleForTrustDomain returns the X.509 bundle for the given trust
+ // domain.
+ GetX509BundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*Bundle, error)
+}