TL;DR: Still relying on basic PDF signing workflows? It’s time to upgrade. Manual or tightly coupled signing processes can’t keep up with modern security and compliance demands. With Syncfusion’s .NET PDF Library, you can implement secure, flexible document workflows using deferred signing, generate a document hash, sign it externally, and embed robust digital signatures with ease.
Introduction
Are you a developer managing secure PDF workflows but struggling with manual or tightly coupled signing processes? Ensuring document integrity, authenticity, and non-repudiation is critical for contracts, invoices, or compliance forms. Traditional signing methods often fall short when external key management or compliance is required.
This post introduces deferred PDF signing in .NET using the Syncfusion® .NET PDF library, a powerful and flexible solution for modern digital signature workflows. You’ll learn how to generate document hash, sign them using external services or HSMs, and embed secure signatures seamlessly. Discover how Syncfusion® simplifies secure document handling while meeting enterprise-grade security and compliance standards.
Understanding Deferred Signing in PDF workflows
Deferred signing is a method that separates digest generation (hashing the document content) from signature application (encrypting the hash using a private key). This two-step process is essential when the signing operation occurs in a different environment than the one generating the document—for example, within a secure signing service or a Hardware Security Module (HSM).
In deferred signing:
- The application first creates a hash of the PDF content to be signed.
- The hash is then sent to an external system or service that performs the cryptographic signature.
- Finally, the signed hash is embedded into the original PDF to complete the signing process.
Benefits and Use Cases of Deferred Signing
Deferred signing is widely used in enterprise systems where high-security policies, compliance requirements, or integration with remote signing services are required. Common use cases include:
- External signing services: Signatures are generated in cloud-based environments where keys are securely stored.
- Hardware security modules (HSMs): Private keys are stored in tamper-proof devices, and signatures are performed within the HSM.
- Time stamping: A Time Stamp Authority (TSA) can sign the hash with a trusted timestamp.
- Document workflow separation: This enables one process to prepare documents and another to sign them without exposing private keys.
Setting up a .NET application for Deferred Signing
Step 1: Create a .NET Core Console app
Open Visual Studio, select Create a new project from the Start Page or File Menu, choose .NET Core Console App, and follow the setup instructions.
Step 2: Open the NuGet Package Manager Console
Navigate Visual Studio’s tools menu, select NuGet Package Manager, and open the Package Manager Console.
Step 3: Install the Syncfusion® PDF NuGet Package
Run the following command in the Package Manager Console to install the Syncfusion Pdf Net Core package.
Install-Package Syncfusion.Pdf.Net.Core
Step-by-step guide to implement Deferred Signing
Deferred signing involves the following steps:
- Create a PDF document with an empty signature and generate the hash.
- Sign the generated hash using an external service.
- Insert the externally signed hash into the empty signature field of the PDF.
Step 1: Generate a document hash
Follow the steps below to generate a document hash using the Syncfusion® PDF library:
- Load the existing PDF document using the PdfLoadedDocument class.
- Create an instance of the PdfSignature class and configure the necessary properties.
- Define a custom class SignEmpty by implementing the IPdfExternalSigner interface.
- Retrieve the document hash from the SignEmpty class.
- Save the PDF document with the empty signature field for the final signing step.
See the code implementation example below for reference.
// Load the input file to sign.
FileStream documentStream = new FileStream(inputPdfFile, FileMode.Open, FileAccess.Read);
// Load an existing PDF document.
PdfLoadedDocument loadedDocument = new PdfLoadedDocument(documentStream);
// Creates a PDF signature and pass the PdfCertificate as null.
PdfSignature signature = new PdfSignature(loadedDocument, loadedDocument.Pages[0], null, signatureName);
// Sets the signature information.
signature.Bounds = new RectangleF(new PointF(0, 0), new SizeF(100, 30));
signature.Settings.CryptographicStandard = CryptographicStandard.CADES;
signature.Settings.DigestAlgorithm = DigestAlgorithm.SHA256;
// Create an empty external signer to get the document hash.
SignEmpty emptyExternalSigner = new SignEmpty("SHA256");
// Add public certificates.
List<X509Certificate2> certificates = new List<X509Certificate2>();
certificates.Add(new X509Certificate2(publicCertificate));
// Add the external signer to the signature.
signature.AddExternalSigner(emptyExternalSigner, certificates, null);
// Save the document.
MemoryStream stream = new MemoryStream();
loadedDocument.Save(stream);
// Close the PDF document.
loadedDocument.Close(true);
// Get the document hash.
documentHash = emptyExternalSigner.dataToSign;
Note: At this stage, the generated hash can be sent to an external system such as a hardware security module (HSM) or a digital signing service for signing.
Step 2: Sign the Hash via External Services or HSM
At this stage, the generated document hash is signed using an external service or a hardware security module (HSM).
In this example, the X509Certificate2 and RSACryptoServiceProvider APIs demonstrate how the hash can be signed. In a real-world scenario, you can integrate with a third-party signing service or implement your custom signing logic as needed.
// Sign the document hash using an external signer. In this example, we use the RSACryptoServiceProvider to sign the document hash for demonstration purposes.
byte[] SignDocument(byte[] documentHash, string privateKeyPath, string password, string hashAlgorithm)
{
//Load the pfx file to sign the document hash.
X509Certificate2 digitalID = new X509Certificate2(privateKeyPath, password);
if (digitalID != null && digitalID.HasPrivateKey)
{
var rsaPrivateKey = digitalID.GetRSAPrivateKey();
if (rsaPrivateKey != null)
{
if (rsaPrivateKey is RSACryptoServiceProvider)
{
RSACryptoServiceProvider rsa = rsaPrivateKey as RSACryptoServiceProvider;
return rsa.SignData(documentHash, hashAlgorithm);
}
else if (rsaPrivateKey is RSACng)
{
RSACng rsa = rsaPrivateKey as RSACng;
return rsa.SignData(documentHash, GetHashAlgorithm(hashAlgorithm), RSASignaturePadding.Pkcs1);
}
else if (rsaPrivateKey is System.Security.Cryptography.RSAOpenSsl)
{
RSAOpenSsl rsa = rsaPrivateKey as RSAOpenSsl;
return rsa.SignData(documentHash, GetHashAlgorithm(hashAlgorithm), RSASignaturePadding.Pkcs1);
}
}
else
{
throw new Exception("The certificate does not have a private key.");
}
}
return null;
}
Refer to the code example below to retrieve the hash algorithm name.
HashAlgorithmName GetHashAlgorithm(string hashAlgorithm)
{
switch (hashAlgorithm)
{
case "SHA1":
return HashAlgorithmName.SHA1;
case "SHA256":
return HashAlgorithmName.SHA256;
case "SHA384":
return HashAlgorithmName.SHA384;
case "SHA512":
return HashAlgorithmName.SHA512;
default:
throw new Exception("Invalid hash algorithm.");
}
}
Step 3: Embed the Signed Hash into the PDF Document
At this stage, the signed hash can be embedded into the PDF document. Refer to the following code example, which demonstrates how to complete this process.
MemoryStream DeferredSigning(MemoryStream inputFile, byte[] signedHash, string hashAlgorithm, string publicCertificate, string signatureName)
{
//Create an external signer to sign the document hash.
ExternalSigner externalSigner = new ExternalSigner(hashAlgorithm, signedHash);
//Add public certificates.
List<X509Certificate2> certificates = new List<X509Certificate2>();
certificates.Add(new X509Certificate2(publicCertificate));
MemoryStream outputFileStream = new MemoryStream();
//Replace the empty signature.
PdfSignature.ReplaceEmptySignature(inputFile, string.Empty, outputFileStream, signatureName, externalSigner, certificates);
return outputFileStream;
}
And that’s it! You’ve successfully signed a PDF using deferred signing with Syncfusion® in a .NET application.
When you run the application, the output will be a digitally signed PDF document, as shown below.
Advanced features
Adding RFC 3161 Timestamps to Deferred Signatures
In addition to embedding the digital signature, you can also include a timestamp in the PDF document when using the deferred signing approach. This can be achieved by applying an RFC 3161-compliant timestamp token through the ExternalSigner.
The following code example demonstrates how to generate an RFC 3161-compliant timestamp token using the open-source BouncyCastle library and embed it into the PDF during the deferred signing process.
// Generate the RFC3161 timestamp token using the provided signed data.
// Note: this method is implemented with the BouncyCastle library.
// You can replace this method based on your third-party service provider.
byte[] GetRFC3161TimeStampToken(byte[] bytes)
{
SHA256 sha256 = SHA256.Create();
byte[] hash = sha256.ComputeHash(bytes);
// Create a timestamp request using the SHA1 hash.
TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
reqGen.SetCertReq(true);
TimeStampRequest tsReq = reqGen.Generate(TspAlgorithms.Sha256, hash, BigInteger.ValueOf(100));
byte[] tsData = tsReq.GetEncoded();
// Use HttpClient instead of HttpWebRequest.
using (HttpClient client = new HttpClient())
{
//client.DefaultRequestHeaders.Add("Authorization", "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes("9024:yourPass")));
HttpContent content = new ByteArrayContent(tsData);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/timestamp-query");
HttpResponseMessage response = client.PostAsync("https://rfc3161.ai.moda", content).Result; //Use your timestamp address
if (response.IsSuccessStatusCode)
{
byte[] responseBytes = response.Content.ReadAsByteArrayAsync().Result;
TimeStampResponse tsRes = new TimeStampResponse(responseBytes);
return tsRes.TimeStampToken.GetEncoded();
}
}
return null;
}
You can now modify the ExternalSigner class as shown below to embed the timestamp into the PDF document.
class ExternalSigner : IPdfExternalSigner
{
public string HashAlgorithm { get; set; }
private byte[] _signedHash;
private byte[]? _timestampResposne;
public ExternalSigner(string hashAlgorithm, byte[] signedHash, byte[]? timestamp = null)
{
HashAlgorithm = hashAlgorithm;
_signedHash = signedHash;
_timestampResposne = timestamp;
}
public byte[] Sign(byte[] message, out byte[] timeStampResponse)
{
//Create a timestamp response.
timeStampResponse = _timestampResposne;
//Send the signed hash.
return _signedHash;
}
}
Then, create the ExternalSigner class within the deferred signing method, as demonstrated below.
//Create an external signer to sign the document hash.
ExternalSigner externalSigner = new ExternalSigner(hashAlgorithm, signedHash, timestampToken);
When you run the application, the signed PDF document will be generated, including the timestamp from the server, as shown below.
Enabling Long-Term Validation (LTV) in Signed PDFs
With the Syncfusion® .NET PDF library, you can enable Long-Term Validity (LTV) for your signed PDF documents. This ensures that the signature remains verifiable over an extended period.
Refer to the following code example to enable LTV information in your PDF document during the deferred signing process.
void CreateLongTermValidity(MemoryStream inputFile, string SignatureName)
{
//Load the signed PDF document
PdfLoadedDocument document = new PdfLoadedDocument(inputFile);
//Get the signature field
PdfLoadedField loadedField = null;
document.Form.Fields.TryGetField(SignatureName, out loadedField);
if (loadedField != null && loadedField is PdfLoadedSignatureField)
{
PdfLoadedSignatureField loadedSignatureField = (PdfLoadedSignatureField)loadedField;
//Create the long-term validity.
loadedSignatureField.Signature.EnableLtv = true;
}
//Save the signed document to disk.
using (FileStream fileStream = new FileStream("Signed Document with LTV.pdf", FileMode.Create, FileAccess.ReadWrite))
{
document.Save(fileStream);
}
//Dispose the document
document.Close(true);
}
Note: Long-term validity (LTV) can only be enabled if the signing certificate includes valid OCSP (online certificate status protocol) or CRL (certificate revocation list) information.
When you run the application, the signed PDF document will be generated as shown below, complete with a timestamp from the timestamp server:
GitHub reference
For more details, refer to the GitHub demo.
FAQs
Q1. Is the Syncfusion® .NET PDF library compatible with cloud and container environments?
Definitely. The library works seamlessly in cloud-based environments like Azure and AWS, and it’s fully compatible with Docker containers, making it ideal for modern DevOps and CI/CD pipelines.
Q2. Is the Syncfusion® PDF Library suitable for enterprise-level applications?
Absolutely. The library is optimized for high performance and scalability, making it ideal for enterprise-grade solutions. It supports multi-threading, large document processing, and integrates seamlessly with ASP.NET Core, Blazor, WinForms, WPF, and Xamarin applications.
Q3. Can I generate PDF reports dynamically using the .NET PDF library?
Yes! Syncfusion’s PDF Library allows dynamic PDF generation from templates, HTML, or data sources like Excel and Word. You can create invoices, reports, certificates, and other documents with custom layouts, branding, and embedded charts or tables.
Q4. How does Syncfusion® ensure PDF document security?
The library includes robust security features such as password protection, encryption (AES and RC4), digital signatures, and permission settings. These tools safeguard sensitive information and ensure compliance with data protection standards.
Syncfusion’s high-performance PDF Library allows you to create PDF documents from scratch without Adobe dependencies.
Conclusion
While traditional PDF signing methods work, modern enterprise applications demand more secure, flexible, and scalable solutions. Deferred signing is essential for today’s digital workflows, especially when integrating with HSMs, remote signing services, or timestamp authorities. It separates the signing operation from document generation, enabling compliance, security, and operational efficiency.
The Syncfusion® .NET PDF Library not only supports deferred signing but empowers developers with full control over hash generation and signature embedding. It’s a robust, enterprise-ready solution for building secure, compliant .NET applications that handle sensitive documents with confidence.
Take the next step: Explore Syncfusion’s .NET PDF Library today! You can examine our online examples and documentation for more features and functionalities. Existing Syncfusion® users can download the newest version of Essential Studio® from the license and downloads page, while new users can start a 30-day free trial to experience its full potential. Our dedicated support team is also available via the support forum, support portal, or feedback portal for any questions or concerns and is committed to providing prompt and comprehensive assistance.