pyjwt
pyjwt copied to clipboard
Can't verify detached payload JWS with JWK from its header
I am trying to verify the signature of a JWS with the JWK that is included in its header. I believe the fact that it has a detached payload is only incidental to the primary issue of not recognizing the correct form of a JWS's key. The JWK is normal and valid, for example:
{'crv': 'P-256', 'kty': 'EC', 'x': 'PY5pUvmWTEz5mCVir-Tyfi1M0q07_qaZSU_UAN3HBSI', 'y': 'aH9ZAGpTidZjxNu2zKXeX9koNQX_BAtIBCa-h7YC_B0'}
I can get a jwt.api_jwk.PyJWK object
if I do api_jwk.PyJWK(jws_jwk, algorithm='ES256')
, proving there is no issue with the JWK itself.
However when I try to use it to verify the signature of a JWS in the manner below, I receive the error message Expecting a PEM-formatted key
.
payload = api_jws.decode(
jws_compact, verification_jwk, algorithms=['ES256'],
options={'verify_signature': True},
detached_payload=payload)
It's clear that this is because the prepare_key
method of the ECAlgorithm
class expects either a key of type EllipticCurvePublicKey
or a PEM string. However this is not how one typically receives the verification key in a JWS. They are always in JWK form, and I can't find any clear way to convert a JWK to a EllipticCurvePublicKey
object nor a PEM.
Is this intended? Am I missing something obvious here? This seems like a bug or an oversight to me, so I appreciate any clarification on the proper verification of a JWS using its own key material.
Expected Result
To verify a standard JWS using the included key material, wherein it passes or fails depending upon the validity of the included signature as verified by the standard JWK included in a JWS protected header.
Actual Result
I am asked for a PEM-formatted key, which is not how keys are sent with a JWS.
Reproduction Steps
Use the JWK in any JWS and pass it into api_jws.decode
along with the JWS as shown above.
This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days
As a workaround I'd say you could load the JWK into a PyJWK object and then access the key
atribute of the resulting object.
(untested code):
jwk_data = {'crv': 'P-256', 'kty': 'EC', 'x': 'PY5pUvmWTEz5mCVir-Tyfi1M0q07_qaZSU_UAN3HBSI', 'y': 'aH9ZAGpTidZjxNu2zKXeX9koNQX_BAtIBCa-h7YC_B0'}
jwk = PyJWK(jwk_data)
payload = api_jws.decode(
jws_compact, jwk.key, algorithms=['ES256'],
options={'verify_signature': True},
detached_payload=payload)
Nice, that does work. In that case it seems like updating the api_jws.decode
method to handle actual JWKs could be implemented pretty easily. The conversion performed by PyJWK.key
could be called on the verification material argument when the type is a dict instead of a PEM string or EllipticCurvePublicKey
instance.
I am open to review any contribution which fix this