TPTruPDF

Digital signatures

PKCS#7 sign + verify with full cert-chain validation, optional OCSP / CRL, time-stamp recognition, and LTV flagging. Multi-signature support via incremental updates.

DigitalSignatureEngine

import { DigitalSignatureEngine, AuditLogger } from '@trupdf/viewer';
 
const engine = new DigitalSignatureEngine();
const audit = new AuditLogger();
 
const signed = await engine.sign(srcBytes, {
  p12: p12Bytes,
  passphrase: '…',
  signer: {
    name: 'Bharat Rathvi',
    reason: 'I approve',
    location: 'Vadodara',
    contactInfo: '[email protected]',
  },
  appearance: {
    page: 1,
    rect: { x: 50, y: 50, width: 200, height: 60 },
    imagePng: stampBytes, // optional signature image
    // invisible: true — sign without a visible widget
  },
  certify: true, // optional; only one certifying signature per PDF
  tsaUrl: 'https://tsa.example.com', // optional RFC 3161 timestamp
  audit,
});

The signing pipeline is lazy-loaded — zero cost until first use. The placeholder + replace flow is standard CMS detached PKCS#7.

Algorithms

  • Signing — RSA-2048, RSA-4096, ECDSA P-256 / P-384 / P-521.
  • Hashing — SHA-256 / SHA-384 / SHA-512 (RSA-PSS padding).
  • Container — CMS detached PKCS#7.

Verify

const r = await engine.verify(signed);
 
if (r.signed && r.intactByteRange) {
  console.log('Signed by', r.signerName, r.reason, r.signedAt);
  console.log('Timestamp present:', r.hasTimestamp);
  console.log('LTV-enabled:', r.isLTV);
  console.log('Issues:', r.issues); // chain warnings, revocation failures, etc.
}

Result fields:

interface VerifyResult {
  signed: boolean;
  signerName?: string;
  reason?: string;
  signedAt?: string;
  intactByteRange: boolean; // signed byte range matches the embedded hash
  chainValidated: boolean; // true when validated against a trust store
  hasTimestamp: boolean; // valid RFC 3161 token found
  isLTV: boolean; // cert + revocation info embedded in DSS
  issues: readonly string[];
}

verify() alone checks structure + byte-range integrity; run CertChainVerifier (below) for full chain validation against your trust anchors.

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).

import { CertChainVerifier } from '@trupdf/viewer';
 
const v = new CertChainVerifier({
  trustAnchors: [trustPem], // PEM strings
  fetchOcsp: async (issuerDer, serialHex) => {
    // ask your OCSP responder; return 'good' | 'revoked' | 'unknown'
    return queryOcspResponder(issuerDer, serialHex);
  },
  fetchCrl: async (issuerDer) => {
    // return the set of revoked serial numbers for this issuer
    return loadRevokedSerials(issuerDer);
  },
});
 
const result = await v.validatePdfSignature(signed);
// { valid, chain, issues }

Multi-signature

Each engine.sign(...) writes an incremental update without invalidating prior signatures. verify() inspects every signature dictionary and aggregates the outcome into a single VerifyResult; per-signature problems are labelled Signature #n in issues.

Field placement

The viewer ships a signature-field annotation kind. Place one (empty signature widget) at design time; when the user signs, the field is replaced with a populated signature appearance dict.

License gating

DigitalSignatureEngine calls gate.require('sign') in its constructor; trial tokens cannot sign. Verify is not gated — every license can verify, including unlicensed sessions.