使用 Deno djwt 验证 Firebase ID 令牌 (JWT)

Verify Firebase ID tokens (JWT) using Deno djwt

我正在尝试按照 Firebase docs 使用第三方库验证 ID 令牌。我已经成功地从 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

但是当我将密钥传递给 djwt verify() or godcrypto RSA.parseKey() 时它在 rsa_import_pem_cert 内部崩溃了 Cannot read property '0' of undefined,在 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],
  };
}

然后我还尝试使用 node.js 使用 node-forge 将 x.509 证书从 PEM 转换为 public 密钥。当我将转换后的 public 密钥传递给那些 deno lib 方法时

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

它工作正常。目前有没有办法使用证书格式或将证书转换为 public 密钥格式?

终于,在提出这个问题将近一年后,有一些好消息: 使用最新版本的 Deno (v1.17.0) and jose (v4.3.7),现在可以导入 RSA 证书。

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)

输出:

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" ]
}

GodCrypto Library 将不再维护,因为所有者认为自从在 Deno 中引入 subtle.crypto 以来它已经过时了。 我打开的问题(见下文)从未得到解决。 原答案如下:

我能够使用 Google 证书以及在 https://mkjwk.org/ and opened an issue on the Godcrypto Gitub 站点上创建的证书重现错误。

问题是编码证书的版本:

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)

所有者正在开发支持所有编码版本的更新。