Skip to content
Sign and LTV Enable in One Revision

Sign and LTV Enable in One Revision

Signing and LTV enabling normally take two revisions, because the per-signature VRI entry is keyed on the signature contents and those are only known once the revision has been written. LTV.EnableChain sidesteps that by writing the certificates and revocation data into the global part of the DSS, which a validator may use for any signature in the document. That fits in the same revision as the signature.

One revision, EnableChainTwo revisions, EnableAll
Validation data scopeGlobal DSS, any signatureVRI entry for the signature, plus global
Chain sourceOnly what you pass inExtracted from the signature, plus what you pass in
Covered by the signatureYesNo, needs a document timestamp to protect it
Revisions in the output12

Pick this form when the output has to be a single revision, or when you want the validation data itself protected by the signature. Otherwise the second-revision form produces the more precise result.

Doing it

if err = appender.Sign(1, field); err != nil {
    return err
}

ltv, err := model.NewLTV(appender)
if err != nil {
    return err
}

if err := ltv.EnableChain(certChain); err != nil {
    return err
}

return appender.WriteToFile(outputPath)

Both operations act on the same appender and only the write has to come last. EnableChain never looks at the signature, so its position relative to Sign makes no difference.

certChain has to start with the signing certificate. The client walks up from chain[0], downloading any issuer it cannot find in what you passed, and stops at the first self-signed certificate. Put the root first and the walk terminates immediately, leaving intermediates out. The example builds the slice from the certificate in the PKCS12 file and then appends the issuers decoded from the optional PEM file.

Limitations

Nothing is extracted from the signature here. EnableChain passes no signature certificates through, so an empty or nil chain fails with ErrSignNoCertificates, “could not retrieve certificate chain”, even on a perfectly good signature.

No VRI entry is written, so a validator has to decide which of the global certificates and responses apply to which signature. With one signature that is unambiguous; with several signed at different times it is less so.

Everything in the LTV enable guide about silently skipped OCSP and CRL requests applies here too: fetch failures are logged at debug level and the call still returns nil.

Run the example

Everything happens in main: the PKCS12 file is decoded, the chain assembled, the document signed with sighandler.NewAdobePKCS7Detached, and the DSS filled in before the single write.

git clone https://github.com/unidoc/unipdf-examples.git
cd unipdf-examples/signatures/ltv
go run pdf_sign_ltv_one_revision.go cert.p12 password input.pdf output.pdf [extra_certs.pem]

If this is your first time using UniPDF, follow the getting started guide to create an API key and set up your development environment.

View the full source
Last updated on