使用 adbe 签署 PDF。pkcs7.detached

Signing a PDF with adbe.pkcs7.detached

我有一个用 C 编写的 PDF 生成器,现在我想给它添加数字签名。我从一个最小的 PDF 开始,用 JSignPdf, and am now trying to get my own program to produce a file that Adobe Acrobat Reader will interpret identically. I've checked the Digitally sign PDF files 问题签名,但那里的评论似乎得出结论,应该使用 iText 而不是尝试自己做。我不要那个。

更新: 我确实也阅读了 1.7 的 PDF 参考和下面的“32000”规范 linked,但有时我对参考的数量感到有点迷茫。从一个工作示例开始通常是我理解所有内容如何组合在一起的最简单方法。很抱歉在我的初始 post.

中没有说清楚

我已经让 Acrobat Reader 确认文件中有签名,但仍然有问题。在签名面板中,它显示 "Signed by Unknown" 而不是使用密钥中的正确名称。打开 "Signature Properties" 时显示 "This signature is invalid because there are errors in the formatting or information contained in this signature"。在"Advanced Signature Properties"上,哈希算法是"Not available".

根据 Acrobat Reader,来自 JSignPdf 的 PDF 是正确的。告诉它接受我的自签名证书后,它会显示一个漂亮的绿色签名复选框。为了找到所需的最少添加,我已经清除了一个又一个 PDF 标签,小心地不更改剩余标签的偏移量。这给出了与上面相同的 "This signature is invalid..." 错误消息,但它仍然显示 "The signer's identity is valid",并将哈希算法显示为 "SHA1".

问题是造成这种差异的原因是什么,是否有任何工具可以更详细地解释错误是什么?

在 /Type/Catalog 词典中,我有一个 /AcroForm。我试过将它放在适当的位置并作为参考,但这没有区别。 /AcroForm 包含 /SigFlags 3 和 /Fields [ x 0 R ],其中 x 是 /Type/Annot 和 /Subtype/Widget 的 ID。 ("endobj" 移到“>>”行以在此处保存一些 space。)

更新: 有一些词典,尽管我现在不记得它们的名字了,其中 "in place" 与 "reference" 很重要。特别是 1.7 规范中的实现说明有一些这样的内容,还有一些 "the spec says this field is optional, but actually it's required".

2 0 obj <<
 /Type /Catalog
 /Pages 3 0 R
 /AcroForm <<
  /Fields [ 8 0 R ]
  /SigFlags 3
  >>
 >> endobj

在 /Type/Page 对象中,我有 /Annots [ x 0 R ],这似乎是让 Acrobat Reader 接受这里有任何签名所必需的。

更新:有了有效的签名,事情发生了一些变化。如果没有此参考,Acrobat Reader 确实会说签名有效,但不会显示任何相关细节。有了它,"Signature Properties" 菜单项再次启用。

4 0 obj <<
 /Type /Page
 /Parent 3 0 R
 /Resources <<
  /ProcSet [/PDF /Text]
  /Font << /F1 6 0 R >>
  >>
 /MediaBox [0 0 595 842]
 /Contents 5 0 R
 /Annots [ 8 0 R ]
>> endobj

/Annot 字典包含 /T(Signature1)、/FT/Sig、/Rect[0 0 0 0] 和 /V y 0 R,其中 y 是一个 /Type/Sig 对象。 JSignPdf 版本还包含“/F 132”和“/P 4 0 R”,但我在 PDF Specification 中找不到它们。无论如何,它们似乎都不是必需的。

更新:啊,我错过了12.7.1到12.5.2的link

8 0 obj <<
 /Subtype/Widget
 /T(Signature1)
 /V 7 0 R
 /Type/Annot
 /FT/Sig
 /Rect [ 0 0 0 0 ]
>> endobj

/Type/Sig对象包含/Filter/Adobe.PPKLite,/SubFilter/adbe.pkcs7.detached,/M(D:20160907094326+02'00'),一个/ByteRange数组和一个 /Contents 字符串。

更新: 我正在使用这个组合,因为它被推荐用于 PDF/A。

7 0 obj <<
 /Contents <3082031f...>
 /Filter/Adobe.PPKLite
 /Type/Sig
 /ByteRange [ 0 904 2907 527 ]
 /SubFilter/adbe.pkcs7.detached
 /M(D:20160907094326+02'00')
>> endobj 

/ByteArray 具有以下值:0、最后一个字节前的偏移量“<”-in-Contents、第一个字节后的偏移量“>”以及文件的其余部分。如果我从 JSignPdf 获取文件,运行 这个(其中 buf 包含文件数据):

SHA1_Init(ctx);
SHA1_Update(ctx, buf + offset1, len1);
SHA1_Update(ctx, buf + offset2, len2);
SHA1_Final(digest, ctx);

我得到的数据与“:messageDigest”标签的 PKCS7 数据完全相同。我自己的文件也是如此。所以,我相信这些值是正确的。

使用相同的证书和密钥,我得到完全相同的 PKCS7 数据,当然除了 messageDigest 和 rsaEncryption 十六进制转储。但是,将 JSignPdf PKCS7 数据复制到我的文件(因为它们的长度完全相同)不起作用,它仍然抱怨找不到哈希算法。我在 JSignPdf 中的 PKCS7 数据有效,但当然给出了错误的校验和。因此,与 OpenSSL 相关的所有内容很可能是正确的,问题一定出在 PDF 标签的某个地方。是否有我遗漏的参考,或者必须遵循的某些标签或对象顺序?

