Skip to main content

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.

VisualSignature

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.

Run Demo: PDF 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:

View Example: How to Apply Multiple 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:

View Example: How to use Azure Key Vault API to sign a PDF document

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:

View Example: How to use a custom signer class to apply signatures to the PDF Document

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:

appearance elements

  • 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:

appearance result

// 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:

View Example: How to: Use a custom timestamp client to apply signatures to the PDF document

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.

See Also