Skip to content

Latest commit

 

History

History
91 lines (71 loc) · 3.84 KB

File metadata and controls

91 lines (71 loc) · 3.84 KB
name pem-certificate-decoder
description Decode and inspect PEM-encoded X.509 certificate chains in the browser with the Secutils.dev PEM Decoder. Build a one-click prefilled URL the user can open by encoding the raw PEM string into the fragment of https://tools.secutils.dev/pem#{encoded}. Trigger when the user asks to "decode this certificate", "inspect a PEM chain", "show the SANs in this cert", "what's the issuer of this PEM", or anything that names secutils.dev/pem.

PEM Certificate Decoder (Secutils.dev)

Hand the user a URL that opens the PEM Decoder pre-loaded with their chain. Parsing happens in the browser - the fragment is never sent to the server, so even a privacy-leaking certificate (or a misplaced private key, see Caveats) stays client-side. The tool auto-sorts chain order (leaf first) and surfaces subject / issuer / SANs / validity / key algorithm and size / signature algorithm / SHA-1 + SHA-256 fingerprints per cert.

Inputs

Field Type Default Notes
pem string required One or more concatenated -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- blocks. Chain order does not matter.

State shape: a raw string - no JSON wrapper. The state is exactly the PEM text the user supplied (including newlines between blocks).

Wire format

After URL-safe base64 decoding:

| 4 bytes uncompressed-length (LE u32) | N bytes raw DEFLATE of UTF-8 string |

Pipeline: take the PEM string verbatim → UTF-8 bytes → deflate-raw → prepend the 4-byte LE u32 of the uncompressed length → base64url (+-, /_, strip =).

How to produce the URL

Run this on any machine with Node ≥ 18 (no deps):

node -e '
const zlib = require("node:zlib");
const fs   = require("node:fs");
const pem  = process.argv[1] === "-" ? fs.readFileSync(0, "utf8") : process.argv[1];
const utf8 = Buffer.from(pem, "utf8");
const out  = Buffer.concat([Buffer.alloc(4), zlib.deflateRawSync(utf8)]);
out.writeUInt32LE(utf8.length, 0);
const enc  = out.toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"");
console.log("https://tools.secutils.dev/pem#" + enc);
' -  <<'EOF'
-----BEGIN CERTIFICATE-----
MIIDXTCCAkWgAwIBAgIJAKl...
-----END CERTIFICATE-----
EOF

Read PEM from stdin (heredoc) so the multi-line block with embedded \n survives untouched. The fragment is opaque - print the full URL.

The same tools.secutils.dev/pem URL with no fragment loads an empty decoder if you'd rather just direct the user to paste themselves.

Decoding without opening the tool (optional)

If the user only wants a textual summary in chat (no UI), parse the PEM locally with any X.509 library: openssl x509 -in cert.pem -text -noout, Node crypto.X509Certificate, Python cryptography, etc. The shareable URL is most useful when the user wants the visual chain ladder + SAN list.

After producing

Hand the URL back in a fenced block or inline code. Keep summaries to one sentence; don't paraphrase certificate fields.

Caveats

  • The PEM travels in the URL fragment. The fragment never reaches the Secutils server but is fully visible to anyone with the link. Rare but catastrophic: if the user accidentally includes a -----BEGIN PRIVATE KEY----- block, refuse to encode and tell them to strip it first.
  • DER-encoded (binary) certs are not supported - base64-wrap them in PEM envelopes first (openssl x509 -inform DER -in cert.der -out cert.pem).
  • Signature verification against the issuer is out of scope for this tool. Use a server-side library (or openssl verify) for trust-chain validation.