Search code examples
javapdfdigital-signaturepdfboxpades

Cannot sign a PDF with CAdES method, although signing it with PAdES succeeds


We 're trying to sign a PDF document using the CAdES method and the examples in dss-cookbook as a starting point using the latest version (4.6.RC1).

Following the example from SignPdfPadesBDetached.java, we have succesfully signed a PDF document using PAdES. However, since there is no example for CAdES, we tried adapting the above example to use CAdES, but it doesn't work. Specifically the generated PDF document has a size of only 7k instead of the expected 2.5MB and the following error is displayed when trying to open the PDF:
enter image description here
We assume the 7k is actually only the signature so that the actual document is not included. The settings we use are:

  • SignatureLevel.CAdES_BASELINE_B
  • SignaturePackaging.DETACHED
  • DigestAlgorithm.SHA256

And the relative's method code is currently this:

public static void signPdfWithCades(DSSDocument toSignDocument) {

    LOG.info("Signing PDF with CADES B");

    try {
        AbstractSignatureTokenConnection signingToken = new Pkcs12SignatureToken("password", KEYSTORE_PATH);
        DSSPrivateKeyEntry privateKey = signingToken.getKeys().get(0);

        // Preparing parameters for the CAdES signature
        CAdESSignatureParameters parameters = new CAdESSignatureParameters();
        // We choose the level of the signature (-B, -T, -LT, -LTA).
        parameters.setSignatureLevel(SignatureLevel.CAdES_BASELINE_B);
        // We choose the type of the signature packaging (ENVELOPING, DETACHED).
        parameters.setSignaturePackaging(SignaturePackaging.DETACHED);
        // We set the digest algorithm to use with the signature algorithm. You must use the
        // same parameter when you invoke the method sign on the token. The default value is
        // SHA256
        parameters.setDigestAlgorithm(DigestAlgorithm.SHA256);

        // We set the signing certificate
        parameters.setSigningCertificate(privateKey.getCertificate());
        // We set the certificate chain
        parameters.setCertificateChain(privateKey.getCertificateChain());

        // Create common certificate verifier
        CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier();
        // Create PAdES xadesService for signature
        CAdESService service = new CAdESService(commonCertificateVerifier);

        // Get the SignedInfo segment that need to be signed.
        ToBeSigned dataToSign = service.getDataToSign(toSignDocument, parameters);

        // This function obtains the signature value for signed information using the
        // private key and specified algorithm
        DigestAlgorithm digestAlgorithm = parameters.getDigestAlgorithm();
        SignatureValue signatureValue = signingToken.sign(dataToSign, digestAlgorithm, privateKey);

        // We invoke the cadesService to sign the document with the signature value obtained in
        // the previous step.
        DSSDocument signedDocument = service.signDocument(toSignDocument, parameters, signatureValue);

        LOG.info("Signed PDF size = " + signedDocument.getBytes().length);

        //We use the DSSUtils to Save to file
        DSSUtils.saveToFile(signedDocument.openStream(), "target/signedPdfCadesBDetached.pdf");
    } catch (Exception e) {
        LOG.error(e.getMessage(), e);
    }
}

The corresponding method for signing with PAdES is similar to the above, adjusted to PAdES (that is, we there used PAdESSignatureParameters, SignatureLevel.PAdES_BASELINE_B and PAdESService) classes.

Please note that the SD-DSS project is not hosted in the Maven Central repository, so we had to make an explicit reference to it:

<repositories>
    <repository>
        <id>europa</id>
        <url>https://joinup.ec.europa.eu/nexus/content/groups/public/</url>
    </repository>
</repositories>

In addition, I believe we included all of the required/corresponding dependencies in our pom.xml:

<dependency>
    <groupId>eu.europa.ec.joinup.sd-dss</groupId>
    <artifactId>dss-token</artifactId>
    <version>4.6.RC1</version>
</dependency>
<dependency>
    <groupId>eu.europa.ec.joinup.sd-dss</groupId>
    <artifactId>dss-pades</artifactId>
    <version>4.6.RC1</version>
</dependency>
<dependency>
    <groupId>eu.europa.ec.joinup.sd-dss</groupId>
    <artifactId>dss-cades</artifactId>
    <version>4.6.RC1</version>
