Artículo técnico

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

Para lograr que un PDF firmado se verifique dentro de unos años, después de que el certificado de firma expire y su CA rote, PDFium Component puede producir firmas PAdES a largo plazo en Windows: una marca de tiempo RFC 3161 para hora de confianza, un Almacén de Seguridad del Documento (Document Security Store o DSS) que incrusta el material de validación, y un DocTimeStamp de archivo sobre todo el documento. Estas tres adiciones representan los niveles de referencia PAdES B-T, B-LT y B-LTA, y PDFium Component los alcanza todos a partir de una única llamada de firma. Esta es una capacidad exclusiva de Windows, controlada por PadesCryptoAvailable

Este artículo es el tercero de una serie. El primero, firma de archivos PDF con PAdES B-B usando PDFium VCL, cubre la firma básica; el segundo, inspección de firmas digitales PDF y niveles PAdES, trata de leer una firma e identificar el nivel que alcanzó. Aquí el objetivo es el archivado: firmas que deben sobrevivir a la expiración de certificados y mantenerse verificables durante periodos de retención medidos 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 se modificaron después de la firma. No demuestra por sí sola cuándo se realizó la firma, y esa laguna 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 una falsificada después de su vencimiento. La firma era correcta el día en que se realizó y se vuelve no verificable sin que sea culpa suya

El archivado a largo plazo soluciona esto en dos movimientos. En primer lugar, un tercero de confianza, una Autoridad de Sellado de Tiempo (TSA), certifica la hora de forma criptográfica para que ya no dependa de la honestidad del firmante. En segundo lugar, cada certificado, respuesta de revocación y CRL necesarios para construir y verificar la cadena de confianza se incrustan dentro del propio PDF, de modo que la validación no depende de servidores que podrían no estar disponibles cuando alguien lo compruebe. PAdES, estandarizado como ETSI EN 319 142-1, los estructura como niveles de referencia, y PDFium Component escribe las estructuras que requiere cada nivel

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

PAdES define cuatro niveles de referencia que se construyen uno sobre otro, y 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 de confianza sobre el valor de la firma. B-LT (a largo plazo) añade el material de validación incrustado, la característica a la que la mayoría de la gente se refiere como "LTV". B-LTA (a largo plazo con marca de tiempo de archivo) envuelve todo en una marca de tiempo adicional que cubre todo el archivo, de modo que el material incrustado en sí está demostrablemente intacto desde el momento del archivado

La interpretación práctica es una escalera. B-T demuestra cuándo. B-LT demuestra con qué se puede verificar todavía la firma. B-LTA demuestra que todo el paquete no ha sido alterado desde que se selló, y es el nivel que se renueva, añadiendo un nuevo DocTimeStamp antes de que el anterior expire, para prolongar el archivado indefinidamente. Para un contrato o un registro de conformidad con una obligación de retención prolongada, B-LTA es el objetivo; B-LT es el mínimo pragmático

Adición de hora de confianza: PAdES B-T con RFC 3161

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, la canalización de firma procesa en un hash los octetos de la firma sin procesar con SHA-256, empaqueta ese resumen como el messageImprint de RFC 3161, envía la solicitud por POST a la TSA a través de WinHttp, e incrusta 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, según EN 319 142-1 §6.3. La marca de tiempo cubre el valor de la firma específicamente, que es lo que 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;

El 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 anti-repetición de RFC 3161; déjelo en cero y el componente derivará uno exclusivo por solicitud a partir de un SHA-256 compuesto de un contador, el reloj, el recuento de ciclos y el ID de proceso, de modo que dos solicitudes emitidas en el mismo milisegundo no colisionen. Pase su propio valor solo cuando disponga de un RNG criptográfico en el que prefiera confiar. Una advertencia honesta: B-T necesita una TSA accesible, por lo que firmar ahora realiza una llamada de red y depende de la disponibilidad y latencia de la TSA

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

El paso hacia la validación a largo plazo es un único cambio: establezca Level en plB_LTA y conserve la TsaUrl. PDFium Component ejecuta entonces la escalera completa dentro de una sola llamada a SignPades. Firma B-B, añade la marca de tiempo para B-T, inyecta el Almacén de Seguridad del Documento para B-LT y añade la marca de tiempo de archivo para B-LTA, cada uno 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, 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 prescribe EN 319 142-1 §5.4.2. La raíz autofirmada se omite deliberadamente, ya que RFC 5652 §10.2.3 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 en mano

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

Ampliación de una firma existente

A veces la firma ya se encuentra en el documento y 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 archivado. 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 tocar 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;

Proporciona los certificados codificados en DER, y opcionalmente respuestas OCSP y CRL, que necesitará un validador. 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: 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 al que se diriga lo exija

Costos y límites a tener en cuenta en la planificación

Tres límites honestos determinan dónde encajan estos niveles. En primer lugar, el motor criptográfico subyacente es exclusivo de Windows: la firma y el sellado de tiempo pasan por los almacenes CNG y WinHttp de la plataforma, por lo que PadesCryptoAvailable devuelve False en otros sistemas y SignPades genera una excepción. La inspección del lado de lectura cubierta en el artículo complementario sigue siendo multiplataforma; solo la escritura de firmas está vinculada a Windows. En segundo lugar, B-T y B-LTA dependen de una Autoridad de Sellado de Tiempo, lo que implica un viaje de ida y vuelta de red en el momento de firmar y un servicio externo cuyo tiempo de actividad y límites de velocidad pasan a formar parte de su ruta de firma

En tercer lugar, cada nivel tiene un costo de almacenamiento. Cada etapa añade una actualización incremental en lugar de reescribir el archivo, el DSS incrusta 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: invierte bytes ahora para comprar verificabilidad después. Para la mayoría de los archivos de contratos y conformidad, es la compensación correcta, pero vale la pena medirla en sus propios documentos en lugar de asumirla. Cuando necesite confirmar si un archivo finalizado alcanzó el nivel previsto, verifíquelo con las técnicas de inspección de firmas digitales PDF y niveles PAdES, y si está protegiendo un flujo de documentos de forma más amplia, las notas sobre auditoría de riesgos de seguridad de PDF cubren las comprobaciones complementarias

Las funciones de firma PAdES, DSS y marcas de tiempo de archivo que se muestran aquí forman parte de PDFium Component para Delphi y C++Builder, cuya página de producto contiene la referencia de firma completa y los requisitos de la plataforma