1

I'm generating a PDF document with signature and I want it to be LTV enabled. For this, I sign the PDF when creating it and then I add the second version containing the DSS with the validation related informations (VRI). As I found in some articles, I need to add the Certificate chain (without the root certificate - Authority) and the Certificate Revocation List (CRL). In my case, both will have 2 elements. After that I add the entry for the VRI which is a SHA-1 hash of the signature content (found in the first PDF verion in the /Contents ) with the value which refers the Certificates and CRL mentioned above.

For both the certificates and the revocation list elements I use the raw bytes stream of the content.

This is the Acrobat Reader message

Here is my PDF sample

Edit

The way I obtain the CRL information is uising WynCrypt like this:

//Retrieve chained certificate
if(!CertGetCertificateChain(hChainEngine, pSignerCert, pTime, hAdditionalStore, &chainPara, dwFlags, NULL, &ppChainContext))
    return NULL;

//first cert in chain is the end cert; last one is the root cert
for(int i = 0; i < ppChainContext->cChain; ++i)
{
    PCERT_SIMPLE_CHAIN simpleChain = ppChainContext->rgpChain[i];

    for(int j = 0; j < (int)simpleChain->cElement - 1; j++)//do not include root certificate
    {
        PCERT_CHAIN_ELEMENT chainElement = simpleChain->rgpElement[j];

        if(chainElement->pCertContext)
        {   
            //the certificate bytes
            byte* certBytes =chainElement->pCertContext->pbCertEncoded
        }

        if(chainElement->pRevocationInfo && chainElement->pRevocationInfo->pCrlInfo)
        {
            PCCRL_CONTEXT crlContext = chainElement->pRevocationInfo->pCrlInfo->pBaseCrlContext;//get revocation context

            //the bytes that will be written in PDF
            byte* crlBytes = crlContext->pbCrlEncoded;
        }
    }
}
  • When creating a LTV enabler utility class myself, trial and error suggested that Adobe requires the presence of a time entry in the final VRI dictionaries, see the section "Patching `LtvVerification`" in [this answer](https://stackoverflow.com/a/51481392/1729265). – mkl Feb 26 '20 at 12:42
  • I don't really understand that. How can you have a time entry in the VRI. The documentation says that VRI entries are SHA-1 hashes of the Contents<> section – Petru Avramescu Feb 26 '20 at 14:25
  • I meant the dictionaries those keys point to. – mkl Feb 26 '20 at 22:03
  • Those keys point to dict like 27 0 obj << /CRL 25 0 R /Cert 97 0 R >> endobj – Petru Avramescu Feb 27 '20 at 08:48
  • What @mkl said is that you need a /TU entry in this object 27 0 obj << /CRL 25 0 R /Cert 97 0 R /TU (datetimevaluehere)>> endobj – iPDFdev Feb 27 '20 at 12:43
  • I see. The thing is that I have also signed my PDF with a signing service a found on the internet (DocuSign) to compare their structure with mine. They don't have this TU, but their PDF is LTV enabled. – Petru Avramescu Feb 27 '20 at 12:57
  • 1
    The VRI entries are merely a convenience to enable faster lookup it, and its entries, are not actually required. Ref: [ETSI TS 102 778-4](https://www.etsi.org/deliver/etsi_ts/102700_102799/10277804/01.01.02_60/ts_10277804v010102p.pdf). As long as the certs and ocsp/crl information is correct in the DSS it should work and I have it working in our tests for ABCpdf without the VRI. Try extracting the objects as hex and paste them into [/lapo.it/asn1js/](https://lapo.it/asn1js/) to see if they can be parsed and that they relate to the correct certificate(s) – Peter G Feb 27 '20 at 13:57
  • 1
    *"They don't have this TU, but their PDF is LTV enabled"* - well, I can only say that trial and error seemed to indicate that it was required - I reduced an LTV enabled file piece by piece to resemble a not LTV enabled one I had created before, and when removing the **TU** it stopped being LTV enabled. But probably that **TU** is only required under certain circumstances, or probably it is not required anymore... – mkl Feb 27 '20 at 21:32
  • SOLUTION -------- It's the same that worked for this issue: [Solution](https://stackoverflow.com/questions/60432684/how-do-you-encode-the-certificate-revocation-list-crl-stream-bytes-in-pdf/60547839#60547839) – Petru Avramescu Mar 05 '20 at 14:43

3 Answers3

4

The term "LTV enabled"

As far as I know, there is no formal specification of the meaning of the term "LTV enabled". There are some non-normative descriptions thereof, in particular:

  • Leonard Rosenthol (PDF Architect & Principal Scientist at Adobe) once characterized it as

    LTV enabled means that all information necessary to validate the file (minus root certs) is contained within.

    (iText mailing list on Jan 10, 2013)

  • Another Adobe employee, Steven.Madwin, describes the implementation as

    As part of the validation process [Acrobat] figures out if it has to go online to download revocation information, or, is all of the revocation information embedded in the PDF file. At this point it knows what it's going to say in the Signature Navigation Panel. If it had to download data then the signature is not LTV enabled, but if all of the revocation collateral is in the file then the signature is LTV enabled.

    (Adobe support forums on Sep 24, 2013)

Thus, the meaning of the term "LTV enabled" depends on implementation details of the signature validation algorithms of Adobe Acrobat (which are closed source and not necessarily fixed) and on the underlying configurations. You can read me ranting about this in multiple older stack overflow answers...

Nonetheless, the mechanisms underneath these implementation details are not completely arbitrary, they essentially form a profile (albeit a proprietary, closed, and probably even changing one) of the existing published specifications on this topic, in particular RFCs.

In particular it is fairly clear what you should do for a good chance to have your signature marked "LTV enabled", add all information that a validator may possibly need in the validation process, in particular

  • Add all intermediary certificates from the signer certificate to a certificate trusted by Adobe. If you are not sure which certificates are trusted, add all certificates up to the root certificate. If you know any of those certificates to be cross-signed by another CA, add the certificates of all those possible chains.
  • For all those certificates (except root certificates) retrieve revocation information (CRLs or OCSP responses) and add them, too.
  • For each added CRL and OCSP response determine its respective signer certificate, add that certificate and the certificates in its chain to the document to, retrieve and add revocation information for them (unless they are root certificates, or certificates with the id-pkix-ocsp-nocheck extension, or you already have revocation information for them) and so forth.

One challenge remains, though, and that is determining how exactly to add all those information to your PDF.

If you know the signer certificate before signing, you can add all the certificates to the certificate store in the signature container to create and all the revocation data to the signed adbe-revocationInfoArchival attribute of the SignerInfo therein.

If you don't, you can put those certificates and revocation information into the PAdES document security store (DSS), i.e. into special structures in an incremental update of the signed PDF. This DSS is not yet defined in ISO 32000-1; it has originally been defined in ETSI technical specifications (ETSI TS 102 778-4) and later norms (ETSI EN 319 142-1), and it has been adopted into the current PDF specification ISO 32000-2.

Why your PDF signature is not LTV enabled

Your PDF uses the DSS to store the certificates and revocation information but there are shortcoming in it.

As already explained by Peter G in his answer, your PDF's DSS in the CRLs and CRL arrays does not contain actual CRLs.

The objects in there are not simply OCSP responses either as Peter G said but instead OCSP responses wrapped into some other structure. The actual OCSP response in those objects starts at offset 160...

I would guess your code in that crlContext->pbCrlEncoded buffer contains some wrapper for arbitrary revocation information and you must first parse it to see which type it actually is and then unwrap that actual revocation information object and embed it according to its type. I don't know WynCrypt, so this is pure guesswork...

Optional elements in the DSS

Two years ago I built a LTV-enabler, too. Back then experiments suggested that Adobe Acrobat requires certain DSS elements which are specified as optional, at least under certain circumstances: I LTV-enabled a PDF using Adobe Acrobat and reduced that PDF step-by-step towards something I built. It turned out that the VRI DSS subsection and the TU entries therein were necessary, removing either made the file not LTV-enabled.

I now used my that LTV-enabler (actually a variant that can be given extra certificates) to LTV-enable your PDF. This worked. Out of interest I also reduced this LTV-enabled PDF. Interestingly, I could remove TU and even VRI without losing the LTV-enabled status.

Thus, either Adobe Acrobat has changed to not require those elements in general anymore or the file I started with in my former experiments was a somewhat special case requiring extra data while they are not required in other cases.

mkl
  • 90,588
  • 15
  • 125
  • 265
  • #mkl. I also noticed that you can get rid of the VRI and the PDF will remain LTV enabled so I think that my problem sticks around the CRLs streams. I'm a little bit buffled tho. The documentation of WinCrypt is not very detailed. Can you tell me how to take the stream (FlateDecode compressed or not) and convert it so I can parse it in the /lapo.it/asn1js/? So I can try some changes in code. – Petru Avramescu Mar 02 '20 at 11:48
  • 1
    *"Can you tell me how to take the stream (FlateDecode compressed or not) and convert it so I can parse it in the /lapo.it/asn1js/"* - You mean taking it from an already produced PDF for analysis? The easiest way is to use a browser for PDF internals which allows saving of stream contents; I usually use [iText RUPS](https://itextpdf.com/en/products/rups) or [PDFBox PDFDebugger](https://pdfbox.apache.org/2.0/commandline.html#pdfdebugger). Alternatively any general purpose PDF library should allow implementing a tool that opens a PDF, visits the DSS structure, and saves CRLs (and other streams). – mkl Mar 02 '20 at 12:07
  • @mkl Thanks for improving the answer - there's quite a learning for this stuff so hopefully it helps someone – Peter G Mar 04 '20 at 09:18
1

Just had a quick look and objects 15 and 16 are OCSP responses but you are adding them as CRLs:

Stream Object 15

Stream Object 16

This ASN.1 Decoder is very handy!

In my source viewer the DSS dictionary (Object 21) is:

<<
/CRLs 19 0 R
/Certs 20 0 R
/VRI 18 0 R
>>

19 points to the Array atom: [15 0 R 16 0 R]

Again VRI is not necessary for LTV it is currently basically an optimisation (see Appendix A1 in ETSI TS 102 778-4 which is basically taken from the PDF 2.0 specification). If you use it and add a timestamp (/TS entry) Adobe does not currently even display it correctly. In the VRI the TU/TS is also entirely optional and does not affect LTV validity (ibid).

Peter G
  • 147
  • 1
  • 10
  • That is weird and it might be the problem. How did you get this informations for specific objects in the pdf? – Petru Avramescu Feb 27 '20 at 14:59
  • If you download [ABCpdf](https://www.websupergoo.com/abcpdf-download.aspx) there's an example project called ContentExtract – Peter G Feb 27 '20 at 15:42
  • Please check my edit. Do you see why whould I obtain OCSP info instead of CRL info? – Petru Avramescu Feb 27 '20 at 16:14
  • @PetruAvramescu Not for C++ Wincrypt APIs I'm afraid. There must be flag somewhere. However if you just change the CRLs to OCSPs in the DSS dictionary it should work. I think Acrobat will ignore an invalid VRI but your could change that too – Peter G Feb 27 '20 at 16:38
  • So you say that OCSPs are equivalent to CRLs? I tried to do this and it still doesn't work.. I also removed the /Filter /FlateDecode from the OCSP dictionary. I only left the /Length attribute. Still not LTV Enabled – Petru Avramescu Feb 27 '20 at 16:55
  • *"Appendix A1 in ETSI TS 102 778-4 which is basically taken from the PDF 2.0 specification"* - it's actually the other way around, pdf 2 copied from etsi. There is a reason for the "ETSI" in the PAdES subfilters. – mkl Feb 27 '20 at 21:23
  • 2
    *"In the VRI the TU/TS is also entirely optional and does not affect LTV validity (ibid)."* - it does not affect LTV validity. Nonetheless Adobe may require such entries for their proprietary term "LTV enabled", at least under certain circumstances. That's at least what my experiments in 2018 seemed to indicate. Such requirements of course may have changed.. – mkl Feb 27 '20 at 22:37
  • https://wetransfer.com/downloads/6a926b994e800c61be89b1a682c0718920200228082606/754389 Here is the PDF that I compared with. It doesn't have TU but it is LTV enabled. The structure is also very similar to my file. – Petru Avramescu Feb 28 '20 at 08:26
  • @PetruAvramescu When I open that [template.pdf](https://wetransfer.com/downloads/6a926b994e800c61be89b1a682c0718920200228082606/754389) in Adobe Reader (2019.012.20040), it shows me ["not LTV enabled"](https://i.stack.imgur.com/YXY4s.png). ("LTV enabled" is a proprietary Adobe term and depends on their exact validation policy and on security settings of your Adobe Reader installation, so different outputs in this regard are to be expected.) – mkl Feb 28 '20 at 08:46
  • I verified on different machines and it pops me with a message like "Do you wanna download certificates for a better experience". Something like that. It probably refers to the Authorities that he needs. I accepted it and the document is LTV enabled. What you are saying is strange because if Acrobat Reader can change it's policy at any other version, fact that will make a file not being LTV anymore, how is that Long Term Validation? – Petru Avramescu Feb 28 '20 at 09:17
  • @PetruAvramescu I assume that that certificate *download* also includes adding them as *trust anchors*. If they are trust anchors (and not merely intermediary certificates in the certificate path to a trust anchor), then Adobe Reader does not require revocation information for them anymore (they are trusted after all), so there are less requirements for being "LTV enabled". Alternatively they may have installed slightly different versions of those certificates than provided via the normal download address, probably with different OCSP/CRL addresses... – mkl Feb 28 '20 at 12:21
  • *"What you are saying is strange because if Acrobat Reader can change it's policy at any other version, fact that will make a file not being LTV anymore, how is that Long Term Validation?"* - Adobe certainly will try not to change their policy in a way rendering signatures formerly marked "LTV enabled" not LTV enabled anymore. But they could. Furthermore, if you change trust anchors an your machine, you can get signatures marked "LTV enabled" on your system but not on others or the other way around. – mkl Feb 28 '20 at 12:32
0

SOLUTION

It's the same solution that worked for this issue: Another issue