簡體   English   中英

ECDSA 簽名的 PDF 無法使用 iText 7 (C#) 進行簽名驗證,但使用 Adobe Reader DC 成功

[英]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 5480SEC 1:橢圓曲線密碼學,在 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。

因此,如果您只需要 Adobe Acrobat 和 iText 7 接受您的簽名,那么確保 ECDSA 簽名值是 TLV 格式就足夠了。

另一方面,如果您希望您的簽名更具互操作性,請將基於 iText 7 的簽名代碼更改為使用IExternalSignatureContainer實現(不是IExternalSignature實現),您可以在其中構建正確的 CMS 簽名容器。 請注意,iText 中的 ECDSA 支持是有限的; 特別是,您將不得不使用暗示 TLV 格式的簽名算法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM