JVM:通过三个步骤签署 PDF 文件

JVM: signing a PDF file in three steps

我有一个网站,允许用户签署任何给定的上传文件。工作流程是:

  1. 用户上传文件。计算文件的 SHA256 摘要并将其存储在数据库中。
  2. 其他用户使用 RSA 对 SHA256 摘要进行签名。签名已添加到数据库中。
  3. 用户可以下载文件和签名(目前在单独的文件中)。签名文件是根据要求生成的。签名文件基本上是 HTML 文件,包含可以打印存档的 Base64 和 QRCode 格式的校验和、签名和证书。

此外,数据库还包含用户的 public 密钥和证书(以及非技术用户的加密私钥,以便应用程序可以为他们处理整个签名过程)。

现在我想调整工作流程以支持特定的 PDF 文件,因为 PDF 文件具有特定的签名支持。折腾了几天PDFBox,成功单独签署了一个PDF文件,但不知道如何适应我平时的工作流程。

目前PDFBox签名的用法是:

ExternalSigningSupport externalSigning =
                document.saveIncrementalForExternalSigning(output);

byte[] cmsSignature = sign(externalSigning.getContent());

externalSigning.setSignature(cmsSignature);

签名的 PDF 文件然后流式传输到 output

摘要和签名的计算,以及将签名和证书合并到PDF文件中,在上面的"sign"方法中一步完成,这意味着我不知道如何实现我常用的计算摘要(1)、签名(2)和生成签名文件(3)三步的工作流程。此外,我假设 externalSigning.getContent() 给出的 InputStream 不包含整个 PDF 文件,这意味着无法使用我现有的代码检查摘要和签名?

为此,您必须在添加签名字段后存储 PDF,因为 pdf 哈希还包括签名字段属性。如果您尝试在第 3 步再次将签名字段添加到原始 pdf,则存储的签名不是与新哈希匹配的签名。您需要检查 PDFBox 是否以及如何允许这样做!

编辑后的工作流程,即

  1. Other users signs the SHA256 digest using RSA. The signatures are added to the database.

而不是

  1. The user signs the SHA256 digest using RSA. The signature is added to the database.

不能用于可互操作的 PDF 签名,因为它们

  • 每个嵌入式 CMS 签名容器只允许一个 SignerInfo,并且
  • 要求签名对完整的当前文档修订进行签名,签名容器的占位符除外:

(有关更多背景和参考文献,请阅读 this answer。)

因此,多个用户的签名签署了不同的哈希值,并且(对于您的体系结构来说可能更糟)各自的哈希值取决于所有先前签名的签名值。此外,如果您想要带有签名可视化的签名,其中包含 PDF 中签名者的信息,这些可视化应该是签名内容本身的一部分;之后添加它们会导致有关更改字段属性的消息,这是人们通常不愿意看到的签名字段。


不过,如果您不局限于可互操作的 PDF 签名,还有一些选择。例如。 PDF/CAdES-A(一种允许在 PDF 签名字段中进行任意 CAdES-A 签名的专有格式)忽略 "single SignerInfo per embedded CMS signature container" 限制,因此可以允许实际的并行签名。

当然,此类签名不可互操作,通常不会按通用查看器和验证器的要求进行显示和验证。例如。 Adobe Reader 将仅显示 PDF/CAdES-A 并行签名的签名者之一的信息。