Append new Time Stamps for Archiving to PAdES-B-LTA

Hi,

is it possible to append new time stamp to document that is in PAdES-B-LTA format? I need to periodically apply new timestamps to the existing signature’s validation data to ensure it remains verifiable even if underlying cryptographic algorithms become vulnerable in the future.

Regards,

Rade

Hi Rade,

Yes, it is possible.

Here is an example code showing how to append a new timestamp to the PDF file whose signature is PAdES B-LTA:

using (var document = PdfDocument.Load("PAdES B-LTA.pdf"))
{
    // Add an invisible signature field to the PDF document that will hold the document timestamp.
    var timestampField = document.Form.Fields.AddSignature();

    // Append a timestamp created by freeTSA.org Time Stamp Authority.
    var timestamper = new PdfTimestamper("https://freetsa.org/tsr");

    // Initiate timestamping of a PDF file with the specified timestamper.
    timestampField.Timestamp(timestamper);

    // Finish timestamping of a PDF file.
    document.Save();
}

The input file of this example code was taken from the example PDF Advanced Electronic Signatures (PAdES) in C# and VB.NET

Regards,
Stipo

Hi,

Thank you very much for the quick and helpful response—and especially for providing a code example!

I really appreciate your support. That said, I’d like to kindly ask for clarification on a few points to ensure I’m using the API correctly for long-term PAdES compliance:

  1. Document Timestamp vs. Signature Timestamp:
    In the context of PAdES B-LTA, the archival timestamp must be a document timestamp that covers the entire current state of the PDF (including all previous signatures and timestamps). Does timestampField.Timestamp(timestamper) indeed produce a document timestamp (as defined in ETSI EN 319 142-1), and not just a signature-time timestamp?

  2. Incremental Update Preservation:
    To maintain PAdES LTA validity, each new timestamp must be added as an incremental update, preserving all prior revisions. Does document.Save() in this scenario guarantee that the file is saved incrementally (i.e., without flattening or rewriting previous content)?

  3. TSA Requirements:
    Are there any specific requirements for the TSA service (e.g., hash algorithm support, certificate chain inclusion) to ensure the resulting timestamp is fully compliant with PAdES B-LTA validation rules?

  4. PDF/A Compliance:
    For long-term archival, we also aim to keep the document compliant with the PDF/A standard (e.g., PDF/A-2b or PDF/A-3b). Does adding a document timestamp via GemBox.Pdf preserve PDF/A conformance? If the original file is PDF/A-compliant, will the resulting updated file remain valid PDF/A after the timestamp is appended?

I’m planning to use this mechanism for periodic re-timestamping (e.g., annually) to protect against cryptographic obsolescence, so it’s critical that each new timestamp properly extends the validation chain while maintaining both PAdES B-LTA and archival format requirements.

Thanks again for your time and assistance!

Best regards,
Rade

Hi Rade,

  1. Yes, timestampField.Timestamp(timestamper) produces a document timestamp. Signature timestamp would be produced if the timestamper is set to the PdfSigner.Timestamper property, like in the PDF Advanced Electronic Signatures (PAdES) in C# and VB.NET example.
  2. Yes, document.Save() guarantee that the file is saved incrementally, otherwise (with full re-save of the entire file) all previous signatures would become invalid.
  3. As far as I know, there are no explicit requirements, except maybe that the SHA-1 hash algorithm should not be used. The timestamper certificate chain and revocation information (OCSP response or CRL) can be downloaded and added to the document’s security store before the actual timestamping (for offline signature validation), but that is not required, as far as I know.
  4. Adding a document timestamp via GemBox.Pdf should preserve PDF/A conformance. I recommend that you check this with a PDF/A validation tool. If it reports that PDF/A conformance has been violated, contact us with the problematic file, and we will investigate it further.

Regards,
Stipo

Hi Stipo,

Thank you again for the clarification.

Regarding your note that the timestamper certificate chain and revocation information (OCSP response or CRL) can be downloaded and added to the document’s security store before timestamping: do you have any recommended approach or best practice on how to do this using GemBox.Pdf?

Best regards,
Rade

Hi Rade,

Here is a code snippet that shows how to download and add the timestamper certificate chain and revocation information (OCSP response or CRL) to the document’s security store after timestamping:

