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

23

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

我已经找到了几个可以完成此任务的模块,但是我在使用每个模块时都遇到了问题:

  • X509可以使用x509.verify(cert, CABundlePath, cb)实现,但需要从FS中读取证书,而我已经将它们存储在内存中。这很繁琐,因为每个到达我的应用程序的Web请求都会执行此操作。
  • 看起来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
[编辑] 基本上我需要在Node.js中执行openssl verify -verbose -CAfile ca-crt.pem client1-crt.pem,但不要依赖于openssl命令行工具和不要临时将证书保存到磁盘。
[编辑2] 是否可以只使用https://nodejs.org/api/crypto.html#crypto_verify_verify_object_signature_signatureformat

7
这是一个写得非常好的问题。谢谢你。 - Dan Grahn
3个回答

14

我最终使用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链。

我不确定这是否是最佳方法,或者此库是否做得很好,因为它们的verifyCertificateChain源代码中充满了#TODO,所以可能还没有准备好投入生产?但至少我有一个基本可用的解决方案。也许创建一个封装libssl c调用的节点模块会更好,但为这个小任务付出太多努力了。


cert 定义在哪里? - J'e
这是您想要验证的证书。它由您提供。 - user826955
对我来说起作用了,但我必须将一个PEM编码(字符串)的证书转换为Forge证书对象:const cert = pki.certificateFromPem(certificate.data);(certificate.data是在我的Electron应用程序中提供的“certificate-error”事件中提供的。) - ZeeCoder

4
如果您想直接检查来自HTTP请求的客户端证书,也可以像这样操作:
// retrieve certificates from the request ( in der format )
clientCert = req.connection.getPeerCertificate(true).raw.toString('base64'))

将DER证书转换为PEM格式并针对CA存储库进行验证的方法。

  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))
    }
  }

我没有找到更好的方法来验证请求中客户端的"der"证书。

fas3r


1
这对我有效:
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)
}

在我的情况下,.verify 抛出了一个错误(而不是返回 false),因此需要使用 try/catch。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接