使用PDFBox添加数字签名后Adobe Acrobat显示蓝框及未签名字段问题求助
我正在使用PDFBox库添加签名
我尝试为PDF附加数字签名,并通过Notarius证书颁发机构验证。将证书附加到PDF后用Adobe Acrobat打开,屏幕显示蓝色框而非签名图片;打开签名面板后,显示PDF已认证但包含三个未签名的签名字段(我的PDF原本有三个签名位)。请问出现蓝色框的原因是什么?如何让签名在Adobe Acrobat中可见且状态为已验证?
问题分析
- 蓝色框(未激活签名字段):你只创建了签名字段的外观,但没有完成实际签名流程——PDFBox中创建签名字段和完成数字签名是两个独立步骤。当前代码仅添加了空白签名字段,未将证书和签名值嵌入字段,所以Acrobat识别为未签名的空白字段,显示默认蓝色框。
- 签名面板显示未签名字段:同理,三个字段都只完成了UI创建,未执行签名加密流程,因此面板标记为未签名。
解决步骤
1. 修正签名字段外观绘制逻辑
当前代码的外观流坐标设置错误,导致签名图片被绘制在可见区域外。修改外观绘制部分:
try (PDPageContentStream cs = new PDPageContentStream(document, appearanceStream)) { // 填充字段背景色,使用字段实际尺寸 cs.setNonStrokingColor(Color.WHITE); cs.addRect(0, 0, rectangle.getWidth(), rectangle.getHeight()); cs.fill(); if (signImage != null) { cs.saveGraphicsState(); PDImageXObject img = PDImageXObject.createFromFileByExtension(signImage, document); // 根据字段尺寸等比例缩放图片,避免超出边界 float scaleX = rectangle.getWidth() / img.getWidth(); float scaleY = rectangle.getHeight() / img.getHeight(); float scale = Math.min(scaleX, scaleY); cs.transform(Matrix.getScaleInstance(scale, scale)); // 居中绘制图片 float x = (rectangle.getWidth() - img.getWidth() * scale) / 2 / scale; float y = (rectangle.getHeight() - img.getHeight() * scale) / 2 / scale; cs.drawImage(img, x, y); cs.restoreGraphicsState(); } }
2. 执行完整数字签名流程
创建签名字段后,需绑定签名对象并完成加密签名:
// 加载密钥库(示例为PKCS12格式) KeyStore ks = KeyStore.getInstance("PKCS12"); ks.load(new FileInputStream("你的密钥库文件.p12"), "密钥库密码".toCharArray()); String alias = ks.aliases().nextElement(); PrivateKey privateKey = (PrivateKey) ks.getKey(alias, "密钥密码".toCharArray()); Certificate[] certChain = ks.getCertificateChain(alias); // 创建签名对象 PDSignature signature = new PDSignature(); signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE); signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED); signature.setName("签名者姓名"); signature.setLocation("签名地点"); signature.setReason("签名原因"); signature.setSignDate(Calendar.getInstance()); // 将签名绑定到之前创建的签名字段 signatureField.setValue(signature); // 执行增量签名(保留原有PDF内容) ExternalSigningSupport externalSigning = document.saveIncrementalForExternalSigning(new FileOutputStream("已签名PDF文件.pdf")); byte[] content = IOUtils.toByteArray(externalSigning.getContent()); // 生成签名值 SignatureFactory sf = SignatureFactory.getInstance("SHA256withRSA"); Signature sig = sf.getInstance("SHA256withRSA"); sig.initSign(privateKey); sig.update(content); byte[] signedBytes = sig.sign(); // 写入签名结果 externalSigning.setSignature(signedBytes);
3. 验证注意事项
- 确保Notarius的根证书已添加到Adobe Acrobat的受信任证书列表,否则会显示签名未验证。
- 必须使用分离式签名(SUBFILTER_ADBE_PKCS7_DETACHED),这是Acrobat支持的标准签名格式。
- 保存PDF时需用增量保存方法,避免破坏原有签名字段结构。
内容的提问来源于stack exchange,提问作者Deep Morker
相关产品推荐
相关产品推荐

