From 8f73995e3bb98713c55cb9fdaf28900495b1a6a5 Mon Sep 17 00:00:00 2001 From: junya koyama Date: Mon, 4 Nov 2024 00:41:05 +0900 Subject: [PATCH 01/13] Bump github.com/zeebo/errs from 1.3.0 to 1.4.0 in /v2 Signed-off-by: junya koyama --- v2/bundle/jwtbundle/bundle.go | 3 ++- v2/bundle/spiffebundle/bundle.go | 3 ++- v2/go.mod | 2 +- v2/go.sum | 4 ++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/v2/bundle/jwtbundle/bundle.go b/v2/bundle/jwtbundle/bundle.go index ff2fcd7..ebd3cac 100644 --- a/v2/bundle/jwtbundle/bundle.go +++ b/v2/bundle/jwtbundle/bundle.go @@ -3,6 +3,7 @@ package jwtbundle import ( "crypto" "encoding/json" + "errors" "io" "os" "sync" @@ -69,7 +70,7 @@ func Parse(trustDomain spiffeid.TrustDomain, bundleBytes []byte) (*Bundle, error 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, errs.Unwrap(err)) + return nil, jwtbundleErr.New("error adding authority %d of JWKS: %v", i, errors.Unwrap(err)) } } diff --git a/v2/bundle/spiffebundle/bundle.go b/v2/bundle/spiffebundle/bundle.go index be17642..13b103e 100644 --- a/v2/bundle/spiffebundle/bundle.go +++ b/v2/bundle/spiffebundle/bundle.go @@ -4,6 +4,7 @@ import ( "crypto" "crypto/x509" "encoding/json" + "errors" "io" "os" "sync" @@ -106,7 +107,7 @@ func Parse(trustDomain spiffeid.TrustDomain, bundleBytes []byte) (*Bundle, error 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, errs.Unwrap(err)) + return nil, spiffebundleErr.New("error adding authority %d of JWKS: %v", i, errors.Unwrap(err)) } } } diff --git a/v2/go.mod b/v2/go.mod index 1aaa679..66c7112 100644 --- a/v2/go.mod +++ b/v2/go.mod @@ -6,7 +6,7 @@ require ( github.com/Microsoft/go-winio v0.6.2 github.com/go-jose/go-jose/v4 v4.0.4 github.com/stretchr/testify v1.9.0 - github.com/zeebo/errs v1.3.0 + github.com/zeebo/errs v1.4.0 google.golang.org/grpc v1.67.1 google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20 google.golang.org/protobuf v1.34.2 diff --git a/v2/go.sum b/v2/go.sum index b44aac2..11b6894 100644 --- a/v2/go.sum +++ b/v2/go.sum @@ -15,8 +15,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/zeebo/errs v1.3.0 h1:hmiaKqgYZzcVgRL1Vkc1Mn2914BbzB0IBxs+ebeutGs= -github.com/zeebo/errs v1.3.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= +github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= +github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= From f3f486e9a5af18e550d7e1b5ef695af904965136 Mon Sep 17 00:00:00 2001 From: junya koyama Date: Mon, 4 Nov 2024 01:34:01 +0900 Subject: [PATCH 02/13] remove errs.Class("federation") Signed-off-by: junya koyama --- v2/federation/fetch.go | 19 +++++++++++-------- v2/federation/watch.go | 3 ++- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/v2/federation/fetch.go b/v2/federation/fetch.go index 11349b0..505bf63 100644 --- a/v2/federation/fetch.go +++ b/v2/federation/fetch.go @@ -4,17 +4,16 @@ import ( "context" "crypto/tls" "crypto/x509" + "errors" + "fmt" "net/http" "github.com/spiffe/go-spiffe/v2/bundle/spiffebundle" "github.com/spiffe/go-spiffe/v2/bundle/x509bundle" "github.com/spiffe/go-spiffe/v2/spiffeid" "github.com/spiffe/go-spiffe/v2/spiffetls/tlsconfig" - "github.com/zeebo/errs" ) -var federationErr = errs.Class("federation") - // FetchOption is an option used when dialing the bundle endpoint. type FetchOption interface { apply(*fetchOptions) error @@ -32,7 +31,7 @@ type fetchOptions struct { func WithSPIFFEAuth(bundleSource x509bundle.Source, endpointID spiffeid.ID) FetchOption { return fetchOption(func(o *fetchOptions) error { if o.authMethod != authMethodDefault { - return federationErr.New("cannot use both SPIFFE and Web PKI authentication") + return wrapFederationErr(errors.New("cannot use both SPIFFE and Web PKI authentication")) } o.transport.TLSClientConfig = tlsconfig.TLSClientConfig(bundleSource, tlsconfig.AuthorizeID(endpointID)) o.authMethod = authMethodSPIFFE @@ -46,7 +45,7 @@ func WithSPIFFEAuth(bundleSource x509bundle.Source, endpointID spiffeid.ID) Fetc func WithWebPKIRoots(rootCAs *x509.CertPool) FetchOption { return fetchOption(func(o *fetchOptions) error { if o.authMethod != authMethodDefault { - return federationErr.New("cannot use both SPIFFE and Web PKI authentication") + return wrapFederationErr(errors.New("cannot use both SPIFFE and Web PKI authentication")) } o.transport.TLSClientConfig = &tls.Config{ RootCAs: rootCAs, @@ -73,22 +72,26 @@ func FetchBundle(ctx context.Context, trustDomain spiffeid.TrustDomain, url stri } request, err := http.NewRequestWithContext(ctx, http.MethodGet, url, http.NoBody) if err != nil { - return nil, federationErr.New("could not create request: %w", err) + return nil, wrapFederationErr(fmt.Errorf("could not create request: %w", err)) } response, err := client.Do(request) if err != nil { - return nil, federationErr.New("could not GET bundle: %w", err) + return nil, wrapFederationErr(fmt.Errorf("could not GET bundle: %w", err)) } defer response.Body.Close() bundle, err := spiffebundle.Read(trustDomain, response.Body) if err != nil { - return nil, federationErr.Wrap(err) + return nil, wrapFederationErr(err) } return bundle, nil } +func wrapFederationErr(err error) error { + return fmt.Errorf("federation: %w", err) +} + type fetchOption func(*fetchOptions) error func (fo fetchOption) apply(opts *fetchOptions) error { diff --git a/v2/federation/watch.go b/v2/federation/watch.go index 1afa18e..1c654ea 100644 --- a/v2/federation/watch.go +++ b/v2/federation/watch.go @@ -2,6 +2,7 @@ package federation import ( "context" + "errors" "time" "github.com/spiffe/go-spiffe/v2/bundle/spiffebundle" @@ -36,7 +37,7 @@ type BundleWatcher interface { // context is canceled, returning ctx.Err(). func WatchBundle(ctx context.Context, trustDomain spiffeid.TrustDomain, url string, watcher BundleWatcher, options ...FetchOption) error { if watcher == nil { - return federationErr.New("watcher cannot be nil") + return wrapFederationErr(errors.New("watcher cannot be nil")) } latestBundle := &spiffebundle.Bundle{} From 90e3b3cc5ec3f8ba5a71f809d798a8c397f0ede2 Mon Sep 17 00:00:00 2001 From: junya koyama Date: Mon, 4 Nov 2024 01:44:35 +0900 Subject: [PATCH 03/13] remove errs.Class("jwtbundle") Signed-off-by: junya koyama --- v2/bundle/jwtbundle/bundle.go | 20 +++++++++++--------- v2/bundle/jwtbundle/set.go | 3 ++- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/v2/bundle/jwtbundle/bundle.go b/v2/bundle/jwtbundle/bundle.go index ebd3cac..78cdadd 100644 --- a/v2/bundle/jwtbundle/bundle.go +++ b/v2/bundle/jwtbundle/bundle.go @@ -4,6 +4,7 @@ import ( "crypto" "encoding/json" "errors" + "fmt" "io" "os" "sync" @@ -11,11 +12,8 @@ import ( "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 @@ -44,7 +42,7 @@ func FromJWTAuthorities(trustDomain spiffeid.TrustDomain, jwtAuthorities map[str 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 nil, wrapJwtbundleErr(fmt.Errorf("unable to read JWT bundle: %w", err)) } return Parse(trustDomain, bundleBytes) @@ -54,7 +52,7 @@ func Load(trustDomain spiffeid.TrustDomain, path string) (*Bundle, error) { 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 nil, wrapJwtbundleErr(fmt.Errorf("unable to read: %v", err)) } return Parse(trustDomain, b) @@ -64,13 +62,13 @@ func Read(trustDomain spiffeid.TrustDomain, r io.Reader) (*Bundle, error) { 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) + return nil, wrapJwtbundleErr(fmt.Errorf("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 nil, wrapJwtbundleErr(fmt.Errorf("error adding authority %d of JWKS: %v", i, errors.Unwrap(err))) } } @@ -116,7 +114,7 @@ func (b *Bundle) HasJWTAuthority(keyID string) bool { // 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") + return wrapJwtbundleErr(errors.New("keyID cannot be empty")) } b.mtx.Lock() @@ -193,8 +191,12 @@ func (b *Bundle) GetJWTBundleForTrustDomain(trustDomain spiffeid.TrustDomain) (* defer b.mtx.RUnlock() if b.trustDomain != trustDomain { - return nil, jwtbundleErr.New("no JWT bundle for trust domain %q", trustDomain) + return nil, wrapJwtbundleErr(fmt.Errorf("no JWT bundle for trust domain %q", trustDomain)) } return b, nil } + +func wrapJwtbundleErr(err error) error { + return fmt.Errorf("jwtbundle: %w", err) +} diff --git a/v2/bundle/jwtbundle/set.go b/v2/bundle/jwtbundle/set.go index 048dd0d..ec0836e 100644 --- a/v2/bundle/jwtbundle/set.go +++ b/v2/bundle/jwtbundle/set.go @@ -1,6 +1,7 @@ package jwtbundle import ( + "fmt" "sort" "sync" @@ -98,7 +99,7 @@ func (s *Set) GetJWTBundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*Bun bundle, ok := s.bundles[trustDomain] if !ok { - return nil, jwtbundleErr.New("no JWT bundle for trust domain %q", trustDomain) + return nil, wrapJwtbundleErr(fmt.Errorf("no JWT bundle for trust domain %q", trustDomain)) } return bundle, nil From b5625f4900625918b698c64aca3cb9cd4bc50661 Mon Sep 17 00:00:00 2001 From: junya koyama Date: Mon, 4 Nov 2024 02:02:25 +0900 Subject: [PATCH 04/13] remove errs.Class("spiffebundle") Signed-off-by: junya koyama --- v2/bundle/spiffebundle/bundle.go | 28 +++++++++++++++------------- v2/bundle/spiffebundle/set.go | 7 ++++--- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/v2/bundle/spiffebundle/bundle.go b/v2/bundle/spiffebundle/bundle.go index 13b103e..712ec63 100644 --- a/v2/bundle/spiffebundle/bundle.go +++ b/v2/bundle/spiffebundle/bundle.go @@ -5,6 +5,7 @@ import ( "crypto/x509" "encoding/json" "errors" + "fmt" "io" "os" "sync" @@ -16,7 +17,6 @@ import ( "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 ( @@ -24,8 +24,6 @@ const ( jwtSVIDUse = "jwt-svid" ) -var spiffebundleErr = errs.Class("spiffebundle") - type bundleDoc struct { jose.JSONWebKeySet SequenceNumber *uint64 `json:"spiffe_sequence,omitempty"` @@ -59,7 +57,7 @@ func New(trustDomain spiffeid.TrustDomain) *Bundle { 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 nil, wrapSpiffebundleErr(fmt.Errorf("unable to read SPIFFE bundle: %w", err)) } return Parse(trustDomain, bundleBytes) @@ -70,7 +68,7 @@ func Load(trustDomain spiffeid.TrustDomain, path string) (*Bundle, error) { 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 nil, wrapSpiffebundleErr(fmt.Errorf("unable to read: %v", err)) } return Parse(trustDomain, b) @@ -81,7 +79,7 @@ func Read(trustDomain spiffeid.TrustDomain, r io.Reader) (*Bundle, error) { 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) + return nil, wrapSpiffebundleErr(fmt.Errorf("unable to parse JWKS: %v", err)) } bundle := New(trustDomain) @@ -95,19 +93,19 @@ func Parse(trustDomain spiffeid.TrustDomain, bundleBytes []byte) (*Bundle, error 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") + return nil, wrapSpiffebundleErr(errors.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)) + return nil, wrapSpiffebundleErr(fmt.Errorf("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 nil, wrapSpiffebundleErr(fmt.Errorf("error adding authority %d of JWKS: %v", i, errors.Unwrap(err))) } } } @@ -239,7 +237,7 @@ func (b *Bundle) HasJWTAuthority(keyID string) bool { // 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") + return wrapSpiffebundleErr(errors.New("keyID cannot be empty")) } b.mtx.Lock() @@ -405,7 +403,7 @@ func (b *Bundle) GetBundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*Bun defer b.mtx.RUnlock() if b.trustDomain != trustDomain { - return nil, spiffebundleErr.New("no SPIFFE bundle for trust domain %q", trustDomain) + return nil, wrapSpiffebundleErr(fmt.Errorf("no SPIFFE bundle for trust domain %q", trustDomain)) } return b, nil @@ -419,7 +417,7 @@ func (b *Bundle) GetX509BundleForTrustDomain(trustDomain spiffeid.TrustDomain) ( defer b.mtx.RUnlock() if b.trustDomain != trustDomain { - return nil, spiffebundleErr.New("no X.509 bundle for trust domain %q", trustDomain) + return nil, wrapSpiffebundleErr(fmt.Errorf("no X.509 bundle for trust domain %q", trustDomain)) } return b.X509Bundle(), nil @@ -433,7 +431,7 @@ func (b *Bundle) GetJWTBundleForTrustDomain(trustDomain spiffeid.TrustDomain) (* defer b.mtx.RUnlock() if b.trustDomain != trustDomain { - return nil, spiffebundleErr.New("no JWT bundle for trust domain %q", trustDomain) + return nil, wrapSpiffebundleErr(fmt.Errorf("no JWT bundle for trust domain %q", trustDomain)) } return b.JWTBundle(), nil @@ -483,3 +481,7 @@ func copySequenceNumber(sequenceNumber *uint64) *uint64 { copied := *sequenceNumber return &copied } + +func wrapSpiffebundleErr(err error) error { + return fmt.Errorf("spiffebundle: %w", err) +} diff --git a/v2/bundle/spiffebundle/set.go b/v2/bundle/spiffebundle/set.go index 2738135..e0d5d45 100644 --- a/v2/bundle/spiffebundle/set.go +++ b/v2/bundle/spiffebundle/set.go @@ -1,6 +1,7 @@ package spiffebundle import ( + "fmt" "sort" "sync" @@ -100,7 +101,7 @@ func (s *Set) GetBundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*Bundle bundle, ok := s.bundles[trustDomain] if !ok { - return nil, spiffebundleErr.New("no SPIFFE bundle for trust domain %q", trustDomain) + return nil, wrapSpiffebundleErr(fmt.Errorf("no SPIFFE bundle for trust domain %q", trustDomain)) } return bundle, nil @@ -114,7 +115,7 @@ func (s *Set) GetX509BundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*x5 bundle, ok := s.bundles[trustDomain] if !ok { - return nil, spiffebundleErr.New("no X.509 bundle for trust domain %q", trustDomain) + return nil, wrapSpiffebundleErr(fmt.Errorf("no X.509 bundle for trust domain %q", trustDomain)) } return bundle.X509Bundle(), nil @@ -128,7 +129,7 @@ func (s *Set) GetJWTBundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*jwt bundle, ok := s.bundles[trustDomain] if !ok { - return nil, spiffebundleErr.New("no JWT bundle for trust domain %q", trustDomain) + return nil, wrapSpiffebundleErr(fmt.Errorf("no JWT bundle for trust domain %q", trustDomain)) } return bundle.JWTBundle(), nil From 48402f2b4ba2cc01a7195e1c134f2ef68b53fbd4 Mon Sep 17 00:00:00 2001 From: junya koyama Date: Mon, 4 Nov 2024 02:07:29 +0900 Subject: [PATCH 05/13] remove errs.Class("x509bundle") Signed-off-by: junya koyama --- v2/bundle/x509bundle/bundle.go | 18 ++++++++++-------- v2/bundle/x509bundle/set.go | 3 ++- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/v2/bundle/x509bundle/bundle.go b/v2/bundle/x509bundle/bundle.go index a70bb62..4cc816d 100644 --- a/v2/bundle/x509bundle/bundle.go +++ b/v2/bundle/x509bundle/bundle.go @@ -2,6 +2,7 @@ package x509bundle import ( "crypto/x509" + "fmt" "io" "os" "sync" @@ -9,11 +10,8 @@ import ( "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 @@ -42,7 +40,7 @@ func FromX509Authorities(trustDomain spiffeid.TrustDomain, authorities []*x509.C 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 nil, wrapX509bundleErr(fmt.Errorf("unable to load X.509 bundle file: %w", err)) } return Parse(trustDomain, fileBytes) @@ -53,7 +51,7 @@ func Load(trustDomain spiffeid.TrustDomain, path string) (*Bundle, error) { 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 nil, wrapX509bundleErr(fmt.Errorf("unable to read X.509 bundle: %v", err)) } return Parse(trustDomain, b) @@ -69,7 +67,7 @@ func Parse(trustDomain spiffeid.TrustDomain, b []byte) (*Bundle, error) { certs, err := pemutil.ParseCertificates(b) if err != nil { - return nil, x509bundleErr.New("cannot parse certificate: %v", err) + return nil, wrapX509bundleErr(fmt.Errorf("cannot parse certificate: %v", err)) } for _, cert := range certs { bundle.AddX509Authority(cert) @@ -87,7 +85,7 @@ func ParseRaw(trustDomain spiffeid.TrustDomain, b []byte) (*Bundle, error) { certs, err := x509.ParseCertificates(b) if err != nil { - return nil, x509bundleErr.New("cannot parse certificate: %v", err) + return nil, wrapX509bundleErr(fmt.Errorf("cannot parse certificate: %v", err)) } for _, cert := range certs { bundle.AddX509Authority(cert) @@ -195,8 +193,12 @@ func (b *Bundle) Clone() *Bundle { // 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 nil, wrapX509bundleErr(fmt.Errorf("no X.509 bundle found for trust domain: %q", trustDomain)) } return b, nil } + +func wrapX509bundleErr(err error) error { + return fmt.Errorf("x509bundle: %w", err) +} diff --git a/v2/bundle/x509bundle/set.go b/v2/bundle/x509bundle/set.go index 522e249..9a90d40 100644 --- a/v2/bundle/x509bundle/set.go +++ b/v2/bundle/x509bundle/set.go @@ -1,6 +1,7 @@ package x509bundle import ( + "fmt" "sort" "sync" @@ -98,7 +99,7 @@ func (s *Set) GetX509BundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*Bu bundle, ok := s.bundles[trustDomain] if !ok { - return nil, x509bundleErr.New("no X.509 bundle for trust domain %q", trustDomain) + return nil, wrapX509bundleErr(fmt.Errorf("no X.509 bundle for trust domain %q", trustDomain)) } return bundle, nil From fb1243b9fceddfcea4009f0f6024f7a708b5c872 Mon Sep 17 00:00:00 2001 From: junya koyama Date: Mon, 4 Nov 2024 02:17:33 +0900 Subject: [PATCH 06/13] remove errs.Class("spiffetls") Signed-off-by: junya koyama --- v2/spiffetls/dial.go | 9 +++++---- v2/spiffetls/listen.go | 9 +++++---- v2/spiffetls/option.go | 8 +++++--- v2/spiffetls/peerid.go | 8 +++++--- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/v2/spiffetls/dial.go b/v2/spiffetls/dial.go index 1f05183..3ce0595 100644 --- a/v2/spiffetls/dial.go +++ b/v2/spiffetls/dial.go @@ -3,6 +3,7 @@ package spiffetls import ( "context" "crypto/tls" + "fmt" "io" "net" @@ -31,7 +32,7 @@ func DialWithMode(ctx context.Context, network, addr string, mode DialMode, opti if source == nil { source, err = workloadapi.NewX509Source(ctx, m.options...) if err != nil { - return nil, spiffetlsErr.New("cannot create X.509 source: %w", err) + return nil, wrapSpiffetlsErr(fmt.Errorf("cannot create X.509 source: %w", err)) } // Close source if there is a failure after this point defer func() { @@ -63,7 +64,7 @@ func DialWithMode(ctx context.Context, network, addr string, mode DialMode, opti case mtlsWebClientMode: tlsconfig.HookMTLSWebClientConfig(tlsConfig, m.svid, m.roots, opt.tlsOptions...) default: - return nil, spiffetlsErr.New("unknown client mode: %v", m.mode) + return nil, wrapSpiffetlsErr(fmt.Errorf("unknown client mode: %v", m.mode)) } var conn *tls.Conn @@ -73,7 +74,7 @@ func DialWithMode(ctx context.Context, network, addr string, mode DialMode, opti conn, err = tls.Dial(network, addr, tlsConfig) } if err != nil { - return nil, spiffetlsErr.New("unable to dial: %w", err) + return nil, wrapSpiffetlsErr(fmt.Errorf("unable to dial: %w", err)) } return &clientConn{ @@ -93,7 +94,7 @@ func (c *clientConn) Close() error { group.Add(c.sourceCloser.Close()) } if err := c.Conn.Close(); err != nil { - group.Add(spiffetlsErr.New("unable to close TLS connection: %w", err)) + group.Add(wrapSpiffetlsErr(fmt.Errorf("unable to close TLS connection: %w", err))) } return group.Err() } diff --git a/v2/spiffetls/listen.go b/v2/spiffetls/listen.go index 1edc961..5c559a4 100644 --- a/v2/spiffetls/listen.go +++ b/v2/spiffetls/listen.go @@ -3,6 +3,7 @@ package spiffetls import ( "context" "crypto/tls" + "fmt" "io" "net" @@ -63,7 +64,7 @@ func NewListenerWithMode(ctx context.Context, inner net.Listener, mode ListenMod if source == nil { source, err = workloadapi.NewX509Source(ctx, m.options...) if err != nil { - return nil, spiffetlsErr.New("cannot create X.509 source: %w", err) + return nil, wrapSpiffetlsErr(fmt.Errorf("cannot create X.509 source: %w", err)) } // Close source if there is a failure after this point defer func() { @@ -95,7 +96,7 @@ func NewListenerWithMode(ctx context.Context, inner net.Listener, mode ListenMod case mtlsWebServerMode: tlsconfig.HookMTLSWebServerConfig(tlsConfig, m.cert, m.bundle, m.authorizer) default: - return nil, spiffetlsErr.New("unknown server mode: %v", m.mode) + return nil, wrapSpiffetlsErr(fmt.Errorf("unknown server mode: %v", m.mode)) } return &listener{ @@ -118,7 +119,7 @@ func (l *listener) Accept() (net.Conn, error) { if !ok { // This is purely defensive. The TLS listeners return tls.Conn's by contract. conn.Close() - return nil, spiffetlsErr.New("unexpected conn type %T returned by TLS listener", conn) + return nil, wrapSpiffetlsErr(fmt.Errorf("unexpected conn type %T returned by TLS listener", conn)) } return &serverConn{Conn: tlsConn}, nil } @@ -133,7 +134,7 @@ func (l *listener) Close() error { group.Add(l.sourceCloser.Close()) } if err := l.inner.Close(); err != nil { - group.Add(spiffetlsErr.New("unable to close TLS connection: %w", err)) + group.Add(wrapSpiffetlsErr(fmt.Errorf("unable to close TLS connection: %w", err))) } return group.Err() } diff --git a/v2/spiffetls/option.go b/v2/spiffetls/option.go index 00e38d6..f999b5b 100644 --- a/v2/spiffetls/option.go +++ b/v2/spiffetls/option.go @@ -2,14 +2,12 @@ package spiffetls import ( "crypto/tls" + "fmt" "net" "github.com/spiffe/go-spiffe/v2/spiffetls/tlsconfig" - "github.com/zeebo/errs" ) -var spiffetlsErr = errs.Class("spiffetls") - // DialOption is an option for dialing. Option's are also DialOption's. type DialOption interface { apply(*dialConfig) @@ -82,3 +80,7 @@ func WithListenTLSOptions(opts ...tlsconfig.Option) ListenOption { c.tlsOptions = opts }) } + +func wrapSpiffetlsErr(err error) error { + return fmt.Errorf("spiffetls: %w", err) +} diff --git a/v2/spiffetls/peerid.go b/v2/spiffetls/peerid.go index 0c050d3..4f3ff52 100644 --- a/v2/spiffetls/peerid.go +++ b/v2/spiffetls/peerid.go @@ -2,6 +2,8 @@ package spiffetls import ( "crypto/tls" + "errors" + "fmt" "net" "github.com/spiffe/go-spiffe/v2/spiffeid" @@ -19,7 +21,7 @@ func PeerIDFromConn(conn net.Conn) (spiffeid.ID, error) { if getter, ok := conn.(PeerIDGetter); ok { return getter.PeerID() } - return spiffeid.ID{}, spiffetlsErr.New("connection does not expose peer ID") + return spiffeid.ID{}, wrapSpiffetlsErr(errors.New("connection does not expose peer ID")) } func PeerIDFromConnectionState(state tls.ConnectionState) (spiffeid.ID, error) { @@ -28,11 +30,11 @@ func PeerIDFromConnectionState(state tls.ConnectionState) (spiffeid.ID, error) { // sets VerifiedChains if it is the one to verify the chain of trust. The // SPIFFE ID must be extracted from the peer certificates. if len(state.PeerCertificates) == 0 { - return spiffeid.ID{}, spiffetlsErr.New("no peer certificates") + return spiffeid.ID{}, wrapSpiffetlsErr(errors.New("no peer certificates")) } id, err := x509svid.IDFromCert(state.PeerCertificates[0]) if err != nil { - return spiffeid.ID{}, spiffetlsErr.New("invalid peer certificate: %w", err) + return spiffeid.ID{}, wrapSpiffetlsErr(fmt.Errorf("invalid peer certificate: %w", err)) } return id, nil } From 470aa5cc620ae7e5d07370e6b0e3e160b0040bdf Mon Sep 17 00:00:00 2001 From: junya koyama Date: Mon, 4 Nov 2024 02:25:34 +0900 Subject: [PATCH 07/13] remove errs.Class("jwtsvid") Signed-off-by: junya koyama --- v2/svid/jwtsvid/svid.go | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/v2/svid/jwtsvid/svid.go b/v2/svid/jwtsvid/svid.go index d46f800..ce320ed 100644 --- a/v2/svid/jwtsvid/svid.go +++ b/v2/svid/jwtsvid/svid.go @@ -1,13 +1,14 @@ package jwtsvid import ( + "errors" + "fmt" "time" "github.com/go-jose/go-jose/v4" "github.com/go-jose/go-jose/v4/jwt" "github.com/spiffe/go-spiffe/v2/bundle/jwtbundle" "github.com/spiffe/go-spiffe/v2/spiffeid" - "github.com/zeebo/errs" ) var ( @@ -22,8 +23,6 @@ var ( jose.PS384, jose.PS512, } - - jwtsvidErr = errs.Class("jwtsvid") ) // tokenValidator validates the token and returns the claims @@ -54,25 +53,25 @@ func ParseAndValidate(token string, bundles jwtbundle.Source, audience []string) // Obtain the key ID from the header keyID := tok.Headers[0].KeyID if keyID == "" { - return nil, jwtsvidErr.New("token header missing key id") + return nil, wrapJwtsvidErr(errors.New("token header missing key id")) } // Get JWT Bundle bundle, err := bundles.GetJWTBundleForTrustDomain(trustDomain) if err != nil { - return nil, jwtsvidErr.New("no bundle found for trust domain %q", trustDomain) + return nil, wrapJwtsvidErr(fmt.Errorf("no bundle found for trust domain %q", trustDomain)) } // Find JWT authority using the key ID from the token header authority, ok := bundle.FindJWTAuthority(keyID) if !ok { - return nil, jwtsvidErr.New("no JWT authority %q found for trust domain %q", keyID, trustDomain) + return nil, wrapJwtsvidErr(fmt.Errorf("no JWT authority %q found for trust domain %q", keyID, trustDomain)) } // Obtain and verify the token claims using the obtained JWT authority claimsMap := make(map[string]interface{}) if err := tok.Claims(authority, &claimsMap); err != nil { - return nil, jwtsvidErr.New("unable to get claims from token: %v", err) + return nil, wrapJwtsvidErr(fmt.Errorf("unable to get claims from token: %v", err)) } return claimsMap, nil @@ -86,7 +85,7 @@ func ParseInsecure(token string, audience []string) (*SVID, error) { // Obtain the token claims insecurely, i.e. without signature verification claimsMap := make(map[string]interface{}) if err := tok.UnsafeClaimsWithoutVerification(&claimsMap); err != nil { - return nil, jwtsvidErr.New("unable to get claims from token: %v", err) + return nil, wrapJwtsvidErr(fmt.Errorf("unable to get claims from token: %v", err)) } return claimsMap, nil @@ -103,26 +102,26 @@ func parse(token string, audience []string, getClaims tokenValidator) (*SVID, er // Parse serialized token tok, err := jwt.ParseSigned(token, allowedSignatureAlgorithms) if err != nil { - return nil, jwtsvidErr.New("unable to parse JWT token") + return nil, wrapJwtsvidErr(errors.New("unable to parse JWT token")) } // Parse out the unverified claims. We need to look up the key by the trust // domain of the SPIFFE ID. var claims jwt.Claims if err := tok.UnsafeClaimsWithoutVerification(&claims); err != nil { - return nil, jwtsvidErr.New("unable to get claims from token: %v", err) + return nil, wrapJwtsvidErr(fmt.Errorf("unable to get claims from token: %v", err)) } switch { case claims.Subject == "": - return nil, jwtsvidErr.New("token missing subject claim") + return nil, wrapJwtsvidErr(errors.New("token missing subject claim")) case claims.Expiry == nil: - return nil, jwtsvidErr.New("token missing exp claim") + return nil, wrapJwtsvidErr(errors.New("token missing exp claim")) } spiffeID, err := spiffeid.FromString(claims.Subject) if err != nil { - return nil, jwtsvidErr.New("token has an invalid subject claim: %v", err) + return nil, wrapJwtsvidErr(fmt.Errorf("token has an invalid subject claim: %v", err)) } // Create generic map of claims @@ -139,9 +138,9 @@ func parse(token string, audience []string, getClaims tokenValidator) (*SVID, er // Convert expected validation errors for pretty errors switch err { case jwt.ErrExpired: - err = jwtsvidErr.New("token has expired") + err = wrapJwtsvidErr(errors.New("token has expired")) case jwt.ErrInvalidAudience: - err = jwtsvidErr.New("expected audience in %q (audience=%q)", audience, claims.Audience) + err = wrapJwtsvidErr(fmt.Errorf("expected audience in %q (audience=%q)", audience, claims.Audience)) } return nil, err } @@ -154,3 +153,7 @@ func parse(token string, audience []string, getClaims tokenValidator) (*SVID, er token: token, }, nil } + +func wrapJwtsvidErr(err error) error { + return fmt.Errorf("jwtsvid: %w", err) +} From 1851e0f8abf73e36ca1d3e0f301795bf76ef4176 Mon Sep 17 00:00:00 2001 From: junya koyama Date: Mon, 4 Nov 2024 02:42:02 +0900 Subject: [PATCH 08/13] remove errs.Class("x509svid") Signed-off-by: junya koyama --- v2/svid/x509svid/svid.go | 51 +++++++++++++++++++------------------- v2/svid/x509svid/verify.go | 31 ++++++++++++----------- 2 files changed, 43 insertions(+), 39 deletions(-) diff --git a/v2/svid/x509svid/svid.go b/v2/svid/x509svid/svid.go index 7302f3a..c2e234d 100644 --- a/v2/svid/x509svid/svid.go +++ b/v2/svid/x509svid/svid.go @@ -7,12 +7,13 @@ import ( "crypto/ed25519" "crypto/rsa" "crypto/x509" + "errors" + "fmt" "os" "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" ) // SVID represents a SPIFFE X509-SVID. @@ -39,12 +40,12 @@ type SVID struct { func Load(certFile, keyFile string) (*SVID, error) { certBytes, err := os.ReadFile(certFile) if err != nil { - return nil, x509svidErr.New("cannot read certificate file: %w", err) + return nil, wrapX509svidErr(fmt.Errorf("cannot read certificate file: %w", err)) } keyBytes, err := os.ReadFile(keyFile) if err != nil { - return nil, x509svidErr.New("cannot read key file: %w", err) + return nil, wrapX509svidErr(fmt.Errorf("cannot read key file: %w", err)) } return Parse(certBytes, keyBytes) @@ -56,12 +57,12 @@ func Load(certFile, keyFile string) (*SVID, error) { func Parse(certBytes, keyBytes []byte) (*SVID, error) { certs, err := pemutil.ParseCertificates(certBytes) if err != nil { - return nil, x509svidErr.New("cannot parse PEM encoded certificate: %v", err) + return nil, wrapX509svidErr(fmt.Errorf("cannot parse PEM encoded certificate: %v", err)) } privateKey, err := pemutil.ParsePrivateKey(keyBytes) if err != nil { - return nil, x509svidErr.New("cannot parse PEM encoded private key: %v", err) + return nil, wrapX509svidErr(fmt.Errorf("cannot parse PEM encoded private key: %v", err)) } return newSVID(certs, privateKey) @@ -74,12 +75,12 @@ func Parse(certBytes, keyBytes []byte) (*SVID, error) { func ParseRaw(certBytes, keyBytes []byte) (*SVID, error) { certificates, err := x509.ParseCertificates(certBytes) if err != nil { - return nil, x509svidErr.New("cannot parse DER encoded certificate: %v", err) + return nil, wrapX509svidErr(fmt.Errorf("cannot parse DER encoded certificate: %v", err)) } privateKey, err := x509.ParsePKCS8PrivateKey(keyBytes) if err != nil { - return nil, x509svidErr.New("cannot parse DER encoded private key: %v", err) + return nil, wrapX509svidErr(fmt.Errorf("cannot parse DER encoded private key: %v", err)) } return newSVID(certificates, privateKey) @@ -89,12 +90,12 @@ func ParseRaw(certBytes, keyBytes []byte) (*SVID, error) { // and private key. func (s *SVID) Marshal() ([]byte, []byte, error) { if len(s.Certificates) == 0 { - return nil, nil, x509svidErr.New("no certificates to marshal") + return nil, nil, wrapX509svidErr(errors.New("no certificates to marshal")) } certBytes := pemutil.EncodeCertificates(s.Certificates) keyBytes, err := pemutil.EncodePKCS8PrivateKey(s.PrivateKey) if err != nil { - return nil, nil, x509svidErr.New("cannot encode private key: %v", err) + return nil, nil, wrapX509svidErr(fmt.Errorf("cannot encode private key: %v", err)) } return certBytes, keyBytes, nil @@ -106,11 +107,11 @@ func (s *SVID) Marshal() ([]byte, []byte, error) { func (s *SVID) MarshalRaw() ([]byte, []byte, error) { key, err := x509.MarshalPKCS8PrivateKey(s.PrivateKey) if err != nil { - return nil, nil, x509svidErr.New("cannot marshal private key: %v", err) + return nil, nil, wrapX509svidErr(fmt.Errorf("cannot marshal private key: %v", err)) } if len(s.Certificates) == 0 { - return nil, nil, x509svidErr.New("no certificates to marshal") + return nil, nil, wrapX509svidErr(errors.New("no certificates to marshal")) } certs := x509util.ConcatRawCertsFromCerts(s.Certificates) @@ -125,12 +126,12 @@ func (s *SVID) GetX509SVID() (*SVID, error) { func newSVID(certificates []*x509.Certificate, privateKey crypto.PrivateKey) (*SVID, error) { spiffeID, err := validateCertificates(certificates) if err != nil { - return nil, x509svidErr.New("certificate validation failed: %v", err) + return nil, wrapX509svidErr(fmt.Errorf("certificate validation failed: %v", err)) } signer, err := validatePrivateKey(privateKey, certificates[0]) if err != nil { - return nil, x509svidErr.New("private key validation failed: %v", err) + return nil, wrapX509svidErr(fmt.Errorf("private key validation failed: %v", err)) } return &SVID{ @@ -144,7 +145,7 @@ func newSVID(certificates []*x509.Certificate, privateKey crypto.PrivateKey) (*S // to the spiffe standard and returns the spiffe id of the leaf certificate func validateCertificates(certificates []*x509.Certificate) (*spiffeid.ID, error) { if len(certificates) == 0 { - return nil, errs.New("no certificates found") + return nil, errors.New("no certificates found") } leafID, err := validateLeafCertificate(certificates[0]) @@ -163,10 +164,10 @@ func validateCertificates(certificates []*x509.Certificate) (*spiffeid.ID, error func validateLeafCertificate(leaf *x509.Certificate) (*spiffeid.ID, error) { leafID, err := IDFromCert(leaf) if err != nil { - return nil, errs.New("cannot get leaf certificate SPIFFE ID: %v", err) + return nil, fmt.Errorf("cannot get leaf certificate SPIFFE ID: %v", err) } if leaf.IsCA { - return nil, errs.New("leaf certificate must not have CA flag set to true") + return nil, errors.New("leaf certificate must not have CA flag set to true") } err = validateKeyUsage(leaf) @@ -180,10 +181,10 @@ func validateLeafCertificate(leaf *x509.Certificate) (*spiffeid.ID, error) { func validateSigningCertificates(signingCerts []*x509.Certificate) error { for _, cert := range signingCerts { if !cert.IsCA { - return errs.New("signing certificate must have CA flag set to true") + return errors.New("signing certificate must have CA flag set to true") } if cert.KeyUsage&x509.KeyUsageCertSign == 0 { - return errs.New("signing certificate must have 'keyCertSign' set as key usage") + return errors.New("signing certificate must have 'keyCertSign' set as key usage") } } @@ -193,18 +194,18 @@ func validateSigningCertificates(signingCerts []*x509.Certificate) error { func validateKeyUsage(leaf *x509.Certificate) error { switch { case leaf.KeyUsage&x509.KeyUsageDigitalSignature == 0: - return errs.New("leaf certificate must have 'digitalSignature' set as key usage") + return errors.New("leaf certificate must have 'digitalSignature' set as key usage") case leaf.KeyUsage&x509.KeyUsageCertSign > 0: - return errs.New("leaf certificate must not have 'keyCertSign' set as key usage") + return errors.New("leaf certificate must not have 'keyCertSign' set as key usage") case leaf.KeyUsage&x509.KeyUsageCRLSign > 0: - return errs.New("leaf certificate must not have 'cRLSign' set as key usage") + return errors.New("leaf certificate must not have 'cRLSign' set as key usage") } return nil } func validatePrivateKey(privateKey crypto.PrivateKey, leaf *x509.Certificate) (crypto.Signer, error) { if privateKey == nil { - return nil, errs.New("no private key found") + return nil, errors.New("no private key found") } matched, err := keyMatches(privateKey, leaf.PublicKey) @@ -212,12 +213,12 @@ func validatePrivateKey(privateKey crypto.PrivateKey, leaf *x509.Certificate) (c return nil, err } if !matched { - return nil, errs.New("leaf certificate does not match private key") + return nil, errors.New("leaf certificate does not match private key") } signer, ok := privateKey.(crypto.Signer) if !ok { - return nil, errs.New("expected crypto.Signer; got %T", privateKey) + return nil, fmt.Errorf("expected crypto.Signer; got %T", privateKey) } return signer, nil @@ -235,7 +236,7 @@ func keyMatches(privateKey crypto.PrivateKey, publicKey crypto.PublicKey) (bool, ed25519PublicKey, ok := publicKey.(ed25519.PublicKey) return ok && bytes.Equal(privateKey.Public().(ed25519.PublicKey), ed25519PublicKey), nil default: - return false, errs.New("unsupported private key type %T", privateKey) + return false, fmt.Errorf("unsupported private key type %T", privateKey) } } diff --git a/v2/svid/x509svid/verify.go b/v2/svid/x509svid/verify.go index 681d284..1784501 100644 --- a/v2/svid/x509svid/verify.go +++ b/v2/svid/x509svid/verify.go @@ -2,16 +2,15 @@ package x509svid import ( "crypto/x509" + "errors" + "fmt" "time" "github.com/spiffe/go-spiffe/v2/bundle/x509bundle" "github.com/spiffe/go-spiffe/v2/internal/x509util" "github.com/spiffe/go-spiffe/v2/spiffeid" - "github.com/zeebo/errs" ) -var x509svidErr = errs.Class("x509svid") - // VerifyOption is an option used when verifying X509-SVIDs. type VerifyOption interface { apply(config *verifyConfig) @@ -36,29 +35,29 @@ func Verify(certs []*x509.Certificate, bundleSource x509bundle.Source, opts ...V switch { case len(certs) == 0: - return spiffeid.ID{}, nil, x509svidErr.New("empty certificates chain") + return spiffeid.ID{}, nil, wrapX509svidErr(errors.New("empty certificates chain")) case bundleSource == nil: - return spiffeid.ID{}, nil, x509svidErr.New("bundleSource is required") + return spiffeid.ID{}, nil, wrapX509svidErr(errors.New("bundleSource is required")) } leaf := certs[0] id, err := IDFromCert(leaf) if err != nil { - return spiffeid.ID{}, nil, x509svidErr.New("could not get leaf SPIFFE ID: %w", err) + return spiffeid.ID{}, nil, wrapX509svidErr(fmt.Errorf("could not get leaf SPIFFE ID: %w", err)) } switch { case leaf.IsCA: - return id, nil, x509svidErr.New("leaf certificate with CA flag set to true") + return id, nil, wrapX509svidErr(errors.New("leaf certificate with CA flag set to true")) case leaf.KeyUsage&x509.KeyUsageCertSign > 0: - return id, nil, x509svidErr.New("leaf certificate with KeyCertSign key usage") + return id, nil, wrapX509svidErr(errors.New("leaf certificate with KeyCertSign key usage")) case leaf.KeyUsage&x509.KeyUsageCRLSign > 0: - return id, nil, x509svidErr.New("leaf certificate with KeyCrlSign key usage") + return id, nil, wrapX509svidErr(errors.New("leaf certificate with KeyCrlSign key usage")) } bundle, err := bundleSource.GetX509BundleForTrustDomain(id.TrustDomain()) if err != nil { - return id, nil, x509svidErr.New("could not get X509 bundle: %w", err) + return id, nil, wrapX509svidErr(fmt.Errorf("could not get X509 bundle: %w", err)) } verifiedChains, err := leaf.Verify(x509.VerifyOptions{ @@ -68,7 +67,7 @@ func Verify(certs []*x509.Certificate, bundleSource x509bundle.Source, opts ...V CurrentTime: config.now, }) if err != nil { - return id, nil, x509svidErr.New("could not verify leaf certificate: %w", err) + return id, nil, wrapX509svidErr(fmt.Errorf("could not verify leaf certificate: %w", err)) } return id, verifiedChains, nil @@ -82,7 +81,7 @@ func ParseAndVerify(rawCerts [][]byte, bundleSource x509bundle.Source, opts ...V for _, rawCert := range rawCerts { cert, err := x509.ParseCertificate(rawCert) if err != nil { - return spiffeid.ID{}, nil, x509svidErr.New("unable to parse certificate: %w", err) + return spiffeid.ID{}, nil, wrapX509svidErr(fmt.Errorf("unable to parse certificate: %w", err)) } certs = append(certs, cert) } @@ -95,9 +94,9 @@ func ParseAndVerify(rawCerts [][]byte, bundleSource x509bundle.Source, opts ...V func IDFromCert(cert *x509.Certificate) (spiffeid.ID, error) { switch { case len(cert.URIs) == 0: - return spiffeid.ID{}, errs.New("certificate contains no URI SAN") + return spiffeid.ID{}, errors.New("certificate contains no URI SAN") case len(cert.URIs) > 1: - return spiffeid.ID{}, errs.New("certificate contains more than one URI SAN") + return spiffeid.ID{}, errors.New("certificate contains more than one URI SAN") } return spiffeid.FromURI(cert.URIs[0]) } @@ -111,3 +110,7 @@ type verifyOption func(config *verifyConfig) func (fn verifyOption) apply(config *verifyConfig) { fn(config) } + +func wrapX509svidErr(err error) error { + return fmt.Errorf("x509svid: %w", err) +} From c74b4437307326f45ca5c832f2a0a8dc96e48399 Mon Sep 17 00:00:00 2001 From: junya koyama Date: Mon, 4 Nov 2024 02:46:00 +0900 Subject: [PATCH 09/13] remove errs.Class("bundlesource") Signed-off-by: junya koyama --- v2/workloadapi/bundlesource.go | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/v2/workloadapi/bundlesource.go b/v2/workloadapi/bundlesource.go index 2a253ef..81c7de5 100644 --- a/v2/workloadapi/bundlesource.go +++ b/v2/workloadapi/bundlesource.go @@ -4,17 +4,16 @@ import ( "context" "crypto" "crypto/x509" + "errors" + "fmt" "sync" "github.com/spiffe/go-spiffe/v2/bundle/jwtbundle" "github.com/spiffe/go-spiffe/v2/bundle/spiffebundle" "github.com/spiffe/go-spiffe/v2/bundle/x509bundle" "github.com/spiffe/go-spiffe/v2/spiffeid" - "github.com/zeebo/errs" ) -var bundlesourceErr = errs.Class("bundlesource") - // BundleSource is a source of SPIFFE bundles maintained via the Workload API. type BundleSource struct { watcher *watcher @@ -73,7 +72,7 @@ func (s *BundleSource) GetBundleForTrustDomain(trustDomain spiffeid.TrustDomain) x509Authorities, hasX509Authorities := s.x509Authorities[trustDomain] jwtAuthorities, hasJWTAuthorities := s.jwtAuthorities[trustDomain] if !hasX509Authorities && !hasJWTAuthorities { - return nil, bundlesourceErr.New("no SPIFFE bundle for trust domain %q", trustDomain) + return nil, wrapBundlesourceErr(fmt.Errorf("no SPIFFE bundle for trust domain %q", trustDomain)) } bundle := spiffebundle.New(trustDomain) if hasX509Authorities { @@ -96,7 +95,7 @@ func (s *BundleSource) GetX509BundleForTrustDomain(trustDomain spiffeid.TrustDom x509Authorities, hasX509Authorities := s.x509Authorities[trustDomain] if !hasX509Authorities { - return nil, bundlesourceErr.New("no X.509 bundle for trust domain %q", trustDomain) + return nil, wrapBundlesourceErr(fmt.Errorf("no X.509 bundle for trust domain %q", trustDomain)) } return x509bundle.FromX509Authorities(trustDomain, x509Authorities), nil } @@ -112,7 +111,7 @@ func (s *BundleSource) GetJWTBundleForTrustDomain(trustDomain spiffeid.TrustDoma jwtAuthorities, hasJWTAuthorities := s.jwtAuthorities[trustDomain] if !hasJWTAuthorities { - return nil, bundlesourceErr.New("no JWT bundle for trust domain %q", trustDomain) + return nil, wrapBundlesourceErr(fmt.Errorf("no JWT bundle for trust domain %q", trustDomain)) } return jwtbundle.FromJWTAuthorities(trustDomain, jwtAuthorities), nil } @@ -182,7 +181,11 @@ func (s *BundleSource) checkClosed() error { s.closeMtx.RLock() defer s.closeMtx.RUnlock() if s.closed { - return bundlesourceErr.New("source is closed") + return wrapBundlesourceErr(errors.New("source is closed")) } return nil } + +func wrapBundlesourceErr(err error) error { + return fmt.Errorf("bundlesource: %w", err) +} From 30e174cce1a69f0662f970b7f3cf2a4fb297df7d Mon Sep 17 00:00:00 2001 From: junya koyama Date: Mon, 4 Nov 2024 02:50:12 +0900 Subject: [PATCH 10/13] remove errs.Class("jwtsource") Signed-off-by: junya koyama --- v2/workloadapi/jwtsource.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/v2/workloadapi/jwtsource.go b/v2/workloadapi/jwtsource.go index 1122353..247f5cc 100644 --- a/v2/workloadapi/jwtsource.go +++ b/v2/workloadapi/jwtsource.go @@ -2,16 +2,15 @@ package workloadapi import ( "context" + "errors" + "fmt" "sync" "github.com/spiffe/go-spiffe/v2/bundle/jwtbundle" "github.com/spiffe/go-spiffe/v2/spiffeid" "github.com/spiffe/go-spiffe/v2/svid/jwtsvid" - "github.com/zeebo/errs" ) -var jwtsourceErr = errs.Class("jwtsource") - // JWTSource is a source of JWT-SVID and JWT bundles maintained via the // Workload API. type JWTSource struct { @@ -121,7 +120,11 @@ func (s *JWTSource) checkClosed() error { s.closeMtx.RLock() defer s.closeMtx.RUnlock() if s.closed { - return jwtsourceErr.New("source is closed") + return wrapJwtsourceErr(errors.New("source is closed")) } return nil } + +func wrapJwtsourceErr(err error) error { + return fmt.Errorf("jwtsource: %w", err) +} From 2608ccab2776f22d09f064ba6af34e20916a367a Mon Sep 17 00:00:00 2001 From: junya koyama Date: Mon, 4 Nov 2024 02:53:10 +0900 Subject: [PATCH 11/13] remove errs.Class("x509source") Signed-off-by: junya koyama --- v2/workloadapi/x509source.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/v2/workloadapi/x509source.go b/v2/workloadapi/x509source.go index 28287f6..2a942a9 100644 --- a/v2/workloadapi/x509source.go +++ b/v2/workloadapi/x509source.go @@ -2,16 +2,15 @@ package workloadapi import ( "context" + "errors" + "fmt" "sync" "github.com/spiffe/go-spiffe/v2/bundle/x509bundle" "github.com/spiffe/go-spiffe/v2/spiffeid" "github.com/spiffe/go-spiffe/v2/svid/x509svid" - "github.com/zeebo/errs" ) -var x509sourceErr = errs.Class("x509source") - // X509Source is a source of X509-SVIDs and X.509 bundles maintained via the // Workload API. type X509Source struct { @@ -74,7 +73,7 @@ func (s *X509Source) GetX509SVID() (*x509svid.SVID, error) { // This is a defensive check and should be unreachable since the source // waits for the initial Workload API update before returning from // New(). - return nil, x509sourceErr.New("missing X509-SVID") + return nil, wrapX509sourceErr(errors.New("missing X509-SVID")) } return svid, nil } @@ -118,7 +117,11 @@ func (s *X509Source) checkClosed() error { s.closeMtx.RLock() defer s.closeMtx.RUnlock() if s.closed { - return x509sourceErr.New("source is closed") + return wrapX509sourceErr(errors.New("source is closed")) } return nil } + +func wrapX509sourceErr(err error) error { + return fmt.Errorf("x509source: %w", err) +} From b67b4ea2b51c457b6be3cdad60cf4a81340dbc77 Mon Sep 17 00:00:00 2001 From: junya koyama Date: Mon, 4 Nov 2024 02:58:53 +0900 Subject: [PATCH 12/13] replace errs.Combine to errors.Join Signed-off-by: junya koyama --- v2/workloadapi/watcher.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/v2/workloadapi/watcher.go b/v2/workloadapi/watcher.go index a105a60..f72e03b 100644 --- a/v2/workloadapi/watcher.go +++ b/v2/workloadapi/watcher.go @@ -2,11 +2,11 @@ package workloadapi import ( "context" + "errors" "sync" "github.com/spiffe/go-spiffe/v2/bundle/jwtbundle" "github.com/spiffe/go-spiffe/v2/svid/jwtsvid" - "github.com/zeebo/errs" ) type sourceClient interface { @@ -58,7 +58,7 @@ func newWatcher(ctx context.Context, config watcherConfig, x509ContextFn func(*X // If this function fails, we need to clean up the source. defer func() { if err != nil { - err = errs.Combine(err, w.Close()) + err = errors.Join(err, w.Close()) } }() From 598202b1311d4744b0d7fbb2b1b9a015ccc3cacb Mon Sep 17 00:00:00 2001 From: junya koyama Date: Mon, 4 Nov 2024 03:05:43 +0900 Subject: [PATCH 13/13] completely remove github.com/zeebo/errs Signed-off-by: junya koyama --- v2/go.mod | 1 - v2/go.sum | 2 -- v2/spiffetls/dial.go | 10 +++++----- v2/spiffetls/listen.go | 10 +++++----- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/v2/go.mod b/v2/go.mod index 66c7112..97e1373 100644 --- a/v2/go.mod +++ b/v2/go.mod @@ -6,7 +6,6 @@ require ( github.com/Microsoft/go-winio v0.6.2 github.com/go-jose/go-jose/v4 v4.0.4 github.com/stretchr/testify v1.9.0 - github.com/zeebo/errs v1.4.0 google.golang.org/grpc v1.67.1 google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20 google.golang.org/protobuf v1.34.2 diff --git a/v2/go.sum b/v2/go.sum index 11b6894..6a58fcf 100644 --- a/v2/go.sum +++ b/v2/go.sum @@ -15,8 +15,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= -github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= diff --git a/v2/spiffetls/dial.go b/v2/spiffetls/dial.go index 3ce0595..fd8e41d 100644 --- a/v2/spiffetls/dial.go +++ b/v2/spiffetls/dial.go @@ -3,6 +3,7 @@ package spiffetls import ( "context" "crypto/tls" + "errors" "fmt" "io" "net" @@ -10,7 +11,6 @@ import ( "github.com/spiffe/go-spiffe/v2/spiffeid" "github.com/spiffe/go-spiffe/v2/spiffetls/tlsconfig" "github.com/spiffe/go-spiffe/v2/workloadapi" - "github.com/zeebo/errs" ) // Dial creates an mTLS connection using an X509-SVID obtained from the @@ -89,14 +89,14 @@ type clientConn struct { } func (c *clientConn) Close() error { - var group errs.Group + var group []error if c.sourceCloser != nil { - group.Add(c.sourceCloser.Close()) + group = append(group, c.sourceCloser.Close()) } if err := c.Conn.Close(); err != nil { - group.Add(wrapSpiffetlsErr(fmt.Errorf("unable to close TLS connection: %w", err))) + group = append(group, wrapSpiffetlsErr(fmt.Errorf("unable to close TLS connection: %w", err))) } - return group.Err() + return errors.Join(group...) } // PeerID returns the peer SPIFFE ID on the connection. The handshake must have diff --git a/v2/spiffetls/listen.go b/v2/spiffetls/listen.go index 5c559a4..149785e 100644 --- a/v2/spiffetls/listen.go +++ b/v2/spiffetls/listen.go @@ -3,6 +3,7 @@ package spiffetls import ( "context" "crypto/tls" + "errors" "fmt" "io" "net" @@ -10,7 +11,6 @@ import ( "github.com/spiffe/go-spiffe/v2/spiffeid" "github.com/spiffe/go-spiffe/v2/spiffetls/tlsconfig" "github.com/spiffe/go-spiffe/v2/workloadapi" - "github.com/zeebo/errs" ) // Listen creates an mTLS listener accepting connections on the given network @@ -129,14 +129,14 @@ func (l *listener) Addr() net.Addr { } func (l *listener) Close() error { - var group errs.Group + var group []error if l.sourceCloser != nil { - group.Add(l.sourceCloser.Close()) + group = append(group, l.sourceCloser.Close()) } if err := l.inner.Close(); err != nil { - group.Add(wrapSpiffetlsErr(fmt.Errorf("unable to close TLS connection: %w", err))) + group = append(group, wrapSpiffetlsErr(fmt.Errorf("unable to close TLS connection: %w", err))) } - return group.Err() + return errors.Join(group...) } type serverConn struct {