iText 如何修复签名 pdf 的交叉引用 table
iText how to fix cross reference table for signed pdf
我正在使用 itext 7 签署具有 2 个签名字段并且 itext 正在打印的 pdf
Error occurred while reading cross reference table. Cross reference table will be rebuilt.
导致错误的行是
new PdfSigner(sourceDoc, signedFile, new StampingProperties().useAppendMode());
通常当我遇到这个错误时,我会通过将 pdf 复制到新的代码来修复它:
sourceDocument.copyPagesTo(firstPage, sourceDocument.getNumberOfPages(), targetDocument, firstPage);
然后在 targetDocument 上签名。它修复了交叉 table 问题,但它不复制现有签名。
所以我添加了
sourceDocument.copyPagesTo(..., new PdfPageFormCopier());
它确实复制了签名,但结果它们是无效的(因为文档哈希已更改并且它影响了签名?)
是否有机会修复文档,使签名完好无损并附加另一个签名?
我不控制正在签名的 pdf,因为它是客户端将它发送给我并且他设法在其他地方签名(可能通过使用旧版本的 itext 或打开 pdf?)尽管存在交叉引用问题(或者是什么导致了问题)。
导致 itext7 出现问题的参考 table
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 在读取第 0000000000 65536 n
行后调用错误 file position {0} cross reference entry in this xref subsection.
(从上数第三个)
问题
最终您发布了有问题的交叉引用 table。立刻映入眼帘的是多个这样的词条:
0000000000 65536 n
它们的意思是代号为65536的对应对象位于偏移量0处。
这在两个方面是无效的:
代号超出允许范围:
ISO 32000-2, section 7.5.4 "Cross-reference table"
The maximum generation number is 65,535
(有人可能认为原始 PDF 的制作者试图在依赖有效值的 PDF 处理器中造成 int16 溢出。您确定 PDF 来自 trustable 来源吗?)
偏移量 0 处的 PDF 有 %PDF-x.y
行而不是对象。即使有人认为 PDF 处理器应该将该行视为常规注释并跳过它,下一个间接对象也只能匹配所有这些条目中的一个,对于其他条目,对象编号将不正确。
顺便说一句:这与 (with 0000000000 00000 n
entries) and the work-around provided below is essentially the same as provided in 到那个问题的问题有关。不同之处在于您的案例中额外的无效代号。
修复交叉引用表以保持签名完整
您在评论中分享了签名的带符号字节范围和 PDF 的大小:
First signature /ByteRange [0 177104 196050 1580 ]
Second signature /ByteRange [0 212340 277878 23120 ]
File size: My linux shows 300,998 bytes
检查第二个签名的字节范围可以看到它的第二个范围包含 23120 个字节,从偏移量 277878 开始,即直到文件末尾 (277878 + 23120 = 300998)。
因此,在 现有文件中的任何修复工作都会更改哈希值。任何使用 appended 新交叉引用 table 的修复工作至少会增加最新修订版的大小,从而使第二个签名不再覆盖其修订版。无论哪种方式,Adobe Reader 都会抱怨。
尽管如此仍要签名
如果您觉得冒险并且想要使用损坏的交叉引用条目签署该文档,您可以让 iText 相信您的 PdfReader
加载的文件毕竟没有损坏。您可以通过覆盖相应的 getter 方法而不是
来实现
PdfReader sourceDoc = new PdfReader(SOURCE);
使用
PdfReader sourceDoc = new PdfReader(SOURCE) {
@Override
public boolean hasRebuiltXref() {
return false;
}
@Override
public boolean hasFixedXref() {
return false;
}
};
实例化您的 PdfReader
。现在应该可以在附加模式下登录了,请参阅我在测试中的 proof-of-concept testSignBrokenXrefForced
class SignBrokenPdf.
当心,你现在得到的结果也是错误的,任何签名或 PDF 验证器都可能拒绝它。仅当您无法说服您的客户生成有效的 PDF 时才这样做。即使那样你也不应该。如果转发已签名的 PDF 导致某些后续处理器出现问题,您尤其要负责。
我正在使用 itext 7 签署具有 2 个签名字段并且 itext 正在打印的 pdf
Error occurred while reading cross reference table. Cross reference table will be rebuilt.
导致错误的行是
new PdfSigner(sourceDoc, signedFile, new StampingProperties().useAppendMode());
通常当我遇到这个错误时,我会通过将 pdf 复制到新的代码来修复它:
sourceDocument.copyPagesTo(firstPage, sourceDocument.getNumberOfPages(), targetDocument, firstPage);
然后在 targetDocument 上签名。它修复了交叉 table 问题,但它不复制现有签名。 所以我添加了
sourceDocument.copyPagesTo(..., new PdfPageFormCopier());
它确实复制了签名,但结果它们是无效的(因为文档哈希已更改并且它影响了签名?)
是否有机会修复文档,使签名完好无损并附加另一个签名?
我不控制正在签名的 pdf,因为它是客户端将它发送给我并且他设法在其他地方签名(可能通过使用旧版本的 itext 或打开 pdf?)尽管存在交叉引用问题(或者是什么导致了问题)。
导致 itext7 出现问题的参考 table
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 在读取第 0000000000 65536 n
行后调用错误 file position {0} cross reference entry in this xref subsection.
(从上数第三个)
问题
最终您发布了有问题的交叉引用 table。立刻映入眼帘的是多个这样的词条:
0000000000 65536 n
它们的意思是代号为65536的对应对象位于偏移量0处。
这在两个方面是无效的:
代号超出允许范围:
ISO 32000-2, section 7.5.4 "Cross-reference table" The maximum generation number is 65,535 (有人可能认为原始 PDF 的制作者试图在依赖有效值的 PDF 处理器中造成 int16 溢出。您确定 PDF 来自 trustable 来源吗?)
偏移量 0 处的 PDF 有
%PDF-x.y
行而不是对象。即使有人认为 PDF 处理器应该将该行视为常规注释并跳过它,下一个间接对象也只能匹配所有这些条目中的一个,对于其他条目,对象编号将不正确。
顺便说一句:这与 0000000000 00000 n
entries) and the work-around provided below is essentially the same as provided in
修复交叉引用表以保持签名完整
您在评论中分享了签名的带符号字节范围和 PDF 的大小:
First signature
/ByteRange [0 177104 196050 1580 ]
Second signature/ByteRange [0 212340 277878 23120 ]
File size: My linux shows 300,998 bytes
检查第二个签名的字节范围可以看到它的第二个范围包含 23120 个字节,从偏移量 277878 开始,即直到文件末尾 (277878 + 23120 = 300998)。
因此,在 现有文件中的任何修复工作都会更改哈希值。任何使用 appended 新交叉引用 table 的修复工作至少会增加最新修订版的大小,从而使第二个签名不再覆盖其修订版。无论哪种方式,Adobe Reader 都会抱怨。
尽管如此仍要签名
如果您觉得冒险并且想要使用损坏的交叉引用条目签署该文档,您可以让 iText 相信您的 PdfReader
加载的文件毕竟没有损坏。您可以通过覆盖相应的 getter 方法而不是
PdfReader sourceDoc = new PdfReader(SOURCE);
使用
PdfReader sourceDoc = new PdfReader(SOURCE) {
@Override
public boolean hasRebuiltXref() {
return false;
}
@Override
public boolean hasFixedXref() {
return false;
}
};
实例化您的 PdfReader
。现在应该可以在附加模式下登录了,请参阅我在测试中的 proof-of-concept testSignBrokenXrefForced
class SignBrokenPdf.
当心,你现在得到的结果也是错误的,任何签名或 PDF 验证器都可能拒绝它。仅当您无法说服您的客户生成有效的 PDF 时才这样做。即使那样你也不应该。如果转发已签名的 PDF 导致某些后续处理器出现问题,您尤其要负责。