问题
I have successfully signed a pdf with LTV support. I can check the pdf and LTV signature is valid through Adobe Acrobat Reader and also with an external validator.
I'm trying to make the same validation with iTextSharp 5.5.10.
I'm following the iText sample code C5_06
But when I call to ltvVerifier.Verify
, I am getting a System.NotSupportedException, The Uri Prefix is not Recognized
. I am loading the certificate used to sign the pdf en cert parameter.
Validation code:
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;
}
Auxiliary function that builds a List of X509Certificates from the certificate chain:
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();
}
A custom verifier, just copied from sample:
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>();
}
}
And this is the relevant stack trace:
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)
Thanks.
回答1:
The problem is that the certificates in the signer certificate chain present two URIs for CRL download, first a ldap URI and then a http URI, cf. @Egl's comment to your question, but that iText assumes it can simply take the first given URI and use System.Net.WebRequest
to request its content.
Unfortunately WebRequest
out-of-the-box only supports http:, https:, ftp:, and file: (cf. this msdn page). Thus, it fails iText's attempt to request the CRL via ldap with an Exception
which iText doesn't catch.
You can make this work by
either registering a ldap
WebRequest
handler (cf. this msdn page).Caveat: While the msdn pages suggest that doing something like this is possible, I have not yet done it. Furthermore the OP could not easily follow this path. Thus, there might be restrictions beyond what the msdn documentation describes. Probably only web-ish protocols (ftp:, file:, http:, https:) can be used?
Or changing the iText verifiers (either actually changing iText classes or copying/deriving one's own
CrlVerifier
andLtvVerifier
variants) to use the http-URI.This can either be implemented by catching such exceptions and then continuing with the next CRL request URI or (as done by the OP) by ignoring the ldap URI altogether (filtering it in
CertificateUtil.GetCRLURL
).
来源:https://stackoverflow.com/questions/41445353/pades-ltv-verification-in-itextsharp-throws-the-uri-prefix-is-not-recognized