SkyLothar / lua-resty-jwt

JWT For The Great Openresty
Apache License 2.0
512 stars 178 forks source link

id_token 'RS256' signature verification failed, client: xxx.xxx.170.207 #72

Open ankitvats24 opened 6 years ago

ankitvats24 commented 6 years ago

I am able to validate the token at jwt.io. Signature validation is also true using my public key.

2018/01/15 06:13:11 [debug] 256#256: *78 [lua] openidc.lua:737: openidc_load_jwt_and_verify_crypto(): jwt: {"signature":"Jb9T5QlRDIJMdhcC_jQ9bZlCKuRBEWe9BJd70g0sw1UJbznKwXb46eGsaGgAF1aorsZaEQqefAxkL5rfgp9dPVETyAQrToGD74QloStLq_15oeCLa0wAeJvHGb4x_pEGNqAjLYHu04MaguQfVZsVulM80kxBLCQ7ILJvii06HuU","reason":"too long",

"reason":"too long" - what could be the reason it repeatedly shows "too long" and verification fails on nginx ?

Reference - https://github.com/zmartzone/lua-resty-openidc/issues/135

grrolland commented 6 years ago

I have got the same issue with last version (0.1.11).

I can reproduce outside nginx with this sample code :

local jwt = require "resty.jwt"

local jwt_string = "eyAidHlwIjogIkpXVCIsICJraWQiOiAiU3lsTEM2Tmp0MUtHUWt0RDlNdCswemNlUVNVPSIsICJhbGciOiAiUlMyNTYiIH0.eyAiYXRfaGFzaCI6ICJkSExCRWpmekdqeVVUZWVESWwybmRRIiwgInN1YiI6ICJkZW1vIiwgImlzcyI6ICJodHRwOi8vb3BlbmFtL29wZW5hbS9vYXV0aDIiLCAidG9rZW5OYW1lIjogImlkX3Rva2VuIiwgImF1ZCI6IFsgIm5naW54X3JwIiBdLCAib3JnLmZvcmdlcm9jay5vcGVuaWRjb25uZWN0Lm9wcyI6ICI3MmUwOGExNy01ZTY4LTRhNmItOTIxYy1mYjUwZTc2NGZlZDUiLCAiYXpwIjogIm5naW54X3JwIiwgImF1dGhfdGltZSI6IDE1MTY2MjQ3NjYsICJyZWFsbSI6ICIvIiwgImV4cCI6IDE1MTY2MjgzNjYsICJ0b2tlblR5cGUiOiAiSldUVG9rZW4iLCAiaWF0IjogMTUxNjYyNDc2NiB9.A1SoyYHd8Z2HRZLCh-YQtuirv7D0jUt5WUXlU5LJYeMGl0JBHiB5ZJJ8hpX5dCX5_7Fkh4iiZNk95XiwwtqrmW1Pz3u0du7x_79SKmzTAYx7mUztX_5u6zp_awpMuhU1B1mNYqXcPzrS3FScEwvRHZWbTkhg16saEqW4l7NeM80"

local jwt_obj = jwt:load_jwt(jwt_string, nil)

local secret_key = "-----BEGIN PUBLIC KEY-----\
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIGJAoGBAK0kHP1O+RgdgLSoWxkuaYoi\
5Jic6hLKeuKw8WzCfsQ68ntBDf6tVOTn/kZA7Gjf4oJAL1dXLlxIEy+kZWnxT3FF\
+0MQ4WQYbGBfaW8LTM4uAOLLvYZ8SIVEXmxhJsSlvaiTWCbNFaOfiII8bhFp4551\
YB07NfpquUGEwOxOmci/AgMBAAE=\
-----END PUBLIC KEY-----"

jwt_obj = jwt:verify_jwt_obj(secret_key, jwt_obj)
print(jwt_obj.reason)

The output is : "too long"

The JWT signature is validated by jwt.io.

grrolland commented 6 years ago

When I renew my keypair (RSA 2048, signing algorithm SHA-256 with RSA), JWT verification is functionnal.

I don't know what the type of keypair before, it was the OpenAM 13.5 default (and don't work).

saggiyogesh commented 6 years ago

Working fine in openresty. Used like this.

