Artigo Técnico

Assinaturas de PDF de longo prazo no Delphi: PAdES B-LT e B-LTA

Para garantir que um PDF assinado continue a ser verificado anos a partir de agora, depois que o certificado de assinatura expirar e sua Autoridade Certificadora for alterada, o Componente PDFium pode gerar assinaturas PAdES de longo prazo no Windows: um carimbo do tempo RFC 3161 para horário confiável, um Document Security Store que incorpora o material de validação e um DocTimeStamp de arquivamento sobre todo o arquivo. Esses três complementos compõem os níveis de linha de base PAdES B-T, B-LT e B-LTA, e o Componente PDFium alcança todos eles a partir de uma única chamada de assinatura. Essa é uma funcionalidade restrita ao Windows, controlada por PadesCryptoAvailable

Este artigo é o terceiro de uma série. O primeiro, assinar PDFs com PAdES B-B usando o PDFium VCL, cobre a assinatura básica; o segundo, inspecionar assinaturas digitais de PDF e níveis PAdES, trata de ler uma assinatura de volta e identificar o nível alcançado. Aqui o foco é o arquivamento: assinaturas que devem sobreviver à expiração do certificado e permanecer verificáveis por um período de retenção medido em anos, não semanas

Por que uma assinatura de PDF válida deixa de ser verificada ao longo do tempo?

Uma assinatura básica responde apenas a uma pergunta: se estes bytes foram alterados após a assinatura. Ela não prova, por si só, quando a assinatura ocorreu, e essa lacuna é o que a invalida posteriormente. A estrutura CMS carrega um atributo de horário de assinatura, mas o signatário escreve esse valor a partir do seu próprio relógio, de modo que o validador não tem motivos para confiar nele. Quando o certificado de assinatura expira ou a AC o revoga, um validador rigoroso não consegue mais distinguir uma assinatura feita enquanto o certificado estava válido de uma forjada após o término de sua validade. A assinatura estava perfeitamente correta no dia em que foi feita e torna-se não verificável sem que o signatário tenha culpa

O arquivamento de longo prazo corrige isso em duas etapas. Primeiro, um terceiro confiável, uma Autoridade de Carimbo do Tempo (TSA), atesta o horário criptograficamente para que ele não dependa mais da honestidade do relógio do signatário. Segundo, cada certificado, resposta de revogação e CRL necessários para construir e checar a cadeia de confiança é incorporado dentro do próprio PDF, de modo que a validação não dependa de servidores que podem não estar mais ativos no momento da verificação. O PAdES, padronizado como ETSI EN 319 142-1, organiza esses recursos em níveis de linha de base, e o Componente PDFium grava as estruturas exigidas por cada nível

O que é uma assinatura de PDF com LTV ou carimbo de arquivamento?

O PAdES define quatro níveis de linha de base que se complementam, e o Componente PDFium os expõe através da enumeração TPadesLevel (plB_B, plB_T, plB_LT, plB_LTA). O B-B é a assinatura simples. O B-T adiciona um carimbo de data/hora confiável sobre o valor da assinatura. O B-LT (long-term) adiciona o material de validação incorporado, que é a propriedade que a maioria das pessoas chama de "LTV". O B-LTA (long-term com carimbo de arquivamento) encapsula tudo em mais um carimbo de data/hora que cobre o arquivo completo, de modo que o próprio material incorporado é provadamente íntegro desde o momento do arquivamento

A interpretação prática é uma escada. O B-T prova quando. O B-LT prova com o que a assinatura ainda pode ser verificada. O B-LTA prova que todo o pacote não foi alterado desde que foi selado, e é o nível que você renova, adicionando um novo DocTimeStamp antes que o anterior expire, para estender o arquivo indefinidamente. Para um contrato ou registro de conformidade com uma obrigação de retenção de longo prazo, o B-LTA é o objetivo; o B-LT é o patamar pragmático

Adicionando horário confiável: PAdES B-T com RFC 3161

