Skip to content

About

🗂NodeJS module to handle certificate related OpenSSL commands

Topics

Resources

Stars

7 stars

Watchers

2 watching

Forks

Latest commit

 

History

95 Commits

Folders and files

Repository files navigation

openssl-cert-tools

npm version CI

Node.js module to handle TLS certificates using OpenSSL.

Installation

cd your-project/
npm install openssl-cert-tools

Usage

All functions return Promises and work with async/await:

const opensslTools = require('openssl-cert-tools');

getCertificateInfo()

Decodes a PEM encoded certificate (string or Buffer) into its issuer, subject, validity dates and subjectAltName extension:

const fs = require('fs');

const demoCertificate = fs.readFileSync('certificate.pem');

const info = await opensslTools.getCertificateInfo(demoCertificate);
console.log(info);
/* =>
 * {
 *   certificate: <Buffer ...>,
 *   issuer: {
 *     C: 'US',
 *     O: "Let's Encrypt",
 *     CN: 'R11'
 *   },
 *   subject: {
 *     CN: 'frd.mn'
 *   },
 *   subjectAltName: {
 *     DNS: ['frd.mn', 'www.frd.mn']
 *   },
 *   validFrom: 2026-06-17T00:00:00.000Z,
 *   validTo: 2026-12-16T00:00:00.000Z,
 *   remainingDays: 84
 * }
 */

For expired certificates, remainingDays is 0 and the additional expiredDays property reports how long ago the certificate expired.

Behaviors worth knowing:

  • certificate echoes the input exactly as it was passed in (a Buffer in, a Buffer out; a string in, a string out).
  • issuer/subject are plain objects keyed by DN component. If a component appears more than once (e.g. two OU= entries), the last occurrence wins.
  • subjectAltName groups the SAN entries by type (DNS, IP Address, email, URI, Registered ID, ...), each type mapping to an array of values. It is absent when the certificate carries no SAN extension. To check whether a hostname is covered, look it up in subjectAltName.DNS.

Distinguished names are parsed from the RFC2253 representation, so values containing escaped commas or equals signs (e.g. O=Foo\, Inc.) are handled correctly. SAN values containing commas (e.g. URIs) are preserved as well.

getCertificateRequestInfo()

Decodes a PEM encoded certificate signing request into its subject:

const demoCertificateRequest = fs.readFileSync('request.csr');

const info = await opensslTools.getCertificateRequestInfo(demoCertificateRequest);
console.log(info);
/* =>
 * {
 *   certificate: <Buffer ...>,
 *   subject: {
 *     C: 'DE',
 *     ST: 'Bavaria',
 *     L: 'Eibelstadt',
 *     O: 'YEAHWHAT?! Minecraft servers',
 *     OU: 'Mail system',
 *     CN: 'chewbacca.yeahwh.at',
 *     emailAddress: 'postmaster@yeahwh.at'
 *   }
 * }
 */

getCertificate()

Downloads the certificate of a remote host:

const crt = await opensslTools.getCertificate('frd.mn', '443');
console.log(crt);
/* =>
 * -----BEGIN CERTIFICATE-----
 * MIIFeDCCA2igAwIBAgISAy3SwuLrRcMtba+SuIL2Dtr7MA0GCSqGSIb3DQEBCwUA
 * ...
 * -----END CERTIFICATE-----
 */

An optional third argument adjusts the timeout (in milliseconds, defaults to 5000):

const crt = await opensslTools.getCertificate('frd.mn', 443, { timeout: 10000 });

getCertificateChain()

Downloads the complete certificate chain served by a remote host:

const chain = await opensslTools.getCertificateChain('frd.mn', '443');
console.log(chain);
/* =>
 * [
 *   '-----BEGIN CERTIFICATE-----\n...',
 *   '-----BEGIN CERTIFICATE-----\n...',
 *   '-----BEGIN CERTIFICATE-----\n...'
 * ]
 */

Accepts the same { timeout } option as getCertificate().

getCertificateHash()

Returns the hash of a certificate's modulus. Useful to check whether a certificate, a request and a private key belong together: matching inputs produce the same modulus hash. Defaults to SHA-256:

await opensslTools.getCertificateHash(demoCertificate);
// => '903852adf40f7087df962b0a04312c36bef3f20206f8a01f5d7e8a23f59e1fd2'

await opensslTools.getCertificateHash(demoCertificate, { algorithm: 'md5' });
// => 'baf59ff7f5b05fde6799439b6f31a290'

Supported algorithms: md5, sha1, sha256 (default) and sha512.

getCertificateRequestHash()

Same as getCertificateHash(), but for certificate signing requests:

await opensslTools.getCertificateRequestHash(demoCertificateRequest);
// => '9ae9b46a2030628f01883f32c88a10e7d62c695dcbfedaa1b1c755a749a5db6a'

getPrivateKeyHash()

Same as getCertificateHash(), but for private keys:

await opensslTools.getPrivateKeyHash(demoPrivateKey);
// => '0583b0f265569ec7b472c587e7704a78462a53a518949df979e921b5feb255f3'

getPublicKeyHash()

Returns the hash of the Subject Public Key Info (SPKI) of the public key inside a certificate, certificate signing request or private key. Matching inputs produce the same hash, for any key algorithm (RSA, EC, Ed25519, ...) — unlike the modulus hash functions above, which only work for RSA. Pass the input type as the second argument:

await opensslTools.getPublicKeyHash(demoCertificate, 'certificate');
await opensslTools.getPublicKeyHash(demoCertificateRequest, 'request');
await opensslTools.getPublicKeyHash(demoPrivateKey, 'key');
// All three resolve to the same hash for inputs of the same keypair
// => 'f552ba4d11bd5a9c2f8827d9e09995315ceff096606dead756afca5d351853ea'

Supported kinds: certificate, request and key; supported algorithms: md5, sha1, sha256 (default) and sha512.

The result is identical to hashing the DER encoded public key with openssl itself, so you can cross-check it by hand:

openssl pkey -in key.pem -pubout -outform DER | openssl dgst -sha256

Migrating from 1.x

Version 2.0 is a breaking rewrite:

  • Promises instead of callbacks: every function returns a Promise, drop the callback and use await (or .then()). If you need callbacks, Node's built-in util.callbackify() can wrap the new functions.
  • SHA-256 instead of MD5: the three hash functions hash the modulus with SHA-256 by default. Pass { algorithm: 'md5' } to keep comparing against openssl x509 -noout -modulus | openssl md5 output.
  • Hash values changed: besides the new default algorithm, 1.x produced mangled hashes (MD5<hash>) on OpenSSL 3.x because its output prefix parsing broke.
  • Configurable timeout: getCertificate() and getCertificateChain() accept { timeout } in milliseconds instead of the fixed 5 second limit.
  • DN values keep their exact content: 1.x split issuer/subject names on every comma and equals sign, corrupting values like O=Foo, Inc..

Contributing

  1. Fork it
  2. Create your feature branch: git checkout -b feature/my-new-feature
  3. Commit your changes: git commit -am 'Add some feature'
  4. Push to the branch: git push origin feature/my-new-feature
  5. Submit a pull request

Requirements / Dependencies

  • Node.js >= 18
  • OpenSSL binary in $PATH (OpenSSL 1.x, OpenSSL 3.x and LibreSSL are supported and covered by CI)

Credits

License

MIT

About

🗂NodeJS module to handle certificate related OpenSSL commands

Topics

Resources

Stars

7 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages