![](/img/trans.png)
[英]C# Itext7 signed pdf signature is invalid in Foxit PDF Reqader but valid in Acrobat reader
[英]ECDSA signed PDF fails signature verification with iText 7 (C#), but succeeds with Adobe Reader DC
我使用 iText 7 创建了代码,该代码能够使用使用 ECDSA 密钥对的 X509 证书对给定的 PDF 进行数字签名。 当我在 Acrobat Reader DC 中打开这个签名的 PDF 时,它会正确读取它,并验证它是有效的(因为签名等原因,文档没有被修改)。
但是,当我尝试使用 iText 7 验证同一文档时,完整性和真实性检查返回 false。
这是一个示例代码:
// ...
PdfDocument pdfDoc = new(new PdfReader(stream));
SignatureUtil signUtil = new(pdfDoc);
IList<string> names = signUtil.GetSignatureNames();
foreach (string name in names) {
PdfPKCS7 pkcs7 = signUtil.ReadSignatureData(name);
bool wholeDocument = signUtil.SignatureCoversWholeDocument(name);
bool signatureIntegrityAndAuthenticity = pkcs7.VerifySignatureIntegrityAndAuthenticity(); // this returns false, even though Adobe has no problem verifying the signature.
// more code to read values and put them in a json
}
// ...
还有我从签名中提取的示例 output:
{
"$id": "1",
"signatures": [
{
"$id": "2",
"integrityAndAuthenticity": false, // <---- should be true in my opinion.
"revisionNumber": 1,
"coversWholeDocument": true,
"invisibleSignature": true,
"filterSubType": "ETSI.CAdES.detached",
"encryptionAlgorithm": "ECDSA",
"hashAlgorithm": "SHA512",
"nameOfSigner": "C=HU, CN=Teszt Elek, GIVENNAME=Elek, L=Budapest, O=Teszt ECC Szervezet, SN=202010260807, SURNAME=Teszt",
"alternateNameOfSigner": null,
"signDate": "2021-04-22T12:50:33Z",
"timestamp": {
"$id": "3",
"signDate": "2021-04-22T12:50:33Z",
"service": "C=HU,L=Budapest,O=Microsec Ltd.,2.5.4.97=VATHU-23584497,CN=Test e-Szigno TSA 2017 01",
"verified": true,
"hashAlgorithmOid": "2.16.840.1.101.3.4.2.3"
},
"location": " Hungary",
"reason": "Approval",
"contactInfo": "",
"name": "GUID_97e1669d-0fbe-409a-a8fc-8518a1bae460",
"signatureType": "approval",
"fillInAllowed": true,
"annotationsAllowed": true,
"fieldLocks": []
}
],
"revisions": 1,
"valid": false // is an aggregate of all the signatures integrity in the array above
}
我使用的是最新的 iText 7 版本,我的平台是 ASP.NET 5 (.Net 5)。 示例代码对应于 iText 自己的示例代码,它们为他们的学习书籍提供(但更新为 7,因为这些书籍是为 iText 5 编写的)。
我在这个 google drive中添加了一个示例 pdf,以及签名版本的一些组合。 它包含一个样本 pdf,它是无符号且纯的。 然后使用 ECDSA 和 RSA 密钥分别对 pdf 进行签名。 然后,它们都使用相反类型的密钥进行签名。 以及他们所有的验证结果。 注意:在integrityAndAuthenticity
文件中,为了简洁起见,integrationAndAuthenticity 被命名为valid
,但它持有的值是pkcs7.VerifySignatureIntegrityAndAuthenticity()
的结果。 所有签名均由我的应用程序完成(使用 iText 7)。
编辑#1:我正在提供进行签名的代码:
using System;
using System.Security.Cryptography;
using iText.Signatures;
public class EcdsaSignature : IExternalSignature
{
private readonly string _encryptionAlgorithm;
private readonly string _hashAlgorithm;
private readonly ECDsa _pk;
public EcdsaSignature(ECDsa pk, string hashAlgorithm)
{
_pk = pk;
_hashAlgorithm = DigestAlgorithms.GetDigest(DigestAlgorithms.GetAllowedDigest(hashAlgorithm));
_encryptionAlgorithm = "ECDSA";
}
public virtual string GetEncryptionAlgorithm()
{
return _encryptionAlgorithm;
}
public virtual string GetHashAlgorithm()
{
return _hashAlgorithm;
}
public virtual byte[] Sign(byte[] message)
{
return _pk.SignData(message, new HashAlgorithmName(_hashAlgorithm), DSASignatureFormat.Rfc3279DerSequence); // <---- I have solved the iText 7 issue by providing this enum to the SignData() method.
}
}
接着:
using (var key = myCertificate.GetECDsaPrivateKey()) {
/*PdfSigner*/ signer.SignDetached(new EcdsaSignature(key, DigestAlgorithms.SHA512), chainArray, crlList, ocspClient, tsaClient, 0, subfilter);
}
感谢@mkl 的回复,它消除了关于签名格式的一些困惑,并且幸运的是微软在SignData()
方法中支持 TLV 序列格式,所以我不必对签名过程进行逆向工程来实现我想要的。 虽然我只假设这个枚举是答案中描述的 TLV 序列,因为它使用不同的 RFC 或 IEEE 规范来引用它。 尽管如此,它解决了我的问题。 (I have also added a new pdf to the drive sample_signed_ecdsa_Rfc3279DerSequence.pdf
and a corresponding response JSON
.) Probably by default it uses DSASignatureFormat.IeeeP1363FixedFieldConcatenation
, because specifying that argument didn't change the signature validity, but specifying the other made it valid in iText 7 也是如此。
现在至于互操作性,我不确定如何更改我的代码以使用IExternalSignatureContainer
。 我是这个数字签名的新手,我只在他们的网站上关注了 iText 5 书和更新的 iText 7 示例,不幸的是,除了 ZDB974238714CA8DE634A7A7C14 参考资料之外,我无法找到有关它的示例或文档。
您的 ECDSA 签名中存在一个问题,该问题仅被 Adobe Acrobat 忽略,而 iText 7 则不会。
编码 ECDSA 签名值有两种主要格式:
作为两个INTEGER
值的 TLV SEQUENCE
ECDSA-Sig-Value::= SEQUENCE { r INTEGER, s INTEGER }
(参见 ANSI X9.62、 RFC 5480和SEC 1:椭圆曲线密码学,在 SECG 文档中由两个附加的可选值扩展);
作为具有固定长度的两个整数的串联(参见BSI TR-03111 ),也就是普通格式。
使用的格式取决于应用的签名算法。 例如:
SEQUENCE
格式。不幸的是,您的 ECDSA CMS 签名容器 SignerInfo 对象的 OID 为 1.2.840.10045.2.1 ,其中签名算法应该是; 并且该 OID 只是 ECDSA 公钥的 OID,根本不是特定的算法标识符。 在不同的验证器中,这具有不同的效果:
因此,如果您只需要 Adobe Acrobat 和 iText 7 接受您的签名,那么确保 ECDSA 签名值是 TLV 格式就足够了。
另一方面,如果您希望您的签名更具互操作性,请将基于 iText 7 的签名代码更改为使用IExternalSignatureContainer
实现(不是IExternalSignature
实现),您可以在其中构建正确的 CMS 签名容器。 请注意,iText 中的 ECDSA 支持是有限的; 特别是,您将不得不使用暗示 TLV 格式的签名算法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.