我想手动验证已签名pdf的完整性。我能够达到: -
PyPDF2
)。这是der
编码的PKCS#7证书。 现在按照pdf specifications
,pdf数据的消息摘要与证书一起存储在/Content
节点中。尝试了很多,但我无法获得最终与散列的pdf内容(由/ByteRange
指定)进行比较的摘要值。
不要理解write signature object data into the dictionary
的最后一部分。这个写实际发生在哪里,我如何提取消息摘要?
答案 0 :(得分:1)
(这更多是评论而不是答案。由于评论的大小和格式限制,我仍然把它写进了一个答案。)
在prior question OP已经插入草图,说明了在 SubFilter ETSI.CAdES.detached 的情况下嵌入PDF中的签名, adbe.pkcs7.detached 或 adbe.pkcs7.sha1 :
但这仅仅是一个草图,并且字面上解释它可能会留下错误的印象,即签名词典中内容条目的值类似于包含“证书”的列表, “签名消息摘要”和“时间戳”。此外,调用此列表的“签名值”也可能会混淆,因为该名称也用于内容的一小部分,请参阅下文。
指定实际内容(参见this document):
当使用PKCS#7签名时,Contents的值应为包含签名的DER编码的PKCS#7二进制数据对象。 PKCS#7对象应符合RFC3852加密消息语法。
(顺便说一句:虽然这里的规范要求数据对象是DER编码的,但是在野外有许多签名的PDF,它们对整个对象使用一些不那么严格的BER编码,而对于部件则使用DER RFC3852也要求进行DER编码。)
包含符合RFC3852 的签名的 PKCS#7二进制数据对象更确切地说是具有 SignedData 内容的 ContentInfo 对象,通常命名为一个“签名容器”。
根据RFC 3852
CMS将内容类型标识符与内容相关联。该 语法必须具有ASN.1类型ContentInfo:
ContentInfo ::= SEQUENCE { contentType ContentType, content [0] EXPLICIT ANY DEFINED BY contentType }
签名数据内容类型应具有ASN.1类型SignedData:
SignedData ::= SEQUENCE { version CMSVersion, digestAlgorithms DigestAlgorithmIdentifiers, encapContentInfo EncapsulatedContentInfo, certificates [0] IMPLICIT CertificateSet OPTIONAL, crls [1] IMPLICIT RevocationInfoChoices OPTIONAL, signerInfos SignerInfos }
在这里,您可以看到可选集合certificates
,其中通常至少包含签署者证书,通常还包含其颁发者证书链。这是上面草图中的“证书”。
您还会看到包含实际签名信息的signerInfos
结构:
SignerInfos ::= SET OF SignerInfo
每个签名者信息以SignerInfo:
类型表示SignerInfo ::= SEQUENCE { version CMSVersion, sid SignerIdentifier, digestAlgorithm DigestAlgorithmIdentifier, signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL, signatureAlgorithm SignatureAlgorithmIdentifier, signature SignatureValue, unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL } SignedAttributes ::= SET SIZE (1..MAX) OF Attribute Attribute ::= SEQUENCE { attrType OBJECT IDENTIFIER, attrValues SET OF AttributeValue }
(在这里你看到RFC调用SignatureValue
的结构......正如已经提到的那样,上面调用整个签名容器“Signature value”的草图可能会混淆,因为这里已经是一个名为的实体那样的。)
您正在查看 adbe.pkcs7.detached 类型PDF签名的已签名PDF字节范围的消息摘要。实际上有两种可能性:
在最简单的SignerInfo
个实例的极少数情况下,没有SignedAttributes
。在这种情况下,SignatureValue
是立即应用于有符号字节范围的签名算法的值。
如果签名算法基于RSA,您可以通过使用签名者的公钥(来自他的证书)解码该值并从解码的DigestInfo对象中提取摘要来检索文档摘要值。
DigestInfo ::= SEQUENCE {
digestAlgorithm DigestAlgorithmIdentifier,
digest Digest }
如果签名算法基于DSA或EC DSA,则根本无法检索摘要值。这些算法只允许您检查您提供的摘要值(例如,在您检索文档时已经散列了文档的带符号字节范围)是否是最初签名的。
在使用SignerInfo
的{{1}}个实例的更常见情况下,您必须在这些SignedAttributes
中搜索由
SignedAttributes
正如评论中已经提到的,我无法解释如何使用Python或openssl向下钻取。您将需要一些知道这些特定ASN.1结构或ASN.1结构的工具。