I'm using itext 7 to sign pdf that has 2 signature fields and itext is printing
Error occurred while reading cross reference table. Cross reference table will be rebuilt.
The line that is causing error is
new PdfSigner(sourceDoc, signedFile, new StampingProperties().useAppendMode());
Usually when I got that error I would fix it by copying pdf to new one with code:
sourceDocument.copyPagesTo(firstPage, sourceDocument.getNumberOfPages(), targetDocument, firstPage);
and then sign targetDocument. It fix cross table problem but it does not copy existing signatures. So I have added
sourceDocument.copyPagesTo(..., new PdfPageFormCopier());
and it does copy signatures but in result they are invalid ( because document hash has changed and it affects signatures?)
Is there any chance that document can be fixed so that signatures are intact and another signature can be appended?
I do not control pdf that is being sign because it is client that is sending it to me and somehow he managed to sign it elsewhere (maybe by using older version of itext or open pdf?) despite cross reference problem (or that what caused problem).
Reference table that causes problem in itext7
xref
0 60
0000000000 65535 f
0000175044 00000 n
0000000000 65536 n
0000095603 00000 n
0000000015 00000 n
0000086011 00000 n
0000020754 00000 n
0000019785 00000 n
0000019501 00000 n
0000000212 00000 n
0000020091 00000 n
0000057104 00000 n
0000054819 00000 n
0000054543 00000 n
0000020921 00000 n
0000055414 00000 n
0000085852 00000 n
0000083751 00000 n
0000083466 00000 n
0000057253 00000 n
0000084295 00000 n
0000000000 65536 n
0000095805 00000 n
0000000000 65536 n
0000164295 00000 n
0000095937 00000 n
0000096014 00000 n
0000107919 00000 n
0000121074 00000 n
0000120425 00000 n
0000120265 00000 n
0000108058 00000 n
0000120701 00000 n
0000121221 00000 n
0000138109 00000 n
0000137022 00000 n
0000136863 00000 n
0000121317 00000 n
0000137511 00000 n
0000138253 00000 n
0000146202 00000 n
0000145690 00000 n
0000145530 00000 n
0000138341 00000 n
0000145904 00000 n
0000164151 00000 n
0000162977 00000 n
0000162818 00000 n
0000146341 00000 n
0000163510 00000 n
0000000000 65536 n
0000174805 00000 n
0000164534 00000 n
0000164611 00000 n
0000174666 00000 n
0000175345 00000 n
0000175115 00000 n
0000175251 00000 n
0000175398 00000 n
0000175459 00000 n
trailer
<</Size 60/Info 59 0 R/ID [<2dda6a23fc5d97b5d4e670c84756e5dd><262a30912f11d84731389759bd75bbf9>]/Root 58 0 R>>
startxref
175602
%%EOF
itext calls error file position {0} cross reference entry in this xref subsection.
after reading line 0000000000 65536 n
(third from the top)
Eventually you posted the problematic cross reference table. What immediately catches one's eye are multiple entries of this kind:
0000000000 65536 n
They mean that the corresponding object with a generation number of 65536 is located at offset 0.
This is invalid in two ways:
The generation number is outside its allowed range:
ISO 32000-2, section 7.5.4 "Cross-reference table" |
---|
The maximum generation number is 65,535 |
(One could believe that the producer of that original PDF attempted to cause int16 overflows in PDF processors that rely on valid values here. Are you sure that PDF is from a trustable source?)
A PDF at offset 0 has the %PDF-x.y
line and not an object. And even if one feels that a PDF processor should consider that line a regular comment and skip it, the next indirect object can only match one of all those entries, for the other ones the object number would be incorrect.
As an aside: This is related to the issue from this question (with 0000000000 00000 n
entries) and the work-around provided below is essentially the same as provided in my answer to that question. The difference is the additional invalid generation number in your case.
In comments you shared the signed byte ranges of the signatures and the size of the PDF:
First signature
/ByteRange [0 177104 196050 1580 ]
Second signature/ByteRange [0 212340 277878 23120 ]
File size: My linux shows 300,998 bytes
Inspecting the byte ranges of the second signature one sees that its second range encompasses 23120 bytes starting at offset 277878, i.e. until the end of the file (277878 + 23120 = 300998).
Thus, any repair work inside the existing file will change the hash. And any repair work using an appended new cross reference table will at least increase the size of the latest revision and so make the second signature not cover its revision anymore. Either way Adobe Reader will complain.
If you feel venturesome and want to sign that document with the broken cross reference entries nonetheless, you can lead iText into believing the file loaded by your PdfReader
is not broken after all. You can do so by overriding the corresponding getter methods, instead of
PdfReader sourceDoc = new PdfReader(SOURCE);
use
PdfReader sourceDoc = new PdfReader(SOURCE) {
@Override
public boolean hasRebuiltXref() {
return false;
}
@Override
public boolean hasFixedXref() {
return false;
}
};
to instantiate your PdfReader
. Now signing in append mode should be possible, see my proof-of-concept testSignBrokenXrefForced
in the test class SignBrokenPdf.
Beware, the result you get now also is broken, and any signature or PDF validator may reject it. Only do this if you cannot convince your client to produce valid PDFs. And even then you shouldn't. In particular you are responsible if forwarding the signed PDF causes issues in some later processor.