1

I have read many of the questions/answers about how to make a pdf ltv enabled using iText. Neither of them worked for me. I have a steam of pdf and I set a signature field which I then use in order to call signDetached method and sign the pdf. I use:

signer.signDetached(new BouncyCastleDigest(), pks, chain,
 Collections.singleton(crlClient), ocspClient, tsc,0, subfilter);

But nothing happened. I have read that you have to include all the certificates except from root. I add the chain of my private certificat (which I use so as to sign pdf), but I have not found a possible way include TSA's certificate.

I use iText version 7.X.

KeyStore ks = getKeyStore();
        Certificate[] chain = null;
        Enumeration<String> al = ks.aliases();
        for (Enumeration<String> l = al; l.hasMoreElements();) {
            String alias = (String) l.nextElement();
            chain = ks.getCertificateChain(alias);
        }
        PrivateKey pk = (PrivateKey) ks.getKey(ks.aliases().nextElement(), "******".toCharArray());
        IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
        OCSPVerifier ocspVerifier = new OCSPVerifier(null, null);
        OcspClientBouncyCastle ocspClient = new OcspClientBouncyCastle(ocspVerifier);
        String url = CertificateUtil.getCRLURL((X509Certificate) chain[0]);
        CrlClientOnline crlClient = new CrlClientOnline(url);
        try {
            signer.signDetached(new BouncyCastleDigest(), pks, chain, Collections.singleton(crlClient), ocspClient, tsc,
                    0, subfilter);

        } catch (Exception ex) {
            System.out.println("Tzizzzzzzzzzzzzzzz" + ex.getCause());
        }

private KeyStore getKeyStore()
            throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
        KeyStore ks = KeyStore.getInstance("pkcs12");
        ks.load(new FileInputStream("tsaPath"), "****".toCharArray());
        ks.load(new FileInputStream("p12Path"), "*******".toCharArray());
        return ks;
    }
