I'm sometimes - but not always - getting an error from Google Identity Toolkit that says "Plaintext too large". It appears to be in a section when it should be trying to verify the signature (using RSA). Since it's verifying the SHA256 hash of the payload, there shouldn't be any variation in the plaintext size.
If I log the token it's trying to use, and give that to the debugger at https://jwt.io/, along with the Google RSA certificate (from https://www.googleapis.com/identitytoolkit/v3/relyingparty/publicKeys; use the key identifier that jwt.io puts in the red box at the top under "kid"), it says the signature is valid.
This only happens a portion of the time, maybe a little over half. If I repeat the authentication, it seems fine.
This seems to only happen on new authentications; if it's already authenticated, everything works fine, even though I'm not currently using a session cookie: my code verifies the gtoken authentication on every request. Once I've signed in, everything is fine until I sign out (again, through gitkit). But then, if I later sign in again, I'm likely to hit this error.
I'm using App Engine for my infrastructure. This is happening with both dev_appserver and on deployed App Engine, and with both desktop browsers using the JavaScript gitkit library and an iOS app using the Objective C gitkit library. (I haven't tested with iOS against dev_appserver, only in deployment.)
The code I'm using looks like this:
gtoken = cookie["gtoken"].value
logging.debug("Verifying Google Identity Toolkit token: %s",
gtoken)
gitkit_user = gitkit_instance.VerifyGitkitToken(gtoken)
The stack trace follows (starting with the line quoted above):
File "/base/data/home/apps/redacted/redacted.py", line 218, in redacted:
gitkit_user = gitkit_instance.VerifyGitkitToken(gtoken)
File "/base/data/home/apps/redacted/lib/identitytoolkit/gitkitclient.py", line 266, in VerifyGitkitToken
parsed = crypt.verify_signed_jwt_with_certs(jwt, certs, aud)
File "/base/data/home/apps/redacted/lib/oauth2client/crypt.py", line 240, in verify_signed_jwt_with_certs
_verify_signature(message_to_sign, signature, certs.values())
File "/base/data/home/apps/redacted/lib/oauth2client/crypt.py", line 119, in _verify_signature
if verifier.verify(message, signature):
File "/base/data/home/apps/redacted/lib/oauth2client/_pycrypto_crypt.py", line 52, in verify
SHA256.new(message), signature)
File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/pycrypto-2.6/Crypto/Signature/PKCS1_v1_5.py", line 148, in verify
m = self._key.encrypt(S, 0)[0]
File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/pycrypto-2.6/Crypto/PublicKey/RSA.py", line 150, in encrypt
return pubkey.pubkey.encrypt(self, plaintext, K)
File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/pycrypto-2.6/Crypto/PublicKey/pubkey.py", line 75, in encrypt
ciphertext=self._encrypt(plaintext, K)
File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/pycrypto-2.6/Crypto/PublicKey/RSA.py", line 224, in _encrypt
return (self.key._encrypt(c),)
ValueError: Plaintext too large
The error "Plaintext too large" should only happen when the size of the payload exceeds the size of the RSA key. Since it's verifying a SHA256 hash against a 2048-bit RSA key, it should be fine, so I'm wondering if there's a problem with loading the key from googleapis.com sometimes. My next step is to use the API stats module to look for urlfetch calls in the requests where this happens, and to augment _pycrypto_crypt.py to log what RSA key it's trying to verify against. But I thought I'd check here at Stack Overflow and see if anybody has gone down this path already.
Update: With some additional logging, I learned a few things. First, rather than using the key ID specified in the JWT headers, the gitkit API (or one of the libraries it uses) iterates trying each key in the Google Identity Toolkit keyset. Second, when I've gotten the error in the times I've had sufficient logging, it's been testing one of the keys that's really in the keyset, so that invalidates my theory about problems loading the keys. But it really is trying to verify a 256-byte string against a 2048-bit key, so it should be perfectly fine.
Finally, although it normally iterates over all the keys, in the times I'm getting this error, it hits the error on the first key it's trying. This makes me wonder if, in some cases, I'm importing a broken pycrypto early on.
As you can see from the backtrace, I'm using the Google-supplied pycrypto, although there's a locally-compiled one in my app's "lib" directory (which is in sys.path) that got saved there when I vendored in the Google Identity Toolkit.