我有一个用C编写的PDF生成器,现在我想为它添加数字签名。我从一个最小的PDF开始,用JSignPdf签名,现在我正在尝试使用我自己的程序来生成Adobe Acrobat Reader将以相同方式解释的文件。我已经检查了Digitally sign PDF files问题,但是那里的评论似乎得出结论,应该使用iText而不是尝试自己做。我不想要那个。
更新的 我确实还阅读了1.7参考文献和#34; 32000"下面链接的规范,但有时我会因引用数量而丢失一些。从一个工作示例开始通常是我理解所有内容如何组合在一起的最简单方法。很抱歉在我的帖子中没有明确说明。
我已经让Acrobat Reader承认文件中有签名,但仍有问题。在签名面板中,它表示"由Unknown签名"而不是使用密钥中的正确名称。打开"签名属性"它说"此签名无效,因为此签名中包含的格式或信息存在错误"。在"高级签名属性"上,哈希算法是"不可用"。
根据Acrobat Reader,来自JSignPdf的PDF是正确的。在告诉它接受我自己签名的证书后,它会为签名显示一个漂亮的绿色复选框。为了找到所需的最小添加量,我已经逐个清除了一个PDF标记,小心地不更改其余标记的偏移量。这给出了相同的#34;这个签名是无效的......"如上所述的错误信息,但它仍然显示"签名者的身份有效",以及将哈希算法显示为" SHA1"。
问题是这种差异的原因是什么,以及是否有任何工具可以更详细地解释什么是错误的?
在/ Type / Catalog字典中,我有一个/ AcroForm。我已经尝试将它们放在适当位置并作为参考,但这没有任何区别。 / AcroForm包含/ SigFlags 3和/ Fields [x 0 R],其中x是带有/ Subtype / Widget的/ Type / Annot的id。 (" endobj"被移动到">>"行以在此处节省一些空间。)
更新:有一些词典,即使我现在还记不起他们的名字,其中"到位" vs"参考"很重要。特别是1.7规范中的实现说明中有一些,以及一些"规范说这个字段是可选的,但实际上它是必需的"。
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确实会说签名有效,但没有显示任何有关它的详细信息。有了它,&#34;签名属性&#34;菜单项再次启用。
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版本还包含&#34; / F 132&#34;和&#34; / P 4 0 R&#34;,但我无法在PDF Specification中找到它们。无论如何,他们似乎都不需要。
更新:啊,我错过了第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
/ Type / Sig对象包含/Filter/Adobe.PPKLite,/SubFilter/adbe.pkcs7.detached,/ M(D:20160907094326 + 02&#39; 00&#39;),a / ByteRange数组和/内容字符串。
更新:我正在使用此组合,因为建议用于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,最后一个字节的偏移量 - &#34;&lt;&#34; -in-Contents,偏移的第一个字节后 - &#34 ;&gt;&#34;,以及文件其余部分的长度。如果我从JSignPdf获取文件,运行它(其中buf包含文件数据):
SHA1_Init(ctx);
SHA1_Update(ctx, buf + offset1, len1);
SHA1_Update(ctx, buf + offset2, len2);
SHA1_Final(digest, ctx);
我得到与&#34;:messageDigest&#34;的PKCS7数据完全相同的数据。标签。我自己的文件也是如此。所以,我相信这些价值是正确的。
使用相同的证书和密钥,我得到完全相同的PKCS7数据,当然除了messageDigest和rsaEncryption十六进制转储。但是,将JSignPdf PKCS7数据复制到我的文件(因为它们的长度完全相同)并不起作用,它仍然抱怨没有找到哈希算法。我在JSignPdf中的PKCS7数据有效,但当然会给出错误的校验和。因此,与OpenSSL相关的所有内容最有可能是正确的,问题必须出在某处的PDF标签中。是否有我错过的参考文献,或者必须遵循的某些标记或对象排序?
已解决:此时唯一可以使用的是ByteRange标记的值。第一个长度实际上是好的。但是,第二个偏移量在实现中偏离了一个,即1太小。调整这个,我有一个签名的绿色复选框!
答案 0 :(得分:2)
您可能有一次性问题,请参阅答案末尾附近的粗体段落。如果结果不是您的问题,请分享相关文件进行分析。
在尝试以该格式操作文件之前,请考虑阅读格式规范。
PDF规范是ISO 32000-1(第2部分正在构建中),您可以在Adobe的网站上下载一个免费副本,只需进行少量更改(明确表示这不是ISO副本) :
http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/PDF32000_2008.pdf
(在问题文本的中间,您显示您确实知道此文档存在,但您还表明您尚未正确研究它。)
有关集成PDF签名的第一个概述,请查看信息安全堆栈交换中的this answer。
有人说过,让我们看看你的问题,并指出你对规范中某些适当的部分:
在/ Type / Catalog字典中,我有一个/ AcroForm。我已经尝试将它们放在适当位置并作为参考,但这没有任何区别。 / AcroForm包含/ SigFlags 3和/ Fields [x 0 R],其中x是带有/ Subtype / Widget的/ Type / Annot的id。 (&#34; endobj&#34;被移动到&#34;&gt;&gt;&#34;行以在此处节省一些空间。)
文档目录在第7.7.2节中指定。
AcroForm 字典指定为
AcroForm 字典(可选; PDF 1.2)文档的交互式表单(AcroForm)字典(参见12.7.2,&#34;互动表格词典&#34;)。
特别是它没有指定它是否是直接对象。因此,&#34;确实没有区别&#34; 。
交互式表格字典在第12.7.2节中指定。
特别是
SigFlags integer (可选; PDF 1.3)一组标志,指定与签名字段相关的各种文档级特征(参见表219和12.7.4.5,“签名字段“)。默认值:0。
...
1&#34; SignaturesExist&#34;如果设置,则文档至少包含一个签名字段。此标志允许符合本标准的阅读器启用与签名处理相关的用户界面项(例如菜单项或按钮),而无需扫描整个文档是否存在签名字段。
2&#34; AppendOnly&#34;如果设置,则文档包含可能无效的签名,如果以改变其先前内容的方式保存(写入)文件,而不是增量更新。仅通过将新信息附加到先前版本的末尾来更新文件是安全的(参见H.7,“更新示例”)。符合条件的读者可以使用此标志通知请求完整保存的用户签名将无效并需要在继续操作之前进行明确确认。
和
字段 array (必需)对文档根字段(字段层次结构中没有祖先的字段)的引用数组。
以及描述交互式表格的整个12.7节。
在/ Type / Page对象中,我有/ Annots [x 0 R],这似乎是让Acrobat Reader接受这里有任何签名所必需的。
第12.5节描述了注释。
签名字段是表单字段。表单字段可以在某些页面上具有可视化。此类可视化是 Widget 注释。如果表单字段只有一个窗口小部件注释,则表单字段对象和窗口小部件对象可以合并为单个对象。
某些页面上的所有注释都是从页面的 Annots 数组中引用的。
但不,你可以拥有不可见的签名(它们确实出现在Adobe Reader签名面板中,但不会出现在文档中),这些签名不需要从页面引用的注释。
/ Annot字典包含/ T(Signature1),/ FT / Sig,/ Rect [0 0 0 0]和/ V y 0 R,其中y是/ Type / Sig对象。 JSignPdf版本还包含&#34; / F 132&#34;和&#34; / P 4 0 R&#34;,但我无法在PDF规范中找到它们。无论如何,他们似乎都不需要。
啊,所以你知道规范。请使用它!
T , FT , V 是表单字段条目,参见第12.7.3节。
矩形,类型, F 和 P 是注释条目,参见第12.5.2节。
/ Type / Sig对象包含/Filter/Adobe.PPKLite,/SubFilter/adbe.pkcs7.detached,/ M(D:20160907094326 + 02&#39; 00&#39;),a / ByteRange数组和/内容字符串。
所有这些条目都在12.8.1节中指定,在12.8的剩余部分中更广泛地说明。
/ ByteArray的值为:0,最后一个字节的偏移量 - &#34;&lt;&#34; -in-Contents,偏移的第一个字节后 - &#34 ;&gt;&#34;,以及文件其余部分的长度。
指定为
ByteRange 数组(对于作为签名字段一部分的所有签名和从权限字典中的UR3条目引用的使用权签名必需)一对数组整数(起始字节偏移量,字节长度),它将描述摘要计算的确切字节范围。应使用多个不连续的字节范围来描述不包含签名值(theContents条目)本身的摘要。
...
此范围应为整个文件,包括签名词典,但不包括签名值本身(目录条目)。
(尽管这仅仅是一项建议,但通常不接受不遵循此建议的签名。)
你的偏离前一个字节 - &#34;&lt;&#34; -in-Contents 似乎很奇怪,它应该是&#的偏移量34;&lt;&#34 ;,即&#34;&lt;&#;;
之前的部分长度除此之外,您似乎已正确识别有问题的值。因此,如果这不是您的问题的原因,我认为您的PDF或您注入的签名容器中还有其他问题。请分享相关文件(例如,通过公共Dropbox或google驱动器共享)以进行进一步分析。
总而言之,根据用例开发您的签名代码,您可能应该研究PAdES风格的签名,而不是好的OL签名。
答案 1 :(得分:0)
证书始终由证书颁发机构认证。因此,证书由权威机构签署。要检查证书,意味着验证此签名,因此您需要权限证书,该证书必须可用于在某个根CA中处理。 您签署的pdf certifiacte是自我认证的。您需要将自签名证书放在cert密钥库中的根CA hive中。