Artículo técnico

Firmas PDF a largo plazo en Delphi: PAdES B-LT y B-LTA

Para garantizar que un PDF firmado se pueda verificar años después, tras la expiración del certificado de firma y la rotación de su autoridad de certificación (CA), el PDFium Component puede generar firmas PAdES a largo plazo en Windows: una marca de tiempo RFC 3161 para una hora confiable, un almacén de seguridad del documento (DSS) que integra el material de validación, y un DocTimeStamp de archivo sobre todo el archivo. Estas tres adiciones corresponden a los niveles base de PAdES B-T, B-LT y B-LTA, y el PDFium Component los alcanza todos mediante una única llamada de firma. Esta es una capacidad exclusiva de Windows, limitada por la comprobación PadesCryptoAvailable

Este artículo es el tercero de una serie. El primero, firmar PDFs con PAdES B-B usando PDFium VCL, cubre la firma básica; el segundo, inspeccionar firmas digitales PDF y niveles PAdES, explica cómo leer una firma y determinar qué nivel alcanzó. En esta entrega, la atención se centra en el archivo: firmas que deben resistir la expiración de certificados y permanecer verificables durante un período de conservación medido en años, no en semanas

¿Por qué una firma PDF válida deja de verificarse con el tiempo?

Una firma básica responde únicamente a una pregunta: si estos bytes fueron alterados después de la firma. No demuestra, por sí misma, cuándo ocurrió la firma, y esa brecha es lo que la invalida más adelante. La estructura CMS contiene un atributo de hora de firma, pero el firmante escribe ese valor a partir de su propio reloj, por lo que un validador no tiene motivos para confiar en él. Cuando el certificado de firma expira posteriormente o la CA lo revoca, un validador estricto ya no puede distinguir entre una firma realizada mientras el certificado era válido y otra falsificada después de su vencimiento. La firma era correcta el día en que se realizó pero se vuelve imposible de verificar sin que sea su culpa

El archivo a largo plazo corrige esto en dos pasos. Primero, un tercero de confianza, una Autoridad de Sellado de Tiempo (TSA), certifica la hora de manera criptográfica para que ya no dependa de la honestidad del firmante. Segundo, cada certificado, respuesta de revocación y CRL necesarios para construir y comprobar la cadena de confianza se integran dentro del propio PDF, de modo que la validación no dependa de servidores que podrían dejar de existir cuando alguien intente verificar el documento. PAdES, estandarizado como ETSI EN 319 142-1, los clasifica en niveles base, y el PDFium Component escribe las estructuras requeridas para cada nivel

¿Qué es una firma PDF LTV o con marca de tiempo de archivo?

PAdES define cuatro niveles base que se construyen uno sobre otro, y el PDFium Component los expone a través de la enumeración TPadesLevel (plB_B, plB_T, plB_LT, plB_LTA). B-B es la firma simple. B-T añade una marca de tiempo confiable sobre el valor de la firma. B-LT (largo plazo) incorpora el material de validación integrado, la característica a la que la mayoría de las personas se refiere con "LTV". B-LTA (largo plazo con marca de tiempo de archivo) envuelve todo en una marca de tiempo adicional que cubre el archivo completo, por lo que el material integrado en sí se mantiene demostrablemente intacto desde el momento del archivo

La interpretación práctica es una escala progresiva. B-T demuestra cuándo. B-LT demuestra con qué se puede seguir comprobando la firma. B-LTA demuestra que todo el conjunto no ha sido alterado desde que fue sellado, y es el nivel que se renueva, añadiendo un nuevo DocTimeStamp antes de que expire el anterior, para extender el archivo indefinidamente. Para un contrato o un registro de conformidad con una obligación de conservación prolongada, B-LTA es el objetivo; B-LT es el nivel mínimo recomendado

Añadir hora de confianza: PAdES B-T con RFC 3161

El PDFium Component convierte una firma B-B en B-T configurando dos campos en TPadesSignOptions: eleve Level a plB_T y proporcione una TsaUrl. Cuando ambos están presentes, el flujo de firma calcula el hash de los octetos de la firma sin formato con SHA-256, empaqueta ese resumen como el mensajeImprint de RFC 3161, envía la solicitud (POST) a la TSA a través de WinHttp, e integra el token devuelto como el atributo no firmado signature-time-stamp (OID 1.2.840.113549.1.9.16.2.14) en el unsignedAttrs [1] de SignerInfo, conforme a la norma EN 319 142-1 §6.3. La marca de tiempo cubre el valor de la firma de manera específica, lo cual vincula la hora de confianza a esa firma exacta

uses
  PDFium, FPdfPades;

procedure SignWithTimestamp;
var
  Pdf: TPdf;
  Options: TPadesSignOptions;
begin
  Pdf := TPdf.Create(nil);
  try
    if not Pdf.PadesCryptoAvailable then
      raise Exception.Create('PAdES signing backend is Windows-only');
    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 := 'Contract execution';
    // Nonce left at 0: the component derives a unique anti-replay value.

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

La propiedad CertificateThumbprint es el hash SHA-1, en hexadecimal, de un certificado en el almacén "MY" de usuario actual cuya clave privada puede utilizar. El campo Nonce es el valor antireproducción de RFC 3161; déjelo en cero y el componente derivará un valor único por solicitud a partir de un hash SHA-256 de un contador, el reloj, el conteo de ciclos del procesador y el ID del proceso, para que dos solicitudes emitidas en el mismo milisegundo no colisionen. Pase su propio valor solo cuando disponga de un generador de números aleatorios criptográfico (RNG) en el que prefiera confiar. Una advertencia honesta: B-T requiere una TSA accesible, por lo que la firma ahora realiza una llamada de red y hereda la disponibilidad y latencia de la TSA

