Skip to content

Commit

Permalink
Update to go-jose v4.0.1 (#276)
Browse files Browse the repository at this point in the history
There are some breaking changes in v4 that affect go-spiffe code:
- When parsing a JWS-protected JWT, the caller must now explicitly pass
  the accepted signature algorithms (corresponding to `alg` JWS header)
  into the parsing function.
- `CompactSerialize()` was removed in favor of just `Serialize()`, which
  has identical behavior.

go-jose v4 updates the minimum Go version requirement to 1.21, which was
released 2023-08-08.

Signed-off-by: Ryan Turner <[email protected]>
Co-authored-by: Andrew Harding <[email protected]>
  • Loading branch information
rturner3 and azdagron authored Apr 1, 2024
1 parent 8e0ce79 commit bf6eecf
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 76 deletions.
6 changes: 2 additions & 4 deletions v2/bundle/jwtbundle/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,13 @@ import (
"os"
"sync"

"github.com/go-jose/go-jose/v3"
"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")
)
var jwtbundleErr = errs.Class("jwtbundle")

// Bundle is a collection of trusted JWT authorities for a trust domain.
type Bundle struct {
Expand Down
6 changes: 2 additions & 4 deletions v2/bundle/spiffebundle/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"sync"
"time"

"github.com/go-jose/go-jose/v3"
"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"
Expand All @@ -23,9 +23,7 @@ const (
jwtSVIDUse = "jwt-svid"
)

var (
spiffebundleErr = errs.Class("spiffebundle")
)
var spiffebundleErr = errs.Class("spiffebundle")

type bundleDoc struct {
jose.JSONWebKeySet
Expand Down
8 changes: 4 additions & 4 deletions v2/go.mod
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
module github.com/spiffe/go-spiffe/v2

go 1.19
go 1.21

require (
github.com/Microsoft/go-winio v0.6.1
github.com/go-jose/go-jose/v3 v3.0.1
github.com/go-jose/go-jose/v4 v4.0.1
github.com/stretchr/testify v1.9.0
github.com/zeebo/errs v1.3.0
google.golang.org/grpc v1.62.1
Expand All @@ -17,10 +17,10 @@ require (
github.com/golang/protobuf v1.5.3 // indirect
github.com/kr/pretty v0.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/crypto v0.18.0 // indirect
golang.org/x/crypto v0.19.0 // indirect
golang.org/x/mod v0.8.0 // indirect
golang.org/x/net v0.20.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.6.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect
Expand Down
25 changes: 8 additions & 17 deletions v2/go.sum
Original file line number Diff line number Diff line change
@@ -1,44 +1,36 @@
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-jose/go-jose/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA=
github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8=
github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U=
github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
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=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
Expand All @@ -57,6 +49,5 @@ google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHh
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
12 changes: 5 additions & 7 deletions v2/internal/test/ca.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import (
"testing"
"time"

"github.com/go-jose/go-jose/v3"
"github.com/go-jose/go-jose/v3/cryptosigner"
"github.com/go-jose/go-jose/v3/jwt"
"github.com/go-jose/go-jose/v4"
"github.com/go-jose/go-jose/v4/cryptosigner"
"github.com/go-jose/go-jose/v4/jwt"
"github.com/spiffe/go-spiffe/v2/bundle/jwtbundle"
"github.com/spiffe/go-spiffe/v2/bundle/spiffebundle"
"github.com/spiffe/go-spiffe/v2/bundle/x509bundle"
Expand All @@ -26,9 +26,7 @@ import (
"github.com/stretchr/testify/require"
)

var (
localhostIPs = []net.IP{net.IPv4(127, 0, 0, 1), net.IPv6loopback}
)
var localhostIPs = []net.IP{net.IPv4(127, 0, 0, 1), net.IPv6loopback}

type CA struct {
tb testing.TB
Expand Down Expand Up @@ -101,7 +99,7 @@ func (ca *CA) CreateJWTSVID(id spiffeid.ID, audience []string, options ...SVIDOp
)
require.NoError(ca.tb, err)

signedToken, err := jwt.Signed(jwtSigner).Claims(claims).CompactSerialize()
signedToken, err := jwt.Signed(jwtSigner).Claims(claims).Serialize()
require.NoError(ca.tb, err)

svid, err := jwtsvid.ParseInsecure(signedToken, audience)
Expand Down
48 changes: 17 additions & 31 deletions v2/svid/jwtsvid/svid.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
package jwtsvid

import (
"fmt"
"time"

"github.com/go-jose/go-jose/v3"
"github.com/go-jose/go-jose/v3/jwt"
"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 (
allowedSignatureAlgorithms = []jose.SignatureAlgorithm{
jose.RS256,
jose.RS384,
jose.RS512,
jose.ES256,
jose.ES384,
jose.ES512,
jose.PS256,
jose.PS384,
jose.PS512,
}

jwtsvidErr = errs.Class("jwtsvid")
)

Expand Down Expand Up @@ -90,16 +101,11 @@ func (svid *SVID) Marshal() string {

func parse(token string, audience []string, getClaims tokenValidator) (*SVID, error) {
// Parse serialized token
tok, err := jwt.ParseSigned(token)
tok, err := jwt.ParseSigned(token, allowedSignatureAlgorithms)
if err != nil {
return nil, jwtsvidErr.New("unable to parse JWT token")
}

// Validates supported token signed algorithm
if err := validateTokenAlgorithm(tok); err != nil {
return nil, err
}

// Parse out the unverified claims. We need to look up the key by the trust
// domain of the SPIFFE ID.
var claims jwt.Claims
Expand Down Expand Up @@ -127,8 +133,8 @@ func parse(token string, audience []string, getClaims tokenValidator) (*SVID, er

// Validate the standard claims.
if err := claims.Validate(jwt.Expected{
Audience: audience,
Time: time.Now(),
AnyAudience: audience,
Time: time.Now(),
}); err != nil {
// Convert expected validation errors for pretty errors
switch err {
Expand All @@ -148,23 +154,3 @@ func parse(token string, audience []string, getClaims tokenValidator) (*SVID, er
token: token,
}, nil
}

// validateTokenAlgorithm json web token have only one header, and it is signed for a supported algorithm
func validateTokenAlgorithm(tok *jwt.JSONWebToken) error {
// Only one header is expected
if len(tok.Headers) != 1 {
return fmt.Errorf("expected a single token header; got %d", len(tok.Headers))
}

// Make sure it has an algorithm supported by JWT-SVID
alg := tok.Headers[0].Algorithm
switch jose.SignatureAlgorithm(alg) {
case jose.RS256, jose.RS384, jose.RS512,
jose.ES256, jose.ES384, jose.ES512,
jose.PS256, jose.PS384, jose.PS512:
default:
return jwtsvidErr.New("unsupported token signature algorithm %q", alg)
}

return nil
}
29 changes: 20 additions & 9 deletions v2/svid/jwtsvid/svid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import (
"testing"
"time"

"github.com/go-jose/go-jose/v3"
"github.com/go-jose/go-jose/v3/cryptosigner"
"github.com/go-jose/go-jose/v3/jwt"
"github.com/go-jose/go-jose/v4"
"github.com/go-jose/go-jose/v4/cryptosigner"
"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/spiffe/go-spiffe/v2/svid/jwtsvid"
Expand All @@ -24,8 +24,19 @@ const hs256Token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODk
"4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"

var (
key1, _ = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
key2, _ = rsa.GenerateKey(rand.Reader, 2048)
key1, _ = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
key2, _ = rsa.GenerateKey(rand.Reader, 2048)
testAllowedSignatureAlgorithms = []jose.SignatureAlgorithm{
jose.RS256,
jose.RS384,
jose.RS512,
jose.ES256,
jose.ES384,
jose.ES512,
jose.PS256,
jose.PS384,
jose.PS512,
}
)

func TestParseAndValidate(t *testing.T) {
Expand Down Expand Up @@ -86,7 +97,7 @@ func TestParseAndValidate(t *testing.T) {
generateToken: func(tb testing.TB) string {
return hs256Token
},
err: `jwtsvid: unsupported token signature algorithm "HS256"`,
err: "jwtsvid: unable to parse JWT token",
},
{
name: "missing subject",
Expand Down Expand Up @@ -313,7 +324,7 @@ func TestParseInsecure(t *testing.T) {
generateToken: func(tb testing.TB) string {
return hs256Token
},
err: `jwtsvid: unsupported token signature algorithm "HS256"`,
err: "jwtsvid: unable to parse JWT token",
},
{
name: "missing subject claim",
Expand Down Expand Up @@ -450,7 +461,7 @@ func TestMarshal(t *testing.T) {
}

func parseToken(t testing.TB, token string) map[string]interface{} {
tok, err := jwt.ParseSigned(token)
tok, err := jwt.ParseSigned(token, testAllowedSignatureAlgorithms)
require.NoError(t, err)
claimsMap := make(map[string]interface{})
err = tok.UnsafeClaimsWithoutVerification(&claimsMap)
Expand Down Expand Up @@ -478,7 +489,7 @@ func generateToken(tb testing.TB, claims jwt.Claims, signer crypto.Signer, keyID
require.NoError(tb, err)

// Sign and serialize token
token, err := jwt.Signed(jwtSigner).Claims(claims).CompactSerialize()
token, err := jwt.Signed(jwtSigner).Claims(claims).Serialize()
require.NoError(tb, err)

return token
Expand Down

0 comments on commit bf6eecf

Please sign in to comment.