From 3b412a548e1e479aa04ed6613747c6d4b2f06e31 Mon Sep 17 00:00:00 2001 From: Steven van der Vegt Date: Tue, 12 May 2026 13:39:22 +0200 Subject: [PATCH] feat(crypto): accept RS256 in SupportedAlgorithms The JWS allowlist used by ParseJWT (wallet ingest, VP verification, OAuth bearer-token parsing) excluded RS256 in favour of PS256. The AET ZORG-ID issuer always signs soft-cert RSA keys with RS256 and offers no algorithm knob, so HealthCareProfessionalDelegationCredential and PatientEnrollmentCredential VCs were rejected at POST /internal/vcr/v2/ holder/{subject}/vc with "token signing algorithm is not supported: RS256". Accept RS256 on input; outbound signing continues to use PS256. The network DAG keeps its own narrower allowlist and still rejects RS256 for transactions. Two tests that asserted RS256 rejection via the shared allowlist now use HS256 instead. Closes #4234 Assisted-by: AI --- auth/services/oauth/authz_server_test.go | 13 ++++--------- crypto/jwx/algorithm.go | 2 +- crypto/jwx_test.go | 10 +++++----- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/auth/services/oauth/authz_server_test.go b/auth/services/oauth/authz_server_test.go index 39f36e1022..7e1141dacd 100644 --- a/auth/services/oauth/authz_server_test.go +++ b/auth/services/oauth/authz_server_test.go @@ -23,7 +23,6 @@ import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" - "crypto/rsa" "encoding/json" "errors" "fmt" @@ -575,19 +574,15 @@ func TestService_parseAndValidateJwtBearerToken(t *testing.T) { }) t.Run("wrong signing algorithm", func(t *testing.T) { - t.Setenv("GODEBUG", "rsa1024min=0") // minimum key-length has changed to 1024 -> https://pkg.go.dev/crypto/rsa#hdr-Minimum_key_size - privateKey, err := rsa.GenerateKey(rand.Reader, 512) - require.NoError(t, err) - keyID := "did:nuts:somedid#key-id" + secret := []byte("test-hmac-secret") - ctx.keyResolver.EXPECT().ResolveKeyByID(keyID, nil, resolver.NutsSigningKeyType).Return(privateKey.Public(), nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(keyID, nil, resolver.NutsSigningKeyType).Return(secret, nil) - // alg: RS256 token := jwt.New() hdrs := jws.NewHeaders() hdrs.Set(jws.KeyIDKey, keyID) - signedToken, err := jwt.Sign(token, jwt.WithKey(jwa.RS256, privateKey, jws.WithProtectedHeaders(hdrs))) + signedToken, err := jwt.Sign(token, jwt.WithKey(jwa.HS256, secret, jws.WithProtectedHeaders(hdrs))) require.NoError(t, err) tokenCtx := &validationContext{ @@ -595,7 +590,7 @@ func TestService_parseAndValidateJwtBearerToken(t *testing.T) { } err = ctx.oauthService.parseAndValidateJwtBearerToken(tokenCtx) assert.Nil(t, tokenCtx.jwtBearerToken) - assert.Equal(t, "token signing algorithm is not supported: RS256", err.Error()) + assert.Equal(t, "token signing algorithm is not supported: HS256", err.Error()) }) t.Run("valid token", func(t *testing.T) { diff --git a/crypto/jwx/algorithm.go b/crypto/jwx/algorithm.go index 4f89d7684e..bbf5eb54c9 100644 --- a/crypto/jwx/algorithm.go +++ b/crypto/jwx/algorithm.go @@ -27,7 +27,7 @@ import ( // ErrUnsupportedSigningKey is returned when an unsupported private key is used to sign. Currently only ecdsa and rsa keys are supported var ErrUnsupportedSigningKey = errors.New("signing key algorithm not supported") -var SupportedAlgorithms = []jwa.SignatureAlgorithm{jwa.ES256, jwa.EdDSA, jwa.ES384, jwa.ES512, jwa.PS256, jwa.PS384, jwa.PS512} +var SupportedAlgorithms = []jwa.SignatureAlgorithm{jwa.ES256, jwa.EdDSA, jwa.ES384, jwa.ES512, jwa.PS256, jwa.PS384, jwa.PS512, jwa.RS256} const DefaultRsaEncryptionAlgorithm = jwa.RSA_OAEP_256 const DefaultEcEncryptionAlgorithm = jwa.ECDH_ES_A256KW diff --git a/crypto/jwx_test.go b/crypto/jwx_test.go index 7891f211e2..6866906fb2 100644 --- a/crypto/jwx_test.go +++ b/crypto/jwx_test.go @@ -120,14 +120,14 @@ func TestSignJWT(t *testing.T) { func TestParseJWT(t *testing.T) { t.Run("unsupported algorithm", func(t *testing.T) { - rsaKey := test.GenerateRSAKey() + secret := []byte("test-hmac-secret") token := jwt.New() - signature, _ := jwt.Sign(token, jwt.WithKey(jwa.RS256, rsaKey)) + signature, _ := jwt.Sign(token, jwt.WithKey(jwa.HS256, secret)) parsedToken, err := ParseJWT(string(signature), func(_ string) (crypto.PublicKey, error) { - return rsaKey.Public(), nil + return secret, nil }, nil, nil) assert.Nil(t, parsedToken) - assert.EqualError(t, err, "token signing algorithm is not supported: RS256") + assert.EqualError(t, err, "token signing algorithm is not supported: HS256") }) t.Run("allow clock skew (default DefaultJWTClockSkew)", func(t *testing.T) { @@ -595,7 +595,7 @@ func TestCrypto_convertHeaders(t *testing.T) { func Test_isAlgorithmSupported(t *testing.T) { assert.True(t, jwx.IsAlgorithmSupported(jwa.PS256)) - assert.False(t, jwx.IsAlgorithmSupported(jwa.RS256)) + assert.True(t, jwx.IsAlgorithmSupported(jwa.RS256)) assert.False(t, jwx.IsAlgorithmSupported("")) }