using (var document = PdfDocument.Load("PAdES B-LT.pdf"))
{
    // Add an invisible signature field to the PDF document that will hold the document timestamp.
    var timestampField = document.Form.Fields.AddSignature();

    var timestamper = new PdfTimestamper("https://freetsa.org/tsr");

    // Initiate timestamping of a PDF file with the specified timestamper.
    timestampField.Timestamp(timestamper);

    // Save any changes done to the PDF file that were done since the last time Save was called and
    // finish timestamping of a PDF file.
    document.Save();

    // Download validation-related information for the timestamp and embed it in the PDF file.
    // This will make the signature "LTV enabled".
    document.SecurityStore.AddValidationInfo(timestampField.Value);

    document.Save();
}

The input for this code is the file created using the example at PDF Advanced Electronic Signatures (PAdES) in C# and VB.NET.
The signature in the input file is at the B-LT level and is promoted to the B-LTA level by the code snippet.

It is irrelevant if adding of the timestamper certificate chain and revocation information is done before or after timestamping, but for the GemBox.Pdf workflow, it is easier to do it after timestamping because then the certificate of the timestamp signer can be retrieved from the timestamp.

But since the revocation information will likely be valid (actual) for a far shorter time than the document timestamp (that is actual until the next timestamp is appended), I would not recommend this practice. After revocation information is no longer valid, clients (Adobe Reader, etc.) will still have to download the actual revocation information, and the embedded revocation information no longer serves its purpose and just bloats the file.

Regards,
Stipo

Hi Stipo,

Thank you for the explanation and the code snippet — much appreciated.

Best regards,
Rade

Hi Stipo,
To avoid opening a new topic, I’ll post my question here.

When adding a new timestamp, the code you provided calls the timestamp server twice instead of once.

The first call happens when executing this line:

timestampField.Timestamp(timestamper);

and the second call occurs during:

document.Save();

This is causing an issue for me because the timestamp service is charged per request, so each additional call results in extra cost.

The same thing happens when I try to generate the PAdES B-LTA level. Instead of calling the TSA server twice, the code calls it three times.

I also tested this using your example code ( PDF Advanced Electronic Signatures (PAdES) in C# and VB.NET ), and the same behavior occurs there as well.
Is there a way to prevent these unnecessary calls to the TSA server, so I can reduce the number of requests and save on TSA usage costs?

Best regards,
Rade

Hi Rade,

The timestamp service is called twice because, when signing a PDF file, we must reserve a “hole” in the PDF where the signature will be inserted, and the signature is calculated from the PDF file’s hash, excluding that “hole”.

The reserved “hole” must be large enough to accommodate the entire signature in the CMS format, but not so large that the space in the “hole” after the signature is wasted.

CMS signature includes additional information, beyond just the raw cryptographic signature, such as the signer’s certificate, certificate chain, revocation information, timestamp, etc.

To properly estimate the CMS signature length, if the signature will also contain a timestamp, GemBox.Pdf will initiate a dummy timestamp request just for the purpose of finding the length of the timestamp that is extended by the extra 32 bytes of padding. PdfTimestamp.EstimatedTimestampTokenLength (a property that is available only if you are deriving from a PdfTimestamper) caches and returns that value. Because the value of this property is cached, the timestamp service is called 3 times instead of 4 times in the PDF Advanced Electronic Signatures (PAdES) in C# and VB.NET example:

  1. To find the estimated timestamp token length that is then cached.
  2. To timestamp the hash of the raw signature value.
  3. To timestamp the hash of the PDF file (excluding the “hole” for the document timestamp signature) when adding a document timestamp signature.

If you plan to use the same timestamp service, its timestamp token length should remain relatively stable, so you can avoid an extra call to estimate the timestamp token length by providing a hardcoded estimated timestamp token length.

You do this by deriving from the PdfTimestamper and providing a hardcoded value of the estimated timestamp token length, like in the following code snippet:

class MyPdfTimestamper : PdfTimestamper
{
    private readonly int estimatedTimestampTokenLength;

    public MyPdfTimestamper(string address, int estimatedTimestampTokenLength) : base(address)
    {
        this.estimatedTimestampTokenLength = estimatedTimestampTokenLength;
    }

    protected override int EstimatedTimestampTokenLength => this.estimatedTimestampTokenLength;
}

To find out the estimated timestamp token length to be hardcoded, you can first use the following PdfTimestamper implementation:

class MyPdfTimestamper : PdfTimestamper
{
    public MyPdfTimestamper(string address) : base(address)
    {
    }

    protected override int EstimatedTimestampTokenLength
    {
        get
        {
            var value = base.EstimatedTimestampTokenLength;

            return value;
        }
    }
}

with the breakpoint on the return value; statement.

Once you get the estimated timestamp token value, hardcode it, and thus reduce the number of calls to the timestamp service by one for each PdfTimestamper(-derived) instance by using MyPdfTimestamper instead of PdfTimestamper in your code.

Regards,
Stipo