</dependency>
<dependency>
    <groupId>eu.europa.ec.joinup.sd-dss</groupId>
    <artifactId>dss-document</artifactId>
    <version>4.6.RC1</version>
</dependency>

Prior to this, we also gave a try to PDFBox, but the documentation wasn't so helpful, according to what we want to accomplish.

Any idea what is wrong here? Changing the packaging ENVELOPING makes no difference either. Is the method for signing with CAdES so different that the PAdES example should not be used as a guide?


Solution

  • In general,

    PAdES signatures are specifically profiled signatures embedded into a PDF. Thus, your PAdES signed PDF can be opened in Adobe Reader, and Adobe Reader can recognize the signature, verify it, and display the result of that in its signature panel.

    CAdES signatures are specifically profiled signatures which either are in a separate file or which contain the signed data. Neither of these formats is recognized by Adobe Reader, in case of the separate file you can open the original PDF but the Reader does not see the signature, in case of the contained PDF the Reader either cannot open the file at all or (as the Reader ignores some leading and trailing extra bytes) considers the signature ignorable trash.

    You only need a PDF aware library (like PDFBox) for PAdES signatures, for CAdES signatures the PDF is treated like generic data bytes.


    In your case, therefore, i.e. for

    • SignatureLevel.CAdES_BASELINE
    • SignaturePackaging.DETACHED

    your 7K indeed is the mere signature in a separate file and you have to keep or forward both the PDF and the signature, the PDF for viewing and the signature for verification.

    Thus,

    Specifically the generated PDF document has a size of only 7k instead of the expected 2.5MB ...

    We assume the 7k is actually only the signature so that the actual document is not included.

    Your assumption is correct, and also the behavior is correct. Yout expectations are the issue.


    Some confusion might result from the facts that the signature container embedded into a PDF in case of a PAdES signature, when extracted, proves to be in CAdES format, that the matching PDF subfilter is called ETSI.CAdES.detached, and that (at least in the most recent draft at hand) the PDF 2.0 specification will treat the PAdES signatures in a section titled "12.8.3.4 CAdES signatures as used in PDF (PDF 2.0)".

    Nonetheless, if you are talking about PAdES signatures, you are talking about ETSI AdES signatures integrated in PDFs. If you are talking about CAdES signatures, you are talking about ETSI AdES CMS signatures independant of a specific document format which may be detached from the signed data or which may wrap them.


    According to your comments, in particular this one

    Signing the PDF using ETSI.CAdES.DETACHED filter is the exact requirement

    you in the end do not want to create a CAdES signature but instead a PAdES signature, more exactly you want to do so according to the Part 3: PAdES Enhanced - PAdES-BES and PAdES-EPES Profiles and not according to Part 2: PAdES Basic - Profile based on ISO 32000-1 which uses the subfilters adbe.pkcs7.detached and adbe.pkcs7.sha1.

    (To get the requirement straight, that is the subfilter value, not the filter value.)

    This is exactly what the dss cookbook examples SignPdfPadesB, SignPdfPadesBDetached, and SignPdfPadesBVisible should be all about:

    • they all in their JavaDoc class comment claim to show How to sign PDF Document with PAdES-BASELINE-B,
    • the cookbook asciidoc/dss-documentation.adoc for PAdES Baseline profiles refers to ETSI TS 103 172,
    • and that standard specifies:

      6 Requirements for B-Level Conformance

      This clause defines requirements that PAdES signatures claiming conformance to the B-Level have to fulfil.

      The current clause specifies compliance requirements for short-term electronic signatures. This clause actually profiles PAdES-BES (signatures that do not incorporate signature-policy-identifier) and PAdES-EPES (signatures that do incorporate signature-policy-identifier) signatures.

      (ETSI TS 103 172 V2.1.1 (2012-03))

    Unfortunately I cannot now verify that the samples do what they claim as my eclipse dss projects are all red with problems.

    If they do, though, it looks like you in the beginning already had what you wanted:

    Following the example from SignPdfPadesBDetached.java, we have succesfully signed a PDF document using PAdES.

    You may share a sample PDF signed with that example for analysis to be sure.