1

I've been reading the official PDFBox examples to visually sign a PDF document, especifically the example from CreateVisualSignature2.java, which generates an empty document as a template to define the signature appearance and then sets it to the real document by calling SignatureOptions.setVisibleSignature().

In my case, I've been using an HSM service to do the signing for me, so I don't have direct access to private keys or certificates. I send the document hash to this service and it returns a PKCS7 byte array which I add to my document using ExternalSigningSupport.setSignature().

The code, which is based on the PDFBox example linked above, looks like this:

// 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();

And my template method, based on the method of the same name in the linked PDFBox example, simplified:

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.

(...)

This works fine and I can add valid visual signatures without issues. My problem is that I need to add the signer name and sign date in the signature appearance, but since I create the template BEFORE calling my HSM service to sign, I don't have access to that data yet, which is why I need to define the content AFTER signing the document.

Is there a way to achieve this? I'm new to PDF signing, so my understanding of the fundamentals is pretty poor.

Thanks in advance!

afs35
  • 359
  • 1
  • 2
  • 14
  • 2
    The in-document visualization of a pdf signature is a pdf widget annotation and as such it is part of the signed content. Thus, it must be known before signing. There is one option, though, most signature types allow changing annotations in a revision after the signed revision. But a pdf viewer then still may warn that changes have been applied to the document after signing. – mkl May 16 '20 at 20:08
  • I see, thanks for the confirmation. When it comes to the signer name, I could just try to retrieve it by other means and add it to the template before signing. 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? – afs35 May 16 '20 at 21:18

1 Answers1

1

The in-document visualization of a pdf signature is a pdf widget annotation and as such it is part of the signed content. Thus, it must be added before signing and only information can be used in it which is known before signing.

There is one option, though, most signature types allow changing annotations in a revision after the signed revision. Read here about allowed and disallowed changes to signed pdf documents.

But a pdf viewer then still may warn that changes have been applied to the document after signing. Such a warning would look like this:

(Here the signature appearance has been changed to a red diagonal cross.)

If you sign this changed document again, you can even get rid of the warning in the signature ribbon at the top:

(Images are from this answer where changes to signature appearances using itext have been tested.)

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?

Well, first of all there is no need for a signing time attribute in the CMS signature container embedded in a pdf signature because the signing time can also be given in the M entry if the signature dictionary.

Thus, one choice is to try and retrieve a signature container without signing time attribute. In that case the PDSignature signing time will be shown in the signature panel.

If you use digital time stamps, though, to document the signing time, it is part of the CMS signature container or even a separate document time stamp, so this's option wouldn't work.

Furthermore, you mention the signature panel. As the exact information can be found there, do you really need the signing time in the signature visualization? The visualization is only cosmetic in nature, it may contain arbitrary information, so nobody should trust it anyways. Adobe had warned about this already many years ago, even before pdf became an ISO standard...

Thus, another choice is simply to put a nice looking logo there and that's it!

mkl
  • 90,588
  • 15
  • 125
  • 265
  • Thanks @mkl for the thorough answer. The visualization indeed holds no actual value when it comes to the signature validation, but in my case showing the date is a requirement, so I have no other choice than to show it. – afs35 May 18 '20 at 00:28
  • Also, since I receive the signature from an HSM, it already comes with the time attribute, so the time shown in the signatures panel differs with what is shown in the page by 10 seconds or so. Still, many thanks for the answer, you helped me have a clearer picture of the problem :) – afs35 May 18 '20 at 00:50
  • 1
    *"since I receive the signature from an HSM, it already comes with the time attribute"* - have you made sure that there is no option to make that HSM signing process drop the signing time attribute? Because if you were creating PAdES baseline pdf signatures, the presence of that attribute would not merely be inconvenient for creating a visualization, it would be an error. Thus, that HSM signing process could not be used in such a case... – mkl May 18 '20 at 04:50
  • _"have you made sure that there is no option to make that HSM signing process drop the signing time attribute?"_ - Honestly, I'm not sure. Since I receive the signature by calling a service made by an external company, I don't have a say in what I receive and I just add it to the document as-is. But the good news is that we are considering dropping the time from the visualization, so there's that. As you said, nobody should trust the visualization anyways, so dropping the time is a step in the right direction. Thanks a lot for your help, not only here but on every PDF-related question. Cheers! – afs35 May 19 '20 at 23:49