Forge PKI

Forge PKI — Readme

A browser-based internal PKI toolkit. Generate private CAs, create certificate signing requests, issue certificates, verify deployments, and store artifacts locally.

What this site does

Forge PKI is a fully client-side PKI workbench. Keys, CSRs, and certificates are generated in your browser using Web Crypto and PKI.js. Nothing is sent to a backend, so your private key material never leaves the device unless you choose to export it.

Certificate Authorities
/ca

Create self-signed root CAs with RSA, ECDSA, or Ed25519 keys. Set active CA, export cert/key, and delete when no longer needed.

Generate CSRs
/csr

Build PKCS#10 certificate signing requests with subject DN, SANs, key usage, and extended key usage. Download PEM CSR and private key, plus a copyable equivalent OpenSSL req -new command.

Issue Certificates
/issue

Sign a CSR with a selected CA. Configure validity, serial number, SANs, KeyUsage, EKU, and BasicConstraints. Export cert, chain, fullchain, and a copyable OpenSSL x509 -req reference command.

Let's Encrypt (ACME)
/acme

Request publicly-trusted TLS certificates from Let's Encrypt using your own CSR. Supports staging and production directories, HTTP-01 and DNS-01 challenges, and resuming in-progress orders from the Library.

Verify & Troubleshoot
/verify

Inspect certificates (including full chains) and CSRs, match CSR to cert, match key to cert, validate chains, and run live TLS checks against deployed hostnames (leaf + certificate bundle when the server sends it).

Library
/library

Store CSRs, private keys, issued certificates, certificate bundles, and in-progress Let's Encrypt orders in IndexedDB for easy retrieval and resumption later in the same browser.

Capabilities

  • Subject DN fields: CN, O, OU, C, ST, L, E
  • Subject Alternative Names: dNSName, iPAddress, rfc822Name, uniformResourceIdentifier
  • Key algorithms: RSA 2048/3072/4096, ECDSA P-256/P-384, Ed25519
  • Key Usage and Extended Key Usage selection
  • Custom validity windows and serial numbers
  • Export PEM, PKCS#12 (.p12), and PKCS#7 (.p7b) bundles
  • Local IndexedDB persistence for generated artifacts
  • OpenSSL reference commands on Generate CSR, Issue Certificate, and Verify match tabs (CSR ↔ Cert, Key ↔ Cert, Key ↔ Key) — copyable CLI equivalents
  • Deployed TLS inspection with selectable TLS version, cipher, mTLS client certificate, and full certificate bundle when the server sends intermediates during the handshake
  • Client cipher capability panel showing the protocol versions and suites the backend can negotiate
  • ACME / Let's Encrypt integration for publicly-trusted certificates via HTTP-01 or DNS-01

Library

The Library is a local IndexedDB store for every PKI artifact you create in this browser: CSRs, private keys, issued certificates, CA roots, and full certificate chains. It is not a cloud service — all records stay on your device.

In addition to certificates and keys, the Library keeps a Let's Encrypt Requests tab. Every in-progress ACME order is auto-saved as a draft, so you can close the tab, refresh, or resume later without creating a duplicate order at Let's Encrypt. Completed requests link to the issued certificate in the Library.

Let's Encrypt (ACME) process

The ACME wizard requests a publicly-trusted certificate from Let's Encrypt. You can choose the staging directory for testing or the production directory for a live, browser-trusted certificate.

  1. 1. Create / select account. A new ACME account key is generated in the browser; only the public key is registered with Let's Encrypt.
  2. 2. Upload or generate a CSR. The CSR defines the domains you want to protect.
  3. 3. Start the order. Let's Encrypt returns an authorization for each domain. The order is saved to the Library as a resumable draft.
  4. 4. Publish the challenge. Choose HTTP-01 (serve a token file at /.well-known/acme-challenge/) or DNS-01 (add a TXT record for _acme-challenge.<domain>).
  5. 5. Validate. Once the challenge is reachable, click validate. The app polls Let's Encrypt until every domain is authorized.
  6. 6. Finalize. After all authorizations are valid, send the CSR to Let's Encrypt and download the issued certificate.

If validation fails, the challenge card shows the exact error from Let's Encrypt and a Verify DNS now button that checks public DNS via Google DNS-over-HTTPS so you can confirm propagation before retrying. Because ACME authorizations are single-shot, a failed authorization cannot be retried on the same order. Use the Start new order button to create a fresh order with the same CSR and domains when you need Let's Encrypt to re-check a challenge.

OpenSSL reference commands

Keys and certificates are created in the browser. Generate CSR, Issue Certificate, and Verify match tabs also show an equivalent OpenSSL command you can copy for servers or automation.

  • Generate CSR openssl req -new with matching -newkey, -subj, and -addext for SANs, Key Usage, and EKU.
  • Issue Certificate — an issue-ext.cnf snippet plus openssl x509 -req using your CA cert/key, validity, serial, BasicConstraints, KU, EKU, and SANs parsed from the CSR.
  • Verify → CSR ↔ Cert — compare SPKI SHA-256 from openssl req -noout -pubkey and openssl x509 -noout -pubkey.
  • Verify → Key ↔ Cert / Key ↔ Key openssl pkey -pubout vs peer pubkey digest (certificate, CSR, or PUBLIC KEY PEM).

