TPDFlibPKCS11Client
安全和签名
描述
在运行时加载厂商的 PKCS #11 模块,暴露未注册到 Windows CSP 或 KSP 提供程序的证书和私钥
客户端枚举在位令牌、打开持久会话、认证用户、以二进制 CKA_ID 把 X.509 证书与签名密钥配对,并通过 CKM_RSA_PKCS 或 CKM_ECDSA 签署已计算的摘要
显式的证书可选发现可按标签或二进制 ID 选择 ML-DSA 私钥,验证其 CKA_PARAMETER_SET,并通过 CKM_ML_DSA 签署原始消息
SignDigest 实现 TPDFlibExternalDigestSignEvent,可直接赋给 TPDFlib.OnExternalDigestSign
单元
PDFlibPKCS11构造与模块生命周期
Constructor TPDFlibPKCS11Client.Create;
Destructor TPDFlibPKCS11Client.Destroy;
Function TPDFlibPKCS11Client.LoadModule: Boolean;
Procedure TPDFlibPKCS11Client.UnloadModule;
Function TPDFlibPKCS11Client.UseFunctionList(FunctionList: PPLPKCS11FunctionList; AlreadyInitialized: Boolean): Boolean;ModulePath 标识导出 C_GetFunctionList 的 Win32 或 Win64 PKCS #11 DLL
使用相同路径的客户端共享一个已加载模块和一个配平的 C_Initialize/C_Finalize 生命周期
加载器先请求 CKF_OS_LOCKING_OK;无法提供内部锁定的模块由共享调用锁保护,而合规模块允许不同客户端会话并发运行
UseFunctionList 支持静态链接、内嵌或应用程序管理的提供程序;调用方必须使所提供的函数表保持有效,直到 UnloadModule 或销毁
令牌发现和连接
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 在热插拔事件改变数量时以有界重试枚举当前存在的槽位,TokenCount 报告上次刷新发现的令牌数量使用
SlotID、TokenLabel、TokenSerial 或其组合选择令牌;空选择仅在恰好存在一个令牌时成功
TPDFlibPKCS11Token 报告槽位描述、制造商、令牌标签、型号、序列号、标志和 PIN 长度边界
标识选择
| CertificateLabel | X.509 证书对象的可选 UTF-8 CKA_LABEL 过滤器 |
|---|---|
| CertificateID | 存储在 AnsiString 中的可选二进制 CKA_ID 过滤器 |
| PrivateKeyLabel | 私钥签名密钥的可选 UTF-8 CKA_LABEL 过滤器 |
| PrivateKeyID | 可选的二进制私钥 CKA_ID;为空时复用证书 ID |
| CertificateOptional | 默认 False;为 True 时要求私钥标签或 ID,且发现只接受没有 X.509 证书的 ML-DSA 密钥 |
默认发现要求一对无歧义的证书与密钥、要求 CKA_SIGN=True、验证证书 DER,并拒绝 RSA/EC 类型不匹配;证书可选发现要求无歧义的 ML-DSA 密钥,并验证参数集 44、65 或 87
解析出的 ML-DSA 参数集通过 MLDSAParameterSet 暴露
解析出的证书通过 CertificateDER 暴露,所选密钥 ID 通过 ResolvedPrivateKeyID 暴露
身份验证
| UserPIN | 只写的用户 PIN,以 UTF-8 编码,会对照令牌边界检查,并在替换或销毁时被擦除 |
|---|---|
| UseProtectedAuthenticationPath | 令牌声明 CKF_PROTECTED_AUTHENTICATION_PATH 时传入空 PIN |
| ReadWriteSession | 添加 CKF_RW_SESSION;签名通常只需要默认的只读串行会话 |
具有 CKA_ALWAYS_AUTHENTICATE=True 的密钥在每次成功的 C_SignInit 之后都会进行上下文特定的登录
ClearPIN 覆盖并释放已配置的 PIN
签名
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 签名使用带本地构造 DER DigestInfo 的原始 CKM_RSA_PKCS,因此令牌不会对 PDF 摘要进行第二次哈希
ECDSA 签名使用原始 CKM_ECDSA;令牌的 P1363 输出在 PDF_EXTERNAL_SIGNATURE_ECDSA_P1363 下原样返回,在 PDF_EXTERNAL_SIGNATURE_ECDSA_DER 下转换为严格 DER
SignMLDSA 把原始消息传给带空机制参数的单部分 CKM_ML_DSA,选择默认的空上下文;它与 SignHash 和 CMS 摘要回调相互独立
SHA-1、SHA-256、SHA-384、SHA-512、SHA3-256、SHA3-384 和 SHA3-512 摘要长度在任何私钥操作之前验证
只有在签名开始前 C_SignInit 失败时才重新打开并重试丢失的会话,以避免在结果不明的 C_Sign 失败后重复私钥操作
示例
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;状态与失败行为
Connected、KeyType、MLDSAParameterSet、AlwaysAuthenticate、FunctionListMajor 和 FunctionListMinor 公开活动的提供程序状态当模块加载、令牌选择、身份验证、对象发现、属性边界、机制检查或签名失败时,方法会返回
False 并同时设置 LastReturnValue 和 LastError
另请参阅
OnExternalDigestSign, SetSignProcessExternalDigestSigner, SetSignProcessDigestAlgorithm, TPDFlibCSCClient
PIN 管理
Function TPDFlibPKCS11Client.InitializeUserPIN(Const SecurityOfficerPIN, NewUserPIN: WideString): Boolean;
Function TPDFlibPKCS11Client.ChangeUserPIN(Const OldPIN, NewPIN: WideString): Boolean;两个操作都在配置的令牌上打开各自的读写会话而不触动签名会话;InitializeUserPIN 在调用 C_InitPIN 前以安全官身份登录,ChangeUserPIN 在调用 C_SetPIN 前以用户身份登录
PIN 缓冲区在使用后清零;缺少所需入口点的模块会报错而不是静默失败