Adding a Digital Signature to a PDF on iOS

PSPDFKit enables signing both existing signature form elements and documents without a signature form element.

Information

If you want to use the Digital Signatures component, make sure it’s included in your license. Please contact Sales for more information.

Approval and Certification Signatures

PDF documents mainly support two types of digital signatures: approval signatures, and certification signatures. Approval signatures are used to indicate that a signer agrees with or acknowledges the contents of a document. A single document can contain multiple approval signatures. Meanwhile, certification signatures restrict the kind of changes that can be applied to a document once it’s signed. A PDF document only allows one certification signature. PSPDFKit provides support for approval signatures. For certification signatures, contact us on Support.

Creating a Digital Signature

Adding a digital signature on a PDF document is both reliable proof of the document’s origin and protection against modification by third parties.

To create a digital signature, you need two things.

  • First, you need an X509 certificate that contains your public key and your signer information. PSPDFKit supports PEM-encoded and DER-encoded X509 certificates, as well as DER-encoded PKCS#7 certificates. You can check the encoding of a certificate file by using the OpenSSL command-line tool as follows:

openssl pkcs7 -noout -text -print_certs -in example.p7b

The above command will print an error message if “example.p7b” is not a PEM-encoded PKCS#7 certificate or certificate chain.

To verify if a PKCS#7 certificate file is correctly DER encoded, you can use this command instead:

openssl pkcs7 -inform der -noout -text -print_certs -in example.p7b

The above command will print an error message if “example.p7b” is not a DER-encoded PKCS#7 certificate or certificate chain.

  • Second, you need your private key.

Signing Process

The signing process produces the signature by signing the message digest from the PDF file with a private key. The certificate, along with its public key, is added to the signature and saved in the PDF file. Keep in mind that certificates installed by a user via opening the .p12 container with built-in apps (via Install Profile) will go to the Apple access group and will only be available to Apple-provided apps such as Safari or Mail. See the Apple Technical Q&A for more details and a suggested workaround.

PSPDFKit allows you to sign a document using the Document.sign(formElement:configuration:outputDataProvider:) API. You have to provide the SignatureFormElement that should be signed, along with a data provider, DataProviding, which defines where the signed document should be stored.

The signing configurations are provided using the SigningConfiguration API, which allows configuration options such as the signature type, certificates, a private key, or a custom signing implementation — and more.

PSPDFKit allows signing using a private key and using a custom signing implementation.

  1. Below is an example of using a private key loaded by the application to sign a document directly:

// Load the unsigned document containing the signature form element to be signed.
let unsignedDocument: Document = ...

// Access the signature form element to be signed.
let signatureFormElement: SignatureFormElement = ...

// Destination URL for the signed document.
let signedDocumentURL: URL = ...

// Load the P12 data. `p12Data` is a `p12` archive `NSData` object.
let p12 = PKCS12(data: p12Data)

// Unlock the certificate and private key from the `p12` data.
let (certificates, privateKey) = try await p12.unlockCertificateChain(withPassword: "AStrongPassword")

// Configure the signing using `SigningConfiguration`.
let configuration = SigningConfiguration(dataSigner: privateKey, certificates: certificates)

// Sign the document.
try await unsignedDocument.sign(formElement: signatureFormElement, configuration: configuration, outputDataProvider: FileDataProvider(fileURL: signedDocumentURL))
  1. A document can be signed by providing your custom implementation by signing the data yourself with the provided hashing algorithm. The sign(unsignedData:hashAlgorithm:) method of the DataSigning protocol is called for signing the data. You’ll then have to carry out your custom signing process in this method in your custom class conforming to the DataSigning protocol:

// Custom implementation of `DataSigning` to carry out the signing.
private class CustomDataSigner: DataSigning {
    func sign(unsignedData: Data, hashAlgorithm: PDFSignatureHashAlgorithm) async throws -> (signedData: Data, dataFormat: PSPDFKit.SignedDataFormat) {
        // Carry out your custom data signing.
        let signedData = ...

        // Return the signed data specifying the data format.
        // Use `.pkcs7` if the data has been wrapped in a PKCS#7 signature container.
        // Otherwise, use `genericSignedData`.
        return (signedData, .genericSignedData)
    }
}

// Carrying out the signing using the above custom implementation.
// Initialize the custom data signing implementation.
let customSigner = CustomDataSigner()

// Load the public certificate.
let certificateURL = AssetLoader.assetURL(for: "John Appleseed Public Key.p7c")
let certificateData = try Data(contentsOf: certificateURL)
let publicCertificates: [X509] = try X509.certificates(fromPKCS7Data: certificateData)

// Use the `SigningConfiguration` API to provide the custom signer and the certificates.
let configuration = SigningConfiguration(dataSigner: customSigner, certificates: publicCertificates)

// Load the unsigned document containing the signature form element to be signed.
let unsignedDocument: Document = ...

// Access the signature form element to be signed.
let signatureFormElement: SignatureFormElement = ...

// Destination URL for the signed document.
let signedDocumentURL: URL = ...

// Sign the document with the signing configuration that states the use of the custom signing implementation.
try await unsignedDocument.sign(formElement: signatureFormElement, configuration: configuration, outputDataProvider: FileDataProvider(fileURL: signedDocumentURL))
Information