local auth = <long jwt token encoded with RS256>
local jwt_obj = jwt:verify("-----BEGIN CERTIFICATE-----\nMIIC9zCCAd+gAwJWAJfmS7WKGsLMA0GCSqGSIb3DQEBCwUAMBkxFzAVBgNVBAMTDnNscGwuYXV0aDAuY29tMB4XDTE3MDMyMzE3MzAzMloXDTMwMTEzMDE3MzAzMlowGTEXMBUGA1UEAxMOc2xwbC5hdXRoMC5jb20wggEiAQUAA4IBDwAwggEKAoIBAQDc+qP5FlIJH/x1Epn3sjVVUjybYCijJzshlrzswkyasmB4X/LoNowZnVzGbw6sS6cka6sGWVp8k+TCrDD44mvcehEu5YA4u13ssUwHcwJeTPQQ8orHb8Hhekl6GfR1N0y7S9N6d63yBeY5OSdeRsTUCyxTtXGARXlSkhFuAtE+5o59LK+W8iJxHgOS8vlSiSR8blCfybKeuPG8pGo5vEialRic5FPmmywblNSREX6vBZE+A1aqRrfHkr9Y7mWv8cL6brUieluOiDP+gEk9rF62l3gCKxfKaKysimL7SBiXyBsvgG0xooQhwusUAPgpfgsQi9LpBAgMjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOJ8K2IQkypV2KHGMIhOZfHBij/cMA4GA1UdDwEB/wQEAwIChDANBgkqhkiG9wEAZHgDrpnxbL2v9/cNTDHcmYzy1RuCnt/YARBdV++kkKFX0bizl+iA/yK1pMHHC/MWXyvVSJHfktnlY4IWTkf4ZYapYA0toLDaafqYj8Lw6eGGggs8pay/Qmvq8LR5E9iS/FJ+B3ZciI4zJlZv4Uuwuwrag==\n-----END CERTIFICATE-----\n", auth)

print('encode------' .. cjson.encode(jwt_obj) );

Token and Signing Certificate are generated by Auth0

grrolland commented 6 years ago

My precedent comment confirm this. When the signing key is corrupt, this don't work and it's normal !!

Althought the error message is not very clear, I think this issue should be closed.

pamiel commented 6 years ago

hello to all of you,

@grrolland I'm indeed facing the same "too long" issue... but no way to identify what's going wrong (so far !). I'm quite interested in your experience as you seems to understand what is the root cause of this problem... but I don't understand the point "When the signing key is corrupt" in your last post.

What do you mean by that ? Do you mean that the key obtained (for example) from the JWKS endpoint of the Identity Provider may be "corrupted" ? What "corrupted" means:

Thanks for your help!

pamiel commented 6 years ago

[In complement to my previous post, as I'm still interesting in @grrolland feedbacks !]

I’m using the lua-resty-openidc component to perform the verification of JWT tokens previously generated by KeyCloak. For that, lua-resty-openidc is using the Realm public key created by KeyCloak (RSA 2046 bits key pair), and relies on lua-resty-jwt to perform the verification of the signature.

Most of the time, everything is ok… but it happens that the JWT token verification leads to an error in the lua-resty-jwt component, with a reason “too long”, error that is raised at upper level into a “jwt signature verification failed”, still with the “too long” reason.

Let me explain the call stack and the analysis I made:

What I realized, is that the occurrence of the error depends on the key pair of the KeyCloak realm: with most of the key pairs I used (generated by KeyCloak at Realm creation time), everything is ok, but with some specific realms keys (but I unfortunately don’t know what is the exact specificity of these keys !! :( ), the JWT token verification always leads to an error in the lua-resty-jwt component, with the famous reason “too long”. Who is responsible for this issue? The KeyCloak key generation mechanism ? lua-resty-openidc that gets the key from the JWKS endpoint of KeyCloak and forwards the JWT + the keys to lua-resty-jwt, or lua-resty-jwt that is wrongly processing the signature verification with these very particular (but still valid!) keys ? I don’t know…

I followed the processing of requests without issue (i.e. with KeyCloak keys that are not generating a JWT token validation issue!) and requests with issues: everything looks similar up to the call of the verify function (at least, the content of the various variables “looks” similar and valid for both!). The only difference I saw is that when calling the EVP_DigestVerifyInit function, the self.evp_pkey parameter was NULL in case of occurrence of the “too long” error: “dump(): cdata<struct evp_pkey_st >: NULL” vs. “dump(): cdata<struct evp_pkey_st >: 0x7f5cdc72b100”

I was unfortunately not able to dump all the input data at low level, but I have the full JWT + the public key for both ok and ko use cases.

Do you think this could be due to a problem in the EVP_DigestVerifyInit code or more generally in the lua-resty-jwt component? In case I provide you the JWT + keys, do you think you could try to reproduce the behavior at low level (i.e. only calling lua-resty-jwt functions), in order to identify the root cause?

Thanks a lot for your help.

pamiel commented 6 years ago

Ok, found ! The issue is in fact not due to lua-resty-jwt. The issue is indeed due to a bug in the lua-resty-openidc library I’m using on top of lua-resty-jwt: in rare cases, the public key is starting with the 0x80 byte, and the bug in lua-resty-openidc makes the DER (and then PEM) structure that is rebuilt based on the data obtained from the JWKS endpoint of the Identity Provider/OP be erroneous !

I’ve just submitted a PR to lua-resty-openidc to correct the issue: https://github.com/zmartzone/lua-resty-openidc/pull/153