'Read expiration date and common name from SSL certificate using Node.js
In an https-enabled Node.js I have the certificate as a .pem file.
Now I would like to read some data from that file to have information about the certificate, such as its expiration date and the common name.
As I have seen neither Node's very own tls module nor modules such as ursa support this.
Of course I might call openssl as a child process and parse its output stream (I think this task should be doable using OpenSSL), but I'd prefer a solution without relying on the availability of an external program in the path.
How could I do this?
Update: Meanwhile, I found the pem module, and its readCertificateInfo provides the common name successfully, even using Node.js 0.8.18 (which is contrary to its docs who state that 0.7+ is not supported). Unfortunately, it does not return the expiration date.
Update 2: Internally, pem just calls out for the openssl command using a child process. Of course I can do this by myself, hence I am able to retrieve the information required from openssl directly. Anyway, if someone has a better idea (which, in this case means, a pure JavaScript / Node.js solution) I'd be happy about it :-)
Solution 1:[1]
Meanwhile I found the answer: The PEM format is basically ASN.1 using a Base64 encryption.
Hence, you need to Base64 decode first, and then parse the result as ASN.1. The result is the data structure of the certificate with the appropriate values in it.
That's it :-)!
Solution 2:[2]
If you're obtaining the certificate from something like tls.connect you can call getPeerCertificate() and you'll get back a structure that looks like this (connected to 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' ] }
I haven't found a decent way to parse arbitrary local certs though, sorry.
Solution 3:[3]
This can be done in Node 11+ with the tls module via getCertificate (the local side analogue to getPeerCertificate):
import { TLSSocket } from "tls";
const socket = new TLSSocket(null, {
cert: readFileSync(certFilePath)
});
const cert = socket.getCertificate();
socket.destroy();
cert:
{
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 */]),
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Golo Roden |
| Solution 2 | Paul Kehrer |
| Solution 3 |