CSR/issue commands reflect the same intent as the in-browser output. Verify commands reproduce the same SPKI SHA-256 check when PEMs are saved to the suggested filenames.

How issuing works

The Issue page signs a CSR with a private CA you created in the app. You can set the validity period, serial number, Key Usage, and Extended Key Usage. After signing, the issued certificate, the CA chain, and the full chain are saved to the Library and can be exported as PEM. An OpenSSL x509 -req reference command is shown alongside the PEM blocks.

The Issue as intermediate CA (sets BasicConstraints CA:TRUE) checkbox turns the issued certificate into a subordinate CA instead of a leaf certificate. When checked, the certificate receives the BasicConstraints CA flag and is also given the Key Usage bits keyCertSign and cRLSign, which are required to sign other certificates or certificate revocation lists. This lets you build a multi-tier PKI where the root CA signs one or more intermediate CAs, and those intermediate CAs sign leaf certificates.

Key Usage and Extended Key Usage

When you generate a CSR, the app lets you request two X.509 extensions that declare what the certificate is allowed to do. They are embedded in the CSR as an extension request and do not change how the private key is generated.

Key Usage (KU)

A bit string that constrains the cryptographic operations the certificate can perform.

  • Digital Signature — TLS, client auth, code signing
  • Non Repudiation — historical legal non-repudiation flag
  • Key Encipherment — RSA TLS server certificates
  • Data Encipherment — raw data encryption (rare)
  • Key Agreement — DH/ECDH key exchange
  • Key Cert Sign — CA certificates
  • CRL Sign — CA/CRL issuer certificates
Extended Key Usage (EKU)

A list of OIDs that further restricts the purpose of the certificate.

  • Server Authentication — TLS server certs
  • Client Authentication — mTLS / client certs
  • Code Signing — signed binaries and scripts
  • Email Protection — S/MIME
  • Time Stamping — RFC 3161 time stamps
  • OCSP Signing — OCSP responder

How verification works

The Verify page offers eight tabs:

Inspect

Decode a PEM certificate, CSR, or full certificate chain. View subject, issuer, SANs, validity, fingerprints, signature validity, and public key info for every certificate in the chain.

CSR ↔ Cert

Compare the public key in a CSR with the public key in a certificate (SPKI SHA-256). Shows copyable OpenSSL pubkey digest commands alongside the match result.

Key ↔ Cert

Compare a private key with a certificate or CSR. Includes OpenSSL pkey -pubout vs peer pubkey digest commands.

Public Key

Paste a certificate or CSR and extract the embedded Subject Public Key as a standalone PUBLIC KEY PEM, with subject, algorithm, and SPKI fingerprint.

Key ↔ Key

Compare a private key to a PUBLIC KEY PEM, certificate, or CSR. Shows OpenSSL SPKI digest commands with the match result.

Chain

Paste a leaf certificate and CA certificate to verify the signature, validity dates, and issuer/subject match.

Deployed

Enter a public hostname to perform a live TLS handshake. Inspect the leaf certificate, decode the full chain when the server sends intermediates, download leaf/chain/fullchain PEMs, and test TLS version, cipher selection, and mTLS client certificates.

Common issues

A checklist of typical PKI problems such as hostname mismatch, untrusted CA, key mismatch, expiry, missing EKU, and broken basicConstraints.

Security model

All cryptographic operations run in the browser. Private keys are generated via Web Crypto (or @noble/ed25519 for Ed25519) and stored only in your browser's IndexedDB when you choose to save them to the Library.

The deployed TLS check and the Let's Encrypt (ACME) integration both use server-side network requests. The deployed TLS check does not transmit any of your private key material unless you explicitly provide a client certificate for mutual TLS testing. For ACME, your account private key is kept in IndexedDB and is only sent to the server to sign ACME protocol messages; it is never persisted on the server.

Important notes

  • Back up exported keys and certificates. Browser storage can be cleared by the user or by automated cleanup.
  • Certificates issued from your own private CAs are useful for internal infrastructure, development environments, and testing. They are not trusted by default in public browsers unless you install the CA root. Certificates issued through the ACME flow from Let's Encrypt are publicly trusted when production is selected.
  • Always verify the intended key usage and extended key usage before issuing or deploying a certificate.

Technical stack

Built with TanStack Start, React 19, Tailwind CSS, shadcn/ui, PKI.js, and Web Crypto. Deploys via Nitro (this project uses the vercel preset). Almost all PKI work runs in the browser; the server is used only where the platform must make outbound network calls.

  • Client-side: CA/CSR issuance, Library, verify pasted PEMs, chain checks
  • Server (Node/Bun): ACME JWS signing proxy to Let's Encrypt
  • Server (Node/Bun only): Deployed TLS inspection and client cipher listing via node:tls
  • Not on edge workers: Cloudflare Workers and Vercel Edge lack node:tls — those two features return a clear error instead of failing silently