当前位置: 首页 > 知识库问答 >
问题:

使用ItextSharp验证数字签名

阳长恨
2023-03-14

我在iText web上遵循了这个示例(http://gitlab.itextsupport.com/itextsharp/tutorial/blob/master/signatures/chapter5/C5_03_CertificateValidation/C5_03_CertificateValidation.cs),但结果与我预期的不一样。具体地说,当试图通过OCSP或CRL验证签名时,结果通常是签名无法验证。我认为这种情况不应该发生,因为Adobe Reader可以验证签名。

我用来测试验证的pdf可以在以下链接中找到:html" target="_blank">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可以做到这一点。任何想法都很感激。

共有1个答案

唐增
2023-03-14

这个问题有两个方面:

  • 为什么iTextSharp似乎无法验证Adobe提供的给定示例签名?
  • 应该在哪个日期、使用哪个CRL进行吊销检查?

使用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是没有意义的。

即使受审查的证书尚未超过其最初的有效期,PKI提供者也可能已经倒闭。在这种情况下,所有用于撤销信息的访问点现在可能只服务于PKI仍然活动或根本不活动时创建的CRL的最终版本。

在这种情况下,可以使用最后的CRL或仍然可用的最新CRL(例如,在某个CRL缓存中),只要CRL足够最近。

上面的iText示例代码中使用的pkcs7.signdate可能只是PDF或CMS容器中某个字段的内容,可能是伪造的:有人可能已经获得了私钥;吊销关联证书后,该人员仍可能滥用密钥,将签名时间信息设置为吊销前的日期。

因此,您可能会以不同的方式确定签名日期。例如。

>

  • 如果签名容器包含签名时间戳,或者PDF文档包含稍后的文档时间戳,并且该时间戳可以信任,则可以使用该时间戳的时间;

  •  类似资料:
    • 为什么我的代码返回奇怪的结果? 我的代码给出了以下结果,它看起来不像是正确的计算结果:

    • 我有字节数组格式的公钥。在我的数据库里。像这样 在此处输入图像描述 总是suc=false。我确信bytetoverify的值与方法符号中的输入值相同。 我不知道我用这种方式生成公钥是问题还是符号有问题。在符号方法中,我使用sh1和pkcs1,但在验证中,我只找到sh1。 每个人都能帮我吗?

    • 出身背景 我使用iTextSharp已经有一段时间了。我已经创建了一个带有两个可签名的PdfFormFields的pdf文档。如果我打开pdf文档,我可以手动对每个字段进行手动签名。我希望通过iTextSharp完成这件事。 我目前正在从X509Store检索证书。直到现在,我都能弄明白。 问题 有人能告诉我如何使用X509Certificate2签署一个已经存在的签名字段吗。 工具书类 以下参考

    • 在我的应用程序中,我有一个公钥(表示为字符串),普通消息和数字签名,表示为base64编码字符串,用SHA256散列,用RSA加密)。现在,我需要验证数字签名。我试图做如下操作: 从创建(取自此处) 根据原始消息创建SHA256摘要 使用函数验证签名 (我正在努力避免使用OpenSSL函数) 此外,我的数字签名是使用Java的SHA256withRSA方法创建的。我在这里读到SHA256WithR

    • 我是使用数字签名的新手。在其中一个项目中,我们使用Apache PdfBox来处理数字签名的pdf文件。虽然我们可以测试所有功能,但签名pdf文件的验证是我们无法破解的。我们使用BouncyCastle作为提供程序。下面是代码: 从pdf文件获取数字签名和签名内容: 数字签名验证: 以下是p7b格式证书的相关摘录-我使用BouncyCastle作为安全提供程序: 使用上面的代码,我总是得到“fal

    • 我已经阅读了I-TEXT数字签名电子文本,以及MKL(他似乎和布鲁诺一起是这个主题的权威)回答的以前的帖子。 本质上,我有一个Azure应用程序服务,它从公司的签名API获得数字签名(基础64)和证书链。该公司的签名API在Base64中返回签名以及证书链。 我只想在pdf中插入一个签名对象/容器,这样当最终用户打开pdf时,它就会显示在签名面板中。我更喜欢使用延期签名。 可悲的是,事情不能工作,