JWT decryption and verify signature - python-3.x

I am trying to decrypt JWT token and verify signature using python. Though I found PyJWT, it does not actually encrypt/decrypt the payload, so I cannot use it. I also looked at https://github.com/IdentityPython/pyjwkest/tree/master/src/jwkest but the decrypt() method is actually returning plain text and then not sure how to "verify" on the plain text.
Can someone share example for decrypt a JWT token using private key and verify the signature using public key. Algo for decrypt: RSA-OAEP-256 and enc: A256GCM. Algo for signing was PS512

Related

Client Assertion verify the signature failed

I have configured app registration with client certificate .cer file in azure
Using jwt.io to create client assertion, and requested access token as in below screenshot
There were few posts about issues with key not found, but in this scenario key Is not able to generate signature. unable to understand the issue here. I used private key and public key in jwt.to to generate client assertion.
Header in JWt used base64 thumbprint value-
{
"alg": "RS256",
"typ": "JWT",
"x5t": "hfbTrE31AcSETk1BFhovA1w1SMc="
}
However, signature is verified in jwt.io.
TIA
I have figured this out, its issue in Private/public key. Extract Private key as PKCS #8 to use in building jwt assertion.
Verify Signature gives error with encrypted Private key, use decrypted private key

JWT with RSA public and private key

I don't understand why I should use the public key in signing JWT. The private key is there so that the JWT token cannot be forged, yes? But why additionally sign it with a public key? Are there any benefits? Because I don't understand it at all. After all, a JWT signed with a private key can be read without the public key. What is this public key for?
Signing a JWT means you take the cleartext, signing it with a key - either the private key from an RSA pair or a symmetric key, then add the signature to the JWT. The JWT itself is still readable without decrtypting the signature. But someone with the key can decrypt the signature and confirm the contents match the cleartext.
The advantage of using RSA over symmetric key is that anyone can verify the signature without them having to have a secret key. You can either pass the public key to the JWT recipient over a side channel, or if using OAuth2 it provides a URL to access public keys.
You would use the public key for encrypting, not signing. You encrypt with the recipient's public key so that only the recipient can decrypt it.

Failing signature validation of JWT tokens from Azure AD

