0

I'm new to iText 7, I've tried adding ltv information to existing signature by using addLtv() method (code provided below)...If I understand right, this method adds crl or ocsp parameters to existing signatures or timestamps and then timestamps the document, but pdf document that is generated is not ltv enabled. However, I am able to generate ltv enabled signature if I sign document with ocsp or crl list in the first place, that leads me to believe that this issue is not related to some certificate missing or not added properly. So the addLtv() method, for some reason does not work for me. I hope I'm making sense :D Any help or suggestion is greatly apriciated :)

    private void addLtv(String src, String dest, IOcspClient ocsp, ICrlClient crl, ITSAClient tsa) throws Exception {
    PdfReader r = new PdfReader(src);
    FileOutputStream fos = new FileOutputStream(dest);
    PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(dest));
    PdfSigner ps= new PdfSigner(r, fos, true);

    LtvVerification v = new LtvVerification(pdfDoc);
    SignatureUtil signatureUtil = new SignatureUtil(pdfDoc);

    List<String> names =   signatureUtil.getSignatureNames();
    String sigName = names.get(names.size() - 1);

    PdfPKCS7 pkcs7 = signatureUtil.verifySignature(sigName);

    if (pkcs7.isTsp()) {
        v.addVerification(sigName, ocsp, crl,
                LtvVerification.CertificateOption.WHOLE_CHAIN,
                LtvVerification.Level.CRL,
                LtvVerification.CertificateInclusion.YES);
    }
    else {
        for (String name : names) {
            v.addVerification(name, ocsp, crl,
                    LtvVerification.CertificateOption.WHOLE_CHAIN,
                    LtvVerification.Level.OCSP,
                    LtvVerification.CertificateInclusion.YES);
            v.merge();
        }
    }
    ps.timestamp(tsa, null);
}
mkl
  • 90,588
  • 15
  • 125
  • 265
Igor Sabo
  • 55
  • 1
  • 1
  • 5
  • *"If I understand right, this method adds crl or ocsp parameters to existing signatures or timestamps and then timestamps the document, but pdf document that is generated is not ltv enabled."* - What you describe before the comma is *not the same* as LTV-enabling. The Adobe-specific term "LTV-enabled" usually does not get along well with the finishing time stamp of it. – mkl Mar 20 '17 at 09:27
  • @mkl Thank you for for answer, I still have no luck in making timestamp itself ltv enabled. I tried using the addLtvNoTS() method from [link](http://developers.itextpdf.com/question/how-enable-ltv-timestamp-signature) but I think the code provided is out of date. Could you please point me to the location where I can get updated version of this method? – Igor Sabo Mar 23 '17 at 13:41
  • I have not yet ported that `addLtvNoTS()` method to iText 7. I'll try and find some time to look into that. – mkl Mar 23 '17 at 15:52

1 Answers1

0

The conceptual issue in your code is that after adding LTV information you want to finalize the process by time stamping. While this is what you would want to do with a PDF which already is in a LTV workflow, it is not what you want to do with a PDF all signatures of which you want Adobe Reader to declare as "LTV-enabled".

(One can consider Adobe's term "LTV-enabled" to mean "ready to enter a LTV workflow," i.e. not yet actually being in a LTV workflow but including all validation information required to enter it without any further ado.)

There are other issues, too, in your method, e.g. you create two separate objects which write to dest, the PdfSigner ps via fos and the PdfDocument pdfDoc via its PdfWriter. Eventually you'll either find the output of only one of these objects in the file or a mish-mash of both.

Thus, here is a working port of my old iText 5 method addLtvNoTS (from this answer) to iText 7:

void addLtvNoTS(InputStream src, OutputStream dest, IOcspClient ocsp, ICrlClient crl, LtvVerification.Level timestampLevel, LtvVerification.Level signatureLevel) throws IOException, GeneralSecurityException 
{
    PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(dest), new StampingProperties().useAppendMode());

    LtvVerification v = new LtvVerification(pdfDoc);
    SignatureUtil signatureUtil = new SignatureUtil(pdfDoc);

    List<String> names = signatureUtil.getSignatureNames();
    String sigName = names.get(names.size() - 1);

    PdfPKCS7 pkcs7 = signatureUtil.verifySignature(sigName);

    if (pkcs7.isTsp())
    {
        v.addVerification(sigName, ocsp, crl, LtvVerification.CertificateOption.WHOLE_CHAIN,
                timestampLevel, LtvVerification.CertificateInclusion.YES);
    }
    else
    {
        for (String name : names)
        {
            v.addVerification(name, ocsp, crl, LtvVerification.CertificateOption.WHOLE_CHAIN,
                    signatureLevel, LtvVerification.CertificateInclusion.YES);
        }
    }

    v.merge();
    pdfDoc.close();
}

(EnableLtv method addLtvNoTS)

As you can see I made the LtvVerification.Level values for time stamps and signatures method parameters.

This is because iText's method LtvVerification.addVerification only adds LTV information for the immediate PDF signatures and document timestamps, not for already embedded or now added OCSP response or CRL signatures.

Often this is no problem, often certificates used for signing OCSP responses are marked in a way that indicates that no revocation checks are required, and certificates used for signing CRLs usually are the implicitly trusted CA certificates themselves.

In case of my test signature, though, the OCSP responses are signed by signatures which do require revocation checks. To make things work without significant additional coding, I used CRLs all over and for that introduced the parameters.

Actually I even had to give the CRL URL explicitly to the CrlClientOnline because of iText by default only using the first CRL distribution point in a certificate and at the same time not supporting LDAP URLs.

The bottom line: You also may have to tweak your code around current iText limits or be the one to improve the iText code itself to reliably produce LTV-enabled PDFs given arbitrary valid input...

mkl
  • 90,588
  • 15
  • 125
  • 265
  • Thank you for for answer, I really appreciate you taking time to help me out. – Igor Sabo Mar 27 '17 at 11:06
  • For code that LTV enables a signed PDF using iText 5 look at [this answer](https://stackoverflow.com/a/51481392/1729265). – mkl Jul 23 '18 at 14:54
  • `v.merge` should be in outside of the for loop imo. It seems that multiple calls are not allowed ([source](https://github.com/sunrenjie/itext/blob/master/itext/src/main/java/com/itextpdf/text/pdf/security/LtvVerification.java)).. – yakya Aug 12 '18 at 17:08
  • 1
    @sotn You're right, I've corrected the code. Additionally I meanwhile have created a slightly different solution which does not have the limitation of the solution outlined here, i.e. the necessity to use CRLs instead of OCSP responses, cf. [this answer](https://stackoverflow.com/a/51675015/1729265). – mkl Aug 15 '18 at 16:19