首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ECDSA签署的PDF无法通过iText 7 (C#)进行签名验证,但在Adobe中成功

ECDSA签署的PDF无法通过iText 7 (C#)进行签名验证,但在Adobe中成功
EN

Stack Overflow用户
提问于 2021-04-22 13:54:27
回答 1查看 779关注 0票数 3

我用iText 7创建了代码,它能够使用使用ECDSA密钥对的X509证书对给定的PDF进行数字签名。当我在Acrobat中打开这个已签名的PDF时,它会正确地读取它,并验证它是否有效(自从签名以来,meaing是未修改的,等等)。

但是,当我试图用iText 7验证同一文档时,完整性和真实性检查返回false。

下面是一个示例代码:

代码语言:javascript
复制
// ...
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
}
// ...

以及从签名中提取的示例输出:

代码语言:javascript
复制
{
  "$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编写的)。

我正在添加一个样本pdf,和一些组合的签名版本在这个谷歌硬盘。它包含一个样本pdf,这是没有签名和纯。然后用ECDSA和RSA密钥分别对pdf进行签名。然后,用相反类型的键对它们进行签名。以及他们所有的验证结果。注意:在json文件中,为了简洁起见,integrityAndAuthenticity只是命名为valid,但是它所保存的值是pkcs7.VerifySignatureIntegrityAndAuthenticity()的结果。所有签名都由我的应用程序完成(使用iText 7)。

编辑1:我提供了执行签名的代码:

代码语言:javascript
复制
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.
    }
}

然后:

代码语言:javascript
复制
using (var key = myCertificate.GetECDsaPrivateKey()) {
   /*PdfSigner*/ signer.SignDetached(new EcdsaSignature(key, DigestAlgorithms.SHA512), chainArray, crlList, ocspClient, tsaClient, 0, subfilter);
}

感谢@mkl的响应,它消除了一些关于签名格式的困惑,而且值得庆幸的是,微软支持SignData()方法中的TLV序列格式,所以我不需要逆向工程签名过程来实现我想要的结果。虽然我只假设这个枚举是答案中描述的TLV序列,因为它使用不同的RFCs或IEEE规范来引用它。尽管如此它还是解决了我的问题。(我还添加了一个新的pdf到驱动器sample_signed_ecdsa_Rfc3279DerSequence.pdf和相应的响应JSON。)默认情况下,它可能使用DSASignatureFormat.IeeeP1363FixedFieldConcatenation,因为指定该参数不会更改签名有效性,但指定另一个参数使其在iText 7中也有效。

至于互操作性,我不知道如何将代码更改为使用IExternalSignatureContainer。我是这个数字签名的新手,我只在他们的网站上遵循了iText 5的书籍和更新的iText 7示例,不幸的是,除了API参考之外,我一直找不到关于它的例子或文档。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-04-25 16:00:03

在您的ECDSA签名中存在一个问题,它只被Acrobat忽略,而不是被iText 7所忽略。

有两种主要格式来编码ECDSA签名值:

  • 作为两个SEQUENCE值的TLV INTEGER ::=序列{r整数,s整数} (见ANSX9.62、RFC 5480椭圆曲线密码学,在由两个额外的可选值扩展的SECG文档中);
  • 作为两个具有固定长度的整数的连接(参见BSI TR-03111),也就是普通格式。

要使用的格式取决于所应用的签名算法。例如:

  • SHA512withECDSA (OID1.2.840.10045.4.3.4)意味着使用TLV SEQUENCE格式。
  • 带有plain -ECDSA的the 512 (OID 0.4.0.127.0.7.1.1.4.1.5)意味着使用普通格式。

但是不幸的是,您的ECDSA签名容器SignerInfo对象有一个OID 1.2.840.10045.2.1,其中应该包含签名算法;而OID只是ECDSA公钥的OID,而不是一个特定的算法标识符。在不同的验证器中,这具有不同的效果:

  • Acrobat忽略OID作为签名算法OID无效,并接受TLV和普通格式的签名。
  • iText 7忽略OID作为签名算法OID无效,并假定为SHAXXXwithECDSA,即期望一个TLV编码的签名值。
  • eSig决策支持系统认为,由于签名算法OID无效,签名密码中断。

因此,如果您只需要您的签名被Acrobat和iText 7接受,那么确保ECDSA签名值是TLV格式就足够了。

另一方面,如果您希望您的签名更具互操作性,将基于iText 7的签名代码更改为使用IExternalSignatureContainer实现(而不是IExternalSignature实现),在该实现中生成正确的CMS签名容器。请注意,iText中对ECDSA的支持是有限的;特别是,您必须使用包含TLV格式的签名算法。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67214674

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档