O Componente PDFium transforma uma assinatura B-B em B-T definindo dois campos em TPadesSignOptions: eleve o Level para plB_T e forneça uma TsaUrl. Quando ambos estão presentes, o fluxo de assinatura processa os octetos brutos da assinatura com SHA-256, empacota essa hash como o messageImprint da RFC 3161, envia a requisição POST para a TSA via WinHttp e incorpora o token retornado como o atributo assinado signature-time-stamp (OID 1.2.840.113549.1.9.16.2.14) na seção SignerInfo unsignedAttrs [1], conforme a EN 319 142-1 §6.3. O carimbo do tempo cobre especificamente o valor da assinatura, vinculando o horário confiável àquela assinatura exata

uses
  PDFium, FPdfPades;

procedure SignWithTimestamp;
var
  Pdf: TPdf;
  Options: TPadesSignOptions;
begin
  Pdf := TPdf.Create(nil);
  try
    if not Pdf.PadesCryptoAvailable then
      raise Exception.Create('O backend de assinatura PAdES está disponível apenas no Windows');
    Pdf.FileName := 'contract.pdf';
    Pdf.Active := True;

    Options := TPadesSignOptions.Default;
    Options.CertificateThumbprint := 'A1B2C3D4E5F6071829304152637485960A1B2C3D';
    Options.Level  := plB_T;
    Options.TsaUrl := 'http://timestamp.example-tsa.com/tsr';
    Options.Reason := 'Assinatura do contrato';
    // Nonce mantido como 0: o componente gera um valor exclusivo anti-replay.

    Pdf.SignPades('contract-bt.pdf', Options);
  finally
    Pdf.Free;
  end;
end;

O CertificateThumbprint é a hash SHA-1, em formato hexadecimal, de um certificado no repositório "MY" do Usuário Atual cuja chave privada você pode utilizar. O campo Nonce é o valor anti-replay da RFC 3161; deixe-o como zero e o componente gerará um valor exclusivo por requisição a partir de uma hash SHA-256 combinando um contador, o relógio, a contagem de ticks e o ID do processo, garantindo que duas requisições enviadas no mesmo milissegundo não colidam. Forneça o seu próprio valor apenas se tiver um gerador de números aleatórios criptográficos de sua preferência. Uma ressalva honesta: o nível B-T exige uma TSA acessível, portanto, assinar agora envolve uma chamada de rede e herda a disponibilidade e latência da TSA

Incorporando material de validação: B-LT e B-LTA em uma única chamada

O avanço para a validação de longo prazo exige apenas uma mudança: defina o Level como plB_LTA e mantenha a TsaUrl. O Componente PDFium executa toda a sequência dentro de uma única chamada SignPades. Ele assina como B-B, adiciona o carimbo como B-T, injeta o Document Security Store para B-LT e anexa o carimbo do tempo de arquivo para B-LTA, cada um como sua própria atualização incremental para que os bytes anteriores permaneçam perfeitamente intactos

procedure SignForArchive;
var
  Pdf: TPdf;
  Options: TPadesSignOptions;
begin
  Pdf := TPdf.Create(nil);
  try
    Pdf.FileName := 'contract.pdf';
    Pdf.Active := True;

    Options := TPadesSignOptions.Default;
    Options.CertificateThumbprint := 'A1B2C3D4E5F6071829304152637485960A1B2C3D';
    Options.Level    := plB_LTA;   // executa B-B -> B-T -> B-LT -> B-LTA
    Options.TsaUrl   := 'http://timestamp.example-tsa.com/tsr';
    Options.Location := 'Escritório Central';

    // Uma única chamada grava o carimbo do tempo, o DSS e o DocTimeStamp de arquivamento.
    Pdf.SignPades('contract-lta.pdf', Options);
  finally
    Pdf.Free;
  end;
end;

Para a etapa B-LT, o Componente PDFium monta a cadeia de certificados com CertGetCertificateChain e grava um dicionário /DSS contendo o certificado do signatário e cada CA intermediária em um array /Certs (com arrays paralelos /OCSPs e /CRLs), ao lado de um marcador /Extensions /ESIC no Level 1, exatamente como a EN 319 142-1 §5.4.2 determina. O certificado raiz autoassinado é omitido por design, já que a RFC 5652 §10.2.3 permite e o raiz já é uma âncora de confiança que o validador possui. O resultado é uma assinatura que o leitor pode verificar usando apenas o arquivo em mãos

