簡體   English   中英

使用ItextSharp驗證數字簽名

[英]Verify digital signature with ItextSharp

我正在嘗試使用iTextSharp在c#中驗證數字簽名。

我已經在iText網站( http://gitlab.itextsupport.com/itextsharp/tutorial/blob/master/signatures/chapter5/C5_03_CertificateValidation/C5_03_CertificateValidation.cs )中進行了跟蹤,但是結果不是我所期望的。 具體來說,當嘗試通過OCSP或CRL驗證簽名時,結果通常是無法驗證簽名。 我認為這不應該發生,因為Adobe Reader可以驗證簽名。

我用於測試驗證的pdf可以在以下鏈接中找到: https : //blogs.adobe.com/security/SampleSignedPDFDocument.pdf

這是我正在使用的代碼(來自上面鏈接的示例的簡短版本):

static void Main(String[] args)
{
    LoggerFactory.GetInstance().SetLogger(new SysoLogger());
    C5_03_CertificateValidation app = new C5_03_CertificateValidation();
    app.VerifySignatures(EXAMPLE); //Pdf file I'm using to test the verification
}

public void VerifySignatures(String path)
{
    Console.WriteLine(path);
    PdfReader reader = new PdfReader(path);
    AcroFields fields = reader.AcroFields;
    List<String> names = fields.GetSignatureNames();
    foreach (string name in names)
    {
        Console.WriteLine("===== " + name + " =====");
        VerifySignature(fields, name);
    }
    Console.WriteLine();
}

public PdfPKCS7 VerifySignature(AcroFields fields, String name)
{
    PdfPKCS7 pkcs7 = fields.VerifySignature(name);
    X509Certificate[] certs = pkcs7.SignCertificateChain;
    DateTime cal = pkcs7.SignDate;

    X509Certificate signCert = certs[0];
    X509Certificate issuerCert = (certs.Length > 1 ? certs[1] : null);
    Console.WriteLine("=== Checking validity of the document at the time of signing ===");
    CheckRevocation(pkcs7, signCert, issuerCert, cal);
    Console.WriteLine("=== Checking validity of the document today ===");
    CheckRevocation(pkcs7, signCert, issuerCert, DateTime.Now);
    return pkcs7;
}

public static void CheckRevocation(PdfPKCS7 pkcs7, X509Certificate signCert, X509Certificate issuerCert, DateTime date)
{
    List<BasicOcspResp> ocsps = new List<BasicOcspResp>();
    if (pkcs7.Ocsp != null)
        ocsps.Add(pkcs7.Ocsp);
    OcspVerifier ocspVerifier = new OcspVerifier(null, ocsps);
    List<VerificationOK> verification =
        ocspVerifier.Verify(signCert, issuerCert, date);
    if (verification.Count == 0)
    {
        List<X509Crl> crls = new List<X509Crl>();
        if (pkcs7.CRLs != null)
            foreach (X509Crl crl in pkcs7.CRLs)
                crls.Add(crl);
        CrlVerifier crlVerifier = new CrlVerifier(null, crls);
        verification.AddRange(crlVerifier.Verify(signCert, issuerCert, date));
    }
    if (verification.Count == 0)
        Console.WriteLine("The signing certificate couldn't be verified with the example");
    else
        foreach (VerificationOK v in verification)
            Console.WriteLine(v);


    //Code not in the example, added by me
    //This way, I can find out if the certificate is revoked or not (through CRL). Not sure if it's the right way though
    if (verification.Count == 0 && pkcs7.CRLs != null && pkcs7.CRLs.Count != 0)
    {
        bool revoked = false;
        foreach (X509Crl crl in pkcs7.CRLs)
        {
            revoked = crl.IsRevoked(pkcs7.SigningCertificate);
            if (revoked)
                break;
        }

        Console.WriteLine("Is certificate revoked?: " + revoked.ToString());
    }
}

這是我得到的輸出:

===== Signature2 =====

=== Checking validity of the document at the time of signing ===
i.t.p.s.OcspClientBouncyCastle INFO  Getting OCSP from http://adobe-ocsp.geotrust.com/responder
iTextSharp.text.pdf.security.OcspClientBouncyCastle ERROR Error en el servidor remoto: (502) Puerta de enlace no válida.
i.t.p.s.OcspVerifier INFO  Valid OCSPs found: 0
i.t.p.s.CrlVerifier INFO  Getting CRL from http://crl.geotrust.com/crls/adobeca1.crl
i.t.p.s.CrlVerifier INFO  Valid CRLs found: 0
The signing certificate couldnt be verified with the example
Is certificate revoked?: False

=== Checking validity of the document today ===
i.t.p.s.OcspClientBouncyCastle INFO  Getting OCSP from http://adobe-ocsp.geotrust.com/responder
iTextSharp.text.pdf.security.OcspClientBouncyCastle ERROR Error en el servidor remoto: (502) Puerta de enlace no válida.
i.t.p.s.OcspVerifier INFO  Valid OCSPs found: 0
i.t.p.s.CrlVerifier INFO  Getting CRL from http://crl.geotrust.com/crls/adobeca1.crl
i.t.p.s.CrlVerifier INFO  Valid CRLs found: 0
The signing certificate couldnt be verified with the example
Is certificate revoked?: False

我不明白為什么無法驗證簽名,因為Adobe可以做到。 任何想法表示贊賞。

這個問題有兩個方面:

  • 為什么iTextSharp似乎無法驗證Adobe提供的給定示例簽名?
  • 應在哪個日期使用哪個CRL進行吊銷檢查?

使用iTextSharp驗證給定簽名

使用C5_03_CertificateValidation.cs中的示例代碼,OP無法驗證有問題的證書(尤其是簽署者證書)沒有被撤銷,無論是“在簽署時”還是在“今天” 另一方面,我可以立即驗證“在簽署時”

OP的測試與我的測試之間的主要區別在於,前者的測試是使用OP的時區UTC-3進行的,而我的則是使用UTC + 2。

因此,我使用不同的系統時區來運行代碼,並且確實是:驗證僅在UTC-01及以上時區(即UTC-01,UTC,UTC + 01等)成功進行。

測試中DateTime cal = pkcs7.SignDate返回的時間證明是使用當前本地時區給出的。

顯然,因此,CRL驗證碼根據本地時區,而是在一些固定的時區UTC本身使用時間,大概。

因此,可以通過以下方式使示例代碼通用

改變中

 crlVerifier.Verify(signCert, issuerCert, date) 

 crlVerifier.Verify(signCert, issuerCert, date.ToUniversalTime()) 

因為OP可以在測試后確認。

選擇正確的日期和CRL進行吊銷檢查

OP提到他希望使用相關PKI的CRL的當前時間和當前版本執行吊銷檢查。

盡管這種方法似乎利用了最新的可用信息,但其用途有限:

  • 如果受審查的證書現在已經超過其原始有效期(即,其有效截止日期是過去的日期),但不是在簽署之時,則有關簽署時可能撤銷的信息可能不會在認證書上。 CRL了。 實際上,根據RFC 5280

    除非該條目出現在已撤銷證書的有效期之后發布的一個定期計划的CRL中,否則不得將其從CRL中刪除。

    因此,暗示而言, 可以在有效期之后發布的任何版本中將其從CRL中刪除。

    因此,使用比證書有效期末新的CRL是沒有意義的。

  • 即使受審查的證書尚未超過其原始有效期,PKI提供商也可能已經倒閉。 在那種情況下,所有撤銷信息的訪問點現在可能僅服務於PKI仍處於活動狀態時創建的CRL的最終版本,或者根本不提供。

    在那種情況下,只要CRL是足夠新的,就可以使用最終的CRL或最新的CRL(例如在某些CRL緩存中)。

因此,驗證策略通常允許甚至要求使用較舊的CRL,只要它足夠新,至少CRL的nextUpdate值必須在簽名時間之后,並且同時足夠老,至少CRL的thisUpdate值必須在證書有效期結束之前。

但是,要考慮的一項是在檢查是否可以使用較舊的CRL時與之進行比較的簽名時間。

上面的iText示例代碼中使用的pkcs7.SignDate可能只是PDF或CMS容器中某個字段的內容,這些字段可能已經被偽造了:有人可能已經掌握了私鑰; 關聯證書被吊銷后,該人仍可能會濫用密鑰,將簽名時間信息設置為吊銷前的日期。

因此,您可能會以其他方式確定簽署日期。 例如

  • 如果簽名容器包含簽名時間戳,或者PDF文檔包含更高版本的文檔時間戳,並且如果可以信任該時間戳,則可以使用該時間戳的時間;

  • 如果已簽名的文檔已經在本地存儲了一段時間(例如,在某個歸檔系統中),並且存儲時間是已知的並且可以信任,則可以使用該時間;

  • ...

暫無
暫無

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

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