VerifyKitv0.5.1
All posts
|8 min read|TrexoLab
pdf verificationjavascriptwasmbrowserdigital signatures

How to Verify PDF Digital Signatures in the Browser with JavaScript

Digital signatures in PDF documents provide cryptographic proof of document integrity and signer identity. Traditionally, verifying these signatures required server-side processing or desktop applications like Adobe Acrobat. With WebAssembly, you can now verify PDF signatures entirely in the browser — no server uploads, no external services.

Why Browser-Side Verification?

When users upload signed PDFs to a server for verification, the document leaves their device. For contracts, medical records, legal filings, and financial documents, this creates unnecessary privacy risk. Browser-side verification keeps the PDF bytes on the user's device throughout the entire process.

VerifyKit uses a Rust-compiled WebAssembly module to perform all cryptographic operations — RSA, ECDSA, Ed25519 signature validation, SHA-256/384/512 hashing, ASN.1 parsing, and X.509 certificate chain building — directly in the browser's WASM sandbox.

The 8-Point Verification Model

VerifyKit evaluates every PDF signature against eight independent checks:

  1. Integrity — Verifies the document bytes match the signed byte range. Detects any post-signing tampering.
  2. Signature — Validates the CMS/PKCS#7 signature is mathematically correct against the signer's public key.
  3. Certificate Chain — Builds a chain from the signer's certificate to a trusted root CA from the built-in AATL store (119 Adobe-trusted roots).
  4. Expiry — Confirms all certificates in the chain were valid at signing time.
  5. Timestamp — Validates any embedded RFC 3161 timestamp token for cryptographic proof of signing time.
  6. Revocation — Checks whether the signer's certificate has been revoked via CRL or OCSP.
  7. Algorithm — Enforces minimum cryptographic strength — no MD5/SHA-1, RSA keys must be 2048 bits or more.
  8. Extended Key Usage — Verifies the certificate permits document signing.

Each check produces its own status (valid, invalid, warning, unknown), and the overall signature status is derived from the combination. This gives you granular visibility into exactly why a signature passed or failed.

Getting Started

Install the React package:

bash
npm install @trexolab/verifykit-react

Add the provider and viewer to your app:

tsx
import { VerifyKitProvider, Viewer } from '@trexolab/verifykit-react'
 
function App() {
  return (
    <VerifyKitProvider config={{
      workerUrl: 'https://unpkg.com/pdfjs-dist@5.5.207/legacy/build/pdf.worker.min.mjs'
    }}>
      <Viewer />
    </VerifyKitProvider>
  )
}

That's it. When a user loads a signed PDF, signatures are automatically verified through the full 8-point pipeline and results are displayed with visual status indicators.

Headless Verification (No UI)

For programmatic verification without a viewer UI:

ts
import { createVerifier } from '@trexolab/verifykit-core'
 
const verifier = await createVerifier()
const result = await verifier.verify(pdfBuffer)
 
for (const sig of result.signatures) {
  console.log(`${sig.signerName}: ${sig.overallStatus}`)
  console.log(`  Integrity: ${sig.integrityCheck.status}`)
  console.log(`  Chain:     ${sig.certificateChainCheck.status}`)
  console.log(`  PAdES:     ${sig.padesLevel ?? 'N/A'}`)
}

This same API works in Node.js 20+, Deno, and Bun — making it possible to share verification logic between client and server.

Built-in Trust Store

The WASM binary ships with 119 Adobe Approved Trust List (AATL) root CA certificates — the same roots that Adobe Acrobat trusts. Certificate chain validation works out of the box without any configuration.

For enterprise deployments, you can extend the trust store with your own root CAs:

ts
const verifier = await createVerifier({
  trustStore: {
    certificates: [myCorpRootPem],
    mode: 'merge', // adds alongside the 119 AATL roots
  },
})

AIA Chain Resolution

Many PDFs don't embed the full certificate chain. VerifyKit automatically resolves missing intermediate certificates using Authority Information Access (AIA) extensions — fetching intermediates from CA-provided URLs and building the complete chain. This significantly improves verification success rates for real-world documents.

Performance

The Rust/WASM core is 3.7x faster than equivalent JavaScript implementations. The WASM binary is base64-embedded in the JavaScript bundle, so there are no external files to host and no additional network requests. First verification takes 20-50ms for WASM initialization, subsequent verifications are near-instant.

Browser Support

VerifyKit works in all modern browsers that support WebAssembly:

  • Chrome 109+
  • Firefox 115+
  • Safari 16.4+
  • Edge 109+

No polyfills needed. No browser extensions required. Just JavaScript and WebAssembly.

Next Steps

Ready to verify PDF signatures in your application?

Get started with VerifyKit in under 5 minutes.