TPTruPDF

@trupdf/signature

PKI signing + structural verify.

DigitalSignatureEngine

const engine = new DigitalSignatureEngine();
const signed = await engine.sign(srcBytes, {
  p12: p12Bytes,
  passphrase: '…',
  signer: { name: 'Bharat Rathvi', reason: 'I approve', location: 'Ahmedabad', contactInfo: '[email protected]' },
  appearance: { page: 1, rect: { x: 50, y: 50, width: 200, height: 60 }, imagePng, invisible: false },
  certify: false,      // certification (MDP) signature instead of approval
  tsaUrl: undefined,   // RFC 3161 timestamp authority
  audit,
  actor: 'signer-ui',
});
 
const r = await engine.verify(signed);
// { signed, signerName?, reason?, signedAt?, intactByteRange,
//   chainValidated, hasTimestamp, isLTV, issues[] }

The signing pipeline is lazy-loaded on first use so it never sits on the viewer's critical path. The placeholder + replace flow is standard CMS detached PKCS#7, so signatures validate in Acrobat and every other compliant viewer.

hasSignedSignatures(bytes) is a fast pre-check for whether a document already carries signed signature fields.

CertChainVerifier

Chain validation against host-supplied trust anchors via the built-in certificate-chain validator, with optional OCSP / CRL fetchers (the host owns the network I/O).

const v = new CertChainVerifier({
  trustAnchors: [trustPem],
  fetchOcsp: async (issuerDer, serial) => {
    /* … */ return 'good';
  },
});
const result = await v.validatePdfSignature(signed);
// { valid, chain, issues }

License gate

Signing calls gate.require('sign'). Verification is not gated.