I'm getting an Org.BouncyCastle.Security.InvalidKeyException
with error message Public key presented not for certificate signature when validating a pdf with LtvVerifier
.
This problem has arisen after circumventing an issue with CRL LDAP URIs. The code used to perform the verification is the same as the previous post:
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>();
}
}
I have re-implemented LtvVerifier
and CrlVerifier
as explained in the previous question. The CRL validation is done ok.
The certificate chain includes the certificate that was used to sign the PDF and the CA root certificate. The function CrlVerifier.Verify
is throwing the mentioned exception when calling the next line:
if (verifier != null)
result.AddRange(verifier.Verify(signCert, issuerCert, signDate));
// verify using the previous verifier in the chain (if any)
return result;
And this is the relevant stack trace of Org.BouncyCastle.Security.InvalidKeyException
:
in Org.BouncyCastle.X509.X509Certificate.CheckSignature(AsymmetricKeyParameter publicKey, ISigner signature)
in Org.BouncyCastle.X509.X509Certificate.Verify(AsymmetricKeyParameter key)
in iTextSharp.text.pdf.security.CertificateVerifier.Verify(X509Certificate signCert, X509Certificate issuerCert, DateTime signDate)
in iTextSharp.text.pdf.security.RootStoreVerifier.Verify(X509Certificate signCert, X509Certificate issuerCert, DateTime signDate)
in PdfCommon.CrlVerifierSkippingLdap.Verify(X509Certificate signCert, X509Certificate issuerCert, DateTime signDate) in c:\Projects\digit\Fuentes\PdfCommon\CrlVerifierSkippingLdap.cs:line 76
in iTextSharp.text.pdf.security.OcspVerifier.Verify(X509Certificate signCert, X509Certificate issuerCert, DateTime signDate)
in PdfCommon.LtvVerifierSkippingLdap.Verify(X509Certificate signCert, X509Certificate issuerCert, DateTime sigDate) in c:\Projects\digit\Fuentes\PdfCommon\LtvVerifierSkippingLdap.cs:line 221
in PdfCommon.LtvVerifierSkippingLdap.VerifySignature() in c:\Projects\digit\Fuentes\PdfCommon\LtvVerifierSkippingLdap.cs:line 148
in PdfCommon.LtvVerifierSkippingLdap.Verify(List`1 result) in c:\Projects\digit\Fuentes\PdfCommon\LtvVerifierSkippingLdap.cs:line 112
And a link to the pdf that I try to validate