Long-Term Validation
LTV ensures signatures remain verifiable after certificates expire or revocation services go offline by embedding all validation data into the PDF via the Document Security Store (DSS).
LTV Classes
| Class | Purpose |
|---|---|
LtvManager | Orchestrates chain building, OCSP/CRL fetching, DSS assembly |
DssBuilder | Builds the DSS dictionary with certs, OCSPs, CRLs |
OcspClient | Fetches OCSP responses (RFC 6960) |
CrlFetcher | Downloads CRLs from distribution points (RFC 5280) |
LtvManager
At B-LT or B-LTA levels, LtvManager runs automatically inside DigitalSigner. For manual control:
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 dictionaryDssBuilder
Constructs the DSS dictionary (ISO 32000-2) containing /Certs, /OCSPs, /CRLs, and optional per-signature /VRI entries.
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
Queries OCSP responders to check certificate revocation status.
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
Downloads CRLs from the CDP declared in certificates, with optional disk caching.
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();Certificate Chain Building
LtvManager follows the AIA caIssuers extension to discover intermediates automatically. If outbound HTTP is restricted, provide the chain manually via CertificateInfo::chain().
$ltv = new LtvManager($pdf);
$ltv->buildChain(signerCertificate: '/certs/signing.pem');
$chain = $ltv->chain(); // array of DER-encoded certificatesArchival Loop (B-LTA)
B-LTA adds a document timestamp after DSS embedding. Re-timestamp before the TSA certificate expires to maintain validity indefinitely:
Sign (B-B) -> TSA timestamp (B-T) -> DSS (B-LT) -> Document timestamp (B-LTA)
-> [re-timestamp before expiry]$ltv = LtvManager::load('/archive/contract-2026.pdf');
$ltv->retimestamp(new TsaClient('https://tsa.example.com/timestamp'));
$ltv->save('/archive/contract-2026.pdf');Error Handling
LTV operations throw typed exceptions: OcspException (responder unreachable), CrlException (download failed), or ChainBuildException (incomplete chain). All are under the Yeeefang\TcpdfNext\Pro\Security\Ltv namespace.
Next Steps
- PAdES Digital Signatures -- Signature creation at all PAdES levels.
- PDF/A-4 Archival -- Combine LTV with archival compliance.
- HSM Integration -- Hardware-based signing with LTV support.