A PDF you just signed is a B-B signature and nothing more. It proves who signed and that the bytes have not moved, but it carries no proof that the signer certificate was valid at signing time, so a validator years from now has to go looking for revocation data that may no longer exist. Closing that gap means writing OCSP responses and CRLs into the document-level Document Security Store, and in HotPDF that is one call: PopulatePAdESLTVEvidence walks every loaded signature, derives the revocation requests from the certificate set, executes them through a transport you supply, and writes the fetched material plus the CMS chain into the DSS. It returns the number of signatures whose evidence landed, or minus one when the document has no signature field at all
The design decision worth understanding before you use it is that the library never opens a socket. Every byte that arrives from the network arrives through a callback you wrote. That is not caution for its own sake; it is the only way this feature can work inside the environments that actually demand long-term validation
Why does the library refuse to do its own HTTP?
Because the places that require B-LT signatures are the places where a library cannot be trusted with the network. Signing services run behind authenticating proxies with corporate roots. Air-gapped signing tiers have no route to a responder and must be fed cached evidence. Audit regimes require that every outbound request be logged by the application, not buried in a dependency. And test suites need deterministic responses, which is impossible if the library dials out on its own
The transport is a plain function reference with a fixed shape, so the policy stays yours. HotPDF hands you a request record describing exactly what to fetch, including the content type and a response size cap, and you return the bytes plus a status
function FetchEvidence(const Request: THPDFSignatureEvidenceRequest;
Attempt: Integer; CancellationToken: THPDFCancellationToken;
out Response: TBytes; out RetryAfterMS: Cardinal;
out ErrorMessage: UnicodeString): THPDFSignatureEvidenceTransportStatus;
begin
RetryAfterMS := 0;
try
// Request.Kind says whether this is an OCSP POST or a CRL GET;
// Request.ContentType and Request.Body are already prepared,
// and Request.MaxResponseBytes is the cap you must honour
Response := HttpExchange(Request.URI, Request.ContentType,
Request.Body, Request.MaxResponseBytes);
Result := setsSucceeded;
except
on E: Exception do
begin
ErrorMessage := E.Message;
// setsRetry lets the retry policy back off; use
// setsPermanentFailure for a 404 or a bad URL
Result := setsRetry;
end;
end;
end;
// One-call B-B to B-LT upgrade for every signature in the loaded file
var
Pdf: THotPDF;
Upgraded: Integer;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.BeginIncrementalUpdate('signed.pdf');
Upgraded := Pdf.PopulatePAdESLTVEvidence(FetchEvidence,
THPDFSignatureEvidenceRetryPolicy.Default);
if Upgraded > 0 then
// Append-only save: the bytes the existing signatures cover
// are preserved verbatim
Pdf.SaveIncrementalUpdate('signed-lt.pdf');
finally
Pdf.Free;
end;
end;
Failures are per signature, not per document. A responder that times out for one signer skips that signer material and leaves the rest of the pass intact, which is the behaviour you want in a batch: partial evidence beats an aborted run, and the return value tells you how many signatures actually improved
The chain the CMS forgot to include
Revocation checking needs the issuer certificate, and a surprising number of signing stacks omit intermediates from the CMS container. The recovery route is the Authority Information Access extension, access method 1.3.6.1.5.5.7.48.2, which advertises a URL where the issuer certificate can be downloaded. HPDFFetchAIAIntermediates walks those URLs through the same transport, parses the DER out of each response, and returns only the certificates the CMS did not already carry, keyed by DER hash so duplicates and loops cannot spin
Two details decide whether this works against real certificate authorities. The first is encoding: CA endpoints serve the certificate as bare DER about as often as they serve it PEM armoured, and there is no reliable content type to distinguish them. The robust probe is textual, then structural. Look for the -----BEGIN CERTIFICATE----- marker, strip the armour and decode base64 if it is present, and in both paths confirm that the first byte of the result is $30, the DER tag for a SEQUENCE. The second is depth: a fetched intermediate can itself advertise an AIA URL for its own issuer, so the walk appends new candidates to the queue and completes chains that are two or three hops short. That has to be capped, which is what the MaxFetch parameter is for
What is a signature seed value, and why does it fail silently?
A seed value is a constraint the document author attaches to a signature field to tell the signer what kind of signature is acceptable: which SubFilter, which digest algorithm, which reasons, which minimum PDF version, whether revocation information must be embedded. It lives in an /SV dictionary on the field and is defined in ISO 32000-1 §12.7.5.5. HotPDF writes it with AttachPAdESSeedValue and checks it with CheckLoadedSignatureSeedValue, which returns True when the field is unconstrained or every present constraint passes, and on False names the first failing constraint through an output parameter you can put straight into an error message
The mechanism that makes seed values easy to get wrong is the /Ff flags entry described in §12.7.5.5.3. A set bit marks its constraint as required: a mismatch is an error and the signer must refuse. A clear bit marks the same constraint as a preference: the value filters what the UI should offer and nothing more. Two traps follow from that. First, /Ff lives inside the /SV dictionary, not on the widget annotation, so code that reads the field-level /Ff gets an empty answer forever and concludes that nothing is forced. Second, the bit assignments are not a simple run of one, two, four, eight; in HotPDF the writer emits 2 for SubFilter, 4 for MinVersion, 32 for AddRevInfo and 64 for DigestMethod. A reader that assumes sequential bits decodes every constraint as optional and passes every test except the one that matters
var
Violation: AnsiString;
begin
// Ask the field whether the profile we are about to sign with is allowed
if not Pdf.CheckLoadedSignatureSeedValue(0, 'ETSI.CAdES.detached',
'SHA256', 'Approved for payment', 1, Violation) then
raise Exception.Create('Signature field rejects this profile: ' +
String(Violation));
// Constraint satisfied: proceed with the signing pass
end;
The test that exposed the original decoding bug was not a positive test. It was the assertion that a forced mismatch must be rejected, and it is the only kind of test that can catch this class of defect: a decoder reading the wrong dictionary or the wrong bit positions produces "no constraints violated" for every input, which looks exactly like correct behaviour until you deliberately violate one
Where this sits on the LTV ladder
Four rungs, and each needs the one below it. B-B is the bare signature. B-T adds a trusted timestamp, which fixes the signing time so a validator knows which moment to evaluate revocation against. B-LT adds the revocation evidence to the DSS, which is what PopulatePAdESLTVEvidence automates. B-LTA adds document timestamps that are renewed before the previous one weakens, extending validity indefinitely; HotPDF exposes that as RenewPAdESLTATimestamp, which appends a new timestamp as an incremental revision and preserves every earlier signature, timestamp and DSS entry untouched
An incremental-update model is the only correct way to add evidence to a signed document, because rewriting the file would break the byte ranges the existing signatures cover. If you need to reason about what changed between revisions, and whether those changes are the sort a signature permits, that analysis is covered separately in the DocMDP and FieldMDP revision analysis. The signing pipeline itself, including certificate sources and byte-order pitfalls, is in the PAdES signing walkthrough, and the validation side is in verifying signatures on loaded documents
One practical warning about ordering. Collect evidence as soon as possible after signing, ideally in the same job. The responders that can answer for a certificate are online while the certificate is current and gone years later, so a document that leaves your pipeline as B-B may never be upgradable again. HotPDF runs as a native VCL component for Delphi and C++Builder, and the whole evidence pass is in-process apart from your own transport; the supported profiles are listed on the HotPDF Delphi PDF component product page