0
votes

I need to make a signed pdf LTV enabled. Signing certificate has a chain with three levels (root / public / personal). I know that it is necessary to add OCSP and CRL of certificates in pdf (except root).

  • Can I use for it basic LtvVerification.addVerification() method? If I add in one run two CRLs, in the result PDF is only a second. If i change order, is there again a second. If I add the CRL in two runs, it will end the same way - in pdf remains CRL added as a second. I thought the "add" will not overwrite the previous state..

  • How to properly use the method LtvVerification.merge()? Before/after adding first/second/both CRL?

  • Or i can use only alternative method LtvVerification.addVerification(String signatureName, Collection ocsps, Collection crls, Collection certs)?

Thank you very much for the tips.

Source code:

public void addLtv(String src, String dest) throws IOException, DocumentException, GeneralSecurityException
{

    BouncyCastleProvider provider = new BouncyCastleProvider();
    Security.addProvider(provider);

    PdfReader r = new PdfReader(src);
    System.out.println("Source file: " + src);
    FileOutputStream fos = new FileOutputStream(dest);
    PdfStamper stp = new PdfStamper(r, fos, '\0', true);
    LtvVerification v = stp.getLtvVerification();
    AcroFields fields = stp.getAcroFields();

    ArrayList<String> names = fields.getSignatureNames();
    String sigName = names.get(names.size() - 1);
    System.out.println("found signature: " + sigName);
    PdfPKCS7 pkcs7 = fields.verifySignature(sigName);

    //add LTV
    OcspClient ocsp = new OcspClientBouncyCastle();
    CrlClient crlClient1 = new CrlClientOnline("http://www.postsignum.cz/crl/psrootqca2.crl");
    ArrayList<CrlClient> crllist = new ArrayList<CrlClient>();
    crllist.add(crlClient1);
    CrlClient crlClient2 = new CrlClientOnline("http://www.postsignum.cz/crl/pspublicca2.crl");
    crllist.add(crlClient2);
    System.out.println("crllist.size=" + crllist.size());

    if (pkcs7.isTsp())
    {
        for (CrlClient crlclient : crllist)
        {
            if (v.addVerification(sigName, new OcspClientBouncyCastle(), crlclient,
                    LtvVerification.CertificateOption.SIGNING_CERTIFICATE,
                    LtvVerification.Level.CRL,
                    LtvVerification.CertificateInclusion.NO)) {
                System.out.println("crl " + crlclient.toString() + " added to timestamp");
            }
        }

    } else{


        for (String name : names)
        {
            for (int i = 0; i < crllist.size(); i++) {
                if (v.addVerification(name, ocsp, crllist.get(i),
                        LtvVerification.CertificateOption.WHOLE_CHAIN,
                        LtvVerification.Level.CRL,
                        LtvVerification.CertificateInclusion.NO)) {
                    System.out.println("crl " + crllist.get(i).toString() + " added to " + name);
                }

                if (i > 0) {
                    System.out.println("found verification, merge");
                    v.merge();
                }

            }
        }
    }

    stp.close();
}
1
Can you share a sample document to reproduce your issue?mkl

1 Answers

0
votes

If you want to provide multiple CRLs to LtvVerification.addVerification, you do not call that method once for each CRL but instead once with all CRLs.

For this CrlClientOnline also accepts multiple URLs:

/**
 * Creates a CrlClientOnline instance using one or more URLs.
 */
public CrlClientOnline(String... crls)

Thus, by using this constructor instead we simplify and fix your code to

PdfReader r = new PdfReader(src);
FileOutputStream fos = new FileOutputStream(dest);
PdfStamper stp = new PdfStamper(r, fos, '\0', true);
LtvVerification v = stp.getLtvVerification();
AcroFields fields = stp.getAcroFields();

ArrayList<String> names = fields.getSignatureNames();
String sigName = names.get(names.size() - 1);
System.out.println("found signature: " + sigName);
PdfPKCS7 pkcs7 = fields.verifySignature(sigName);

//add LTV
OcspClient ocsp = new OcspClientBouncyCastle();
CrlClient crlClient = new CrlClientOnline("http://www.postsignum.cz/crl/psrootqca2.crl", "http://www.postsignum.cz/crl/pspublicca2.crl");

if (pkcs7.isTsp())
{
    if (v.addVerification(sigName, new OcspClientBouncyCastle(), crlClient,
            LtvVerification.CertificateOption.SIGNING_CERTIFICATE,
            LtvVerification.Level.CRL,
            LtvVerification.CertificateInclusion.NO))
    {
        System.out.println("crl " + crlClient.toString() + " added to timestamp");
    }
}
else
{
    for (String name : names)
    {
        if (v.addVerification(name, ocsp, crlClient,
                LtvVerification.CertificateOption.WHOLE_CHAIN,
                LtvVerification.Level.CRL,
                LtvVerification.CertificateInclusion.NO))
        {
            System.out.println("crl " + crlClient.toString() + " added to " + name);
        }
    }
}
stp.close();

(AddLtvCrls.java, method addLtvFixed)

Applying it to your sample file, we get:

Signature panel view


For some background, LtvVerification.addVerification stores the information it has as the validation information required for the signature in question. Calling it multiple times results in the information only from the last attempt to count.

Calling LtvVerification.merge does not help either here as it merely merges validation information required for different signatures from older revisions into the new validation related information section.