๐ Try the demo: https://github.com/LM-Kit/lm-kit-net-samples/tree/main/console_net/document-intelligence/digital-signatures/pdf_digital_signatures
PDF Digital Signatures for C# .NET Applications
๐ฏ Purpose of the Demo
Show LM-Kit.NET's digital-signature engine end to end, fully offline: sign a PDF (PAdES detached CAdES), verify it on independent axes (integrity, identity, revocation, timestamp), countersign it without breaking the first signature, and watch a single tampered byte turn the verdict INVALID. Signing appends an incremental revision by construction, so LM-Kit never rewrites the document it signs.
๐ฅ Who Should Use This Demo (Target Audience)
- .NET developers adding legally meaningful signatures to contracts, invoices, approvals, and reports.
- Teams replacing cloud e-signature round-trips with local, private signing.
- Security engineers who need verifiable audit answers: what exactly is signed, by whom, at what proven time.
๐ What Problem It Solves
Most PDF tooling treats a signature as a boolean. Real questions are separate facts: do the bytes still match the signature, does the signer chain to an anchor you chose, is the certificate revoked, and is the time claimed or proven? The demo prints each axis for every signature, so the difference between "math checks out" and "signer is trusted" stays visible.
๐ป Demo Application Overview
The console app generates a sample contract from Markdown (or takes your PDF as an argument), creates a self-signed demo certificate, signs, validates, countersigns, validates again (signature 1 covers its revision, signature 2 covers the whole file, both valid), then flips one byte of signed content and validates a third time.
โจ Key Features
PdfSigner.Sign: one call, anyX509Certificate2private key the BCL reaches (PFX, OS store, hardware-backed).PdfSigner.BeginSign: a two-phase session (byte ranges, SHA-256 digest,Complete) for HSMs and signing services.PdfSignatureValidator.Validate: verdicts on four axes plus an Adobe-compatible Valid / Indeterminate / Invalid status.--tsa <url>: PAdES B-T, the signing time proven by an RFC 3161 authority.PdfSigner.AddDocumentTimestampandPdfSigner.ExtendLtvfor document timestamps and offline long-term validation.
Example Output
== After countersigning ==
Overall: VALID
Signature #1 (ETSI.CAdES.detached)
Status : VALID
Integrity : Valid
Identity : Trusted (CN=LM-Kit Demo Signer)
Covers all : False
Detail : ... The document was extended after this signature; only the signed revision is covered.
Signature #2 (ETSI.CAdES.detached)
Status : VALID
Covers all : True
== After tampering with one byte ==
Overall: INVALID
Integrity : DocumentModified
๐๏ธ Architecture
Markdown โโ> sample PDF โโโโโโโโโโโโโโโ
v
X509Certificate2 โโ> PdfSigner.Sign โโ> incremental revision
(any BCL key) โ (original bytes verbatim)
v
PdfSignatureValidator โโ> integrity | identity | revocation | timestamp
โ
v
countersign / tamper โโ> re-validate
โ๏ธ Getting Started
Prerequisites
- .NET 8.0 SDK or newer. No model download and no GPU: this demo exercises the document engine only.
Download and Run
git clone https://github.com/LM-Kit/lm-kit-net-samples.git
cd lm-kit-net-samples/console_net/document-intelligence/digital-signatures/pdf_digital_signatures
dotnet run
Pass your own document and authority: dotnet run -- path/to/your.pdf --tsa http://timestamp.digicert.com
๐ง Troubleshooting
- Identity shows Untrusted: trust is explicit. Add the signer's root to
PdfSignatureValidationOptions.TrustedRoots, or enableTrustSystemRootsfor the OS store. - Signing a signed document is refused elsewhere: full rewrites of signed documents require the operation's
AllowSignatureInvalidationopt-in; signing itself is incremental and needs no consent. - The container does not fit: raise
PdfSigningOptions.SignatureCapacitywhen embedding long chains.
๐ Extend the Demo
- Certify instead of approve: set
PdfSigningOptions.Certificationto a DocMDP level. - Place a visible field with
PdfSigningOptions.Bounds: it renders who signed, when, and why, localized throughAppearanceCulture(fourteen languages built in).Appearanceoverrides the lines, size, and color, andAppearance.FontFileembeds a font for scripts beyond WinAnsi (Cyrillic, CJK, Arabic). - Sign through an HSM:
BeginSign, shipGetDigest()out,Complete(cms). - Make validation self-contained for the archive:
PdfSigner.ExtendLtv, then validate offline.