【发布时间】:2021-08-16 11:01:06
【问题描述】:
简介
我在对标记为符合 PDF/A - 3A 的 PDF 文档进行数字签名时遇到问题。使用 PDFBox(最新版本,2.0.24)我最终在 Adobe Acrobat 中得到一个无效签名,而使用 iText7(最新版本)我得到一个有效签名。目标是获得符合 PAdES LTV 的签名。
概述
我的过程如下(PDFBox 和 iText7):
- 我打开 PDF,创建用于签名的哈希(要签名的数据)
- 我打电话给第 3 方服务来取回数字签名
- 在服务响应中,我还获得了 OCSP 和 CRL 内容,我需要在 PDF 中嵌入以提高 LTV 质量
- 我在 PDF 中嵌入了签名
- 我将文档保存到内存中,然后重新打开它以嵌入 OCSP 和 CRL
- 我嵌入了 OCSP 和 CRL 项,创建了各自的 DSS 和 VRI 字典
- 我将 PDF 保存到磁盘
对于 PDFBox,签名代码是 here,对于 OCSP/CRL 嵌入代码是 here。 对于 iText7,用于签名和 OCSP/CRL 嵌入的代码是here。
问题
现在,这适用于大多数 PDF 文件,包括多重签名文档。问题在于一个特定的 PDF,它被创建为 PDF/A compliat,级别 3A。
使用 PDFBox,如果我只是嵌入签名并在 Adobe Acrobet 中打开文档,则签名是有效的。如果我还嵌入了 OCSP/CRL 内容,则签名不再有效。 Adobe Acrobat 抱怨说:
签名无效:文档自签名后已被更改或损坏。
我也注意到,只是这样做:
document.load(inputStream);
document.save(outputStream);
我破坏了签名。根据我的测试,实际嵌入并不是问题的真正原因,而只是我在嵌入签名后重新打开 PDF 并将其保存回磁盘。
通过 iText7 使用相同的过程(密钥、证书等),我最终在 Adobe Acrobat 中获得了有效的 LTV 签名。
示例 PDF
示例文档为here。原件包含未签名的文档,然后有2个样本,一个用于PDFBox(在Adobe Acrobat中无效),一个用于iText7(在Adobe Acrobat中有效)。
到目前为止,我的研究表明,在签名嵌入后加载 PDF 时,PDFBox 以某种方式破坏了元素的顺序。它提示 this issue 加载和保存文档,尽管对于所有其他 PDF 我执行相同的过程并且 Adobe Acrobat 不会抱怨签名。
我还尝试使用 PDFBox 2.1.0-SNAPSHOT 和 3.0.0-SNAPSHOT,希望问题与 PDF 中元素的排序有关,并且已修复。不过,我得到了相同的结果。
稍后编辑 1
请看下面的后期编辑2,这里的后期编辑1不是个好主意!
根据@mkl 下面接受的答案,问题出在原始 PDF 文件上,其中包含分成几个小节而不是一个小节的交叉引用表。这似乎是由最初生成 PDF 的服务使用的库(Aspose PDF for .NET,版本 21.3 或更早版本)引起的。
似乎适用于我当前代码的一种解决方法如下:
PDDocumentInformation info = pdDocument.getDocumentInformation();
if (info != null && StringUtils.containsIgnoreCase(info.getProducer(), "Aspose")) {
try {
pdDocument.save(inMemoryStream);
pdDocument.close();
pdDocument = PDDocument.load(inMemoryStream.toByteArray());
inMemoryStream.reset();
} catch (Exception e) {
基本上,如果我检测到文档的创建者是 Aspose,我会将文档保存在内存中(通过 PDFBox 的 pdDocument.save())并将其加载回来。这可确保交叉引用表在内存中正确写入,并且从那里签名和 OCSP+CRL 嵌入按预期工作,从而在 Adobe Acrobat 中生成有效签名。
稍后编辑 2
谢谢@mkl 和@TilmanHausherr,你是对的。假设使用某个库生成的所有文档都必须自动标准化并不是一个好主意,因为现有签名将失效。最后,更好的办法是保持代码不变,并期待一个正确构建的 PDF。修复创建位置的问题。
【问题讨论】:
-
您似乎正在使用 Aspose.PDF for .NET 生成/签署 PDF 文档。请确保使用最新版本的 API,即 21.8,如果您仍然收到有问题的 PDF,请在我们的官方 Aspose.PDF 支持论坛 (forum.aspose.com/c/pdf/10) 中分享完整的详细信息和代码 sn-p,我们将在其中进行调查并相应地解决问题。请注意,我们的支持论坛是报告和跟踪此类问题的正确场所。我是 Asad Ali,我是 Aspose 的开发人员布道师。
-
@AsadAli 更重要的是,OP 似乎已获得使用 Aspose.PDF 生成的 PDF 作为基于 iText 和 PDFBox 的签名方法的测试文档。特别是他没有使用 Aspose.PDF 签名,因此在意识到问题实际上是由他的测试文档中的错误而不是他的代码。
-
您的最后一次编辑使签署现有文件的整个想法无效。 (如果您的文件已经有签名,那么您保存它会使该签名无效)
-
关于您的第二次编辑 - 您可能需要考虑更改您的 iText 代码以登录增量更新,以免破坏以前的签名。或者首先检查 PDF 是否包含签名,在这种情况下使用附加模式。
标签: java pdf pdfbox signing pades