RSA keys cannot be used to verify PS signature
Version(s) affected
4.x
Description
Using the JWSVerifier one can check if a Signed Token has been correctly signed. For OpenID Connect I provide a keyset with all keys the IDP annouces to encrypt keys with. Auth0 signs keys using PS256 with the RSA keys.
This libaray fails the correctly validate the PS256 signature with an RSA key.
Reason for this is the strict checking inside KeyChecker::checkKeyAlgorithm
From my understanding, it should accept RSA keys for PS signatures
How to reproduce
The last line should result true, however the current implementation returns false
use Jose\Component\Core\AlgorithmManagerFactory;
use Jose\Component\Core\JWK;
use Jose\Component\Core\JWKSet;
use Jose\Component\KeyManagement\JWKFactory;
use Jose\Component\Signature\Algorithm\PS256;
use Jose\Component\Signature\Algorithm\RS256;
use Jose\Component\Signature\Serializer\CompactSerializer;
use Jose\Component\Signature\Serializer\JWSSerializerManager;
use Jose\Component\Signature\JWSVerifier;
use Jose\Component\Core\JWKSet;
$algorithmManagerFactory = new AlgorithmManagerFactory();
$algorithmManagerFactory->add("RS256", new RS256());
$algorithmManagerFactory->add("PS256", new PS256());
$token =
"eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.iOeNU4dAFFeBwNj6qdhdvm-IvDQrTa6R22lQVJVuWJxorJfeQww5Nwsra0PjaOYhAMj9jNMO5YLmud8U7iQ5gJK2zYyepeSuXhfSi8yjFZfRiSkelqSkU19I-Ja8aQBDbqXf2SAWA8mHF8VS3F08rgEaLCyv98fLLH4vSvsJGf6ueZSLKDVXz24rZRXGWtYYk_OYYTVgR1cg0BLCsuCvqZvHleImJKiWmtS0-CymMO4MMjCy_FIl6I56NqLE9C87tUVpo1mT-kbg5cHDD8I7MjCW5Iii5dethB4Vid3mZ6emKjVYgXrtkOQ-JyGMh6fnQxEFN1ft33GX2eRHluK9eg";
$serializerManager = new JWSSerializerManager([new CompactSerializer()]);
$jws = $serializerManager->unserialize($token);
$signature = $jws->getSignature(0);
$alg = $signature->getProtectedHeaderParameter("alg");
$algorithmManager = $algorithmManagerFactory->create([$alg]);
$jwsVerifier = new JWSVerifier($algorithmManager);
$jwk = JWKFactory::createFromValues([
"kty" => "RSA",
"alg" => "RS256",
"n" =>
"u1SU1LfVLPHCozMxH2Mo4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0_IzW7yWR7QkrmBL7jTKEn5u-qKhbwKfBstIs-bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyehkd3qqGElvW_VDL5AaWTg0nLVkjRo9z-40RQzuVaE8AkAFmxZzow3x-VJYKdjykkJ0iT9wCS0DRTXu269V264Vf_3jvredZiKRkgwlL9xNAwxXFg0x_XFw005UWVRIkdgcKWTjpBP2dPwVZ4WWC-9aGVd-Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbcmw",
"e" => "AQAB",
"use" => "sig"
]);
$jwkSet = new JWKSet([$jwk]);
$jwsVerifier->verifyWithKeySet($jws, $jwkSet, 0);
Possible Solution
https://github.com/web-token/jwt-framework/blob/4.1.x/src/Library/Core/Util/KeyChecker.php#L38
if ($alg !== $algorithm) {
+ // Allow RSA keys to be used for PS
+ $alternativeAlgName = str_replace('PS', 'RS', $algorithm);
+ if($alg !== $alternativeAlgName) {
throw new InvalidArgumentException(sprintf('Key is only allowed for algorithm "%s".', $alg));
+ }
}
Additional Context
No response
Hi @SamuelWei, thank you for the detailed report.
This behavior is intentional and compliant with RFC 7517 section 4.4, which defines the alg parameter as indicating the intended algorithm for the key.
When this parameter is present, it is interpreted as a usage constraint (same for use or other parameters).
Therefore, a JWK with alg": RS256 must not be used to verify or sign tokens using a different algorithm, such as PS256 even if both algorithms use RSA keys.
This strictness prevents algorithm substitution attacks and aligns with security recommendations, including those from RFC 8725, section 3.3.
You should contact the issuer of the token/keyset
If you really want to use it, you may alter the JWK to remove or change the alg parameter but this is not a compliant or recommended solution as it opens the door to algorithm confusion attacks (e.g. using RSA keys across RS* and PS* with different paddings).
Thank's for your quick reply and this detailed answer. I observed this issue while using Auth0
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.