我正在使用最新版本的iText7 sign模块(7.1.11)来验证预先存在的文档上的数字签名。在少数情况下,SignatureUtil构造函数会抛出
com.itextpdf.kernel.PdfException: There is no associate PdfWriter for making indirects.根据最新版本的Acrobat Reader的报告,我收到异常的一些文档似乎签名正确。下面是其中一个文档的链接:https://drive.google.com/file/d/1biuG9pIOS2piIBLNFNFrV2bhH_U9nk6E/view?usp=sharing
您可以使用最小的一段代码亲自尝试它,例如
public void test(byte[] fileData) throws IOException {
try (ByteArrayInputStream bais = new ByteArrayInputStream(fileData);
PdfReader signedPdfReader = new PdfReader(bais);
PdfDocument signedPdf = new PdfDocument(signedPdfReader);) {
SignatureUtil signatureUtil = new SignatureUtil(signedPdf);
}
}发布于 2020-06-23 19:10:28
总之
原因是文件结构中的错误。三个文档修订中的第一个修订已经在其尾部包含无效条目,这会导致创建以下两个修订的处理器在文件结构中引入进一步的错误。
详述
您的文档包含三个修订版。
第一个版本,初始版本
第一个以
xref
0 9
0000000000 65535 f
0000481819 00000 n
0000481871 00000 n
0000000017 00000 n
0000000351 00000 n
0000000431 00000 n
0000481637 00000 n
0000481721 00000 n
0000481917 00000 n
trailer
<</Size 8/Root 2 0 R/Info 8 0 R/ID [<24348fc363d4c39bd928bff26d44da5c><7bb5325418f976360243700f8e91598d>]>>
startxref
482135
%%EOF 这里的错误是尾部声称大小是8。此条目指定为
Size integer (必需;不应是间接引用)文件交叉引用表中的条目总数,由原始节和所有更新节的组合定义。等效地,此值应比文件中定义的最高对象编号大1。
(ISO 32000-1,表15 -文件尾部字典中的条目)
然而,在第一个修订版中,交叉引用表具有从对象编号0到8条目,尾部甚至明确引用对象8作为信息字典。因此,Size的值应该是9。
乍一看,这看起来是无害的,但它会使附加两个签名的PDF处理器失败:
第二个版本(无法访问的签名)
在第二个版本中,签名软件试图添加签名作为增量更新。由于第一个修订版的尾部中的Size值为8,因此它假定8比文件中已定义的最高对象编号大1,因此可供新对象使用。
因此,它添加了具有签名字段的对象8,最终在其中对该修订进行了签名。它还引用了document AcroForm definition的字段数组中的对象8。
但与此同时,它试图更新信息字典。根据第一次修订的预告片,该字典位于对象8中。因此,它还添加了一个对象8,其中包含更新的信息字典。
因此,现在在第二个修订版中有两个编号为8的对象,但只有一个可以从交叉引用中引用。由于处理器的实现细节,这恰好是具有更新的信息字典的对象8。
因此,第二个修订版包含一个签名字段,它不能从任何地方访问,并且AcroForm引用信息字典作为字段定义。
由于无法访问签名字段,因此此修订版本看起来未签名。因此,此文件再次被发送到签名,从而产生第三个修订版。
第三个版本(可访问的签名)
在第三个版本中,签名软件再次尝试添加签名作为增量更新。由于第二个修订版的尾部中的大小条目是正确的,因此可以正常工作:
此外,具有更新的信息数据的对象8的另一个副本被添加到此修订中。
iText SignatureUtil解析失败
在为具有这三个修订的文档实例化SignatureUtil类时,iText尝试解析AcroForm结构。在这里,它找到对对象8的引用,并尝试将其解析为字段字典。这显然是失败的,毕竟可到达对象8包含信息字典,而不是字段字典。
iText尝试完成此字典,使其成为字段字典。但是,由于您以只读的方式打开文档,因此此操作将失败,并显示奇怪的异常消息。
摘要
本质上是一种GIGO情况:垃圾输入-垃圾输出。
主要的错误是在生产者的第一个修订版,一些secPdfProducer扫描处理机根据原始的信息字典。创建错误的预告片信息会造成各种各样的破坏。
但签名应用程序也有一个错误:它不应该接受来自原始版本中对象8的信息数据,因为那里不可能有这样的对象8。
iText中有一个小错误:在解析只读文档的AcroForm时,它不应该尝试完成“不完整”的字段。
https://stackoverflow.com/questions/62518805
复制相似问题