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

C#添加LTV至PDF签名后签名无效且提示文档已变更

问题:添加LTV后PDF签名失效,多签名场景旧签名也无效

看起来你在使用iTextSharp处理PDF签名和LTV时遇到了挺棘手的问题——添加LTV后签名失效,甚至多签名场景下旧签名也出问题。结合你提供的代码和文档情况,我梳理了几个关键问题和修复方案:

相关文档状态:

  • 未签名PDF
  • 未添加LTV的已签名PDF
  • 单签名且添加LTV的PDF
  • 双签名且添加LTV的PDF

代码问题分析与修复建议

1. AddLtv方法逻辑缺陷

你的AddLtv方法中,对TSA签名和普通签名的处理逻辑存在不合理之处:

  • 当签名是TSA签名时仅验证最后一个签名,但普通签名时遍历所有签名添加验证数据,这会导致重复处理,甚至破坏原有签名结构。
  • 更合理的逻辑应该是遍历所有签名,针对每个签名添加对应的LTV验证数据,无需刻意区分TSA与否(除非有特殊业务需求)。

修改后的AddLtv方法:

public void AddLtv(string src, string dest, IOcspClient ocsp, ICrlClient crl, ITSAClient tsa)
{
    using (PdfReader r = new PdfReader(src))
    {
        // 启用非伦理读取,避免因文档权限问题无法处理
        PdfReader.unethicalreading = true;
        using (FileStream fos = new FileStream(dest, FileMode.CreateNew))
        {
            // 使用Append模式,避免覆盖原有签名的交叉引用表
            PdfStamper stp = PdfStamper.CreateSignature(r, fos, '\0', null, true);
            LtvVerification v = stp.LtvVerification;
            AcroFields fields = stp.AcroFields;
            List<String> names = fields.GetSignatureNames();

            foreach (var name in names)
            {
                try
                {
                    PdfPKCS7 pkcs7 = fields.VerifySignature(name);
                    // 根据签名类型选择合适的证书选项
                    var certOption = pkcs7.IsTsp 
                        ? LtvVerification.CertificateOption.SIGNING_CERTIFICATE 
                        : LtvVerification.CertificateOption.WHOLE_CHAIN;
                    v.AddVerification(name, ocsp, crl, certOption, LtvVerification.Level.OCSP_CRL, LtvVerification.CertificateInclusion.NO);
                }
                catch (Exception ex)
                {
                    // 处理单个签名验证失败的情况,避免影响其他签名
                    Console.WriteLine($"处理签名 {name} 时出错: {ex.Message}");
                }
            }
            stp.Close();
        }
    }
}

2. SignPdf方法中的目录创建错误

你在创建目录时存在逻辑错误:

if (!Directory.Exists(Path.GetDirectoryName(trustedSignedpdf)))
{
    Directory.CreateDirectory(trustedSignedpdf); // 错误:这里应该创建目录而非文件路径
}

trustedSignedpdf是文件路径,直接调用Directory.CreateDirectory会创建一个和文件名同名的目录,后续写入文件时会报错。修改为:

string trustedSignedDir = Path.GetDirectoryName(trustedSignedpdf);
if (!Directory.Exists(trustedSignedDir))
{
    Directory.CreateDirectory(trustedSignedDir);
}

同样的问题也出现在tempPdf的目录创建逻辑中,需要一并修正。

3. 交叉引用表破坏问题

根据你提到的跨PDF引用问题,iTextSharp在处理已签名PDF时,如果使用普通的PdfStamper而非CreateSignature的Append模式,可能会破坏原有的交叉引用表,导致签名验证失败:

  • 务必确保在添加LTV时使用PdfStamper.CreateSignature的Append模式(即最后一个参数为true),这会保留原有的签名和交叉引用表,仅添加LTV数据。

4. 签名容器处理的潜在问题

在SignPdf方法中,生成哈希和获取外部签名的逻辑可以优化:

  • 移除while (!check)循环,因为SHA256哈希的长度固定为64位十六进制字符串,只要哈希计算正确就不会出现长度不足的情况,循环重试没有必要。
  • 确保ocspResponse的传递正确,避免空值或无效的OCSP响应导致LTV验证失败。

额外验证建议

针对跨PDF引用问题,可以使用Adobe Acrobat的签名验证工具查看详细错误信息:

  1. 打开PDF,右键点击签名 -> 验证签名
  2. 查看“签名属性”中的“高级信息”,获取具体的验证失败原因(比如交叉引用表损坏、CRL/OCSP数据无效等)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 05:10:19