Migrating to the Advanced Digital Signatures API
This guide covers migrating from the old digital signing API using PDFSigner
(opens in a new tab) to the new advanced digital signatures API. This API, which was released alongside PSPDFKit 13.2 for iOS, is available as a method on Document
.
The sign(_:withCertificate...
(opens in a new tab) APIs of PDFSigner
(opens in a new tab) will soon be deprecated, but the new API has complete support for PAdES signatures, including timestamping support. PDFSigner
(opens in a new tab) allows passing a name, which is considered unsafe, as this could be interpreted as a form of identity theft. The newer API mitigates this risk by using the name saved in the signing certificate.
We strongly encourage you to migrate to the new advanced digital signatures API, as it not only provides extensive functionality, but it’s also more streamlined and easier to use.
A subset of features on PDFSigner
(opens in a new tab) and its subclasses should be migrated to the advanced digital signatures API as described below.
Signing a FormElement
For advanced digital signatures, use Document.sign(formElement:configuration:outputDataProvider:)
(opens in a new tab) to sign a form field instead of the sign(_:withCertificate...
(opens in a new tab) APIs available on PDFSigner
(opens in a new tab) and its subclasses. Note that the often-used APIs — such as sign(_:usingPassword:writeTo:)
(opens in a new tab) and its variants on PKCS12Signer
(opens in a new tab), which is a subclass of PDFSigner
(opens in a new tab) — will be deprecated soon.
The new API, like the outgoing PDFSigner
(opens in a new tab) API, takes the SignatureFormElement
(opens in a new tab) to be signed and a data provider implementing DataProviding
(opens in a new tab) to specify the destination of the signed document. The entire configuration of the signature is housed under the new SigningConfiguration
(opens in a new tab) API, which aids discoverability. The private key and the certificate for signing need to be provided to the SigningConfiguration
(opens in a new tab) instance instead of the PDFSigner.sign(_:withCertificate:...)
API:
let configuration: SigningConfiguration = ...try await unsignedDocument.sign(formElement: signatureFormElement, configuration: configuration, outputDataProvider: FileDataProvider(fileURL: signedDocumentURL))
Using SigningConfiguration for Signature Customizations
Specify the signature type (PDFSignatureType
(opens in a new tab)) using SigningConfiguration
(opens in a new tab) instead of the PDFSigner
(opens in a new tab) instance.
Customizations such as signature appearance, biometric data, estimated size, and hashing algorithm, which required implementing PDFDocumentSignerDataSource
(opens in a new tab), have now been added to the SigningConfiguration
(opens in a new tab) API that’s supplied while signing the element.
Instead of implementing the PDFDocumentSignerDataSource
(opens in a new tab) protocol, you can provide the signature appearance, biometric data, estimated size, hashing algorithm, and more to the SigningConfiguration
(opens in a new tab) instance directly. The signature appearance and biometric data are still represented using the same types of PDFSignatureAppearance
(opens in a new tab) and PDFSignatureBiometricProperties
(opens in a new tab), respectively.
With this new API, the encryption algorithm is now chosen automatically based on the signing configuration, so you no longer have to specify it like before with PDFSigner
(opens in a new tab) APIs.
The reason for signing and the location of signing should also be provided to the SigningConfiguration
(opens in a new tab) instance instead of the PDFSigner
(opens in a new tab) instance.
The API also supports timestamping by providing the URL for the timestamping authority server to the SigningConfiguration
(opens in a new tab) instance.
All of the above-mentioned customization options are optional, and the SigningConfiguration
(opens in a new tab) only requires its data signer and signing certificates to be specified for intialization. The certificates still use the same API of X509
(opens in a new tab). The data signer is an instance that implements the DataSigning
(opens in a new tab) protocol. In some cases, this will be the private key (PrivateKey
(opens in a new tab)) instance that you’ll have after unlocking a PKCS#12 blob using the PKCS12.unlockCertificateChain(withPassword:)
(opens in a new tab) API:
// Default initializer.let defaultInitConfig = SigningConfiguration(dataSigner: privateKey, certificates: certificates)
let privateKey: PrivateKey = ...let certificates: [X509] = ...let timestampSource: URL = ...let customAppearance: PDFSignatureAppearance = ...let biometricData: PDFSignatureBiometricProperties = ...
// Custom initializer with all components.let signingConfiguration = SigningConfiguration(type: .pades, dataSigner: privateKey, certificates: certificates, hashAlgorithm: .SHA256, appearance: customAppearance, estimatedSize: 16_384, reason: "I approve", location: "End of the Universe", timestampSource: timestampSource, biometricData: biometricData)
Custom Signing
The DataSigning
(opens in a new tab) protocol mentioned above comes in handy when you want to implement your custom signing — for example, if you want to send your data to a server for signing. Use a custom implementation of DataSigning.sign(unsignedData:hashAlgorithm:)
(opens in a new tab) instead of implementing the PDFDocumentSignerDelegate
(opens in a new tab) API:
// 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) }}