gpt4 book ai didi

c# - iTextSharp 中的 Pades LTV 验证抛出公钥不是用于根 CA 证书的证书签名

转载 作者:行者123 更新时间:2023-11-30 12:22:16 26 4
gpt4 key购买 nike

我得到一个 Org.BouncyCastle.Security.InvalidKeyException使用 LtvVerifier 验证 pdf 时出现错误消息 Public key presented not for certificate signature .

这个问题出现在circumventing an issue with CRL LDAP URIs之后.用于执行验证的代码与上一篇文章相同:

   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>();
}
}

我重新实现了LtvVerifierCrlVerifier如上一个问题所述。 CRL 验证完成。

证书链包括用于签署 PDF 的证书和 CA 根证书。函数 CrlVerifier.Verify调用下一行时抛出上述异常:

 if (verifier != null)
result.AddRange(verifier.Verify(signCert, issuerCert, signDate));
// verify using the previous verifier in the chain (if any)
return result;

这是 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

还有一个 link to the pdf that I try to validate

最佳答案

经过一些调试后发现

iText(Sharp) 5.5.10 LtvVerifier 在验证证书链未以自签名证书结尾的证书时,以观察到的方式失败。

原因

原因很简单:LtvVerifier 建立了一系列 Verifier 实例(OcspVerifierCrlVerifierRootStoreVerifier, CertificateVerifier;最后一个通过基类调用链接)。然后它请求相关签名的签名证书的证书链,并为链中的每个证书调用由该证书及其颁发者组成的证书对的 Verifier 序列;如果是链中的最终证书,null 将作为颁发者证书转发。

不幸的是,最终的VerifierCertificateVerifier,在null颁发者证书的情况下假定要验证的证书是自签名的:

// Check if the signature is valid
if (issuerCert != null) {
signCert.Verify(issuerCert.GetPublicKey());
}
// Also in case, the certificate is self-signed
else {
signCert.Verify(signCert.GetPublicKey());
}

(来自 CertificateVerifier 方法 Verify)

如果最初请求的 LtvVerifier 证书链没有以自签名证书结尾,则最终测试正确地得出观察到的结果

Org.BouncyCastle.Security.InvalidKeyException with error message Public key presented not for certificate signature

OP 的例子

在手头的案例中,我们有一个由

发布的文档时间戳

cn=AUTORIDAD DE SELLADO DE TIEMPO FNMT-RCM, ou=CERES, o=FNMT-RCM, c=ES

颁发者

cn=AC Administración Pública, serialNumber=Q2826004J, ou=CERES, o=FNMT-RCM, c=ES

颁发者

ou=AC RAIZ FNMT-RCM, o=FNMT-RCM, c=ES

这是自签名的。

在这种情况下,中介证书 AC Administración Pública 已经在欧洲信任列表中(参见 the TL manager for Spain,“信任服务提供商”,“Fábrica Nacional de Moneda y Timbre - Real Casa de la Moneda (FNMT-RCM)、“信托服务”、“Certificados reconocidos para su uso en el ámbito de...”、“数字身份”)。

因此,只需要前两个证书即可建立信任,不需要自签名根证书。因此,只有前两个证书嵌入到时间戳中并作为证书链返回给 LtvVerifier,而不是自签名根。

结果是 LtvVerifier 中观察到的错误。

做什么?

好吧,因为我们已经开始在 previous question 中创建我们自己的相关类副本。 ,对它们进行更多更改应该是一种选择。

在这种情况下,应该另外更改 RootStoreVerifier。它的 Verify 方法如下所示:

override public List<VerificationOK> Verify(X509Certificate signCert, X509Certificate issuerCert, DateTime signDate) {
LOGGER.Info("Root store verification: " + signCert.SubjectDN);
// verify using the CertificateVerifier if root store is missing
if (certificates == null)
return base.Verify(signCert, issuerCert, signDate);
try {
List<VerificationOK> result = new List<VerificationOK>();
// loop over the trusted anchors in the root store
foreach (X509Certificate anchor in certificates) {
try {
signCert.Verify(anchor.GetPublicKey());
LOGGER.Info("Certificate verified against root store");
result.Add(new VerificationOK(signCert, this, "Certificate verified against root store."));
result.AddRange(base.Verify(signCert, issuerCert, signDate));
return result;
} catch (GeneralSecurityException) {}
}
result.AddRange(base.Verify(signCert, issuerCert, signDate));
return result;
} catch (GeneralSecurityException) {
return base.Verify(signCert, issuerCert, signDate);
}
}

我们只需要删除标记线

                signCert.Verify(anchor.GetPublicKey());
LOGGER.Info("Certificate verified against root store");
result.Add(new VerificationOK(signCert, this, "Certificate verified against root store."));
// vvv remove
result.AddRange(base.Verify(signCert, issuerCert, signDate));
// ^^^ remove
return result;

在内部 try block 中。由于我们刚刚确定证书 signCert 是由信任 anchor 签署的,因此无论如何都不需要 base.Verify

关于c# - iTextSharp 中的 Pades LTV 验证抛出公钥不是用于根 CA 证书的证书签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41548918/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com