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

使用iText 8验证PDF是否由自身自签名证书签署且未篡改

验证自签名证书签署的PDF(基于iText)

当然可以实现你的需求——直接用你持有的自签名证书验证PDF签名的真实性,同时确认文档未被篡改,完全不需要依赖PDF中的签名者名称等属性。核心思路是跳过信任链验证,直接用你本地证书的公钥验证签名值与文档内容的匹配性。

实现步骤与代码示例(Java)

  1. 加载本地的自签名证书,提取公钥
  2. 解析PDF中的签名信息,获取被签名的文档内容与签名值
  3. 用本地证书公钥验证签名是否有效,同时确认文档未被篡改
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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 17:48:13