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.