2
$\begingroup$

According to Google, to access the id_token it sends along with Access Tokens (for accessing their API), you must first validate the token using the RS256 Public Key available from this page. The public key responses look like this:

  {
   "kty": "RSA",
   "alg": "RS256",
   "use": "sig",
   "kid": "8c9eb968f73744eaed421e48010142bce51a067f",
   "n": "uweJ3hFY9wqZ6ZG-iSNhQwHtKCGl8G_jcQgGPjOrS-Rum3dyDjicqkAyfS8XDn480KD_TZ5m-lqBjqfimePu2_cH4URDPIwsqSzJI2_piEhaqnXRptIe5YB5imAL6iETKaOPjw284Fc7EdHK-ekHMn3AXjsy9AIErwAVw4-4ZXXwHbyQXJy1DyUB4ZzxiEvw_qkQmLdltmrNkLOw-Xh-C9UkTZ9NA58bYPBnxLwnAu_ggw_g_-hCAs6OvXZbAfFHhIGBLyjtdDLVrfXo1112QREB9d5sEds0bKZtJcD9afl4E7Ht6G-g3jNP2clAu6-6B-cIe4-j8Ph1uJDPkAmDfw",
   "e": "AQAB"
},

According to Google & RFC Specification 7518, this is a Base64urlUInt-encoded RS256 Public key. The "n" parameter is the modulus, and the "e" parameter is the exponent. The rest are simply for verifying the algorithm itself, not pertaining to use of the Public Key for decryption/vaidation.

My Issue stems from the fact that this is not, from what I've read online, a standard RS256 Public Key. When trying to verify my IDtoken, it spits back ValueError: Could not deserialize key data. (The technology isn't important, but I'm using the pyJWT module in python). I know the problem isn't with the ID token, because if I skip validation I don't have a problem. This of course isn't suitable for a production environment.

I've tried converting it to regular Base64 by replacing '-' and '_' with '+' & '/', respectively, along with adding '=' for padding. I even tried prefixing the '-----BEGIN PUBLIC KEY-----\n' string & appending the similar string at the end, but to no avail. I also tried appending the "AQAB" exponent to the end of the modulus, again without any success.

I've also tried playing around with other public keys generated online & those work fine. Even if I purposefully mistype them, I get a error stating it simply couldn't validate the token, instead of spitting back a weird ValueError.

So my question stands; Is there something wrong with the "public key" modulus/exponent Google is giving me, or in how I'm using/converting it? Am I missing steps? Any help is greatly appreciated as I'm new to this topic. Thanks in advance!!

$\endgroup$

1 Answer 1

3
$\begingroup$

Both values are unsigned, big endian values, encoded as base-64-url. Basically that means that there is no sign bit and that the most significant bit is all the way to the left (bit B_7 - zero based indexing - on byte index zero). So you first need to base-64-url decode the values and then convert them to a big number. Finally, you need to combine both big numbers to form the public key, by providing the numbers as modulus $n$ and exponent $e$.

If you cannot combine the numbers to a public key you may need to encode the public key as PKCS#1 public key or SubjectPublicKeyInfo, which is an X.509 structure. For both these operations you either need to create the encoding yourself (which is pretty hard) or you need to have access and understand how to use an ASN.1 library.


You may want to have a look at the RSA public key interface in the "hazmat" cryptography package, with load_rsa_public_numbers and public_bytes(encoding, format) with PEM and SubjectPublicKeyInfo.

$\endgroup$
5
  • $\begingroup$ Thanks for the insight! I have a few follow-up questions if you don't mind. I tried decoding the base64-url value & got a long UTF-8 encoded string, which throws me errors if I try to decode it further. Which again makes me believe there's something I need to do before actually manipulating this "n" modulus value. (Here's a snippet of the result of my initial base65-url decoding: b"\xbb\x07\x89\xde\x11X\xf7\n\x99\xe9\x91\xbe\x89#aC\x01\xed(!\xa5\.....) $\endgroup$ Jul 12, 2018 at 21:39
  • $\begingroup$ So I was able to get big numbers from my modulus & exponent by converting the base64 byte value to HEX, then converting that hex value to a 2048bit big int. Not sure how to "combine" them back into a public key. I'll have to do more digging into the Python Cryptography // Hazmat package. $\endgroup$ Jul 12, 2018 at 22:38
  • $\begingroup$ Adjusted answer, included link to load_rsa_public_numbers for yiou. The key / modulus size of 2048 bits is correct. $\endgroup$
    – Maarten Bodewes
    Jul 12, 2018 at 22:57
  • $\begingroup$ Yes I had just been looking into that! Thank you, it was just what I was looking for. There is still some implementation details I need to iron out, but I believe I can handle that. I appreciate your thorough explanation! $\endgroup$ Jul 12, 2018 at 23:01
  • 1
    $\begingroup$ You should be able to directly convert to bytes by the way, there is no need to go from base-64-url to hex. However, the result is just that: bytes, not UTF-8. You would need hexadecimals to view the result, but they can remain bytes until you convert them to a number. $\endgroup$
    – Maarten Bodewes
    Jul 12, 2018 at 23:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.