By following this MS info about client credential grants, I got a JWT token:
eyJ0eXAiOiJKV1QiLCJub25jZSI6InBOWU1CVkZKcFAxVjJ1VTFaUnM1V3NOLVhyeDhjXzhWWjU5RWxhTFZBeDAiLCJhbGciOiJSUzI1NiIsIng1dCI6IllNRUxIVDBndmIwbXhvU0RvWWZvbWpxZmpZVSIsImtpZCI6IllNRUxIVDBndmIwbXhvU0RvWWZvbWpxZmpZVSJ9.eyJhdWQiOiJodHRwczovL2dyYXBoLm1pY3Jvc29mdC5jb20iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC8wMmRhZjUwZC00ZDFlLTRhOTUtYTI0YS1jOTg3MDUzNDBlYzAvIiwiaWF0IjoxNTg0NzIwNjk3LCJuYmYiOjE1ODQ3MjA2OTcsImV4cCI6MTU4NDcyNDU5NywiYWlvIjoiNDJOZ1lIaTZxVjRxS0xoLzRteUd0UzBmb3lLWEFRQT0iLCJhcHBfZGlzcGxheW5hbWUiOiJSc2tUZXN0QXBwIiwiYXBwaWQiOiJlMjcwYmNkNC00ZDU0LTRiN2MtYWFmYy1hYjUyZWZmMjA5N2UiLCJhcHBpZGFjciI6IjEiLCJpZHAiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC8wMmRhZjUwZC00ZDFlLTRhOTUtYTI0YS1jOTg3MDUzNDBlYzAvIiwib2lkIjoiMGQ3MDU2NWItZWQzMi00ZGMzLWJmMTYtOWFjMTRjOTVlYzJiIiwic3ViIjoiMGQ3MDU2NWItZWQzMi00ZGMzLWJmMTYtOWFjMTRjOTVlYzJiIiwidGlkIjoiMDJkYWY1MGQtNGQxZS00YTk1LWEyNGEtYzk4NzA1MzQwZWMwIiwidXRpIjoiMVVxeV9PemJJMDZOSGp6VHo1Qm9BQSIsInZlciI6IjEuMCIsInhtc190Y2R0IjoxNTg0NzE3OTU0fQ.fy2TIhXb89Ic2wuw7ysao-JzBqzpQGHD29A_X-JrjeEXOTvO5AB75tn0G1zV69vYkg2hEMsv3Dej5pNJ82w8NETRXMEEhC6ke9-URk0uKzWJ_ZzxNrL9I1eD8N4UUhqXeJifYE9gatDRqSfFmEn5eQbRVgEegJMmpqb7DMeUH8pOkTZLKzFHjSmJATx2eQBkW1PiMEL5u-QuIiZohObxficQ8PvK-IgE2V_LcTuVnEVXBrgYfZllPesQTP9-fjV_iGnM5gwcnVhwqNdpk9Ws-Vz2XDgRRCDu604IbYv3SvA9JhbKByo0CPreMfhqjrP5l_0Rm_bJeGj9iJrql5Jj3w
When I simply copy-paste it to jwt.io, the token is correctly decoded but its signature validation fails.
So I suspected jwt.io not to work properly and wanted to verify the token myself.
The token's header:
{
"typ": "JWT",
"nonce": "pNYMBVFJpP1V2uU1ZRs5WsN-Xrx8c_8VZ59ElaLVAx0",
"alg": "RS256",
"x5t": "YMELHT0gvb0mxoSDoYfomjqfjYU",
"kid": "YMELHT0gvb0mxoSDoYfomjqfjYU"
}
According to this description where the Azure public keys/certificates are available I fetched them and the key with kid=YMELHT0gvb0mxoSDoYfomjqfjYU is there:
{
"kty":"RSA",
"use":"sig",
"kid":"YMELHT0gvb0mxoSDoYfomjqfjYU",
"x5t":"YMELHT0gvb0mxoSDoYfomjqfjYU",
"n":"ni9SAyu9EsltQlV7Jo3wMUvcpYb4mmfHzV4IsDZ6NQvJjtQJuhsfqiG86VntMd76R44kCmkfMGvtQRA2_UmnVBSSLxQKvcGUqNodH7YaMYOTmHlbOSoVpi3Ox2wj6cWvhaTTm_4xzJ3F0yF0Y_aRBMxSCIwLv3nTMRNe74k4zdBnhL7k5ObOY_vUGt_5-sPo6BXoV7oov4Ps6jeyUdRKtqVZSp5_kzz16kPh1Ng_2tn4vpQimNbHRralq8rNM_gOLPAar6v7mL_qsqpgx-48e5ENFxikbB-NzAmLll1QSkzciu2rCjFGH4j_-bCHr7FxUNDL_E0vMFVDFw8SUlYMgQ",
"e":"AQAB",
"x5c":[
"MIIDBTCCAe2gAwIBAgIQG4GFMDOjD7lKSdsgshqQ/DANBgkqhkiG9w0BAQsFADAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MB4XDTIwMDIwNTAwMDAwMFoXDTI1MDIwNDAwMDAwMFowLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ4vUgMrvRLJbUJVeyaN8DFL3KWG+Jpnx81eCLA2ejULyY7UCbobH6ohvOlZ7THe+keOJAppHzBr7UEQNv1Jp1QUki8UCr3BlKjaHR+2GjGDk5h5WzkqFaYtzsdsI+nFr4Wk05v+McydxdMhdGP2kQTMUgiMC7950zETXu+JOM3QZ4S+5OTmzmP71Brf+frD6OgV6Fe6KL+D7Oo3slHUSralWUqef5M89epD4dTYP9rZ+L6UIpjWx0a2pavKzTP4DizwGq+r+5i/6rKqYMfuPHuRDRcYpGwfjcwJi5ZdUEpM3IrtqwoxRh+I//mwh6+xcVDQy/xNLzBVQxcPElJWDIECAwEAAaMhMB8wHQYDVR0OBBYEFHssLV3w8SFEdZk03/TJwDfWQ6mRMA0GCSqGSIb3DQEBCwUAA4IBAQAh9iGtY+wKAMrYYLCU8uRZnUY9f+s936HhZdnJfVCuJM7y3fIbzvPO0T0dMHLz++ba0rkptoe+HjZaNA7vVwzdEtAdNff0wFef470sb+kxPi64PZK/IhtqBEwEvy090ZwGsZqM/Ut9QxFH21/t/wcz0wUBc6QGGxgWr1T/Qfzlemnz5DxuHaKQdiafz6yrwGyVjmaRkjMqeqhQy3J0nNoJNbofopSnnGH0g5IWBJBJPBk7k8RaliY0i+GwTliCgiI59ZPt1dS1+EXfNS06v1+TjTe1tPHyGot03i+iIA3WJk3REgT14y7Rhl94htzmMFmrlGNioXlfLFx9fDJQkJfz"
],
"issuer":"https://login.microsoftonline.com/{tenantid}/v2.0"
}
Next I extract the public key from the certificate:
openssl x509 -in ms_signing_cert4.pem -pubkey -noout
-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAni9SAyu9EsltQlV7Jo3w
MUvcpYb4mmfHzV4IsDZ6NQvJjtQJuhsfqiG86VntMd76R44kCmkfMGvtQRA2/Umn
VBSSLxQKvcGUqNodH7YaMYOTmHlbOSoVpi3Ox2wj6cWvhaTTm/4xzJ3F0yF0Y/aR
BMxSCIwLv3nTMRNe74k4zdBnhL7k5ObOY/vUGt/5+sPo6BXoV7oov4Ps6jeyUdRK
tqVZSp5/kzz16kPh1Ng/2tn4vpQimNbHRralq8rNM/gOLPAar6v7mL/qsqpgx+48
e5ENFxikbB+NzAmLll1QSkzciu2rCjFGH4j/+bCHr7FxUNDL/E0vMFVDFw8SUlYM
gQIDAQAB
-----END PUBLIC KEY-----
And lastly I use the Python PyJWT library to verify the signature:
import jwt
token = 'eyJ0eXAiOiJKV1QiLCJub25jZSI6InBOWU1CVkZKcFAxVjJ1VTFaUnM1V3NOLVhyeDhjXzhWWjU5RWxhTFZBeDAiLCJhbGciOiJSUzI1NiIsIng1dCI6IllNRUxIVDBndmIwbXhvU0RvWWZvbWpxZmpZVSIsImtpZCI6IllNRUxIVDBndmIwbXhvU0RvWWZvbWpxZmpZVSJ9.eyJhdWQiOiJodHRwczovL2dyYXBoLm1pY3Jvc29mdC5jb20iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC8wMmRhZjUwZC00ZDFlLTRhOTUtYTI0YS1jOTg3MDUzNDBlYzAvIiwiaWF0IjoxNTg0NzIwNjk3LCJuYmYiOjE1ODQ3MjA2OTcsImV4cCI6MTU4NDcyNDU5NywiYWlvIjoiNDJOZ1lIaTZxVjRxS0xoLzRteUd0UzBmb3lLWEFRQT0iLCJhcHBfZGlzcGxheW5hbWUiOiJSc2tUZXN0QXBwIiwiYXBwaWQiOiJlMjcwYmNkNC00ZDU0LTRiN2MtYWFmYy1hYjUyZWZmMjA5N2UiLCJhcHBpZGFjciI6IjEiLCJpZHAiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC8wMmRhZjUwZC00ZDFlLTRhOTUtYTI0YS1jOTg3MDUzNDBlYzAvIiwib2lkIjoiMGQ3MDU2NWItZWQzMi00ZGMzLWJmMTYtOWFjMTRjOTVlYzJiIiwic3ViIjoiMGQ3MDU2NWItZWQzMi00ZGMzLWJmMTYtOWFjMTRjOTVlYzJiIiwidGlkIjoiMDJkYWY1MGQtNGQxZS00YTk1LWEyNGEtYzk4NzA1MzQwZWMwIiwidXRpIjoiMVVxeV9PemJJMDZOSGp6VHo1Qm9BQSIsInZlciI6IjEuMCIsInhtc190Y2R0IjoxNTg0NzE3OTU0fQ.fy2TIhXb89Ic2wuw7ysao-JzBqzpQGHD29A_X-JrjeEXOTvO5AB75tn0G1zV69vYkg2hEMsv3Dej5pNJ82w8NETRXMEEhC6ke9-URk0uKzWJ_ZzxNrL9I1eD8N4UUhqXeJifYE9gatDRqSfFmEn5eQbRVgEegJMmpqb7DMeUH8pOkTZLKzFHjSmJATx2eQBkW1PiMEL5u-QuIiZohObxficQ8PvK-IgE2V_LcTuVnEVXBrgYfZllPesQTP9-fjV_iGnM5gwcnVhwqNdpk9Ws-Vz2XDgRRCDu604IbYv3SvA9JhbKByo0CPreMfhqjrP5l_0Rm_bJeGj9iJrql5Jj3w'
pub_key = b'-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAni9SAyu9EsltQlV7Jo3w\nMUvcpYb4mmfHzV4IsDZ6NQvJjtQJuhsfqiG86VntMd76R44kCmkfMGvtQRA2/Umn\nVBSSLxQKvcGUqNodH7YaMYOTmHlbOSoVpi3Ox2wj6cWvhaTTm/4xzJ3F0yF0Y/aR\nBMxSCIwLv3nTMRNe74k4zdBnhL7k5ObOY/vUGt/5+sPo6BXoV7oov4Ps6jeyUdRK\ntqVZSp5/kzz16kPh1Ng/2tn4vpQimNbHRralq8rNM/gOLPAar6v7mL/qsqpgx+48\ne5ENFxikbB+NzAmLll1QSkzciu2rCjFGH4j/+bCHr7FxUNDL/E0vMFVDFw8SUlYM\ngQIDAQAB\n-----END PUBLIC KEY-----'
print(jwt.decode(token, pub_key, algorithms=['RS256']))
Results in
jwt.exceptions.InvalidSignatureError: Signature verification failed
I tried to generate on my PC my own JWT, also signed by RS256 - passes both on jwt.io and PyJWT. Same for a sample token I found somewhere on the web. Just cannot handle tokens issued by AAD.
What am I missing with these AAD tokens?
Many thanks.
Your token is correct. It is just a specific token for graph api. You will see a nonce in Jwt.Header. This means you need special processing. Normal processing will fail.
If you're a client getting a token for Graph, assume that it's an
encrypted string that you should never look at - sometimes it will be.
We use a special token format for Graph that they know how to validate
- you shouldn't be looking at access tokens if they're not for you.
See the details here.
Reference:
Can not validate signature
Yes indeed. This nonce is in V2, the addition to the V1 token.
I used to validate V1 using this snippet:
var signatureKey = signatureKeyIdentifier.X509CertificateChain.First();
var certificate = new X509Certificate2(signatureKey.ToBytesFromBase64URLString());
var rsa = certificate.GetRSAPublicKey();
var data = string.Format("{0}.{1}", header, payload).ToBytes();
var isValidSignature = rsa.VerifyData(
data,
signature.ToBytesFromBase64URLString(),
HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1);
But now this validation will fail.
Please note that I am creating a certificate as provided by header.
The nonce has nothing to do with signature, it is just a number that changes for each request/token to make sure no one is replaying that valid token. Validating the nonce is by saving all of them in a database and check uniqueness.
I think we need to find out the changes in calculating the signation. are they still using the same padding? same Algo?
The way I am using to validate now is to send that token to the same active directory to get data, then AD will give the data ONLY upon valid token.

