【问题标题】:Pades LTV verification in itextsharp throws The Uri Prefix is not Recognized在 itextsharp 中进行 LTV 验证会抛出无法识别 Uri 前缀
【发布时间】:2017-05-17 15:41:48
【问题描述】:

我已成功签署了一份支持 LTV 的 pdf。我可以通过 Adob​​e Acrobat Reader 和外部验证器检查 pdf 和 LTV 签名是否有效。

我正在尝试使用 iTextSharp 5.5.10 进行相同的验证。

我正在关注 iText 示例代码C5_06

但是当我打电话给ltvVerifier.Verify 时,我得到了System.NotSupportedException, The Uri Prefix is not Recognized。我正在加载用于签署 pdf en cert 参数的证书。

验证码:

   public static bool Validate(byte[] pdfIn, X509Certificate2 cert)
    {
        using (var reader = new PdfReader(pdfIn))
        {
            var fields = reader.AcroFields;
            var signames = fields.GetSignatureNames();

            if (!signames.Any(n => fields.SignatureCoversWholeDocument(n)))
                throw new Exception("None signature covers all document");

            var verifications = signames.Select(n => fields.VerifySignature(n));

            var invalidSignature = verifications.Where(v => !v.Verify());
            var invalidTimeStamp = verifications.Where(v => !v.VerifyTimestampImprint());

            if (invalidSignature.Any())
                throw new Exception("Invalid signature found");
        }

        using (var reader = new PdfReader(pdfIn))
        {
            var ltvVerifier = new LtvVerifier(reader)
            {
                OnlineCheckingAllowed = false,
                CertificateOption = LtvVerification.CertificateOption.WHOLE_CHAIN,
                Certificates = GetChain(cert).ToList(),
                VerifyRootCertificate = false,
                Verifier = new MyVerifier(null)
            };

            var ltvResult = new List<VerificationOK> { };
            ltvVerifier.Verify(ltvResult);

            if (!ltvResult.Any())
                throw new Exception("Ltv verification failed");
        }
        return true;
   }

从证书链构建 X509Certificates 列表的辅助函数:

    private static X509.X509Certificate[] GetChain(X509Certificate2 myCert)
    {
        var x509Chain = new X509Chain();
        x509Chain.Build(myCert);

        var chain = new List<X509.X509Certificate>();
        foreach(var cert in x509Chain.ChainElements)
        {
            chain.Add(
                DotNetUtilities.FromX509Certificate(cert.Certificate)
                );
        }

        return chain.ToArray();
    }

一个自定义验证器,刚刚从示例中复制:

 class MyVerifier : CertificateVerifier
{
    public MyVerifier(CertificateVerifier verifier) : base(verifier) { }

    override public List<VerificationOK> Verify(
        X509.X509Certificate signCert, X509.X509Certificate issuerCert, DateTime signDate)
    {
        Console.WriteLine(signCert.SubjectDN + ": ALL VERIFICATIONS DONE");
        return new List<VerificationOK>();
    }
}

