当前位置: 首页 > 面试题库 >

PDFBox 1.8.10:“填充并签名” PDF会生成无效的签名

谭锐藻
2023-03-14
问题内容

我在PDF文档中(以编程方式)填写了表格(AcroPdf),然后在文档上签名。我从doc.pdf开始,使用PDFBox的setFields.java示例创建doc_filled.pdf。然后,我根据签名示例使用一些代码对doc_filled.pdf进行签名,以创建doc?filled_signed.pdf,然后在Acrobat
Reader中打开pdf。输入的字段数据可见,签名面板告诉我

“此签名中包含格式或信息方面的错误(签名字节数组无效)”

到目前为止,我知道:

  • 单独应用的签名代码(即直接创建一些doc_signed.pdf)会创建有效的签名
  • 存在将“不可见签名”,可见签名和可见签名添加到现有签名字段的问题。
  • 如果我不填写表格,而仅打开并保存表格,则甚至会出现问题,即:
    PDDocument doc = PDDocument.load(new File("doc.pdf"));
    

    doc.save(new File(“doc_filled.pdf”));
    doc.close();

足以破坏后来应用的签名代码

另一方面,如果我使用相同的doc.pdf,请在Adobe中手动输入该字段的值,签名代码会产生有效的签名。

我究竟做错了什么?

更新:

@mkl要求我提供文件,我正在谈论(我目前没有足够的声誉,无法将所有文件发布为链接,对于给您带来的不便表示抱歉):

  • odc.pdf:https://www.dropbox.com/s/ev8x9q48w5l0hof/doc.pdf ? dl = 0
  • doc_filled.pdf:https://www.dropbox.com/s/fxn4gyneizs1zzb/doc_filled.pdf ? dl = 0
  • doc_filled_signed.pdf:https://www.dropbox.com/s/xm846sj8f9kiga9/doc_filled_signed.pdf ? dl = 0
  • doc_filled_and_signed.pdf:https ://www.dropbox.com/s/5jftje6ke87jedr/doc_filled_and_signed.pdf ? dl =0

通过使用以下方法一次性签名并填写文档来创建最后一个

    doc.saveIncremental();

正如我在评论中所写,

    setNeedToBeUpdate(true);

不过似乎丢失了。参考@mkl的第二条评论,我发现了一个SO问题:“
保存的文本字段”值未正确显示在使用PDFBOX生成的PDF中,该值还覆盖了一些未显示的输入文本。我尝试了一下,申请了

    setBoolean(COSName.getPDFName("NeedAppearances"), true);

到字段和表单的字典中,该字典随后显示字段上下文,但是最后没有添加签名。我仍然需要进一步研究。


问题答案:

OP原始问题的原因,即在用PDFBox加载他的PDF(用于表单填充)然后保存它之后,该新PDF无法使用PDFBox签名代码成功签名,此答案]已经详细说明,简而言之:

  • 当定期保存文档时,PDFBox使用交叉引用表来保存。

    • 如果已经使用交叉引用流从PDF加载了要定期保存的文档,则交叉引用流字典的所有条目都将保存在尾部字典中。
    • 在应用签名过程中保存文档时,PDFBox会创建一个增量更新。由于此类增量更新要求更新使用与原始修订相同的交叉引用,因此在这种情况下,PDFBox尝试使用相同的技术。

    • 用于识别该技术最初使用PDFBox的着眼于 类型 在其文档表示成拖车或交叉参考流字典已加载的字典的项:如果有一个 类型 与值条目 外部参照 (其因此对于交叉引用流指定) ,则假定为流,否则为表。

