javapdfitextpkcs#7

Converting XML Signature to PKCS#7 and embedding into PDF results in "Signature is invalid" error in Adobe Reader


I'm working on digitally signing a PDF using an external signature service. The signing flow is as follows:

  1. I add a SignatureField to the existing PDF to generate a valid /ByteRange, and produce a placeholder PDF.

  2. I calculate the SHA-256 hash of the byte ranges (i.e., the portions of the PDF that are actually signed).

  3. I send this hash to a remote signature provider.

  4. The provider returns an XML Signature response containing:

: a base64-encoded PKCS#1 signature

: a base64-encoded signing certificate

  1. I use these values to construct a PKCS#7 (CMS SignedData) object using BouncyCastle in Java.

  2. I embed the generated PKCS#7 into the /Contents field of the original PDF.

However, when I open the resulting PDF in Adobe Reader, I get the error: "Signature is invalid", even though Adobe correctly recognizes and displays the certificate details.

My Goal: To convert the XML Signature (PKCS#1 signature + certificate) into a valid PKCS#7 signature, embed it into the PDF, and have Adobe Reader validate it as a proper digital signature.

Is there anything wrong with converting an XML Signature to a PKCS#7 structure like this?

Even though I correctly place the digest into messageDigest, could Adobe Reader reject the signature due to subtle ASN.1 or attribute encoding issues?

I'm not sure which part of my code would be most helpful to share. If you have suggestions on where to focus, I’d be happy to include code snippets.


Solution

  • First of all, you request a signature value directly for the document byte ranges hash. This implies that you don't want to use signed attributes in your PKCS#7 signature container.

    On the other hand, in your answer with extra information you mentioned that your PKCS#7 signature container actually should be a CAdES signature container. But CAdES signature containers do require the use of signed attributes.

    Thus, your current approach has to be changed to take that into account and support generating signed attributes.

    This means that after hashing the byte ranges in the PDF you have to build the to-be-signed attributes for your signature container, hash and sign that set of attributes, and then put the attributes and their signature into a signature container.

    You can use BC classes to do the heavy lifting for you: If you put your remote signing service call into a ContentSigner implementation, you can use a simple IExternalSignatureContainer implementation like the PadesSignatureContainerBc from this answer.