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

使用iText实现PDF延迟签名后签名验证失败求助

iText延迟签名验证失败排查与证书链使用疑问

我在使用iText实现PDF延迟签名时,遇到签名验证失败的问题,系统提示“文档在签名后已被更改或损坏”。参考相关问题修改代码后,问题仍未解决。同时我有一个疑问:延迟签名前无法获取Certificate链,该如何使用emptySignature方法的chain参数?

核心实现代码

public static void emptySignature(String src, String dest, String fieldname, Certificate[] chain) throws IOException, DocumentException, GeneralSecurityException {
        PdfReader reader = new PdfReader(src);
        FileOutputStream os = new FileOutputStream(dest);
        PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');
        PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
        appearance.setVisibleSignature(new Rectangle(50, 780, 144, 780), 1, fieldname);
        appearance.setCertificate(chain[0]);
        ExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
        MakeSignature.signExternalContainer(appearance, external, 8192);
        InputStream inp = appearance.getRangeStream();
        BouncyCastleDigest digest = new BouncyCastleDigest();
        byte[] hash = DigestAlgorithms.digest(inp, digest.getMessageDigest("SHA256"));
// 需要将此哈希值传给第三方系统,获取签名后的哈希用于验证
        System.out.println("Hash: " + Base64.getEncoder().encodeToString(hash));
    }

    public static void createSignature(String src, String dest, String fieldname, PrivateKey pk, Certificate[] chain) throws IOException, DocumentException, GeneralSecurityException {
        PdfReader reader = new PdfReader(src);
        FileOutputStream os = new FileOutputStream(dest);
        ExternalSignatureContainer external = new MyExternalSignatureContainer(pk, chain);
        MakeSignature.signDeferred(reader, fieldname, os, external);
    }

main方法代码

public static void main(String[] args) throws DocumentException, GeneralSecurityException, IOException {
        // 1. 生成临时空签名文件
        emptySignature("mypdf.pdf", "temp.pdf", "", null);// 延迟签名前无法获取chain?该如何使用这个参数?
        // 2. 从第三方系统获取证书
        Certificate[] cert = getCert();
        KeyStore ks = KeyStore.getInstance("PKCS12");
        ks.load(new FileInputStream("aaa.p12"), "ogcio".toCharArray());
        String alias = ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey) ks.getKey(alias, "ogcio".toCharArray());
        createSignature("temp.pdf", "result.pdf", "", pk, cert);
    }

MyExternalSignatureContainer类代码

public class MyExternalSignatureContainer implements ExternalSignatureContainer {
    protected PrivateKey pk;
    protected Certificate[] chain;

    public MyExternalSignatureContainer(PrivateKey pk, Certificate[] chain) {
        this.pk = pk;
        this.chain = chain;
    }

    public byte[] sign(InputStream is) throws GeneralSecurityException {
        try {
            Security.addProvider(new BouncyCastleProvider());
            PrivateKeySignature signature = new PrivateKeySignature(pk, "SHA256", "BC");
            String hashAlgorithm = signature.getHashAlgorithm();
            BouncyCastleDigest digest = new BouncyCastleDigest();
            PdfPKCS7 sgn = new PdfPKCS7(null, chain, hashAlgorithm, null, digest, false);
            byte[] hash = DigestAlgorithms.digest(is, digest.getMessageDigest(hashAlgorithm));
            byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, MakeSignature.CryptoStandard.CMS);
            byte[] extSignature = signature.sign(sh);
            sgn.setExternalDigest(extSignature, null, signature.getEncryptionAlgorithm());
            return sgn.getEncodedPKCS7(hash, null, null, null, MakeSignature.CryptoStandard.CMS);
        } catch (IOException ioe) {
            throw new ExceptionConverter(ioe);
        }
    }

    public void modifySigningDictionary(PdfDictionary signDic) {
        //signDic.put(PdfName.FILTER, PdfName.ADOBE_PPKLITE);
        //signDic.put(PdfName.SUBFILTER, PdfName.ADBE_PKCS7_DETACHED);
    }
}

我已上传问题PDF文件,恳请帮忙排查签名验证失败的原因。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 08:14:57