【问题标题】:ECDSA signed PDF fails signature verification with iText 7 (C#), but succeeds with Adobe Reader DCECDSA 签名的 PDF 无法使用 iText 7 (C#) 进行签名验证,但使用 Adob​​e Reader DC 成功
【发布时间】:2021-07-16 18:14:05
【问题描述】:

我使用 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
}
// ...

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

{
  "$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 编写的)。

我在this google drive 中添加了一个示例 pdf,以及一些签名版本的组合。它包含一个样本 pdf,它是无符号的和纯的。然后使用 ECDSA 和 RSA 密钥分别对该 pdf 进行签名。然后,它们都使用相反类型的密钥进行签名。以及他们所有的验证结果。注意:在 json 文件中,integrityAndAuthenticity 为简洁起见只是命名为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 规范来引用它。尽管如此,它解决了我的问题。 (我还在驱动器sample_signed_ecdsa_Rfc3279DerSequence.pdf 中添加了一个新的pdf 和相应的响应JSON。)可能默认情况下它使用DSASignatureFormat.IeeeP1363FixedFieldConcatenation,因为指定该参数并没有改变签名的有效性,但指定另一个就可以了在 iText 7 中也有效。

至于互操作性,我不确定如何更改我的代码以使用IExternalSignatureContainer。我是这个数字签名的新手,我只关注了他们网站上的 iText 5 书和更新的 iText 7 示例,不幸的是,除了 API 参考之外,我找不到关于它的示例或文档。

【问题讨论】:

  • 请分享有问题的 PDF。没有它,这只是猜测。
  • @mkl 我添加了一些 PDF 示例。
  • 我只是 d/l'ed 文件。我今天晚些时候再看看。
  • 好的,您的签名值格式不正确。 Adobe Acrobat 似乎忽略了这个细节,但 BouncyCastle 没有。下周我会检查更多并写一个答案。

标签: c# pdf digital-signature itext7 ecdsa


【解决方案1】:

您的 ECDSA 签名中存在一个问题,该问题仅被 Adob​​e Acrobat 而不是 iText 7 忽略。

有两种主要的格式可以对 ECDSA 签名值进行编码:

  • 作为 TLV SEQUENCE 的两个 INTEGER

    ECDSA-Sig-Value ::= SEQUENCE {
      r  INTEGER,
      s  INTEGER
    }
    

    (参见 ANSI X9.62、RFC 5480SEC 1: Elliptic Curve Cryptography,在 SECG 文档中由两个额外的可选值扩展);

  • 作为两个具有固定长度的整数的串联(参见BSI TR-03111),也就是普通格式。

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

  • SHA512withECDSA (OID 1.2.840.10045.4.3.4) 暗示使用 TLV SEQUENCE 格式。
  • SHA512withPLAIN-ECDSA (OID 0.4.0.127.0.7.1.1.4.1.5) 暗示使用纯格式。

不幸的是,您的 ECDSA CMS 签名容器 SignerInfo 对象的 OID 为 1.2.840.10045.2.1,签名算法应该在该位置;并且该 OID 只是 ECDSA 公钥的 OID,根本不是特定的算法标识符。在不同的验证器中,这具有不同的效果:

  • Adobe Acrobat 忽略 OID 作为签名算法 OID 无效,并接受 TLV 和纯格式的签名。
  • iText 7 忽略 OID 作为签名算法 OID 无效,并假定 SHAXXXwithECDSA,即期望 TLV 编码的签名值。
  • eSig DSS 认为由于 OID 作为签名算法 OID 无效而导致签名被密码破解。

因此,如果您只需要 Adob​​e Acrobat 和 iText 7 接受您的签名,只需确保 ECDSA 签名值采用 TLV 格式即可。

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

【讨论】:

  • 非常感谢您的广泛响应。我使用的 sign() 方法接受这个 DSASignatureFormat 枚举。在我没有将它作为参数提供之前,所以我假设它使用了 IeeeP1363FixedFieldConcatenation 值,因为我现在已经尝试了两者,并且没有在我的代码中更改任何其他内容,它与 Rfc3279DerSequence 一起使用。但我很困惑,因为这使用不同的标准来指代您所做的事情。为了清楚起见,我将更新我的问题并添加我的签名代码。 docs.microsoft.com/en-us/dotnet/api/…
  • “但我很困惑,因为这使用不同的标准来指代你所做的事情。” - 嗯,这方面的很多标准都是相互复制的,或者可能更正确,互相描述。如果您查看 RFC 3279,第 2.2.3 节 ECDSA 签名算法“椭圆曲线数字签名算法 (ECDSA) 在 [X9.62] 中定义”开头。 而 X9.62 是我引用的来源之一;此处的 RFC 仅描述了用于 X.509 PKI 的 ECDSA(和其他算法)。此外,我提到的 RFC 5480 实际上更新了 RFC 3279。
  • BSI TR-03111 也指 IEEE P1363 和 P1363a,它没有发明普通格式,只是将其与 1.2.840.10045.4 下的某些 OID 相关联
猜你喜欢
  • 2020-03-05
  • 1970-01-01
  • 1970-01-01
  • 2020-06-11
  • 2013-07-01
  • 1970-01-01
  • 2020-07-11
  • 1970-01-01
相关资源
最近更新 更多