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

使用iText 5.5.13实现外部数字签名时遇NO FIELD错误求助

iText 5.5.13 外部数字签名 signDeferred 报 NO FIELD 错误解决

问题描述

使用Java结合iText 5.5.13实现外部数字签名时,执行MakeSignature.signDeferred()方法触发NO FIELD错误,签名流程分为4步:

  • 准备待签名PDF
  • 计算哈希值
  • 对哈希值进行签名
  • 将签名结果合并到源PDF

异常信息:

Exception in thread "main" com.itextpdf.text.DocumentException: No field
at com.itextpdf.text.pdf.security.MakeSignature.signDeferred(MakeSignature.java:291)
at test.SignerFinal.main(SignerFinal.java:219)

相关代码:

//step 1 - preparing pdf to sign

int contentEstimated2 = 8192;
String src = "src.pdf";
String dest = "dest.pdf";
InputStream is = new FileInputStream(src);
PdfReader reader = new PdfReader(is);
reader.setAppendable(true);
ByteArrayOutputStream  baos = new ByteArrayOutputStream ();
FileOutputStream os = new FileOutputStream(dest);
PdfStamper stamper = PdfStamper.createSignature(reader, baos, '\0');
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
String MotSigner = "GIF.jpg"; //IMAGE
Image image = Image.getInstance(MotSigner);
appearance.setImage(image);
appearance.setLayer2Text("");
Rectangle rect = new Rectangle(250, 795, 300, 840);
appearance.setVisibleSignature(rect, 1, "sig1");
ExternalSignatureContainer external = new
ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
MakeSignature.signExternalContainer(appearance, external, size);

// step 2 - calculating the hash
is = new ByteArrayInputStream(baos.toByteArray());
BouncyCastleDigest digest = new BouncyCastleDigest();
byte[] hash = DigestAlgorithms.digest(is, digest.getMessageDigest("SHA-256"));

//step 3 - signing the hash 
    //sending hash to signer server. getting SignedBytes as result
byte[] SignHashedPDF = Base64.decode(SignedBytes);


//step 4 - combine hash to the source pdf                                   
reader = new PdfReader(src);
FileOutputStream os1 = new FileOutputStream(dest);
ExternalSignatureContainer external1 = new MyExternalSignatureContainer(SignHashedPDF);
MakeSignature.signDeferred(reader, "sig1", os1, external1);
os.close();

}                       


class MyExternalSignatureContainer implements ExternalSignatureContainer {

    protected byte[] sig;

    public MyExternalSignatureContainer(byte[] sig) {
        this.sig = sig;
    }

    public byte[] sign(InputStream is) {
      return sig;
    }

    public void modifySigningDictionary(PdfDictionary signDic) {
    }

}

问题原因

第4步调用signDeferred时,传入的是原始的src.pdf,但签名域sig1是在第1步中添加到baos对应的临时PDF中的,原始PDF中根本不存在这个签名域,因此触发"No field"错误。

修复方案

核心修改点

  1. 第1步执行完signExternalContainer后,将baos中带有空白签名域的临时PDF保存到文件或内存;
  2. 第4步调用signDeferred时,读取带有空白签名域的临时PDF,而非原始的src.pdf。

修改后的关键代码片段

// step 1 修改:保存带有空白签名域的临时PDF
File tempFile = new File("temp.pdf");
try (FileOutputStream tempOs = new FileOutputStream(tempFile)) {
    baos.writeTo(tempOs);
}

// step 4 修改:读取临时文件而非原始src.pdf
try (PdfReader reader = new PdfReader(new FileInputStream(tempFile));
     FileOutputStream os1 = new FileOutputStream(dest)) {
    ExternalSignatureContainer external1 = new MyExternalSignatureContainer(SignHashedPDF);
    MakeSignature.signDeferred(reader, "sig1", os1, external1);
}
// 可选:删除临时文件
tempFile.delete();

其他细节修正

  • 第1步中size变量未定义,替换为已声明的contentEstimated2;
  • 补全MyExternalSignatureContainer构造方法的大括号;
  • 使用try-with-resources语法自动关闭流,避免资源泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 04:34:51