Google KMS 非对称密钥验证失败

Google KMS asymmetric keys validation failure

我正在为自定义目的开发 OAuth 服务器实现,并尝试将 Google 的 KMS 服务用于 JWT 令牌的 signining/verification。

我能够很好地创建签名,问题始于验证步骤 - 总是导致错误(无效令牌)。然后我继续简化代码以找到原因并最终得到一个我无法进一步简化但仍然无法正常工作的代码。我的代码基于 Google KMS Docs.

中的示例
export async function sign (message: string): Promise<Buffer> {
    const name = getKeyPath();
    const digest = crypto.createHash('sha512').update(message).digest();

    const [ result ] = await client.asymmetricSign({
        name,
        digest: {
            sha512: digest
        }
    });

    return result.signature as Buffer;
}

export async function verify (message: string, signature: Buffer): Promise<boolean> {
    const publicKey = await getPublicKey();
    const verifier = crypto.createVerify('SHA512');

    verifier.write(message);
    verifier.end();

    return verifier.verify(publicKey, signature);
}

export async function getPublicKey (): Promise<string> {
    const name = getKeyPath();

    const [ publicKey ] = await client.getPublicKey({ name });

    return publicKey.pem;
}

(async () => {
    const message = 'test';
    const signature = await sign(message);
    const valid = await verify(message, signature);

    console.log(message);
    console.log(signature);
    console.log(valid);
})();

结果:

test
<Buffer 19 a2 89 37 e5 43 78 c8 63 6b 7e 19 28 10 f7 93 ad c0 fa 10 ce 0a 06 2d 79 52 58 9a a4 7c d5 77 1c 99 b2 cb ce 67 e8 93 d6 0e ef b9 f6 95 89 19 4e 28 ... 462 more bytes>
false

天哪,天哪,真是个好时机。我在 rewriting the Node.js Cloud KMS samples 的过程中,昨晚浪费了整整 2 个小时的调试时间。我猜这是一个 RSA 密钥?

问题是Node discards/ignores padding规范,导致验证失败。你必须通过构造一个关键对象来强制它使用 PSS 填充:

async function verify(message, signatureBuffer) {
  // Get public key
  const [publicKey] = await client.getPublicKey({
    name: 'projects/my-p/locations/.../cryptoKeyVersions/123',
  });

  // Create the verifier. The algorithm must match the algorithm of the key.
  const crypto = require('crypto');
  const verify = crypto.createVerify('sha512');
  verify.update(message);
  verify.end();

  const key = {
    key: publicKey.pem,
    padding: crypto.constants.RSA_PKCS1_PSS_PADDING, // <-- THIS
  };

  const verified = verify.verify(key, signatureBuffer);
  return verified;
}