Sign PDF Documents
- 14 minutes to read
You can use the PDF Document API to apply multiple signatures. A signature is used to authenticate the user’s identity and document contents.
A signature contains validation data (certificate, hash algorithm, timestamp, etc.) and visual parameters (image and signer information). The signature appears in the corresponding form field that defines that signature’s location and size.
You can apply a signature to an existing form field or create a new signature field and sign it. You can also sign documents that already have a signature.
Create a Signature Form Field
You can use the PdfSignatureFieldInfo class to create a signature field and specify its parameters (name, location and rotation angle).
The code sample below creates a new signature field:
// Create a signature field on the first page:
var signatureFieldInfo = new PdfSignatureFieldInfo(1);
// Specify the field's name, location and rotation angle:
signatureFieldInfo.Name = "SignatureField";
signatureFieldInfo.SignatureBounds = new PdfRectangle(10, 10, 150, 150);
signatureFieldInfo.RotationAngle = PdfAcroFormFieldRotation.Rotate90;
Sign a Form Field
Use the PdfSignatureBuilder class to apply a signature to the form field. The PDF Document API supports PKCS#7 signatures with X.509 certificates and document-level time timestamps. The PdfDocumentSigner class allows you to sign and save a document.
The table below lists API used to sign a form field:
API | Description |
---|---|
PdfDocumentSigner | Signs the document. Pass the document to sign to the object’s constructor. |
Pkcs7Signer | Creates a PKCS#7 signature. Specify the signature certificate and password in the object’s constructor. Use the HashAlgorithmType enumeration to specify the signatures hashing algorithm. |
PdfSignatureBuilder | Applies a signature to a form field. Specify the signature field’s name in the object’s constructor to sign this field. If the field with the specified name does not exist, a System.ArgumentException is thrown.Use the PdfSignatureFieldInfo object to create a new form field. Refer to the previous section for a code sample. |
PdfDocumentSigner.SaveDocument | Applies the signature(s) and saves the document. |
The code sample below applies a digital signature to a new and existing form field and signs a document with these signatures:
using System;
using DevExpress.Pdf;
using System.Diagnostics;
using System.IO;
using DevExpress.Office.DigitalSignatures;
// Load a document to sign:
using (var signer = new PdfDocumentSigner("Document.pdf"))
{
// Create a PKCS#7 signature:
Pkcs7Signer pkcs7Signature = new Pkcs7Signer("Signing Documents/certificate.pfx", "123",
HashAlgorithmType.SHA256);
// Apply a signature to a newly created signature field:
var cooperSignature = new PdfSignatureBuilder(pkcs7Signature, signatureFieldInfo);
// Specify an image and signer information:
cooperSignature.SetImageData(File.ReadAllBytes("Signing Documents//JaneCooper.jpg"));
cooperSignature.Location = "USA";
cooperSignature.Name = "Jane Cooper";
cooperSignature.Reason = "Acknowledgement";
// Apply a signature to an existing form field:
var santuzzaSignature = new PdfSignatureBuilder(pkcs7Signature, "Sign");
// Specify an image and signer information:
santuzzaSignature.SetImageData(File.ReadAllBytes("Signing Documents//SantuzzaValentina.jpg"));
santuzzaSignature.Location = "Australia";
santuzzaSignature.Name = "Santuzza Valentina";
santuzzaSignature.Reason = "I Agree";
// Add signatures to an array:
PdfSignatureBuilder[] signatures = { cooperSignature, santuzzaSignature };
// Sign and save the document:
signer.SaveDocument("SignedDocument.pdf", signatures);
}
You can create the Pkcs7SignerBase descendant and use a custom PKCS#7 signature builder:
If you need to calculate a document hash in a custom manner, you can use a custom digest calculator instead of DigestCalculator with a custom PKCS#7 signature builder:
Re-Sign the Form Field
You can remove a signature from a form field and sign it with another signature. Call the PdfDocumentSigner.ClearSignatureField method with the form field’s name passed as a parameter. Use the GetSignatureFieldNames method to retrieve signed field names.
Call the PdfDocumentSigner.ClearSignatureFields() method to clear all signature fields.
The code sample below shows how to retrieve signed form field names and apply a new signature to the first field:
using DevExpress.Pdf;
using System.Diagnostics;
using System.IO;
using DevExpress.Office.DigitalSignatures;
// Load a document to sign:
using (var signer = new PdfDocumentSigner("Document.pdf"))
{
// Create a PKCS#7 signature:
Pkcs7Signer pkcs7Signature = new Pkcs7Signer("Signing Documents//certificate.pfx", "123",
HashAlgorithmType.SHA256);
// Retrieve all signed form fields:
var signedFields = signer.GetSignatureFieldNames(false);
// Clear the first signature field:
signer.ClearSignatureField(signedFields[0]);
// Apply a new signature to this form field:
var santuzzaSignature = new PdfSignatureBuilder(pkcs7Signature, signedFields[0]);
// Specify image and signer information:
santuzzaSignature.SetImageData(File.ReadAllBytes("Signing Documents//SantuzzaValentina.jpg"));
santuzzaSignature.Location = "Australia";
santuzzaSignature.Name = "Santuzza Valentina";
santuzzaSignature.Reason = "I Agree";
santuzzaSignature.CertificationLevel = PdfCertificationLevel.FillFormsAndAnnotate;
// Sign and save the document:
signer.SaveDocument("SignedDocument.pdf", santuzzaSignature);
}
Customize the Signature Appearance
Personalized signature appearance allows you to display additional information about the signer, affiliations, or company.
The appearance consists of two components:
Signature – a graphic that identifies the signer on the left side of the signature (a photo, scanned signatures and so on).
Signature details – data that appears on the right side.
The PdfSignatureAppearance class properties allow you to customize the signature appearance. Call the SetImageData method to specify an image displayed on the left side of the signature. If no image is specified, the signer name is displayed. The name is extracted from the signing certificate or the PdfSignatureBuilder.Name property. Set the AppearanceType property to None to display only signature details.
Call the PdfSignatureBuilder.SetSignatureAppearance() method and pass the PdfSignatureAppearance
object as a parameter to apply changes to the signature. The SetSignatureAppearance
method call discards an image set by the PdfSignatureBuilder.SetImageData() method.
The code sample below customizes the signature appearance:
// Apply a signature to an existing form field
var santuzzaSignature = new PdfSignatureBuilder(pkcs7Signature, "Sign");
// Specify an image and signer information
santuzzaSignature.Location = "Australia";
santuzzaSignature.Name = "Santuzza Valentina";
santuzzaSignature.Reason = "I Agree";
// Specify signature appearance parameters:
PdfSignatureAppearance signatureAppearance = new PdfSignatureAppearance();
// Add a signature image:
signatureAppearance.SetImageData("Signing Documents/logo.png");
// Specify what information to display:
signatureAppearance.ShowDate = true;
signatureAppearance.ShowLocation = true;
// Set display format for date and time:
signatureAppearance.DateTimeFormat = "MM/dd/yyyy";
// Change font settings for signature details:
signatureAppearance.SignatureDetailsFont.Size = 12;
signatureAppearance.SignatureDetailsFont.Italic = true;
// Apply changes:
santuzzaSignature.SetSignatureAppearance(signatureAppearance);
Add a Signature Timestamp
Use the TsaClient object to create a timestamp. Specify the URI of a timestamp server in the object constructor. You can specify the username and password to log into the server. If the server rejects the timestamp request, a TspValidationException is thrown.
Pass the TsaClient object to the Pkcs7Signer instance as a constructor parameter.
The code sample below creates a PKCS#7 signature with a timestamp. The FreeTSA server is used for demonstration purposes as a free trusted TSA client. You may wish to use another client as required.
using DevExpress.Pdf;
using DevExpress.Office.DigitalSignatures;
using DevExpress.Office.Tsp;
using (var signer = new PdfDocumentSigner("Document.pdf"))
{
// Create a timestamp:
ITsaClient tsaClient = new TsaClient(new Uri(@"https://freetsa.org/tsr"),
HashAlgorithmType.SHA256);
// Create a PKCS#7 signature:
Pkcs7Signer pkcs7Signature = new Pkcs7Signer("Signing Documents/certificate.pfx", "123",
HashAlgorithmType.SHA256, tsaClient, null, null, PdfSignatureProfile.PAdES_BES);
// Apply the signature to an existing form field:
var santuzzaSignature = new PdfSignatureBuilder(pkcs7Signature, "Sign");
// Specify an image and signer information:
santuzzaSignature.SetImageData(System.IO.File.ReadAllBytes("Signing Documents/SantuzzaValentina.jpg"));
santuzzaSignature.Location = "Australia";
santuzzaSignature.Name = "Santuzza Valentina";
santuzzaSignature.Reason = "I Agree";
// Sign and save the document:
signer.SaveDocument("SignedDocument.pdf", santuzzaSignature);
}
You can create an ITsaClient interface implementation to create a custom timestamp client:
Sign a Form Field with a Document-Level Timestamp
The PdfTimeStamp object allows you to generate a document-level timestamp. Use the ITsaClient interface implementation to specify the timestamp client.
You can pass the PdfTimeStamp
object and the form field information to the PdfSignatureBuilder constructor to apply the document-level timestamp to the signature field. Pass only the PdfTimeStamp
object to the PdfSignatureBuilder instance as a constructor parameter to apply a timestamp to the whole document.
The code sample below creates a document-level timestamp and applies it to a signature form field. The FreeTSA server is used for demonstration purposes as a free trusted TSA client. You may wish to use another client as required.
using DevExpress.Pdf;
using DevExpress.Office.DigitalSignatures;
using DevExpress.Office.Tsp;
using (var signer = new PdfDocumentSigner("Document.pdf"))
{
// Create a timestamp:
ITsaClient tsaClient = new TsaClient(new Uri(@"https://freetsa.org/tsr"), HashAlgorithmType.SHA256);
// Create a new signature form field:
var signatureFieldInfo1 = new PdfSignatureFieldInfo(1);
signatureFieldInfo1.Name = "SignatureField1";
signatureFieldInfo1.SignatureBounds = new PdfRectangle(200, 200, 250, 250);
// Create a document-level timestamp:
PdfTimeStamp pdfTimeStamp = new PdfTimeStamp(tsaClient);
// Apply this timestamp to the form field:
var timeStampSignature = new PdfSignatureBuilder(pdfTimeStamp, signatureFieldInfo1);
// Sign and save the document:
signer.SaveDocument("SignedDocument.pdf", timeStampSignature);
}
Add Signature Information to the Document Security Store
PAdES signatures with LT and LTA levels require that you pass signature information to the Document Security Store (DSS). To do this, call the PdfDocumentSigner.AddToDss method and pass the corresponding signature field as the method parameter. If the signature is not signed, the ArgumentException
is thrown.
To provide certificates used to build a chain, you can specify a list of certificates, use a CertificateStoreProvider class or create an ICertificateStoreProvider interface implementation.
The code sample below retrieves the name of the first signature field, adds the related signature’s information to the DSS, and applies a timestamp to the document.
using (var signer = new PdfDocumentSigner(@"signed.pdf"))
{
ITsaClient tsaClient = new TsaClient(new Uri(@"https://freetsa.org/tsr"), HashAlgorithmType.SHA256);
string signatureName = signer.GetSignatureFieldNames(false)[0];
// Create a provider that retrieves certificates from a store:
using (var certificateStoreProvider =
new CertificateStoreProvider(new X509Store(StoreLocation.CurrentUser), true))
{
// Add the signature to the security store
// and specify the CrlClient and OcspClient objects
// used to check the certificates' revocation status:
signer.AddToDss(signatureName, new CrlClient(), new OcspClient(), certificateStoreProvider);
}
signer.SaveDocument(@"signedLTV.pdf", new[] { new PdfSignatureBuilder(new PdfTimeStamp(tsaClient)) });
}
Sign a Document in Deferred Mode
Use the following API to apply a signature or a document-level timestamp to the document hash.
Member | Description |
---|---|
ExternalSignerInfo | Contains the signature parameters: type, size, hashing algorithm, etc. |
PdfDeferredSignatureBuilder | Allows you to build a signature for the document hash. Use the PdfSignatureFieldInfo object to apply a signature to a new form field. Specify the field name in the PdfDeferredSignatureBuilder object constructor to apply a signature to an existing form field. |
PdfDocumentSigner.SignDeferred | Adds the signature to the document and retrieves the document hash. The returned PdfDeferredSigner object contains the hash value. |
PdfDeferredSigner.Sign | Adds the signature contents and saves the document to the file or stream. Use the ITsaClient.GenerateTimeStamp(Byte[], String) or IExternalSigner.BuildSignature(Byte[], String) method to obtain the signature contents. |
The code sample below uses a document hash to apply a signature externally:
using DevExpress.Office.DigitalSignatures;
using DevExpress.Pdf;
using (var signer = new PdfDocumentSigner(File.OpenRead("SignDemo.pdf")))
{
// Specify the information about the signature metadata:
var digestCalculator = new DigestCalculator(HashAlgorithmType.SHA256);
var signerInfo = new ExternalSignerInfo(PdfSignatureType.Pkcs7, 8000, digestCalculator);
// Create a new form field:
var fieldInfo = new PdfSignatureFieldInfo(1) { SignatureBounds = new PdfRectangle(10, 10, 100, 100) };
// Apply the metadata to the form field:
var builder = new PdfDeferredSignatureBuilder(signerInfo, fieldInfo);
// Add the signature to the document:
var deferredSigner = signer.SignDeferred(builder);
// Obtain the document hash and hash algorithm's object identifier:
var digest = deferredSigner.HashValue;
var digestAlgorithmOID = digestCalculator.AlgorithmOid;
// Generate the signature content to insert into the document:
byte[] signature = CreateSignature(digest, digestAlgorithmOID);
// Add the signature contents and save the document to the file:
deferredSigner.Sign("signed.pdf", signature);
}
static byte[] CreateSignature(byte[] digest, string digestAlgorithmOID)
{
var signer = new Pkcs7Signer(@"SignDemo.pfx", "dxdemo");
byte[] signature = signer.BuildSignature(digest, digestAlgorithmOID);
return signature;
}
Tip
Use the PdfDocumentProcessor to sign a PDF document. Refer to the following help topic for a code sample: How to: Use PdfDocumentProcessor to Add a Visual Signature into a PDF. Note, however, that this approach has limitations.
Verify a Signature
The PDF Document API allows you to validate PKCS #7 signatures in a PDF document. Use the PdfPkcs7Signature class methods to obtain information about the PKCS#7 signature and verify it.
Call the PdfPkcs7Signature.CheckCertificateRevocation method to obtain information about signature certificate revocation based on Online Certificate Status Protocol (OCSP) and Certificate Revocation List (CRL) responses. Call the PdfDocumentSigner.VerifyLtv method to obtain Long Term Validation (LTV) records about the state of the signature certificate.
Review the following tutorial for more information: How to: Validate a PDF Document Signature.