使用iText 8验证PDF是否由自身自签名证书签署且未篡改
验证自签名证书签署的PDF(基于iText)
当然可以实现你的需求——直接用你持有的自签名证书验证PDF签名的真实性,同时确认文档未被篡改,完全不需要依赖PDF中的签名者名称等属性。核心思路是跳过信任链验证,直接用你本地证书的公钥验证签名值与文档内容的匹配性。
实现步骤与代码示例(Java)
- 加载本地的自签名证书,提取公钥
- 解析PDF中的签名信息,获取被签名的文档内容与签名值
- 用本地证书公钥验证签名是否有效,同时确认文档未被篡改
import com.itextpdf.kernel.pdf.PdfDocument; import com.itextpdf.kernel.pdf.PdfReader; import com.itextpdf.signatures.PdfSignature; import com.itextpdf.signatures.SignatureUtil; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.io.FileInputStream; import java.security.PublicKey; import java.security.Signature; public class SelfSignedPdfVerifier { public static boolean verifyPdf(String pdfFilePath, String selfSignedCertPath) throws Exception { // 加载本地自签名证书 CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); X509Certificate localCert = (X509Certificate) certFactory.generateCertificate(new FileInputStream(selfSignedCertPath)); PublicKey publicKey = localCert.getPublicKey(); // 读取PDF并获取签名工具 PdfReader reader = new PdfReader(pdfFilePath); PdfDocument pdfDoc = new PdfDocument(reader); SignatureUtil signatureUtil = new SignatureUtil(pdfDoc); // 遍历PDF中的所有签名(如果有多个签名) for (String sigName : signatureUtil.getSignatureNames()) { PdfSignature pdfSignature = signatureUtil.getSignature(sigName); // 可选:对比证书指纹,确保签名使用的证书与本地证书完全一致 X509Certificate sigCert = (X509Certificate) pdfSignature.getSignCertificate(); if (!getCertFingerprint(localCert, "SHA-256").equals(getCertFingerprint(sigCert, "SHA-256"))) { continue; } // 初始化签名验证器 String hashAlg = pdfSignature.getHashAlgorithm(); Signature signature = Signature.getInstance(hashAlg + "with" + publicKey.getAlgorithm()); signature.initVerify(publicKey); // 读取签名对应的文档内容(自动排除签名区域,确保只验证签名时的原始内容) byte[] signedContent = signatureUtil.getSignedContent(sigName); signature.update(signedContent); // 获取签名值并验证 byte[] sigBytes = pdfSignature.getContents(); if (signature.verify(sigBytes)) { pdfDoc.close(); reader.close(); return true; } } pdfDoc.close(); reader.close(); return false; } // 辅助方法:获取证书的SHA-256指纹 private static String getCertFingerprint(X509Certificate cert, String algorithm) throws Exception { byte[] certBytes = cert.getEncoded(); java.security.MessageDigest md = java.security.MessageDigest.getInstance(algorithm); byte[] digest = md.digest(certBytes); StringBuilder sb = new StringBuilder(); for (byte b : digest) { sb.append(String.format("%02X:", b)); } return sb.substring(0, sb.length() - 1); } }
关键说明
- 跳过信任链:因为你明确目标是验证自己的自签名证书,不需要依赖第三方信任机构,直接用本地证书公钥验证即可,完全规避对签名属性的信任风险。
- 文档完整性:
signatureUtil.getSignedContent()会自动提取PDF中签名时的原始内容(排除后续添加的签名或篡改内容),因此签名验证通过即意味着文档未被篡改。 - 证书指纹校验:添加指纹比对可以进一步确保PDF中的签名证书与你本地的证书完全一致,避免出现伪造的同名证书签名情况。
- 私钥无需参与验证:验证签名只需要证书中的公钥,你只需要妥善保管自签名证书即可,私钥不需要在验证环节暴露。
内容的提问来源于stack exchange,提问作者Hagay Goshen
相关产品推荐
相关产品推荐

