Search code examples
javavalidationpdfdigital-signatureintegrity

Unexpected result when validating a Pdf signature with Itext


I'm trying to validate a PDF signature(which was signed mannually with my digital certificate via Adobe Reader X) with Itext 5.4 and BouncyCastle 1.49.

But the validation result is always unexpected, here's my Java code:

  **Security.addProvider(new BouncyCastleProvider());
  PdfReader reader = new PdfReader("E:/signTest.pdf");
  AcroFields acro = reader.getAcroFields();
  PdfPKCS7 pkcs7 = acro.verifySignature("signatureField");
  System.out.println("Integrity check OK? " + pkcs7.verify());**

The console showing: Integrity check OK? true

But be mind that I have modified the document of "signTest.pdf". The expected result should be: Integrity check OK? false

Does anyone ever had to solve this problem ?

I would appreciate any suggestions regarding.


Solution

  • "Integrity check ok" (as a result of pkcs7.verify()) only tells you that the originally signed revision, the originally signed byte range of the PDF has not been changed. If you applied changes in append mode, aka using incremental updates, that originally signed byte range is not touched.

    If you want to check whether changes have been made as incremental updates, inspect acro.signatureCoversWholeDocument("signatureField"), too:

    /**
     * Checks is the signature covers the entire document or just part of it.
     *
     * @param name the signature field name
     * @return <CODE>true</CODE> if the signature covers the entire document,
     * <CODE>false</CODE> otherwise
     */
    public boolean signatureCoversWholeDocument(String name)
    

    If you actually did change the originally signed byte range, please supply your PDF both before and after your modification.

    Concerning your comments...

    I follow your suggestion and get "false" return when inspect acro.signatureCoversWholeDocument("signatureField"). So does it mean that "originally signed byte range is not touched"?

    You have to consider the combination of those result values:

    • pkcs7.verify() indicates whether the indicated signature itself is internally ok and correctly signs the byte range indicated in the associated signature dictionary.

    • acro.signatureCoversWholeDocument("signatureField") indicates whether byte range signed by the indicated signature covers the whole document (except the signature itself, obviously).

    Only if both results are true, the signature is positively verified to sign the document in its current state.

    If the former one is true and the latter one is false, the signature is positively verified to sign a former state of the document which can be extracted from the document using acro.extractRevision("signatureField").

    In contrast to e.g. Adobe Reader, iText cannot yet check the kind of changes to the content. Thus, it cannot tell you whether the changes are allowed or disallowed.

    If the former one is false, the state which the signature originally did sign correctly (if there ever was such a state), cannot be extracted anymore.

    Then how can I apply the signature to cover the whole document?

    When you sign a PDF, the signature covers the whole document. E.g. the signature in your sample file signTest_after.pdf does cover the whole file. Filling fields afterwards added a new revision in your sample file signTest_modified.pdf which is not covered by your signature.

    For some backgrounds on this you might want to read this answer to get to know how PDF signatures work, this answer for information on multiple revisions in PDFs, and this answer on allowed and disallowed changes to signed documents.

    For working with iText and integrated PDF signatures in general you might want to study Digital Signatures for PDF documents, a White Paper by Bruno Lowagie (iText Software), especially chapter 5 Validation of signed documents.