PDFBox - 签名后定义视觉签名模板

PDFBox - Define visual signature template after signing

我一直在阅读官方 PDFBox 示例以可视化方式签署 PDF 文档,特别是来自 CreateVisualSignature2.java 的示例,它生成一个空文档作为模板来定义签名外观,然后将其设置为通过调用 SignatureOptions.setVisibleSignature().

的真实文档

就我而言,我一直在使用 HSM 服务为我进行签名,因此我无法直接访问私钥或证书。我将文档哈希发送到此服务,它 returns 一个 PKCS7 字节数组,我使用 ExternalSigningSupport.setSignature().

添加到我的文档中

基于上面链接的 PDFBox 示例的代码如下所示:

// Read the document and prepare a signature.

PDDocument document = PDDocument.load( "path/to/file.pdf" );

PDSignature signature = new PDSignature();
signature.setFilter( PDSignature.FILTER_ADOBE_PPKLITE );
signature.setSubFilter( PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED );
signature.setReason( "Test" );

InputStream template = createVisualSignatureTemplate( document ); // Implementation defined below.
SignatureOptions options = new SignatureOptions();
options.setVisibleSignature( template );
options.setPage( 0 );

document.addSignature( signature, options );

// Get the content to sign using PDFBox external signing support.

FileOutputStream outputStream = new FileOutputStream();
ExternalSigningSupport externalSigning = document.saveIncrementalForExternalSigning( outputStream );
byte[] content = IOUtils.toByteArray( externalSigning.getContent() );

// Send the content to the HSM service and get the response.

byte[] hash = MessageDigest.getInstance( "SHA-256" ).digest( content );
byte[] pkcs7 = MyHSMService.getSignedHash( hash );

// Add the signature to the PDF. 

externalSigning.setSignature( pkcs7 );
document.close();

而我的模板方法,基于链接的 PDFBox 示例中的同名方法,简化了:

PDDocument emptyDocument = new PDDocument();
emptyDocument.addPage( new PDFPage( document.getPage(0).getMediaBox() ) );

// Create the PDAcroForm, PDSignatureField, PDAppearanceDictionary, etc,
// just like in the official example.

(...)

// Define the content stream of the visual signature.

PDPageContentStream content = new PDPageContentStream( emptyDocument, appearanceStream );

content.beginText();
content.showText( "Signed by: ... " ); // The signer name should be here.
content.newLine();
content.showText( "Date: ..." ); // The signature datetime should be here.
content.endText();
content.close();

// Convert the empty document as an input stream and return it, just like the example.

(...)

这很好用,我可以毫无问题地添加有效的视觉签名。我的问题是我需要在签名外观中添加签名者姓名和签名日期,但由于我在调用我的 HSM 服务进行签名之前创建了模板,所以我还无法访问该数据,这就是我需要的原因签署文件后定义内容。

有办法实现吗?我是 PDF 签名的新手,所以我对基础知识的理解很差。

提前致谢!

pdf 签名的文档内可视化是 pdf 小部件注释,因此它是签名内容的一部分。因此,必须在签名前添加,并且只能在其中使用签名前已知的信息。

虽然有一种选择,但大多数签名类型都允许在签名修订后更改修订中的注释。阅读 here 关于允许和不允许更改签名 pdf 文档的信息。

但是 pdf 查看器仍然可能会警告更改已在签名后应用到文档。这样的警告看起来像这样:

(此处签名外观已更改为红色对角十字。)

如果您再次签署这个更改后的文档,您甚至可以去掉顶部签名功能区中的警告:

(图片来自 this answer,其中使用 itext 更改签名外观已经过测试。)

When it comes to the datetime, I could show the date of the PDSignature object itself, but in this case the time shown in the visualization won't be the same as the time shown in the signatures panel in the PDF viewer, since the actual signature will happen a few seconds later when I call the HSM service. In this case I have no other choice than to make a new revision just to correct the time, right?

嗯,首先,嵌入在 pdf 签名中的 CMS 签名容器中不需要签名时间属性,因为签名时间也可以在 M 中给出entry if 签名字典。

因此,一种选择是尝试检索没有签名时间属性的签名容器。在这种情况下,PDSignature 签名时间将显示在签名面板中。

但是,如果您使用数字时间戳来记录签名时间,它是 CMS 签名容器的一部分,甚至是单独的文档时间戳,所以这个选项将不起作用。

此外,您还提到了签名面板。由于可以在那里找到确切的信息,您真的需要签名可视化中的签名时间吗?可视化本质上只是装饰性的,它可能包含任意信息,因此任何人都不应该相信它。 Adobe 早在多年前就已经警告过这一点,甚至在 pdf 成为 ISO 标准之前...

因此,另一种选择就是在此处放置一个漂亮的徽标,仅此而已!