这是相关的堆栈跟踪:

  in System.Net.WebRequest.Create(Uri requestUri, Boolean useUriBase)
   in System.Net.WebRequest.Create(String requestUriString)
   in iTextSharp.text.pdf.security.CrlVerifier.GetCrl(X509Certificate signCert, X509Certificate issuerCert)
   in iTextSharp.text.pdf.security.CrlVerifier.Verify(X509Certificate signCert, X509Certificate issuerCert, DateTime signDate)
   in iTextSharp.text.pdf.security.OcspVerifier.Verify(X509Certificate signCert, X509Certificate issuerCert, DateTime signDate)
   in iTextSharp.text.pdf.security.LtvVerifier.Verify(X509Certificate signCert, X509Certificate issuerCert, DateTime sigDate)
   in iTextSharp.text.pdf.security.LtvVerifier.VerifySignature()
   in iTextSharp.text.pdf.security.LtvVerifier.Verify(List`1 result)

谢谢。

【问题讨论】:

  • 你能分享有问题的PDF吗?看起来某些证书的 CRL 的位置没有作为System.Net.WebRequest 支持的 URL 给出。
  • @mkl,请在以下链接中找到 PDF:drive.google.com/file/d/0BxGvNZY_rGbVRlV5blZFOV9jZ2c/…
  • Validate 无法编译 - “并非所有代码路径都返回值”。实际上没有。
  • 您将哪个X509Certificate2 输入Validate
  • 从 PDF 签名中,证书包含此 CRLDistributionPoints 扩展:
    X509v3 CRL Distribution Points: &lt;br/&gt; Full Name:&lt;br/&gt; URI:ldap://ldapcomp.cert.fnmt.es/CN=CRL1,OU=AC%20Componentes%20Informaticos,O=FNMT-RCM,C=ES?certificateRevocationList;binary?base?objectclass=cRLDistributionPoint&lt;br/&gt; URI:http://www.cert.fnmt.es/crlscomp/CRL1.crl

标签: c# pdf itext digital-signature


【解决方案1】:

问题在于签署者证书链中的证书提供了两个用于 CRL 下载的 URI,首先是 ldap URI,然后是 http URI,参见。 @Egl 对您的问题的评论,但 iText 假设它可以简单地获取第一个给定的 URI 并使用 System.Net.WebRequest 来请求其内容。

不幸的是,WebRequest 开箱即用仅支持 http:、https:、ftp: 和 file:(参见 this msdn page)。因此,它失败了 iText 通过 ldap 请求 CRL 的尝试,其中 iText 没有捕获到 Exception

你可以通过

  • 要么注册一个 ldap WebRequest 处理程序(参见this msdn page)。

    警告:虽然 msdn 页面表明可以执行此类操作,但我还没有这样做。此外,OP 不能轻易地遵循这条道路。因此,可能存在超出 msdn 文档描述的限制。可能只有web-ish 协议(ftp:、file:、http:、https:)可以使用?

  • 或更改 iText 验证器(实际更改 iText 类或复制/派生自己的 CrlVerifierLtvVerifier 变体)以使用 http-URI。

    这可以通过捕获此类异常然后继续下一个 CRL 请求 URI 来实现,或者(由 OP 完成)完全忽略 ldap URI(在 CertificateUtil.GetCRLURL 中过滤它)。

【讨论】:

  • 第一种方法。我通过 WebRequest.RegisterPrefix("ldap://", new MyWebRequest()) 注册了一个 ldap 处理程序,其中 MyWebRequest 只需调用 WebRequest.Create(uri)。它仍然拒绝“ldap”前缀。不知道如何避免这种情况。
  • 第二种方法。我创建了自定义副本 MyLtvVerifer、MyCrlVerifier。唯一必须更改的是在 CrlVerifier 中对 CertificateUtil.GetCRLURL 的调用。它检索找到的第一个 Crl Uri,因此我过滤掉任何以“ldap://”开头的 Uri。通过该更改,我避免了 Uri Prefix 错误。不幸的是,我在验证 CA 证书时遇到了一个新错误,但我想这将是另一个问题(Org.BouncyCastle.Security.InvalidKeyException: Public key Presented not for certificate signature)。
  • mkl,感谢您的建议。我的 cmets 对你有意义吗?如果猜到我将不得不坚持使用第二个选项。
  • @jruizaranguren 我承认我没有玩过WebRequest.RegisterPrefix。因此,我无法给出关于如何正确执行此操作的提示。但无论如何,第二种选择听起来并不那么糟糕。是的,InvalidKeyException 听起来完全是一个不同的问题。
  • 我想将此响应标记为答案,但也许最好添加提到的“警告”:RegisterPrefix 尚未针对 ldap 进行测试,第二种方法需要修改 LtvVerifier, CrlVerifier 并提供备用 CertificateUtil.GetCRLURL。
猜你喜欢
  • 2023-03-05
  • 2020-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-26
  • 1970-01-01
  • 2021-09-28
相关资源
最近更新 更多