ZingPDF logo

Guide

How to validate a signed PDF in C#

Use Pdf.GetSignaturesAsync() to enumerate signed fields, then call ValidateIntegrityAsync() or ValidateAsync(...).

ZingPDF validates the PDF /ByteRange, reads the detached CMS payload from /Contents, and reports integrity, coverage, certificate, revocation, timestamp, and permission results separately.

Validate signature integrity

ValidateIntegrityAsync() checks that the signed byte ranges still match the detached CMS signature. It does not use the machine trust store, network revocation checks, or the current clock.

using ZingPDF;

using var pdf = Pdf.Load(File.OpenRead("contract-signed.pdf"));

var signatures = await pdf.GetSignaturesAsync();
var result = await signatures[0].ValidateIntegrityAsync();

if (result.Status == PdfSignatureValidationStatus.Valid)
{
    Console.WriteLine("The signed byte ranges match the CMS signature.");
}

Validate from a signature field

If your code already has the AcroForm field, call ValidateSignatureAsync(...) on the SignatureFormField.

using ZingPDF;
using ZingPDF.Elements.Forms.FieldTypes.Signature;

using var pdf = Pdf.Load(File.OpenRead("contract-signed.pdf"));

var form = await pdf.GetFormAsync();
var field = await form!.GetFieldAsync<SignatureFormField>("Approval.Signature");

var result = await field!.ValidateSignatureAsync();

Build a certificate chain

Use ValidateAsync(...) when you want certificate-chain validation. You can pass extra intermediate certificates or custom trusted roots through PdfSignatureValidationOptions.

using System.Security.Cryptography.X509Certificates;
using ZingPDF;

using var pdf = Pdf.Load(File.OpenRead("contract-signed.pdf"));
using var trustedRoot = new X509Certificate2("trusted-root.cer");

var signatures = await pdf.GetSignaturesAsync();
var result = await signatures[0].ValidateAsync(new PdfSignatureValidationOptions
{
    Profile = PdfSignatureValidationProfile.CertificateChain,
    TrustedRoots = new X509Certificate2Collection(trustedRoot)
});

Read the validation result

The top-level Status is a summary. Inspect the layer results when you need to distinguish a changed PDF from an untrusted certificate or unsigned bytes appended after signing.

Console.WriteLine(result.Status);
Console.WriteLine(result.Integrity.Status);
Console.WriteLine(result.Coverage.HasUnsignedChangesAfterSignature);
Console.WriteLine(result.Certificate.Status);

foreach (var finding in result.Findings)
{
    Console.WriteLine($"{finding.Code}: {finding.Message}");
}

Current limits

ZingPDF validates ByteRange integrity, detached CMS signatures, signer certificate extraction, and optional X509Chain validation. Trusted timestamp token validation, DSS/VRI long-term validation data, and DocMDP certification permissions are reported as separate result layers but are not validated yet.

Signature validation requires a seekable input stream because the signed byte ranges are reconstructed from the original PDF bytes.

Need to sign the PDF first?

Create a detached CMS signature in an existing field or a hidden field before validating the saved output.

Open signing guide Open forms docs