For an interactive example of digital signatures, check out the signing examples in FormExamples.swift included in the Catalog app.

Long-Term Validation (LTV)

Long-term validation (LTV) is a feature in digital signatures that ensures the longevity of a signature’s validity. This is achieved by incorporating additional information into the signature at the time of signing. This additional information allows any future validator to verify the status of the certificate at the time of signing, thereby ensuring the signature’s validity over an extended period.

LTV information can be added to a signature in two ways:

  • By adding LTV information to a signature when it’s created.

  • By refreshing or adding LTV information to an existing signature.

The second option is useful because sometimes the person who signs the document doesn’t have access to the internet at the time of signing, or the recipient of a signed document may want to preserve the document in the long term. In this case, the signature can be created without LTV information and the LTV information can be added later.

For LTV information to be added to the signature, SDK.shared.signatureManager must contain the trust anchor certificate of the signing certificate chain. If the trust anchor certificate isn’t present in the signature manager, the signature will be created without LTV information. You might want to add these certificates soon after your app is launching, as our validation UI also uses these trusted certificates to verify a signature. To add the trust anchor certificate to the signature manager, you need to call SignatureManager.addTrustedCertificate(_:):

// Load a certificate (with a public key) from a `p7` archive.
let certificateData = try Data(contentsOf: p7URL)
let certificates = try X509.certificatesFromPKCS7Data(certificateData)
for certificate in certificates {
    SDK.shared.signatureManager.addTrustedCertificate(certificate)
}

Adding a Signature with LTV Enabled

Since a certificate chain is already required to create a CAdES signature, to add LTV information to a signature when it’s created, you only need to make sure long-term validation is enabled in the SigningConfiguration, which is the case by default. The following code snippet shows how to explicitly enable adding LTV information to a signature when it’s created:

let configuration = SigningConfiguration(dataSigner: privateKey, certificates: certificates, isLongTermValidationEnabled: true)
try await unsignedDocument.sign(formElement: signatureFormElement, configuration: configuration, outputDataProvider: FileDataProvider(fileURL: url))

Refreshing or Adding LTV to an Existing Signature

To refresh or add LTV information to an existing signature, you need to call Document.addLongTermValidation(toFormElement:certificates:). This method takes both the signed signature form element that you want to add LTV information to and an array of certificates as parameters. The latter is a list of certificates needed for long-term validation, and it mainly includes signing certificates, along with the timestamp certificate chain if the signature was timestamped. If the certificates array is empty, we search the document for every signed signature field and try to extract the signing certificate from it. The following code snippet shows how to refresh or add LTV information to an existing signature:

document.addLongTermValidation(toFormElement:signedFormElement certificates:signingCertificateChain)

App Transport Security for Revocation Checks

Because LTV revocation checks perform HTTP requests, if the OCSP URLs embedded in your certificates use http:// rather than https:// then you’ll need to add NSExceptionDomains or NSAllowsArbitraryLoads to your app’s Info.plist in order to satisfy App Transport Security requirements.

Editing a Digitally Signed Document

When displaying digitally signed documents, PSPDFKit will allow annotation editing unless a DocMDP transform method is specified under the TransformMethod key of the signature information dictionary. When PSPDFKit is used for the signing process, this method is never set, which means annotation editing remains enabled.

Signing a PDF Multiple Times

One of the prominent features of digital signatures in PDFs is the possibility for an unlimited number of signers. This feature is especially useful for multi-party contracts, legal documents, and other formal agreements where more than two parties are involved. Each of these parties can append their signature to a document, ensuring it carries the approvals needed to make it legally binding.

Each time a signature is added to a PDF, an extra layer of security is included with the document. This increases the integrity of the document up to the point of each signature, a feature known as “non-repudiation.” In simpler terms, non-repudiation ensures that a party involved in a contract or agreement cannot deny the authenticity of their electronic signature, as it serves as a proof of consent or approval.

Each digital signature generates a version, or revision, of the document. Hence, a document can house multiple revisions if it has been signed repeatedly with approval signatures (see Approval and Certification Signatures). When third-party software such as Adobe Acrobat verifies a document with several digital signatures, it ensures each revision only includes specific permissible modifications. Typically, new revisions allow the addition of notes, filling out form fields, or placing subsequent signatures on the document. However, alterations like page modifications will invalidate the digital signature.

Here’s a diagram that shows how revisions work in a PDF document.

Diagram of a PDF document with three revisions.

Digital PDF signatures, which can include time stamps, provide a comprehensive audit trail detailing when each party reviewed and consented to the document’s content. This chronological record is particularly beneficial in compliance scenarios, as it presents an irrefutable timeline of when approvals were procured.

If you wish to sign a document again after executing permissible changes (e.g. filling in a form), add a new signature form field by following the steps outlined in the Add a Signature Field section, and then complete the signing process by following the guidelines provided in the Signing a PDF section.

Note that each signature added will slightly increase the file size. This can impact storage and sharing capabilities of the document, especially when there are a large number of signatures appended. However, considering the security that digital signatures provide, it’s usually considered a small price to pay.