C# 无法识别itextsharp中的Pades LTV验证抛出Uri前缀

C# 无法识别itextsharp中的Pades LTV验证抛出Uri前缀,c#,pdf,itext,digital-signature,C#,Pdf,Itext,Digital Signature,我已成功签署了一份带有LTV支持的pdf。我可以通过Adobe Acrobat Reader和外部验证器检查pdf和LTV签名是否有效 我试图用iTextSharp 5.5.10进行同样的验证 我遵循iText示例代码 但是当我调用ltvVerifier.Verify时,我得到一个System.NotSupportedException,Uri前缀无法识别。我正在加载用于签署pdf en cert参数的证书 验证代码: public static bool Validate(byte[]

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

我试图用iTextSharp 5.5.10进行同样的验证

我遵循iText示例代码

但是当我调用
ltvVerifier.Verify
时,我得到一个
System.NotSupportedException,Uri前缀无法识别。我正在加载用于签署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;
   }

谢谢。

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

不幸的是
WebRequest
开箱即用仅支持http:、https:、ftp:、和file:(cf.)。因此,iText通过ldap请求CRL的尝试失败,出现了iText无法捕获的
异常

你可以通过

  • 注册ldap
    WebRequest
    处理程序(参见)

    警告:虽然msdn页面表明这样做是可能的,但我还没有这样做。此外,OP无法轻易遵循这条路径。因此,可能存在msdn文档描述之外的限制。可能只有web ish协议(ftp:,文件:,http:,https:)可以使用

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

    这可以通过捕获此类异常然后继续下一个CRL请求URI来实现,也可以通过完全忽略ldap URI(在
    CertificateUtil.GetCRLURL
    中对其进行过滤)来实现


您能分享有问题的PDF吗?某些证书的CRL位置似乎不是作为
System.Net.WebRequest
支持的URL提供的。@mkl,请在以下链接中找到PDF:
Validate
无法编译-“并非所有代码路径都返回值”。实际上没有。您将哪个
X509Certificate2
输入到
Validate
?从PDF签名中,证书包含此CRLDistributionPoints扩展名:
X509v3 CRL分发点:
全名:
URI:ldap://ldapcomp.cert.fnmt.es/CN=CRL1,OU=AC%20组件%20信息,O=FNMT-RCM,C=ES?证书职业列表;binary?base?objectclass=cRLDistributionPoint
URI:http://www.cert.fnmt.es/crlscomp/CRL1.crl
1次进近。我通过WebRequest.RegisterPrefix(“ldap://”,new MyWebRequest())注册ldap处理程序,其中MyWebRequest只需调用WebRequest.Create(uri)。它仍然拒绝“ldap”前缀。不知道如何才能避免这种情况。第二种方法。我已经创建了自定义副本MyTvVerifer、MyCrlverifer。唯一需要更改的是在CrlVerifier中调用CertificateUtil.GetCRLURL。它检索找到的第一个Crl Uri,因此我过滤掉任何以“ldap://”开头的Uri。通过这种更改,我避免了Uri前缀错误。不幸的是,我在验证CA证书时遇到了一个新的错误,但我想这将是另一个问题(Org.bounchycastle.Security.InvalidKeyException:公钥不是用于证书签名的)。mkl,感谢您的建议。我的评论对你有意义吗?如果我猜我必须坚持第二个选择。@jruizaranguren我承认我没有玩过
WebRequest.RegisterPrefix
。因此,我无法给出如何正确操作的提示。但第二种选择听起来并没有那么糟糕。是的,
InvalidKeyException
听起来完全是另一个问题。我想将此响应标记为答案,但可能最好添加以下“注意事项”:RegisterPrefix尚未针对ldap进行测试,第二种方法需要修改LtvVerifier,crlverifer并提供备用证书eutil.GetCRLURL。
    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)