因此,doc.pdf对于具有交叉参考流的OP原始PDF :

  • 加载并填写表格后,将定期保存文档,即使用交叉引用表,但是将所有以前的交叉引用流条目(包括 Type )复制到预告片中。(doc_filled.pdf

  • 使用交叉引用表加载此保存的PDF以进行签名后,使用增量更新再次保存它。PDFBox假定(由于 Type 尾部条目)现有文件具有交叉引用流,因此,在增量更新结束时也使用交叉引用流。(doc_filled_signed.pdf

  • 因此,最后,已填充然后签名的PDF具有两个修订版本,一个是内部版本,带有一个交叉引用表,另一个是外部版本,带有交叉引用流。

  • 由于无效,因此Adobe Reader在加载PDF时会以其内部文档表示形式对其进行修复。修复会更改文档字节。因此,Adobe Reader眼睛中的签名被破坏了。

  • 大多数其他签名验证者都不会尝试进行此类修复,而是按原样检查文档的签名。他们成功验证了签名。

上面引用的答案还提供了一些解决方法:

  • 答:加载PDF以进行表单填写后,请从预告栏删除“ 类型” 条目,然后定期保存。如果对该文件应用签名,PDFBox将假定一个交叉引用表(因为不存在误导的 Type 条目。因此,签名增量更新将是有效的。

  • B:也可以使用增量更新来保存表单填写更改,无论是在单独运行中还是在与签名相同的运行中。这也会导致有效的增量更新。

通常,我会建议使用后一个选项,因为如果使PDFBox保存例程相互兼容,则前一个选项可能会中断。

但是,遗憾的是,后一种选项要求 将添加和更改的对象标记为已更新,包括来自文档目录的路径。 如果这不可能或至少太麻烦,则首选第一个选项。

在当前情况下,OP尝试了后一种选择(doc_filled_and_signed.pdf):

当选中文本框时(仅使用Acrobat
Reader和Preview具有相同的行为),该文本框的内容仅在当下可见。我标记PDField,它的所有父对象,AcroForm,目录以及显示它的页面。

他将更改的字段标记为 已更新, 但未标记关联的外观流,该外观流在设置表单字段值时由PDFBox自动生成。

因此,在结果PDF文件中,该字段具有新值,但是旧的,空的外观流。仅当单击该字段时,Adobe Reader才会根据要编辑的值创建新外观。

因此,OP还必须标记新的正常外观流(表单字段字典包含引用字典的条目 AP ,其中 N
引用正常外观流)。另外(如果查找更改或添加的条目变得太麻烦了),他可以尝试其他选择。



 类似资料:
  • 我在PDF文档中(以编程方式)填写一个表单(AcroPdf),然后在文档上签名。我从doc.pdf开始,使用pdfbox的setfields.java示例创建doc_filler.pdf。然后我对doc_fill.pdf进行签名,创建doc?filled_signer.pdf,使用一些代码,基于签名示例并在Acrobat Reader中打开pdf。输入的字段数据是可见的,并且签名面板告诉我 “此签

  • 问题内容: 我正在尝试学习使用Apache的pdfBox处理经过数字签名的文档。在测试期间,我创建了一个完全空白的pdf文档。 然后,我使用带有证书的签名功能通过Adobe Reader对该文档进行了签名。 我尝试使用pdfBox打开,保存和关闭签名文件,没有进行任何修改。但是,一旦我在Adobe中打开文件,这些文件将不再有效。 Adobe告诉我:“此签名中包含的格式或信息有错误(支持信息:Sig

  • 我有一个问题与数字签名PDF文件已标记为PDF/A-3A兼容。使用PDFBox(最新版本,2.0.24)最终在Adobe Acrobat中获得无效签名,而使用iText7(最新版本)获得有效签名。目标是获得符合PAdES LTV的签名。 我的流程如下(使用PDFBox和iText7): 打开PDF,创建用于签名的散列(要签名的数据) 我呼叫第三方服务以取回数字签名 在服务响应中,我还获得了OCSP

  • 作为我对客户机/服务器pdf签名研究的一部分,我测试了itext pdf延迟签名示例。不幸的是,我得到的合并空签名pdf和哈希值的pdf ie输出显示无效签名。 下面是我的代码片段 我正在使用pkcss11 usb令牌进行签名

  • PDF下载示例:https://drive.google.com/file/d/12wv1Pb7gh4vCKOGhX4cZ3aOrLSiOo4If/view?usp=sharing 因此,当PDF在A.Reader(连续版本)中打开时,它表示证书无效,因为对该文档所做的更改导致签名无效。 但我看不出有什么变化。我们自己的应用程序只添加了一个签名(证书),为数千个其他PDF添加了正确的签名。未执行其

  • 我对iTextSharp有意见。我有一个带有表单字段的文档,并且我已经为签名生成了字段。当第一个人在文件上签字时,它就会正常工作。Adobe Reader显示有效签名。当我让第二个人在文档上签名时,Adobe Reader显示签名1现在是“未知签名”,签名无效。Adobe reader显示: 此签名中包含的格式或信息有错误(支持信息:SigDict/Contents非法数据)