ecdsa.com

Decode a certificate · Node.js

How to decode an X.509 certificate in Node.js

Node.js decodes X.509 certificates natively: the crypto.X509Certificate class parses PEM or DER and exposes subject, issuer, validity, fingerprints and the public key as plain properties — no ASN.1 wrangling and no dependencies.

Tested with Node.js 26 (OpenSSL 3.x backend).

Same recipe in:Node.jsPythonGoOpenSSL
decode-cert.mjs — read the fields that matter
import { readFileSync } from "node:fs";
import { X509Certificate } from "node:crypto";
 
const cert = new X509Certificate(readFileSync("cert.pem")); // PEM or DER
 
console.log("subject:", cert.subject);
console.log("issuer:", cert.issuer);
console.log("valid:", cert.validFrom, "->", cert.validTo);
console.log("serial:", cert.serialNumber);
console.log("SHA-256 fingerprint:", cert.fingerprint256);
 
const key = cert.publicKey;
console.log("key type:", key.asymmetricKeyType); // 'ec' for ECDSA certs
console.log("key details:", key.asymmetricKeyDetails); // { namedCurve: 'prime256v1' }
date math and chain checks
const expiresInDays =
(new Date(cert.validTo) - Date.now()) / 86_400_000;
console.log("days until expiry:", Math.floor(expiresInDays));
 
// does this certificate belong to that CA?
// console.log(cert.checkIssued(caCert)); // caCert: another X509Certificate

How it works

  1. The constructor accepts a PEM string/Buffer or raw DER — detection is automatic.
  2. cert.publicKey is a regular KeyObject: pass it straight to crypto.verify or export it as SPKI PEM.
  3. asymmetricKeyDetails.namedCurve reports the OpenSSL curve name — prime256v1 means P-256.
  4. fingerprint256 is the SHA-256 hash of the whole DER certificate, colon-separated — the value browsers and audit tools display.
  5. cert.raw exposes the certificate's DER bytes as a Buffer — hand them to other parsers or hash them yourself to reproduce fingerprint256.

Gotchas

  • validFrom/validTo are human-format strings, not Date objects — wrap them in new Date(...) before comparing, as the second snippet does.
  • The certificate fingerprint hashes the entire certificate; the *key* fingerprint hashes only the SPKI. Same key re-issued in a new certificate changes the first, not the second.
  • Parsing a certificate proves nothing about trust: X509Certificate decodes self-signed and expired certs happily. Chain validation is a separate step (checkIssued, or a TLS library).

Related recipes