Para o B-LTA, o componente anexa um Document Time-stamp: um dicionário de assinatura com /SubFilter /ETSI.RFC3161 cujo /ByteRange abrange o arquivo completo, com sua entrada /Contents guardando um token RFC 3161 sobre esse intervalo, e eleva o marcador ESIC para Level 2. Essa é a etapa de arquivamento descrita na §5.4.3 e na TS 119 142-3. Como o DocTimeStamp cobre o DSS e também a assinatura, ele prova que o material de validação incorporado estava presente e inalterado no momento do arquivamento, que é exatamente o que uma política de retenção de longo prazo precisa mostrar

Aumentando uma assinatura que já existe

Às vezes, a assinatura já está no documento e você precisa apenas adicionar ou atualizar o repositório de validação, por exemplo, para elevar uma assinatura B-B de terceiros para B-LT em seu arquivo. O Componente PDFium expõe o injetor de DSS diretamente por meio do SaveAsPadesDss, que anexa as estruturas /DSS e /Extensions como uma atualização incremental sem afetar os bytes da assinatura existente

procedure AddValidationStore;
var
  Pdf: TPdf;
  DssOpts: TPadesDssOptions;
  Cert: TPadesDssMaterial;
begin
  Pdf := TPdf.Create(nil);
  try
    Pdf.FileName := 'already-signed.pdf';
    Pdf.Active := True;

    DssOpts := TPadesDssOptions.Default;
    DssOpts.EsicExtensionLevel := 1;         // 1 para B-LT, 2 para B-LTA
    Cert.DerBytes := LoadSignerCertDer;       // seu certificado codificado em DER
    SetLength(DssOpts.Certs, 1);
    DssOpts.Certs[0] := Cert;

    Pdf.SaveAsPadesDss('already-signed-lt.pdf', DssOpts);
  finally
    Pdf.Free;
  end;
end;

Você fornece os certificados codificados em DER e, opcionalmente, respostas OCSP e CRLs que um validador necessitará. Defina o EsicExtensionLevel como 1 para um repositório B-LT ou 2 quando um DocTimeStamp for adicionado a seguir. Deixe o IncludeVri em seu padrão False: a norma EN 319 142-1 §5.4.2.3 trata o dicionário /VRI por assinatura como opcional e desaconselha seu uso, a menos que um leitor específico que você tenha como alvo exija

Custos e limitações que valem a pena planejar

Três limitações reais moldam onde esses níveis se aplicam. Primeiro, o backend criptográfico é restrito ao Windows: a assinatura e a geração de carimbos do tempo passam pelos repositórios CNG e WinHttp da plataforma, de modo que o PadesCryptoAvailable retorna False em outros sistemas e o SignPades gera exceções. A inspeção de leitura descrita no artigo complementar continua multiplataforma; apenas a gravação de assinaturas está restrita ao Windows. Segundo, os níveis B-T e B-LTA dependem de uma Autoridade de Carimbo do Tempo, o que significa uma viagem de rede no momento da assinatura e um serviço externo cujos limites de taxa e tempo de atividade passam a fazer parte do seu fluxo de assinatura

Terceiro, cada nível consome armazenamento. Cada etapa anexa uma atualização incremental em vez de sobrescrever o arquivo, o DSS incorpora uma cadeia completa de certificados e o DocTimeStamp de arquivamento reserva espaço para seu token, de modo que um arquivo B-LTA é significativamente maior do que o original B-B. Essa é uma troca intencional: você consome bytes agora para garantir a verificabilidade depois. Para a maioria dos arquivos de contratos e conformidade, é a escolha correta, mas vale a pena medir em seus próprios documentos em vez de apenas presumir. Quando precisar confirmar se um arquivo finalizado realmente atingiu o nível desejado, verifique-o usando as técnicas descritas em inspecionar assinaturas de PDF e níveis PAdES e, se estiver protegendo um pipeline de documentos de forma mais ampla, as notas sobre auditar riscos de segurança em PDF abordam as verificações ao redor. Os recursos de assinatura PAdES, DSS e carimbo de arquivamento mostrados aqui são fornecidos no Componente PDFium para Delphi e C++Builder, cuja página de produto contém a referência de assinatura completa e os requisitos da plataforma