Verify Firebase ID tokens (JWT) using Deno djwt

Viewed 427

I'm trying to follow Firebase docs for verifying ID tokens using third-party libraries. I've successfully grabbed the correct key from https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com,

-----BEGIN CERTIFICATE-----\nMIIDHDCCAgSgAwIBAgIIcYOBxdgv20wwDQYJKoZIhvcNAQEFBQAwMTEvMC0GA1UE\nAxMmc2VjdXJldG9rZW4uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wHhcNMjAx\nMjE1MDkyMDExWhcNMjAxMjMxMjEzNTExWjAxMS8wLQYDVQQDEyZzZWN1cmV0b2tl\nbi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD\nggEPADCCAQoCggEBALCJi7xqry88tJOn0sluSRAXjERc8uWZnbdp3BhvvNVGh1jp\nLQ83njFs/v8G7NwupgihNkCV9B5IyzJAUnCNPFC085sQUsNbUhestj18NGIvIrOm\nmU2U8/Oe9tzMCCdTtKcFhVkcaoT5usBpakOT/pi6UxwzN1T/TH+9RTJcvc9g0M1m\noUT6pPBMtl6cph4Gba7mJw2n6uZpgG5c4v0y42KcgwwIHn+U6jbTFnUXxwOSX6Sm\n7N+JThkt4YIvCrbMf2o0PoRM0II//5c4aWrsWI5hrgIRTns4wq7K3VssHQyjigl+\nm181J4fcw9XM4XrDU92ICd+VPduRXp2JO4as6vcCAwEAAaM4MDYwDAYDVR0TAQH/\nBAIwADAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDQYJ\nKoZIhvcNAQEFBQADggEBAFTU2phg+MEJrWi1SVUR1eqP6qmvGavBVXl8kAPY9B0d\n1bNwbovj8WM6MFQQm6K/mCys5LA7iTMPu0B9duFhmpX9M8g/1TJ6hUmstw6scr38\nYBrhJulQ7HCbUTaI7+yPcSdT7WHXSnYvF/1fOFWaE8vVL9ZtM0DE/ldqx/MetvdQ\nWZWEkm6SEpLf3bKweza2PK/3RHtER8l/iV0KCdkh8Dugnf58QYVcsmy5wZkvXKII\n2qMl0e9y7wGTW9OvxQFpr4HB1T982r9M56a4TTMTCC8+KWJ/i34DmVro1Ngb+jOp\nu7cfh/Z2ahSym5asBz66UOk29W0nk3y4HeNCVwD+CZg=\n-----END CERTIFICATE-----\n

but when I pass the key to djwt verify() or godcrypto RSA.parseKey() it crashes inside rsa_import_pem_cert with Cannot read property '0' of undefined, at length: gey_key_size

function rsa_import_pem_cert(key: string): RSAKeyParams {
  const trimmedKey = key.substr(27, key.length - 53);
  const parseKey = ber_simple(
    ber_decode(base64_to_binary(trimmedKey)),
  ) as RSACertKeyFormat;

  return {
    length: get_key_size(parseKey[0][5][1][0][0]),
    n: parseKey[0][5][1][0][0],
    e: parseKey[0][5][1][0][1],
  };
}

I then also tried using node.js to convert the x.509 certificate from PEM to a public key using node-forge. When I pass the converted public key to those deno lib methods

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsImLvGqvLzy0k6fSyW5J
EBeMRFzy5Zmdt2ncGG+81UaHWOktDzeeMWz+/wbs3C6mCKE2QJX0HkjLMkBScI08
ULTzmxBSw1tSF6y2PXw0Yi8is6aZTZTz85723MwIJ1O0pwWFWRxqhPm6wGlqQ5P+
mLpTHDM3VP9Mf71FMly9z2DQzWahRPqk8Ey2XpymHgZtruYnDafq5mmAblzi/TLj
YpyDDAgef5TqNtMWdRfHA5JfpKbs34lOGS3hgi8Ktsx/ajQ+hEzQgj//lzhpauxY
jmGuAhFOezjCrsrdWywdDKOKCX6bXzUnh9zD1czhesNT3YgJ35U925FenYk7hqzq
9wIDAQAB
-----END PUBLIC KEY-----

