Skip to content

Long-Term Validation

Pro — Commercial License Required
Long-Term Validation (LTV) requiere el paquete Pro.

LTV asegura que las firmas permanezcan verificables después de que los certificados expiren o los servicios de revocación se desconecten, al incrustar todos los datos de validación en el PDF via el Document Security Store (DSS).

Clases LTV

ClasePropósito
LtvManagerOrquesta la construcción de cadena, obtención de OCSP/CRL, ensamblaje de DSS
DssBuilderConstruye el diccionario DSS con certificados, OCSPs, CRLs
OcspClientObtiene respuestas OCSP (RFC 6960)
CrlFetcherDescarga CRLs desde puntos de distribución (RFC 5280)

LtvManager

En los niveles B-LT o B-LTA, LtvManager se ejecuta automáticamente dentro de DigitalSigner. Para control manual:

php
use Yeeefang\TcpdfNext\Pro\Security\Ltv\LtvManager;

$ltv = new LtvManager($pdf);
$ltv->addCertificate(file_get_contents('/certs/intermediate.pem'));
$ltv->addCertificate(file_get_contents('/certs/root.pem'));
$ltv->addOcspResponse($ocspResponseDer);
$ltv->addCrl($crlDer);
$ltv->apply(); // builds and embeds the DSS dictionary

DssBuilder

Construye el diccionario DSS (ISO 32000-2) que contiene /Certs, /OCSPs, /CRLs y entradas /VRI opcionales por firma.

php
use Yeeefang\TcpdfNext\Pro\Security\Ltv\DssBuilder;

$dss = new DssBuilder();
$dss->addCertificate($intermediateDer);
$dss->addOcspResponse($ocspDer);
$dss->addCrl($crlDer);
$dss->addVri($sigHash, [$signerDer], [$ocspDer], [$crlDer]); // optional per-signature VRI
$dssDict = $dss->build();

OcspClient

Consulta respondedores OCSP para verificar el estado de revocación de certificados.

php
use Yeeefang\TcpdfNext\Pro\Security\Ltv\OcspClient;

$ocsp = new OcspClient();
$ocsp->timeout(10);
$ocsp->cacheDir('/tmp/ocsp-cache');

$response = $ocsp->query(
    certificate:  '/certs/signing.pem',
    issuer:       '/certs/intermediate.pem',
    responderUrl: 'https://ocsp.example.com', // optional; extracted from AIA if omitted
);

echo $response->status();     // 'good', 'revoked', or 'unknown'
echo $response->producedAt(); // DateTimeImmutable
$derBytes = $response->toDer();

CrlFetcher

Descarga CRLs desde el CDP declarado en los certificados, con caché en disco opcional.

php
use Yeeefang\TcpdfNext\Pro\Security\Ltv\CrlFetcher;

$fetcher = new CrlFetcher();
$fetcher->cacheDir('/tmp/crl-cache');
$fetcher->cacheTtl(86400); // 24 hours

$crl = $fetcher->fetchForCertificate('/certs/signing.pem');
echo $crl->issuerDN();
echo $crl->revokedCount();
$crl->isRevoked('01:AB:CD:EF'); // bool
$derBytes = $crl->toDer();

Construcción de cadena de certificados

LtvManager sigue la extensión AIA caIssuers para descubrir intermediarios automáticamente. Si el HTTP saliente está restringido, proporciona la cadena manualmente via CertificateInfo::chain().

php
$ltv = new LtvManager($pdf);
$ltv->buildChain(signerCertificate: '/certs/signing.pem');
$chain = $ltv->chain(); // array of DER-encoded certificates

Bucle de archivo (B-LTA)

B-LTA agrega un document timestamp después de la incrustación del DSS. Vuelve a firmar con timestamp antes de que expire el certificado TSA para mantener la validez indefinidamente:

Sign (B-B) -> TSA timestamp (B-T) -> DSS (B-LT) -> Document timestamp (B-LTA)
    -> [re-timestamp before expiry]
php
$ltv = LtvManager::load('/archive/contract-2026.pdf');
$ltv->retimestamp(new TsaClient('https://tsa.example.com/timestamp'));
$ltv->save('/archive/contract-2026.pdf');

Manejo de errores

Las operaciones LTV lanzan excepciones tipadas: OcspException (respondedor inalcanzable), CrlException (descarga fallida) o ChainBuildException (cadena incompleta). Todas están bajo el namespace Yeeefang\TcpdfNext\Pro\Security\Ltv.

Próximos pasos

Distribuido bajo la licencia LGPL-3.0-or-later.