PDFBox 1.8.10:填写并签署PDF会生成无效签名 [英] PDFBox 1.8.10: Fill and Sign PDF produces invalid signatures

查看:1249
本文介绍了PDFBox 1.8.10:填写并签署PDF会生成无效签名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I fill (programatically) a form (AcroPdf) in a PDF document and sign the document afterwards. I start with doc.pdf, create doc_filled.pdf, using the setFields.java example of PDFBox. Then I sign doc_filled.pdf, creating doc?filled_signed.pdf, using some code, based on the signature examples and open the pdf in the Acrobat Reader. The entered Field data is visible and the signature panel tells me

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

"There are errors in the formatting or information contained in this signature (The signature byte array is invalid)"

到目前为止,我知道:


  • 单独使用签名代码(即直接创建一些doc_signed.pdf)创建一个有效的签名

  • 隐形签名,可见签名和可见签名存在的问题被添加到现有签名字段中。

  • 问题甚至发生,如果我没有填写表格,但只打开并保存,即:

  • the signature code applied alone (i.e. directly creating some doc_signed.pdf) creates a valid signature
  • the problem exists for "invisible signatures", visible signatures and visible signatures, being added to existing signature fields.
  • the problem even occurs, if I do not fill the form, but only open it and save it, i.e.:

PDDocument doc = PDDocument.load(new File("doc.pdf"));
doc.save(new File("doc_filled.pdf"));
doc.close();


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

suffices to break the afterwards applied signing code.

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

On the other hand, if I take the same doc.pdf, enter the field's values manually in Adobe, the signing code produces valid signatures.

我做错了什么?

更新:

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

@mkl asked me to provide the files, i am talking about (I do not have enough reputation currently, to post all files as links, sorry for that inconvenience):

  • 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

最后一个是通过一次签署和填写文档创建的,使用

the last one was created, by signing and filling the document in one go, using

    doc.saveIncremental(); 

正如我在评论中写的那样,一些

As I already wrote in the comment, some

    setNeedToBeUpdate(true);

似乎不见了。
参考@mkl的第二条评论,我发现这个
SO问题:使用PDFBOX生成的PDF中无法正确显示保存的文本字段值,这也包括某些未显示的输入文本。我给了它第一次尝试,应用

seems to be missing, though. With reference to @mkl 's second comment, I found this SO question: Saved Text Field value is not displayed properly in PDF generated using PDFBOX, which also covers to some entered text not being show. I gave it a first try, applying

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

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

to the field's and form's dictionary, which then shows the fields context, but the signature does not get added in the end. Still I have to look further into that.

更新:
故事在这里继续: PDFBox 1.8.10:填写并签署文档,再次填充失败

推荐答案

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

The cause of the OP's original problem, i.e. that after loading his PDF (for form fill-in) with PDFBox and then saving it, this new PDF cannot be successfully signed using PDFBox signing code, has already been explained in detail in this answer, in short:


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

  • When saving documents regularly, PDFBox does so using a cross reference table.


  • 如果定期保存的文档是从带有交叉引用流的PDF加载的,则交叉引用流字典的所有条目都会保存在预告片词典中。

在t中保存文档时在应用签名的过程中,PDFBox创建了增量更新;因为这样的增量更新要求更新使用与原始版本相同类型的交叉引用,在这种情况下,PDFBox会尝试使用相同的技术。

When saving documents in the process of applying a signature, PDFBox creates an incremental update; as such incremental updates require that the update uses the same kind of cross reference as the original revision, PDFBox in this case tries to use the same technique.


  • 为了识别最初使用的技术,PDFBox在其载入预告片或交叉引用流字典的文档表示中查看字典的类型条目:如果有类型条目值 XRef (为交叉引用流指定),假设为流,否则为表。

  • For recognizing the technique originally used PDFBox looks at the Type entry of the dictionary in its document representation into which trailer or cross reference stream dictionary had been loaded: If there is a Type entry with value XRef (which is so specified for cross reference streams), a stream is assumed, otherwise a table.

