Sign Documents

  • 12 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.

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, an ArgumentException is thrown.
Use the PdfSignatureFieldInfo object to create a new form field. Refer to the previous section for a code sample.
PdfSignatureBuilder.SetImageData Specifies the signature's image data. You can provide data in the BMP, JPEG, PNG, and EMF+ formats. The image is not displayed if the form field's SignatureBounds property is not specified.
PdfSignatureBuilder.Name Gets or sets the name of the person or authority who signs the document.
PdfSignatureBuilder.Location Gets or sets the location associated with the signer's identity.
PdfSignatureBuilder.ContactInfo Specifies the signer's contact information.
PdfSignatureBuilder.Reason Gets or sets the reason to sign the document (for example, "I Agree").
PdfSignatureBuilder.CertificationLevel Defines what changes are available to users when the signature is applied. If a user makes a restricted change, the signature becomes invalid.
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. Refer to the following repository for a code sample: 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 PdfDocumentSigner.GetSignatureFieldNames method to retrieve signed field names.

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);
}

Call the PdfDocumentSigner.ClearSignatureFields() method to clear all signature fields.

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:

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. Refer to the following repository for a code sample: 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.

The code sample below creates a document-level timestamp and applies it to a signature form field:

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 time stamp:
    PdfTimeStamp pdfTimeStamp = new PdfTimeStamp(tsaClient);

    //Apply this time stamp to the form field:
    var timeStampSignature = new PdfSignatureBuilder(pdfTimeStamp, signatureFieldInfo1);

    //Sign and save the document:
    signer.SaveDocument("SignedDocument.pdf", timeStampSignature);
}

Pass only the PdfTimeStamp object to the PdfSignatureBuilder instance as a constructor parameter to apply a timestamp to the whole document.

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.

See Also