Signed and current.
Embedded CMS signature validates. SPKI pin matches the issuer. Hash recorded. Not revoked.
Work / Enterprise & Security / PDF Authenticator
No. 31 · Enterprise · Documents · Zero-knowledgeA signed PDF can be forged with a $5 app and an afternoon. Universities, banks, and governments still pretend "wet signature scanned" is verification. This portal does not. PAdES signatures, SPKI-pinned verifier, TOTP-secured revocation. Server stores only a 32-byte SHA-256. The document itself never leaves your machine.
Issued by Shoolini University on 14 May 2024.
4a8d7c1f...b9e2c19fsha256:b1f4...e22aThis is a representative card. Real documents are never stored on the server.
Act I · The Problem
"Wet signature, scanned. Looks official. Move on."
Act II · The Promise
The verifier asks one question and gets one of four answers. The document never leaves their browser. The portal never sees its contents.
Embedded CMS signature validates. SPKI pin matches the issuer. Hash recorded. Not revoked.
Re-computed SHA-256 does not match. The signature math fails. Reject the document. Investigate.
Issuer rotated TOTP and revoked. Hash recorded as void. Verifier sees the change in real time.
Hash never seen. Could be a draft, a forgery, or a document from a different issuer. Default conservative.
Act III · The Pipeline
Step 01 · Sign
Admin authenticates via Argon2id-hashed password and TOTP. A Cloudflare Worker forwards a timestamp, nonce, and SHA-256 digest, HMAC-protected, to a Java microservice running Apache PDFBox + Bouncy Castle.
Step 02 · Store
D1 records 32 bytes per document plus metadata. The PDF itself is returned to the admin and never stored. Zero-knowledge in the literal sense.
Step 03 · Verify
The verify portal validates the embedded CMS signature locally and checks the pinned SPKI fingerprint against the issuer. Returns one of four states. Never uploads the document.
Step 04 · Revoke
Issuer signs in, presents TOTP, clicks revoke. CSRF protection. Origin pin. The next verifier sees REVOKED instantly.
Act IV · The Deploy
An automated deployment script orchestrates the entire setup on a fresh Ubuntu or Debian VM. System dependencies, nginx, certificates, the Worker, the Java signer, the database wiring. Secrets are generated automatically.
sudo bash -lc 'curl -fsSL \ https://raw.githubusercontent.com/divyamohan1993/dmj-one-pdf-authenticator/refs/heads/main/one-click-deployment/static/autoconfig.sh?nocache=$(date +%s) \ | sudo bash -s -- YOUR-D1-DATABASE-ID'
part 01
dmj-part1.sh installs dependencies, configures nginx, provisions certificates, wires firewall.
part 02
dmj-part2.sh builds and deploys the Worker (TypeScript) and the Java signer (Maven). Dynamic port detection. Auto-reload nginx.
cron
Purges expired sessions, replay nonces, and rate-limit buckets. Database stays small. Forever.
CI
GitHub Actions CI plus CodeQL run on every push. Both badges live on the repo README.
Act V · Proof
Edge-served verify portal. Globally distributed. Rate limited. Stores only 32-byte digests plus metadata. The PDF is not on the server. Ever.
Worker authenticates each signing request to the Java service with timestamp, nonce, and SHA-256. Replay-protected. Origin-pinned.
Signing happens in a Java microservice using PDFBox for PAdES embedding and Bouncy Castle for the CMS signature. Java 17 friendly.
Use it freely. Credit the author. AAL requires attribution in user-facing UI, derivative works, and source. CITATION.cff in the repo.
autoconfig.sh wraps both deployment phases. Wrangler-authenticated. Secrets generated and stored automatically. Idempotent.
GitHub Actions. Pipeline badges live on the README. Every push checked. Every release tagged.
I build verification systems where the verifier does not have to trust the issuer's server, and the issuer's server does not have to hold the document. The portal answers one question, four ways. Nothing more.