7

I'm trying to migrate my application from iText 5.5.9 to iText 7 and I have a problem with signing a document on the server using a signature created on the client (described in the Digital Signatures for PDF documents).

As the getRangeStream() method isn't public anymore as it was in iText 5.5.9, how can I obtain a reference to the range stream?

David L
  • 175
  • 1
  • 14
  • Why was this question down-voted? It's a good question. I don't know the answer to it, because writing documentation is scheduled for later this year. I've given an up-vote so that the question doesn't have a negative score anymore. My advice however, would be to contact customer support at iText Group. As you are using iText 5.5.9, chances are that you need a commercial license. If not, please show us where we can find the code of your application released as AGPL software. – Bruno Lowagie Aug 10 '16 at 09:47
  • Hello Bruno, in fact my application is not yet finished and after reading your warnings about supports i decided to upgrade to Itext 7 before going too far. But don't worry, i'll buy a commercial licence – David L Aug 10 '16 at 09:58
  • *why is the result of this step invalid* - in which way is it invalid? I.e. *when* does *which exception* or other unexpected behavior occur? That been asked, I'm not sure it is a good idea to start with `Files.createTempFile` for a file which you want to keep across requests. – mkl Aug 25 '16 at 15:29
  • Ok, apart of the fact that this file will be deleted when the VM shutdown or if there is not enough disk space...this file is not readable within a second request nor in a pdf reader... – David L Aug 25 '16 at 15:44
  • In that case set the temp file permissions accordingly or refrain from using the temp file mechanism. – mkl Aug 25 '16 at 17:11
  • Complementary question on getRangeStream() at [link](http://stackoverflow.com/questions/39151230/in-itext-7-how-to-sign-a-pdf-with-2-steps) – David L Aug 25 '16 at 17:26

1 Answers1

3

getRangeStream is not the only method that was refactored from PdfSignatureAppearance to PdfSigner and made protected on that way. The same problem exists for other methods, too, like preClose and close which are also methods used in the PreSign and PostSign servlets from Digital Signatures for PDF documents which you seem to use or at least borrow code from.

This, as I presume, has been done to make iText 7 users use the signDeferred, signDetached, and signExternalContainer methods which usually are sufficient for signing applications and "do it correctly", i.e. use the other, now not anymore public methods in a way that creates valid signatures.

The PreSign and PostSign servlets as they are unfortunately cannot use those three methods, they actually are like the signDetached code ripped in two halves with the relevant local variables stored in the HTTP session.

Thus, you essentially have two choices:

Use the protected methods nonetheless

Unless I overlooked something, this can even be done by deriving your own signer class from PdfSigner and making those methods and probably member variables publicly accessibly again; using reflection magic at first sight doesn't seem necessary.

Change the PreSign and PostSign servlet architecture

If you could switch from keeping those signing related objects in memory (referenced via the HTTP session) to merely keeping an intermediary PDF file in memory or even on disk and probably the half-baked signature container in memory, you could proceed like this:

  • Replace the PreSign servlet by a servlet that "signs" the PDF using PdfSigner.signExternalContainer with a IExternalSignatureContainer implementation that merely provides a dummy signature, e.g. new byte[0].

    This IExternalSignatureContainer retrieves the sought-for range stream as parameter of its sign method, so it can calculate the range stream hash.

    Now the PDF with the dummy signature can be saved to disk or held in memory. And based on the range stream hash you can continue constructing and feeding the PdfPKCS7 instance as before. And hold that in memory, e.g. referenced from the HTTP session.

  • Replace the PostSign servlet by a servlet that as before finishes feeding the PdfPKCS7 instance and generates a CMS signature container. Then inject this container into the saved PDF using the PdfSigner.signDeferred method.

Alternatively you could even move the whole CMS signature container creation to the client. In that case all the session has to remember is where the intermediary PDF is stored...

Some inspiration may come from the C4_09_DeferredSigning.java iText 7 example.

mkl
  • 90,588
  • 15
  • 125
  • 265
  • Hello, I've tried as you said but when the document is closed after that the blank container was applied...it's not possible to reopen it without a file pointer exception...n.b. The document on which I apply the blank container already contains an empty signature field – David L Aug 25 '16 at 05:29
  • *it's not possible to reopen it without a file pointer exception* - that shouldn't be the case. But it's hard to say anything definitive without seeing the sources. *The document on which I apply the blank container already contains an empty signature field* - and you want to use that? Or keep it unused? – mkl Aug 25 '16 at 08:01
  • Complementary question on getRangeStream() at [link](http://stackoverflow.com/questions/39151230/in-itext-7-how-to-sign-a-pdf-with-2-steps) – David L Aug 25 '16 at 17:26
  • @mkl I went the route of deriving from PdfSigner and it worked perfectly. Did not require any reflection. Our signer client application now signs the hash without iText dependency. – brz May 21 '21 at 14:33
  • Hi @breez . How you do that? I try but it not work. Could you share your code? I need to get the hashes of several files to be signed in a single process. – Marcelo D. Ré Jun 28 '22 at 11:00