Lefteris Bab
  • 787
  • 9
  • 19
  • *"I have read many of the questions/answers about how to make a pdf ltv enabled using iText. Neither of them worked for me."* - in which way did [this answer](https://stackoverflow.com/a/51675015/1729265) fail to work for you? – mkl Feb 13 '19 at 14:10
  • Becasue the signature is still not LTV enabled (Acrobat Reader DC) and at certificate details at Revocation tab it says: The selected certificate is considered valid because it does not appear in a Certificate Revocation List (CRL) obtained on-line. The CRL was signed by "ADACOM Class 1 Consumer Individual Subscriber CA - G2" on 2019/02/12 23:59:09 +02'00' and is valid until 2019/02/13 23:59:09 +02'00'. Click Signer Details to get more information on the source of the revocation information. – Lefteris Bab Feb 13 '19 at 14:43
  • Please share the PDF before and after applying `AdobeLtvEnabling`. Some limitations of that class are listed at the bottom of [that answer](https://stackoverflow.com/a/51675015/1729265). If one of those limitations is the issue, that class might be improved to lift that limitation. – mkl Feb 13 '19 at 14:47
  • I will try to show you the file, but I would like to find a pfx file that is not from my company. The self signed pfx don’t have the revoke part. So it is a bit difficult – Lefteris Bab Feb 13 '19 at 20:47
  • Well, if you share a replacement pdf, please make sure that ltv enabling fails with it for the same reasons as it does for your actual signed pdfs. – mkl Feb 14 '19 at 05:40
  • https://ufile.io/if9xb – Lefteris Bab Feb 14 '19 at 06:30
  • Just to mention that I want to sign it and make it LTV-enabled simultaneously – Lefteris Bab Feb 14 '19 at 06:54
  • *"Just to mention that I want to sign it and make it LTV-enabled simultaneously."* - that makes a huge difference. Because it is not necessarily possible to do so. (I assume by *simultaneously* you mean "in the same revision". – mkl Feb 14 '19 at 08:50
  • Yes, I get the stream of PDF from the report server and then i use signer.signDetached(....) method to sign it. I want the output of this proceedure to be a pdf that it is signed and LTV-enabled – Lefteris Bab Feb 14 '19 at 09:02
  • `signer.signDetached(....)` in general does not add the information required for LTV-enabling (at least it did not the last time I checked). Thus, I proposed adding the missing information in a second pass using the `AdobeLtvEnabling` helper. If that is no option for you, I cannot help easily enough (i.e. in the scope of an answer here). – mkl Feb 14 '19 at 09:53
  • I just could inspect your example files. It is not possible to LTV enable your example signature in general, cf. my answer. – mkl Feb 14 '19 at 12:57

3 Answers3

1

In case someone still has a problem with adobeLTV. Same as it was in itext5 and it still need to be done in itext7 to enable AdobeLTV, you need to create document security storage on your own and add within indirect reference information about your validation data /ocsp/crls/certs.

https://github.com/mkl-public/testarea-itext7/blob/master/src/main/java/mkl/testarea/itext7/signature/AdobeLtvEnabling.java

0

It is not possible to LTV enable your example signature in general.

First of all, your signer certificate is not from a CA trusted by Adobe Reader by default, i.e. the CA certificate is neither on the AATL nor on the EUTL. The PDF Reader will never call a signature "LTV-enabled" unless it somehow trusts the signer.

Furthermore, the signer certificate does not have any AIA (Authority Information Access) extension from which signing code could determine locations to retrieve the issuer certificate or revocation information from. The missing information makes automatic retrieval of certificates and of revocation information impossible without further ado.

Even if the CA was trusted, therefore, automatic LTV-enabling still would require custom code.


In the course of comments here (and in communication with iText support) it turned out that the provided example signature was not representative; on the other hand there were other relevant boundary conditions, and you eventually got to a routine creating LTV-enabled signatures in your use case.

Details on this routine can be found in your answer.

mkl
  • 90,588
  • 15
  • 125
  • 265
  • I am talking with the support of iText, so in case I find a solution I will post it – Lefteris Bab Feb 15 '19 at 07:20
  • For a conceptually different certificate there may be a solution. For the given certificate without explicit Adobe Reader configuration changes not. – mkl Feb 15 '19 at 12:07
  • Yes, you have to verify that your root certificate is trusted by Adobe, or you should change some settings to acrobat to check your windows truststore. I will soon post a mini project to github that creates a signature and makes it LTV enabled, using iText 7.1.5, without using any workarounds . I hope that this will help. – Lefteris Bab Feb 19 '19 at 07:05
  • *"you have to verify that your root certificate is trusted by Adobe"* - You don't necessarily trust the root certificate, sometimes you only trust an intermediary certificate because it is the issuer of a certain sub-CA with a policy adequate in your context. *"I will soon post a mini project to github that creates a signature and makes it LTV enabled, using iText 7.1.5, without using any workarounds ."* - I'm curious about it... ;) – mkl Feb 19 '19 at 07:54
  • If it works for you, I can post it as an answer: https://github.com/lmpampaletakis/demo-pdf As i promissed – Lefteris Bab Feb 25 '19 at 08:20
  • @LefterisBab I had a quick look at your code. An issue: In a comment to your question I remarked *'I assume by simultaneously you mean "in the same revision".'* I took the *'Yes'* at the start of your next comment as a confirmation of that because you did not otherwise react to that remark. – mkl Feb 25 '19 at 11:53
  • @LefterisBab But your code definitively doesn't sign and LTV-enable in the same revision, `SecurePDFImpl.sign` in the line `signer.signDetached(new BouncyCastleDigest(), pks, chain, Collections.singleton(crlClient), ocspClient, tsc, 0, subfilter);` creates one revision and in the line `ltvEnable(signer, baos, os, name, ocspClient, crlClient, tsc)` creates another one. My further comments relied on the assumption you wanted to sign and LTV-enable in a single revision. – mkl Feb 25 '19 at 11:55
  • When I say at once, I mean in the same request. Of course as you can see there are InputstSeams and OutputStreams used, but all in the same context. You cannot do it with another way. I say again that once means that i request a pdf and I get a signed, encrypted and ltv enabled PDF – Lefteris Bab Feb 25 '19 at 12:17
  • @LefterisBab Furthermore, your code uses `LtvVerification.addVerification`. As has been discussed in multiple q&a here, that method only adds validation related information for the certificates in the chain of the original signer certificate. It does not add any VRI for the signatures in time stamps or the already added VRI. Thus, your code only works as desired if the time stamp signer certificate is immediately trusted by Adobe and the signer certificates of the VRI are at least implicitly trusted (which e.g. is the case for CRLs signed by the CA certificate). By far no universal solution... – mkl Feb 25 '19 at 12:17
  • You include ther certificates inside the jks. As iText says you have to include all the chain except the root. The root should be trusted from adobe, or you should have stored it at your windows certificate store (in that case you should configure acrobat reader to look up for windows certificates). So far I have not seen such a solution, using pure iText 7, without workarrounds. That's why I uploaded on GitHub – Lefteris Bab Feb 25 '19 at 12:22
  • Your code only adds the chain of the signer certificate. For some CAs this suffices, for some not (for the reasons mentioned above). Ok, the bottom line is that I thought at first you were looking for a generic solution (because you didn't share any information on the specific CA and setups) and then (after you shared those example signed PDFs) that you were looking for something impossible (those sample signer certificates won't sign LTV-enabled with your code either). But in the end you wanted to make do with a specific CA the properties of which were unclear. – mkl Feb 25 '19 at 12:34
  • You were the one that suggested me the: https://stackoverflow.com/questions/51639464/itext7-ltvverification-addverification-not-enabling-ltv/51675015#51675015 . That was a workarraound. I provided a final solution. So I suppose that you had understood what I was asking and wondering. – Lefteris Bab Feb 25 '19 at 12:46
  • @LefterisBab *"You were the one that suggested me the ..."* - Yes, I suggested that (and I still would like to know why it does not work; you only quoted the Adobe outputs but were not allowed to share actual test files, so this will likely remain a mystery). In comments thereafter, though, the misunderstandings explained above came up. *"That was a workarraound. I provided a final solution."* - as already explained, there are some specific requirements for this "final solution" to work at all. Also you did not claim that helper class I pointed to was a workaround, you claimed it didn't work. – mkl Feb 25 '19 at 13:57
  • First and foremost signature time stamps are ignored so that was the main reason I suppose that my PDF was not LTV enabled, cause I tried to use. So it was not only a workarround but it did not work for me too. I will not continue as the difference is obvious. – Lefteris Bab Feb 26 '19 at 06:09
  • *"First and foremost signature time stamps are ignored"* - ah ok. That's a known deficit, see the answer itself. And can easily be resolved. By the way, signature time stamps also are ignored in your code. Only by addition of an externally provided certificate Adobe reader is satisfied. Nonetheless you might want to create an answer here with your code. While there are a number of shortcomings, there likely are numerous other people with similar requirements and setups as you to make that worthwhile. – mkl Feb 26 '19 at 06:58
  • I agree with you. I think that we cleared out this issue. Just to know, one of my big problems was that iText 7 has not examples as iText 5 becasue it is still new – Lefteris Bab Feb 26 '19 at 07:07
  • Concerning your answer I'd propose you add some pivotal code (code important in addition to that present in itext 7 samples). In its current state it might be taken for a link-only answer, and link-only answers are not so well received here. – mkl Feb 26 '19 at 08:44
0

After some hours, I figured out a solution. Just to be clear, that Adobe has it's own truststore, so you have to either use one of their certificate or to use the truststore of windows and configure AC Reader accordingly and add the root certificate there. As all have mention you should include all the certification chain inside your PDF document. You can visit my GitHub project in order to see a working example that signs a PDF document, encrypt it with a private key and make it ltv-enabled, using iText 7 using timepstap from ERMIS.

Making ltv enabled sample:

private void ltvEnable(PdfSigner signer, ByteArrayOutputStream baos, OutputStream os, String name,
            OcspClientBouncyCastle ocspClient, CrlClientOnline crlClient, CustomTSAClient tsc) {
        ByteArrayInputStream signedPdfInput = new ByteArrayInputStream(baos.toByteArray());
        try {
            PdfReader pdfReader = new PdfReader(signedPdfInput);
            PdfDocument document = new PdfDocument(pdfReader.setUnethicalReading(true), new PdfWriter(os),
                    new StampingProperties().useAppendMode());
            LtvVerification ltvVerification = new LtvVerification(document);
            ltvVerification.addVerification(name, ocspClient, crlClient, LtvVerification.CertificateOption.WHOLE_CHAIN,
                    LtvVerification.Level.OCSP_CRL, LtvVerification.CertificateInclusion.YES);
            ltvVerification.merge();
            document.getCatalog().getPdfObject().getAsDictionary(PdfName.DSS).getAsArray(PdfName.Certs)
                    .add(new PdfStream(
                            IOUtils.toByteArray(getClass().getClassLoader().getResourceAsStream("HPARCA_CA.cer"))));
            document.close();
            pdfReader.close();

        } catch (IOException | GeneralSecurityException e) {
            LOG.error("Error while making signature ltv enabled");
        }
    }

Tricky part parameters:

OCSPVerifier ocspVerifier = new OCSPVerifier(null, null);
OcspClientBouncyCastle ocspClient = new OcspClientBouncyCastle(ocspVerifier);
CrlClientOnline crlClient = new CrlClientOnline();
Lefteris Bab
  • 787
  • 9
  • 19