3

I'm working on pdf signatures using itext7 and currently need to support all PAdES signature levels: B-B, B-T, B-LT, B-LTA https://ec.europa.eu/digital-building-blocks/wikis/display/ESIGKB/What+are+the+B-T-LT+and+LTA+levels+of+an+electronic+signature

My problem is how i can create B-LT signature with itext? I have created B-B and B-T with this code:

signer.signDetached(
                new BouncyCastleDigest(),
                customExternalSignature,
                new Certificate[]{clientX509Certificate},
                null,
                null,
                tsaClient,
                0,
                PdfSigner.CryptoStandard.CADES);

Then I wanted add B-LTA level so I have used this code https://github.com/mkl-public/testarea-itext7/blob/master/src/main/java/mkl/testarea/itext7/signature/AdobeLtvEnabling.java to check adding BASELINE-LTA level, but after applying this logic to my signature adobe says that it is BASELINE-LT

enter image description here

This creates two questions:

  1. Is this implementation in AdobeLtvEnabling correct way to add PAdES level B-LT?
  2. Is this proper way to add B-LTA level?
//This method extend B-T signature to B-LT
private byte[] addLt(final byte[] signed) throws IOException, GeneralSecurityException {
        final ByteArrayOutputStream out = new ByteArrayOutputStream();
        try (InputStream resource = new ByteArrayInputStream(signed);
             PdfReader pdfReader = new PdfReader(resource);
             PdfWriter pdfWriter = new PdfWriter(out);
             PdfDocument pdfDocument = new PdfDocument(pdfReader, pdfWriter, new StampingProperties().preserveEncryption().useAppendMode())) {
            AdobeLtvEnabling adobeLtvEnabling = new AdobeLtvEnabling(pdfDocument);
            IOcspClient ocsp = new OcspClientBouncyCastle(null);
            ICrlClient crl = new CrlClientOnline();
            adobeLtvEnabling.enable(ocsp, crl);
        }

        return addLtv(out.toByteArray());
    }

//This method extend B-LT signature to B-LTA
private byte[] addLtv(final byte[] pdf) throws IOException, GeneralSecurityException {
        final ByteArrayOutputStream signedFile = new ByteArrayOutputStream();
        final PdfReader sourceDoc = new PdfReader(new ByteArrayInputStream(pdf));
        final PdfSigner signer = new PdfSigner(sourceDoc, signedFile, STAMPING_PROPERTIES);

        signer.timestamp(tsaClient, null);

        return signedFile.toByteArray();
    }
demonplus
  • 5,613
  • 12
  • 49
  • 68
JK_codes
  • 175
  • 9
  • 1
    The `AdobeLtvEnabling` is meant as a tool to add the information required for the Adobe "LTV enabled" profile, and this profile requires no time stamps at all. Applied to a B-T, therefore, one can not get a B-LTA which requires an additional time stamp. To make sure to get a B-LT, by the way, one has to extend `AdobeLtvEnabling` a bit: currently it ignores time stamps, but processing time stamps usually is necessary for LT. – mkl Mar 04 '22 at 23:45
  • @mkl After using logic in `AdobeLtvEnabling` I got B-LT in Adobe but what exactly do I need to add to it to work properly? – JK_codes Mar 07 '22 at 07:18
  • 2
    As mentioned, `AdobeLtvEnabling` ignores time stamps; signature time stamps to be more exact. To process them, too, you need to extend the loop in `enable` to not only walk the certificate path of `pdfPKCS7.getSigningCertificate()` but also of the signing certificate of `pdfPKCS7.getTimeStampToken()` if applicable. Of course it is possible that in your case this is not necessary: if the TSA certificate immediately is on the Trusted Lists (and not merely an ancestor in its certificate path), then no extra validation information is required. This is the case for some but not for all TSAs. – mkl Mar 07 '22 at 09:52

1 Answers1

5

Looks about right. The only material difference between PAdES-B-LT and PAdES-B-LTA is that the signature validation data needs to be timestamped as well. As such, to go from PAdES-B-LT to PAdES-B-LTA, it suffices to add a document timestamp.

With iText, that more or less works like this:

try(InputStream is = ...; // this should contain the PAdES-B-LT output
    PdfReader reader = new PdfReader(is);
    OutputStream os = new FileOutputStream(OUTPUT_DOCUMENT)) {

    PdfSigner pdfSigner = new PdfSigner(reader, os, new StampingProperties().useAppendMode());
    // .timestamp(...) is for producing document timestamps
    pdfSigner.timestamp(tsaClient, timeStampFieldName);
}

See also here for some context: https://dzone.com/articles/7-tips-for-creating-pdf-signatures (ignore the buzzfeedy title...).

EDIT: If you're looking for a tool to test your PAdES signatures for conformance with the format requirements in the specification, you might want to request access to the ETSI conformance checker: https://signatures-conformance-checker.etsi.org/pub/index.php.

mval
  • 295
  • 2
  • 10
  • Thank you for response. I have some more questions. In the article you have linked there is ` ltvVerification.addVerification("Signature1",...)` which means that that i extends signature level only for one signature. If i have many B-T signatures I need to apply this to all of them before adding timestamp to make them all LTA, right? – JK_codes Mar 07 '22 at 13:06
  • Yep. PAdES doesn't specify that you need separate document timestamps for all signatures, so covering all validation data with a single document timestamp makes sense in that sort of workflow. – mval Mar 09 '22 at 12:36