Commit "Document has been modified or damaged"
The error is that you are calling PDDocument.saveIncremental with an InputStream , just covering the original PDF:
FileInputStream fis1 = new FileInputStream(pdfFile); FileInputStream fis = new FileInputStream(pdfFile); FileOutputStream fos = new FileOutputStream(signedPdfFile); ... doc.saveIncremental(fis, fos);
But the method expects the InputStream to cover the source file, as well as the changes made to prepare for signing.
Thus, fis should also point to signedPdfFile , and since this file may not exist before, the order of creation of fis and fos must be disabled>
FileInputStream fis1 = new FileInputStream(pdfFile); FileOutputStream fos = new FileOutputStream(signedPdfFile); FileInputStream fis = new FileInputStream(signedPdfFile); ... doc.saveIncremental(fis, fos);
Unfortunately, JavaDocs do not indicate this.
Another problem
There is another problem with the generated signature. If you look at the dump of the ASN.1 sample, you will see something starting like this:
<30 80> 0 NDEF: SEQUENCE { <06 09> 2 9: OBJECT IDENTIFIER signedData (1 2 840 113549 1 7 2) : (PKCS #7) <A0 80> 13 NDEF: [0] { <30 80> 15 NDEF: SEQUENCE { <02 01> 17 1: INTEGER 1 <31 0F> 20 15: SET {
NDEF length NDEF show that an indefinite length method is used to encode these outer layers of the signature container. The use of this method is permitted in basic coding rules (BER), but not in more stringent rules for outstanding encodings (DER). Although BER for external layers is allowed for generic PKCS # 7 / CMS signatures, the PDF specification explicitly requires:
When using PKCS # 7 signatures, the Content value must be a PKCS # 7 binary data object containing DER containing the signature.
(Section 12.8.3.3.1 "PKCS Signatures No. 7 Used in ISO 32000" / "General" in ISO 32000-1 )
Thus, strictly speaking, your signature is even structurally invalid . Typically, this is not detected by the PDF signature verification services, since most of them use the standard PKCS # 7 / CMS libraries or signature container verification methods.
If you want to make sure that your signatures are indeed genuine PDF signatures, you can achieve this by replacing
return signedData.getEncoded();
something like
ByteArrayOutputStream baos = new ByteArrayOutputStream(); DEROutputStream dos = new DEROutputStream(baos); dos.writeObject(signedData.toASN1Structure()); return baos.toByteArray();
Now the entire signature object is DER encoded.
(You can find test creation of signatures with both your original and fixed code with or without improved encoding: SignLikeLoneWolf.java )