Node.js签名PDF配置正确但Adobe Acrobat验证无效求助
问题:Node.js签名PDF在Adobe Acrobat中无效且未正确识别TSA时间戳
背景信息
- 项目需求:使用Node.js对PDF进行数字签名,要求使用.pfx证书并添加TSA时间戳
- 已完成操作:
- 使用
@signpdf/signpdf库执行签名 - 通过
@signpdf/placeholder-plain添加ByteRange占位符 - 配置TSA地址为
https://freetsa.org/tsr - 确认.pfx证书与私钥匹配
- 使用
- 异常现象:
- 签名后的PDF可通过巴西官方ITI验证器验证
- 在Adobe Acrobat中显示签名无效,且提示“文档使用计算机本地时间签名”(已配置TSA)
相关代码
const fs = require('fs'); const { plainAddPlaceholder } = require('@signpdf/placeholder-plain'); const { SignPdf } = require('@signpdf/signpdf'); const { P12Signer } = require('@signpdf/signer-p12'); // Paths const pdfPath = '../resources/pdf-entrada.pdf'; // Input PDF const pfxPath = '../resources/certificado.pfx'; // PFX certificate const signedPath = '../resources/output-signed.pdf'; // Final signed PDF const pfxPassword = 'your_password_here'; // Certificate password const tsaUrl = 'https://freetsa.org/tsr'; // TSA URL async function signPdfWithTSA() { try { console.log('--- Start of Signing Process ---'); console.log('[1] Reading the original PDF...'); const pdfBuffer = fs.readFileSync(pdfPath); console.log(`[1] Original PDF size: ${pdfBuffer.length} bytes`); console.log('[2] Adding ByteRange (Placeholder for signature)...'); const pdfWithPlaceholder = plainAddPlaceholder({ pdfBuffer, reason: 'Digital Signature', contactInfo: 'email@example.com', name: 'Your Name', location: 'City / Country', }); console.log(`[2] PDF with Placeholder size: ${pdfWithPlaceholder.length} bytes`); console.log('[3] Reading the PFX certificate...'); const pfxBuffer = fs.readFileSync(pfxPath); console.log(`[3] PFX certificate size: ${pfxBuffer.length} bytes`); console.log('[4] Configuring signer with TSA...'); const signer = new P12Signer(pfxBuffer, { passphrase: pfxPassword, tsaUrl }); const signPdf = new SignPdf(); console.log('[5] Signing the PDF...'); const signedPdfBuffer = await signPdf.sign(pdfWithPlaceholder, signer); console.log(`[5] Signed PDF size: ${signedPdfBuffer.length} bytes`); console.log('[6] Saving the signed PDF...'); fs.writeFileSync(signedPath, signedPdfBuffer); console.log(`[6] Signed PDF saved at: ${signedPath}`); console.log('--- End of Signing Process ---'); } catch (error) { console.error('Error while signing the PDF:', error.message || error); } } signPdfWithTSA();
执行日志
--- Start of Signing Process --- [1] Reading the original PDF... [1] Original PDF size: 22368 bytes [2] Adding ByteRange (Placeholder for signature)... [2] PDF with Placeholder size: 39989 bytes [3] Reading the PFX certificate... [3] PFX certificate size: 9200 bytes [4] Configuring signer with TSA... [5] Signing the PDF... [5] Signed PDF size: 39989 bytes [6] Saving the signed PDF... [6] Signed PDF saved at: ../resources/output-signed.pdf --- End of Signing Process ---
可能的原因及排查步骤
TSA时间戳未正确嵌入签名字典
- Adobe要求时间戳必须嵌入到签名字典的
TimeStamp字段中,需确认@signpdf/signer-p12是否正确将TSA返回的RFC 3161格式时间戳令牌写入该字段。可使用PDF解析工具(如PDFtk)查看签名字典结构,检查是否存在TimeStamp条目。
- Adobe要求时间戳必须嵌入到签名字典的
占位符生成未包含TSA相关字段
plainAddPlaceholder生成的签名模板可能缺少TimeStamp相关的预留配置,导致签名后无法被Adobe识别为带时间戳的签名。尝试手动扩展签名字典,添加TimeStamp占位字段,或使用支持TSA的占位符生成方法。
@signpdf库的TSA实现存在兼容性问题
- 部分版本的
@signpdf/signer-p12可能存在TSA请求/响应处理的bug,建议升级到库的最新版本测试。也可替换为node-signpdf等其他成熟PDF签名库对比结果,排除库本身的问题。
- 部分版本的
Adobe对TSA证书的信任限制
- Adobe的信任列表可能未包含freetsa.org的根证书,导致无法验证时间戳有效性。可尝试手动导入该TSA的根证书到Adobe的信任存储,或更换为Adobe信任的TSA服务进行验证。
签名字节范围替换异常
- 日志显示签名前后PDF大小完全一致,正常情况下嵌入签名值和时间戳后文件应略有增大。需检查
SignPdf.sign方法是否正确替换了ByteRange占位符,是否存在签名值未写入PDF的情况。
- 日志显示签名前后PDF大小完全一致,正常情况下嵌入签名值和时间戳后文件应略有增大。需检查
内容的提问来源于stack exchange,提问作者Julio Martins
相关产品推荐
相关产品推荐