已解决: 此时唯一剩下的事情就是 ByteRange 标签的值。第一个长度实际上还可以。但是,第二个偏移量在实现中偏离了 1,因为 1 太小了。调整这个,我得到了一个绿色的签名复选框!

简而言之,

您可能遇到了一次性问题,请参阅答案末尾的粗体段落。如果这不是您的问题,请分享有问题的文件以供分析。

首先,

在尝试操作某种格式的文件之前,请考虑阅读该格式的规范。

PDF 规范是 ISO 32000-1(第 2 部分正在建设中),您可以在 Adob​​e 的网站上下载一个有少量更改的免费副本(明确这不是 ISO 副本):

http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/PDF32000_2008.pdf

(在你的问题文本中间,你表明你确实知道这份文件存在,但你也表明你没有正确研究过它。)

有关集成 PDF 签名的初步概述,请查看信息安全堆栈交换上的 this answer

详细,

话虽如此,让我们看看您的问题并为您指出规范中的一些适当部分:

In the /Type/Catalog dictionary, I have an /AcroForm. I've tried putting it both in place and as a reference, but that makes no difference. The /AcroForm contains /SigFlags 3 and /Fields [ x 0 R ], where x is the id of a /Type/Annot with /Subtype/Widget. (The "endobj" is moved to the ">>" line to save some space here.)

文档目录在7.7.2节指定。

AcroForm 字典指定为

AcroForm dictionary (Optional; PDF 1.2) The document’s interactive form (AcroForm) dictionary (see 12.7.2, "Interactive Form Dictionary").

特别是它没有指定它是否是直接宾语。因此,确实"that makes no difference"

交互式表单词典在第 12.7.2 节中指定。

特别是,

SigFlags integer (Optional; PDF 1.3) A set of flags specifying various document-level characteristics related to signature fields (see Table 219, and 12.7.4.5, “Signature Fields”). Default value: 0.

...

1 "SignaturesExist" If set, the document contains at least one signature field. This flag allows a conforming reader to enable user interface items (such as menu items or pushbuttons) related to signature processing without having to scan the entire document for the presence of signature fields.

2 "AppendOnly" If set, the document contains signatures that may be invalidated if the file is saved (written) in a way that alters its previous contents, as opposed to an incremental update. Merely updating the file by appending new information to the end of the previous version is safe (see H.7, “Updating Example”). Conforming readers may use this flag to inform a user requesting a full save that signatures will be invalidated and require explicit confirmation before continuing with the operation.

Fields array (Required) An array of references to the document’s root fields(those with no ancestors in the field hierarchy).

以及描述交互形式的整个 12.7 节。

In the /Type/Page object, I have /Annots [ x 0 R ], which seemed to be required to get Acrobat Reader to accept that there was any signature here at all.

第 12.5 节描述了注释。

签名域是表单域。表单字段可以在某些页面上具有可视化效果。此类可视化是 Widget 注释。如果一个表单域只有一个控件注解,表单域对象和控件对象可以合并为一个对象。

某些页面上的所有注释均引用自该页面的 Annots 数组。

但是不,您可以拥有不可见的签名(它们确实出现在 Adob​​e Reader 签名面板中,只是不出现在文档中),不需要从页面引用注释。

The /Annot dictionary contains /T(Signature1), /FT/Sig, /Rect[0 0 0 0], and /V y 0 R, where y is a /Type/Sig object. The JSignPdf version also contains "/F 132" and "/P 4 0 R", but I can't find them in the PDF Specification. They don't seem to be required anyway.

啊,所以你知道规格。请使用它!

TFTV 是表单字段条目,请参见。第 12.7.3.

RectTypeFP 是注释条目,请参见。第 12.5.2.

The /Type/Sig object contains /Filter/Adobe.PPKLite, /SubFilter/adbe.pkcs7.detached, /M(D:20160907094326+02'00'), a /ByteRange array and a /Contents string.

所有这些条目都在第 12.8.1 节中指定,并在 12.8 的其余部分中更广泛地指定。

The /ByteArray has for values: 0, offset-of-last-byte-before-"<"-in-Contents, offset-of-first-byte-after-">", and the length of the remainder of the file.

指定为

ByteRange array (Required for all signatures that are part of a signature field and usage rights signatures referenced from the UR3 entry in the permissions dictionary) An array of pairs of integers (starting byte offset, length in bytes) that shall describe the exact byte range for the digest calculation. Multiple discontiguous byte ranges shall be used to describe a digest that does not include the signature value (theContents entry) itself.

..

This range should be the entire file, including the signature dictionary but excluding the signature value itself (the Contents entry).

(尽管这只是一个建议,但通常不接受不遵循此建议的签名。)


你的 offset-of-last-byte-before-"<"-in-Contents 看起来很奇怪,应该是 "< ",即"<"之前部分的长度。

除此之外,您似乎已经正确识别了所讨论的值。如果这不是您问题的原因,那么我认为您的 PDF 或您注入的签名容器中还有其他问题。请共享有问题的文件(例如通过 public 保管箱或 google 驱动器共享)以供进一步分析。


综上所述,根据您开发签名代码的用例,您可能应该研究 PAdES 风格的签名,而不是好的老式签名。

证书始终由证书颁发机构认证。因此,证书由权威机构签署。要检查证书,意味着要验证此签名,因此您需要授权证书 必须可以在某些根 CA 中处理。 您的签名 pdf 证书是自我认证的。您需要将自签名证书放入证书密钥库的根 CA 配置单元中。