Dan*_*org 3 pdf-generation openssl pkcs#7
我有一个用 C 编写的 PDF 生成器,现在我想为其添加数字签名。我从一个最小的 PDF 开始,使用JSignPdf对其进行签名,现在尝试使用我自己的程序来生成 Adobe Acrobat Reader 能够进行相同解释的文件。我已经检查了数字签名 PDF 文件问题,但那里的评论似乎得出结论,应该使用 iText 而不是尝试自己做。我不想要这样。
更新: 我确实还阅读了 1.7 的 PDF 参考和下面链接的“32000”规范,但有时我会因为参考的数量而感到有点迷失。从一个工作示例开始通常是我理解所有内容如何组合在一起的最简单方法。抱歉,我在最初的帖子中没有明确说明这一点。
我已让 Acrobat Reader 确认文件中有签名,但仍有问题。在签名面板中,它显示“由未知签名”,而不是使用密钥中的正确名称。打开“签名属性”时,显示“此签名无效,因为此签名中包含的格式或信息存在错误”。在“高级签名属性”上,哈希算法为“不可用”。
根据 Acrobat Reader,JSignPdf 中的 PDF 是正确的。在告诉它接受我的自签名证书后,它会显示一个漂亮的绿色签名复选框。为了找到所需的最少添加内容,我清除了一个又一个 PDF 标签,并小心翼翼地不更改剩余标签的偏移量。这会给出与上面相同的“此签名无效...”错误消息,但它仍然显示“签名者的身份有效”,并将哈希算法显示为“SHA1”。
问题是造成这种差异的原因是什么,是否有任何工具可以更详细地解释错误所在?
在 /Type/Catalog 字典中,我有一个 /AcroForm。我尝试过将其放在适当的位置并作为参考,但这没有什么区别。/AcroForm 包含 /SigFlags 3 和 /Fields [ x 0 R ],其中 x 是带有 /Subtype/Widget 的 /Type/Annot 的 id。(“endobj”被移动到“>>”行以节省一些空间。)
更新:有一些词典,尽管我现在不记得它们的名字,其中“就地”与“参考”很重要。特别是1.7规范中的实现说明中有一些这样的内容,以及一些“规范说这个字段是可选的,但实际上它是必需的”。
2 0 obj <<
/Type /Catalog
/Pages 3 0 R
/AcroForm <<
/Fields [ 8 0 R ]
/SigFlags 3
>>
>> endobj
Run Code Online (Sandbox Code Playgroud)
在 /Type/Page 对象中,我有 /Annots [ x 0 R ],这似乎需要让 Acrobat Reader 接受这里有任何签名。
更新:有了有效的签名,事情就会发生一些变化。如果没有此参考,Acrobat Reader 确实会说签名有效,但不会显示有关签名的任何详细信息。有了它,“签名属性”菜单项将再次启用。
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
Run Code Online (Sandbox Code Playgroud)
/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规范中找不到它们。无论如何,它们似乎并不需要。
更新:啊,我错过了第 12.7.1 节到 12.5.2 节的链接。
8 0 obj <<
/Subtype/Widget
/T(Signature1)
/V 7 0 R
/Type/Annot
/FT/Sig
/Rect [ 0 0 0 0 ]
>> endobj
Run Code Online (Sandbox Code Playgroud)
/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
Run Code Online (Sandbox Code Playgroud)
/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);
Run Code Online (Sandbox Code Playgroud)
我得到的数据与“:messageDigest”标签的 PKCS7 数据完全相同。我自己的文件也是如此。所以,我相信这些价值观是正确的。
使用相同的证书和密钥,我得到完全相同的 PKCS7 数据,当然除了 messageDigest 和 rsaEncryption 十六进制转储。但是,将 JSignPdf PKCS7 数据复制到我的文件(因为它们的长度完全相同)不起作用,它仍然抱怨找不到哈希算法。JSignPdf 中的我的 PKCS7 数据有效,但当然给出了错误的校验和。因此,所有与 OpenSSL 相关的内容很可能都是正确的,问题一定出在 PDF 标签的某个地方。是否有我遗漏的参考,或者必须遵循的某些标签或对象顺序?
已解决:此时唯一需要处理的是 ByteRange 标记的值。第一个长度其实还可以。然而,第二个偏移量在实现中偏离了 1,因为 1 太小了。调整这个,我得到了一个绿色的签名复选框!
您可能会遇到一次性问题,请参阅答案末尾附近的粗体段落。如果这不是您的问题,请共享有问题的文件以供分析。
\n\n在尝试操作某种格式的文件之前,请考虑阅读该格式的规范。
\n\nPDF 规范是 ISO 32000-1(第 2 部分正在建设中),您可以在 Adobe 网站上下载一个经过很少更改的免费副本(明确表明这不是 ISO 副本):
\n\nhttp://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/PDF32000_2008.pdf
\n\n(在问题文本的中间,您表明您确实知道该文档存在,但您也表明您没有正确研究它。)
\n\n有关集成 PDF 签名的初步概述,请查看此答案。
\n\n话虽如此,让我们看看您的问题并向您指出规范的某些适当部分:
\n\n\n\n\n在 /Type/Catalog 字典中,我有一个 /AcroForm。我尝试过将其放置到位并作为参考,但这没有什么区别。/AcroForm 包含 /SigFlags 3 和 /Fields [ x 0 R ],其中 x 是带有 /Subtype/Widget 的 /Type/Annot 的 id。(“endobj”被移动到“>>”行以节省一些空间。)
\n
文档目录在第 7.7.2 节中指定。
\n\nAcroForm指定为
\n\n\n\n\n\n\nAcroForm字典(可选;PDF 1.2) document\xe2\x80\x99s交互式表单 (AcroForm) 字典(请参阅 12.7.2,“交互式表单字典”)。
\n
特别是它没有指定它是否是直接对象。因此,“这没有什么区别”。
\n\n交互式表单字典在第 12.7.2 节中指定。
\n\n尤其,
\n\n\n\n\n\n\nSigFlags整数(可选;PDF 1.3)一组标志,指定与签名字段相关的各种文档级特征(请参见表 219 和 12.7.4.5,\xe2\x80\x9cSignature Fields\xe2\x80\x9d)。默认值:0。
\n\n...
\n\n1 “SignaturesExist” 如果设置,则文档至少包含一个签名字段。该标志允许合格的阅读器启用与签名处理相关的用户界面项(例如菜单项或按钮),而无需扫描整个文档以查找是否存在签名字段。
\n\n2 “AppendOnly” 如果设置,则如果文件以更改其先前内容(而不是增量更新)的方式保存(写入),则文档包含的签名可能会失效。仅通过将新信息附加到先前版本的末尾来更新文件是安全的(请参阅 H.7,\xe2\x80\x9c更新示例\xe2\x80\x9d)。符合要求的读者可以使用此标志来通知请求完全保存的用户,签名将无效,并且在继续操作之前需要明确确认。
\n
和
\n\n\n\n\n\n\n字段数组(必填)对文档\xe2\x80\x99s 根字段(在字段层次结构中没有祖先的字段)的引用的数组。
\n
以及整个 12.7 节描述交互形式。
\n\n\n\n\n在 /Type/Page 对象中,我有 /Annots [ x 0 R ],这似乎需要让 Acrobat Reader 接受这里有任何签名。
\n
12.5 节描述了注释。
\n\n签名字段是一个表单字段。表单字段可以在某些页面上进行可视化。此类可视化是Widget注释。如果表单字段只有一个小部件注释,则表单字段对象和小部件对象可以合并为单个对象。
\n\n某个页面上的所有注释均引用自该页面的注释数组引用的。
\n\n但不,您可以拥有不可见的签名(它们确实出现在 Adobe Reader 签名面板中,但不在文档中),不需要从页面引用的注释。
\n\n\n\n\n/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规范中找不到它们。无论如何,它们似乎并不需要。
\n
啊,所以你确实知道规格。请使用它!
\n\n时间、FT和V是表单字段条目,参见。第 12.7.3 节。
\n\n矩形、类型、F和P是注释条目,参见。第 12.5.2 节。
\n\n\n\n\n/Type/Sig 对象包含 /Filter/Adobe.PPKLite、/SubFilter/adbe.pkcs7.detached、/M(D:20160907094326+02\'00\')、一个 /ByteRange 数组和一个 /Contents 字符串。
\n
所有这些条目均在第 12.8.1 节中指定,并在 12.8 的其余部分中进行了更广泛的指定。
\n\n\n\n\n/ByteArray 的值为:0、最后一个字节之前的偏移量“<”-in-Contents、第一个字节之后的偏移量>”以及文件剩余部分的长度。
\n
它被指定为
\n\n\n\n\n\n\nByteRange数组(对于属于签名字段一部分的所有签名和从权限字典中的 UR3 条目引用的使用权签名来说是必需的)整数对的数组(起始字节偏移量,以字节为单位的长度),应描述确切的字节范围用于摘要计算。应当使用多个不连续的字节范围来描述不包括签名值(内容条目)本身的摘要。
\n\n..
\n\n该范围应该是整个文件,包括签名字典,但不包括签名值本身(内容条目)。
\n
(尽管这只是一个建议,但不遵循此建议的签名通常不被接受。)
\n\n您的offset-of-last-byte-before-"<"-in-Contents看起来很奇怪,它应该是“<”的偏移量,即“<”之前部分的长度。
\n\n除此之外,您似乎已经正确认识到了所讨论的价值观。如果这不是您问题的原因,那么我认为您的 PDF 或您注入的签名容器中仍然存在其他问题。请共享有问题的文件(例如通过公共保管箱或谷歌驱动器共享)以进行进一步分析。
\n\n综上所述,根据您开发签名代码的用例,您可能应该研究 PAdES 风格的签名,而不是好的老式签名。
\n| 归档时间: |
|
| 查看次数: |
6399 次 |
| 最近记录: |