Azure Api Management ValidateJWT With Rs256 PrivateKey

I can understand that we can do JWT validation easily by using symmetric keys(HS256) and open id for the RS256.
In my case I want to validate the JWT using existing private key that I already have. Payload will be encoded by public key, and at the API Management side I want to validate that token with my own predefined private key. Is there a way to do that?
It should be possible to decrypt it manually if needed. But perhaps using output-token-variable-name attribute of validate-jwt policy will be a simpler way out.
Well I can't decrypt the payload but we managed to make it pass di validate-jwt set open id url to a mock openid-configuration file, and convert our *.pem key into jwt key, and then refer the jwtk-url in the mock openid-configuration to that jwtkey json.

Does NodeJS crypto module fail verification if the RSA cert is expired?

If 'key' in the following code is an expired cert, will res always be false regardless of the signature's validity?
var verifier = crypto.createVerify("RSA-SHA1")
verifier.update(str)
var res = verifier.verify(key, signatureValue, 'base64')
In other words, does the NodeJS crypto module care about a certificate's expiration when validating a signature. This is all in the context of validating a signed XML document.
No, the expiration is not validated using the code above. If you directly use the public key instead of the signature then the algorithm doesn't even receive the end-of-validity date.
If the key in your code is not a key but a certificate then the signature verification does normally not fail either. The test to see if the certificate is valid should be performed before the signature over the data is verified.
The certificate verification and validation procedures in other words should contain the check that the certificate is in its validity period - among all the other checks. Signature verification should only take place after that.

Resources