iText 8.0.3初始签名失效求助:添加/升级PAdES签名时签名无效
解决iText 8.0.3追加模式下破坏PAdES B-T签名的问题
问题场景
使用iText 8.0.3将PAdES B-T签名升级为B-LT,或执行添加新签名操作时,初始签名会触发“签名应用后文档已被更改或损坏”的无效提示。甚至仅用如下简单的追加模式读写代码,也会导致该问题(仅特定PDF文件出现,其他PDF正常):
String srcFileName = "./BT.pdf"; String outFileName = "./B-LT01.pdf"; PdfDocument document = new PdfDocument(new PdfReader(srcFileName), new PdfWriter(outFileName), new StampingProperties().useAppendMode()); document.close();
升级签名的完整业务代码如下:
byte[] addLTV(byte[] in) throws IOException, GeneralSecurityException, java.io.IOException { IOcspClient ocsp = new OcspClientBouncyCastle(new com.itextpdf.signatures.OCSPVerifier(null, null)); ICrlClient crl = new CrlClientOnline(); PdfReader reader = new PdfReader(new ByteArrayInputStream(in)); ByteArrayOutputStream out = new ByteArrayOutputStream(); PdfWriter writer = new PdfWriter(out); PdfDocument pdfDoc = new PdfDocument(reader, writer, new StampingProperties().useAppendMode()); LtvVerification v = new LtvVerification(pdfDoc); SignatureUtil signatureUtil = new SignatureUtil(pdfDoc); List<String> names = signatureUtil.getSignatureNames(); String sigName = names.get(names.size() - 1); PdfPKCS7 pkcs7 = signatureUtil.readSignatureData(sigName); if (pkcs7.isTsp()) { v.addVerification(sigName, ocsp, crl, LtvVerification.CertificateOption.WHOLE_CHAIN, LtvVerification.Level.OCSP_CRL, LtvVerification.CertificateInclusion.NO); } else { for (String name : names) { v.addVerification(name, ocsp, crl, LtvVerification.CertificateOption.WHOLE_CHAIN, LtvVerification.Level.OCSP_CRL, LtvVerification.CertificateInclusion.YES); } } v.merge(); pdfDoc.close(); return out.toByteArray(); }
问题原因
该问题源于目标PDF存在非标准结构(如异常的交叉引用表、对象流或自定义字典字段),iText默认的宽松解析模式会自动修复这些结构,导致原签名覆盖的字节内容发生变更,触发签名哈希验证失败。
解决方法
通过配置PdfReader启用严格解析模式,强制iText保留原文档的原始结构,仅在增量更新中添加新内容,避免修改原签名覆盖的字节:
1. 修改简单测试代码
String srcFileName = "./BT.pdf"; String outFileName = "./B-LT01.pdf"; // 配置Reader严格解析,禁用自动修复 PdfReaderProperties readerProps = new PdfReaderProperties().setStrictParsing(true); PdfReader reader = new PdfReader(srcFileName, readerProps); // 保持追加模式 StampingProperties stampProps = new StampingProperties().useAppendMode(); PdfDocument document = new PdfDocument(reader, new PdfWriter(outFileName), stampProps); document.close();
2. 修改添加LTV的完整代码
byte[] addLTV(byte[] in) throws IOException, GeneralSecurityException { IOcspClient ocsp = new OcspClientBouncyCastle(new com.itextpdf.signatures.OCSPVerifier(null, null)); ICrlClient crl = new CrlClientOnline(); // 启用严格解析模式,避免iText自动修改原文档结构 PdfReaderProperties readerProps = new PdfReaderProperties().setStrictParsing(true); PdfReader reader = new PdfReader(new ByteArrayInputStream(in), readerProps); ByteArrayOutputStream out = new ByteArrayOutputStream(); PdfWriter writer = new PdfWriter(out); // 使用追加模式,仅添加增量内容 StampingProperties stampProps = new StampingProperties().useAppendMode(); PdfDocument pdfDoc = new PdfDocument(reader, writer, stampProps); LtvVerification v = new LtvVerification(pdfDoc); SignatureUtil signatureUtil = new SignatureUtil(pdfDoc); List<String> names = signatureUtil.getSignatureNames(); String sigName = names.get(names.size() - 1); PdfPKCS7 pkcs7 = signatureUtil.readSignatureData(sigName); if (pkcs7.isTsp()) { v.addVerification(sigName, ocsp, crl, LtvVerification.CertificateOption.WHOLE_CHAIN, LtvVerification.Level.OCSP_CRL, LtvVerification.CertificateInclusion.NO); } else { for (String name : names) { v.addVerification(name, ocsp, crl, LtvVerification.CertificateOption.WHOLE_CHAIN, LtvVerification.Level.OCSP_CRL, LtvVerification.CertificateInclusion.YES); } } v.merge(); pdfDoc.close(); return out.toByteArray(); }
额外排查建议
如果严格解析模式仍未解决问题,可以尝试:
- 使用PDF结构检查工具(如Adobe Preflight)确认目标PDF是否存在交叉引用、对象流等结构异常。
- 检查原签名字典是否包含自定义扩展字段,必要时通过
PdfDictionary手动保留这些字段,避免iText误修改。
内容的提问来源于stack exchange,提问作者Vinh Dương
相关产品推荐
相关产品推荐

