我一直在使用itextpdf-5.5.5,并且完整性检查返回false。
PdfPKCS7 pkcs7 = fields.verifySignature(name);
pkcs7.verify();<------ HERE return false
但Adobe Acrobat Reader说:已签名且所有签名均有效。 :(
这是文件:Test.pdf。
有人可以解释发生了什么吗?
提前致谢
答案 0 :(得分:3)
PDF中嵌入的CMS签名容器具有一些可疑属性。特别是它具有封装内容,即使它只是一个长度为0的字节数组。这使得iText在测试中包含该值然后失败。我建议创建更清洁的签名容器。
CMS对象类型EncapsulatedContentInfo
指定为:
5.2。 EncapsulatedContentInfo类型
内容以EncapsulatedContentInfo:
类型表示EncapsulatedContentInfo ::= SEQUENCE { eContentType ContentType, eContent [0] EXPLICIT OCTET STRING OPTIONAL } ContentType ::= OBJECT IDENTIFIER
EncapsulatedContentInfo类型的字段具有以下内容 含义:
eContentType是一个对象标识符。对象标识符 唯一指定内容类型。
eContent是内容本身,以八位字符串形式携带。该 电子内容无需进行DER编码。
可选的省略电子内容 EncapsulatedContentInfo字段使得构造成为可能 &#34;外部签名&#34;。在外部签名的情况下, EncapsulatedContentInfo值中不存在正在签名的内容 包含在签名数据内容类型中。如果是eContent值 在EncapsulatedContentInfo中没有,那么signatureValue就是 计算并分配eContentType,就像电子内容一样 价值存在。
因此,对于嵌入到PDF中的签名容器,应省略eContent
以表示此eContent
未签名但是单独的数据,即周围的PDF数据。
OP签名文档的签名容器包含此EncapsulatedContentInfo
对象:
<30 0F>
43 15: SEQUENCE {
<06 09>
45 9: OBJECT IDENTIFIER data (1 2 840 113549 1 7 1)
: (PKCS #7)
<A0 02>
56 2: [0] {
<04 00>
58 0: OCTET STRING
: }
: }
因此,这个签名容器没有省略eContent
,因此iText将此数组包含在其检查中以最终失败。
我以一种相当克制的方式制定了上述内容,原因很简单:尽管EncapsulatedContentInfo
类型的使用具有误导性,但在手边的情况下并非完全无效!
对于原始ISO 32000-1集成签名,该规范指定
当使用PKCS#7签名时,内容的值应为DER编码的PKCS#7二进制数据 包含签名的对象。 PKCS#7对象应符合RFC3852加密消息 句法。可以使用不同的子过滤器,并应按照附录E进行注册。 SubFilter 应 采用以下值之一:
adbe.pkcs7.detached :文档字节范围内的原始签名消息摘要应为 作为正常的PKCS#7 SignedData字段合并。 PKCS#7中不应封装任何数据 SignedData字段。
adbe.pkcs7.sha1 :文档字节范围的SHA1摘要应封装在PKCS#7中 带有DataInfo的ContentInfo的SignedData字段。该SignedData的摘要应合并为 正常的PKCS#7消化。
(ISO 32000-1部分12.8.3.3 PKCS#7 ISO 32000中使用的签名)
因此,对于这样的签名,要么没有封装数据(甚至不是零长度字节数组),要么封装数据是要检查的摘要值。
这就是为什么iText的验证码在一个地方假设它是在后一种情况下:因为有一些封装的内容,它必须是要检查的哈希。
但是,手头的签名不是原始类型之一,而是使用 SubFilter ETSI.CAdES.detached 。这些签名最初由ETSI指定:
4.2一般要求
对于本文件中涉及的所有概况:
b)CMS(RFC 3852)中指定的DER编码的SignedData对象应作为PDF包含在内 使用ISO 32000-1中描述的签名字典的内容键的条目中的签名, 第12.8.1条。此CMS对象形成TS 101 733中描述的CAdES签名,因为它可能包含 以下条款中给出的规则所要求的几个属性。
d)ISO 32000-1中规定的要求,条款12.8.3.2(PKCS#1)和12.8.3.3(PKCS#7)签名为 ISO 32000-1中使用的不适用。
4.6.2文件摘要
验证者应检查文件摘要是否与ISO 32000-1中规定的签名中的文摘摘要相匹配, 第12.8.1条
因此,对于当前情况下的签名,以前部分引用的ISO 32000-1部分不适用,签名中的散列(消息摘要属性)必须与文档摘要匹配(按定义计算)通过ISO 32000-1,即仅针对定义的字节范围),而不考虑封装内容。
如果您在调用PdfPKCS7
之前稍微修补了PdfPKCS7.verify()
对象,则可以使用iText正面验证该文档,参见测试VerifySignature.java:
原始验证
System.out.println("Signature name: " + name);
System.out.println("Signature covers whole document: " + acroFields.signatureCoversWholeDocument(name));
PdfPKCS7 pk = acroFields.verifySignature(name);
System.out.println("Subject: " + CertificateInfo.getSubjectFields(pk.getSigningCertificate()));
System.out.println("Document verifies: " + pk.verify());
返回失败
Signature name: Signature1
Signature covers whole document: false
Subject: {SURNAME=[CHARPENTIER DIAZ], C=[CR], OU=[CIUDADANO], SN=[CPF-01-1093-0964], CN=[JOSE ALBERTO CHARPENTIER DIAZ (FIRMA)], GIVENNAME=[JOSE ALBERTO], O=[PERSONA FISICA]}
Document verifies: false
修补验证
System.out.println("Signature name: " + name);
System.out.println("Signature covers whole document: " + acroFields.signatureCoversWholeDocument(name));
PdfPKCS7 pk = acroFields.verifySignature(name);
System.out.println("Subject: " + CertificateInfo.getSubjectFields(pk.getSigningCertificate()));
Field rsaDataField = PdfPKCS7.class.getDeclaredField("RSAdata");
rsaDataField.setAccessible(true);
Object rsaDataFieldContent = rsaDataField.get(pk);
if (rsaDataFieldContent != null && ((byte[])rsaDataFieldContent).length == 0)
{
System.out.println("Found zero-length encapsulated content: ignoring");
rsaDataField.set(pk, null);
}
System.out.println("Document verifies: " + pk.verify());
返回成功:
Signature name: Signature1
Signature covers whole document: false
Subject: {SURNAME=[CHARPENTIER DIAZ], C=[CR], OU=[CIUDADANO], SN=[CPF-01-1093-0964], CN=[JOSE ALBERTO CHARPENTIER DIAZ (FIRMA)], GIVENNAME=[JOSE ALBERTO], O=[PERSONA FISICA]}
Found zero-length encapsulated content: ignoring
Document verifies: true
(补丁尝试轻柔,只将零长度字节数组补丁到null
。)