繁体   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