it works fine. Is there currently a way to use the certificate format or convert the certificate to a public key format?

1 Answers

Finally, almost one year after this was asked, there is some good news: With the latest versions of Deno (v1.17.0) and jose (v4.3.7), it's now possible to import RSA certificates.

import * as jose from 'https://deno.land/x/jose@v4.3.7/index.ts'

const algorithm = 'RS256'
const x509 = `-----BEGIN CERTIFICATE-----
MIIDHDCCAgSgAwIBAgIIcYOBxdgv20wwDQYJKoZIhvcNAQEFBQAwMTEvMC0GA1UE
AxMmc2VjdXJldG9rZW4uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wHhcNMjAx
MjE1MDkyMDExWhcNMjAxMjMxMjEzNTExWjAxMS8wLQYDVQQDEyZzZWN1cmV0b2tl
bi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBALCJi7xqry88tJOn0sluSRAXjERc8uWZnbdp3BhvvNVGh1jp
LQ83njFs/v8G7NwupgihNkCV9B5IyzJAUnCNPFC085sQUsNbUhestj18NGIvIrOm
mU2U8/Oe9tzMCCdTtKcFhVkcaoT5usBpakOT/pi6UxwzN1T/TH+9RTJcvc9g0M1m
oUT6pPBMtl6cph4Gba7mJw2n6uZpgG5c4v0y42KcgwwIHn+U6jbTFnUXxwOSX6Sm
7N+JThkt4YIvCrbMf2o0PoRM0II//5c4aWrsWI5hrgIRTns4wq7K3VssHQyjigl+
m181J4fcw9XM4XrDU92ICd+VPduRXp2JO4as6vcCAwEAAaM4MDYwDAYDVR0TAQH/
BAIwADAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDQYJ
KoZIhvcNAQEFBQADggEBAFTU2phg+MEJrWi1SVUR1eqP6qmvGavBVXl8kAPY9B0d
1bNwbovj8WM6MFQQm6K/mCys5LA7iTMPu0B9duFhmpX9M8g/1TJ6hUmstw6scr38
YBrhJulQ7HCbUTaI7+yPcSdT7WHXSnYvF/1fOFWaE8vVL9ZtM0DE/ldqx/MetvdQ
WZWEkm6SEpLf3bKweza2PK/3RHtER8l/iV0KCdkh8Dugnf58QYVcsmy5wZkvXKII
2qMl0e9y7wGTW9OvxQFpr4HB1T982r9M56a4TTMTCC8+KWJ/i34DmVro1Ngb+jOp
u7cfh/Z2ahSym5asBz66UOk29W0nk3y4HeNCVwD+CZg=
-----END CERTIFICATE-----`

const rsaPublicKey = await jose.importX509(x509, algorithm)

console.log(rsaPublicKey)

Output:

CryptoKey {
  type: "public",
  extractable: false,
  algorithm: {
    name: "RSASSA-PKCS1-v1_5",
    modulusLength: 2048,
    publicExponent: Uint8Array(3) [ 1, 0, 1 ],
    hash: { name: "SHA-256" }
  },
  usages: [ "verify" ]
}

The GodCrypto Library won't be maintained anymore as the owner feels it's obsolete since the introduction of subtle.crypto in Deno. The issue that I opened (see below) has never been resolved. Original Answer below:

I was able to reproduce the error with the Google certificate and also certificates created on https://mkjwk.org/ and opened an issue on the Godcrypto Gitub site.

The problem is the version of the encoded certificate:

The certificate that I used in my test case is version 3. Your current certificate is version 2. (https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.1)

The owner is working on an update to support all encoding versions.

Related