因此,对于OP的原始PDF doc.pdf ,其中有一个交叉引用stream:

Thus, in the case of the OP's original PDF doc.pdf which has a cross reference stream:


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

  • After loading and form fill-in the document is saved regularly, i.e. using a cross reference table, but all the former cross reference stream entries, among them the Type, are copied to the trailer. (doc_filled.pdf)

将此保存的PDF加载到交叉引用表进行签名后,使用增量更新再次保存。 PDFBox假定(由于类型预告片条目)现有文件具有交叉引用流,因此在增量更新结束时也使用交叉引用流。 ( doc_filled_signed.pdf

After loading this saved PDF with a cross reference table for signing, it is saved again using an incremental update. PDFBox assumes (due to the Type trailer entry) that the existing file has a cross reference stream and, therefore, uses a cross reference stream at the end of the incremental update, too. (doc_filled_signed.pdf)

因此,最后填写,然后签名的PDF有两个修订版,内部版本带有交叉引用表,外部版本带有交叉引用流。

Thus, in the end the filled-in, then signed PDF has two revisions, the inner one with a cross reference table, the outer one with a cross reference stream.

因为这是无效的,所以Adobe Reader在加载时PDF,在其内部文档表示中修复此问题。修复会更改文档字节。因此,Adobe Reader眼中的签名被破坏。

As this is not valid, Adobe Reader upon loading the PDF, repairs this in its internal document representation. Repairing changes the document bytes. Thus, the signature in Adobe Reader's eyes is broken.

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

Most other signature validators don't attempt such repairs but check the signature of the document as is. They validate the signature successfully.

上面提到的答案也提供了一些解决方法:

The answer referenced above also offers some ways around this:


  • A:加载PDF后表格填写,在定期保存之前从预告片中删除类型条目。如果对此文件应用了签名,则PDFBox将采用交叉引用表(因为误导性类型条目不存在。因此,签名增量更新将有效。

  • A: After loading the PDF for form fill-in, remove the Type entry from the trailer before saving regularly. If signing is applied to this file, PDFBox will assume a cross reference table (because the misleading Type entry is not there. Thus, the signature incremental update will be valid.

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

B: Use an incremental update for saving the form fill-in changes, too, either in a separate run or in the same run as signing. This also results in a valid incremental update.

通常我会提出后一种选择,因为如果PDFBox保存例程与之兼容,前一选项可能会中断彼此。

Generally I would propose the latter option because the former option likely will break if the PDFBox saving routines ever are made compatible with each other.

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

Unfortunately, though, the latter option requires marking the added and changed objects as updated, including a path from the document catalog. If this is not possible or at least too cumbersome, the first option might be preferable.

在手头的情况下OP尝试了后一种选择( doc_filled_and_signed.pdf ):

In the case at hand the OP tried the latter option (doc_filled_and_signed.pdf):

只有当选中文本框时,文本框的内容才可见(使用Acrobat Reader和预览相同的行为)。我标记了PDField,其所有父项,AcroForm,目录以及显示它的页面。

At the Moment the text box's content is only visible, when the text box is selected (with Acrobat reader and Preview the same behaviour). I flag the PDField, all of its parents, the AcroForm, the Catalog as well as the page where it is displayed.

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

He marked the changed field as updated but not the associated appearance stream which automatically is generated by PDFBox when setting the form field value.

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

Thus, in the result PDF file the field has the new value but the old, empty appearance stream. Only when clicking into the field, Adobe Reader creates a new appearance based on the value for editing.

因此,OP还必须标记新的正常外观流(表单字段字典包含引用 N 引用正常外观流的字典的条目 AP 。或者(如果发现更改或添加的条目变得太麻烦),他可能会尝试其他选项。

Thus, the OP also has to mark the new normal appearance stream (the form field dictionary contains an entry AP referencing a dictionary in which N references the normal appearance stream). Alternatively (if finding the changed or added entries becomes too cumbersome) he might try the other option.

这篇关于PDFBox 1.8.10:填写并签署PDF会生成无效签名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