Digitally Sign a PDF
With a digital signature, the reader of a PDF can verify who signed it and that it has not been changed since. TX Text Control signs a PDF while saving it, with an X.509 certificate from a .pfx file. In the editor window of your first WPF application, you create a certificate for testing, sign the document invisibly and sign a visible signature field that shows an image of a handwritten signature. The timestamp section explains a limitation in version 34.0 SP5.
How PDF Signing Works
A DigitalSignature holds an X.509 certificate with its private key. Passed in the SaveSettings of a PDF or PDF/A save, it makes TX Text Control sign the file, in one of two ways:
- The whole document. SaveSettings.DigitalSignature signs the document without a visible mark. PDF readers list the signature in their signature panel.
- Signature fields. A SignatureField is a visible frame in the document, which can show an image and information about the signer. SaveSettings.SignatureFields signs fields by name, each with its own certificate, so several people can sign one document.
Prerequisites
- The application from Create Your First WPF Application, with a
TextControlnamedtextControl1in MainWindow.xaml. - A certificate with its private key in a .pfx file. The next section creates one for testing.
- For the signature field, an image of a signature named signature.png in the output folder of the application.
MainWindow.xaml.cs needs these using directives:
using System;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Windows;
using TXTextControl;
Create a Self-Signed Certificate for Testing
A self-signed certificate works for tests and internal documents. No trusted certificate authority has issued it, so PDF readers of other people don't trust it. For documents that others must be able to verify, use a certificate from a certificate authority.
In PowerShell on Windows, the following command creates a certificate in your personal certificate store:
$cert = New-SelfSignedCertificate `
-Subject "CN=MyTXCert" `
-CertStoreLocation "Cert:\CurrentUser\My" `
-KeyExportPolicy Exportable `
-KeySpec Signature `
-FriendlyName "My PDF Signing Certificate" `
-NotAfter (Get-Date).AddYears(5)
The next commands export it with its private key to a .pfx file protected by the password 123:
$Password = ConvertTo-SecureString -String "123" -Force -AsPlainText
Export-PfxCertificate `
-Cert "Cert:\CurrentUser\My\$($cert.Thumbprint)" `
-FilePath "C:\Path\To\certificate.pfx" `
-Password $Password
Add certificate.pfx to the project with Copy to Output Directory set to Copy if newer, or use its full path in the code below.
Sign the Whole Document
Add a button named signPdfButton to the DockPanel of MainWindow.xaml, before the TextControl element, and this handler to MainWindow.xaml.cs:
private void signPdfButton_Click(object sender, RoutedEventArgs e)
{
// Load the certificate with its private key
X509Certificate2 certificate = X509CertificateLoader.LoadPkcs12FromFile(
"certificate.pfx", "123", X509KeyStorageFlags.Exportable);
SaveSettings saveSettings = new SaveSettings()
{
// An empty string signs with the date and time of the computer
DigitalSignature = new DigitalSignature(certificate, "")
};
string path = System.IO.Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
"signed.pdf");
textControl1.Save(path, StreamType.AdobePDF, saveSettings);
Process.Start(new ProcessStartInfo(path) { UseShellExecute = true });
}
The code works as follows:
X509CertificateLoader.LoadPkcs12FromFilereads the certificate and its private key from the .pfx file. The class exists from .NET 9 on. A project for .NET 8 or the .NET Framework uses the constructor instead:new X509Certificate2("certificate.pfx", "123", X509KeyStorageFlags.Exportable).- The DigitalSignature constructor takes the certificate and the URL of a timestamp server. An empty string uses the current date and time of the computer.
- Save signs the document as it writes the PDF.
StreamType.AdobePDFAworks the same way.
Run the application and click the button. The PDF reader opens signed.pdf and lists the signature in its signature panel, as an invisible signature:

Add a Trusted Timestamp
Anyone can change the clock of a computer. A timestamp server, also called a time-stamping authority, confirms the time of signing independently: it receives a hash of the signature, not the document, and returns a signed timestamp that is embedded in the PDF.
Warning
Timestamp Servers in Version 34.0 SP5. Requesting a server timestamp can fail during PDF export with a
FilterException(TXT-5460). Keep the timestamp-server parameter empty for this tutorial. Before enabling server timestamps, verify that your installed build resolves TXT-5460.
Keep new DigitalSignature(certificate, "") in signPdfButton_Click. It signs with the computer's current date and time and does not provide a trusted timestamp or independent proof of the signing time.
Sign a Signature Field
A signature field shows on the page where the document is signed and by whom. The following handler inserts a field with an image at the input position and signs it while saving:
private void signFieldButton_Click(object sender, RoutedEventArgs e)
{
X509Certificate2 certificate = X509CertificateLoader.LoadPkcs12FromFile(
"certificate.pfx", "123", X509KeyStorageFlags.Exportable);
// A field of 3000 x 1500 twips named "txsign", with the ID 10
SignatureField signatureField = new SignatureField(
new System.Drawing.Size(3000, 1500), "txsign", 10);
// The image of the signature. Filter index 4 is PNG.
signatureField.Image = new SignatureImage("signature.png", 4);
signatureField.SignerData = new SignerData(
"Tim Typer", "CEO", "Charlotte, NC", "tim@example.com", "Approval");
// -1 inserts the field at the current input position
textControl1.SignatureFields.Add(signatureField, -1);
SaveSettings saveSettings = new SaveSettings()
{
// Sign the field named "txsign"
SignatureFields = new DigitalSignature[]
{
new DigitalSignature(certificate, "", "txsign")
}
};
textControl1.Save("signed-field.pdf", StreamType.AdobePDF, saveSettings);
}
The code works as follows:
- The SignatureField constructor takes the size in twips as a
System.Drawing.Size, not a WPFSize, then the name and an ID. The name is required when a certificate is assigned to the field. - The SignatureImage constructor loads the image the field shows. Its second argument is the image format: 1 BMP, 2 TIF, 3 WMF, 4 PNG, 5 JPG, 6 GIF, 7 EMF or 8 SVG.
- The SignerData constructor takes the name, title, address and contact information of the signer and the reason for signing.
- SignatureFields.Add inserts the field into the document of the editor.
- The third argument of
DigitalSignaturenames the field to sign. For several signers, pass oneDigitalSignaturefor each field.
In a PDF reader, the field shows the image, and the signature panel names the field txsign:

Next Steps
- Digital Signatures: certificates, signature fields, multiple signatures and timestamps in detail.
- Create a PDF: document properties, PDF/A and passwords.
- The blog article Signing a PDF Document vs. Signing Signature Fields in a PDF in C#: when to use which way.
- The blog article Building Long-Term Trust with Digital Signatures and Timestamps in C# .NET: why timestamps matter.