Digital Signatures on PSPDFKit for Windows

ℹ️ Note: For an introduction to the concept of digital signatures, please start with this guide.

PSPDFKit for Windows can validate digitally signed documents and sign documents with a digital signature as well. Even when there’s no signature form field in the current document, PSPDFKit for Windows gives you the byte range and a hash representation of the current state of the document, so you can digitally sign it by obtaining a DER PKCS#7 container from either the byte range or the hash and then applying that DER PKCS#7 container to a new, ad hoc invisible signature form field.

You are only responsible for providing the signing service that will receive the byte range and the hash as input values and return the DER PKCS#7 container to be applied to the prepared signature form field. Our implementation allows you to produce, validate, and display digitally signed documents in a totally flexible way.

ℹ️ Note: If you want to use the Digital Signatures feature, it must be included in your license. Please follow this link to contact sales to start using it.

Single-Step or Two-Step Signing

With PSPDFKit for Windows, there are two strategies for digitally signing documents. You can provide the certificate and private key in PEM formats and sign the document in a single step. Alternatively, there is a two-step process where you can register an event handler that gets called by the framework to retrieve the signature. In that handler, you can generate the signature yourself and provide that to PSPDFKit for Windows. The two-step process can be useful for workflows where you may wish to perform the signing with specialized hardware devices or sign remotely, etc. It also has the benefit of ensuring that PSPDFKit doesn’t need access to the private key that ultimately will be used to produce the signature value, leaving you complete freedom to choose which strategy to use to manage its lifecycle and security.

How It Works

Under the hood, the process of signing a document is divided into three phases:

  1. PSPDFKit prepares the document for a signature, adding an invisible form field that will contain the signature value.
  2. PSPDFKit then either generates the signature in a PKCS#7 container internally or fires the two-step signature signing event handler for you to generate the signature.
  3. PSPDFKit applies the signature and saves the document.

If the signing process is successful, the document is reloaded with the new invisible digital signature added to it.

During the call to Document.SignAndSaveAsync, and until either the DER PKCS#7 container is generated and PSPDFKit applies the signature to the document or the process is disregarded due to a rejection from the callback, all UI interactions from the user are disabled. This ensures that no modifications are made to the document while a new digital signature is about to be added to it.

Single-Step Signing Example

Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
// PSPDFKit for Windows supports certificates and private keys in PEM format.
var certificate = await GetTestAssetTextAsync("certificate.pem");
var privateKey = await GetTestAssetTextAsync("private-key.pem");

var doc = await Document.OpenDocumentAsync(source);

// Sign the document. SHA256 or greater is recommended.
await doc.SignAndSaveAsync(HashAlgorithm.Sha256, certificate, privateKey, new SignatureMetadata
            {
                SignerName = "James Swift",
                SignatureReason = "Example Signature",
                SignatureLocation = "Vienna, Austria"
            });

Two-Step Signing Example

Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// PSPDFKit for Windows supports certificates and private keys in PEM format.
var certificate = await GetTestAssetTextAsync("certificate.pem");
var privateKey = await GetTestAssetTextAsync("private-key.pem");

var doc = await Document.OpenDocumentAsync(source);

// Register the two-step signature signer event handler.
doc.TwoStepSignatureSigning += async (deferral, signingData) =>
{
    var certificate = GetCertificate();
    var privateKey = GetPrivateKey();

    // Hash the PDF data. SHA256 or greater is recommended.
    byte[] hash;
    using (var sha256 = new SHA256CryptoServiceProvider())
    {
        hash = sha256.ComputeHash(signingData.FileContents.AsStreamForRead());
    }

    // You can compare your own hash with a hash generated by PSPDFKit from the same data using the specified algorithm.
    if (CryptographicBuffer.EncodeToHexString(hash.AsBuffer()).ToUpperInvariant() != signingData.Hash)
    {
        throw new Exception("Hashes don't match.");
    }

    try
    {
        // Sign the hash.
        // For this example, we use a utility method provided by PSPDFKit, but you can use your own library
        // if you need to ensure that PSPDFKit doesn’t have access to the private key.
        var signature = await Utilities.GeneratePKCS7ContainerAsync(
            hash.AsBuffer(),
            certificate,
            privateKey,
            HashAlgorithm.Sha256);

        signingData.Pkcs7Container = signature;
    }
    finally
    {
        // It is essential to complete the deferral.
        // Read more about `Deferral`s in this blog post:
        // https://pspdfkit.com/blog/2019/async-callbacks-with-deferral-csharp/
        deferral.Complete();
    }
};

// Sign the document. SHA256 or greater is recommended.
// No need to provide a certificate or private key.
await doc.SignAndSaveAsync(HashAlgorithm.Sha256, "", "", new SignatureMetadata
            {
                SignerName = "James Swift",
                SignatureReason = "Example Signature",
                SignatureLocation = "Vienna, Austria"
            });

Digital Signatures Validation

Using the UI for Displaying the Validation Status of Digital Signatures

By default, the digital signatures validation UI is not enabled. You can easily turn it on by specifying the desired option on the PSPDFKit.PdfView.ShowSignatureValidationStatusMode property. The available options are:

  • ShowSignatureValidationStatusMode.Never (default) — Do not show the digital signature validation UI at any time, even if there are digital signatures on the document.
  • ShowSignatureValidationStatusMode.IfSigned — Show the digital signature validation UI whenever the document is digitally signed.
  • ShowSignatureValidationStatusMode.HasWarnings — Only show the digital signature validation UI if there are warnings for the document’s digital signatures.
  • ShowSignatureValidationStatusMode.HasErrors — Only show the digital signature validation UI if there are invalid signatures in the document.

The signature validation UI consists of a colored bar shown under the main toolbar and, if they exist, under the annotation toolbars. The bar will have the background color corresponding to the current document’s validation status: red for “error,” yellow for “warning,” and green for “OK.” The status bar will show an informative text about the validation status of the document.

The diagram below shows the decision tree that leads to each possible validation status text and color. The bar will be shown or hidden on each case depending upon the value of PSPDFKit.ViewState.showSignatureValidationStatus.

The validation status bar will pop up either when the document is loaded (or reloaded), or when PSPDFKit.PdfView.ShowSignatureValidationStatusMode is updated, depending on its value. The bar can be closed at any time by pressing the Close button at the end of the bar. The validation status displayed is automatically updated whenever the document changes, e.g. if an annotation is added, the bar will reflect that modifications were made to the document since it was signed.

Using the API for Gathering the Validation Status of Digital Signatures

You can obtain the overall validation status of the current document and information about each one of the digital signatures found on it with the Document.GetSignaturesInfoAsync method. It returns a SignaturesInfo object.

The DocumentValidationStatus property returns a value indicating the result of the signatures’ validation of the document. Additionally, the DocumentModifiedSinceSignature property can be queried to determine if the document was altered in any way after all signatures were applied. If true, it means there is a signature that doesn’t cover the entire document. See the [API documentation][signaturesinfo] for more information.

If you need granular information about each one of the digital signatures found on the document, the SignatureInfos property of SignaturesInfo returns an IEnumerable with SignatureInfo objects. The general status of each signature is present on the SignatureValidationStatus property, wherein the property is SignatureValidationStatus.Valid if no issues have been found on the signature, SignatureValidationStatus.Warning if there are certain concerns with it, and SignatureValidationStatus.Error if the signature is invalid.

For more details about the status of the certificate chain or the integrity of the document, you can check out the CertificateChainValidationStatus and DocumentIntegrityStatus properties. Additionally, there are flags that indicate if the signing certificate is trusted, self-signed, or expired.