使用Node.js读取SSL证书的过期日期和通用名称

7
在启用https的Node.js中,我有一个.pem文件作为证书。现在,我想从该文件中读取一些数据,以获取有关证书的信息,例如其到期日期和通用名称。但是,我发现既不是Node的tls模块,也不是ursa等模块支持此操作。当然,我可以调用openssl作为子进程并解析其输出流(我认为使用OpenSSL应该可以完成此任务),但我更喜欢在路径中不依赖外部程序的情况下解决问题。我该如何做呢?
更新:与此同时,我找到了pem模块,它的readCertificateInfo成功地提供了通用名称,甚至可以在使用Node.js 0.8.18(与其文档相反,说明不支持0.7+)。不幸的是,它没有返回到期日期。

更新2: 在内部,pem 只是使用子进程调用 openssl 命令。当然,我也可以自己做到这一点,因此我能够直接从 openssl 中检索所需的信息。无论如何,如果有人有更好的想法(在这种情况下意味着纯 JavaScript / Node.js 解决方案),我会很高兴的 :-)

3个回答

4

同时我找到了答案:PEM格式基本上是使用Base64加密的ASN.1。

因此,您需要先进行Base64解码,然后将结果解析为ASN.1。结果是带有适当值的证书数据结构。

就是这样 :-)!


1
你知道有没有一个JS模块可以做到这一点?我看到的所有东西都依赖于安装OpenSSL。 - Aaron
2
@Golo Roden:仅作为旁注:base64是一种编码(它可以将字节表示为文本),而不是加密(base64根本不提供任何保密性)。 - joonas.fi

3

如果您从类似 tls.connect 的方法获取证书,您可以调用 getPeerCertificate() 方法,您将获得一个类似于以下结构的结果(连接到 github.com):

{ subject: 
   { C: 'US',
     ST: 'California',
     L: 'San Francisco',
     O: 'GitHub, Inc.',
     CN: '*.github.com' },
  issuer: 
   { C: 'US',
     O: 'DigiCert Inc',
     OU: 'www.digicert.com',
     CN: 'DigiCert High Assurance CA-3' },
  subjectaltname: 'DNS:*.github.com, DNS:github.com',
  modulus: 'EF45CDFAEC13EF3E0CD38685530109CA9A3A4E5AF980CBC1BD51509C9944A8CDEB61EA951D4F3053C69FD6D355EDD13A3A43E96DD437C98813DA458E5C99F0811D7A0736EAB1DF0E3C600590A212DB3566D6E077A8A37951A653104F37BC46E38EDC101393990D6AB3101D8714DD78607B547B34A9F2E9E33B5F51B56AA76220BF9DE12A757D9424524A8DCD2D9B5C962FD8DFE8FD38BD80AC116061E7B3B7BF81AE8321C9EB7488F27D116603425FA755F4EC00ABF123BB5AABFBCA7C13AB288C0EC122F99424CA06A4D2A846D6D44618E5CF21B6B9D6D9518639506604A906600F1D6FA8A09B82AF7143645577A656B16D35EC7CAF48AD012E762D16E6D7C1',
  exponent: '10001',
  valid_from: 'Apr 30 00:00:00 2012 GMT',
  valid_to: 'Jul  9 12:00:00 2014 GMT',
  fingerprint: 'B1:4B:A1:6F:5C:EE:28:DA:C4:86:CD:D9:F2:80:8F:2E:A7:4A:51:F4',
  ext_key_usage: [ '1.3.6.1.5.5.7.3.1', '1.3.6.1.5.5.7.3.2' ] }

很抱歉,我还没有找到一种好的方法来解析任意本地证书。


基本上是正确的,但我需要在实际连接之外 :-( - Golo Roden

0

在Node 11+中,可以通过tls模块的getCertificate(本地端对应于getPeerCertificate)来完成此操作:

import { TLSSocket } from "tls";

const socket = new TLSSocket(null, {
  cert: readFileSync(certFilePath)
});
const cert = socket.getCertificate();
socket.destroy();

证书:

{
  subject: {
    CN: "localhost",
  },
  issuer: {
    CN: "localhost",
  },
  subjectaltname: "DNS:localhost",
  modulus: "C35160396...<truncated>",
  bits: 2048,
  exponent: "0x10001",
  pubkey: new Uint8Array([48, 130, /* truncated */]),
  valid_from: "Dec 10 20:27:22 2021 GMT",
  valid_to: "Dec 10 20:27:22 2022 GMT",
  fingerprint: "1E:04:BA:8E:01:C5:E9:1B:F9:A3:09:04:77:45:BB:C9:C4:A0:BB:D0",
  fingerprint256: "68:8F:97:70:AC:E2:52:AB:06:7B:F8:EA:2D:A5:6E:C7:DF:75:C4:D3:12:FB:E8:22:01:0A:71:5A:8D:05:6B:63",
  ext_key_usage: [
    "1.3.6.1.5.5.7.3.1",
  ],
  serialNumber: "D02496A814147089",
  raw: new Uint8Array([48, 130, /* truncated */]),
}

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