JVM:通过三个步骤签署 PDF 文件
JVM: signing a PDF file in three steps
我有一个网站,允许用户签署任何给定的上传文件。工作流程是:
- 用户上传文件。计算文件的 SHA256 摘要并将其存储在数据库中。
- 其他用户使用 RSA 对 SHA256 摘要进行签名。签名已添加到数据库中。
- 用户可以下载文件和签名(目前在单独的文件中)。签名文件是根据要求生成的。签名文件基本上是 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 是否以及如何允许这样做!
编辑后的工作流程,即
- Other users signs the SHA256 digest using RSA. The signatures are added to the database.
而不是
- 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 并行签名的签名者之一的信息。
我有一个网站,允许用户签署任何给定的上传文件。工作流程是:
- 用户上传文件。计算文件的 SHA256 摘要并将其存储在数据库中。
- 其他用户使用 RSA 对 SHA256 摘要进行签名。签名已添加到数据库中。
- 用户可以下载文件和签名(目前在单独的文件中)。签名文件是根据要求生成的。签名文件基本上是 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 是否以及如何允许这样做!
编辑后的工作流程,即
- Other users signs the SHA256 digest using RSA. The signatures are added to the database.
而不是
- 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 并行签名的签名者之一的信息。