You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

禁用在线获取时,SignatureValidator为何无法使用DSS中的OCSP/CRL?

问题描述

我基于iText 9.0构建了以下PDF归档验证工作流:

  1. 使用iText为PDF添加时间戳
  2. 将长期验证(LTV)信息嵌入文档安全存储(DSS)
  3. 通过SignatureValidator验证文档是否符合归档标准

为实现离线验证,我配置SignatureValidator禁用OCSP/CRL的在线获取,但验证失败;仅启用在线获取时才能成功。调试发现SignatureValidator未使用嵌入在DSS中的OCSP/CRL数据。

复现代码如下:

// 1) 为PDF添加时间戳
var inputPdfReader = new PdfReader("not_signed.pdf");
var outputStream = new FileStream("signed.pdf", FileMode.Create);
var tsaClient = new TSAClientBouncyCastle("https://freetsa.org/tsr", null, null, 8192, "SHA-256");
var stampingProperties = new StampingProperties();
PdfSigner pdfSigner = new PdfSigner(inputPdfReader, outputStream, stampingProperties);
pdfSigner.Timestamp(tsaClient, null);
outputStream.Close();

// 2) 嵌入LTV信息到DSS
var signedReader = new PdfReader("signed.pdf");
var ltvWriter = new PdfWriter("signed_ltv.pdf");
var ltvDocument = new PdfDocument(signedReader, ltvWriter, new StampingProperties().UseAppendMode());
LtvVerification v = new LtvVerification(ltvDocument);
SignatureUtil signatureUtil = new SignatureUtil(ltvDocument);
var names = signatureUtil.GetSignatureNames();
var pkcs7 = signatureUtil.ReadSignatureData(names.Single());
Debug.Assert(pkcs7.IsTsp());
v.AddVerification(names[0], (IOcspClient)new OcspClientBouncyCastle(), new CrlClientOnline(), LtvVerification.CertificateOption.WHOLE_CHAIN,
    LtvVerification.Level.OCSP_CRL, LtvVerification.CertificateInclusion.NO);
v.Merge();
ltvDocument.Close();

// 3) 验证LTV信息(禁用在线获取时失败)
var validationProperties = new SignatureValidationProperties();

// 注释此行允许在线获取则验证成功,但需要完全离线验证
validationProperties.SetRevocationOnlineFetching(ValidatorContexts.All(), CertificateSources.All(), TimeBasedContexts.All(), SignatureValidationProperties.OnlineFetching.NEVER_FETCH);

// iText 9.0 bug修复:处理缺失的必要扩展
List<CertificateExtension> certIssuerRequiredExtensions = new();
certIssuerRequiredExtensions.Add(new KeyUsageExtension(KeyUsage.KEY_CERT_SIGN));
certIssuerRequiredExtensions.Add(new DynamicBasicConstraintsExtension());
validationProperties.SetRequiredExtensions(CertificateSources.Of(CertificateSource.CERT_ISSUER),
    [new KeyUsageExtension(KeyUsage.KEY_CERT_SIGN), new MyDynamicBasicConstraintsExtension()]);
var ks = new List<IX509Certificate>();
using (var stream = new FileStream("freetsa_root.cer", FileMode.Open))
{
    ks.Add(new X509CertificateBC(new X509CertificateParser().ReadCertificate(stream)));
}

using (var stream = new FileStream("freetsa_root2.cer", FileMode.Open))
{
    ks.Add(new X509CertificateBC(new X509CertificateParser().ReadCertificate(stream)));
}
var validatorChainBuilder = new ValidatorChainBuilder()
    .WithSignatureValidationProperties(validationProperties)
    .WithTrustedCertificates(ks);
ltvDocument = new PdfDocument(new PdfReader("signed_ltv.pdf"));
var validator = validatorChainBuilder.BuildSignatureValidator(ltvDocument);

var validationReport = validator.ValidateSignatures();
var validationFailures = validationReport.GetFailures();
解决思路与方法

1. 确认DSS中已正确嵌入吊销数据

时间戳签名的LTV处理逻辑与普通签名略有差异,需确保LtvVerification的配置正确写入了OCSP/CRL数据到DSS:

  • 检查names[0]是否为正确的时间戳签名名称,可通过signatureUtil.GetSignatureNames()输出确认
  • 调整AddVerification的参数:对于时间戳,可尝试将CertificateOption改为SIGNING_CERTIFICATE,避免不必要的证书链处理
  • 使用PDF查看工具(如iText RUPS)打开signed_ltv.pdf,确认DSS字典中包含OCSPs和CRLs条目

2. 显式配置SignatureValidator使用嵌入的DSS数据

iText 9的SignatureValidator默认不会自动优先读取DSS中的吊销数据,需手动提取并注入到验证链中:

// 在构建validator前,从DSS提取嵌入的吊销数据
DssParser dssParser = new DssParser(ltvDocument);
DssInfo dssInfo = dssParser.Parse();
List<IRevocationData> embeddedRevocationData = new List<IRevocationData>();
embeddedRevocationData.AddRange(dssInfo.GetOcsps().Cast<IRevocationData>());
embeddedRevocationData.AddRange(dssInfo.GetCrls().Cast<IRevocationData>());

// 将嵌入数据添加到验证链构建器
var validatorChainBuilder = new ValidatorChainBuilder()
    .WithSignatureValidationProperties(validationProperties)
    .WithTrustedCertificates(ks)
    .WithAdditionalRevocationData(embeddedRevocationData);

3. 调整验证属性配置

确保validationProperties允许从文档嵌入来源获取吊销数据:

  • 无需额外禁用文档内吊销数据的读取,默认配置下SignatureValidator会优先使用嵌入数据,但需显式注入(如步骤2)
  • 确认MyDynamicBasicConstraintsExtension的实现正确,避免因证书扩展验证失败导致整体验证不通过

4. 验证时间戳签名的特殊逻辑

时间戳签名的验证依赖TSA证书链,需确保:

  • 信任库中包含freetsa.org的完整根证书链
  • 时间戳的签名数据被正确识别为TSP(代码中已通过Debug.Assert(pkcs7.IsTsp())确认,此部分无问题)

内容的提问来源于stack exchange,提问作者craffael

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 23:49:57