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

无私钥场景下,如何用iText实现PDF多轮延迟签名?

用iText实现无私钥的多次PDF签名方案

核心限制说明

你遇到的错误是iText的设计限制:signDeferred()只能作用于最后一个添加的签名域。这是因为PDF签名链是顺序依赖的,后续签名的哈希计算必须基于前一个签名完成后的文档状态,预创建多个空域的思路本质上违背了这个依赖逻辑。

正确实现流程

1. 第一次签名操作

  • 先创建第一个空签名域,生成待签名哈希传给客户端:
    // 读取源PDF,准备添加第一个空签名域
    PdfReader reader = new PdfReader("source.pdf");
    ByteArrayOutputStream tempBaos = new ByteArrayOutputStream();
    PdfSigner signer = new PdfSigner(reader, tempBaos, new StampingProperties().useAppendMode());
    
    // 配置签名外观与域信息
    PdfSignatureAppearance appearance = signer.getSignatureAppearance();
    appearance.setFieldName("Signature1");
    signer.setSignatureCreator("YourApp");
    signer.setCertificationLevel(PdfSigner.NOT_CERTIFIED);
    
    // 生成待签名哈希(以SHA256为例)
    ExternalBlankSignatureContainer blankContainer = new ExternalBlankSignatureContainer(PdfName.Adobe_PPKLite, PdfName.Adbe_pkcs7_detached);
    byte[] hash = signer.getDocumentHash(blankContainer);
    
    // 将hash传给客户端,获取签名后的字节数组sigBytes
    
  • 拿到客户端返回的签名值后,填充第一个签名域:
    // 加载带有空签名域的临时PDF
    PdfReader deferredReader = new PdfReader(new ByteArrayInputStream(tempBaos.toByteArray()));
    ByteArrayOutputStream finalBaos = new ByteArrayOutputStream();
    PdfSigner deferredSigner = new PdfSigner(deferredReader, finalBaos, new StampingProperties().useAppendMode());
    
    // 用客户端返回的签名填充域
    ExternalSignatureContainer filledContainer = new ExternalSignatureContainer() {
        @Override
        public byte[] sign(InputStream data) throws GeneralSecurityException {
            return sigBytes; // 客户端返回的签名字节
        }
    };
    deferredSigner.signDeferred("Signature1", filledContainer);
    
    // 保存第一次签名完成的PDF,作为后续签名的源文件
    FileUtils.writeByteArrayToFile(new File("signed_once.pdf"), finalBaos.toByteArray());
    

2. 后续多次签名(重复此流程)

每一次新的签名都必须基于上一次签名完成后的PDF文件,重复以下步骤:

  1. 加载上一轮签名完成的PDF
  2. 添加新的唯一命名的空签名域(如"Signature2"、"Signature3")
  3. 生成该域对应的待签名哈希,传给客户端签名
  4. 用signDeferred()填充新添加的域,保存为新的PDF版本

为什么预创建多域不可行?

PDF签名机制要求每个签名的哈希必须包含之前所有签名的完整状态。预创建多个空域时,后续签名的哈希无法正确纳入前一个已填充签名的内容,而且iText限制signDeferred()仅操作最后一个域,是为了强制保证签名链的完整性和正确性。

关键注意事项

  • 每次签名必须启用useAppendMode(),避免修改原有签名内容,保证PDF的不可篡改性
  • 每个签名域的名称必须唯一,防止域覆盖冲突
  • 客户端返回的签名值必须严格对应当前步骤生成的哈希,不能跨步骤混用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 01:08:19