Integrar el material de validación: B-LT y B-LTA en una sola llamada

El paso hacia la validación a largo plazo consiste en un único cambio: establezca Level en plB_LTA y conserve la TsaUrl. El PDFium Component ejecuta entonces la escala completa dentro de una sola llamada a SignPades. Firma como B-B, añade la marca de tiempo para B-T, inyecta el almacén de seguridad del documento (DSS) para B-LT, y añade la marca de tiempo de archivo para B-LTA, cada una como su propia actualización incremental para que los bytes anteriores permanezcan intactos byte por byte

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;   // drives B-B -> B-T -> B-LT -> B-LTA
    Options.TsaUrl   := 'http://timestamp.example-tsa.com/tsr';
    Options.Location := 'Head Office';

    // One call writes the timestamp, the DSS and the archive DocTimeStamp.
    Pdf.SignPades('contract-lta.pdf', Options);
  finally
    Pdf.Free;
  end;
end;

Para la etapa B-LT, el PDFium Component construye la cadena de certificados con CertGetCertificateChain y escribe un diccionario /DSS que contiene el certificado del firmante más cada CA intermedia en un arreglo /Certs (con arreglos paralelos /OCSPs y /CRLs), junto con un marcador /Extensions /ESIC en el Nivel 1, exactamente como lo prescribe la norma EN 319 142-1 §5.4.2. La raíz autofirmada se omite deliberadamente, dado que la sección §10.2.3 de RFC 5652 lo permite y la raíz ya es un ancla de confianza que posee el validador. El resultado es una firma que un lector puede verificar teniendo únicamente el archivo a la mano

Para B-LTA, el componente añade una marca de tiempo del documento (Document Time-stamp): un diccionario de firma con /SubFilter /ETSI.RFC3161 cuyo /ByteRange cubre todo el archivo, con /Contents que contiene un token RFC 3161 sobre ese rango, y promueve el marcador ESIC al Nivel 2. Este es el paso de archivo de la sección §5.4.3 y la norma TS 119 142-3. Debido a que el DocTimeStamp cubre tanto el DSS como la firma, demuestra que el material de validación integrado estaba presente y sin alteraciones en el momento del archivo, que es exactamente lo que una política de conservación a largo plazo debe poder demostrar

Ampliar una firma que ya existe

A veces la firma ya se encuentra en el documento y usted solo necesita añadir o actualizar el almacén de validación (por ejemplo, para elevar una firma B-B de terceros a B-LT para su archivo). El PDFium Component expone el inyector DSS directamente a través de SaveAsPadesDss, que añade las estructuras /DSS y /Extensions como una actualización incremental sin alterar los bytes de la firma 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 for B-LT, 2 for B-LTA
    Cert.DerBytes := LoadSignerCertDer;       // your DER-encoded certificate
    SetLength(DssOpts.Certs, 1);
    DssOpts.Certs[0] := Cert;

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

Usted proporciona los certificados codificados en DER, y opcionalmente las respuestas OCSP y CRL, que un validador necesitará. Establezca EsicExtensionLevel en 1 para un almacén B-LT o en 2 cuando le siga un DocTimeStamp. Deje IncludeVri en su valor predeterminado False: la norma EN 319 142-1 §5.4.2.3 trata el diccionario /VRI por firma como opcional y desaconseja su uso a menos que un lector específico de su objetivo lo requiera

Costos y límites que vale la pena planificar

Tres límites reales definen dónde encajan estos niveles. Primero, el soporte criptográfico es exclusivo de Windows: la firma y el sellado de tiempo pasan por las tiendas CNG y WinHttp de la plataforma, por lo que PadesCryptoAvailable devuelve False en otros entornos y SignPades genera una excepción. La inspección del lado de lectura descrita en el artículo complementario se mantiene multiplataforma; solo la escritura de firmas está vinculada a Windows. Segundo, B-T y B-LTA dependen de una Autoridad de Sellado de Tiempo, lo que se traduce en un viaje de ida y vuelta a través de la red al momento de la firma y en un servicio externo cuya disponibilidad y límites de velocidad pasan a formar parte de su flujo de firma

Tercero, cada nivel consume almacenamiento. Cada etapa añade una actualización incremental en lugar de reescribir el archivo, el DSS integra una cadena de certificados completa y el DocTimeStamp de archivo reserva espacio para su token, por lo que un archivo B-LTA es significativamente más grande que el original B-B. Esa es la compensación deliberada: consume bytes ahora para ganar verificabilidad más adelante. Para la mayoría de los archivos de contratos y conformidad, es la compensación correcta, pero vale la pena medirlo en sus propios documentos en lugar de asumirlo. Cuando necesite confirmar que un archivo finalizado alcanzó el nivel que esperaba, verifíquelo con las técnicas de inspeccionar firmas digitales PDF y niveles PAdES, y si está reforzando un flujo de documentos de forma más amplia, las notas sobre auditar riesgos de seguridad de PDF cubren las comprobaciones relacionadas

Las funciones de firma PAdES, DSS y marca de tiempo de archivo mostradas aquí forman parte del PDFium Component para Delphi y C++Builder, cuya página de producto incluye la referencia de firma completa y los requisitos de la plataforma