Verifying PDF Signature in Java using Bouncy Castle and PDFBox

前端 未结 2 1387
梦如初夏
梦如初夏 2021-01-23 01:18

I am trying to verify digitally signed PDF document in Java.

I\'m using Apache PDFBox 2.0.6 to get the signature and the original PDF that was signed, then I\'m using B

相关标签:
2条回答
  • 2021-01-23 01:51

    You appear to have a misconception concerning the getSignedContent method in particular and PDF signing in general.

    I'm using Apache PDFBox 2.0.6 to get the signature and the original PDF that was signed

    If by "the original PDF that was signed" you mean a PDF before it entered the signing process, then the second part of your task is impossible for generic signed PDFs.

    The reason is that the original PDF before creation of the actual signature is prepared for the act of signing.

    This preparation might mean as little as adding a value dictionary (including a gap for later injection of the signature container) for a pre-existing empty signature field as an incremental update leaving the original PDF an untouched starting piece of the resulting signed document.

    On the other hand, though, it may additionally mean that a number of the following changes also occur:

    • a new signature field may be created from scratch;
    • an additional page may be added to the document for signature visualizations;
    • extra signature visualizations (either inactive images or actual signature form field widgets) may be added to each page;
    • missing appearances for form fields may be created;
    • the signing application may add its name to meta data entries as document processor, date and time of last change may be updated to the signing time;
    • in case of a pre-existing empty signature field, form fields indicated by that field's field lock dictionary may be set read only;
    • etc pp

    If the document was not signed before, these additions need not be added as incremental updates, instead all the objects (changed or unchanged) may be re-ordered, renumbered, indirect object may become direct ones and vice versa, unused objects might be dropped, duplicate objects might be reduced to a single one, fonts of form fields made read-only may be reduced to the actually used glyphs, etc pp

    Only for this prepared PDF the actual signature is created and embedded in the gap left in the signature value dictionary.

    If you apply your calls

    byte[] origPDF = doc.getSignatureDictionaries().get(0).getSignedContent(signedPDF);
    byte[] signature = doc.getSignatureDictionaries().get(0).getContents(signedPDF);
    

    to the signed document, origPDF contains the bytes of the signed document except the gap in the signature value dictionary and signature contains the (hex decoded) contents of the gap.

    So origPDF in particular contains all the changes done during the preparation; calling it orig, therefore, is vehemently misleading.

    Furthermore, as the gap originally reserved for the signature container is missing, it is very likely that these bytes actually don't form a valid PDF anymore: PDFs contain cross references which point to the starting offsets (from the start of the document) of each PDF object; as the gap is missing, the bytes after its former position have moved and offsets going there now are wrong.

    Thus, your origPDF merely contains the ensemble of signed bytes which may be very different from the file you consider the original one.


    Your verifySig completely ignores the SubFilter of the signature field value dictionary. Depending on that value, the signature bytes you retrieve using getContents might have entirely different contents.

    So without your signed PDF, further review of that method does not make sense.

    0 讨论(0)
  • 2021-01-23 02:12

    In my case there was an error in the code where I set the signature and signedData. I accidentally swappped the values.

    So, instead of:

    signedData = pdfUtils.getSignature(signedData);
    byte[] sig = pdfUtils.getSignedContent(signedData);
    

    It should be:

    byte[] sig = pdfUtils.getSignature(signedData);
    signedData = pdfUtils.getSignedContent(signedData); 
    

    Now, it's working. The file I was testing it with, was signed using adbe.pkcs7.detached. However, it wouldn't work if other signing methonds were used.

    So, thanks to @Tilman Hausherr for pointing me to the ShowSignature.java example. That's how signature verification should be done.

    And, also thanks to @mkl for detailed explanation.

    I now understand that when a signature is created signature fields are added and hash is calculated from that new value. That's why the verification is working. You don't need the original PDF without the signature fields.

    0 讨论(0)
提交回复
热议问题