Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions auth/api/iam/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ import (
"github.com/nuts-foundation/nuts-node/core/to"

"github.com/labstack/echo/v4"
"github.com/lestrrat-go/jwx/v2/jwk"
"github.com/lestrrat-go/jwx/v2/jwt"
"github.com/lestrrat-go/jwx/v3/jwk"
"github.com/lestrrat-go/jwx/v3/jwt"
"github.com/nuts-foundation/go-did/did"
"github.com/nuts-foundation/nuts-node/audit"
"github.com/nuts-foundation/nuts-node/auth"
Expand Down Expand Up @@ -402,7 +402,8 @@ func (r Wrapper) introspectAccessToken(input string) (*ExtendedTokenIntrospectio
// SHA256 hashing won't fail.
var cnf *Cnf
if token.DPoP != nil {
hash, _ := token.DPoP.Headers.JWK().Thumbprint(crypto.SHA256)
key, _ := token.DPoP.Headers.JWK()
hash, _ := key.Thumbprint(crypto.SHA256)
Comment thread
reinkrul marked this conversation as resolved.
Outdated
base64Hash := base64.RawURLEncoding.EncodeToString(hash)
cnf = &Cnf{Jkt: base64Hash}
}
Expand Down Expand Up @@ -653,7 +654,7 @@ func (r Wrapper) OpenIDConfiguration(ctx context.Context, request OpenIDConfigur
}
}
// create JWK and add to set
jwkKey, err := jwk.FromRaw(key)
jwkKey, err := jwk.Import(key)
if err != nil {
return nil, oauth.OAuth2Error{
Code: oauth.ServerError,
Expand Down
8 changes: 4 additions & 4 deletions auth/api/iam/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ import (
"time"

"github.com/labstack/echo/v4"
"github.com/lestrrat-go/jwx/v2/jwa"
"github.com/lestrrat-go/jwx/v2/jws"
"github.com/lestrrat-go/jwx/v2/jwt"
"github.com/lestrrat-go/jwx/v3/jwa"
"github.com/lestrrat-go/jwx/v3/jws"
"github.com/lestrrat-go/jwx/v3/jwt"
ssi "github.com/nuts-foundation/go-did"
"github.com/nuts-foundation/go-did/did"
"github.com/nuts-foundation/go-did/vc"
Expand Down Expand Up @@ -1538,7 +1538,7 @@ func createIssuerCredential(issuerDID did.DID, holderDID did.DID) *vc.Verifiable
for key, val := range claims {
request.Set(key, val)
}
sign, err := jwt.Sign(request, jwt.WithKey(jwa.ES256, privateKey, jws.WithProtectedHeaders(hdrs)))
sign, err := jwt.Sign(request, jwt.WithKey(jwa.ES256(), privateKey, jws.WithProtectedHeaders(hdrs)))
return string(sign), err
}

Expand Down
9 changes: 5 additions & 4 deletions auth/api/iam/dpop.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ func (r Wrapper) ValidateDPoPProof(_ context.Context, request ValidateDPoPProofR
return ValidateDPoPProof200JSONResponse{Reason: &reason}, nil
}
// check if ath claim matches hash of access_token
ath, ok := dpopToken.Token.Get(dpop.ATHKey)
if !ok {
var ath string
if err := dpopToken.Token.Get(dpop.ATHKey, &ath); err != nil {
reason := "missing ath claim"
return ValidateDPoPProof200JSONResponse{Reason: &reason}, nil
}
Expand All @@ -87,13 +87,14 @@ func (r Wrapper) ValidateDPoPProof(_ context.Context, request ValidateDPoPProofR
return ValidateDPoPProof200JSONResponse{Reason: &reason}, nil
}
// check if the jti is already used, if not add it to the store for the duration of the access token lifetime
jti, _ := dpopToken.Token.JwtID()
Comment thread
reinkrul marked this conversation as resolved.
var target struct{}
if err := r.useNonceOnceStore().Get(dpopToken.Token.JwtID(), &target); err != nil {
if err := r.useNonceOnceStore().Get(jti, &target); err != nil {
if !errors.Is(err, storage.ErrNotFound) {
log.Logger().WithError(err).Error("ValidateDPoPProof: failed to retrieve jti usage state")
return nil, err
}
if err := r.useNonceOnceStore().Put(dpopToken.Token.JwtID(), target); err != nil {
if err := r.useNonceOnceStore().Put(jti, target); err != nil {
log.Logger().WithError(err).Error("ValidateDPoPProof: failed to store jti usage state")
return nil, err
}
Expand Down
14 changes: 8 additions & 6 deletions auth/api/iam/dpop_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import (
"net/http"
"testing"

"github.com/lestrrat-go/jwx/v2/jwa"
"github.com/lestrrat-go/jwx/v3/jwa"
ssi "github.com/nuts-foundation/go-did"
"github.com/nuts-foundation/go-did/did"
"github.com/nuts-foundation/nuts-node/auth/oauth"
Expand Down Expand Up @@ -172,7 +172,7 @@ func TestWrapper_ValidateDPoPProof(t *testing.T) {
require.NoError(t, err)
require.IsType(t, ValidateDPoPProof200JSONResponse{}, resp)
assert.False(t, resp.(ValidateDPoPProof200JSONResponse).Valid)
assert.Equal(t, "failed to parse DPoP header: invalid DPoP token\ninvalid compact serialization format: invalid number of segments", *resp.(ValidateDPoPProof200JSONResponse).Reason)
assert.Equal(t, "failed to parse DPoP header: invalid DPoP token\njws.ParseString: failed to parse string: jws.Parse: failed to parse compact format: jws.Parse: invalid compact serialization format: jwsbb: invalid number of segments", *resp.(ValidateDPoPProof200JSONResponse).Reason)
})
t.Run("invalid accestoken", func(t *testing.T) {
ctx := newTestClient(t)
Expand All @@ -188,7 +188,8 @@ func TestWrapper_ValidateDPoPProof(t *testing.T) {
})
t.Run("already used once", func(t *testing.T) {
ctx := newTestClient(t)
_ = ctx.client.useNonceOnceStore().Put(dpopProof.Token.JwtID(), struct{}{})
jti, _ := dpopProof.Token.JwtID()
_ = ctx.client.useNonceOnceStore().Put(jti, struct{}{})

resp, err := ctx.client.ValidateDPoPProof(nil, request)

Expand Down Expand Up @@ -229,9 +230,10 @@ func newSignedTestDPoP() (*dpop.DPoP, *dpop.DPoP, string) {
withProof := newTestDPoP()
keyPair, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
_ = withProof.GenerateProof("token")
_, _ = withProof.Sign("kid", keyPair, jwa.ES256)
_, _ = dpopToken.Sign("kid", keyPair, jwa.ES256)
thumbprintBytes, _ := dpopToken.Headers.JWK().Thumbprint(crypto2.SHA256)
_, _ = withProof.Sign("kid", keyPair, jwa.ES256())
_, _ = dpopToken.Sign("kid", keyPair, jwa.ES256())
jwkKey, _ := dpopToken.Headers.JWK()
thumbprintBytes, _ := jwkKey.Thumbprint(crypto2.SHA256)
thumbprint := base64.RawURLEncoding.EncodeToString(thumbprintBytes)
return dpopToken, withProof, thumbprint
}
15 changes: 10 additions & 5 deletions auth/api/iam/jar.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ import (
"bytes"
"context"
"crypto"
"encoding/json"
"errors"
"github.com/lestrrat-go/jwx/v2/jwk"
"github.com/lestrrat-go/jwx/v2/jwt"
"github.com/lestrrat-go/jwx/v3/jwk"
"github.com/lestrrat-go/jwx/v3/jwt"
"github.com/nuts-foundation/go-did/did"
"github.com/nuts-foundation/nuts-node/auth"
"github.com/nuts-foundation/nuts-node/auth/oauth"
Expand Down Expand Up @@ -183,8 +184,12 @@ func (j jar) validate(ctx context.Context, rawToken string, clientId string) (oa
if err != nil {
return nil, oauth.OAuth2Error{Code: oauth.InvalidRequestObject, Description: "request signature validation failed", InternalError: err}
}
claimsAsMap, err := token.AsMap(ctx)
if err != nil {
// Convert the token's claims to a map via its JSON representation. This mirrors jwx v2's
// token.AsMap: it preserves all claims including null-valued ones (a per-claim Get loop
// errors on null values in v3).
claimsAsMap := make(map[string]interface{})
claimsJSON, _ := json.Marshal(token)
if err := json.Unmarshal(claimsJSON, &claimsAsMap); err != nil {
Comment thread
reinkrul marked this conversation as resolved.
Outdated
// very unlikely
return nil, oauth.OAuth2Error{Code: oauth.InvalidRequestObject, Description: "invalid request parameter", InternalError: err}
}
Expand Down Expand Up @@ -213,7 +218,7 @@ func compareThumbprint(configurationKey jwk.Key, publicKey crypto.PublicKey) err
if err != nil {
return err
}
signerKey, err := jwk.FromRaw(publicKey)
signerKey, err := jwk.Import(publicKey)
if err != nil {
return err
}
Expand Down
14 changes: 7 additions & 7 deletions auth/api/iam/jar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ import (
"crypto"
"errors"
"fmt"
"github.com/lestrrat-go/jwx/v2/jwk"
"github.com/lestrrat-go/jwx/v3/jwk"
"github.com/nuts-foundation/nuts-node/crypto/storage/spi"
"github.com/nuts-foundation/nuts-node/test"
"testing"
"time"

"github.com/lestrrat-go/jwx/v2/jwa"
"github.com/lestrrat-go/jwx/v2/jws"
"github.com/lestrrat-go/jwx/v2/jwt"
"github.com/lestrrat-go/jwx/v3/jwa"
"github.com/lestrrat-go/jwx/v3/jws"
"github.com/lestrrat-go/jwx/v3/jwt"
"github.com/nuts-foundation/go-did/did"
"github.com/nuts-foundation/nuts-node/auth"
"github.com/nuts-foundation/nuts-node/auth/client/iam"
Expand Down Expand Up @@ -126,7 +126,7 @@ func TestJar_Parse(t *testing.T) {
// setup did document and keys
privateKey, _ := spi.GenerateKeyPair()
kid := fmt.Sprintf("%s#%s", holderDID.String(), "key")
jwkKey, _ := jwk.FromRaw(privateKey.Public())
jwkKey, _ := jwk.Import(privateKey.Public())
jwkKey.Set(jwk.KeyIDKey, kid)
jwkSet := jwk.NewSet()
_ = jwkSet.AddKey(jwkKey)
Expand Down Expand Up @@ -329,7 +329,7 @@ func TestJar_Parse(t *testing.T) {
t.Run("error - openID configuration key mismatch", func(t *testing.T) {
ctx := newJarTestCtx(t)
alternateKey, _ := spi.GenerateKeyPair()
jwkKey, _ := jwk.FromRaw(alternateKey.Public())
jwkKey, _ := jwk.Import(alternateKey.Public())
jwkKey.Set(jwk.KeyIDKey, kid)
jwkSet := jwk.NewSet()
_ = jwkSet.AddKey(jwkKey)
Expand Down Expand Up @@ -358,7 +358,7 @@ func createSignedRequestObject(t testing.TB, kid string, privateKey crypto.Priva
}
headers := jws.NewHeaders()
require.NoError(t, headers.Set(jws.KeyIDKey, kid))
return jwt.Sign(request, jwt.WithKey(jwa.ES256, privateKey, jws.WithProtectedHeaders(headers)))
return jwt.Sign(request, jwt.WithKey(jwa.ES256(), privateKey, jws.WithProtectedHeaders(headers)))
}

type testJarCtx struct {
Expand Down
10 changes: 5 additions & 5 deletions auth/api/iam/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@
package iam

import (
"github.com/lestrrat-go/jwx/v2/jwk"
"github.com/lestrrat-go/jwx/v3/jwk"
"net/url"
"strings"
"time"

"github.com/lestrrat-go/jwx/v2/jwa"
"github.com/lestrrat-go/jwx/v3/jwa"
"github.com/nuts-foundation/nuts-node/auth/oauth"
"github.com/nuts-foundation/nuts-node/core"
"github.com/nuts-foundation/nuts-node/core/to"
Expand Down Expand Up @@ -67,10 +67,10 @@ func staticAuthorizationServerMetadata() oauth.AuthorizationServerMetadata {
ClientIdSchemesSupported: clientIdSchemesSupported,
ResponseTypesSupported: []string{oauth.VPTokenResponseType},
VPFormatsSupported: map[string]map[string][]string{
"jwt_vp_json": {"alg_values_supported": []string{string(jwa.ES256)}},
"jwt_vc_json": {"alg_values_supported": []string{string(jwa.ES256)}},
"jwt_vp_json": {"alg_values_supported": []string{jwa.ES256().String()}},
"jwt_vc_json": {"alg_values_supported": []string{jwa.ES256().String()}},
},
RequestObjectSigningAlgValuesSupported: []string{string(jwa.ES256)},
RequestObjectSigningAlgValuesSupported: []string{jwa.ES256().String()},
}
}

Expand Down
2 changes: 1 addition & 1 deletion auth/api/iam/openid4vci.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (
"net/url"
"time"

"github.com/lestrrat-go/jwx/v2/jwt"
"github.com/lestrrat-go/jwx/v3/jwt"
"github.com/nuts-foundation/go-did/did"
"github.com/nuts-foundation/go-did/vc"
"github.com/nuts-foundation/nuts-node/auth/oauth"
Expand Down
7 changes: 3 additions & 4 deletions auth/api/iam/openid4vp.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ import (
"strings"
"time"

"github.com/lestrrat-go/jwx/v2/jwk"
"github.com/lestrrat-go/jwx/v2/jwt"
"github.com/lestrrat-go/jwx/v3/jwk"
"github.com/lestrrat-go/jwx/v3/jwt"
"github.com/nuts-foundation/go-did/did"
"github.com/nuts-foundation/go-did/vc"
"github.com/nuts-foundation/nuts-node/auth/oauth"
Expand Down Expand Up @@ -598,8 +598,7 @@ func extractChallenge(presentation vc.VerifiablePresentation) (string, error) {
var nonce string
switch presentation.Format() {
case vc.JWTPresentationProofFormat:
nonceRaw, _ := presentation.JWT().Get("nonce")
nonce, _ = nonceRaw.(string)
_ = presentation.JWT().Get("nonce", &nonce)
case vc.JSONLDPresentationProofFormat:
proof, err := credential.ParseLDProof(presentation)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion auth/api/iam/openid4vp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import (
"github.com/nuts-foundation/nuts-node/http/user"
"github.com/nuts-foundation/nuts-node/vcr/verifier"

"github.com/lestrrat-go/jwx/v2/jwt"
"github.com/lestrrat-go/jwx/v3/jwt"
"github.com/nuts-foundation/go-did/did"
"github.com/nuts-foundation/go-did/vc"
"github.com/nuts-foundation/nuts-node/auth/oauth"
Expand Down
3 changes: 1 addition & 2 deletions auth/api/iam/s2s_vptoken.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,7 @@ func extractNonce(presentation vc.VerifiablePresentation) (string, error) {
var nonce string
switch presentation.Format() {
case vc.JWTPresentationProofFormat:
nonceRaw, _ := presentation.JWT().Get("nonce")
nonce, _ = nonceRaw.(string)
_ = presentation.JWT().Get("nonce", &nonce)
Comment thread
reinkrul marked this conversation as resolved.
case vc.JSONLDPresentationProofFormat:
proof, err := credential.ParseLDProof(presentation)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions auth/api/iam/s2s_vptoken_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import (
"testing"
"time"

"github.com/lestrrat-go/jwx/v2/jwt"
"github.com/lestrrat-go/jwx/v3/jwt"
ssi "github.com/nuts-foundation/go-did"
"github.com/nuts-foundation/go-did/did"
"github.com/nuts-foundation/go-did/vc"
Expand Down Expand Up @@ -182,7 +182,7 @@ func TestWrapper_handleS2SAccessTokenRequest(t *testing.T) {
ctx := newTestClient(t)
resp, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), clientID, issuerSubjectID, requestedScope, submissionJSON, "[true, false]")

assert.EqualError(t, err, "invalid_request - assertion parameter is invalid: unable to parse PEX envelope as verifiable presentation: invalid JWT")
assert.EqualError(t, err, "invalid_request - assertion parameter is invalid: unable to parse PEX envelope as verifiable presentation: jwt.Parse: failed to parse token: unknown payload type (payload is not JWT?)")
assert.Nil(t, resp)
})
t.Run("not all VPs have the same credential subject ID", func(t *testing.T) {
Expand Down
6 changes: 3 additions & 3 deletions auth/api/iam/user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ import (
"testing"
"time"

"github.com/lestrrat-go/jwx/v2/jwa"
"github.com/lestrrat-go/jwx/v2/jwk"
"github.com/lestrrat-go/jwx/v3/jwa"
"github.com/lestrrat-go/jwx/v3/jwk"
ssi "github.com/nuts-foundation/go-did"
"github.com/nuts-foundation/go-did/did"
"github.com/nuts-foundation/go-did/vc"
Expand Down Expand Up @@ -128,7 +128,7 @@ func TestWrapper_handleUserLanding(t *testing.T) {
sessionKey, err := jwk.ParseKey(userSession.Wallet.JWK)
require.NoError(t, err)
assert.NotEmpty(t, sessionKey.KeyID)
assert.Equal(t, jwa.EC, sessionKey.KeyType())
assert.Equal(t, jwa.EC(), sessionKey.KeyType())
// check for details of issued NutsEmployeeCredential
assert.Equal(t, "NutsEmployeeCredential", employeeCredentialTemplate.Type[0].String())
employeeCredentialSubject := employeeCredentialTemplate.CredentialSubject[0]
Expand Down
2 changes: 1 addition & 1 deletion auth/api/iam/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func (r Wrapper) validatePresentationAudience(presentation vc.VerifiablePresenta
var audience []string
switch presentation.Format() {
case vc.JWTPresentationProofFormat:
audience = presentation.JWT().Audience()
audience, _ = presentation.JWT().Audience()
Comment thread
reinkrul marked this conversation as resolved.
case vc.JSONLDPresentationProofFormat:
proof, err := credential.ParseLDProof(presentation)
if err != nil {
Expand Down
17 changes: 11 additions & 6 deletions auth/client/iam/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ import (
"strings"
"time"

"github.com/lestrrat-go/jwx/v2/jws"
"github.com/lestrrat-go/jwx/v2/jwt"
"github.com/lestrrat-go/jwx/v3/jws"
"github.com/lestrrat-go/jwx/v3/jwt"
"github.com/nuts-foundation/nuts-node/crypto"
"github.com/nuts-foundation/nuts-node/vdr/resolver"

Expand Down Expand Up @@ -264,12 +264,17 @@ func (hb HTTPClient) OpenIDConfiguration(ctx context.Context, issuerURL string)
if err != nil {
return nil, fmt.Errorf("unable to parse response: %w", err)
}
claims, err := token.AsMap(ctx)
if err != nil {
// Convert the token's claims to a map via its JSON representation. This mirrors jwx v2's
// token.AsMap: it preserves all claims including null-valued ones (a per-claim Get loop
// errors on null values in v3).
claims := make(map[string]interface{})
claimsJSON, _ := json.Marshal(token)
if err = json.Unmarshal(claimsJSON, &claims); err != nil {
Comment thread
reinkrul marked this conversation as resolved.
Outdated
return nil, fmt.Errorf("unable to parse response: %w", err)
}
// hack, broken iat
claims["iat"] = token.IssuedAt().Unix()
iat, _ := token.IssuedAt()
claims["iat"] = iat.Unix()
Comment thread
reinkrul marked this conversation as resolved.
asJSON, _ := json.Marshal(claims)
if err = json.Unmarshal(asJSON, &configuration); err != nil {
return nil, fmt.Errorf("unable to unmarshal response: %w", err)
Expand All @@ -279,7 +284,7 @@ func (hb HTTPClient) OpenIDConfiguration(ctx context.Context, issuerURL string)

func (hb HTTPClient) KeyProvider() jws.KeyProviderFunc {
return func(context context.Context, keySink jws.KeySink, signature *jws.Signature, message *jws.Message) error {
keyID := signature.ProtectedHeaders().KeyID()
keyID, _ := signature.ProtectedHeaders().KeyID()
publicKey, err := hb.keyResolver.ResolveKeyByID(keyID, nil, resolver.AssertionMethod)
if err != nil {
return fmt.Errorf("failed to resolve key (kid=%s): %w", keyID, err)
Expand Down
Loading
Loading