TPDFlibPKCS11Client
Segurança e assinaturas
Descrição
Carrega um módulo PKCS #11 do fornecedor em tempo de execução e expõe certificados e chaves privadas que não estão registados junto dos fornecedores CSP ou KSP do Windows
O cliente enumera os tokens presentes, abre uma sessão persistente, autentica o utilizador, emparelha um certificado X.509 com uma chave de assinatura pelo CKA_ID binário e assina resumos já calculados através de CKM_RSA_PKCS ou CKM_ECDSA
A descoberta explicitamente opcional quanto a certificado pode selecionar uma chave privada ML-DSA por etiqueta ou ID binário, validar o respetivo CKA_PARAMETER_SET e assinar mensagens originais através de CKM_ML_DSA
SignDigest implementa TPDFlibExternalDigestSignEvent e pode ser atribuído diretamente a TPDFlib.OnExternalDigestSign
Unit
PDFlibPKCS11Construção e ciclo de vida do módulo
Constructor TPDFlibPKCS11Client.Create;
Destructor TPDFlibPKCS11Client.Destroy;
Function TPDFlibPKCS11Client.LoadModule: Boolean;
Procedure TPDFlibPKCS11Client.UnloadModule;
Function TPDFlibPKCS11Client.UseFunctionList(FunctionList: PPLPKCS11FunctionList; AlreadyInitialized: Boolean): Boolean;ModulePath identifica uma DLL PKCS #11 Win32 ou Win64 que exporta C_GetFunctionList
Os clientes que utilizam o mesmo caminho partilham um módulo carregado e um tempo de vida equilibrado de C_Initialize/C_Finalize
O carregador pede primeiro CKF_OS_LOCKING_OK; os módulos que não conseguem fornecer bloqueio interno são protegidos por um bloqueio de chamada partilhado, enquanto os módulos conformes permitem que sessões de clientes separadas corram em simultâneo
UseFunctionList suporta fornecedores estaticamente ligados, embutidos ou geridos pela aplicação; o chamador tem de manter a tabela fornecida viva até UnloadModule ou destruição
Deteção e ligação de tokens
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 enumera os slots presentes com repetição delimitada quando um evento hot-plug muda a contagem, e TokenCount reporta quantos tokens a última atualização encontrouSelecione um token com
SlotID, TokenLabel, TokenSerial ou uma combinação; uma seleção vazia só tem êxito quando existe exatamente um token presente
TPDFlibPKCS11Token reporta a descrição do slot, o fabricante, a etiqueta do token, o modelo, o número de série, os sinalizadores e os limites do comprimento do PIN
Seleção de identidade
| CertificateLabel | Filtro CKA_LABEL UTF-8 opcional para o objeto de certificado X.509 |
|---|---|
| CertificateID | Filtro CKA_ID binário opcional guardado num AnsiString |
| PrivateKeyLabel | Filtro CKA_LABEL UTF-8 opcional para a chave privada de assinatura |
| PrivateKeyID | CKA_ID binário opcional da chave privada; quando vazio, o ID do certificado é reutilizado |
| CertificateOptional | Assume False por predefinição; quando True, é exigida uma etiqueta ou um ID de chave privada e a descoberta aceita apenas chaves ML-DSA sem certificado X.509 |
A descoberta predefinida exige um certificado e uma chave inequívocos, exige CKA_SIGN=True, valida o DER do certificado e recusa discrepâncias de tipo RSA/EC; a descoberta opcional quanto a certificado exige uma chave ML-DSA inequívoca e valida o conjunto de parâmetros 44, 65 ou 87
O conjunto de parâmetros ML-DSA resolvido é exposto através de MLDSAParameterSet
O certificado resolvido é exposto através de CertificateDER e o ID da chave selecionada através de ResolvedPrivateKeyID
Autenticação
| UserPIN | PIN de utilizador só de escrita codificado em UTF-8, verificado contra os limites do token, e apagado quando substituído ou destruído |
|---|---|
| UseProtectedAuthenticationPath | Passa um PIN nulo quando o token anuncia CKF_PROTECTED_AUTHENTICATION_PATH |
| ReadWriteSession | Acrescenta CKF_RW_SESSION; a assinatura normalmente precisa apenas da sessão série só de leitura predefinida |
Chaves com CKA_ALWAYS_AUTHENTICATE=True recebem um início de sessão específico do contexto após cada C_SignInit bem-sucedido
ClearPIN sobrescreve e liberta o PIN configurado
Assinatura
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;As assinaturas RSA utilizam CKM_RSA_PKCS bruto com um DigestInfo DER construído localmente, pelo que o token não volta a fazer o hash do resumo do PDF
As assinaturas ECDSA utilizam CKM_ECDSA bruto; a saída P1363 do token é devolvida inalterada para PDF_EXTERNAL_SIGNATURE_ECDSA_P1363 ou convertida em DER estrito para PDF_EXTERNAL_SIGNATURE_ECDSA_DER
SignMLDSA passa a mensagem original para CKM_ML_DSA de parte única com parâmetros de mecanismo vazios, selecionando o contexto vazio predefinido; é independente de SignHash e da chamada de retorno de resumo CMS
Os comprimentos de resumo SHA-1, SHA-256, SHA-384, SHA-512, SHA3-256, SHA3-384 e SHA3-512 são validados antes de qualquer operação com a chave privada
Uma sessão perdida é reaberta e repetida apenas quando C_SignInit falha antes de a assinatura começar, evitando operações de chave privada duplicadas após uma falha ambígua de C_Sign
Exemplo
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;Estado e comportamento em caso de falha
Connected, KeyType, MLDSAParameterSet, AlwaysAuthenticate, FunctionListMajor e FunctionListMinor expõem o estado do fornecedor ativoOs métodos devolvem
False e definem tanto LastReturnValue como LastError quando o carregamento do módulo, a seleção do token, a autenticação, a descoberta de objetos, os limites de atributos, as verificações de mecanismos ou a assinatura falham
Consulte também
OnExternalDigestSign, SetSignProcessExternalDigestSigner, SetSignProcessDigestAlgorithm, TPDFlibCSCClient
Administração de PIN
Function TPDFlibPKCS11Client.InitializeUserPIN(Const SecurityOfficerPIN, NewUserPIN: WideString): Boolean;
Function TPDFlibPKCS11Client.ChangeUserPIN(Const OldPIN, NewPIN: WideString): Boolean;Ambas as operações abrem a respetiva sessão de leitura/escrita no token configurado e deixam a sessão de assinatura intacta; InitializeUserPIN inicia sessão como oficial de segurança antes de chamar C_InitPIN, e ChangeUserPIN inicia sessão como utilizador antes de chamar C_SetPIN
Os buffers de PIN são apagados após a utilização; um módulo sem o ponto de entrada necessário comunica um erro em vez de falhar silenciosamente