使用 node.js 验证带有 CA 证书的 X509 证书

Posted

技术标签:

【中文标题】使用 node.js 验证带有 CA 证书的 X509 证书【英文标题】:Using node.js to verify a X509 certificate with CA cert 【发布时间】:2018-06-30 20:33:56 【问题描述】:

我正在寻找一种 node.js 方法来验证 X509 格式的客户端证书和给我的 CA 证书(这些都不是我创建/管理的,我的软件只需要验证发送的内容给它)。

我已经为这项工作找到了几个模块,但是每个模块都有问题:

X509 可以使用x509.verify(cert, CABundlePath, cb) 来做到这一点,但是它需要从 FS 读取证书,并且我已经将它们保存在内存中。这很麻烦,因为每个到达我的应用程序的网络请求都会这样做。 似乎PKI.js 能够做到这一点,但是他们的示例对我不起作用,但抱怨缺少文件,所以我什至无法尝试。 我尝试了 node-forge,但我不确定我是否正确使用它(他们没有任何 API 文档),但它从 forge.pki.verifyCertificateChain(caStore, [ cer ], cb) 引发了 forge.pki.BadCertificate 错误。 尝试pem 时,使用简单的pem.verifySigningChain(cer, [ ca ], cb) 会引发一些错误,抱怨从/var/... 加载文件。即使它可以工作,我也会避免使用这个库,因为它依赖于 openssl 命令行工具,我想避免这种情况

现在我觉得自己很愚蠢,因为我无法使用上述任何模块完成这个简单的任务。有人能指出一个简单的解决方案,它允许我使用给定的 CA 证书验证 X509 证书的签名/有效性吗? :s

[edit] 基本上我需要Node.js 中的openssl verify -verbose -CAfile ca-crt.pem client1-crt.pem没有 依赖于openssl 命令行工具并且没有 em> 暂时将证书保存到磁盘。

[edit2] 可以只使用https://nodejs.org/api/crypto.html#crypto_verify_verify_object_signature_signatureformat吗?

【问题讨论】:

这是一个写得很好的问题。谢谢。 【参考方案1】:

我终于设法使用node-forge 做到了。这是一个工作代码示例:

let pki = require('node-forge').pki;
let fs = require('fs');

let caCert;
let caStore;

try 
    caCert = fs.readFileSync('path/to/ca-cert.pem').toString();
    caStore = pki.createCaStore([ caCert ]);
 catch (e) 
    log.error('Failed to load CA certificate (' + e + ')');
    return....;


try 
    pki.verifyCertificateChain(caStore, [ cert ]);
 catch (e) 
    return handleResponse(new Error('Failed to verify certificate (' + e.message || e + ')'));

两个证书都应以 base64 编码的 PEM 格式/js 字符串给出。

verifyCertificateChain 检查证书有效性 (notBefore/notAfter) 并验证给定的 CA 链。

我不能 100% 确定这是否是最好的方法,或者这个库是否做得很好,因为它们的源代码 verifyCertificateChain 充满了 #TODOs,所以也许这还没有准备好投入生产? 但至少我有一个可行的解决方案。可能最好创建一个包装libssl c 调用的节点模块,但这对于这个小任务来说只是很多努力。

【讨论】:

cert 定义在哪里? 它是您要验证的证书。它由您提供。 为我工作,但我必须将 PEM 编码(字符串)证书转换为伪造证书对象:const cert = pki.certificateFromPem(certificate.data);(certificate.data 在我的 Electron 应用程序中的 certificate-error 事件中提供.)【参考方案2】:

如果您想直接从 http 请求中检查使用客户端证书,您也可以这样做:

// retrieve certificates from the request ( in der format )
clientCert = req.connection.getPeerCertificate(true).raw.toString('base64'))

将der证书转换为pem并针对castore进行验证的方法。

  const caCert = fs....
  const ca = pki.certificateFromPem(caCert)
  const caStore = pki.createCaStore([ ca ])

  const verify = (clientCert, next) => 
    try 
      const derKey = forge.util.decode64(clientCert)
      const asnObj = forge.asn1.fromDer(derKey)
      const asn1Cert = pki.certificateFromAsn1(asnObj)
      const pemCert = pki.certificateToPem(asn1Cert)
      const client = pki.certificateFromPem(pemCert)
      return pki.verifyCertificateChain(caStore, [ client ], cb)
     catch (err) 
      next(new Error(err))
    
  

我没有找到更好的方法来验证来自request 的客户端“der”证书。

fas3r

【讨论】:

【参考方案3】:

这对我有用:

const fs = require('fs'), pki = require('node-forge').pki
var ca = pki.certificateFromPem(fs.readFileSync('ca.pem', 'ascii'))
var client = pki.certificateFromPem(fs.readFileSync('client.pem', 'ascii'))
try 
    if (!ca.verify(client)) throw 'verify failed'
 catch (err) 
    console.log(err)

try/catch 是必需的,因为在我的情况下 .verify 引发了错误(而不是返回 false)。

【讨论】:

以上是关于使用 node.js 验证带有 CA 证书的 X509 证书的主要内容,如果未能解决你的问题,请参考以下文章

在 Node JS 中为 WebSocket (ws) 使用自签名 CA 证书

Nginx 配置HTTPS 与Node.js 配置HTTPS方法

基于 Azure AD 证书的身份验证:如何在 Node JS 中指定证书路径?

Curl 中出现错误 - 对等证书无法使用已知 CA 证书进行身份验证

Azure 中的客户端证书身份验证和 CA 证书

我在 x509(作为 JWS 中的 x5c 标头)中验证哪些字段以证明证书的合法性?