EPdfPkcs11Error = class(Exception);
TPdfPkcs11Options = record
ModulePath: string;
SlotId: UInt64;
UseSpecificSlot: Boolean;
Pin: string;
CertificateLabel: string;
class function Default: TPdfPkcs11Options; static;
end;
TPdfPkcs11SignerProvider = class(TInterfacedObject, IPadesSignerProvider,
IPdfPkcs11SignerProvider)
constructor Create(const Options: TPdfPkcs11Options);
destructor Destroy; override;
function BackendName: string;
function Resolve(const Options: TPadesSignerOptions): TPadesResolvedSigner;
function EnumerateSlots: TPdfPkcs11Slots;
function EnumerateCertificates(SlotID: UInt64): TPdfPkcs11Certificates;
procedure CloseProtectedSessions;
end;
function Pkcs11ModuleAvailable(const ModulePath: string): Boolean;
function Pkcs11ModuleVersion(const ModulePath: string): string;
function Pkcs11AbiLayout: string;
function ConfigurePkcs11SignerProvider(
const Options: TPdfPkcs11Options): IPdfPkcs11SignerProvider;
FPdfPkcs11 is the portable PAdES signing backend and the counterpart of the Windows CNG backend. It resolves a signer certificate and its private key from a PKCS#11 token, then returns a TPadesResolvedSigner whose ICmsSigner produces the SignerInfo signature through the token, so the key never leaves it
The module is loaded at run time by path - opensc-pkcs11.so, libsofthsm2.so, a vendor DLL - so nothing is linked at build time and an absent module is reported rather than fatal. Only C_GetFunctionList is resolved by name; every other entry point comes out of the function table it returns, which is how the standard intends a module to be reached
ConfigurePkcs11SignerProvider builds a TPdfPkcs11SignerProvider from a TPdfPkcs11Options value and installs it as the active PAdES signer backend, returning the IPdfPkcs11SignerProvider interface that also carries the token enumeration methods
Pkcs11ModuleAvailable and Pkcs11ModuleVersion report whether a given module loads and exposes a usable function table, so an application can decide at startup whether token signing is possible on this machine. Loaded modules are cached by path, because the standard allows only one initialisation per process per module
Resolve selects the certificate by TPadesSignerOptions.CertificateThumbprint when one is supplied and by CertificateLabel otherwise, then locates the private key object that carries the same token identifier as the certificate. The certificate key algorithm decides the algorithm family: an EC key signs with ECDSA and its raw signature is re-encoded as the DER SEQUENCE that CMS expects, while an RSA key follows the requested padding scheme
EnumerateSlots and EnumerateCertificates serve selection user interfaces, letting an application list the slots a module reports and the certificates a chosen slot holds before any signing option is fixed
| Function | Description |
|---|---|
Pkcs11ModuleAvailable | Returns True when the module at the given path loads and exposes a usable function table |
Pkcs11ModuleVersion | Returns the version string the module reports, or an empty string when the module does not load |
Pkcs11AbiLayout | Returns the ABI layout this build resolved, as ulong=<n> attr=<n> pss=<n> table=<n> |
ConfigurePkcs11SignerProvider | Builds a provider from the supplied options, installs it as the PAdES signer backend, and returns it as IPdfPkcs11SignerProvider |
| Type | Purpose |
|---|---|
EPdfPkcs11Error | Exception raised when no module path is configured, the module cannot be loaded, a token call fails, or no matching certificate or private key is found |
TPdfPkcs11Options | Record naming the module, slot, PIN, and certificate the provider works with |
TPdfPkcs11SignerProvider | Provider class implementing IPadesSignerProvider and IPdfPkcs11SignerProvider on top of a PKCS#11 module |
| Field | Description |
|---|---|
ModulePath | Path to the PKCS#11 module; required, because which module serves a token is a deployment decision and there is no useful default |
SlotId | Token slot to open, honoured only when UseSpecificSlot is True |
UseSpecificSlot | Leave False to take the first slot that reports a token present |
Pin | User PIN; the provider clears its own copy once the token has consumed it, and the caller stays responsible for the lifetime of the string it passes in |
CertificateLabel | Optional object label of the certificate to sign with, used only when TPadesSignerOptions.CertificateThumbprint is empty |
Default | Static factory returning options with an empty module path, slot 0, automatic slot selection, and no PIN or label |
| Member | Description |
|---|---|
Create | Constructs the provider from a TPdfPkcs11Options value; the module itself is opened on first use |
Destroy | Closes any open token session before the instance is released |
BackendName | Returns the backend name, with the module file name appended when a module path is configured |
Resolve | Resolves TPadesSignerOptions into a TPadesResolvedSigner holding the token signer and the signer certificate DER |
EnumerateSlots | Returns every slot the module reports as TPdfPkcs11Slots, including slots with no token present |
EnumerateCertificates | Returns the certificates held in one slot as TPdfPkcs11Certificates, opening a session on that slot first |
CloseProtectedSessions | Logs out where a login took place and closes the open session, releasing the token for other consumers |
CK_ULONG follows the C unsigned long, so it is 4 bytes on Windows (LLP64) and 8 bytes on Linux and macOS (LP64); every handle, count, and attribute type is a CK_ULONGPkcs11AbiLayout reports the layout this build resolved, so a mismatch is diagnosable rather than a silent crash: Win32 reports ulong=4 attr=12 pss=12 table=2, Win64 reports ulong=4 attr=16 pss=12 table=2, and an LP64 target reports ulong=8 attr=24 pss=24 table=8CertificateLabel, the first certificate on the token wins, which suits a single-certificate token and no production deployment