Migrating to the Advanced Digital Signatures API
This guide covers migrating from the old digital signing API using PDFSigner
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...
APIs of PDFSigner
will soon be deprecated, but the new API has complete support for PAdES signatures, including timestamping support. PDFSigner
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
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:)
to sign a form field instead of the sign(_:withCertificate...
APIs available on PDFSigner
and its subclasses. Note that the often-used APIs — such as sign(_:usingPassword:writeTo:)
and its variants on PKCS12Signer
, which is a subclass of PDFSigner
— will be deprecated soon.
The new API, like the outgoing PDFSigner
API, takes the SignatureFormElement
to be signed and a data provider implementing DataProviding
to specify the destination of the signed document. The entire configuration of the signature is housed under the new SigningConfiguration
API, which aids discoverability. The private key and the certificate for signing need to be provided to the SigningConfiguration
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
) using SigningConfiguration
instead of the PDFSigner
instance.
Customizations such as signature appearance, biometric data, estimated size, and hashing algorithm, which required implementing PDFDocumentSignerDataSource
, have now been added to the SigningConfiguration
API that’s supplied while signing the element.
Instead of implementing the PDFDocumentSignerDataSource
protocol, you can provide the signature appearance, biometric data, estimated size, hashing algorithm, and more to the SigningConfiguration
instance directly. The signature appearance and biometric data are still represented using the same types of PDFSignatureAppearance
and PDFSignatureBiometricProperties
, 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
APIs.
The reason for signing and the location of signing should also be provided to the SigningConfiguration
instance instead of the PDFSigner
instance.
The API also supports timestamping by providing the URL for the timestamping authority server to the SigningConfiguration
instance.
All of the above-mentioned customization options are optional, and the SigningConfiguration
only requires its data signer and signing certificates to be specified for intialization. The certificates still use the same API of X509
. The data signer is an instance that implements the DataSigning
protocol. In some cases, this will be the private key (PrivateKey
) instance that you’ll have after unlocking a PKCS#12 blob using the PKCS12.unlockCertificateChain(withPassword:)
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
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:)
instead of implementing the PDFDocumentSignerDelegate
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) } }