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_ECDSAExplicit certificate-optional discovery can select an ML-DSA private key by label or binary ID, validate its

CKA_PARAMETER_SETCKM_ML_DSA

SignDigest, and sign original messages through TPDFlibExternalDigestSignEventTPDFlib.OnExternalDigestSign implements

Unit

PDFlibPKCS11

Construction 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_GetFunctionListClients 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

UseFunctionList; modules that cannot provide internal locking are protected by a shared call lock, while compliant modules allow separate client sessions to run concurrentlyUnloadModule supports statically linked, embedded, or application-managed providers; the caller must keep the supplied table alive until

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 foundSelect 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

CertificateLabelOptional UTF-8 CKA_LABEL filter for the X.509 certificate object
CertificateIDOptional binary CKA_ID filter stored in an AnsiString
PrivateKeyLabelOptional UTF-8 CKA_LABEL filter for the private signing key
PrivateKeyIDOptional binary private-key CKA_ID; when empty, the certificate ID is reused
CertificateOptionalDefaults to False; when True, a private-key label or ID is required and discovery accepts only ML-DSA keys without an X.509 certificate

CKA_SIGN=True

MLDSAParameterSet

CertificateDER, 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 87The resolved ML-DSA parameter set is exposed through ResolvedPrivateKeyIDThe resolved certificate is exposed through

Authentication

UserPINWrite-only user PIN encoded as UTF-8, checked against token bounds, and wiped when replaced or destroyed
UseProtectedAuthenticationPathPasses a null PIN when the token advertises CKF_PROTECTED_AUTHENTICATION_PATH
ReadWriteSessionAdds 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 timeECDSA 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 behaviour

Connected, KeyType, MLDSAParameterSet, AlwaysAuthenticate, FunctionListMajor, and FunctionListMinor expose the active provider stateMethods 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