TPDFlibPKCS11Client
Security and signatures
Description
Loads a vendor PKCS #11 module at runtime and exposes certificates and private keys that are not registered with Windows CSP or KSP providers
The client enumerates present tokens, opens a persistent session, authenticates the user, pairs an X.509 certificate with a signing key by binary CKA_ID, and signs already-computed digests through CKM_RSA_PKCS or CKM_ECDSA
Explicit certificate-optional discovery can select an ML-DSA private key by label or binary ID, validate its CKA_PARAMETER_SET, and sign original messages through CKM_ML_DSA
SignDigest implements TPDFlibExternalDigestSignEvent and can be assigned directly to TPDFlib.OnExternalDigestSign
Unit
PDFlibPKCS11Construction and module lifecycle
Constructor TPDFlibPKCS11Client.Create;
Destructor TPDFlibPKCS11Client.Destroy;
Function TPDFlibPKCS11Client.LoadModule: Boolean;
Procedure TPDFlibPKCS11Client.UnloadModule;
Function TPDFlibPKCS11Client.UseFunctionList(FunctionList: PPLPKCS11FunctionList; AlreadyInitialized: Boolean): Boolean;ModulePath identifies a Win32 or Win64 PKCS #11 DLL exporting C_GetFunctionList
Clients that use the same path share one loaded module and one balanced C_Initialize/C_Finalize lifetime
The loader first requests CKF_OS_LOCKING_OK; modules that cannot provide internal locking are protected by a shared call lock, while compliant modules allow separate client sessions to run concurrently
UseFunctionList supports statically linked, embedded, or application-managed providers; the caller must keep the supplied table alive until UnloadModule or destruction
Token discovery and connection
Function TPDFlibPKCS11Client.RefreshTokens: Boolean;
Function TPDFlibPKCS11Client.GetToken(Index: Integer; Out Token: TPDFlibPKCS11Token): Boolean;
Function TPDFlibPKCS11Client.Connect: Boolean;
Procedure TPDFlibPKCS11Client.Disconnect;
Function TPDFlibPKCS11Client.GetSelectedToken(Out Token: TPDFlibPKCS11Token): Boolean;
Property TPDFlibPKCS11Client.TokenCount: Integer;RefreshTokens enumerates present slots with bounded retry when a hot-plug event changes the count, and TokenCount reports how many tokens the last refresh found
Select a token with SlotID, TokenLabel, TokenSerial, or a combination; an empty selection succeeds only when exactly one present token exists
TPDFlibPKCS11Token reports slot description, manufacturer, token label, model, serial number, flags, and PIN length bounds
Identity selection
| CertificateLabel | Optional UTF-8 CKA_LABEL filter for the X.509 certificate object |
|---|---|
| CertificateID | Optional binary CKA_ID filter stored in an AnsiString |
| PrivateKeyLabel | Optional UTF-8 CKA_LABEL filter for the private signing key |
| PrivateKeyID | Optional binary private-key CKA_ID; when empty, the certificate ID is reused |
| CertificateOptional | Defaults to False; when True, a private-key label or ID is required and discovery accepts only ML-DSA keys without an X.509 certificate |
Default discovery requires one unambiguous certificate and key, requires CKA_SIGN=True, validates certificate DER, and rejects RSA/EC type mismatches; certificate-optional discovery requires an unambiguous ML-DSA key and validates parameter set 44, 65 or 87
The resolved ML-DSA parameter set is exposed through MLDSAParameterSet
The resolved certificate is exposed through CertificateDER and the selected key ID through ResolvedPrivateKeyID
Authentication
| UserPIN | Write-only user PIN encoded as UTF-8, checked against token bounds, and wiped when replaced or destroyed |
|---|---|
| UseProtectedAuthenticationPath | Passes a null PIN when the token advertises CKF_PROTECTED_AUTHENTICATION_PATH |
| ReadWriteSession | Adds CKF_RW_SESSION; signing normally needs only the default read-only serial session |
Keys with CKA_ALWAYS_AUTHENTICATE=True receive a context-specific login after every successful C_SignInit
ClearPIN overwrites and releases the configured PIN
Signing
Function TPDFlibPKCS11Client.SupportsMechanism(MechanismType: Cardinal): Boolean;
Function TPDFlibPKCS11Client.SupportsAlgorithm(DigestAlgorithm, SignatureAlgorithm: Integer): Boolean;
Function TPDFlibPKCS11Client.SignMLDSA(Const Message: AnsiString; Out Signature: AnsiString): Boolean;
Function TPDFlibPKCS11Client.SignHash(Const Digest: AnsiString; DigestAlgorithm, SignatureAlgorithm: Integer; Out Signature: AnsiString): Boolean;
Function TPDFlibPKCS11Client.SignDigest(Sender: TObject; SignProcessID: Integer; Const Digest: AnsiString; DigestAlgorithm, SignatureAlgorithm: Integer; Var Signature: AnsiString): Boolean;RSA signatures use raw CKM_RSA_PKCS with a locally constructed DER DigestInfo, so the token does not hash the PDF digest a second time
ECDSA signatures use raw CKM_ECDSA; token P1363 output is returned unchanged for PDF_EXTERNAL_SIGNATURE_ECDSA_P1363 or converted to strict DER for PDF_EXTERNAL_SIGNATURE_ECDSA_DER
SignMLDSA passes the original message to single-part CKM_ML_DSA with empty mechanism parameters, selecting the default empty context; it is independent of SignHash and the CMS digest callback
SHA-1, SHA-256, SHA-384, SHA-512, SHA3-256, SHA3-384, and SHA3-512 digest lengths are validated before any private-key operation
A lost session is reopened and retried only when C_SignInit fails before signing begins, avoiding duplicate private-key operations after an ambiguous C_Sign failure
Example
var
Token: TPDFlibPKCS11Client;
ProcessID: Integer;
begin
Token:= TPDFlibPKCS11Client.Create;
try
Token.ModulePath:= 'C:\Program Files\Vendor\pkcs11.dll';
Token.TokenLabel:= 'Signing token';
Token.CertificateLabel:= 'Document signer';
Token.UserPIN:= UserPIN;
if not Token.Connect then
raise Exception.Create(String(Token.LastError));
PDF.OnExternalDigestSign:= Token.SignDigest;
ProcessID:= PDF.NewSignProcessFromFile(InputFile, '');
PDF.SetSignProcessField(ProcessID, 'Approval');
PDF.SetSignProcessDigestAlgorithm(ProcessID, 2);
PDF.SetSignProcessExternalDigestSigner(ProcessID,
Token.CertificateDER, PDF_EXTERNAL_SIGNATURE_RSA_PKCS1, 512);
PDF.EndSignProcessToFile(ProcessID, OutputFile);
finally
Token.Free;
end;
end;Status and failure behavior
Connected, KeyType, MLDSAParameterSet, AlwaysAuthenticate, FunctionListMajor, and FunctionListMinor expose the active provider state
Methods return False and set both LastReturnValue and LastError when module loading, token selection, authentication, object discovery, attribute bounds, mechanism checks, or signing fails
See also
OnExternalDigestSign, SetSignProcessExternalDigestSigner, SetSignProcessDigestAlgorithm, TPDFlibCSCClient
PIN administration
Function TPDFlibPKCS11Client.InitializeUserPIN(Const SecurityOfficerPIN, NewUserPIN: WideString): Boolean;
Function TPDFlibPKCS11Client.ChangeUserPIN(Const OldPIN, NewPIN: WideString): Boolean;Both operations open their own read/write session on the configured token and leave the signing session untouched; InitializeUserPIN logs in as the security officer before calling C_InitPIN, ChangeUserPIN logs in as the user before calling C_SetPIN
PIN buffers are wiped after use; a module without the required entry point reports an error instead of failing silently